面临问题:训练数据训练的很好,误差也不大,为什么在测试集上面有问题呢?
模型复杂的原因:数据的特征和目标值之间的关系不仅仅是线性关系
接下来,我们将探究模型训练中经常出现的两类典型问题:
1、欠拟合
一类是模型无法得到较低的训练误差,我们将这一现象称作欠拟合(underfitting);
原因:学习到数据的特征过少
解决办法:增加数据的特征数量
2、过拟合
另一类是模型的训练误差远小于它在测试数据集上的误差,我们称该现象为过拟合(overfitting)。
原因:原始特征过多,存在一些嘈杂特征,模型过于复杂是因为模型尝试去兼顾各个测试数据点
解决办法:
- 进行特征选择,消除关联性大的特征(很难做)
- 交叉验证(让所有数据都有过训练)
- 正则化
3、欠拟合、过拟合的判定
通过交叉验证中的训练集结果及测试集进行判断,训练集和测试集都表现不好(一般看准确率和误差),此时被判定为欠拟合。训练集很好,测试集不太理想,则是过拟合。
4、特征选择方式
根据特征选择的形式又可以将特征选择方法分为3种:
-
Filter:过滤法,按照发散性或者相关性对各个特征进行评分,设定阈值或者待选择阈值的个数,选择特征。
-
Wrapper:包装法,根据目标函数(通常是预测效果评分),每次选择若干特征,或者排除若干特征。
-
Embedded:嵌入法,先使用某些机器学习的算法和模型进行训练,得到各个特征的权值系数,根据系数从大到小选择特征。类似于Filter方法,但是是通过训练来确定特征的优劣。
我们使用sklearn中的feature_selection库来进行特征选择。
过滤式:低方差特征
嵌入式:正则化,决策树,神经网路
5、过拟合解决方法——L2正则化
作用:可以使得W的每个元素都很小,都接近于0
优点:越小的参数说明模型越是简单,越简单的模型则越不容易产生过拟合现象。
6、岭回归Ridge
线性回归中,LinearRegression容易出现过拟合现象,为了解决过拟合现象可以使用到 岭回归(L2正则化),带有正则化的线性回归。
岭回归(英文名:ridge regression, Tikhonov regularization)是一种专用于供线性数据分析的有偏估计回归方法,实质上是一种改良的最小二乘估计法,通过放弃最小二乘法的无偏性,以损失部分信息、降低精度为代价获得回归系数更为符合实际、更可靠的回归方法,对病态数据的拟合要强于最小二乘法。
sklearn.linear_model.Ridge(alpha = 1.0)
- 具有L2正则化的线性最小二乘法
- alpha:正则化力度( λ )
- coef_:回归系数
正则化程度(alpha)的变化,对结果起到的影响:
岭回归总结:
岭回归:得到的回归系数更加符合实际、更可靠。另外,能让估计参数的波动范围很小,变得更稳定。在存在病态数据偏多的研究中有较大的实用价值。
7、使用岭回归进行波士顿房价预测
from sklearn.linear_model import SGDRegressor, LinearRegression, Ridge
from sklearn.datasets import load_boston #波士顿房价数据集
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error
import pandas as pd
def linear():
"""
线性回归直接预测房子价格
:return: None
"""
#获取数据
lb = load_boston()
#分割数据集到训练集和测试集
x_train, x_test,y_train,y_test = train_test_split(lb.data, lb.target, test_size=0.25)
#进行标准化处理(此处目标值需要标准化处理),实例化两个标准化API
#标准化的效果:所有的数都变得很小
std_x = StandardScaler()
x_train = std_x.fit_transform(x_train)
x_test = std_x.transform(x_test)
std_y = StandardScaler()
y_train = std_y.fit_transform(y_train.reshape(-1, 1)) #在0.19版本后,往转换器传入的必须是二维数组
y_test = std_y.transform(y_test.reshape(-1, 1)) #在0.18版本不做参数格式要求
#estimator预测
#岭回归进行房价预测
rd = Ridge()
rd.fit(x_train, y_train)
print("权重值:", rd.coef_)
#预测测试集的房子价格
y_rd_predict = std_y.inverse_transform(rd.predict(x_test))
print("梯度下降测试集里面每个房子的预测价格:", y_rd_predict.flatten())
print("梯度下降的均方误差:", mean_squared_error(std_y.inverse_transform(y_test), y_rd_predict))
return None
if __name__ == '__main__':
linear()