昨日の記事の続き
■目的
300万個のIDそれぞれに対して、1ヶ月分のデータが用意されている
データの中身は、説明変数と目的変数が1つずつ。
つまりテーブルのカラムは、ID、説明変数、目的変数の3つ
レコード数は300万×30日 ≒ 9000万
この時、300万のIDそれぞれに対し、30日分の説明変数と目的変数の単回帰を行い、
アウトプットとしてそれぞれのIDに対して相関係数、傾き、p値を格納したい。
■方針
300万のIDに対し、forループの中で回帰を行い、結果をリストとして格納
最後にリストを結合してデータフレームとする
■環境
EC2インスタンス (ubuntu: r5d.4xlarge)
JupyterLab 0.35.3
■課題
IDをindexにしてdf.loc[]で抽出 + daskデータフレームを使用でも処理が遅い (2ヶ月かかる)
■解決策
下記のような形のテーブルを
| ID | x | y |
|---|---|---|
| 01 | x.xx | y.yy |
| 01 | x.xx | y.yy |
| ・・・ | ・・・ | ・・・ |
| 01 | x.xx | y.yy |
| 02 | x.xx | y.yy |
| 02 | x.xx | y.yy |
| ・・・ | ・・・ | ・・・ |
| 02 | x.xx | y.yy |
下記のような形に変換
| ID | monthly_x | monthly_y |
|---|---|---|
| 01 | [x.xx, x.xx ,....] | [y.yy, y.yy ,....] |
| 02 | [x.xx, x.xx ,....] | [y.yy, y.yy ,....] |
| 03 | [x.xx, x.xx ,....] | [y.yy, y.yy ,....] |
| 04 | [x.xx, x.xx ,....] | [y.yy, y.yy ,....] |
| 05 | [x.xx, x.xx ,....] | [y.yy, y.yy ,....] |
| 06 | [x.xx, x.xx ,....] | [y.yy, y.yy ,....] |
変換の流れは下記2段階
-
pandas.pivot_tableを使用してpivot化 (内包表記を使える形にするため)
この処理は比較的高速。 (1IDあたり 約50μs、300万IDで 約2.5min)
import pandas as pd
# 元のデータフレームに日付を表す列を追加した状態(ここでは「date_」という列名とする)
pivot_df = pd.pivot_table(df, index="ID",columns="date_")
これでx,yそれぞれの値が日付ごとに横持された形になる。
- IDごとに月間(30日分)のxとyの値をリスト化して、別列に格納(内包表記で処理)
pivot_df["x"] = [list(pivot_df.x.loc[i,:]) for i in pivot_df.index]
pivot_df["y"] = [list(pivot_df.y.loc[i,:]) for i in pivot_df.index]
この処理は1IDあたり 約0.2ms、300万IDで 約10 ~ 15min (内包表記強し)
変換したテーブルに対して、回帰の処理を行ってみる
今回の回帰は、外れ値の事を考えロバスト回帰を使用
(ロバスト回帰についてはこちらがわかりやすい)
(ロバスト回帰の決定係数R^2の導出について、癖があるので時間があるときにまとめる、予定。あくまでも、予定)
import statsmodels.api as sm
pivot_df["model"] = [sm.RLM(i, sm.add_constant(j)) for i,j in zip(pivot_df.x ,pivot_df.y)]
pivot_df["result"] = [i.fit() for i in pivot_df.model]
上記コードで1IDあたり 約8.8ms
"model"の保存を行わず、ワンライナーでfitまで行うと1IDあたり 約7.9ms
ここまでで合計で、1IDあたり 約9ms
前回記事では、1IDの抽出だけで1.7sかかっていたので、
回帰まで含めても1/200、回帰の前処理までの時間で比較すると1/10000に処理時間を短縮できた
■結論
内包表記最強
300万IDのIDごとの処理時間が馬鹿正直にやると1年以上かかる計算だったのを、少しの工夫で8時間くらい回せば済むようにできた
(他に良い方法等あればご教示いただけるとありがたいです)
■今後の予定
回帰に関して、今回の記事では単純にStatsModelsを使っただけだが、ロバスト回帰の決定係数はStatsModels等どのライブラリでも簡単に導出することができない(私の知る限り)ため、少し工夫が必要になる。こちらに関して調べながらまとめられたらいいな~、とフワッと思っている(思っているだけ)