使用相关矩阵对数据进行聚类是一个合理的想法,但必须首先对相关性进行预处理。首先,相关矩阵,由numpy.corrcoef
,受机器算术误差的影响:
- 它并不总是对称的。
- 对角项并不总是恰好为 1
这些可以通过转置取平均值并用 1 填充对角线来修复:
import numpy as np
data = np.random.randint(0, 10, size=(20, 10)) # 20 variables with 10 observations each
corr = np.corrcoef(data) # 20 by 20 correlation matrix
corr = (corr + corr.T)/2 # made symmetric
np.fill_diagonal(corr, 1) # put 1 on the diagonal
其次,任何聚类方法的输入,例如linkage
,需要测量差异性的物体。相关性测量相似。所以需要进行变换,使得0相关性映射到一个大数,而1相关性映射到0。
这篇博文 http://research.stowers.org/mcm/efg/R/Visualization/cor-cluster/index.htm讨论了此类数据转换的几种方法,并建议dissimilarity = 1 - abs(correlation)
。这个想法是,强负相关性也表明对象是相关的,就像正相关性一样。这是该示例的延续:
from scipy.cluster.hierarchy import linkage, fcluster
from scipy.spatial.distance import squareform
dissimilarity = 1 - np.abs(corr)
hierarchy = linkage(squareform(dissimilarity), method='average')
labels = fcluster(hierarchy, 0.5, criterion='distance')
请注意,我们不会将完整的距离矩阵输入linkage
,它需要被压缩squareform
first.
使用什么准确的聚类方法以及什么阈值取决于问题的上下文,没有通用规则。通常,0.5 是用于相关性的合理阈值,所以我这样做了。通过我的 20 组随机数,我最终得到了 7 个簇:编码为labels
as
[7, 7, 7, 1, 4, 4, 2, 7, 5, 7, 2, 5, 6, 3, 6, 1, 5, 1, 4, 2]