Pandas按Date和ticker分组取当日最低价后的最大值实现
逐组计算「当日最低价出现后区间最高价」的实现方案
和你现有代码完全兼容的实现路径
你已经通过df.groupby(['Date','ticker'])['Low'].idxmin()拿到了每组最低价对应的行索引,不需要改动这部分逻辑,顺着往下接就行:
- 先把拿到的最低价索引转成可关联的结构化表
# 复用你已有的最低价索引计算逻辑 low_min_idx = df.groupby(['Date','ticker'])['Low'].idxmin() # 转成带分组键的普通DataFrame,方便和原表拼接 low_pos_df = low_min_idx.reset_index(name='low_row_idx') - 把这个表和原DataFrame按分组键
Date、ticker左连接,给每一行打上它所属组的最低价所在行的索引值df_with_low_pos = df.merge(low_pos_df, on=['Date', 'ticker'], how='left') - 在连接后的表中,基于Datetime索引的大小关系标记「当前行是否在最低价点位之后」,再分组求对应区间的最高价
# 标记逻辑:当前行的时间戳 > 当日最低价所在行的时间戳 # 要是需要把最低价本身所在K线纳入统计,把>改成>=即可 df_with_low_pos['after_low_window'] = df_with_low_pos.index > df_with_low_pos['low_row_idx'] # 按原分组维度,筛选标记为真的行计算最大值 max_after_low = df_with_low_pos.groupby(['Date','ticker']).apply( lambda g: g.loc[g['after_low_window'], 'High'].max() ).reset_index(name='max_price_after_low')注:如果你的统计口径不是K线最高价列,把代码里的
'High'替换成你要统计的目标价格列名即可。
大数据量下的优化实现
如果你的数据集超过百万行(比如全市场1分钟级行情),上面逐组apply的写法会有性能损耗,可以换成纯向量化的组内位置判断,运算速度会提升数倍:
# 给每个分组内的行按时间顺序打从0开始的相对位置序号 df['group_row_seq'] = df.groupby(['Date','ticker']).cumcount() # 提前做全局索引到组内序号的映射,避免重复计算 idx_to_seq_map = df['group_row_seq'].to_dict() # 直接找到每个组内最低价对应的组内位置序号 df['low_seq'] = df.groupby(['Date','ticker'])['Low'].transform('idxmin').map(idx_to_seq_map) # 直接筛出组内序号大于最低价位置的行,分组求最大值 max_after_low_fast = df[df['group_row_seq'] > df['low_seq']].groupby( ['Date','ticker'] )['High'].max().reset_index()
必须注意的踩坑细节
- 所有索引大小比较都要在分组维度内生效,绝对不能直接拿全局的Datetime索引跨组比较:不同ticker、不同日期的行情时间戳是交叉混排的,脱离分组绑定的时间比较会出现跨组统计的bug
- 要提前校验每个(Date, ticker)分组内的Datetime索引是严格按交易时间升序排列的:时间排序不对的话,「之后的区间」的判断逻辑就完全失效
- 如果当日最低价出现在收盘时点,后续没有剩余交易数据,两种方法都会自动返回空值/NaN,和实际业务场景匹配,不需要额外做空值判断
- 如果你的数据里存在同一个时间戳下多根K线(比如同时间的逐笔成交),要先把同时间戳的行做聚合,不然会出现索引重复导致的位置判断错误
内容的提问来源于stack exchange,提问作者Wboy
相关产品推荐
相关产品推荐

