pla感知器(C语言简单实现)

这篇博客介绍了二维平面点的分类问题,使用感知机模型和_perceptron_学习算法(PLA)。文章通过伪代码详细解释了迭代过程,并提供了C语言实现代码。在实例中,创建了一个中心为原点、半径不大于1的圆内点标记为-1,以及一个左边界大于2的矩形内点标记为1,每个区域包含1000个样本。通过调整不同的学习率,观察算法的收敛性和效果。
摘要由CSDN通过智能技术生成

一、思路

思路以布置的题目(给二维平面点分类)为例子讲述,所以w、x都是三维的

(1)背景

假设有一组容量为m的样本,总存储方式为

#define dim 3    //也就是方程的维度
#define eta 调试数值  //学习率,根据实际样本自己调整大小,过大会过拟合,过小迭代慢
double x[m][3]; //数组!的第一个维度是第k个点,第二维度是点的坐标(把截距b也合并进去了,并且默认x[][0] ≡ 1
int tag[m];    //表示每个点的标志,为1或-1

那么用于拟合判断点的方程为sgn函数

$$ sgn(x) = \begin{cases}1,x>0\ -1, x≤ 0\end{cases}$$

$$ y^{i} = sgn(\sum{k = 1}^{dim}w{k}*x_{k}^{i}) $$

(注释:是指的第个点,是指的维度)()算法核心迭代公式是

$$ w = w + η * y^{i}* x^{i} $$ (这里用不太像伪代码的伪代码解释一下过程)

至于这样迭代收敛的原因,其他博客写得很形象,这里推荐一个连接

【机器学习基石】感知机模型+PLA(二)_taoxing-CSDN博客

while 1:
 st = rand()%m  #随机产生一个迭代开始的位置(下标),只要样本点没错,就会一直迭代下去,直到把所有的点迭代完,这个st成为后面的迭代变量
 n = 0   #表示已经检查的点的个数
 while n < m:   #限制一下最多能找的点的个数,也就是样本个数        
     if st >= m:  #注意这里的判断,是必须考虑=m的情况,因为数组下标问题,否则会越界
         index = st % m
     else:
         index = st
     if judge_right(x[st]) == 0:#当第st个样本点判断错误时,结束该次迭代,并且进行修正
         for k in range(0,3):
             w[k] = w[k] + eta * tag[st] * x[st][k]
         break                                     
     st += 1
     n += 1
    if all_right() == 1 or n >= m:
     break

二、题目&代码

题目:构造中心为原点,半径不大于1的圆,其中所有点tag为-1,和一个左边界大于2的矩形,tag为1,两个区域样本个数各为1000个,利用w(w1,w2,w3)拟合z = w1+w2x2+w3x3,使得y = sgn(z)正确判断各个点

代码:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
​
#define PI2 6.2831853071795864 // PI*2
#define RAND01 ((double)rand()/RAND_MAX)
#define dim 3  //3维的
#define m 2000
#define eta 0.05
​
int tag[m];
double x[m][3], w[3];
​
//误差,作为收敛与否的判断用
int error(void)
{
 int all = 0, i;
 for (i = 0; i < m; i++)
     all += judge_right(x[i],w,tag[i]);
 printf("正确样本数为%d\n", all);
 return all;
}
​
//判断点是否预估正确,x是第m组的数据,所以为一维,tag,w本来就是一个一维数组
int judge_right(double x[3], double w[3], int right_y)
{
 int i,ress;
 double res = 0.;
 for (i = 0; i < dim; i++)
     res += w[i] * x[i];
 ress = res > 0 ? 1 : -1;
 return ress == right_y ? 1 : 0;      
}
​
void pla(void)
{
 int tmp, cnt = 0,i;
 for (i = 0; i < dim; i++)
     w[i] = 0;
 while (1)
 {
     int n, index;
     tmp = rand() % m;
     for (n = 0, i = tmp; n < m; i++, n++)//tmp是指的开始变化的下标,index是转化后的真正下标(第index组
     {       
         if (i >=  m)
             index = i % m;
         else
             index = i;
         if (!judge_right(x[index], w, tag[index]))
         {
             for (tmp = 0; tmp < dim; tmp++)
                 w[tmp] = w[tmp] + eta * tag[index] * x[index][tmp];
             break;
         }
     }
     cnt++;
     printf("迭代%d次\n", cnt);
     printf("w值为:");
     for (int k = 0; k < dim; k++)
         printf("%lf ",w[k]);
     puts(" ");
     if (error() >= m)
         break;
 }
}
​
​
int main()
{
 int i, I ;
 double theta, r;
 srand(time(0));
 // 生成2000个样本(x[i][0],x[i][1],tag[i]), i=0...1999,x是二维的
 for (i = 0; i < 1000; i++)
 {
     theta = PI2 * RAND01;
     r = RAND01;
     x[i][0] = 1;
     x[i][1] = r * cos(theta); // in a disc圆盘为-1
     x[i][2] = r * sin(theta);
     tag[i] = -1;
​
     I = 1000 + i;
     x[I][0] = 1;
     x[I][1] = 2 + RAND01; // in a box 矩形为1
     x[I][2] = 2 * (RAND01 - 0.5);
     tag[I] = 1;
 }
 pla();
 printf("迭代结束,tag = sgn( ");
 for (int i = 0; i < dim; i++)
     printf("%lf * x%d +", w[i], i);
 puts(")\n");
 return 0;
}

三、运行结果

(自己选的学习率为0.05)

(这个学习率选的1)

(等俺电脑修好了就来试试easy_x绘图,把图像画出来)

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

robinbird_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值