LoginSignup
2
6

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-01-09

■目的

300万個のIDそれぞれに対して、1ヶ月分のデータが用意されている
データの中身は、説明変数と目的変数が1つずつ。
つまりテーブルのカラムは、ID、説明変数x、目的変数yの3つ
レコード数は300万×30日 ≒ 9000万

この時、300万のIDそれぞれに対し、30日分の説明変数と目的変数の単回帰を行い、
アウトプットとしてそれぞれのIDに対して相関係数、傾き、p値を格納したい。

■方針

300万のIDに対し、forループの中で回帰を行い、結果をリストとして格納
最後にリストを結合してデータフレームとする。
この手法の速さに関してはこちらを参照

■環境

  • EC2インスタンス(ubuntu: r5d.4xlarge)
  • JupyterLab 0.35.3

■課題

単純にデータフレームから各IDに対応するレコードをクエリ抽出すると、時間がかかる(1idあたり約13秒)

code1.py
for id in id_list:
    tmp_x = df[df.id == id].x
    tmp_y = df[df.id == id].y

■解決策

  • idをindexにしdf.loc[]で抽出することで高速化 (1idあたり約3.9秒)
code2.py
df.index = df.id
for id in id_list:
    tmp_x = df.loc[id].x
    tmp_y = df.loc[id].y
  • 上記と合わせて、pandasデータフレームの代わりにdaskデータフレームを使用 (1idあたり1.7秒)
    ※daskとはなんぞや
code3.py
import dask.dataframe as dd
import multiprocessing

df.index = df.id
# 現環境では cpu_count = 32
ddf = dd.from_pandas(df, npartitions=multiprocessing.cpu_count())
for id in id_list:
    tmp_x = ddf.loc[id].x.compute()
    tmp_y = ddf.loc[id].y.compute()

■結論

まだ遅い。これだと全データの処理が完了するのに2ヶ月かかってしまう。。

■今後の予定

現状、1つのIDにつき30レコードが格納されている状況であるのを、30日分のデータをリストとして1セルに格納することで1IDにつき1レコードにする
こうすることで、ループ処理に内包処理が使用できるため、処理速度の向上が望める可能性がある。
(ただしそもそも30レコード → 1レコードへの変換にどれだけ時間がかかるか。。。 pivot_tableですんなりいってほしい)

2
6
3

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
6