有效地计算大熊猫的滚动时间差

Luk*_*uke 5 python pandas

我在熊猫中有一个小组,我试图计算一个人在每个阶段花费的时间.为了更好地理解这一点,我的数据集如下:

group       date    stage  
 A     2014-01-01   one   
 A     2014-01-03   one    
 A     2014-01-04   one    
 A     2014-01-05   two    
 B     2014-01-02  four    
 B     2014-01-06  five    
 B     2014-01-10  five    
 C     2014-01-03   two    
 C     2014-01-05   two    
Run Code Online (Sandbox Code Playgroud)

我想计算阶段持续时间给出:

 group       date    stage  dur
  A     2014-01-01   one    0
  A     2014-01-03   one    2
  A     2014-01-04   one    3
  A     2014-01-05   two    0
  B     2014-01-02  four    0
  B     2014-01-06  five    0
  B     2014-01-10  five    4
  C     2014-01-03   two    0
  C     2014-01-05   two    2
Run Code Online (Sandbox Code Playgroud)

我在下面使用的方法非常慢.关于更快方法的任何想法?

df['stage_duration'] = df.groupby(['group', 'stage']).date.apply(lambda y: (y - y.iloc[0])).apply(lambda y:y / np.timedelta64(1, 'D')))
Run Code Online (Sandbox Code Playgroud)

Kar*_* D. 6

根据您的代码(您的groupby/apply),看起来(尽管您的示例...但是我可能误会了您想要什么,然后Andy做了什么才是最好的主意),您正在使用datetime64dtype 的'date'列而不是integer实际数据中的dtype。而且看起来您想要计算从给定的第一次观察到的天数变化group/stage。我认为这是一组更好的示例数据(如果我正确理解了您的目标):

>>> df

  group       date stage  dur
0     A 2014-01-01   one    0
1     A 2014-01-03   one    2
2     A 2014-01-04   one    3
3     A 2014-01-05   two    0
4     B 2014-01-02  four    0
5     B 2014-01-06  five    0
6     B 2014-01-10  five    4
7     C 2014-01-03   two    0
8     C 2014-01-05   two    2
Run Code Online (Sandbox Code Playgroud)

鉴于您应该通过修改应用程序(如Jeff在他的评论中建议的)来提高速度,timedelta64方法是在应用程序之后以向量化的方式除以(或者您可以在应用程序中做到):

>>> df['dur'] = df.groupby(['group','stage']).date.apply(lambda x: x - x.iloc[0])
>>> df['dur'] /= np.timedelta64(1,'D')
>>> df

  group       date stage  dur
0     A 2014-01-01   one    0
1     A 2014-01-03   one    2
2     A 2014-01-04   one    3
3     A 2014-01-05   two    0
4     B 2014-01-02  four    0
5     B 2014-01-06  five    0
6     B 2014-01-10  five    4
7     C 2014-01-03   two    0
8     C 2014-01-05   two    2
Run Code Online (Sandbox Code Playgroud)

但是您也可以避免groupby/apply给定您的数据按组,阶段,日期顺序排列。每个['group','stage']分组的第一个日期发生在组更改或阶段更改时。因此,我认为您可以执行以下操作:

>>> beg = (df.group != df.group.shift(1)) | (df.stage != df.stage.shift(1))
>>> df['dur'] = (df['date'] - df['date'].where(beg).ffill())/np.timedelta64(1,'D')
>>> df

  group       date stage  dur
0     A 2014-01-01   one    0
1     A 2014-01-03   one    2
2     A 2014-01-04   one    3
3     A 2014-01-05   two    0
4     B 2014-01-02  four    0
5     B 2014-01-06  five    0
6     B 2014-01-10  five    4
7     C 2014-01-03   two    0
8     C 2014-01-05   two    2
Run Code Online (Sandbox Code Playgroud)

说明:请注意df['date'].where(beg)创建的内容:

>>> beg = (df.group != df.group.shift(1)) | (df.stage != df.stage.shift(1))
>>> df['date'].where(beg)

0   2014-01-01
1          NaT
2          NaT
3   2014-01-05
4   2014-01-02
5   2014-01-06
6          NaT
7   2014-01-03
8          NaT
Run Code Online (Sandbox Code Playgroud)

然后,我ffill输入值并与“日期”列取不同。

编辑:正如安迪指出,您还可以使用transform

>>> df['dur'] = df.date - df.groupby(['group','stage']).date.transform(lambda x: x.iloc[0])
>>> df['dur'] /= np.timedelta64(1,'D')

  group       date stage  dur
0     A 2014-01-01   one    0
1     A 2014-01-03   one    2
2     A 2014-01-04   one    3
3     A 2014-01-05   two    0
4     B 2014-01-02  four    0
5     B 2014-01-06  five    0
6     B 2014-01-10  five    4
7     C 2014-01-03   two    0
8     C 2014-01-05   two    2
Run Code Online (Sandbox Code Playgroud)

速度:我使用类似的数据帧对400,000个观察值进行计时,以计时两种方法:

申请方法:

1 loops, best of 3: 18.3 s per loop
Run Code Online (Sandbox Code Playgroud)

不适用方法:

1 loops, best of 3: 1.64 s per loop
Run Code Online (Sandbox Code Playgroud)

因此,我认为避免申请可能会大大提高速度


And*_*den 5

我想我会diff在这里使用:

In [11]: df.groupby('stage')['date'].diff().fillna(0)
Out[11]:
0    0
1    2
2    0
3    0
4    0
5    4
dtype: float64
Run Code Online (Sandbox Code Playgroud)

(假设阶段是连续的。)

如果只是减去每个组中的第一个,请使用以下转换

In [21]: df['date'] - df.groupby('stage')['date'].transform(lambda x: x.iloc[0])
Out[21]:
0    0
1    2
2    0
3    0
4    0
5    4
Name: date, dtype: int64
Run Code Online (Sandbox Code Playgroud)

注意:这可能快得多...