【问题标题】:How to optimize Pandas DataFrame speed?如何优化 Pandas DataFrame 速度?
【发布时间】:2019-03-20 02:27:52
【问题描述】:

我有这个 pandas 代码,但是速度很慢。我该如何优化它?这意味着当我运行它时,大约需要 4 秒钟。我在这里调用的这段代码是我一遍又一遍地调用的代码,它应该尽可能快,目前还没有……有人知道吗?

    self.dataframe = pd.DataFrame(columns=list(['O' ,'H' ,'L' ,'C' ,'RSI', 'Upper Band', 'Lower Band'])) 

    BinanceHistoricalUrl = "https://api.binance.com/api/v1/klines?"
    BinanceHistoricalPayload = {'symbol' : 'BTCUSDT','interval': '1m','limit': 100}
    HistoricalRequestData = requests.get(url=BinanceHistoricalUrl, params=BinanceHistoricalPayload).json()

    Lenght = len(HistoricalRequestData)

    for i in range(Lenght):

        O = HistoricalRequestData[i][1]
        O = "{:.4f}".format(O)
        O = float(O)

        H = HistoricalRequestData[i][2]
        H = "{:.4f}".format(H)
        H = float(H)

        L = HistoricalRequestData[i][3]
        L = "{:.4f}".format(H)
        L = float(L)

        C = HistoricalRequestData[i][4]
        C = "{:.4f}".format(C)
        C = float(C)

#        Volume = HistoricalRequestData[0]["priceData"][i]['volume']
#        Volume = "{:.4f}".format(Volume)
#        Volume = float(Volume)

        self.dataframe = self.dataframe.append({'O': O, 'H' : H, 'L' : L, 'C' : C}, ignore_index=True)         

    make_RSI(self.dataframe)
    make_bollinger_bands(self.dataframe)
    RSI = self.dataframe['RSI'][99]
    RSI = float(RSI)
    UppBoll = self.dataframe['Upper Band'][99]
    UndBoll = self.dataframe['Lower Band'][99]
    previouscloseprice = self.dataframe['C'][99]
    MA = self.dataframe['20 Day MA'][99]
    DistanceUppBoll = UppBoll - MA
    DistanceUppBoll = float(DistanceUppBoll)
    DistanceUndBoll = UndBoll - MA
    DistanceUndBoll = float(DistanceUndBoll)

    self.dataframe = self.dataframe.iloc[0:0]




def make_RSI(dataframe):
    delta = dataframe['C'].diff()
    dUp, dDown = delta.copy(), delta.copy()
    dUp[dUp < 0] = 0
    dDown[dDown > 0] = 0
    RolUp = dUp.rolling(14).mean()
    RolDown = dDown.rolling(14).mean().abs()

    RS = RolUp / RolDown
    dataframe['RSI'] = 100 - (100/(1+RS))

def make_bollinger_bands(dataframe):
    dataframe['20 Day MA'] = dataframe['C'].rolling(window=20).mean()
    dataframe['20 Day STD'] = dataframe['C'].rolling(window=20).std()
    dataframe['Upper Band'] = dataframe['20 Day MA'] + (dataframe['20 Day STD'] * 2)
    dataframe['Lower Band'] = dataframe['20 Day MA'] - (dataframe['20 Day STD'] * 2)

【问题讨论】:

  • 你看过pandas' guide for performance tuning吗?我不确定make_RSImake_bollinger_bands 做了什么,但我怀疑它们也可以进行优化。
  • 嗨 jandevies,欢迎来到 SO。请生成mcve,特别是发布您的原始数据样本和预期输出。在我看来,这是一个非常容易矢量化的问题。
  • @JordanSinger 我不确定 OP 使用的是哪个库,但有许多优化良好的金融库。
  • 我正在使用熊猫@user32185
  • @jandevries 这很清楚。不过,如果您能够制作一个可重复的示例,您很快就会得到答案。

标签: python pandas dataframe optimization


【解决方案1】:

您的代码并不是真正可重现的。来点菜吧

# first import libraries
import pandas as pd
import requests

#define functions
def make_RSI(dataframe):
    delta = dataframe['C'].diff()
    dUp, dDown = delta.copy(), delta.copy()
    dUp[dUp < 0] = 0
    dDown[dDown > 0] = 0
    RolUp = dUp.rolling(14).mean()
    RolDown = dDown.rolling(14).mean().abs()

    RS = RolUp / RolDown
    dataframe['RSI'] = 100 - (100/(1+RS))

def make_bollinger_bands(dataframe):
    dataframe['20 Day MA'] = dataframe['C'].rolling(window=20).mean()
    dataframe['20 Day STD'] = dataframe['C'].rolling(window=20).std()
    dataframe['Upper Band'] = dataframe['20 Day MA'] + (dataframe['20 Day STD'] * 2)
    dataframe['Lower Band'] = dataframe['20 Day MA'] - (dataframe['20 Day STD'] * 2)

#############
# your code #
############
BinanceHistoricalUrl = "https://api.binance.com/api/v1/klines?"
BinanceHistoricalPayload = {'symbol' : 'BTCUSDT','interval': '1m','limit': 100}
#get data
HistoricalRequestData = requests.get(url=BinanceHistoricalUrl, 
                                     params=BinanceHistoricalPayload)\
                                .json()

# put on a dataframe
dataframe = pd.DataFrame(HistoricalRequestData)
# consider only columns from 1 to 4(included)
dataframe = dataframe[dataframe.columns[1:5]]
# assign column names
dataframe.columns = ["O", "H", "L", "C"]
# set type float
dataframe = dataframe.astype("float64")
# call functions
make_RSI(dataframe)
make_bollinger_bands(dataframe)

目前还不太清楚你最后想要实现什么,但你只是在使用dataframe 的最后一行,所以你可以考虑

last = dataframe.iloc[-1]
DistanceUppBoll = last["Upper Band"] - last["20 Day MA"]
DistanceUndBoll = last["Lower Band"] - last["20 Day MA"]

这在我的笔记本电脑上占用了717 ms。我想这主要取决于您的连接速度。

注意:这里的要点是尽可能避免循环。

更新:如果您尝试实施基于基本技术分析的交易策略,您应该看看如何在流中计算MA

【讨论】:

  • 嗯,我试过了,它看起来很好用值到正确的列....您能否向我解释一下它是如何将其分配到相应的位置的,因为我似乎没有得到那个..如果我将不同的数据集连接到它会发生什么?例如具有以下格式:pastebin.com/wrkZ5nNN 我无法想象它自己将正确的值分配给正确的列?你能解释一下吗?此外,谢谢,这非常有用!
  • PS,我的需要大约 400 毫秒,这太棒了!
  • 这里我使用了 HistoricalRequestData 是一个列表列表这一事实。对于每个列表,索引为 1、2、3、4 的元素分别是 OHLC。当我执行 df.columns[1:5] 时,我只是选择这些列。如果答案有用,请考虑接受和/或投票。
  • 所以 df.columns[1:5] 需要: [[false,true,true,true,true,false,false,false]] 来自列表等,所以如果我想要第一个例如 3 个值我会做 df.columns[0:4] 导致:[[true,true,true,false,false,false,false,false]] 并且它对所有列表执行此操作,等等。 ..?
  • @jandevries 现场!最终为您在之前评论中发布的数据打开另一个问题。
猜你喜欢
  • 1970-01-01
  • 2019-01-07
  • 1970-01-01
  • 2011-08-01
  • 2016-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多