
随机森林是一种非常强大的机器学习算法,它属于集成学习中的Bagging方法。随机森林的基本单元是决策树,而森林就是由很多棵决策树组成的。简单的说随机森林就是由多个决策树组成的森林,每棵树都是一个独立的预测模型。通过集体投票或平均意见来做出最终决策,这样比单棵决策树更准确、更稳定。
随机森林的核心思想是:通过构建多个决策树,并将它们的预测结果结合起来,从而获得比单个决策树更准确、更稳定的预测。
随机森林的重要性:
决策树是随机森林的基本单元,前期文章《决策树的核心机制(一):刨根问底鸢尾花分类中的参数推理计算》,我们详细探讨了决策树的细节内容,如不清楚建议先了解,简单来说决策树是一种模拟人类决策过程的模型,它通过一系列的问题对数据进行分割,直到得到最终的决策。例如,我们定是否外出,我们会先看看天气如何:如果是晴天,在看看看气温,如果温度大于25°C ,那么我们考虑去游泳,如果温度不到25°C,那么我们可能考虑去爬山,如果天气是下雨的,那么我们就选择不出门,在家看书。
决策树就像我们做决策时的思考过程。比如决定是否外出:
今天天气如何? ├── 晴天 → 温度如何? │ ├── 温度 > 25°C → 去游泳 │ └── 温度 ≤ 25°C → 去爬山 └── 下雨 → 在家看书
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.tree import DecisionTreeClassifier, plot_tree
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建示例数据
X, y = make_classification(n_samples=100, n_features=2, n_redundant=0,
n_informative=2, n_clusters_per_class=1, random_state=42)
# 训练决策树
tree = DecisionTreeClassifier(max_depth=3, random_state=42)
tree.fit(X, y)
# 可视化决策树
plt.figure(figsize=(12, 8))
plot_tree(tree, filled=True, feature_names=['特征1', '特征2'],
class_names=['类别0', '类别1'])
plt.title('决策树结构')
plt.show()代码详解:
输出结果:

决策树通过递归分割数据来学习,其生成过程包括特征选择、树的构建和剪枝。在特征选择中,关键问题是:如何选择最佳分割点?通常使用信息增益、基尼指数等指标,其目标是选择能让数据变得"最纯净"的分割方式。
from collections import Counter
import math
import numpy as np
def calculate_entropy(labels):
"""计算信息熵"""
counter = Counter(labels)
total = len(labels)
entropy = 0.0
for count in counter.values():
probability = count / total
entropy -= probability * math.log2(probability)
return entropy
def calculate_information_gain(data, labels, feature_index, threshold):
"""计算信息增益"""
# 保证 labels 为 numpy 数组,便于布尔索引
labels_np = np.asarray(labels)
# 分割数据
left_mask = data[:, feature_index] <= threshold
right_mask = ~left_mask
left_labels = labels_np[left_mask]
right_labels = labels_np[right_mask]
# 计算父节点熵
parent_entropy = calculate_entropy(labels_np)
# 计算子节点加权平均熵
n_left, n_right, n_total = len(left_labels), len(right_labels), len(labels_np)
children_entropy = (n_left / n_total) * calculate_entropy(left_labels) + \
(n_right / n_total) * calculate_entropy(right_labels)
# 信息增益 = 父节点熵 - 子节点加权平均熵
return parent_entropy - children_entropy
# 示例:计算不同分割点的信息增益
print("信息熵计算示例:")
sample_labels = [0, 0, 0, 1, 1, 1]
print(f"样本标签: {sample_labels}")
print(f"信息熵: {calculate_entropy(sample_labels):.4f}")
# 测试不同分割
test_data = np.array([[1], [2], [3], [4], [5], [6]])
test_labels = [0, 0, 0, 1, 1, 1]
for threshold in [2.5, 3.5, 4.5]:
gain = calculate_information_gain(test_data, test_labels, 0, threshold)
print(f"阈值 {threshold} 的信息增益: {gain:.4f}")推理过程:
输出结果:
信息熵计算示例: 样本标签: [0, 0, 0, 1, 1, 1] 信息熵: 1.0000 阈值 2.5 的信息增益: 0.4591 阈值 3.5 的信息增益: 1.0000 阈值 4.5 的信息增益: 0.4591
决策树涉及的相关概念参考:
集成学习的核心思想在于群体智慧,其“从一棵树到一片森林”的构建范式,形象地揭示了这一理念:通过构建大量存在差异的决策树,形成一个规模庞大的模型集合(森林)。在预测时,这片“森林”并非依赖其中任何单一树木的判断,而是通过集体投票或平均来做出最终决策,从而有效规避单棵树的个体偏见与不稳定性,汇聚为更强大、更稳健的预测能力。
集成学习通过组合多个学习器来获得比单一学习器更好的性能。随机森林属于集成学习中的Bagging方法。
Bagging的基本思想是:
随机森林在Bagging的基础上又进了一步:不仅在数据上进行随机抽样,而且在训练每棵树时,对特征也进行随机选择。这样进一步增加了树的多样性,从而提升模型的泛化能力。详细内容可参考《集成学习:从三个臭皮匠到AI集体智慧的深度解析》。
随机森林通过两个随机性来增强多样性:
1.1 Bootstrap采样:每棵树用不同的训练子集
Bootstrap采样是一种统计学方法,它的核心思想是“以小见大,通过模拟逼近真实”,即在只有一份样本的情况下,通过对原始数据集进行有放回的随机抽样,这个过程重复多次,从而得到多个Bootstrap样本。然后,我们可以基于这些Bootstrap样本估计统计量(如均值、方差、中位数等)的抽样分布。这种方法特别适用于小样本数据集,能够有效估计统计量的分布和不确定性。
Bootstrap采样的步骤:
每个Bootstrap样本与原始数据集的大小相同,但由于是有放回抽样,每个Bootstrap样本中有些样本会出现多次,而有些样本则不会出现。
1.2 特征随机选择:每棵树分裂时只考虑部分特征
特征随机选择是指在模型训练过程中,随机地选取一部分特征来进行学习,而不是每次都使用全部的特征。在模型训练的每个步骤中,随机限制可用的特征,迫使模型学习更鲁棒、更多样的规则。
目标:通过降低模型间的相关性来减少方差,防止过拟合。
核心思想与作用:
在随机森林中的工作流程:
特征随机的优势:
集成的“群体智慧”要发挥作用,其基础是个体模型必须具备多样性。如果所有模型都一样,那集成毫无意义。特征随机选择正是为了刻意地创造模型之间的多样性,多样性决定集成效果。

随机森林的构建过程:
import numpy as np
def bootstrap_sampling(data, labels, n_trees=3):
"""Bootstrap采样实现"""
n_samples = len(data)
bootstrap_datasets = []
for i in range(n_trees):
# 有放回随机采样
indices = np.random.choice(n_samples, n_samples, replace=True)
bootstrap_data = data[indices]
bootstrap_labels = labels[indices]
bootstrap_datasets.append((bootstrap_data, bootstrap_labels))
print(f"树{i+1}的采样结果:")
print(f" 采样索引: {indices}")
print(f" 唯一样本数: {len(np.unique(indices))}/{n_samples}")
print()
return bootstrap_datasets
# 示例数据
simple_data = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
simple_labels = np.array([0, 1, 0, 1])
bootstrap_datasets = bootstrap_sampling(simple_data, simple_labels)输出结果:
树1的采样结果: 采样索引: [0 1 1 3] 唯一样本数: 3/4 树2的采样结果: 采样索引: [3 2 0 1] 唯一样本数: 4/4 树3的采样结果: 采样索引: [2 3 3 0] 唯一样本数: 3/4
关键概念:有放回抽样
采样过程分析:
import numpy as np
def feature_sampling(features, max_features='sqrt'):
"""特征随机选择"""
n_features = len(features)
if max_features == 'sqrt':
n_select = int(np.sqrt(n_features))
elif max_features == 'log2':
n_select = int(np.log2(n_features))
else:
n_select = max_features
selected_indices = np.random.choice(n_features, n_select, replace=False)
selected_features = [features[i] for i in selected_indices]
return selected_indices, selected_features
# 示例
features = ['年龄', '工资', '学历', '工作经验', '城市', '性别', '婚姻状况']
print("所有特征:", features)
selected_indices, selected_features = feature_sampling(features, 'sqrt')
print(f"随机选择的特征索引: {selected_indices}")
print(f"随机选择的特征: {selected_features}")输出结果:
所有特征: ['年龄', '工资', '学历', '工作经验', '城市', '性别', '婚姻状况'] 随机选择的特征索引: [2 5] 随机选择的特征: ['学历', '性别']
特征选择策略:
超参数是机器学习模型在训练开始前需要设定的配置参数,它们不是从数据中学习得到的,而是用来控制学习过程的指导参数,通俗的理解,想象一下,我们在骑自行车时,需要先进行一些调整,比如座椅高度、把手位置和轮胎气压。这些设置不是我们在骑行过程中自动学会的,而是我们在开始前手动调整的。超参数就像这些设置,它们是机器学习模型在训练开始前,由我们人工设定的参数,用来控制模型如何学习。
建议看本小节务必先了解超参数基本原理:《超参数如何影响大模型?通俗讲解原理、作用与实战示例》
随机森林有一些重要的超参数,例如:
调整这些超参数可以优化模型性能。
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.metrics import classification_report, confusion_matrix
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
# 加载乳腺癌数据集
data = load_breast_cancer()
X, y = data.data, data.target
feature_names = data.feature_names
print("数据集信息:")
print(f"特征数量: {X.shape[1]}")
print(f"样本数量: {X.shape[0]}")
print(f"类别分布: {np.bincount(y)}")
# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 创建随机森林
rf = RandomForestClassifier(
n_estimators=100, # 树的数量
max_depth=10, # 最大深度
min_samples_split=2, # 内部节点再划分所需最小样本数
min_samples_leaf=1, # 叶节点最少样本数
max_features='sqrt', # 特征选择方式
random_state=42,
n_jobs=-1 # 使用所有CPU核心
)
# 训练模型
rf.fit(X_train, y_train)
# 预测
y_pred = rf.predict(X_test)
y_pred_proba = rf.predict_proba(X_test)
# 评估模型
print("\n=== 模型评估 ===")
print(f"训练集准确率: {rf.score(X_train, y_train):.4f}")
print(f"测试集准确率: {rf.score(X_test, y_test):.4f}")
# 交叉验证
cv_scores = cross_val_score(rf, X, y, cv=5)
print(f"交叉验证准确率: {cv_scores.mean():.4f} (±{cv_scores.std() * 2:.4f})")
# 详细分类报告
print("\n分类报告:")
print(classification_report(y_test, y_pred, target_names=data.target_names))
# 混淆矩阵
plt.figure(figsize=(8, 6))
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=data.target_names,
yticklabels=data.target_names)
plt.title('混淆矩阵')
plt.xlabel('预测标签')
plt.ylabel('真实标签')
plt.show()
# 定义参数网格
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [5, 10, 15, None],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 4],
'max_features': ['sqrt', 'log2']
}
# 网格搜索
grid_search = GridSearchCV(
RandomForestClassifier(random_state=42),
param_grid,
cv=5,
scoring='accuracy',
n_jobs=-1,
verbose=1
)
# 简化版参数调优
simple_param_grid = {
'n_estimators': [50, 100],
'max_depth': [5, 10]
}
simple_search = GridSearchCV(
RandomForestClassifier(random_state=42),
simple_param_grid,
cv=3,
scoring='accuracy',
n_jobs=-1
)
simple_search.fit(X_train, y_train)
print("简化调优最佳参数:", simple_search.best_params_)
print("简化调优最佳分数:", simple_search.best_score_)2.1 参数调优的核心:GridSearchCV
网格搜索是一种穷举式的参数调优方法:
代码中的参数网格:
simple_param_grid = {
'n_estimators': [50, 100], # 树的数量
'max_depth': [5, 10], # 树的最大深度
}参数的意义:
数据集信息: 特征数量: 30 样本数量: 569 类别分布: [212 357] === 模型评估 === 训练集准确率: 1.0000 测试集准确率: 0.9708 交叉验证准确率: 0.9561 (±0.0457) 分类报告: precision recall f1-score support malignant 0.98 0.94 0.96 63 benign 0.96 0.99 0.98 108 accuracy 0.97 171 macro avg 0.97 0.96 0.97 171 weighted avg 0.97 0.97 0.97 171 简化调优最佳参数: {'max_depth': 10, 'n_estimators': 50} 简化调优最佳分数: 0.9622920938710413

分类报告: precision recall f1-score support malignant 0.98 0.94 0.96 63 benign 0.96 0.99 0.98 108 accuracy 0.97 171 macro avg 0.97 0.96 0.97 171 weighted avg 0.97 0.97 0.97 171 简化调优最佳参数: {'max_depth': 10, 'n_estimators': 50} 简化调优最佳分数: 0.9622920938710413
这表示:
数据集信息:
核心指标详解:
Precision(精确率/查准率)
Recall(召回率/查全率)
F1-Score(F1分数)
混淆矩阵推理:
根据这些指标,我们可以推断出混淆矩阵:

计算验证:
平均值说明:
macro avg(宏平均)
weighted avg(加权平均)
随机森林是一种强大的集成学习算法,其核心思想是通过构建众多决策树,并以集体投票或平均的方式作出最终预测,从而显著提升模型的泛化能力和鲁棒性。
该算法的成功关键在于引入两大随机性:在数据层面使用Bootstrap采样为每棵树构建略有差异的训练集,同时在特征层面进行随机选择,这种机制确保了树与树之间的差异性,有效避免了过拟合。
与许多复杂模型相比,随机森林具有显著的工程化优势,它无需复杂的特征进行归一化缩放,能原生处理混合数据类型,并且其训练过程高度并行化。这些特性使其在工业界的大规模数据场景下,成为一个非常可靠、易于部署和维护的基石模型。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。