J'ai un grand Pandas dataframe (~ 15 Go, 83m de lignes) que je souhaite enregistrer en tant que fichier h5
(Ou feather
). Une colonne contient longues chaînes d'ID de nombres, qui devraient avoir un type chaîne/objet. Mais même lorsque je m'assure que pandas analyse toutes les colonnes comme object
:
df = pd.read_csv('data.csv', dtype=object)
print(df.dtypes) # sanity check
df.to_hdf('df.h5', 'df')
> client_id object
event_id object
account_id object
session_id object
event_timestamp object
# etc...
Je reçois cette erreur:
File "foo.py", line 14, in <module>
df.to_hdf('df.h5', 'df')
File "/shared_directory/projects/env/lib/python3.6/site-packages/pandas/core/generic.py", line 1996, in to_hdf
return pytables.to_hdf(path_or_buf, key, self, **kwargs)
File "/shared_directory/projects/env/lib/python3.6/site-packages/pandas/io/pytables.py", line 279, in to_hdf
f(store)
File "/shared_directory/projects/env/lib/python3.6/site-packages/pandas/io/pytables.py", line 273, in <lambda>
f = lambda store: store.put(key, value, **kwargs)
File "/shared_directory/projects/env/lib/python3.6/site-packages/pandas/io/pytables.py", line 890, in put
self._write_to_group(key, value, append=append, **kwargs)
File "/shared_directory/projects/env/lib/python3.6/site-packages/pandas/io/pytables.py", line 1367, in _write_to_group
s.write(obj=value, append=append, complib=complib, **kwargs)
File "/shared_directory/projects/env/lib/python3.6/site-packages/pandas/io/pytables.py", line 2963, in write
self.write_array('block%d_values' % i, blk.values, items=blk_items)
File "/shared_directory/projects/env/lib/python3.6/site-packages/pandas/io/pytables.py", line 2730, in write_array
vlarr.append(value)
File "/shared_directory/projects/env/lib/python3.6/site-packages/tables/vlarray.py", line 547, in append
self._append(nparr, nobjects)
File "tables/hdf5extension.pyx", line 2032, in tables.hdf5extension.VLArray._append
OverflowError: value too large to convert to int
Apparemment, il essaie de convertir cela en int de toute façon et échoue.
Lors de l'exécution de df.to_feather()
J'ai un problème similaire:
df.to_feather('df.feather')
File "/shared_directory/projects/env/lib/python3.6/site-packages/pandas/core/frame.py", line 1892, in to_feather
to_feather(self, fname)
File "/shared_directory/projects/env/lib/python3.6/site-packages/pandas/io/feather_format.py", line 83, in to_feather
feather.write_dataframe(df, path)
File "/shared_directory/projects/env/lib/python3.6/site-packages/pyarrow/feather.py", line 182, in write_feather
writer.write(df)
File "/shared_directory/projects/env/lib/python3.6/site-packages/pyarrow/feather.py", line 93, in write
table = Table.from_pandas(df, preserve_index=False)
File "pyarrow/table.pxi", line 1174, in pyarrow.lib.Table.from_pandas
File "/shared_directory/projects/env/lib/python3.6/site-packages/pyarrow/pandas_compat.py", line 501, in dataframe_to_arrays
convert_fields))
File "/usr/lib/python3.6/concurrent/futures/_base.py", line 586, in result_iterator
yield fs.pop().result()
File "/usr/lib/python3.6/concurrent/futures/_base.py", line 425, in result
return self.__get_result()
File "/usr/lib/python3.6/concurrent/futures/_base.py", line 384, in __get_result
raise self._exception
File "/usr/lib/python3.6/concurrent/futures/thread.py", line 56, in run
result = self.fn(*self.args, **self.kwargs)
File "/shared_directory/projects/env/lib/python3.6/site-packages/pyarrow/pandas_compat.py", line 487, in convert_column
raise e
File "/shared_directory/projects/env/lib/python3.6/site-packages/pyarrow/pandas_compat.py", line 481, in convert_column
result = pa.array(col, type=type_, from_pandas=True, safe=safe)
File "pyarrow/array.pxi", line 191, in pyarrow.lib.array
File "pyarrow/array.pxi", line 78, in pyarrow.lib._ndarray_to_array
File "pyarrow/error.pxi", line 85, in pyarrow.lib.check_status
pyarrow.lib.ArrowInvalid: ('Could not convert 1542852887489 with type str: tried to convert to double', 'Conversion failed for column session_id with type object')
Alors:
Après avoir fait quelques lectures sur ce sujet, il semble que le problème concerne les colonnes de type string
. Mes colonnes string
contiennent un mélange de chaînes de nombres entiers et de chaînes de caractères. Pandas a l'option flexible de conserver les chaînes en tant que object
, sans type déclaré, mais lors de la sérialisation vers hdf5
Ou feather
le contenu de la colonne est convertie en type (str
ou double
, par exemple) et ne peut pas être mélangée. Ces deux bibliothèques échouent lorsqu'elles sont confrontées à une bibliothèque suffisamment grande de type mixte.
La conversion forcée de ma colonne mixte en chaînes m'a permis de l'enregistrer en plume, mais en HDF5, le fichier a explosé et le processus s'est terminé lorsque j'ai manqué d'espace disque.
Ici est une réponse dans un cas comparable où un commentateur note (il y a 2 ans) "Ce problème est très standard, mais les solutions sont rares".
Les types de chaîne dans Pandas sont appelés object
, mais cela masque qu'il peut s'agir de chaînes pures ou de dtypes mixtes (numpy a des types de chaîne intégrés, mais Pandas ne les utilise jamais pour le texte). Donc la première chose à faire dans un cas comme celui-ci est d'appliquer tous les cols de chaîne comme type de chaîne (avec df[col].astype(str)
). Mais même ainsi, dans un fichier suffisamment volumineux (16 Go, avec de longues chaînes), cela a toujours échoué. Pourquoi?
La raison pour laquelle je rencontrais cette erreur était que j'avais des données qui longues et à haute entropie (nombreuses valeurs uniques différentes) chaînes. (Avec des données à faible entropie, cela aurait peut-être valu la peine de passer à categorical
dtype.) Dans mon cas, j'ai réalisé que je n'avais besoin que de ces chaînes pour identifier les lignes - afin de pouvoir les remplacer par des entiers uniques !
df[col] = df[col].map(dict(Zip(df[col].unique(), range(df[col].nunique()))))
Pour les données texte, il existe d'autres solutions recommandées que hdf5
/feather
, notamment:
json
msgpack
(notez que dans Pandas 0,25 read_msgpack
est déconseillé))pickle
(qui a connu problèmes de sécurité , alors soyez prudent - mais cela devrait être OK pour le stockage interne/transfert de trames de données)parquet
, qui fait partie de l'écosystème Apache Arrow.Ici est une réponse de Matthew Rocklin (l'un des développeurs dask
) comparant msgpack
et pickle
. Il a écrit une comparaison plus large sur son blog .
HDF5 n'est pas la solution appropriée pour ce cas d'utilisation. hdf5 est une meilleure solution si vous avez plusieurs cadres de données que vous souhaitez stocker dans une seule structure. Il a plus de frais généraux lors de l'ouverture du fichier, puis il vous permet de charger efficacement chaque trame de données et également de charger facilement des tranches d'entre eux. Il doit être considéré comme un système de fichiers qui stocke les trames de données.
Dans le cas d'un événement de trame de données unique de séries chronologiques, les formats recommandés seraient l'un des formats de projet Apache Arrow, à savoir feather
ou parquet
. On devrait les considérer comme des fichiers csv basés sur des colonnes (compressés). Le compromis particulier entre ces deux est bien présenté sous Quelles sont les différences entre la plume et le parquet? .
Un problème particulier à considérer concerne les types de données. Puisque feather
n'est pas conçu pour optimiser l'espace disque par compression, il peut prendre en charge un plus grande variété de types de données . Alors que parquet
essaie de fournir une compression très efficace, il ne peut prendre en charge qu'un sous-ensemble limité qui lui permettrait de mieux gérer la compression des données.