9

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?

Hobo
  • 7,536
  • 5
  • 40
  • 50
Oposum
  • 1,155
  • 3
  • 22
  • 38
  • 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. – steveb Jan 17 '16 at 19:52
  • Just to clarify, you will have to take the result of `confusionMatrix` and put the data you require from it, into a data.frame. – steveb Jan 17 '16 at 19:56
  • @steveb yes, I see now. mroto in the response below outlined it very clearly. – Oposum Jan 17 '16 at 20:37

5 Answers5

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

6

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")
mtoto
  • 23,919
  • 4
  • 58
  • 71
  • 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. – Oposum Jan 17 '16 at 21:08
  • 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)`? – Oposum Jan 17 '16 at 21:26
  • 1
    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. – mtoto Jan 18 '16 at 09:09
2

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")
anakar
  • 316
  • 2
  • 13
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.

nate-m
  • 557
  • 3
  • 14
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")
jiggunjer
  • 1,905
  • 1
  • 19
  • 18