尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

乳腺癌决策树分类实验包:数据选型、剪枝调参与避坑指南

乳腺癌决策树分类实验包:数据选型、剪枝调参与避坑指南 简介这份资源是面向机器学习初学者与医学数据分析爱好者的决策树分类实验包围绕wpbc乳腺癌数据集展开帮助读者理解如何用决策树完成良恶性肿瘤预测。包内共13个文件以data数据文件、names说明文件、png结果图、txt文本、csv表格和m脚本为主压缩包约572KB涵盖数据、代码与可视化结果便于对照复现。实验涉及缺失值处理、数据标准化、决策树构建与剪枝并通过准确率、召回率、F1分数等指标评估模型同时对比剪枝前后效果直观展示过拟合与欠拟合的平衡。已有1546人学习下载适合希望掌握决策树原理、特征划分策略与医疗分类实战的读者参考借鉴。1. 拆开这个乳腺癌决策树实验包它到底能跑出什么结果如果你手头正好有一个决策树分类实验乳腺癌.zip里面躺着wdbc.data、wpbc.data、breast-cancer-wisconsin.data三套数据外加main_2016a.m和几张剪枝前后对比图那这篇就是写给你的。它不是一份只讲“决策树是什么”的科普而是一份把包拆开、把数据喂进去、把树画出来、把剪枝前后差异量化出来的实操记录。核心解决三件事第一搞清楚 wdbc 和 wpbc 到底该用哪个第二用最短路径复现出准确率和混淆矩阵第三弄明白剪枝前后那两张图背后的参数到底动了什么。适合谁看手上有一份医学二分类数据、想用决策树跑通 baseline 的算法工程师正在做课程设计、需要交一份带剪枝对比实验报告的学生以及被“决策树如何逼近真实曲线”这类问题绕进去、想拿真实数据验证一遍的从业者。这个包的价值不在于算法多新而在于它把数据、脚本、结果图打包在一起省掉了你从 UCI 官网翻页面、对字段、补缺失值的半小时。下面按“数据怎么选 → 脚本怎么跑 → 剪枝怎么调 → 坑在哪 → 怎么验证”的顺序推下去。2. 数据选型与预处理wdbc、wpbc、breast-cancer-wisconsin 到底用哪个2.1 三套数据的字段差异与适用场景这个包里同时出现wdbc.data、wpbc.data和breast-cancer-wisconsin.data很多人第一反应是“随便挑一个能读的就行”结果跑出来的准确率忽高忽低还以为是决策树玄学。实际上这三套数据来自同一个 Wisconsin 乳腺细胞核数据库的不同版本字段结构和任务定义都不一样。文件样本数特征数任务类型标签含义wdbc.data56930二分类M恶性B良性wpbc.data19833二分类复发时间R复发N未复发breast-cancer-wisconsin.data6999二分类2良性4恶性wdbc.data是诊断型数据30 个特征全部是细胞核的形态学测量值半径、纹理、周长、面积、光滑度等没有缺失值标签干净最适合做决策树分类的入门实验。wpbc.data是预后型数据多了复发时间和淋巴结状态标签是“是否复发”样本只有 198 条且存在缺失值直接拿来跑分类容易过拟合。breast-cancer-wisconsin.data是原始版本只有 9 个特征且第 7 列存在 16 个?缺失标记需要额外清洗。我一般会这样选如果目标是复现“决策树分类程序”的标准流程用wdbc.data如果要做“wpbc数据集”相关的预后分析用wpbc.data但必须先处理缺失值breast-cancer-wisconsin.data更适合做缺失值填充的练习不适合直接对比剪枝效果。2.2 用 pandas 读入并做最小预处理决策树对量纲不敏感不需要标准化但缺失值和标签编码必须处理。下面这段代码把wdbc.data读进来完成标签映射和训练集划分。import pandas as pd from sklearn.model_selection import train_test_split # wdbc.data 没有表头第一列是 ID第二列是标签 columns [id, diagnosis] [ffeature_{i} for i in range(1, 31)] df pd.read_csv(wdbc.data, headerNone, namescolumns) # 标签映射M1恶性B0良性 df[diagnosis] df[diagnosis].map({M: 1, B: 0}) # 丢掉 ID 列它不参与建模 X df.drop(columns[id, diagnosis]) y df[diagnosis] # 固定随机种子保证每次划分一致 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) print(f训练集: {X_train.shape}, 测试集: {X_test.shape}) print(f恶性比例: {y.mean():.3f})逻辑说明stratifyy是关键参数它保证训练集和测试集里恶性/良性的比例与原始数据一致。乳腺癌数据里恶性样本约占 37%如果不分层某次随机划分可能让测试集里恶性样本只有 20%准确率会虚高。random_state42是为了让剪枝前后的对比实验在同一个数据划分上进行否则你无法判断准确率变化是剪枝带来的还是数据划分带来的。参数说明test_size0.3是常见起点569 条样本按 7:3 分测试集约 171 条足够计算召回率和 F1。如果要做交叉验证可以把train_test_split换成StratifiedKFold(n_splits5)但剪枝对比实验用固定划分更直观。2.3 缺失值处理wpbc 和 breast-cancer-wisconsin 的差异wpbc.data的缺失值用?标记breast-cancer-wisconsin.data同样。直接pd.read_csv会把?读成字符串导致整列变成 object 类型后面fit会报错。常见做法是先把?替换成np.nan再用中位数填充。import numpy as np # 以 breast-cancer-wisconsin.data 为例 df_raw pd.read_csv(breast-cancer-wisconsin.data, headerNone) df_raw.replace(?, np.nan, inplaceTrue) # 第 7 列索引 6是唯一有缺失的列用中位数填充 df_raw[6] pd.to_numeric(df_raw[6], errorscoerce) df_raw[6].fillna(df_raw[6].median(), inplaceTrue) # 标签映射2良性(0)4恶性(1) df_raw[10] df_raw[10].map({2: 0, 4: 1})这里有个容易翻车的点pd.to_numeric的errorscoerce会把无法转换的值变成 NaN如果你不先替换?这一步会直接把整列变成 NaN。填充策略用中位数而不是均值是因为细胞核测量值存在偏态分布均值容易被极端值拉偏。3. 决策树建模与剪枝从 main_2016a.m 到 sklearn 的等价实现3.1 决策树的核心参数criterion、max_depth、min_samples_split包里main_2016a.m是 MATLAB 脚本核心逻辑是构建 CART 树并做后剪枝。用 Python 复现时sklearn.tree.DecisionTreeClassifier对应的是 CART 的优化版本但参数含义需要对齐。MATLAB 参数sklearn 参数作用MinParentmin_samples_split内部节点再划分所需最小样本数MinLeafmin_samples_leaf叶节点最少样本数MaxDepthmax_depth树的最大深度Pruneccp_alpha代价复杂度剪枝参数criterion选gini还是entropy在乳腺癌数据上差异通常小于 1%。gini计算更快是默认选择。真正影响过拟合的是max_depth和min_samples_leaf。from sklearn.tree import DecisionTreeClassifier from sklearn.metrics import accuracy_score, classification_report # 不剪枝的完整树 clf_full DecisionTreeClassifier( criteriongini, random_state42 ) clf_full.fit(X_train, y_train) y_pred_full clf_full.predict(X_test) print(f完整树深度: {clf_full.get_depth()}) print(f完整树叶节点数: {clf_full.get_n_leaves()}) print(f完整树准确率: {accuracy_score(y_test, y_pred_full):.4f}) print(classification_report(y_test, y_pred_full, target_names[良性, 恶性]))逻辑说明不设max_depth时决策树会一直分裂到叶节点纯净或样本数小于min_samples_split默认 2。在 569 条样本、30 个特征的数据上完整树深度通常能到 8 到 12 层训练集准确率接近 100%但测试集准确率会掉到 90% 到 93% 之间。这就是剪枝前后对比图里“剪枝前”那一侧的典型表现。参数说明random_state42控制特征分裂时的随机性。当多个特征的分裂增益相同时sklearn 会随机选一个固定种子保证结果可复现。classification_report输出的support列告诉你测试集里良性、恶性各多少条方便判断召回率是否可信。3.2 预剪枝用 max_depth 和 min_samples_leaf 控制复杂度预剪枝是在树生长过程中就限制条件优点是计算快缺点是可能错过“先分裂再合并”的更优结构。在乳腺癌数据上我一般先扫一遍max_depth从 2 到 10 的测试集准确率找到拐点。import matplotlib.pyplot as plt depths range(2, 11) train_scores, test_scores [], [] for d in depths: clf DecisionTreeClassifier(max_depthd, random_state42) clf.fit(X_train, y_train) train_scores.append(clf.score(X_train, y_train)) test_scores.append(clf.score(X_test, y_test)) for d, tr, te in zip(depths, train_scores, test_scores): print(f深度{d}: 训练集{tr:.4f}, 测试集{te:.4f})跑完你会看到深度 2 到 4 时训练集和测试集准确率都在上升深度 5 到 6 时测试集达到峰值通常在 0.94 到 0.96 之间深度超过 7 后训练集继续上升但测试集开始下降。这个拐点就是预剪枝的max_depth取值。min_samples_leaf可以配合使用设成 5 到 10 能防止叶节点只包含一两个样本的过拟合情况。3.3 后剪枝ccp_alpha 代价复杂度剪枝与剪枝前后对比图后剪枝是先让树长满再自底向上合并子树。sklearn 用cost_complexity_pruning_path给出不同ccp_alpha对应的不纯度下降值你从中选一个让测试集准确率最高的 alpha。path clf_full.cost_complexity_pruning_path(X_train, y_train) ccp_alphas path.ccp_alphas clfs [] for alpha in ccp_alphas: clf DecisionTreeClassifier(ccp_alphaalpha, random_state42) clf.fit(X_train, y_train) clfs.append(clf) # 找出测试集准确率最高的 alpha best_alpha, best_score None, 0 for clf, alpha in zip(clfs, ccp_alphas): score clf.score(X_test, y_test) if score best_score: best_score score best_alpha alpha print(f最佳 ccp_alpha: {best_alpha:.6f}) print(f对应测试集准确率: {best_score:.4f}) clf_pruned DecisionTreeClassifier(ccp_alphabest_alpha, random_state42) clf_pruned.fit(X_train, y_train) print(f剪枝后深度: {clf_pruned.get_depth()}) print(f剪枝后叶节点数: {clf_pruned.get_n_leaves()})逻辑说明cost_complexity_pruning_path返回的ccp_alphas是从小到大排列的alpha 越大剪得越狠。clfs列表里第一个是 alpha 接近 0 的完整树最后一个是只剩根节点的树。遍历找测试集最高分就是剪枝前后对比图里“剪枝后”那一侧的数据来源。参数说明ccp_alpha的取值不需要手动猜用路径自动生成。但要注意如果测试集太小最高分对应的 alpha 可能不稳定这时候应该用交叉验证选 alpha而不是单次划分。包里那两张决策树剪枝前后对比.png和决策树剪枝前后.png本质上就是完整树和剪枝树的深度、叶节点数、测试集准确率三个指标的对比。4. 避坑与排查跑这个实验包最容易翻车的五个地方4.1 现象准确率 100%但换一批数据就崩原因没有划分训练集和测试集或者用训练集评估模型。决策树在不限制深度时能完美记住训练集每个样本但这不是模型能力是过拟合。解决强制用train_test_split划分且stratifyy。评估只看测试集训练集准确率只用来判断是否过拟合。4.2 现象ValueError: could not convert string to float: ?原因wpbc.data或breast-cancer-wisconsin.data里的缺失值标记?没有被替换成np.nanpandas 把整列读成 object 类型。解决读入后立刻df.replace(?, np.nan, inplaceTrue)再用pd.to_numeric(..., errorscoerce)强制转换最后用中位数或均值填充。4.3 现象剪枝后准确率反而下降原因ccp_alpha选得太大把有用的分支也剪掉了。或者测试集划分不合理导致评估结果波动。解决不要直接取ccp_alphas的最大值而是遍历找测试集最高分。如果最高分对应的 alpha 仍然让准确率下降说明数据本身噪声大应该回到预剪枝用max_depth控制。4.4 现象wdbc.data读进来多了一列全是 NaN原因wdbc.data每行末尾可能有多余逗号或者列数对不上。用headerNone读入时pandas 按第一行列数推断如果某行列数不一致就会补 NaN。解决先pd.read_csv(wdbc.data, headerNone)看df.shape确认是 569 行 32 列ID 标签 30 特征。如果列数不对用df.dropna(axis1, howall)删掉全空列再手动指定列名。4.5 现象MATLAB 脚本main_2016a.m在 Python 里找不到对应函数原因MATLAB 的fitctree和 Python 的DecisionTreeClassifier参数命名不同且 MATLAB 默认做后剪枝Python 默认不剪枝。解决按第 3.1 节的参数对照表映射。MATLAB 的Prune设为on对应 Python 设置ccp_alpha 0。不要指望逐行翻译理解逻辑后重写更快。5. 验证与进阶用交叉验证和特征重要性把结论钉死单次划分的准确率有随机性要验证剪枝效果是否稳定用分层交叉验证跑 10 次看准确率的均值和标准差。下面这段代码同时输出特征重要性排序帮你判断哪些细胞核特征对恶性判断贡献最大。from sklearn.model_selection import cross_val_score, StratifiedKFold import numpy as np cv StratifiedKFold(n_splits10, shuffleTrue, random_state42) # 完整树 vs 剪枝树的交叉验证对比 scores_full cross_val_score( DecisionTreeClassifier(random_state42), X, y, cvcv, scoringaccuracy ) scores_pruned cross_val_score( DecisionTreeClassifier(ccp_alphabest_alpha, random_state42), X, y, cvcv, scoringaccuracy ) print(f完整树 CV 准确率: {scores_full.mean():.4f} ± {scores_full.std():.4f}) print(f剪枝树 CV 准确率: {scores_pruned.mean():.4f} ± {scores_pruned.std():.4f}) # 特征重要性 importances pd.Series( clf_pruned.feature_importances_, indexX.columns ).sort_values(ascendingFalse) print(\nTop 10 重要特征:) print(importances.head(10))逻辑说明cross_val_score返回 10 个折的准确率均值代表模型泛化能力标准差代表稳定性。如果剪枝树的均值比完整树高、标准差比完整树小说明剪枝确实抑制了过拟合。特征重要性输出的是每个特征在分裂中带来的不纯度下降总和归一化后加起来等于 1。在 wdbc 数据上通常feature_1半径均值、feature_8周长均值、feature_21最差半径排在前列这和医学上“细胞核越大越可能是恶性”的直觉一致。参数说明shuffleTrue让每折的样本顺序随机避免数据原始排序带来的偏差。scoringaccuracy可以换成f1或recall如果更关心恶性样本不漏诊用recall更合适。最后说一个我自己的习惯每次跑完剪枝对比我都会把max_depth、ccp_alpha、测试集准确率、叶节点数四个值写进实验记录而不是只存一张图。因为过两周回头看决策树剪枝前后对比.png你根本想不起来当时 alpha 设的是 0.002 还是 0.02。从那以后我每次做树模型实验都强制走一遍“参数记录 → 交叉验证 → 特征重要性”三步缺一步都不算跑完。希望帮到你。本文还有配套的精品资源点击获取
返回列表