groupby中按日期时间过滤的有效方法
Posted
技术标签:
【中文标题】groupby中按日期时间过滤的有效方法【英文标题】:Efficient way of filtering by datetime in groupby 【发布时间】:2021-02-05 13:34:23 【问题描述】:鉴于DataFrame
由以下生成:
import numpy as np
import pandas as pd
from datetime import timedelta
np.random.seed(0)
rng = pd.date_range('2015-02-24', periods=14, freq='9H')
ids = [1]*5 + [2]*2 + [3]*7
df = pd.DataFrame('id': ids, 'time_entered': rng, 'val': np.random.randn(len(rng)))
df
:
id time_entered val
0 1 2015-02-24 00:00:00 1.764052
1 1 2015-02-24 09:00:00 0.400157
2 1 2015-02-24 18:00:00 0.978738
3 1 2015-02-25 03:00:00 2.240893
4 1 2015-02-25 12:00:00 1.867558
5 2 2015-02-25 21:00:00 -0.977278
6 2 2015-02-26 06:00:00 0.950088
7 3 2015-02-26 15:00:00 -0.151357
8 3 2015-02-27 00:00:00 -0.103219
9 3 2015-02-27 09:00:00 0.410599
10 3 2015-02-27 18:00:00 0.144044
11 3 2015-02-28 03:00:00 1.454274
12 3 2015-02-28 12:00:00 0.761038
13 3 2015-02-28 21:00:00 0.121675
对于每个 id
,我需要从最新的 time_entered
中删除超过 24 小时(1 天)的行,对于该 id
。我目前的解决方案:
def custom_transform(x):
datetime_from = x["time_entered"].max() - timedelta(days=1)
x = x[x["time_entered"] > datetime_from]
return x
df.groupby("id").apply(lambda x: custom_transform(x)).reset_index(drop=True)
给出正确的、预期的输出:
id time_entered val
0 1 2015-02-24 18:00:00 0.978738
1 1 2015-02-25 03:00:00 2.240893
2 1 2015-02-25 12:00:00 1.867558
3 2 2015-02-25 21:00:00 -0.977278
4 2 2015-02-26 06:00:00 0.950088
5 3 2015-02-28 03:00:00 1.454274
6 3 2015-02-28 12:00:00 0.761038
7 3 2015-02-28 21:00:00 0.121675
但是,我的真实数据是几千万行,几十万个唯一id,正因为如此,这个解决方案是不可行的(需要很长时间)。
有没有更有效的方法来过滤数据?我感谢所有想法!
【问题讨论】:
【参考方案1】:一般情况下,请避免使用 groupby().apply()
,因为它不是跨组向量化的,更不用说在您的情况下返回新数据帧时的内存分配开销。
如何使用groupby().transform
找到时间阈值,然后对整个数据使用布尔索引:
time_max_by_id = df.groupby('id')['time_entered'].transform('max') - pd.Timedelta('1D')
df[df['time_entered'] > time_max_by_id]
输出:
id time_entered val
2 1 2015-02-24 18:00:00 0.978738
3 1 2015-02-25 03:00:00 2.240893
4 1 2015-02-25 12:00:00 1.867558
5 2 2015-02-25 21:00:00 -0.977278
6 2 2015-02-26 06:00:00 0.950088
11 3 2015-02-28 03:00:00 1.454274
12 3 2015-02-28 12:00:00 0.761038
13 3 2015-02-28 21:00:00 0.121675
【讨论】:
【参考方案2】:df.groupby('id').apply(lambda x : x[(x['time_entered'].max()-x['time_entered'])<pd.Timedelta('1D')]).reset_index(drop=True)
Out[322]:
id time_entered val
0 1 2015-02-24 18:00:00 0.978738
1 1 2015-02-25 03:00:00 2.240893
2 1 2015-02-25 12:00:00 1.867558
3 2 2015-02-25 21:00:00 -0.977278
4 2 2015-02-26 06:00:00 0.950088
5 3 2015-02-28 03:00:00 1.454274
6 3 2015-02-28 12:00:00 0.761038
7 3 2015-02-28 21:00:00 0.121675
【讨论】:
以上是关于groupby中按日期时间过滤的有效方法的主要内容,如果未能解决你的问题,请参考以下文章
在 Pandas GroupBy 数据框中按 ID 计算两个日期之间的行数