Perceptron Classifier / CSC 578D / Fall 2018

Notes:

  1. Dataset can be found here.
  2. See notes by hand here.

Author: Andreas P. Koenzen akoenzen@uvic.ca
Version: 0.1

In [53]:
%matplotlib inline

import pandas as pd
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.animation as ani

from mpl_toolkits import mplot3d

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

from IPython.display import HTML

mpl.rcParams['animation.embed_limit'] = 100

Bankruptcy example:

  • L = is the number of late payments on credit cards over the past year.
  • R = is the ratio of earnings to expenses (earnings : expenses).
  • Bankrupt = -1 is NO / 1 is YES.
In [2]:
data = pd.read_csv("http://www.apkc.net/data/csc_578d/perceptron_1.csv")
data
Out[2]:
L R Bankupt
0 3 0.2 -1
1 1 0.3 -1
2 4 0.5 -1
3 2 0.7 -1
4 0 1.0 -1
5 1 1.2 -1
6 1 1.7 -1
7 6 0.2 1
8 7 0.3 1
9 6 0.7 1
10 3 1.1 1
11 2 1.5 1
12 4 1.7 1
13 2 1.9 1

Plot the data:

In [93]:
_, ax = plt.subplots(figsize=(8, 4))
data.plot.scatter(x=1, 
                  y=0, 
                  c=2, 
                  colormap='jet', 
                  ax=ax)
_ = ax.set_xlabel('Earning:Expenses', fontsize=14)
_ = ax.set_ylabel('Late Payments', fontsize=14)
_ = plt.title('# of Late Payments on CC vs. Earning:Expenses', fontsize=14)
plt.show();

Compute the weights of the line:

Do N iterations and test the classifier.

In [63]:
iterations = 200
eta = 0.01
debug = False
w = np.array([[1.0, 1.0, 1.0]])
plot_data = []

for k in range(iterations):
    # create vector x: should be feature #2, feature #1, y-intercept or feature #0
    # 1. add the feature #0 to the X vector
    w0 = np.ones((len(data.index), 1), dtype=float)
    x = np.hstack([data.values[:,:2], w0])
    if debug:
        if k + 1 == iterations:
            x

    # 2. create the y vector. the class vector and compute its transpose
    y = np.array([[-1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 1, 1, 1]])
    y = y.T
    if debug:
        if k + 1 == iterations:
            y

    # 4. compute the dot product of x.w
    # x @ w.T

    # 5. multiply by y
    # y * (x @ w.T)

    # 6. nudge vector w
    # select instances that evaluate to True (Wrongly classified) and add them 
    # to a new array. the line: ((y * (x @ w.T)) < 0).reshape(x.shape[0]) 
    # creates a 1D array of boolean values which is used as row evaluation 
    # subscript in x. only rows that evaluate to TRUE will be added to the xx array.
    xx = x[((y * (x @ w.T)) < 0).reshape(x.shape[0]), :]
    yy = y[((y * (x @ w.T)) < 0).reshape(x.shape[0]), :]
    # debug
    if debug:
        if k + 1 == iterations:
            ((y * (x @ w.T)) < 0)
            xx
            yy
        
    z = np.sum(yy * xx, axis=0, keepdims=True)
    if debug:
        if k + 1 == iterations:
            z
    
    if debug:
        if k + 1 == iterations:
            nyx = ((yy * xx) * eta)
            nyx
    
    w = w + (z * eta)
    if debug:
        if k + 1 == iterations:
            w
            
    # 7. Append to plot data.
    plot_data.append(w)

# w

Animate the weight vector:

In [92]:
fig1, ax1 = plt.subplots(figsize=(8, 4))
_ = ax1.set_xlabel('Earning:Expenses', fontsize=14)
_ = ax1.set_ylabel('Late Payments', fontsize=14)
_ = plt.title('# of Late Payments on CC vs. Earning:Expenses', fontsize=14)
_ = ax1.scatter(x=data.values[:,1:2],
                y=data.values[:,0:1], 
                c=data.values[:,2:], 
                cmap='jet')
line, = ax1.plot([], [], c= "red")

def init():
    line.set_data([], [])
    return line,

def animate(i, ax):
    ax.legend(["Iteration {}".format(i + 1)])
    
    w2 = np.asscalar(plot_data[i][0][0])
    w1 = np.asscalar(plot_data[i][0][1])
    w0 = np.asscalar(plot_data[i][0][2])
        
    x = np.linspace(0.0, 2.0, num=10)
    y = [((-(w1 * k) - (w0)) / w2) for k in x]
    line.set_data(x, y)
    
    return line,

anim = ani.FuncAnimation(fig1,
                         animate,
                         init_func=init,
                         frames=iterations, 
                         fargs=(ax1,))
plt.close()
HTML(anim.to_jshtml())

# FOR 3D PLOTTING, WHICH IN THIS CASE DOESN'T MAKE MUCH SENSE.
# fig1 = plt.figure(figsize=(12, 8))
# ax1 = fig1.gca(projection='3d')

# _ = ax1.view_init(azim = 180 - 80, elev = 15)
# _ = ax1.set(xlabel='R', ylabel='L', zlabel='y')
# _ = ax1.labelsize = 18
# _ = ax1.labelweight = 'heavy'
# _ = plt.title('# of Late Payments on CC vs. Earning:Expenses', fontsize=20)

# _ = ax1.scatter3D(xs=data.values[:,1:2],
#                   ys=data.values[:,0:1],
#                   zs=data.values[:,2:],
#                   c=data.values[:,2:].ravel(),
#                   cmap='jet')
# line, = ax1.plot3D([], [], [], c= "red")

# def init():
#     line.set_data([], [])
#     line.set_3d_properties([])
#     return line,

# def animate(i, ax):
#     ax.legend(["Iteration {}".format(i + 1)])
#     
#     w2 = np.asscalar(plot_data[i][0][0])
#     w1 = np.asscalar(plot_data[i][0][1])
#     w0 = np.asscalar(plot_data[i][0][2])
#        
#     x = np.linspace(0.0, 2.0, num=10)
#     y = [((-(w1 * k) - (w0)) / w2) for k in x]
#     line.set_data(x, y)
    
#     z = np.linspace(-1.0, 1.0, num=10)
#     line.set_3d_properties(z)
    
#     return line,

# anim = ani.FuncAnimation(fig1,
#                          animate,
#                          init_func=init,
#                          frames=iterations, 
#                          fargs=(ax1,))
# plt.close()
# HTML(anim.to_jshtml())
Out[92]:


Once Loop Reflect