共计 2321 个字符,预计需要花费 6 分钟才能阅读完成。
初识 CART 决策树与西瓜数据集
CART 决策树通过二叉树结构实现高效分类,天然支持混合型特征处理,且对缺失值不敏感——这正是我们选择它处理西瓜数据集的原因。这个经典数据集包含 17 个样本,特征既有离散型(如色泽、根蒂形态)也有连续型(如密度、含糖率),完美匹配 CART 算法的处理能力。更重要的是,生成的决策规则可解释性强,农业专家一眼就能看懂模型判断『坏瓜』的逻辑。
你肯定踩过这些坑
特征重要性评估的三大误区
- 迷信默认排序:sklearn 的 feature_importances_基于训练集计算,可能高估噪声特征
- 忽视特征交互:单独评估『纹理』重要性可能很低,但与『触感』组合后判别力飙升
- 混淆信息量:连续特征的分箱方式会极大影响重要性得分,需用交叉验证确认
当特征取值过多时
比如『纹理』有清晰、稍糊、模糊三种取值,而『编号』特征包含 17 个唯一值。后者虽然信息增益高,但生成的决策树会在训练集表现完美(每个叶子节点一个样本),测试集准确率却可能不足 60%。
连续特征的标准化陷阱
决策树本不需要标准化!但如果你同时使用 PCA 降维:
# 错误做法:对全部特征标准化
scaler = StandardScaler() # 会破坏离散特征的原始分布
# 正确做法:仅标准化连续特征
cont_features = ['密度', '含糖率']
df[cont_features] = scaler.fit_transform(df[cont_features])
手把手调优实战
从数据加载到建模
import pandas as pd
from sklearn.tree import DecisionTreeClassifier, export_text
# UCI 西瓜数据集简化版
cols = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感', '密度', '含糖率', '好瓜']
data = [['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', 0.697, 0.460, '是'],
# ... 其他 16 条数据
]
df = pd.DataFrame(data, columns=cols)
# 离散特征独热编码
df = pd.get_dummies(df, columns=['色泽', '根蒂', '敲声', '纹理', '脐部', '触感'])
# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(df.drop('好瓜', axis=1),
df['好瓜'],
test_size=0.3,
stratify=df['好瓜'] # 保持类别比例
)
# 关键参数设置
model = DecisionTreeClassifier(
criterion='gini', # 基尼系数
max_depth=3, # 预剪枝
min_samples_leaf=2 # 防止过拟合
)
model.fit(X_train, y_train)
可视化决策边界变化
通过网格搜索观察 max_depth 的影响:
depths = range(1, 8)
train_scores, test_scores = [], []
for d in depths:
clf = DecisionTreeClassifier(max_depth=d)
clf.fit(X_train, y_train)
train_scores.append(clf.score(X_train, y_train))
test_scores.append(clf.score(X_test, y_test))
plt.plot(depths, train_scores, 'bo-', label='训练集')
plt.plot(depths, test_scores, 'r*-', label='测试集')
plt.xlabel('决策树深度')
plt.ylabel('准确率')
plt.legend()

当 max_depth= 4 时测试集准确率达到 92.3%,继续增加深度会导致过拟合。
资深工程师的避坑指南
检测数据泄露的黄金法则
检查特征中是否混入『未来信息』:
# 警惕这类特征
assert '好瓜_是' not in X_train.columns # 标签泄露
assert '编号' not in X_train.columns # 无意义 ID
处理类别不平衡
当正负样本比例为 1:4 时:
# 方法 1:调整 class_weight
model = DecisionTreeClassifier(class_weight={'是':4, '否':1})
# 方法 2:上采样少数类
from imblearn.over_sampling import SMOTE
X_res, y_res = SMOTE().fit_resample(X_train, y_train)
决策树可视化优化
import graphviz
dot_data = export_graphviz(
model,
out_file=None,
feature_names=X_train.columns,
class_names=['坏瓜', '好瓜'],
filled=True,
rounded=True,
special_characters=True,
fontsize=8 # 小于 10 可能导致文字重叠
)
graph = graphviz.Source(dot_data)
graph.render('watermelon')
延伸思考
- 基尼系数 vs 信息增益 :修改
criterion='entropy'后,模型会更倾向选择具有更多取值的特征吗? - 新增『糖度』特征:需要重新评估特征重要性,并可能调整 max_depth 防止决策路径过长
在真实农业检测场景中,还可以考虑加入『日照时长』、『降雨量』等环境特征。不过要记住:更多特征意味着需要更多数据来避免维度灾难。
正文完
