9 votes

Enregistrement dans un fichier d'un tableau ou d'un DataFrame avec d'autres informations

Le logiciel statistique Stata permet d'enregistrer de courts extraits de texte dans un ensemble de données. Ceci est réalisé soit en utilisant notes et/ou characteristics .

Cette fonction m'est très utile, car elle me permet de sauvegarder toute une série d'informations, allant de rappels et de listes de tâches à des informations sur la façon dont j'ai généré les données, ou même sur la méthode d'estimation d'une variable particulière.

J'essaie maintenant de proposer une fonctionnalité similaire dans Python 3.6. Jusqu'à présent, j'ai regardé en ligne et consulté un certain nombre d'articles, qui ne répondent toutefois pas exactement à ce que je veux faire.

Voici quelques postes de référence :

Pour un petit NumPy j'en ai conclu qu'une combinaison de la fonction numpy.savez() y un dictionary peut stocker adéquatement toutes les informations pertinentes dans un seul fichier.

Par exemple :

a = np.array([[2,4],[6,8],[10,12]])
d = {"first": 1, "second": "two", "third": 3}

np.savez(whatever_name.npz, a=a, d=d)
data = np.load(whatever_name.npz)

arr = data['a']
dic = data['d'].tolist()

Cependant, la question demeure :

Existe-t-il de meilleurs moyens d'incorporer potentiellement d'autres éléments d'information dans un fichier contenant un NumPy ou un (grand) Pandas DataFrame ?

Je suis particulièrement intéressé à entendre parler de la particularité pros y contre de toute suggestion que vous pourriez avoir avec des exemples. Moins il y a de dépendances, mieux c'est.

9voto

jpp Points 83462

Il existe de nombreuses options. Je ne parlerai que du HDF5, car j'ai de l'expérience avec ce format.

Avantages : Portable (peut être lu en dehors de Python), compression native, capacités hors mémoire, support des métadonnées.

Inconvénients : Dépendance à l'égard d'une seule API C de bas niveau, possibilité de corruption des données en tant que fichier unique, la suppression des données ne réduit pas automatiquement la taille.

Selon mon expérience, pour les performances et la portabilité, éviter pyTables / HDFStore pour stocker des données numériques. Vous pouvez plutôt utiliser l'interface intuitive fournie par h5py .

Stocker un tableau

import h5py, numpy as np

arr = np.random.randint(0, 10, (1000, 1000))

f = h5py.File('file.h5', 'w', libver='latest')  # use 'latest' for performance

dset = f.create_dataset('array', shape=(1000, 1000), data=arr, chunks=(100, 100),
                        compression='gzip', compression_opts=9)

Compression et regroupement

Il existe de nombreux choix de compression, par ex. blosc y lzf sont de bons choix pour les performances de compression et de décompression respectivement. Remarque : gzip est natif ; d'autres filtres de compression peuvent ne pas être fournis par défaut avec votre installation HDF5.

Le "chunking" est une autre option qui, lorsqu'elle est alignée sur la façon dont vous lisez les données hors mémoire, peut améliorer considérablement les performances.

Ajouter quelques attributs

dset.attrs['Description'] = 'Some text snippet'
dset.attrs['RowIndexArray'] = np.arange(1000)

Stocker un dictionnaire

for k, v in d.items():
    f.create_dataset('dictgroup/'+str(k), data=v)

Accès hors-mémoire

dictionary = f['dictgroup']
res = dictionary['my_key']

Rien ne remplace la lecture du h5py documentation qui expose la plupart de l'API C, mais vous devriez voir d'après ce qui précède qu'il y a une quantité significative de flexibilité.

0 votes

Quelques remarques : 1) Le blosc sera beaucoup plus rapide pour la compression des données. 2) Si beaucoup de dsets sont créés et que la compatibilité ascendante n'est pas un gros problème, vous pouvez utiliser f = h5py.File('name.hdf5', libver='latest'). Cela devrait améliorer la vitesse de manière significative (petit, mais beaucoup de dsets).

0 votes

@max9111, (1) Est blosc natif / portable en dehors de Python, par exemple, vous pouvez afficher dans HDFView / d'autres bibliothèques ? (2) Merci, je vais mettre à jour avec libver argument.

1 votes

Le filtre Blosc peut être installé dans tout le système. github.com/Blosc/hdf5-blosc Je l'ai mentionné parce qu'il peut être une magnitude plus rapide que gzip, mais vous avez raison, il n'est pas installé par une installation HDF5 par défaut.

1voto

Christian Points 633

Un moyen pratique pourrait être d'intégrer les méta-données directement dans le tableau Numpy. L'avantage est que, comme vous le souhaitez, il n'y a pas de dépendance supplémentaire et que c'est très simple à utiliser dans le code. Cependant, cela ne répond pas entièrement à votre question, car vous avez toujours besoin d'un mécanisme pour sauvegarder les données, et je recommanderais l'utilisation de jpp à l'aide de HDF5.

Pour inclure des métadonnées dans un ndarray il y a un exemple dans la documentation . Vous devez essentiellement sous-classer un ndarray et ajouter un champ info o metadata ou autre.

Cela donnerait (code du lien ci-dessus)

import numpy as np

class ArrayWithInfo(np.ndarray):

    def __new__(cls, input_array, info=None):
        # Input array is an already formed ndarray instance
        # We first cast to be our class type
        obj = np.asarray(input_array).view(cls)
        # add the new attribute to the created instance
        obj.info = info
        # Finally, we must return the newly created object:
        return obj

    def __array_finalize__(self, obj):
        # see InfoArray.__array_finalize__ for comments
        if obj is None: return
        self.info = getattr(obj, 'info', None)

Pour sauvegarder les données par numpy vous devrez surcharger la fonction write ou utiliser une autre solution.

0voto

tnknepp Points 2251

Je suis d'accord avec JPP pour dire que le stockage hdf5 est une bonne option ici. La différence entre sa solution et la mienne est que la mienne utilise des dataframes Pandas au lieu de tableaux numpy. Je préfère le dataframe car il permet des types mixtes, une indexation multi-niveaux (même l'indexation par date, ce qui est TRÈS important pour mon travail), et l'étiquetage des colonnes, ce qui m'aide à me souvenir de l'organisation des différents ensembles de données. De plus, Pandas fournit un grand nombre de fonctionnalités intégrées (un peu comme numpy). Un autre avantage de l'utilisation de Pandas est qu'il possède un créateur hdf intégré (i.e. pandas.DataFrame.to_hdf), ce que je trouve pratique.

Lorsque vous stockez le cadre de données dans h5, vous avez la possibilité de stocker également un dictionnaire de métadonnées, qui peuvent être vos notes à vous-même, ou des métadonnées réelles qui n'ont pas besoin d'être stockées dans le cadre de données (je l'utilise également pour définir les drapeaux, par exemple {'is_agl' : True, 'scale_factor' : 100, 'already_corrected' : False, etc.}. À cet égard, il n'y a aucune différence entre l'utilisation d'un tableau numpy et d'un dataframe. Pour la solution complète, voir ma question originale et la solution ici.

0voto

Darren Brien Points 101

La réponse de jpp est assez complète, je voulais juste mentionner qu'à partir de pandas v22, le parquet est une option très pratique et rapide avec presque aucun inconvénient par rapport au csv (sauf peut-être la pause café).

lire le parquet

écrire le parquet

Au moment de la rédaction du présent document, vous devrez également

pip install pyarrow

En termes d'ajout d'informations, vous avez les métadonnées qui sont attachées aux données.

import pyarrow as pa
import pyarrow.parquet as pq
import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.normal(size=(1000, 10)))

tab = pa.Table.from_pandas(df)

tab = tab.replace_schema_metadata({'here' : 'it is'})

pq.write_table(tab, 'where_is_it.parq')

pq.read_table('where_is_it.parq')

qui donnent ensuite un tableau

Pyarrow table
0: double
1: double
2: double
3: double
4: double
5: double
6: double
7: double
8: double
9: double
__index_level_0__: int64
metadata
--------
{b'here': b'it is'}

Pour en revenir aux pandas :

tab.to_pandas()

0voto

WillMonge Points 713

C'est une question intéressante, bien que très ouverte, je pense.

Extraits de texte
Pour les extraits de texte contenant des notes littérales (c'est-à-dire qui ne sont ni du code ni des données), je ne sais pas quel est votre cas d'utilisation, mais je ne vois pas pourquoi je m'écarterais de la méthode habituelle with open() as f: ...

Petites collections de données diverses
Bien sûr, votre npz travaux. En fait, ce que vous faites est très similaire à la création d'un dictionnaire avec tout ce que vous voulez sauvegarder et au décapage de ce dictionnaire.

Voir ici pour une discussion sur les différences entre pickle et npz (mais principalement, npz est optimisé pour les tableaux numpy).

Personnellement, je dirais que si vous ne stockez pas des tableaux Numpy, j'utiliserais pickle, et même implémenter un rapide MyNotes qui est essentiellement un dictionnaire dans lequel vous pouvez enregistrer des données, avec quelques fonctionnalités supplémentaires que vous pouvez souhaiter.

Collecte de grands objets
Pour les très gros np.arrays ou dataframes, j'ai déjà utilisé le format HDF5. La bonne chose est qu'il est déjà intégré dans pandas et que vous pouvez directement df.to_hdf5() . Il a besoin d'un dessous pytables -L'installation devrait être assez facile avec pip ou conda, mais l'utilisation directe de pytables peut être beaucoup plus difficile.

Là encore, l'idée est très similaire : vous créez un HDFStore, qui est en fait un grand dictionnaire dans lequel vous pouvez stocker des objets (presque tous). L'avantage est que le format utilise l'espace de manière plus intelligente en exploitant la répétition de valeurs similaires. Lorsque je l'ai utilisé pour stocker des trames de données de ~2GB, il a été capable de les réduire de presque un ordre de grandeur complet (~250MB).

Un dernier joueur : feather
Feather est un projet créé par Wes McKinney et Hadley Wickham sur le cadre Apache Arrow, pour faire persister les données dans un format binaire qui n'est pas lié au langage (et que vous pouvez donc lire depuis R et Python). Cependant, il est toujours en développement, et la dernière fois que j'ai vérifié, ils n'encourageaient pas à l'utiliser pour le stockage à long terme (puisque la spécification peut changer dans les futures versions), plutôt que de l'utiliser simplement pour la communication entre R et Python.

Ils viennent tous deux de lancer Ursalabs il y a quelques semaines, qui continuera à développer cette initiative et d'autres similaires.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X