Saving output of confusionMatrix as a .csv table
Asked Answered
A

5

10

I have a following code resulting in a table-like output

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

 xtab <- table(pred, truth)

 library(caret)
 confusionMatrix(xtab)

 confusionMatrix(pred, truth)
 confusionMatrix(xtab, prevalence = 0.25)   

I would like to export the below part of the output as a .csv table

               Accuracy : 0.8285          
                 95% CI : (0.7844, 0.8668)
    No Information Rate : 0.75            
    P-Value [Acc > NIR] : 0.0003097       

                  Kappa : 0.5336          
 Mcnemar's Test P-Value : 0.6025370       

            Sensitivity : 0.8953          
            Specificity : 0.6279          
         Pos Pred Value : 0.8783          
         Neg Pred Value : 0.6667          
             Prevalence : 0.7500          
         Detection Rate : 0.6715          
   Detection Prevalence : 0.7645          
      Balanced Accuracy : 0.7616  

Attempt to write it as a .csv table results in the error message:

write.csv(confusionMatrix(xtab),file="file.csv")
Error in as.data.frame.default(x[[i]], optional = TRUE, stringsAsFactors = stringsAsFactors) : 
cannot coerce class ""confusionMatrix"" to a data.frame

Doing the whole work manually, for obvious reasons, is impractical and prone to human errors.

Any suggestions on how to export it as a .csv?

Autobiographical answered 17/1, 2016 at 19:45 Comment(3)
Is the thing you want to write in the form "key : value" ? write.csv is expecting a data.frame according to the error so you will have to massage your result into something it can take.Scrag
Just to clarify, you will have to take the result of confusionMatrix and put the data you require from it, into a data.frame.Scrag
@Scrag yes, I see now. mroto in the response below outlined it very clearly.Autobiographical
B
7

Ok, so if you inspect the output of confusionMatrix(xtab, prevalence = 0.25) , it's a list:

cm <- confusionMatrix(pred, truth)
str(cm)

    List of 5
 $ positive: chr "abnormal"
 $ table   : 'table' int [1:2, 1:2] 231 27 32 54
  ..- attr(*, "dimnames")=List of 2
  .. ..$ Prediction: chr [1:2] "abnormal" "normal"
  .. ..$ Reference : chr [1:2] "abnormal" "normal"
 $ overall : Named num [1:7] 0.828 0.534 0.784 0.867 0.75 ...
  ..- attr(*, "names")= chr [1:7] "Accuracy" "Kappa" "AccuracyLower" "AccuracyUpper" ...
 $ byClass : Named num [1:8] 0.895 0.628 0.878 0.667 0.75 ...
  ..- attr(*, "names")= chr [1:8] "Sensitivity" "Specificity" "Pos Pred Value" "Neg Pred Value" ...
 $ dots    : list()
 - attr(*, "class")= chr "confusionMatrix"

From here on you select the appropriate objects that you want to create a csv from and make a data.frame that will have a column for each variable. In your case, this will be:

tocsv <- data.frame(cbind(t(cm$overall),t(cm$byClass)))

# You can then use
write.csv(tocsv,file="file.csv")
Baksheesh answered 17/1, 2016 at 20:7 Comment(3)
thank you, this is very close. In fact, I changed your code slightly to get what I want: tocsv<-as.data.frame(t(data.frame(cbind(t(cm$byClass),t(cm$overall))))) But, if I may ask you, why did you have transpose in the first place to begin with? Also, is there away to round the numeric values before we get to the tocsv stage? I know afterwards I can name the column, round it, and then replace it but I was wondering if there is a more efficient way on an initial stage.Autobiographical
Also I noticed that the code alters the original row 95% CI : (0.7844, 0.8668) and instead displays these two rows: AccuracyLower 0.7844134380 and AccuracyUpper 0.8667985207. Is there a way to keep the original way 95% CI : (0.7844, 0.8668)?Autobiographical
By default byClass and overall are named numerical vectors, which couldn't be cbinded together in their current form. If you transpose them, you create a character vector of the names beside the values. As for rounding them, probably yes, but it is generally good practice to ask new question if you have one, instead of cramming them in comments.Baksheesh
P
8

Using caret package

results <- confusionMatrix(pred, truth)

as.table(results) gives

         Reference
Prediction  X1  X0
        X1  36  29
        X0 218 727

as.matrix(results,what="overall") gives

Accuracy       7.554455e-01
Kappa          1.372895e-01
AccuracyLower  7.277208e-01
AccuracyUpper  7.816725e-01
AccuracyNull   7.485149e-01
AccuracyPValue 3.203599e-01
McnemarPValue  5.608817e-33

and as.matrix(results, what = "classes") gives

Sensitivity          0.8953488
Specificity          0.6279070
Pos Pred Value       0.8783270
Neg Pred Value       0.6666667
Precision            0.8783270
Recall               0.8953488
F1                   0.8867562
Prevalence           0.7500000
Detection Rate       0.6715116
Detection Prevalence 0.7645349
Balanced Accuracy    0.7616279

Using these and write.csv command you can get the entire confusionMatrix info

Pewit answered 17/5, 2018 at 20:16 Comment(0)
B
7

Ok, so if you inspect the output of confusionMatrix(xtab, prevalence = 0.25) , it's a list:

cm <- confusionMatrix(pred, truth)
str(cm)

    List of 5
 $ positive: chr "abnormal"
 $ table   : 'table' int [1:2, 1:2] 231 27 32 54
  ..- attr(*, "dimnames")=List of 2
  .. ..$ Prediction: chr [1:2] "abnormal" "normal"
  .. ..$ Reference : chr [1:2] "abnormal" "normal"
 $ overall : Named num [1:7] 0.828 0.534 0.784 0.867 0.75 ...
  ..- attr(*, "names")= chr [1:7] "Accuracy" "Kappa" "AccuracyLower" "AccuracyUpper" ...
 $ byClass : Named num [1:8] 0.895 0.628 0.878 0.667 0.75 ...
  ..- attr(*, "names")= chr [1:8] "Sensitivity" "Specificity" "Pos Pred Value" "Neg Pred Value" ...
 $ dots    : list()
 - attr(*, "class")= chr "confusionMatrix"

From here on you select the appropriate objects that you want to create a csv from and make a data.frame that will have a column for each variable. In your case, this will be:

tocsv <- data.frame(cbind(t(cm$overall),t(cm$byClass)))

# You can then use
write.csv(tocsv,file="file.csv")
Baksheesh answered 17/1, 2016 at 20:7 Comment(3)
thank you, this is very close. In fact, I changed your code slightly to get what I want: tocsv<-as.data.frame(t(data.frame(cbind(t(cm$byClass),t(cm$overall))))) But, if I may ask you, why did you have transpose in the first place to begin with? Also, is there away to round the numeric values before we get to the tocsv stage? I know afterwards I can name the column, round it, and then replace it but I was wondering if there is a more efficient way on an initial stage.Autobiographical
Also I noticed that the code alters the original row 95% CI : (0.7844, 0.8668) and instead displays these two rows: AccuracyLower 0.7844134380 and AccuracyUpper 0.8667985207. Is there a way to keep the original way 95% CI : (0.7844, 0.8668)?Autobiographical
By default byClass and overall are named numerical vectors, which couldn't be cbinded together in their current form. If you transpose them, you create a character vector of the names beside the values. As for rounding them, probably yes, but it is generally good practice to ask new question if you have one, instead of cramming them in comments.Baksheesh
G
3

I found that capture.output works best for me.

It simply copies your output as a .csv file

(you can also do it as .txt)

capture.output(
confusionMatrix(xtab, prevalence = 0.25),
 file = "F:/Home Office/result.csv")
Galactopoietic answered 16/7, 2020 at 12:32 Comment(0)
U
0

The absolute easiest solution is to simply write out using readr::write_rds. You can export and import all while keeping the confusionMatrix structure intact.

Unused answered 26/2, 2019 at 1:48 Comment(0)
M
0

If A is a caret::confusionMatrix object, then:

broom::tidy(A) %>% writexl::write_xlsx("mymatrix.xlsx")


optionally replace writexl with write.csv().

To also include the table on a separate sheet:

broom::tidy(A) %>% list(as.data.frame(A$table)) %>% writexl::write_xlsx("mymatrix.xlsx")
Marrowbone answered 1/5, 2020 at 19:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.