5

I have to plot a graph for SVM classifier. This is the code I am using to plot:

plt.contour(xx, yy, Z)

Here xx and yy are features and Z is the label. These labels are in strings. When I run the code I get the error

ValueError: could not convert string to float: dog  

How can I plot this graph ?

ImportanceOfBeingErnest
  • 289,005
  • 45
  • 571
  • 615
  • 1
    So should *"dog"* be at a higher or lower contour level than *"cat"* and *"cow"* ? Since I don't think the problem has anything to do with SVM classifiers, you can easily provide a [mcve] of the issue. – ImportanceOfBeingErnest Apr 04 '17 at 11:13

1 Answers1

4

Because "dog" is not a numeric value, you cannot plot it directly. What you need is a mapping between the categorical values and numeric values, e.g. using a dicitionary,

an = {"cow":1,"no animal":0,"chicken":2,"cat":3, "fox":4}

Using this dictionary you can then plot the array of numbers between 0 and 4 using contourf or imshow. The difference between the two can be observed below. Imshow preserves catergories better, as it plots the pixels instead of interpolating between them. And since categories can rarely be interpolated (what's the mean between a cat and a fox?), it's probably closer to what is needed here.

import numpy as np; np.random.seed(0)
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (6,2.8)

animals = [['no animal', 'no animal', 'no animal', 'chicken', 'chicken'],
     ['no animal', 'no animal', 'cow', 'no animal', 'chicken'],
     ['no animal', 'cow', 'cat', 'cat', 'no animal'],
     ['no animal', 'cow', 'fox', 'cat', 'no animal'],
     ['cow', 'cow', 'fox', 'chicken', 'no animal'],
     ['no animal','cow', 'chicken', 'chicken', 'no animal'],
     ['no animal', 'no animal', 'chicken', 'cat', 'chicken'],
     ['no animal', 'no animal', 'no animal', 'cat', 'no animal']]

y = np.linspace(-4,4, 8)
x = np.linspace(-3,3, 5)
X,Y = np.meshgrid(x,y)

an = {"cow":1,"no animal":0,"chicken":2,"cat":3, "fox":4}
aninv =  { val: key for key, val in an.items()  }
f = lambda x: an[x]
fv = np.vectorize(f)
Z = fv(animals)


fig, (ax, ax2) = plt.subplots(ncols=2)
ax.set_title("contourf"); ax2.set_title("imshow")

im = ax.contourf(X,Y,Z, levels=[-0.5,0.5,1.5,2.5,3.5,4.5] )
cbar = fig.colorbar(im, ax=ax)
cbar.set_ticks([0,1,2,3,4])
cbar.set_ticklabels([aninv[t] for t in [0,1,2,3,4]])


im2 = ax2.imshow(Z, extent=[x.min(), x.max(), y.min(), y.max() ], origin="lower" )
cbar2 = fig.colorbar(im2, ax=ax2 )
cbar2.set_ticks([0,1,2,3,4])
cbar2.set_ticklabels([aninv[t] for t in [0,1,2,3,4]])


plt.tight_layout()
plt.show()

enter image description here

ImportanceOfBeingErnest
  • 289,005
  • 45
  • 571
  • 615
  • So if this answers your question, consider [accepting](https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work) it. If it doesn't, feel free to provide further details in the question or asking more specifically. Instead of writing "thank you" you may just [upvote](http://stackoverflow.com/help/privileges/vote-up) (votes will be counted once you have 15 reputation). – ImportanceOfBeingErnest Apr 05 '17 at 10:36
  • what's the purpose of dx and dy? – bmillare Aug 17 '17 at 15:45
  • @bmillare Well, spotted, this has no purpose in this code ;-) One may use the difference between values along the axes to get the actual extent of the image (i.e. one pixel per value). However I did not use it here, so I left it out completely. – ImportanceOfBeingErnest Aug 17 '17 at 15:55