原始及对偶感知机代码实现

(1)原始感知机代码

import numpy as np
import copy#用于深拷贝 用的到吗?
import operator #支持一些常规操作 C实现 比python快
import os#系统调用
from  matplotlib import pyplot as plt
from matplotlib import animation
'''
    常规感知机的python3实现
'''
##训练集合
training_set=[[(1,2,),1],[(2,3,),1],[(3,1,),-1],[(4,2,),-1]]

w=[0,0]##参数init
b=0
history = []#记录下w,b

def update(item):
    '''
    随机梯度下降 (只是用一个样本更新参数 注意批量梯度下降以及梯度下降的区别)
    :param item: 当前超平面分类错误点
    :return: None
    '''
    global w,b,history #表示这些变量不是当前方法里的 属于全局变量的
    ##对w的更新 W <-- W+N*Yi*Xi 是步常
    for i in range(len(item[0])):
        w[i] +=1*item[1]*item[0][i]
    # w[1] +=1*item[1]*item[0][1]
    ##对b的更新 B <-- B + N*Yi
    b+=1*item[1]
    history.append([copy.copy(w),b])#添加记录

def cal(item):
    '''
    Yi*(W * Xi +B)的计算
    :param item: 一个样本点
    :return: 公式计算的结果
    '''
    result = 0
    for i in range(len(item[0])):#i 第i个特征
        result+=item[0][i]*w[i]
    result+=b
    result*=item[1]#要记得乘以Yi
    return result

def chec():
    """
    检测是否已完全正确分类
    :return: bool True表示有错
    """
    flag = False
    for item in training_set:
        if cal(item)<=0:
            flag = True #还有错误 需要更新参数 算法的前提条件是完全可分
    if not flag:
        print("已经全部正确分类,w:{0} b:{1}".format(w,b))
    return flag
if __name__ == '__main__':
    i = 0
    while chec()==True:
        for item in training_set:
            if cal(item)<=0:
                i+=1
                # flag = True #还有错误 需要更新参数 算法的前提条件是完全可分
                update(item)
                print("迭代第{0}次;w:{1} b:{2}".format(i,w, b))
    ##可视化部分
        # 以下代码是将迭代过程可视化
        # 首先建立我们想要做成动画的图像figure, 坐标轴axis,和plot element
        fig = plt.figure()
        ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
        line, = ax.plot([], [], 'g', lw=2)  # 画一条线
        label = ax.text([], [], '')


        def init():
            line.set_data([], [])
            x, y, x_, y_ = [], [], [], []
            for p in training_set:
                if p[1] > 0:
                    x.append(p[0][0])  # 存放yi=1的点的x1坐标
                    y.append(p[0][1])  # 存放yi=1的点的x2坐标
                else:
                    x_.append(p[0][0])  # 存放yi=-1的点的x1坐标
                    y_.append(p[0][1])  # 存放yi=-1的点的x2坐标
            plt.plot(x, y, 'bo', x_, y_, 'rx')  # 在图里yi=1的点用点表示,yi=-1的点用叉表示
            plt.axis([-6, 6, -6, 6])  # 横纵坐标上下限
            plt.grid(True)  # 显示网格
            plt.xlabel('x1')  # 这里我修改了原文表示
            plt.ylabel('x2')  # 为了和原理中表达方式一致,横纵坐标应该是x1,x2
            plt.title('Perceptron Algorithm (www.hankcs.com)')  # 给图一个标题:感知机算法
            return line, label


        def animate(i):
            global history, ax, line, label
            w = history[i][0]
            b = history[i][1]
            if w[1] == 0: return line, label
            # 因为图中坐标上下限为-6~6,所以我们在横坐标为-7和7的两个点之间画一条线就够了,这里代码中的xi,yi其实是原理中的x1,x2
            x1 = -7
            y1 = -(b + w[0] * x1) / w[1]
            x2 = 7
            y2 = -(b + w[0] * x2) / w[1]
            line.set_data([x1, x2], [y1, y2])  # 设置线的两个点
            x1 = 0
            y1 = -(b + w[0] * x1) / w[1]
            label.set_text(history[i])
            label.set_position([x1, y1])
            return line, label


        print("参数w,b更新过程:", history)
        anim = animation.FuncAnimation(fig, animate, init_func=init, frames=len(history), interval=1000, repeat=True,
                                       blit=True)
        plt.show()
        

参考博客:https://blog.csdn.net/Daycym/article/details/81032016

(2)对偶感知机代码

from __future__ import division
import random
import numpy as np
import matplotlib.pyplot as plt


def sign(v):
    if v>=0:
        return 1
    else:
        return -1

def train(train_num,train_datas,lr):
    '''

    :param train_num: 迭代次数
    :param train_datas: 训练集
    :param lr: 步长
    :return:权重w ,b,a:alpha,格拉姆矩阵gram
    '''
    w=0.0
    b=0
    datas_len = len(train_datas)#共有多少数据
    alpha = [0 for i in range(datas_len)]#全是0 应该是公式中的a
    # print(alpha)
    train_array = np.array(train_datas)
    # print(train_array[:,-1])
    # print(train_array[:, 0:-1])
    gram = np.matmul(train_array[:,0:-1] , train_array[:,0:-1].T) #train_array[:,0:-1] 取数据 去掉lable
    for idx in range(train_num):#开始迭代 一步一步
        tmp=0 #存结果
        i = random.randint(0,datas_len-1)#随机选一个样本  随机梯度下降的本质
        yi=train_array[i,-1]#表示取第i行数据中 倒数第一个值 就是y值
        for j in range(datas_len):
            ## alphaj*yj*xj*xi
            tmp+=alpha[j]*train_array[j,-1]*gram[i,j]
        tmp+=b
        if(yi*tmp<=0):#有错 更新
            alpha[i]=alpha[i]+lr
            b=b+lr*yi
    ##计算W
    ##W= 所有alpha*yj*xj的和
    for i in range(datas_len):
        w+=alpha[i]*train_array[i,0:-1]*train_array[i,-1]#train_array[i,0:-1] 选的是第i行的最后一元素
        # train_array[i,-1]第i行的前两个元素
    return w,b,alpha,gram

def plot_points(train_datas,w,b):
    plt.figure()
    x1 = np.linspace(0, 8, 1000)
    x2 = (-b-w[0]*x1)/(w[1]+1e-10)
    plt.plot(x1, x2, color='r', label='y1 data')
    datas_len=len(train_datas)
    for i in range(datas_len):
        if(train_datas[i][-1]==1):
            plt.scatter(train_datas[i][0],train_datas[i][1],s=50)
        else:
            plt.scatter(train_datas[i][0],train_datas[i][1],marker='x',s=50)
    plt.show()

if __name__=='__main__':
    train_data1 = [[1, 3, 1], [2, 2, 1], [3, 8, 1], [2, 6, 1]]  # 正样本
    train_data2 = [[2, 1, -1], [4, 1, -1], [6, 2, -1], [7, 3, -1]]  # 负样本
    train_datas = train_data1 + train_data2  # 样本集
    # print(train_datas)
    w,b,alpha,gram=train(train_num=50,train_datas=train_datas,lr=0.01)
    plot_points(train_datas,w,b)

参考博客:https://blog.csdn.net/winter_evening/article/details/70196040

猜你喜欢

转载自blog.csdn.net/weixin_40642306/article/details/83246904
今日推荐