详见,前面博客的详解:点我
完全人肉出品,代码如下所示。
在实现时要意识到,对偶形式中训练实例仅仅以内积的形式出现。为了方便,可以预先将训练集中实例间的内积计算出来并以矩阵的形式存储,这个矩阵就是所谓的Gram Matrix,如下所示:
import numpy as np
X = np.array([[3,3],
[4,3],
[1,1]])
X_GM = np.dot(X,X.T)
print(X_GM)
#[[18 21 6]
# [21 25 7]
# [ 6 7 2]]
这个是为了展示感知机学习算法的对偶形式的数学求解过程的代码,不是对偶形式的最精简的代码,最精简的代码详见2.4.
# -*- coding: utf-8 -*-
"""
@author: 蔚蓝的天空tom
Talk is cheap, show me the code
Aim:实现感知机学习算法的对偶形式
"""
import numpy as np
class CPerceptronDual(object):
'''实现感知机学习算法的对偶形式
'''
def __init__(self, train_samples, Y):
self.X = train_samples
self.Y = Y
self.GM = np.dot(self.X, self.X.T)
self.A = [] #每个x的权值
self.b = 0 #bias偏置
self.alpha = 1.0 #学习率,即学习步长
self.W = []
self.cnt = 0
print('特征集X:\n', self.X)
print('分类集Y:\n', self.Y)
print('特征集的Gram Matrix:\n', self.GM)
self.study()
def study(self):
'''
感知机学习算法的对偶形式的实现
'''
N = np.shape(self.X)[0] #训练样本集的样本个数
if 0 == np.shape(self.A)[0]: #第一次学习,初始化A和b都为0
self.A = np.full(shape=(N,), fill_value=0.0)
self.b = 0
#感知机学习
misclassify_cnt = 0
self.cnt += 1
print('=======================第%d次学习'%self.cnt)
for i in range(N):
dual_efunc = lambda a,y,dot : a*y*dot
dual_func = np.frompyfunc(dual_efunc, 3, 1)
dual = dual_func(self.A, self.Y, self.GM[:,i]).sum()
ret = self.Y[i]*(dual + self.b)
if ret <= 0:#分类错误
old_A,old_b = self.A,self.b
self.A[i] += self.alpha
self.b += self.Y[i]
print('误分条件值:%d'%ret, '误分类点x%d:'%i, self.X[i], '更新前A:', old_A, 'b:', old_b, '更新后A:', self.A, 'b:', self.b)
misclassify_cnt += 1
else:
print('误分条件值:%d'%ret, 'x%d:'%i, self.X[i], 'A:', self.A, 'b:', self.b)
#如果有错误分类,继续感知机学习
if misclassify_cnt > 0:
return self.study()
else:
self.W = sum([a*x*y for a,x,y in zip(self.A, self.X, self.Y)])
print('perceptron succeed, W:', self.W, 'b:',self.b)
return self.W, self.b
def Classifier(self, test_samples):
ret = []
p_sign = lambda x : (x>=0 and [+1] or [-1])[0]
ret = [p_sign(np.dot(self.W, x) + self.b) for x in test_samples]
return ret
def CPerceptron_manual():
#实例的特征集
X = np.array([[3,3],[4,3],[1,1]])
#实例的类别集
Y = np.array([+1,+1,-1])
p = CPerceptronDual(X,Y)
test_X = X
ret = p.Classifier(test_X)
print('测试特征集:', test_X)
print('感知机分类结果:', ret)
return
if __name__=='__main__':
CPerceptron_manual()
runfile('C:/Users/tom/perceptron_duiou.py', wdir='C:/Users/tom')
特征集X:
[[3 3]
[4 3]
[1 1]]
分类集Y:
[ 1 1 -1]
特征集的Gram Matrix:
[[18 21 6]
[21 25 7]
[ 6 7 2]]
=======================第1次学习
误分条件值:0 误分类点x0: [3 3] 更新前A: [ 1. 0. 0.] b: 0 更新后A: [ 1. 0. 0.] b: 1
误分条件值:22 x1: [4 3] A: [ 1. 0. 0.] b: 1
误分条件值:-7 误分类点x2: [1 1] 更新前A: [ 1. 0. 1.] b: 1 更新后A: [ 1. 0. 1.] b: 0
=======================第2次学习
误分条件值:12 x0: [3 3] A: [ 1. 0. 1.] b: 0
误分条件值:14 x1: [4 3] A: [ 1. 0. 1.] b: 0
误分条件值:-4 误分类点x2: [1 1] 更新前A: [ 1. 0. 2.] b: 0 更新后A: [ 1. 0. 2.] b: -1
=======================第3次学习
误分条件值:5 x0: [3 3] A: [ 1. 0. 2.] b: -1
误分条件值:6 x1: [4 3] A: [ 1. 0. 2.] b: -1
误分条件值:-1 误分类点x2: [1 1] 更新前A: [ 1. 0. 3.] b: -1 更新后A: [ 1. 0. 3.] b: -2
=======================第4次学习
误分条件值:-2 误分类点x0: [3 3] 更新前A: [ 2. 0. 3.] b: -2 更新后A: [ 2. 0. 3.] b: -1
误分条件值:20 x1: [4 3] A: [ 2. 0. 3.] b: -1
误分条件值:-5 误分类点x2: [1 1] 更新前A: [ 2. 0. 4.] b: -1 更新后A: [ 2. 0. 4.] b: -2
=======================第5次学习
误分条件值:10 x0: [3 3] A: [ 2. 0. 4.] b: -2
误分条件值:12 x1: [4 3] A: [ 2. 0. 4.] b: -2
误分条件值:-2 误分类点x2: [1 1] 更新前A: [ 2. 0. 5.] b: -2 更新后A: [ 2. 0. 5.] b: -3
=======================第6次学习
误分条件值:3 x0: [3 3] A: [ 2. 0. 5.] b: -3
误分条件值:4 x1: [4 3] A: [ 2. 0. 5.] b: -3
误分条件值:1 x2: [1 1] A: [ 2. 0. 5.] b: -3
perceptron succeed, W: [ 1. 1.] b: -3
测试特征集: [[3 3]
[4 3]
[1 1]]
感知机分类结果: [1, 1, -1]
最后根据测试结果,和上篇博客实现的感知机学习算法的原始形式的python代码测试结果一样,可以验证python代码 是ok的,代码如下:
# -*- coding: utf-8 -*-
"""
@author: 蔚蓝的天空tom
Talk is cheap, show me the code
Aim:实现感知机学习算法的对偶形式
"""
import numpy as np
class CPerceptronDual(object):
'''实现感知机学习算法的对偶形式
'''
def __init__(self, train_samples, Y):
self.X = train_samples
self.Y = Y
self.GM = np.dot(self.X, self.X.T)
self.A = [] #每个x的权值
self.b = 0 #bias偏置
self.alpha = 1.0 #学习率,即学习步长
self.W = []
self.study()
def study(self):
'''
感知机学习算法的对偶形式的实现
'''
print('\nstart one study....')
N = np.shape(self.X)[0] #训练样本集的样本个数
if 0 == np.shape(self.A)[0]: #第一次学习,初始化A和b都为0
self.A = np.full(shape=(N,), fill_value=0.0)
self.b = 0
#感知机学习
misclassify_cnt = 0
for i in range(N):
dual_efunc = lambda a,y,dot : a*y*dot
dual_func = np.frompyfunc(dual_efunc, 3, 1)
dual = dual_func(self.A, self.Y, self.GM[:,i]).sum()
ret = self.Y[i]*(dual + self.b)
if ret <= 0:#分类错误
old_A,old_b = self.A,self.b
self.A[i] += self.alpha
self.b += self.Y[i]
print('误分条件值:%d'%ret, '误分类点x%d:'%i, self.X[i], '更新前A:', old_A, 'b:', old_b, '更新后A:', self.A, 'b:', self.b)
misclassify_cnt += 1
else:
print('误分条件值:%d'%ret, 'x%d:'%i, self.X[i], 'A:', self.A, 'b:', self.b)
#如果有错误分类,继续感知机学习
if misclassify_cnt > 0:
return self.study()
else:
self.W = sum([a*x*y for a,x,y in zip(self.A, self.X, self.Y)])
print('perceptron succeed, W:', self.W, 'b:',self.b)
return self.W, self.b
def Classifier(self, test_samples):
'''感知机预测方法
'''
p_sign = lambda x : (x>=0 and [+1] or [-1])[0]
ret = [p_sign(np.dot(self.W, x) + self.b) for x in test_samples]
return ret
def CPerceptron_manual():
#实例的特征集
X = np.array([[3,3],[4,3],[1,1]])
#实例的类别集
Y = np.array([+1,+1,-1])
p = CPerceptronDual(X,Y)
print('\n下面用学习的感知机进行预测~~~~~~~~~~')
test_X = X
#调用学习的感知机进行预测
ret = p.Classifier(test_X)
print('\n测试特征集:', test_X)
print('感知机预测分类结果:', ret)
#新的测试样本集
test_X = np.array([[0.5, 0.5],
[1,2],
[2,2],
[5,5]])
#调用学习的感知机进行预测
ret = p.Classifier(test_X)
print('\n测试特征集:', test_X)
print('感知机预测分类结果:', ret)
return
if __name__=='__main__':
CPerceptron_manual()
runfile('C:/Users/tom/perceptron_duiou_implie.py', wdir='C:/Users/tom')
start one study....
误分条件值:0 误分类点x0: [3 3] 更新前A: [ 1. 0. 0.] b: 0 更新后A: [ 1. 0. 0.] b: 1
误分条件值:22 x1: [4 3] A: [ 1. 0. 0.] b: 1
误分条件值:-7 误分类点x2: [1 1] 更新前A: [ 1. 0. 1.] b: 1 更新后A: [ 1. 0. 1.] b: 0
start one study....
误分条件值:12 x0: [3 3] A: [ 1. 0. 1.] b: 0
误分条件值:14 x1: [4 3] A: [ 1. 0. 1.] b: 0
误分条件值:-4 误分类点x2: [1 1] 更新前A: [ 1. 0. 2.] b: 0 更新后A: [ 1. 0. 2.] b: -1
start one study....
误分条件值:5 x0: [3 3] A: [ 1. 0. 2.] b: -1
误分条件值:6 x1: [4 3] A: [ 1. 0. 2.] b: -1
误分条件值:-1 误分类点x2: [1 1] 更新前A: [ 1. 0. 3.] b: -1 更新后A: [ 1. 0. 3.] b: -2
start one study....
误分条件值:-2 误分类点x0: [3 3] 更新前A: [ 2. 0. 3.] b: -2 更新后A: [ 2. 0. 3.] b: -1
误分条件值:20 x1: [4 3] A: [ 2. 0. 3.] b: -1
误分条件值:-5 误分类点x2: [1 1] 更新前A: [ 2. 0. 4.] b: -1 更新后A: [ 2. 0. 4.] b: -2
start one study....
误分条件值:10 x0: [3 3] A: [ 2. 0. 4.] b: -2
误分条件值:12 x1: [4 3] A: [ 2. 0. 4.] b: -2
误分条件值:-2 误分类点x2: [1 1] 更新前A: [ 2. 0. 5.] b: -2 更新后A: [ 2. 0. 5.] b: -3
start one study....
误分条件值:3 x0: [3 3] A: [ 2. 0. 5.] b: -3
误分条件值:4 x1: [4 3] A: [ 2. 0. 5.] b: -3
误分条件值:1 x2: [1 1] A: [ 2. 0. 5.] b: -3
perceptron succeed, W: [ 1. 1.] b: -3
下面用学习的感知机进行预测~~~~~~~~~~
测试特征集: [[3 3]
[4 3]
[1 1]]
感知机预测分类结果: [1, 1, -1]
测试特征集: [[ 0.5 0.5]
[ 1. 2. ]
[ 2. 2. ]
[ 5. 5. ]]
感知机预测分类结果: [-1, 1, 1, 1]
感知机在统计学习算法中算是比较简单的一个算法,但是虽然简单,感知机的学习策略的精髓和其他算法都是一样的,重要的是理解算法的学习策略。
(end)