Python pandas - 分组后过滤行

75

例如,我有以下表格:

index,A,B
0,0,0
1,0,8
2,0,8
3,1,5
4,1,3

按照 A 分组后:

0:
index,A,B
0,0,0
1,0,8
2,0,8

1:
index,A,B
3,1,5
4,1,3
我需要的是从每个组中删除列B中小于该组中所有行的列B的最大值的行。我在翻译和表述这个问题方面遇到了问题,以下是示例:
在组0的列B中,行的最大值为8。 因此,我想删除索引为0的行,并保留索引为1和2的行。
在组1的列B中,行的最大值为5。 因此,我想删除索引为4的行,并保留索引为3的行。
我尝试使用pandas筛选函数,但问题是它一次操作所有组中的所有行。
data = <example table>
grouped = data.groupby("A")
filtered = grouped.filter(lambda x: x["B"] == x["B"].max())

所以我理想中需要的是一个过滤器,遍历所有组中的所有行。

谢谢帮助!

P.S. 是否有仅删除组中行而不返回 DataFrame 对象的方法?


如果您在每个组中删除行,但返回数据框,则最后一位是完全模糊的:那么您想要返回什么? - Paul H
您的数据在将整个表与分组进行比较时不匹配,请澄清此问题。 - Paul H
抱歉,我在撰写这个问题时有点忙。现在数据是正确的。我的意思是只删除组中的行,并保持这些组不变 - 我需要应用几个过滤器,在每次应用后都需要新的分组。 - jirinovo
df.querypd.eval似乎非常适合这种用例。有关pd.eval()函数系列的信息、特性和用例,请访问使用pd.eval()在pandas中进行动态表达式评估 - cs95
如何将筛选器应用于groupby结果?我需要将groupby结果转换为数据框然后应用筛选器吗?我想创建一个“having”效果。dfg = df2[(df2 ['AcctType'] == 'E')]. groupby('CoaDescription')['TotalExpense']. sum()filter = dfg.apply(lambda g:g> 10000)dfg = dfg [filter] ax = sns.barplot(y = dfg.index,x = dfg)plt.show() - Golden Lion
4个回答

90

你只需要在 groupby 对象上使用 apply 即可。我修改了你的示例数据,使其更加清晰:

import pandas
from io import StringIO

csv = StringIO("""index,A,B
0,1,0.0
1,1,3.0
2,1,6.0
3,2,0.0
4,2,5.0
5,2,7.0""")

df = pandas.read_csv(csv, index_col='index')
groups = df.groupby(by=['A'])
print(groups.apply(lambda g: g[g['B'] == g['B'].max()]))

这将打印:

         A  B
A index      
1 2      1  6
2 4      2  7

谢谢,它运行得很好。我可以问一下,apply()具体是做什么的吗?而且我对g[g['B']有点困惑。 - jirinovo
6
@jirinovo 的代码中,groupby.apply(function) 会将每个分组都传递给指定的函数,并拼接所有结果。而 g[...] 是高级/布尔索引 -- 意味着它只返回满足内部条件的行。在这种情况下,条件是 g['B'] == g['B'].max(),即列 B 中的值等于该组中 B 的最大值的所有行。 - Paul H
3
感谢您。我个人认为,“filter”函数不根据某些标准过滤行的行为很容易误导人,这似乎是显而易见的行为。 - gustafbstrom

34

编辑:我刚学会了一种更简洁的方法,使用 .transform 分组方法:

def get_max_rows(df):
    B_maxes = df.groupby('A').B.transform(max)
    return df[df.B == B_maxes] 
B_maxes是一个序列,与原始的df具有相同的索引,其中包含每个A组的B的最大值。您可以将许多函数传递给transform方法。我认为它们输出后要么是标量,要么是相同长度的向量。您甚至可以通过一些字符串作为常见函数名称(如'median')来传递。这与Paul H的方法略有不同,因为'A'在结果中不会成为索引,但是您可以在之后轻松设置它。
import numpy as np
import pandas as pd
df_lots_groups = pd.DataFrame(np.random.rand(30000, 3), columns = list('BCD')
df_lots_groups['A'] = np.random.choice(range(10000), 30000)

%timeit get_max_rows(df_lots_groups)
100 loops, best of 3: 2.86 ms per loop

%timeit df_lots_groups.groupby('A').apply(lambda df: df[ df.B == df.B.max()])
1 loops, best of 3: 5.83 s per loop

编辑:

这里有一个抽象概念,允许您使用任何有效的比较运算符和任何有效的groupby方法从组中选择行:

def get_group_rows(df, group_col, condition_col, func=max, comparison='=='):
    g = df.groupby(group_col)[condition_col]
    condition_limit = g.transform(func)
    df.query('condition_col {} @condition_limit'.format(comparison))

因此,例如,如果您想要在每个A组中选择所有高于中位数B值的行,则调用:
get_group_rows(df, 'A', 'B', 'median', '>')

一些例子:
%timeit get_group_rows(df_lots_small_groups, 'A', 'B', 'max', '==')
100 loops, best of 3: 2.84 ms per loop
%timeit get_group_rows(df_lots_small_groups, 'A', 'B', 'mean', '!=')
100 loops, best of 3: 2.97 ms per loop

10
由于Pandas文档让我的血压飙升,所以我不得不减少咖啡的摄入量...请问您是从哪里了解到这件事的?另外,我允许您 链接到 transform() 文档页面 - mccc
3
我喜欢熊猫,但它的文档、错误信息和测试有所不足。我不记得我在哪里第一次看到transform被使用,但我很确定是在这里(指 Stack Overflow)。通过查看这里的问题和答案,我经常发现解决问题的新方法。如果你使用ipython notebook,你可以使用Tab键自动补全功能浏览各种方法,阅读文档字符串(不够好,我知道),并进行尝试(在这种情况下创建一个分组对象并浏览其方法)。 - JoeCondron
@mccc 你需要查看人工编写的文档,而不是自动生成的参考文献:http://pandas.pydata.org/pandas-docs/stable/groupby.html#transformation - Paul H
这个方法是否也可以不使用像max、mean等聚合函数?例如,如果我只想返回'some_column == 1'的组的行,这样可行吗? - Anonymous
这真的很棒,你有什么想法可以应用多个过滤条件吗? - John Stud
不确定您所说的“多个条件”具体是什么意思。我的初步回答是,您可以为每个条件生成一个布尔向量,并使用 & 连接它们。您能提供一个例子吗? - JoeCondron

12

以下是另一个示例:使用idxmax()和.loc()在分组操作后过滤具有最大值的行

In [465]: import pandas as pd

In [466]:   df = pd.DataFrame({
               'sp' : ['MM1', 'MM1', 'MM1', 'MM2', 'MM2', 'MM2'],
               'mt' : ['S1', 'S1', 'S3', 'S3', 'S4', 'S4'], 
               'value' : [3,2,5,8,10,1]     
                })

In [467]: df
Out[467]: 
   mt   sp  value
0  S1  MM1      3
1  S1  MM1      2
2  S3  MM1      5
3  S3  MM2      8
4  S4  MM2     10
5  S4  MM2      1

### Here, idxmax() finds the indices of the rows with max value within groups,
### and .loc() filters the rows using those indices :
In [468]: df.loc[df.groupby(["mt"])["value"].idxmax()]                                                                                                                           
Out[468]: 
   mt   sp  value
0  S1  MM1      3
3  S3  MM2      8
4  S4  MM2     10

4

所有这些答案都很好,但我想要以下内容:

(DataframeGroupby object) --> filter some rows out --> (DataframeGroupby object)

耸耸肩,看起来比我预想的更困难和有趣。所以这个一行代码实现了我的目标,但可能不是最有效的方式 :)
gdf.apply(lambda g: g[g['team'] == 'A']).reset_index(drop=True).groupby(gdf.grouper.names) 

可工作的代码示例:

import pandas as pd

def print_groups(gdf): 
    for name, g in gdf: 
        print('\n'+name) 
        print(g)

df = pd.DataFrame({'name': ['sue', 'jim', 'ted', 'moe'],
                   'team': ['A', 'A', 'B', 'B'], 
                   'fav_food': ['tacos', 'steak', 'tacos', 'steak']})                               

gdf = df.groupby('fav_food')                                                                                                                                           
print_groups(gdf)                                                                                                                                                      

    steak
        name team fav_food
    1  jim    A    steak
    3  moe    B    steak

    tacos
        name team fav_food
    0  sue    A    tacos
    2  ted    B    tacos

fgdf = gdf.apply(lambda g: g[g['team'] == 'A']).reset_index(drop=True).groupby(gdf.grouper.names)                                                                      
print_groups(fgdf)                                                                                                                                                     

    steak
      name team fav_food
    0  jim    A    steak

    tacos
      name team fav_food
    1  sue    A    tacos

大家为什么在Python编写代码时讨厌语义化变量名呢?“g”的意思是什么?“fgdf”的意思是什么? - bibscy
1
@bibscy g 是指分组(我想)。通常使用groupeddf 被广泛用作 dataframefgdf = 最终分组数据框(我猜)。 - MasayoMusic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接