计算聚类精度

时间:2019-02-27 22:47:05

标签: python cluster-analysis

我想编写一个python代码来计算群集精度 r ,如下所示:

r = ( A1 + ... + Ai + ... Ak ) / (the number of data objects)

其中 Ai 是在第 i 个簇及其对应的真实簇中出现的数据对象的数量。

为了将聚类性能与使用该精度标准的研究论文进行比较,我需要实现它。
我在sklearn中搜索了现有方法,但找不到一个可以做到这一点的方法,并尝试自己编写。

这是我写的代码:

    # For each label in prediction, extract true labels of the same 
    # index as 'labels'. Then count the number of instances of respective
    # true labels in 'labels', and assume the one with the maximum 
    # number of instances is the corresponding true label.
    pred_to_true_conversion={}
    for p in np.unique(pred):
        labels=true[pred==p]
        unique, counts=np.unique(labels, return_counts=True)
        label_count=dict(zip(unique, counts))
        pred_to_true_conversion[p]=max(label_count, key=label_count.get)

    # count the number of instances whose true label is the same
    # as the converted predicted label.
    count=0
    for t, p in zip(true, pred):
        if t==pred_to_true_conversion[p]: count+=1

    return count/len(true)

但是,我认为我的“标签重新映射”方法不是一个聪明的方法,应该有一种更好的方法来计算 r 。我的方法存在以下问题:

  1. 它基于这样一个假设,即对应的真实标签是在预测的群集中最频繁出现的标签,但并非总是如此。
  2. 不同的预测聚类标签与相同的真实聚类标签相关联,尤其是当真实标签和预测标签中的类数不同时。

如何实现精度 r ?还是现有的任何群集库中都有一种方法可以做到这一点?

1 个答案:

答案 0 :(得分:1)

我相信您所描述的是我不久前也想做的事情。这是我解决的方法:

from sklearn.metrics.cluster import contingency_matrix
from sklearn.preprocessing import normalize

normalize(contingency_matrix(labels_pred=pred, labels_true=true), norm='l1', axis=1)

此矩阵提供每种聚类/标签组合的召回率。

编辑:

您认为使用此方法时遇到的问题是它固有的。由于某些原因,有些论文宁愿报告聚类结果的准确性或F度量,即使它们不太适合。This论文使用另一种方法计算聚类结果的F度量,至少可以解决将多个群集映射到单个真相标签问题。他们使用任务分配算法来解决此特定问题。

这是我的“匈牙利F1”成绩代码:

from munkres import Munkres
def f_matrix(labels_pred, labels_true):
    # Calculate F1 matrix
    cont_mat = contingency_matrix(labels_pred=labels_pred, labels_true=labels_true)
    precision = normalize(cont_mat, norm='l1', axis=0)
    recall = normalize(cont_mat, norm='l1', axis=1)
    som = precision + recall
    f1 =  np.round(np.divide((2 * recall * precision), som, out=np.zeros_like(som), where=som!=0), 3)
    return f1

def f1_hungarian(f1):
    m = Munkres()
    inverse = 1 - f1
    indices = m.compute(inverse.tolist())
    fscore = sum([f1[i] for i in indices])/len(indices)
    return fscore
f1_hungarian(f_matrix(pred, true))