使用 3 个最高概率的多类分类器的性能

Posted

技术标签:

【中文标题】使用 3 个最高概率的多类分类器的性能【英文标题】:performance of a multi-class classifier using the 3 highest probabilities 【发布时间】:2018-11-22 18:17:53 【问题描述】:

我有一个如下的熊猫数据框

predictions.head()
Out[22]: 
          A    B         C    D    E         G    H         L         N  \
0  0.718363  0.5  0.403466  0.5  0.5  0.458989  0.5  0.850190  0.620878   
1  0.677776  0.5  0.366128  0.5  0.5  0.042405  0.5  0.894200  0.510644   
2  0.682019  0.5  0.074347  0.5  0.5  0.562217  0.5  0.417786  0.539949   
3  0.482981  0.5  0.065436  0.5  0.5  0.112383  0.5  0.743659  0.604382   
4  0.700207  0.5  0.515825  0.5  0.5  0.078089  0.5  0.437839  0.249892   

          P         R         S         U    V LABEL  
0  0.182169  0.483631  0.432915  0.328495  0.5     A  
1  0.015789  0.523462  0.547838  0.691239  0.5     L  
2  0.799223  0.603212  0.620806  0.335204  0.5     G  
3  0.246766  0.399070  0.341081  0.229407  0.5     P  
4  0.064734  0.822834  0.769277  0.512239  0.5     U  

每一行是不同类别(列)的预测概率。 最后一列是标签(正确的类)。

我想评估允许 2 个错误的分类器的性能。 我的意思是,如果最高 3 个概率之一是正确的标签,我认为预测是正确的。 在 scikit-learn 中有一个聪明的方法吗?

【问题讨论】:

在您向他们展示您的尝试后,我相信您的问题属于Code Review。 @andrewnagyeb 仅当当前代码有效时。似乎还没有代码。 @Mast,我认为 OP 可能已经进行了一些尝试,因为他正在寻找一种 智能 方式。 @andrewnagyeb 很有趣,这向我表明他想跳过反复试验并在第一次尝试时采用最佳方法。 【参考方案1】:

试试这个方法:

In [57]: x = df.drop('LABEL',1).T.apply(lambda x: x.nlargest(3).index).T

In [58]: x
Out[58]:
   0  1  2
0  L  A  N
1  L  U  A
2  P  A  S
3  L  N  B
4  R  S  A

In [59]: x.eq(df.LABEL, axis=0).any(1)
Out[59]:
0     True
1     True
2    False
3    False
4    False
dtype: bool

类似的解决方案,少用一个transpose

In [66]: x = df.drop('LABEL',1).T.apply(lambda x: x.nlargest(3).index)

In [67]: x
Out[67]:
   0  1  2  3  4
0  L  L  P  L  R
1  A  U  A  N  S
2  N  A  S  B  A

In [68]: x.eq(df.LABEL).any()
Out[68]:
0     True
1     True
2    False
3    False
4    False
dtype: bool

来源 DF:

In [70]: df
Out[70]:
          A    B         C    D    E         G    H         L         N         P         R         S         U    V LABEL
0  0.718363  0.5  0.403466  0.5  0.5  0.458989  0.5  0.850190  0.620878  0.182169  0.483631  0.432915  0.328495  0.5     A
1  0.677776  0.5  0.366128  0.5  0.5  0.042405  0.5  0.894200  0.510644  0.015789  0.523462  0.547838  0.691239  0.5     L
2  0.682019  0.5  0.074347  0.5  0.5  0.562217  0.5  0.417786  0.539949  0.799223  0.603212  0.620806  0.335204  0.5     G
3  0.482981  0.5  0.065436  0.5  0.5  0.112383  0.5  0.743659  0.604382  0.246766  0.399070  0.341081  0.229407  0.5     P
4  0.700207  0.5  0.515825  0.5  0.5  0.078089  0.5  0.437839  0.249892  0.064734  0.822834  0.769277  0.512239  0.5     U

更新:试图重现错误(来自 cmets):

In [81]: df
Out[81]:
   a  b  c  d  e LABEL
0  1  2  3  4  5     c
1  3  4  5  6  7     d

In [82]: x = df.drop('LABEL',1).T.apply(lambda x: x.nlargest(3).index)

In [83]: x
Out[83]:
   0  1
0  e  e
1  d  d
2  c  c

In [84]: x.eq(df.LABEL).any()
Out[84]:
0    True
1    True
dtype: bool

PS 我正在使用 Pandas 0.23.0

【讨论】:

在第一个命令之后我得到 ValueError: 值的长度与索引的长度不匹配 @gabboshow,试试你在问题中指定的 DF @gabboshow,我担心我需要一个数据集,它可以帮助我重现这个问题...... 你是如何创建你的 df 的? @gabboshow,我已将您问题中的 DF 放在一行中并使用了df = pd.read_clipboard()【参考方案2】:

如果性能很重要,请使用 numpy.argsort 并通过 iloc 删除最后一列:

print (np.argsort(-df.iloc[:, :-1].values, axis=1)[:,:3])
[[ 7  0  8]
 [ 7 12  0]
 [ 9  0 11]
 [ 7  8  1]
 [10 11  0]]

v = df.columns[np.argsort(-df.iloc[:, :-1].values, axis=1)[:,:3]]
print (v)
Index([['L', 'A', 'N'], ['L', 'U', 'A'], ['P', 'A', 'S'], ['L', 'N', 'B'],
       ['R', 'S', 'A']],
      dtype='object')

a = pd.DataFrame(v).eq(df['LABEL'], axis=0).any(axis=1)
print (a)
0     True
1     True
2    False
3    False
4    False
dtype: bool

感谢@Maxu 提供另一个与numpy.argpartition 类似的解决方案:

v = df.columns[np.argpartition(-df.iloc[:, :-1].values, 3, axis=1)[:,:3]]

样本数据:

df = pd.DataFrame('A': [0.718363, 0.677776, 0.6820189999999999, 0.48298100000000005, 0.700207], 'B': [0.5, 0.5, 0.5, 0.5, 0.5], 'C': [0.403466, 0.366128, 0.074347, 0.06543600000000001, 0.515825], 'D': [0.5, 0.5, 0.5, 0.5, 0.5], 'E': [0.5, 0.5, 0.5, 0.5, 0.5], 'G': [0.45898900000000004, 0.042405, 0.562217, 0.112383, 0.07808899999999999], 'H': [0.5, 0.5, 0.5, 0.5, 0.5], 'L': [0.85019, 0.8942, 0.417786, 0.7436590000000001, 0.43783900000000003], 'N': [0.6208779999999999, 0.510644, 0.539949, 0.604382, 0.249892], 'P': [0.182169, 0.015788999999999997, 0.7992229999999999, 0.24676599999999999, 0.064734], 'R': [0.48363100000000003, 0.523462, 0.603212, 0.39907, 0.8228340000000001], 'S': [0.43291499999999994, 0.547838, 0.6208060000000001, 0.34108099999999997, 0.769277], 'U': [0.328495, 0.691239, 0.335204, 0.22940700000000003, 0.512239], 'V': [0.5, 0.5, 0.5, 0.5, 0.5], 'LABEL': ['A', 'L', 'G', 'P', 'U'])

print (df)
          A    B         C    D    E         G    H         L         N  \
0  0.718363  0.5  0.403466  0.5  0.5  0.458989  0.5  0.850190  0.620878   
1  0.677776  0.5  0.366128  0.5  0.5  0.042405  0.5  0.894200  0.510644   
2  0.682019  0.5  0.074347  0.5  0.5  0.562217  0.5  0.417786  0.539949   
3  0.482981  0.5  0.065436  0.5  0.5  0.112383  0.5  0.743659  0.604382   
4  0.700207  0.5  0.515825  0.5  0.5  0.078089  0.5  0.437839  0.249892   

          P         R         S         U    V LABEL  
0  0.182169  0.483631  0.432915  0.328495  0.5     A  
1  0.015789  0.523462  0.547838  0.691239  0.5     L  
2  0.799223  0.603212  0.620806  0.335204  0.5     G  
3  0.246766  0.399070  0.341081  0.229407  0.5     P  
4  0.064734  0.822834  0.769277  0.512239  0.5     U  

【讨论】:

是的,我正在研究非常相似的解决方案。 BTW argpartition 应该更快:df.columns[np.argpartition(-df.iloc[:, :-1].values, 3, axis=1)[:,:3]] ;) @MaxU - 谢谢,添加到答案中:)【参考方案3】:

我想不出sklearn 中的解决方案,所以这是pandas 中的解决方案

# Data
predictions
Out[]:
          A    B         C    D    E         G    H         L         N         P         R         S         U    V LABEL
0  0.718363  0.5  0.403466  0.5  0.5  0.458989  0.5  0.850190  0.620878  0.182169  0.483631  0.432915  0.328495  0.5     A
1  0.677776  0.5  0.366128  0.5  0.5  0.042405  0.5  0.894200  0.510644  0.015789  0.523462  0.547838  0.691239  0.5     L
2  0.682019  0.5  0.074347  0.5  0.5  0.562217  0.5  0.417786  0.539949  0.799223  0.603212  0.620806  0.335204  0.5     G
3  0.482981  0.5  0.065436  0.5  0.5  0.112383  0.5  0.743659  0.604382  0.246766  0.399070  0.341081  0.229407  0.5     P
4  0.700207  0.5  0.515825  0.5  0.5  0.078089  0.5  0.437839  0.249892  0.064734  0.822834  0.769277  0.512239  0.5     U

# Check if the label is in the top 3 (one line solution)
predictions.apply(lambda row: row['LABEL'] in list(row.drop('LABEL').sort_values().tail(3).index), axis=1)

Out[]: 
0     True
1     True
2    False
3    False
4    False

这是正在发生的事情:

# List the top 3 results:
predictions.apply(lambda row: list(row.drop('LABEL').sort_values().tail(3).index), axis=1)

Out[]:
0    [N, A, L]
1    [A, U, L]
2    [S, A, P]
3    [V, N, L]
4    [A, S, R]

# Then check if the 'LABEL' is inside this list

你可以在Cross Validated 上问这个问题,因为他们会广泛使用 sklearn

【讨论】:

谢谢,如果 3 个最高概率之一是标签,则输出为 True? @gabboshow 是的,我已经更新了答案以显示这个

以上是关于使用 3 个最高概率的多类分类器的性能的主要内容,如果未能解决你的问题,请参考以下文章

使用高斯朴素贝叶斯的多类分类

从多类分类算法输出前2类

在有监督的多类分类中,为啥使用宏 F1 分数而不是平衡精度?

使用 PyTorch 的多标签、多类图像分类器 (ConvNet)

如何提高 Weka 中 SMO 分类器的性能?

用于多标签问题的 keras 模型的 scikit 学习链分类器的拟合方法错误