多标签混淆矩阵

5

我正在处理关于多标签分类的实际数据和来自分类器的预测数据。实际数据包括三个类别(c1、c2和c3),同样地,预测数据也包括三个类别(c1、c2和c3)。数据如下:

Actual_data     Predicted_data
c1 c2 c3         c1 c2 c3
1  1  0          1  1  1
1  1  0          1  0  1
1  0  1          0  1  1
0  1  1          1  0  0
1  0  0          1  1  0
1  1  1          1  0  1

在多标签分类中,一个文档可能属于多个类别。上述数据中,1表示文档属于特定类别,0表示文档不属于特定类别。

实际数据的第一行表示文档属于c1和c2类,不属于c3类。同样地,预测数据的第一行表示文档属于c1、c2和c3类。

最初,我使用了R编程来找到实际数据和预测数据之间的混淆矩阵。我将这些数据框保存在y_actual和y_predict中。

y_actual<-as.matrix(Actual_data)
y_predict<-as.matrix(Predicted_data)
xtab<-table(y_actual,y_predict)

输出的 xtab 是:
            y_predict
 y_actual     0 1
            0 1 5
            1 5 7

接下来,我使用 R 语言的 caret 包创建了混淆矩阵,如下所示:

library(caret) 
confusionMatrix(xtab)
Confusion Matrix and Statistics
                   y_predict
           y_actual 0 1
                  0 1 5
                  1 5 7

               Accuracy : 0.4444          
                 95% CI : (0.2153, 0.6924)
     No Information Rate : 0.6667          
     P-Value [Acc > NIR] : 0.9856          

              Kappa : -0.25           
 Mcnemar's Test P-Value : 1.0000          

            Sensitivity : 0.16667         
            Specificity : 0.58333         
         Pos Pred Value : 0.16667         
         Neg Pred Value : 0.58333         
             Prevalence : 0.33333         
         Detection Rate : 0.05556         
   Detection Prevalence : 0.33333         
      Balanced Accuracy : 0.37500         

       'Positive' Class : 0  

在这种情况下,我没有获得多标签混淆矩阵,而是获得了二进制标签混淆矩阵。我希望在y-actual和y-predict中都有c1、c2、c3的混淆矩阵,而不是0、1。
然后我在互联网上搜索,发现utiml包用于R中的多标签分类,但它没有提供所需的输出。然后我尝试使用python的scikit包进行多标签分类,以下是代码。
import numpy as np
from sklearn.metrics import multilabel_confusion_matrix
y_actual = np.array([[1, 1, 0],
                     [1, 1, 0],
                     [1, 0, 1],
                     [0, 1, 1],
                     [1, 0, 0],
                     [1, 1, 1]])
y_predict = np.array([[1, 1, 1],
                      [1, 0, 1],
                      [0, 1, 1],
                      [1, 0, 0],
                      [1, 1, 0],
                      [1, 0, 1]])
matrix = multilabel_confusion_matrix(y_actual, y_predict)
print(matrix)
print(classification_report(y_actual,y_predict))

程序的输出是:
    [[[0 1]
      [1 4]]

    [[0 2]
      [3 1]]

    [[1 2]
      [1 2]]]
              precision    recall  f1-score   support

           0       0.80      0.80      0.80         5
           1       0.33      0.25      0.29         4
           2       0.50      0.67      0.57         3

   micro avg       0.58      0.58      0.58        12
   macro avg       0.54      0.57      0.55        12
weighted avg       0.57      0.58      0.57        12
 samples avg       0.53      0.61      0.54        12

在这种情况下,我无法按标签输出结果。 有人可以帮我确定在任何平台(R编程、Python或Weka)中需要使用哪种软件包来获取上述实际和预测数据的多标签混淆矩阵吗? 输出的混淆矩阵需要是y_actual和y_predict的c1、c2和c3的3*3矩阵。
                    y_predict
    y_actual       c1 c2 c3
                c1 4
                c2    1
                c3       2

这里的对角元素表明实际上它属于 c1,而分类器预测它属于 c1。c2和c3同理。我的问题是如何获得混淆矩阵的其他值,因为这是多标签分类问题。这个问题不是多类别分类问题,而是多标签分类问题。


@Kaushik 我希望评估我的分类器,使用不同的算法。因此,我考虑制作一个混淆矩阵,其中行和列分别表示真实主题和预测主题。然后,对于指标,我将计算精度、召回率和分类错误率。 除非有其他方法可以评估多标签分类,否则我很想知道您的想法。非常感谢您的时间! - yishairasowsky
你能再解释一下吗?因为按标签划分的混淆矩阵意味着如果你有L个标签,你将会有L个混淆矩阵。我认为你想要在一个单独的矩阵中捕获被正确预测为正面的标签,就像你的例子中一样?在这种情况下,它不是混淆矩阵,因为它只有一个对角线。本质上,它是预测正确的列表? - phoxis
1个回答

0

一种解决方案是改变数据的表示方式,使其与 caretsklearn 期望的混淆矩阵相匹配。如果您考虑到混淆矩阵中的每个单元格都代表一个离散的类别预测(即,“对于这个类别,我们预测这个,但实际上我们看到的是这个”),那么您会发现在您的示例中,实际上无法构建这样的矩阵,因为类别可以同时具有多个值。

考虑到这一点,在您的示例中,您实际上并没有三个离散的类别 - 您有8个。

这意味着对于每一行观察值,给定存在的三个分类值,您的数据点可以采用以下任何一种:

none of the categories
only c1
c1&c2
c1&c3
only c2
c2&c3
only c3
all categories

您只需要向数据框添加一个新列,重新编码您现有的三个目标列,使得新列采用1或8的值来表示这些组合中的每一个。

以下是一个解决方案示例:

#Recreating your data

Actual_data <- cbind(c(1, 1, 1, 0, 1, 1),
                     c(1, 1, 0, 1, 0, 1),
                     c(0, 0, 1, 1, 0, 1)
)

colnames(Actual_data) <- c("c1", "c2", "c3")

Predicted_data <- cbind(c(1, 1, 0, 1, 1, 1),
                        c(1, 0, 1, 0, 1, 0),
                        c(1, 1, 1, 0, 0, 1)
)

colnames(Predicted_data) <- c("c1", "c2", "c3")

#To make it easy to recode everything, we can convert these two objects into dataframes:

Predicted_data <-as.data.frame(Predicted_data)
Actual_data <- as.data.frame(Actual_data)

#Next, we make a simple function that goes through each row and recodes the class 
#combinations to a distinct category

set_class_combinations <- function(df){
    df$target <- 0
    for (i in nrow(df)){
        df$target[df$c1 == 0 & df$c2 == 0 & df$c3 == 0] <- 1
        df$target[df$c1 == 1 & df$c2 == 0 & df$c3 == 0] <- 2
        df$target[df$c1 == 1 & df$c2 == 1 & df$c3 == 0] <- 3
        df$target[df$c1 == 1 & df$c2 == 0 & df$c3 == 1] <- 4
        df$target[df$c1 == 0 & df$c2 == 1 & df$c3 == 0] <- 5
        df$target[df$c1 == 0 & df$c2 == 1 & df$c3 == 1] <- 6
        df$target[df$c1 == 0 & df$c2 == 0 & df$c3 == 1] <- 7
        df$target[df$c1 == 1 & df$c2 == 1 & df$c3 == 1] <- 8
    }
    return(df)
}

#With the function, we can add a new "target" column to our respective dataframes

Predicted_data <- set_class_combinations(Predicted_data)
Actual_data <- set_class_combinations(Actual_data)

#As your example does not include all available combinations, we just need to ensure that we 
#account for this when we set the factor levels (1 through 8) and call the `confusionMatrix` function

cm <- confusionMatrix(factor(Predicted_data$target, levels = 1:8), factor(Actual_data$target, levels = 1:8))

print(cm)

谢谢你的努力和回答。但我有两个问题;第一个是我大约有15个类;如果按照你的编码技术,我需要2^n个测试用例;这将增加代码的复杂性。其次,对于一个实际的文档,假设数字6根据你的技术,我的分类器预测数字7(意味着文档最初属于c1、c2不属于c3,分类后属于所有类别)。即使它与c1和c2匹配,由于预测数字为7,它在混淆矩阵中被视为不同。 - Rama Ranjan Panda
如果类别是互斥的,那么获得一个3x3的混淆矩阵就很容易,但如果类别不是互斥的,如你所述,那么在3x3的格式下是不可能的。这里的挑战不是技术/编码方面的,而更多地涉及到混淆矩阵的可能性。 - anguyen1210
是的,你说得完全正确。我正在努力寻找其他可能性。实际上,我对多标签分类非常陌生。我无法将我的代码与现有的R和Python多标签算法连接起来。 - Rama Ranjan Panda

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