本文目录导读:

在Python中实现决策树剪枝主要通过两种方式:预剪枝和后剪枝,我详细介绍一下这两种方法在scikit-learn中的实现。
预剪枝(Pre-pruning)
在决策树生长过程中提前停止分裂,最常用的方法:
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
# 加载数据
iris = load_iris()
X, y = iris.data, iris.target
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
# 对比不同剪枝参数的效果
param_comparison = {
'max_depth': [3, 5, 10, None], # 最大深度
'min_samples_split': [2, 5, 10, 20], # 内部节点最小样本数
'min_samples_leaf': [1, 2, 5, 10], # 叶节点最小样本数
'max_leaf_nodes': [3, 5, 10, None] # 最大叶节点数
}
# 示例:使用max_depth进行预剪枝
for max_depth in [3, 5, 10, None]:
dt = DecisionTreeClassifier(
max_depth=max_depth,
random_state=42
)
dt.fit(X_train, y_train)
train_score = dt.score(X_train, y_train)
test_score = dt.score(X_test, y_test)
print(f"max_depth={max_depth}: 训练集准确率={train_score:.3f}, 测试集准确率={test_score:.3f}")
后剪枝(Post-pruning)
使用代价复杂度剪枝(Cost Complexity Pruning, CCP),这是最常用的后剪枝方法:
from sklearn.tree import DecisionTreeClassifier
import numpy as np
def cost_complexity_pruning_example(X_train, X_test, y_train, y_test):
"""代价复杂度剪枝示例"""
# 1. 训练一个完整(未剪枝)的决策树
clf = DecisionTreeClassifier(random_state=42)
# 2. 计算剪枝路径
path = clf.cost_complexity_pruning_path(X_train, y_train)
ccp_alphas = path.ccp_alphas # 获取不同的alpha值
impurities = path.impurities # 对应的不纯度
print(f"共有 {len(ccp_alphas)} 个不同的alpha值")
print(f"alpha范围: {min(ccp_alphas):.4f} 到 {max(ccp_alphas):.4f}")
# 3. 训练不同alpha值下的决策树
clfs = []
for ccp_alpha in ccp_alphas:
clf = DecisionTreeClassifier(random_state=42, ccp_alpha=ccp_alpha)
clf.fit(X_train, y_train)
clfs.append(clf)
# 4. 计算训练集和测试集准确率
train_scores = [clf.score(X_train, y_train) for clf in clfs]
test_scores = [clf.score(X_test, y_test) for clf in clfs]
# 5. 找出最佳alpha值(测试集准确率最高时)
best_index = np.argmax(test_scores)
best_alpha = ccp_alphas[best_index]
best_clf = clfs[best_index]
print(f"\n最佳alpha值: {best_alpha:.4f}")
print(f"最终树的大小: {best_clf.tree_.node_count} 个节点")
print(f"测试集准确率: {test_scores[best_index]:.3f}")
return best_clf, ccp_alphas, test_scores, train_scores
# 使用示例
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
best_tree, alphas, test_scores, train_scores = cost_complexity_pruning_example(
X_train, X_test, y_train, y_test
)
# 可视化剪枝效果
def plot_pruning_effect(alphas, train_scores, test_scores):
"""可视化不同alpha值下的模型性能"""
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(alphas, train_scores, marker='o', label='训练集', drawstyle="steps-post")
ax.plot(alphas, test_scores, marker='*', label='测试集', drawstyle="steps-post")
ax.set_xlabel('alpha')
ax.set_ylabel('准确率')
ax.set_title('代价复杂度剪枝效果')
ax.legend()
ax.grid(True)
# 标记最佳alpha值
best_idx = np.argmax(test_scores)
ax.axvline(x=alphas[best_idx], color='r', linestyle='--', alpha=0.7)
plt.show()
# plot_pruning_effect(alphas, train_scores, test_scores)
交叉验证选择最佳剪枝参数
使用GridSearchCV自动寻找最佳参数:
from sklearn.model_selection import GridSearchCV
def find_best_pruning_params(X_train, y_train, cv=5):
"""使用网格搜索寻找最佳剪枝参数"""
# 定义参数网格
param_grid = {
'max_depth': [3, 5, 7, 9, None],
'min_samples_split': [2, 5, 10, 20],
'min_samples_leaf': [1, 2, 5, 10],
'max_leaf_nodes': [None, 5, 10, 20],
'ccp_alpha': [0.0, 0.001, 0.005, 0.01, 0.02, 0.05, 0.1]
}
# 创建决策树基础模型
base_clf = DecisionTreeClassifier(random_state=42)
# 网格搜索
grid_search = GridSearchCV(
base_clf,
param_grid,
cv=cv,
scoring='accuracy',
n_jobs=-1,
verbose=1
)
grid_search.fit(X_train, y_train)
print("最佳参数组合:")
print(grid_search.best_params_)
print(f"最佳交叉验证得分: {grid_search.best_score_:.3f}")
return grid_search.best_estimator_
# 使用示例
best_model = find_best_pruning_params(X_train, y_train)
实战:完整的剪枝流程
from sklearn.tree import DecisionTreeClassifier, plot_tree
from sklearn.metrics import classification_report, confusion_matrix
import pandas as pd
class PrunedDecisionTreeDemo:
"""决策树剪枝完整演示"""
def __init__(self, X_train, X_test, y_train, y_test):
self.X_train = X_train
self.X_test = X_test
self.y_train = y_train
self.y_test = y_test
def no_pruning(self):
"""无剪枝的决策树"""
clf = DecisionTreeClassifier(random_state=42)
clf.fit(self.X_train, self.y_train)
return clf
def pre_pruning(self, max_depth=5, min_samples_split=10, min_samples_leaf=5):
"""预剪枝"""
clf = DecisionTreeClassifier(
max_depth=max_depth,
min_samples_split=min_samples_split,
min_samples_leaf=min_samples_leaf,
random_state=42
)
clf.fit(self.X_train, self.y_train)
return clf
def post_pruning(self):
"""代价复杂度后剪枝"""
# 先训练完整树
clf = DecisionTreeClassifier(random_state=42)
path = clf.cost_complexity_pruning_path(self.X_train, self.y_train)
# 使用交叉验证选择最佳alpha
from sklearn.model_selection import cross_val_score
best_score = 0
best_alpha = 0
best_clf = None
# 只测试部分alpha值以节省时间
alphas_to_test = path.ccp_alphas[::len(path.ccp_alphas)//20 + 1]
for alpha in alphas_to_test:
clf = DecisionTreeClassifier(random_state=42, ccp_alpha=alpha)
scores = cross_val_score(clf, self.X_train, self.y_train, cv=5)
mean_score = scores.mean()
if mean_score > best_score:
best_score = mean_score
best_alpha = alpha
# 使用最佳alpha训练最终模型
final_clf = DecisionTreeClassifier(random_state=42, ccp_alpha=best_alpha)
final_clf.fit(self.X_train, self.y_train)
print(f"最佳alpha值: {best_alpha:.4f}")
print(f"交叉验证得分: {best_score:.3f}")
return final_clf
def compare_models(self):
"""比较不同剪枝策略"""
models = {
'无剪枝': self.no_pruning(),
'预剪枝': self.pre_pruning(),
'后剪枝': self.post_pruning()
}
results = []
for name, model in models.items():
train_score = model.score(self.X_train, self.y_train)
test_score = model.score(self.X_test, self.y_test)
tree_size = model.tree_.node_count
results.append({
'剪枝策略': name,
'训练集准确率': f"{train_score:.3f}",
'测试集准确率': f"{test_score:.3f}",
'树节点数': tree_size
})
return pd.DataFrame(results)
# 使用示例
demo = PrunedDecisionTreeDemo(X_train, X_test, y_train, y_test)
results_df = demo.compare_models()
print("\n剪枝策略对比:")
print(results_df)
关键总结
预剪枝参数对比
| 参数 | 作用 | 常用范围 | 效果 |
|---|---|---|---|
max_depth |
限制树的最大深度 | 3-10 | 最常用的剪枝参数 |
min_samples_split |
内部节点的最小样本数 | 10-100 | 防止过细划分 |
min_samples_leaf |
叶节点的最小样本数 | 5-50 | 确保叶节点统计意义 |
max_leaf_nodes |
最大叶节点数 | 10-100 | 控制模型复杂度 |
后剪枝(CCP)优势
- α值越小,树越大,越容易过拟合
- α值越大,树越小,可能欠拟合
- 通过交叉验证选择最佳α值
剪枝建议
- 优先使用预剪枝:计算效率高,适合大多数场景
- 必要时使用后剪枝:当预剪枝效果不佳时
- 组合使用:先做预剪枝控制大概范围,再用CCP精细调整
- 交叉验证:总是使用交叉验证选择参数
选择哪种剪枝方法取决于你的具体需求:如果追求模型解释性,可以稍大一些的树;如果追求泛化性能,需要更积极的剪枝。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播