聚类算法评价指标python实现_[ML] 聚类评价指标

本文将介绍几个常见的聚类评价指标: Purity, NMI, RI, Precision(查准率), Recall(查全率), F, ARI, Accuracy(正确率).

好的聚类算法,一般要求类簇具有:高的类内 (intra-cluster) 相似度 (documents within a cluster are similar)

低的类间 (inter-cluster) 相似度 (documents from different clusters are dissimilar)

对于聚类算法大致可分为 3 类度量标准:External

Internal

Relative

本篇将只介绍第一类,即外部评价标准。

外部评价标准

外部评价标准 (External measures), 它针对的是给定一个基准, 根据这个基准对聚类结果进行评价。

下面介绍3个外部评价指标:Purityis a simple and transparent evaluation measure.

Normalized mutual information can be information-theoretically interpreted.

The Rand index penalizes both false positive and false negative decisions during clustering.

The F measure in addition supports differential weighting of these two types of errors.

Purity

其中, N 表示总的样本个数,

表示聚类簇 (cluster) 划分,

表示真实类别 (class) 划分。上述过程即给每个「聚类簇」分配一个「类别」,且「为这个类别的样本」在该簇中「出现的次数最多」,然后计算所有 K 个聚类簇的这个次数之和再归一化即为最终值。

,越接近1表示聚类结果越好。

该值无法用于权衡聚类质量与簇个数之间的关系。

EXAMPLE

如上图,在 「cluster 1」 中 「class

」数目最多为 5,在 「cluster 2」 中 「class

」数目最多为 4,在 「cluster 3」 中 「class

」数目最多为 3。因此:

NMI

NMI (Normalized Mutual Information) 即归一化互信息。

其中,

表示互信息(Mutual Information), H 为熵,当

取 2 为底时,单位为 bit,取 e 为底时单位为 nat。

其中,

可以分别看作样本 (document) 属于聚类簇

, 属于类别

, 同时属于两者的概率。第二个等价式子则是由概率的极大似然估计推导而来。

互信息

表示给定类簇信息

的前提条件下,类别信息

的增加量,或者说其不确定度的减少量。直观地,互信息还可以写出如下形式:

互信息的最小值为 0, 当类簇相对于类别只是随机的, 也就是说两者独立的情况下,

对于

未带来任何有用的信息;

如果得到的

关系越密切, 那么

值越大. 如果

完整重现了

, 此时互信息最大

时,即类簇数和样本个数相等,MI 也能达到最大值。所以 MI 也存在和纯度类似的问题,即它并不对簇数目较大的聚类结果进行惩罚,因此也不能在其他条件一样的情况下,对簇数目越小越好的这种期望进行形式化。

NMI 则可以解决上述问题,因为熵会随着簇的数目的增长而增大。当

时,

会达到其最大值

, 此时就能保证 NMI 的值较低。之所以采用

作为分母,是因为它是

的紧上界, 因此可以保证

EXAMPLE

gnd 是 ground truth 的意思,grps 表示聚类后的 groups. 问题是:计算序列 gnd 和 grps 的 NMI.

1. 先计算联合概率分布

2. 计算边际分布

3. 计算熵和互信息

4. 计算 NMI

RI

兰德指数 (Rand index, RI), 将聚类看成是一系列的决策过程,即对文档集上所有

个【文档对】进行决策。当且仅当两篇文档相似时,我们将它们归入同一簇中。

正确决策:TP 将两篇相似文档归入一个簇 (同 - 同)

TN 将两篇不相似的文档归入不同的簇 (不同 - 不同)

错误决策:FP 将两篇不相似的文档归入同一簇 (不同 - 同)

FN 将两篇相似的文档归入不同簇 (同- 不同) (worse)

2020.04.21 注:这本书里说的 positives是指 "pairs of documents that are in the same cluster",我当时写的 Positive 的解释有误,已更正。

RI 则是计算「正确决策」的比率(精确率, accuracy).

EXAMPLE

1. 先算 「文档对」出现在同一 cluster 中的数目,这包括了决策正确的和错误的,分别对应 TP 和 FP。

表示每个 cluster 中 2 点的组合数之和.

2020.04.21 注:今天重新看到这里的时候突然有点不理解,重新思考下这里的意思可以这么理解:关键在于 TP 和 FP 中 positives,也就是【文档对】放入同一 cluster,因此我们只要以 cluster 为对象进行考察,因为某一 cluster 中的任意点对就是位于同一个 cluster,所以只要取 cluster 内点的组合数即可。

2. TP 为「同 class 文档对」出现在同一 cluster 中的数目

2020.04.21 注:看图写组合数,找一个cluster 中个数大于等于2的同类点,初版这里写错了,已更正。

因此, FP = 40-20=20。

3. 可以按同样的方法计算 FN 和 TN,但是实际中计算 RI 并不需要这些准确的值,而只需要 TP+FP.

但是 RI 给 FP 和 FN 相同的权重,「分开相似的文档」的后果有时比将「不相似的文档放在同一类」更严重,因此我们可以 FN 罚更多,通过取

中的

大于 1, 此时实际上也相当于赋予召回率更大的权重(把好瓜全部挑上)。

来源自互联网

同样对于上例:

一个求混淆矩阵的 Python 实现

%matplotlib inline

import numpy as np

import matplotlib.pyplot as plt

label = [0,0,1,0,1,0,0,1]

pred = [0,0,0,0,0,1,1,1]

bins = np.array([0,0.5,1]) # 表示x,y轴每个 bin 的坐标范围

tn, fp, fn, tp = plt.hist2d(label, pred, bins=bins, cmap='Blues')[0].flatten() # flatten 按列展开混淆矩阵

如果单纯想输出混淆矩阵可以使用 np.histogram2d()

ARI

调整兰德系数(Adjusted Rand index, ARI), 为什么要引进 ARI呢,因为 RI 的问题在于对两个随机的划分, 其 RI 值不是一个接近于 0 的常数。ARI 则是针对该问题对 RI 的修正。

要计算该值, 先计算出列联表(contingency table ), 表中每个值

表示某个 document 同时位于 cluster (

) 和 class (

) 的个数, 在通过该表可以计算 ARI 值即可。

equation?tex=%5Cbegin%7Barray%7D%7Bc%7Ccccc%7Cc%7D%7B%5Catop+X%7D%5Cdiagdown+%5E%7BY%7D%26Y_%7B1%7D%26Y_%7B2%7D%26%5Cldots+%26Y_%7Bs%7D%26%7B%5Ctext%7BSums%7D%7D%5C%5C%5Chline+X_%7B1%7D%26n_%7B11%7D%26n_%7B12%7D%26%5Cldots+%26n_%7B1s%7D%26a_%7B1%7D%5C%5CX_%7B2%7D%26n_%7B21%7D%26n_%7B22%7D%26%5Cldots+%26n_%7B2s%7D%26a_%7B2%7D%5C%5C%5Cvdots+%26%5Cvdots+%26%5Cvdots+%26%5Cddots+%26%5Cvdots+%26%5Cvdots+%5C%5CX_%7Br%7D%26n_%7Br1%7D%26n_%7Br2%7D%26%5Cldots+%26n_%7Brs%7D%26a_%7Br%7D%5C%5C%5Chline+%7B%5Ctext%7BSums%7D%7D%26b_%7B1%7D%26b_%7B2%7D%26%5Cldots+%26b_%7Bs%7D%26%5Cend%7Barray%7D%5C%5C

equation?tex=%7B%5Cdisplaystyle+%5Coverbrace+%7BARI%7D+%5E%7B%5Ctext%7BAdjusted+Index%7D%7D%3D%7B%5Cfrac+%7B%5Coverbrace+%7B%5Csum+_%7Bij%7D%7B%5Cbinom+%7Bn_%7Bij%7D%7D%7B2%7D%7D%7D+%5E%7B%5Ctext%7BIndex%7D%7D-%5Coverbrace+%7B%5B%5Csum+_%7Bi%7D%7B%5Cbinom+%7Ba_%7Bi%7D%7D%7B2%7D%7D%5Csum+_%7Bj%7D%7B%5Cbinom+%7Bb_%7Bj%7D%7D%7B2%7D%7D%5D%2F%7B%5Cbinom+%7Bn%7D%7B2%7D%7D%7D+%5E%7B%5Ctext%7BExpected+Index%7D%7D%7D%7B%5Cunderbrace+%7B%7B%5Cfrac+%7B1%7D%7B2%7D%7D%5B%5Csum+_%7Bi%7D%7B%5Cbinom+%7Ba_%7Bi%7D%7D%7B2%7D%7D%2B%5Csum+_%7Bj%7D%7B%5Cbinom+%7Bb_%7Bj%7D%7D%7B2%7D%7D%5D%7D+_%7B%5Ctext%7BMax+Index%7D%7D-%5Cunderbrace+%7B%5B%5Csum+_%7Bi%7D%7B%5Cbinom+%7Ba_%7Bi%7D%7D%7B2%7D%7D%5Csum+_%7Bj%7D%7B%5Cbinom+%7Bb_%7Bj%7D%7D%7B2%7D%7D%5D%2F%7B%5Cbinom+%7Bn%7D%7B2%7D%7D%7D+_%7B%5Ctext%7BExpected+Index%7D%7D%7D%7D%7D%5C%5C 值越大意味着聚类结果与真实情况越吻合

from sklearn import metrics

labels_true = [0, 0, 0, 1, 1, 1]

labels_pred = [0, 0, 1, 1, 2, 2]

# 基本用法

score = metrics.adjusted_rand_score(labels_true, labels_pred)

print(score)

# 与标签名无关

labels_pred = [1, 1, 0, 0, 3, 3]

score = metrics.adjusted_rand_score(labels_true, labels_pred)

print(score)

# 具有对称性

score = metrics.adjusted_rand_score(labels_pred, labels_true)

print(score)

# 接近 1 最好

labels_pred = labels_true[:]

score = metrics.adjusted_rand_score(labels_true, labels_pred)

print(score)

# 独立标签结果为负或者接近 0

labels_true = [0, 1, 2, 0, 3, 4, 5, 1]

labels_pred = [1, 1, 0, 0, 2, 2, 2, 2]

score = metrics.adjusted_rand_score(labels_true, labels_pred)

print(score)

指标比较The adjusted Rand index is the most strict measure, evaluating on a pairwise-basis if pathways are incorrectly grouped. NMI penalizes more on the cluster-level, while cluster purity falls in between the two other measures.

Purity, NMI, RI 等上述指标均需要给定 truth label 才能对 cluster label 进行评价,但是均不要求后者的类标与前者一致。那什么时候需要进行类标签的 best map 呢?例如,我们需要对预测结果和真实值之间统计聚类正确的比例时就需要进行最佳类标的重现分配,这样才能保证统计的正确。

AC

聚类精确度 (Accuracy, AC) 用于比较获得标签和数据提供的真实标签.

其中,

分别表示数据

所对应的获得的标签和真实标签,

为数据总的个数,

表示指示函数如下:

而式中的 map 则表示最佳类标的重现分配,以才能保证统计的正确。一般的该最佳重分配可以通过匈牙利算法 (Kuhn-Munkres or Hungarian Algorithm) 实现,从而在多项式时间内求解该任务(标签)分配问题。

EXAMPLE

a = [ones(1,5)*1, ones(1,5)*2, ones(1,5)*3, ones(1,5)*4, ones(1,5)*5];

b = [ones(1,5)*2, ones(1,5)*1, ones(1,5)*4, ones(1,5)*3, ones(1,5)*5];

acc = length(find(a == b))/length(a);

fprintf('nmi is %f\n', cluster_nmi(a,b))

fprintf('acc is %f\n', acc)

b = bestMap(a, b)';

acc = length(find(a == b))/length(a);

fprintf('best map acc is %f\n', acc)

输出

nmi is 1.0000

acc is 0.2000

best map acc is 1.0000

Code

Reference

知识共享

署名-非商业性使用-相同方式共享(CC BY-NC-SA 4.0)

使用者可以对本创作进行署名转载、节选、混编、二次创作,但不得运用于商业目的,采用本创作的内容必须同样采用本协议进行授权。CC BY-NC-SA 4.0

你可能感兴趣的:(聚类算法评价指标python实现_[ML] 聚类评价指标)