Python 3 pandas.groupby.filter

Fin*_*rog 11 python dataframe pandas

我正在尝试执行groupby过滤器,它与本文档中的示例非常相似: pandas groupby filter

>>> df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar',
...                           'foo', 'bar'],
...                    'B' : [1, 2, 3, 4, 5, 6],
...                    'C' : [2.0, 5., 8., 1., 2., 9.]})
>>> grouped = df.groupby('A')
>>> grouped.filter(lambda x: x['B'].mean() > 3.)
     A  B    C
1  bar  2  5.0
3  bar  4  1.0
5  bar  6  9.0
Run Code Online (Sandbox Code Playgroud)

我试图返回一个包含所有3列但只有2行的DataFrame.在按A列分组后,这两行包含列B的最小值.我尝试了以下代码行:

grouped.filter(lambda x: x['B'] == x['B'].min())
Run Code Online (Sandbox Code Playgroud)

但这不起作用,我得到这个错误: TypeError: filter function returned a Series, but expected a scalar bool

我试图返回的DataFrame应如下所示:

    A   B   C
0  foo  1  2.0
1  bar  2  5.0
Run Code Online (Sandbox Code Playgroud)

我很感激您提供的任何帮助.预先感谢您的帮助.

ALo*_*llz 6

有一个根本的区别:在文档例子,有一个单独的Boolean组。也就是说,返回整组如果平均大于3.在你的榜样,你要过滤特定行的一组。

对于您的任务,通常的技巧是对值进行排序并分别使用.head.tail过滤到具有最小值或最大值的行:

df.sort_values('B').groupby('A').head(1)

#     A  B    C
#0  foo  1  2.0
#1  bar  2  5.0
Run Code Online (Sandbox Code Playgroud)

对于更复杂的查询,您可以使用.transform.apply创建一个布尔值Series来切片。在这种情况下,如果多行共享最小值并且您需要所有行,则更安全:

df[df.groupby('A').B.transform(lambda x: x == x.min())]

#     A  B    C
#0  foo  1  2.0
#1  bar  2  5.0
Run Code Online (Sandbox Code Playgroud)


Mar*_*anD 6

简短的回答:

grouped.apply(lambda x: x[x['B'] == x['B']].min())
Run Code Online (Sandbox Code Playgroud)

...和更长的一个:

您的grouped对象有 2 组:

In[25]: for df in grouped:
   ...:     print(df)
   ...:     
('bar',      
     A  B    C
1  bar  2  5.0
3  bar  4  1.0
5  bar  6  9.0)

('foo',      
     A  B    C
0  foo  1  2.0
2  foo  3  8.0
4  foo  5  2.0)
Run Code Online (Sandbox Code Playgroud)

filter()GroupBy 对象的方法用于将组作为实体过滤,而不是用于过滤它们的各个行。所以使用该filter()方法,你可能只能得到4个结果:

  • 一个空的DataFrame(0 行),
  • 'bar' 组的行(3 行),
  • 'foo' 组的行(3 行),
  • 基(6行)

没有别的,不管方法中使用的参数(布尔函数)如何filter()


所以你必须使用其他方法。一个合适的apply()方法是非常灵活的方法,它允许您应用任意函数

  • 将 DataFrame(一组 GroupBy 对象)作为其唯一参数
  • 返回Pandas 对象标量

在您的情况下,该函数应返回(对于您的 2 个组中的每一个)列中具有最小值'B'的 1 行 DataFrame ,因此我们将使用布尔掩码

group['B'] == group['B'].min()
Run Code Online (Sandbox Code Playgroud)

用于选择这样的一行(或者 - 也许 - 更多行):

In[26]: def select_min_b(group):
   ...:     return group[group['B'] == group['B'].min()]
Run Code Online (Sandbox Code Playgroud)

现在使用这个函数作为apply()GroupBy 对象的方法的参数,grouped我们将获得

In[27]: grouped.apply(select_min_b)
Out[27]: 
         A  B    C
A                 
bar 1  bar  2  5.0
foo 0  foo  1  2.0
Run Code Online (Sandbox Code Playgroud)

笔记:

相同,但只有一个命令(使用lambda函数):

grouped.apply(lambda group: group[group['B'] == group['B']].min())
Run Code Online (Sandbox Code Playgroud)


WeN*_*Ben 5

不需要groupby:-)

df.sort_values('B').drop_duplicates('A')
Out[288]: 
     A  B    C
0  foo  1  2.0
1  bar  2  5.0
Run Code Online (Sandbox Code Playgroud)


Bal*_*Ben 3

>>> # sort=False to return the rows in the order they originally occurred
>>> df.loc[df.groupby("A", sort=False)["B"].idxmin()]

     A  B    C
0  foo  1  2.0
1  bar  2  5.0
Run Code Online (Sandbox Code Playgroud)