医疗AI白箱编程:从理论到实践指南(代码部分)

第四章:实战编程(一):从数据到固有可解释模型
本章将通过一个完整的医疗案例,展示如何从零开始,使用内在可解释模型(逻辑回归和决策树)进行建模和解释。我们将使用一个公开的心脏病预测数据集(UCI Heart Disease Dataset)。
4.1 案例背景:心脏病风险预测
目标:基于患者的临床指标(如年龄、性别、血压、胆固醇等),预测其是否患有心脏病。这是一个二分类问题。
4.2 第一步:数据准备与探索
首先,我们加载数载、清洗数据,并进行初步探索。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns# 加载数据
# 假设数据文件为 'heart.csv'
# url = 'http://.../heart.csv' # 也可以从网络加载
try:df = pd.read_csv('heart.csv')
except FileNotFoundError:print("请下载 heart.csv 文件到当前目录,或提供正确路径。")exit()# 数据基本信息
print("数据形状:", df.shape)
print("\n数据列信息:")
df.info()# 查看前几行数据
print("\n数据预览:")
print(df.head())# 查看目标变量的分布
print("\n目标变量 'target' 的分布:")
print(df['target'].value_counts())
sns.countplot(x='target', data=df)
plt.title('Target Distribution (0: No Disease, 1: Has Disease)')
plt.show()# 检查缺失值
print("\n缺失值统计:")
print(df.isnull().sum())# 可视化特征与目标的关系 (以年龄为例)
plt.figure(figsize=(10, 6))
sns.histplot(data=df, x='age', hue='target', kde=True, multiple='stack')
plt.title('Age Distribution by Heart Disease Status')
plt.show()
代码解释:
- 我们使用
pandas加载数据,并检查了数据的基本情况,包括形状、类型、缺失值。 df['target'].value_counts()显示了患病和未患病的人数,这是一个相对均衡的数据集。- 我们用
seaborn绘制了年龄的分布图,直观地看到不同心脏病状态下年龄的差异,这是特征工程和理解数据的重要一步。
4.3 第二步:数据预处理
机器学习模型需要数值型输入,因此我们需要对分类特征进行编码,并对数据进行标准化。
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer# 定义特征和目标
X = df.drop('target', axis=1)
y = df['target']# 区分数值型和分类型特征
numerical_features = ['age', 'trestbps', 'chol', 'thalach', 'oldpeak', 'ca']
categorical_features = ['sex', 'cp', 'fbs', 'restecg', 'exang', 'slope', 'thal']# 创建预处理器
# 数值型特征:标准化
# 分类型特征:独热编码
preprocessor = ColumnTransformer(transformers=[('num', StandardScaler(), numerical_features),('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features)])# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)# 拟合并转换数据
X_train_processed = preprocessor.fit_transform(X_train)
X_test_processed = preprocessor.transform(X_test)# 获取独热编码后的特征名称,以便后续解释
ohe_feature_names = preprocessor.named_transformers_['cat'].get_feature_names_out(categorical_features)
all_feature_names = numerical_features + list(ohe_feature_names)print("预处理后的训练集形状:", X_train_processed.shape)
print("所有特征名称:", all_feature_names)
代码解释:
ColumnTransformer是Scikit-learn中非常方便的工具,可以对不同列应用不同的转换。StandardScaler对数值特征进行标准化,使其均值为0,方差为1,这对逻辑回归等模型很重要。OneHotEncoder将分类特征转换为多个0/1的二元特征。handle_unknown='ignore'可以防止测试集中出现训练集未见的类别时报错。- 我们划分了训练集和测试集,并保存了预处理后的特征名称
all_feature_names,这对于后续解释模型的权重至关重要。
4.4 第三步:训练并解释逻辑回归模型
现在我们来训练一个经典的“白箱”模型——逻辑回归,并解释其结果。
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, roc_auc_score, classification_report# 训练逻辑回归模型
# 使用L2正则化防止过拟合,C是正则化强度的倒数
lr_model = LogisticRegression