Python 随机森林算法:原理、实现与完整案例解析
·
随机森林(Random Forest)是机器学习中经典的集成学习算法,基于 “多棵决策树投票” 的思想,兼具高准确率、抗过拟合、可解释性强等优势,广泛应用于分类、回归、特征重要性分析等场景。本文将从算法原理入手,结合分类任务(鸢尾花品种预测) 和回归任务(房价预测) 两个完整代码案例,带你掌握随机森林的实现与应用。
一、随机森林算法核心原理
随机森林本质是 “多棵决策树的集合”,通过 “随机采样数据 + 随机选择特征” 降低单棵决策树的方差,最终通过投票(分类)或平均(回归)输出结果。其核心步骤如下:
1.1 两大随机机制(关键!)
- 随机样本采样(Bootstrap 抽样):从原始数据集(含
N个样本)中有放回地随机抽取N个样本,生成每棵决策树的训练数据(每棵树的训练集不完全相同,避免过拟合)。 - 随机特征选择:构建每棵决策树的每个节点时,从所有
M个特征中随机选择k个特征(通常k=√M),仅基于这k个特征寻找最优分裂规则(进一步降低树与树之间的相关性)。
1.2 模型训练与预测逻辑
| 任务类型 | 训练过程 | 预测过程 |
|---|---|---|
| 分类任务 | 每棵决策树独立训练,输出类别概率 | 所有树的预测结果投票,得票最多的类别为最终结果 |
| 回归任务 | 每棵决策树独立训练,输出连续值 | 所有树的预测结果取平均值,作为最终结果 |
1.3 随机森林的优势
- 抗过拟合:多棵树的 “集体决策” 抵消单棵树的极端预测,降低过拟合风险;
- 鲁棒性强:对异常值、缺失值不敏感,无需复杂的数据预处理;
- 可解释性:能输出特征重要性,明确哪些因素对结果影响最大;
- 适用范围广:同时支持分类和回归任务,无需调整核心框架。
二、环境准备
在开始案例前,需安装并导入以下库(均为 Python 机器学习常用库):
# 基础数据处理库
import pandas as pd
import numpy as np
# 数据集库(自带经典数据集)
from sklearn.datasets import load_iris, load_boston
# 模型相关库
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor # 随机森林分类/回归
from sklearn.model_selection import train_test_split, cross_val_score # 数据划分、交叉验证
from sklearn.preprocessing import StandardScaler # 数据标准化(回归任务用)
# 模型评估库
from sklearn.metrics import (
accuracy_score, classification_report, confusion_matrix, # 分类评估
mean_squared_error, r2_score # 回归评估
)
# 可视化库
import matplotlib.pyplot as plt
import seaborn as sns
# 设置中文字体(避免图表中文乱码)
plt.rcParams['font.sans-serif'] = ['WenQuanYi Zen Hei']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['figure.dpi'] = 300 # 提高图表清晰度
三、案例 1:随机森林分类 —— 鸢尾花品种预测
3.1 数据集介绍
鸢尾花(Iris)数据集是机器学习入门经典分类数据集,包含 3 个品种(山鸢尾、变色鸢尾、维吉尼亚鸢尾)的 150 个样本,每个样本有 4 个特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度。任务目标:根据 4 个特征预测鸢尾花品种。
3.2 完整代码实现
步骤 1:加载并探索数据
# 1. 加载鸢尾花数据集
iris = load_iris()
# 转换为DataFrame(便于查看)
iris_df = pd.DataFrame(
data=iris.data,
columns=iris.feature_names # 特征名:花萼长度、花萼宽度、花瓣长度、花瓣宽度
)
# 添加目标变量(品种)
iris_df['species'] = iris.target
# 映射品种编号为中文名称(0=山鸢尾,1=变色鸢尾,2=维吉尼亚鸢尾)
species_map = {0: '山鸢尾', 1: '变色鸢尾', 2: '维吉尼亚鸢尾'}
iris_df['species_name'] = iris_df['species'].map(species_map)
# 2. 探索数据基本信息
print("数据集形状(样本数×特征数):", iris_df.shape)
print("\n数据集前5行:")
print(iris_df.head())
print("\n各品种样本数量:")
print(iris_df['species_name'].value_counts())
# 3. 可视化特征分布(散点图矩阵,观察特征与品种的关系)
plt.figure(figsize=(10, 8))
sns.pairplot(
iris_df,
hue='species_name', # 按品种着色
vars=iris.feature_names, # 仅显示特征列
markers=['o', 's', '^'] # 不同品种用不同标记
)
plt.suptitle('鸢尾花特征散点图矩阵', y=1.02) # 调整标题位置
plt.show()
步骤 2:数据划分与模型训练
# 1. 划分特征(X)和目标变量(y)
X = iris.data # 4个特征
y = iris.target # 品种(0/1/2)
# 2. 划分训练集(80%)和测试集(20%)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42, stratify=y # stratify=y:保持训练/测试集品种分布一致
)
print(f"\n训练集大小:{X_train.shape},测试集大小:{X_test.shape}")
# 3. 初始化随机森林分类器
# n_estimators:决策树数量(通常100-200,过多会增加计算量)
# max_depth:每棵树的最大深度(None表示不限制,可防止过拟合)
# random_state:随机种子(确保结果可复现)
rf_clf = RandomForestClassifier(
n_estimators=100,
max_depth=None,
random_state=42,
n_jobs=-1 # 用所有CPU核心训练,加快速度
)
# 4. 训练模型
rf_clf.fit(X_train, y_train)
print("\n随机森林分类器训练完成!")
步骤 3:模型预测与评估
# 1. 测试集预测
y_pred = rf_clf.predict(X_test) # 预测类别
y_pred_proba = rf_clf.predict_proba(X_test) # 预测每个类别的概率(可选,用于概率分析)
# 2. 计算准确率(分类任务核心指标)
accuracy = accuracy_score(y_test, y_pred)
print(f"\n测试集准确率:{accuracy:.4f}(1.0表示完全正确)")
# 3. 详细分类报告(精确率、召回率、F1分数)
print("\n详细分类报告:")
print(classification_report(
y_test, y_pred,
target_names=species_map.values() # 显示品种中文名称
))
# 4. 混淆矩阵(可视化预测结果与真实结果的对比)
conf_matrix = confusion_matrix(y_test, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(
conf_matrix,
annot=True, # 显示数值
fmt='d', # 数值格式为整数
cmap='Blues',
xticklabels=species_map.values(),
yticklabels=species_map.values()
)
plt.xlabel('预测品种')
plt.ylabel('真实品种')
plt.title('鸢尾花品种预测混淆矩阵')
plt.show()
步骤 4:特征重要性分析(随机森林的核心优势)
# 1. 提取特征重要性(值越大,对预测结果影响越大)
feature_importance = pd.DataFrame({
'特征名称': iris.feature_names,
'重要性': rf_clf.feature_importances_
}).sort_values('重要性', ascending=False)
print("\n特征重要性排序:")
print(feature_importance)
# 2. 可视化特征重要性
plt.figure(figsize=(10, 6))
sns.barplot(
x='重要性',
y='特征名称',
data=feature_importance,
palette='viridis'
)
plt.xlabel('重要性得分')
plt.ylabel('特征名称')
plt.title('鸢尾花品种预测:随机森林特征重要性')
plt.show()
3.3 案例结果解读
- 模型性能:测试集准确率达 1.0(100%),说明随机森林能完美区分鸢尾花品种;
- 特征重要性:花瓣长度(重要性≈0.45)和花瓣宽度(重要性≈0.43)是预测的关键特征,与生物学常识一致(鸢尾花品种主要通过花瓣形态区分);
- 混淆矩阵:所有测试样本均被正确分类,无错分情况。
四、案例 2:随机森林回归 —— 波士顿房价预测
4.1 数据集介绍
波士顿房价(Boston Housing)数据集是经典回归数据集,包含波士顿地区 506 个住宅的 13 个特征(如犯罪率、平均房间数、距离市中心距离等)和 1 个目标变量(房屋中位数价格,单位:千美元)。任务目标:根据 13 个特征预测房屋价格。
4.2 完整代码实现
步骤 1:加载并预处理数据
# 1. 加载波士顿房价数据集(注意:sklearn 1.2+ 版本需用 fetch_openml 加载)
try:
# 旧版本 sklearn(<1.2)加载方式
from sklearn.datasets import load_boston
boston = load_boston()
except ImportError:
# 新版本 sklearn(≥1.2)加载方式(load_boston 已 deprecated)
from sklearn.datasets import fetch_openml
boston = fetch_openml(name='boston', version=1, as_frame=True)
boston.data = boston.frame.drop('MEDV', axis=1)
boston.target = boston.frame['MEDV']
# 转换为DataFrame
boston_df = pd.DataFrame(
data=boston.data,
columns=boston.feature_names # 13个特征(如CRIM=犯罪率,RM=平均房间数)
)
boston_df['price'] = boston.target # 目标变量:房屋中位数价格(千美元)
# 2. 探索数据(检查缺失值、特征分布)
print("数据集形状(样本数×特征数):", boston_df.shape)
print("\n数据集前5行:")
print(boston_df.head())
print("\n数据描述性统计:")
print(boston_df.describe().round(2))
# 3. 检查缺失值(随机森林对缺失值不敏感,但此处数据无缺失)
print("\n各列缺失值数量:")
print(boston_df.isnull().sum())
# 4. 可视化房价分布(目标变量分布)
plt.figure(figsize=(8, 5))
sns.histplot(boston_df['price'], bins=30, kde=True, color='skyblue')
plt.xlabel('房屋中位数价格(千美元)')
plt.ylabel('样本数量')
plt.title('波士顿房价分布')
plt.show()
# 5. 特征标准化(回归任务中,特征量纲差异可能影响结果,建议标准化)
scaler = StandardScaler()
# 对特征进行标准化(目标变量无需标准化)
X_scaled = scaler.fit_transform(boston.data)
y = boston.target
步骤 2:数据划分与模型训练
# 1. 划分训练集(80%)和测试集(20%)
X_train, X_test, y_train, y_test = train_test_split(
X_scaled, y, test_size=0.2, random_state=42
)
print(f"\n训练集大小:{X_train.shape},测试集大小:{X_test.shape}")
# 2. 初始化随机森林回归器
# n_estimators:决策树数量
# max_depth:每棵树最大深度(设为10,避免过拟合)
# min_samples_split:节点分裂所需最小样本数(避免过拟合)
rf_reg = RandomForestRegressor(
n_estimators=100,
max_depth=10,
min_samples_split=5,
random_state=42,
n_jobs=-1
)
# 3. 训练模型
rf_reg.fit(X_train, y_train)
print("\n随机森林回归器训练完成!")
# 4. 交叉验证(评估模型稳定性,避免单次划分的偶然性)
cv_scores = cross_val_score(rf_reg, X_scaled, y, cv=5, scoring='r2') # 5折交叉验证,用R²评分
print(f"\n5折交叉验证 R² 得分:{cv_scores.round(4)}")
print(f"交叉验证平均 R² 得分:{cv_scores.mean():.4f}(越接近1越好)")
步骤 3:模型预测与评估
# 1. 测试集预测
y_pred = rf_reg.predict(X_test)
# 2. 回归任务评估指标(核心指标:MSE、R²)
# MSE(均方误差):衡量预测值与真实值的平均平方差(越小越好)
mse = mean_squared_error(y_test, y_pred)
# RMSE(均方根误差):MSE的平方根(单位与目标变量一致,更易理解)
rmse = np.sqrt(mse)
# R²(决定系数):衡量模型解释方差的比例(0~1,越接近1说明模型拟合越好)
r2 = r2_score(y_test, y_pred)
print("\n测试集评估结果:")
print(f"均方误差(MSE):{mse:.4f}")
print(f"均方根误差(RMSE):{rmse:.4f}(千美元)")
print(f"决定系数(R²):{r2:.4f}")
# 3. 可视化预测值与真实值的对比(散点图)
plt.figure(figsize=(8, 6))
plt.scatter(y_test, y_pred, alpha=0.6, color='coral') # alpha:透明度,避免点重叠
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--') # 对角线:完美预测线
plt.xlabel('真实房价(千美元)')
plt.ylabel('预测房价(千美元)')
plt.title('波士顿房价:真实值 vs 预测值')
plt.legend(['完美预测线', '预测值'])
plt.show()
# 4. 可视化残差(真实值-预测值)分布(残差应接近正态分布,说明模型无系统偏差)
residuals = y_test - y_pred
plt.figure(figsize=(8, 6))
sns.histplot(residuals, bins=20, kde=True, color='lightgreen')
plt.xlabel('残差(真实值 - 预测值)')
plt.ylabel('频次')
plt.title('波士顿房价预测:残差分布')
plt.axvline(x=0, color='red', linestyle='--') # 残差=0线
plt.show()
步骤 4:特征重要性分析
# 1. 提取特征重要性
feature_importance = pd.DataFrame({
'特征名称': boston.feature_names,
'重要性': rf_reg.feature_importances_
}).sort_values('重要性', ascending=False)
print("\n特征重要性排序:")
print(feature_importance)
# 2. 可视化特征重要性
plt.figure(figsize=(12, 7))
sns.barplot(
x='重要性',
y='特征名称',
data=feature_importance,
palette='plasma'
)
plt.xlabel('重要性得分')
plt.ylabel('特征名称')
plt.title('波士顿房价预测:随机森林特征重要性')
plt.show()
4.3 案例结果解读
- 模型性能:测试集 R² 达 0.87(87%),说明模型能解释 87% 的房价方差;RMSE 约 3.3 千美元,预测误差较小;
- 特征重要性:平均房间数(RM,重要性≈0.4)和低收入人口比例(LSTAT,重要性≈0.3)是影响房价的关键因素 —— 房间越多、低收入人口越少,房价越高,符合现实逻辑;
- 残差分布:残差接近正态分布且围绕 0 对称,说明模型无系统偏差,预测结果可靠。
五、随机森林超参数调优(进阶)
随机森林的性能受超参数影响较大,常用超参数及调优方法如下:
5.1 核心超参数说明
| 超参数 | 作用 | 推荐取值范围 |
|---|---|---|
n_estimators |
决策树数量 | 100~200(过少易欠拟合,过多增加计算量) |
max_depth |
每棵树最大深度 | None~30(None 表示不限制,过深易过拟合) |
min_samples_split |
节点分裂所需最小样本数 | 2~20(过小易过拟合) |
min_samples_leaf |
叶子节点最小样本数 | 1~10(过小易过拟合) |
max_features |
每棵树可选特征数 | sqrt(默认,分类任务)、log2(回归任务) |
5.2 超参数调优代码(网格搜索)
from sklearn.model_selection import GridSearchCV
# 1. 定义超参数网格
param_grid = {
'n_estimators': [100, 150, 200],
'max_depth': [8, 10, 12],
'min_samples_split': [3, 5, 7],
'max_features': ['sqrt', 'log2']
}
# 2. 初始化网格搜索(用随机森林回归器为例)
grid_search = GridSearchCV(
estimator=RandomForestRegressor(random_state=42, n_jobs=-1),
param_grid=param_grid,
cv=5, # 5折交叉验证
scoring='r2', # 用R²评分
verbose=1 # 显示调优过程
)
# 3. 执行网格搜索
grid_search.fit(X_train, y_train)
# 4. 输出最优超参数和得分
print(f"\n最优超参数组合:{grid_search.best_params_}")
print(f"最优交叉验证 R² 得分:{grid_search.best_score_:.4f}")
# 5. 用最优模型预测
best_rf = grid_search.best_estimator_
y_pred_best = best_rf.predict(X_test)
print(f"最优模型测试集 R² 得分:{r2_score(y_test, y_pred_best):.4f}")
六、总结与应用场景
6.1 随机森林的适用场景
- 分类任务:图像识别、客户流失预测、疾病诊断、风险评估;
- 回归任务:房价预测、销量预测、股票价格预测、能耗预测;
- 特征工程:特征重要性分析(如用户行为分析中识别关键行为)。
6.2 注意事项
- 计算成本:树数量过多或深度过深会增加训练时间,可通过
n_jobs=-1利用多核 CPU 加速; - 过拟合处理:若模型过拟合,可减小
max_depth、增大min_samples_split; - 类别不平衡:分类任务中若类别不平衡,可通过
class_weight参数调整类别权重。
通过本文的原理讲解和两个完整案例,你已掌握随机森林的核心逻辑与 Python 实现。实际应用中,只需根据任务类型(分类 / 回归)调整模型参数和评估指标,即可快速落地到业务场景中。
更多推荐
所有评论(0)