二值数据Jaccard距离计算疑问:全样本vs唯一样本(层次聚类用)
关于二值数据集Jaccard距离计算与层次聚类的选择问题
你提的这个问题正好戳中了二值数据集聚类的一个常见痛点——当观测存在大量重复时,到底该用全量数据还是唯一值来计算距离?咱们一步步理清楚:
先明确核心问题:过表示确实存在,重复计算完全没必要
你的判断完全正确:10个二值变量最多只有1024种唯一组合,10000条样本里肯定有大量重复的观测行,这就是所谓的“过表示”。直接用全量数据计算Jaccard距离的话,本质上是在反复计算相同组合之间的距离(结果都是0),既浪费算力,还会生成一个10000×10000的超大距离矩阵,后续聚类的速度会慢到让人崩溃。
两种计算方式的差异与选择建议
1. 直接用全量数据:philentropy::distance(dats, method = "jaccard")
这种方式唯一的“好处”是完全保留原始样本的行数,但代价极高:计算量是1024唯一值版本的近100倍,而且聚类结果的核心结构其实和用唯一值计算的完全一致——因为重复行只会在聚类树里形成密集的小分支,不会改变不同组合之间的聚类关系。除非你有特殊需求必须保留原始样本的行数(比如某些特定可视化),否则完全不推荐。
2. 用唯一观测计算:philentropy::distance(unique(dats), method = "jaccard")
这才是更高效、更合理的选择:
- 计算量骤降:从近5000万对距离计算降到约50万对,速度提升非常明显;
- 结果等价:唯一观测之间的Jaccard距离完全代表了所有样本间的差异本质,不会丢失任何聚类需要的信息;
- 后续扩展灵活:如果需要考虑每个唯一组合的出现次数(也就是权重),可以在聚类阶段单独加入权重参数,让聚类结果更贴合原始数据的分布。
适配层次聚类的完整流程(带权重版本)
# 1. 提取唯一观测并统计每个组合的出现次数 dats_unique <- unique(dats) # 生成每行的唯一标识,用来匹配计数 row_ids <- apply(dats, 1, paste, collapse = ",") counts <- as.numeric(table(row_ids)) # 确保计数顺序和唯一观测的顺序一致 counts <- counts[match(apply(dats_unique, 1, paste, collapse = ","), names(counts))] # 2. 计算唯一观测的Jaccard距离 dat.jac <- philentropy::distance(dats_unique, method = "jaccard") dist.jac.mat <- as.matrix(dat.jac) dist.jac.mat[is.na(dist.jac.mat)] <- 0 # 3. 带权重的层次聚类(需要weighted.hclust包) library(weighted.hclust) hc <- hclust(as.dist(dist.jac.mat), method = "single", weights = counts) # 4. 聚类数选择:用原始数据配合距离矩阵即可 fviz_nbclust(dats, FUN = hcut, diss = as.dist(dist.jac.mat), k.max = 15, nboot = 250, method = "silhouette")
如果不需要考虑权重,直接用基础的hclust函数就行,去掉weights参数即可。
总结一下
优先选择基于唯一观测计算Jaccard距离,这是兼顾效率和结果合理性的最优解。如果需要体现不同组合的样本占比,记得在聚类时加入权重参数,这样聚类结果会更贴合你的原始数据分布。
内容的提问来源于stack exchange,提问作者akash87
相关产品推荐
相关产品推荐

