有什么比groupby更快地遍历组的?

时间:2019-06-05 21:09:16

标签: python pandas

因此,我将先前的问题缩小为:我有一个看起来像这样的DataFrame

              id  temp1  temp2
    9       10.0   True  False
    10      10.0   True  False
    11      10.0  False   True
    12      10.0  False   True
    17      15.0   True  False
    18      15.0   True  False
    19      15.0   True  False
    20      15.0   True  False
    21      15.0  False  False
    33      27.0   True  False
    34      27.0   True  False
    35      27.0  False   True
    36      27.0  False  False
    40      31.0   True  False
    41      31.0  False   True 
               .
               .
               .

实际上,它的长度是几百万行(并且还有其他几列)。

我目前正在做的是

    grouped = coinc.groupby('id')
    final = grouped.filter(lambda x: ( x['temp2'].any() and x['temp1'].any()))
    lanif = final.drop(['temp1','temp2'],axis = 1 )

(coinc是数据框的名称)

仅在某些具有相同id的行的temp1和temp2中都为true时,才保留行(按id分组)。例如,使用上述数据框,它将删除ID为15的行,但保留其他所有内容。

但是,这太慢了,我想知道是否有更快的方法来做到这一点。

4 个答案:

答案 0 :(得分:3)

在此处将filter与lambda函数一起使用会大大降低您的速度。您可以通过删除它来加快速度。


u = coinc.groupby('id')
m = u.temp1.any() & u.temp2.any()
res = df.loc[coinc.id.isin(m[m].index), ['id']]

将此与您在较大框架上的方法进行比较。

a = np.random.randint(1, 1000, 100_000)
b = np.random.randint(0, 2, 100_000, dtype=bool)
c = ~b

coinc = pd.DataFrame({'id': a, 'temp1': b, 'temp2': c})

In [295]: %%timeit
     ...: u = coinc.groupby('id')
     ...: m = u.temp1.any() & u.temp2.any()
     ...: res = coinc.loc[coinc.id.isin(m[m].index), ['id']]
     ...:
13.5 ms ± 476 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [296]: %%timeit
     ...: grouped = coinc.groupby('id')
     ...: final = grouped.filter(lambda x: ( x['temp2'].any() and x['temp1'].any()))
     ...: lanif = final.drop(['temp1','temp2'],axis = 1 )
     ...:
527 ms ± 7.91 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

np.array_equal(res.values, lanif.values)

True

答案 1 :(得分:1)

i, u = pd.factorize(coinc.id)
t = np.zeros((len(u), 2), bool)
c = np.column_stack([coinc.temp1.to_numpy(), coinc.temp2.to_numpy()])

np.logical_or.at(t, i, c)

final = coinc.loc[t.all(1)[i], ['id']]

final

      id
9   10.0
10  10.0
11  10.0
12  10.0
33  27.0
34  27.0
35  27.0
36  27.0
40  31.0
41  31.0

答案 2 :(得分:0)

问题不是groupby,而是lambda。 Lambda运算未向量化*。您可以使用agg更快地获得相同的结果。我会做的:

A

*这是一个非常细微的问题,对不起,我太过简化了。

答案 3 :(得分:0)

这是另一种替代解决方案

f = coinc.groupby('id').transform('any')
result = coinc.loc[f['temp1'] & f['temp2'], coinc.columns.drop(['temp1', 'temp2'])]