机器学习---用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 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现 ...
随机推荐
- [洛谷P5323][BJOI2019]光线
题目大意:有$n$层玻璃,每层玻璃会让$a\%$的光通过,并把$b\%$的光反射.有一束光从左向右射过,问多少的光可以透过这$n$层玻璃 题解:事实上会发现,可以把连续的几层玻璃合成一层玻璃,但是要注 ...
- go 读取BMP文件头二进制读取
BMP文件头定义: WORD 两个字节 16bit DWORD 四个字节 32bit package main import ( "encoding/binary" "f ...
- 创建包含CRUD操作的Web API接口3:实现Post方法
本节是前面两节的延续,前面我们为Web API创建了必要的基础设施,并实现了Get方法.在这里,我们将在Web API中实现POST方法. 在RESTful架构中,使用HTTP POST请求用来在数据 ...
- Centos 7系统在线安装docker
在线安装docker 以下操作步骤均在root用户下操作 1. 检查内核是否符合要求 Docker 要求 Centos系统的内核版本高于 3.10 ,建议在Centos 7版本命令如下: uname ...
- Web SSH远程连接利器:gotty
Web SSH远程连接利器:gotty 这个东东能让你使用浏览器连接你远程的机器! 一. 环境准备 下载https://github.com/yudai/gotty. 请先配置好 Golang 环境, ...
- php后台实现页面跳转的方法-转载
地址:http://blog.csdn.net/abandonship/article/details/6459104 其中方法三的js代码在tp框架使用存在故障,一个是需要把代码写在一起(可能也不需 ...
- 如何恢复SVN被删除文件、文件夹
转自:https://blog.csdn.net/chuangxin/article/details/81226657 一.摘要本文讲述在客户端(如:Tortoise SVN,开发工具IDE SVN插 ...
- JS去除字符串左右两端的空格(转载)
来源:https://www.cnblogs.com/fanyf/p/3785387.html var str=' 测试 '; 一.函数 <script type="t ...
- Redis3.2集群部署安装
Redis集群部署安装 Linux版本:CentOS release 6.9 Redis 版本:redis-3.2.12.tar.gz 1.执行解压命令 tar -xzf redis-3.2.12.t ...
- MySQL Backup--Xtrabackup备份异常(MySQL Server has gone away)
错误场景MySQL 版本:5.7.24XtraBackup 版本:2.4.8CentOS 版本:6.5 MySQL需要新增一个从库,为避免XtraBackup备份影响生产,选择在从库上进行备份,备份脚 ...