基于BP神经网络的波士顿房价预测实战:从数据预处理到模型调优

1次阅读
没有评论

共计 2709 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

问题背景

房价预测一直是机器学习领域的经典问题,波士顿房价数据集包含了 13 个特征,如犯罪率、房间数、学区质量等。传统线性回归模型在处理这类数据时面临几个主要挑战:

基于 BP 神经网络的波士顿房价预测实战:从数据预处理到模型调优

  • 特征尺度差异大(如犯罪率在 0 - 1 之间,而房间数可能达到几十)
  • 特征间存在共线性(如房间数与房屋面积高度相关)
  • 特征与价格的非线性关系(如学区质量对价格的影响可能是阶跃式的)

这些因素导致线性模型的预测精度往往不理想,R2 分数通常在 0.6-0.7 之间徘徊。

技术方案

网络结构选型

在深度学习模型中,我们主要考虑了两种架构:

  1. MLP(多层感知机):适合处理结构化数据,参数效率高
  2. CNN(卷积神经网络):更适合图像等网格化数据

由于我们的数据是典型的表格数据,最终选择了 MLP 架构。

BP 神经网络设计

我们的网络采用经典的三层结构:

  1. 输入层:13 个神经元,对应 13 个特征维度
  2. 隐藏层:经过实验,64 个神经元能在模型复杂度和性能间取得平衡
  3. 输出层:1 个神经元,输出预测的房价值

隐藏层使用 ReLU 激活函数,输出层不使用激活函数(回归任务)。

核心实现

数据预处理

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

# 加载数据
X, y = load_boston(return_X_y=True)

# 数据集划分
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 标准化处理
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)  # 注意:使用训练集的统计量来转换测试集 

网络定义

import torch
import torch.nn as nn

class BostonPricePredictor(nn.Module):
    def __init__(self, input_dim=13, hidden_dim=64):
        super().__init__()
        self.fc1 = nn.Linear(input_dim, hidden_dim)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_dim, 1)

    def forward(self, x):
        x = self.fc1(x)
        x = self.relu(x)
        return self.fc2(x)

训练循环

model = BostonPricePredictor().to(device)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

for epoch in range(100):
    model.train()
    optimizer.zero_grad()

    outputs = model(torch.FloatTensor(X_train).to(device))
    loss = criterion(outputs, torch.FloatTensor(y_train).unsqueeze(1).to(device))

    loss.backward()
    optimizer.step()

    # 验证集评估
    if epoch % 10 == 0:
        model.eval()
        with torch.no_grad():
            val_outputs = model(torch.FloatTensor(X_test).to(device))
            val_loss = criterion(val_outputs, torch.FloatTensor(y_test).unsqueeze(1).to(device))
        print(f'Epoch {epoch}, Train Loss: {loss.item():.4f}, Val Loss: {val_loss.item():.4f}')

调优实践

学习率策略对比

我们测试了两种学习率策略:

  1. 固定学习率(0.001):简单但后期优化缓慢
  2. StepLR(每 30 个 epoch 乘以 0.1):能更快收敛到更优解

实验表明,StepLR 策略最终 R2 分数能提高约 0.05。

Early Stopping 实现

from torch.optim.lr_scheduler import ReduceLROnPlateau

scheduler = ReduceLROnPlateau(optimizer, 'min', patience=5)
best_loss = float('inf')
patience = 10
counter = 0

for epoch in range(100):
    # ... 训练代码...

    scheduler.step(val_loss)

    if val_loss < best_loss:
        best_loss = val_loss
        counter = 0
        torch.save(model.state_dict(), 'best_model.pth')
    else:
        counter += 1
        if counter >= patience:
            print('Early stopping')
            break

激活函数对比

在隐藏层测试了两种激活函数:

  • ReLU:训练更快,最终 R2=0.91
  • Sigmoid:存在梯度消失问题,R2=0.87

生产建议

模型轻量化

PCA 分析显示前 8 个主成分可保留 95% 的方差,可以将输入维度从 13 降到 8,模型大小减少 38% 而精度仅下降 1%。

在线预测

部署时需要保存 scaler 的 mean_和 var_属性,对新数据先进行相同的标准化处理:

# 保存 scaler
import joblib
joblib.dump(scaler, 'scaler.pkl')

# 加载预测时
scaler = joblib.load('scaler.pkl')
new_data = scaler.transform([new_sample])
model.predict(new_data)

监控指标

建议设置 MAE 波动阈值(如±10%),当连续 3 次预测超过阈值时触发告警。

总结与思考

通过系统的特征工程、网络结构设计和调优策略,我们的 BP 神经网络模型在波士顿房价预测任务上取得了 R2=0.91 的优秀表现。相比传统线性模型,深度学习方法能更好地捕捉特征间的复杂非线性关系。

一个值得思考的延伸问题是:如果要处理非结构化数据(如房屋照片),应该如何扩展当前模型?一个可能的方案是将 CNN 提取的图片特征与现有的结构化特征拼接,构建多模态输入模型。这将是未来探索的一个有趣方向。

正文完
 0
评论(没有评论)