一、感知机代码实现
(1)原始感知机代码
import numpy as np
import copy#用于深拷贝 用的到吗?
import operator #支持一些常规操作 C实现 比python快
import os#系统调用
from matplotlib import pyplot as plt
from matplotlib import animation
'''
常规感知机的python3实现
'''
##训练集合
training_set=[[(1,2,),1],[(2,3,),1],[(3,1,),-1],[(4,2,),-1]]
w=[0,0]##参数init
b=0
history = []#记录下w,b
def update(item):
'''
随机梯度下降 (只是用一个样本更新参数 注意批量梯度下降以及梯度下降的区别)
:param item: 当前超平面分类错误点
:return: None
'''
global w,b,history #表示这些变量不是当前方法里的 属于全局变量的
##对w的更新 W <-- W+N*Yi*Xi 是步常
for i in range(len(item[0])):
w[i] +=1*item[1]*item[0][i]
# w[1] +=1*item[1]*item[0][1]
##对b的更新 B <-- B + N*Yi
b+=1*item[1]
history.append([copy.copy(w),b])#添加记录
def cal(item):
'''
Yi*(W * Xi +B)的计算
:param item: 一个样本点
:return: 公式计算的结果
'''
result = 0
for i in range(len(item[0])):#i 第i个特征
result+=item[0][i]*w[i]
result+=b
result*=item[1]#要记得乘以Yi
return result
def chec():
"""
检测是否已完全正确分类
:return: bool True表示有错
"""
flag = False
for item in training_set:
if cal(item)<=0:
flag = True #还有错误 需要更新参数 算法的前提条件是完全可分
if not flag:
print("已经全部正确分类,w:{0} b:{1}".format(w,b))
return flag
if __name__ == '__main__':
i = 0
while chec()==True:
for item in training_set:
if cal(item)<=0:
i+=1
# flag = True #还有错误 需要更新参数 算法的前提条件是完全可分
update(item)
print("迭代第{0}次;w:{1} b:{2}".format(i,w, b))
##可视化部分
# 以下代码是将迭代过程可视化
# 首先建立我们想要做成动画的图像figure, 坐标轴axis,和plot element
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], 'g', lw=2) # 画一条线
label = ax.text([], [], '')
def init():
line.set_data([], [])
x, y, x_, y_ = [], [], [], []
for p in training_set:
if p[1] > 0:
x.append(p[0][0]) # 存放yi=1的点的x1坐标
y.append(p[0][1]) # 存放yi=1的点的x2坐标
else:
x_.append(p[0][0]) # 存放yi=-1的点的x1坐标
y_.append(p[0][1]) # 存放yi=-1的点的x2坐标
plt.plot(x, y, 'bo', x_, y_, 'rx') # 在图里yi=1的点用点表示,yi=-1的点用叉表示
plt.axis([-6, 6, -6, 6]) # 横纵坐标上下限
plt.grid(True) # 显示网格
plt.xlabel('x1') # 这里我修改了原文表示
plt.ylabel('x2') # 为了和原理中表达方式一致,横纵坐标应该是x1,x2
plt.title('Perceptron Algorithm (www.hankcs.com)') # 给图一个标题:感知机算法
return line, label
def animate(i):
global history, ax, line, label
w = history[i][0]
b = history[i][1]
if w[1] == 0: return line, label
# 因为图中坐标上下限为-6~6,所以我们在横坐标为-7和7的两个点之间画一条线就够了,这里代码中的xi,yi其实是原理中的x1,x2
x1 = -7
y1 = -(b + w[0] * x1) / w[1]
x2 = 7
y2 = -(b + w[0] * x2) / w[1]
line.set_data([x1, x2], [y1, y2]) # 设置线的两个点
x1 = 0
y1 = -(b + w[0] * x1) / w[1]
label.set_text(history[i])
label.set_position([x1, y1])
return line, label
print("参数w,b更新过程:", history)
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=len(history), interval=1000, repeat=True,
blit=True)
plt.show()
参考博客:https://blog.csdn.net/Daycym/article/details/81032016
(2)对偶感知机代码
from __future__ import division
import random
import numpy as np
import matplotlib.pyplot as plt
def sign(v):
if v>=0:
return 1
else:
return -1
def train(train_num,train_datas,lr):
'''
:param train_num: 迭代次数
:param train_datas: 训练集
:param lr: 步长
:return:权重w ,b,a:alpha,格拉姆矩阵gram
'''
w=0.0
b=0
datas_len = len(train_datas)#共有多少数据
alpha = [0 for i in range(datas_len)]#全是0 应该是公式中的a
# print(alpha)
train_array = np.array(train_datas)
# print(train_array[:,-1])
# print(train_array[:, 0:-1])
gram = np.matmul(train_array[:,0:-1] , train_array[:,0:-1].T) #train_array[:,0:-1] 取数据 去掉lable
for idx in range(train_num):#开始迭代 一步一步
tmp=0 #存结果
i = random.randint(0,datas_len-1)#随机选一个样本 随机梯度下降的本质
yi=train_array[i,-1]#表示取第i行数据中 倒数第一个值 就是y值
for j in range(datas_len):
## alphaj*yj*xj*xi
tmp+=alpha[j]*train_array[j,-1]*gram[i,j]
tmp+=b
if(yi*tmp<=0):#有错 更新
alpha[i]=alpha[i]+lr
b=b+lr*yi
##计算W
##W= 所有alpha*yj*xj的和
for i in range(datas_len):
w+=alpha[i]*train_array[i,0:-1]*train_array[i,-1]#train_array[i,0:-1] 选的是第i行的最后一元素
# train_array[i,-1]第i行的前两个元素
return w,b,alpha,gram
def plot_points(train_datas,w,b):
plt.figure()
x1 = np.linspace(0, 8, 1000)
x2 = (-b-w[0]*x1)/(w[1]+1e-10)
plt.plot(x1, x2, color='r', label='y1 data')
datas_len=len(train_datas)
for i in range(datas_len):
if(train_datas[i][-1]==1):
plt.scatter(train_datas[i][0],train_datas[i][1],s=50)
else:
plt.scatter(train_datas[i][0],train_datas[i][1],marker='x',s=50)
plt.show()
if __name__=='__main__':
train_data1 = [[1, 3, 1], [2, 2, 1], [3, 8, 1], [2, 6, 1]] # 正样本
train_data2 = [[2, 1, -1], [4, 1, -1], [6, 2, -1], [7, 3, -1]] # 负样本
train_datas = train_data1 + train_data2 # 样本集
# print(train_datas)
w,b,alpha,gram=train(train_num=50,train_datas=train_datas,lr=0.01)
plot_points(train_datas,w,b)
参考博客:https://blog.csdn.net/winter_evening/article/details/70196040