You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效创建依赖后续行的DataFrame目标列?

百万级外汇时间序列高效生成Target列的优化方案

问题背景

我正在处理外汇时间序列数据,数据格式如下:

DATEOPENHIGHLOWCLOSE
2023.01.031.207821.207821.207751.20775
2023.01.031.207711.207711.207711.20771
2023.01.031.207391.207391.207391.20731
2023.01.031.207421.207421.207421.20742
2023.01.031.207361.207361.207361.20736
2023.01.031.207441.207441.207441.20744
2023.01.031.207621.207621.207621.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 00:01:04