You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何筛选Pandas DataFrame以保留分组内最早和最晚年份的所有行?

问题:保留每个ID分组内最早和最晚年份的所有行

给定如下DataFrame:

import pandas as pd

data = [
    [123456, "2017", 150.235],
    [123456, "2017", 160],
    [123456, "2017", 135],
    [123456, "2017", 135],
    [123456, "2017", 135],
    [123456, "2018", 202.5],
    [123456, "2019", 168.526],
    [123456, "2020", 175.559],
    [123456, "2020", 176],
    [123456, "2021", 206.667],
    [789101, "2017", 228.9],
    [789101, "2018", 208],
    [789101, "2018", 208],
    [789101, "2018", 208],
]

df = pd.DataFrame(
    data,
    columns=["ID", "year", "value"],
)

需求:筛选该DataFrame,保留每个ID分组内最早年份的所有行(含重复value)以及最晚年份的所有行(含重复value)。

之前尝试的代码仅保留了最早年份的第一行和最晚年份的最后一行,无法满足需求:

g = df.groupby("ID")

(pd.concat([g.head(1), g.tail(1)])
   .drop_duplicates()
   .sort_values('ID')
   .reset_index(drop=True))

解决方案

方法1:使用transform标记分组内的最小/最大年份

# 先将year转为数值类型,确保年份比较准确
df['year'] = df['year'].astype(int)

# 按ID分组,获取每个分组的最小和最大年份,映射到每一行
grouped_year = df.groupby('ID')['year']
df['is_min_year'] = grouped_year.transform(lambda x: x == x.min())
df['is_max_year'] = grouped_year.transform(lambda x: x == x.max())

# 筛选出属于最早或最晚年份的行
result = df[df['is_min_year'] | df['is_max_year']]

# 清理临时列,按ID和年份排序并重置索引
result = result.drop(['is_min_year', 'is_max_year'], axis=1)
result = result.sort_values(['ID', 'year']).reset_index(drop=True)

print(result)

方法2:更简洁的掩码写法

df['year'] = df['year'].astype(int)

# 生成布尔掩码,判断每行年份是否为分组内的最小或最大值
mask = df.groupby('ID')['year'].transform(lambda x: x == x.min() | x == x.max())

# 筛选并整理结果
result = df[mask].sort_values(['ID', 'year']).reset_index(drop=True)

print(result)

说明

  • 先将year转为数值类型是为了避免字符串排序的潜在问题(比如"2019"和"202"的错误比较)。
  • transform方法会将分组计算的结果映射到原DataFrame的每一行,这样就能精准筛选出每个ID分组内所有属于最早或最晚年份的行,包括重复的value。

内容的提问来源于stack exchange,提问作者user

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:00:31