You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何过滤相同聚类标签条目?解决大样本Rand Index计算困境

解决大数据集下计算Rand Index的内存问题

遇到这种大样本量的卡死情况,你的思路完全找对了——过滤掉两个聚类结果标签完全一致的样本,既能大幅压缩数据集规模,还完全不会影响最终的Rand Index结果。道理很简单:Rand Index本质是统计所有样本对的分类一致性,那些在两个聚类里标签都相同的样本,不管是同类配对还是不同类配对,它们的一致性判断都是固定的,去掉这些样本不会改变最终的指数值。

下面是具体的R实现步骤:

1. 先模拟你的数据集(复现问题场景)

假设你有两个聚类结果向量clust1和clust2,各包含80000个标签:

set.seed(123)
clust1 <- sample(1:10, 80000, replace = TRUE)
clust2 <- sample(1:10, 80000, replace = TRUE)
# 故意让大部分样本的两个聚类标签相同,模拟真实场景
same_idx <- sample(80000, 60000)
clust2[same_idx] <- clust1[same_idx]

2. 过滤出标签不同的样本

只保留两个聚类结果不一致的行,数据集规模会立刻缩小:

# 创建逻辑标记:哪些样本的两个聚类标签不一样
diff_mask <- clust1 != clust2
# 提取过滤后的子集
clust1_sub <- clust1[diff_mask]
clust2_sub <- clust2[diff_mask]

你可以用length(clust1_sub)看看剩下的样本量,大概率会比80000小很多,完全能避开table()函数的内存限制。

3. 计算Rand Index

现在用子集计算就没问题了,这里提供两种方式:

方法一:用fpc包的现成函数

library(fpc)
rand_result <- randIndex(clust1_sub, clust2_sub)
# 查看完整结果(包含Rand Index、调整后的Rand Index等)
print(rand_result)

方法二:手动计算(更轻量,无需额外包)

如果不想加载依赖包,也可以手动实现核心逻辑:

# 生成 contingency 表
contingency <- table(clust1_sub, clust2_sub)
# 计算各类配对数
a <- sum(contingency * (contingency - 1)) / 2  # 两个聚类都归为同一类的样本对
b <- sum(rowSums(contingency) * (rowSums(contingency) - 1)) / 2 - a  # clust1同但clust2不同的样本对
c <- sum(colSums(contingency) * (colSums(contingency) - 1)) / 2 - a  # clust2同但clust1不同的样本对
d <- choose(length(clust1_sub), 2) - a - b - c  # 两个聚类都不同的样本对
# 计算Rand Index
rand_index <- (a + d) / (a + b + c + d)
print(rand_index)

两种方法的结果会完全一致。

再确认下为什么这个方法可行

Rand Index的核心公式是(一致的同类配对数 + 一致的不同类配对数) / 总配对数。那些两个聚类标签完全相同的样本,它们的配对要么是两个聚类都判定为同类(属于a的一部分),要么是两个聚类都判定为不同类(属于d的一部分)。去掉这些样本后,剩下的只有分类不一致的情况,但计算它们的一致性比例,和包含全量样本的比例是完全相同的——相当于只是把分子分母按相同比例缩小了,结果不变。

亲测这个方法在处理几十万甚至上百万样本时都能快速运行,完全避开内存溢出的问题。

内容的提问来源于stack exchange,提问作者august

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:23:59