个人机器学习笔记之正则化
吴恩达机器学习笔记(3)——正则化
机器学习个人笔记,学习中水平有限,内容如有缺漏还请多多包涵
本章节笔记对应吴恩达课程的第8章。正则化给予所有参数一个缩小的趋势,防止高次项的参数过高出现过拟合现象。
因为θTX形式的线性模型只能做到欠拟合,这里我们不能使用θTX形来模拟过拟合现象,需要一个带有高次项变量的多项式模型来进行过拟合,但是我目前并没有一个可靠的方案实现逻辑回归的多次项模型,因此只好直接在θT*X形式的逻辑回归上应用正则化。
应用正则化的逻辑回归的python代码
import numpy as np
import matplotlib.pyplot as plt
def sigmoid(x):
return 1/(1+np.exp(-x))
def h(x,pram):#假设函数,这里等价于y=sigmoid(θTX)
temp=np.matmul(x,pram[1:].reshape(x.shape[1],1))+pram[0]
return np.apply_along_axis(sigmoid, 0, temp)
def logictic(a,itertimes,datax,datay,lam):#逻辑回归
#a:学习率
#itertimes:迭代次数
#datax:数据集中的自变量部分
#datay:数据集中的结果部分
#正则化参数
m=datax.shape[0]#训练集长度
pram=np.zeros(datax.shape[1]+1)#参数,初始化为0
temppram=np.zeros(datax.shape[1]+1)#临时存储本次迭代的参数
for i in range(0,itertimes):#迭代过程,执行itertimes次
temppram[0]=pram[0]-a*(np.sum(h(datax,pram)-datay)+lam*pram[0]/m)#对参数theta0进行迭代
te=h(datax,pram)-datay
for j in range(1,pram.shape[0]):#对剩余参数进行迭代
temppram[j]=pram[j]-a*(np.sum((h(datax,pram)-datay).T*datax2[...,j-1])+lam*pram[j]/m)
if i%10==0:
print("迭代",i)
print( "参数:",pram)
print("log误差:",np.sum(-datay*np.log(h(datax,pram))-(1-datay)*np.log(1-h(datax,pram))))#每十代输出误差
pram=temppram
pass
return pram
x=np.zeros([100,2])#在10*10的样本空间中做逻辑回归
for i in range(0,10):
for j in range(0,10):
x[i*10+j][0]=i
x[i*10+j][1]=j
print(x.shape[1])
y=np.zeros([100,1])
for i in range(0,10):
for j in range(0,10):
if i+j-9>0:#数据集分类边界取直线y=-x+9
y[i*10+j][0]=1
print(y.shape)
d=logictic(0.01, 500, x, y,1)#执行逻辑回归算法,返回分类边界线的参数
drawx=[]#设置用于绘图的坐标集合
drawy=[]
drawx1=[]
drawy1=[]
for i in range(0,100):
if y[i]==1:#如果y中的第i个元素是1,则取出x中第i个样本作为坐标放入drawx列表
drawx.append(x[i][0])
drawy.append(x[i][1])
else:#如果y中的第i个元素是0,则取出x中第i个样本作为坐标放入drawx1列表
drawx1.append(x[i][0])
drawy1.append(x[i][1])
plt.figure()
plt.scatter(drawx, drawy)#分别绘制数据集中drawx,drawx1两个分类的散点图
plt.scatter(drawx1, drawy1)
plt.plot(range(0,10), np.array(range(0,10))*-d[1]/d[2]-d[0]/d[2],color='red')#绘制分类线的图
plt.ylabel("var1")#注意不能设label为中文
plt.xlabel("var2")
plt.show()
使用正则化导致损失值出现了NAN,就不放图了
应用正则化的多项式线性回归的python代码(双变量)
import numpy as np
def h(x,pram):#假设函数,这里等价于y=ax1+bx2+cx1^2+dx2^2+c
pramt=np.array(pram[1:])
temp2=np.zeros([x.shape[0],2])
temp2[...,0]=x[...,0]*x[...,0]#生成x1^2
temp2[...,1]=x[...,1]*x[...,1]#生成x2^2
datax=np.hstack((x,temp2))#组合生成x1,x2,x1^2,x2^2矩阵
return np.matmul(datax,pramt.reshape(len(pram)-1,1))+pram[0]
def gradientDescent(a,itertimes,datax,datay,lam):#双变量梯度下降的线性回归
#a:学习率
#itertimes:迭代次数
#datax:数据集中的自变量部分
#datay:数据集中的结果部分
#正则化参数
m=datax.shape[0]#训练集长度
pram=np.zeros(datax.shape[1]+3)#参数,初始化为0
temppram=np.zeros(pram.shape)#临时存储本次迭代的参数
temp2=np.zeros([x.shape[0],2])
temp2[...,0]=datax[...,0]*datax[...,0]#生成x1^2
temp2[...,1]=datax[...,1]*datax[...,1]#生成x2^2
datax2=np.hstack((datax,temp2))
for i in range(0,itertimes):#迭代过程,执行itertimes次
temppram[0]=pram[0]-a*(np.sum(h(datax,pram)-datay)+lam*pram[0])/m#对参数theta0进行迭代
for j in range(1,pram.shape[0]):#对剩余参数进行迭代
temppram[j]=pram[j]-a*(np.sum((h(datax,pram)-datay).reshape(1,m)*datax2[...,j-1])+lam*pram[j]/m)
if i%10==0:
print("迭代",i)
print( "参数:",pram)
print("平方根误差:",np.sqrt(np.sum((h(datax,pram)-datay)**2)))#没十代
pram=temppram
pass
return pram
def test(datax,pram,datay):#计算测试误差
return np.sum(np.sqrt(np.sum((h(datax,pram)-datay)**2)))
x=np.random.rand(10,2)
pram=np.array([1,2,3])#真实参数
y=np.matmul(x,pram[1:].reshape(len(pram)-1,1))+pram[0]+np.random.rand(10,1)#生成训练数据集
p=gradientDescent(0.1, 1000, x, y,10)#执行梯度下降算法,返回预测参数,10为正则化参数,为0退化为普通梯度下降
datax=np.random.rand(10,2)
datay=np.matmul(datax,pram[1:].reshape(len(pram)-1,1))+pram[0]#生成测试集y=1+2*x1+3*x2
print("测试误差:",test(datax,p,datay))#计算测试误差
不使用正则化的多项式线性回归
使用正则化的多项式线性回归
注:平方根误差代表训练误差
实现过程记录
使用正则化似乎会使收敛速度变慢
公式部分
使用正则化的梯度下降的迭代公式:
目前线性回归和逻辑回归都是使用梯度下降来最小化代价函数的,而正则化作用是在梯度下降算法上的,因此正则化对于线性回归和逻辑回归的公式是相同的。