机器学习---用python实现感知机算法和口袋算法(Machine Learning PLA Pocket Algorithm Application)

之前在《机器学习---感知机(Machine Learning Perceptron)》一文中介绍了感知机算法的理论知识,现在让我们来实践一下。

有两个数据文件:data1和data2,分别用于PLA和Pocket Algorithm。可在以下地址下载:

先回顾一下感知机算法:

1,初始化w

2,找出一个分类错误点

3,修正错误,假设迭代次数为t次(t=1,2,...),那么修正公式为:

4,直至没有分类错误点,返回最终的w

接下来让我们安照算法步骤,一步一步进行。

首先导入需要用到的库,其中pandas用于读取数据文件,matplotlib用于画图,numpy用于数组运算:

import pandas as pd
import matplotlib.pyplot as plt
fig,ax=plt.subplots()
import numpy as np

读取数据文件:

data=pd.read_csv(r"...\data1.csv",header=None)

提取特征和目标:

X=data.iloc[:,[0,1]]  #提取特征
y=data[2]   #提取目标

提取不同类别的数据,用于画图:

x_positive=X[y==1]
x_negative=X[y==-1]

画图:

ax.scatter(x_positive[0],x_positive[1],marker="o",label="y=+1")
ax.scatter(x_negative[0],x_negative[1],marker="x",label="y=-1")
ax.legend()
ax.set_xlabel("x1")
ax.set_ylabel("x2")
ax.set_title("Original Data")

从上图可以看到数据是线性可分的,接下来我们先把数据归一化:

mean=X.mean(axis=0)
sigma=X.std(axis=0)
X=(X-mean)/sigma

再画图看看:

设置好特征和权重,用于数组运算:

X[2]=np.ones((X.shape[0],1))   #给特征增加一列常数项
X=X.values    #把特征转换成ndarray格式

###初始化w###
w=X[0].copy()  #选取原点到第一个点的向量作为w的初始值
w[2]=0  #增加一项---阈值,阈值初始化为0
w=w.reshape(3,1)

画出初始法向量和初始分类直线(因为是在二维空间,所以是直线):

###画出初始法向量###
ax.scatter(w[0],w[1],color="red")
ax.plot([0,w[0]],[0,w[1]])  

###画出初始分类直线###
line_x=np.linspace(-3,3,10)
line_y=(-w[2]-w[0]*line_x)/w[1]
ax.plot(line_x,line_y)

注:因为w1x1+w2x2+b=0,现在我们已经有了w和b的值,因此只需要设置x1的值,就可以计算出x2的值。

注:注意要适当调整一下图像比例,否则显示不对,具体请见完整代码。

现在我们已经完成初始化w的工作,接下去就是要找出分类错误点。现在的思路是:先计算出在当前参数w下的预测目标,然后把其和目标y进行比较,这样就可以知道分类错误的地方了。

scores=np.dot(X,w)  #把特征和权重点乘,得到目前参数下预测出的目标分数

y_pred=np.ones((scores.shape[0],1))  #设置预测目标,初始化值全为1,形状和目标分数相同
y=y.values.reshape((y_pred.shape[0],1))  #把目标转换成ndarray格式,形状和预测目标相同

loc_negative=np.where(scores<0)[0]  #标记分数为负数的地方
y_pred[loc_negative]=-1  #使标记为负数的地方预测目标变为-1

loc_wrong=np.where(y_pred!=y)[0]  #标记分类错误的地方

找出分类错误点后,我们对w进行修正(这里选取第一个分类错误点进行更新):

w=w+y[loc_wrong][0]*X[loc_wrong,:][0].reshape(3,1)

最后进行迭代就可以找出最终的w:

for i in range(100):
    scores=np.dot(X,w)  #把特征和权重点乘,得到此参数下预测出的目标分数

    y_pred=np.ones((scores.shape[0],1))  #设置预测目标,初始化值全为1,形状和目标分数相同

    loc_negative=np.where(scores<0)[0]  #标记分数为负数的地方
    y_pred[loc_negative]=-1  #使标记为负数的地方预测目标变为-1

    loc_wrong=np.where(y_pred!=y)[0]  #标记分类错误的地方
    print("错误分类点有{}个。".format(len(loc_wrong)))
    if len(loc_wrong)>0:
        w=w+y[loc_wrong][0]*X[loc_wrong,:][0].reshape(3,1)
    else:
        break

print("参数w:{}".format(w))
print("分类直线:{}x1+{}x2+{}=0".format(w[0][0],w[1][0],w[2][0]))
line_x=np.linspace(-3,3,10)
line_y=(-w[2]-w[0]*line_x)/w[1]
ax.plot(line_x,line_y)

运行结果:

错误分类点有5个。
错误分类点有2个。
错误分类点有3个。
错误分类点有0个。
参数w:[[0.24622161]
 [2.81328976]
 [1.        ]]
分类直线:0.2462216100520832x1+2.8132897563595076x2+1.0=0

画出的分类直线:

最后的最后,将上述代码整理一下。感知机算法完整代码如下(除去用于画图的代码,核心代码不到20行):

import pandas as pd
import matplotlib.pyplot as plt
fig,ax=plt.subplots(figsize=(6,6))
import numpy as np

data=pd.read_csv(r"...\data1.csv",header=None)

X=data.iloc[:,[0,1]]  #提取特征
y=data[2]   #提取目标

###把数据归一化###
mean=X.mean(axis=0)
sigma=X.std(axis=0)
X=(X-mean)/sigma

###提取不同类别的数据,用于画图###
x_positive=X[y==1]
x_negative=X[y==-1]

ax.scatter(x_positive[0],x_positive[1],marker="o",label="y=+1")
ax.scatter(x_negative[0],x_negative[1],marker="x",label="y=-1")
ax.legend()
ax.set_xlabel("x1")
ax.set_ylabel("x2")
ax.set_title("Standardized Data")
ax.set_xlim(-2,2.6)
ax.set_ylim(-2,2.6)

X[2]=np.ones((X.shape[0],1))   #给特征增加一列常数项
X=X.values    #把特征转换成ndarray格式

###初始化w###
w=X[0].copy()  #选取原点到第一个点的向量作为w的初始值
w[2]=0  #增加一项---阈值,阈值初始化为0
w=w.reshape(3,1)

y=y.values.reshape(100,1)  #把目标转换成ndarray格式,形状和预测目标相同

def compare(X,w,y):
    ###用于比较预测目标y_pred和实际目标y是否相符,返回分类错误的地方loc_wrong###
    ###输入特征,权重,目标###
    scores=np.dot(X,w)  #把特征和权重点乘,得到此参数下预测出的目标分数

    y_pred=np.ones((scores.shape[0],1))  #设置预测目标,初始化值全为1,形状和目标分数相同

    loc_negative=np.where(scores<0)[0]  #标记分数为负数的地方
    y_pred[loc_negative]=-1  #使标记为负数的地方预测目标变为-1

    loc_wrong=np.where(y_pred!=y)[0]  #标记分类错误的地方

    return loc_wrong

def update(X,w,y):
    ###用于更新权重w,返回更新后的权重w###
    ###输入特征,权重,目标###
    w=w+y[compare(X,w,y)][0]*X[compare(X,w,y),:][0].reshape(3,1)
    return w

def perceptron(X,w,y):
    ###感知机算法,显示最终的权重和分类直线,并画出分类直线###
    ###输入特征,初始权重,目标###
    while len(compare(X,w,y))>0:
        print("错误分类点有{}个。".format(len(compare(X,w,y))))
        w=update(X,w,y)

    print("参数w:{}".format(w))
    print("分类直线:{}x1+{}x2+{}=0".format(w[0][0],w[1][0],w[2][0]))
    line_x=np.linspace(-3,3,10)
    line_y=(-w[2]-w[0]*line_x)/w[1]
    ax.plot(line_x,line_y)

plt.show()


接下来看一下data2文件和口袋算法的应用。首先回顾一下Pocket Algorithm:

1,初始化w,把w作为最好的解放入口袋

2,随机找出一个分类错误点

3,修正错误,假设迭代次数为t次(t=1,2,...),那么修正公式为:

4,如果wt+1比w犯的错误少,那么用wt+1替代w,放入口袋

5,经过t次迭代后停止,返回口袋里最终的结果

口袋算法和PLA差不多,因此代码还是用上述感知机算法的框架,只需要局部修改一下即可。

首先画出原始数据图像和归一化后的数据图像:(代码和之前类似,故在此不再赘述)

     

可以看到数据是线性不可分的。接下来修改一下perceptron函数和update函数。

def perceptron_pocket(X,w,y):
    ###感知机口袋算法,显示n次迭代后最好的权重和分类直线,并画出分类直线###
    ###输入特征,初始权重,目标###
    best_len=len(compare(X,w,y))  #初始化最少的分类错误点个数
    best_w=w  #初始化口袋里最好的参数w
    for i in range(100):
        print("错误分类点有{}个。".format(len(compare(X,w,y))))
        w=update(X,w,y)
        #如果当前参数下分类错误点个数小于最少的分类错误点个数,那么更新最少的分类错误点个数和口袋里最好的参数w
        if len(compare(X,w,y))<best_len:
            best_len=len(compare(X,w,y))
            best_w=w

    print("参数best_w:{}".format(best_w))
    print("分类直线:{}x1+{}x2+{}=0".format(best_w[0][0],best_w[1][0],best_w[2][0]))
    print("最少分类错误点的个数:{}个".format(best_len))
    line_x=np.linspace(-3,3,10)
    line_y=(-best_w[2]-best_w[0]*line_x)/best_w[1]
    ax.plot(line_x,line_y)

perceptron函数主要增加了一个口袋,用于存放最好的解,函数名称改为perceptron_pocket。

def update(X,w,y):
    ###用于更新权重w,返回更新后的权重w###
    ###输入特征,权重,目标###
    num=len(compare(X,w,y)) #分类错误点的个数
    w=w+y[compare(X,w,y)][np.random.choice(num)]*X[compare(X,w,y),:][np.random.choice(num)].reshape(3,1)
    return w

update函数将“选取第一个分类错误点进行更新”修改为“随机选取分类错误点进行更新”。

运行结果如下(由于带有随机性,每次运行结果都不同):

错误分类点有9个。
错误分类点有30个。
错误分类点有11个。
错误分类点有24个。
错误分类点有5个。
错误分类点有22个。
错误分类点有16个。
错误分类点有17个。
错误分类点有5个。
错误分类点有15个。
错误分类点有5个。
错误分类点有15个。
错误分类点有6个。
错误分类点有13个。
错误分类点有7个。
错误分类点有12个。
错误分类点有9个。
错误分类点有14个。
错误分类点有12个。
错误分类点有16个。
错误分类点有9个。
错误分类点有10个。
错误分类点有12个。
错误分类点有12个。
错误分类点有7个。
错误分类点有16个。
错误分类点有5个。
错误分类点有7个。
错误分类点有6个。
错误分类点有10个。
错误分类点有6个。
错误分类点有9个。
错误分类点有11个。
错误分类点有7个。
错误分类点有5个。
错误分类点有11个。
错误分类点有6个。
错误分类点有8个。
错误分类点有6个。
错误分类点有12个。
错误分类点有6个。
错误分类点有11个。
错误分类点有14个。
错误分类点有10个。
错误分类点有5个。
错误分类点有5个。
错误分类点有5个。
错误分类点有4个。
错误分类点有6个。
错误分类点有6个。
错误分类点有6个。
错误分类点有9个。
错误分类点有6个。
错误分类点有10个。
错误分类点有6个。
错误分类点有7个。
错误分类点有6个。
错误分类点有10个。
错误分类点有6个。
错误分类点有10个。
错误分类点有5个。
错误分类点有10个。
错误分类点有6个。
错误分类点有8个。
错误分类点有6个。
错误分类点有5个。
错误分类点有6个。
错误分类点有7个。
错误分类点有9个。
错误分类点有7个。
错误分类点有6个。
错误分类点有7个。
错误分类点有6个。
错误分类点有4个。
错误分类点有6个。
错误分类点有10个。
错误分类点有6个。
错误分类点有11个。
错误分类点有15个。
错误分类点有10个。
错误分类点有5个。
错误分类点有5个。
错误分类点有6个。
错误分类点有9个。
错误分类点有6个。
错误分类点有8个。
错误分类点有5个。
错误分类点有10个。
错误分类点有5个。
错误分类点有10个。
错误分类点有6个。
错误分类点有10个。
错误分类点有18个。
错误分类点有9个。
错误分类点有10个。
错误分类点有10个。
错误分类点有5个。
错误分类点有5个。
错误分类点有6个。
错误分类点有8个。
参数best_w:[[-1.09227879]
 [ 5.19393394]
 [ 1.        ]]
分类直线:-1.0922787897353627x1+5.193933943326238x2+1.0=0
最少分类错误点的个数:4个

分类直线画图如下:

口袋算法完整代码如下:

import pandas as pd
import matplotlib.pyplot as plt
fig,ax=plt.subplots()
import numpy as np

data=pd.read_csv(r"...\data2.csv",header=None)

X=data.iloc[:,[0,1]]  #提取特征
y=data[2]   #提取目标

###把数据归一化###
mean=X.mean(axis=0)
sigma=X.std(axis=0)
X=(X-mean)/sigma

###提取不同类别的数据,用于画图###
x_positive=X[y==1]
x_negative=X[y==-1]

ax.scatter(x_positive[0],x_positive[1],marker="o",label="y=+1")
ax.scatter(x_negative[0],x_negative[1],marker="x",label="y=-1")
ax.legend()
ax.set_xlabel("x1")
ax.set_ylabel("x2")
ax.set_title("standardized Data")

X[2]=np.ones((X.shape[0],1))   #增加一列常数项
X=X.values    #把特征转换成ndarray格式

###初始化w###
w=X[0].copy()  #选取原点到第一个点的向量作为w的初始值
w[2]=0  #增加一项---阈值,阈值初始化为0
w=w.reshape(3,1)

y=y.values.reshape(100,1)  #把目标转换成ndarray格式,形状和预测目标相同

def compare(X,w,y):
    ###用于比较预测目标y_pred和实际目标y是否相符,返回分类错误的地方loc_wrong###
    ###输入特征,权重,目标###
    scores=np.dot(X,w)  #把特征和权重点乘,得到此参数下预测出的目标分数

    y_pred=np.ones((scores.shape[0],1))  #设置预测目标,初始化值全为1,形状和目标分数相同

    loc_negative=np.where(scores<0)[0]  #标记分数为负数的地方
    y_pred[loc_negative]=-1  #使标记为负数的地方预测目标变为-1

    loc_wrong=np.where(y_pred!=y)[0]  #标记分类错误的地方

    return loc_wrong

def update(X,w,y):
    ###用于更新权重w,返回更新后的权重w###
    ###输入特征,权重,目标###
    num=len(compare(X,w,y)) #分类错误点的个数
    w=w+y[compare(X,w,y)][np.random.choice(num)]*X[compare(X,w,y),:][np.random.choice(num)].reshape(3,1)
    return w

def perceptron_pocket(X,w,y):
    ###感知机口袋算法,显示n次迭代后最好的权重和分类直线,并画出分类直线###
    ###输入特征,初始权重,目标###
    best_len=len(compare(X,w,y))  #初始化最少的分类错误点个数
    best_w=w  #初始化口袋里最好的参数w
    for i in range(100):
        print("错误分类点有{}个。".format(len(compare(X,w,y))))
        w=update(X,w,y)
        #如果当前参数下分类错误点个数小于最少的分类错误点个数,那么更新最少的分类错误点个数和口袋里最好的参数w
        if len(compare(X,w,y))<best_len:
            best_len=len(compare(X,w,y))
            best_w=w

    print("参数best_w:{}".format(best_w))
    print("分类直线:{}x1+{}x2+{}=0".format(best_w[0][0],best_w[1][0],best_w[2][0]))
    print("最少分类错误点的个数:{}个".format(best_len))
    line_x=np.linspace(-3,3,10)
    line_y=(-best_w[2]-best_w[0]*line_x)/best_w[1]
    ax.plot(line_x,line_y)

plt.show()

原文地址:https://www.cnblogs.com/HuZihu/p/10764916.html

时间: 2024-10-08 05:30:41

机器学习---用python实现感知机算法和口袋算法(Machine Learning PLA Pocket Algorithm Application)的相关文章

机器学习案例学习【每周一例】之 Titanic: Machine Learning from Disaster

https://zhuanlan.zhihu.com/p/25185856 [Kaggle实例分析]Titanic Machine Learning from Disasterhttp://blog.csdn.net/wiking__acm/article/details/42742961 Titanic: Machine Learning from Disaster(Kaggle 数据挖掘竞赛)http://blog.csdn.net/han_xiaoyang/article/details/

机器学习【1】(Python Machine Learning读书笔记)

依旧是作为读书笔记发布,不涉及太多代码和工具,作为了解性文章来介绍机器学习. 文章主要分为两个部分,machine learning的概述和 scikit-learn的简单介绍,两部分关系紧密,合并书写,以致整体篇幅较长,分为1.2两篇. 首先,是关于机器学习.要点如下: 1.1 机器学习三种主要方式 1.2 四大过程 1.3 python相关实现(安装包) [1.1] 机器学习方式主要有三大类:supervised learning(监督式学习), unsupervised learning(

Python Tools for Machine Learning

Python Tools for Machine Learning Python is one of the best programming languages out there, with an extensive coverage in scientific computing: computer vision, artificial intelligence, mathematics, astronomy to name a few. Unsurprisingly, this hold

《机器学习实战》之二分K-均值聚类算法的python实现

<机器学习实战>之二分K-均值聚类算法的python实现 上面博文介绍了K-均值聚类算法及其用python实现,上篇博文中的两张截图,我们可以看到,由于K-均值聚类算法中由于初始质心的选取,会造成聚类的局部最优,并不是全局最优,因此,会造成聚类的效果并不理想,为克服K-均值算法收敛于局部最小值的问题,就有了二分K-均值算法. 二分K-均值聚类算法 二分K均值算法是基本K均值算法的直接扩充,其基本思想是:为了得到K个簇,首先将所有点的集合分裂成两个簇,然后从这些簇中选取一个继续分裂,迭代直到产生

机器学习:Python实现聚类算法(三)之总结

考虑到学习知识的顺序及效率问题,所以后续的几种聚类方法不再详细讲解原理,也不再写python实现的源代码,只介绍下算法的基本思路,使大家对每种算法有个直观的印象,从而可以更好的理解函数中参数的意义及作用,而重点是放在如何使用及使用的场景. (题外话: 今天看到一篇博文:刚接触机器学习这一个月我都做了什么?  里面对机器学习阶段的划分很不错,就目前而言我们只要做到前两阶段即可) 因为前两篇博客已经介绍了两种算法,所以这里的算法编号从3开始. 3.Mean-shift 1)概述 Mean-shift

机器学习经典分类算法 —— k-均值算法(附python实现代码及数据集)

目录 工作原理 python实现 算法实战 对mnist数据集进行聚类 小结 附录 工作原理 聚类是一种无监督的学习,它将相似的对象归到同一个簇中.类似于全自动分类(自动的意思是连类别都是自动构建的).K-均值算法可以发现k个不同的簇,且每个簇的中心采用簇中所含值的均值计算而成.它的工作流程的伪代码表示如下: 创建k个点作为起始质心 当任意一个点的簇分配结果发生改变时 对数据集中的每个数据点 对每个质心 计算质心与数据点之间的距离 将数据点分配到距其最近的簇 对每一个簇,计算簇中所有点的均值并将

机器学习优化算法之爬山算法小结

简言 机器学习的项目,不可避免的需要补充一些优化算法,对于优化算法,爬山算法还是比较重要的.鉴于此,花了些时间仔细阅读了些爬山算法的paper.基于这些,做一些总结. 目录 1. 爬山算法简单描述  2. 爬山算法的主要算法 2.1 首选爬山算法 2.2 最陡爬山算法 2.3 随机重新开始爬山算法 2.4 模拟退火算法(也是爬山算法) 3. 实例求解 正文 爬山算法,是一种局部贪心的最优算法. 该算法的主要思想是:每次拿相邻点与当前点进行比对,取两者中较优者,作为爬坡的下一步. 举一个例子,求解

《机器学习实战》学习笔记:k-近邻算法实现

上一学期主要的学习和研究任务是模式识别.信号理论和图像处理,实际上这些领域都与机器学习有或多或少的交集.因此,仍在继续深入阅读<机器学习>.观看斯坦福大学的机器学习课程.在此过程中因为未来课题组项目的要求,需要接触Python,因此选择了<机器学习实战>这本书,同时参考教材和视频一起学习.事实上该书的理论研究不够深入,只能算是练习Python并验证一些著名的机器学习算法的工具书了. 在介绍k-近邻算法之前,对机器学习算法进行简单的分类和梳理:简单来说,机器学习主要分为两大类,有监督

机器学习之基于朴素贝叶斯文本分类算法

原理 在分类(classification)问题中,常常需要把一个事物分到某个类别.一个事物具有很多属性,把它的众多属性看做一个向量,即x=(x1,x2,x3,-,xn),用x这个向量来代表这个事物.类别也是有很多种,用集合Y=y1,y2,-ym表示.如果x属于y1类别,就可以给x打上y1标签,意思是说x属于y1类别.这就是所谓的分类(Classification). x的集合记为X,称为属性集.一般X和Y的关系是不确定的,你只能在某种程度上说x有多大可能性属于类y1,比如说x有80%的可能性属