1.PLA算法
作为机器学习的入门基础算法,主要是要理解其产生由来。感知机模型为了应对线性可分二分类问题而设计的算法,求得一个超平面S使得所有数据能正确分类。
即使得每个数据都
f
(
x
)
=
s
i
g
n
(
w
⋅
x
+
b
)
f(x)=sign(w\cdot x+b)
f(x)=sign(w⋅x+b)
然而这个数学问题无法优化,因此转化为求错误分类的代价函数的最小值
m
i
n
L
(
w
)
=
∑
x
i
=
M
k
−
y
i
(
w
⋅
x
i
+
b
)
minL(w) =\sum_{x_i=M}^{k} -y_i(w\cdot x_i+b)
minL(w)=xi=M∑k−yi(w⋅xi+b)
其中有两个注意的点:
- (xi,yi)是分类错误的点,也就是说其本质是有错误点驱动的优化函数,对于可线性分类数据总存在一个超平面S使得L(w)为0,对于无法线性可分数据也能找出分类错误最少的超平面
- 有高数知识可知,要求的函数最小值即在其梯度方向寻找,损失函数L(w)关于w求导可知其导数为
m
i
n
L
(
w
)
′
=
∑
x
i
=
M
k
−
y
i
x
i
minL(w)' =\sum_{x_i=M}^{k} -y_i x_i
minL(w)′=xi=M∑k−yixi
即每次w更新应在梯度方向上更新为 w i + 1 = w i + y i ⋅ x i ( 旋 转 ) w_{i+1}=w_i+y_i\cdot x_i(旋转) wi+1=wi+yi⋅xi(旋转)
b i + 1 = b i + y i ( 平 移 ) b_{i+1}=b_i+y_i(平移) bi+1=bi+yi(平移)
2.收敛性
关于收敛性的证明过程如下:
对上面证明过程进行补充:
3.算法实现
以numpy生成两类正态数据,再对其标记,最后使用PLA算法进行分类,并用matplotlib显示分类效果
from matplotlib import pyplot as plt
import numpy as np
#生成训练数据
def generate_data(u1,o1,u2,o2,n,m):
#此产生两组正态分布数据(产出为元组数据)
t1=np.random.normal(u1,o1,size=(n,2))
t2=np.random.normal(u2,o2,size=(m,2))
a_x=np.array(t1)
b_x=np.array(t2)
#给两组正态数据打标签
a_y=np.ones(n)
b_y=np.negative(np.ones(m))
class1=np.c_[a_x,a_y]
class2=np.c_[b_x,b_y]
return class1,class2
#pla算法实现
def pla():
w=np.zeros(3)#初始化w0
n=50#正类数据量
m=50#负类数据量
c1,c2=generate_data(2,1,-2,1,n,m)
test=np.vstack((c1,c2))#合并两类数据,将c1类与c2类合并为同一二维矩阵
x0=np.ones(m+n)
test=np.c_[x0,test]#插入列向量x0=[1,1,...,1],实现w=[b,w1,w2] * x[1,x1,x2]
cnt=0
while True:
cnt+=1
if cnt>1000:
print('非线性可分数据')
break
success=True
for i in range(len(test)):
x=np.array(test[i][:-1])
y=np.dot(x,w)
if np.sign(y)==np.sign(test[i][-1]):
continue
w=w+test[i][-1]*x #更新w值
success = False
break
if success==True:
break
#绘制分类前效果
plt.scatter(c1[:, 0], c1[:, 1], c='r', marker='o') # 正类正态分布
plt.scatter(c2[:, 0], c2[:, 1], c='b', marker='x') # 负类正态分布
plt.show()
#绘制分类后效果
x=np.linspace(min(test[:,1])-1,max(test[:,2])+1,50)
y=-w[1]/w[2]*x-w[0]/w[2] #见下文数学推导
plt.plot(x,y,c='g')#超平面
plt.scatter(c1[:, 0], c1[:, 1], c='r',marker='o') # 正类正态分布
plt.scatter(c2[:, 0], c2[:, 1], c='b',marker='x') # 负类正态分布
plt.show()
return cnt,w
if __name__=='__main__':
cnt,w=pla()
print("迭代次数:",cnt)
print("超平面法向量:",w)
其中由法向量推超平面直线推导:
已知超平面为
W
⋅
X
=
0
{\rm W\cdot X=0}
W⋅X=0,其中
X
{\rm X}
X为二维向量,即x,y轴
W
⋅
X
=
W
⋅
(
x
,
y
)
=
(
b
,
w
1
,
w
2
)
⋅
(
1
,
x
,
y
)
=
b
+
w
1
x
+
w
2
y
=
0
{\rm W\cdot X= W\cdot(x,y)=(b,w_1,w_2)\cdot(1,x,y)=b+w_1x+w_2y=0}
W⋅X=W⋅(x,y)=(b,w1,w2)⋅(1,x,y)=b+w1x+w2y=0,则直线表达式为:
y
=
−
w
1
w
2
x
−
b
w
2
{y=-\frac{w_1}{w_2}x-\frac{b}{w_2}}
y=−w2w1x−w2b
注:
b
{b}
b为代码中的w[0],
x
{x}
x为test的第二列,
y
{y}
y为tes的第三列
4.分类效果展示
其算法分类效果如下:
分类前:
分类后: