【问题标题】:Filter rows from subsets of a Pandas DataFrame efficiently有效地从 Pandas DataFrame 的子集中过滤行
【发布时间】:2021-10-05 07:10:28
【问题描述】:

我有一个由医疗数据组成的 DataFrame,其中的列是 [“Patient_ID”、“Code”、“Data”],其中“Code”仅代表患者“Patient_ID”在“日期”上进行的一些医疗交互。任何患者通常会有不止一排,因为他们有不止一个交互。我想对这些数据应用两种类型的过滤。

  1. 删除所有min_len 互动次数少于一些的患者
  2. 对每位患者应用一个长度为T 天的半重叠滑动窗口。在每个窗口内只保留第一个重复的代码,然后在窗口内打乱代码

所以我需要修改整个数据框的子集,但修改涉及更改子集的大小。我将这两个实现为更大管道的一部分,但是就时间而言,它们是一个重要的瓶颈。我想知道是否有更有效的方法来实现同样的事情,因为我真的只是把有用的东西放在一起,而且我对 pandas 操作的效率不太熟悉。以下是我目前拥有它们的方式:

def Filter_by_length(df, min_len = 1):
    print("Filtering short sequences...")
    df = df.sort_values(axis = 0, by = ['ID', 'DATE']).copy(deep = True)
    new_df = []
    for sub_df in tqdm((df[df.ID == sub] for sub in df.ID.unique()), total = len(df.ID.unique()), miniters = 1):
        if len(sub_df) >= min_len:
            new_df.append(sub_df.copy(deep = True))
    if len(new_df) != 0:
        df =  pd.concat(new_df, sort = False)
    else:
        df = pd.DataFrame({})
    print("Done")
    return df
def shuffle_col(df, col):
    df[col] = np.random.permutation(df[col])
    return df

def Filter_by_redundancy(df, T, min_len = 1):
    print("Filtering redundant concepts and short sequences...")
    df = df.sort_values(axis = 0, by = ['ID', 'DATE']).copy(deep = True)
    new_df = []
    for sub_df in tqdm((df[df.ID == sub] for sub in df.ID.unique()), total = len(df.ID.unique()), miniters = 1):
        start_date = sub_df.DATE.min()
        end_date = sub_df.DATE.max()
        next_date = start_date + dt.timedelta(days = T)
        while start_date <= end_date:
            sub_df = pd.concat([sub_df[sub_df.DATE < start_date],\
                                shuffle_col(sub_df[(sub_df.DATE <= next_date) & (sub_df.DATE >= start_date)]\
                                            .drop_duplicates(subset = ['CODE']), "CODE"),\
                                sub_df[sub_df.DATE > next_date]], sort = False )
            start_date += dt.timedelta(days = int(T/2))
            next_date += dt.timedelta(days = int(T/2))
        if len(sub_df) >= min_len:
            new_df.append(sub_df.copy(deep = True))
    if len(new_df) != 0:
        df =  pd.concat(new_df, sort = False)
    else:
        df = pd.DataFrame({})
    print("Done")
    return df

如您所见,在第二种情况下,我实际上同时应用了两个过滤器,因为可以选择同时应用这两个过滤器或单独应用一个过滤器很重要,但我对可以进行的任何性能改进感兴趣一个或两个。

【问题讨论】:

  • 通过df.groupby('id').size()获取组长度,然后删除任何长度不足的ID。我不确定您的其他部分完全是做什么的,但您也可以随时将 for sub_df in [df[df['id'] == i] for i in df['id'].unique()] 替换为 for id, sub_df in df.groupby('id')
  • 这种方法的长度要快得多,谢谢。

标签: pandas dataframe filtering data-manipulation


【解决方案1】:

对于第一部分,我会使用这种方法,而不是像这样计算你的 group-by:

>>> d = pd.DataFrame({'id': [1, 2, 3, 4, 5], 'q': [np.random.randint(1, 15, size=np.random.randint(1, 5)) for _ in range(5)]}).explode('q')
   id   q
0   1   1
0   1   9
1   2   9
1   2  10
1   2   4
2   3   3
2   3   6
2   3   2
2   3  10
3   4  11
3   4   5
4   5   5
4   5   6
4   5   3
4   5   2

>>> sizes = d.groupby('id').size()
>>> d[d['id'].isin(sizes[sizes >= 3].index)]  # index is list of IDs meeting criteria
   id   q
1   2   9
1   2  10
1   2   4
2   3   3
2   3   6
2   3   2
2   3  10
4   5   5
4   5   6
4   5   3
4   5   2

我不确定您为什么要在某个窗口中随机播放您的代码。为了避免 X-Y 问题,您实际上想在那里做什么?

【讨论】:

  • 我会尝试第一种方法,谢谢。改组的想法是数据的整体顺序性质很重要,但在某个时间窗口内,顺序是任意的。举一个最简单的例子,如果患者在同一天开出 3 种药物,那么如果对这 3 种药物不重要的话,那么这个顺序是不是很重要。这也是论文工作的实施,不是我自己决定做的事情。当然,洗牌最终可能毫无意义。
猜你喜欢
  • 1970-01-01
  • 2021-09-05
  • 2012-10-05
  • 2020-06-22
  • 2013-09-02
  • 1970-01-01
  • 2017-03-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多