R语言中如何移除距离矩阵/对称矩阵及层次聚类中的异常值?
解答你的两个聚类异常值处理问题
我来帮你一步步解决这两个关于异常值处理的问题:
一、距离/对称矩阵中查找并移除异常值
针对距离矩阵或对称矩阵的异常值检测,核心思路是基于样本间的相对距离识别离群点,这里分享两种实用方法:
方法1:基于平均距离的IQR法
异常样本通常和其他所有样本的平均距离远大于大部分样本,我们可以用四分位距(IQR)划定正常范围,超出范围的视为异常值:
# 假设你的距离矩阵是dist对象d,先转换为矩阵格式 d_matrix <- as.matrix(d) # 计算每个样本到其他所有样本的平均距离 avg_dist <- rowMeans(d_matrix) # 用IQR计算异常值阈值 q1 <- quantile(avg_dist, 0.25) q3 <- quantile(avg_dist, 0.75) iqr_range <- q3 - q1 upper_cutoff <- q3 + 1.5 * iqr_range # 常用1.5倍IQR作为边界 # 找出平均距离超出上限的异常样本索引 outlier_idx <- which(avg_dist > upper_cutoff) # 从距离矩阵中移除异常值(同时删除对应的行和列) d_clean <- d[-outlier_idx, -outlier_idx]
方法2:局部离群因子(LOF)算法
LOF会计算每个样本的局部密度,若某样本的密度远低于其邻居,就会被标记为异常值,适合复杂分布的数据:
library(dbscan) # 用预处理后的原始数据计算LOF值(k取5-10都可以,代表参考的邻居数量) lof_scores <- lof(engmale161, k = 5) # 设定阈值(通常LOF>2就可视为异常值,可根据数据调整) outlier_idx <- which(lof_scores > 2) # 移除异常值后重新生成距离矩阵 engmale161_clean <- engmale161[-outlier_idx, ] d_clean <- dist(engmale161_clean, method = "euclidean")
二、移除层次聚类中识别出的单样本异常值
你已经通过聚类结果发现了ID为4165634865的单样本异常值,直接从原始数据中移除后重新执行聚类流程即可:
# 找到异常样本在原始数据中的行索引(根据行名匹配) outlier_idx <- which(rownames(engmale161) == "4165634865") # 从原始数据中移除该异常样本 engmale161_clean <- engmale161[-outlier_idx, ] # 重新执行你的预处理和聚类流程 engmale161_clean <- na.omit(engmale161_clean) engmale161_clean <- scale(engmale161_clean) d_clean <- dist(engmale161_clean, method = "euclidean") hc1_clean <- hclust(d_clean, method = "average") # 重新切割聚类(你之前已确定最优k=4,直接使用即可) sub_grp_clean <- cutree(hc1_clean, k = 4) table(sub_grp_clean) # 可视化验证聚类结果 fviz_cluster(list(data = engmale161_clean, cluster = sub_grp_clean), geom = "point")
补充建议:
如果后续经常遇到这类单样本聚类的情况,建议在聚类前先做异常值检测(用上面提到的IQR或LOF方法),提前过滤离群点,避免聚类结果出现极端的单样本簇。
内容的提问来源于stack exchange,提问作者김태환
相关产品推荐
相关产品推荐

