对于给定的一个数据集$T={(x_1,y_1),(x_2,y_2),…(x_n,y_n)}$,其中,$x_i \in X \subseteq R^n , y \in Y={-1, +1}, i=1,2,…,N$,如果存在某个超平面$S: w \cdot x+b = 0$,能将正负样例分到$S$两侧,则说明数据集$T$是线性可分的,那么接下来就是要求这个超平面$S$的表达式。
损失函数
数据集$T$中任意一个误分类点到这个超平面$S$的距离之和为: $$\frac{1}{\Vert w \Vert}\sum_{x_i \in M}{\vert w \cdot x_i+b \vert}$$ 其中$M$为误分类点的集合。如何去掉绝对值呢?我们注意到$y_i$的取值是有好处的。对于误分类点来说$y_i$的符号和$w \cdot x_i+b$相反。且$y_i$取值+1,-1。则我们可以将上式转换成: $$- \frac{1}{\Vert w \Vert}\sum_{x_i \in M}{y_i (w \cdot x_i+b)}$$ 确定损失函数时,不考虑$\frac{1}{\Vert w \Vert}$。
Q:感知机损失函数确定过程中的系数$\frac{1}{\Vert w \Vert}$,为什么可以忽略?
1)感知机的损失函数时基于误分类的,$L2$范数项不会影响$y_i (w \cdot x_i+b)$的正负判断,所以$\frac{1}{\Vert w \Vert}$对感知机学习算法的中间过程可有可无
2)$\frac{1}{\Vert w \Vert}$不影响感知机学习算法的最终结果,当所有输入被正确分类时,不存在误分类的点,此时损失函数为零,缺少此项并不会影响感知机损失函数的收敛
3)我思考的是即使缺少这个项,损失函数也能对线性可分数据在有限次学习后正确分开。李航书上有证明。
4)权重$w$是一个向量,$\frac{1}{\Vert w \Vert}$的大小不会影响向量的方向,确定超平面是通过确定法向量$w$和截距$b$来确定的,而的大对权重$w$的方向没有任何影响,所以可以固定$\frac{1}{\Vert w \Vert}$|为1或者不考虑。
算法步骤
输入:训练数据$T={(x_1,y_1),(x_2,y_2),…(x_n,y_n)}$,其中,$x_i \in X \subseteq R^n , y \in Y={-1, +1}, i=1,2,…,N$,;学习率$\eta(0<\eta<=1)$; 输出:$w,b$;感知机模型$f(x)=sign(w \cdot x+b)$。
xArr = np.array([x[0] for x in datas]) yArr = np.array([x[1] for x in datas]) xPlotx,xPlotx_,xPloty,xPloty_ = [],[],[],[] for i in range(len(datas)): y = yArr[i] if y>0: xPlotx.append(xArr[i][0]) xPloty.append(xArr[i][1]) else: xPlotx_.append(xArr[i][0]) xPloty_.append(xArr[i][1]) plt.title('Perception 输入数据') plt.grid(True) pPlot1,pPlot2 = plt.plot(xPlotx,xPloty,'b+',xPlotx_,xPloty_,'rx') plt.legend(handles = [pPlot1,pPlot2],labels=['Positive Sample','Negtive Sample'],loc='upper center') plt.show()
#感知机算法 w = np.array([1, 1]) b = 3 eta = 0.5 whileTrue: num = 0 for i in range(len(datas)): num = num + 1 x = xArr[i] y = yArr[i] z = y*(np.dot(w,x)+b) if z <= 0: w = w+eta*y*x b = b+eta*y num = 0# 只要更新一次,强制令num=0,否则到最后一个数据不满足条件更新后,会直接跳出,而此时并不满足条件。 break if num >= len(datas): break fig = plt.figure('Output Figure') plt.title('Perception 输出平面') x0 =np.linspace(0,5,100) w0 = w[0] w1 = w[1] x1 = -(w0/w1)*x0-b/w1 plt.xlabel('x0',fontsize=15) plt.ylabel('x1',fontsize=15) plt.plot(x0,x1,'k', lw=1) pPlot1,pPlot2 = plt.plot(xPlotx,xPloty,'b+',xPlotx_,xPloty_,'rx') plt.legend(handles = [pPlot1,pPlot2],labels=['Positive Sample','Negtive Sample'],loc='upper right') plt.annotate('Output Hyperplane',xy=(2.0,3.0),xytext=(1.7,3.5)) # 图形注释 # xy设置箭头尖的坐标,xytext设置注释内容显示的起始位置