【机器学习】【感知机-3】感知机(Perceptron)学习算法的对偶形式的Python实现

1.感知机学习算法的对偶形式的讲解+数学求解过程展示

详见,前面博客的详解:点我

2.感知机学习算法的对偶形式的python实现

完全人肉出品,代码如下所示。

2.1知识点

在实现时要意识到,对偶形式中训练实例仅仅以内积的形式出现。为了方便,可以预先将训练集中实例间的内积计算出来并以矩阵的形式存储,这个矩阵就是所谓的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.2数学求解过程展示的python代码

这个是为了展示感知机学习算法的对偶形式的数学求解过程的代码,不是对偶形式的最精简的代码,最精简的代码详见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()

2.3运行结果

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]

2.4感知机学习算法的对偶形式的精简python代码

最后根据测试结果,和上篇博客实现的感知机学习算法的原始形式的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()

2.5运行结果

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)

你可能感兴趣的:(人工智能,机器学习,跟我一起学机器学习,Machine,Learning)