如何高效创建依赖后续行的DataFrame目标列?
百万级外汇时间序列高效生成Target列的优化方案
问题背景
我正在处理外汇时间序列数据,数据格式如下:
| DATE | OPEN | HIGH | LOW | CLOSE |
|---|---|---|---|---|
| 2023.01.03 | 1.20782 | 1.20782 | 1.20775 | 1.20775 |
| 2023.01.03 | 1.20771 | 1.20771 | 1.20771 | 1.20771 |
| 2023.01.03 | 1.20739 | 1.20739 | 1.20739 | 1.20731 |
| 2023.01.03 | 1.20742 | 1.20742 | 1.20742 | 1.20742 |
| 2023.01.03 | 1.20736 | 1.20736 | 1.20736 | 1.20736 |
| 2023.01.03 | 1.20744 | 1.20744 | 1.20744 | 1.20744 |
| 2023.01.03 | 1.20762 | 1.20762 | 1.20762 | 1.20762 |
需要新增布尔类型的target列,规则是:
- 对每行,检查当日所有后续行
- 若后续行的
high比当前行close高100点(即≥close+0.001),则target=True - 若在触发止盈前,后续行的
low比当前行close低10点(即≤close-0.0001),则target=False
原代码用迭代行+维护未结束交易列表的方式实现,10万行数据没问题,但百万级数据效率极低,求优化方案。
原代码低效原因
原代码的嵌套循环(每日内逐行遍历+遍历未结束交易)时间复杂度是O(N²),数据量翻倍时耗时会平方级增长;再加上频繁的列表remove操作(每次都是O(k)复杂度,k是当前未结束交易数),百万级数据下肯定卡得不行。
高效优化方案:反向遍历+向量化运算
核心思路是用反向遍历+数组追踪触发点替代嵌套循环,完全利用NumPy的向量化运算提速,逻辑和原代码完全一致,但效率提升几个数量级。
优化代码
import pandas as pd import numpy as np def add_target_data_optimized(df): new_df = df.copy() new_df['target'] = False # 按日期分组处理每日数据 for date, day_df in new_df.groupby('date'): close = day_df['close'].values high = day_df['high'].values low = day_df['low'].values row_indices = day_df.index.values total_rows = len(day_df) # 计算每行的止损、止盈价格 stop_loss = close - 0.0001 take_profit = close + 0.001 # 初始化触发位置数组,默认设为total_rows(表示当日内没触发) stop_trigger_pos = np.full(total_rows, total_rows) tp_trigger_pos = np.full(total_rows, total_rows) # 从倒数第二行开始反向遍历,追踪第一个触发止损/止盈的位置 for i in range(total_rows - 2, -1, -1): # 更新止损触发点:如果下一行的low触发了当前行的止损,就记为下一行位置;否则继承下一行的止损触发结果 if low[i+1] <= stop_loss[i]: stop_trigger_pos[i] = i + 1 else: stop_trigger_pos[i] = stop_trigger_pos[i+1] # 更新止盈触发点:同理,检查下一行的high是否触发止盈 if high[i+1] >= take_profit[i]: tp_trigger_pos[i] = i + 1 else: tp_trigger_pos[i] = tp_trigger_pos[i+1] # 确定target值:止盈触发点比止损早,且在当日内触发 target_mask = (tp_trigger_pos < stop_trigger_pos) & (tp_trigger_pos < total_rows) new_df.loc[row_indices[target_mask], 'target'] = True return new_df
为什么快?
- 时间复杂度降到了O(N):每组内只做一次反向遍历,没有嵌套循环
- 用NumPy数组替代Python列表,所有运算都是底层C实现,比Python层面的循环快得多
- 避免了频繁的列表增删操作,数组的赋值和访问都是O(1)复杂度
额外优化建议
- 如果日期分组特别多,可以用
swifter库实现并行分组处理,进一步提速 - 千万级以上的超大规模数据,可以用Dask进行分块处理,避免内存不足
内容的提问来源于stack exchange,提问作者Kyete Franck
相关产品推荐
相关产品推荐

