转载自 博客
1.pocket_PLA
上篇讲述了感知机算法(一)
PLA算法只能解决线性可分的问题。对于数据本身不是线性可分的情况,又该如何解决呢?下面,我们就将对PLA进行优化,以解决更一般的线性不可分问题。
首先,我们来看一下线性不可分的例子:
因为数据线性不可分,所以PLA算法会陷入无限循环,这时候需要对PLA进行优化。优化后的PCA的基本做法很简单,就是如果迭代更新后分类错误样本比前一次少,则更新权重系数 w ;没有减少则保持当前权重系数 w 不变。也就是说,可以把条件放松,即不苛求每个点都分类正确,而是容忍有错误点,取错误点的个数最少时的权重系数 w 。通常在有限的迭代次数里,都能保证得到最佳的分类线。
这种算法也被称为「口袋PLA」Pocket PLA。怎么理解呢?就好像我们在搜寻最佳分类直线的时候,随机选择错误点修正,修正后的直线放在口袋里,暂时作为最佳分类线。然后如果还有错误点,继续随机选择某个错误点修正,修正后的直线与口袋里的分类线比较,把分类错误点较少的分类线放入口袋。一直到迭代次数结束,这时候放在口袋里的一定是最佳分类线,虽然可能还有错误点存在,但已经是最少的了。
2.算法实现
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
if __name__=='__main__':
data=pd.read_csv('./MachineLearningInAction-master/Perceptron Linear Algorithm/data/data2.csv',header=None)
x=data.iloc[:,:2].values
y=data.iloc[:,2].values
#显示原始数据
plt.scatter(x[:50,0],x[:50,1],color='blue',marker='o',label='positive')
plt.scatter(x[50:,0],x[50:,1],color='red',marker='+',label='negative')
plt.xlabel('feature1')
plt.ylabel('feature2')
plt.title('original data')
plt.legend(loc='upper left')
plt.show()
#归一化
u=np.mean(x,axis=0)
v=np.std(x,axis=0)
X=(x-u)/v
#增加一列,加上偏置
X=np.hstack((X,np.ones((X.shape[0],1))))
#随机初始化
w=np.random.randn(3,1)
x1=-2
y1=(-w[2]-w[1]*x1)/w[1]
x2=2
y2=(-w[2]-w[1]*x2)/w[1]
plt.scatter(X[:50, 0], X[:50, 1], color='blue', marker='o', label='Positive')
plt.scatter(X[50:, 0], X[50:, 1], color='red', marker='x', label='Negative')
plt.plot((x1,y1),(x2,y2),color='pink')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend(loc = 'upper left')
plt.title('Normalization data')
plt.show()
num_best=100
for i in range(1000):
y_pre1=np.dot(X,w)
y_pre2=np.ones_like(y)
y_pre2[np.where(y_pre1<0)[0]]=-1
num_fault=len(np.where(y_pre2!=y)[0])
if num_fault==0:
break
if i==0:
w_best=w
num_best=num_fault
else:
if num_fault<num_best:# 新的权重对应的直线对点分类错误更少,则更新权重
w_best=w
num_best=num_fault
print('第%2d次循环,更新,分类错误的点个数:%2d' % (i, num_fault))
x1 = -2
y1 = -1 / w_best[1] * (w_best[2] * 1 + w_best[0] * x1)
# 直线第二个坐标(x2,y2)
x2 = 2
y2 = -1 / w_best[1] * (w_best[2] * 1 + w_best[0] * x2)
# 作图
plt.scatter(X[:50, 0], X[:50, 1], color='blue', marker='o', label='Positive')
plt.scatter(X[50:, 0], X[50:, 1], color='red', marker='x', label='Negative')
plt.plot([x1,x2], [y1,y2],'r')
plt.xlabel('Feature 1')
plt.ylabel('Feature 2')
plt.legend(loc = 'upper left')
plt.show()
time.sleep(2)
r=np.random.choice(num_fault)#每次随机选择错误分类的点
t=np.where(y_pre2!=y)[0][r]
w+=y[t]*X[t,:].reshape((3,1))
3.优点分析
1.wt是随机的,可能算了很多次都没有找出一个更好的。
2.假设数据一开始就是线性可分,那么这个算法找出来的未必是最好解,且时间花费也可能比较大。
4.运行过程图
可以看到,经过一定次数的循环,可以找到较好的分类直线