Python 理財程式小技巧 – 優化程式執行速度,從減少重複索引龐大數據和向量化做起

一、前言

隨著 Python 越來越普及,許多讀者在求學階段就對 Python 有些著墨,甚至是使用 Python 來完成學校作業。但其實,除了資訊科系以外,大部分 Python 初學者的程式只能說是「跑得出結果」,但是效率是有明顯改善空間的。

確實,Python 在眾多程式語言當中,本身速度就沒有優勢,但我們可以透過一些小技巧,大幅縮短程式運行時間。

本篇主要講述的是 for 迴圈的設計,以及龐大數據量的 pandas 資料索引的優化。

立即訂閱電子報,掌握最新資訊!

    電子郵件

    有興趣的主題
    量化交易金融知識台灣股市國內期貨海外期貨虛擬貨幣

    有興趣的量化交易軟體/平台
    不清楚MultiChartsTradingViewPythonXQMT4MT5

    還有什麼詢問的?

    好富投 1920x400
    好富投 978x258

    點我了解更多資訊


    二、情境解說與資料讀取

    首先,這裡介紹一個很常見的情境,比較一下不同做法的速度:

    假設我們要對一個資料長度超過 100 萬的一分線價量資料 DataFrame,比對每筆收盤價有沒有比當根 K 棒開盤價高。(這通常會出現在我們要計算策略訊號的時候)

    首先,先讀取資料:

    
    import pandas as pd
    price = pd.read_csv(“BTCUSDT.csv”, index_col=”timestamp”)
    
    

    讀取進來的資料長相為:

    print(price) # DataFrame長寬: 1164743 rows x 5 columns
    timestampopenhighlowclosevolume
    2020/1/1 00:007170.257170.571577163.254.65E+05
    2020/1/1 00:017163.257163.757161.257161.751.50E+04
    2020/1/1 00:027159.57161.57155.57157.753.87E+05
    2020/1/1 00:037157.757162.57157.257162.55.35E+05
    2020/1/1 00:047160.757160.757157.257158.252.20E+05
    2022/3/19 23:56422364224242225422421.06E+06
    2022/3/19 23:57422424224542228422366.86E+05
    2022/3/19 23:58422364226342232422327.39E+05
    2022/3/19 23:59422324224942231422385.12E+05
    2022/3/20 00:00422384223842209422095.25E+05

    Py 101209161710
    Py 101209161711

    三、迴圈設計:初學者版本

    要比對每筆資料,一般初學者往往會很直覺地寫出這個解法:

    
    for i in range(len(price)):
        if price.iloc[i]["close"] > price.iloc[i]["open"]:
            movement = "rise"
        elif price.iloc[i]["close"] < price.iloc[i]["open"]:
            movement = "drop"
        else:
            movement = "flat"
    
    

    這個解法在學校應該沒什麼問題,放著一個晚上總是跑得完。實際上,我們實測這段程式碼花了 277.03 秒。這速度都超過一碗泡麵的時間了!

    那這段程式碼的問題在哪?

    首先,for 迴圈我們用 range 每圈對應到「第 i 行」,這個迴圈的寫法注定讓後面取用資料的時候,運行異常緩慢。再來,在迴圈內,我們調用了四次 price 整個 DataFrame 來找到該行的收盤價和開盤價的值。每一次這種調用不會多花多少時間,但是每一圈都有四次調用,而我們有 1,164,743 圈,累積下來的時間花費就變得非常可觀!

    所以,我們接著來修正看看,如果每圈只調用兩次 price 一整份的 DataFrame,可以節省多少時間?

    
    for i in range(len(price)):
        close_price = price.iloc[i]["close"]
        open_price = price.iloc[i]["open"]
        if close_price > open_price:
            movement = "rise"
        elif close_price < open_price:
            movement = "drop"
        else:
            movement = "flat"
    
    

    結果總花費時間為 179.66 秒。相比節省了將近 100 秒,也就是 36% 的時間!

    四、迴圈設計:使用 index

    如果我們再優化,不要用 iloc 的方式,改用 index 做 for 迴圈,效率有改善嗎?

    
    for index in price.index:
        close_price = price.loc[index, "close"]
        open_price = price.loc[index, "open"]
        if close_price > open_price:
            movement = "rise"
        elif close_price < open_price:
            movement = "drop"
        else:
            movement = "flat"
    
    

    程式碼優化如上方區塊紅色字體的部分。實測結果,我們在 20.19 秒就運行完成了!儘管每一圈迴圈都要調用兩次 price,但顯然透過 loc,比 iloc 查找資料的運行速度快得多了!

    五、迴圈設計:使用 iterrows

    如果是透過許多初學者愛用的 iterrows 來遍歷每一行呢?

    
    for index, row in price.iterrows():
        if row["close"] > row["open"]:
            movement = "rise"
        elif row["close"] < row["open"]:
            movement = "drop"
        else:
            movement = "flat"
    
    

    實測結果為 65.86 秒,比 iloc 快,但沒有 loc 快。

    六、效率最強王牌:向量化運算

    但其實,Python 最強王牌在這裡:向量化(Vectorize)運算!

    
    price["movement"] = pd.Series(
        np.where(price["close"] > price["open"], "rise", "drop"),
        index = price.index
    )
    price.loc[price["close"] == price["open"], "movement"] = "flat"
    
    

    這段程式碼僅花費 1.28 秒就完成任務!

    向量化(Vectorize)運算

    這裡講解一下程式碼:我們直接在 price 這個 DataFrame 新增一個 column 叫做“movement”,定義這欄的值是用 np.where 判斷收盤價是否大於開盤價的結果,若收盤價大於開盤價,則存為“rise”。若否,則存為“drop”。把這個 np.where 輸出的 array 轉成 pd.Series 格式,就能準確對齊 price 的 index 存入了!

    不過要注意,收盤價與開盤價比較,不只有上升、下跌,還有平盤。因此,要另外寫一行,把收盤價大於開盤價的 movement 的值都要改為“flat”,這才會是正確答案。

    七、結論

    Python 有很多小撇步可以改善運行效率,向量化是一個非常強大的武器!雖然有時候無法避免使用迴圈,但光是迴圈設計的不同,就有明顯速度差異了。如果有其他更有效率的運行方式,歡迎私訊或留言讓我們知道哦!讓我們一起成長下去吧!

      電子郵件

      有興趣的主題
      量化交易金融知識台灣股市國內期貨海外期貨虛擬貨幣

      有興趣的量化交易軟體/平台
      不清楚MultiChartsTradingViewPythonXQMT4MT5

      還有什麼詢問的?


      量化通粉絲社群,一起討論程式交易!

      加入LINE社群量化交易討論群」無壓力討論與分享!

      加入臉書社團「程式交易 Taiwan」即時獲取實用的資源!

      QP66
      QP66

      具備逾十年交易經驗,研究交易資產橫跨股票、債券、外匯、原物料,以及加密貨幣。現為量化避險基金交易員,亦曾任職於資金規模逾百億的避險基金,以及在區塊鏈企業擔任顧問一職。

      擅長從宏觀至微觀,由淺入深挖掘交易機會,並運用Python實現全自動化的投資組合管理。

      文章: 24

      發佈留言

      發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *