算法
输入:
- 线性可分的数据集 T = ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) T={(x_1,y_1),(x_2,y_2),...,(x_N,y_N)} T=(x1,y1),(x2,y2),...,(xN,yN),其中 x i ∈ X = R n , y i ∈ Y = { − 1 , 1 } , i = 1 , 2 , . . . , N x_i∈X=R^n,y_i∈Y=\{-1,1\},i=1,2,...,N xi∈X=Rn,yi∈Y={−1,1},i=1,2,...,N
- 学习率 η ( 0 < η < = 1 ) \eta(0<\eta<=1) η(0<η<=1)
输出:
-
w,b
其中w= ∑ j = 1 N α j y j x j \overset{N}{\underset{j=1}{\sum}}\alpha_jy_jx_j j=1∑Nαjyjxj
-
感知机模型 f ( x ) = s i g n ( ∑ j = 1 N α j y j x j ⋅ x + b ) f(x)=sign(\overset{N}{\underset{j=1}{\sum}}\alpha_jy_jx_j·x+b) f(x)=sign(j=1∑Nαjyjxj⋅x+b)
流程:
-
选取初始值 α 0 , b 0 \alpha_0,b_0 α0,b0
-
在训练集中选取数据 ( x i , y i ) (x_i,y_i) (xi,yi)
-
如果 y i ( ∑ j = 1 N α j y j x j ⋅ x i + b ) < = 0 y_i(\overset{N}{\underset{j=1}{\sum}}\alpha_jy_jx_j·x_i+b)<=0 yi(j=1∑Nαjyjxj⋅xi+b)<=0
α i ← α i + η b ← b + η y i \alpha_i\leftarrow{\alpha_i}+\eta\\ b\leftarrow{b+{\eta}y_i} αi←αi+ηb←b+ηyi -
跳转至2,直到训练集中没有误分类点
其中,每次实例仅以内积的形式出现,即公式中的 x j ⋅ x i x_j\cdot{x_i} xj⋅xi,每次循环算一遍不方便
我们可以预先将所有的 x j ⋅ x i x_j\cdot{x_i} xj⋅xi算好放到矩阵中存储,这个矩阵就是所谓的Gram矩阵
G = [ x i ⋅ x j ] N × N G = [x_i\cdot{x_j}]_{N\times{N}} G=[xi⋅xj]N×N
题目
有一训练集T,其正实例的点是 x 1 = ( 3 , 3 ) T , x 2 = ( 4 , 3 ) T x_1=(3,3)^T,x_2=(4,3)^T x1=(3,3)T,x2=(4,3)T,负实例的点是 x 3 = ( 1 , 1 ) T x_3=(1,1)^T x3=(1,1)T
求感知机模型 f ( x ) = s i g n ( w ⋅ x + b ) f(x)=sign(w·x+b) f(x)=sign(w⋅x+b),其中, w = ( w ( 1 ) , w ( 2 ) ) T w=(w^{(1)},w^{(2)})^T w=(w(1),w(2))T, x = ( x ( 1 ) , x ( 2 ) ) T x=(x^{(1)},x^{(2)})^T x=(x(1),x(2))T
解法
-
选取 α i = 0 , i = 1 , 2 , 3 , n = 0 , η = 1 \alpha_i=0,i=1,2,3,n=0,\eta=1 αi=0,i=1,2,3,n=0,η=1
-
计算Grama矩阵存储,即 G = [ x i ⋅ x j ] N × N G = [x_i\cdot{x_j}]_{N\times{N}} G=[xi⋅xj]N×N,供下面计算判断使用
-
循环实例,若 y i ( ∑ j = 1 N α j y j x j ⋅ x i + b ) < = 0 y_i(\overset{N}{\underset{j=1}{\sum}}\alpha_jy_jx_j·x_i+b)<=0 yi(j=1∑Nαjyjxj⋅xi+b)<=0
α i ← α i + η b ← b + η y i \alpha_i\leftarrow{\alpha_i}+\eta\\ b\leftarrow{b+{\eta}y_i} αi←αi+ηb←b+ηyi -
重复执行第三步,直到没有误分类的点
代码
# -*- coding: UTF-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
class PERCEPTRON:
def __init__(self):
# 这里写死数据,可自行改为动态读取
df = pd.read_excel('../data/perceptronExample.xlsx')
self.df = pd.DataFrame(df)
# 结果
self.a = 0
self.w = 0
self.b = 0
self.eta = 1 # 步长
'''训练'''
def train(self):
df = self.df
x = df.values[:, :-1] # 提取所有特征向量
y = df.values[:, -1] # 提取分类结果
# 获取特征向量的个数
temp = x.shape
n = temp[0]
# 计算gram矩阵 点积转置即可
gram = np.dot(x,np.transpose(x))
# 初始化alpha和b
alpha = np.zeros(n) # alpha表示每个实例更新了多少次w,所以长度和实例个数一致
b = 0
# 循环迭代
flag = True # 迭代条件
while flag:
flag = False
# 对每个实例进行计算并更新alpha和b
for i in range(n):
res = y[i] * (np.dot(alpha*y,gram[i])+b)
if res <= 0: # 误分类时,更新alpha和b,并重新迭代
alpha[i] += self.eta
b += self.eta * y[i]
flag = True
break
self.w = np.dot(alpha*y,x)
self.b = b
print("计算得到法向量w={0},b={1}".format(self.w, self.b))
'''可视化展示'''
def show(self):
y = self.df.values[:, -1]
x1 = self.df.values[:, 0]
x2 = self.df.values[:, 1]
# 点
for i in range(len(self.df)):
if (y[i] == 1):
s1 = plt.scatter(x1[i], x2[i], c='red')
else:
s2 = plt.scatter(x1[i], x2[i], c='blue')
plt.legend([s1, s2], ['正类', '负类'])
# 线
xmin = self.df.values[:, :-1].min()
xmax = self.df.values[:, :-1].max()
xstep = (xmax - xmin) * 0.5 # 步长
xx = np.linspace(xmin - xstep, xmax + xstep, 3) # 横坐标
yy = -self.w[0] * xx - self.b # 根据得到的参数计算纵坐标
plt.plot(yy, xx)
plt.rcParams['font.sans-serif'] = ['SimHei'] # 中文乱码问题
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.show()
if __name__ == '__main__':
perceptron = PERCEPTRON()
perceptron.train()
perceptron.show()