根据《统计学习方法》第2章,用python实现感知机。
import numpy as np
import matplotlib.pyplot as plt
class Perceptron:
def __init__(self, dim):
""" 初始化权重 w b 以及x特征的维度dim"""
self.w = np.random.random((dim,))
self.b = np.random.rand()
self.dim = dim
def f(self, x):
""" w * x + b"""
return np.dot(self.w, x.T) + self.b
def gw(self, x, y):
""" w梯度 """
return x * y
def gb(self, y):
""" b梯度"""
return y
def train_2(self, xs, ys, alpha=1, max_step=1000):
"""
学习算法的对偶形式
"""
n = len(xs)
matrix = np.zeros((n,n),dtype=int)
for i in range(n):
for j in range(n):
matrix[i][j] = np.dot(xs[i],xs[j])
print("matrix:", matrix)
a, b = [0]*n, 0
step = 1
error = float("inf")
while error and step < max_step:
print("step: {}, error: {}".format(step, error))
error = 0
for i,(x, y) in enumerate(zip(xs, ys)):
sum_ = b
for j in range(n):
sum_ += a[j]*ys[j]*matrix[j][i]
if y*sum_ <= 0:
a[i] = a[i] + alpha
b += alpha * y
error += 1
step += 1
self.w = sum(a[i]*xs[i]*ys[i] for i in range(n))
self.b = b
if step >= max_step:
print("max_step limit")
else:
print("successfully learn")
print("w: {} b: {}".format(self.w, self.b))
def train(self, xs, ys, alpha=0.1, max_step=1000):
"""
学习算法
:param xs: 输入样本特征
:param ys: 样本分类
:param alpha: 学习率
:param max_step: 最大迭代伦次
:return:
"""
# 输入数据维度要等于指定维度(画图只能是二维)
if xs.shape[1] != self.dim:
raise ValueError("x sample must {} dim".format(self.dim))
# 初始化图
fig = self.figure_init(xs, ys)
error = float("inf")
step = 1
while error and step < max_step:
print("step: {}, error: {}".format(step, error))
error = 0
for x, y in zip(xs, ys):
if self.f(x) * y <= 0:
self.w += alpha * self.gw(x, y)
self.b += alpha * self.gb(y)
self.figure_update(fig) # 更新图
error += 1
step += 1
if step >= max_step:
print("max_step limit")
else:
print("successfully learn")
print("w: {} b: {}".format(self.w, self.b))
# 关闭交互模式
plt.ioff()
# 图形显示
plt.show()
def figure_init(self, xs, ys):
fig = plt.figure(figsize=(8, 6), dpi=80)
ax = fig.add_subplot(1, 1, 1)
# 设定标题等
plt.title("Perceptron")
plt.grid(True)
# 设置X轴
plt.xlabel("x(1)")
plt.xlim(-10, 10)
# 设置Y轴
plt.ylabel("x(2)")
plt.ylim(-10, 10)
# 画点
for x_, y_ in zip(xs, ys):
if y_ == 1:
ax.plot(x_[0], x_[1], "ro")
else:
ax.plot(x_[0], x_[1], "go")
# 生成超平面 w1 * x1 + w2 * x2 + b = 0,随机取两个x1,计算x2连起来
x1 = np.linspace(-10, 10, 2, endpoint=True)
x2 = (- self.b - self.w[0] * x1) / self.w[1]
# 画直线
lines = ax.plot(x1, x2, "b-", linewidth=2.0, label="hyperplane")
# 设置图例位置,loc可以为[upper, lower, left, right, center]
ax.legend(loc="upper left", shadow=True)
# 暂停
plt.pause(0.5)
ax.lines.remove(lines[0])
# 打开交互模式
plt.ion()
return ax
def figure_update(self, ax):
"""
画图程序,每更新一次权重,调用一次
"""
# 生成超平面 w1 * x1 + w2 * x2 + b = 0,随机取两个x1,计算x2连起来
x1 = np.linspace(-10, 10, 2, endpoint=True)
x2 = (- self.b - self.w[0]*x1)/self.w[1]
# 更新直线
lines = ax.plot(x1, x2, "b-", linewidth=2.0, label="hyperplane")
# 暂停
plt.pause(0.5)
# 删掉直线
ax.lines.remove(lines[0])
p = Perceptron(2)
x_data = np.array([[3, 3], [4, 3], [1, 1]])
y_data = np.array([1, 1, -1])
p.train(x_data, y_data)
# p.train_2(x_data, y_data)