如何在Pandas+FreqTrade中高效实现Trend列按Up值规则填充?
高效实现Pandas中基于前值填充Trend列(无循环)
问题背景
我用Python Pandas结合FreqTrade工具时,遇到了DataFrame的列填充问题,现有DataFrame结构如下:
import pandas as pd data = { 'high': [123, 222, 333, 555, 231], 'low': [112, 121, 231, 444, 211], 'up': [0, 1, 1, 0, 0], 'trend': [0, 0, 0, 0, 0] } df = pd.DataFrame(data)
需要基于up列的值填充trend列,规则是:
- 当
up == 1时,trend = low - high(最初尝试过high/low,后来更新了规则) - 当
up == -1时,trend = high + low - 当
up == 0时,trend沿用前一行的trend值
最初尝试的问题
一开始写了批量赋值的代码:
# 设置up=1时的trend值 df.loc[df["up"] == 1, "trend"] = df["high"] / df["low"] # 设置up=0时沿用前值 df.loc[df["up"] == 0, "trend"] = df["trend"].shift(1)
但输出不符合预期:
| high | low | up | trend |
|---|---|---|---|
| 123 | 112 | 0 | 0 |
| 222 | 121 | 1 | 1.83 |
| 333 | 231 | 1 | 1.44 |
| 555 | 444 | 0 | 1.44 |
| 231 | 211 | 0 | 1.44 |
问题出在Pandas的批量赋值是基于原始数据的,shift(1)取的是赋值前的前一行值,没法实现连续的向前填充。
临时低效方案
后来更新了填充规则,但只能用循环解决,效率很低:
maxRange = len(df.trend) for x in range(maxRange): df.loc[df["up"] == 0, "trend"] = df["trend"].shift(1)
需要找无循环的高效实现方法。
高效无循环实现方案
核心思路是先算出所有trend的"锚点值"(即up不为0时的计算值),再用Pandas的向前填充(ffill)批量处理up==0的情况,全程用向量化操作,不用循环。
完整代码示例
import pandas as pd data = { 'high': [123, 222, 333, 555, 231], 'low': [112, 121, 231, 444, 211], 'up': [0, 1, 1, 0, 0], 'trend': [0, 0, 0, 0, 0] } df = pd.DataFrame(data) # 第一步:把up==0的trend设为NA,只保留锚点位置的值 df['trend'] = df.apply( lambda row: row['trend'] if row['up'] != 0 else pd.NA, axis=1 ) # 第二步:计算不同up值对应的trend锚点值 df.loc[df['up'] == 1, 'trend'] = df['low'] - df['high'] df.loc[df['up'] == -1, 'trend'] = df['high'] + df['low'] # 处理第一行的特殊情况:如果第一行up=0,保留初始值(按需调整) if pd.isna(df.iloc[0]['trend']): df.iloc[0]['trend'] = 0 # 第三步:向前填充所有up==0的位置 df['trend'] = df['trend'].ffill() print(df)
输出结果
high low up trend 0 123 112 0 0.0 1 222 121 1 -101.0 2 333 231 1 -102.0 3 555 444 0 -102.0 4 231 211 0 -102.0
原理说明
ffill()(即向前填充)会自动把每一个NA值替换为上一个非NA的值,完美匹配up==0时沿用前值的需求。- 先设置锚点再填充的方式,完全利用Pandas的向量化运算,比循环效率高几个量级,尤其适合大数据量的场景。
内容的提问来源于stack exchange,提问作者IT Proger
相关产品推荐
相关产品推荐

