基于Pandas滚动窗口的条件检查

3

基于下面可重复的代码,我有以下数据框:

df.tail(10)

             open   high    low       close   200MA       20MA    Trend
date                            
2020-12-24  1.3273  1.3384  1.3257  1.3384  1.324826    1.325365    Up
2020-12-25  1.3408  1.3408  1.3268  1.3268  1.324926    1.326240    Up
2020-12-26  1.3268  1.3283  1.3217  1.3239  1.325008    1.326085    Up
2020-12-27  1.3240  1.3240  1.3078  1.3078  1.325009    1.325215    Up
2020-12-28  1.3103  1.3103  1.2878  1.2878  1.324973    1.323490    Down
2020-12-29  1.2893  1.2932  1.2876  1.2886  1.324951    1.321890    Down
2020-12-30  1.2871  1.2937  1.2810  1.2906  1.324923    1.319755    Down
2020-12-31  1.2905  1.3020  1.2905  1.2993  1.324934    1.318450    Down
2021-01-01  1.3006  1.3022  1.2896  1.2905  1.324893    1.316830    Down
2021-01-02  1.2909  1.3085  1.2890  1.3008  1.324908    1.315660    Down

我希望根据以下条件创建一个新的列:
  • 对于每一行,向后查看20个周期的滚动窗口
  • 如果在过去的20个周期中存在df['20MA'] > df['200MA']的行,且
  • 如果在过去的20个周期中还存在df['20MA'] < df['200MA']的行

期望输出:

  • 如果满足条件,则将值“Neutral”添加到名为“Trend 20 Window”的新列中。

我尝试使用Pandas中的滚动窗口功能,但无法获得所需的结果。

可复制示例代码:

import pandas as pd
import numpy as np

def genMockDataFrame(days,startPrice,colName,startDate,seed=None): 
   
    periods = days*24
    np.random.seed(seed)
    steps = np.random.normal(loc=0, scale=0.0018, size=periods)
    steps[0]=0
    P = startPrice+np.cumsum(steps)
    P = [round(i,4) for i in P]

    fxDF = pd.DataFrame({ 
        'ticker':np.repeat( [colName], periods ),
        'date':np.tile( pd.date_range(startDate, periods=periods, freq='H'), 1 ),
        'price':(P)})
    fxDF.index = pd.to_datetime(fxDF.date)
    fxDF = fxDF.price.resample('D').ohlc()
    return fxDF

df = genMockDataFrame(290,1.1904,'eurusd','19/3/2020',seed=1)

df["200MA"] = df["close"].rolling(window=200).mean()
df["20MA"] = df["close"].rolling(window=20).mean()
df.loc[df['20MA'] > df['200MA'], "Trend"] = "Up"
df.loc[df['20MA'] < df['200MA'], "Trend"] = "Down"
1个回答

4
您可以使用通过比较 df['20MA']df['200MA'] 创建的布尔掩码,使用 .gt().lt() 进行检查,并在滚动窗口内使用 .rolling() 检查满足条件的行数是否大于等于1,使用 .ge(1)。 然后对掩码使用 .loc() 分配“Neutral”到新列中匹配的行,如下所示:
df['Trend 20 Window'] = ''        # init to ''
periods = 20
mask = df['20MA'].gt(df['200MA']).rolling(periods).sum().ge(1) & df['20MA'].lt(df['200MA']).rolling(periods).sum().ge(1)
df.loc[mask, 'Trend 20 Window'] = 'Neutral'

演示

现在让我们使用您的样本数据(10行)和更小的滚动窗口(3)进行测试:

df['Trend 20 Window'] = ''
periods = 3
mask = df['20MA'].gt(df['200MA']).rolling(periods).sum().ge(1) & df['20MA'].lt(df['200MA']).rolling(periods).sum().ge(1)
df.loc[mask, 'Trend 20 Window'] = 'Neutral'

结果:

              open    high     low   close     200MA      20MA Trend Trend 20 Window
date                                                                                
2020-12-24  1.3273  1.3384  1.3257  1.3384  1.324826  1.325365    Up                
2020-12-25  1.3408  1.3408  1.3268  1.3268  1.324926  1.326240    Up                
2020-12-26  1.3268  1.3283  1.3217  1.3239  1.325008  1.326085    Up                
2020-12-27  1.3240  1.3240  1.3078  1.3078  1.325009  1.325215    Up                
2020-12-28  1.3103  1.3103  1.2878  1.2878  1.324973  1.323490  Down         Neutral
2020-12-29  1.2893  1.2932  1.2876  1.2886  1.324951  1.321890  Down         Neutral
2020-12-30  1.2871  1.2937  1.2810  1.2906  1.324923  1.319755  Down                
2020-12-31  1.2905  1.3020  1.2905  1.2993  1.324934  1.318450  Down                
2021-01-01  1.3006  1.3022  1.2896  1.2905  1.324893  1.316830  Down                
2021-01-02  1.2909  1.3085  1.2890  1.3008  1.324908  1.315660  Down                

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接