<div class="article-copyright">
<span class="creativecommons">
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">
</a>
<span>
版权声明:本文为博主原创文章,遵循<a href="http://creativecommons.org/licenses/by-sa/4.0/" target="_blank" rel="noopener"> CC 4.0 BY-SA </a>版权协议,转载请附上原文出处链接和本声明。 </span>
<div class="article-source-link2222">
本文链接:<a href="https://blog.csdn.net/weixin_44863781/article/details/90522382">https://blog.csdn.net/weixin_44863781/article/details/90522382</a>
</div>
</span>
</div>
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-3019150162.css">
<div id="content_views" class="markdown_views prism-atom-one-dark">
<!-- flowchart 箭头图标 勿删 -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
</svg>
<p>一、学习曲线与高偏差、高方差<br>
学习曲线描述了训练集样本数与训练误差、在验证集误差的关系。通过学习曲线,我们能够清楚地知道我们的模型是高偏差还是高方差,即欠拟合还是过拟合。
下图为高偏差情况:
在高偏差情况下,可以看出训练误差
J
t
r
a
i
n
J
t
r
a
i
n
J
t
r
a
i
n
JtrainJtrain J_{train}
JtrainJtrainJtrainJcv减小。
二、学习曲线的应用
下面我们应用绘制学习曲线来帮助我们选择模型参数
1、先导入需要使用的模块:
import numpy as np
from scipy.io import loadmat
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
from scipy.optimize import minimize
- 1
- 2
- 3
- 4
- 5
- 6
2、读取并查看处理数据:
data = loadmat('F:\\MachineLearning\data\ex5data1.mat')
print(data)
- 1
- 2
我们可以发现data中包含训练集X
,训练集标记y
,测试集Xtest
,测试集标记ytest
,验证集Xval
以及验证集标记yval
。
我们分别取出x,y,Xtest,ytest,Xval以及yval。并为了之后的计算方便,把标记全部由矩阵形式改为数组形式:
X=data['X']
y=data['y']
Xval = data['Xval']
yval = data['yval']
Xtest = data['Xtest']
ytest = data['ytest']
X1=np.ravel(X)
y1=np.ravel(y)
m_Xval,d_Xval = Xval.shape
Xval1 = np.ravel(Xval)
yval1 = np.ravel(yval)
Xtest1 = np.ravel(Xtest)
ytest1 = np.ravel(ytest)
m,d = X.shape
m_test,d_test=Xtest.shape
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
下面我们查看训练集样本样本分布:
#查看训练集
df = pd.DataFrame({'water_level':X1,'flow':y1})
sns.lmplot('water_level','flow',data=df,fit_reg=False)
plt.show()
- 1
- 2
- 3
- 4
得到图:
由于常数项的存在,我们需要对X,Xtest,Xval添加全为1的列:
X1=X
Xval1=Xval
Xtest1=Xtest
X=np.insert(X,0,values=np.ones(m),axis=1)
Xval=np.insert(Xval,0,values=np.ones(m_Xval),axis=1)
Xtest=np.insert(Xtest,0,values=np.ones(m_test),axis=1)
- 1
- 2
- 3
- 4
- 5
- 6
3、用线性拟合数据
首先我们是正则化的代价函数和不带正则化的代价函数,这里之所以要有一个带正则化和不带正则化,是因为在训练参数是我们需要使用的是带正则化的代价函数和梯度函数,然而在绘制学习曲线时,我们需要使用不带正则化的代价函数:
def regularized_cost(theta,X,y,regularized_param):
m = X.shape[0]
delta= X @ theta - y
cost_term = (delta.T @ delta) / (2*m)
regularized_term = (theta[1:].T @ theta[1:]) * (regularized_param/(2*m))
cost = regularized_term + cost_term
return cost
def cost(theta,X,y):
m = X.shape[0]
delta= X @ theta - y
total_cost = (delta.T @ delta) / (2*m)
return total_cost
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
然后是带正则化的梯度函数:
def regularized_gradient(theta,X,y1,regularized_param):
m = X.shape[0]
delta = X @ theta - y1
gradient_term = (X.T @ delta) / m
theta1 = np.insert(theta[1:],0,values=0)
regularized_term = (regularized_param / m) * theta1
gradient=gradient_term + regularized_term
return gradient
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
用scipy
中的minimize
函数去求参数,因为这里我们的数据只有一个属性,如果加上常数项对应的参数,我们应该得到的是二维数组:
#拟合数据
theta=np.ones(2)
res = minimize(fun=regularized_cost,x0=theta,args=(X,y1,1),method='Newton-CG',\
jac=regularized_gradient,options={'disp':True})
x=res.x
- 1
- 2
- 3
- 4
- 5
我们绘制曲线图查看模型与数据的拟合情况:
#对比线性拟合情况
plt.scatter(X1,y1,label='Trainning Set',color='blue')
plt.plot(X1,x[1]*X1+x[0],label='Prediction',color='red')
plt.legend()
plt.show()
- 1
- 2
- 3
- 4
- 5
得到图:
从图上可以看出我们的模型过于简单不能很好的描述训练集数据的特点。下面我们看看学习曲线的情况:
#画出学习曲线
Jtraining = []
Jcv = []
for i in range(m):
res=minimize(fun=regularized_cost,x0=theta,args=(X[:i+1,:],y1[:i+1],1),method='Newton-CG',\
jac=regularized_gradient,options={'disp':True})
x=res.x
jtraining = cost(x,X[:i+1,:],y1[:i+1])
Jtraining.append(jtraining)
jcv = cost(x,Xval,yval1)
Jcv.append(jcv)
plt.plot(np.arange(1,m+1),Jcv,label='Jcv',color='red')
plt.plot(np.arange(1,m+1),Jtraining,label='Jtraining',color='blue')
plt.legend()
plt.show()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
这里使用迭代,从i=0逐渐扩大i,取X[:i+1,:]
,这就相当与训练集样本数从1逐渐扩大,然后把不同样本集样本数下的训练集代价和验证集代价分别存于列表中。这样我们可以到学习曲线图:
我们可以看到
J
t
r
a
i
n
J
t
r
a
i
n
J
t
r
a
i
n
JtrainJtrain J_{train}
JtrainJtrainJtrainJcv不会太大表明在新样本上依然拥有较好的泛化能力。
我们还可以计算在测试集上的误差来选择正则化常数:
#得到测试集上的代价值
prepared_test = prepare_data(Xtest1,8)
theta8=np.ones(9)
for l in L:
test_fmin=minimize(fun=regularized_cost,x0=theta8,args=(prepared_data[:i+1,:],y1[:i+1],l),\
method='TNC',jac=regularized_gradient,options={'disp':True})
test_cost = cost(test_fmin.x,prepared_test,ytest1)
print(str(l)+' : '+str(test_cost))
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
得到:
0 : 9.873941227352864
0.001 : 11.008145910102536
0.003 : 11.301862220853764
0.01 : 10.988460477608943
0.03 : 10.218881836544037
0.1 : 8.953968731131386
0.3 : 7.745110198919966
1 : 7.851586049767016
3 : 11.770306579735657
10 : 26.894076292237678
30 : 52.76679321644176
100 : 79.07925641027286
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
我们发现在测试集上正则化常数为0.3时,测试集上的代价最小,所以我们选择正则化常数为0.3。
</div>
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-095d4a0b23.css" rel="stylesheet">