Python - K均值聚类,某些列方差为零

4 投票
2 回答
2251 浏览
提问于 2025-04-17 19:54

我有一个数据集,大约有200个99x20的频率数组,每一列的总和都是1。我用热图把这些数据可视化,像这样 this。每个数组都很稀疏,在99个位置中,只有大约1到7个值是非零的。

不过,我想根据这些频率的相似性来对样本进行聚类(比如说最小欧几里得距离之类的)。我把每个99x20的数组整理成了一个1980x1的数组,然后把它们合并成一个200x1980的观测数组。

在寻找聚类之前,我尝试用 scipy.cluster.vq.whiten 来对数据进行白化处理。whiten 是通过每列的方差来标准化数据,但因为我把数据数组压平了,有8列的频率都是零,所以它们的方差也是零。因此,白化后的数组会出现无穷大的值,导致找不到中心点(或者得到大约200个中心点)。

我想问的是,我该如何解决这个问题?到目前为止,我尝试过:

  • 不对数据进行白化。这会导致k-means每次运行时给出不同的中心点(这有点意料之中),尽管我把 iter 参数调得很高。
  • 在压平数组之前先转置它们。零方差的列只是位置发生了变化。

直接删除这些零方差的列可以吗?这样会不会对聚类造成偏差?

补充:我还尝试了自己写的白化函数,内容就是

for i in range(arr.shape[1]):
    if np.abs(arr[:,i].std()) < 1e-8: continue
    arr[:,i] /= arr[:,i].std()

这个方法似乎有效,但我不确定这是否会对聚类造成偏差。

谢谢

2 个回答

3

去掉全是0的那一列数据不会影响数据的整体情况。如果你有N维的数据,但其中一维的数值都是一样的,那其实就和只有N-1维的数据是一样的。这种有效维度的特性叫做

想象一下3维的数据,但所有的数据点都在x=0的平面上。你能明白这其实和2维的数据是一样的吗?

3

首先,去掉那些常量列是完全可以的。显然,这些列没有提供任何信息,所以没必要保留它们。

不过,K-means算法对稀疏向量的效果并不好。问题在于,最终得到的“中心点”可能会彼此之间更相似,而不是和各自的群组成员相似。因为在稀疏数据中,每个对象在某种程度上都是异常值。而K-means对异常值非常敏感,因为它试图最小化平方和。

我建议你可以这样做:

  1. 找到一个适合你领域的相似性度量。花一些时间去研究,看看怎样才能捕捉到你特定用例的相似性。

  2. 一旦你有了相似性度量,就计算一个200x200的相似性矩阵。由于你的数据集非常小,你实际上可以使用一些计算量大的聚类方法,比如层次聚类,这些方法在处理成千上万的对象时就不太适用了。如果你愿意,也可以尝试OPTICS聚类或DBSCAN。不过,特别是DBSCAN在数据集更大的时候会更有趣。对于小数据集,层次聚类就可以了。

撰写回答