1感知机学习算法原理
1.1算法应用背景
假设训练数据集是线性可分的,感知机学习其实可以算是一个二分类问题,因为其输出Y的取值只能在1,-1之间取得,所以感知机的目标就是找到完全正确将训练集分为正实例以及负实例的超平面S,可以表示为
所以我们的目标就是通过不断迭代找到w,b直至完全正确分类。
1.2算法数学原理
为了衡量一个超平面对于训练集分类的正确程度,引入损失函数来表示学习效果的好与坏。可以选择所有误分类点到超平面的距离和作为损失函数。首先写出输入空间中任意一点到超平面S的距离是
其中称为w的L2范数。对于误分类的点有,并且为一常数,则损失函数可以写为如下形式:
M为所有误分类点的集合。则感知机学习算法就可以看成求解损失函数最小化的最优化问题,最优化的方法采用随机梯度下降法,大致可以分为如下两个步骤
1.随机选取一个误分类点使其梯度下降,则的梯度由
表示
2.对w,b进行更新
其中为学习率,这样经过不断迭代就能使损失函数不断减小,直到为0。
2感知机学习算法python实现
2.1 问题描述
问题来源于李航《统计学习方法》中的例题。有一训练数据集,其正实例点是,,负实例点是,使用感知机学习算法的原始形式求感知机模型。这里。本文使用python来实现。
2.2数据导入
在python中导入numpy,用数组的形式将数据导入,方便后续处理
def loadData():
data=np.array([[3,3],[4,3],[1,1]]) #导入数据
labels=np.array([1,1,-1]) #导入标签
x0=np.ones((1,len(labels))) #bias偏置
data=np.insert(data,0,values=x0,axis=1) #按列插入1,作为偏置
return data,labels
其中把偏置b认为是特殊的特征,取,可得,则后续b的更新可以合并入w一起更新,简化了代码。通过以上操作,最终得到的data为3×3的矩阵
[[1 3 3]
[1 4 3]
[1 1 1]]
2.3初始化
新建一个类并命名为PLA,对其进行初始化代码如下
class PLA:
def __init__(self,data,labels,a=1): #初始化
self.data=data #实例的数据
self.labels=labels #实例的标签
self.a=a #a为学习率
self.w=np.zeros((data.shape[1],1)) #初始权重为0
self.numdata=data.shape[0] #样本数
self.numfeatures=data.shape[1] #特征数
其中所有的权重初始化为0,学习率a初始化为1,将偏置b看作特殊的特征,故此处numfeatures应该为3而不是2。
2.4写sign函数
通过判断的符号即可说明某样本点是否是误分类点,所以需要自行写一个sign函数来判断符号,代码如下
def sign(self,data_i,labels_i):
tmp=int(np.dot(data_i,self.w))*labels_i #以yi*(w*xi+b)的符号来判别是否正确分类
if tmp>0:
return 1
else:
return -1
其中np.dot用于两个矩阵进行点乘操作。
2.5更新参数
运用梯度下降法更新参数,由于上文将偏置b看作特殊的特征,故此处b和w的更新公式便统一成了一个,代码如下
def update(self,data_i,labels_i):
self.w=self.w+(self.a*labels_i*data_i).reshape(self.w.shape)
2.6 训练模型
将样本点代入模型进行迭代运算,直至不再出现误分类点,即感知机模型训练完成。
def trainPLA(self):
bMisClassify=True
while bMisClassify:
mMisClassifyNum=0
for i in range(self.numdata):
if self.sign(self.data[i,:],self.labels[i])==-1:
mMisClassifyNum+=1
self.update(self.data[i,:],self.labels[i])
if mMisClassifyNum==0:
bMisClassify=False
print('The PLA Training has finished! The w is :\n',self.w)
return self.w
最后输出的应该是一个3×1的权重矩阵w。
2.7可视化
在python中导入matplotlib.pyplot来进行模型可视化,新建一个Plot类专门用于画图。
class Plot:
def __init__(self,x,y,w):
self.w=w
plt.figure(1)
plt.title('Perceptron Learning Algorithm')
plt.xlabel('X0')
plt.ylabel('X1')
xdata=np.arange(0,7) #x轴范围
ydata=-(w[0][0]+w[1][0]*xdata)/w[2][0]
plt.plot(xdata,ydata,c='r')
for i in range(len(y)):
if y[i]==1:
plt.scatter(x[i,1],x[i,2],c='g',marker='o')
else:
plt.scatter(x[i,1],x[i,2],c='b',marker='x')
plt.savefig('Blog1.png')
plt.show()
其中w[0][0]就是b,所以在此题中超平面S的形式应为,故。
2.8整体代码
添加主程序后,整体代码如下
import numpy as np
import matplotlib.pyplot as plt
def loadData():
data=np.array([[3,3],[4,3],[1,1]]) #导入数据
labels=np.array([1,1,-1]) #导入标签
x0=np.ones((1,len(labels))) #bias偏置
data=np.insert(data,0,values=x0,axis=1) #按列插入1,作为偏置
return data,labels
class PLA:
def __init__(self,data,labels,a=1): #初始化
self.data=data #实例的数据
self.labels=labels #实例的标签
self.a=a #a为学习率
self.w=np.zeros((data.shape[1],1)) #初始权重为0
self.numdata=data.shape[0] #样本数
self.numfeatures=data.shape[1] #特征数
def sign(self,data_i,labels_i):
tmp=int(np.dot(data_i,self.w))*labels_i #以yi*(w*xi+b)的符号来判别是否正确分类
if tmp>0:
return 1
else:
return -1
def update(self,data_i,labels_i):
self.w=self.w+(self.a*labels_i*data_i).reshape(self.w.shape)
def trainPLA(self):
bMisClassify=True
while bMisClassify:
mMisClassifyNum=0
for i in range(self.numdata):
if self.sign(self.data[i,:],self.labels[i])==-1:
mMisClassifyNum+=1
self.update(self.data[i,:],self.labels[i])
if mMisClassifyNum==0:
bMisClassify=False
print('The PLA Training has finished! The w is :\n',self.w)
return self.w
class Plot:
def __init__(self,x,y,w):
self.w=w
plt.figure(1)
plt.title('Perceptron Learning Algorithm')
plt.xlabel('X0')
plt.ylabel('X1')
xdata=np.arange(0,7) #x轴范围
ydata=-(w[0][0]+w[1][0]*xdata)/w[2][0]
plt.plot(xdata,ydata,c='r')
for i in range(len(y)):
if y[i]==1:
plt.scatter(x[i,1],x[i,2],c='g',marker='o')
else:
plt.scatter(x[i,1],x[i,2],c='b',marker='x')
plt.savefig('Blog1.png')
plt.show()
if __name__=='__main__':
data,labels=loadData()
print(data)
myPLA=PLA(data,labels)
weights=myPLA.trainPLA()
Plot(data,labels,weights)
运行之后输出权重矩阵w为
The PLA Training has finished! The w is :
[[-3.]
[ 1.]
[ 1.]]
绘制出的分离超平面如下图
可见与书中所得结果一致,成功将正负实例点进行了分离,具体迭代过程见书中下表。
3 学习心得
大四终于有时间系统学习机器学习,翻了几页西瓜书,感觉其中涉及的推导过于简洁,实在令人高山仰止。求助网友后开始学习李航老师的《统计学习方法》,发现其中无论是概念还是推导都十分地详尽,不知不觉就学习完了一章,手推完公式后便赶紧用python将例题复现一遍以加深记忆。第一次写博客,就当是在学习机器学习过程中随手记录下来的笔记,有不正当之处恳请各位包容并指出。研路漫漫,唯学习不可懈怠,与诸君共勉!