基本概念与数学形式
线性回归是一种监督学习算法,用于找出输入特征与目标变量之间的线性关系。
它的数学表达式是:
y^=w1x1+w2x2+⋯+wnxn+b
含义:
- y^:预测值。
- xi:第 i 个输入特征
- wi:特征权重(回归系数,表示该特征对预测的影响)
- b:偏置(截距项,整体向上或向下平移预测结果)
分类与层次
graph TD
A[线性回归] --> B[一元线性回归]
A --> C[多元线性回归]
A --> D[正则化回归]
D --> D1[岭回归 Ridge]
D --> D2[Lasso回归]
D --> D3[弹性网络 Elastic Net]
各类型详细解释
一元线性回归
y^=wx+b
- 用途:预测单一因素影响的结果
例如:用房屋面积预测价格。
多元线性回归
y^=w1x1+w2x2+⋯+wnxn+b
- 用途:同时考虑多个因素的影响
例如:用面积、位置、房龄等预测房价。
最小二乘法(OLS)
最小二乘法是一种参数估计方法,用于找到使误差平方和最小的模型参数。
它的核心思想是:在已知输入x与输出y的数据下,选择模型参数,使预测值与真实值之间的差的平方和最小。
符号介绍
推导过程
一元线性回归
假设我们有以下数据集D={(x(i),y(i))}i=1m
接下来在图中画一条f(x)=x直线。
再将每个点向函数f(x)做垂线段,长度即是∣f(x)−y∣,又可以称为真实点坐标y的值与预测f(x)的误差,故然可以改为(f(x)−y)2。且由于f(x)是预测的,可以随意变化为f(x)=2x+1、f(x)=x+1等。
接下来我们将每个点坐标的误差值相加∑(f(x(i))−y)2后求关于w的偏导与关于b的偏导:
S=∑(f(x(i))−y(i))2{∂w∂S=2∑(f(x(i))−y(i))x(i)=0∂b∂S=2∑(f(x(i))−y(i))=0
整理后可得:
w=∑(x(i)−xˉ)2∑(x(i)−xˉ)(y(i)−yˉ),b=yˉ−wxˉ
多元线性回归
假设模型为:
y=Xw+ϵ
其中:
- y∈Rn:输出向量
- X∈Rn×p:输入矩阵(第一列为1表示截距)
- w∈Rp:参数向量
- ϵ:误差向量
最小化:
S(w)=∥Xw−y∥2
展开:
S(w)=(Xw−y)T(Xw−y)
对w求导:
∂w∂S=2XT(Xw−y)
令导数为0:
XT(Xw−y)=0
最终整理得:
w=(XTX)−1XTy
Python实现
一元最小二乘
import numpy as np
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) y = np.array([5.9, 8.1, 10.4, 12.3, 15.0, 17.2, 20.1, 22.0, 25.4, 28.1])
x_mean = np.mean(x) y_mean = np.mean(y)
w = np.sum((x - x_mean) * (y - y_mean)) / np.sum((x - x_mean)**2)
b = y_mean - w * x_mean
print(f"b = {b:.3f}, w = {w:.3f}")
|
多元最小二乘
import numpy as np
X = np.array([[1, 1], [1, 2], [1, 3], [1, 4]]) y = np.array([2.1, 4.0, 5.9, 8.1])
w = np.linalg.inv(X.T @ X) @ X.T @ y
print("参数 w:", w)
|
使用scikit-learn
from sklearn.linear_model import LinearRegression import numpy as np
X = np.array([[1], [2], [3], [4], [5], [6], [7], [8], [9], [10]]) y = np.array([5.9, 8.1, 10.4, 12.3, 15.0, 17.2, 20.1, 22.0, 25.4, 28.1])
model = LinearRegression() model.fit(X, y)
print("斜率 w:", model.coef_) print("截距 b:", model.intercept_)
|
最终图像
根据以上内容,最终画图后可得到:
梯度下降法(Gradient Descent)
梯度下降是一种优化算法,主要用于找到函数的最小值。在机器学习中,我们用它来最小化损失函数,让模型预测更接近真实值。
直观理解:
想象你在一座山谷里,眼睛被蒙住了,想找到山谷的最低点(最小值)。你感觉脚下的坡度,然后沿着坡度下降,每一步走一点,最终慢慢到达谷底。
- 山谷 → 损失函数(Loss Function)
- 最低点 → 最优参数
- 坡度 → 函数的导数/梯度
我们的目标是让损失函数最小,接下来我们将多种损失函数任意一种表述为L(w,b)。
接下来是min L(w,b)的过程:
一元函数的泰勒展开
对于函数f(x)在x0附近的泰勒展开:
f(x)=f(x0)+1!f′(x0)(x−x0)+2!f′′(x0)(x−x0)2+3!f′′′(x0)(x−x0)3+…
忽略二阶及以上项,得到:
f(x)≈f(x0)+f′(x0)(x−x0)
为什么能忽略二阶及以上项?
解释一:梯度下降的特点
- 每次迭代步长很小x−x0=−ηf′(x0)
- 学习率η通常很小(例如:0.01,0.001)
- 负号不改变步长大小,只改变方向。
- 所以∣x−x0∣很小。
且高阶项的量级随着步长的幂次增长迅速减小:
- 二阶项:2!f′′(x0)(x−x0)2
- 三阶项:3!f′′′(x0)(x−x0)3
- (x−x0)2≪(x−x0)
- (x−x0)3≪(x−x0)2≪(x−x0)
小步长的平方、立方远小于步长本身,故可以忽略其贡献。
解释二:拉格朗日余项(Lagrange remainder)
由于学习率η通常很小且由x−x0=−ηf′(x0)显然看出x−x0≪1。
且一元函数一阶泰勒展开的拉格朗日余项为:
R1=2!f′′(ξ)(x−x0)2
其中 ξ∈[x0,x]。当 ∣x−x0∣→0 时,R1→0,所以一阶近似越来越精确,可舍弃二阶及以上。
解释三:数值计算
假设(x−x0)=0.01
- 一阶项:(x−x0)∼0.01
- 二阶项:(x−x0)2∼0.0001
- 三阶项:(x−x0)3∼0.000001
梯度下降条件
为了使得函数值减小:
f(x)<f(x0)⟹f′(x0)(x−x0)<0
选择沿负梯度方向:
x−x0=−ηf′(x0)
梯度下降条件为什么使得梯度下降?
从一元函数的一阶泰勒展开看:假设当前位置是x,下一步更新到x0:
f(x0)≈f(x)+f′(x)(x0−x)
我们希望新高度比当前低:
f(x0)<f(x)
代入一元函数的一阶泰勒展开:
f(x)+f′(x)(x0−x)<f(x)
两边减去f(x):
f′(x)(x0−x)<0
进行分析:
f′(x)>0(上坡)→x0−x<0→ 往左走。
f′(x)<0(下坡)→x0−x>0→ 往右走。
梯度下降更新公式与梯度下降怎么沿着梯度相反方向行走?
由梯度下降条件为什么使得梯度下降得:
f′(x)(x0−x)<0
移项得:
x0−x<−f′(x)
接下来为了控制每步走多远而引入正数η>0(学习率)即将不等式告诉我们的方向明确告诉我们走多远的移动量x0−x(用等号定义具体步长,是为了算法可操作):
x0−x=−ηf′(x)
- −号确保梯度反方向
- η 控制步长大小
由于η>0且(f′(x))2≥0不等式成立而最终推导且满足下降条件:
f′(x)(x0−x)=f′(x)(−ηf′(xt))=−η(f′(xt))2<0
由上最终得到梯度下降更新公式:
x0=x−ηf′(x)
多元梯度下降
假设参数向量wt=[w1,w2,...,wn]T:
梯度定义:
∇wf(wt)=∂w1∂f∂w2∂f⋮∂wn∂f
更新公式:
wt+1=wt−η∇wf(wt)
在一元线性回归中的应用
模型:
f(x(i))=wx(i)+b
损失函数(均方误差):
L(w,b)=2m1i=1∑m[wx(i)+b−y(i)]2
对 w 求偏导:
∂w∂L=m1i=1∑m[wx(i)+b−y(i)]x(i)
对 b 求偏导:
∂b∂L=m1i=1∑m[wx(i)+b−y(i)]
梯度下降更新公式:
w←w−η⋅m1i=1∑m[wx(i)+b−y(i)]x(i)
b←b−η⋅m1i=1∑m[wx(i)+b−y(i)]
Python实现
import numpy as np
data = np.array([ [1, 5.9], [2, 8.1], [3, 10.4], [4, 12.3], [5, 15.0], [6, 17.2], [7, 20.1], [8, 22.0], [9, 25.4], [10, 28.1] ])
X = data[:, 0].reshape(-1, 1) y = data[:, 1].reshape(-1, 1) m = X.shape[0]
w = np.random.randn(1, 1) b = 0.0 eta = 0.01 iterations = 4500
print(f"{'迭代':>5} | {'w':>8} | {'b':>8} | {'dw':>10} | {'db':>10} | {'损失值 L':>12}") print("-"*70)
for t in range(1, iterations + 1): y_hat = X.dot(w) + b L = (1/(2*m)) * np.sum((y_hat - y)**2) dw = (1/m) * np.sum((y_hat - y) * X) db = (1/m) * np.sum(y_hat - y)
w -= eta * dw b -= eta * db
print(f"{t:5d} | {w[0][0]:8.4f} | {b:8.4f} | {dw:10.4f} | {db:10.4f} | {L:12.6f}")
print("\n训练完成后的参数:") print(f"权重 w: {w[0][0]:.4f}") print(f"偏置 b: {b:.4f}")
X_test = np.array([[0], [1], [5], [10]]) y_test_hat = X_test.dot(w) + b print("\n预测值 ŷ^(i) :", y_test_hat.ravel())
|
可视化过程
迭代次数: 0
为节约网页性能,仅显示1~19次梯度下降过程,20次为最终收敛结果。