是否有比groupby transform更快的替代方案?

2 投票
1 回答
1871 浏览
提问于 2025-04-18 00:04

我刚把Pandas更新到了0.13.1版本,但现在有一行代码(在0.12.0版本时就已经很慢了)变得慢得让人受不了。我想知道有没有更快的替代方法。

我在使用一个数据框。假设我有这样的数据:

import pandas as pd
df = pd.DataFrame({'A': ['one', 'one', 'two', 'three', 'three', 'one'], 'B': range(6)})
print df

       A  B
0    one  0
1    one  1
2    two  2
3  three  3
4  three  4
5    one  5

我通过先按'A'分组,然后选择每组中'B'的最后一个值,来创建第三列'C':

df['C'] = df.groupby('A')['B'].transform(lambda x: x.iloc[-1])
print df

      A   B  C
0    one  0  5
1    one  1  5
2    two  2  2
3  three  3  4
4  three  4  4
5    one  5  5

我的问题是:在Pandas 0.13.1版本中,有没有更快的方法来做到这一点?

谢谢

1 个回答

3

是的,这个功能还在等待实现:https://github.com/pydata/pandas/issues/6496

不过你可以这样做:

生成数据或分组:

In [31]: np.random.seed(0)

In [32]: N = 120000

In [33]: N_TRANSITIONS = 1400

In [35]: transition_points = np.random.permutation(np.arange(N))[:N_TRANSITIONS]

In [36]: transition_points.sort()

In [37]: transitions = np.zeros((N,), dtype=np.bool)

In [38]: transitions[transition_points] = True

In [39]: g = transitions.cumsum()

In [40]: df = pd.DataFrame({ "signal" : np.random.rand(N)})

In [41]: grp = df["signal"].groupby(g)

这里是实际的转换过程:

In [42]: result2 = grp.transform(lambda x: x.iloc[-1])

In [43]: result1 = pd.concat([ Series([r]*len(grp.groups[i])) for i, r in enumerate(grp.tail(1).values) ],ignore_index=True)

In [44]: result1.equals(result2)
Out[44]: True

时间记录。

In [26]: %timeit pd.concat([ Series([r]*len(grp.groups[i])) for i, r in enumerate(grp.tail(1).values) ],ignore_index=True)
10 loops, best of 3: 123 ms per loop

In [27]: %timeit grp.transform(lambda x: x.iloc[-1])
1 loops, best of 3: 472 ms per loop

撰写回答