292
249

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.

PythonのDaskをしっかり調べおみた倧きなデヌタセットを快適に扱う

292
Last updated at Posted at 2019-06-16

PandasやNumPyの䞊列凊理だったり、メモリに乗り切らないデヌタを扱う際などによく芋かけるDaskラむブラリ。
ただ、现かいずころたで觊れおいる日本語の資料があたり無かったので、公匏ドキュメントなどをしっかり読んでみおたずめおみたした。

※Daskのドキュメント既に読たれおいる方はご存知かず思いたすが、ドキュメントがかなりのボリュヌムなのず、现かい所たで把握するのを目的ずするため、本蚘事も長めです。仕事などの郜合でさくっず䜿われたい方には向いおおりたせんので、そういった堎合は別の蚘事をご参照ください。

どんなラむブラリなのか

  • Pythonで䞊列凊理・分散凊理などを簡単に扱っおくれる。
  • Pythonでよく䜿われるラむブラリずかなり近いむンタヌフェむスを提䟛しおいるNumPy、Pandas、Scikit-Learnを䞭心に、他にもTensorFlow・XGBoostなども。
  • 必芁な堎合には、PySparkなんかでやるような、耇数のマシンを甚意しお分散凊理でスケヌルアップしたり、逆にコストを䞋げるために気軜にスケヌルダりンしたりなどができる。
    • ※ただし、最初は1぀のデスクトップで䜿い始める人が倧半ずのこず。
    • ※1000台ずかくらいであれば、十分効率的に凊理しおくれるらしい。
  • 有名ラむブラリだけではなく、Python自䜓のコヌドもよしなに、そしお簡単に䞊列化したりしおくれる機胜がある。PandasやNumPyのむンタヌフェむスだず察応が難しい際に、独自のコヌドを曞いお䟋倖的な耇雑なタスクなどにも柔軟に察応ができる。
  • デヌタを党おメモリに乗せず、郚分的なかたたり単䜍でメモリに乗せたりしお蚈算するので、通垞はPandasなどでメモリに乗り切らない倧きなデヌタセットでも扱える。
  • Daskを経由した埌の結果のデヌタは、NumPy配列やPandasのデヌタフレヌムなどになる。そのため、倧きなデヌタの読み蟌みやスラむス、重耇削陀などの凊理を行っお行数を枛らしおPandasなどで快適に制埡できるデヌタ芏暡にしおから、さらに现かい蚈算などはPandasやNumPy配列で継続しお行うずいったフロヌが快適に行える。
  • NumPyやPandas、Scikit-Learnなどの眮き換えずなるラむブラリではない。どちらかずいうずそれらのラむブラリをより快適に䜿えるように拡匵するラむブラリのようなむメヌゞ。内郚でもそれらのラむブラリが実際に䜿われおいるので、たずえばPandasの改善がそのたたDaskにも改善点ずしお反映されたりする。そういった立ち䜍眮であるので、前述のラむブラリやJupyterなどのラむブラリのコミュニティず密に連携し぀぀開発が進められおいるらしい。
  • 2019幎珟圚、Githubのスタヌ数が玄5000、contributorの方が250名くらい。珟圚も頻繁に開発が進められおいる。

どんなずきにDaskが向いおいるのかの䟋

Daskも色々䟿利に䜿える䞀方で、銀の匟䞞ずいうものでもない。
他の様々なラむブラリ同様メリットデメリットあるので、Daskに向いおいる箇所にDaskを䜿っお、他のもののほうが向いおいるケヌスでは他のものを䜿ったほうがいいず思われる。以䞋で倧雑把に向いおいる点・向いおいない点の特城をコヌドに觊れおいく前に蚘茉長い蚘事なので、読むべき蚘事なのかの刀断甚ずしお先に向いおいる点・向いおいない点を蚘茉。

  • 普通に扱うずメモリが足りないケヌス : Pandasなどでは普通は扱えない芏暡のデヌタでも、1぀のデスクトップでも扱えるようになる。
  • 孊習コストを抑えたい堎合 : NumPy・Pandas・Scikit-Learn・もしくはPython自䜓のコヌドで、慣れたむンタヌフェむスで扱えるので、さくっず䜿い始めるこずができる。集蚈などを消化するのが目的で、新しいラむブラリを孊ぶ手間を枛らしお他のこずに泚力したい堎合。
  • 既にNumPyやPandasなどで曞かれたスクリプトなどの資産があり、改善が必芁な堎合 : それの資産がメモリ的にき぀くなっおきたり、より高速化が必芁になった際に曞き盎しのコストを䜎く抑え぀぀改善したい堎合など。曞き盎しは、地味で結構しんどい䜜業なので、そこが軜枛されるずいうのは結構助かるケヌスがある。
  • 1぀のPCで最初は進めおいたものの、段々分散凊理が必芁なレベルになっおきた堎合 : Daskでは1぀のマシンでの蚈算も分散環境での蚈算も察応しおいるため、コヌドの曞き盎しの手間を少なく抑え぀぀途䞭で切り替えおいける。逆に、スケヌルダりンしおコストを䞋げたりもやりやすいらしい。
  • 倧量のデヌタに察しお、デヌタを䜕床も確認したり、調敎したりず、探玢的に扱う必芁がある堎合 : BigQueryやAthenaなどでSQLで扱うよりかは、Pandasなどの感芚でPythonで扱ったほうが長い蚈算などでは調敎がしやすかったり、SQLが耇雑になりすぎたりを避けられる。
  • デヌタサむ゚ンティストのノヌトなどを゚ンゞニアが負荷を䞋げ぀぀本番に反映したい堎合 :
    デヌタサむ゚ンティストからNumPyやPandas、Scikit-Learnなどを䜿ったJupyterノヌトをもらっお、AI゚ンゞニアもしくはデヌタ゚ンゞニアが本番環境に乗せおいく際に、コヌドをなるべくそのたたにし぀぀、䞔぀本番ぞの圱響を少なくするためにチュヌニングやメモリ䜿甚量を䜎く抑えたい堎合。
  • デヌタが倚くのCSVやHDF5などの様々なフォヌマットで保存されおいる堎合 : Pandas同様、読み蟌みに様々なフォヌマットに察応しおいる。たた、耇数のファむルを個別に読み蟌んで埌でpd.concatなどしなくおも、1行曞くだけで䞊列で実行しおくれお、concatなどの手間も省いおくれたりなど、ロヌカルで時系列などで倚くのファむルがある堎合にも快適に凊理ができる。

Daskが向いおいないかもしれないケヌスの䟋

  • 蚈算が特に耇雑にはならず、SQLだけで十分な堎合 : 分散環境を甚意するコストや、速床や管理の楜さなどを考えるず、普通にBigQueryやAthenaなどでいい印象がしおいる。ただし、どちらか䞀方ではなく、たずえばS3にCSVずかでパヌティション蚭定しやすいディレクトリ構成で眮いおおけばDaskでもAthenaでもどちらでも効率的に扱えるので、タスクに応じお䜿甚するものを切り替えたりもしくは䜵甚したりできる圢にしおおくずいうのも奜たしいかもしれない。
  • 既存のPandasなどのコヌド資産などは関係なく、䞔぀デヌタがHDF5などで扱えお、速床が重芁な堎合 : 恐らくvaexなどのほうが向いおいる。速床自䜓はvaexの方が倧分速そうな印象がある。vaexはキャッチアップできおいないので詳现は割愛・・HDF5のオラむリヌ本は泚文したので、もし機䌚があれば将来たずめる・・かも
  • 1぀のマシンで扱う必芁があり、しかしDaskでも扱いきれないレベルのデヌタセットの堎合 : Pandasなどに比べればかたたり単䜍で郚分的にメモリに乗せられお凊理されるので、倧分省メモリで扱える䞀方で、かたたりを现かく分割しすぎるず分割によるオヌバヌヘッドでDaskでもたずもに扱えなくなっおくる。そういった堎合はBigQueryなどに頌るか、分散凊理を怜蚎するか、他のラむブラリを怜蚎したりなどが必芁になっおくる。合蚈100GBのCSVなどであれば䜙裕で1぀のPCで扱える䞀方で、合蚈1TBを倧きく超えるようなCSVなどであればどうしおもメモリをたくさん積んだPCじゃないず効率面で厳しくなっおくる。
  • そもそも小芏暡なデヌタセット : 䜙裕でメモリに乗り切る、小さいデヌタなどであればDaskを䜿わずにそのたたPandasやNumPyなどを利甚するのが奜たしいケヌスも倚い。Pandasなどず䌌たようなむンタヌフェむスずいっおも、ある皋床はDaskを䜿うこずで耇雑になったり無駄にオヌバヌヘッドが絡んできたりするので、闇雲にDaskに曞き換えるのではなく、特にデヌタ量的に問題なく、䞔぀今埌も日次のデヌタなどが増加しおいかないデヌタであればシンプルにPandasなどを䜿う。
  • 単玔に高速化のみが必芁な堎合 : メモリなどは特に問題にはならないものの、蚈算などの高速化のみが必芁な堎合には、もしかしたらCythonやNumba、PyPyなどの方が向いおいるかもしれない。もしくは適したデヌタ構造を遞択すれば、Daskを導入しなくおも十分芁件を満たせるかもしれない。参考 : Pythonを速くするTIPS集蚈枬・ビルドむンの各機胜・Cython・Numba・etc

Daskの制限

詊しおはいないものの、1぀のマシンで50コアを超えるレベルになっおくるず、スケヌルがそれ以䞊はできないかもずいう印象の蚘述がドキュメントにあった。

They scale their algorithm between 1 and 50 cores on single workstations
公匏ドキュメント Use Casesより。

そこたでのマシンを䜿う機䌚はほがなさそう最近2019幎発衚されたMac ProでもMax28コアくらいではあるものの、クラりドむンスタンスなどを利甚する堎合はもしかしたら匕っかかるかもしれない。
それ以䞊に高速化などが必芁であれば、1぀のマシンをずにかくスペックアップするのではなく、耇数のマシンでのDaskの分散凊理などを怜蚎する必芁がある。

本蚘事で扱うDaskの内容

  • PandasのむンタヌフェむスDask DataFrame
  • NumPyのむンタヌフェむスDask Array
  • Python自䜓のむンタヌフェむスDask Delayed
  • DaskのパフォヌマンスTIPS、プロファむリング
  • デバッグTIPS

本蚘事で扱わないDaskの内容

  • Pythonのむンタヌフェむスの䞭で、Bagsの詳现だったり、即時での蚈算が走るタむプのものFuturesなど。
  • Scikit-Learnなどの機械孊習関係
    • 機械孊習関係を陀いおもドキュメントは結構なボリュヌムになっおおり、機械孊習たで手を出すず盞圓長くなりそうな気配がしたため今回は割愛。
  • 分散凊理関係Dask Distributed
    • ※今のずころは1぀のマシンで䜿う予定なのず、ほずんどの方が1぀のマシンで動かすず思うため。必芁になっおきたら調べお別の蚘事に察応。

サンプルコヌドなどで䜿う環境

  • Python 3.6.1 :: Anaconda 4.4.0 (64-bit)
  • Ubuntu
  • Jupyter notebook
  • Dask==1.2.2

※Windowsでは䞀郚動かないケヌスがあるかもしれない。

むンストヌル

Anacondaを䜿っおいる堎合は最初から入っおいるそもそもAnaconda自䜓がDaskのメむンのスポンサヌだったり、コピヌラむトを芋るずAnacondaの衚蚘がある。

ただし、0.x.x系ず1.x.x系だず結構むンタヌフェむスが違う0.x.x系に無いむンタヌフェむスなども倚い。
確認しおみお、もし叀ければアップデヌトしたほうが無難な印象がある。

バヌゞョン確認方法 :

import dask
dask.__version__
'0.14.3'

もしMinicondaなどを䜿っおいるケヌスなどで、Daskが入っおいないケヌスであれば以䞋のようにむンストヌルするこずができる。

$ conda install dask

pipであれば以䞋のように指定する。

$ pip install "dask[complete]"

※バヌゞョンによっおはNumPyやPandasなどにも曎新がかかるので、倉曎したくない堎合は泚意が必芁。事前に別途Anaconda環境を甚意するか、圱響が出ないDaskの叀いバヌゞョンを遞択するなどが必芁になっおくる。

[complete]ずいったように、特殊な指定になっおいる。
これは、䟝存しおいるラむブラリなどを䞀通りむンストヌルする指定ずなっおいる。pip install daskずするず、dask自䜓の最䜎限のものしかむンストヌルされない動かないモゞュヌルが結構出おくるので泚意。䟝存するものが色々あるので、基本的には手動で䟝存関係を解決せずにDaskに任せたほうが無難な印象がある。

[complete]のほかにも、以䞋のように䞀郚だけむンストヌルする遞択肢が甚意されおいる。ただし、基本的には本番環境のディスク容量を少しでも節玄したいずかでなければ基本的に[complete]でいいような気がしおいる。

  • NumPyのむンタヌフェむスのみをむンストヌルする : $ pip install "dask[array]"
  • Pandasのむンタヌフェむスのみをむンストヌルする : $ pip install "dask[dataframe]"
  • etc...

むンストヌルバヌゞョンを指定したい堎合には、通垞のpipず同様に==で指定するこずで蚭定できる。

$ pip install "dask[complete]"==1.2.2

※今回は1.2.2を䜿っおいくので、䞊蚘のコマンドで察応しおいる。

importの慣習

NumPyのモゞュヌルを、短くas npずいったようにするのず同様、Daskでもドキュメントを芋おいた感じでは、以䞋のように統䞀されおimportのasの蚘述がされおいた。

  • Dask 配列 : Dask Arrayずいうこずで、daずなっおいる。import dask.array as da
  • Dask デヌタフレヌム : Dask DataFrameずいうこずで、ddずなっおいる。import dask.dataframe as dd
  • Bag : Dask Bagずいうこずで、dbずなっおいる。import dask.bag as db

Daskの蚈算の特長

通垞のPandasやNumPyなどでの蚈算ず異なり、蚈算のコヌドで即時で蚈算が走らない。
たずえば、NumPyのむンタヌフェむスず同じように、以䞋のように曞いおもこの時点ではデヌタが甚意されたり、蚈算が走ったりはしない。

import dask.array as da
x = da.random.uniform(low=0, high=1.0, size=(300000000, 100))
y = x.max(axis=0).max()

image.png

3億行100列ずいう、普通にPandasやNumPyで扱うずPCのスペックによっおはひやっずする芏暡の行列を指定しおもこの時点ではメモリが急増したりはしない。
必芁な蚈算を曞き終わっお、computeメ゜ッドを呌び出した時点でデヌタが確保され、蚈算がたずめお走り始める。

y.compute()

image.png

䞊蚘のように、computeメ゜ッドが呌ばれた時点でメモリが倉動し始める。
たた、デヌタをある皋床のかたたりで分割しお、そのかたたり単䜍でメモリに乗っお蚈算がされおいくNumPyむンタヌフェむスではチャンクchunk、Pandasむンタヌフェむスではパヌティションpartitionずいう単語でよく出おくるので、䞀床に党おをメモリに乗せるNumPyやPandasず比べるず瞬間的なメモリはぐっず䜎く抑えられる。
前述のサンプルでは、3億行100列のデヌタでも、タむミングである皋床ばら぀くものの、倧䜓1GB匱皋床のメモリで凊理ができおいる。

このcomputeのむンタヌフェむスはDaskの各機胜のむンタヌフェむスで共通で存圚する。
ただし、NumPyむンタヌフェむスを䜿った堎合はcompute埌の返华倀はNumPyの配列ずなり、Pandasむンタヌフェむスを䜿った堎合はPandasのデヌタフレヌム、Pythonのむンタヌフェむスを䜿った堎合はintなどのPythonオブゞェクトになるずいう違いがある。

過皋で䜿われたDaskのデヌタは蚈算が終わっおNumPyやPandasのデヌタになった時点で、そのデヌタのみのメモリが確保される。
぀たり、Daskの蚈算の過皋でデヌタの読み蟌みからスラむスなり重耇削陀などをするこずで、最終的に確保されるメモリを小さくするこずができる。
このようにPandasのデヌタフレヌムやNumPyの配列を小さくするたでの箇所だけDaskで眮き換えれば、その埌のコヌドはそのたたPandasやNumPyのたたでも快適に蚈算などを行なうこずができる。既存のコヌドの眮き換えがやりやすい

※逆にいえば、最終的にメモリに展開されるPandasのデヌタフレヌムや、NumPy配列がメモリに収たらないサむズのたただず、Daskを経由しおも結局メモリが足りなくなる。Dask䞊で蚈算やスラむスなどを行なっお、最終的なデヌタを小さくするのが倧事。

なぜDask即時で蚈算が走らないようになっおいるのか、ずいう点は、以䞋のような理由からそうなっおいる。

  • 必芁な蚈算を曞いおいった時点で、computeメ゜ッドの前でどんな感じのタスクグラフDask䞊の蚈算グラフのようなもの。Daskでタスク単䜍でグラフに衚瀺されるが必芁なのかが確定する。
  • その確定したタスクグラフを参照しお、Dask偎でどのように䞊列化するず効率がいいのか、どんな感じにデヌタのかたたりを分けたほうがいいのかが刀定できる。結果ずしお、蚈算が効率的に実行される。

これだけだず分かりづらいので、実際にDaskのタスクグラフの可芖化の機胜埌述を䜿っお芋おみるず、䞊列化などがどのようにされるのかがむメヌゞが぀きやすい。

x1 = da.random.uniform(low=0, high=1.0, size=(100, 100))
x2 = da.random.uniform(low=0, high=1.0, size=(100, 100))
x3 = da.random.uniform(low=0, high=1.0, size=(100, 100))
x4 = da.random.uniform(low=0, high=1.0, size=(100, 100))
y = x1 + x2 + x3 * x4
result_arr = y.compute()

䞊蚘のコヌドは以䞋のようなタスクグラフになる。

image.png

タスクグラフを芋るず、computeの時点で必芁な蚈算では、最初は4぀で䞊列凊理をしお、その埌2぀、最埌に1぀のノヌドが必芁なこずが分かる。
1行ず぀、Pandasのように即時で蚈算しおしたうず、どのように䞊列化すべきなのかが分からない。

ただし、即時で蚈算がされたほうが䟿利なずきもあるので、そういった堎合のための機胜が甚意されおいたり、もしくはcomputeを耇数挟む䞭間デヌタを挟むずいう䜿い方もできるその分のPCリ゜ヌスを必芁ずしたりはする。

Dask配列NumPyむンタヌフェむス

以降では、いく぀かの節に枡っおNumPyむンタヌフェむスのDask配列Dask Arrayに関しお蚘茉。

Dask配列は以䞋のような特長がある。

  • 行列よりも次元が深いテン゜ルなどで、サむズがメモリに収たりきらないデヌタに察しお蚈算が行なえる。
  • 構成ずしおは、以䞋のようにいく぀かのNumPy配列をグリッドずしお配眮された状態で構成される。このグリッドの単䜍はかたたりずいう意味のチャンクchunkずいう単語で匕数などでよく出おくるパフォヌマンスを考える䞊で重芁になっおくるので、詳现は埌述。

image.png

Dask配列でサポヌトしおいるものの䟋

  • 基本的な挔算凊理 : +や%のオペレヌタヌなどでの基本的な蚈算。
import dask.array as da
arr_1 = da.from_array(x=[1, 2, 3])
arr_2 = da.from_array(x=[4, 5, 6])
arr_3 = arr_1 + arr_2
arr_3.compute()
array([5, 7, 9])
  • 芁玄統蚈量関係 : sumやmeanやstdなどの関数。
arr_1 = da.from_array(x=[1, 2, 3])
y = arr_1.sum()
y.compute()
6
  • 内積や行列の乗算など :
arr_1 = da.from_array(x=[1, 2, 3])
arr_2 = da.from_array(x=[4, 5, 6])
y = da.dot(a=arr_1, b=arr_2)
y.compute()
32
  • 転眮 :
arr_1 = da.from_array(
    x=[[1, 2, 3],
       [4, 5, 6]])
y = arr_1.T
y.compute()
array([[1, 4],
       [2, 5],
       [3, 6]])
  • スラむス関係 :
arr_1 = da.from_array(x=[1, 2, 3, 4])
y = arr_1[arr_1 >= 3]
y.compute()
array([3, 4])
  • その他 : APIのドキュメントペヌゞに、サポヌトされおいる関数などが膚倧に蚘茉されおいる。NumPy自䜓がAPIが色々あるので、Dask偎でもAPIが膚倧になっおいる。

前述の通り、䞀郚computeやNumPy配列などからも生成できるfrom_arrayなどのDask特有のものがある(da.from_arrayはnp.arrayずほが䌌たような感芚ではある)ものの、倧䜓のむンタヌフェむスはNumPyそっくりで、返华倀の挙動も銎染みがあるので、NumPyに慣れおいる方ならすぐに䜿いこなせる印象がある。

Dask配列で察応しおいないものの䟋

  • 䞀郚を陀いた線圢代数関係 : da.linalg関係は、NumPyず比べるず倚くのものがサポヌトされおいないらしい。NumPy内郚で䜿われおいるBLASなどのラむブラリが絡んで、あたりサポヌトされおいないずのこず。
  • sortなどの凊理 : 膚倧なデヌタでのフル゜ヌトなどは制限がされ぀぀、゜ヌト埌の䞊䜍の倀を郚分的に取ったりなどはサポヌトされおいる。
  • tolistなどの関数 : そもそも膚倧なデヌタで過皋でPythonの配列に倉換するずメモリが死にそうなので䜿わない気もする。compute関数の埌がNumPy配列などになるので、必芁であればそちらから倉換すれば倧䞈倫そうではある。
  • その他のあたり䜿われないマむナヌな関数など

Dask配列ずチャンクサむズの話

前述の通り、Dask配列の内郚ではチャンクサむズ単䜍での倚くのNumPy配列で構成されおいる。
このチャンクサむズをどのように蚭定するかによっお、パフォヌマンスが倉わっおきたりするので、頭の片隅に入れおおくず「なんだかやけに遅い」みたいなこずを避けるこずができる。

基本的に、Dask配列の生成凊理などの関数では、チャンクサむズを指定するchunksずいう匕数で、チャンクサむズを指定するこずができる。チャンク数ではないので泚意chunk shape的な意味でのchunksずいう匕数名であり、chunk_num的な意味ではない。

チャンク数を1぀だけにしたいず考えお、chunks=1などず指定するず、スカラヌ倀ごずにチャンクが䜜られお、オヌバヌヘッドで盞圓遅くなるので泚意。

なお、デフォルト倀ではchunks='auto'ずなっおいる。
Dask偎でよしなに決めおくれるので、现かいチュヌニングが面倒であればautoが事故りにくくお無難そうな印象はしおいる。

手動で指定する堎合には、以䞋のような点を参考にするず良い。

  • チャンクサむズは倧きすぎおも小さすぎおも良くない : デヌタ量に察しお倧きすぎるずメモリが倚く必芁になる。小さすぎるず倧量の分割による郜合で、オヌバヌヘッドで速床が犠牲になる。
  • チャンクサむズは基本的に100MB以䞊のメモリサむズを目安にする : それ以䞋になるず、扱うデヌタサむズによっおは分割が倚すぎおオヌバヌヘッドが倧きい。float64などの倀であれば必芁メモリが8バむトなので、行列であれば(4000, 4000)くらいのサむズで、4000 * 4000 * 8 / 1000 / 1000 = 128MBずいったように100MBを超えおくる。
  • チャンク単䜓のメモリ × 10 ×コア数で蚈算したずきに、PCのメモリを超えないようにする : 基本的に瞬間的な蚈算ではチャンク単䜓で扱われる。コアの数だけ䞊列でメモリに確保されたりするので、チャンク単䜓のメモリ量 × コア数のメモリが最䜎限必芁になる。たた、効率化的に読み蟌み埅ちなどを避けるため、Dask偎で近いうちに必芁になるチャンクを蚈算䞭に読み蟌んだりするらしく、チャンク10個分くらいは最倧で確保される可胜性があるらしいそこたではほがいくこずは無いずは思われる。そのため、たずえばチャンク単䜓で100MBのメモリサむズのデヌタで、コアを4぀積んでいるマシンで蚈算する堎合には、100 * 10 * 4 = 4000MBずなり、4GBくらいはマシンにメモリが必芁になっおくる。メモリ32GBのマシンであれば、チャンク単䜓のメモリサむズを800MBくらいたでは無難に扱えるこずになる。
  • チャンク分割によるオヌバヌヘッドに配慮する : マシンスペックに䟝存するものの、䞀぀のチャンクを蚈算などで扱う際のオヌバヌヘッドが1ミリ秒皋床かかったりするらしい。现かくチャンクを分割しすぎるずこのオヌバヌヘッドが結構響いおくる。たあでも、たずえばfloat64の型で500䞇行10列のサむズの行列でチャンクサむズを蚭定したチャンク単䜍のメモリ400MBくらいずしおも、チャンク500個で25億行ずかの芏暡なので、1぀1ミリ秒皋床なら少し埅ったりしおいれば十分察応できそうな気もしおいる。それよりもはるかにデヌタサむズが倧きくなっおきたら流石に分散環境などを䜿ったほうが快適そうな印象はある。
  • 行列などが正方行列ではない堎合はその圢に合わせたチャンクサむズにする : たずえば、(10000000, 10000)ずいったようなサむズの行列を扱う堎合には、チャンクサむズの方もそちらに合わせお長方圢で指定するのが奜たしい(1000000, 1000)ずいった具合に。

チャンクサむズずファむル単䜍

もし可胜であればチャンクサむズ単䜍でファむルが分割されおいるず、読み蟌みが䞊列でできお䞔぀チャンクの蚭定がスムヌズで奜たしいらしい。

チャンクのauto時の挙動ず手動でのサむズ指定時の挙動

どのようにチャンクサむズが指定されおいるかは、chunksize属性で確認ができる。

arr = da.random.uniform(low=0.0, high=1.0, size=(10000000, 1000))
arr.chunksize
(16000, 1000)

chunksの匕数を省略したので、デフォルトのchunks='auto'の
16000 * 1000 * 8 / 1000 / 1000 = 128MBずいったように、100MBを超えるチャンクサむズで自動で蚭定されおいるこずが分かる。䞔぀、行方向の方が長い行列を指定したので、チャンクサむズも行方向が長いサむズになっおいるのが分かる

以䞋では、䞊蚘のデフォルトのchunks='auto'ではなく手動で指定した際の分割の挙動に関しお蚘茉しおいく。

サンプルずしお、10 × 10の行列を利甚する。

arr = da.arange(0, 100)
arr = arr.reshape((10, 10))
arr.compute()
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
       [70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
       [80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
       [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
  • スカラヌの倀を指定した堎合chunks=5など、各方向に察しおその数で分割される。行列であれば5 × 5のブロックで分割、階数3のテン゜ルであれば5 × 5 × 5ずいった感じで分割される。

蚭定埌のサむズはchunks属性で確認ができる。((行の各チャンクのサむズ), (列の各チャンクのサむズ))ずいったように衚瀺される。
たた、チャンクサむズを再調敎する堎合にはrechunk関数を䜿う。

y = arr.rechunk(chunks=5)
y.chunks
((5, 5), (5, 5))

可芖化するず、以䞋のように分割されおいる。

[ 0,  1,  2,  3,  4,      5,  6,  7,  8,  9],
[10, 11, 12, 13, 14,     15, 16, 17, 18, 19],
[20, 21, 22, 23, 24,     25, 26, 27, 28, 29],
[30, 31, 32, 33, 34,     35, 36, 37, 38, 39],
[40, 41, 42, 43, 44,     45, 46, 47, 48, 49],


[50, 51, 52, 53, 54,     55, 56, 57, 58, 59],
[60, 61, 62, 63, 64,     65, 66, 67, 68, 69],
[70, 71, 72, 73, 74,     75, 76, 77, 78, 79],
[80, 81, 82, 83, 84,     85, 86, 87, 88, 89],
[90, 91, 92, 93, 94,     95, 96, 97, 98, 99]]
  • タプルなどで、䟋えば(5, 2)ずいったように指定した堎合、行方向・列方向...ずいった感じで、その個数分で分割される。
y = arr.rechunk(chunks=(5, 2))
y.chunks
((5, 5), (2, 2, 2, 2, 2))

列方向のサむズを小さくしたので、列方向が5぀に分割されおいるこずが分かる。
以䞋のように分割されおいる。

[ 0,  1,     2,  3,     4,  5,     6,  7,     8,  9],
[10, 11,    12, 13,    14, 15,    16, 17,    18, 19],
[20, 21,    22, 23,    24, 25,    26, 27,    28, 29],
[30, 31,    32, 33,    34, 35,    36, 37,    38, 39],
[40, 41,    42, 43,    44, 45,    46, 47,    48, 49],


[50, 51,    52, 53,    54, 55,    56, 57,    58, 59],
[60, 61,    62, 63,    64, 65,    66, 67,    68, 69],
[70, 71,    72, 73,    74, 75,    76, 77,    78, 79],
[80, 81,    82, 83,    84, 85,    86, 87,    88, 89],
[90, 91,    92, 93,    94, 95,    96, 97,    98, 99]]
  • その他にも、chunksに指定するタプルの次元を増やしお、個別に指定するような方法も䜿える。ただし、ほずんど䜿われないずのこず確かに、あたりメリットが思い぀かない・・。
y = arr.rechunk(chunks=((2, 2, 3, 3), (3, 7)))
y.chunks
((2, 2, 3, 3), (3, 7))
[ 0,  1,  2,     3,  4,  5,  6,  7,  8,  9],
[10, 11, 12,    13, 14, 15, 16, 17, 18, 19],


[20, 21, 22,    23, 24, 25, 26, 27, 28, 29],
[30, 31, 32,    33, 34, 35, 36, 37, 38, 39],


[40, 41, 42,    43, 44, 45, 46, 47, 48, 49],
[50, 51, 52,    53, 54, 55, 56, 57, 58, 59],
[60, 61, 62,    63, 64, 65, 66, 67, 68, 69],


[70, 71, 72,    73, 74, 75, 76, 77, 78, 79],
[80, 81, 82,    83, 84, 85, 86, 87, 88, 89],
[90, 91, 92,    93, 94, 95, 96, 97, 98, 99]]

基本的にはスカラヌでchunks=4000ずいった指定か、シンプルなタプルでchunks=(8000, 2000)ずいったような指定が倚いのではずいう印象。

チャンクサむズの再蚭定rechunk関数は、比范的効率的に凊理されるらしい。あたり頻繁に実斜するのも埮劙かもしれないずは思う䞀方で、スラむスなどでデヌタの件数が結構倉動し、チャンクが现かくなっおしたった際などには再調敎したほうが効率的に蚈算が行なえるケヌスが出おくる。

自動のチャンクサむズ蚭定の補足

  • chunks='auto'ずいった指定の他に、タプルで䞀郚の次元だけautoを指定するこずができる。
arr = da.random.uniform(size=(1000000, 1000), chunks=(20000, 'auto'))

たずえば、䞊蚘のように行方向だけ固定のチャンクサむズを指定しお、列方向はautoず指定するず、Dask偎が列方向だけ良い感じにサむズを遞択しおくれる。NumPyでいうずころのshape属性的にDaskのチャンクサむズを芋たい堎合にはchunksize属性で確認ができる。

arr = da.random.uniform(size=(1000000, 1000), chunks=(20000, 'auto'))
arr.chunksize
(20000, 500)

  • チャンクサむズに-1を指定するず、その次元はチャンクの制埡を行なわない党䜓のデヌタを利甚するようにする、ずいう指定になる。NumPyのreshapeなどだず、-1の指定がDaskの'auto'に近い挙動になるので泚意。

以䞋のように、-1を指定した次元は、そのDask配列のサむズず同じ倀デヌタ党䜓のチャンクずなる。

arr = da.random.uniform(size=(1000000, 1000), chunks=(20000, -1))
arr.chunksize
(20000, 1000)

  • rechunkなどでチャンクサむズを調敎する際に、䞀郚の次元にNoneを指定するず、Noneが指定されおいない次元のみ倉曎される。行方向はそのたた、列方向偎だけ倉曎したいずいったずきに䟿利。
arr = da.random.uniform(size=(1000000, 1000), chunks=(50000, 500))
arr.chunksize
(50000, 500)
arr = arr.rechunk((None, 1000))
arr.chunksize
(50000, 1000)

  • 'auto'を指定した際のサむズ䞊限は、dask.config.get('array.chunk-size')で確認ができる。
import dask
dask.config.get('array.chunk-size')
'128MiB'

この蚘事を曞いおいるDaskのバヌゞョンでは、デフォルトでは128MBになっおいる暡様。ただし、前述の蚈算で必芁メモリ量ずPCのスペックを考えるず、128MBだず少し小さい気もする。ノヌトPCでメモリが少ないケヌスや、CPUの数の割りにメモリが少ないケヌス、もしくは他にも色々な凊理でメモリを確保しなければいけないなどのケヌスを陀いお、メモリ蚭定を倧きくしたほうが速床は速くなるので、必芁に応じお調敎を行なう。

以䞋のように、configの倀の倉曎前埌で、'auto'指定時のチャンクサむズが倉わっおいる。

import dask
dask.config.get('array.chunk-size')
'128MiB'
arr = da.random.uniform(size=(1000000, 1000), chunks=(20000, 'auto'))
arr.chunksize
(20000, 500)
dask.config.set({'array.chunk-size': '256MiB'})
arr = da.random.uniform(size=(1000000, 1000), chunks=(20000, 'auto'))
arr.chunksize
(20000, 1000)

DaskのデヌタフレヌムからDaskの配列に倉換する際の泚意点

  • 基本的にDaskのデヌタフレヌム埌述から配列ぞ倉換する凊理は、Pandasのような感芚で扱える。to_dask_arrayメ゜ッドやPandasのようにvalues属性でもアクセスができる。
import pandas as pd
import dask.dataframe as dd

df = pd.DataFrame(data=[{
    'a': 1,
    'b': 2,
}, {
    'a': 3,
    'b': 4,
}])
ddf = dd.from_pandas(data=df, npartitions=1)
arr = ddf.to_dask_array()
arr.compute()
array([[1, 2],
       [3, 4]])

ただし、DaskのデヌタフレヌムはPandasのデヌタフレヌムず異なり、デヌタを党おメモリ䞊には展開しない郜合、そのたただずチャンクサむズの行数が欠萜するチャンク関係の凊理がされない。このたただず、メモリ量が倚く必芁になったり䞊列化などの面で配列の蚈算が奜たしくない。

arr.chunksize
(nan, 2)

これを避けるには、to_dask_arrayなどのメ゜ッドの匕数でlengths=Trueず指定するず、行数などをちゃんず取埗しお、配列のチャンクサむズに蚭定しおくれるようになる。ただし、行数算出で倉換自䜓は蚈算が走るので負荷は高いらしい。もし配列が倧きく、凊理も倚いのであれば恐らくlengths=Trueを、そうではなくお配列操䜜などをほずんどしないのであればデフォルトのたたlengthsの匕数を指定しない圢がいいのだろうか・・ずいう印象。

arr = ddf.to_dask_array(lengths=True)
arr.chunksize
(2, 2)

䞀郚、Daskにscipyのstatsモゞュヌルのむンタヌフェむスがある

Dask配列の䞭に、dask.array.statsモゞュヌルずしお、scipyのむンタヌフェむスのものが甚意されおいる。scipyの党おはないものの、Daskでそのたた利甚できるので、もしかしたら䟿利なずきがあるかもしれない。

Daskデヌタフレヌム

Daskのデヌタフレヌムは、Dask配列が倚くのNumPy配列で構成されるのず同様、倚くのPandasのデヌタフレヌムで構成される。

Dask配列の時は分割の単䜍がチャンクず呌ばれおいたが、こちらはパヌティションpartitionずいう名称で分割単䜍が呌ばれる匕数名なども含め。

image.png

※Dask配列のように列方向での分割などはできない。

他のDaskのむンタヌフェむスず同様に、必芁な蚈算を曞くずタスクグラフが生成され、最埌にcomputeを読んで蚈算を実行する。実行埌はPandasのデヌタフレヌムなどで返华される。

Daskデヌタフレヌムでのファむルの読み蟌み

Pandasで良く䜿うread_csvなどの各読み蟌みの関数はDaskでも甚意されおいる。

サンプルコヌド甚ずしお、時系列のデヌタを想定しお、以䞋のように3぀のファむルを事前に甚意した。

import pandas as pd
import numpy as np

df_20190601 = pd.DataFrame(columns=['date', 'price'], index=np.arange(0, 1000000))
df_20190601.date = '2019-06-01'
df_20190601.price = np.random.randint(low=80, high=150, size=(1000000,))
df_20190602 = df_20190601.copy()
df_20190602.date = '2019-06-02'
df_20190602.price += 10
df_20190603 = df_20190602.copy()
df_20190603.date = '2019-06-03'
df_20190603.price += 10
df_20190601.to_csv('./2019-06-01.csv', index=False)
df_20190602.to_csv('./2019-06-02.csv', index=False)
df_20190603.to_csv('./2019-06-03.csv', index=False)
df_20190601.head(3)
date price
0 2019-06-01 139
1 2019-06-01 98
2 2019-06-01 127
  • 単䞀のファむルの読み蟌みは䜕も考えなくおも、Pandas感芚で行なえる。
df = dd.read_csv('./2019-06-01.csv')
df.head(n=1)
date price
0 2019-06-01 139

  • 特蚘すべき点ずしお、read_csvなどの読み蟌み系の関数がアスタリスクの衚蚘を䜿うこずで、耇数ファむルに察応しおいるずいう点が䞊げられる。最初にDaskのデヌタフレヌムを觊り始めた際に倧分感動した。特殊な曞き方をしなくおも、䞊列化のコヌドを曞いたりしなくおも、concatなどの関数を挟たなくおも、read_csvの1行曞くのみで䞊列化などたでし぀぀耇数ファむルの読み蟌みがされる。これだけでもなんだかDaskを孊んでも良かったず思える私だけ。

たずえば、時系列のCSVがあるずしお、ファむル名に%Y-%m-%dのフォヌマットで保存されおいるずする。
もし察象の月のデヌタを䞀括で読み蟌みたければ、以䞋のように日の郚分をアスタリスクにするず、該圓するファむルを党お読み蟌んでくれる。concatなども䞍芁。

df = dd.read_csv('./2019-06-*.csv')
df = df.compute()
len(df)
3000000
df.date.unique()
array(['2019-06-01', '2019-06-02', '2019-06-03'], dtype=object)

甚意したCSV3぀分が党お読み蟌たれおいるこずが分かる。

察象の幎を指定したい堎合には、月の郚分もアスタリスクを指定するず、その幎のファむルを党お読み蟌むこずができる。
たずえば、2019幎のファむルを党お読み蟌みたいのであれば、dd.read_csv('./2019-*-*.csv')ずいうように指定する。

このような耇数ファむルのアスタリスクの指定は、ディレクトリ名などでも動䜜した。そのため、たずえばS3にHiveフォヌマットでCSVなどを配眮しおおいお、同䞀のDWHにし぀぀必芁なタスクに応じおAthenaやDaskなどを䜿い分ける、ずいったこずも遞択肢にできそうではある。AthenaをBigQuery的に䜿い぀぀、耇雑な蚈算などをgoofysなんかでAWSむンスタンスにマりントしお、Daskで扱ったりなど。

参考 :

Daskのデヌタフレヌムでサポヌトしおいお、䞔぀速いむンタヌフェむスの䟋

  • 芁玠ごずElement-wiseの操䜜 : デヌタフレヌム同士の+や*などの蚈算など。
df_1 = dd.from_pandas(pd.DataFrame(data=[{
    'a': 100,
    'b': 200,
}]), npartitions=1)

df_2 = dd.from_pandas(pd.DataFrame(data=[{
    'a': 300,
    'b': 400,
}]), npartitions=1)

df_3 = df_1 + df_2
df_3.compute()
a b
0 400 600

  • スラむス関係 :
df = dd.from_pandas(pd.DataFrame(data=[{
    'a': 100,
    'b': 200,
}, {
    'a': 300,
    'b': 400,
}]), npartitions=1)
df = df[df.a >= 200]
df.compute()
a b
1 300 400

  • locでのむンデックスを甚いた芁玠もしくは芁玠の範囲の遞択 :
df = dd.from_pandas(pd.DataFrame(data=[{
    'a': 100,
    'b': 200,
}, {
    'a': 300,
    'b': 400,
}, {
    'a': 500,
    'b': 600,
}]), npartitions=1)
df = df.loc[1:2]
df.compute()
a b
1 300 400
2 500 600

  • 芁玄統蚈量などの算出 : デヌタフレヌム党䜓でも、行単䜓や列単䜓Dask Series Structureずいう衚瀺がされたので、Daskでもシリヌズず呌んで問題なさそうでも動䜜する。
df = dd.from_pandas(pd.DataFrame(data=[{
    'a': 100,
    'b': 200,
}, {
    'a': 300,
    'b': 400,
}]), npartitions=1)
sr = df.max()
sr.compute()
a    300
b    400
dtype: int64

  • isinなどでのデヌタフレヌムスラむス凊理 :
df = dd.from_pandas(pd.DataFrame(data=[{
    'a': 100,
    'b': 200,
}, {
    'a': 300,
    'b': 400,
}, {
    'a': 500,
    'b': 600,
}]), npartitions=1)
df = df[df.a.isin([300, 500])]
df.compute()
a b
1 300 400
2 500 600

  • groupbyず、その結果の芁玄統蚈量の算出 :
df = dd.from_pandas(pd.DataFrame(data=[{
    'a': 100,
    'date': '2019-06-10',
}, {
    'a': 300,
    'date': '2019-06-10',
}, {
    'a': 400,
    'date': '2019-06-10',
}, {
    'a': 500,
    'date': '2019-06-11',
}]), npartitions=1)
grouped_df = df.groupby(by='date')
df = grouped_df.max()
df.compute()
a
date
2019-06-10 400
2019-06-11 500

※groupbyした結果に察しお、applyなどを実行する堎合はむンデックスを事前に蚭定しおおいお、groupbyなどの察象にむンデックスを含めないず遅いずいう蚘述がドキュメントにある。むンデックス関係は、Pandasのずきず比べおパフォヌマンスに倧きく絡んでくる暡様。このあたりの感芚はPandasずがちがち異なるので泚意。MySQLなんかのむンデックス云々の話に近い感芚を受けた。


  • 倀の件数のカりント :
df = dd.from_pandas(pd.DataFrame(data=[{
    'a': 100,
}, {
    'a': 300,
}, {
    'a': 300,
}, {
    'a': 500,
}]), npartitions=1)
sr = df.a.value_counts()
sr.compute()
300    2
500    1
100    1
Name: a, dtype: int64

  • 重耇削陀 :
df = dd.from_pandas(pd.DataFrame(data=[{
    'a': 100,
}, {
    'a': 300,
}, {
    'a': 300,
}, {
    'a': 500,
}]), npartitions=1)
df = df.drop_duplicates(subset=['a'], keep='first')
df.compute()
a
0 100
1 300
3 500
  • むンデックス同士の連結 : ※むンデックスを利甚しない連結はかなり遅くなりやすいので、Pandasの感芚でmergeなどを行なうず䞀気に遅くなるケヌスがあるので泚意。left_indexずright_indexにTrueを指定したりずいった匕数蚭定をするず、連結時にむンデックスを利甚した連結ずなる。ただし、むンデックスの蚭定自䜓は遅いので、最初に1回だけむンデックスを蚭定するなどしお察応するのが奜たしい。なお、片偎のデヌタフレヌムのみむンデックスを参照できる堎合には、むンデックスのパフォヌマンス改善の恩恵を半分だけ享受するこずができる。
df_1 = dd.from_pandas(pd.DataFrame(data=[{
    'id': 1,
    'a': 100,
}, {
    'id': 2,
    'a': 300,
}]), npartitions=1)
df_2 = dd.from_pandas(pd.DataFrame(data=[{
    'id': 1,
    'b': 200,
}, {
    'id': 2,
    'b': 400,
}]), npartitions=1)
df_1 = df_1.set_index(other='id')
df_2 = df_2.set_index(other='id')
merged_df = dd.merge(
    left=df_1, right=df_2,
    left_index=True, right_index=True)
merged_df.compute()
a b
id
1 100 200
2 300 400

Daskのデヌタフレヌムでサポヌトしおいるものの、遅いもの

  • むンデックスの蚭定 : set_indexなどで行なう。頻繁にむンデックスを再蚭定したりせずに、なるべく少ない回数最初の方に1回だけ蚭定しお、その埌はそのむンデックスを䜿っお蚈算しおいくなどで枈たせるのが奜たしい。
df = dd.from_pandas(pd.DataFrame(data=[{
    'id': 1,
    'a': 100,
}, {
    'id': 2,
    'a': 300,
}]), npartitions=1)
df = df.set_index(other='id')
  • 1行1行曎新を行なう制埡 : この蟺りはPandasでも遅かったりするが、Daskでも同様に遅い。
  • むンデックスを䜿わない連結や、groupby埌のオブゞェクトの倀を曎新するような凊理

※䞀郚のPandasのAPIはサポヌトがされおいないPandas偎がむンタヌフェむスが膚倧にあるため。察応しおいるものはドキュメントのAPIのペヌゞで確認できるDask偎も膚倧にある・・・。

Daskのデヌタフレヌムを蚈算過皋で䞀郚確認したい堎合

Daskのデヌタフレヌムは、Pandasのデヌタフレヌムず異なりメモリに過皋でデヌタを茉せない䜜りになっおいる郜合、盎接デヌタの確認ができない。以䞋のように倀の郚分が...ずいう衚蚘になる。

df = dd.from_pandas(pd.DataFrame(data=[{
    'id': 1,
    'a': 100,
}, {
    'id': 2,
    'a': 300,
}]), npartitions=1)

df

image.png

郚分的に過皋のデヌタを確認したい堎合には、headやtailなどのメ゜ッドであれば、内容の確認が効くのでそちらを䜿う。

df.head(n=1)

image.png

df.tail(n=1)

image.png

デヌタフレヌムのむンデックス

前述したように、mergeやgroupbyなどの制埡の際に、DaskではPandasの時よりもむンデックスが重芁になっおくる。䞀方で、むンデックスの蚭定自䜓が遅いずいうゞレンマはある・・・

1回だけしかむンデックスを䜿う制埡をしないようなあれば、set_indexなどでむンデックスを蚭定するのはあたり効率的にならないかもしれない。䞀方で、䜕床もむンデックスが䜿われるようなケヌスであれば、事前にset_indexでむンデックスを蚭定しおおいたほうがトヌタルでは恐らく速くなる。

たた、たずえばデヌタが日付などで分割されおいおそれらを統合した際に、Dask偎で自動で各デヌタがパヌティションが蚭定されるが、むンデックスを貌るこずで各デヌタの日付の境界などがDask偎で分かるようになる。そのような状態では、たずえばむンデックスを参照した日付のスラむスなども非垞に高速に動䜜する。そういった凊理が高速に動䜜する状態になっおいるかどうかは、デヌタフレヌムのknown_divisions属性で確認ができる。

df_1 = pd.DataFrame(columns=['date', 'a'], index=np.arange(0, 3000000))
df_1.date = '2019-06-10'
df_1.a = 100

df_2 = pd.DataFrame(columns=['date', 'a'], index=np.arange(0, 3000000))
df_2.date = '2019-06-11'
df_2.a = 200

df_3 = pd.DataFrame(columns=['date', 'a'], index=np.arange(0, 3000000))
df_3.date = '2019-06-12'
df_3.a = 300

df = dd.concat([df_1, df_2, df_3])

この時点ではただ統合のみで、むンデックスを貌っおいないのでknown_divisionsはFalseになっおいる。

df.known_divisions
False

むンデックスを貌るずknown_divisionsがTrueになる。

df = df.set_index(other='date')
df.known_divisions
True

デヌタフレヌムを確認するず、以䞋のような衚瀺になり、パヌティションの境界が゜ヌトされおいるこずが分かる2019-06-12が2個あるずも思ったが、ドキュメントを読んでいた限り倧䞈倫そうな印象があるのでスルヌする。

image.png

詊しに、2019-06-10, 2019-06-12, 2019-06-11ずいう順番でデヌタフレヌムをconcatしおみたずころ、前述のスクショの12 tasksずなっおいる箇所のタスク数が増えた。ドキュメントに、むンデックスは゜ヌトされおいるずむンデックスの蚭定が早く終わるず曞かれおいたので、恐らく゜ヌトの制埡が増える分蚈算が遅くなるのかな、ずいう印象。
デヌタの指定順など堎合によっおはCSVなどで保存時などにも、゜ヌトしおおくなどには気を配ったほうが良いケヌスがあるかもしれない。

さらに蚀うず、事前に゜ヌトが確実にされおいる前提で、set_indexメ゜ッドでsorted=Trueを匕数に指定するずむンデックスの蚭定が高速にされるらしい。詊しに、日付が゜ヌトされおいない状態のset_indexず゜ヌトされおいる状態でconcatされ、sorted=Trueを指定しおむンデックスを蚭定した際の速床の差を確認しおみる300䞇行のデヌタフレヌム × 3。

たずは゜ヌトされおいない条件から。

%%timeit
df = dd.concat([df_1, df_3, df_2])
df = df.set_index(other='date')
1 loop, best of 3: 5.49 s per loop

倧分遅い。

続いお゜ヌトされおいる条件。

%%timeit
df = dd.concat([df_1, df_2, df_3])
df = df.set_index(other='date', sorted=True)

5倍匱皋床速くなった。

パヌティションの話

Daskのデヌタフレヌムでは、指定を省略した堎合などは読み蟌みで指定されたファむル数や、concatなどでデヌタの連結をした堎合はその個数に応じたパヌティションが自動で蚭定される。

ただし、Dask配列のチャンクサむズず同様、このパヌティションのサむズも、小さすぎおも倧きすぎおもパフォヌマンス面で奜たしくない。小さすぎるず分割によるオヌバヌヘッドが倧きくなり、倧きすぎるず瞬間的にメモリが倚く必芁になっおしたう
パヌティションが数䞇ずかになっおいたらオヌバヌヘッド的に倧分き぀いかもしれない。

奜たしいサむズ的には、倧䜓チャンクサむズのずきず同じような感芚で問題はない。䜿うマシンのメモリやコア数に合わせお、1぀のパヌティションで倧䜓100MB数癟MB皋床の範囲になるようにしおおくず奜たしい。

よくあるケヌスでは、蚈算の途䞭でスラむスなどをしお、デヌタ量は少なくなっおいるにも関わらず、倧量のパヌティションのたた蚈算を色々やっおしたうケヌス。そういった、過皋でデヌタが倧分少なくなる条件があり、䞔぀その埌も蚈算が結構続く堎合には䞀旊repartitionなどのメ゜ッドでパヌティション数を枛らしおおくず、その埌の蚈算が効率的に実行される。

スラむスで枛った件数に比率に応じお、パヌティション数も枛った比率を加味しお枛らす蚭定をする䟋 :

row_num = 10000000
df = pd.DataFrame(
    columns=['a', 'b', 'c'],
    index=np.arange(0, row_num))
df.a = np.random.randint(0, 100, size=(row_num,))
df.b = np.random.randint(0, 100, size=(row_num,))
df.c = np.random.randint(0, 100, size=(row_num,))
df = dd.from_pandas(data=df, npartitions=10)
before_row_num = len(df)
df = df[df.a >= 75]
after_row_num = len(df)
print('before_row_num:', before_row_num, ', after_row_num:', after_row_num)
before_row_num: 10000000 , after_row_num: 2500901
npartitions = int(df.npartitions / (before_row_num / after_row_num))
npartitions
2
df = df.repartition(npartitions=npartitions)

連結の話

既にむンデックスなどの節である皋床觊れおいる、mergeなどの連結関係の操䜜に関しお、むンデックス同士の連結以倖でも以䞋のようなケヌスでは速くなる。

  • 耇数のパヌティションを持぀デヌタフレヌムず、1぀のパヌティションしか持たないデヌタフレヌムを連結する堎合 : 耇数のパヌティションを持぀倧きな既存のデヌタフレヌムに察しお、1぀のパヌティションしか持たない小さなデヌタフレヌム远加で必芁になっお読み蟌たれたデヌタフレヌムなどを連結するケヌスは速く動䜜する。
  • DaskのデヌタフレヌムずPandasのデヌタフレヌムを連結する堎合 : このケヌスも、実質Pandas偎のデヌタフレヌムがパヌティションが1぀のデヌタフレヌムずしお扱えるので速く動䜜する。

䞊蚘のケヌス以倖で、䞔぀むンデックスも加味しない連結の堎合、パヌティション間のデヌタの移動や怜玢などが色々必芁になるため、凊理が遅くなる。Pandasず異なり、Daskのデヌタフレヌムは耇数のパヌティションでデヌタが分けられおおり、䞀郚しかメモリ䞊に展開されおいないので、Pandasの感芚で扱うずぐっず遅くなる

locずiloc

Pandasでは特定の䜍眮の芁玠を参照する際に、locやilocが必芁になるケヌスががちがちある。
Daskでは、locの方は基本的にPandasの感芚で扱える。
たずえば、以䞋のような曞き方はサポヌトされおいる。

df.loc[0]
df.loc[1]
df.loc[:, ['id']]

䞀方で、ilocの方は、Daskが行数を垞には保持しおいないため、特定行の遞択には䜿えなかったりする。列番号の指定には察応しおいるので、基本的に行の方はコロンで党行指定をする圢でしか利甚できない。

2番目の列のみのデヌタフレヌムを取埗する䟋 :

df.iloc[:, [1]]

なお、Pandasの堎合はlocず異なりilocでの[行, 列]ずいった遞択は確かできない気がするiloc[行むンデックス][列名]などず指定する必芁があるものの、Daskだず前述のような曞き方ができる。

ilocで特定行の遞択をしようずするず、特定行の遞択には察応しおいないのでコロンで行党䜓を遞択しおくれず怒られる。

df.iloc[0, [1]]
NotImplementedError: 'DataFrame.iloc' only supports selecting columns. It must be used like 'df.iloc[:, column_indexer]'.

タスクグラフの可芖化

前述したタスクグラフを可芖化する機胜がDaskには甚意されおいる。
利甚するには、graphviz関係のラむブラリが必芁になる。pipなどだず、graphviz自䜓のむンストヌルずPythonのgraphvizラむブラリの2぀が必芁になる。
Anacondaのコマンドだず1回のコマンドでよしなにむンストヌルしおくれる。
䟝存関係ずかが若干面倒な印象があるので、Anacondaのコマンドの方が楜な印象はある。

$ conda install python-graphviz -y
The following NEW packages will be INSTALLED:

    graphviz:        2.38.0-5    
    python-graphviz: 0.5.2-py36_0

可芖化自䜓はvisualizeメ゜ッドで実行できる。これはcomputeメ゜ッド同様、Daskの各むンタヌフェむス共通で甚意されおいる。

import dask.array as da
x1 = da.random.uniform(low=0, high=1.0, size=(100, 100))
x2 = da.random.uniform(low=0, high=1.0, size=(100, 100))
x3 = da.random.uniform(low=0, high=1.0, size=(100, 100))
x4 = da.random.uniform(low=0, high=1.0, size=(100, 100))
y = x1 + x2 + x3 * x4
y.visualize()

image.png

ただし、あたりにノヌドが倚いものなどは可芖化にかなり時間がかかったり、倱敗したりするので泚意。

可芖化に関しおは、内容が確認できるだけでなく、ケヌスによっおは遅くなりそうな箇所の特定にも圹に立぀堎合がある。
たずえば、ノヌド数が統合されお枛っおいる箇所があれば、䞊列で凊理される件数も枛ったり、それぞれのノヌドが終わるたで統合ができないので凊理を埅ったりする。
そのため、たずえば片偎だけ極端に遅く、そのノヌドが統合予定であれば、統合時にそのタスク消化埅ちボトルネックが発生したりする。

Dask Delayed

NumPyむンタヌフェむスのDaskの配列や、PandasむンタヌフェむスのDaskのデヌタフレヌムのほかに、Python自䜓のコヌドのむンタヌフェむスずしお䜿えるDelayedずいうむンタヌフェむスが甚意されおいる。
通垞のPythonコヌドで即時で凊理が走るケヌスずは違い、凊理が遅延評䟡他のDaskむンタヌフェむス同様、即時では蚈算が走らず、compute呌び出し時点で蚈算などが開始されるため、恐らくこういった名前が付いおいる。

Pythonビルトむンの、普通のマルチスレッドなどの蚘述よりも蚘述がシンプルに曞けお䞊列化ずタスクグラフの利甚などが実珟できる。

䜿い方は、遅延評䟡を蚭定したい関数をdask.delayed関数で囲むか、デコレヌタヌを利甚するこずでシンプルに曞くこずができる。

  • delayed関数を挟む䟋 : dask.delayed(察象の関数)(関数に蚭定する匕数)ずいった曞き方になる。
import dask


def increment(x):
    return x + 1


def add(a, b):
    return a + b


x = dask.delayed(increment)(5)
y = dask.delayed(increment)(10)
z = dask.delayed(add)(x, y)

dask.delayed(increment(5))ずいった曞き方ず間違えないように泚意。匕数郚分は倖に出さないず遅延評䟡されずに即時で蚈算が走っおしたう。
この時点ではただ蚈算などは走っおいない。zの内容を芋おも数倀の内容などは確認できない。

image.png

compute関数を呌び出した時点ではじめお各蚈算が走り始め、数倀が取埗できる。

z.compute()
17

たた、Dask配列などのむンタヌフェむスず同様、こちらもタスクグラフの可芖化ができる。
自分で蚈算を曞く圢になるので、グラフ内容も分かりやすい。

z.visualize()

image.png

  • デコレヌタヌを付けお察応する堎合 : @dask.delayedずタスクグラフで扱いたい関数に蚭定する。こちらはキヌワヌド匕数なども受け付けおくれるただし、デコレヌタヌを付けるず匕数が*args、**kwargsずいう衚蚘になっお入力補間などが利かなくなるのず、蚘述も自然で違和感がない。
@dask.delayed
def increment(x):
    return x + 1


@dask.delayed
def add(a, b):
    return a + b


x = increment(x=5)
y = increment(x=10)
z = add(a=x, b=y)
z.compute()
17

これだけで䞊列化されたコヌドになる。ずおもシンプル。
Pythonビルトむンの䞊列凊理モゞュヌルの完党な代替にはならないけれども、Delayedで必芁十分な際にさくっず䞊列化したいずきなど䟿利な印象は受けた。

Daskの配列やDaskのデヌタフレヌムが苊手ずする、Python自䜓のルヌプを回したりなどにも向いおいる。
たた、Pythonビルトむンの関数などに察しおもdelayed関数を挟んで遅延評䟡にしたりもできる䞋蚘コヌドのsum郚分など。ほずんどのPython関数をサポヌトしおいるらしい。

data_tuple = ((1, 2), (3, 4), (5, 6), (7, 8), (9, 10))
output_list = []
for x, y in data_tuple:
    x = increment(x=x)
    y = increment(x=y)
    z = add(a=x, b=y)
    output_list.append(z)
total = dask.delayed(sum)(output_list)
total.compute()
65

タスクグラフを衚瀺しおみるず、ルヌプ分ノヌドが増えおいっおいるこずが分かる。

image.png

どんなずきにDaskのDelayedを䜿うかの䟋

  • Daskの配列やデヌタフレヌムで甚意されおいるAPIだけでは足りないケヌスが発生し、ルヌプを回したりが必芁になった堎合。過皋でDelayedを経由する堎合でも、配列やデヌタフレヌムのむンスタヌフェむスでfrom_delayedやto_delayedなどのむンタヌフェむスが甚意されおおり、盞互に倉換ができる。
  • Pythonのビルトむンの䞊列凊理を䜿っお现かい調敎をしたり・・が䞍芁な堎合。前述の通り、シンプルな蚘述で䞊列凊理などが実珟できる。

良くないDelayedの曞き方

  • computeはなるべく少ない数を呌び出す : できれば1回にたずたるようにする。回数が倚くなるず、それぞれのcomputeが終わらないず次の蚈算に移らなくなり、䞊列化された蚈算だずそこがボトルネックになったりする。multiprocessingモゞュヌルなどのjoinをルヌプ内で基本曞かないのず同様、ルヌプ内でcomputeを呌び出したりしないように泚意。
  • 入力倀を盎接曎新しない : 匕数に枡される倀をそのたたむンクリメントしたりなどは奜たしくないらしい。動䜜はするこずは確認した。䞊列化時のメモリのロックなどの郜合なんだろうか・・以䞋良くないコヌド䟋。
@dask.delayed
def test_func(x):
    x += 1
    return x


x = test_func(x=1)
x.compute()
2

前述のようなコヌドが必芁な堎合には盎接むンクリメントではなくreturn x + 1ずいった別の倉数で扱われる圢で曞くか、copyなどを挟むずいいらしい。

from copy import copy


@dask.delayed
def test_func(x):
    x = copy(x)
    x += 1
    return x


x = test_func(x=1)
x.compute()
2
  • グロヌバル倉数などにはアクセスしない : Daskはマルチスレッドやマルチプロセス、もしくは分散環境などで扱えるが、マルチスレッド以倖ではグロヌバル倉数などにアクセスしおいるず動かないケヌスが出おくる。マルチスレッドから別のものに切り替えた際に躓く芁因になるので、基本的にグロヌバル倉数などにアクセスしおいる曞き方は奜たしくない。以䞋良くない曞き方。
global_list = []


@dask.delayed
def test_func(x):
    global_list.append(x + 1)


x = test_func(x=1)
  • タスクが膚倧になるケヌスは避ける : 现かい関数で膚倧にDelayedを反映したものを呌び出したりするず、1぀1぀のDelayedのオヌバヌヘッドは些现でも、地味に銬鹿にならないオヌバヌヘッドになる。そういった堎合はある皋床たずめられるずころは耇数の関数の凊理をたずめお、オヌバヌヘッドが枛るように調敎するか、ビルトむンのmultiprocessing.Poolなどの方が向いおいるかもしれない。

  • Delayedの指定が入れ子になるような曞き方は避ける : たずえば、デコレヌタヌが぀けられた関数内でさらにdelayedを挟んで他の関数を呌び出したりなど。基本的にそういった入れ子になる䜿い方はNGずのこずで、どちらかのみに蚭定する圢に調敎する必芁がある。

  • Delayed指定された関数に、盎接倧きなデヌタの匕数を䜕床も指定する : そういった堎合は、先にそのデヌタ自䜓にDelayedを挟んでおくず奜たしい関数以倖もDelayedを挟むこずができる。そうするずやりずり面でオヌバヌヘッドが少なくなるらしい恐らく、。以䞋少し倧きめの配列に察しお、delayedを挟んでみた䟋。

large_arr = np.ones(shape=(100000,))
large_arr = dask.delayed(large_arr)


@dask.delayed
def sum_large_arr(large_arr):
    return sum(large_arr)


output_list = []
for i in range(10):
    x = sum_large_arr(large_arr=large_arr)
    output_list.append(x)
total = dask.delayed(sum)(output_list)

total.compute()
1000000.0

タスクグラフを可芖化しおみる。

image.png

スタヌトが1぀になっおいる。配列にdelayedを挟んでいるので、各ノヌドに枡されるものが同䞀のものが参照されおいるこずが分かる。恐らく䞊列化時に枡すデヌタのコピヌなどはされず、同じものが䜿いたわされおいるので効率的に凊理される・・・ずいうこずなのだろうか。ちなみに、配列にdelayedを挟たないもののタスクグラフを確認するず、以䞋のように開始ノヌドが1぀にたずたったりはしおいない。

image.png

パフォヌマンスチュヌニング

そのたただず、Daskは䞊列凊理や分散凊理が絡む郜合で、関数単䜍での凊理時間のプロファむリング甚の%%prunのマゞックコマンドや、そのほかのプロファむリング甚の機胜が動かなかったりする。
さらに蚀うず、そういった蚈枬が必芁なずころ以倖にも、䞊列凊理や分散凊理によるデヌタの倉換のやりずりやデヌタ転送時間、タスクグラフ化によるオヌバヌヘッドなど、通垞のPythonでは蚈枬が難しい箇所が色々ずある。

そのため、蚈枬などに関しおはDask自䜓にある皋床甚意されおおり、遅くなっおいる箇所の特定などに圹立おるこずができる。

䞊列環境の蚈枬・蚺断

分散環境だずたた話が倉わっおくるずころもあるが、䞊列環境であれば以䞋のような機胜が甚意されおいるキャッシュ呚りなど䞀郚割愛。
本蚘事では割愛するものの、分散環境であればTensorBoardみたくwebベヌスで確認できる蚈枬機胜などもある

  • プログレスバヌ : tqdm的な衚瀺を、Daskの䞊列凊理環境で利甚できる。
  • タスク単䜍のプロファむラヌ : タスク単䜍での凊理時間が確認できる。
  • リ゜ヌスプロファむラヌ : メモリ䜿甚量や、CPU䜿甚率などを確認できる。

プログレスバヌ

䞊列環境で各凊理が党郚でどのくらい進んでいるのかをtqdm的に確認ができる。
dask.diagnostics.ProgressBarクラスを䜿う。

䜿う堎合には、withステヌトメントで蚈枬したいcomputeの箇所のみ囲うか、もしくはregisterメ゜ッドを利甚する。埌者はコヌド党䜓に反映される

  • withステヌトメントで囲う堎合 :
import dask.array as da
from dask.diagnostics import ProgressBar

arr = da.random.randint(low=0, high=100, size=(500000000,))
arr += 1
arr += 2
arr += 3
mean_val = arr.mean()
with ProgressBar():
    result = mean_val.compute()

image.png

  • registerで登録する堎合 :

こちらはグロヌバルに反映される。withステヌトメントなどは䞍芁になるので、耇数個所で䜕床もcomputeを呌ぶ堎合などでは䟿利。
郚分的に蚈枬したい堎合などには泚意。衚瀺自䜓はwithステヌトメントを䜿った際ず倉わらない。

progress_bar = ProgressBar()
progress_bar.register()
result = mean_val.compute()

image.png

タスク単䜍のプロファむラヌ

こちらは各タスクの開始時間・終了時間などの蚈枬ずしお䜿う。dask.diagnostics.Profilerクラスを䜿う。
プログレスバヌず同様に、withステヌトメントやregisterなどで利甚できる。
Profilerクラスのオブゞェクトは埌で利甚するので、䞀旊倉数に蚭定しおいる。

from dask.diagnostics import Profiler

profiler = Profiler()
with profiler:
    result = mean_val.compute()

蚈枬結果はプロファむラヌオブゞェクトのresults属性に栌玍される。
ただし、そのたた確認しおもなんだかタスク情報がたくさん情報がある・・・ずいうくらいしか分からない。

profiler.results
[TaskData(key=('randint-mean_chunk-812e8f0cb4ac9321a67b998f47ae5f64', 0), task=(subgraph_callable, 3, 2, (<function _apply_random at 0x7fcf6a384598>, None, 'randint', array([1483484144, 3925864007, 3606941276, 3622924718, 2457601011,
       2992342959, 3580848644, 3214909470,  229022156, 2784167203,
          1520372, 1072208554,  870698918, 2640623133, 1663924999,
         71001927, 3028677620, 1358626999, 3744700271, 2796033730,
       2908454865, 4008216102,  728249598, 4040528145, 3680559835,
...

そのため、基本的には可芖化しお䜿う。プロファむラヌにvisualizeメ゜ッドが甚意されおいるので、そちらを䜿う。
内郚でbokehが䜿われおいるので、Jupyter䞊で䜿う堎合には以䞋のようなbokehの蚘述をしないず衚瀺しおくれない%matplotlib inline的な蚘述ず思っおいただければ。

from bokeh.plotting import output_notebook
output_notebook()
BokehJS 0.12.5 successfully loaded.

image.png

瞊軞がワヌカヌごずコアが8個のマシンで動かしおいるため、8個分分割されおいる、暪軞が経過時間で、タスクごずに四角のブロックで衚瀺されおいる。
各ブロックにマりスオヌバヌするず、そのタスクのキヌや番号、簡単な内容などが芋れる。どのタスクなのか・・ずいうこずは正盎分かりづらい感もある。タスクグラフを䜜るずきに名前ずか付けられるのだろうか・・

今回のケヌスでは、黄色の色が付いおいるブロックが各ワヌカヌで凊理を実行䞭、癜い領域がリ゜ヌスが空いおいる状態他のワヌカヌの凊理埅ちなどかず思われるスクショの右䞊を芋るず、若干の癜いブロック領域があるこずが分かる。

今回のサンプルコヌドでは、正盎倧きくボトルネックになっおいるものも無さそうほずんど党面が黄色くなっおいるで、調敎も䞍芁そうなプロット結果ずなった。
公匏のドキュメントを芋おいるず、もっずボトルネックが顕著なプロットになっおいるので、恐らくアンバランスな耇雑なタスクになっおきたらもっず有益なプロットになるのだろう・・ずいう印象。

image.png

※䞊蚘の図は公匏のドキュメント Diagnostics (local)から匕甚。

なお、registerでグロヌバルに登録しおいるず、耇数のcomputeでの蚈算の内容がプロットに入っおくる。あたり芋やすいずは蚀えない印象を受けたので、堎合によっおはwithステヌトメントで単䜓のcomputeのみを察象にしたほうが芋やすくお奜たしいかもしれないこれは、埌述のリ゜ヌスプロファむラヌでも同様。

リ゜ヌスプロファむラヌ

リ゜ヌスプロファむラヌでは、䞊列環境でのCPU䜿甚率やメモリ䜿甚量MB単䜍の確認ができる。
基本的な䜿い方は、䜿うクラスがResourceProfilerクラスになるだけで、他のプログレスバヌやプロファむラヌずほが倉わらず、withステヌトメントやregisterなどのメ゜ッドで登録しお利甚する。

from dask.diagnostics import ResourceProfiler

resource_profiler = ResourceProfiler()
with resource_profiler:
    result = mean_val.compute()

results属性を芋おみるず、タスクごずのプロファむラヌずは異なり、こちらはプロットしなくおも十分分かる内容ずなっおいる。

resource_profiler.results
[ResourceData(time=903533.34111646, mem=632.418304, cpu=0.0),
 ResourceData(time=903534.38281667, mem=3682.156544, cpu=786.1999999999999),
 ResourceData(time=903535.38432508, mem=2337.964032, cpu=779.7)]

デフォルトでは1秒ごずに蚈枬される。今回の蚈算は2.5秒かかったので、3件分蚈枬されおいる。
時間の情報ず、そのタむミングのメモリ䜿甚量・CPU䜿甚量が確認できる。CPUは、Kaggleカヌネルみたいに、コア数×100がMAXずしお衚瀺されるので、今回は8個のコアのマシンで動かしおいるので、完党にCPUリ゜ヌスが䜿われおいれば800ずなる780皋床の数字になっおいるので、ほずんど無駄なくCPUを䜿っおいるこずが分かる。

1秒埌ずの蚈枬を、0.5秒ごずにしおもっず现かく蚈枬したいもしくはもっず長いスパンで蚈枬したい堎合には、ResourceProfilerクラスのdt匕数に秒数を指定するず調敎ができるdtはdatetimeなどではなく、delta timeだず思われる。たずえば、0.2を指定すれば0.2秒間隔で蚈枬され、先ほどたでよりも现かく蚈枬される。結果のデヌタの件数が増える

resource_profiler = ResourceProfiler(dt=0.2)
with resource_profiler:
    result = mean_val.compute()
resource_profiler.results
[ResourceData(time=904075.205010556, mem=366.73536, cpu=0.0),
 ResourceData(time=904075.445630621, mem=2024.218624, cpu=772.9),
 ResourceData(time=904075.646472633, mem=3496.87808, cpu=790.6),
 ResourceData(time=904075.847534518, mem=662.540288, cpu=781.8),
 ResourceData(time=904076.048325532, mem=2146.500608, cpu=795.9),
 ResourceData(time=904076.249606525, mem=3610.038272, cpu=790.3),
 ResourceData(time=904076.450497805, mem=754.847744, cpu=772.3),
 ResourceData(time=904076.651280945, mem=2326.319104, cpu=796.0),
 ResourceData(time=904076.852340879, mem=3300.59776, cpu=785.7),
 ResourceData(time=904077.05340738, mem=1114.50112, cpu=781.8),
 ResourceData(time=904077.254200403, mem=2304.077824, cpu=731.4),
 ResourceData(time=904077.455156886, mem=1699.852288, cpu=617.8)]

先ほどよりも結果の件数が倚いこずが分かる。たた、タスク単䜍のプロファむラヌで、最埌のほうが埮劙に空いおいるワヌカヌがあったずいう点から分かるように、こちらでも最埌の方の蚈枬が埮劙にリ゜ヌスが空いおいるこずが分かる。

こちらも同様に、visualizeメ゜ッドでプロットを衚瀺するこずができる。

resource_profiler.visualize()

image.png

玫がCPU䜿甚率、青緑がメモリ䜿甚量。
CPUはほずんどフルに䜿われおおり、メモリのほうはタスクごずに必芁なずころだけ確保しお、次のタスクで䞍芁になったずころを砎棄しお・・ずやっおいる郜合、山あり谷ありな結果になっおいる。

通垞のデバッグや蚈枬のツヌルを䜿いたい堎合

通垞は、Daskで䞊列化されおいおも、゚ラヌなどがちゃんず怜知できたり、蚈枬甚の機胜が甚意されおいるのでDaskだけでもなんずかなったりする。
しかし、Dask以倖の%pdbだったり、%debugのデバッグのマゞックコマンドだったり、%prunなどを利甚したりがしたくなるケヌスがあるDask偎で䞊列化や分散凊理などされる郜合、通垞はこれらは䜿えない。

そういった堎合には、Daskのスケゞュヌラヌ䞊行凊理・䞊列凊理・分散凊理などの蚈算方匏的なものの遞択を、1぀のスレッドのものに䞀時的に蚭定するこずで、䞊列化などが䞀通り無効化され、前述のマゞックコマンドも利甚できるようになる。

䞊列化がされなくなるので、もちろん遅くなるものの、デバッグなどの面で必芁になった堎合に利甚するこずができる。デバッグなどが終わったら指定を消しお元に戻したりなどを行う

computeメ゜ッドのschedulerの匕数に'single-threaded'ず指定するず、単䞀のスレッドで実行されるようになる。

resource_profiler = ResourceProfiler()
with resource_profiler:
    result = mean_val.compute(scheduler='single-threaded')
resource_profiler.visualize()
[########################################] | 100% Completed |  5.2s

image.png

先ほどは2秒台で終わっおいたので、䞊列化がされなくなったので遅くなったこずが分かる。たた、CPU䜿甚率の最倧が100になっおいるこずも分かる。
あずは、必芁なマゞックコマンドを挟めば、通垞のPythonコヌドのように調査ができる。


他にもPythonなどを䞭心に色々蚘事を曞いおいたす。そちらもどうぞ
今たでに投皿した䞻な蚘事たち

参考文献たずめ

292
249
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
292
249

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?