daskのファイル入出力メソッドのcompute()でハマった話

# daskとは

daskは、Pythonのnumpy arrayやPandas DataFrameのいろいろな処理を並列処理できるようにしてくれるパッケージです。

[Dask: Scalable analytics in Python](https://dask.pydata.org/en/latest/)

# 結論
**daskのファイル出力系メソッドは、通常`compute()`不要です！**
おそらく入力系メソッドも`compute()`不要です。（`read_csv()`のみ確認）

# 普通の使い方

**基本的にdaskはやりたい処理に対して`compute()`を実行することで処理を行います。**

（例）

```python 
import pandas as pd
import dask.dataframe as dd

"""
(dask_0.csv)
A,B
1.1,1.2
2.1,2.2
3.1,3.2

"""

ddf = dd.read_csv("dask_*.csv")

sum_order = ddf.sum()
sum_order.compute()


"""
>>> df
     A    B
0  1.2  1.2
1  2.1  2.2
2  3.1  3.2

>>> ddf
Dask DataFrame Structure:
                     A        B
npartitions=1
               float64  float64
                   ...      ...
Dask Name: from-delayed, 3 tasks
>>>

>>> ddf.compute()
     A    B
0  1.1  1.2
1  2.1  2.2
2  3.1  3.2

>>> sum_order
Dask Series Structure:
npartitions=1
A    float64
B        ...
dtype: float64
Dask Name: dataframe-sum-agg, 5 tasks

>>> sum_order.compute()
A    6.4
B    6.6
dtype: float64
"""

```

# ファイル入出力の場合

CSVに出力するメソッド`to_csv()`を例にとってみます。

<a id="予想した動作"></a>
## 予想した動作
いままで通り、処理を定義してから`compute()`で実行させるものだと思っていました。

```python
csv_order = ddf.to_csv("dask_*.csv", index=False)
for order in csv_order:
    order.compute()

"""
>>> csv_order
[Delayed('_to_csv_chunk-c09f9b22-c7b9-4d07-b228-094a480438e7')]

>>> for x in csv_order:
...     x.compute()

# dask_0.csvが出力される

"""
```

## 実際の動作

1行目の`csv_order = ddf.to_csv("dask_*.csv", index=False)`を呼び出した時点で、**`compute()`を実行しない段階で**CSVファイルが出力されます。
（他の出力系メソッド`to_hdf()`、`to_text_files()`、`to_parquet()`でも同じような結果になります。）
（入力系メソッドも、おそらく同様です。）

```python
csv_order = ddf.to_csv("dask_*.csv", index=False)
for order in csv_order:
    order.compute()

"""
>>> csv_order = ddf.to_csv("dask_*.csv", index=False)
# dask_0.csvが出力される

>>> csv_order
['dask_0.csv']

>>> for x in csv_order:
...     x.compute()
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
AttributeError: 'str' object has no attribute 'compute'

"""
```

## 原因

`to_csv()`の定義を見てみると、

```python
def to_csv(df, filename, name_function=None, compression=None, compute=True, 
    get=None, storage_options=None, **kwargs):
```

となっていて、`compute=True`という属性がありました。ここから、デフォルトでは`compute()`も同時に実行していることが推測されます。

もし`compute`を独立して実行させたい場合は、

```python
csv_order = ddf.to_csv("dask_*.csv", index=False, compute=False)
for order in csv_order:
    order.compute()
```

とすれば、[予想した動作](#予想した動作)の実行結果が得られます。


# ハマった原因

まず、daskといえば`compute()`を実行する必要があると思い込んでいた、、、（慢心、ダメ、絶対）

また、[dask.dataframe.to_csvのドキュメント](dask.dataframe.to_csv)を読んでもはっきりとは書いていないし、**Parametersを見ても`compute`なんて書いていないし、、、、(2018年3月28日現在)**
（これってプルリク送って直してもらった方が良いのかな…？）

<img src="https://qiita-image-store.s3.amazonaws.com/0/213129/3e38dd21-9966-450a-fb2f-a87747478db5.png" width=50%></img>
<img src="https://qiita-image-store.s3.amazonaws.com/0/213129/3a9eb92b-936f-61d4-b456-75046071bec2.png" width=50%></img>
<img src="https://qiita-image-store.s3.amazonaws.com/0/213129/1b517b71-99cb-36ea-bd66-548b0bb22b6a.png" width=50%></img>

実はメソッドの定義にしれっと書いてあったんだけどね。。
<img src="https://qiita-image-store.s3.amazonaws.com/0/213129/3cb94c0d-24fa-9857-3b46-ac76e4b9ac59.png" width=75%></img>

# あとがき

daskはなんでもかんでも`compute()`するわけではないと知れて勉強になりました。








# 参考文献
* [Dask &mdash; dask 0.17.2 documentation](http://dask.pydata.org/en/latest/docs.html)
* [Python Dask で 並列 DataFrame 処理 - StatsFragments](http://sinhrks.hatenablog.com/entry/2015/09/24/222735)
* [PythonでCSVを高速＆省メモリに読みたい - tkm2261's blog](http://yutori-datascience.hatenablog.com/entry/2017/08/03/230047#daskdataframeread_csv)