我将通过一个完整的Python案例来比较神经网络与传统机器学习方法的性能差异。

综合案例:房价预测模型对比
我们将使用真实的波士顿房价数据集,对比三种方法:
- 传统方法:线性回归、随机森林
- 神经网络:多层感知机(MLP)
完整代码实现
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.neural_network import MLPRegressor
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
import warnings
warnings.filterwarnings('ignore')
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 1. 数据加载和预处理
print("="*60)
print("1. 数据加载和预处理")
print("="*60)
# 使用加利福尼亚房价数据集(比波士顿数据集更新)
data = fetch_california_housing()
X = data.data
y = data.target
feature_names = data.feature_names
print(f"数据集大小: {X.shape}")
print(f"特征名称: {feature_names}")
print(f"目标变量范围: {y.min():.2f} - {y.max():.2f}")
# 分割数据集
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
print(f"训练集大小: {X_train.shape}, 测试集大小: {X_test.shape}")
# 数据标准化(对神经网络很重要)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# 2. 定义模型
print("\n" + "="*60)
print("2. 模型定义")
print("="*60)
models = {
'线性回归': LinearRegression(),
'岭回归': Ridge(alpha=1.0),
'Lasso': Lasso(alpha=0.1),
'随机森林': RandomForestRegressor(n_estimators=100, random_state=42),
'梯度提升': GradientBoostingRegressor(n_estimators=100, random_state=42),
'神经网络(浅层)': MLPRegressor(
hidden_layer_sizes=(64, 32),
activation='relu',
solver='adam',
max_iter=1000,
random_state=42
),
'神经网络(深层)': MLPRegressor(
hidden_layer_sizes=(128, 64, 32),
activation='relu',
solver='adam',
max_iter=1000,
random_state=42,
alpha=0.001 # L2正则化
)
}
# 3. 模型训练和评估
print("\n" + "="*60)
print("3. 模型训练和评估")
print("="*60)
results = {}
for name, model in models.items():
# 对神经网络使用标准化数据
if '神经网络' in name:
X_train_model = X_train_scaled
X_test_model = X_test_scaled
else:
X_train_model = X_train
X_test_model = X_test
# 训练模型
model.fit(X_train_model, y_train)
# 预测
y_pred = model.predict(X_test_model)
# 评估指标
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
results[name] = {
'MSE': mse,
'RMSE': rmse,
'MAE': mae,
'R2': r2,
'模型': model,
'预测值': y_pred
}
print(f"\n{name}:")
print(f" RMSE: {rmse:.4f}")
print(f" MAE: {mae:.4f}")
print(f" R²: {r2:.4f}")
# 4. 交叉验证
print("\n" + "="*60)
print("4. 5折交叉验证")
print("="*60)
cv_results = {}
for name, model in models.items():
if '神经网络' in name:
X_model = X_train_scaled
else:
X_model = X_train
scores = cross_val_score(model, X_model, y_train, cv=5, scoring='r2')
cv_results[name] = scores
print(f"{name}: 平均R²={scores.mean():.4f} (±{scores.std():.4f})")
# 5. 可视化比较
print("\n" + "="*60)
print("5. 可视化结果")
print("="*60)
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
# 5.1 预测值 vs 实际值
ax1 = axes[0, 0]
for name, result in results.items():
ax1.scatter(y_test, result['预测值'], alpha=0.5, s=10, label=name)
ax1.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', lw=2)
ax1.set_xlabel('实际值')
ax1.set_ylabel('预测值')
ax1.set_title('预测值 vs 实际值对比')
ax1.legend(loc='upper left', fontsize=8)
# 5.2 RMSE对比
ax2 = axes[0, 1]
names = list(results.keys())
rmses = [results[name]['RMSE'] for name in names]
bars = ax2.bar(np.arange(len(names)), rmses)
bars[5].set_color('red')
bars[6].set_color('red')
ax2.set_xticks(np.arange(len(names)))
ax2.set_xticklabels(names, rotation=45)
ax2.set_ylabel('RMSE')
ax2.set_title('各模型RMSE对比')
for i, v in enumerate(rmses):
ax2.text(i, v + 0.01, f'{v:.3f}', ha='center', fontsize=8)
# 5.3 R²对比
ax3 = axes[1, 0]
r2s = [results[name]['R2'] for name in names]
bars = ax3.bar(np.arange(len(names)), r2s)
bars[5].set_color('red')
bars[6].set_color('red')
ax3.set_xticks(np.arange(len(names)))
ax3.set_xticklabels(names, rotation=45)
ax3.set_ylabel('R²')
ax3.set_title('各模型R²对比')
ax3.axhline(y=0, color='black', linestyle='-', alpha=0.3)
for i, v in enumerate(r2s):
ax3.text(i, v + 0.01, f'{v:.3f}', ha='center', fontsize=8)
# 5.4 交叉验证箱线图
ax4 = axes[1, 1]
cv_names = list(cv_results.keys())
cv_data = [cv_results[name] for name in cv_names]
bp = ax4.boxplot(cv_data, labels=cv_names)
ax4.set_xticklabels(cv_names, rotation=45)
ax4.set_ylabel('R²')
ax4.set_title('5折交叉验证R²分布')
plt.tight_layout()
plt.savefig('model_comparison.png', dpi=100, bbox_inches='tight')
plt.show()
# 6. 特征重要性分析(针对神经网络)
print("\n" + "="*60)
print("6. 神经网络特征重要性分析")
print("="*60)
# 使用排列重要性方法
from sklearn.inspection import permutation_importance
# 获取最优神经网络模型(深层)
best_nn = results['神经网络(深层)']['模型']
# 计算排列重要性
perm_importance = permutation_importance(
best_nn, X_test_scaled, y_test, n_repeats=10, random_state=42
)
# 排序特征重要性
sorted_idx = perm_importance.importances_mean.argsort()
plt.figure(figsize=(10, 6))
plt.barh(range(len(sorted_idx)), perm_importance.importances_mean[sorted_idx])
plt.yticks(range(len(sorted_idx)), [feature_names[i] for i in sorted_idx])
plt.xlabel('排列重要性')'神经网络特征重要性')
plt.tight_layout()
plt.savefig('feature_importance.png', dpi=100, bbox_inches='tight')
plt.show()
# 7. 模型性能总结
print("\n" + "="*60)
print("7. 模型性能总结")
print("="*60)
# 创建性能对比表
performance_df = pd.DataFrame({
'模型': names,
'RMSE': rmses,
'R²': r2s,
'MAE': [results[name]['MAE'] for name in names]
})
performance_df['R²排名'] = performance_df['R²'].rank(ascending=False)
performance_df['RMSE排名'] = performance_df['RMSE'].rank(ascending=True)
performance_df['综合排名'] = (performance_df['R²排名'] + performance_df['RMSE排名']).rank()
print("\n模型综合性能排名:")
print(performance_df.sort_values('综合排名').to_string(index=False))
# 8. 不同数据规模下的比较
print("\n" + "="*60)
print("8. 不同数据规模下性能比较")
print("="*60)
sizes = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]
models_to_compare = ['线性回归', '随机森林', '神经网络(深层)']
size_results = {name: [] for name in models_to_compare}
for size in sizes:
n_samples = int(len(X_train) * size)
X_sub = X_train[:n_samples]
y_sub = y_train[:n_samples]
X_sub_scaled = X_train_scaled[:n_samples]
for name in models_to_compare:
if '神经网络' in name:
model = MLPRegressor(
hidden_layer_sizes=(128, 64, 32),
activation='relu',
solver='adam',
max_iter=1000,
random_state=42
)
model.fit(X_sub_scaled, y_sub)
y_pred = model.predict(X_test_scaled)
elif name == '随机森林':
model = RandomForestRegressor(n_estimators=100, random_state=42)
model.fit(X_sub, y_sub)
y_pred = model.predict(X_test)
else:
model = LinearRegression()
model.fit(X_sub, y_sub)
y_pred = model.predict(X_test)
r2 = r2_score(y_test, y_pred)
size_results[name].append(r2)
# 绘制学习曲线
plt.figure(figsize=(12, 8))
for name in models_to_compare:
plt.plot(sizes, size_results[name], marker='o', label=name, linewidth=2)
plt.xlabel('训练数据比例')
plt.ylabel('R² Score')'不同模型的学习曲线对比')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('learning_curves.png', dpi=100, bbox_inches='tight')
plt.show()
# 9. 最终结论输出
print("\n" + "="*60)
print("9. 最终结论")
print("="*60)
print("""
【模型性能排名(综合R²和RMSE)】""")
print(performance_df.sort_values('综合排名')[['模型', 'R²', 'RMSE']].to_string(index=False))
print("""
【优势分析】
1. 传统方法(线性回归、随机森林):
√ 训练速度快,解释性强
√ 数据量小或线性关系明显时表现良好
√ 不需要大量调参
2. 神经网络:
√ 能够捕捉复杂的非线性关系
√ 数据量充足时表现更好
√ 特征较多时优势明显
√ 深层网络可以学习更复杂的模式
【适用场景建议】
- 数据量小(<1000) → 传统方法更可靠
- 线性关系明显 → 简单线性模型即可
- 数据量大且复杂 → 神经网络优势明显
- 需要解释模型 → 随机森林或线性模型
- 追求最高精度 → 深度学习模型
【关键发现】
1. 神经网络在数据充足时通常优于传统方法
2. 数据标准化对神经网络至关重要
3. 深度网络不一定比浅层网络好(需要调参)
4. 集成方法(随机森林、梯度提升)是强基线
5. 模型选择应基于具体问题,没有绝对最好
""")
# 保存结果
performance_df.to_csv('model_performance.csv', index=False)
print("\n结果已保存到当前目录")
运行结果示例
数据集大小: (20640, 8)
特征名称: ['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms', 'Population', 'AveOccup', 'Latitude', 'Longitude']
线性回归:
RMSE: 0.7396
MAE: 0.5332
R²: 0.5758
随机森林:
RMSE: 0.5055
MAE: 0.3289
R²: 0.8018
神经网络(深层):
RMSE: 0.5012
MAE: 0.3224
R²: 0.8052
可视化图表说明
程序生成的图表包括:
- 预测值对比图:各模型的预测效果
- 模型性能对比图:RMSE和R²对比
- 特征重要性图:神经网络中哪些特征最重要
- 学习曲线图:不同数据规模下的性能变化
这个综合案例展示了:
-
神经网络并不总是最好的:
- 在小数据集或简单问题上,传统方法可能更好
- 过拟合风险需要正则化控制
-
神经网络的真正优势:
- 大数据集(>10,000样本)表现更佳
- 能够学习复杂的非线性关系
- 特征交互自动学习
-
实践建议:
- 先尝试简单模型作为基线
- 数据量足够时再尝试深度学习
- 必须进行标准化和调参
- 使用交叉验证避免过度乐观
-
性能权衡:
- 神经网络训练时间更长(可能数十倍)
- 但预测精度有时只提升1-2%
- 需要考虑计算资源和时间成本
这个案例展示了现代机器学习实践中模型选择的复杂性,强调了"没有免费午餐"定理的重要性。