01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
01-什么是机器学习?从零基础到自动驾驶案例全解析
02-从过拟合到强化学习:机器学习核心知识全解析
03-从零精通机器学习:线性回归入门
线性回归是机器学习中最基础、最经典的算法之一,也是许多复杂模型的起点。它简单易懂,却能解决许多实际问题,比如预测房价、分析销售趋势或研究变量之间的关系。本文将带你从零开始,全面剖析线性回归的原理、数学基础、损失函数、优化方法以及实际应用场景。无论你是初学者还是希望深入理解的高阶读者,这篇文章都将以通俗的语言、清晰的结构和丰富的示例,帮你彻底掌握线性回归。
线性回归的核心是通过数据建立变量之间的线性关系,用于预测或解释现象。它是监督学习的基础,广泛应用于各个领域。
线性回归是一种统计方法,旨在通过自变量(输入特征)和因变量(输出目标)之间的线性关系进行建模。简单来说,它试图找到一条直线(或高维超平面),使这条线尽可能贴近所有数据点。
举个例子:假设我们要预测房价,可以用房屋面积作为自变量,房价作为因变量。线性回归会找到一条直线,让我们通过面积尽可能准确地预测房价。
线性回归的有效性依赖于几个关键假设:
这些假设在真实世界中可能不完全成立,但线性回归仍然能提供有意义的预测。
对于只有一个自变量的情况,线性回归的数学公式为:
y = β 0 + β 1 x + ϵ y = \beta_0 + \beta_1 x + \epsilon y=β0+β1x+ϵ
我们的目标是通过数据学习 ( \beta_0 ) 和 ( \beta_1 ) 的最佳值。
当有多个自变量时,公式扩展为:
y = β 0 + β 1 x 1 + β 2 x 2 + ⋯ + β p x p + ϵ \ y = \beta_0 + \beta_1 x_1 + \beta_2 x_2 + \cdots + \beta_p x_p + \epsilon y=β0+β1x1+β2x2+⋯+βpxp+ϵ
例如,预测房价可能需要综合考虑面积、位置和建造年份等多重因素。
为了便于计算,多变量线性回归通常用矩阵表示:
y = X β + ϵ \mathbf{y} = \mathbf{X} \boldsymbol{\beta} + \boldsymbol{\epsilon} y=Xβ+ϵ
这种形式在编程实现(如 NumPy 或 scikit-learn)中非常常见。
假设我们有以下数据:
房屋面积 (x) | 房价 (y) |
---|---|
50 | 100 |
70 | 130 |
90 | 160 |
线性回归会拟合一条直线(如 ( y = 1.5x + 25 )),如下图:
这条直线尽量靠近所有点,误差(即点到直线的距离)被最小化。
线性回归用途广泛,例如:
这些场景展示了线性回归的普适性和实用性。
损失函数是衡量模型预测效果的核心指标,在线性回归中,均方误差(MSE)是最常用的选择。
模型的预测值不可能完全等于真实值,误差总是存在的。损失函数的作用是量化这些误差,帮助我们评估模型的好坏,并指导参数调整。例如,如果预测房价偏离实际值太多,我们需要一个“标准”来衡量这种偏差。
均方误差(MSE)计算的是预测值与真实值之差的平方的平均值,公式为:
MSE = 1 n ∑ i = 1 n ( y i − y ^ i ) 2 \text{MSE} = \frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2 MSE=n1i=1∑n(yi−y^i)2
例如,对于以下数据:
真实值 (y) | 预测值 ((\hat{y})) |
---|---|
100 | 105 |
130 | 125 |
160 | 155 |
MSE 计算如下:
MSE = ( 100 − 105 ) 2 + ( 130 − 125 ) 2 + ( 160 − 155 ) 2 3 = 25 + 25 + 25 3 = 25 \text{MSE} = \frac{(100-105)^2 + (130-125)^2 + (160-155)^2}{3} = \frac{25 + 25 + 25}{3} = 25 MSE=3(100−105)2+(130−125)2+(160−155)2=325+25+25=25
MSE 越小,说明预测越准确。
MSE 可以看作是所有数据点到拟合直线的垂直距离平方的平均值:
graph TD
A[数据点] --> B(真实值)
A --> C(预测值)
B --> D[误差: y - ŷ]
D --> E[平方: (y - ŷ)²]
E --> F[平均: MSE]
除了 MSE,线性回归还可以使用其他损失函数:
RMSE = 1 n ∑ i = 1 n ( y i − y ^ i ) 2 \text{RMSE} = \sqrt{\frac{1}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i)^2} RMSE=n1i=1∑n(yi−y^i)2
RMSE 是 MSE 的平方根,与原始数据的单位相同,更直观。
MAE = 1 n ∑ i = 1 n ∣ y i − y ^ i ∣ \text{MAE} = \frac{1}{n} \sum_{i=1}^{n} |y_i - \hat{y}_i| MAE=n1i=1∑n∣yi−y^i∣
MAE 对异常值不敏感,但优化时不如 MSE 平滑。
选择哪种损失函数取决于数据特性和任务需求。
线性回归的目标是找到使损失函数最小的参数,而梯度下降法是一种高效的优化方法,尤其在大规模数据中。
我们希望调整 ( \beta_0, \beta_1, \ldots, \beta_p ),使 MSE 最小化。这是一个典型的优化问题。理论上可以用最小二乘法直接求解(通过矩阵运算),但在数据量大或特征多时,计算成本高昂,梯度下降成为更实际的选择。
梯度是损失函数对参数的偏导数,表示函数值增加最快的方向。优化时,我们沿梯度的反方向移动,以减少损失。对于 MSE,损失函数 ( J(\beta) ) 定义为:
J ( β ) = 1 n ∑ i = 1 n ( y i − ( β 0 + β 1 x i 1 + ⋯ + β p x i p ) ) 2 J(\beta) = \frac{1}{n} \sum_{i=1}^{n} (y_i - (\beta_0 + \beta_1 x_{i1} + \cdots + \beta_p x_{ip}))^2 J(β)=n1i=1∑n(yi−(β0+β1xi1+⋯+βpxip))2
梯度为:
∇ J ( β ) = [ ∂ J ∂ β 0 , ∂ J ∂ β 1 , … , ∂ J ∂ β p ] \nabla J(\beta) = \left[ \frac{\partial J}{\partial \beta_0}, \frac{\partial J}{\partial \beta_1}, \ldots, \frac{\partial J}{\partial \beta_p} \right] ∇J(β)=[∂β0∂J,∂β1∂J,…,∂βp∂J]
梯度下降通过以下公式迭代更新参数:
β j = β j − α ⋅ ∂ J ∂ β j \beta_j = \beta_j - \alpha \cdot \frac{\partial J}{\partial \beta_j} βj=βj−α⋅∂βj∂J
例如,对于单变量线性回归:
∂ J ∂ β 0 = 2 n ∑ i = 1 n ( y i − y ^ i ) \frac{\partial J}{\partial \beta_0} = \frac{2}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i) ∂β0∂J=n2i=1∑n(yi−y^i)
∂ J ∂ β 1 = 2 n ∑ i = 1 n ( y i − y ^ i ) x i \frac{\partial J}{\partial \beta_1} = \frac{2}{n} \sum_{i=1}^{n} (y_i - \hat{y}_i) x_i ∂β1∂J=n2i=1∑n(yi−y^i)xi
学习率 ( \alpha ) 是梯度下降的关键参数:
下图展示了不同学习率的效果:
使用整个数据集计算梯度并更新参数。
每次迭代随机选择一个数据点计算梯度。
每次使用一小批数据(例如 32 或 64 个样本)计算梯度。
import numpy as np
# 模拟数据
X = np.array([[1, 1], [1, 2], [1, 3], [1, 4]]) # 包含偏置项
y = np.array([2, 4, 5, 7])
beta = np.zeros(2) # 初始参数
alpha = 0.05 # 学习率
epochs = 200
batch_size = 2
# 小批量梯度下降
for epoch in range(epochs):
indices = np.random.permutation(len(y)) # 随机打乱数据
for start in range(0, len(y), batch_size):
batch_indices = indices[start:start + batch_size]
X_batch = X[batch_indices]
y_batch = y[batch_indices]
y_pred = X_batch.dot(beta)
error = y_pred - y_batch
gradient = X_batch.T.dot(error) / batch_size
beta -= alpha * gradient
print("训练后的参数:", beta)
梯度下降通常在以下情况下停止:
为了加速收敛,可以动态调整学习率:
这些方法在实践中显著提高了效率。
线性回归在现实中有无数应用,以下是两个详细案例。
假设我们有一个房屋数据集,包含面积、房间数和位置等特征,以及对应的房价。我们希望预测新房屋的房价。
使用 scikit-learn 实现:
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import StandardScaler
import pandas as pd
import numpy as np
# 模拟数据
data = pd.DataFrame({
'area': [50, 70, 90, 120],
'rooms': [1, 2, 2, 3],
'location': [1, 2, 1, 3],
'price': [100, 130, 160, 200]
})
X = data[['area', 'rooms', 'location']]
y = data['price']
# 标准化特征
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 训练模型
model = LinearRegression()
model.fit(X_scaled, y)
# 预测新房屋
new_house = scaler.transform([[100, 2, 1]]) # 100平米,2房间,位置1
predicted_price = model.predict(new_house)
print("预测房价:", predicted_price[0])
模型会输出参数(如 ( \beta )),我们可以分析每个特征对房价的影响。例如,如果 ( \beta_{\text{area}} ) 较大,说明面积对房价的影响更显著。
企业希望通过历史销售数据预测未来几个月的销售额。
假设数据如下:
月份 (x) | 销售额 (y) |
---|---|
1 | 100 |
2 | 150 |
3 | 200 |
4 | 250 |
import numpy as np
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
# 数据
X = np.array([1, 2, 3, 4]).reshape(-1, 1)
y = np.array([100, 150, 200, 250])
# 训练
model = LinearRegression()
model.fit(X, y)
# 预测未来3个月
future_X = np.array([5, 6, 7]).reshape(-1, 1)
predicted_sales = model.predict(future_X)
print("预测销售额:", predicted_sales)
# 可视化
plt.scatter(X, y, color='blue', label='历史数据')
plt.plot(np.vstack([X, future_X]), np.hstack([y, predicted_sales]), color='red', label='拟合与预测')
plt.xlabel('月份')
plt.ylabel('销售额')
plt.legend()
plt.show()
模型假设销售额随时间线性增长。如果数据呈现非线性趋势,可以考虑多项式回归或时间序列模型。
当特征过多或数据过拟合时,可以引入正则化: