临床数据分析与回归建模(PICU临床数据应用)

Published:

项目背景

儿科重症监护室(PICU)患者的临床数据包含年龄、性别、实验室指标等多维度信息,对这些数据的深入分析可揭示关键指标与患者结局的关联。本项目基于13258条PICU患者数据,通过数据清洗、特征探索与逻辑回归建模,掌握临床数据处理核心流程,量化分析实验室指标与患者临床结局的关系,为临床风险评估提供数据支撑。

代码实现

编程库

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from collections import Counter
import statsmodels.api as sm
from sklearn.metrics import roc_auc_score, roc_curve, auc
import matplotlib.pyplot as plt

1. 数据读取与预处理

筛选感兴趣的临床特征,为建模奠定基础。

path = "icu_first24hours.csv"
picu_data = pd.read_csv(path)
picu_data
# 筛选感兴趣的特征集(年龄、结局变量、关键实验室指标)
core_features = [
    'age_month', 'HOSPITAL_EXPIRE_FLAG',
    'lab_5097_max', 'lab_5099_min', 'lab_5237_min',
    'lab_5227_min', 'lab_5225_range', 'lab_5235_max', 'lab_5257_min'
]
new_picu_data = picu_data[core_features].copy()

2. 统计分析

数据集探索,将感兴趣的指标进行统计和可视化

# 查看各列的非空值数量 (count)
new_picu_data.count()
# 计算均值 (mean)
new_picu_data.mean()
# 计算中位数 (median)
new_picu_data.median()
# 计算方差 (var)
new_picu_data.var()
#new_picu_data.to_excel("data.xlsx", index=False)
变量非空值数 (Count)均值 (Mean)中位数 (Median)方差 (Variance)
age_month1325829.998.001939.01
HOSPITAL_EXPIRE_FLAG132580.060.000.06
lab_5097_max1134638.2736.9080.80
lab_5099_min11343120.59118.00977.03
lab_5237_min86687.357.370.01
lab_5227_min86162.251.803.33
lab_5225_range86663.841.5029.85
lab_5235_max867142.6139.60218.75
lab_5257_min866291.55105.003052.25
  • 结局变量(HOSPITAL_EXPIRE_FLAG):HOSPITAL_EXPIRE_FLAG均值为 0.06,说明数据集内仅 6% 的患者住院期间死亡,数据存在明显的类别不平衡
  • 年龄(age_month): 均值29.99个月,中位数仅8个月,说明PICU患者以低龄婴幼儿为主;
  • 实验室指标: lab_5257_min方差(3052.25)远高于其他指标,提示该指标在患者间差异极大,可能是重要的预后特征。

临床特征的直方图和箱线图展示

# === 直方图绘制代码 ===
# 定义要绘制直方图的列名列表,包含8个临床指标
colname =['age_month','lab_5097_max','lab_5099_min','lab_5237_min','lab_5227_min','lab_5225_range','lab_5235_max','lab_5257_min']

# 创建子图,共4行2列,使用seaborn的histplot函数绘制直方图
fig, axs = plt.subplots(int(len(colname)/2), 2, constrained_layout=True, figsize=(8, 6), dpi=150)

# 使用seaborn的histplot函数绘制直方图
for i in range(len(colname)):
    sns.histplot(x=colname[i], data=new_picu_data, alpha=0.4, kde=True, ax=axs[i//2, i%2])
plt.suptitle("Bar Plot")
# === 箱线图绘制代码) ===
# 创建一个新的图形对象和子图数组用于绘制箱线图
fig, axs = plt.subplots(
    int(len(colname) / 2), 2, 
    constrained_layout=True, 
    figsize=(8, 6), 
    dpi=150
)
# 使用seaborn的boxplot函数绘制分组箱线图
for i in range(len(colname)): 
    sns.boxplot(
        data=new_picu_data, 
        x="HOSPITAL_EXPIRE_FLAG", 
        y=colna

直方图 箱线图

3. 构建逻辑回归模型

由于因变量是二分类,这里改为使用逻辑回归模型

#数据清洗,填补缺失值
picu_data_with_median = new_picu_data.fillna(new_picu_data.median())

# 自变量 X 和 因变量 y
X = picu_data_with_median.drop(columns="HOSPITAL_EXPIRE_FLAG")
y = picu_data_with_median["HOSPITAL_EXPIRE_FLAG"]

# 加截距项
X = sm.add_constant(X)

# Logistic 回归
logit_model = sm.Logit(y, X)
result = logit_model.fit()

# 提取回归系数和置信区间
params = result.params
conf = result.conf_int()
conf.columns = ['2.5%', '97.5%']

# 合并并指数化(得到 OR)
or_table = pd.concat([params, conf], axis=1)
or_table = np.exp(or_table)

# 重命名列
or_table.columns = ['OR', '2.5%', '97.5%']
# 去掉截距(
or_table = or_table.drop(index='const', errors='ignore')
# 保留两位小数
or_table = or_table.round(2)
# 按 OR 排序
or_table = or_table.sort_values(by='OR', ascending=False)
or_table

变量名OR2.5%97.5%
lab_5227_min1.051.011.09
lab_5225_range1.031.021.05
lab_5097_max1.011.001.03
lab_5235_max1.011.001.01
age_month1.000.9981.00
lab_5099_min1.000.991.00
lab_5257_min0.990.990.99
lab_5237_min0.080.030.22

在多因素 Logistic 回归分析中,lab_5237_min、lab_5257_min、lab_5227_min、lab_5225_range 为 HOSPITAL_EXPIRE_FLAG 的独立相关因素;其余变量在校正后未显示统计学显著性。

4. 预测模型评估与可视化

# 预测概率
y_pred_prob = result.predict(X)

# AUC
auc = roc_auc_score(y, y_pred_prob)
print("AUC =", auc)

# ROC 曲线
fpr, tpr, _ = roc_curve(y, y_pred_prob)

plt.figure(figsize=(5, 5), dpi=150)
plt.plot(fpr, tpr, label=f"AUC = {auc:.3f}")
plt.plot([0, 1], [0, 1], linestyle="--", color="gray")
plt.xlabel("False Positive Rate")
plt.ylabel("True Positive Rate")
plt.title("ROC Curve")
plt.legend()
plt.show()

AUC1

5. 模型优化与展示

选择保留对预测结果影响较大的变量进行模型优化。我们选择了 lab_5237_min、lab_5257_min、lab_5227_min、lab_5225_range 作为预测模型中的独立相关因素。

selected_features = [
    'lab_5237_min',
    'lab_5227_min',
    'lab_5225_range',
    'lab_5235_max',
    'lab_5257_min'
]

# 构建新数据集
X = picu_data_with_median[selected_features]
y = picu_data_with_median['HOSPITAL_EXPIRE_FLAG']
X_const = sm.add_constant(X)
# 拟合模型
logit_model_reduced = sm.Logit(y, X_const)
result_reduced = logit_model_reduced.fit()

# 输出结果
y_pred_prob = result_reduced.predict(X_const)

params = result_reduced.params
conf = result_reduced.conf_int()
conf.columns = ['2.5%', '97.5%']

# 转换为 OR
or_df = pd.DataFrame({
    'OR': np.exp(params),
    '2.5%': np.exp(conf['2.5%']),
    '97.5%': np.exp(conf['97.5%'])
})

# 去掉截距
or_df = or_df.drop(index='const', errors='ignore')

# 保留两位小数
or_df = or_df.round(2)

or_df
变量名OR2.5%97.5%
lab_5237_min0.090.030.22
lab_5227_min1.051.011.09
lab_5225_range1.041.021.05
lab_5235_max1.011.001.01
lab_5257_min0.990.990.99

结果可视化

# y_true: 真实标签
# y_pred_prob: 预测概率(logit_model.predict())

fpr, tpr, thresholds = roc_curve(y, y_pred_prob)
roc_auc = auc(fpr, tpr)

plt.figure(figsize=(5, 5), dpi=150)

# ROC 曲线 —— 棕色
plt.plot(
    fpr, tpr,
    color='saddlebrown',
    lw=2,
    label=f'ROC curve (AUC = {roc_auc:.3f})'
)

# 对角线 —— 灰色
plt.plot(
    [0, 1], [0, 1],
    color='gray',
    lw=1.5,
    linestyle='--',
    label='Random'
)

plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')
plt.legend(loc='lower right')
plt.grid(alpha=0.3)

plt.show()

AUC2

在剔除无显著意义的预测因子后,构建了一个简化的多变量逻辑回归模型。最终模型包含五个实验室检测得出的变量,并且对住院期间死亡率具有良好的判别能力(曲线下面积 AUC = 0.715)。所有保留下来的预测因子均与死亡率独立相关(p < 0.05)。