このノートでは、Exploratoryでの処理のパフォーマンスを向上させるための方法を紹介します。
Exploratoryではデータをインポートすると、データをメモリに読み込み、メモリ上のデータに対して様々な処理を実行することになります。
またExploratoryは、データをインポートした際、軽量・高速に扱えるParquetファイルも自動で生成します。
そして、プロジェクトを開き直し、同じデータフレームを開くとハードディスク上に保存されていたParquetファイルからデータがメモリに読み込まれます。
なおさ、生成されるParquetファイルはCSVと比べて、圧倒的にサイズが小さいため、データを読み込む際に優れたパフォーマンスを発揮します。
そして、データ加工のステップを追加すると、そのステップごとにメモリ上にデータフレームが作られることになります。なお、このとき、データが丸々コピーされるわけではなく、最適化された差分のみが付け加えられていくことになります。
Exploratoryは上記のような仕組みでデータを扱っているため、サイズが大きい(列数や行数が多い)データを処理するときや、ステップの数ガ増えるとメモリの使用量が増えるわけです。
Exploratoryでは、メモリの使用量が増え、メモリの量が足りなくなると、以下の2つの問題が発生します。
そして、メモリはExploratory以外のアプリケーションも使用するため、別のアプリケーションのメモリの使用量が大きければ、そちらを調べて、終了させることで、メモリを解放して、メモリの容量を確保することが可能です。
また、Exploratoryの各プロジェクトが利用しているメモリ量は、プロジェクトの中から確認して、不要なプロジェクトを閉じることで、利用されていたメモリ空間を解放することが可能です。
ここからは、以下の3つの切り口で、Exploratoryでの処理のパフォーマンスを向上させるための具体的な方法を紹介していきます。
Exploratoryでは、ファイルやデータベースから様々なデータをインポートすることができます。特にデータベースから大量のデータを取得すると、以下のようなパフォーマンスに関わる問題が発生する可能性があります。
そこで、データベースからデータを取得する際は、以下の2つの方法で効率化を図ることができます。
データラングリングの領域では、より多くのベストプラクティスが存在しており、こちらのセクションでは、1つ1つそれらを紹介していきます。
前述したように、Exploratoryでデータを加工すると、ステップが追加され、各ステップごとにメモリにデータが読み込まれます。
そのため、このことを押さえて効率的なデータ加工を行うことで、メモリ使用量を抑え、パフォーマンスを向上させることができます。
例えば同じような処理を複数回に渡って実施している場合、不必要にメモリを使用してしまい、パフォーマンスの低下につながります。
例えば、上記の例では、列を並び替える処理を3度に渡って実行していますが、1つのステップに全ての処理まとめられれば、メモリへの負荷を小さくすることが可能です。
また、同じような処理(処理名が同じステップ)が連続して、複数のステップにまたがっている場合、「ステップごと」に、実行結果がメモリに読み込まれることになり、処理がステップ事に実行される、あるいは、「ステップごと」に、実行結果がメモリに読み込まれることで、パフォーマンスが損なわれる場合があります。
そういったときには、複数のステップを1つのステップにまとめることで、メモリに読み込むデータを最適化できます。
Exploratoryにはステップ機能があるために、以下のようなことを実現できます。
一方で、データの加工が終わってしていて、前述したような再現性が不要な場合もあります。
例えば、必要なデータが最後のステップのデータでステップの情報がいらない場合、最後のステップの「ステップなし」のファイルやデータフレームとしてデータをエクスポートして、そのデータを利用することが可能です。
ステップを持たない加工済みのデータを利用することで、メモリに使用量を節約することができるわけです。
ただし、このアプローチでは、再現性を失われてしまい、データ加工の履歴が追いづらくなるため注意が必要です。
Exploratoryでデータを加工するときによくやることの1つに「フィルタ」を使ったデータの絞り込みがあります。
そして、データをフィルタするときに、フィルタのステップを後ろにもってくると、不要な行に対しても、データ加工を実施することになってしまいます。
例えば、上記の例では、最終的にフィルタされることになる行に対して、データを結合したり、計算を実行していることになるため、不要な処理を実行していると考えられます。
フィルタを早い段階で実施しておくと、不要な行に対してデータ加工を実施しないで済むため、メモリへの負荷が小さくなるだけでなく、処理スピードも速くなります。
探索的にデータを加工したり分析を進めるときや、データ加工のための試行錯誤中には、データのおおまかな分布やサマリ情報だけ理解できていれば良いことも少なくありません。
そのようなときに、ステップを追加/削除する度に生じる処理待ちの時間は、最小減に抑えたいものです。
そのようなときには、ステップの早い段階で「サンプルを抽出」しておくことが有効です。
データの加工や探索が一段落したら、「サンプル」のステップを「無効化」あるいは「削除」することで、同じ処理を全データに対して実行することができます。
このようなアプローチをとることで、仮にサイズの大きいデータを扱っていたとしても、サイズの大きいデータに対する処理は一度きりで済ませられます。
Exploratoryは、ステップが追加/変更される度に、全列のサマリ情報を計算したうえで、指定した列数分のサマリ情報を可視化しています。
言い換えれば、ステップを追加/移動する度にサマリの計算と描画が行われるため、表示する列数が、多い場合、描画のための時間が増えることになります。
そこで、表示する列数を少なくしておくことで、描画にかかる時間を短くすることが可能です。
なお、テーブルビューでは、表示する「行数」および「列数」の指定が可能で、いずれも、表示する数が少ないほど描画は速くなります。
「Exploratoryのデータ処理の仕組み」のセクションで紹介しましたが、Exploratoryではデータをインポートすると、軽量・高速に扱えるparquetファイルが自動で生成されます。
また再度同じプロジェクトを開くときはParquetファイルを読み込み、高速でメモリにデータを読み込むことができるようになっています。
一方で、各ステップのデータが保存されているわけではないため、一度閉じたプロジェクトのデータフレームを開き直すと、Parquetファイルを読み込んだうえで、最後にいたステップまでの処理を再実行することになります。
そのため、サイズの大きいデータを利用していたプロジェクトを開き直すと、ステップの実行の処理待ちが発生してしまい、すぐに作業を開始できないことがあります。
なお、データの加工が終わっていて、特定の(例えば最後の)ステップのみのデータだけが必要な場合、データをエクスポートして利用することが可能ですが、再現性を失いたくないときや、ステップごとにチャートを作りたいときには、そのようなアプローチが有効とは言えません。
そのようなときには、ステップのデータをキャッシュして、そのステップのデータを保存することが可能です。
ステップをキャッシュすると、該当のステップが青くなり、それ以前のステップの処理をすることなしに、データを読み込むことができるようになります。
ここからは、このことをもう少し詳しく説明していきます。
ステップを「キャッシュ」すると、Parquetファイルが作られ、PC上のレポジトリに保存されます。
そして、プロジェクトを開き直し、キャッシュされたステップを含む同じデータフレームを開くと、キャッシュされたParquetファイルからデータが読み込まれるます。
なお、キャッシュしたステップの後に、ステップがあった場合は、データフレームを開いた時、キャッシュしたステップ以降の処理が実行されることになります。
そしてキャッシュされたステップより前のステップに変更があったときは、そのステップの色が黄色に変わり、そのステップのキャッシュされたデータが古くなったことがわかります。
キャッシュされたステップのデータを更新したいときは、キャッシュしたステップで「実行ボタン」をクリックして、キャッシュを更新することが可能です。
Exploratoryでは、グループごとに計算をしたり、フィルタで絞り込みたい時には「グループ化」の機能を使うことがあります。
グループごとに処理ができるので便利な機能ですが、グループに対する処理が必要ない場合は、グループを解除するべきです。
これは、グループ化がかかったままだと、常にグループ単位での処理がかかってしまい、余計な時間がかかってしまうことがあるためです。
グループ済みの緑のボタンをクリックし、「グループ解除」を行うことで、グループ化を解除することができます。
グループ化の解除は1つのステップとして追加され、それ以降の処理はグループを考慮しない処理となります。
ここでは、以下のような1行が1つの注文を表し、列には「顧客ID」、購入した製品の「製品カテゴリー」や「売上」の情報を持つデータを例に考えてみます。
このようなデータを使って、顧客ごとに「電化製品の売上」「家具の売上」を集計したいときには、以下のように、集計ダイアログの中で、条件付きの集計関数を利用して、複雑な条件をもとにした集計を簡単に行うことが可能です。
このような条件付きの集計は、通常の集計よりも複雑な処理になるため、その分だけ処理に時間がかかります。
さらに、「グループ」に選択している列の一意な値の数が多ければ多いほど、処理は重くなります。これは、グループごとに条件にマッチする行を選別し、そのうえで計算処理を行うからです。
そこで、「グループ」に選択している列の一意な値の数が多いようなデータを使って、条件付きの集計を行いたいときには、集計のダイアログの中で、条件を指定するのではなく、条件に合致する列をあらかじめ追加しておくことで、処理効率を高められます。
例えば、今回の例の場合、以下のように、製品カテゴリー別の売上の列を「条件をもとに計算」機能を利用して、追加しておきます。
すると、集計のダイアログの中で、条件付きの関数を利用せずに、あらかじめ用意しておいた条件に合致する列を集計するだけで、同じ処理を実現できるため、集計にかかる処理速度を速めることが可能です。
集計テーブル・ピボットテーブルでは、変数を選択する度に、集計処理が走ることになるため、都度処理に時間がかかることになります。
そこで、あらかじめ集計のステップを追加しておき、データを「テーブル」で可視化した方がチャート上で集計処理をする必要がなくなるので、処理が速くなります。
データのサイズが大きくなると、カテゴリの数も多くなりがちですが、あまりに多くのカテゴリを可視化しようとすると描画に時間がかかることになります。
そこで、そのような自体を未然に防げるように、あまりにカテゴリが多い列をチャートで選択した場合、「一意な値のチェック」の確認画面が表示され、表示する情報をコントロールできるようになっています。
サイズの大きいデータを使ってアナリティクスを実行すると、計算処理に時間がかかることがあります。
大まかな予測精度や相関の傾向を確かめたいときには、アナリティクスを実行する際にサンプルサイズを指定して、モデルの実行スピードを調整することが可能です。
Exploratoryでは、データラングリング(加工・整形)の処理をステップとして管理しており、上から順番にステップの処理が実行されるようになっています。
データラングリングは大きく分けると、下記の3つのタイプに分けられ、上から順番に処理をしていくのが望ましいです。
例えば、1行1注文のデータをもとに「リピート購入比率」、「RFM」分析を行いたいとします。
そのために必要なデータの形は異なり、目的に合わせてデータラングリングの処理を行うためには、それぞれでデータフレームを作らなければいけません。
そこで、Exploratoryでは1つのデータフレームから枝分かれさせた「ブランチデータフレーム」を作ることができ、これによってメインとブランチのデータフレームで異なるデータ加工を行うことができます。
ブランチはメインのデータフレームにあるどのステップからでも作ることができ、そのステップを作成した以前の処理を反映させることができます。さらには、ブランチは複数作成することが可能です。
ブランチデータフレームはステップにある「枝」のアイコンから作ることが可能です。
ブランチの詳しい使い方については、こちらをご覧ください。
例えば、「結合」を使って属性情報などのデータを列として追加したい時に、ブランチごとに同じ処理をしてしまっては効率が悪いです。
そこで、メインのデータフレームで共通する前処理を行なっておけば、それぞれのブランチでは前処理を行う手間を省くことができます。
以上のことより、データの前処理は事前に行なっておいた方が、その後にデータラングリングをしていく際に管理がしやすく、さらには同じ処理を複数回行う必要がなくなるため、パフォーマンスを向上させていくことにつながります。
Exploratoryでは、ダッシュボードやノートを通してデータを分析した結果を他の人に効果的にレポートしていくことができます。
その際に、パラメーターの機能を使うことで、ダッシュボード内で表示するチャートのデータを動的に変更していくことができます。
パラメーターの詳しい使い方については、こちらをご覧ください。
また、このパラメーターはデータラングリングのステップとして適用する方法と、チャートやアナリティクス内のフィルターとして適用することができます。
データラングリングのステップ
チャートまたはアナリティクス内のフィルタ
データラングリングのステップとして、パラメーターを設定している場合、ステップの順番によっては処理に時間がかかってしまうことがあります。
例えば、時間がかかる処理の前にパラメーターが埋め込まれている場合、パラメーターで値を変更する度にその後のステップの処理が走り、時間がかかってしまうことがあります。
一方で、下記のようにパラメーターを使用するステップを後ろの方に設定している場合、パラメーターで値を変更してもその後に処理が走ることはないため、実行した結果がすぐに返ってきます。
やりたい処理の内容によっては、パラメーターを使用するステップが最初、または途中に挟んだ方が良いこともありますが、一般的にはパラメーターは後ろのステップにあったほうが変更の都度その後の処理の実行がなくなるために、パフォーマンスを向上させることにつながっていきます。