2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

300万IDデータのループ処理に苦労していた話

Last updated at Posted at 2020-01-10

昨日の記事の続き

■目的

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)
code1.py

import pandas as pd
# 元のデータフレームに日付を表す列を追加した状態(ここでは「date_」という列名とする)
pivot_df = pd.pivot_table(df, index="ID",columns="date_")

これでx,yそれぞれの値が日付ごとに横持された形になる。

  • IDごとに月間(30日分)のxとyの値をリスト化して、別列に格納(内包表記で処理)
code2.py

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の導出について、癖があるので時間があるときにまとめる、予定。あくまでも、予定)

code3.py
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等どのライブラリでも簡単に導出することができない(私の知る限り)ため、少し工夫が必要になる。こちらに関して調べながらまとめられたらいいな~、とフワッと思っている(思っているだけ

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?