web-dev-qa-db-fra.com

Comment enregistrer un énorme pandas dataframe sur hdfs?

Je travaille avec pandas et avec spark dataframes. Les dataframes sont toujours très gros (> 20 Go) et le standard spark = les fonctions ne sont pas suffisantes pour ces tailles. Actuellement, je convertis mon pandas dataframe en un spark dataframe comme ceci:

dataframe = spark.createDataFrame(pandas_dataframe)  

Je fais cette transformation car avec spark l'écriture de cadres de données sur hdfs est très facile:

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

Mais la transformation échoue pour les trames de données supérieures à 2 Go. Si je transforme un spark dataframe en pandas je peux utiliser 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)

Ceci est une conversion rapide de spark à pandas et cela fonctionne également pour les trames de données supérieures à 2 Go. Je n'ai pas encore trouvé de moyen de le faire l'autre) Cela signifie avoir un pandas dataframe que je transforme en spark avec l'aide de pyarrow. Le problème est que je ne peux vraiment pas trouver comment écrire un = pandas dataframe to hdfs.

Ma pandas version: 0.19.0

8
Mulgard

Cela signifie avoir un cadre de données pandas que je transforme en spark à l'aide de pyarrow.

pyarrow.Table.fromPandas est la fonction que vous recherchez:

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

Le résultat peut être écrit directement sur Parquet/HDFS sans passer de données via Spark:

import pyarrow.parquet as pq

fs  = pa.hdfs.connect()

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

Voir aussi

Spark notes :

De plus, depuis Spark 2.3 (maître actuel), Arrow est pris en charge directement dans createDataFrame ( SPARK-20791 - Utilisez Apache Arrow pour améliorer Spark createDataFrame de Pandas. DataFrame ). Il utilise SparkContext.defaultParallelism Pour calculer le nombre de morceaux afin que vous puissiez facilement contrôler la taille des lots individuels.

Enfin, defaultParallelism peut être utilisé pour contrôler le nombre de partitions générées à l'aide du _convert_from_pandas Standard, réduisant ainsi la taille des tranches à quelque chose de plus gérable.

Malheureusement, il est peu probable que ceux-ci résolvent vos problèmes de mémoire actuels . Les deux dépendent de parallelize, donc stockez toutes les données dans la mémoire du nœud du pilote. Passer à Arrow ou ajuster la configuration ne peut qu'accélérer le processus ou résoudre les limitations de taille de bloc.

Dans la pratique, je ne vois aucune raison de passer à Spark ici, tant que vous utilisez local Pandas DataFrame comme entrée. Le goulot d'étranglement le plus grave dans ce scénario est les E/S réseau du pilote et la distribution des données ne résoudra pas cela.

10
zero323

Une autre façon est de convertir votre pandas dataframe en spark dataframe (en utilisant pyspark) et de l'enregistrer dans hdfs avec la commande save. Example

    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)

Ici astype change le type de votre colonne de object à string. Cela vous évite une exception autrement levée car spark n'a pas pu comprendre pandas type object. Mais assurez-vous que ces colonnes sont vraiment de type chaîne.

Maintenant, pour enregistrer votre df dans hdfs:

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

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

Prise en charge de la parallélisation des données R d'une taille supérieure à 2 Go

est résolu.

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

Conversion de DataFrames en objets R

vous pouvez convertir un pandas dataframe en un R data.frame

Alors peut-être que la transformation pandas -> R -> Spark -> hdfs?

1
mikep