web-dev-qa-db-ja.com

csvファイルからの読み取りをdask parallelizeできますか?

より高速なデータアクセスを期待して、大きなテキストファイルをhdfストレージに変換しています。変換は問題なく機能しますが、csvファイルからの読み取りは並行して行われません。それは本当に遅いです(SSD上の1GBのテキストファイルで約30分かかるので、それはIOバウンドではないと私は推測しています)。

並列で複数のスレッドで読み取る方法はありますか?重要なことかもしれませんが、私は現在Windowsでの実行を余儀なくされています。

from dask import dataframe as ddf
df = ddf.read_csv("data/Measurements*.csv",
             sep=';', 
             parse_dates=["DATETIME"], 
             blocksize=1000000,
             )

df.categorize([ 'Type',
                'Condition',               
          ])

df.to_hdf("data/data.hdf", "Measurements", 'w')
17
Magellan88

はい、dask.dataframeは並行して読み取ることができます。ただし、次の2つの問題が発生しています。

Pandas.read_csvが部分的にGILを解放する

ほとんどのPandasは複数のスレッドで並行して実行できるため、デフォルトではdask.dataframeはスレッドと並列化します(GILを解放します)。特に、結果のデータフレームがオブジェクトのdtypeを使用する場合、Pandas.read_csvは例外ですテキスト

dask.dataframe.to_hdf(filename)は逐次計算を強制します

単一のHDFファイルに書き込むと、順次計算が強制されます(単一のファイルに並列に書き込むのは非常に困難です。)

編集:新しいソリューション

今日はHDFを避け、代わりにParquetを使用します。単一のマシンでのGILの問題を回避するために、おそらくmultiprocessingまたはdask.distributedスケジューラーを使用します。これら2つの組み合わせにより、完全な線形スケーリングが得られます。

from dask.distributed import Client
client = Client()

df = dask.dataframe.read_csv(...)
df.to_parquet(...)

解決

データセットはメモリに収まる可能性が高いため、dask.dataframe.read_csvを使用して複数のプロセスと並行してロードし、すぐにPandasに切り替えます。

import dask.dataframe as ddf
import dask.multiprocessing

df = ddf.read_csv("data/Measurements*.csv",  # read in parallel
             sep=';', 
             parse_dates=["DATETIME"], 
             blocksize=1000000,
             )

df = df.compute(get=dask.multiprocessing.get)     # convert to pandas

df['Type'] = df['Type'].astype('category')
df['Condition'] = df['Condition'].astype('category')

df.to_hdf('data/data.hdf', 'Measurements', format='table', mode='w')
15
MRocklin

@MRocklinの答えから便乗して、daskの新しいバージョンでは、df.compute(scheduler='processes')またはdf.compute(scheduler='threads')を使用して、マルチプロセッシングまたはマルチスレッドを使用してpandasに変換できます)。

from dask import dataframe as ddf
df = ddf.read_csv("data/Measurements*.csv",
             sep=';', 
             parse_dates=["DATETIME"], 
             blocksize=1000000,
             )

df = df.compute(scheduler='processes')     # convert to pandas

df['Type'] = df['Type'].astype('category')
df['Condition'] = df['Condition'].astype('category')

df.to_hdf('data/data.hdf', 'Measurements', format='table', mode='w')
6
mgoldwasser