7.多项式回归和模型选择
7.1多项式回归
7.1.1多项式回归的实现思想
在现实生活中,很多数据之间是非线性关系;虽然使用多线性回归来拟合非线性数据集,但是其拟合效果是非常的差。
#程序7-1
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(123456)
x = np.random.uniform(-5,5,size=150)
y = 1*(x**2) + 2*x + 3 + np.random.normal(0,3,size=150)
X = x.reshape(-1,1)
print(y.shape)
from sklearn.linear_model import LinearRegression
lin_reg = LinearRegression()
lin_reg.fit(X,y)
y_predict = lin_reg.predict(X)
plt.scatter(X,y)
plt.plot(X,y_predict,color='r')
plt.show()
运行结果:
对于y = ax2 + bx + c,我们可以把x和x2各当做一个特征,然后使用线性回归的方法来求解。
#程序7-2
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(123456)
X = np.random.uniform(-5,5,size=150).reshape(-1,1)
#(列)向量和矩阵之间的运算,最好将向量也转化成矩阵再运算
#若矩阵是(150,1),向量是(150,),则相加得(150,150)
#因为将矩阵的每一行元素都加上向量
y = 1*(X**2) + 2*X + 3 + np.random.normal(0,3,size=150).reshape(-1,1)
print(y.shape)
from sklearn.linear_model import LinearRegression
X2 = np.hstack([X,X**2])
print(X2.shape)
lin_reg = LinearRegression()
lin_reg.fit(X2,y)
print(lin_reg.coef_)
print(lin_reg.intercept_)
y_predict = lin_reg.predict(X2)
plt.scatter(X,y)
#由于使用fancy indexing,其[]内不能是矩阵,因此使用reshape转换为向量
plt.plot(np.sort(X,axis=0), y_predict[np.argsort(X,axis=0).reshape(-1,)],color='r')
plt.show()
运行结果:
(150, 1)
(150, 2)
[[1.91743701 1.05227471]]
[2.67113733]
多项式回归本质上使用的还是多线性回归,不过在其样本的数据集上,增加了特征项。在满足y = ax2 + bx + c关系的数据集中,将x和x2当做特征,来求出系数b、a和截距c。
7.1.2使用sklearn来实现多项式回归
在sklearn库中,并没有封装多项式回归的具体算法;但是在sklearn.preprocessing中提供了PolynomialFeatures类,其作用是创建多项式特征。
在PolynomialFeatures中有参数degree,当degree = 2,表示创建2阶多项式特征。若数据集原有特征x1,则生成x10=1、x11、x12,即增加了2个特征;若原数据集有特征x1、x2,则生成1、x11、x21、x1*x2、x12、x22,即增加了4个特征。
#程序7-3
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(123456)
X = np.random.uniform(-5,5,size=150).reshape(-1,1)
#(列)向量和矩阵之间的运算,最好将向量也转化成矩阵再运算
#若矩阵是(150,1),向量是(150,),则相加得(150,150)
#因为将矩阵的每一行元素都加上向量
y = 1*(X**2) + 2*X + 3 + np.random.normal(0,3,size=150).reshape(-1,1)
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
pol_fea = PolynomialFeatures(degree=2)
pol_fea.fit(X)
X2 = pol_fea.transform(X)
print(X[:5])
print(X2[:5])
lin_reg = LinearRegression()
lin_reg.fit(X2,y)
print(lin_reg.coef_)
print(lin_reg.intercept_)
y_predict = lin_reg.predict(X2)
plt.scatter(X,y)
#由于使用fancy indexing,其[]内不能是矩阵,因此使用reshape转换为向量
plt.plot(np.sort(X,axis=0), y_predict[np.argsort(X,axis=0).reshape(-1,)],color='r')
plt.show()
运行结果:
[[-3.73030167]
[ 4.66717838]
[-2.39523994]
[ 3.97236524]
[-1.23250284]]
[[ 1. -3.73030167 13.91515055]
[ 1. 4.66717838 21.78255408]
[ 1. -2.39523994 5.73717438]
[ 1. 3.97236524 15.77968563]
[ 1. -1.23250284 1.51906325]]
[[0. 1.91743701 1.05227471]]
[2.67113733]
根据多项式的系数和截距可以得出y = 1.91743701x + 1.05227471x2 + 2.67113733,这与y=x2+2x+3及其相近。
7.1.3使用pipeline进行封装
在pipeline模块中,使用Pipeline将相同处理过程的类进行封装。
#程序7-4
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(123456)
X = np.random.uniform(-5,5,size=150).reshape(-1,1)
#(列)向量和矩阵之间的运算,最好将向量也转化成矩阵再运算
#若矩阵是(150,1),向量是(150,),则相加得(150,150)
#因为将矩阵的每一行元素都加上向量
y = 1*(X**2) + 2*X + 3 + np.random.normal(0,3,size=150).reshape(-1,1)
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
pol_lin = Pipeline([
('pol_fea',PolynomialFeatures(degree=2)),
('lin_reg',LinearRegression())
])
pol_lin.fit(X,y)
y_predict = pol_lin.predict(X)
plt.scatter(X,y)
#由于使用fancy indexing,其[]内不能是矩阵,因此使用reshape转换为向量
plt.plot(np.sort(X,axis=0), y_predict[np.argsort(X,axis=0).reshape(-1,)],color='r')
plt.show()
运行结果:
7.2模型选择
7.2.1欠拟合和过拟合
把模型在训练数据集上的误差,称为“训练误差”;模型在测试数据集上的误差称为“泛化误差”。当模型的泛化误差很小时,称模型的泛化能力较强。
我们希望得到泛化误差较小的模型,而在实际训练过程中,当模型未能学到训练数据集的“规律”,称为欠拟合;当模型从训练数据集中学的“太好”,把一些无关的“规律”也学了进去,称为过拟合。
欠拟合的具体表现是模型在训练数据集和测试数据集上的表现都不好。引起欠拟合的原因有:模型过于简单;特征数太少难以建立正确的映射关系。
#程序7-5:欠拟合
import numpy as np
np.random.seed(123456)
X = np.random.uniform(-5,5,size=150).reshape(-1,1)
#(列)向量和矩阵之间的运算,最好将向量也转化成矩阵再运算
#若矩阵是(150,1),向量是(150,),则相加得(150,150)
#因为将矩阵的每一行元素都加上向量
y = 1*(X**2) + 2*X + 3 + np.random.normal(0,3,size=150).reshape(-1,1)
print(y.shape)
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=888)
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
lin_reg = LinearRegression()
lin_reg.fit(X_train,y_train)
y_train_predict = lin_reg.predict(X_train)
print('在训练数据集上的MSE:',mean_squared_error(X_train,y_train_predict))
y_test_predict = lin_reg.predict(X_test)
print('在测试数据集上的MSE:',mean_squared_error(y_test,y_test_predict))
import matplotlib.pyplot as plt
plt.scatter(X,y)
plt.plot(X_test,y_test_predict,color='r')
plt.show()
运行结果:
(150, 1)
在训练数据集上的MSE: 121.00150550552617
在测试数据集上的MSE: 74.27873202535352
过拟合的具体表现是在训练数据集表现好,而在测试数据集上表现不好。引起过拟合的原因:模型本身过于复杂,拟合了训练数据集中的噪声;训练样本太少并缺乏代表性;训练样本噪声干扰,因此需要降噪。
#程序7-6:过拟合
import numpy as np
np.random.seed(123456)
X = np.random.uniform(-5,5,size=200).reshape(-1,1)
#(列)向量和矩阵之间的运算,最好将向量也转化成矩阵再运算
#若矩阵是(150,1),向量是(150,),则相加得(150,150)
#因为将矩阵的每一行元素都加上向量
y = 1*(X**2) + 2*X + 3 + np.random.normal(0,3,size=200).reshape(-1,1)
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=888)
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error
def PolynomialRegression(degree):
return Pipeline([
("poly", PolynomialFeatures(degree=degree)),
#数据归一化容易看过拟合情况下曲线的弯曲情况
("std_scaler", StandardScaler()),
("lin_reg", LinearRegression())
])
pol_reg = PolynomialRegression(100)
pol_reg.fit(X_train,y_train)
y_train_predict = pol_reg.predict(X_train)
print('在训练数据集上的MSE:',mean_squared_error(y_train,y_train_predict))
y_test_predict = pol_reg.predict(X_test)
print('在测试数据集上的MSE:',mean_squared_error(y_test,y_test_predict))
import matplotlib.pyplot as plt
plt.scatter(X_train,y_train)
#由于使用fancy indexing,其[]内不能是矩阵,因此使用reshape转换为向量
plt.plot(np.sort(X_train,axis=0), y_train_predict[np.argsort(X_train,axis=0).reshape(-1,)],color='r')
plt.show()
运行结果:
在训练数据集上的MSE: 12.604951173822858
在测试数据集上的MSE: 295656869483.6039
我们发现在训练数据集上的MSE很小,而在测试数据集上的MSE达到上亿,这就是过拟合的实际表现。
当degree越大,其模型复杂度越高,训练数据集的模型准确率也越来越高,测试数据集的模型准确率是先高后低。其关系如下图所示:
#程序7-7
import numpy as np
np.random.seed(123456)
X = np.random.uniform(-5,5,size=200).reshape(-1,1)
#(列)向量和矩阵之间的运算,最好将向量也转化成矩阵再运算
#若矩阵是(150,1),向量是(150,),则相加得(150,150)
#因为将矩阵的每一行元素都加上向量
y = 1*(X**2) + 2*X + 3 + np.random.normal(0,3,size=200).reshape(-1,1)
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=888)
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error
def PolynomialRegression(degree):
return Pipeline([
("poly", PolynomialFeatures(degree=degree)),
#数据归一化容易看过拟合情况下曲线的弯曲情况
("std_scaler", StandardScaler()),
("lin_reg", LinearRegression())
])
pol_reg = PolynomialRegression(2)
pol_reg.fit(X_train,y_train)
y_train_predict = pol_reg.predict(X_train)
print('在训练数据集上的MSE:',mean_squared_error(y_train,y_train_predict))
y_test_predict = pol_reg.predict(X_test)
print('在测试数据集上的MSE:',mean_squared_error(y_test,y_test_predict))
import matplotlib.pyplot as plt
plt.scatter(X_train,y_train)
#由于使用fancy indexing,其[]内不能是矩阵,因此使用reshape转换为向量
plt.plot(np.sort(X_train,axis=0), y_train_predict[np.argsort(X_train,axis=0).reshape(-1,)],color='r')
plt.show()
运行结果:
在训练数据集上的MSE: 10.641749410813102
在测试数据集上的MSE: 12.205588379868715
当模型在训练数据集和测试数据集上表现讲好时,称为适度拟合。
7.2.2交叉验证法
为了检测模型的拟合程度,把数据集分为训练数据集和测试数据集。在训练数据集上获得模型,再使用测试数据集来检测模型的准确率。
当模型使用测试数据集进行检测,其效果并不好时,需要调整参数重新训练得到新的模型。由于测试数据集是不变的,这个新模型实际上是针对测试数据集的。
简单的将数据集划分为训练数据集和测试数据集来检测模型的拟合程度,有一个重大的缺陷—模型可能仅仅高度拟合测试数据集,而对一个新的陌生数据集,其表现并不好。因此,这小节使用交叉验证法来检测模型的拟合程度。
交叉验证法:(1)将数据集分为训练数据集和测试数据集;
(2)将训练数据集划分为k个大小相似的互斥子集,每个子集尽量保持数据分布的一致性;
(3)每次使用k-1个子集来训练模型,使用剩下的子集来验证模型,得到k个测试结果;
(4)使用k个测试结果的均值作为最终结果;
(5)模型使用测试数据集获得的结果,作为模型的最终表现。
#程序7-8
import numpy as np
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
digits = datasets.load_digits()
X = digits.data
y = digits.target
from sklearn.model_selection import train_test_split,cross_val_score
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=123456)
best_score,k,p = 0.,0,0
for k in range(1,11):
for p in range(1,6):
knn_clf = KNeighborsClassifier(weights='distance',n_neighbors=k,p=p,n_jobs=-1)
scores = cross_val_score(knn_clf,X_train,y_train,cv=3)
score = np.mean(scores)
if(score > best_score):
best_score = score
best_k = k
best_p = p
print('best_k = ',best_k)
print('best_p = ',best_p)
print('best_score = ',best_score)
运行结果:
best_k = 4
best_p = 2
best_score = 0.9874909561534227
使用model_selection模块下的cross_val_score函数进行交叉验证;在前面的网格搜索中使用的也是交叉验证法。
7.2.3偏差和方差
模型的泛化误差可以分解为偏差和方差。
偏差(Bias)是模型本身导致的误差,它是模型预测值的数学期望和真实值的数学期望之间的差距。方差(Variance)是由于训练样本集的一点点扰动都会较大的影响模型,进而导致的误差。方差可以理解为模型预测值的变化范围或样本的离散程度。
高偏差意味着模型本身预测值的期望和真实值得期望差距很大。其主要原因是对问题本身的假设不正确(如非线性数据使用线性回归),导致模型的欠拟合。
高反差意味着算法对训练样本中的随机噪声进行建模。主要原因是使用的模型太过复杂(如高阶多项式回归),导致模型的过拟合。
机器学习算法又可以分为参数学习和非参数学习。简化目标函数为已知形式的算法就称为参数机器学习算法;对于目标函数形式不作过多的假设的算法称为非参数机器学习算法。
由于非参数学习不对数据进行任何假设,如kNN,一般都是高方差的算法;参数学习由于对数据具有极强的假设性,如线性回归,一般都是高偏差的算法。
模型过于简单,一般会有高偏差低方差;模型过于复杂,会有高方差低偏差。偏差和方差一般是矛盾的,降低偏差就会提高方差,降低方差就会提高偏差。因此在偏差和方差之间需要选择合适的数值。
机器学习的主要挑战是来自于方差,而如何降低方差是我们主要关注的。
降低方差的办法:(1)降低模型复杂度;
(2)降低数据维度或降噪;
(3)增加样本数;
(4)使用交叉验证法;
(5)模型正则化。
7.2.4正则化
正则化可以减小模型的方差,以高阶多项式回归为例。当多项式的阶数(degree)越高,模型就越复杂,表现形式是模型生成的曲线非常的弯曲和陡峭,即特征向量的系数θ值越来越大。
正则化的作用就是控制θ值的大小,使得模型生成的曲线变得光滑。正则性越高,曲线越光滑。
1.岭回归
#程序7-9
import numpy as np
np.random.seed(123456)
X = np.random.uniform(-5,5,size=200).reshape(-1,1)
#(列)向量和矩阵之间的运算,最好将向量也转化成矩阵再运算
#若矩阵是(150,1),向量是(150,),则相加得(150,150)
#因为将矩阵的每一行元素都加上向量
y = 1*(X**2) + 2*X + 3 + np.random.normal(0,3,size=200).reshape(-1,1)
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=888)
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error
# def PolynomialRegression(degree):
# return Pipeline([
# ("poly", PolynomialFeatures(degree=degree)),
# #数据归一化容易看过拟合情况下曲线的弯曲情况
# ("std_scaler", StandardScaler()),
# ("lin_reg", LinearRegression())
# ])
# pol_reg = PolynomialRegression(100)
# pol_reg.fit(X_train,y_train)
# y_train_predict = pol_reg.predict(X_train)
# print('在训练数据集上的MSE:',mean_squared_error(y_train,y_train_predict))
# y_test_predict = pol_reg.predict(X_test)
# print('在测试数据集上的MSE:',mean_squared_error(y_test,y_test_predict))
pol_fea = PolynomialFeatures(degree=50)
pol_fea.fit(X_train)
X2_train = pol_fea.transform(X_train)
X2_test = pol_fea.transform(X_test)
std_sca = StandardScaler()
std_sca.fit(X2_train)
X2_train_std = std_sca.transform(X2_train)
X2_test_std = std_sca.transform(X2_test)
lin_reg = LinearRegression()
lin_reg.fit(X2_train_std,y_train)
print('特征向量的系数theta:',lin_reg.coef_)
print('截距:',lin_reg.intercept_)
y_train_predict = lin_reg.predict(X2_train_std)
y_test_predict = lin_reg.predict(X2_test_std)
print('在训练数据集上的MSE:',mean_squared_error(y_train,y_train_predict))
print('在测试数据集上的MSE:',mean_squared_error(y_test,y_test_predict))
import matplotlib.pyplot as plt
plt.scatter(X_train,y_train)
#由于使用fancy indexing,其[]内不能是矩阵,因此使用reshape转换为向量
plt.plot(np.sort(X_train,axis=0), y_train_predict[np.argsort(X_train,axis=0).reshape(-1,)],color='r')
plt.show()
运行结果:
特征向量的系数theta:
[[-6.56494261e+13 1.78905584e+01 1.18504747e+02 -2.44204009e+03
-1.79329824e+03 1.34966093e+05 -4.29183814e+04 -3.92465339e+06
1.97257799e+06 7.35434776e+07 -3.66208081e+07 -9.63273764e+08
4.21518131e+08 9.17595746e+09 -3.30070115e+09 -6.50031299e+10
1.83793894e+10 3.46677665e+11 -7.54228508e+10 -1.39785077e+12
2.36677549e+11 4.24141229e+12 -5.89193629e+11 -9.51026207e+12
1.18497149e+12 1.50523338e+13 -1.85295767e+12 -1.47754881e+13
1.91037640e+12 4.20131322e+12 -4.62269036e+11 9.90049255e+12
-1.95423320e+12 -1.21238965e+13 2.46008030e+12 -1.31144064e+12
6.75412645e+11 1.29271998e+13 -3.75958815e+12 -6.82407520e+12
1.66039761e+12 -8.62302797e+12 3.97071826e+12 1.51834955e+13
-6.69352370e+12 -1.01562587e+13 4.68754422e+12 3.39872578e+12
-1.65791036e+12 -4.72630029e+11 2.43454616e+11]]
截距: [10.50465527]
在训练数据集上的MSE: 18.28855679690813
在测试数据集上的MSE: 81473.42618595813
过拟合的情况下,θ值非常的大;因此损失函数需要加上一项来控制θ值的大小。对于线性回归算法,其损失函数:
在线性回归中,使J(θ)尽可能的小,进而使用最小二乘法的正规方程解或梯度下降法得到θ的值。
在损失函数中加入正则项,则:
这称为“岭回归”。
岭回归是在均方误差的基础上加上正则项,通过确定α的值,使得模型在方差和偏差之间达到平衡。α值增大,模型方差减小偏差增大。
#程序7-10:岭回归-linear_model.Ridge
import numpy as np
np.random.seed(123456)
X = np.random.uniform(-5,5,size=200).reshape(-1,1)
#(列)向量和矩阵之间的运算,最好将向量也转化成矩阵再运算
#若矩阵是(150,1),向量是(150,),则相加得(150,150)
#因为将矩阵的每一行元素都加上向量
y = 1*(X**2) + 2*X + 3 + np.random.normal(0,3,size=200).reshape(-1,1)
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=888)
from sklearn.linear_model import LinearRegression,Ridge
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error
# def PolynomialRidge(degree,alpha):
# return Pipeline([
# ("poly", PolynomialFeatures(degree=degree)),
# #数据归一化容易看过拟合情况下曲线的弯曲情况
# ("std_scaler", StandardScaler()),
# ("rid", Ridge(alpha=alpha))
# ])
# pol_rid = PolynomialRidge(50,0.0001)
# pol_rid.fit(X_train,y_train)
# y_train_predict = pol_rid.predict(X_train)
# print('在训练数据集上的MSE:',mean_squared_error(y_train,y_train_predict))
# y_test_predict = pol_rid.predict(X_test)
# print('在测试数据集上的MSE:',mean_squared_error(y_test,y_test_predict))
pol_fea = PolynomialFeatures(degree=50)
pol_fea.fit(X_train)
X2_train = pol_fea.transform(X_train)
X2_test = pol_fea.transform(X_test)
std_sca = StandardScaler()
std_sca.fit(X2_train)
X2_train_std = std_sca.transform(X2_train)
X2_test_std = std_sca.transform(X2_test)
rid = Ridge(alpha=0.0001)
rid.fit(X2_train_std,y_train)
print('特征向量的系数theta:\n',rid.coef_)
print('截距:',rid.intercept_)
y_train_predict = rid.predict(X2_train_std)
y_test_predict = rid.predict(X2_test_std)
print('在训练数据集上的MSE:',mean_squared_error(y_train,y_train_predict))
print('在测试数据集上的MSE:',mean_squared_error(y_test,y_test_predict))
import matplotlib.pyplot as plt
plt.scatter(X_train,y_train)
#由于使用fancy indexing,其[]内不能是矩阵,因此使用reshape转换为向量
plt.plot(np.sort(X_train,axis=0), y_train_predict[np.argsort(X_train,axis=0).reshape(-1,)],color='r')
plt.show()
运行结果:
特征向量的系数theta:
[[ 0. 6.97135358 9.10384854 -17.59722933 -14.62793881
60.72511598 9.8568805 -60.15342208 57.60211227 -24.66772623
-28.34015303 28.53832163 -59.68911536 38.21035916 -33.60702842
15.89621076 6.24257128 -11.23590436 33.39507911 -26.69958714
41.32950475 -27.35276611 33.82261572 -17.80018832 17.72586774
-4.68141439 -0.5431035 6.71711799 -16.22542871 13.64989874
-26.39539898 15.72618809 -29.75874415 14.11343524 -26.36864467
10.63057946 -17.35999903 6.9886767 -4.72201539 4.27091836
8.89648165 2.65099317 20.35818197 1.30630417 26.19092521
-1.52957787 22.72629496 -8.42740115 6.22333402 -22.57795392
-27.02338054]]
截距: [10.50348309]
在训练数据集上的MSE: 9.835486453304295
在测试数据集上的MSE: 13.01305405167717
在线性回归的损失函数中加入另一个正则项,则:
这称为“LASSO回归”。
#程序7-11:LASSO回归-linear_model.Lasso
import numpy as np
np.random.seed(123456)
X = np.random.uniform(-5,5,size=200).reshape(-1,1)
#(列)向量和矩阵之间的运算,最好将向量也转化成矩阵再运算
#若矩阵是(150,1),向量是(150,),则相加得(150,150)
#因为将矩阵的每一行元素都加上向量
y = 1*(X**2) + 2*X + 3 + np.random.normal(0,3,size=200).reshape(-1,1)
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=888)
from sklearn.linear_model import LinearRegression,Lasso
from sklearn.preprocessing import PolynomialFeatures,StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import mean_squared_error
# def PolynomialLasso(degree,alpha):
# return Pipeline([
# ("poly", PolynomialFeatures(degree=degree)),
# #数据归一化容易看过拟合情况下曲线的弯曲情况
# ("std_scaler", StandardScaler()),
# ("las", Lasso(alpha=alpha))
# ])
# pol_las = PolynomialLasso(50,0.01)
# pol_las.fit(X_train,y_train)
# y_train_predict = pol_las.predict(X_train)
# print('在训练数据集上的MSE:',mean_squared_error(y_train,y_train_predict))
# y_test_predict = pol_las.predict(X_test)
# print('在测试数据集上的MSE:',mean_squared_error(y_test,y_test_predict))
pol_fea = PolynomialFeatures(degree=50)
pol_fea.fit(X_train)
X2_train = pol_fea.transform(X_train)
X2_test = pol_fea.transform(X_test)
std_sca = StandardScaler()
std_sca.fit(X2_train)
X2_train_std = std_sca.transform(X2_train)
X2_test_std = std_sca.transform(X2_test)
las = Lasso(alpha=0.01)
las.fit(X2_train_std,y_train)
print('特征向量的系数theta:\n',las.coef_)
print('截距:',las.intercept_)
y_train_predict = las.predict(X2_train_std)
y_test_predict = las.predict(X2_test_std)
print('在训练数据集上的MSE:',mean_squared_error(y_train,y_train_predict))
print('在测试数据集上的MSE:',mean_squared_error(y_test,y_test_predict))
import matplotlib.pyplot as plt
plt.scatter(X_train,y_train)
#由于使用fancy indexing,其[]内不能是矩阵,因此使用reshape转换为向量
plt.plot(np.sort(X_train,axis=0), y_train_predict[np.argsort(X_train,axis=0).reshape(-1,)],color='r')
plt.show()
运行结果:
特征向量的系数theta:
[ 0. 5.48638699 7.21330656 0.53319593 0.56711415 0.
-0. -0. -0. -1.03799411 -0.8783933 -0.
-0. -0. -0. -0. -0. -0.
0. 0. 0. 0. 0. 0.
0.44377862 1.06246554 0.55515671 0.45626085 0.32101146 0.01546315
0.05376119 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0.
0. -0. -0. -0. -0. -0.
-0. -1.35397309 -0.66427881]
截距: [10.50348309]
在训练数据集上的MSE: 10.29995346491136
在测试数据集上的MSE: 12.652483622957615
在岭回归和LASSO回归中,其α的取值是不同的。由于岭回归中加入的是L2正则项,因此其α取值要非常小才可以;而LASSO回归中加入的是L1正则项,因此α取值可以稍大一点。
对于,称为Lp范数。将岭回归中的称为L2正则项;将LASSO回归中的称为L1正则项。具体可以参考明可夫斯基距离。
LASSO回归趋向于使得一部分θ值变为0,所以可以作为特征选择使用。当θ值为0,表示对应的特征是完全没有用的;当θ值不为0,表示对应的特征是有用的。岭回归中趋向于使得一部分θ值无限接近0,但不等于0。
总结:
(1)在正则化中,α作为正则化参数,其选取过大,会把所有参数θ最小化,造成欠拟合,如果α选取过小,会导致对过拟合问题解决不当,因此α的选取是一个难点。
(2)岭回归与LASSO回归最大的区别在于岭回归引入的是L2范数惩罚项,LASSO回归引入的是L1范数惩罚项。
(3)LASSO回归能够使得损失函数中的许多θ均变成0,而岭回归是要所有的θ均存在。因此LASSO回归的计算量将远远小于岭回归。
(4)LASSO回归使很多θ变为0,因此LASSO回归最终会趋向于一条直线;而岭回归会有一个坡度。