皆さんこんにちは。
@tereka114です。
今年末はKaggleで開催される面白いコンペも多くて日々、エンジョイしています。
最近は巨大なデータを扱うことが増えており、Pandasだと時間がかかりすぎて効率が悪いと感じています。
そのため、データを高速に処理できるcuDFを利用することも多くなってきました。
この記事ではcuDFの魅力と扱う際の注意点を説明していきます。
※この記事は「Pythonその2 アドベントカレンダー」10日目の記事です。
qiita.com
cuDFとは
cuDFはNVIDIAさんが開発している、Pandasの代わりに利用することができるGPUのライブラリです。
最も大きな特徴はGPUで計算するため、高速であることです。
主に、カテゴリ変数ごとの平均計算や、テーブル同士の結合といった、時間のかかるテーブル処理で、効果を発揮します。
cuDFは特徴量を簡単に作れるライブラリであるxfeatでもサポートされています。
cuDFとPandasの性能比較
cuDFがどの程度強力なライブラリなのかを評価します。
今回は利用頻度の多い、次の2点に関して性能を計測しました。
- カテゴリごとの平均値の計算
- テーブルの結合
前準備
Colaboratory上での準備
cuDFは手元にGPU環境がなくとも、Google Colaboratoryを利用すれば、簡単に試せます。
今回の性能計測もGoogle Colaboratory上で実施しました。
Google ColaboratoryでcuDFを動かすためには、次のコマンドを最初に実行してください。
!git clone https://github.com/rapidsai/rapidsai-csp-utils.git !bash rapidsai-csp-utils/colab/rapids-colab.sh stable import sys, os dist_package_index = sys.path.index('/usr/local/lib/python3.6/dist-packages') sys.path = sys.path[:dist_package_index] + ['/usr/local/lib/python3.6/site-packages'] + sys.path[dist_package_index:] sys.path exec(open('rapidsai-csp-utils/colab/update_modules.py').read(), globals())
データ作成
本検証では擬似データとして2つのテーブルを作成します。
作成条件は次の通りです。
- メインテーブル:2000万レコード、カテゴリを2つ100000種類
- 結合用テーブル:100万レコード、カテゴリを100000種類
import numpy as np import pandas as pd import cudf N = 20000000 MERGE_N = 1000000 df = pd.DataFrame([{"Category": np.random.randint(0,100000), "Category2":np.random.randint(0,100000), "Value": np.random.rand()} for _ in range(N)]) right_df = pd.DataFrame([{"Category": np.random.randint(0,100000), "Value2": np.random.rand()} for _ in range(MERGE_N)]) cudf_table = cudf.from_pandas(df) cudf_right_table = cudf.from_pandas(right_df)
試したこと
カテゴリごとの平均値の計算
巨大データからカテゴリごとの平均を計算する(df.groupby.mean)ケースで試してみます。
この場合Pandasだと非常に長時間の計算が必要です。
先程作成した「メインテーブル」で平均を計算します。実装は次の通りです。(時間計算部は省略しています)
df.groupby(["Category", "Category2"]).mean() # Pandas cudf_table.groupby(["Category", "Category2"]).mean() # cuDF
結果はcuDFが50倍高速でした。(驚異的なスピード)
- Pandas:50.92s
- cuDF:1.02s
テーブルの結合
次に巨大ファイルの結合を試します。
作成した「メインテーブル」と「結合用テーブル」を"Category"列で結合します。実装は次の通りです。
df.merge(right_df, on="Category", how="left") # Pandas cudf_table.merge(cudf_right_table, on="Category", how="left") # cuDF
結果、cuDFが37.5倍高速です。(早い!)
- Pandas:20.65s
- cuDF:0.55s
cuDFを扱う上での注意点
Pandasと比較して爆速なcuDFですが、3点注意点があります。
1. mergeの並び順が異なる。
Pandasのmergeは元のテーブルと順番が変わりません。
しかし、cuDFの出力結果は並列計算の都合で元のテーブルと順番が異なります。
そのため、順番に依存する処理(ex:インデックス番号でデータを分ける)を記載している場合に期待しない動作になるので注意が必要です。
2. 平均の結果がPandasと異なる。
巨大なデータを扱うときにはPandasと平均値の結果が異なる場合があります。
現在Kaggleで開催されている「Riiid! Answer Correctness Prediction」では、平均値を取ったときに計算結果がpandasとcuDFで異なる結果が返ってきます。
本件についてはオープンに議論しており、議論している場所は次の箇所です。
原因は不明ですが、色々と検証した結果、cuDFの値が正しそうです。
何らかの事情で計算環境が異なりPandasとcuDFの実装が混ざる状況の場合はテストコードを書いて検知するなど、対策が必要だと思っています。
3. 未実装/IFが異なる関数がある
cuDFは全てのPandasの関数をサポートできておらず、未実装関数やIFがPandasと合わないものがいくつかあります。
df.unstackのIFが若干異なることでプログラムで例外が発生したり、df.applyを対応していなかったりします。
その場合は一時的にPandasに変換(df.to_pandas())を行い、計算するなどで回避可能です。
最後に
ここまでcuDFが爆速であることをお伝えしてきました。
しかし、挙動を把握しながら実装していかないと思わぬ罠にハマり、苦労することがあります。
個人的にcuDFの性能が最高なので、挙動のクセを正しく理解、評価した上で、使っていきたいと思います!
Acroquest Technologyでは、キャリア採用を行っています。
- ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
- Elasticsearch等を使ったデータ収集/分析/可視化
- マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
- 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。【データ分析】
Kaggle Masterと働きたい尖ったエンジニアWanted! - Acroquest Technology株式会社のデータサイエンティストの求人 - Wantedlywww.wantedly.com