Python 有效地计算大熊猫的滚动时差
我有一个关于熊猫的小组,我试图计算一个人在每个阶段花费的时间。为了更好地理解这一点,我的数据集如下所示:Python 有效地计算大熊猫的滚动时差,python,pandas,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
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
我希望计算阶段持续时间,给出:
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
我在下面使用的方法非常慢。有没有更快的方法
df['stage_duration'] = df.groupby(['group', 'stage']).date.apply(lambda y: (y - y.iloc[0])).apply(lambda y:y / np.timedelta64(1, 'D')))
我想我应该在这里使用
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
(假设阶段是连续的。)
如果您只是减去每组中的第一个,请使用:
注意:这可能要快得多…基于您的代码(您的groupby/apply
),它看起来像(尽管有您的示例…但可能我误解了您的想法,然后Andy做了什么才是最好的主意)您使用的“日期”列是实际数据中的datetime64
dtype,而不是integer
dtype。此外,您还需要计算从给定组/阶段的第一次观察中测量的变化(以天为单位)。我认为这是一组更好的示例数据(如果我正确理解您的目标):
考虑到您只需修改应用程序(正如Jeff在评论中所建议的那样),就可以在应用后以矢量化方式除以timedelta64
(或者您可以在应用程序中执行此操作),从而获得一定的速度:
但是,如果您的数据是按组、阶段、日期顺序排列的,您也可以避免使用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
说明:请注意df['date']所创建的内容。其中(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
然后我将值与'date'列进行比较
编辑:正如Andy指出的那样,您也可以使用转换
:
>>> 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
速度:我使用一个类似的数据帧对这两种方法进行计时,共观察了400000次:
应用方法:
1 loops, best of 3: 18.3 s per loop
1 loops, best of 3: 1.64 s per loop
不适用方法:
1 loops, best of 3: 18.3 s per loop
1 loops, best of 3: 1.64 s per loop
因此,我认为避免应用程序可以显著提高速度您不需要最终的应用程序,请参见此处:,您可以简单地astype('timedelta64[D')
或除以np.timedelta64(1,'D')
(它们的取整方式略有不同。+1这可能对OP想要的东西更有意义……我认为你可以使用转换更有效地实现这一点。是的@Andy,我考虑过transform
,但至少对于0.13.1,我通常发现转换不比一般的应用快,所以我没有包括它。但我会我更新答案作为替代。有兴趣看看它是否更快,我的猜测是它会更快(尽管取决于群体规模-如果群体更大,怀疑会更快)@Andy,我的transform
慢了很多。我原以为Jeff提到了transform
的一些性能问题,但可能我记错了。哎呀,是的,你的方法快多了(专门针对这个连续的案例),误读了你的第二个解决方案!
1 loops, best of 3: 1.64 s per loop