总结
- 欠拟合:(对训练集的数据和测试集的数据拟合的都不是很好)
- 原因:模型学习到样本的特征太少
- 解决:增加样本的特征数量(多项式回归)
- 多项式回归:from sklearn.preprocessing import PolynomialFeatures
- 在原有特征的基础上增加高次方特征
- 过拟合:(对训练集的数据高度拟合,对测试集的数据拟合的很离谱)
- 原因:原始特征过多,存在一些嘈杂特征。
- 解决:
- 1.进行特征选择,消除关联性大的特征
- 2.正则化之岭回归:from sklearn.linear_model import Ridge
- 将对模型影响较大的特征(高次方)的权重系数变小,将模型弯曲程度大的地方捋直一定,降低关联性大的特征对预测模型的影响
模型的保存和加载
- 方式一 (推荐):from sklearn.externals import joblib
- joblib.dump(model,'xxx.m'):保存
- joblib.load('xxx.m'):加载
- 方式二:import pickle
- with open('./123.pkl','wb') as fp:
- pickle.dump(linner,fp)
- with open('./123.pkl','rb') as fp:
- linner = pickle.load(fp)
欠拟合&&过拟合问题引入
问题
训练好的模型在训练集上表现的预测效果很好,但是在测试集上却有很大的问题和误差,why?
- 案例1:
- 现在有一组天鹅的特征数据然后对模型进行训练,然后模型学习到的内容是有翅膀,嘴巴长的就是天鹅。然后使用模型进行预测,该模型可能会将所有符合这两个特征的动物都预测为天鹅,则肯定会有误差的,因为鹦鹉,秃鹫都符合有翅膀和嘴巴长的特征。
- 原因:模型学习到的天鹅的特征太少了,导致区分标准太粗糙,不能准确的识别出天鹅。
- 案例2:
- 更新了样本的特征数据了,增加了一些特征,然后训练模型。模型这次学习到的内容是,有翅膀、嘴巴长、白色、体型像2、脖子长且有弯度的就是天鹅。然后开始使用模型进行预测,现在一组测试数据为鹦鹉,因为鹦鹉的体型小,脖子短不符合天鹅的特征,则预测结果为不是天鹅。然后又有一组特征为黑天鹅,结果因为颜色不是白色,预测成了不是天鹅。
- 原因:现在模型学习到的特征已经基本可以区分天鹅和其他动物了。但是学习到的特征中有一项是羽毛是白色,那么就会导致将黑天鹅无法识别出来。也就是机器学习到的特征太依赖或者太符合训练数据了。
欠拟合&&过拟合
- 欠拟合:案例1中的场景就可以表示欠拟合
- 一个假设在训练数据上不能获得很好的拟合,但是在训练数据以外的数据集上也不能很好的拟合数据,此时认为这个假设出现了欠拟合的现象。(模型过于简单)
- 过拟合:案例2中的场景就可以表示过拟合
- 一个假设在训练数据上能够获得比其他假设更好的拟合,但是在训练数据以外的数据集上却不能很好的拟合数据,此时认为这个假设出现了过拟合现象。(模型过于复杂)
欠拟合和过拟合问题的解决
- 欠拟合:
- 原因:模型学习到样本的特征太少
- 解决:增加样本的特征数量(多项式回归)
- 过拟合:
- 原因:原始特征过多,存在一些嘈杂特征。
- 解决:
- 进行特征选择,消除关联性大的特征(很难做)
- 正则化之岭回归(掌握)
- 模型的复杂度--》回归出直线or曲线:
- 我们的回归模型最终回归出的一定是直线吗(y=wx+b)?有没有可能是曲线(非线性)呢(y=wx**2+b)?
- 我们都知道回归模型算法就是在寻找特征值和目标值之间存在的某种关系,那么这种关系越复杂则表示训练出的模型的复杂度越高,反之越低。
- 模型的复杂度是由特征和目标之间的关系导致的!特征和目标之间的关系不仅仅是线性关系!
欠拟合的处理:多项式回归
- 为了解决欠拟合的情 经常要提高线性的次数(高次多项式)建立模型拟合曲线,次数过高会导致过拟合,次数不够会欠拟合。
- y = w*x + b 一次多项式函数
- y = w1x^2 + w2x + b 二次多项式函数
- y = w1x^3 + w2x^2 + w3*x + b 三次多项式函数
- 。。。
- 高次多项式函数的表示为曲线
- 相对于线性回归模型y=wx+b只能解决线性(回归出的为直线)问题,多项式回归能够解决非线性回归(回归出的为曲线)问题。
- 拿最简单的线性模型来说,其数学表达式可以表示为:y=wx+b,它表示的是一条直线,而多项式回归则可以表示成:y=w1x∧2+w2x+b,它表示的是二次曲线,
实际上,多项式回归可以看成特殊的线性模型
- 其中的y=w1x∧2+w2x+b就是所谓的二次多项式:aX∧2+bX+c(a≠0).
- 当然还可以将y=wx+b转为更高次的多项式。是否需要转成更高次的多项式取决于我们想要拟合样本的程度了,更高次的多项式可以更好的拟合我们的样本数据,但是也不是一定的,很可能会造成过拟合。
示例
- 下面模拟 根据蛋糕的直径大小 预测蛋糕价格
from sklearn.linear_model import LinearRegression
import numpy as np
import matplotlib.pyplot as plt
# 样本的训练数据,特征和目标值
x_train = [[6], [8], [10], [14], [18]] #大小
y_train = [[7], [9], [13], [17.5], [18]]#价格
# 训练模型
linear = LinearRegression()
linear.fit(x_train,y_train)
y_pred = linner.predict(x_train)
plt.scatter(x_train,y_train)
plt.plot(x_train,y_pred)
plt.xlabel('size_x')
plt.ylabel('price_y')
给原始特征增加高次项特征,可以是模型直线变弯曲,从而更加拟合数据
建立二次多项式线性回归模型进行预测
- 根据二次多项式公式可知,需要给原始特征添加更高次的特征数据x^2.
- y=w1x∧2+w2x+b
- 如何给样本添加高次的特征数据呢?
- 使用sklearn.preprocessing.PolynomialFeatures来进行更高次特征的构造
- 它是使用多项式的方法来进行的,如果有a,b两个特征,那么它的2次多项式为(1,a,b,a^2,ab, b^2)
- PolynomialFeatures有三个参数
- degree:控制多项式的度
- interaction_only: 默认为False,如果指定为True,上面的二次项中没有a^2和b^2。
- include_bias:默认为True。如果为False的话,那么就不会有上面的1那一项
工具类的基本使用(在原本数据的特征上增加多次方特征)
from sklearn.preprocessing import PolynomialFeatures
# 参数degree控制增加特征的次数
# 参数interaction_only默认为False是有二次项,如果变成True就会去掉二次项
# 参数include_bias默认为True,如果是False就是不要增加出来的1那一项
p = PolynomialFeatures(degree=2,interaction_only=True, include_bias=True)
p.fit_transform([[3,5]]) # 需要传入二维的特征 array([[ 1., 3., 5., 15.]])
p = PolynomialFeatures(degree=2,interaction_only=False, include_bias=True)
p.fit_transform([[3,5]]) # 需要传入二维的特征 array([[ 1., 3., 5., 9., 15., 25.]])
p = PolynomialFeatures(degree=2,interaction_only=False, include_bias=False)
p.fit_transform([[3,5]]) # 需要传入二维的特征 array([[ 3., 5., 9., 15., 25.]])
建立2次多项式线性回归模型进行预测
from sklearn.linear_model import LinearRegression
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
# 样本的训练数据,特征和目标值
x_train = [[6], [8], [10], [14], [18]] #大小
y_train = [[7], [9], [13], [17.5], [18]]#价格
# 在原有特征上增加2次方特征
p = PolynomialFeatures(degree=2)
d_2_train = p.fit_transform(x_train)
array([[ 1., 6., 36.],
[ 1., 8., 64.],
[ 1., 10., 100.],
[ 1., 14., 196.],
[ 1., 18., 324.]])
# 训练模型
linear = LinearRegression().fit(d_2_train,y_train)
y_pred = linear.predict(d_2_train)
plt.scatter(x_train,y_train)
plt.plot(x_train,y_pred)
plt.xlabel('size_x')
plt.ylabel('price_y')
# 可以看出增加到2次方特征后,模型看起来更加拟合
建立3次多项式线性回归模型进行预测
# 在原有特征上增加3次方特征
p = PolynomialFeatures(degree=3)
d_3_train = p.fit_transform(x_train)
array([[1.000e+00, 6.000e+00, 3.600e+01, 2.160e+02],
[1.000e+00, 8.000e+00, 6.400e+01, 5.120e+02],
[1.000e+00, 1.000e+01, 1.000e+02, 1.000e+03],
[1.000e+00, 1.400e+01, 1.960e+02, 2.744e+03],
[1.000e+00, 1.800e+01, 3.240e+02, 5.832e+03]])
linear = LinearRegression().fit(d_3_train,y_train)
y_pred = linear.predict(d_3_train)
plt.scatter(x_train,y_train)
plt.plot(x_train,y_pred)
plt.xlabel('size_x')
plt.ylabel('price_y')
# 可以看出增加3次方特征后,模型看起来有点过拟合
对上篇文章的实战使用多次项回归
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
import pandas as pd
from sklearn.metrics import mean_squared_error as MSE,r2_score
from sklearn.preprocessing import PolynomialFeatures
# 1.导入数据
df = pd.read_excel('./house.xlsx')
df.head(1)
# 2.提取样本数据
feature = df.loc[:,df.columns != 'Y house price of unit area']
target = df[ 'Y house price of unit area']
# 3.给原始特征增加高次特征
p = PolynomialFeatures(degree=2)
d_2_feature = p.fit_transform(feature)
d_2_feature.shape # (414, 28)
target.shape # (414,)
# 4.切分样本数据
x_train,x_test,y_train,y_test = train_test_split(d_2_feature,target,test_size=0.2, random_state=2020)
# 5. 训练模型
linear = LinearRegression()
linear.fit(x_train,y_train)
# 6. 评估模型
# 均方误差MSE
y_pred = linear.predict(x_test)
MSE(y_test, y_pred) # 30.83018292349415
y_test.max(),y_test.min() # (63.2, 13.8)
# R^2
linear.score(x_test,y_test) # 0.7831616150606915
# 7.绘制拟合图
import matplotlib.pyplot as plt
%matplotlib inline
plt.plot(range(len(y_test)),sorted(y_test), c='black', label='y_true')
plt.plot(range(len(y_pred)),sorted(y_pred),c='red', label='y_predict')
plt.legend()
plt.show()
过拟合处理:L2正则化Ridge岭回归模型
- 将过拟合的曲线的凹凸幅度减少就可以将过拟合曲线趋近于拟合曲线了。那么过拟合曲线的凹凸肯定是由y=wx**2+x**3+x**4中的高次项导致的
- 那么L2正则化就是通过将高次项的特征的权重w调小到趋近于0,则高次项的特征就几乎没有了,那么凹凸幅度就会减少,就越趋近于拟合曲线了!
- LinnerRegression是没有办法进行正则化的,所以该算法模型容易出现过拟合,并且无法解决。
- L2正则化:
- 使用带有正则化算法的回归模型(Ridge岭回归)处理过拟合的问题。
Ridge岭回归模型:具备L2正则化的线性回归模型
- API:from sklearn.linear_model import Ridge
- Ridge(alpha=1.0):
- alpha:正则化的力度,力度越大,则表示高次项的权重w越接近于0,导致过拟合曲线的凹凸幅度越小。
- 取值:0-1小数或者1-10整数
- coef_:回归系数
使用岭回归可以通过控制正则化力度参数alpha降低高次项特征的权重
from sklearn.linear_model import Ridge
from sklearn.linear_model import LinearRegression
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import PolynomialFeatures
# 样本的训练数据,特征和目标值
x_train = [[6], [8], [10], [14], [18]] #大小
y_train = [[7], [9], [13], [17.5], [18]]#价格
# 在原有特征上增加3次方特征
p = PolynomialFeatures(degree=3)
d_3_train = p.fit_transform(x_train)
linear = LinearRegression().fit(d_3_train,y_train)
# 原本线性回归权重系数
linear.coef_
array([[ 0. , -1.42626096, 0.31320489, -0.01103344]])
# 使用L2正则化力度调整权重系数
# 参数alpha正则化力度
ridge = Ridge(alpha=0.5)
ridge.fit(d_3_train,y_train)
ridge.coef_
# 调整后权重系数,明显将高权重的变低了
array([[ 0. , -0.14579637, 0.19991159, -0.00792083]])
岭回归的优点:
- 获取的回归系数更符合实际更可靠
- 在病态数据(异常值多的数据)偏多的研究中有更大的存在意义
模型的保存和加载
方式一 (推荐使用方式一,更加便捷)
- from sklearn.externals import joblib
- joblib.dump(model,'xxx.m'):保存
- joblib.load('xxx.m'):加载
方式二
- import pickle
- with open('./123.pkl','wb') as fp:
- pickle.dump(linner,fp)
- with open('./123.pkl','rb') as fp:
- linner = pickle.load(fp)