• 【数据挖掘】任务2:医学数据库MIMIC-III数据处理


    要求

    本次任务的目的是处理PO2,PCO2两个指标。这两个指标均为病人的血气指标,以一定的时间间隔采集。一个病人一次住院期间可能收集一次或者多次。要求,按照采集时间的前后顺序,汇总每个病人每次住院期间的所有的pO2, pCO2指标值。涉及到的预处理方法包括插值,去噪,缺失值填充,离群点数据处理,可视化等。

    数据集说明

    patients:包含所有患者数据。

    chart_events:包含了所有可供患者使用的图表数据。在他们的ICU停留期间,病人信息的主要存储库是他们的电子图表。电子图表显示病人的日常生命体征和与他们的护理有关的任何额外信息:呼吸机设置、实验室值、代码状态、精神状态等等。因此,关于病人住院的大部分信息都包含在chartevent中。此外,即使在其他地方捕获了实验室值(labevent),它们也经常在chartevent中重复。这是因为在病人的电子图上显示实验室值是可取的,因此这些值是从存储实验室值的数据库复制到存储chartevent的数据库中。当labevent中的值与chartevent中的值不同时,以labevent中的值为准。

    label_events:实验检查信息表,主要是患者的实验室检测记录信息

    数据集下载方式:https://download.csdn.net/download/qq1198768105/85259010

    导库

    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    • 1
    • 2
    • 3
    • 4

    基本设置

    # 设置可视化风格
    plt.style.use('tableau-colorblind10')
    # 设置字体为SimHei(黑体)
    plt.rcParams['font.sans-serif'] = ['SimHei']
    # 解决中文字体下坐标轴负数的负号显示问题
    plt.rcParams['axes.unicode_minus'] = False
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    数据提取

    提取LABEVENTS表格中PO2和PCO2数据

    # 根据采集时间来读取数据
    df = pd.read_csv('mini_label_events.csv', index_col='CHARTTIME')
    
    • 1
    • 2
    # 筛选出po2和pco2数据
    po2 = df.query('ITEMID==490 | ITEMID==3785 | ITEMID==3837 | ITEMID==50821')
    pco2 = df.query('ITEMID==3784 | ITEMID==3835 | ITEMID==50818')
    
    • 1
    • 2
    • 3
    # 创建DateFrame来存储数据
    a1 = pd.DataFrame()
    a1["PO2"] = po2["VALUENUM"]
    a1["PCO2"] = pco2["VALUENUM"]
    a1["SUBJECT_ID"] = po2["SUBJECT_ID"]
    a1["HADM_ID1"] = po2["HADM_ID"]
    a1['采集时间'] = a1.index
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    # 重置索引
    a1.reset_index()
    # 根据采集时间从早到晚进行排序
    a1.sort_values("CHARTTIME", inplace=True)
    # 插入序号并设为索引
    a1.insert(0, '序号', range(1, 1 + len(a1)))
    a1.set_index('序号', inplace=True)
    a1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    PO2PCO2SUBJECT_IDHADM_ID1采集时间
    序号
    1186.032.060207164814.02101-07-19 14:56:00
    2173.033.060207164814.02101-07-19 22:07:00
    3194.029.060207164814.02101-07-20 05:29:00
    4239.037.01205152970.02101-12-20 09:03:00
    5129.040.01205152970.02101-12-20 11:33:00
    ..................
    466988.028.024851111571.02199-01-25 09:41:00
    467035.041.024851111571.02199-01-30 05:08:00
    467165.036.023765193447.02200-05-08 19:52:00
    467289.032.023765193447.02200-05-09 02:24:00
    467338.044.070646NaN2201-01-25 12:23:00

    4673 rows × 5 columns

    提取CHARTEVENTS表格中PO2和PCO2数据

    df2 = pd.read_csv('mini_chart_events.csv',
                      low_memory=False, index_col="CHARTTIME")
    
    • 1
    • 2
    # 筛选出po2和pco2数据
    po2 = df2.query('ITEMID==490 | ITEMID==3785 | ITEMID==3837 | ITEMID==50821')
    pco2 = df2.query('ITEMID==3784 | ITEMID==3835 | ITEMID==50818')
    # 这里存在重复时间索引,删除前面一个,保留最后一个
    po2 = po2.reset_index().drop_duplicates(
        subset='CHARTTIME', keep='last').set_index('CHARTTIME')
    pco2 = pco2.reset_index().drop_duplicates(
        subset='CHARTTIME', keep='last').set_index('CHARTTIME')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    # 创建DateFrame来存储数据
    a2 = pd.DataFrame()
    a2["PO2"] = po2["VALUENUM"]
    a2["PCO2"] = pco2["VALUENUM"]
    a2["SUBJECT_ID"] = po2["SUBJECT_ID"]
    a2["HADM_ID1"] = po2["HADM_ID"]
    a2['采集时间'] = a2.index
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    # 重置索引
    a2.reset_index()
    # 根据采集时间从早到晚进行排序
    a2.sort_values("CHARTTIME", inplace=True)
    # 插入序号并设为索引
    a2.insert(0, '序号', range(1, 1 + len(a2)))
    a2.set_index('序号', inplace=True)
    a2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    PO2PCO2SUBJECT_IDHADM_ID1采集时间
    序号
    1NaNNaN130811207372102-01-11 06:00:00
    2257.200012NaN324761198622109-05-30 18:59:00
    354.00000047.0307121673922111-02-22 19:23:00
    468.00000047.0307121673922111-02-22 23:32:00
    542.00000042.0307121673922111-02-23 06:23:00
    ..................
    13249.00000039.095571783662195-08-07 12:00:00
    133NaNNaN95571783662195-08-10 12:00:00
    134228.199997NaN121831807442197-06-03 03:00:00
    13565.00000036.0237651934472200-05-08 19:52:00
    136NaNNaN237651934472200-05-16 02:00:00

    136 rows × 5 columns

    最小采集时间的间隔

    # 根据病人ID和不同住院时间的ID进行分组
    group = a1.groupby(["SUBJECT_ID", "HADM_ID1"])
    
    • 1
    • 2
    # 提取采集时间大于1的组别(只有2个时间以上才能求间隔)
    tem_list = []
    for key, item in group['采集时间']:
        if item.count() > 1:
            tem_list.append(item)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    # 提取各组的所有采集时间间隔
    interval_list = []
    for i in range(len(tem_list)):
        tem_list[i].sort_values(ascending=False, inplace=True)  # 对采集时间进行从大到小的排序
        for j in range(tem_list[i].count() - 1):
            interval = pd.to_datetime(
                tem_list[i].iloc[j]) - pd.to_datetime(tem_list[i].iloc[j+1])
            interval_list.append(interval)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    # 选取最小的时间间隔
    min(interval_list)
    
    • 1
    • 2

    输出:

    Timedelta('0 days 00:01:00')
    
    • 1

    可以发现,最小的采集时间间隔为1分钟,下面就利用该时间来进行插值。

    插值

    pandas 插值核心函数为interpolate()

    可选的插值方式有:

    nearest:最邻近插值法

    zero:阶梯插值

    slinear、linear:线性插值

    quadratic、cubic:2、3阶B样条曲线插值

    对LABEVENTS表格中PO2和PCO2数据进行插值

    ipl = pd.DataFrame()  # 用来存储插值后的结果
    
    • 1
    for key, item in group:
        item.set_index('采集时间', inplace=True)
        item.index = pd.to_datetime(item.index)
        # 设置重采样时间间隔为1min,该时间由上面选取得到
        ev_ipl = item.resample('1min').interpolate()  # 这里使用默认的线性插值
        ipl = pd.concat([ipl, ev_ipl], axis=0)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    # 重置索引
    ipl.reset_index(inplace=True)
    # 插入序号并设为索引
    ipl.insert(0, '序号', range(1, 1 + len(ipl)))
    ipl.set_index('序号', inplace=True)
    # 更换顺序
    order = ['PO2', 'PCO2', 'SUBJECT_ID', 'HADM_ID1', '采集时间']
    ipl = ipl[order]
    ipl
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    PO2PCO2SUBJECT_IDHADM_ID1采集时间
    序号
    163.00000048.000000127.0141647.02183-08-21 10:26:00
    2347.00000057.000000273.0158689.02141-04-19 05:26:00
    3346.57360456.994924273.0158689.02141-04-19 05:27:00
    4346.14720856.989848273.0158689.02141-04-19 05:28:00
    5345.72081256.984772273.0158689.02141-04-19 05:29:00
    ..................
    236551056.03081037.99763099863.0100749.02142-04-24 17:46:00
    236551156.02310837.99822299863.0100749.02142-04-24 17:47:00
    236551256.01540537.99881599863.0100749.02142-04-24 17:48:00
    236551356.00770337.99940799863.0100749.02142-04-24 17:49:00
    236551456.00000038.00000099863.0100749.02142-04-24 17:50:00

    2365514 rows × 5 columns

    对CHARTEVENTS表格中PO2和PCO2数据进行插值

    ipl2 = pd.DataFrame()  # 用来存储插值后的结果
    
    • 1
    # 根据病人ID和不同住院时间的ID进行分组
    group2 = a2.groupby(["SUBJECT_ID", "HADM_ID1"])
    for key, item in group2:
        item.set_index('采集时间', inplace=True)
        item.index = pd.to_datetime(item.index)
        # 设置重采样时间间隔为1min,该时间由上面选取得到
        ev_ipl = item.resample('1min').interpolate()  # 这里使用默认的线性插值
        ipl2 = pd.concat([ipl2, ev_ipl], axis=0)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    # 重置索引
    ipl2.reset_index(inplace=True)
    # 插入序号并设为索引
    ipl2.insert(0, '序号', range(1, 1 + len(ipl2)))
    ipl2.set_index('序号', inplace=True)
    # 更换顺序
    order = ['PO2', 'PCO2', 'SUBJECT_ID', 'HADM_ID1', '采集时间']
    ipl2 = ipl2[order]
    ipl2
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    PO2PCO2SUBJECT_IDHADM_ID1采集时间
    序号
    1257.200012NaN907.0149649.02155-08-21 19:00:00
    2308.500000NaN946.0183564.02120-05-05 05:00:00
    3308.491890NaN946.0183564.02120-05-05 05:01:00
    4308.483781NaN946.0183564.02120-05-05 05:02:00
    5308.475671NaN946.0183564.02120-05-05 05:03:00
    ..................
    32511561.02290135.98473330712.0167392.02111-02-24 06:10:00
    32511661.01526735.98982230712.0167392.02111-02-24 06:11:00
    32511761.00763435.99491130712.0167392.02111-02-24 06:12:00
    32511861.00000036.00000030712.0167392.02111-02-24 06:13:00
    325119257.200012NaN32476.0119862.02109-05-30 18:59:00

    325119 rows × 5 columns

    缺失点处理

    对LABEVENTS表格中PO2和PCO2数据缺失点进行处理

    # 检测PO2缺失值
    ipl.loc[ipl["PO2"].isnull(), :]
    
    • 1
    • 2
    PO2PCO2SUBJECT_IDHADM_ID1采集时间
    序号
    # 检测PCO2缺失值
    ipl.loc[ipl["PCO2"].isnull(), :]
    
    • 1
    • 2
    PO2PCO2SUBJECT_IDHADM_ID1采集时间
    序号

    LABEVENTS表格中PO2和PCO2数据均无缺失点,不进行处理。

    对LABEVENTS表格中PO2和PCO2数据缺失点进行处理

    PO2PCO2SUBJECT_IDHADM_ID1采集时间
    序号
    22158NaNNaN7285.0150783.02175-04-21 08:00:00
    29662NaNNaN13081.0120737.02102-01-11 06:00:00
    86560NaNNaN18305.0120110.02187-02-06 10:00:00
    # 检测PCO2缺失值
    ipl2.loc[ipl2["PCO2"].isnull(), :]
    
    • 1
    • 2
    PO2PCO2SUBJECT_IDHADM_ID1采集时间
    序号
    1257.200012NaN907.0149649.02155-08-21 19:00:00
    2308.500000NaN946.0183564.02120-05-05 05:00:00
    3308.491890NaN946.0183564.02120-05-05 05:01:00
    4308.483781NaN946.0183564.02120-05-05 05:02:00
    5308.475671NaN946.0183564.02120-05-05 05:03:00
    ..................
    86557249.199997NaN16378.0179705.02134-03-15 19:00:00
    86560NaNNaN18305.0120110.02187-02-06 10:00:00
    270864310.500000NaN20913.0102847.02137-12-18 22:45:00
    296323249.199997NaN29769.0179221.02178-02-28 19:00:00
    325119257.200012NaN32476.0119862.02109-05-30 18:59:00

    7813 rows × 5 columns

    这里总共检测出7813条数据具有缺失值,将这些数据进行删除处理

    ipl2.dropna(axis='index', how='any', inplace=True)  # any表示只要有一个缺失值则整行删除
    
    • 1

    处理后的数据如下表所示

    ipl2
    
    • 1
    PO2PCO2SUBJECT_IDHADM_ID1采集时间
    序号
    756250.00000058.0000004033.0196289.02159-06-15 01:00:00
    756350.00000058.0000004033.0196289.02159-06-15 01:01:00
    756450.00000058.0000004033.0196289.02159-06-15 01:02:00
    756550.00000058.0000004033.0196289.02159-06-15 01:03:00
    756650.00000058.0000004033.0196289.02159-06-15 01:04:00
    ..................
    32511461.03053435.97964430712.0167392.02111-02-24 06:09:00
    32511561.02290135.98473330712.0167392.02111-02-24 06:10:00
    32511661.01526735.98982230712.0167392.02111-02-24 06:11:00
    32511761.00763435.99491130712.0167392.02111-02-24 06:12:00
    32511861.00000036.00000030712.0167392.02111-02-24 06:13:00

    317306 rows × 5 columns

    去噪

    在原始数据中添加了高斯白噪声,需要进行去噪。我选择删除偏离均值三倍标准差数据的方式进行去噪。

    def drop_noisy(df):
        df_copy = df.copy()
        df_describe = df_copy.describe()
        for column in df.columns:
            mean = df_describe.loc['mean', column]
            std = df_describe.loc['std', column]
            minvalue = mean - 3*std
            maxvalue = mean + 3*std
            df_copy = df_copy[df_copy[column] >= minvalue]
            df_copy = df_copy[df_copy[column] <= maxvalue]
        return df_copy
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    对LABEVENTS表格中PO2和PCO2数据进行去噪

    # 这里只对PO2和PCO2列进行去噪
    dno1 = drop_noisy(ipl.iloc[:, :2])
    dno1
    
    • 1
    • 2
    • 3
    PO2PCO2
    序号
    163.00000048.000000
    2347.00000057.000000
    3346.57360456.994924
    4346.14720856.989848
    5345.72081256.984772
    .........
    236551056.03081037.997630
    236551156.02310837.998222
    236551256.01540537.998815
    236551356.00770337.999407
    236551456.00000038.000000

    2266786 rows × 2 columns

    对PO2和PCO2去噪结果进行可视化展示

    # PO2去噪前后可视化
    plo1 = pd.DataFrame()
    plo1['PO2去噪前'] = ipl['PO2']
    plo1['PO2去噪后'] = dno1['PO2']
    plo1.plot.hist(alpha=0.9)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    # PCO2去噪前后可视化
    plo2 = pd.DataFrame()
    plo2['PCO2去噪前'] = ipl['PCO2']
    plo2['PCO2去噪后'] = dno1['PCO2']
    plo2.plot.hist(alpha=0.9)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    对CHARTEVENTS表格中PO2和PCO2数据进行去噪

    dno2 = drop_noisy(ipl2.iloc[:, :2])
    dno2
    
    • 1
    • 2
    PO2PCO2
    序号
    756250.00000058.000000
    756350.00000058.000000
    756450.00000058.000000
    756550.00000058.000000
    756650.00000058.000000
    .........
    32511461.03053435.979644
    32511561.02290135.984733
    32511661.01526735.989822
    32511761.00763435.994911
    32511861.00000036.000000

    312190 rows × 2 columns

    对PO2和PCO2去噪结果进行可视化展示

    # PO2去噪前后可视化
    plo3 = pd.DataFrame()
    plo3['PO2去噪前'] = ipl2['PO2']
    plo3['PO2去噪后'] = dno2['PO2']
    plo3.plot.hist(alpha=0.9)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    # PCO2去噪前后可视化
    plo4 = pd.DataFrame()
    plo4['PCO2去噪前'] = ipl2['PCO2']
    plo4['PCO2去噪后'] = dno2['PCO2']
    plo4.plot.hist(alpha=0.9)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    离群点处理

    通过绘制箱形图,将上边缘和下边缘之外的数据视作离群点,将其进行去除

    对LABEVENTS表格中PO2和PCO2数据离群点进行处理

    c = pd.DataFrame()
    c['PO2'] = plo1['PO2去噪后']
    c['PCO2'] = plo2['PCO2去噪后']
    
    • 1
    • 2
    • 3
    c.boxplot(showmeans=True, sym='b+')
    
    • 1

    在这里插入图片描述

    对PO2数据进行处理,将箱体图上下边缘的数据进行去除

    a = pd.DataFrame()
    b = pd.DataFrame()
    a['PO2'] = plo1['PO2去噪后']
    b['PO2离群点处理前'] = a['PO2']
    # 将箱体图上下边缘的数据进行去除
    first_quartile = a['PO2'].describe()['25%']
    third_quartile = a['PO2'].describe()['75%']
    iqr = third_quartile - first_quartile
    b['PO2离群点处理后'] = a[(a['PO2'] > (first_quartile - 1.5 * iqr)) &
                       (a['PO2'] < (third_quartile + 1.5 * iqr))]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    b.plot.hist(alpha=0.9)
    
    • 1

    在这里插入图片描述

    对PCO2数据进行处理

    a = pd.DataFrame()
    b = pd.DataFrame()
    a['PCO2'] = plo2['PCO2去噪后']
    b['PCO2离群点处理前'] = a['PCO2']
    # 将箱体图上下边缘的数据进行去除
    first_quartile = a['PCO2'].describe()['25%']
    third_quartile = a['PCO2'].describe()['75%']
    iqr = third_quartile - first_quartile
    b['PCO2离群点处理后'] = a[(a['PCO2'] > (first_quartile - 1.5 * iqr)) &
                        (a['PCO2'] < (third_quartile + 1.5 * iqr))]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    b.plot.hist(alpha=0.9)
    
    • 1

    在这里插入图片描述

    对CHARTEVENTS表格中PO2和PCO2数据离群点进行处理

    c = pd.DataFrame()
    c['PO2'] = plo3['PO2去噪后']
    c['PCO2'] = plo4['PCO2去噪后']
    
    • 1
    • 2
    • 3
    c.boxplot(showmeans=True, sym='b+')
    
    • 1

    在这里插入图片描述

    对PO2数据进行处理,将箱体图上下边缘的数据进行去除

    a = pd.DataFrame()
    b = pd.DataFrame()
    a['PO2'] = plo3['PO2去噪后']
    b['PO2离群点处理前'] = a['PO2']
    # 将箱体图上下边缘的数据进行去除
    first_quartile = a['PO2'].describe()['25%']
    third_quartile = a['PO2'].describe()['75%']
    iqr = third_quartile - first_quartile
    b['PO2离群点处理后'] = a[(a['PO2'] > (first_quartile - 1.5 * iqr)) &
                       (a['PO2'] < (third_quartile + 1.5 * iqr))]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    b.plot.hist(alpha=0.9)
    
    • 1

    在这里插入图片描述

    对PCO2数据进行处理

    a = pd.DataFrame()
    b = pd.DataFrame()
    a['PCO2'] = plo4['PCO2去噪后']
    b['PCO2离群点处理前'] = a['PCO2']
    # 将箱体图上下边缘的数据进行去除
    first_quartile = a['PCO2'].describe()['25%']
    third_quartile = a['PCO2'].describe()['75%']
    iqr = third_quartile - first_quartile
    b['PCO2离群点处理后'] = a[(a['PCO2'] > (first_quartile - 1.5 * iqr)) &
                        (a['PCO2'] < (third_quartile + 1.5 * iqr))]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    b.plot.hist(alpha=0.9)
    
    • 1

    在这里插入图片描述

  • 相关阅读:
    ISP-ASF
    【JVM】内存结构
    Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析
    spring kafka使用(三)
    傲游3浏览器中如何启用JavaScript编程
    秋招面经第二弹:百度一面-大数据开发工程师
    5Python的Pandas:数据结构
    计网第六章(应用层)(一)(动态主机配置协议DHCP)
    Vue项目保持用户登录状态(localStorage + vuex 刷新页面后状态依然保持)
    手撕漏桶&令牌桶限流算法(Java版)
  • 原文地址:https://blog.csdn.net/qq1198768105/article/details/125570475