rdata-miningconfusion-matrix

R Code Warning: number of items to replace is not a multiple of replacement length


From the Iris dataset, I have created the following confusion matrix: enter image description here

In attempting to perform multiclass classification using the one vs many strategy, I have come up with the following R code:

mtrx <- matrix(c(10,0,0,0,10,1,0,0,9), ncol = 3)
rownames(mtrx) <- c("setosa","veriscolor", "virginica")
colnames(mtrx) <- c("setosa", "versicolor", "virginica")
cat <- colnames(mtrx)

for(n in 1:length(cat)) {
  current <- cat[n]
  binaryConMat <- mtrx
  binaryConMat[binaryConMat != 0] <- ifelse(rownames(binaryConMat) == current, 1, 0)
  
  print(binaryConMat)
  
  TP <- binaryConMat[n, n]
  FN <- sum(binaryConMat[n,]) - TP
  FP <- sum(binaryConMat[,n]) - TP
  TN <- sum(diag(binaryConMat)) - TP
  
  sensitivity <- ifelse((TP + FN) == 0, 0, TP / (TP + FN))
  specificity <- ifelse((TN + FP) == 0, 0, TN / (TN+FP))
  precision <- ifelse((TP + FP) == 0, 0, TP / (TP + FP))
  
  cat("Class:", current, "\n")
  cat("Sensitivity:", round(sensitivity, 2), "\n")
  cat("Specificity:", round(specificity, 2), "\n")
  cat("Precision:", round(precision, 2), "\n")
  cat("\n")
}

accuracy <- sum(diag(mtrx))/sum(mtrx)
cat("Overall Accuracy:",round(accuracy, 2), "\n")

However, this results in the following error upon running the code:

Warning: number of items to replace is not a multiple of replacement length

I've isolated the problem to this line of code:

binaryConMat[binaryConMat != 0] <- ifelse(rownames(binaryConMat) == current, 1, 0)

However, I'm not sure what a suitable fix for this problem is. What can I do to resolve this error?


Solution

  • Here is the question's code corrected.
    Except for the data creation code, which I believe is now simpler, the changes are documented in comments.

    mtrx <- matrix(c(10,0,0,0,10,1,0,0,9), ncol = 3)
    catg <- c("setosa","veriscolor", "virginica")
    rownames(mtrx) <- catg
    colnames(mtrx) <- catg
    
    for(n in seq_along(catg)) {
      current <- catg[n]
      binaryConMat <- mtrx
      # use the logical values directly since they alreay
      # are FALSE/TRUE, meaning, 0/1
      cond1 <- binaryConMat != 0
      cond2 <- rownames(binaryConMat) == current
      # the square brackets in binaryConMat[] are meant
      # to preserve the shape of binaryConMat, a matrix
      binaryConMat[] <- as.integer(cond1 & cond2)
    
      print(binaryConMat)
      
      TP <- binaryConMat[n, n]
      FN <- sum(binaryConMat[n,]) - TP
      FP <- sum(binaryConMat[,n]) - TP
      TN <- sum(diag(binaryConMat)) - TP
      
      sensitivity <- ifelse((TP + FN) == 0, 0, TP / (TP + FN))
      specificity <- ifelse((TN + FP) == 0, 0, TN / (TN+FP))
      precision <- ifelse((TP + FP) == 0, 0, TP / (TP + FP))
      
      cat("Class:", current, "\n")
      cat("Sensitivity:", round(sensitivity, 2), "\n")
      cat("Specificity:", round(specificity, 2), "\n")
      cat("Precision:", round(precision, 2), "\n")
      cat("\n")
    }
    #>            setosa veriscolor virginica
    #> setosa          1          0         0
    #> veriscolor      0          0         0
    #> virginica       0          0         0
    #> Class: setosa 
    #> Sensitivity: 1 
    #> Specificity: 0 
    #> Precision: 1 
    #> 
    #>            setosa veriscolor virginica
    #> setosa          0          0         0
    #> veriscolor      0          1         0
    #> virginica       0          0         0
    #> Class: veriscolor 
    #> Sensitivity: 1 
    #> Specificity: 0 
    #> Precision: 1 
    #> 
    #>            setosa veriscolor virginica
    #> setosa          0          0         0
    #> veriscolor      0          0         0
    #> virginica       0          1         1
    #> Class: virginica 
    #> Sensitivity: 0.5 
    #> Specificity: 0 
    #> Precision: 1
    
    accuracy <- sum(diag(mtrx))/sum(mtrx)
    cat("Overall Accuracy:",round(accuracy, 2), "\n")
    #> Overall Accuracy: 0.97
    

    Created on 2023-10-17 with reprex v2.0.2