pandas:如何在每个GROUP BY组中选择第一行?

iha*_*nny 19 python pandas

基本上与每个GROUP BY组中的Select第一行相同只在熊猫里

df = pd.DataFrame({'A' : ['foo', 'foo', 'foo', 'foo', 'bar', 'bar', 'bar', 'bar'],
                'B' : ['3', '1', '2', '4','2', '4', '1', '3'],
                    })
Run Code Online (Sandbox Code Playgroud)

排序看起来很有希望:

df.sort('B')

     A  B
1  foo  1
6  bar  1
2  foo  2
4  bar  2
0  foo  3
7  bar  3
3  foo  4
5  bar  4
Run Code Online (Sandbox Code Playgroud)

但是首先不会给出期望的结果... df.groupby('A').first()

     B
A     
bar  2
foo  3
Run Code Online (Sandbox Code Playgroud)

EdC*_*ica 15

通常,如果您希望您的数据在groupby中排序,但它不是要分组的列之一,那么sort在执行之前最好是df groupby:

In [5]:
df.sort_values('B').groupby('A').first()

Out[5]:
     B
A     
bar  1
foo  1
Run Code Online (Sandbox Code Playgroud)


fir*_*ynx 13

大熊猫GROUPBY功能可以用于你想要的东西,但它确实意味着聚集.这是一个简单的"先行"操作.

你真正想要的是pandas drop_duplicates函数,它默认会返回第一行.您通常会考虑groupby键,您应该作为subset = variable传递

df.drop_duplicates(subset='A')
Run Code Online (Sandbox Code Playgroud)

应该做你想做的.

此外,df.sort('A')不对DataFrame df进行排序,它返回一个已排序的副本.如果要对其进行排序,则必须添加inplace=True参数.

df.sort('A', inplace=True)
Run Code Online (Sandbox Code Playgroud)


Joh*_*hnE 8

以下是使用以下方法的替代方法groupby().rank():

df[ df.groupby('A')['B'].rank() == 1 ]

     A  B
1  foo  1
6  bar  1
Run Code Online (Sandbox Code Playgroud)

对于OP的示例数据帧,这给出了与@ EdChum相同的答案,但如果在排序期间有任何关系,可以给出不同的答案,例如,对于这样的数据:

df = pd.DataFrame({'A': ['foo', 'foo', 'bar', 'bar'], 
                   'B': ['2', '1', '1', '1'] })
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您可以使用可选method参数进行一些选项,具体取决于您希望如何处理排序关系:

df[ df.groupby('A')['B'].rank(method='average') == 1 ]   # the default
df[ df.groupby('A')['B'].rank(method='min')     == 1 ]
df[ df.groupby('A')['B'].rank(method='first')   == 1 ]   # doesn't work, not sure why
Run Code Online (Sandbox Code Playgroud)


小智 7

EdChum 的答案可能并不总是按预期工作。而不是first()使用nth(0).

该方法first()受到这个多年来未解决的错误的影响。代替预期的行为,first()返回每个组内的每一列中没有丢失的第一个元素即它忽略 NaN 值。例如,假设您有一个包含一些缺失值的第三列:

df = pd.DataFrame({'A' : ['foo', 'foo', 'bar', 'bar', 'bar'],
                   'B' : ['1', '2','2', '4', '1'],
                   'C' : [np.nan, 'X', 'Y', 'Y', 'Y']})

    A   B   C
0   foo 1   NaN
2   foo 2   X
3   bar 2   Y
4   bar 4   Y
5   bar 1   Y
Run Code Online (Sandbox Code Playgroud)

使用first()这里(排序后,就像 EdChum 在他们的答案中正确评估一样)将跳过缺失值(注意它是如何混合来自不同行的值):

df.sort_values('B').groupby('A').first()

    B   C
A       
bar 1   Y
foo 1   X
Run Code Online (Sandbox Code Playgroud)

获取完整行(包括缺失值)的正确方法是使用nth(0),它执行预期的操作:

df.sort_values('B').groupby('A').nth(0)

    B   C
A       
bar 1   Y
foo 1   NaN
Run Code Online (Sandbox Code Playgroud)

为了完整起见,这个错误也会影响last(),它的正确替代是nth(-1)

将其发布在答案中,因为评论太长了。不确定这是否在问题的范围内,但我认为它与许多寻找此答案的人有关(就像我在撰写本文之前一样)并且非常容易错过。

  • 截至 2020 年初,这个答案可能是该线程中最重要的答案。 pandas 聚合的长期存在的错误是如此安静,以至于它似乎有效,直到您仔细检查您的输出 - 特别是对于大型数据集。很高兴 nth() 提供了一种快速出路 (2认同)

fpe*_*syn 5

使用排序方法,然后保留第一个值,.drop_duplicates()并将其keep参数设置为\'first\'(默认)。这种方法的好处是可以保留索引。

\n

例子:

\n
df.sort_values(\'B\', ascending=True) \\\n  .drop_duplicates(\'A\', keep=\'first\')\n
Run Code Online (Sandbox Code Playgroud)\n

输出:

\n
    A   B\n1   foo 1\n6   bar 1\n
Run Code Online (Sandbox Code Playgroud)\n

在这种情况下,您不需要\xe2\x80\x99t GroupBy,因为不需要对每个组运行计算(请参阅:split-apply-combine 模式)。

\n