使用Scikit-learn包训练基于随机森林的回归器模型
一、引言
在机器学习领域,回归任务的目标是预测一个连续值——比如房价、温度或销量。单棵决策树虽然直观易懂,但容易过拟合,对训练数据中的噪声过于敏感。随机森林(Random Forest)正是为了解决这个问题而生的——它不靠“一棵树”单打独斗,而是用“多棵树”集体决策,通过集成学习的方式显著提升预测的稳定性和准确性。
随机森林是一种基于Bagging(Bootstrap Aggregating)思想的集成学习算法,通过在训练过程中引入双重随机性来降低模型方差:
- 样本随机采样:每棵树使用有放回抽样(Bootstrap)从原始数据集中抽取不同的子样本;
- 特征随机子集:每次节点分裂时,仅从随机选取的部分特征中寻找最优划分。
在回归任务中,随机森林的每棵决策树都会输出一个具体的数值预测,最终将所有树的预测值取算术平均作为模型的最终输出。这种“集体智慧”既保留了决策树处理非线性关系的能力,又有效控制了过拟合风险。
二、RandomForestRegressor 核心参数
Scikit-learn 的 RandomForestRegressor 提供了丰富的超参数,以下是最关键的几个:
| 参数 | 默认值 | 说明 |
|---|---|---|
n_estimators |
100 | 森林中决策树的数量。值越大模型越稳定,但训练时间也越长 |
criterion |
‘squared_error’ | 分裂质量评估函数。可选 ‘squared_error’(均方误差)、‘absolute_error’(绝对误差)、‘friedman_mse’、‘poisson’ |
max_depth |
None | 每棵树的最大深度。None 表示节点会一直扩展直到所有叶子纯化或达到最小样本数 |
min_samples_split |
2 | 内部节点分裂所需的最小样本数 |
min_samples_leaf |
1 | 叶子节点的最小样本数 |
max_features |
1.0 | 每次分裂时考虑的最大特征数。常用 ‘sqrt’ 或 ‘log2’ |
bootstrap |
True | 是否使用自助采样(有放回抽样) |
random_state |
None | 随机种子,设置后可保证结果可复现 |
n_jobs |
None | 并行计算使用的CPU核心数,-1 表示使用所有核心 |
oob_score |
False | 是否使用袋外样本(out-of-bag)进行模型评估 |
三、完整建模流程
下面我们以 Scikit-learn 内置的 California Housing 数据集为例,演示从数据加载到模型训练、评估的完整流程。
3.1 导入所需库
import numpy as np
import pandas as pd
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import matplotlib.pyplot as plt
import seaborn as sns
3.2 加载并探索数据
# 加载加州住房数据集
housing = fetch_california_housing()
X = pd.DataFrame(housing.data, columns=housing.feature_names)
y = pd.Series(housing.target, name='MedHouseVal')
print(f"特征数量: {X.shape[1]}")
print(f"样本数量: {X.shape[0]}")
print(X.head())
该数据集包含8个特征,如收入中位数、房龄、平均房间数等,目标变量是街区房价中位数(单位:十万美元)。
3.3 划分训练集和测试集
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[0]}")
print(f"测试集大小: {X_test.shape[0]}")
3.4 创建并训练随机森林回归模型
# 创建模型实例
rf_model = RandomForestRegressor(
n_estimators=100, # 100棵决策树
max_depth=10, # 限制树的最大深度,防止过拟合
min_samples_split=5, # 内部节点分裂最少需要5个样本
min_samples_leaf=2, # 叶子节点最少需要2个样本
n_jobs=-1, # 使用所有CPU核心并行计算
random_state=42, # 固定随机种子保证可复现
oob_score=True # 启用袋外评估
)
# 训练模型
rf_model.fit(X_train, y_train)
print("模型训练完成!")
这里的关键参数设置思路:
n_estimators=100是一个常用的起点,可根据数据规模和计算资源在50-500之间调整;max_depth=10限制了树的深度,避免单棵树过度拟合训练数据;min_samples_split和min_samples_leaf进一步控制了树的生长粒度。
3.5 模型预测与评估
# 在测试集上进行预测
y_pred = rf_model.predict(X_test)
# 计算评估指标
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)
print("=== 模型评估结果 ===")
print(f"均方误差 (MSE): {mse:.4f}")
print(f"均方根误差 (RMSE): {rmse:.4f}")
print(f"平均绝对误差 (MAE): {mae:.4f}")
print(f"决定系数 (R²): {r2:.4f}")
# 袋外评分(如果启用了oob_score)
if hasattr(rf_model, 'oob_score_'):
print(f"袋外评分 (OOB Score): {rf_model.oob_score_:.4f}")
评估指标解读:
- MSE / RMSE:值越小,预测误差越小;
- MAE:反映了预测值与真实值的平均绝对偏差;
- R²(决定系数) :取值范围0到1,越接近1表示模型对目标变量变异的解释能力越强。
3.6 特征重要性分析
随机森林的一大优势是可以天然提供特征重要性评估。feature_importances_ 属性返回每个特征的重要性分数,数值越大表示该特征对预测越关键。
# 获取特征重要性
importances = rf_model.feature_importances_
feature_names = housing.feature_names
# 创建特征重要性DataFrame并排序
importance_df = pd.DataFrame({
'特征': feature_names,
'重要性': importances
}).sort_values('重要性', ascending=False)
print("\n=== 特征重要性排序 ===")
print(importance_df)
# 可视化特征重要性
plt.figure(figsize=(10, 6))
sns.barplot(data=importance_df, x='重要性', y='特征')
plt.title('随机森林回归模型 - 特征重要性')
plt.xlabel('重要性分数')
plt.tight_layout()
plt.show()
3.7 模型持久化保存
训练好的模型可以通过 joblib 保存到磁盘,方便后续直接加载使用,无需重新训练:
import joblib
# 保存模型
joblib.dump(rf_model, 'random_forest_regressor.pkl')
print("模型已保存为 random_forest_regressor.pkl")
# 加载模型
# loaded_model = joblib.load('random_forest_regressor.pkl')
# predictions = loaded_model.predict(X_new)
四、超参数调优(进阶)
默认参数通常不是最优的,可以通过网格搜索(GridSearchCV) 系统地寻找最佳超参数组合:
from sklearn.model_selection import GridSearchCV
# 定义参数搜索空间
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'max_features': ['sqrt', 'log2']
}
# 创建网格搜索对象(5折交叉验证)
grid_search = GridSearchCV(
RandomForestRegressor(random_state=42),
param_grid,
cv=5,
scoring='r2',
n_jobs=-1,
verbose=1
)
# 执行搜索
grid_search.fit(X_train, y_train)
print(f"最佳参数组合: {grid_search.best_params_}")
print(f"最佳交叉验证R²: {grid_search.best_score_:.4f}")
# 使用最佳模型进行预测
best_model = grid_search.best_estimator_
y_pred_best = best_model.predict(X_test)
print(f"测试集R²: {r2_score(y_test, y_pred_best):.4f}")
- 点赞
- 收藏
- 关注作者
评论(0)