Pandas:选择 groupby.sum() 满足条件的行



在熊猫中,我有一个形式的数据帧:

>>> import pandas as pd  
>>> df = pd.DataFrame({'ID':[51,51,51,24,24,24,31], 'x':[0,1,0,0,1,1,0]})
>>> df
ID   x
51   0
51   1
51   0
24   0
24   1
24   1
31   0

对于每个"ID","x"的值被记录多次,它要么是0,要么是1。我想从包含"ID"的行中选择那些df,其中"x"至少两次为 1。

对于每个"ID",我设法计算"x"为1的次数,通过

>>> df.groupby('ID')['x'].sum()
ID
51    1
24    2
31    0

但我不知道如何从这里开始。我想要以下输出:

ID   x
24   0
24   1
24   1

使用 groupbyfilter

df.groupby('ID').filter(lambda s: s.x.sum()>=2)

输出:

   ID  x
3  24  0
4  24  1
5  24  1
df = pd.DataFrame({'ID':[51,51,51,24,24,24,31], 'x':[0,1,0,0,1,1,0]})
df.loc[df.groupby(['ID'])['x'].transform(func=sum)>=2,:]
out:
   ID  x
3  24  0
4  24  1
5  24  1

使用 np.bincountpd.factorize
替代高级技术以绘制更好的性能

f, u = df.ID.factorize()
df[np.bincount(f, df.x.values)[f] >= 2]
   ID  x
3  24  0
4  24  1
5  24  1

以令人讨厌的one-liner形式

df[(lambda f, w: np.bincount(f, w)[f] >= 2)(df.ID.factorize()[0], df.x.values)]
   ID  x
3  24  0
4  24  1
5  24  1

np.bincountnp.unique
我本可以将np.uniquereturn_inverse 参数一起使用来完成完全相同的事情。 但是,np.unique将对数组进行排序,并将更改解决方案的时间复杂度。

u, f = np.unique(df.ID.values, return_inverse=True)
df[np.bincount(f, df.x.values)[f] >= 2]

单行

df[(lambda f, w: np.bincount(f, w)[f] >= 2)(np.unique(df.ID.values, return_inverse=True)[1], df.x.values)]

定时

%timeit df[(lambda f, w: np.bincount(f, w)[f] >= 2)(df.ID.factorize()[0], df.x.values)]
%timeit df[(lambda f, w: np.bincount(f, w)[f] >= 2)(np.unique(df.ID.values, return_inverse=True)[1], df.x.values)]
%timeit df.groupby('ID').filter(lambda s: s.x.sum()>=2)
%timeit df.loc[df.groupby(['ID'])['x'].transform(func=sum)>=2]
%timeit df.loc[df.groupby(['ID'])['x'].transform('sum')>=2]

小数据

1000 loops, best of 3: 302 µs per loop
1000 loops, best of 3: 241 µs per loop
1000 loops, best of 3: 1.52 ms per loop
1000 loops, best of 3: 1.2 ms per loop
1000 loops, best of 3: 1.21 ms per loop

大数据

np.random.seed([3,1415])
df = pd.DataFrame(dict(
        ID=np.random.randint(100, size=10000),
        x=np.random.randint(2, size=10000)
    ))
1000 loops, best of 3: 528 µs per loop
1000 loops, best of 3: 847 µs per loop
10 loops, best of 3: 20.9 ms per loop
1000 loops, best of 3: 1.47 ms per loop
1000 loops, best of 3: 1.55 ms per loop

更大的数据

np.random.seed([3,1415])
df = pd.DataFrame(dict(
        ID=np.random.randint(100, size=100000),
        x=np.random.randint(2, size=100000)
    ))
1000 loops, best of 3: 2.01 ms per loop
100 loops, best of 3: 6.44 ms per loop
10 loops, best of 3: 29.4 ms per loop
100 loops, best of 3: 3.84 ms per loop
100 loops, best of 3: 3.74 ms per loop

最新更新