多标签混淆矩阵

时间:2019-09-21 06:46:08

标签: 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

在多标签分类中,文档可能属于多个类别。在上述数据中,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)

输出xtab为

            y_predict
 y_actual     0 1
            0 1 5
            1 5 7

然后我使用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  

在这种情况下,我没有多标签混淆矩阵,而有二进制标签混淆矩阵。我想要一个在y-actual中具有c1,c2,c3以及y--predict的混淆矩阵,而不是在y-actual和y-predict中的0,1。

然后我在Internet上搜索了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-programming,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同样。我的问题是如何获得混淆矩阵的其他值,因为它是多标签分类。这个问题不是多分类问题,而是多标签分类问题。

2 个答案:

答案 0 :(得分:1)

您可以按以下方式使用multilabel_confusion_matrix中的sklearn函数:

import numpy as np
from sklearn.metrics import multilabel_confusion_matrix, classification_report

y_true = np.array([[1, 0, 1],
                   [0, 1, 0]])
y_pred = np.array([[1, 0, 0],
                   [0, 1, 1]])
matrix = multilabel_confusion_matrix(y_true, y_pred)
print(matrix)
print(classification_report(y_true,y_pred))

答案 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)