web-dev-qa-db-ja.com

巨大なpandasデータフレームをhdfsに保存する方法は?

私はpandasおよびsparkデータフレームを使用しています。データフレームは常に非常に大きく(> 20 GB)、標準spark =関数はこれらのサイズには不十分です。現在、pandasデータフレームをsparkデータフレームに次のように変換しています:

dataframe = spark.createDataFrame(pandas_dataframe)  

sparkを使用すると、データフレームをhdfsに書き込むのが非常に簡単であるため、この変換を行います。

dataframe.write.parquet(output_uri, mode="overwrite", compression="snappy")

しかし、2 GBを超えるデータフレームの変換は失敗しています。 sparkデータフレームをpandasに変換すると、pyarrowを使用できます。

// temporary write spark dataframe to hdfs
dataframe.write.parquet(path, mode="overwrite", compression="snappy")

// open hdfs connection using pyarrow (pa)
hdfs = pa.hdfs.connect("default", 0)
// read parquet (pyarrow.parquet (pq))
parquet = pq.ParquetDataset(path_hdfs, filesystem=hdfs)
table = parquet.read(nthreads=4)
// transform table to pandas
pandas = table.to_pandas(nthreads=4)

// delete temp files
hdfs.delete(path, recursive=True)

これはspark to pandasからの高速な会話であり、2 GBを超えるデータフレームでも機能します。他の方法はまだ見つかりませんでした。 pandasデータフレームをpyarrowの助けを借りてsparkに変換することを意味します。問題は、私が実際に= pandas hdfsへのデータフレーム。

私のpandasバージョン:0.19.0

8
Mulgard

Pyarrowを使用してpandasデータフレームをsparkに変換することを意味します。

pyarrow.Table.fromPandas は、探している関数です。

Table.from_pandas(type cls, df, bool timestamps_to_ms=False, Schema schema=None, bool preserve_index=True)

Convert pandas.DataFrame to an Arrow Table
import pyarrow as pa

pdf = ...  # type: pandas.core.frame.DataFrame
adf = pa.Table.from_pandas(pdf)  # type: pyarrow.lib.Table

結果は、Sparkを介してデータを渡すことなく、Parquet/HDFSに直接書き込むことができます。

import pyarrow.parquet as pq

fs  = pa.hdfs.connect()

with fs.open(path, "wb") as fw
    pq.write_table(adf, fw)

も参照してください

スパークノート

さらに、Spark 2.3(現在のマスター)ArrowがcreateDataFrameで直接サポートされているため( SPARK-20791-Apache Arrowを使用してSpark createDataFrame from Pandas.DataFrame を改善) 。それは SparkContext.defaultParallelismを使用してチャンクの数を計算する なので、個々のバッチのサイズを簡単に制御できます。

最後に、defaultParallelismを使用して、標準の_convert_from_pandasを使用して生成されるパーティションの数を制御し、スライスのサイズをより扱いやすいものに効果的に縮小できます。

残念ながら、これらが 現在のメモリの問題 を解決する可能性は低いです。どちらもparallelizeに依存しているため、すべてのデータをドライバーノードのメモリに格納します。 Arrowへの切り替えまたは構成の調整は、プロセスまたはアドレスブロックサイズの制限をスピードアップするだけです。

実際には、ローカルSpark DataFrameを入力として使用している限り、ここでPandasに切り替える理由はありません。このシナリオで最も深刻なボトルネックは、ドライバーのネットワークI/Oであり、データの配信では対応できません。

10
zero323

もう1つの方法は、pandasデータフレームをsparkデータフレーム(pysparkを使用)に)変換し、saveコマンドでhdfsに保存することです。

    df = pd.read_csv("data/as/foo.csv")
    df[['Col1', 'Col2']] = df[['Col2', 'Col2']].astype(str)
    sc = SparkContext(conf=conf)
    sqlCtx = SQLContext(sc)
    sdf = sqlCtx.createDataFrame(df)

ここでastypeは、列のタイプをobjectからstringに変更します。これは、sparkが理解できなかったpandas type objectであるため、他の方法で発生した例外からあなたを救います。しかし、これらの列が本当にタイプであることを確認してくださいストリング。

次に、dfをhdfsに保存します。

    sdf.write.csv('mycsv.csv')
2
lego king

から https://issues.Apache.org/jira/browse/SPARK-6235

2GBより大きいR data.frameの並列化のサポート

解決されました。

から https://pandas.pydata.org/pandas-docs/stable/r_interface.html

データフレームをRオブジェクトに変換する

pandas dataframeをR data.frameに変換できます

したがって、おそらく変換pandas-> R-> Spark-> hdfs?

1
mikep