The problem is that the way you have the data set up isn't really appropriate for what is being represented. To start with, you have categorical data (so you won't be able to make a scatterplot). Moreover, you have actual classes and the predicted classes from some classifier. So you should represent this via a confusion matrix (i.e., a contingency table of counts for the class combinations). Often a properly set up table is enough to see what is happening in your data. Here I set one up (coded with R
):
av = rep(c("A","F","J","P","T","Z"), times=c(30,40,10,20,50,10))
ev = c(rep("P",10), rep("J",10), rep("A",10),
rep("F",40),
rep("F",10),
rep("P",10), rep("T",10),
rep("Z",30), rep("P",20),
rep("T",10) )
av = as.factor(av)
ev = as.factor(ev)
print(tab <- table(ev,av), zero.print="")
# av
# ev A F J P T Z
# A 10
# F 40 10
# J 10
# P 10 10 20
# T 10 10
# Z 30
It may be more useful to view the conditional probabilities. Since the true categories are in columns here, we can get 'column-wise' proportions:
print(round(prop.table(tab, 2), 2), zero.print="")
# av
# ev A F J P T Z
# A 0.33
# F 1.00 1.00
# J 0.33
# P 0.33 0.50 0.40
# T 0.50 1.00
# Z 0.60
This doesn't quite tell you the proportion correct for each category, so we can do that:
round(mapply(function(x,y){mean(y==x)}, split(ev,av), list("A","F","J","P","T","Z")), 2)
# A F J P T Z
# 0.33 1.00 0.00 0.50 0.00 0.00
sum(diag(tab))/sum(tab) # overall proportion correct
# [1] 0.375
sum((colSums(tab)/sum(tab))^2) # proportion correct for naive classifier
# [1] 0.21875
Your classifier does as well as 100% correct for F
, and as little as 0% correct for J
, T
, and Z
. Overall, you get 37.5% correct. A naive classifier that just assigned labels according to the marginal probability of the classes would achieve 21.9% correct, which isn't that much worse. As @MarkL.Stone notes, this classifier isn't very good.
We might wonder if this classifier is actually better than a naive version. These are a kind of agreement data. We can test if the agreement is better than chance using Cohen's kappa:
library(irr)
kappa2(data.frame(av=av, ev=ev))
# Cohen's Kappa for 2 Raters (Weights: unweighted)
#
# Subjects = 160
# Raters = 2
# Kappa = 0.242
#
# z = 7.06
# p-value = 1.73e-12
Although the agreement isn't very good, it is clear that it's better than chance.
Once you have the data represented correctly (as a confusion matrix), and are thinking in these terms, there are various ways of trying to visualize a contingency table, if you really want a plot. Some methods, like mosaic plots, might be reasonable, but I think it will be hard to pick out the correct classifications. My first hunch would be to try a heatmap. To make it more immediately useful, I outlined the cells where correct classifications go. In addition, because your data are categorical, classes that are closer alphabetically aren't actually closer to correct, but you have a number of cases where what appears to be the adjacent category is highlighted. That makes your classifier look better than it is. So I shuffled the orderings of the labels to break that illusion:
windows()
image(t(tab[c(1,6,4,2,5,3),c(1,6,4,2,5,3)]), axes=F,
xlab="Actual classes", ylab="Estimated classes",
col=colorRampPalette(c("white","blue"))(5))
box()
axis(side=1, at=seq(0,1,.2), labels=c("A","F","J","P","T","Z")[c(1,6,4,2,5,3)])
axis(side=2, at=seq(0,1,.2), labels=c("A","F","J","P","T","Z")[c(1,6,4,2,5,3)])
polygon(x=c(-.1,rep(seq(.1,1.1,.2),each=2), rep(seq(.9,-.1,-.2),each=2)),
y=c(rep(seq(-.1,1.1,.2),each=2), rep(seq(.9,.1,-.2),each=2),-.1),
border="black", col=NA, lwd=2)
