Python pandas:在groupby中选择第二小的值

6 投票
3 回答
10598 浏览
提问于 2025-04-18 14:40

我有一个示例数据表,长得像这样:

import pandas as pd
import numpy as np
df = pd.DataFrame({'ID':[1,2,2,2,3,3,], 'date':array(['2000-01-01','2002-01-01','2010-01-01','2003-01-01','2004-01-01','2008-01-01'],dtype='datetime64[D]')})

我想要找出每个ID组中第二早的日期。所以我写了下面这个函数:

def f(x):
    if len(x)==1:
        return x[0]
    else:
        x.sort()
        return x[1]

然后我又写了:

df.groupby('ID').date.apply(lambda x:f(x))

结果却出现了错误。

你能帮我想办法让它正常工作吗?

3 个回答

1

你可能不想把第一个也是唯一的值当作第二个值,就像在被接受的答案中那样(也就是说,2000-01-01 不是第二个值,而是唯一的值)。如果是这种情况,你可以对每个组进行排名,这样就能更通用地选择第一个、第二个、第三个等最小值:

df['rank'] = df.sort_values('date').groupby('ID').cumcount()+1

要获取第二小的值:

df[df['rank'] == 2]

这将返回

ID  date        rank
2   2003-01-01  2
3   2008-01-01  2
3

看看这个索引的文档 - 一般来说,pandas 默认是通过标签来索引数据,而不是通过位置来索引,这就是你遇到 KeyError 的原因。

在你的具体情况下,你可以使用 .iloc 来进行基于位置的索引。

In [266]: def f(x):
     ...:     if len(x)==1:
     ...:         return x.iloc[0]
     ...:     else:
     ...:         x.sort()
     ...:         return x.iloc[1]
     ...:     

In [267]: df.groupby('ID').date.apply(f)
Out[267]: 
ID
1    2000-01-01
2    2003-01-01
3    2008-01-01
Name: date, dtype: datetime64[ns]
7

这个需要版本0.14.1。这样做会非常高效,特别是当你有很多数据组的时候,因为它不需要对这些数据进行完全排序。

In [32]: df.groupby('ID')['date'].nsmallest(2)
Out[32]: 
ID   
1   0   2000-01-01
2   1   2002-01-01
    3   2003-01-01
3   4   2004-01-01
    5   2008-01-01
dtype: datetime64[ns]

In [33]: df.groupby('ID')['date'].nsmallest(2).groupby(level='ID').last()
Out[33]: 
ID
1    2000-01-01
2    2003-01-01
3    2008-01-01
dtype: datetime64[ns]

撰写回答