
1. 认识UCI心脏病数据集第一次接触UCI心脏病数据集时我被它丰富的临床属性吸引了。这个数据集包含了来自四个不同医疗机构的患者数据但最常用的是克利夫兰诊所的数据。数据集有14个关键特征从基本的人口统计信息到专业的医学指标覆盖了诊断心脏病所需的方方面面。我特别喜欢这个数据集的一点是它非常贴近真实临床场景。比如胸痛类型(cp)这个特征就包含了四种不同的心绞痛分类这在临床上非常重要。还有thal这个指标它反映的是一种叫做地中海贫血的血液疾病这个特征在大多数公开数据集中都很难见到。不过这个数据集也有些坑需要注意。最大的问题是缺失值特别是ca(主要血管数目)和thal(地中海贫血)这两个特征。我在第一次使用时没注意这个问题直接建模结果惨不忍睹。后来才发现数据集里有6条记录存在缺失值必须得先处理这个问题。2. 数据清洗实战2.1 处理缺失值处理缺失值前我习惯先用pandas做个快速检查import pandas as pd data pd.read_csv(processed.cleveland.csv) print(data.isnull().sum())结果显示ca列有4个缺失值thal列有2个缺失值。对于医学数据我一般不会用均值填充因为每个患者的状况都很独特。我的做法是直接删除这些记录data.dropna(inplaceTrue)删除后还剩297条记录。虽然损失了一些数据但保证了数据的可靠性。如果你实在不想删除可以考虑用众数填充ca列因为它的取值是离散的0-3thal列则可以用正常作为默认值填充。2.2 统一编码格式原始数据中thal和target列的编码不太一致。比如thal在原始数据中用3、6、7表示不同状态而在处理后的版本中用0、1、2表示。为了让模型更好理解我建议统一编码# 统一thal编码 data[thal] data[thal].replace({3:0, 6:1, 7:2}) # 将target转为二分类 data[target] data[target].apply(lambda x: 1 if x 0 else 0)这样处理后所有分类特征都有了统一的编码规范模型训练时会更加稳定。3. 特征工程技巧3.1 特征理解与转换这个数据集有几个特征需要特别注意年龄(age)我习惯将其分箱处理因为心脏病风险与年龄不是简单的线性关系。可以这样操作data[age_group] pd.cut(data[age], bins[0,40,50,60,70,100], labels[40,40-50,50-60,60-70,70])血压(trestbps)和胆固醇(chol)这些连续值特征我通常会做标准化处理from sklearn.preprocessing import StandardScaler scaler StandardScaler() data[[trestbps,chol]] scaler.fit_transform(data[[trestbps,chol]])thalach(最大心率)这个特征很有意思我发现在不同年龄段的正常范围不同所以创建了一个新的特征心率年龄比data[hr_age_ratio] data[thalach] / data[age]3.2 特征相关性分析在建模前我必做的一件事是分析特征相关性。用seaborn画热力图是个好方法import seaborn as sns import matplotlib.pyplot as plt plt.figure(figsize(12,10)) sns.heatmap(data.corr(), annotTrue, cmapcoolwarm) plt.show()从我的分析结果看exang(运动引起的心绞痛)和oldpeak(ST段压低)与目标变量的相关性最高而fbs(空腹血糖)的相关性很低。这提示我们在特征选择时可能需要有所侧重。4. 构建预测模型4.1 数据准备在建模前我们需要做最后的准备工作from sklearn.model_selection import train_test_split # 选择特征 features [age, sex, cp, trestbps, chol, fbs, restecg, thalach, exang, oldpeak, slope, ca, thal] X data[features] y data[target] # 划分训练测试集 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42)4.2 模型训练与评估我比较喜欢先用随机森林做个baseline因为它对特征工程的要求相对较低from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score, f1_score rf RandomForestClassifier(n_estimators100, random_state42) rf.fit(X_train, y_train) y_pred rf.predict(X_test) print(f准确率: {accuracy_score(y_test, y_pred):.2f}) print(fF1分数: {f1_score(y_test, y_pred):.2f})在我的测试中这个baseline模型能达到约85%的准确率。如果想进一步提升性能可以尝试以下方法调整类别权重因为数据集中阳性和阴性样本的比例可能不均衡使用网格搜索优化超参数尝试其他算法如XGBoost或逻辑回归5. 实际应用中的注意事项在临床环境中应用这个模型时有几个关键点需要注意首先不同医疗机构的数据收集标准可能不同。比如血压测量方法、胆固醇检测方式等这些都会影响模型的泛化能力。我建议在实际部署前用本地数据对模型进行微调。其次要特别注意特征的解释性。医生们更愿意相信那些他们能理解的预测结果。因此使用SHAP或LIME等可解释性工具非常重要import shap explainer shap.TreeExplainer(rf) shap_values explainer.shap_values(X_test) shap.summary_plot(shap_values[1], X_test, feature_namesfeatures)最后要定期更新模型。医学知识和技术在不断进步模型的预测标准也应该与时俱进。我通常每半年就会用新数据重新训练一次模型。这个项目最让我有成就感的是经过适当的数据预处理和特征工程后即使是相对简单的模型也能达到不错的预测效果。这再次验证了在机器学习项目中数据和特征的质量往往比算法选择更重要。