线性回归机器学习中是最基础的模型之一
先简单说下机器学习模型的一般套路:
-确定模型函数
-定义损失函数
-确定目标函数
-化简求解目标函数(梯度下降求极值)更新参数
-迭代优化
-评估、调优(调参)
普通线性回归
先举个例子,比如有一组数据,美国纽约若干程序员职位的年薪
可以看出,年薪只跟工作经验有关,将数据抽取出来
X代表工作经验,y代表年薪。那x和y到底有没有线性关系呢?能不能写成y=ax+b的形式,根据x来求y。即根据工作经验来预测年薪
我们先画个图看下
从这6个点来看,看着像个直线,那么假设存在y=ax+b,是合理的
我们将x=0代入求出b=103100,再求出a=1800,于是y=1800x+103100
将x的值分别代入求y,发现结果与真实值都不完全一样,但真实值和预测值差别不太大。
我们开始假设的数据符合线性模型函数y=ax+b,由此来引出线性回归模型。
线性回归的模型函数
f(x)= ax + b
我们要处理的数据集一般都是包含多个特征的(如人的年龄、专业、职业、体重...),即每一条数据(一个样本)会包含多个特征,数据集包含多条数据。线性回归的模型写成更一般的形式为:f(x)=w·x+b ,x代表样本,w是权值。w和b是要求的参数。
线性回归是一种回归技术,回归分析本质上是一个函数估计的问题,就是找出因变量和自变量的因果关系。因变量是连续的数值。回归分析是一个有监督学习的问题。
附,线性的含义
线性回归模型是:利用线性函数对一个或多个自变量(x或(x1,x2,...xkx1,x2,...xk))和因变量(y)之间的关系进行拟合的模型。也就是说,线性回归模型构建成功后,这个模型表现为线性函数的形式。
线性函数的定义是:一阶(或更低阶)多项式,或零多项式。
当线性函数只有一个自变量时,y = f(x)。
f(x)的函数形式是:
f(x) = a + bx(a,b为常数,且 b≠0b≠0)——一阶多项式
或者f(x) = c (c为常数,且 c≠0c≠0) ——零阶多项式
或者f(x) = 0 ——零多项式
但如果有多个独立自变量,y=f(x1,x2,...,xk)y=f(x1,x2,...,xk) 的函数形式则是:
也就是说,只有当训练数据集的特征是一维的时候,线性回归模型可以在直角坐标系中展示,其形式是一条直线。
换言之,直角坐标系中,除了平行于y轴的那些直线之外,所有的直线都可以对应一个一维特征(自变量)的线性回归模型(一元多项式函数)。
但如果样本特征本身是多维的,则最终的线性模型函数是一个多维空间内的[一阶|零阶|零]多项式。
总结一下:特征是一维的,线性模型在二维空间构成一条直线;特征是二维的,线性模型在三维空间中构成一个平面;若特征是三维的,则最终模型在四维空间中构成一个体;以此类推……
损失函数
得到模型函数后,我们的目标是在预测数据时,预测值跟真实值的误差越小越好。在线性回归中,误差的函数称为损失函数。根据均方差,损失函数为
我们的目标函数,即是最小化损失函数,使用梯度下降法求解损失函数的最小值,
1. 初始化参数θ(随机初始化)
2. 沿着负梯度方向迭代,更新后的θ使J(θ)更小,α是学习率(步长)
3. 直至收敛
求梯度的过程:
可以用最小二乘法求解解析解,参数的解析式的求解过程
目标函数:
求梯度:
得到参数的解析解为,前提是可逆,参数的解析式为:
增加λ扰动项(正则项),使得
可逆,防止过拟合
求得参数,得到模型函数,在进行评估、调参最终得到最优模型
解析式为:
加入正则化的回归模型:
Ridge回归
线性回归的目标函数为:
加入平方和损失(称为L2正则),即是Ridge回归:
Lasso回归
加入L1正则项,得到Lasso回归模型
Elastic Net
Elastic Net是将L1,L2综合,
其中
模型评估、调优
具体评估、调优这里先略去,后续单独讲下
另外,使用梯度下降法时,要注意特征归一化:
特征归一化的好处:
1.提升模型的收敛速度,归一化可以减少寻找最优解的时间
2.提升模型精度,比如计算欧氏距离,取值范围小的特征比取值范围大的特征对结果影响小,这就造成了精度损失。归一化可以让各个特征对结果的贡献相同。
在求解线性回归的模型时,还有一个问题要注意,那就是特征组合问题,比如房子的长度和宽度作为两个特征参与模型的构造,不如把其相乘得到面积作为一个特征来进行求解,这样在特征选择上就做了减少维度的工作
代码实战
为避免篇幅过长,此处只贴出线性回归的代码,Ridge回归、Lasso回归、Elastic Net的代码也类似,如需要,可加群交流
# 1.线性回归
import numpy as np
from sklearn import datasets, linear_model,model_selection
def load_data():
'''
加载用于回归问题的数据集
:return: 一个元组,用于回归问题。元组元素依次为:训练样本集、测试样本集、训练样本集对应的值、测试样本集对应的值
'''
diabetes = datasets.load_diabetes() # 使用 scikit-learn 自带的一个糖尿病病人的数据集
# irisdata = datasets.load_iris() # 使用 scikit-learn 自带的一个鸢尾花的数据集
# return cross_validation.train_test_split(datasets.data, diabetes.target,
# test_size=0.25, random_state=0)
# # 拆分成训练集和测试集,测试集大小为原始数据集大小的 1/4 上面代码中cross_validation新版本不建议用了
return model_selection.train_test_split(diabetes.data, diabetes.target,
test_size = 0.25, random_state=0)
# return model_selection.train_test_split(irisdata.data,irisdata.target,test_size=0.25,random_state=0)
def mytest_LinearRegression(*data):
'''
测试 LinearRegression 的用法
:param data: 可变参数。它是一个元组,这里要求其元素依次为:训练样本集、测试样本集、训练样本的值、测试样本的值
:return: None
'''
X_train, X_test, y_train, y_test = data
regr = linear_model.LinearRegression()
regr.fit(X_train, y_train)
print('Coefficients:%s, intercept %.2f' % (regr.coef_, regr.intercept_)) # 输出训练后的参数值 w,b
print("Residual sum of squares: %.2f" % np.mean((regr.predict(X_test) - y_test) ** 2)) # 残差平方和
print('Score: %.2f' % regr.score(X_test, y_test)) # 预测打分
if __name__ == '__main__':
X_train, X_test, y_train, y_test = load_data() # 产生用于回归问题的数据集
mytest_LinearRegression(X_train, X_test, y_train, y_test) # 调用 test_LinearRegression
关注-微-公众号【学习与成长资源库】获取更多免费学习资料
参考资料
Python大战机器学习
周志华 机器学习
邹博 机器学习
李烨 机器学习极简入门课
公众号后台回复0110领福利啦 ~