如何根据组标准使用Pandas对数据框进行子集化?

rol*_*and 5 python pandas

我有一个大型数据集,具有以下结构

User     X
1        0
1        0
2        0
2        0
2        1
3        0
3        0
Run Code Online (Sandbox Code Playgroud)

我想获取数据的子集,使得每个用户的列X的总和为0.给定上述示例,子集应仅包括用户1和3的观察结果,如下所示

User     X
1        0
1        0
3        0
3        0
Run Code Online (Sandbox Code Playgroud)

有没有办法使用groupby函数执行此操作而不分组数据?我希望子集包含个别观察.

DSM*_*DSM 8

作为@ unutbu答案的替代品,也有

>>> df.loc[df.groupby("User")["X"].transform(sum) == 0]
   User  X
0     1  0
1     1  0
5     3  0
6     3  0
Run Code Online (Sandbox Code Playgroud)

这将创建一个df用于选择器的-length布尔系列:

>>> df.groupby("User")["X"].transform(sum) == 0
0     True
1     True
2    False
3    False
4    False
5     True
6     True
dtype: bool
Run Code Online (Sandbox Code Playgroud)

transform当你想要通过缩减操作"广播"一个组的结果备份到每个组的所有元素时使用.它派上用场了.


unu*_*tbu 5

DSM的答案是使用布尔掩码选择行,即使DataFrame具有非唯一索引也能正常工作.我的方法使用索引值选择行,当索引是唯一的时稍微慢一些,当索引包含重复值时显着慢.

@roland:请考虑接受DSM的答案.


你可以使用groupby-filter:

In [16]: df.loc[df.groupby('User')['X'].filter(lambda x: x.sum() == 0).index]
Out[16]: 
   User  X
0     1  0
1     1  0
5     3  0
6     3  0
Run Code Online (Sandbox Code Playgroud)

groupby-filter本身只返回:

In [29]: df.groupby('User')['X'].filter(lambda x: x.sum() == 0)
Out[29]: 
0    0
1    0
5    0
6    0
Name: X, dtype: int64
Run Code Online (Sandbox Code Playgroud)

但是你可以使用它的索引,

In [30]: df.groupby('User')['X'].filter(lambda x: x.sum() == 0).index
Out[30]: Int64Index([0, 1, 5, 6], dtype='int64')
Run Code Online (Sandbox Code Playgroud)

使用选择所需的行df.loc.


这是我使用的基准:

In [49]: df2 = pd.concat([df]*10000)   # df2 has a non-unique index
Run Code Online (Sandbox Code Playgroud)

Ctrl- C这是因为它需要很长时间才能完成:

In [50]: %timeit df2.loc[df2.groupby('User')['X'].filter(lambda x: x.sum() == 0).index]
Run Code Online (Sandbox Code Playgroud)

当我意识到自己的错误时,我创建了一个具有唯一索引的DataFrame:

In [51]: df3 = df2.reset_index()     # this gives df3 a unique index

In [52]: %timeit df3.loc[df3.groupby('User')['X'].filter(lambda x: x.sum() == 0).index]
100 loops, best of 3: 13 ms per loop

In [53]: %timeit df3.loc[df3.groupby("User")["X"].transform(sum) == 0]
100 loops, best of 3: 11.4 ms per loop
Run Code Online (Sandbox Code Playgroud)

这表明即使使用非唯一索引,DSM的方法也能很好地运行:

In [54]: %timeit df2.loc[df2.groupby("User")["X"].transform(sum) == 0]
100 loops, best of 3: 11.2 ms per loop
Run Code Online (Sandbox Code Playgroud)