机器学习---用python实现感知机算法和口袋算法(Machine Learning PLA Pocket Algorithm Application)
之前在《机器学习---感知机(Machine Learning Perceptron)》一文中介绍了感知机算法的理论知识,现在让我们来实践一下。
有两个数据文件:data1和data2,分别用于PLA和Pocket Algorithm。可在以下地址下载:https://github.com/RedstoneWill/MachineLearningInAction/tree/master/Perceptron%20Linear%20Algorithm/data。
先回顾一下感知机算法:
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()
另外附上感知机算法用损失函数和梯度下降法实现的代码(和上述感知机算法的不同之处在于w每次是用离当前分类直线最远的那个分类错误点进行更新的):
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] #提取目标 class Perceptron:
def __init__(self):
self._w = self._b = None def standardization(self,X):
#将输入的X归一化
mean=X.mean(axis=0)
sigma=X.std(axis=0)
X=(X-mean)/sigma return X def fit(self, X, y, lr=1, epoch=100):
#训练数据
#将输入的X,y转换为numpy数组
X, y = np.asarray(X, np.float32), np.asarray(y, np.float32)
#初始化w,b
self._w = np.zeros(X.shape[1])
self._b = 0 for _ in range(epoch):
# 计算 w·x+b
y_pred = np.dot(X,self._w) + self._b
# 标记使损失函数最大的样本
idx = np.argmax(np.maximum(0, -y_pred * y))
# 若该样本被正确分类,则结束训练
if y[idx] * y_pred[idx] > 0:
break
# 否则,让参数沿着负梯度方向走一步
else:
delta = lr * y[idx]
self._w += delta * X[idx]
self._b += delta return self._w,self._b def print_results(self,w,b):
print("参数w:{}".format(w))
print("参数b:{}".format(b))
print("分类直线:{}x1+{}x2+{}=0".format(w[0],w[1],b)) def draw_pics(self,X,w,b):
#提取不同分类的数据
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") #画出分类直线
line_x=np.linspace(-3,3,10)
line_y=(-b-w[0]*line_x)/w[1]
ax.plot(line_x,line_y) def predict(self,X):
return np.where(np.dot(X,self._w)-self._b>0,1,-1) if __name__=="__main__":
PLA=Perceptron()
X=PLA.standardization(X)
w,b=PLA.fit(X,y,lr=1,epoch=100)
PLA.print_results(w,b)
PLA.draw_pics(X,w,b)
机器学习---用python实现感知机算法和口袋算法(Machine Learning PLA Pocket Algorithm Application)的更多相关文章
- 机器学习---用python实现朴素贝叶斯算法(Machine Learning Naive Bayes Algorithm Application)
在<机器学习---朴素贝叶斯分类器(Machine Learning Naive Bayes Classifier)>一文中,我们介绍了朴素贝叶斯分类器的原理.现在,让我们来实践一下. 在 ...
- 机器学习案例学习【每周一例】之 Titanic: Machine Learning from Disaster
下面一文章就总结几点关键: 1.要学会观察,尤其是输入数据的特征提取时,看各输入数据和输出的关系,用绘图看! 2.训练后,看测试数据和训练数据误差,确定是否过拟合还是欠拟合: 3.欠拟合的话,说明模 ...
- 机器学习:Python中如何使用支持向量机(SVM)算法
(简单介绍一下支持向量机,详细介绍尤其是算法过程可以查阅其他资) 在机器学习领域,支持向量机SVM(Support Vector Machine)是一个有监督的学习模型,通常用来进行模式识别.分类(异 ...
- 【机器学习Machine Learning】资料大全
昨天总结了深度学习的资料,今天把机器学习的资料也总结一下(友情提示:有些网站需要"科学上网"^_^) 推荐几本好书: 1.Pattern Recognition and Machi ...
- 机器学习(Machine Learning)&深度学习(Deep Learning)资料【转】
转自:机器学习(Machine Learning)&深度学习(Deep Learning)资料 <Brief History of Machine Learning> 介绍:这是一 ...
- 机器学习(Machine Learning)&深度学习(Deep Learning)资料汇总 (上)
转载:http://dataunion.org/8463.html?utm_source=tuicool&utm_medium=referral <Brief History of Ma ...
- 机器学习(Machine Learning)与深度学习(Deep Learning)资料汇总
<Brief History of Machine Learning> 介绍:这是一篇介绍机器学习历史的文章,介绍很全面,从感知机.神经网络.决策树.SVM.Adaboost到随机森林.D ...
- 【Machine Learning】KNN算法虹膜图片识别
K-近邻算法虹膜图片识别实战 作者:白宁超 2017年1月3日18:26:33 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...
- 【Machine Learning】Python开发工具:Anaconda+Sublime
Python开发工具:Anaconda+Sublime 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现 ...
随机推荐
- UOJ343 清华集训2017 避难所 构造、打表
传送门 玄学题 考虑构造三个数\(p_1p_2,p_1p_2,p_1p_2\)满足贪心分解会分解为\(p_1^3,p_2,p_2,p_2\),那么需要满足条件 1.\(p_1 , p_2 \in Pr ...
- activiti串行会签的使用
1.串行任务的配置 2.当任务走到串行会签节点时,会从你之前保存的流程变量中找集合(我这里设置的assigneeList),串行会签会根据这个集合设置一系列该节点的流程变量 3.结束条件的设置,若满足 ...
- Mycat分布式数据库架构解决方案--Server.xml详解
echo编辑整理,欢迎转载,转载请声明文章来源.欢迎添加echo微信(微信号:t2421499075)交流学习. 百战不败,依不自称常胜,百败不颓,依能奋力前行.--这才是真正的堪称强大!!! 该文件 ...
- 【洛谷 P3193】 [HNOI2008]GT考试(KMP,dp,矩阵乘法)
题目链接 \(f[i][j]\)表示准考证号到第\(i\)位,不吉利数字匹配到第\(j\)位的方案数. 答案显然是\(\sum_{i=0}^{m-1}f[n][i]\) \(f[i][j]=\sum_ ...
- 装饰器带类参数 & 一个函数应用多个装饰器
装饰器:不改变原函数的基础上,给函数增加功能的方式,称为装饰器 即:为已经存在的对象添加额外的功能 装饰器其实就是一个闭包,把一个函数当做参数后返回一个替代版的函数 decos.py:(装饰器的参数类 ...
- centos7.5 配置sftp
1.创建sftp组 groupadd sftp 2.sftp组的用户的home目录统一指定到/u01/sftp下 mkdir -p /u01/sftp/ 3.创建一个sftp用户,用户名为devsft ...
- oracle 删除表空间
第一步,删除表空间前如果忘记表空间名称和用户名,可以通过以下命令进行查询. ---查找用户select * from dba_users; --查找工作空间的路径select * from dba_d ...
- Python_列表操作1
1.列表相关操作:声明,添加,删除,修改,获取len colors=['红','橙','黄','绿'] #声明一个列表 def colors_getall(): #获取列表中所有元素 return c ...
- wget下载出现错误 403:Forbidden
在我尝试wget下载一张图片的时候,出现了如下错误: wget "https://k4b8k3x5.ssl.hwcdn.net/content/140516/1622-saaya-irie- ...
- Django之路——10 django的分页组件
Django的分页器(paginator) view from django.shortcuts import render,HttpResponse # Create your views here ...