我有一个大数据框(约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
答案 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