机器学习在乳腺癌生存预测中的应用与优化
1. 乳腺癌患者生存概率预测模型开发指南在医疗数据分析领域构建能够准确预测患者生存概率的模型具有重要价值。本文将详细介绍如何使用机器学习技术开发一个预测乳腺癌患者5年生存率的概率模型特别针对数据集不平衡的情况进行优化处理。1.1 项目背景与挑战我们使用的Haberman数据集记录了1958-1970年间在芝加哥大学比林斯医院接受乳腺癌手术的306名患者的临床数据。该数据集存在几个显著特点类别不平衡生存患者(73.5%)远多于未生存患者(26.5%)特征有限仅包含患者年龄、手术年份和阳性腋窝淋巴结数量历史数据数据来自上世纪50-60年代现代医疗条件下可能不完全适用注意本项目旨在演示不平衡数据集的概率建模方法而非提供实际的医疗诊断建议。任何临床决策都应基于更全面、现代的医疗数据。1.2 技术路线设计我们的建模流程将分为以下几个关键阶段数据探索分析特征分布和类别不平衡情况基准建立确定随机猜测的性能基准模型评估测试多种概率预测算法性能优化通过数据预处理提升模型表现最终应用使用最佳模型进行新数据预测2. 数据准备与探索分析2.1 数据集加载与预处理首先我们需要加载数据并进行基本处理from pandas import read_csv from sklearn.preprocessing import LabelEncoder def load_dataset(full_path): # 加载CSV文件 data read_csv(full_path, headerNone) data data.values # 分割特征和标签 X, y data[:, :-1], data[:, -1] # 将标签编码为0(生存)和1(未生存) y LabelEncoder().fit_transform(y) return X, y2.2 数据特征分析数据集包含三个特征年龄患者手术时的年龄(30-83岁)年份手术年份(1958-1969)淋巴结阳性腋窝淋巴结数量(0-52个)通过描述性统计可以看到特征平均值标准差最小值25%分位中位数75%分位最大值年龄52.4610.8030445260.7583年份62.853.2558606365.7569淋巴结4.037.190014522.3 类别分布可视化from collections import Counter from matplotlib import pyplot # 加载数据 X, y load_dataset(haberman.csv) # 统计类别分布 counter Counter(y) for k, v in counter.items(): per v / len(y) * 100 print(fClass{k}, Count{v}, Percentage{per:.1f}%) # 绘制饼图 labels [Survived, Not Survived] sizes [counter[0], counter[1]] pyplot.pie(sizes, labelslabels, autopct%1.1f%%) pyplot.title(Class Distribution) pyplot.show()输出结果Class0, Count225, Percentage73.5% Class1, Count81, Percentage26.5%3. 模型评估框架构建3.1 评估指标选择对于概率预测问题我们使用Brier Skill Score(BSS)作为主要评估指标from sklearn.metrics import brier_score_loss def brier_skill_score(y_true, y_prob): # 计算参考Brier分数(基于类别先验) pos_prob sum(y_true) / len(y_true) ref_probs [pos_prob for _ in range(len(y_true))] bs_ref brier_score_loss(y_true, ref_probs) # 计算模型Brier分数 bs_model brier_score_loss(y_true, y_prob) # 计算技能分数 return 1.0 - (bs_model / bs_ref)BSS解释0模型等同于基准预测1完美预测0比基准预测更差3.2 交叉验证策略采用分层重复K折交叉验证from sklearn.model_selection import RepeatedStratifiedKFold from sklearn.model_selection import cross_val_score def evaluate_model(X, y, model): # 定义10折重复3次的验证策略 cv RepeatedStratifiedKFold(n_splits10, n_repeats3, random_state1) # 使用BSS作为评分指标 metric make_scorer(brier_skill_score, needs_probaTrue) # 评估模型 scores cross_val_score(model, X, y, scoringmetric, cvcv, n_jobs-1) return scores3.3 基准模型建立使用简单策略作为基准from sklearn.dummy import DummyClassifier # 基准模型总是预测类别先验概率 baseline DummyClassifier(strategyprior) # 评估基准模型 baseline_scores evaluate_model(X, y, baseline) print(fBaseline BSS: {mean(baseline_scores):.3f} (±{std(baseline_scores):.3f}))预期输出Baseline BSS: 0.000 (±0.000)4. 概率模型比较与选择4.1 候选模型测试我们评估以下6种概率模型from sklearn.linear_model import LogisticRegression from sklearn.discriminant_analysis import LinearDiscriminantAnalysis, QuadraticDiscriminantAnalysis from sklearn.naive_bayes import GaussianNB, MultinomialNB from sklearn.gaussian_process import GaussianProcessClassifier models [ LogisticRegression(solverlbfgs), LinearDiscriminantAnalysis(), QuadraticDiscriminantAnalysis(), GaussianNB(), MultinomialNB(), GaussianProcessClassifier() ]4.2 模型性能对比执行评估并可视化结果results [] names [] for model in models: # 获取模型简称 name model.__class__.__name__[:7] # 评估模型 scores evaluate_model(X, y, model) # 记录结果 results.append(scores) names.append(name) # 打印性能摘要 print(f{name:15}: {mean(scores):.3f} (±{std(scores):.3f})) # 绘制箱线图 pyplot.figure(figsize(10,6)) pyplot.boxplot(results, labelsnames, showmeansTrue) pyplot.title(Model Comparison) pyplot.ylabel(Brier Skill Score) pyplot.show()典型输出结果模型平均BSS标准差LogisticRegression0.1420.096LinearDiscriminantAnalysis0.1380.098QuadraticDiscriminantAnalysis0.0850.150GaussianNB0.0920.137MultinomialNB-0.0420.086GaussianProcessClassifier0.1230.1144.3 结果分析从测试结果可以看出逻辑回归表现最佳BSS达到0.142线性判别分析紧随其后性能接近逻辑回归多项式朴素贝叶斯表现最差甚至低于基准所有模型的标准差较大说明性能对数据划分敏感经验分享对于小型医疗数据集简单的线性模型(如逻辑回归)往往比复杂模型表现更好因为它们不容易过拟合。5. 数据预处理优化5.1 特征缩放测试尝试标准化和归一化对模型的影响from sklearn.preprocessing import StandardScaler, MinMaxScaler from sklearn.pipeline import Pipeline # 定义预处理方法 preprocessors [ (原始数据, None), (标准化, StandardScaler()), (归一化, MinMaxScaler()) ] # 测试不同预处理对最佳模型的影响 for name, scaler in preprocessors: if scaler is None: pipeline LogisticRegression(solverlbfgs) else: pipeline Pipeline([(scaler, scaler), (model, LogisticRegression(solverlbfgs))]) scores evaluate_model(X, y, pipeline) print(f{name:10}: {mean(scores):.3f} (±{std(scores):.3f}))5.2 特征变换尝试对偏态分布的特征进行幂变换from sklearn.preprocessing import PowerTransformer # 应用Ye-Johnson幂变换 transformer PowerTransformer(methodyeo-johnson) pipeline Pipeline([ (transform, transformer), (model, LogisticRegression(solverlbfgs)) ]) scores evaluate_model(X, y, pipeline) print(f幂变换后: {mean(scores):.3f} (±{std(scores):.3f}))5.3 优化结果预处理方法比较预处理方法平均BSS性能提升原始数据0.142基准标准化0.1452.1%归一化0.1473.5%幂变换0.1494.9%6. 最终模型与应用6.1 模型训练与评估选择最佳配置训练最终模型from sklearn.preprocessing import PowerTransformer from sklearn.linear_model import LogisticRegression from sklearn.pipeline import Pipeline # 创建最优管道 model Pipeline([ (preprocess, PowerTransformer()), (classifier, LogisticRegression(solverlbfgs)) ]) # 在全数据集上训练 model.fit(X, y) # 使用保留测试集评估 # 假设X_test, y_test是预留数据 y_prob model.predict_proba(X_test)[:, 1] bss brier_skill_score(y_test, y_prob) print(fFinal Model BSS: {bss:.3f})6.2 预测新数据使用训练好的模型预测新患者生存概率def predict_survival(age, year, nodes): # 准备输入数据 case [[age, year, nodes]] # 预测生存概率(返回的是未生存概率需要取反) prob_not_survive model.predict_proba(case)[0][1] prob_survive 1 - prob_not_survive return prob_survive # 示例预测50岁患者1965年手术3个阳性淋巴结的生存概率 probability predict_survival(50, 65, 3) print(f5年生存概率: {probability:.1%})6.3 模型解释对于逻辑回归模型我们可以分析特征重要性# 获取训练后的逻辑回归系数 lr model.named_steps[classifier] feature_names [年龄, 年份, 淋巴结] coefficients pd.DataFrame({ 特征: feature_names, 系数: lr.coef_[0], 重要性: np.abs(lr.coef_[0]) }).sort_values(重要性, ascendingFalse) print(coefficients)典型输出特征系数重要性淋巴结-0.120.12年龄-0.050.05年份0.030.03这表明阳性淋巴结数量是最重要的预测因素与年龄呈负相关而较晚的手术年份略微有利于生存。7. 项目总结与经验分享通过本项目我们完成了从数据探索到模型部署的全流程特别关注了不平衡数据集下的概率预测问题。以下是一些关键经验评估指标选择对于概率预测Brier Skill Score比准确率更适合不平衡数据模型选择简单线性模型在小型医疗数据上往往表现优异数据预处理适当的特征变换可以小幅提升模型性能可解释性医疗领域需要能够解释模型决策过程实际应用中的注意事项历史数据的局限性现代医疗条件下结果可能不同特征有限性临床决策需要更多维度的数据不确定性沟通向患者解释预测结果时应强调概率性质这个项目展示了如何系统性地解决医疗领域的分类问题其方法论可以扩展到其他类似的预测任务中。