之前在《机器学习---感知机(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)的更多相关文章

  1. 机器学习---用python实现朴素贝叶斯算法(Machine Learning Naive Bayes Algorithm Application)

    在<机器学习---朴素贝叶斯分类器(Machine Learning Naive Bayes Classifier)>一文中,我们介绍了朴素贝叶斯分类器的原理.现在,让我们来实践一下. 在 ...

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

     下面一文章就总结几点关键: 1.要学会观察,尤其是输入数据的特征提取时,看各输入数据和输出的关系,用绘图看! 2.训练后,看测试数据和训练数据误差,确定是否过拟合还是欠拟合: 3.欠拟合的话,说明模 ...

  3. 机器学习:Python中如何使用支持向量机(SVM)算法

    (简单介绍一下支持向量机,详细介绍尤其是算法过程可以查阅其他资) 在机器学习领域,支持向量机SVM(Support Vector Machine)是一个有监督的学习模型,通常用来进行模式识别.分类(异 ...

  4. 【机器学习Machine Learning】资料大全

    昨天总结了深度学习的资料,今天把机器学习的资料也总结一下(友情提示:有些网站需要"科学上网"^_^) 推荐几本好书: 1.Pattern Recognition and Machi ...

  5. 机器学习(Machine Learning)&深度学习(Deep Learning)资料【转】

    转自:机器学习(Machine Learning)&深度学习(Deep Learning)资料 <Brief History of Machine Learning> 介绍:这是一 ...

  6. 机器学习(Machine Learning)&深度学习(Deep Learning)资料汇总 (上)

    转载:http://dataunion.org/8463.html?utm_source=tuicool&utm_medium=referral <Brief History of Ma ...

  7. 机器学习(Machine Learning)与深度学习(Deep Learning)资料汇总

    <Brief History of Machine Learning> 介绍:这是一篇介绍机器学习历史的文章,介绍很全面,从感知机.神经网络.决策树.SVM.Adaboost到随机森林.D ...

  8. 【Machine Learning】KNN算法虹膜图片识别

    K-近邻算法虹膜图片识别实战 作者:白宁超 2017年1月3日18:26:33 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

  9. 【Machine Learning】Python开发工具:Anaconda+Sublime

    Python开发工具:Anaconda+Sublime 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现 ...

随机推荐

  1. 使用QMetaObject获取类的属性

    const QMetaObject *metaobject = object->metaObject(); int count = metaobject->propertyCount(); ...

  2. [CodeChef-ANUDTQ] Dynamic Trees and Queries

    类似维护括号序列,给每个点建两个点,然后所有操作都能轻松支持了.注意sum和lastans是long long. #include<cstdio> #include<algorith ...

  3. Jekyll自动检测代码更新

    Jekyll自动检测代码更新 jekyll是一个静态博客生成软件, 我们把代码放在一个仓库里, 只要远程代码更新, 我们就从把它拉到自己的服务器, 然后重新启动jekyll. cd /root/blo ...

  4. VsCode中好用的git源代码管理插件GitLens

    1.在插件tab搜索GitLens 2.安装成功后将光标移至代码行即会显示代码编写者 3.在VsCode左侧菜单栏,点击GitLens图标即可查看History,也可以查看全部的日志 4.查看上下pu ...

  5. Mongodb 学习笔记(一)

    MongoDB 是一款开源.跨平台.分布式,具有大数据处理能力的文档存储数据库.在 2007 年由 MongoDB 软件公司开发完成,并实现全部代码源发展.目 前,该文档数据库被国内外众多知名网因所采 ...

  6. 在SQL Server中,为何都建议禁止 VIA 协议,VIA协议具体内容是什么?

    在SQL Server 在SQL Server中,为何都建议禁止 VIA 协议,VIA协议具体内容是什么? 中,为何都建议禁止 VIA 协议,VIA协议具体内容是什么? 在SQL Server中,为何 ...

  7. go语言实现限流器

    本文:https://chai2010.cn/advanced-go-programming-book/ch5-web/ch5-06-ratelimit.html Ratelimit 服务流量限制 计 ...

  8. navicat for mysql 链接时报错:1251-Client does not support authentication protocol requested by server

    客户端使用navicat for mysql.本地安装了mysql 8.0.但是在链接的时候提示: 主要原因是mysql服务器要求的认证插件版本与客户端不一致造成的. 打开mysql命令行输入如下命令 ...

  9. python字符串的常见方法

    1.join方法:拼接字符串------->str a = "你是风儿我是沙"b = "@".join(a)print(b)>>>你@是 ...

  10. Linux命令——du

    参考:10 Useful du (Disk Usage) Commands to Find Disk Usage of Files and Directories 前言 du(Disk Usage), ...