机器学习之感知机模型

机器学习:感知机模型(perceptron)

简介

感知机是二类分类问题的线性分类模型,输入为实例的特征向量,输出为实例的类别,取+1和-1值

定义

假设输入空间(特征空间)是 X ∈ R n X \in R^n XRn,输出空间是 Y = { − 1 , + 1 } Y = \{-1, +1\} Y={1,+1},输入 x ∈ X x \in X xX表示实例的特征向量,对应与输入空间(特征空间)的点;输出 y ∈ Y y \in Y yY表示实例的类别,则由输入空间倒输出空间的如下函数:
f ( x ) = s i g n ( w ∗ x + b ) f(x) = sign(w * x + b) f(x)=sign(wx+b),称为感知机

几何解释

线性方程 w ∗ x + b = 0 w*x + b = 0 wx+b=0对应于特征空间 R n R^n Rn的一个超平面S(关于超平面),这个平面将特征空间分为了两个部分,将处于特征空间中的点分为了正,负两类。其中 w w w是这个超平面的“斜率”, b b b是“截距”(尽管 w w w b b b都可能用向量来表示)

感知机学习策略

损失函数: L ( w , b ) = − ∑ x i ∈ M y i ( w ∗ x i + b ) L(w, b) = -\sum_{x_i \in M}y_i(w*x_i + b) L(w,b)=xiMyi(wxi+b),这个损失函数就是感知机学习的经验风险函数,直观上看,当一个点 x i x_i xi是负分类的,那么 y i ( w ∗ x i + b ) < 0 y_i(w*x_i + b)<0 yi(wxi+b)<0,因为误分类点的 w ∗ x i + b w*x_i + b wxi+b y i y_i yi的符号一定是相反的。因此损失函数是非负的,误分类点越少,损失函数的值便越小。感知机的学习策略便是在训练过程中使用随机梯度下降法不断更新 w w w b b b的值,使得损失函数最小

感知机学习算法

原始形式

整个学习过程是对以下最优化问题(极小化问题)的求解:
m i n w , b L ( w , b ) = m i n w , b ∑ x i ∈ M y i ( w ∗ x i + b ) min_{w, b}L(w, b) = min_{w, b}\sum_{x_i \in M}y_i(w*x_i + b) minw,bL(w,b)=minw,bxiMyi(wxi+b)
先求损失函数的梯度: (倒三角的markdown代码是\nabla)
∇ w L ( w , b ) = − ∑ x i ∈ M y i x i ∇ b L ( w , b ) = − ∑ x i ∈ M y i \nabla_wL(w, b) = -\sum_{x_i\in M}y_ix_i \\ \nabla_bL(w, b) = -\sum_{x_i \in M}y_i wL(w,b)=xiMyixibL(w,b)=xiMyi
则整个学习的步骤是:

  • 选取初值 w 0 , b 0 w_0, b_0 w0,b0
  • 在训练集中选取误分类点 ( x i , y i ) (x_i, y_i) (xi,yi)(判断条件 y i ( w ∗ x i + b ) < = 0 y_i(w*x_i + b) <= 0 yi(wxi+b)<=0
  • 跟新参数 w , b w, b w,b:
    w ← w + η y i x i b ← b + η y i w\leftarrow w + \eta y_ix_i \\ b\leftarrow b + \eta y_i ww+ηyixibb+ηyi
    其中 η \eta η称为学习率(learning rate),决定学习的快慢/精确与否。
  • 直到训练集中没有误分类点(不是所有情况都满足,算法提升在支持向量机)

对偶形式

在原始形式中,我们假设初始参数为 w 0 = 0 , b 0 = 0 w_0 = 0, b_0 = 0 w0=0,b0=0,然后通过:
w ← w + η y i x i b ← + η y i w \leftarrow w + \eta y_ix_i \\ b \leftarrow + \eta y_i ww+ηyixib+ηyi
逐步修改 w , b w, b w,b,假设修改了n次,则最后学习到的 w , b w,b w,b 可以分别表示为:
w = ∑ i = 1 N α i y i x i b = ∑ i = 1 N α i y i w = \sum_{i=1}^N \alpha_i y_i x_i b = \sum_{i=1}^N \alpha_i y_i w=i=1Nαiyixib=i=1Nαiyi
则对偶形式的感知机模型可以表示为:
f ( x ) = s i g n ( ∑ j = 1 N α j y j x j ∗ x + b ) f(x) = sign(\sum_{j=1}^N \alpha_j y_j x_j * x + b) f(x)=sign(j=1Nαjyjxjx+b)
则判断分类错误的条件变为:
y i ( ∑ j = 1 N α j y j x j ∗ x i + b ) < = 0 y_i(\sum_{j=1}^N \alpha_j y_j x_j * x_i + b) <= 0 yi(j=1Nαjyjxjxi+b)<=0
更新参数的方法变为:
α i ← α i + η \alpha_i \leftarrow \alpha_i + \eta αiαi+η
b ← b + η y i b \leftarrow b + \eta y_i bb+ηyi
这里预先将 x x x的内积 x j x i x_jx_i xjxi计算出来,用一个矩阵(Gram矩阵)表示,便可以加速训练过程,不用每次判断误分类的时候都计算一次内积。这里也是对偶形式的算法比原始形式更加优化的地方。
G i , j = x i ∗ x j G_{i, j} = x_i * x_j Gi,j=xixj

代码实现

github

核心代码perceptron.py

  • 原始形式
import numpy as np
import pandas as pd

class Perceptron:
	def __init__(self, dimension):
		self.w = np.zeros((1, dimension))
		self.b = 0
		self.step = 0.5

	def model(self, x):
		# t_x = np.transpose(x)
		# print(t_x)
		return 1 if np.dot(self.w, x) + self.b >= 0 else -1

	def classify_fault(self, node):
		# t_x = np.transpose(node[0:2])
		return (np.dot(self.w, node[0:2]) + self.b) * node[2] <= 0

	def update(self, x, y):
		self.w = self.w + self.step * y * x
		self.b = self.b + self.step * y

	

	def learn(self, data_set):
		fault_nodes = []
		while True:
			for node in fault_nodes:
				self.update(node[0:2], node[2])
			fault_nodes[:] = []
			for node in data_set:
				if self.classify_fault(node):
					fault_nodes.append(node)
			if not fault_nodes:
				break;
	def get_parameter(self):
		return self.w[0], self.b
  • 对偶形式
class Perceptron_antithesis:
	def __init__(self, data_set):
		self.b = 0
		self.step = 0.5
		self.data_set = data_set
		self.nums = data_set.shape[0]
		self.alpha = np.zeros(self.nums)
		self.G = np.zeros((self.nums, self.nums))
		for i in range(self.nums):
			x_i = self.data_set[i][0:2]
			for j in range(self.nums):
				x_j = self.data_set[j][0:2]
				self.G[i][j] = np.dot(x_i, x_j)
		self.x = self.data_set[:, 0:2]
		self.y = self.data_set[:, 2]


	def modle(self, x):
		l = [np.dot(self.x[i], x)*self.y[i]*self.alpha[i] for i in range(self.nums)]
		f_x = np.sum(l) + self.b
		return 1 if f_x >= 0 else -1

	def classify_fault(self, i):
		l = [self.alpha[j]*self.y[j]*self.G[j, i] for j in range(self.nums)]
		f_x = np.sum(l) + self.b
		return self.y[i] * f_x <= 0

	def update(self, i):
		self.alpha[i] = self.alpha[i] + self.step
		self.b = self.b + self.step*self.y[i]

	def learn(self):
		fault_nodes = []
		while True:
			for i in fault_nodes:
				self.update(i)
			fault_nodes[:] = []
			for i in range(self.nums):
				if self.classify_fault(i):
					fault_nodes.append(i)
			if not fault_nodes:
				break;
				
	def get_parameter(self):
		l_w = [self.alpha[i]*self.y[i]*self.x[i] for i in range(self.nums)]
		w = np.sum(l_w, axis=0)
		return w, self.b

数据可视化`data_view.py

import matplotlib.pyplot as plt

def draw(data_set, parameter):
	x_1 = data_set[:, 0]
	x_2 = data_set[:, 1]
	color = data_set[:, 2]
	fig = plt.figure()
	plt.scatter(x_1, x_2, c=color)

	w, b = parameter[0], parameter[1]

	#draw a classifying line
	#x_1 = 0
	t_x_2 = (-b) / w[1]
	#x_2 = 0
	t_x_1 = (-b) / w[0]

	plt.plot([0, t_x_1], [t_x_2, 0])
	plt.show()

实验效果

由于对测试的数据由限制,分类效果还算不错,生成数据的代码如下:

def get_data_set_random(num_node):
	data_set = np.random.random((num_node, 3)) * 10
	for i in range(num_node):
		data_set[i,2] = 1 if data_set[i, 0] ** 2 + data_set[i, 1] ** 2 <= 50 else -1
	return data_set

实验效果图:

MD搞了一晚上,最后发现是图画错了…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值