Python 熊猫:如何按组选择每组的第一行?

Python 熊猫:如何按组选择每组的第一行?,python,pandas,Python,Pandas,基本上和大熊猫一样 df = pd.DataFrame({'A' : ['foo', 'foo', 'foo', 'foo', 'bar', 'bar', 'bar', 'bar'], 'B' : ['3', '1', '2', '4','2', '4', '1', '3'], }) 排序看起来很有希望: df.sort('B') A B 1 foo 1 6 bar 1 2 foo 2 4 ba

基本上和大熊猫一样

df = pd.DataFrame({'A' : ['foo', 'foo', 'foo', 'foo', 'bar', 'bar', 'bar', 'bar'],
                'B' : ['3', '1', '2', '4','2', '4', '1', '3'],
                    })
排序看起来很有希望:

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
但是第一次不会得到想要的结果。。。 df.groupby('A').first()


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

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

Out[5]:
     B
A     
bar  1
foo  1
该函数可以用于您想要的内容,但它实际上是用于聚合的。这是一个简单的“先发制人”操作

您实际需要的是函数,默认情况下,该函数将返回第一行。通常你会考虑GROPPEBY,你应该作为子集=变量

df.drop_duplicates(subset='A')
你应该做你想做的

另外,
df.sort('A')
不会对数据帧df进行排序,而是返回一个已排序的副本。如果要对其进行排序,必须添加
inplace=True
参数

df.sort('A', inplace=True)

下面是另一种使用
groupby().rank()的方法

对于OP的示例数据帧,这将为您提供与@EdChum相同的答案,但如果您在排序过程中有任何联系,则可能会给出不同的答案,例如,使用以下数据:

df = pd.DataFrame({'A': ['foo', 'foo', 'bar', 'bar'], 
                   'B': ['2', '1', '1', '1'] })
在这种情况下,您可以使用可选的
方法
参数选择一些选项,具体取决于您希望如何处理排序关系:

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
如果需要对每个组运行计算,通常使用(请参阅:)

如果只想为列(或列的唯一组合)的每个唯一值保留第一行,则可以使用(或)进行排序,然后使用保留每个第一次出现的值

这种方法提供了一种无损的结果,其中初始数据帧结构和索引保持不变:

    A   B
4   bar 2
0   foo 3
可能并不总是按预期工作。使用
nth(0)
代替
first()

方法
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
在这里使用
first()
(排序后,就像EdChum在回答中正确评估一样)将跳过缺少的值(注意它是如何将不同行的值混合在一起的):

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

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

    B   C
A       
bar 1   Y
foo 1   NaN
为完整起见,此错误还影响
last()
,其正确替代项为
nth(-1)


在回答中发布此消息,因为它太长,无法发表评论。不确定这是否在问题的范围内,但我认为这与许多人寻找这个答案有关(就像我在写这篇文章之前一样),而且很容易错过。

谢谢@firelynx,但我真正想要的是
df.sort('B').groupby('A').first()
hey,我更喜欢@JohnE的方法,因为它更干净,更像SQL。也许在pandas中,您可以依靠排序在通过另一列(timsort?)分组后保持稳定,但它不像
rank
syntax@ihadanny. 我完全同意,这是一个糟糕的想法。问题是
df.sort('B')
返回df的一个排序副本,它不会改变df本身。如果要更改df,需要执行以下操作之一:
df=df.sort\u值('B')
df.sort\u值(inplace=True)
。(熊猫现在使用
sort\u values
而不是
sort
)注意-您可以通过输入
.sort\u values()
.drop\u duplicates()
列名列表来保持每个第一个唯一的组合。
.drop\u duplicates()
keep
参数的默认值为“first”。明确地设置它是可选的,但可以在这样的上下文中提高可读性。这个答案可能是2020年初该线程中最重要的。pandas聚合的长期缺陷是如此的沉默,以至于它似乎可以工作,直到您真正仔细地检查您的输出——特别是使用大型数据集时。很高兴nth()提供了一个快速的解决方法
    A   B
4   bar 2
0   foo 3
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
df.sort_values('B').groupby('A').first()

    B   C
A       
bar 1   Y
foo 1   X
df.sort_values('B').groupby('A').nth(0)

    B   C
A       
bar 1   Y
foo 1   NaN