Pandas数据帧中高效筛选N个重复项并保留最后N条记录

花韻仙語
发布: 2025-09-05 15:48:02
原创
743人浏览过

Pandas数据帧中高效筛选N个重复项并保留最后N条记录

本教程将探讨如何在Pandas数据帧中高效处理重复数据,具体目标是针对指定列的重复组,仅保留每组的最后N条记录。我们将介绍并演示使用groupby().tail()方法的简洁实现,该方法对于在内存中处理中等规模数据集时,能提供比基于行号的窗口函数更直观和高效的解决方案。

问题描述与背景

在数据处理过程中,我们经常会遇到需要从数据集中筛选重复记录的场景。有时,我们并非要完全删除所有重复项,而是希望为每个重复组保留特定数量的记录,例如最新的n条或按某种顺序排列的最后n条记录。

考虑一个包含用户交易记录或日志条目的数据帧,其中first_name、last_name和sex可能存在大量重复,但id和country是唯一的。我们的目标是,对于每个相同的first_name、last_name和sex组合,只保留其对应的最后3条记录(通常根据id或其他时间戳字段来定义“最后”)。

原始数据帧示例如下:

id first_name last_name sex country
01 John Doe Male USA
02 John Doe Male Canada
03 John Doe Male Mexico
04 Mark Kay Male Italy
05 John Doe Male Spain
06 Mark Kay Male France
07 John Doe Male Peru
08 Mark Kay Male India
09 Mark Kay Male Laos
10 John Doe Male Benin

期望结果是,对于John Doe Male和Mark Kay Male这两个重复组,分别只保留其最后3条记录:

id first_name last_name sex country
05 John Doe Male Spain
06 Mark Kay Male France
07 John Doe Male Peru
08 Mark Kay Male India
09 Mark Kay Male Laos
10 John Doe Male Benin

对于大规模数据集,尤其是在分布式计算环境如Spark中,一种常见的解决方案是使用窗口函数(Window.partitionBy().orderBy().row_number())来为每个组内的记录分配行号,然后筛选出小于等于N的记录。这种方法在Spark中是标准且高效的,但在Pandas中,我们有更简洁且同样高效的替代方案。

Pandas groupby().tail() 方法详解

Pandas库提供了一个非常直观且高效的方法groupby().tail(n)来解决上述问题。它允许我们对数据帧进行分组,然后从每个组的末尾选择指定数量的记录。

核心思想

df.groupby(by_columns).tail(n)的工作原理是:

  1. 根据by_columns指定的列将数据帧分成若干个组。
  2. 对于每个独立的分组,从其末尾(即最后)选取n条记录。
  3. 将这些选取的记录合并成一个新的数据帧。

需要注意的是,tail()方法中的“末尾”是基于当前数据帧的行顺序。因此,如果“最后N条”的定义是基于某个特定字段(例如时间戳或ID)的最新记录,那么在应用groupby().tail()之前,对数据帧进行相应的排序是至关重要的一步。

降重鸟
降重鸟

要想效果好,就用降重鸟。AI改写智能降低AIGC率和重复率。

降重鸟 113
查看详情 降重鸟

实现步骤

以下是使用Pandas groupby().tail() 方法的详细实现步骤:

  1. 导入必要的库: 首先,我们需要导入pandas库。

  2. 创建示例数据帧: 为了演示,我们使用与问题描述中相同的数据来构建一个Pandas DataFrame。

  3. 数据排序(关键步骤): 由于我们希望保留“最后3条”记录,并且这个“最后”是基于id列的递增顺序来定义的,因此在执行分组和选择操作之前,必须先根据id列对整个数据帧进行升序排序。这确保了在每个组内,tail(3)操作会正确地选择具有最大id值的3条记录。

  4. 应用 groupby() 和 tail(): 使用groupby()方法指定分组的键(first_name, last_name, sex),然后链式调用tail(3)来保留每个组的最后3条记录。

  5. 重置索引(可选): groupby().tail()操作会保留原始数据帧的索引。如果需要一个从0开始的连续新索引,可以调用reset_index(drop=True)。

示例代码

import pandas as pd

# 1. 创建示例数据帧
data = {
    'id': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    'first_name': ['John', 'John', 'John', 'Mark', 'John', 'Mark', 'John', 'Mark', 'Mark', 'John'],
    'last_name': ['Doe', 'Doe', 'Doe', 'Kay', 'Doe', 'Kay', 'Doe', 'Kay', 'Kay', 'Doe'],
    'sex': ['Male', 'Male', 'Male', 'Male', 'Male', 'Male', 'Male', 'Male', 'Male', 'Male'],
    'country': ['USA', 'Canada', 'Mexico', 'Italy', 'Spain', 'France', 'Peru', 'India', 'Laos', 'Benin']
}

df = pd.DataFrame(data)

print("原始数据帧:")
print(df)
print("-" * 30)

# 2. 排序数据帧:确保 '最后N条' 是根据 'id' 的最新值
# 如果不排序,tail(3)会根据原始输入顺序的最后3行来取
df_sorted = df.sort_values(by='id', ascending=True)

# 3. 使用 groupby().tail() 保留每个组的最后3条记录
# 分组键为 'first_name', 'last_name', 'sex'
# tail(3) 表示保留每个组的最后3行
result_df = df_sorted.groupby(['first_name', 'last_name', 'sex']).tail(3)

# 4. 重置索引(可选,使索引从0开始连续)
result_df = result_df.reset_index(drop=True)

print("\n筛选后的数据帧 (保留每个重复组的最后3条记录):")
print(result_df)
登录后复制

输出结果

运行上述代码将得到以下输出:

原始数据帧:
   id first_name last_name   sex country
0   1       John       Doe  Male     USA
1   2       John       Doe  Male  Canada
2   3       John       Doe  Male  Mexico
3   4       Mark       Kay  Male   Italy
4   5       John       Doe  Male   Spain
5   6       Mark       Kay  Male  France
6   7       John       Doe  Male    Peru
7   8       Mark       Kay  Male   India
8   9       Mark       Kay  Male    Laos
9  10       John       Doe  Male   Benin
------------------------------

筛选后的数据帧 (保留每个重复组的最后3条记录):
   id first_name last_name   sex country
0   5       John       Doe  Male   Spain
1   6       Mark       Kay  Male  France
2   7       John       Doe  Male    Peru
3   8       Mark       Kay  Male   India
4   9       Mark       Kay  Kay   Laos
5  10       John       Doe  Male   Benin
登录后复制

方法比较与适用场景

  • Pandas groupby().tail():

    • 优点: 代码简洁,易于理解和实现。对于在内存中能够处理的数据集(通常是中等规模),其执行效率非常高。避免了显式创建额外的行号列,减少了中间步骤。
    • 适用场景: 适用于数据量可以在单机内存中处理的场景,或者作为数据探索和预处理的快速方法。
  • Spark 窗口函数 (row_number()):

    • 优点: 专为分布式计算设计,能够高效处理PB级别的大规模数据集。是Spark中处理此类分组排序筛选问题的标准和推荐方法。
    • 适用场景: 适用于需要处理超出单机内存容量的超大规模数据集,或在Hadoop/Spark集群环境中进行数据处理的场景。

选择建议: 如果您正在使用Pandas处理数据,并且数据集大小适中(能够完全载入内存),那么groupby().tail()无疑是实现此目标的最佳选择,它提供了简洁性和高效性。如果您在分布式环境(如Spark)中工作,并且数据量巨大,那么使用Spark的窗口函数是更合适的策略。

注意事项

  • 排序的重要性: 再次强调,如果“最后N条”的定义依赖于某个特定字段的顺序(例如时间戳、ID等),则在应用groupby().tail()之前,务必对数据帧进行相应的排序。否则,tail()将根据数据帧当前的物理顺序来选取行。
  • 性能考量: 尽管groupby().tail()在Pandas中效率很高,但Pandas本身是基于内存的库。对于数十GB甚至TB级别的数据,即使使用此方法,也可能遇到内存限制。在这种情况下,分布式计算框架(如Spark)是不可避免的选择。
  • head() 与 tail(): 与tail(n)类似,Pandas也提供了groupby().head(n)方法,用于保留每个分组的前N条记录。根据具体需求,可以选择使用head()或tail()。

总结

通过本教程,我们学习了如何在Pandas数据帧中高效地筛选出每个重复组的最后N条记录。df.sort_values().groupby().tail(n).reset_index(drop=True)这一组合操作提供了一个简洁而强大的解决方案,尤其适用于在内存中处理中等规模数据集的场景。理解其背后的原理以及排序的重要性,将帮助您更灵活、更高效地进行数据清洗和预处理工作。在面对不同规模和环境的数据时,选择合适的工具和方法是数据处理成功的关键。

以上就是Pandas数据帧中高效筛选N个重复项并保留最后N条记录的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号