【问题标题】:Pandas Vectorization speed up dataframe function熊猫矢量化加速数据帧功能
【发布时间】:2022-01-17 11:05:23
【问题描述】:

我有这个超级趋势实现的 python 代码。我正在使用熊猫数据框。代码工作正常,但是随着数据帧长度的增加,supertrend 函数运行得越来越慢。我想知道如何将 supertrend 函数中的 for 循环转换为 Pandas 矢量化或使用 apply() 方法

def trueRange(df):
    df['prevClose'] = df['close'].shift(1)
    df['high-low'] = df['high'] - df['low']
    df['high-pClose'] = abs(df['high'] - df['prevClose'])
    df['low-pClose'] = abs(df['low'] - df['prevClose'])
    tr = df[['high-low','high-pClose','low-pClose']].max(axis=1)
    
    return tr

def averageTrueRange(df, peroid=12):
    df['trueRange'] = trueRange(df)
    the_atr = df['trueRange'].rolling(peroid).mean()
    
    return the_atr
    

def superTrend(df, peroid=5, multipler=1.5):
    df['averageTrueRange'] = averageTrueRange(df, peroid=peroid)
    h2 = ((df['high'] + df['low']) / 2)
    df['Upperband'] = h2 + (multipler * df['averageTrueRange'])
    df['Lowerband'] = h2 - (multipler * df['averageTrueRange'])
    df['inUptrend'] = None

    for current in range(1,len(df.index)):
        prev = current- 1
        
        if df['close'][current] > df['Upperband'][prev]:
            df['inUptrend'].iloc[current] = True
            
        elif df['close'][current] < df['Lowerband'][prev]:
            df['inUptrend'].iloc[current] = False
        else:
            df['inUptrend'].iloc[current] = df['inUptrend'][prev]
            
            if df['inUptrend'][current] and df['Lowerband'][current] < df['Lowerband'][prev]:
                df['Lowerband'].iloc[current] = df['Lowerband'][prev]
                
            if not df['inUptrend'][current] and df['Upperband'][current] > df['Upperband'][prev]:
                df['Upperband'].iloc[current] = df['Upperband'][prev]

矢量版

def superTrend(df, peroid=5, multipler=1.5):
    df['averageTrueRange'] = averageTrueRange(df, peroid=peroid)
    h2 = ((df['high'] + df['low']) / 2)
    df['Upperband'] = h2 + (multipler * df['averageTrueRange'])
    df['Lowerband'] = h2 - (multipler * df['averageTrueRange'])
    df['inUptrend'] = None


    cond1 = df['close'].values[1:] > df['Upperband'].values[:-1]
    cond2 = df['close'].values[1:] < df['Lowerband'].values[:-1]

    df.loc[cond1, 'inUptrend'] = True
    df.loc[cond2, 'inUptrend'] = False

    df.loc[(~cond1) & (cond2), 'inUptrend'] = df['inUptrend'][:-1]
    df.loc[(~cond1) & (cond2) & (df['inUptrend'].values[1:] == True) & (df['Lowerband'].values[1:] < df['Lowerband'].values[:-1]), 'Lowerband'] = df['Lowerband'][:-1]
    df.loc[(~cond1) & (cond2) & (df['inUptrend'].values[1:] == False) & (df['Upperband'].values[1:] > df['Upperband'].values[:-1]), 'Upperband'] = df['Upperband'][:-1]
   
Traceback (most recent call last):

  File "<ipython-input-496-ad346c720199>", line 3, in <module>
    superTrend(df, peroid=2, multipler=1.5)

  File "<ipython-input-495-57c750e273c2>", line 16, in superTrend
    df.loc[(~cond1) & (cond2) & (df['inUptrend'].values[1:] == True) & (df['Lowerband'].values[1:] < df['Lowerband'].values[:-1]), 'Lowerband'] = df['Lowerband'][:-1]

  File "C:\Users\fam\Anaconda3\lib\site-packages\pandas\core\indexing.py", line 189, in __setitem__
    self._setitem_with_indexer(indexer, value)

  File "C:\Users\fam\Anaconda3\lib\site-packages\pandas\core\indexing.py", line 606, in _setitem_with_indexer
    raise ValueError('Must have equal len keys and value '

ValueError: Must have equal len keys and value when setting with an iterable

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:

    使用.values[1:].values[:-1] 进行矢量化比较。
    也就是说,.values[1:] 在您的代码中是 current.values[:-1]prev

    这是将 IF 语句转换为向量化比较的示例。

    cond1 = df['close'].values[1:] > df['Upperband'].values[:-1]
    cond1 = np.insert(cond1, 0, False)
    df.loc[cond1, 'inUptrend'] = True
    

    使用insert的原因是第0个元素没有可比较的元素。

    【讨论】:

    • 嘿,我已经更新了函数和矢量化版本的问题,你能帮我检查一下代码吗?它不像循环版本那样工作
    猜你喜欢
    • 2019-06-04
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    • 2015-09-30
    • 2018-02-05
    • 2020-10-02
    • 2021-12-28
    • 1970-01-01
    相关资源
    最近更新 更多