python单层感知机训练过程绘制(动态绘制)

以简单的单层感知机和支持向量机为例,展示动态绘制训练过程的方法。

代码如下:        

import numpy as np
import matplotlib.pyplot as plt


def Count_y(x, N, w, b):
    y_ = 0
    for i in range(N):  # 计算预测值
        y_ += w[i] * x[i]
    y_ += b  # 添加偏置
    return y_


def Generate_Dataset():  # 生成数据集,
    X = np.random.randn(50, 2)  # 生成50行2列的数据集
    Y = np.array([1 if 5 * i[0] - 3 * i[1] +2 >= 0 else -1 for i in X])  # 填写标签
    data_cole = ["g" if i > 0 else 'b' for i in Y]
    return X, Y, data_cole


def Train(X, Y, data_cole, N=2, lr=0.003, num_epochs=100):  # 样本,标签,学习率和循环轮数
    w = np.random.rand(N)  # 数据维数为2
    b = 0
    plt_x = []  # 画图用
    w_all = []
    b_all = []
    for i in range(N):
        plt_x.append([data[i] for data in X])
    x_max = [min(plt_x[0]), max(plt_x[0])]  #
    for j in range(num_epochs):  # 循环
        stop = True  # 停止标记,没有分类错误的就停止
        for i in range(Y.size):  # 一轮
            x = X[i]
            y = Y[i]
            y_ = 1 if Count_y(x, N, w, b)>=0 else -1  # 计算预测值
            if y_ * y <= 0:  # 标记错误
                w_all.append([w[0],w[1]])
                b_all.append(b)
                update = lr*(y-y_)
                w += update * x  # 更新权重
                b += update  # 更新偏置
                stop = False
        if stop:
            break
    w_all.append(w)
    b_all.append(b)
    Draw(plt_x, x_max, N, data_cole, w_all, b_all)  # 绘图
    # print(w,b)


def Draw(plt_x, x_max, N, data_cole, w_all, b_all):  # 绘图
    plt.figure()
    for i in range(np.size(b_all)):
        # 清除上次绘图
        plt.clf()
        # 设置显示范围
        plt.xlim(x_max[0], x_max[1])
        plt.ylim(x_max[0], x_max[1])
        w= w_all[i]
        b = b_all[i]
        print(w,b)
        plt.scatter(plt_x[0], plt_x[1], c=data_cole, alpha=0.8)  # 绘点散点
        # 绘制分类线
        y_ = [(-w[0] * i - b) / w[1] for i in x_max]
        plt.plot(x_max, y_, 'r')
        # 刷新图形
        plt.draw()
        # 等待0.05s
        plt.pause(0.05)
    plt.show()  # 遍历完成后不消失



X, Y, data_cole = Generate_Dataset()
Train(X, Y, data_cole, )

运行结果:

感知机训练过程展示

注意事项:

对w,b的保存注意不能直接w_all.append(w),注意拷贝影响。

主要其实是对绘图的应用,也可以快速应用到之前的代码上,比如支持向量机:https://blog.csdn.net/weixin_58196051/article/details/124555732icon-default.png?t=N7T8https://blog.csdn.net/weixin_58196051/article/details/124555732

没加除零处理,不过问题不大。 

import math  # 数学
import random  # 随机
import numpy as np
import matplotlib.pyplot as plt


def zhichi_w(zhichi, xy, a):  # 计算更新 w
    w = [0, 0]
    if len(zhichi) == 0:  # 初始化的0
        return w
    for i in zhichi:
        w[0] += a[i] * xy[0][i] * xy[2][i]  # 更新w
        w[1] += a[i] * xy[1][i] * xy[2][i]
    return w


def zhichi_b(zhichi, xy, a):  # 计算更新 b
    b = 0
    if len(zhichi) == 0:  # 初始化的0
        return 0
    for s in zhichi:  # 对任意的支持向量有 ysf(xs)=1 所有支持向量求解平均值
        sum = 0
        for i in zhichi:
            sum += a[i] * xy[2][i] * (xy[0][i] * xy[0][s] + xy[1][i] * xy[1][s])
        b += 1 / xy[2][s] - sum
    return b / len(zhichi)


def SMO(xy):
    # 初始化=========================================
    fx = []  # 储存所有的fx
    yfx = []  # 储存所有yfx-1的值
    Ek = []  # Ek,记录fx-y用于启发式搜索
    E_ = -1  # 贮存最大偏差,减少计算
    a1 = 0  # SMO  a1
    a2 = 0  # SMO  a2
    w_all = []
    b_all = []
    # 初始化结束======================================
    a = [0.0] * len(xy[0])  # 拉格朗日乘子
    zhichi = set()  # 支持向量下标
    loop = 1  # 循环标记(符合KKT)
    w = [0, 0]  # 初始化 w
    b = 0  # 初始化 b
    while loop:
        # 清除上次绘图
        plt.clf()
        plt.scatter(x1[0], x1[1], c=x1[2], alpha=0.8)  # 绘点训练集
        plt.scatter(x2[0], x2[1], c=x2[2], alpha=0.8)  # 绘点测试集
        plt.xlabel('x')  # x轴标签
        plt.ylabel('y')  # y轴标签
        plt.title('y=wx+b')  # 标题
        plt.xlim((0, 120))
        plt.ylim((0, 120))
        xl = np.arange(-10, 120, 0.1)  # 绘制分类线
        yl = (-w[0] * xl - b) / w[1]
        plt.plot(xl, yl, 'k')

        loop += 1
        if loop == 50:
            print("达到早停标准")
            print("循环了:", loop, "次")
            loop = 0
            break
        # 初始化=========================================
        fx = []  # 储存所有的fx
        yfx = []  # 储存所有yfx-1的值
        Ek = []  # Ek,记录fx-y用于启发式搜索
        E_ = -1  # 贮存最大偏差,减少计算
        a1 = 0  # SMO  a1
        a2 = 0  # SMO  a2
        # 初始化结束======================================
        # 寻找a1,a2======================================
        for i in range(len(xy[0])):  # 计算所有的 fx yfx-1 Ek
            fx.append(w[0] * xy[0][i] + w[1] * xy[1][i] + b)  # 计算 fx=wx+b
            yfx.append(xy[2][i] * fx[i] - 1)  # 计算 yfx-1
            Ek.append(fx[i] - xy[2][i])  # 计算 fx-y
            if i in zhichi:  # 之前看过的不看了,防止重复找某个a
                continue
            if yfx[i] <= yfx[a1]:
                a1 = i  # 得到偏离最大位置的下标(数值最小的)
        if yfx[a1] >= 0:  # 最小的也满足KKT
            print("循环了:", loop, "次")
            loop = 0  # 循环标记(符合KKT)置零(没有用到)
            break
        for i in range(len(xy[0])):  # 遍历找间隔最大的a2
            if i == a1:  # 如果是a1,跳过
                continue
            Ei = abs(Ek[i] - Ek[a1])  # |Eki-Eka1|
            if Ei < E_:  # 找偏差
                E_ = Ei  # 储存偏差的值
                a2 = i  # 储存偏差的下标
        # 寻找a1,a2结束===================================
        zhichi.add(a1)  # a1录入支持向量
        zhichi.add(a2)  # a2录入支持向量
        # 分析约束条件=====================================
        # c=a1*y1+a2*y2
        c = a[a1] * xy[2][a1] + a[a2] * xy[2][a2]  # 求出c
        # n=K11+k22-2*k12
        n = xy[0][a1] ** 2 + xy[1][a1] ** 2 + xy[0][a2] ** 2 + xy[1][a2] ** 2 - 2 * (
                xy[0][a1] * xy[0][a2] + xy[1][a1] * xy[1][a2])
        # 确定a1的可行域=====================================
        if xy[2][a1] == xy[2][a2]:
            L = max(0.0, a[a1] + a[a2] - 0.5)  # 下界
            H = min(0.5, a[a1] + a[a2])  # 上界
        else:
            L = max(0.0, a[a1] - a[a2])  # 下界
            H = min(0.5, 0.5 + a[a1] - a[a2])  # 上界
        if n > 0:
            a1_New = a[a1] - xy[2][a1] * (Ek[a1] - Ek[a2]) / n  # a1_New = a1_old-y1(e1-e2)/n
            # print("x1=",xy[0][a1],"y1=",xy[1][a1],"z1=",xy[2][a1],"x2=",xy[0][a2],"y2=",xy[1][a2],"z2=",xy[2][a2],"a1_New=",a1_New)
            # 越界裁剪============================================================
            if a1_New >= H:
                a1_New = H
            elif a1_New <= L:
                a1_New = L
        else:
            a1_New = min(H, L)
        # 参数更新=======================================
        a[a2] = a[a2] + xy[2][a1] * xy[2][a2] * (a[a1] - a1_New)  # a2更新
        a[a1] = a1_New  # a1更新
        w = zhichi_w(zhichi, xy, a)  # 更新w
        b = zhichi_b(zhichi, xy, a)  # 更新b
        # 标记支持向量======================================
        for i in zhichi:
            if a[i] == 0:  # 选了,但值仍为0
                loop = loop + 1
                e = 'silver'
            else:
                if xy[2][i] == 1:
                    e = 'b'
                else:
                    e = 'r'
            plt.scatter(x1[0][i], x1[1][i], c='none', s=100, linewidths=1, edgecolor=e)
        # 刷新图形
        plt.draw()
        plt.pause(0.2)
        # print("W=", w, "b=", b, "zhichi=", zhichi, "a1=", a[a1], "a2=", a[a2])

    print("支持向量数为:", len(zhichi), "\na为零支持向量:", loop)
    print("有用向量数:", len(zhichi) - loop)
    # 返回数据 w b =======================================
    return [w, b]


def panduan(xyz, w_b):
    c = 0
    for i in range(len(xyz[0])):
        if (xyz[0][i] * w_b[0][0] + xyz[1][i] * w_b[0][1] + w_b[1]) * xyz[2][i] < 0:
            c = c + 1
    return (1 - c / len(xyz[0])) * 100


# 生成数据集=============================================
x = []  # 数据集x属性
y = []  # 数据集y属性
x.extend(np.random.normal(loc=40.0, scale=10, size=100))  # 向x中放100个均值为30,方差为10,正态分布的随机数
x.extend(np.random.normal(loc=80.0, scale=10, size=100))  # 向x中放100个均值为80,方差为10,正态分布的随机数
y.extend(np.random.normal(loc=80.0, scale=10, size=100))  # 向y中放100个均值为80,方差为10,正态分布的随机数
y.extend(np.random.normal(loc=40.0, scale=10, size=100))  # 向y中放100个均值为30,方差为10,正态分布的随机数
c = [1] * 100  # c标签第一类为 1  x均值:30 y均值:80
c.extend([-1] * 100)  # # c标签第二类为 -1  x均值:80 y均值:30
# 生成训练集与测试集=======================================
lt = list(range(200))  # 得到一个顺序序列
random.shuffle(lt)  # 打乱序列
x1 = [[], [], []]  # 初始化x1
x2 = [[], [], []]  # 初始化x2
for i in lt[0:150]:  # 截取部分做训练集
    x1[0].append(x[i])  # 加上数据集x属性
    x1[1].append(y[i])  # 加上数据集y属性
    x1[2].append(c[i])  # 加上数据集c标签
for i in lt[150:200]:  # 截取部分做测试集
    x2[0].append(x[i])  # 加上数据集x属性
    x2[1].append(y[i])  # 加上数据集y属性
    x2[2].append(c[i])  # 加上数据集c标签
# 计算 w b============================================
plt.figure(1)  # 第一张画布
wb= SMO(x1)
print("w为:", wb[0], " b为:", wb[1])
# 计算正确率===========================================
print("训练集上的正确率为:", panduan(x1, wb), "%")
print("测试集上的正确率为:", panduan(x2, wb), "%")
# 绘图 ===============================================
# 红色和蓝色是训练集,圈着的是曾经选中的值,灰色的是选中但更新为0
# 黄色和蓝色是测试集
for i in range(len(x1[2])):  # 对训练集‘上色’
    if x1[2][i] == 1:
        x1[2][i] = 'r'  # 训练集  1 红色
    else:
        x1[2][i] = 'b'  # 训练集 -1 蓝色
for i in range(len(x2[2])):  # 对测试集‘上色’
    if x2[2][i] == 1:
        x2[2][i] = 'y'  # 测试集  1 黄色
    else:
        x2[2][i] = 'g'  # 测试集 -1 绿色
plt.show()  # 显示

结果:

支持向量机的动态训练过程

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值