回归是一种应用广泛的预测建模技术,这种技术的核心在于预测的结果是连续型变量。
线性回归的任务,就是构造一个预测函数来映射输入的特征矩阵 和标签值 的线性关系,这个预测函数在不同的教 材上写法不同,可能写作 , ,或者 等等形式,但无论如何,这个预测函数的本质就是我们需要构建的 模型,而构造预测函数的核心就是找出模型的参数向量 。
希望我们的预测结果和真实值差异越小越好

现在问题转换成了求解让RSS最小化的参数向量 ,这种通过最小化真实值和预测值之间的RSS来求解参数的方法叫 做最小二乘法。

- from sklearn.linear_model import LinearRegression as LR
- from sklearn.model_selection import train_test_split
- from sklearn.model_selection import cross_val_score
- from sklearn.datasets import fetch_california_housing as fch #加利福尼亚房屋价值数据集
- import pandas as pd
-
- housevalue = fch() #会需要下载,大家可以提前运行试试看
- X = pd.DataFrame(housevalue.data) #放入DataFrame中便于查看
- y = housevalue.target
- X.shape
- y.shape
- X.head()
- housevalue.feature_names
- X.columns = housevalue.feature_names
- """
- MedInc:该街区住户的收入中位数
- HouseAge:该街区房屋使用年代的中位数
- AveRooms:该街区平均的房间数目
- AveBedrms:该街区平均的卧室数目
- Population:街区人口
- AveOccup:平均入住率
- Latitude:街区的纬度
- Longitude:街区的经度
- """
-
- Xtrain, Xtest, Ytrain, Ytest = train_test_split(X,y,test_size=0.3,random_state=420)
- for i in [Xtrain, Xtest]:
- i.index = range(i.shape[0])
- Xtrain.shape
- #如果希望进行数据标准化,还记得应该怎么做吗?
- #先用训练集训练标准化的类,然后用训练好的类分别转化训练集和测试集
-
- reg = LR().fit(Xtrain, Ytrain)
- yhat = reg.predict(Xtest)
- yhat
-
- reg.coef_
- [*zip(Xtrain.columns,reg.coef_)]
- """
- MedInc:该街区住户的收入中位数
- HouseAge:该街区房屋使用年代的中位数
- AveRooms:该街区平均的房间数目
- AveBedrms:该街区平均的卧室数目
- Population:街区人口
- AveOccup:平均入住率
- Latitude:街区的纬度
- Longitude:街区的经度
- """
- reg.intercept_

是否预测了正确的数值:

- from sklearn.metrics import mean_squared_error as MSE
- MSE(yhat,Ytest)
- y.max()
- y.min()
- cross_val_score(reg,X,y,cv=10,scoring="mean_squared_error")
- #为什么报错了?来试试看!
- import sklearn
- sorted(sklearn.metrics.SCORERS.keys())
- cross_val_score(reg,X,y,cv=10,scoring="neg_mean_squared_error")
是否拟合了足够的信息:

衡量的是1 - 我们的模型没 有捕获到的信息量占真实标签中所带的信息量的比例,所以, 越接近1越好
- #调用R2
- from sklearn.metrics import r2_score
- r2_score(yhat,Ytest)
- r2 = reg.score(Xtest,Ytest)
- r2
求 解系数 的式子和过程:

多重共线性如果存在,则线性回归就无法使用最小二乘法来进行求解,或者求解就会出现偏差。幸运的是,不能存在 多重共线性,不代表不能存在相关性——机器学习不要求特征之间必须独立,必须不相关,只要不是高度相关或者精 确相关就好。
是为了修复漏洞而设 计的(实际上,我们使用岭回归或者Lasso,模型的效果往往会下降一些,因为我们删除了一小部分信息 )
在sklearn中,岭回归由线性模型库中的Ridge类来调用:

就在加利佛尼亚房屋价值数据集上来验证一下这个说法:
- import numpy as np
- import pandas as pd
- from sklearn.linear_model import Ridge, LinearRegression, Lasso
- from sklearn.model_selection import train_test_split as TTS
- from sklearn.datasets import fetch_california_housing as fch
- import matplotlib.pyplot as plt
- housevalue = fch()
- X = pd.DataFrame(housevalue.data)
- y = housevalue.target
- X.columns = ["住户收入中位数","房屋使用年代中位数","平均房间数目"
- ,"平均卧室数目","街区人口","平均入住率","街区的纬度","街区的经度"]
- X.head()
- Xtrain,Xtest,Ytrain,Ytest = TTS(X,y,test_size=0.3,random_state=420)
- #数据集索引恢复
- for i in [Xtrain,Xtest]:
- i.index = range(i.shape[0])
- #使用岭回归来进行建模
- reg = Ridge(alpha=1).fit(Xtrain,Ytrain)
- reg.score(Xtest,Ytest)
- #交叉验证下,与线性回归相比,岭回归的结果如何变化?
- alpharange = np.arange(1,1001,100)
- ridge, lr = [], []
- for alpha in alpharange:
- reg = Ridge(alpha=alpha)
- linear = LinearRegression()
- regs = cross_val_score(reg,X,y,cv=5,scoring = "r2").mean()
- linears = cross_val_score(linear,X,y,cv=5,scoring = "r2").mean()
- ridge.append(regs)
- lr.append(linears)
- plt.plot(alpharange,ridge,color="red",label="Ridge")
- plt.plot(alpharange,lr,color="orange",label="LR")
- plt.title("Mean")
- plt.legend()
- plt.show()
- #细化一下学习曲线
- alpharange = np.arange(1,201,10)
- #模型方差如何变化?
- alpharange = np.arange(1,1001,100)
- ridge, lr = [], []
- for alpha in alpharange:
- reg = Ridge(alpha=alpha)
- linear = LinearRegression()
- varR = cross_val_score(reg,X,y,cv=5,scoring="r2").var()
- varLR = cross_val_score(linear,X,y,cv=5,scoring="r2").var()
- ridge.append(varR)
- lr.append(varLR)
- plt.plot(alpharange,ridge,color="red",label="Ridge")
- plt.plot(alpharange,lr,color="orange",label="LR")
- plt.title("Variance")
- plt.legend()
- plt.show()
使用岭迹图来判 断正则项参数的最佳取值
岭迹图认 为,线条交叉越多,则说明特征之间的多重共线性越高。我们应该选择系数较为平稳的喇叭口所对应的 取值作为最 佳的正则化参数的取值。
绘制岭迹图的方法非常简单,代码如下:
- import numpy as np
- import matplotlib.pyplot as plt
- from sklearn import linear_model
- #创造10*10的希尔伯特矩阵
- X = 1. / (np.arange(1, 11) + np.arange(0, 10)[:, np.newaxis])
- y = np.ones(10)
- #计算横坐标
- n_alphas = 200
- alphas = np.logspace(-10, -2, n_alphas)
- #建模,获取每一个正则化取值下的系数组合
- coefs = []
- for a in alphas:
- ridge = linear_model.Ridge(alpha=a, fit_intercept=False)
- ridge.fit(X, y)
- coefs.append(ridge.coef_)
- #绘图展示结果
- ax = plt.gca()
- ax.plot(alphas, coefs)
- ax.set_xscale('log')
- ax.set_xlim(ax.get_xlim()[::-1]) #将横坐标逆转
- plt.xlabel('正则化参数alpha')
- plt.ylabel('系数w')
- plt.title('岭回归下的岭迹图')
- plt.axis('tight')
- plt.show()
Lasso的损失函数表达式为:
Lasso的核心作用:特征选择
在sklearn中我们的Lasso使用的损失函数是:
看lasso如何做特征选择:
- import numpy as np
- import pandas as pd
- from sklearn.linear_model import Ridge, LinearRegression, Lasso
- from sklearn.model_selection import train_test_split as TTS
- from sklearn.datasets import fetch_california_housing as fch
- import matplotlib.pyplot as plt
- housevalue = fch()
- X = pd.DataFrame(housevalue.data)
- y = housevalue.target
- X.columns = ["住户收入中位数","房屋使用年代中位数","平均房间数目"
- ,"平均卧室数目","街区人口","平均入住率","街区的纬度","街区的经度"]
- X.head()
- Xtrain,Xtest,Ytrain,Ytest = TTS(X,y,test_size=0.3,random_state=420)
- #恢复索引
- for i in [Xtrain,Xtest]:
- i.index = range(i.shape[0])
- #线性回归进行拟合
- reg = LinearRegression().fit(Xtrain,Ytrain)
- (reg.coef_*100).tolist()
- #岭回归进行拟合
- Ridge_ = Ridge(alpha=0).fit(Xtrain,Ytrain)
- (Ridge_.coef_*100).tolist()
- #Lasso进行拟合
- lasso_ = Lasso(alpha=0).fit(Xtrain,Ytrain)
- (lasso_.coef_*100).tolist()
- #岭回归进行拟合
- Ridge_ = Ridge(alpha=0.01).fit(Xtrain,Ytrain)
- (Ridge_.coef_*100).tolist()
- #Lasso进行拟合
- lasso_ = Lasso(alpha=0.01).fit(Xtrain,Ytrain)
- (lasso_.coef_*100).tolist()
- #加大正则项系数,观察模型的系数发生了什么变化
- Ridge_ = Ridge(alpha=10**4).fit(Xtrain,Ytrain)
- (Ridge_.coef_*100).tolist()
- lasso_ = Lasso(alpha=10**4).fit(Xtrain,Ytrain)
- (lasso_.coef_*100).tolist()
- #看来10**4对于Lasso来说是一个过于大的取值
- lasso_ = Lasso(alpha=1).fit(Xtrain,Ytrain)
- (lasso_.coef_*100).tolist()
- #将系数进行绘图
- plt.plot(range(1,9),(reg.coef_*100).tolist(),color="red",label="LR")
- plt.plot(range(1,9),(Ridge_.coef_*100).tolist(),color="orange",label="Ridge")
- plt.plot(range(1,9),(lasso_.coef_*100).tolist(),color="k",label="Lasso")
- plt.plot(range(1,9),[0]*8,color="grey",linestyle="--")
- plt.xlabel('w') #横坐标是每一个特征所对应的系数
- plt.legend()
- plt.show()
lasso选取最佳的正则化参数取值
使用交叉验证的Lasso类的参数看起来与岭回归略有不同,这是由于Lasso对于alpha的取值更加敏感的性质决定的。 之前提到过,由于Lasso对正则化系数的变动过于敏感,因此我们往往让 在很小的空间中变动。这个小空间小到超 乎人们的想象(不是0.01到0.02之间这样的空间,这个空间对lasso而言还是太大了)

- from sklearn.linear_model import LassoCV
- #自己建立Lasso进行alpha选择的范围
- alpharange = np.logspace(-10, -2, 200,base=10)
- #其实是形成10为底的指数函数
- #10**(-10)到10**(-2)次方
- alpharange.shape
- Xtrain.head()
- lasso_ = LassoCV(alphas=alpharange #自行输入的alpha的取值范围
- ,cv=5 #交叉验证的折数
- ).fit(Xtrain, Ytrain)
- #查看被选择出来的最佳正则化系数
- lasso_.alpha_
- #调用所有交叉验证的结果
- lasso_.mse_path_
- lasso_.mse_path_.shape #返回每个alpha下的五折交叉验证结果
- lasso_.mse_path_.mean(axis=1) #有注意到在岭回归中我们的轴向是axis=0吗?
- #在岭回归当中,我们是留一验证,因此我们的交叉验证结果返回的是,每一个样本在每个alpha下的交叉验证结果
- #因此我们要求每个alpha下的交叉验证均值,就是axis=0,跨行求均值
- #而在这里,我们返回的是,每一个alpha取值下,每一折交叉验证的结果
- #因此我们要求每个alpha下的交叉验证均值,就是axis=1,跨列求均值
- #最佳正则化系数下获得的模型的系数结果
- lasso_.coef_
- lasso_.score(Xtest,Ytest)
- #与线性回归相比如何?
- reg = LinearRegression().fit(Xtrain,Ytrain)
- reg.score(Xtest,Ytest)
- #使用lassoCV自带的正则化路径长度和路径中的alpha个数来自动建立alpha选择的范围
- ls_ = LassoCV(eps=0.00001
- ,n_alphas=300
- ,cv=5
- ).fit(Xtrain, Ytrain)
- ls_.alpha_
- ls_.alphas_ #查看所有自动生成的alpha取值
- ls_.alphas_.shape
- ls_.score(Xtest,Ytest)
- ls_.coef_