Pandas Groupby:如何从分组中提取首个、末尾或首个非NaN值
解决Pandas groupby.agg聚合时保留非数值列的问题
核心问题分析
你遇到的问题本质是:agg()聚合时,未指定非数值列的聚合规则导致信息丢失;而用head/tail无效,是因为这两个方法返回的是Series而非单个标量,不符合agg()对聚合函数的要求(需返回单个值)。下面针对你的两个场景给出具体解决方案:
场景1:1分钟时间重采样保留Name列
针对含DateTime索引、Name、Price、Volume的DataFrame,只需在agg()中为Name指定first/last(根据需求选择,若每组Name一致,用first即可):
# 假设df的DateTime是索引 1_min_df = df.groupby(pd.Grouper(freq="1T")).agg({ 'Name': 'first', # 保留每组第一个Name值,若每组Name唯一/一致更合适 'Price': 'ohlc', 'Volume': 'sum' })
如果需要保留每组的最后一个Name值,把'first'换成'last'即可。
场景2:按累计Volume分组保留首行DateTime
首先要确保DateTime是普通列(如果是索引,先转成列),然后同样用first聚合DateTime:
# 若DateTime是索引,先转为列 df_concat['DateTime'] = df_concat.index # 按累计Volume分组并聚合 vol_1000_df = df_concat.groupby(bar(np.cumsum(df_concat['Volume']), 1000)).agg({ 'DateTime': 'first', # 保留每组的首个DateTime值 'Name': 'first', # 按需保留Name的首/尾值 'Price': 'ohlc', 'Volume': 'sum' })
进阶:提取非数值列的首个非NaN值
如果非数值列存在NaN,想提取每组第一个非空值,可以自定义聚合函数:
import numpy as np def first_non_nan(x): filtered = x.dropna() return filtered.iloc[0] if not filtered.empty else np.nan # 使用自定义函数聚合 vol_1000_df = df_concat.groupby(bar(np.cumsum(df_concat['Volume']), 1000)).agg({ 'Name': first_non_nan, 'DateTime': 'first', 'Price': 'ohlc', 'Volume': 'sum' })
关键注意事项
- 避免用
head/tail作为聚合规则:这两个方法返回的是Series,agg()无法将其解析为单个值,会导致报错或不符合预期 - 索引列的处理:若要保留索引信息,先通过
reset_index()或直接赋值将索引转为普通列,再进行聚合 - 一致性验证:如果非数值列(如Name)在每组内值一致,用
first/last完全没问题;若值不一致,需提前确认业务需求(取首/尾还是其他规则)
内容的提问来源于stack exchange,提问作者JackyChan
相关产品推荐
相关产品推荐

