第4篇:线性回归——找一条最合适的直线

🤔 什么是线性回归?

想象你在预测房价:

  • 你知道房子的面积越大,价格通常越高
  • 你也发现房间越多,价格也会上涨
  • 但你想要一个具体的数值预测,而不只是"大概会贵一些"

线性回归就是找一条直线,用这条直线来预测数值

📈 生活中的直线关系

例子1:学习时间与成绩

成绩 = 50 + 10 × 学习时间
  • 不学习也能得50分(基础分)
  • 每学习1小时,成绩提高10分
  • 学习5小时,预计成绩 = 50 + 10×5 = 100分

例子2:工作年限与工资

工资 = 3000 + 500 × 工作年限
  • 刚毕业3000元起薪
  • 每多工作1年,工资涨500元

🎯 线性回归的核心思想

🔍 找最佳拟合直线

现实中的数据点往往不是完美地在一条直线上:

房价(万)
  ↑
  |    ●
  |  ●
  |●     ●
  |      ●
  |        ●
  +------------------→ 面积(㎡)

我们要找一条直线,​让所有点到这条直线的垂直距离之和最小

这条线就是我们的预测模型​!

📐 数学表达

线性回归方程:

y = wx + b

其中:

  • y​:要预测的值(比如房价)
  • x​:输入的特征(比如面积)
  • w​:权重/斜率(面积每增加1㎡,房价增加w万)
  • b​:偏置/截距(当面积为0时的基础房价)

🛠️ 用Python实现线性回归

方法1:手工实现(理解原理)

import numpy as np
import matplotlib.pyplot as plt

class SimpleLinearRegression:
    def __init__(self):
        self.w = 0  # 权重
        self.b = 0  # 偏置
    
    def fit(self, X, y):
        """
        训练模型:找到最佳的w和b
        使用最小二乘法
        """
        # 将数据转换为numpy数组
        X = np.array(X)
        y = np.array(y)
        
        # 最小二乘法公式:
        # w = Σ[(xi - x̄)(yi - ȳ)] / Σ[(xi - x̄)²]
        # b = ȳ - w*x̄
        
        x_mean = np.mean(X)
        y_mean = np.mean(y)
        
        numerator = np.sum((X - x_mean) * (y - y_mean))
        denominator = np.sum((X - x_mean) ** 2)
        
        self.w = numerator / denominator
        self.b = y_mean - self.w * x_mean
        
        print(f"训练完成!")
        print(f"直线方程: y = {self.w:.2f}x + {self.b:.2f}")
    
    def predict(self, X):
        """预测"""
        return self.w * np.array(X) + self.b
    
    def score(self, X, y):
        """计算R²决定系数(衡量拟合好坏)"""
        X = np.array(X)
        y = np.array(y)
        predictions = self.predict(X)
        
        # 总平方和
        ss_tot = np.sum((y - np.mean(y)) ** 2)
        # 残差平方和
        ss_res = np.sum((y - predictions) ** 2)
        
        r_squared = 1 - (ss_res / ss_tot)
        return r_squared

# 准备房价数据:面积(㎡) -> 价格(万)
areas = [50, 80, 100, 120, 150, 180, 200, 220, 250, 280]
prices = [80, 120, 150, 180, 220, 260, 290, 320, 360, 400]

# 创建并训练模型
model = SimpleLinearRegression()
model.fit(areas, prices)

# 预测
test_areas = [60, 130, 200, 300]
predicted_prices = model.predict(test_areas)

print(f"\n预测结果:")
for area, price in zip(test_areas, predicted_prices):
    print(f"面积{area}㎡ -> 预测价格{price:.1f}万")

# 评估模型
r2 = model.score(areas, prices)
print(f"\n模型表现:R² = {r2:.3f} (越接近1越好)")

运行结果:

训练完成!
直线方程: y = 1.43x + 8.57

预测结果:
面积60㎡ -> 预测价格94.5万
面积130㎡ -> 预测价格194.1万
面积200㎡ -> 预测价格295.0万
面积300㎡ -> 预测价格437.9万

模型表现:R² = 0.992 (越接近1越好)

方法2:使用sklearn(实际应用)

from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt

# 准备数据(注意:sklearn要求二维数组)
X = np.array(areas).reshape(-1, 1)  # 转换成n×1的矩阵
y = np.array(prices)

# 创建模型
sk_model = LinearRegression()

# 训练模型
sk_model.fit(X, y)

# 查看学到的参数
print(f"sklearn训练结果:")
print(f"权重w: {sk_model.coef_[0]:.2f}")
print(f"偏置b: {sk_model.intercept_:.2f}")
print(f"方程: y = {sk_model.coef_[0]:.2f}x + {sk_model.intercept_:.2f}")

# 预测
test_X = np.array(test_areas).reshape(-1, 1)
sk_predictions = sk_model.predict(test_X)

# 评估
sk_r2 = r2_score(y, sk_model.predict(X))
sk_mse = mean_squared_error(y, sk_model.predict(X))

print(f"\nsklearn模型表现:")
print(f"R² = {sk_r2:.3f}")
print(f"均方误差 = {sk_mse:.2f}")

# 可视化
plt.figure(figsize=(10, 6))
plt.scatter(areas, prices, color='blue', label='实际数据')
plt.plot(areas, sk_model.predict(X), color='red', linewidth=2, label='拟合直线')
plt.xlabel('面积(㎡)')
plt.ylabel('价格(万)')
plt.title('房价与面积的关系')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

🔍 深入理解:损失函数

📉 什么是损失函数?

损失函数衡量预测值与真实值的差距。我们希望这个差距越小越好。

对于线性回归,常用均方误差(MSE)​​:

MSE = (1/n) × Σ(yi - ŷi)²

其中:

  • yi:真实值
  • ŷi:预测值
  • n:数据点个数

🎯 梯度下降优化

当数据比较复杂时,我们不能直接用公式求解,需要用梯度下降​:

class GradientDescentLinearRegression:
    def __init__(self, learning_rate=0.01, n_iterations=1000):
        self.learning_rate = learning_rate
        self.n_iterations = n_iterations
        self.w = 0
        self.b = 0
        self.loss_history = []
    
    def compute_loss(self, X, y):
        """计算均方误差"""
        predictions = self.w * X + self.b
        return np.mean((y - predictions) ** 2)
    
    def fit(self, X, y):
        """使用梯度下降训练"""
        X = np.array(X)
        y = np.array(y)
        
        n = len(X)
        
        for i in range(self.n_iterations):
            # 计算预测值
            predictions = self.w * X + self.b
            
            # 计算梯度
            dw = (-2/n) * np.sum(X * (y - predictions))  # w的梯度
            db = (-2/n) * np.sum(y - predictions)        # b的梯度
            
            # 更新参数
            self.w -= self.learning_rate * dw
            self.b -= self.learning_rate * db
            
            # 记录损失
            loss = self.compute_loss(X, y)
            self.loss_history.append(loss)
            
            # 每100次迭代打印进度
            if i % 100 == 0:
                print(f"迭代{i}: 损失 = {loss:.2f}, w = {self.w:.2f}, b = {self.b:.2f}")
    
    def predict(self, X):
        return self.w * np.array(X) + self.b

# 使用梯度下降版本
gd_model = GradientDescentLinearRegression(learning_rate=0.001, n_iterations=1000)
gd_model.fit(areas, prices)

print(f"\n梯度下降结果:")
print(f"方程: y = {gd_model.w:.2f}x + {gd_model.b:.2f}")

# 绘制损失下降过程
plt.figure(figsize=(10, 4))
plt.plot(gd_model.loss_history)
plt.xlabel('迭代次数')
plt.ylabel('损失值')
plt.title('梯度下降优化过程')
plt.grid(True, alpha=0.3)
plt.show()

🧠 多变量线性回归

现实中,我们通常有多个特征影响结果:

房价预测的高级版本​:

房价 = w₁×面积 + w₂×房间数 + w₃×地段评分 + b
# 多变量数据:面积、房间数、地段评分 -> 房价
X_multi = np.array([
    [120, 3, 8],    # 房子1
    [80,  2, 6],    # 房子2  
    [150, 4, 9],    # 房子3
    [90,  2, 7],    # 房子4
    [110, 3, 7],    # 房子5
    [200, 5, 9]     # 房子6
])

y_multi = np.array([300, 180, 450, 220, 280, 520])  # 对应房价

# 使用sklearn的多变量线性回归
multi_model = LinearRegression()
multi_model.fit(X_multi, y_multi)

print("多变量线性回归结果:")
print(f"权重 (面积, 房间数, 地段): {multi_model.coef_}")
print(f"偏置: {multi_model.intercept_:.2f}")
print(f"方程: 房价 = {multi_model.coef_[0]:.2f}×面积 + {multi_model.coef_[1]:.2f}×房间数 + {multi_model.coef_[2]:.2f}×地段 + {multi_model.intercept_:.2f}")

# 预测新房子
new_house = np.array([[100, 2, 7]])  # 100㎡, 2室, 地段7分
predicted_price = multi_model.predict(new_house)[0]
print(f"\n预测新房子价格: {predicted_price:.1f}万")

⚠️ 线性回归的局限性

1️⃣ 只能捕捉线性关系

如果真实关系是曲线的,线性回归就不行了:

# 非线性数据示例
np.random.seed(42)
X_nonlinear = np.linspace(0, 10, 100)
y_nonlinear = 2 * X_nonlinear + 3 * X_nonlinear**2 + np.random.normal(0, 10, 100)

# 用线性回归拟合非线性数据
linear_model = LinearRegression()
linear_model.fit(X_nonlinear.reshape(-1, 1), y_nonlinear)

# 可视化对比
plt.figure(figsize=(12, 4))

plt.subplot(1, 2, 1)
plt.scatter(X_nonlinear, y_nonlinear, alpha=0.6, label='真实数据')
plt.plot(X_nonlinear, linear_model.predict(X_nonlinear.reshape(-1, 1)), 
         color='red', label='线性拟合')
plt.legend()
plt.title('线性回归拟合非线性数据(效果差)')

# 多项式回归效果更好
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline

poly_model = Pipeline([
    ('poly', PolynomialFeatures(degree=2)),
    ('linear', LinearRegression())
])
poly_model.fit(X_nonlinear.reshape(-1, 1), y_nonlinear)

plt.subplot(1, 2, 2)
plt.scatter(X_nonlinear, y_nonlinear, alpha=0.6, label='真实数据')
plt.plot(X_nonlinear, poly_model.predict(X_nonlinear.reshape(-1, 1)), 
         color='green', label='多项式拟合')
plt.legend()
plt.title('多项式回归拟合非线性数据(效果好)')

plt.tight_layout()
plt.show()

2️⃣ 对异常值敏感

# 加入异常值的影响
normal_areas = [50, 80, 100, 120, 150, 180, 200]
normal_prices = [80, 120, 150, 180, 220, 260, 290]

# 加入一个异常值:面积很小但价格极高
outlier_areas = normal_areas + [60]  # 多加一个点
outlier_prices = normal_prices + [1000]  # 这个房子60㎡却卖1000万!

# 分别训练模型
normal_model = LinearRegression().fit(
    np.array(normal_areas).reshape(-1, 1), normal_prices)
outlier_model = LinearRegression().fit(
    np.array(outlier_areas).reshape(-1, 1), outlier_prices)

# 可视化对比
test_x = np.linspace(40, 220, 100).reshape(-1, 1)

plt.figure(figsize=(10, 6))
plt.scatter(normal_areas, normal_prices, color='blue', s=50, label='正常数据')
plt.scatter([60], [1000], color='red', s=100, marker='x', label='异常值')
plt.plot(test_x, normal_model.predict(test_x), 'b-', label='正常数据拟合')
plt.plot(test_x, outlier_model.predict(test_x), 'r--', label='含异常值拟合')
plt.xlabel('面积(㎡)')
plt.ylabel('价格(万)')
plt.legend()
plt.title('异常值对线性回归的影响')
plt.grid(True, alpha=0.3)
plt.show()

print("正常数据模型的斜率:", normal_model.coef_[0])
print("含异常值模型的斜率:", outlier_model.coef_[0])

🤖 为什么线性回归是机器学习的基石?

1️⃣ 简单有效

  • 容易理解和实现
  • 计算速度快
  • 在小数据集上往往效果不错

2️⃣ 理论基础扎实

  • 统计性质明确
  • 可以进行显著性检验
  • 是更复杂模型的基础

3️⃣ 可解释性强

# 解释模型结果
print("=== 模型解释 ===")
print(f"面积每增加1㎡,房价平均增加{multi_model.coef_[0]:.1f}万")
print(f"房间数每增加1间,房价平均增加{multi_model.coef_[1]:.1f}万") 
print(f"地段评分每增加1分,房价平均增加{multi_model.coef_[2]:.1f}万")
print(f"即使什么都没有(面积=0),基础房价是{multi_model.intercept_:.1f}万")

📝 本篇小结

  1. 线性回归找直线​:用直线 y = wx + b 预测数值
  2. 最小二乘法​:让所有数据点到直线的距离平方和最小
  3. 梯度下降​:复杂情况下的参数优化方法
  4. 多变量扩展​:可以有多个特征同时影响结果
  5. 局限性​:只能处理线性关系,对异常值敏感
  6. 重要性​:是理解更复杂机器学习算法的基础

🎯 练习题

  1. 手工计算​:给定数据点 (1,2), (2,3), (3,5),用手工方法计算线性回归的参数w和b
  2. 实际数据​:找一组你感兴趣的数据(比如学习时间与考试成绩),用线性回归分析它们的关系
  3. 改进模型​:尝试给房价数据加入"装修程度"特征,看看预测效果是否提升
  4. 异常值处理​:思考如何处理数据中的异常值,让模型更稳健?

🔮 下一篇预告

第5篇:逻辑回归——不只是预测数字,还能分类

线性回归只能预测连续数值,但现实中我们经常需要分类:

  • 这封邮件是垃圾邮件还是正常邮件?
  • 这张图片是猫还是狗?
  • 这个用户会购买产品还是不会?

逻辑回归就是解决这类问题的利器!我们将学习如何让AI学会"做选择题"。

准备好进入分类的世界了吗? 🚀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值