机器学习——线性回归
本文详细介绍了线性回归的基本原理和过程,展现了线性回归模型的scikit-learn实现,包括:普通线性回归、基于 L1 正则化的Lasso回归、基于 L2 正则化的岭回归、基于 L1 和 L2 正则化融合的ElasticNet回归四种,从结果看ElasticNet回归模型的性能最优不足的一点,模型的参数是随意取值的,由于没有做模型优化,所以四种模型的预测准确率都不是特别高,而且四种模型的区分度也
目录
1.3.2 Lasso回归(Lasso Regression)
1.3.4 ElasticNet回归(ElasticNet Regression)
1.1 问题引入
回归分析是一种预测性建模技术,主要用来研究自变量 和因变量 之间的关系,通常被用于预测分析、时间序列等
简单来说,回归分析就是使用曲线(直线是曲线的特例)或曲面来拟合某些已知的数据点,使数据点离曲线或曲面的距离差异达到最小,得到这样的回归曲线或曲面后,我们就可以对新的自变量进行预测,将其带入回归曲线或曲面,就可以得到一个对应的因变量值,达到预测目的
以二维数据为例,假设有一个房价数据如下表所示:
将上面的数据可视化可以得到:
通过线性拟合得到:
得到回归曲线后,当有新样本数据时(即给定横轴值),我们就可以定位出结果值(即对应的纵轴值),实现预测
本文使用波士顿房价预测来展示线性回归模型的应用,该数据集包含美国人口普查局收集的美国马萨诸塞州波士顿住房价格的有关信息,数据集很小,只有506个案例,每个样本都涵盖房屋的13种特征信息和对应的房屋价格,特征情况如下:
房屋价格MEDV:自有住房的中位数报价, 单位1000美元
该数据在version 1.2版本被移除了,原因懂的都懂,所以只能网上下载
链接:https://pan.baidu.com/s/1WELkePK7KCKFtrrghguueg?pwd=n73p
提取码:n73p
数据导入
# 1. 波士顿房价数据
import pandas as pd
data = pd.read_csv("boston.csv",header=0,sep=',')
X = data.drop(columns='MEDV')
y = data['MEDV']
print(X)
print(y)
输出:
划分数据集
# 2. 划分数据集,训练集:验证集=7:3
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size = 0.7)
数据标准化
处理方法:
fit():Method calculates the parameters μ and σ and saves them as internal objects.
解释:简单来说,就是求得训练集X的均值,方差,最大值,最小值,这些训练集X固有的属性。
transform():Method using these calculated parameters apply the transformation to a particular dataset.
解释:在fit的基础上,进行标准化,降维,归一化等操作(看具体用的是哪个工具,如PCA,StandardScaler等
fit_transform():joins the fit() and transform() method for transformation of dataset.
解释:fit_transform 是 fit 和 transform 的组合,既包括了训练又包含了转换。
transform() 和 fit_transform() 二者的功能都是对数据进行某种统一处理(比如标准化~N(0,1),将数据缩放(映射)到某个固定区间,归一化,正则化等)
fit_transform(trainData)对部分数据先拟合fit,找到该part的整体指标,如均值、方差、最大值最小值等等(根据具体转换的目的),然后对该trainData进行转换transform,从而实现数据的标准化、归一化等等
根据对之前部分trainData进行 fit 的整体指标,对剩余的数据(testData)使用同样的均值、方差、最大最小值等指标进行转换transform(testData),从而保证train、test处理方式相同。
这段内容来自:https://blog.csdn.net/weixin_38278334/article/details/82971752
# 3. 数据标准化
from sklearn import preprocessing
standard_X = preprocessing.StandardScaler()
X_train = standard_X.fit_transform(X_train)
X_test = standard_X.transform(X_test)
y_train = y_train.values.reshape(-1,1) #将y_train转置为一行
y_test = y_test.values.reshape(-1,1) #将y_test转置为一行
standard_y = preprocessing.StandardScaler()
y_train = standard_y.fit_transform(y_train)
y_test = standard_y.transform(y_test)
print(X_train[:2])
print(X_test[:2])
print(y_train[:2])
print(y_test[:2])
输出:
1.2 线性回归模型
机器学习算法三要素详情:https://blog.csdn.net/T940842933/article/details/131606224?spm=1001.2014.3001.5502
1.2.1 模型建立
假设我们用 去代表影响房子价格的各个因素,例如: 代表房子的面积, 代表房间的朝向……,代表地理位置,房子的价格为
显然,房子价格 是一个由变量 共同决定的函数,由于不同因素对房子价格的影响不同,所以不同变量在函数中的权重也不同
我们给每项影响因素 赋予一个对应的权重 ,由此我们可以得到因变量 关于自变量 的函数表达式为:
写成矩阵的形式,
即向量 是由各个特征权重组成的;向量 是某个样本数据的特征向量,则:
得到表达式后,每当要预测一个新房子的价格时,我们只需要将房子对应的特征代入该表达式即可,例如某套房子 ,其特征为 ,那么利用模型预测出的结果为:
但该表达式中的权重系数向量 和偏置常数 还未确定,不用担心,机器学习会从已知数据中学习出这些权重系数 和偏置常数 各自取多少时可以使得该回归模型的预测准确度更高,学习方式就是下面要讲的 “ 策略 ”
1.2.2 策略确定
假设现在我们拥有一份数据,包含了 套房子过去的交易情况,如下:
其中 表示第 套房子,每套房子包含 项特征 ,对应的价格为
对于回归问题,我们采用的策略是使用最小均方误差损失来描述模型的好坏,即
其中, 是对样本数据 的预测值;是样本数据 对应的实际值;样本总数为 ; 是各个特征权重组成的向量, 为偏置常数(反复提及这些量的含义,一定要理解清楚)
当损失函数 取值最小时,意味着样本预测值与实际值差距最小,说明此时模型的预测效果是最好的
所以我们的策略就是最小化损失函数 ,即
通过求解上面的最优化问题,我们就可以得到待定参数 和偏置常数 ,求解过程就是下文介绍的 ” 算法 “
1.2.3 算法求解
对于上面的优化问题,可以使用最常用的梯度下降法,对损失函数求偏导数
对 求偏导:
对 求偏导:
所以可以得到权重系数向量 和 偏置常数 的更新式为
其中, 是学习率,即学习步长,这样通过迭代可以使损失函数 以较快的速度不断减小,直至满足要求
1.2.4 线性回归模型流程
输入:训练集 ,学习率
输出:线性回归模型
步骤如下:
第 1 步:选取初值向量 和偏置常数
第 2 步:在训练集中随机选择数据 ,进行更新
第 3 步:重复第 2 步,直至模型满足训练要求
1.3 线性回归模型的 scikit-learn实现
普通线性回归只是最小化了损失函数 ,除此之外还有基于 L1 正则化的Lasso回归,基于 L2 正则化的岭回归,以及基于 L1 和 L2 正则化融合的ElasticNet回归
正则化详情:https://blog.csdn.net/T940842933/article/details/131876860?spm=1001.2014.3001.5502
1.3.1 普通线性回归(最小二乘法线性回归)
普通线性回归原理如上所述,scikit-learn实现如下:
from sklearn.linear_model import LinearRegression
Linear_clf = LinearRegression(fit_intercept=True, copy_X=True, n_jobs=1)
参数
fit_intercept:选择是否计算偏置常数 ,默认是True,表示计算
copy_X:选择是否拷贝特征矩阵X,默认True,表示拷贝,若设置为False,机器学习过程中会影响原始数据,导致X矩阵被覆盖
n_jobs:指定计算机运行使用的CPU核数,默认-1,表示使用所有可用的CPU核
属性
coef_:用于输出线性回归模型的权重向量
intercept_:用于输出线性回归模型的偏置常数
方法
fit(X_train, y_train):在训练集 (X_train, y_trian) 上训练模型
predicate(X):用训练好的模型来预测待预测数据集X,返回数据为预测集对应的预测结果
score(X_test, y_test):返回模型在测试集 (X_test, y_test) 上的预测准确率,计算公式为
其中, 表示测试集样本 对应的真值,为测试集样本 对应的预测值,为测试集中所有样本对应真值 的平均;score是一个小于 1 的值,也可能是负值,其值越大表示模型预测性能好
程序如下:
# 4.1 运用普通线性回归模型训练和预测
from sklearn.linear_model import LinearRegression
Linear_clf = LinearRegression(fit_intercept=True, copy_X=True, n_jobs=1)
Linear_clf.fit(X_train,y_train) #训练模型
Linear_clf_score = Linear_clf.score(X_test,y_test) #模型得分
Linear_clf_result = Linear_clf.predict(X_test) #验证集对应的预测结果
print("特征向量 w = ",Linear_clf.coef_)
print("偏置常数 b = ",Linear_clf.intercept_)
print("拟合优度R^2:",Linear_clf_score)
Drawing(y_test, Linear_clf_result,'Linear Regression') #画图
# 5.画图
import matplotlib.pyplot as plt
def Drawing(y_test, result, title):
fig = plt.figure(figsize=(20, 3))
axes = fig.add_subplot(1, 1, 1)
line1, = axes.plot(range(len(y_test)),y_test,'b',label='Actual_Value')
line2, = axes.plot(range(len(result)),result,'r--',label='Predicted',linewidth=2)
axes.grid()
fig.tight_layout()
plt.legend(handles=[line1,line2])
plt.title(title)
plt.show()
输出:
可以看出普通线性回归模型的预测能力不是特别优秀
1.3.2 Lasso回归(Lasso Regression)
Lasso回归就是在基本的线性回归的基础上加一个L1正则化项
scikit-learn实现如下:
from sklearn.linear_model import Lasso
Lasso_clf = Lasso(alpha=1.0, #L1正则化项前面带的常数调节因子
fit_intercept=True, #选择是否计算偏置常数 ,默认为True,表示计算
precompute=False, #选择是否使用预先计算的Gram矩阵来加快计算,默认False
max_iter=1000, #设置最大迭代次数,默认为1000
tol=0.0001, #判定判断迭代收敛的阈值,默认为0.0001
warm_start=False, #设定是否使用前一次训练的结果继续训练,默认False,表示每次从头开始训练
positive=False, #默认为False,如果为True,则表示强制所有权重系数为正值
selection='cyclic') #每轮迭代是选择哪个权重系数进行更新,默认为cycle,表示从前往后依次选择,如果设定为random,则表示每次随机选择一个权重系数进行更新
参数
alpha:L1正则化项前面带的常数调节因子
fit_intercept:选择是否计算偏置常数 ,默认为True,表示计算
precompute:选择是否使用预先计算的Gram矩阵来加快计算,默认False
max_iter:设置最大迭代次数,默认为1000
tol:判定判断迭代收敛的阈值,默认为0.0001
warm_start:设定是否使用前一次训练的结果继续训练,默认False,表示每次从头开始训练
positive:默认为False,如果为True,则表示强制所有权重系数为正值
selection:每轮迭代是选择哪个权重系数进行更新,默认为cycle,表示从前往后依次选择,如果设定为random,则表示每次随机选择一个权重系数进行更新
属性
coef_:用于输出线性回归模型的权重向量
intercept_:用于输出线性回归模型的偏置常数
n_iter:用于输出实际迭代次数
方法同上
程序如下:
# 4.2 运用Lasso回归模型训练和预测
from sklearn.linear_model import Lasso
Lasso_clf = Lasso(alpha=0.001)
Lasso_clf.fit(X_train,y_train)
Lasso_clf_score = Lasso_clf.score(X_test,y_test) #模型得分
Lasso_clf_result = Lasso_clf.predict(X_test) #验证集对应的预测结果
print("特征向量 w = ",Lasso_clf.coef_)
print("偏置常数 b = ",Lasso_clf.intercept_)
print("迭代次数:",Lasso_clf.n_iter_)
print("拟合优度R^2:",Lasso_clf_score)
Drawing(y_test, Lasso_clf_result,'Lasso Regression') #画图
输出:
可以看出,Lasso回归的拟合优度是略高于普通线性回归的,因为加上了L1正则项
1.3.3 岭回归(Ridge Regression)
岭回归就是在普通线性回归的基础上加上了一个L2正则项
scikit-learn实现如下:
Ridge_clf = Ridge(alpha=1.0,
fit_intercept=True,
max_iter=1000,
tol=0.0001,
solver='auto'
)
参数
alpha,fit_intercept,max_iter,tol 的用法与Lasso回归相同
slover:指定求解最优化问题的算法,默认为auto,表示自动选择,其他可选项如下:
svd:使用奇异值分解来计算回归系数
cholesky:使用标准的scipy.linalg.solve 函数来求解
sparse_cg:使用scipy.sparse.linalg.cg中的共轭梯度求解器求解
lsqr:使用专门的正则化最小二乘法scipy.sparse.linalg.lsqr,速度是最快的
sag:使用随机平均梯度下降法求解
属性和方法同上
程序如下:
# 4.3 运用Lasso回归模型训练和预测
from sklearn.linear_model import Ridge
Ridge_clf = Ridge(alpha=0.001)
Ridge_clf.fit(X_train,y_train)
Ridge_clf_score = Ridge_clf.score(X_test,y_test) #模型得分
Ridge_clf_result = Ridge_clf.predict(X_test) #验证集对应的预测结果
print("特征向量 w = ",Ridge_clf.coef_)
print("偏置常数 b = ",Ridge_clf.intercept_)
print("迭代次数:",Ridge_clf.n_iter_)
print("拟合优度R^2:",Ridge_clf_score)
Drawing(y_test, Ridge_clf_result,'Ridge Regression') #画图
输出:
可以看出,L2正则项是优于L1正则项的,岭回归拟合优度有大幅提高
1.3.4 ElasticNet回归(ElasticNet Regression)
ElasticNet回归(弹性网络回归)是将 L1 和 L2 正则化进行融合,即在基本的线性回归种加入下面的混合正则化项:
scikit-learn实现如下:
from sklearn.linear_model import ElasticNet
ElasticNet_clf = ElasticNet(alpha=1.0, #L1正则化项前面带的常数调节因子
l1_ratio=0.5, #l1_ratio参数就是上式中的ρ值,默认为0.5
fit_intercept=True, #选择是否计算偏置常数 ,默认为True,表示计算
precompute=False, #选择是否使用预先计算的Gram矩阵来加快计算,默认False
max_iter=1000, #设置最大迭代次数,默认为1000
tol=0.0001, #判定判断迭代收敛的阈值,默认为0.0001
warm_start=False, #设定是否使用前一次训练的结果继续训练,默认False,表示每次从头开始训练
positive=False, #默认为False,如果为True,则表示强制所有权重系数为正值
selection='cyclic') #每轮迭代是选择哪个权重系数进行更新,默认为cycle,表示从前往后依次选择,如果设定为random,则表示每次随机选择一个权重系数进行更新
参数
alpha,fit_intercept,precompute,max_iter,tol,warm_start,positive,selection与Lasso回归用法相同
l1_ratio:l1_ratio参数就是上式中的ρ值,默认为0.5
属性和方法同上
程序如下:
# 4.4 运用Lasso回归模型训练和预测
from sklearn.linear_model import ElasticNet
from sklearn.linear_model import ElasticNet
ElasticNet_clf = ElasticNet(alpha=0.001,l1_ratio=0.71)
ElasticNet_clf.fit(X_train,y_train)
ElasticNet_clf_score = ElasticNet_clf.score(X_test,y_test) #模型得分
ElasticNet_clf_result = ElasticNet_clf.predict(X_test) #验证集对应的预测结果
print("特征向量 w = ",ElasticNet_clf.coef_)
print("偏置常数 b = ",ElasticNet_clf.intercept_)
print("迭代次数:",ElasticNet_clf.n_iter_)
print("拟合优度R^2:",ElasticNet_clf_score)
Drawing(y_test, ElasticNet_clf_result,'Ridge Regression') #画图
输出:
预测准确率又高了一丢丢
1.4 总结
本文详细介绍了线性回归的基本原理和过程,展现了线性回归模型的scikit-learn实现,包括:普通线性回归、基于 L1 正则化的Lasso回归、基于 L2 正则化的岭回归、基于 L1 和 L2 正则化融合的ElasticNet回归四种,从结果看ElasticNet回归模型的性能最优
不足的一点,模型的参数是随意取值的,由于没有做模型优化,所以四种模型的预测准确率都不是特别高,而且四种模型的区分度也不是很高
感兴趣的朋友可以自己尝试完成优化任务,模型调优详情https://blog.csdn.net/T940842933/article/details/131968261?spm=1001.2014.3001.5502
原码如下:
# 1. 波士顿房价数据
import pandas as pd
data = pd.read_csv("boston.csv",header=0,sep=',')
X = data.drop(columns='MEDV')
y = data['MEDV']
"""
print(X)
print(y)
"""
# 2. 划分数据集,训练集:验证集=7:3
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size = 0.7)
# 3. 数据标准化
from sklearn import preprocessing
standard_X = preprocessing.StandardScaler()
X_train = standard_X.fit_transform(X_train)
X_test = standard_X.transform(X_test)
y_train = y_train.values.reshape(-1,1) #将y_train转置为一行
y_test = y_test.values.reshape(-1,1) #将y_test转置为一行
standard_y = preprocessing.StandardScaler()
y_train = standard_y.fit_transform(y_train)
y_test = standard_y.transform(y_test)
"""
print(X_train[:2])
print(X_test[:2])
print(y_train[:2])
print(y_test[:2])
"""
# 5.画图
import matplotlib.pyplot as plt
def Drawing(y_test, result, title):
fig = plt.figure(figsize=(20, 3))
axes = fig.add_subplot(1, 1, 1)
line1, = axes.plot(range(len(y_test)),y_test,'b',label='Actual_Value')
line2, = axes.plot(range(len(result)),result,'r--',label='Predicted',linewidth=2)
axes.grid()
fig.tight_layout()
plt.legend(handles=[line1,line2])
plt.title(title)
plt.show()
# 4.1 运用普通线性回归模型训练和预测
from sklearn.linear_model import LinearRegression
Linear_clf = LinearRegression(fit_intercept=True, copy_X=True, n_jobs=1)
Linear_clf.fit(X_train,y_train) #训练模型
Linear_clf_score = Linear_clf.score(X_test,y_test) #模型得分
Linear_clf_result = Linear_clf.predict(X_test) #验证集对应的预测结果
print("特征向量 w = ",Linear_clf.coef_)
print("偏置常数 b = ",Linear_clf.intercept_)
print("拟合优度R^2:",Linear_clf_score)
Drawing(y_test, Linear_clf_result,'Linear Regression') #画图
# 4.2 运用Lasso回归模型训练和预测
from sklearn.linear_model import Lasso
Lasso_clf = Lasso(alpha=0.001)
Lasso_clf.fit(X_train,y_train)
Lasso_clf_score = Lasso_clf.score(X_test,y_test) #模型得分
Lasso_clf_result = Lasso_clf.predict(X_test) #验证集对应的预测结果
print("特征向量 w = ",Lasso_clf.coef_)
print("偏置常数 b = ",Lasso_clf.intercept_)
print("迭代次数:",Lasso_clf.n_iter_)
print("拟合优度R^2:",Lasso_clf_score)
Drawing(y_test, Lasso_clf_result,'Lasso Regression') #画图
# 4.3 运用Lasso回归模型训练和预测
from sklearn.linear_model import Ridge
Ridge_clf = Ridge(alpha=0.001)
Ridge_clf.fit(X_train,y_train)
Ridge_clf_score = Ridge_clf.score(X_test,y_test) #模型得分
Ridge_clf_result = Ridge_clf.predict(X_test) #验证集对应的预测结果
print("特征向量 w = ",Ridge_clf.coef_)
print("偏置常数 b = ",Ridge_clf.intercept_)
print("迭代次数:",Ridge_clf.n_iter_)
print("拟合优度R^2:",Ridge_clf_score)
Drawing(y_test, Ridge_clf_result,'Ridge Regression') #画图
# 4.4 运用Lasso回归模型训练和预测
from sklearn.linear_model import ElasticNet
from sklearn.linear_model import ElasticNet
ElasticNet_clf = ElasticNet(alpha=0.001,l1_ratio=0.71)
ElasticNet_clf.fit(X_train,y_train)
ElasticNet_clf_score = ElasticNet_clf.score(X_test,y_test) #模型得分
ElasticNet_clf_result = ElasticNet_clf.predict(X_test) #验证集对应的预测结果
print("特征向量 w = ",ElasticNet_clf.coef_)
print("偏置常数 b = ",ElasticNet_clf.intercept_)
print("迭代次数:",ElasticNet_clf.n_iter_)
print("拟合优度R^2:",ElasticNet_clf_score)
Drawing(y_test, ElasticNet_clf_result,'Ridge Regression') #画图
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)