【问题标题】:Rand Index function (clustering performance evaluation)兰德指数函数(聚类性能评估)
【发布时间】:2018-09-10 05:19:52
【问题描述】:

据我所知,python 中没有可用于 Rand Index 的包,而对于 Adjusted Rand Index,您可以选择使用 sklearn.metrics.adjusted_rand_score(labels_true, labels_pred)

我为 Rand Score 编写了代码,我将与其他人分享它作为帖子的答案。

【问题讨论】:

  • 为什么要使用未经调整的兰德指数?
  • @Anony-Mousse 这是一些论文中使用的方法。大多数情况下,这两种方法都已实施并在结果表中报告。不过,我同意在大多数情况下 ARI 是一个更好的指标。

标签: python cluster-analysis precision unsupervised-learning


【解决方案1】:

从 scikit-learn 0.24.0 开始,添加了sklearn.metrics.rand_score 函数,实现了(未调整的)兰德指数。请查看changelog

你所要做的就是:

from sklearn.metrics import rand_score

rand_score(labels_true, labels_pred)

labels_truelabels_pred 可以在不同的域中具有值。例如:

>>> rand_score(['a', 'b', 'c'], [5, 6, 7])
1.0

【讨论】:

    【解决方案2】:
    from scipy.misc import comb
    from itertools import combinations
    import numpy as np
    
    def check_clusterings(labels_true, labels_pred):
        """Check that the two clusterings matching 1D integer arrays."""
        labels_true = np.asarray(labels_true)
        labels_pred = np.asarray(labels_pred)    
        # input checks
        if labels_true.ndim != 1:
            raise ValueError(
                "labels_true must be 1D: shape is %r" % (labels_true.shape,))
        if labels_pred.ndim != 1:
            raise ValueError(
                "labels_pred must be 1D: shape is %r" % (labels_pred.shape,))
        if labels_true.shape != labels_pred.shape:
            raise ValueError(
                "labels_true and labels_pred must have same size, got %d and %d"
                % (labels_true.shape[0], labels_pred.shape[0]))
        return labels_true, labels_pred
    
    def rand_score (labels_true, labels_pred):
    """given the true and predicted labels, it will return the Rand Index."""
        check_clusterings(labels_true, labels_pred)
        my_pair = list(combinations(range(len(labels_true)), 2)) #create list of all combinations with the length of labels.
        def is_equal(x):
            return (x[0]==x[1])
        my_a = 0
        my_b = 0
        for i in range(len(my_pair)):
                if(is_equal((labels_true[my_pair[i][0]],labels_true[my_pair[i][1]])) == is_equal((labels_pred[my_pair[i][0]],labels_pred[my_pair[i][1]])) 
                   and is_equal((labels_pred[my_pair[i][0]],labels_pred[my_pair[i][1]])) == True):
                    my_a += 1
                if(is_equal((labels_true[my_pair[i][0]],labels_true[my_pair[i][1]])) == is_equal((labels_pred[my_pair[i][0]],labels_pred[my_pair[i][1]])) 
                   and is_equal((labels_pred[my_pair[i][0]],labels_pred[my_pair[i][1]])) == False):
                    my_b += 1
        my_denom = comb(len(labels_true),2)
        ri = (my_a + my_b) / my_denom
        return ri
    

    举个简单的例子:

    labels_true = [1, 1, 0, 0, 0, 0]
    labels_pred = [0, 0, 0, 1, 0, 1]
    rand_score (labels_true, labels_pred)
    #0.46666666666666667
    

    可能有一些方法可以改进它并使其更加pythonic。如果您有任何建议,您可以改进它。

    我发现this implementation 似乎更快。

    import numpy as np
    from scipy.misc import comb
    def rand_index_score(clusters, classes):
        tp_plus_fp = comb(np.bincount(clusters), 2).sum()
        tp_plus_fn = comb(np.bincount(classes), 2).sum()
        A = np.c_[(clusters, classes)]
        tp = sum(comb(np.bincount(A[A[:, 0] == i, 1]), 2).sum()
                 for i in set(clusters))
        fp = tp_plus_fp - tp
        fn = tp_plus_fn - tp
        tn = comb(len(A), 2) - tp - fp - fn
        return (tp + tn) / (tp + fp + fn + tn)
    

    举个简单的例子:

    labels_true = [1, 1, 0, 0, 0, 0]
    labels_pred = [0, 0, 0, 1, 0, 1]
    rand_index_score (labels_true, labels_pred)
    #0.46666666666666667
    

    【讨论】:

    • @theausome 我收回我的评论。
    • 对我来说看起来像一个非常慢的代码。如果你在更大的数据集上运行它,需要多长时间?与 ARI 实现相比?
    • 肯定会更慢,因为它包含一个 ARI 中不存在的 for 循环。如果您有任何改进建议,请发表评论或添加答案。我从类似的 R 代码转换它。 @Anony-Mousse
    • 它不应该比 ARI 慢,其中包括 RI 的计算。
    猜你喜欢
    • 1970-01-01
    • 2022-08-19
    • 1970-01-01
    • 2018-10-14
    • 1970-01-01
    • 2021-06-10
    • 2020-05-14
    • 2018-12-18
    • 2014-02-12
    相关资源
    最近更新 更多