import numpy as np
import pandas as pd
import seaborn as sns
from matplotlib import pyplot as plt
from sklearn.datasets import make_blobs
Implementing the Perceptron Algorithm
The following blog post will implement the perceptron algorithm using numerical programming to demonstrate its use on a variety of data sets.
To view the source code containing the perceptron algorithm itself, pelase follow this link: https://github.com/madgallop/madgallop.github.io/blob/main/posts/perceptron_blog/perceptron.py
Introduction
First of all, what is the perceptron algorithm?
The source code containing my implementation of the perceptron algorithm can be found here: https://github.com/madgallop/madgallop.github.io/blob/main/posts/perceptron_blog/perceptron.py
This source code contains three primary functions: fit, predict, and score. Fit is the primary method of the perceptron, and is the one that actually performs the update. This function initializes a random initial weight vector and then until convergence, picks a random index, and updates the algorithm. Predict and score compare the labels predicted by the update with the true labels provided, and calculate the algorithm’s accuracy at each time stamp.
This blog post exemplifies the perceptron algorithm using three different examples: linearly seperable data in 2 dimensions, non-linearly seperable data in 2 dimensions, and data in 5 dimensions.
Before beginning, import all necessary packages
Experiment one: lineraly seperable 2D data.
In this example, the perceptron algorithm converges, indicating that the data set is linearly seperable and can be divided well by a certain line.
Visualizing the data
12345)
np.random.seed(
= 100
n = 3
p_features
= make_blobs(n_samples = 100, n_features = p_features - 1, centers = [(-1.7, -1.7), (1.7, 1.7)])
X, y
= plt.scatter(X[:,0], X[:,1], c = y)
fig = plt.xlabel("Feature 1")
xlab = plt.ylabel("Feature 2")
ylab = plt.title("Seperable Data in 2D") title
Create an instance of Perceptron from source code and fit it to the data
from perceptron import Perceptron #import class from .py file
#create an instance of the class and fit it to data.
= Perceptron()
p = 1000)
p.fit(X, y, max_steps
p.wprint("Accuracy of the last 10 timestamps of the perceptron:")
print(p.history[-10:]) #just the last few values
Accuracy of the last 10 timestamps of the perceptron:
[0.99, 0.99, 0.99, 0.99, 0.99, 0.99, 0.99, 0.99, 0.99, 1.0]
Visualizing Accuracy over time
= plt.plot(p.history)
fig = plt.xlabel("Iteration")
xlab = plt.ylabel("Accuracy")
ylab = plt.title("Accuracy Over Time") title
Visualizing the separating line
def draw_line(w, x_min, x_max):
= np.linspace(x_min, x_max, 101)
x = -(w[0]*x + w[2])/w[1]
y = "black")
plt.plot(x, y, color
= plt.scatter(X[:,0], X[:,1], c = y)
fig = draw_line(p.w, -2, 2)
fig
= plt.xlabel("Feature 1")
xlab = plt.ylabel("Feature 2")
ylab = plt.title("Perceptron on Seperable Data") title
Ensure that the final accuracy is 1 for converging perceptron
p.score(X, y)
1.0
Experiment two: not lineraly seperable 2D data
In this example, the perceptron algorithm will not converge or settle on a final value, but will run until the specified maximum number of iterations is reached. In this example, the algorithm will not reach perfect accuracy.
Visualizing the data
= make_blobs(n_samples = 100, n_features = p_features - 1, centers = [(-1.7, -1.7), (-1.7, -1.7)])
X2, y2
= plt.scatter(X2[:,0], X2[:,1], c = y2)
fig2 = plt.xlabel("Feature 1")
xlab2 = plt.ylabel("Feature 2")
ylab2 = plt.title("Non-Seperable Data in 2D") title
Create a new instance of Perceptron and fit to data
from perceptron import Perceptron
#create an instance of the class and fit it to data.
= Perceptron()
p2 = 1000)
p2.fit(X2, y2, max_steps
p2.wprint("Accuracy of the last 10 timestamps of the perceptron:")
print(p2.history[-10:])
Accuracy of the last 10 timestamps of the perceptron:
[0.58, 0.58, 0.5, 0.5, 0.48, 0.48, 0.5, 0.49, 0.49, 0.47]
Visualize how the accuracy changes over time
#visualize how the score evolved over time
= plt.plot(p2.history)
fig = plt.xlabel("Iteration")
xlab = plt.ylabel("Accuracy")
ylab = plt.title("Accuracy Over Time") title
Visualizing the separator in the final iteration
#visualize the line that the algorithm finds to separate the data
= plt.scatter(X2[:,0], X2[:,1], c = y2)
fig = draw_line(p2.w, -2, 2)
fig
= plt.xlabel("Feature 1")
xlab = plt.ylabel("Feature 2")
ylab = plt.title("Perceptron on Non-Seperable Data") title
Here, the seperating line is far from perfect. The line simply falls on whichever point was selected in the final iteration of the algorithm.
Experiment three: perceptron in multiple dimensions
In this experiment, the algorithm will run on 5 features and then evaluate whether or not the data is linearly separable.
= 6
p_features3
= make_blobs(n_samples = 100, n_features = p_features3 - 1, centers = [(-1.7,-1.7), (1.7,1.7)]) X3, y3
Create new instance of Perceptron and fit to data
from perceptron import Perceptron
#create an instance of the class and fit it to data.
= Perceptron()
p3 = 1000)
p3.fit(X3, y3, max_steps
p3.wprint(p3.history[-10:]) #just the last few values
[0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 0.94, 1.0]
Visualize how the accuracy changes over time
#visualize how the score evolved over time
= plt.plot(p3.history)
fig = plt.xlabel("Iteration")
xlab = plt.ylabel("Accuracy")
ylab = plt.title("Accuracy Over Time") title
In this example, the perceptron converges and does so realtively quickly. The data originates from the data in Example 1, which was linearly seperable in 2 dimensions. Given that, the data should still be seperable in 5.
Runtime
The runtime complexity of the perceptron algorithm is dependent on the number of features p the data has, but not with the number of points n for a single iteration of the perceptron algorithm.