当前位置:   article > 正文

【机器学习】手撕多元线性回归

【机器学习】手撕多元线性回归

目录

1.引入

2.向量表示

3.参数估计

3.1误差分布

3.2极大似然估计

3.3 对数似然函数

3.4 损失函数

3.5损失函数向量化表示

3.6 损失函数求导

3.7 损失函数化简

4 复现多元线性回归类


#学习笔记#

线性回归模型是机器学习的入门经典模型

多元线性回归模型的原理是什么,今天来梳理一下,文章末尾复现sklearn中的LinearRegression

1.引入

在简单线性回归中,我们用一个特征值来拟合目标值,然而现实中的数据通常是比较复杂的,自变量也很可能不止一个。例如,影响房屋价格不止房屋面积一个因素,可能还有距离地铁的距离,距市中心距离,房屋数量,房屋所在层数等诸多因素。

但这些因素对房屋价格影响的程度(权重)是不同的。例如,房屋所在层数对房屋价格的影响就远不及房屋面积,因此我们可以为每个特征指定不同的权重。

37c080444898414691da7ab852a3a4b5.png

  • eq?x_%7Bi%7D:第i个输入特征
  • eq?w_%7Bi%7D:第i个特征权重(影响力度)
  • eq?n特征的个数。
  • eq?y%5Chat%7B%7D:预测值(房屋价格)

2.向量表示

我们也可以使用向量的表示方式,设eq?x%5Cvec%7B%7Deq?w%5Cvec%7B%7D为两个向量:

f092ab18ba6d4ec092c8e27185db7f2d.png

则回归方程可表示为:

7290cea609c14a7f9e9491693271ffe2.png

我们可以进一步简化,为向量eq?w%5Cvec%7B%7Deq?x%5Cvec%7B%7D各加入一个分量eq?w_%7B0%7Deq?x_%7B0%7D,并令eq?x_%7B0%7D=1

于是向量eq?w%5Cvec%7B%7Deq?x%5Cvec%7B%7D就会变成:

99cbdfd9d97c434b83b5ae45144c3c26.png

这样,就可以表示为:

1aaec5e18df34033b9c51fcb555d598f.png

这样做是为了将偏置eq?w_%7B0%7D也纳入矩阵中以便于我们进行计算。

在简单线性回归中我们是对误差ypre-y进行了平方,然后分别对w0和w1求偏导,以求出loss损失函数的极值点,也就是驻点。从而求出了对应的w0和w1。

多元回归中同样如此,只不过是对矩阵进行操作

3.参数估计

3.1误差分布

下面我们看一下线性回归模型中的误差,线性回归中的自变量与因变量是存在线性关系的,然而这种线性关系不是严格的函数映射关系,但是我们构建的模型是严格的函数映射关系,因此,对于每个样本来说,我们拟合的结果会与真实值之间存在一定的误差,我们可以将误差表示为:

48f8f4f759044681b6fba300e901bccd.png

eq?%5Cvarepsilon%20_%7Bi%7D代表第i个样本真实值与预测值之间的误差(残差)

对线性回归而言,具有一个前提假设eq?%5Cvarepsilon服从均值为0,方差为eq?%5Cdelta%5E%7B2%7D的正态分布,容易理解,我们的预测的的残差较小的较多,较大的较少。

根据正态分布的概率密度函数:

96fc54a82bec4d03bb24e7bba1d5a582.png

则误差eq?%5Cvarepsilon的分布为:

a8f125e1a4254915b93150b3d8782cff.png

因此对于每一个样本的误差eq?%5Cvarepsilon%20%5E%7B%28i%29%7D,其概率值为:

fda40ec60d3247eb8a9dd25766b152f8.png

3.2极大似然估计

简单来说极大似然估计是在已知一些观测数据的情况下,我们应该选择使这些观测数据出现概率最大的参数。换句话说,就是在所有可能的参数选择中,找到一个最能“解释”已观察到的数据的参数。

根据该原则,我们让所有误差出现的联合概率最大,这样参数w的值就是我们要求解的值

b90fd0ea7f4e4a0cac471ef5c4b4f091.png

3.3 对数似然函数

不过,累计乘积方式并不利于我们求解,我们这里可以使用对数似然函数,也就是在似然函数上取对数操作,这样就可以将累计乘积的方式转化为累计求和的形式啦

4d793631c4ba4f979746ffa80764166a.png

有的同学可能会有疑问

我们原本的目的是要求的令似然函数eq?L%28w%29最大时,参数w的值

然而我们对似然函数eq?L%28w%29取对数时,得到的eq?ln%28L%28w%29%29似乎会将原似然函数改变

这样我们对似然函数eq?ln%28L%28w%29%29取得的极大值还会与原来的似然函数计算的eq?w相同吗?

我们不妨用程序来验证这一点

  1. x = np.linspace(-3,3,200)
  2. # 原函数
  3. y = 0.5 * x **2 +1
  4. # 对数函数
  5. lny = np.log(y)
  6. plt.plot(x,y,label = '原函数')
  7. plt.plot(x,lny,label = '对数函数')
  8. plt.legend

d6ba971bed594695a5d16d350101905e.png

通过观察图像我们发现,加上ln的函数极值点并没有受到影响,所以对我们的参数eq?w的求解也不会有影响。

至此,我们通过极大似然参数估计的当时也验证了我们要求的目标和损失函数相同。

3.4 损失函数

在上式中,常数忽略,我们只需让后半部分的值最小即可,因此后半部分:

6d8eb94efc07473191ec419cbe6047c9.png

该函数是二次函数,显然具有唯一极小值

3.5损失函数向量化表示

4b8fabd293124a98b2b9ca3f01fc586d.png

e078439c16fd471596798651e3137f1a.png

3.6 损失函数求导

我们要求损失函数的最小值,只需要对向量eq?w%5Cvec%7B%7D进行求导,令倒数为0,此时的eq?w%5Cvec%7B%7D就是最佳解。

21d1aa77a84040e299581420d2117c80.png

3.7 损失函数化简

根据矩阵与向量的求导公式,有:

7739ed049c4349b8927dfac468b97c71.png特别的,如果eq?A%20%3D%20A%5E%7BT%7D(A为对称矩阵),则:

f860e778bb784e06881a1fd93875692b.png

因此:

6aebba3ec98f4583975a754cdc915048.png令导函数的值为0,则:

3ad4f6d4cbc2450580bd1c8aaa6db2c7.png

矩阵eq?X%5E%7BT%7DX必须是可逆的

假设X为训练集的特征,y为训练集的目标值

根据以上推导,我们把结果拿来套用就可以很容易的计算得到eq?w

代码如下:

  1. # 创建一个元素都为1的矩阵,并与x拼起来,因为需要加上常数w0
  2. one = np.ones(shape = (len(X),1))
  3. X = np.concatenate([one,X],axis=1)
  4. # np.linalg.inv求矩阵的逆
  5. w = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)
  6. w

4 复现多元线性回归类

下面,我们自己来复现一个能够实现多元线性回归的类(参考sklearn中的LinearRegression)

这个类满足一下条件:

  • 具有fit方法,训练模型
  • 具有predict方法,预测未知数据
  • 具有coef_属性,返回所有权重(不包括偏置eq?w_%7B0%7D
  • 具有intercept_属性,返回偏置b(eq?w_%7B0%7D)

代码如下:

  1. import numpy as np
  2. from matplotlib import pyplot
  3. class LinearRegression:
  4. def __init__(self):
  5. self.w = None
  6. self.coef_ = None
  7. self.intercept_ = None
  8. # fit方法训练模型
  9. def fit(self, X_train, y_train):
  10. '''
  11. :param X_train: 训练数据集
  12. :param y_train: 训练数据集的标签
  13. :return: None
  14. '''
  15. one = np.ones(shape=(len(X_train), 1))
  16. X_train = np.concatenate([one, X_train], axis=1)
  17. # np.linalg.inv求矩阵的逆
  18. w = np.linalg.inv(X_train.T.dot(X_train)).dot(X_train.T).dot(y_train)
  19. self.w = w
  20. self.coef_ = w[1:]
  21. self.intercept_ = w[0]
  22. # predict方法预测
  23. def predict(self, X_test):
  24. '''
  25. :param X_test: 测试数据集
  26. :return: 预测结果
  27. '''
  28. one = np.ones(shape=(len(X_test), 1))
  29. X_test = np.concatenate([one, X_test], axis=1)
  30. y_pred = X_test.dot((self.w).T)
  31. return y_pred
  32. # 生成训练数据
  33. x0 = [1, 2, 3, 4, 5, 6, 7, 8, 9,10]
  34. x1 = [1, 3, 3, 8, 5, 6, 0, 8, 9,8]
  35. X = np.array([[x0[i], x1[i]] for i in range(len(x0))])
  36. y = np.zeros(len(x0))
  37. for i in range(len(x0)):
  38. y[i] = 2 * x0[i] + 3 * x1[i] + 4
  39. X_train = X[:8]
  40. y_train = y[:8]
  41. X_test = X[8:]
  42. y_test = y[8:]
  43. # 模型训练
  44. model = LinearRegression()
  45. model.fit(X_train, y_train)
  46. print(f'model.coef_:{model.coef_}')
  47. print(f'model.intercept_:{model.intercept_}')
  48. # 模型预测
  49. y_pred = model.predict(X_test)
  50. print(f'y_pred:{y_pred}')

 输出结果:

  1. model.coef_:[2. 3.]
  2. model.intercept_:3.9999999999999964
  3. y_pred:[49. 48.]

可以看到,成功预测!

补充:

如果出现以下报错,代表尝试求逆的矩阵是奇异的(或称为非满秩矩阵)

numpy.linalg.LinAlgError: Singular matrix

两种可能

  1. 数据列线性相关:如果你的数据集中的某些特征是其他特征的线性组合,那么这些列之间的线性相关性会导致矩阵不可逆。

  2. 重复数据:如果训练数据中有重复的行,这也会导致矩阵奇异。

这个报错是我将两行特征写成一样时出现的错误,实际上在使用机器学习进行实践时,两个线性相关列没有必要同时存在,例如年薪和平均月薪。在未来实践中这是值得注意的

 

今天的分享就到这里,学习重在总结和坚持,共勉!

ab4927a3e6504f21b285a5e267e2d09d.jpeg

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/72140
推荐阅读
相关标签
  

闽ICP备14008679号