多标签混淆矩阵

Ram*_*nda 5 python r weka confusion-matrix multilabel-classification

我正在对实际数据和分类器的预测数据进行多标签分类。实际数据由三个类(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
Run Code Online (Sandbox Code Playgroud)

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

Actual_data 的第一行表示文档属于类 c1 和 c2,不属于类 c3。类似地,predicted_data 的第一行表示文档属于类 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)
Run Code Online (Sandbox Code Playgroud)

输出xtab是

            y_predict
 y_actual     0 1
            0 1 5
            1 5 7
Run Code Online (Sandbox Code Playgroud)

然后我使用 R 的插入符包创建了混淆矩阵,如下所示

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  
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我没有得到多标签混淆矩阵,而是得到了二进制标签混淆矩阵。我想要一个混淆矩阵,其中 y-实际和 y-预测中包含 c1,c2,c3,而不是 y-实际和 y-预测中的 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))
Run Code Online (Sandbox Code Playgroud)

程序的输出是

    [[[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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我也没有明智地获得输出标签。任何人都可以帮助我在任何平台(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
Run Code Online (Sandbox Code Playgroud)

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

ang*_*210 0

一种解决方案是改变数据的表示方式,使其符合混淆矩阵的内容caret或预期。sklearn如果您认为混淆矩阵中的每个单元代表一个离散类预测(即“对于这个类,我们预测这个,但我们实际上看到这个”),那么您可以看到没有办法实际构造这样的矩阵对于您的示例,其中类可以同时具有值​​。

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

这意味着对于每一行观察结果,给定存在的三个分类值,您的数据点可能会呈现:

none of the categories
only c1
c1&c2
c1&c3
only c2
c2&c3
only c3
all categories
Run Code Online (Sandbox Code Playgroud)

您需要做的就是向数据框中添加一个新列,重新编码您的三个现有目标列,以便新列采用 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)
Run Code Online (Sandbox Code Playgroud)