Plot confusion matrix in R using ggplot

前端 未结 5 2035
情歌与酒
情歌与酒 2020-12-29 08:38

I have two confusion matrices with calculated values as true positive (tp), false positives (fp), true negatives(tn) and false negatives (fn), corresponding to two different

相关标签:
5条回答
  • 2020-12-29 08:49

    It is a very old question, still it seems there is a quite straight forward solution to that using ggplot2 which hasn't been mentioned.

    Hope it might be helpful to someone:

    cm <- confusionMatrix(factor(y.pred), factor(y.test), dnn = c("Prediction", "Reference"))
    
    ggplot(as.data.frame(cm$table), aes(Prediction,sort(Reference,decreasing = T), fill= Freq)) +
            geom_tile() + geom_text(aes(label=Freq)) +
            scale_fill_gradient(low="white", high="#009194") +
            labs(x = "Reference",y = "Prediction") +
            scale_x_discrete(labels=c("Class_1","Class_2","Class_3","Class_4")) +
            scale_y_discrete(labels=c("Class_4","Class_3","Class_2","Class_1"))
    

    0 讨论(0)
  • 2020-12-29 08:51

    Old question, but I wrote this function which I think makes a prettier answer. Results in a divergent color palette (or whatever you want, but default is divergent):

    prettyConfused<-function(Actual,Predict,colors=c("white","red4","dodgerblue3"),text.scl=5){
      actual = as.data.frame(table(Actual))
      names(actual) = c("Actual","ActualFreq")
    
      #build confusion matrix
      confusion = as.data.frame(table(Actual, Predict))
      names(confusion) = c("Actual","Predicted","Freq")
    
      #calculate percentage of test cases based on actual frequency
    
      confusion = merge(confusion, actual, by=c('Actual','Actual'))
      confusion$Percent = confusion$Freq/confusion$ActualFreq*100
      confusion$ColorScale<-confusion$Percent*-1
      confusion[which(confusion$Actual==confusion$Predicted),]$ColorScale<-confusion[which(confusion$Actual==confusion$Predicted),]$ColorScale*-1
      confusion$Label<-paste(round(confusion$Percent,0),"%, n=",confusion$Freq,sep="")
      tile <- ggplot() +
        geom_tile(aes(x=Actual, y=Predicted,fill=ColorScale),data=confusion, color="black",size=0.1) +
        labs(x="Actual",y="Predicted")
    
      tile = tile +
            geom_text(aes(x=Actual,y=Predicted, label=Label),data=confusion, size=text.scl, colour="black") +
            scale_fill_gradient2(low=colors[2],high=colors[3],mid=colors[1],midpoint = 0,guide='none')
    }
    

    0 讨论(0)
  • 2020-12-29 08:56

    This could be a good start

    library(ggplot2)
    ggplot(data =  dframe, mapping = aes(x = label, y = method)) +
      geom_tile(aes(fill = value), colour = "white") +
      geom_text(aes(label = sprintf("%1.0f",value)), vjust = 1) +
      scale_fill_gradient(low = "white", high = "steelblue")
    

    Edited

    TClass <- factor(c(0, 0, 1, 1))
    PClass <- factor(c(0, 1, 0, 1))
    Y      <- c(2816, 248, 34, 235)
    df <- data.frame(TClass, PClass, Y)
    
    library(ggplot2)
    ggplot(data =  df, mapping = aes(x = TClass, y = PClass)) +
      geom_tile(aes(fill = Y), colour = "white") +
      geom_text(aes(label = sprintf("%1.0f", Y)), vjust = 1) +
      scale_fill_gradient(low = "blue", high = "red") +
      theme_bw() + theme(legend.position = "none")
    

    0 讨论(0)
  • 2020-12-29 08:56

    Here's another ggplot2 based option; first the data (from caret):

    library(caret)
    
    # data/code from "2 class example" example courtesy of ?caret::confusionMatrix
    
    lvs <- c("normal", "abnormal")
    truth <- factor(rep(lvs, times = c(86, 258)),
                    levels = rev(lvs))
    pred <- factor(
      c(
        rep(lvs, times = c(54, 32)),
        rep(lvs, times = c(27, 231))),
      levels = rev(lvs))
    
    confusionMatrix(pred, truth)
    

    And to construct the plots (substitute your own matrix below as needed when setting up "table"):

    library(ggplot2)
    library(dplyr)
    
    table <- data.frame(confusionMatrix(pred, truth)$table)
    
    plotTable <- table %>%
      mutate(goodbad = ifelse(table$Prediction == table$Reference, "good", "bad")) %>%
      group_by(Reference) %>%
      mutate(prop = Freq/sum(Freq))
    
    # fill alpha relative to sensitivity/specificity by proportional outcomes within reference groups (see dplyr code above as well as original confusion matrix for comparison)
    ggplot(data = plotTable, mapping = aes(x = Reference, y = Prediction, fill = goodbad, alpha = prop)) +
      geom_tile() +
      geom_text(aes(label = Freq), vjust = .5, fontface  = "bold", alpha = 1) +
      scale_fill_manual(values = c(good = "green", bad = "red")) +
      theme_bw() +
      xlim(rev(levels(table$Reference)))
    

    option 1

    # note: for simple alpha shading by frequency across the table at large, simply use "alpha = Freq" in place of "alpha = prop" when setting up the ggplot call above, e.g.,
    ggplot(data = plotTable, mapping = aes(x = Reference, y = Prediction, fill = goodbad, alpha = Freq)) +
      geom_tile() +
      geom_text(aes(label = Freq), vjust = .5, fontface  = "bold", alpha = 1) +
      scale_fill_manual(values = c(good = "green", bad = "red")) +
      theme_bw() +
      xlim(rev(levels(table$Reference)))
    

    option 2

    0 讨论(0)
  • 2020-12-29 09:00

    A slightly more modular solution based on MYaseen208's answer. Might be more effective for large datasets / multinomial classification:

    confusion_matrix <- as.data.frame(table(predicted_class, actual_class))
    
    ggplot(data = confusion_matrix
           mapping = aes(x = predicted_class,
                         y = Var2)) +
      geom_tile(aes(fill = Freq)) +
      geom_text(aes(label = sprintf("%1.0f", Freq)), vjust = 1) +
      scale_fill_gradient(low = "blue",
                          high = "red",
                          trans = "log") # if your results aren't quite as clear as the above example
    
    0 讨论(0)
提交回复
热议问题