多项式回归是线性回归法的改进,针对一些不是线性关系的数据
进而引出模型泛化--机器学习中非常重要的概念
一,什么是多项式回归
程序实现:
import numpy as np
importmatplotlib.pyplot as plt
x =np.random.uniform(-3, 3, size=100)
X = x.reshape(-1, 1)
y = 0.5 * x**2 + x + 2+ np.random.normal(0, 1, 100)
![](https://i-blog.csdnimg.cn/blog_migrate/f0be8a1bf223f1d5ab9c9a23533f46d2.png)
使用线性回归拟合:
fromsklearn.linear_model import LinearRegression
lin_reg =LinearRegression()
lin_reg.fit(X, y)
y_predict =lin_reg.predict(X)
![](https://i-blog.csdnimg.cn/blog_migrate/23d079407049282895ac0285971dd1ce.png)
解决方案,添加一个特征
X2 =np.hstack([X, X**2]) #X^2是新构建的特征
lin_reg2 =LinearRegression()
lin_reg2.fit(X2, y)
y_predict2 =lin_reg2.predict(X2)
plt.scatter(x, y)
plt.plot(np.sort(x),y_predict2[np.argsort(x)], color='r')
#注意这里生成的y_predict是无序的。因此要对这俩个参数进行排列
![](https://i-blog.csdnimg.cn/blog_migrate/c1c3af7bafd0c0116076b062d68a2f16.png)
![](https://i-blog.csdnimg.cn/blog_migrate/394d2e733f08374c182acbbcddc831cf.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b2e975bb84fc9b042348d36907c08202.png)
多项式回归没有用到新模型,而是是继续使用线性回归的思路,不同的是多项式回归在线性回归的基础上增加了特征,并对这些新特征进行线性组合。
二,scikit-learn中的多项式回归与Pipline
数据同上
fromsklearn.preprocessing import PolynomialFeatures
poly =PolynomialFeatures(degree=2) #最多添加几次幂
poly.fit(X)
X2 =poly.transform(X) #针对现有的X进行变形,很多算法都有
![](https://i-blog.csdnimg.cn/blog_migrate/6aae4220b6b685a9b9b24797a4560137.png)
从这里也可以看出数据是无序的,并且第一列对应的是零次幂,第三列数据是第二列数据的平方
fromsklearn.linear_model import LinearRegression
lin_reg2 =LinearRegression()
lin_reg2.fit(X2, y)
y_predict2 =lin_reg2.predict(X2)
利用线性回归进行预测
fromsklearn.linear_model import LinearRegression
lin_reg2 =LinearRegression()
lin_reg2.fit(X2, y)
y_predict2 =lin_reg2.predict(X2)
![](https://i-blog.csdnimg.cn/blog_migrate/6036d22bd9561ce6fe6331aca24dc431.png)
![](https://i-blog.csdnimg.cn/blog_migrate/2efb4aceb722fabd62014ef6335735d7.png)
关于PolynomialFeatures类
X =np.arange(1, 11).reshape(-1, 2) #相当于有俩个特征,五行俩列
![](https://i-blog.csdnimg.cn/blog_migrate/5d89a5b677b405ba5c383858ff0f9486.png)
poly =PolynomialFeatures(degree=2)
poly.fit(X)
X2 = poly.transform(X)
![](https://i-blog.csdnimg.cn/blog_migrate/1fe44aa1f8134a0e5e90508c8355a865.png)
观察X2和X的关系,分别生成了原来X的X(1),X(2)和X(1)*X(2),以及平方
也就是生成了不同特征对应的各种排列组合的项
![](https://i-blog.csdnimg.cn/blog_migrate/74f36984d597ed750edd2335fada9c86.png)
pipline用法
进行线性回归过程中进行的三步:多项式的特征,数据的归一化和线性回归。pipline可以将这三步合在一起。
数据生成:
x =np.random.uniform(-3, 3, size=100)
X = x.reshape(-1, 1)
y = 0.5 * x**2 + x + 2+ np.random.normal(0, 1, 100)
使用pipline:
from sklearn.pipelineimport Pipeline
fromsklearn.preprocessing import StandardScaler
poly_reg = Pipeline([
("poly",PolynomialFeatures(degree=2)), #引号里是起的名称
("std_scaler", StandardScaler()), #数据的归一化
("lin_reg", LinearRegression()) #线性回归
])
创建了这个管道,就可以使数据沿着这个管道进行处理
poly_reg.fit(X, y)
y_predict =poly_reg.predict(X)
![](https://i-blog.csdnimg.cn/blog_migrate/263e4b8f879850d45059942c668c9e00.png)
三,过拟合与欠拟合
np.random.seed(666)
x =np.random.uniform(-3.0, 3.0, size=100)
X = x.reshape(-1, 1)
y = 0.5 * x**2 + x + 2+ np.random.normal(0, 1, size=100)
使用线性回归:
fromsklearn.linear_model import LinearRegression
lin_reg =LinearRegression()
lin_reg.fit(X, y)
lin_reg.score(X, y)
![](https://i-blog.csdnimg.cn/blog_migrate/71060d252b5907fac9451281b819a442.png)
y_predict =lin_reg.predict(X)
plt.scatter(x, y)
plt.plot(np.sort(x),y_predict[np.argsort(x)], color='r')
plt.show()
![](https://i-blog.csdnimg.cn/blog_migrate/7136edc0a7ccc3b9320fec798ec54efe.png)
拟合效果很差
对于线性回归,可以使用R^2来判定线性关系,但是对于多项式回归要使用其他的判断标准,为了统一,使用均方误差计算效果。
from sklearn.metricsimport mean_squared_error
y_predict =lin_reg.predict(X)
mean_squared_error(y,y_predict)
使用多项式回归:
同上一节,建立一个pipline
from sklearn.pipelineimport Pipeline
fromsklearn.preprocessing import PolynomialFeatures
fromsklearn.preprocessing import StandardScaler
defPolynomialRegression(degree):
return Pipeline([
("poly",PolynomialFeatures(degree=degree)),
("std_scaler",StandardScaler()),
("lin_reg",LinearRegression())
])
poly2_reg =PolynomialRegression(degree=2)
poly2_reg.fit(X, y)
y2_predict =poly2_reg.predict(X)
mean_squared_error(y,y2_predict)
![](https://i-blog.csdnimg.cn/blog_migrate/904d2685de095b71a75e6fbe7662ee1b.png)
degree=2拟合结果:
![](https://i-blog.csdnimg.cn/blog_migrate/73cc3d7b57c7044c1ca457b19348faa5.png)
如果degree=10:
poly10_reg =PolynomialRegression(degree=10)
poly10_reg.fit(X, y)
y10_predict =poly10_reg.predict(X)
mean_squared_error(y,y10_predict)
![](https://i-blog.csdnimg.cn/blog_migrate/5f380da8f17fb93edc99b02352a9f1aa.png)
拟合结果:
![](https://i-blog.csdnimg.cn/blog_migrate/568b0516c60cdf3f2e7e139f5f00d50d.png)
如果degree=100:
poly100_reg =PolynomialRegression(degree=100)
poly100_reg.fit(X, y)
y100_predict =poly100_reg.predict(X)
mean_squared_error(y,y100_predict)
![](https://i-blog.csdnimg.cn/blog_migrate/18cec30f8963fb2b760e369a753c5ad6.png)
拟合结果:
![](https://i-blog.csdnimg.cn/blog_migrate/cf735cdc2338d4a9acfaa90ac94df722.png)
再看拟合的结果:
X_plot =np.linspace(-3, 3, 100).reshape(100, 1)
y_plot =poly100_reg.predict(X_plot)
plt.scatter(x, y)
plt.plot(X_plot[:,0],y_plot, color='r')
plt.axis([-3, 3, 0,10])
plt.show()
![](https://i-blog.csdnimg.cn/blog_migrate/e5a49cd2337d7808e01d9cdff21b1610.png)
degree越高,均方误差越低,但是不能更好的反应数据样本的变化曲线,也就是多项式拟合的过程中将数据的函数曲线便复杂了。这就是过拟合。
而对于把函数曲线弄的太简单的情况就是欠拟合。
train test split的意义
模型的泛化能力:新加入数据后,看看拟合的曲线是否满足新的样本点
使用训练数据集与测试数据集来测试预测模型的泛化能力
fromsklearn.model_selection import train_test_split
X_train, X_test,y_train, y_test = train_test_split(X, y, random_state=666)
分别使用不同degree的多项式回归来拟合训练数据集,并使用测试数据集进行测试分数:
![](https://i-blog.csdnimg.cn/blog_migrate/4adae517813521d46a22f5ebe10cf2ed.png)
![](https://i-blog.csdnimg.cn/blog_migrate/73479cdcc9a511830d66e2c909fdaf71.png)
四,学习曲线
随着训练样本的逐渐增多,算法训练出的模型的表现能力
生成的数据同上
fromsklearn.model_selection import train_test_split
X_train, X_test,y_train, y_test = train_test_split(X, y, random_state=10)
fromsklearn.linear_model import LinearRegression
from sklearn.metricsimport mean_squared_error
train_score = []
test_score = []
for i in range(1, 76):#从一个数据到76个数据
lin_reg = LinearRegression()
lin_reg.fit(X_train[:i], y_train[:i])
y_train_predict =lin_reg.predict(X_train[:i])
train_score.append(mean_squared_error(y_train[:i],y_train_predict))
y_test_predict = lin_reg.predict(X_test)
test_score.append(mean_squared_error(y_test, y_test_predict))
plt.plot([i for i inrange(1, 76)], np.sqrt(train_score), label="train")
plt.plot([i for i inrange(1, 76)], np.sqrt(test_score), label="test")
plt.legend()
plt.show()
![](https://i-blog.csdnimg.cn/blog_migrate/4357c54c144ca68a23bb37c0fa72ccf1.png)
封装成一个函数:
![](https://i-blog.csdnimg.cn/blog_migrate/903f8d70fb49e8a0d2b6bcc294ea899a.png)
线性回归学习曲线:(欠拟合)
![](https://i-blog.csdnimg.cn/blog_migrate/720aec7cf90dae506f88941b5e2383c4.png)
利用pipline训练模型:
二阶多项式:
![](https://i-blog.csdnimg.cn/blog_migrate/cf50338261335c240f9e74cf5df980d2.png)
二阶多项式回归学习曲线:(最佳)
![](https://i-blog.csdnimg.cn/blog_migrate/fc262576af036c6a18009871ca0d4233.png)
拟合结果比较好
degree=20:(过拟合)
poly20_reg =PolynomialRegression(degree=20)
plot_learning_curve(poly20_reg,X_train, X_test, y_train, y_test)
![](https://i-blog.csdnimg.cn/blog_migrate/d64162f80569366dbd1e22fa2adb370b.png)
泛化能力很差,过拟合
五,验证数据集与交叉验证
验证数据集:
测试数据集的意义:发生过拟合却不自知
问题:针对特定测试数据集过拟合
![](https://i-blog.csdnimg.cn/blog_migrate/1da48cf5113bcc68b4e50ea58079ec48.png)
训练数据集获得模型;验证数据集用于调整超参数,仿真过拟合;最终的测试数据集作为衡量最终模型性能的数据集。
交叉验证:
![](https://i-blog.csdnimg.cn/blog_migrate/29a64f6b51f70df231ebd610bf9d9de7.png)
交叉验证程序实现:
导入数据集:
import numpy as np
from sklearn importdatasets
digits =datasets.load_digits()
X = digits.data
y = digits.target
测试train_test_split:
fromsklearn.model_selection import train_test_split
X_train, X_test,y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=666)
from sklearn.neighborsimport KNeighborsClassifier
best_k, best_p,best_score = 0, 0, 0
for k in range(2, 11):
for p in range(1, 6):
knn_clf =KNeighborsClassifier(weights="distance", n_neighbors=k, p=p)
knn_clf.fit(X_train, y_train)
score = knn_clf.score(X_test, y_test)
if score > best_score:
best_k, best_p, best_score = k, p,score
print("Best K=", best_k)
print("Best P=", best_p)
print("Best Score=", best_score)
![](https://i-blog.csdnimg.cn/blog_migrate/fed5a760fca481d0c5b38833f1f9dabd.png)
使用交叉验证:
fromsklearn.model_selection import cross_val_score
knn_clf =KNeighborsClassifier()
cross_val_score(knn_clf,X_train, y_train)
![](https://i-blog.csdnimg.cn/blog_migrate/6a57649fd800d60f8494143d375a9e48.png)
默认分成了五份进行交叉验证
![](https://i-blog.csdnimg.cn/blog_migrate/96a115eacc5fa3274840c423f07ec16b.png)
得到和上边不同的参数
![](https://i-blog.csdnimg.cn/blog_migrate/394c6b6b387f62b32a4b73b64d3d493b.png)
交叉验证的准确度低于普通验证方式,是因为交叉验证并没有过拟合
并且交叉验证的目的是为了得到最好的超参数,而不是得到最好的准确率。要得到最好的准确率就需要重新利用得到的超参数进行fit,再计算准确率。
![](https://i-blog.csdnimg.cn/blog_migrate/1637216da747b8b18add13e22e3b099c.png)
回顾网格搜索:
用到了交叉验证的方式GridSearchCV
![](https://i-blog.csdnimg.cn/blog_migrate/db9ed5434d0de976014044650964c319.png)
同样默认将训练集分成5份,每份计算9*5=45种参数的组合,因此一共要进行5*45=225次训练
![](https://i-blog.csdnimg.cn/blog_migrate/167c1db2a720b7c8961ab0bbda8916b2.png)
best_estimator包就是找到最佳参数对应的准确率
CV参数:
![](https://i-blog.csdnimg.cn/blog_migrate/2b340416b393799a1b73c61f781f349c.png)
总结:
把训练数据集分成k份,称为k-fola crossvalidation,缺点就是速度慢了k倍
极端的情况是把训练数据集分成最多份,只留一个数据进行测试,称为留一法,leave-one-out cross validation,简称LOO-CV。这样就完全不受随机分配的影响,最接近模型真正的性能指标。计算量巨大
六,偏差方差权衡BiasVariance Trade off
![](https://i-blog.csdnimg.cn/blog_migrate/5a56380eff78a178f480fec24087cd19.png)
模型误差=偏差+方差+不可避免的误差(数据本身的噪音)
导致偏差的主要原因:
对问题本身的假设不正确,比如非线性数据使用线性回归(欠拟合underfitting)
方差:数据的一点点扰动都会较大的影响模型。通常原因是使用的模型太复杂。比如使用高阶多项式(过拟合overfitting)
有些算法天生是高方差的算法(KNN,对数据敏感,有一个数据错误,整体的数据预测就不准确)
非参数学习通常是高方差算法,因为不对数据进行任何假设,只能根据现有的数据进行预测(例子还是KNN,数据本身就是算法,高度依赖数据,还有决策树也是)
有些算法天生是高偏差算法(比如线性回归,因为现实中的很多问题并不是线性关系)
参数学习通常都是高偏差算法,因为对数据有极强的假设
大多数算法具有相应的参数,可以调整偏差和方差(比如KNN中的k,还有线性回归中的多项式回归)
偏差和方差通常是矛盾的,降低偏差会提高方差,反之同理。
机器学习的主要挑战来自方差!(只局限于算法的层面)
降低方差的常见手段有:
降低模型复杂度
减少数据的维数;降噪
增加样本数
使用验证集
模型的正则化
七,模型泛化与岭回归
模型正则化Regularization
限制参数的大小
![](https://i-blog.csdnimg.cn/blog_migrate/ddaa0aefc7868afb7b079270b55c991e.png)
加入模型正则化后,可以使系数不太大,防止拟合的曲线太过于陡峭(注意没有加入theta0)
1/2也可以不加,α是个超参数,表示正则化因素的影响程度
以上的正则化方式叫做岭回归(Ridge Gegression)
岭回归程序实现:
生成参数
![](https://i-blog.csdnimg.cn/blog_migrate/1f1b93e9a6c01d3c937c71c2e1e0e36c.png)
训练拟合
![](https://i-blog.csdnimg.cn/blog_migrate/eeddbabd6b6d977488c3a2fde74dd0c6.png)
![](https://i-blog.csdnimg.cn/blog_migrate/5b36b34d6402321f8693759dab29744c.png)
定义一个绘图函数,方便调用:
![](https://i-blog.csdnimg.cn/blog_migrate/fd5e4b5d2aff0802ea978cf22e853fad.png)
使用岭回归:
fromsklearn.linear_model import Ridge
defRidgeRegression(degree, alpha):
return Pipeline([
("poly",PolynomialFeatures(degree=degree)),
("std_scaler",StandardScaler()),
("ridge_reg",Ridge(alpha=alpha))
])
ridge1_reg =RidgeRegression(20, 0.0001)
ridge1_reg.fit(X_train,y_train)
y1_predict =ridge1_reg.predict(X_test)
mean_squared_error(y_test,y1_predict)
![](https://i-blog.csdnimg.cn/blog_migrate/68de3270e9d5d9cdedef31b7cd81ee9c.png)
plot_model(ridge1_reg)
![](https://i-blog.csdnimg.cn/blog_migrate/1d634afa2d6b9bfbd0d9471036cb4c76.png)
线条缓和了许多
ridge2_reg =RidgeRegression(20, 1)
ridge2_reg.fit(X_train,y_train)
y2_predict =ridge2_reg.predict(X_test)
mean_squared_error(y_test,y2_predict)
![](https://i-blog.csdnimg.cn/blog_migrate/e5bab5ca6bd138736fff57d549c8795e.png)
结果进一步优化
当α=100
![](https://i-blog.csdnimg.cn/blog_migrate/bb933c0de667984f80e8cd9bff2c4889.png)
正则化过头了
![](https://i-blog.csdnimg.cn/blog_migrate/af68c7c2c81d68c1fae441d6985dacbf.png)
α=10000000
![](https://i-blog.csdnimg.cn/blog_migrate/03f653d28162abcb6849a09171ca25a5.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0b18ac1651db635aa3e28d162074c96d.png)
几乎是一条直线(所有θ=0)
八,LASSO回归
LeastAbsolute Shrinkage and SelectionOperator Regression
![](https://i-blog.csdnimg.cn/blog_migrate/e7015385e9e8f6914a337d650dc8b966.png)
程序实现:
![](https://i-blog.csdnimg.cn/blog_migrate/b70d93deb48f68a5a7d1a40766ac19cd.png)
![](https://i-blog.csdnimg.cn/blog_migrate/0e11e236290de3a628bbb2805d8a8dd5.png)
lasso2_reg =LassoRegression(20, 0.1)
![](https://i-blog.csdnimg.cn/blog_migrate/540a63caae9722603c89fad205dc73c5.png)
lasso3_reg =LassoRegression(20, 1)
![](https://i-blog.csdnimg.cn/blog_migrate/9077623db8e3422b34e4a1457ff13e09.png)
比较Ridge和LASSO
Ridge得到的拟合曲线相比LASSO更倾向于是弯曲的,因为正则化形式是二次方的性质
LASSO趋向于使一部分的theta变为0,所以可作为特征选择使用,即把一些特征的系数变为0,表示这个特征没有用
![](https://i-blog.csdnimg.cn/blog_migrate/1bb53cd0db38d7827b32d4d7c9a42bff.png)
![](https://i-blog.csdnimg.cn/blog_migrate/b3e6790677f5745726ef56efe5ef127a.png)
从准确性来看Ridge更好,但如果特征太大太多就可以用LASSO回归
九,L1,L2和弹性网络
![](https://i-blog.csdnimg.cn/blog_migrate/823db2bdf4778a97d4f98c88528550e7.png)
回顾明可夫斯基距离
Lp范数:
p=1曼哈顿距离,p=2欧拉距离
岭回归的正则项也被称为L2正则项
LASSO正则项也叫L1正则项
L0正则项是让theta的数量尽可能的少,进而使曲线不要太陡,但一般不使用,实际用L1取代
弹性网ElasticNet
![](https://i-blog.csdnimg.cn/blog_migrate/c452aca18c46a753b22971442880eb00.png)
引入俩个正则项。一般来说计算力强,数据特征不多,纯使用岭回归更好
不同的数据样本有不同的特征,要具体问题具体分析