在Pandas分组聚合中,按日期最值获取对应value列值的实现问题
Pandas分组聚合获取对应日期的value值问题
现有数据
先定义DataFrame并确保日期列格式正确:
import pandas as pd data = pd.DataFrame ({ 'group': ['A', 'A', 'B', 'B', 'C', 'C'], 'date': ['2023-01-15', '2023-02-20', '2023-01-10', '2023-03-05', '2023-02-01', '2023-04-10'], 'value': [10, 15, 5, 25, 8, 12]} ) # 转换日期格式为datetime,确保日期比较逻辑正常 data['date'] = pd.to_datetime(data['date'])
需求与问题
需要按group分组,获取每个组的最小日期、最大日期,以及对应日期的value值。原尝试的聚合代码无法运行:
## 原代码报错 output = ( data .groupby(['group'],as_index=False).agg( # 此处还有其他聚合函数 value_at_min = ('value' , lambda x: x.loc[x['date'].idxmin()]) , value_at_max = ('value' , lambda x: x.loc[x['date'].idxmax()]) ))
错误原因
在agg的lambda函数中,参数x是当前聚合列(这里是value列)的Series对象,无法通过x['date']访问同组的date列,因此会触发KeyError。
解决方案
方法一:使用groupby.apply直接操作分组后的DataFrame
通过apply可以获取每个分组的完整DataFrame,直接计算所需统计值:
def calc_group_metrics(group_df): min_date_idx = group_df['date'].idxmin() max_date_idx = group_df['date'].idxmax() return pd.Series({ 'min_date': group_df['date'].min(), 'max_date': group_df['date'].max(), 'value_at_min': group_df.loc[min_date_idx, 'value'], 'value_at_max': group_df.loc[max_date_idx, 'value'] }) # 执行分组计算并整理列顺序 output = data.groupby('group', as_index=False).apply(calc_group_metrics).reset_index() output = output[['group', 'min_date', 'max_date', 'value_at_min', 'value_at_max']]
方法二:先聚合日期再合并匹配对应value
先获取每个组的最小/最大日期,再通过两次合并匹配对应value,适合需要和其他聚合逻辑结合的场景:
# 第一步:获取每个组的最小、最大日期 date_summary = data.groupby('group').agg( min_date=('date', 'min'), max_date=('date', 'max') ).reset_index() # 第二步:合并获取最小日期对应的value output = pd.merge( date_summary, data[['group', 'date', 'value']], left_on=['group', 'min_date'], right_on=['group', 'date'] ).rename(columns={'value': 'value_at_min'}).drop(columns='date') # 第三步:合并获取最大日期对应的value output = pd.merge( output, data[['group', 'date', 'value']], left_on=['group', 'max_date'], right_on=['group', 'date'] ).rename(columns={'value': 'value_at_max'}).drop(columns='date')
方法三:用transform标记目标行再筛选聚合
通过transform标记每个组内最小/最大日期的行,再筛选后合并统计结果:
# 标记每个组内最小、最大日期的行 data['is_min_date'] = data['date'] == data.groupby('group')['date'].transform('min') data['is_max_date'] = data['date'] == data.groupby('group')['date'].transform('max') # 提取对应value值 min_value_df = data[data['is_min_date']][['group', 'value']].rename(columns={'value': 'value_at_min'}) max_value_df = data[data['is_max_date']][['group', 'value']].rename(columns={'value': 'value_at_max'}) # 合并日期统计与对应value date_summary = data.groupby('group').agg(min_date=('date', 'min'), max_date=('date', 'max')).reset_index() output = pd.merge(date_summary, min_value_df, on='group') output = pd.merge(output, max_value_df, on='group')
最终输出
无论哪种方法,都能得到如下结果:
group min_date max_date value_at_min value_at_max 0 A 2023-01-15 2023-02-20 10 15 1 B 2023-01-10 2023-03-05 5 25 2 C 2023-02-01 2023-04-10 8 12
内容的提问来源于stack exchange,提问作者Ankhnesmerira
相关产品推荐
相关产品推荐

