read_csv("./data/CAMDA.csv") %$% table(predicted, actual) -> CAMDA.confusion
## 
## -- Column specification --------------------------------------------------------
## cols(
##   actual = col_character(),
##   predicted = col_character()
## )

Given a multinomial confusion matrix C, OVA(C) produces a data frame of the binary confusion matrices formed by the one-versus-all treatment of each class.

OVA <- function(C){
# Takes the i^th row and column of the confusion matrix C and forms the binary ("one vs all") confusion matrix
# Let "A" be the name of the i^th row. Then
#            actual
# predicted  A  nA
#         A TP  FP
#        nA FN  TN  

  N        <- sum(C)
  nclasses <- nrow(C)
  # Make space to store the results
  TP <- TN <- FP <- FN <- integer(nclasses)

  for(i in 1:nrow(C)){
    TP[i] <- C[i,i]
    FP[i] <- sum(C[i,]) - TP[i]
    FN[i] <- sum(C[,i]) - TP[i]
    TN[i] <- N - TP[i]  - FP[i] - FN[i]
  }
  
  tibble(class=rownames(C), TP, FP, FN, TN) %>%
    mutate(
      Pos=TP+FN,
      Neg=FP+TN,
      TPR=TP/Pos,
      FPR=FP/Neg,
      O.act=Pos/Neg,          # Odds of actual class being X
      P.act=O.act/(O.act+1), # Probability of actual class being X
      O.act.g.prd=TP/FP,      # Odds of actual class being X given the prediction that it is X
      P.act.g.prd=            # Probability of actual class being X given the prediction that it is X
        O.act.g.prd/(O.act.g.prd+1)
    )
}
C <- CAMDA.confusion
C.conf <- as_tibble(C)
OVA(C) %>% 
  mutate(
    class=fct_reorder(class, P.act.g.prd, .desc = TRUE)
  ) -> C.OVA

as_tibble(C) %>%
    mutate(
    actual=factor(actual, levels=levels(C.OVA$class)),
    predicted=factor(predicted,   levels=levels(C.OVA$class))
  ) -> C.conf
filter(C.conf, n>0) %>%
  ggplot(aes(x=actual, y=predicted)) + 
  geom_count(aes(size=n)) + scale_size_area() + scale_y_discrete(limits=rev, position="right") + 
  #scale_x_discrete(position="top") + 
  #coord_equal() +
  theme(axis.text.x = element_text(angle = 90), legend.position = "none") -> p22
 ggplot(C.OVA, aes(x=class, y=P.act)) + 
  geom_step(group=1, direction="mid", color="blue") + 
  scale_y_continuous(trans="logit", position="right", breaks=c(0.01, 0.1, 0.5, 0.9, 0.99), limits = c(0.01, 0.99)) +
  scale_x_discrete(position = "top") +
  xlab("actual") + ylab("P(actual)") +
  theme(axis.text.x = element_text(angle = 90), legend.position = "none") -> p12
ggplot(C.OVA,aes(x=class)) + 
  geom_step(aes(y=P.act      ), group=1, direction="mid", color="blue") +
  geom_step(aes(y=P.act.g.prd), group=1, direction="mid", color="red") + 
  scale_y_continuous(trans="logit", breaks=c(0.01, 0.1, 0.5, 0.9, 0.99), limits = c(0.01, 0.99)) + 
  scale_x_discrete(limits=rev) + 
  xlab("predicted") +ylab("P(actual | predicted)") +
  coord_flip() -> p21
plot_spacer() + p12 +  p21 + p22 +
  plot_layout(widths=c(1,3), heights=c(1,3))
## Warning: Transformation introduced infinite values in continuous y-axis