web-dev-qa-db-fra.com

Comment forcer les types de parquet lors de la sauvegarde de pd.DataFrame?

Existe-t-il un moyen de forcer un fichier parquet à coder une colonne pd.DataFrame sous un type donné, même si toutes les valeurs de la colonne sont nulles? Le fait que parquet affecte automatiquement "null" dans son schéma m'empêche de charger plusieurs fichiers dans un seul dask.dataframe.

Essayer de lancer la colonne pandas en utilisant df.column_name = df.column_name.astype(sometype) n'a pas fonctionné.

Pourquoi je demande ceci

Je veux charger plusieurs fichiers de parquet dans un seul dask.dataframe. Tous les fichiers ont été générés à partir de autant d'instances de pd.DataFrame, à l'aide de df.to_parquet(filename). Toutes les images ont les mêmes colonnes, mais pour certaines, une colonne donnée peut contenir uniquement des valeurs NULL. En essayant de charger tous les fichiers dans le dask.dataframe (en utilisant df = dd.read_parquet('*.parquet'), j'obtiens le message d'erreur suivant:

Schema in filename.parquet was different.
id: int64
text: string
[...]
some_column: double

vs

id: int64
text: string
[...]
some_column: null

Procédure pour reproduire mon problème

import pandas as pd
import dask.dataframe as dd
a = pd.DataFrame(['1', '1'], columns=('value',))
b = pd.DataFrame([None, None], columns=('value',))
a.to_parquet('a.parquet')
b.to_parquet('b.parquet')
df = dd.read_parquet('*.parquet')  # Reads a and b

Cela me donne ce qui suit:

ValueError: Schema in path/to/b.parquet was different. 
value: null
__index_level_0__: int64
metadata
--------
{b'pandas': b'{"index_columns": ["__index_level_0__"], "column_indexes": [{"na'
            b'me": null, "field_name": null, "pandas_type": "unicode", "numpy_'
            b'type": "object", "metadata": {"encoding": "UTF-8"}}], "columns":'
            b' [{"name": "value", "field_name": "value", "pandas_type": "empty'
            b'", "numpy_type": "object", "metadata": null}, {"name": null, "fi'
            b'eld_name": "__index_level_0__", "pandas_type": "int64", "numpy_t'
            b'ype": "int64", "metadata": null}], "pandas_version": "0.22.0"}'}

vs

value: string
__index_level_0__: int64
metadata
--------
{b'pandas': b'{"index_columns": ["__index_level_0__"], "column_indexes": [{"na'
            b'me": null, "field_name": null, "pandas_type": "unicode", "numpy_'
            b'type": "object", "metadata": {"encoding": "UTF-8"}}], "columns":'
            b' [{"name": "value", "field_name": "value", "pandas_type": "unico'
            b'de", "numpy_type": "object", "metadata": null}, {"name": null, "'
            b'field_name": "__index_level_0__", "pandas_type": "int64", "numpy'
            b'_type": "int64", "metadata": null}], "pandas_version": "0.22.0"}'}

Remarquez comment dans un cas nous avons "pandas_type": "unicode" et dans l'autre nous avons "pandas_type": "empty".

Questions connexes qui ne m'ont pas apporté de solution

8
HugoMailhot

Si vous utilisez plutôt fastparquet, vous pouvez réaliser le chat de votre choix

import pandas as pd
import dask.dataframe as dd
a = pd.DataFrame(['1', '1'], columns=('value',))
b = pd.DataFrame([None, None], columns=('value',))
a.to_parquet('a.parquet', object_encoding='int', engine='fastparquet')
b.to_parquet('b.parquet', object_encoding='int', engine='fastparquet')

dd.read_parquet('*.parquet').compute()

donne

   value
0    1.0
1    1.0
0    NaN
1    NaN
2
mdurant