自己写简单的感知机算法

自己动手写感知机

1 什么是感知机?

​ 感知机(perceptron)是一种二分类的线性分类模型,可以将所有输入的实例划分为True或是False两类。感知机模型的输入向量是实例的特征向量,其任务就是在N维空间中寻找一个平面,让这个平面可以正好将实例划分为正负两类,这个平面我们称其为超平面。感知机是神经网络与支持向量机的基础。

2 感知机模型

​ 输入空间: χRn χ ⊆ R n

​ 输出空间: y={+1,1} y = { + 1 , − 1 }

​ 输入空间到输出的函数:

f(x)=sign(wx+b) f ( x ) = s i g n ( w ⋅ x + b )

​ 其中:
sign(x)={+11x0x<0 s i g n ( x ) = { + 1 x ≥ 0 − 1 x < 0

​ 几何解释:

​ 函数中的 w w 可以理解为超平面的法向量,b为超平面的截距,超平面将整个空间分为两部分,就是分类出来的正、负两类。

3 感知机学习算法

感知机学习算法的具体策略就是使用误分类点到超平面的距离和为损失函数,并使用梯度下降法最小化损失函数,即可求解出超平面。

  • 原始形式

    首先初始化所有参数为0,然后根据梯度下降法,用每个误分类点来更新参数,封装成类:

    class PreceptronClassifier:
      def __init__(self,learning_rate):
          self.b = 0
          self.w = []
          self.rate = learning_rate
    
      def func(self, x):
          # 定义模型
          res = 0.0
          for i in range(len(x)):
              res += self.w[i]*x[i]
          res += self.b
          return res
    
      def update(self,error_x,error_y):
          # 更新参数
          for i in range(len(error_x)):
              self.w[i] += self.rate*error_x[i]*error_y
          self.b += self.rate*error_y
    
      def error_label(self,temp_res:list,trainY):
          # 标记误分类点
          for i in range(len(self.w)):
              if temp_res[i] == trainY[i]:
                  temp_res[i] = 0
              else:
    
                  temp_res[i] = 1
          return temp_res
    
      def fit(self, trainX,trainY):
          # 初始化参数
          self.w = [0]*len(trainX[0])
          self.b = 0
          temp_res = self.prediction(trainX)
          temp_res = self.error_label(temp_res, trainY)
          train_iter = 0
          while(1 in temp_res):
              # 显示迭代过程
              print('第'+str(train_iter)+'次迭代','w:',self.w,'b:',self.b)
              error_index = temp_res.index(1)
              self.update(trainX[error_index],trainY[error_index])
              temp_res = self.prediction(trainX)
              temp_res = self.error_label(temp_res, trainY)
    
      def prediction(self, testX):
          # 进行预测
          res  = []
          for x in testX:
              res.append(1 if self.func(x) > 0 else -1 )
          return res
    
    
    if __name__ == '__main__':
      # 准备训练数据和测试数据
      trainX = [[3,3],[4,3],[1,1]]
      trainY = [1,1,-1]
      testX  = [[1,2],[3,4]]
      # 创建对象,指定学习率
      pc = PreceptronClassifier(0.5)
      pc.fit(trainX,trainY)       # 训练
      print(pc.prediction(testX)) # 测试
  • 对偶形式

    前面提到过,每次更新 w w 参数,使用w=w+ηyixi 这个式子是模型对求的偏导, η η 表示学习率。

    所以相对于每一个实例,他们的 yixi y i x i 是不会变的,所以最终的的模型参数可以表示为:

    w=i1Nαiyixib=i1Nαiyi w = ∑ i − 1 N α i y i x i b = ∑ i − 1 N α i y i

    αi α i 表示第 i i <script type="math/tex" id="MathJax-Element-16">i</script>个点被误分类用来更新模型的次数,这就是对偶形式,下面放代码:

    class PreceptronClassifier:
      def __init__(self,learning_rate):
          self.b = 0
          self.w = []
          self.rate = learning_rate
    
      def func(self, x):
          # 定义模型
          res = 0.0
          for i in range(len(x)):
              res += self.w[i]*x[i]
          res += self.b
          return res
    
      def update(self,error_index, trainY):
          # 更新参数
          self.a[error_index] += 1
          for i in range(len(self.w)):
              self.w[i] += self.rate*self.matrix[error_index][i]
          self.b += self.rate*trainY[error_index]
    
      def error_label(self,temp_res:list,trainY):
          # 标记误分类点
          for i in range(len(self.w)):
              if temp_res[i] == trainY[i]:
                  temp_res[i] = 0
              else:
    
                  temp_res[i] = 1
          return temp_res
    
      def fit(self, trainX,trainY):
          # 初始化参数
          self.w = [0]*len(trainX[0])
          self.a = [0]*len(trainX)
          self.b = 0
          self.matrix = []
          for i in range(len(trainX)):
              self.matrix.append([xi*trainY[i] for xi in trainX[i]])
          temp_res = self.prediction(trainX)
          temp_res = self.error_label(temp_res, trainY)
          train_iter = 0
          while(1 in temp_res):
              train_iter += 1
              error_index = temp_res.index(1)
              self.update(error_index,trainY)
              temp_res = self.prediction(trainX)
              temp_res = self.error_label(temp_res, trainY)
              print('第'+str(train_iter)+'次迭代','w:',self.w,'b:',self.b)
    
      def prediction(self, testX):
          # 进行预测
          res  = []
          for x in testX:
              res.append(1 if self.func(x) > 0 else -1 )
          return res
    
    
    if __name__ == '__main__':
      # 准备训练数据和测试数据
      trainX = [[3,3],[4,3],[1,2]]
      trainY = [1,1,-1]
      testX  = [[1,2],[3,4]]
      # 创建对象,指定学习率
      pc = PreceptronClassifier(0.5)
      pc.fit(trainX,trainY)       # 训练
      print(pc.prediction(testX)) # 测试

4 总结

感知机模型简单且易于实现,是入门级算法,同时又是神经网络和支持向量机的基础。比如说神经网络的全连接层就和感知机很相似,所以这个算法还是值得理解一下的。

初学乍练,请多多指正!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值