如何按Id和Name分组筛选最新时间戳且非空值的Pandas行?
问题描述
我有如下Pandas DataFrame:
| Id | Name | Timestamp | Val 1 | Val 2 |
|---|---|---|---|---|
| 1 | A | 2017-04-13 14:09:00 | 2.3 | None |
| 1 | A | 2017-04-13 14:09:00 | 2.3 | 4.3 |
| 1 | A | 2017-04-11 13:09:00 | 2.1 | 3.3 |
| 1 | B | 2017-06-13 11:09:00 | None | None |
| 1 | B | 2017-06-13 11:09:00 | 3.3 | 1.3 |
| 2 | A | 2018-08-10 11:08:00 | 4.3 | None |
| 2 | A | 2017-04-13 14:29:00 | 4.3 | 4.3 |
| 3 | B | 2019-04-11 13:09:00 | None | None |
| 3 | B | 2017-06-13 11:09:00 | 1.2 | 2.1 |
| 4 | B | 2017-05-13 11:09:00 | 1.5 | 2.7 |
需求是:针对每个Id和Name分组,找出时间戳最新且Val 1、Val 2均为非空值的记录,预期输出如下:
| Id | Name | Timestamp | Val 1 | Val 2 |
|---|---|---|---|---|
| 1 | A | 2017-04-13 14:09:00 | 2.3 | 4.3 |
| 1 | B | 2017-06-13 11:09:00 | 3.3 | 1.3 |
| 2 | A | 2017-04-13 14:29:00 | 4.3 | 4.3 |
| 3 | B | 2017-06-13 11:09:00 | 1.2 | 2.1 |
| 4 | B | 2017-05-13 11:09:00 | 1.5 | 2.7 |
我尝试用代码df.groupby(['Id','Name']).max()分组取最大值,但返回的结果包含空值的行,请问该如何正确实现需求?
解决方案
你之前用的max()方法会直接取分组内各列的最大值,但不会过滤掉Val 1/Val 2为空的无效记录,需要调整步骤来实现需求:
步骤1:先过滤有效记录
首先筛选出Val 1和Val 2都不为空的行,排除无效数据:
filtered_df = df.dropna(subset=['Val 1', 'Val 2'])
步骤2:按分组排序并取最新记录
对过滤后的数据集,按Id和Name分组,每组内按Timestamp降序排序,然后取每组的第一条(也就是时间戳最新的有效记录):
result = filtered_df.sort_values('Timestamp', ascending=False).groupby(['Id', 'Name'], as_index=False).first()
或者用更高效的nth(0)写法,效果完全一致:
result = filtered_df.sort_values('Timestamp', ascending=False).groupby(['Id', 'Name'], as_index=False).nth(0)
完整代码示例
import pandas as pd # 构造原始数据 data = [ [1, 'A', '2017-04-13 14:09:00', 2.3, None], [1, 'A', '2017-04-13 14:09:00', 2.3, 4.3], [1, 'A', '2017-04-11 13:09:00', 2.1, 3.3], [1, 'B', '2017-06-13 11:09:00', None, None], [1, 'B', '2017-06-13 11:09:00', 3.3, 1.3], [2, 'A', '2018-08-10 11:08:00', 4.3, None], [2, 'A', '2017-04-13 14:29:00', 4.3, 4.3], [3, 'B', '2019-04-11 13:09:00', None, None], [3, 'B', '2017-06-13 11:09:00', 1.2, 2.1], [4, 'B', '2017-05-13 11:09:00', 1.5, 2.7] ] df = pd.DataFrame(data, columns=['Id', 'Name', 'Timestamp', 'Val 1', 'Val 2']) # 转换Timestamp为datetime类型(如果原始数据不是该类型的话) df['Timestamp'] = pd.to_datetime(df['Timestamp']) # 执行过滤和分组取最新操作 filtered_df = df.dropna(subset=['Val 1', 'Val 2']) result = filtered_df.sort_values('Timestamp', ascending=False).groupby(['Id', 'Name'], as_index=False).first() print(result)
关键说明
dropna(subset=['Val 1', 'Val 2']):确保只保留两个值都非空的有效行,从根源排除空值干扰;- 按
Timestamp降序排序后,每组的首行就是该分组内时间最新的记录; as_index=False:让分组后的结果保持和原始数据一致的列结构,避免Id和Name变成索引。
内容的提问来源于stack exchange,提问作者Abhishek Singh
相关产品推荐
相关产品推荐

