一、总结
所谓偏差和方差,可以用打靶来作为比喻。
偏差可以用来衡量打中的位置距离靶心的距离(精确度)
方差可以用来衡量打中位置的集中程度(若分散则方差比较大)
偏差大表现为拟合曲线与实际样本不符。
方差大表现为拟合曲线与实际样本过于贴合,当出现新增样本的时候,与其不符合。
二、python实现
1、代价函数和梯度下降
使用的预测模型为线性模型,在前面的练习已经写过,直接上代码:
梯度下降:(注意返回的梯度下降为一维,用flatten函数处理)
import numpy as np
def gradient(theta, x, y, mylamda):
m = len(theta)
theta = np.array(theta).reshape([m, 1])
m = x.shape[0]
one = np.ones([m, 1])
x = np.hstack([one, x])
hx = np.dot(x, theta)
grad = np.dot(x.T, hx - y) / m
grad[1:, 0] = grad[1:, 0] + (mylamda / m) * theta[1:, 0]
return grad.flatten()
代价函数:
import numpy as np
def costfunction(theta, x, y, mylambda):
m = np.size(theta)
theta = np.array(theta).reshape([m, 1])
m = x.shape[0]
one = np.ones([m, 1])
x = np.hstack([one, x])
hx = np.dot(x, theta)
cost1 = np.sum(np.power(hx - y, 2)) / (2 * m)
if theta.shape[0] > 2:
cost2 = mylambda / (2 * m) * np.sum(np.power(theta[1:, :], 2))
else:
cost2 = mylambda / (2 * m) * np.power(theta[1:, :], 2)
return cost1 + cost2
2、学习曲线
根据训练集大小的增加来计算对应训练集的误差、交叉验证集的误差
import numpy as np
from trainLinearReg import trainLinearReg
from costFunction import costfunction
def learningcurve(x, y, xval, yval, mylambda):
m = x.shape[0]
cost_train = np.zeros(m)
cost_val = np.zeros(m)
init_theta = np.ones(x.shape[1] + 1)
for i in range(m):
x_temp = x[0:i+1, :]
y_temp = y[0:i+1, :]
theta = trainLinearReg(init_theta, x_temp, y_temp, mylambda) # 传入0相当于不进行正则化
cost_train[i] = costfunction(theta, x_temp, y_temp, mylambda)
cost_val[i] = costfunction(theta, xval, yval, mylambda)
return cost_train, cost_val
寻找最小值的函数 trainLinearReg 实现 :
import numpy as np
import scipy.optimize as opt
from costFunction import costfunction
from linearRegressionGradient import gradient
def trainLinearReg(theta, x, y, mylambda):
result = opt.minimize(fun=costfunction, x0=theta,
args=(x, y, mylambda), method='TNC', jac=gradient)
return result.x
结果:
训练集的误差和交叉验证集的误差中间始终存在一条沟壑,且训练集误差不趋近于0。说明拟合的曲线出现偏差,而且增加训练集的方式并不能减少两者之间误差的大小。
3、特征增加来减少偏差
本来训练集X只有一个特征,通过X的高次方来构建新的特征。
import numpy as np
def polyfeature(x, p):
m = x.shape[0]
x_ploy = np.zeros([m, p])
for i in range(p):
x_ploy[:, i] = np.power(x[:, 0], i+1)
return x_ploy
练习中的X最高到了八次方,多了七个特征。但是过高阶数的特征其数值比较大,最好将其缩小:处理成正态分布的类型:
import numpy as np
def featureNormalize(x):
m, n = x.shape
mu = np.zeros(m)
sigma = np.zeros(m)
x_norm = np.zeros([m, n])
for i in range(n):
mu[i] = np.mean(x[:, i])
sigma[i] = np.std(x[:, i])
x_norm[:, i] = (x[:, i] - mu[i]) / sigma[i]
return x_norm, mu, sigma
结果,通过λ的设置来观察拟合过程(主要观察过拟合)
-
过拟合状态:λ= 0
拟合曲线(不光滑,不具有普遍性,高方差)
-
过拟合状态,λ= 0.03
-
过拟合状态, λ = 0.1
-
最佳状态 λ = 1
加大对Theta的惩罚之后,训练集的过拟合状态再次得到改善,但是cost也从0增加,交叉验证集的cost再次减少,两者趋于相等。
拟合曲线:(相对平滑)
至此,该练习的思路:1 线性模型无法很好拟合数据(偏差,学习曲线沟壑无法随着训练集的增加减少而有效交叉验证集的cost),因此想增加特征来更好的拟合预测曲线。 2 增加特征后发现预测曲线出现过拟合的现象(训练集的cost接近0, 而交叉验证集最终不会随着训练集的增加减少,学习曲线沟壑无法随着训练集的增加而减少)。 3 通过增加 λ 的值来减少过拟合,使预测曲线平滑。