首页 > 解决方案 > 熊猫:在列高于或等于 0 时复制数据框条目

问题描述

我有一个包含医院患者临床读数的数据框,例如类似的数据框可能如下所示

   heartrate  pid  time
0         67  151   0.0
1         75  151   1.2
2         78  151   2.5
3         99  186   0.0

实际上还有更多列,但我将只保留这 3 个以使示例更简洁。

我想“扩展”数据集。简而言之,我希望能够给出一个论点n_times_back和另一个论点interval

对于对应于 的每次迭代,for i in range (n_times_back + 1)我们执行以下操作:

因为我意识到用文字解释这个有点混乱,这里有一个例子。

使用上面的数据集,如果我们让n_times_back = 1然后interval=1我们得到

   heartrate    pid  time
0         67  15100   0.0
1         75  15100   1.2
2         78  15100   2.5
3         67  15101   0.0
4         75  15101   1.2
5         99  18600   0.0

对于n_times_back = 2,结果将是

   heartrate    pid  time
0         67  15100   0.0
1         75  15100   1.2
2         78  15100   2.5
3         67  15101   0.0
4         75  15101   1.2
5         67  15102   0.0
6         99  18600   0.0

n_times_back = 3及以上将导致与 相同的结果n_times_back = 2,因为没有患者数据低于该时间点

我为此编写了代码。

def expand_df(df, n_times_back, interval):
    for curr_patient in df['pid'].unique():
        patient_data = df[df['pid'] == curr_patient]
        final_time = patient_data['time'].max()
        for i in range(n_times_back + 1):
            new_data = patient_data[patient_data['time'] <= final_time - i * interval]
            new_data['pid'] = patient_data['pid'].astype(str) + str(i).zfill(2)
            new_data['pid'] = new_data['pid'].astype(int)
            #check if there is any time index left, if not don't add useless entry to dataframe
            if(new_data['time'].count()>0):
                df = df.append(new_data)
        df = df[df['pid'] != curr_patient]  # remove original patient data, now duplicate
    df.reset_index(inplace = True, drop = True)
    return df

就功能而言,此代码按预期工作。但是,它非常缓慢。我正在处理一个包含 30'000 名患者的数据框,并且代码已经运行了 2 个多小时。

有没有办法使用熊猫操作来加快速度?我环顾四周,但到目前为止,我还没有设法用高级熊猫功能重现此功能

标签: pythonpython-3.xpandas

解决方案


最终使用了 groupby 函数并在没有更多时间可用时中断,并创建了一个“索引”列,我在最后与“pid”列合并。

def expand_df(group, n_times, interval):
    df = pd.DataFrame()
    final_time = group['time'].max()
    for i in range(n_times + 1):
        new_data = group[group['time'] <= final_time - i * interval]
        new_data['iteration'] = str(i).zfill(2)
        #check if there is any time index left, if not don't add useless entry to dataframe
        if(new_data['time'].count()>0):
            df = df.append(new_data)
        else:
            break
    return df

new_df = df.groupby('pid').apply(lambda x : expand_df(x, n_times_back, interval))
new_df = new_df.reset_index(drop=True)
new_df['pid'] = new_df['pid'].map(str) + new_df['iteration']

推荐阅读