Hello,大家好!最近事情太多,导致这次停更时间有点长了,但是经过了这半年的学习,也学了不少东西,思考后决定,先把李航的《统计学习》这本书上的算法一一代码实现一下,来检测一下是否真的学会了,所以先分享给大家的是第二章:感知机模型!
因为网上python的实现比较多,以及我最近用R比较多,所以本文的代码实现用R来写,python后续再找时间补上!
李航《统计学习方法》(第2版)P39——算法2.1
输入:线性可分训练集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x N , y N ) } T=\{(x_1,y_1),(x_2,y_2),\dots,(x_N,y_N)\} T={(x1,y1),(x2,y2),…,(xN,yN)},其中 x i ∈ X = R n x_i\in\mathcal{X}=\mathbf{R}^n xi∈X=Rn, y i ∈ Y = { − 1 , + 1 } , i = 1 , 2 , … , N y_i\in\mathcal{Y}=\{-1,+1\},i=1,2,\dots,N yi∈Y={−1,+1},i=1,2,…,N;学习率 η ( 0 < η ⩽ 1 ) \eta(0<\eta\leqslant1) η(0<η⩽1);
输出: w , b w,b w,b;感知机模型 f ( x ) = s i g n ( w ∙ x + b ) f(x)=\mathrm{sign}(w\bullet x+b) f(x)=sign(w∙x+b)。
(1)选取初值 w 0 , b 0 w_0,b_0 w0,b0;
(2)在训练集中选取数据 ( x i , y i ) (x_i,y_i) (xi,yi);
(3)如果 y i ( w ∙ x i + b ) ⩽ 0 y_i(w\bullet x_i+b)\leqslant0 yi(w∙xi+b)⩽0,
w ← w + η y i x i b ← b + η y i w \leftarrow w + \eta y_ix_i\\ b \leftarrow b + \eta y_i w←w+ηyixib←b+ηyi
(4)转至(2),直至训练集中没有误分类点。
实验数据用李航《统计学习方法》(第2版)P152——习题7.2的数据
data <- data.frame(y=c(1,1,1,-1,-1),x1=c(1,2,3,2,3),x2=c(2,3,3,1,2))
plot(data[which(data$y>0),][,2:3], xlim=c(0,6), ylim=c(0,6), pch=19, xlab=expression(x[1]), ylab=expression(x[2]), cex.lab=1.2, main='感知机模型测试')
points(data[which(data$y<0),][,2:3], pch=4)
(1)设置初值 w 0 , b 0 w_0,b_0 w0,b0;学习率 η \eta η;最大迭代次数;
eta<-0.5 #学习率
max_iter<-100 #最大迭代次数
w<-matrix(0,ncol(data)-1,1) #初始值w0
b<-0 #初始值b0
y<-as.matrix(data[,1])
x<-as.matrix(data[,-1])
(2)运用矩阵计算 y ( w ∙ x + b ) y(w\bullet x+b) y(w∙x+b),可大大提高运算效率;
y*(x%*%w+b)
(3)判断 y ( w ∙ x + b ) y(w\bullet x+b) y(w∙x+b)的结果中是否有≤0的数;如果有,则随机选择选择一个≤0的样本,更新 w , b w,b w,b;
for (i in 1:max_iter) {
index<-as.integer(y*(x%*%w+b)<=0)
names(index)<-1:nrow(data)
if (sum(index)==0){break}
j <- sample(as.integer(names(index[index==1])),1)
w <- w+eta*data[j,1]*as.numeric(matrix(data[j,-1],ncol(data)-1,1))
b <- b+eta*data[j,1]
}
注:
as.integer(y(xw+b)<=0):将逻辑值T、F转换为数值1、0;再通过求和来判断是否所有值都符合要求.
制作了一个动图,来展示每次的迭代效果,最终得到的结果为 w 1 = − 2.5 , w 2 = 3.5 , b = 0 w_1=-2.5,w_2=3.5,b=0 w1=−2.5,w2=3.5,b=0,成功分离了所有的样本点。
下列动图是使用animation包+ImageMagick制作而成,完整代码中有写,可在文末获取;以后有时间会专门出一期动图制作。
最后封装,便于以后使用,大功告成!
perceptron <- function(data, eta, max_iter){
w<-matrix(0,ncol(data)-1,1)
b<-0
y<-as.matrix(data[,1])
x<-as.matrix(data[,-1])
for (i in 1:max_iter) {
index<-as.integer(y*(x%*%w+b)<=0)
names(index)<-1:nrow(data)
if (sum(index)==0){break}
j <- sample(as.integer(names(index[index==1])),1)
w <- w+eta*data[j,1]*as.numeric(matrix(data[j,-1],ncol(data)-1,1))
b <- b+eta*data[j,1]
}
return(list(w=w,b=b))
}