pandas按日期保留列内最后一次值为1的信号,其余同天置0
按自然日保留当日最后一次1值止损信号的实现方案
你的需求本质是按自然日把长时序数据拆成单天片段,仅保留每个片段里时间最晚的一次信号为1的位置,同天其他所有信号值全部置0,最终保证任意自然日最多只出现一次值为1的信号行。
之前尝试drop_duplicates、普通groupby没得到预期结果的原因很简单:
drop_duplicates是基于列值做全局去重,只会机械地删除重复的1值,根本不会考虑时间顺序,更没法精准定位到当天最后一个1的位置- 常规
groupby取聚合值的写法,会把同一个分组下所有行的信号值统一成聚合结果,比如取max就会把同天所有行都变成1,根本做不到只留单个1、其余置0的效果
新手友好的直观循环实现
这种写法逻辑和手动处理的思路完全一致,逐行调试时很容易定位问题,没有晦涩的API:
import pandas as pd # 先备份原始信号值,避免后续赋值操作覆盖原始数据 original_signal = df['Long Stop Loss Signal'].copy() # 初始化目标列,全量填充0 df['Long Stop Loss Signal'] = 0 # 基于datetime类型的索引提取自然日维度,逐天拆分分组 for trade_date, group in df.groupby(df.index.date): # 定位当前自然日内所有原始信号为1的行 daily_1_rows = group[original_signal.loc[group.index] == 1] # 若当天存在1值信号,取时间最晚的那个1的位置赋值为1 if not daily_1_rows.empty: last_one_position = daily_1_rows.index[-1] df.loc[last_one_position, 'Long Stop Loss Signal'] = 1
适配长周期数据的高性能向量化实现
当数据覆盖多年时长、总行数达到几十万甚至百万规模时,循环的运行效率会偏低,可直接用pandas原生向量化运算实现,运行速度会提升几个量级,最终输出结果和循环写法完全一致:
# 备份原始信号值 original_signal = df['Long Stop Loss Signal'].copy() # 生成布尔标记:每个自然日内,仅最后一个1值的位置标记为True last_one_mask = original_signal.groupby(df.index.date).transform( lambda daily_series: ( daily_series.index == daily_series[daily_series == 1].index[-1] if (daily_series == 1).any() else False ) ) # 把布尔标记转为0/1值,替换原有信号列 df['Long Stop Loss Signal'] = last_one_mask.astype(int)
以上两种实现的输出完全匹配你给出的目标格式:
- 2008-01-01当天原始信号的最后一个1出现在03:30,转换后仅该位置为1,其余位置(包括之前09:56、03:29出现的1)全部置0
- 2008-01-02当天连续的1信号最后停在03:28,转换后仅该位置为1,其余全天的连续1全部置0
- 若某自然日全程没有出现值为1的信号,当天所有行的信号值自动保持为0
内容的提问来源于stack exchange,提问作者Jaffer Sheriff
相关产品推荐
相关产品推荐

