一、打卡内容概览
本次打卡正式进入回归问题核心篇章(核心目标:预测连续数值,如房价、气温、混凝土抗压强度),围绕四大核心展开:
- 回归模型与分类模型的本质区别
- 回归任务核心评估指标
- 多输出回归任务实现思路
- 置信区间的意义与Bootstrap实战
实战数据集:UCI混凝土抗压强度数据集(8个特征→预测抗压强度)
二、核心知识点回顾
1. 回归器 vs 分类器:本质区别
| 维度 | 回归器(预测连续值) | 分类器(预测离散类别) |
|---|---|---|
| 核心目标 | 猜「多少」(如强度、销量) | 猜「是谁」(如类别、标签) |
| 切分依据 | 方差(数值样本聚集程度) | 纯度(基尼系数/信息熵) |
| 代表模型 | LinearRegression、RandomForestRegressor | LogisticRegression、RandomForestClassifier |
| 关键提醒 | 逻辑回归是「分类模型」,非回归! | 分类问题无法直接转化为回归任务 |
2. 回归任务核心评估指标
| 指标名称 | 计算公式(简化) | 核心特点 |
|---|---|---|
| 平均绝对误差(MAE) | $\frac{1}{n}\sum | y_{true}-y_{pred} |
| 均方误差(MSE) | 1n∑(ytrue−ypred)2\frac{1}{n}\sum(y_{true}-y_{pred})^2n1∑(ytrue−ypred)2 | 对大误差惩罚重,放大异常值影响 |
| 均方根误差(RMSE) | MSE\sqrt{MSE}MSE | 量纲与原始数据一致,论文常用 |
| 决定系数(R2R^2R2) | 1−∑(ytrue−ypred)2∑(ytrue−yˉ)21-\frac{\sum(y_{true}-y_{pred})^2}{\sum(y_{true}-\bar{y})^2}1−∑(ytrue−yˉ)2∑(ytrue−ypred)2 | 取值0~1,越接近1拟合效果越好 |
3. 多输出回归任务(预测多个连续值)
- 适用场景:气象预测(温度+湿度+风速)、工业质检(多维度性能指标)
- 实现思路:
- 原生支持:树模型(决策树/随机森林)、神经网络(原生支持多输出)
- 包装器扩展:用
sklearn.multioutput.MultiOutputRegressor包装单输出模型 - 拆分单任务:为每个输出构建独立模型(缺点:丢失标签间关联信息)
4. 置信区间与Bootstrap思想
- 置信区间:并非"确定预测值",而是"包含真实值的概率范围"(如95%置信区间表示"有95%概率真实值在此范围内"),解决点预测的"绝对化"问题。
- Bootstrap(自助法)核心逻辑:
- 无总体数据时,将「手头样本视为总体」
- 通过「有放回重采样」生成多个平行训练集
- 用多个模型的预测结果统计分布,得到置信区间
- 优势:无需依赖复杂统计分布假设(如t分布、正态分布),工程实用性强
三、代码实战:混凝土抗压强度回归任务
1. 环境准备与数据加载
python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
# 全局绘图设置(支持中文)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
sns.set(style="whitegrid", font='SimHei')
# 加载数据集(GitHub稳定源)
url = "https://raw.githubusercontent.com/stedy/Machine-Learning-with-R-datasets/master/concrete.csv"
try:
df = pd.read_csv(url)
print("✅ 成功加载混凝土抗压强度数据集")
except Exception as e:
print(f"❌ 数据加载失败:{e}")
raise e
# 重命名列为中文(增强可读性)
df.columns = [
'Cement (水泥)', 'BlastFurnaceSlag (矿渣)', 'FlyAsh (粉煤灰)',
'Water (水)', 'Superplasticizer (减水剂)', 'CoarseAggregate (粗骨料)',
'FineAggregate (细骨料)', 'Age (养护天数)', 'Strength (抗压强度)'
]
# 数据集概览
print("\n" + "="*50)
print("数据集基本信息")
print("="*50)
print(f"数据形状:{df.shape}")
print(f"前5行数据:\n{df.head()}")
数据集输出结果
✅ 成功加载混凝土抗压强度数据集
==================================================
数据集基本信息
==================================================
数据形状:(1030, 9)
前5行数据:
Cement (水泥) BlastFurnaceSlag (矿渣) FlyAsh (粉煤灰) Water (水) \
0 540.0 0.0 0.0 162.0
1 540.0 0.0 0.0 162.0
2 332.5 142.5 0.0 228.0
3 332.5 142.5 0.0 228.0
4 198.6 132.4 0.0 192.0
Superplasticizer (减水剂) CoarseAggregate (粗骨料) FineAggregate (细骨料) \
0 2.5 1040.0 676.0
1 2.5 1055.0 676.0
2 0.0 932.0 594.0
3 0.0 932.0 594.0
4 0.0 978.4 825.5
Age (养护天数) Strength (抗压强度)
0 28 79.99
1 28 61.89
2 270 40.27
3 365 41.05
4 360 44.30
2. 数据切分与多模型训练
python
# 特征与目标变量拆分
X = df.iloc[:, :-1] # 前8列:特征
y = df.iloc[:, -1] # 最后1列:目标(抗压强度)
# 80%训练集,20%测试集(固定随机种子保证可复现)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# 定义待对比的回归模型
regressors = {
"Linear Regression (线性回归)": LinearRegression(),
"Decision Tree (决策树)": DecisionTreeRegressor(random_state=42),
"Random Forest (随机森林)": RandomForestRegressor(n_estimators=100, random_state=42),
"Gradient Boosting (梯度提升)": GradientBoostingRegressor(n_estimators=100, random_state=42)
}
# 训练模型并记录结果
results = []
preds_dict = {} # 存储各模型预测结果(用于后续可视化)
print("\n" + "="*50)
print("模型训练与评估")
print("="*50)
for name, model in regressors.items():
# 训练模型
model.fit(X_train, y_train)
# 预测测试集
y_pred = model.predict(X_test)
preds_dict[name] = y_pred
# 计算评估指标
r2 = r2_score(y_test, y_pred)
mse = mean_squared_error(y_test, y_pred)
rmse = np.sqrt(mse)
mae = mean_absolute_error(y_test, y_pred)
# 记录结果
results.append({
"模型名称": name,
"R²": round(r2, 4),
"RMSE": round(rmse, 4),
"MAE": round(mae, 4)
})
print(f"✅ {name} 训练完成 | R² = {r2:.4f} | RMSE = {rmse:.4f}")
# 整理结果为DataFrame(按R²降序排序)
results_df = pd.DataFrame(results).sort_values(by="R²", ascending=False)
print("\n" + "="*50)
print("模型性能排行榜")
print("="*50)
print(results_df)
模型训练输出结果
==================================================
模型训练与评估
==================================================
✅ Linear Regression (线性回归) 训练完成 | R² = 0.6276 | RMSE = 9.7965
✅ Decision Tree (决策树) 训练完成 | R² = 0.8348 | RMSE = 6.5254
✅ Random Forest (随机森林) 训练完成 | R² = 0.8841 | RMSE = 5.4639
✅ Gradient Boosting (梯度提升) 训练完成 | R² = 0.8829 | RMSE = 5.4934
==================================================
模型性能排行榜
==================================================
模型名称 R² RMSE MAE
2 Random Forest (随机森林) 0.8841 5.4639 3.7363
3 Gradient Boosting (梯度提升) 0.8829 5.4934 4.1350
1 Decision Tree (决策树) 0.8348 6.5254 4.2938
0 Linear Regression (线性回归) 0.6276 9.7965 7.7456
3. 模型可视化:拟合效果与置信区间
python
# 设置画布(2行2列子图)
fig, axes = plt.subplots(2, 2, figsize=(16, 14))
axes = axes.flatten() # 展平为1维数组,方便遍历
colors = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728"] # 每个模型对应颜色
# 统一坐标轴范围(所有子图保持一致,增强对比性)
all_preds = [preds_dict[m] for m in regressors.keys()]
data_min = min(y_test.min(), np.min(all_preds)) - 5
data_max = max(y_test.max(), np.max(all_preds)) + 5
print("\n📊 正在绘制模型拟合效果与置信区间图...")
for i, (name, model) in enumerate(regressors.items()):
ax = axes[i]
y_pred = preds_dict[name]
# 绘制带95%置信区间的散点图(sns.regplot自动计算置信区间)
sns.regplot(
x=y_test, y=y_pred, ax=ax,
color=colors[i],
ci=95, # 关键参数:绘制95%置信区间
scatter_kws={'s': 30, 'alpha': 0.5, 'edgecolor': 'white'}, # 散点样式
line_kws={'color': '#333333', 'linewidth': 2, 'label': '拟合趋势线'} # 拟合线样式
)
# 绘制完美预测线(y=x,即预测值=真实值)
ax.plot(
[data_min, data_max], [data_min, data_max],
'r--', linewidth=3, label='完美预测线 (y=x)'
)
# 计算当前模型指标(用于图中显示)
r2 = r2_score(y_test, y_pred)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
# 在图中添加指标文本框
text_str = f'$R^2$ = {r2:.3f}\nRMSE = {rmse:.3f}'
ax.text(
0.05, 0.95, text_str, transform=ax.transAxes, fontsize=14,
verticalalignment='top', bbox=dict(boxstyle='round', facecolor='white', alpha=0.9)
)
# 子图装饰
ax.set_title(name, fontsize=16, fontweight='bold')
ax.set_xlabel('真实强度 (Actual Strength)', fontsize=12)
ax.set_ylabel('预测强度 (Predicted Strength)', fontsize=12)
ax.set_xlim(data_min, data_max)
ax.set_ylim(data_min, data_max)
ax.legend(loc='lower right')
ax.grid(True, linestyle='--', alpha=0.5)
# 总标题与布局调整
plt.suptitle('各回归模型拟合效果与95%置信区间分析', fontsize=20, y=0.98)
plt.tight_layout()
plt.subplots_adjust(top=0.92)
plt.savefig('模型拟合与置信区间.png', dpi=300, bbox_inches='tight')
plt.show()
今天的学习,是连接模型与现实世界的关键桥梁。感谢 @浙大疏锦行 老师带来的精彩一课,让我对数据科学的理解又深入了一层!