前言
近日开始学习机器学习,拜读了一下李航老师的《统计学习方法》,有点不求甚解,为了让自己更好的理解,写些系列文章把,第一章为感知机。
学习笔记
感知机就是一个二分类的一个线性模型,将数据集分为两个部分,划分为-1,+1两个大部分,算法的目的就是寻找这么一个超平面wx+b。
由图可知,这就是一个较为简单的二分类概念。举个例子,在现实生活中,判定一个产品的好坏,就是在这图片中的两侧,如果只有两个评判标准时,这个超平面就是ax+by+c这个之间,当不止两个标准时,就是多维世界,即超平面wx+b。
用户在使用感知机的目的无非就是想知道这个分类的结果属于图中的蓝点还是黑点。所以定义一个函数。
f
(
x
)
=
s
i
g
n
(
w
⋅
x
+
b
)
f(x) = sign (w \cdot\ x+b)
f(x)=sign(w⋅ x+b)
s
i
g
n
(
x
)
=
{
+
1
,
x>=0
−
1
,
x<0
sign(x)=\left\{ \begin{aligned} +1,& \text{x>=0}\\ -1 ,&\text{x<0}\\ \end{aligned} \right.
sign(x)={+1,−1,x>=0x<0
从公式中,可以看到sign函数就是分出了+1和-1部分,联立两个公式,就是wx+b>=0,y为1,反之为-1。在训练过程中,需要找到误分类点到超平面得距离,为此距离公式为:
1
∣
∣
w
∣
∣
∣
w
⋅
x
+
b
∣
\frac{1}{||w||}|w \cdot\ x +b|
∣∣w∣∣1∣w⋅ x+b∣
为什么最后不考虑
1
∣
∣
w
∣
∣
\frac{1}{||w||}
∣∣w∣∣1,由于感知机是误分类驱动的算法,它的终极目标是没有误分类的点,如果没有误分类的点,总和距离就变成了0,w和b值怎样都没用。所以几何间隔和函数间隔在感知机的应用上没有差别,为了计算简单,使用函数间隔。这样反而忽略可以提高效率。
以上是原始形式的方法,这里再介绍对偶形式的方法。
在原始方法和对偶方法选择上,有以下两个指标
- 当向量的维度高时,在计算内积时需要大量内存,为此采用对偶方法加速
- 当向量的数量特别多时,计算累计和反而耗时麻烦,为此采用原始的办法。
源码学习
'''
Descripttion: 李航《统计学习方法》复现,感知机
version:
Author: WenZeng Cai
Date: 2020-08-29 15:50:51
LastEditors: WenZeng Cai
LastEditTime: 2020-08-30 11:34:13
'''
import numpy as np
import time
def loadData(filename:str):
'''
name:
msg:
param {type}
return {type}
'''
print('加载数据')
# 数据和标签
data,label=[],[]
fr=open(filename,'r')
for line in fr.readlines():
# 每行以逗号分隔
cur=line.strip().split(',')
# 数据集有0-9标签,0-5标记为1,大于标记为-1,二分
if int(cur[0])>=5:
label.append(1)
else:
label.append(-1)
# 除第一列外,进行归一化处理
data.append([int(num)/255 for num in cur[1:]])
return data,label
def perceptron_train(data:list,label:list,iter=50):
'''
name: 感知训练
msg:
param {type} 数据和标签,默认迭代50次
return {type}训练好的超平面参数w和b
'''
print('开始训练')
# 转化为矩阵,label转置,label本题是1*N列表,可以直接使用label[i]获得标签数据
# 为了格式统一将他转置为矩阵,为了使用label[i]得到数据,就需要转置为列矩阵
dataMat=np.mat(data)
labelMat=np.transpose(np.mat(label))
# 取数据维度
m,n=np.shape(dataMat)
# 初始化超平面参数,和偏置量为0,使用随机梯度下降,步长为0.001
w=np.zeros((1,n))
b=0
h=0.0001
for k in range(iter):
for i in range(m):
xi=dataMat[i]
yi=labelMat[i]
# -yi(w*xi+b)>=0
# 误分类部分为>=0,进行梯度下降更新w和b
if -yi * (w * xi.T + b) >= 0:
w = w + h * yi * xi
b = b + h * yi
return w,b
def test(data,label,w,b):
'''
name: 模型测试
msg:
param {type} 数据测试集,标签,权重w,偏置b
return {type} 精确度
'''
print('开始测试')
dataMat=np.mat(data)
labelMat=np.mat(label).T
errCnt=0
m,n=np.shape(dataMat)
for i in range(m):
xi=dataMat[i]
yi=labelMat[i]
# 对测试集进行计算,当>=0时就是误判加1。
result=-yi * (w * xi.T + b)
if result>=0:
errCnt+=1
# 得到正确率
accuracy=1-(errCnt/m)
return accuracy
if __name__ == '__main__':
start=time.time()
trainData,trainLabel=loadData('../Mnist/mnist_train.csv')
testData,testLabel=loadData('../Mnist/mnist_test.csv')
w,b=perceptron_train(trainData,trainLabel)
accuracy=test(testData,testLabel,w,b)
print('准确率',accuracy)
end=time.time()
print('运行时间',end-start)
推荐源码在github链接中查看,有mnist数据集。
感知机源码