写在前面:最近正在学习机器学习,为了养成好的习惯,就按章节做了笔记并用python实现。文章中必不可少出现错误,还请大家谅解。写出来是为了激励自己努力学习,可以写出更多的东西和大家分享学习心得和体会。
感知机(perceptron)
感知机是二类分类的线性分类模型,其输入为实例的特征向量,输出为实例的类别,取+1和-1。
例如,人们总是可以轻而易举的分辨出橘子和苹果,但机器怎么分辨出橘子和苹果呢?所以人们提出了感知机这个线性分类模型。就拿这个例子来说,为了成功地分辨出苹果和橘子,机器需要输入量,包括重量、光滑度、颜色和形状等特点,将这些特点组成一个向量,就是特征向量。分类结果只包括橘子和苹果,这些结果就是类别,在机器中用+1和-1来表示。
机器通过对特征向量计算,经行判断。但各个特征占的权重各不相同,比如,对苹果和橘子来说,颜色这个特征就比较明显,苹果偏向红色而橘子偏向橘黄色,所以颜色特征权重应该稍大。特种明显的权重应该较大,特征不明显的权重较小。所以在感知机中为每一个特征分配了一个权重值w。有时加上权重依然分辨不出结果,就需要加上偏置bias。
初始化的感知机针对特定问题的适应度不够,错误率很高,所以需要一组已知结果的训练集,(x,y)。通过训练,改变的模型中的权重值和偏置,降低分类的错误率。
那么通过训练,该如何改变权值和偏置呢?
梯度下降法,具体的推导公式可以google。但其思想就是,总是朝着负方向改变,直到找到极小值。初中数学中,对一个函数求导可以得到函数在某一点的斜率k(表示函数的增长速率,朝着正方向改变),如果我们将斜率取负号-k,那么就得到了朝着负方向增长的速率。在感知机中定义了损失函数,为了得到适当的权值和偏置,采取的策略是损失函数极小化。简单的,我们将函数的最大值比作山峰,将极小值比作谷底,解比作人。那么极小化,就是使人总是朝向谷底移动,移动的方向就是梯度的负方向。
感知机这部分之知识在神经网络中也有提到。
下面是一些相关公式。
分类模型:
分离超平面:
当 ,
当 ,
策略:极小化损失函数
在三维空间内,点到面距离定义为:
对于误分类数据来说:
不考虑,损失函数定义为:
感知机学习算法
损失函数对w的梯度为:
损失函数对b的梯度为:
梯度指向使函数值增大,因此w的变化方向应是梯度的反方向,使得函数值下降。偏置b也是一样的。
其中 为学习速度。
判定条件:
框架:
输入:训练数据集,学习速度输出:权值w和偏置b,感知机模型
(1)选取初值
(2)在训练数据集中选取数据
(3)如果,
则,
(4) 转至(2),直至训练集中没有误分类点。
感知机学习算法的对偶性
将判定条件中的w展开:
其中 为对应的学习速率 的增量。
将判定公式展开,针对每一个 都有:
若成立,则更新:
,
其中的 内积,可以提前算出来内积,并以矩阵存储。称为Gram矩阵。
针对对偶性,可以对原始框架经行修改。
输入:训练数据集,学习速度
输出: ;感知机模型
(1) 初始 等于0
(2)在训练数据集中选取数据
(3)若,
则更新,,
(4)转至(2),直到没有误分类点。
最后计算权值w,。
----------------------------------------------分割线--------------------------------------------------
python源码
#__author__ = 'altaman' #coding = utf-8 import numpy as np import matplotlib.pyplot as plt class showPicture: def __init__(self,data,w,b): self.b = b self.w = w plt.figure(1) plt.title('Plot 1', size=14) plt.xlabel('x-axis', size=14) plt.ylabel('y-axis', size=14) xData = np.linspace(0, 5, 100) yData = self.expression(xData) plt.plot(xData, yData, color='r', label='y1 data') plt.scatter(data[0][0],data[0][1],s=50) plt.scatter(data[1][0],data[1][1],s=50) plt.scatter(data[2][0],data[2][1],marker='x',s=50,) plt.savefig('2d.png',dpi=75) def expression(self,x): y = (-self.b - self.w[0]*x)/self.w[1] return y def show(self): plt.show() class perceptron: def __init__(self,x,y,a=1): self.x = x self.y = y self.w = np.zeros((x.shape[1],1)) self.b = 0 self.a = 1 def sign(self,w,b,x): result = 0 y = np.dot(x,w)+b return int(y) def train(self): flag = True length = len(self.x) while flag: count = 0 for i in range(length): tmpY = self.sign(self.w,self.b,self.x[i,:]) if tmpY*self.y[i]<=0: tmp = self.y[i]*self.a*self.x[i,:] tmp = tmp.reshape(self.w.shape) self.w = tmp +self.w self.b = self.b + self.y[i] count +=1 if count == 0: flag = False return self.w,self.b #原始数据 data = [[3,3],[4,3],[1,1]] xArray = np.array([3,3,4,3,1,1]) xArray = xArray.reshape((3,2)) yArray = np.array([1,1,-1]) #感知机计算权值 myPerceptron = perceptron(x=xArray,y=yArray) weight,bias = myPerceptron.train() #画图 picture = showPicture(data,w=weight,b=bias) picture.show()
实验结果如下图:
从上图可以看到,分割面即超平面。