如何在 Scikit-learn 凝聚聚类中使用 Pearson 相关性作为距离度量

Posted

技术标签:

【中文标题】如何在 Scikit-learn 凝聚聚类中使用 Pearson 相关性作为距离度量【英文标题】:How to use Pearson Correlation as distance metric in Scikit-learn Agglomerative clustering 【发布时间】:2015-11-25 00:20:15 【问题描述】:

我有以下data:

State   Murder  Assault UrbanPop    Rape
Alabama 13.200  236 58  21.200
Alaska  10.000  263 48  44.500
Arizona 8.100   294 80  31.000
Arkansas    8.800   190 50  19.500
California  9.000   276 91  40.600
Colorado    7.900   204 78  38.700
Connecticut 3.300   110 77  11.100
Delaware    5.900   238 72  15.800
Florida 15.400  335 80  31.900
Georgia 17.400  211 60  25.800
Hawaii  5.300   46  83  20.200
Idaho   2.600   120 54  14.200
Illinois    10.400  249 83  24.000
Indiana 7.200   113 65  21.000
Iowa    2.200   56  57  11.300
Kansas  6.000   115 66  18.000
Kentucky    9.700   109 52  16.300
Louisiana   15.400  249 66  22.200
Maine   2.100   83  51  7.800
Maryland    11.300  300 67  27.800
Massachusetts   4.400   149 85  16.300
Michigan    12.100  255 74  35.100
Minnesota   2.700   72  66  14.900
Mississippi 16.100  259 44  17.100
Missouri    9.000   178 70  28.200
Montana 6.000   109 53  16.400
Nebraska    4.300   102 62  16.500
Nevada  12.200  252 81  46.000
New Hampshire   2.100   57  56  9.500
New Jersey  7.400   159 89  18.800
New Mexico  11.400  285 70  32.100
New York    11.100  254 86  26.100
North Carolina  13.000  337 45  16.100
North Dakota    0.800   45  44  7.300
Ohio    7.300   120 75  21.400
Oklahoma    6.600   151 68  20.000
Oregon  4.900   159 67  29.300
Pennsylvania    6.300   106 72  14.900
Rhode Island    3.400   174 87  8.300
South Carolina  14.400  279 48  22.500
South Dakota    3.800   86  45  12.800
Tennessee   13.200  188 59  26.900
Texas   12.700  201 80  25.500
Utah    3.200   120 80  22.900
Vermont 2.200   48  32  11.200
Virginia    8.500   156 63  20.700
Washington  4.000   145 73  26.200
West Virginia   5.700   81  39  9.300
Wisconsin   2.600   53  66  10.800
Wyoming 6.800   161 60  15.600

我使用它来执行基于状态的层次聚类。 这是完整的工作代码:

import pandas as pd 
from sklearn.cluster import AgglomerativeClustering
df = pd.io.parsers.read_table("http://dpaste.com/031VZPM.txt")
samples = df["State"].tolist()
ndf = df[["Murder", "Assault", "UrbanPop","Rape"]]
X = ndf.as_matrix()

cluster = AgglomerativeClustering(n_clusters=3, 
                               linkage='complete',affinity='euclidean').fit(X)
label = cluster.labels_
outclust = list(zip(label, samples))  
outclust_df = pd.DataFrame(outclust,columns=["Clusters","Samples"])  

for clust in outclust_df.groupby("Clusters"):
    print (clust)

请注意,在该方法中,我使用euclidean 距离。我想做的是使用1-Pearson correlation distance。在 R 中它看起来像这样:

dat <- read.table("http://dpaste.com/031VZPM.txt",sep="\t",header=TRUE)
dist2 = function(x) as.dist(1-cor(t(x), method="pearson"))
dat = dat[c("Murder","Assault","UrbanPop","Rape")]
hclust(dist2(dat), method="ward.D")

如何使用Scikit-learn AgglomerativeClustering 实现这一目标? 我了解亲和力存在“预先计算”的论点。但不确定如何使用它来解决我的问题。

【问题讨论】:

您想在人口和犯罪之间建立关联? 【参考方案1】:

您可以将自定义关联矩阵定义为一个函数,该函数接收您的数据并返回关联矩阵:

from scipy.stats import pearsonr
import numpy as np

def pearson_affinity(M):
   return 1 - np.array([[pearsonr(a,b)[0] for a in M] for b in M])

然后你可以用这个作为亲和函数来调用凝聚聚类(你必须改变链接,因为'ward'只适用于欧几里得距离。

cluster = AgglomerativeClustering(n_clusters=3, linkage='average',
                           affinity=pearson_affinity)
cluster.fit(X)

请注意,由于某种原因,它似乎不适用于您的数据:

cluster.labels_
Out[107]: 
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1,
       0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 1, 0])

【讨论】:

代码对我不起作用。例如pearson_affinity(X) 失败。顺便说一句,为什么函数中有df.valuesM 是 np 矩阵还是 pandas 数据框? ok 现在把代码修好了,改成一减号,簇稍微好一点;) M 是一个 np.array @maxymoo 你能解释一下为什么'ward'链接只适用于欧几里得距离吗? @iMad 这只是来自 ward 方法的定义,尽管这似乎是一个活跃的研究领域,例如journals.plos.org/plosone/article?id=10.1371/…

以上是关于如何在 Scikit-learn 凝聚聚类中使用 Pearson 相关性作为距离度量的主要内容,如果未能解决你的问题,请参考以下文章

使用 scikit 选择层次凝聚聚类中的聚类数

scikit-learn:随着数据集增加的层次凝聚聚类性能

Scikit-learn 凝聚聚类连接矩阵

如何从 SciPy 的层次凝聚聚类中获取质心?

根据相关性使用 Python 对数据进行聚类

凝聚法层次聚类之ward linkage method