当使用 scipy 执行层次聚类时,文档 here 中说 scipy.cluster.hierarchy.linkage 将一维压缩距离矩阵或二维观察向量数组作为输入。但是,我使用 Pandas Dataframe 生成了一个简单的(对称的)相似度矩阵,scipy 将其作为输入完全没有问题,并且生成的树状图很好。
谁能解释一下,这怎么可能?我有过时的文档还是...?
答案 0 :(得分:0)
文档是准确的,只是没有告诉您如果您实际尝试使用未压缩的距离矩阵会发生什么。
该函数发出警告但仍运行,因为 it first tries to convert input into a numpy array。这将从您的 2-D DataFrame 创建一个 2-D 数组,同时认识到这可能不是基于数组维度和对称性的预期输入。
根据输入数据的复杂性(例如集群分离、集群数量、数据在集群间的分布),如您所指出的,聚类可能看起来仍能成功生成合适的树状图。这在概念上是有道理的,因为结果是 n 个相似向量的聚类,在简单的情况下这些向量可以很好地分离。
例如,以下是一些包含 150 个观察值和 2 个聚类的合成数据:
import pandas as pd
from scipy.spatial.distance import cosine, pdist, squareform
np.random.seed(42) # for repeatability
a = np.random.multivariate_normal([10, 0], [[3, 1], [1, 4]], size=[100,])
b = np.random.multivariate_normal([0, 20], [[3, 1], [1, 4]], size=[50,])
obs_df = pd.DataFrame(np.concatenate((a, b),), columns=['x', 'y'])
obs_df.plot.scatter(x='x', y='y')
Z = linkage(obs_df, 'ward')
fig = plt.figure(figsize=(8, 4))
dn = dendrogram(Z)
如果您生成一个相似度矩阵,这是一个 n
x n
矩阵,它仍然可以像 n
向量一样进行聚类。我无法绘制 150 维向量,但绘制每个向量的幅度,然后绘制树状图似乎来确认类似的聚类。
def similarity_func(u, v):
return 1-cosine(u, v)
dists = pdist(obs_df, similarity_func)
sim_df = pd.DataFrame(squareform(dists), columns=obs_df.index, index=obs_df.index)
sim_array = np.asarray(sim_df)
sim_lst = []
for vec in sim_array:
mag = np.linalg.norm(vec,ord=1)
sim_lst.append(mag)
pd.Series(sim_lst).plot.bar()
Z = linkage(sim_df, 'ward')
fig = plt.figure(figsize=(8, 4))
dn = dendrogram(Z)
我们真正在这里聚类的是一个向量,其分量是 150 个点中每个点的相似性度量。我们正在对每个点的集群内和集群间相似性度量的集合进行聚类。由于两个集群的大小不同,一个集群中的一个点相对于另一个集群中的一个点将具有相当不同的集群内和集群间相似性集合。因此,就像我们在第一步中所做的那样,我们得到了两个与每个集群中的点数成正比的主要集群。