共计 2522 个字符,预计需要花费 7 分钟才能阅读完成。
慢性肾病 (CKD) 数据集是医疗 AI 研究的重要资源,它能帮助预测患者肾功能衰退风险,但原始数据常包含大量缺失值和噪声。医疗数据的特殊性要求我们在特征工程阶段兼顾统计规律与临床意义,而类别不平衡问题更是模型训练的常见挑战。本文将带初学者用 Python 完整走通从数据清洗到模型部署的全流程,特别分享处理医疗数据时的实用技巧。

数据初探与清洗
原始 CKD 数据集通常包含 25 个临床特征(如血压、血糖、红细胞计数等),我们先看原始数据统计:
import pandas as pd
raw_df = pd.read_csv('ckd_raw.csv')
print(raw_df.describe())
输出示例显示多个特征的缺失率超过 15%(如 sg 密度特征缺失 26%)。经过清洗后数据质量显著提升:
# 缺失值处理对比
def clean_data(df):
# 删除缺失超过 30% 的特征
df = df.dropna(thresh=len(df)*0.7, axis=1)
# 数值型特征用 KNN 填充
from sklearn.impute import KNNImputer
num_cols = df.select_dtypes(include='number').columns
imputer = KNNImputer(n_neighbors=3)
df[num_cols] = imputer.fit_transform(df[num_cols])
# 类别特征用众数填充
cat_cols = df.select_dtypes(exclude='number').columns
for col in cat_cols:
df[col] = df[col].fillna(df[col].mode()[0])
return df
clean_df = clean_data(raw_df)
print(clean_df.describe())
特征工程实战
医疗数据的特征编码需要特别谨慎,这里比较两种方法:
# 独热编码 vs 目标编码
from sklearn.preprocessing import OneHotEncoder
from category_encoders import TargetEncoder
# 方法 1:常规独热编码(适合低基数特征)ohe = OneHotEncoder(drop='first')
cat_features = ['rbc', 'pc'] # 红细胞、脓细胞
X_ohe = ohe.fit_transform(clean_df[cat_features])
# 方法 2:目标编码(适合高基数特征)tencoder = TargetEncoder()
X_te = tencoder.fit_transform(clean_df[cat_features], clean_df['target'])
标准化处理对医疗指标尤为重要,不同方法效果对比:
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler, RobustScaler
plt.figure(figsize=(12,4))
plt.subplot(131)
plt.hist(clean_df['bgr'], bins=30) # 血糖原始分布
plt.title('Original')
plt.subplot(132)
plt.hist(StandardScaler().fit_transform(clean_df[['bgr']]), bins=30)
plt.title('StandardScaler')
plt.subplot(133)
plt.hist(RobustScaler().fit_transform(clean_df[['bgr']]), bins=30)
plt.title('RobustScaler')
plt.show()
模型训练与调优
针对不均衡数据(CKD 阳性样本通常只占 20-30%),XGBoost 的 class_weight 参数很关键:
import xgboost as xgb
from sklearn.model_selection import StratifiedKFold
# 基线模型
model = xgb.XGBClassifier(objective='binary:logistic',
scale_pos_weight=3) # 正样本权重
# 分层交叉验证
cv = StratifiedKFold(n_splits=5)
for train_idx, val_idx in cv.split(X, y):
X_train, X_val = X.iloc[train_idx], X.iloc[val_idx]
y_train, y_val = y.iloc[train_idx], y.iloc[val_idx]
model.fit(X_train, y_train)
print(f'ROC-AUC: {roc_auc_score(y_val, model.predict_proba(X_val)[:,1])}')
SHAP 分析可解释模型决策:
import shap
shap_values = shap.TreeExplainer(model).shap_values(X)
shap.summary_plot(shap_values, X, plot_type='bar')
医疗数据特殊注意事项
- 标签泄露预防
- 所有预处理操作(如填充、缩放)必须在交叉验证的每个 fold 内独立进行
-
避免使用包含未来信息的统计量(如用全体数据的均值填充)
-
交叉验证要点
- 必须使用分层抽样保证每折的阳性样本比例
-
患者 ID 去重:同一患者的多次检测记录不应分散在不同折中
-
特征选择陷阱
- 过滤式方法(如卡方检验)可能忽略特征交互作用
- 包装法计算成本高但更适合临床指标关联性分析
实践资源
- Colab 完整代码
- 扩展阅读:
- 《Machine Learning for Healthcare》Chapter 3
- Kaggle 上的 CKD 特征工程竞赛方案
处理医疗数据需要比常规 ML 项目更严谨的态度——某个血糖指标的异常填充可能直接影响模型对糖尿病肾病的判断。建议在临床专家的指导下验证特征工程逻辑,毕竟在医疗领域,可解释性往往比绝对精度更重要。
正文完
