考虑以下数据框(请参阅此答案的结尾以获取生成代码的代码):
A T0 T1
0 0 2017-01-02 2017-01-04
1 2 2017-01-02 2017-01-05
2 1 2017-01-03 2017-01-04
3 3 2017-01-04 2017-01-07
4 2 2017-01-07 2017-01-10
5 0 2017-01-08 2017-01-10
6 3 2017-01-08 2017-01-09
7 1 2017-01-10 2017-01-11
8 0 2017-01-11 2017-01-13
9 3 2017-01-12 2017-01-15
10 2 2017-01-13 2017-01-16
11 1 2017-01-15 2017-01-17
12 0 2017-01-18 2017-01-20
13 3 2017-01-19 2017-01-20
14 1 2017-01-20 2017-01-22
15 2 2017-01-20 2017-01-21
16 2 2017-02-03 2017-02-06
17 1 2017-02-03 2017-02-06
18 0 2017-02-04 2017-02-07
19 3 2017-02-05 2017-02-07
20 1 2017-02-07 2017-02-08
21 3 2017-02-09 2017-02-11
22 0 2017-02-09 2017-02-10
23 1 2017-02-13 2017-02-16
24 3 2017-02-15 2017-02-17
25 2 2017-02-15 2017-02-18
26 0 2017-02-17 2017-02-18
27 2 2017-02-19 2017-02-21
28 3 2017-02-20 2017-02-21
29 2 2017-02-24 2017-02-27
30 1 2017-02-25 2017-02-26
31 0 2017-02-27 2017-03-01
我希望使用pandas.Grouper
(例如按月)和A
进行分组,并为每个组g
计算g.T0 - g.T1.shift()
的最大值。
我目前正在做以下事情:
def fun(x):
x['G'] = x.T0 - x.T1.shift()
return x
u = df.groupby((pd.Grouper(freq='MS', key='T0'), 'A')).apply(fun)
u = df.groupby((pd.Grouper(freq='MS', key='T0'), 'A'))['G'].max()
这有效,但是非常慢 - 我当前的数据帧包含~80m行,并且需要超过30分钟来计算我想要的组。
上述数据框的预期输出为:
T0 A
2017-01-01 0 5 days
1 6 days
2 4 days
3 4 days
2017-02-01 0 9 days
1 9 days
2 9 days
3 4 days
Name: G, dtype: timedelta64[ns]
我测试了另一种方法,包括在结束前计算差距:
df = df.sort_values(['A', 'T0'])
df['G'] = df.T0 - df.T1.shift()
df.loc[df['A'].diff() != 0, 'G'] = pd.NaT
然后我可以简单地说:
df.groupby((pd.Grouper(freq='MS', key='T0'), 'A'))['G'].max()
这里的问题是每组的第一个条目是当前组和前一组之间的差距,所以我得到:
T0 A
2017-01-01 0 5 days
1 6 days
2 4 days
3 4 days
2017-02-01 0 15 days
1 12 days
2 13 days
3 16 days
Name: G, dtype: timedelta64[ns]
我需要的是:
df.groupby((pd.Grouper(freq='MS', key='T0'), 'A')).all_but_first()['G'].max()
问题是pandas中不存在all_but_first
。
有没有办法:
apply
; 生成数据帧的代码:
import numpy as np
import pandas as pd
A = np.repeat(range(4), 8)
T0 = [1, 7, 10, 17, 34, 39, 47, 57,
2, 9, 14, 19, 33, 37, 43, 55,
1, 6, 12, 19, 33, 45, 49, 54,
3, 7, 11, 18, 35, 39, 45, 50]
T1 = [3, 9, 12, 19, 37, 40, 48, 59,
3, 10, 16, 21, 36, 38, 46, 56,
4, 9, 15, 20, 36, 48, 51, 57,
6, 8, 14, 19, 37, 41, 47, 51]
df = pd.DataFrame({'A': A, 'T0': T0, 'T1': T1})
df['T0'] = pd.to_datetime(df['T0'], unit='D', origin=pd.Timestamp('2017-01-01'))
df['T1'] = pd.to_datetime(df['T1'], unit='D', origin=pd.Timestamp('2017-01-01'))
df = df.sort_values('T0')
df = df.reset_index(drop=True)
答案 0 :(得分:2)
您可以使用:
df['new'] = df['T0'].sub(df.groupby((pd.Grouper(freq='MS', key='T0'), 'A'))['T1'].shift())
df = df.groupby((pd.Grouper(freq='MS', key='T0'), 'A'))['new'].max()
print (df)
T0 A
2017-01-01 0 5 days
1 6 days
2 4 days
3 4 days
2017-02-01 0 9 days
1 9 days
2 9 days
3 4 days
Name: new, dtype: timedelta64[ns]
一个想法是在max
中使用apply
:
u = df.groupby('A').apply(lambda x: (x.T0 - x.T1.shift()).max())
print (u)
A
0 4.0
1 6.0
2 5.0
3 3.0
dtype: float64
或首先减去shifted
列,然后汇总max
:
df = df['T0'].sub(df.groupby(['A'])['T1'].shift()).groupby(df['A']).max()
print (df)
A
0 4.0
1 6.0
2 5.0
3 3.0
dtype: float64
通过更改数据编辑:
df = df['T0'].sub(df.groupby(['A', 'V'])['T1'].shift()).groupby([df['A'], df['V']]).max()
print (df)
A V
0 False 4.0
True 2.0
1 False 3.0
True 4.0
2 False 1.0
True 5.0
3 False 3.0
True 3.0
dtype: float64