from IPython.display import HTML, Markdown, display
from matplotlib import animation
# Initialize w to zero
w = np.array([0 , 0 ])
fig, (ax, ax1) = plt.subplots(1 , 2 , figsize= (16 * 2 / 3 , 7 * 2 / 3 ), dpi= 150 )
artists = []
frame = []
converged = False
n_iter = 0
while not converged and n_iter<= 10 :
frame1 = []
y_pred = np.array(list (map (sign, w@ X.T)))
true_negatives = np.logical_and(y_pred==- 1 , y==- 1 )
true_positives = np.logical_and(y_pred== 1 , y== 1 )
mistakes = np.logical_or(np.logical_and(y_pred== 1 , y==- 1 ), np.logical_and(y_pred==- 1 , y== 1 ))
frame1.append(ax1.text(0.5 , 1.05 , f'( { n_iter} ) Check - w = [ { w[0 ]:.2f} { w[1 ]:.2f} ]' , transform= ax1.transAxes, ha= "center" ))
if np.linalg.norm(w):
frame1.append(ax1.axline([0 , 0 ], slope= perp(w), c= 'black' ))
frame1.append(ax1.scatter(X[:, 0 ][true_positives], X[:, 1 ][true_positives], color= 'green' ))
frame1.append(ax1.scatter(X[:, 0 ][true_negatives], X[:, 1 ][true_negatives], color= 'red' ))
frame1.append(ax1.scatter(X[:, 0 ][mistakes], X[:, 1 ][mistakes], color= 'blue' ))
else :
frame1.append(ax1.scatter(X[:, 0 ][true_positives], X[:, 1 ][true_positives], color= 'green' , label= 'Positive' ))
frame1.append(ax1.scatter(X[:, 0 ][true_negatives], X[:, 1 ][true_negatives], color= 'red' , label= 'Negative' ))
frame1.append(ax1.scatter(X[:, 0 ][mistakes], X[:, 1 ][mistakes], color= 'blue' , label= 'Mistakes' ))
frame1.append(ax.scatter([], [], color= 'cornflowerblue' , s= [50 ], label= 'Update; False Negative' ))
frame1.append(ax.scatter([], [], color= 'lightcoral' , s= [50 ], label= 'Update; False Positive' ))
ax1.legend(loc= 'lower right' )
ax.legend(loc= 'lower right' )
frame1.append(ax1.axvline(x= 0 , c= 'black' ))
frame1.append(ax1.axhline(y= 0 , c= 'black' ))
frame1.append(ax1.arrow(0 , 0 , w[0 ], w[1 ], length_includes_head= True , head_width= 0.1 ))
artists.append(frame1+ frame)
n_iter += 1
for i in range (n):
if sign(w@ X[i].T) != y[i]: # if mistake
frame = []
frame.append(ax.text(0.5 , 1.05 , f'( { n_iter} ) Arbitrary mistake on [ { X[i][0 ]:.2f} { X[i][1 ]:.2f} ] ' + ['(False Positive)' , '(False Negative)' ][int (y[i]== 1 )], transform= ax.transAxes, ha= "center" ))
frame.append(ax.axvline(x= 0 , c= 'black' ))
frame.append(ax.axhline(y= 0 , c= 'black' ))
frame.append(ax.arrow(0 , 0 , w[0 ], w[1 ], length_includes_head= True , head_width= 0.1 ))
if y[i] == 1 :
frame.append(ax.scatter([X[i][0 ]], [X[i][1 ]], color= 'cornflowerblue' , s= [50 ]))
else :
frame.append(ax.scatter([X[i][0 ]], [X[i][1 ]], color= 'lightcoral' , s= [50 ]))
if np.linalg.norm(w):
frame.append(ax.axline([0 , 0 ], slope= perp(w), c= 'black' ))
artists.append(frame+ frame1)
frame = []
frame.append(ax.text(0.5 , 1.05 , f'( { n_iter} ) Update - w = [ { w[0 ]:.2f} { w[1 ]:.2f} ] + ( { y[i]} ) * [ { X[i][0 ]:.2f} { X[i][1 ]:.2f} ]' , transform= ax.transAxes, ha= "center" ))
frame.append(ax.axvline(x= 0 , c= 'black' ))
frame.append(ax.axhline(y= 0 , c= 'black' ))
frame.append(ax.arrow(0 , 0 , w[0 ], w[1 ], length_includes_head= True , head_width= 0.1 ))
if y[i] == 1 :
frame.append(ax.arrow(w[0 ], w[1 ], y[i]* X[i][0 ], y[i]* X[i][1 ], length_includes_head= True , head_width= 0.1 , color= 'cornflowerblue' ))
frame.append(ax.arrow(0 , 0 , y[i]* X[i][0 ], y[i]* X[i][1 ], length_includes_head= True , head_width= 0.1 , color= 'cornflowerblue' , linestyle= '--' ))
frame.append(ax.scatter([X[i][0 ]], [X[i][1 ]], color= 'cornflowerblue' , s= [50 ]))
else :
frame.append(ax.arrow(w[0 ], w[1 ], y[i]* X[i][0 ], y[i]* X[i][1 ], length_includes_head= True , head_width= 0.1 , color= 'lightcoral' ))
frame.append(ax.arrow(0 , 0 , y[i]* X[i][0 ], y[i]* X[i][1 ], length_includes_head= True , head_width= 0.1 , color= 'lightcoral' , linestyle= '--' ))
frame.append(ax.scatter([X[i][0 ]], [X[i][1 ]], color= 'lightcoral' , s= [50 ]))
if np.linalg.norm(w):
frame.append(ax.axline([0 , 0 ], slope= perp(w), c= 'black' ))
artists.append(frame+ frame1)
# update w
w = w + X[i]* y[i]
frame = []
frame.append(ax.text(0.5 , 1.05 , f'( { n_iter} ) Updated w = [ { w[0 ]:.2f} { w[1 ]:.2f} ]' , transform= ax.transAxes, ha= "center" ))
frame.append(ax.axvline(x= 0 , c= 'black' ))
frame.append(ax.axhline(y= 0 , c= 'black' ))
frame.append(ax.arrow(0 , 0 , w[0 ], w[1 ], length_includes_head= True , head_width= 0.1 ))
if y[i] == 1 :
frame.append(ax.scatter([X[i][0 ]], [X[i][1 ]], color= 'cornflowerblue' , s= [50 ]))
else :
frame.append(ax.scatter([X[i][0 ]], [X[i][1 ]], color= 'lightcoral' , s= [50 ]))
if np.linalg.norm(w):
frame.append(ax.axline([0 , 0 ], slope= perp(w), c= 'black' ))
artists.append(frame+ frame1)
break
else :
# if no mistakes, perceptron has converged
converged = True
plt.close()
anim = animation.ArtistAnimation(fig, artists, interval= 500 , repeat= False , blit= False );
display(HTML(anim.to_jshtml()))
Markdown(r"Perceptron converges to $$\mathbf {w} =\begin {pmatrix}%.2f \\ %.2f \end {pmatrix} $$ after %i updates." % (w[0 ], w[1 ], n_iter))