在scikit-learn中获取多标签预测的准确性

28
多标签分类设置中,sklearn.metrics.accuracy_score仅计算子集准确率(3):即对于一个样本,预测的标签集必须与y_true中相应的标签集完全匹配。这种计算准确率的方式有时被称为精确匹配比率(1)。

enter image description here

有没有办法在scikit-learn中获得另一种典型的计算准确度的方法,即

enter image description here

(如(1)和(2)所定义,并且被称为汉明得分(4)(因为它与汉明损失密切相关),或者)

(1) Sorower, Mohammad S. "多标签学习算法的文献综述。" 俄勒冈州立大学,科瓦利斯(2010)。

(2) Tsoumakas,Grigorios和Ioannis Katakis。 "多标签分类:概述。" 希腊塞萨洛尼基亚里士多德大学信息学系(2006)。

(3) Ghamrawi,Nadia和Andrew McCallum。 "集体多标签分类。" 第14届ACM国际信息与知识管理会议论文集。 ACM,2005年。

(4) Godbole, Shantanu和Sunita Sarawagi。 "多标签分类的判别方法。" 《知识发现和数据挖掘进展》。Springer Berlin Heidelberg,2004年。22-30页。

3个回答

27

您可以自己编写一个版本,这里提供一个示例,不考虑权重和标准化。

import numpy as np

y_true = np.array([[0,1,0],
                   [0,1,1],
                   [1,0,1],
                   [0,0,1]])

y_pred = np.array([[0,1,1],
                   [0,1,1],
                   [0,1,0],
                   [0,0,0]])

def hamming_score(y_true, y_pred, normalize=True, sample_weight=None):
    '''
    Compute the Hamming score (a.k.a. label-based accuracy) for the multi-label case
    https://dev59.com/EVwY5IYBdhLWcg3wwqL1
    '''
    acc_list = []
    for i in range(y_true.shape[0]):
        set_true = set( np.where(y_true[i])[0] )
        set_pred = set( np.where(y_pred[i])[0] )
        #print('\nset_true: {0}'.format(set_true))
        #print('set_pred: {0}'.format(set_pred))
        tmp_a = None
        if len(set_true) == 0 and len(set_pred) == 0:
            tmp_a = 1
        else:
            tmp_a = len(set_true.intersection(set_pred))/\
                    float( len(set_true.union(set_pred)) )
        #print('tmp_a: {0}'.format(tmp_a))
        acc_list.append(tmp_a)
    return np.mean(acc_list)

if __name__ == "__main__":
    print('Hamming score: {0}'.format(hamming_score(y_true, y_pred))) # 0.375 (= (0.5+1+0+0)/4)

    # For comparison sake:
    import sklearn.metrics

    # Subset accuracy
    # 0.25 (= 0+1+0+0 / 4) --> 1 if the prediction for one sample fully matches the gold. 0 otherwise.
    print('Subset accuracy: {0}'.format(sklearn.metrics.accuracy_score(y_true, y_pred, normalize=True, sample_weight=None)))

    # Hamming loss (smaller is better)
    # $$ \text{HammingLoss}(x_i, y_i) = \frac{1}{|D|} \sum_{i=1}^{|D|} \frac{xor(x_i, y_i)}{|L|}, $$
    # where
    #  - \\(|D|\\) is the number of samples  
    #  - \\(|L|\\) is the number of labels  
    #  - \\(y_i\\) is the ground truth  
    #  - \\(x_i\\)  is the prediction.  
    # 0.416666666667 (= (1+0+3+1) / (3*4) )
    print('Hamming loss: {0}'.format(sklearn.metrics.hamming_loss(y_true, y_pred))) 

输出:

Hamming score: 0.375
Subset accuracy: 0.25
Hamming loss: 0.416666666667

2
我如何获取不同标签的准确性得分的标签明细分解? - Ankur Sinha
@trollster,你找到了实现的方法吗?如果是这样,能否请你告诉我你的方法?谢谢 :) - sariii
1
是的,我做了。你可以在这里看到解决方案:https://github.com/scikit-multilearn/scikit-multilearn/issues/84 - Ankur Sinha

4
一个简单的总结函数:
import numpy as np

def hamming_score(y_true, y_pred):
    return (
        (y_true & y_pred).sum(axis=1) / (y_true | y_pred).sum(axis=1)
    ).mean()


hamming_score(y_true, y_pred)
# 0.375

0
基于nocibambi的答案进行导入。处理零除法。
    def hamming_score(y_true: np.ndarray, y_pred: np.ndarray):
        numerator = (y_true & y_pred).sum(axis=1)
        denominator = (y_true | y_pred).sum(axis=1)

        return np.divide(numerator, denominator, out=np.ones_like(numerator, dtype=np.float_),
                         where=denominator != 0).mean()

如果你想要在零除法的结果中得到0,就把np.ones_like替换为np.zeros_like

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接