-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathperceptron.py
127 lines (92 loc) · 3.9 KB
/
perceptron.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
__author__ = 'ayates'
import numpy as np
import random
import matplotlib.pyplot as plt
from matplotlib import animation
class Perceptron():
def __init__(self, training_set=None, testing_set=None, weights=None):
self.training_set = training_set
self.testing_set = testing_set
fig, ax = plt.subplots()
ax.set_xlim((-1, 1))
ax.set_ylim((-1, 1))
self.fig = fig
self.ax = ax
if weights is None:
self.weights = np.array([[random.uniform(-1, 1), random.uniform(-1, 1), random.uniform(-1, 1)]]).T
else:
self.weights = weights
# points that define the target function
self.point1 = (random.uniform(-1, 1), random.uniform(-1, 1))
self.point2 = (random.uniform(-1, 1), random.uniform(-1, 1))
def target(self, feature):
x, y = feature[1], feature[2]
x1, y1 = self.point1
x2, y2 = self.point2
slope = (y2 - y1) / (x2 - x1)
# simple check to see if point (x, y) is above or below the line
return 1 if y > (slope * (x - x1) + y1) else -1
def hypothesis(self, feature):
return np.sign(np.dot(feature, self.weights))
def test(self):
mismatches = 0
for feature in self.testing_set:
if self.hypothesis(feature) != self.target(feature):
mismatches += 1
return mismatches / float(len(self.testing_set))
def graph(self):
xs = np.array([i[1] for i in self.training_set])
ys = np.array([i[2] for i in self.training_set])
# Graph target function
x1, y1 = self.point1
x2, y2 = self.point2
slope = (y2 - y1) / (x2 - x1)
self.ax.plot([-1, 1], slope * (np.array([-1, 1]) - x1) + y1, "g")
# Graph the testing set as a scatterplot
self.ax.scatter(xs, ys)
def animate(self):
line, = self.ax.plot([], [], lw=2)
line.set_c("r")
self.test_data = True # Flag for printing test error, after finished animating
def init():
line.set_data([], [])
return line,
'''
Called each frame. Runs one 'step' of the algorithm every frame.
'''
def animate(i):
misclassified = []
# Loops through each point in the training set and finds misclassified points
for feature in self.training_set:
intended = self.target(feature)
if self.hypothesis(feature) != intended:
misclassified += [(feature, intended)]
# pick a random misclassified point
# and adjust the perceptron in its direction
if misclassified:
feature, intended = random.choice(misclassified)
adapt = np.array([feature]).T * intended
self.weights += adapt
else:
# We're done. Print error over test data.
if self.test_data:
print("Error: " + str(np.around(self.test() * 100, decimals=3)) + "%")
self.test_data = False
# Updates line based on updated weights
lineDom = np.linspace(-1, 1)
line.set_data(lineDom, (-self.weights[1] * lineDom - self.weights[0]) / self.weights[2])
return line,
return init, animate
def test_run(data_size, testing_size):
training_size = data_size
training_set = [[1., random.uniform(-1, 1), random.uniform(-1, 1)]
for _ in range(training_size)]
testing_set = [[1., random.uniform(-1, 1), random.uniform(-1, 1)]
for _ in range(testing_size)]
pla = Perceptron(training_set=training_set, testing_set=testing_set)
pla.graph()
init, animate = pla.animate()
anim = animation.FuncAnimation(pla.fig, animate, init_func=init,
frames=100000000000000000, interval=100, blit=True)
plt.show()
test_run(50, 200)