【机器学习】吴恩达作业5.0,python实现方差与偏差

 5.0 方差与偏差

实现正则化线性回归,使用其来研究具有不同偏差-方差属性的模型。

在练习的前半部分,您将使用水库水位的变化实现正则化线性回归来预测大坝的出水量。在下半部分中,您将对调试学习算法进行诊断,并检查偏差和方差的影响。
本次的数据是以.mat格式储存的,x表示水位的变化,y表示大坝的出水量。数据集共分为三部分:训练集(X, y)、交叉验证集(Xval, yval)和测试集(Xtest, ytest)。

  •  高偏差:欠拟合  高方差:过拟合

  • 正则化(解决过拟合问题)

惩罚系数过大,欠拟合,惩罚系数过小,过拟合

  • 学习曲线(用来判断过拟合/欠拟合) 

  • 训练集、验证集、测试集(6:2:2)

训练数据集:训练模型;(习得模型的参数)
验证数据集:验证模型的效果;如果模型的效果不好,则重新调整参数再次训练新的模型,直到找到了一组参数,使得模型针对验证数据集来说已经达到最优了;(将每个训练集训练好的参数在交叉验证集上计算交叉验证误差,选择误差最小的那个假设作为我们的模型,这里是用来选择lmd)
测试数据集:将此数据集传入由验证数据集得到的最佳模型,得到模型最终的性能;(作为衡量最终模型性能的数据集)

  •  特征缩放

归一化和标准化的区别:

归一化(normalization):归一化是将样本的特征值转换到同一量纲下,把数据映射到[0,1]或者[-1, 1]区间内。

标准化(standardization):标准化是将样本的特征值转换为标准值(z值),每个样本点都对标准化产生影响。

  

  •  python语法

1         np.sum(a)
           np.sum(a, axis=0) ------->列求和
           np.sum(a, axis=1) ------->行求和

2   np.c_[ ]可以合并矩阵

3   flatten( )返回一个折叠成一维的数组。但该函数只适用于numpy对象,即array或者mat,普通的list列表不的。以将shape为(12, 1)的返回为(12, )。
4   np.std(x, axis=0, ddof=1) axis=0  计算每一列的标准差,ddof=1表示自由度为N-1 

5   np.insert()函数  将向量插入某一行或列,axis=1表示增加的向量以列的形式

https://blog.csdn.net/Mxeron/article/details/113405004

 X.shape[1] : X的列数

1 导入数据处理数据,可视化

import numpy as np
from scipy.io import loadmat
from scipy.optimize import minimize
import matplotlib.pyplot as plt

data = loadmat("ex5data1.mat")
# 训练集(12,1)
X_train, y_train = data['X'], data['y']
# 验证集 (21,1)
X_val, y_val = data['Xval'], data['yval']
# 测试集 (21,1
X_test, y_test = data['Xtest'], data['ytest']
# 加入截距项
X_train = np.insert(X_train, 0, 1, axis=1)
X_val = np.insert(X_val, 0, 1, axis=1)
X_test = np.insert(X_test, 0, 1, axis=1)


# 可视化
def plot_data():
    fig, ax = plt.subplots()
    ax.scatter(X_train[:, 1], y_train)
    ax.set(xlabel="water level",
           ylabel="water flowing out")


plot_data()  

 这犯了一个错误,可视化数据集的时候,全写的plt. 导致后续在数据集上画拟合曲线的时候,是两张图,错误代码如下

# #可视化训练集
# def plot_data():
#     fig,ax = plt.subplots()
#     plt.scatter(X_train[:, 1], y_train)#x取第二列
#     plt.xlabel('Change in water level (x)')
#     plt.ylabel('Water flowing out of the dam (y)')
#     plt.show()

 2 损失函数

def reg_cost(theta, X, y, lamda):
    cost = np.sum(np.power((X @ theta - y.flatten()), 2))#对y进行降维
    reg = np.sum(np.power(theta[1:], 2)) * lamda
    return (cost + reg) / (2 * len(X))


# theta = np.ones(X_train.shape[1])#theta初始为一维
# lamda = 1
# print(reg_cost(theta, X_train, y_train, lamda))

 3 梯度函数

def reg_gradient(theta, X, y, lamda):
    grad = (X @ theta - y.flatten()) @ X
    reg = lamda * theta
    reg[0] = 0#第一项不做正则化
    return (grad + reg) / (len(X))


# print(reg_gradient(theta, X_train, y_train, lamda))

 4 神经网络训练参数并可视化lmd=0时拟合的线性方程

# 训练参数并可视化拟合曲线

from scipy.optimize import minimize
def train_model(X,y,lmd):
    theta = np.ones(X.shape[1])
    res = minimize(fun = reg_cost,
                   x0 = theta,
                   args = (X,y,lmd),
                   method = 'TNC',
                   jac = grad_reg)
    return res.x #易错!!!!记得返回x!!!!!!

theta_final = train_model(X_train,y_train,lmd = 0)
print(theta_final)  #[13.0879035   0.36777923]

#拟合图像
fig,ax = plt.subplots()
plt.scatter(X_train[:, 1], y_train, c='r', marker='x')
plt.xlabel('Change in water level (x)')
plt.ylabel('Water flowing out of the dam (y)')  
plt.plot(X_train[:,1],X_train@theta_final,c = 'b')
plt.show()

 拟合曲线显示拟合的不是很好,由第5步绘制出lamda = 0的学习曲线可以看出存在高偏差问题。若二者损失都大且差距不明显,则设定的模型过于简单,无法很好的拟合数据,存在欠拟合问题。

 5 画学习曲线,判断高偏差、高方差问题

训练样本从开始递增进行训练,比较训练集和验证集上的损失函数的变化情况,

学习曲线用来判断样本存在高偏差/高方差的情况
若二者损失都大且差距不明显,则为高偏差,训练集低损失而验证集高损失,说明高偏差
利用选择不同的lamda来解决问题,高偏差减小lamda,高方差增大lamda

def plot_learning_curve(X_train,y_train,X_val,y_val,lmd):
    train_cost = []
    cv_cost = []
    x = range(1,len(X_train+1))
    
    for i in x:#x (1-13)
        res = train_model(X_train[:i,:],y_train[:i,:],lmd)
#         res0 = list(res.values()) #将优化后的参数字典中的数值转为列表
#         res_ = res0[0]#提取参数字典中的theta
        training_cost_i = reg_cost(res,X_train[:i,:],y_train[:i,:], lmd)
        cv_cost_i = reg_cost(res,X_val,y_val, lmd)
        train_cost.append(training_cost_i)
        cv_cost.append(cv_cost_i)

    plt.plot(x,train_cost,label = 'training cost')
    plt.plot(x,cv_cost,label = 'cv cost')
    plt.legend(loc = 1)
#     plt.xlim(0, 12)
#     plt.ylim(0)
    plt.xlabel('number of training examples')
    plt.ylabel('costs')
    plt.show()

# 不考虑正则化的情况,出现欠拟合的情况
plot_learning_curve(X_train,y_train,X_val,y_val,lmd = 0)#lmd = 0,表示误差

 可以看出,二者损失都较大,高偏差,因此特征映射创造多项式特征,进行多项式回归,用更复杂的函数去拟合

6 特征映射  均值归一化 

# 增加多项式,从x的平方到x的多次方
def poly_feature(X, power):
    for i in range(2, power + 1):#从二次方到power次方
        X = np.insert(X, X.shape[1], np.power(X[:, 1], i), axis=1)#从第二列开始插入多列多项式
    return X

#获取均值和方差
def get_standard(X):
    # 按行计算,即求每一列的均值和方差
    means = np.mean(X, axis=0)
    stds = np.std(X, axis=0)
    return means, stds

#标准化
def feature_normalize(X, means, stds):
    X[:, 1:] = (X[:, 1:] - means[1:]) / stds[1:]#取所有行,去掉第一列
    return X


# 测试,最大六次方
power = 6

#特征映射

X_train_poly = poly_feature(X_train, power)
X_val_poly = poly_feature(X_val, power)
X_test_poly = poly_feature(X_test, power)
#标准化
train_means, train_stds = get_standard(X_train_poly)
X_train_norm = feature_normalize(X_train_poly, train_means, train_stds)
X_val_norm = feature_normalize(X_val_poly, train_means, train_stds)
X_test_norm = feature_normalize(X_test_poly, train_means, train_stds)

theta_fit = train_model(X_train_norm, y_train, lamda=0)
print(theta_fit)


 7 绘制多项式回归的拟合曲线

def plot_poly_fit():
    plot_data()
    x = np.linspace(-60, 60, 100)#生成网格数据(100,)
    xReshape = x.reshape(100, 1)#从(100,)到(100,1)
    xReshape = np.insert(xReshape, 0, 1, axis=1)#插入第一列1
    xReshape = poly_feature(xReshape, power)#特征映射
    xReshape = feature_normalize(xReshape, train_means, train_stds)#标准化

    plt.plot(x, xReshape @ theta_fit, 'r--')  #曲线  (x,xx@thte)
    plt.show()

plot_poly_fit()

 

8  显示不同lamda取值下的学习曲线

# 高方差,次数太多,过拟合
plot_learning_curve(X_train_norm, y_train, X_val_norm, y_val, lamda=0)
# 加入正则化
plot_learning_curve(X_train_norm, y_train, X_val_norm, y_val, lamda=1)
# 正则化很大,欠拟合
plot_learning_curve(X_train_norm, y_train, X_val_norm, y_val, lamda=100)


 9  用交叉验证集选择最佳lmd

# 用交叉验证集选择lmd
lamdas = [0, 0.001, 0.003, 0.01, 0.03, 0.1, 0.3, 1, 3, 10]
training_cost = []
cv_cost = []
for lamda in lamdas:
    res = train_model(X_train_norm, y_train, lamda)
    tc = reg_cost(res, X_train_norm, y_train, lamda=0)#计算训练集上的误差
    cv = reg_cost(res, X_val_norm, y_val, lamda=0)#计算验证集上的误差

    training_cost.append(tc)
    cv_cost.append(cv)

plt.plot(lamdas, training_cost, label='training cost')#不同lamda取值下训练集的损失
plt.plot(lamdas, cv_cost, label='cv cost')
plt.legend()
plt.show()

#拿到最佳lamda
bestLamda = lamdas[np.argmin(cv_cost)]
print(bestLamda)#3
#用最佳lamda来训练测试集
res = train_model(X_train_norm, y_train, bestLamda)
print(reg_cost(res, X_test_norm, y_test, lamda=0))#4.3976161577441975

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值