DataFrameのrolling利用した集計

やりたいこと

PythonのDataFrameでresampleを利用して一定期間毎に集計を行う場合、時間区切りをresample後の区間ではなく、元データの区間で一定期間毎に集計したい場合がある。

結論

rollingを使う

サンプル

例えば、以下のようなデータを各行毎に過去5分間の値で集計したい場合はrollingを使う必要がある。

                         open      high       low     close     volume      closetime quote_asset_volume  trade     taker_buy        taker_sell ignore
opentime
2023-09-13 04:19:00  25877.00  25877.00  25876.99  25876.99    3.24381  1694578799999     83940.04993810    266    1.10062000    28480.74374000      0
2023-09-13 04:20:00  25876.99  25879.70  25876.99  25879.70    2.42946  1694578859999     62867.29750250    176    1.43217000    37060.41785720      0
2023-09-13 04:21:00  25879.70  25889.54  25879.70  25889.54    5.93222  1694578919999    153560.82116000    364    4.01234000   103859.82802150      0
2023-09-13 04:22:00  25889.54  25892.23  25889.53  25892.23    4.03286  1694578979999    104411.25400370    155    1.63533000    42339.86011000      0
2023-09-13 04:23:00  25892.22  25908.30  25892.22  25907.75   15.43625  1694579039999    399847.18983080    348   12.15098000   314743.74357380      0
...                       ...       ...       ...       ...        ...            ...                ...    ...           ...               ...    ...
2023-09-13 12:34:00  26114.99  26140.00  26091.07  26091.47   84.72744  1694608499999   2212712.33725940   1468   39.45336000  1030282.74286180      0
2023-09-13 12:35:00  26091.07  26138.10  26083.33  26133.56   73.16256  1694608559999   1910696.61983500   1254   29.47772000   769604.49889400      0
2023-09-13 12:36:00  26133.56  26165.30  26115.00  26158.51   81.95945  1694608619999   2142623.98408060   1250   47.53452000  1242973.86156010      0
2023-09-13 12:37:00  26158.52  26245.00  26156.87  26238.11  180.19198  1694608679999   4722858.69512200   3833  116.25198000  3046681.93148760      0
2023-09-13 12:38:00  26238.10  26238.11  26162.19  26164.00   96.75866  1694608739999   2534558.00456210   1316   29.58746000   774699.71054490      0

resampleで集計すると5分間隔のデータとして集計される。

                         open       low      high     close      volume
opentime
2023-09-13 04:15:00  25877.00  25876.99  25877.00  25876.99     3.24381
2023-09-13 04:20:00  25876.99  25876.99  25928.65  25928.30    62.11364
2023-09-13 04:25:00  25928.30  25922.24  25945.00  25928.23    89.80995
2023-09-13 04:30:00  25928.23  25922.67  25949.19  25939.94    78.05533
2023-09-13 04:35:00  25939.94  25926.19  25939.94  25926.26    30.38798
...                       ...       ...       ...       ...         ...
2023-09-13 12:15:00  26215.00  26198.62  26247.08  26239.01   177.00272
2023-09-13 12:20:00  26239.00  26168.74  26244.45  26171.26   172.40035
2023-09-13 12:25:00  26171.26  26162.13  26203.22  26193.99   170.24136
2023-09-13 12:30:00  26193.99  26016.22  26215.95  26091.47  1113.58251
2023-09-13 12:35:00  26091.07  26083.33  26245.00  26164.00   432.07265

rollingで集計すると各行毎に直近5分間のデータを集計できる。
ただし、rollingではfirstやlastが使えないため、lambda式を利用してfirstとlastを取得する必要がある。

                         open       low      high     close     volume
opentime
2023-09-14 04:33:00       NaN       NaN       NaN       NaN        NaN
2023-09-14 04:34:00       NaN       NaN       NaN       NaN        NaN
2023-09-14 04:35:00       NaN       NaN       NaN       NaN        NaN
2023-09-14 04:36:00       NaN       NaN       NaN       NaN        NaN
2023-09-14 04:37:00  26239.30  26227.32  26239.30  26234.05   58.23133
...                       ...       ...       ...       ...        ...
2023-09-14 12:48:00  26417.90  26411.69  26453.19  26437.31  115.75706
2023-09-14 12:49:00  26414.53  26411.69  26453.19  26445.00   97.73054
2023-09-14 12:50:00  26429.52  26429.51  26459.39  26457.40  100.09218
2023-09-14 12:51:00  26448.82  26437.31  26467.25  26457.75   89.49876
2023-09-14 12:52:00  26438.86  26437.31  26467.25  26465.00   77.52727

ソースコード

検証に利用したソースコードは以下。

import pandas as pd
import requests


def create_resample_kline(data:pd.DataFrame, period:int):
    result = data.rolling(period).agg({
        'open':lambda rows: rows[0],
        'low':'min',
        'high':'max',
        'close':lambda rows: rows[-1],
        'volume':'sum'
    })
    return result


data = requests.get('https://api.binance.com/api/v3/klines', params={'symbol':'BTCUSDT', 'interval':'1m'})
kline = pd.DataFrame(data.json(),
                     columns=['opentime', 'open', 'high', 'low', 'close', 'volume', 'closetime', 'quote_asset_volume', 'trade', 'taker_buy', 'taker_sell', 'ignore'])
kline['opentime'] = pd.to_datetime(kline['opentime'], unit='ms')
kline.set_index('opentime', inplace=True)
kline = kline.astype({
    'open':'float',
    'high':'float',
    'low':'float',
    'close':'float',
    'volume':'float',
})

# resample
result = kline.resample('5T').agg({
    'open':     'first',
    'low':      'min',
    'high':     'max',
    'close':    'last',
    'volume':   'sum'
})
print(result)

# rolling
result = create_resample_kline(kline, 5)
print(result)

ただし、lambdaでの集計はデータ量が増えると遅くなる。
高速化する場合は以下のように記載すべき。

ここから先は

343字

¥ 300

この記事が気に入ったらチップで応援してみませんか?