熊猫如何有效地将大型数据帧分为两组,并在日期时间进行分组

时间:2019-02-14 10:49:53

标签: python-3.x pandas performance numpy pandas-groupby

我有一个大数据框(约4000万行),我想将其分为两部分。 'group'列指示样本所属的组,'date'列指示样本发生的日期。在以下测试用例中,可以有多个相等的样本,但是在原始集中,情况并非如此。此外,在原始数据中,存在三列。 现在,如果一组的最新日期早于或等于'2017-01-30',我想将整个组放到s1,否则放到s2

下面的代码完成了应有的工作,但是速度很慢。您有什么想法,我如何加快这一过程?您知道吗,为什么这种方法这么慢? df['split'] = grouped['date'].transform(lambda x: x.max() < date_)行是瓶颈。 感谢您的帮助。

from random import randint
import numpy as np
import time
import pandas as pd

length = int(1e5)

bimonthly_days = np.arange(0, 30)
base_date = np.datetime64('2017-01-01')
random_date = base_date + np.random.choice(bimonthly_days)

groups = np.random.randint(1, int(2e4), length)
dates = np.array([base_date + np.random.choice(bimonthly_days) for _ in range(length)], dtype='datetime64[ns]')

df = pd.DataFrame({'group': groups, 'date': dates})

grouped = df.groupby('group')
date_ = np.datetime64('2017-01-30')

start_time = time.process_time()
df['split'] = grouped['date'].transform(lambda x: x.max() < date_)
dif = time.process_time() - start_time
print(f" elapsed time: {dif}")

s1 = df[df['split'] == 1].drop(columns=['split'])
s2 = df[df['split'] == 0].drop(columns=['split'])

输出:

elapsed time: 12.923806

2 个答案:

答案 0 :(得分:2)

使用transform创建Series,然后只比较一次,就像分别比较每个组一样。您也可以创建新的掩码而不是列进行比较,并使用~来反转掩码:

mask = grouped['date'].transform('max') < date_

s1 = df[mask]
s2 = df[~mask]

性能

np.random.seed(10)
length = int(1e5)

bimonthly_days = np.arange(0, 30)
base_date = np.datetime64('2017-01-01')
random_date = base_date + np.random.choice(bimonthly_days)

groups = np.random.randint(1, int(2e4), length)
dates = np.array([base_date + np.random.choice(bimonthly_days) for _ in range(length)], dtype='datetime64[ns]')

df = pd.DataFrame({'group': groups, 'date': dates})


In [219]: %timeit df.groupby('group')['date'].transform('max') < np.datetime64('2017-01-30')
9.81 ms ± 645 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [220]: %timeit df.groupby('group')['date'].transform(lambda x: x.max() < np.datetime64('2017-01-30'))
9.05 s ± 159 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

答案 1 :(得分:1)

尝试一下:

start_time = time.process_time() df.loc[:,'split'] = df.groupby('group').date.transform('max') dif = time.process_time() - start_time print(f" elapsed time: {dif}")

s1 = df[df.split < date_] s2 = df[df.split >= date_]

 elapsed time: 0.01961299999999966

用你的方法,我的时间是:

elapsed time: 6.9499130000000005