From the Iris dataset, I have created the following confusion matrix:
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?
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