感知机是用于二分类的线性分类模型,目标是求出将实例划分正负的超平面,属于判别式模型。
感知机的形式如下:
f ( x ) = s i g n ( w ⋅ x + b ) f(x)=sign(w\cdot{x}+b) f(x)=sign(w⋅x+b)
其中 w w w称为权值向量, b b b称为偏置, w ⋅ x w\cdot{x} w⋅x表示内积, s i g n sign sign是符号函数,表示:
s i g n ( x ) = { + 1 , x > 0 − 1 , x < 0 sign(x)=\begin{cases} +1, & x>0 \\[2ex] -1, & x<0 \end{cases} sign(x)=⎩⎨⎧+1,−1,x>0x<0
如果存在一个超平面可以将二分类数据集的正负实例完全正确的划分到两边,那么称数据集是线性可分的。
学习策略等价于定义一个损失函数并且将损失函数极小化。感知机的损失函数定义为误分类点到超平面的总距离:
− 1 ∣ ∣ w ∣ ∣ ∑ x i ∈ M y i ( w ⋅ x i + b ) -\frac{1}{||w||}\sum_{x_i\in{M}}y_i(w\cdot{x_i}+b) −∣∣w∣∣1xi∈M∑yi(w⋅xi+b)
由于只考虑分类正误,那么损失函数可以定义为:
L ( x , b ) = − ∑ x i ∈ M y i ( w ⋅ x i + b ) L(x,b)=-\sum_{x_i\in{M}}y_i(w\cdot{x_i}+b) L(x,b)=−xi∈M∑yi(w⋅xi+b)
感知机的学习策略是再假设空间选取使损失函数最小的模型参数 w w w, b b b。
$$
感知机的学习算法的目标是极小化损失函数的解:
min w , b L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x i + b ) \min_{w,b}{L(w,b)}=-\sum_{x_i\in{M}}y_i(w\cdot{x_i}+b) w,bminL(w,b)=−xi∈M∑yi(w⋅xi+b)
感知机的学习算法是误分类驱动的,采用随机梯度下降算法,即每次从误分类的点中选择一个,进行梯度下降。
▽ w L ( w , b ) = − ∑ x i ∈ M y i ⋅ x i \bigtriangledown_{w}L(w,b)=-\sum_{x_i\in{M}}y_i\cdot{x_i} ▽wL(w,b)=−xi∈M∑yi⋅xi
▽ b L ( w , b ) = − ∑ x i ∈ M y i \bigtriangledown_{b}L(w,b)=-\sum_{x_i\in{M}}y_i ▽bL(w,b)=−xi∈M∑yi
从误分类点中随机选取一个,对 w w w, b b b,进行更新:
w ← w + η y i x i w\leftarrow w+\eta{y_ix_i} w←w+ηyixi
b ← b + η y i b\leftarrow b+\eta{y_i} b←b+ηyi
其中 η \eta η是每一步更新的步长也成为学习率。
算法1:原始形式
(1) 选取初值 w 0 w_0 w0 b 0 b_0 b0
(2) 在训练集中选取数据 ( x i , y i ) (x_i,y_i) (xi,yi)
(3) 如果 y i ( w ⋅ x i + b ) ≤ 0 y_i(w\cdot{x_i}+b)\leq0 yi(w⋅xi+b)≤0
w ← w + η y i x i w\leftarrow w+\eta{y_ix_i} w←w+ηyixi
b ← b + η y i b\leftarrow b+\eta{y_i} b←b+ηyi
(4) 转至(2),直到训练集中没有误分类点
当一个实例点被误分类的时候,调整 w w w和 b b b的值,使超平面向误分类点一边移动,以减小误分类点和超平面的距离,直到超平面越过误分类点使其被正确分类。感知机算法由于采用了不同的初值,解可以有不同的结果。
Novikoff定理
表明误分类的次数是有上界的,通过有限次的搜索可以找到分开的超平面,当训练集线性不可分时,感知机算法不收敛。
对偶形式的基本思路是:将 w w w和 b b b表示为实例 x i x_i xi和标记 y i y_i yi的线性组合的形式,通过求解其系数求 w w w和 b b b.当 w w w和 b b b初始值被设置为0的时候,可以得到最后学习的 w w w和 b b b分别是:
w = ∑ i = 1 N α i y i x i w=\sum_{i=1}^N\alpha_iy_ix_i w=i=1∑Nαiyixi
b = ∑ i = 1 N α i y i b=\sum_{i=1}^N\alpha_iy_i b=i=1∑Nαiyi
其中 α i = n i η \alpha_i=n_i\eta αi=niη,当 η = 1 \eta=1 η=1,表示第 i i i个实例点由于误分类而进行更新的次数,实例点更新的越多,表示误分类的次数越多,表示距离超平面越近,越难正确分类。
算法2:对偶形式
感知机模型变成 f ( x ) = s i g n ( ∑ j = 1 N α j y j x j ⋅ x + b ) f(x)=sign(\sum_{j=1}^N\alpha_jy_jx_j\cdot{x}+b) f(x)=sign(∑j=1Nαjyjxj⋅x+b)
可以先把训练实例以Gram矩阵存起来。和原始形式一样,感知机的对偶形式迭代也是收敛的,且存在多个解。
import numpy as np
class Perceptron(object):
"""Perceptron classifier.
Parameters
------------
eta:float,Learning rate (between 0.0 and 1.0)
n_iter:int,Passes over the training dataset.
Attributes
-------------
w_: 1d-array,Weights after fitting.
errors_: list,Numebr of misclassifications in every epoch.
"""
def __init__(self,eta=0.01,n_iter=10):
self.eta = eta
self.n_iter = n_iter
def fit(self,X,y):
"""Fit training data.先对权重参数初始化,然后对训练集中每一个样本循环,根据感知机算法学习规则对权重进行更新
Parameters
------------
X: {array-like}, shape=[n_samples, n_features]
Training vectors, where n_samples is the number of samples and n_featuers is the number of features.
y: array-like, shape=[n_smaples]
Target values.
Returns
----------
self: object
"""
self.w_ = np.zeros(1 + X.shape[1]) # add w_0 #初始化权重。数据集特征维数+1。
self.errors_ = []#用于记录每一轮中误分类的样本数
for _ in range(self.n_iter):
errors = 0
for xi, target in zip(X,y):
update = self.eta * (target - self.predict(xi))#调用了predict()函数
self.w_[1:] += update * xi
self.w_[0] += update
errors += int(update != 0.0)
self.errors_.append(errors)
return self
def net_input(self,X):
"""calculate net input"""
return np.dot(X,self.w_[1:]) + self.w_[0]#计算向量点乘
def predict(self,X):#预测类别标记
"""return class label after unit step"""
return np.where(self.net_input(X) >= 0.0,1,-1)
import pandas as pd#用pandas读取数据
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.colors import ListedColormap
df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data',header=None)#读取数据还可以用request这个包
print(df.tail())#输出最后五行数据,看一下Iris数据集格式
"""抽取出前100条样本,这正好是Setosa和Versicolor对应的样本,我们将Versicolor
对应的数据作为类别1,Setosa对应的作为-1。对于特征,我们抽取出sepal length和petal
length两维度特征,然后用散点图对数据进行可视化"""
y = df.iloc[0:100,4].values
y = np.where(y == 'Iris-setosa',-1,1)
X = df.iloc[0:100,[0,2]].values
plt.scatter(X[:50,0],X[:50,1],color = 'red',marker='o',label='setosa')
plt.scatter(X[50:100,0],X[50:100,1],color='blue',marker='x',label='versicolor')
plt.xlabel('petal length')
plt.ylabel('sepal lenght')
plt.legend(loc='upper left')
plt.show()
#train our perceptron model now
#为了更好地了解感知机训练过程,我们将每一轮的误分类
#数目可视化出来,检查算法是否收敛和找到分界线
ppn=Perceptron(eta=0.1,n_iter=10)
ppn.fit(X,y)
plt.plot(range(1,len(ppn.errors_)+1),ppn.errors_,marker='o')
plt.xlabel('Epoches')
plt.ylabel('Number of misclassifications')
plt.show()
#画分界线超平面
def plot_decision_region(X,y,classifier,resolution=0.02):
#setup marker generator and color map
markers=('s','x','o','^','v')
colors=('red','blue','lightgreen','gray','cyan')
cmap=ListedColormap(colors[:len(np.unique(y))])
#plot the desicion surface
x1_min,x1_max=X[:,0].min()-1,X[:,0].max()+1
x2_min,x2_max=X[:,1].min()-1,X[:,1].max()+1
xx1,xx2=np.meshgrid(np.arange(x1_min,x1_max,resolution),
np.arange(x2_min,x2_max,resolution))
Z=classifier.predict(np.array([xx1.ravel(),xx2.ravel()]).T)
Z=Z.reshape(xx1.shape)
plt.contour(xx1,xx2,Z,alpha=0.4,cmap=cmap)
plt.xlim(xx1.min(),xx1.max())
plt.ylim(xx2.min(),xx2.max())
#plot class samples
for idx,cl in enumerate(np.unique(y)):
plt.scatter(x=X[y==cl,0],y=X[y==cl,1],alpha=0.8,c=cmap(idx), marker=markers[idx],label=cl)
plot_decision_region(X,y,classifier=ppn)
plt.xlabel('sepal length [cm]')
plt.ylabel('petal length [cm]')
plt.legend(loc='upperleft')
plt.show()