Pandas 获取每组中前 n 条记录

2024-12-19 09:23:00
admin
原创
132
摘要:问题描述:假设我有这样的 pandas DataFrame:df = pd.DataFrame({'id':[1,1,1,2,2,2,2,3,4], 'value':[1,2,3,1,2,3,4,1,1]}) 看起来像: id value 0 1 1 1 1 2 2 1 ...

问题描述:

假设我有这样的 pandas DataFrame:

df = pd.DataFrame({'id':[1,1,1,2,2,2,2,3,4], 'value':[1,2,3,1,2,3,4,1,1]})

看起来像:

   id  value
0   1      1
1   1      2
2   1      3
3   2      1
4   2      2
5   2      3
6   2      4
7   3      1
8   4      1

我想要获取一个包含每个 id 前 2 条记录的新 DataFrame,如下所示:

   id  value
0   1      1
1   1      2
3   2      1
4   2      2
7   3      1
8   4      1

我可以使用以下方式对组内的记录进行编号groupby

dfN = df.groupby('id').apply(lambda x:x['value'].reset_index()).reset_index()

看起来像:

   id  level_1  index  value
0   1        0      0      1
1   1        1      1      2
2   1        2      2      3
3   2        0      3      1
4   2        1      4      2
5   2        2      5      3
6   2        3      6      4
7   3        0      7      1
8   4        0      8      1

然后得到期望的输出:

dfN[dfN['level_1'] <= 1][['id', 'value']]

输出:

   id  value
0   1      1
1   1      2
3   2      1
4   2      2
7   3      1
8   4      1

但是有没有更有效/更优雅的方法来做到这一点?还有没有更优雅的方法来对每个组内的记录进行编号(如 SQL 窗口函数row_number())。


解决方案 1:

你试过吗

df.groupby('id').head(2)

生成的输出:

       id  value
id             
1  0   1      1
   1   1      2 
2  3   2      1
   4   2      2
3  7   3      1
4  8   4      1

(请记住,您可能需要先进行排序,具体取决于您的数据)

编辑:正如提问者提到的,使用

df.groupby('id').head(2).reset_index(drop=True)

删除多重索引并使结果平坦化:

    id  value
0   1      1
1   1      2
2   2      1
3   2      2
4   3      1
5   4      1

解决方案 2:

从 0.14.1 开始,您现在可以在对象上nlargest执行:nsmallest`groupby`

In [23]: df.groupby('id')['value'].nlargest(2)
Out[23]: 
id   
1   2    3
    1    2
2   6    4
    5    3
3   7    1
4   8    1
dtype: int64

您在那里也会获得原始索引,这有点奇怪,但这可能真的很有用,具体取决于您的原始索引什么。

如果您对它不感兴趣,您可以.reset_index(level=1, drop=True)将其完全摆脱掉。

(注意:从 0.17.1 版本开始您也可以在 DataFrameGroupBy 上执行此操作,但目前它仅适用于SeriesSeriesGroupBy。)

解决方案 3:

有时提前对整个数据进行排序非常耗时。我们可以先 groupby ,然后对每组进行 topk :

g = df.groupby(['id']).apply(lambda x: x.nlargest(topk,['value'])).reset_index(drop=True)

解决方案 4:

df.groupby('id').apply(lambda x : x.sort_values(by = 'value', ascending = False).head(2).reset_index(drop = True))
  • 这里对值进行升序排序,如果为 false,则结果类似于 nlargest,如果为 True,则结果类似于 nsmallest。

  • head 里面的值与我们在 nlargest 里面给出的值相同,以获取每个组要显示的值的数量。

  • reset_index 是可选的,不是必需的。

解决方案 5:

要获取每个组的前 N ​​行,另一种方法是通过groupby().nth[:N]。此调用的结果与相同groupby().head(N)。例如,对于每个 id 的前 2 行,调用:

N = 2
df1 = df.groupby('id', as_index=False).nth[:N]

为了获得每个组的最大 N 值,我建议采用两种方法。

  1. 首先按“id”和“value”排序(确保通过ascending适当使用参数对“id”按升序排序,“value”按降序排序),然后调用groupby().nth[]

N = 2
df1 = df.sort_values(by=['id', 'value'], ascending=[True, False])
df1 = df1.groupby('id', as_index=False).nth[:N]
  1. 另一种方法是对每个组的值进行排序,然后使用这些排序进行过滤。

# for the entire rows
N = 2
msk = df.groupby('id')['value'].rank(method='first', ascending=False) <= N
df1 = df[msk]

# for specific column rows
df1 = df.loc[msk, 'value']

这两个方法都比这里其他答案( 1、2、3groupby().apply() ) 中建议的调用快得多。在一个有 100k 行和 8000 个组的样本上,测试表明它比这些解决方案快 24-150 倍。groupby().nlargest()`%timeit`


另外,除了切片之外,您还可以将列表/元组/范围传递给调用.nth()

df.groupby('id', as_index=False).nth([0,1])

# doesn't even have to be consecutive
# the following returns 1st and 3rd row of each id
df.groupby('id', as_index=False).nth([0,2])

解决方案 6:

这适用于重复的值

如果前 n 个值中有重复的值,并且只想要唯一值,则可以这样做:

import pandas as pd

ifile = "https://raw.githubusercontent.com/bhishanpdl/Shared/master/data/twitter_employee.tsv"
df = pd.read_csv(ifile,delimiter='    ')
print(df.query("department == 'Audit'")[['id','first_name','last_name','department','salary']])

    id first_name last_name department  salary
24  12   Shandler      Bing      Audit  110000
25  14      Jason       Tom      Audit  100000
26  16     Celine    Anston      Audit  100000
27  15    Michale   Jackson      Audit   70000

If we do not remove duplicates, for the audit department we get top 3 salaries as 110k,100k and 100k.
If we want to have not-duplicated salaries per each department, we can do this:

(df.groupby('department')['salary']
 .apply(lambda ser: ser.drop_duplicates().nlargest(3))
 .droplevel(level=1)
 .sort_index()
 .reset_index()
)

This gives

department  salary
0   Audit   110000
1   Audit   100000
2   Audit   70000
3   Management  250000
4   Management  200000
5   Management  150000
6   Sales   220000
7   Sales   200000
8   Sales   150000





相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用