Enregistrer des attributs supplémentaires dans Pandas Dataframe

je me souviens de mes jours MatLab utilisant des tableaux structurés où vous pourriez stocker des données différentes comme un attribut de la structure principale. Quelque chose comme:

a = {}
a.A = magic(10)
a.B = magic(50); etc.

où A. A et A. B sont complètement séparés les uns des autres vous permettant de stocker différents types au sein de a et d'opérer sur eux comme vous le souhaitez. Les Pandas nous permet de faire quelque chose de similaire, mais pas tout à fait la même.

j'utilise Pandas et je veux stocker les attributs d'un dataframe sans le mettre dans une dataframe. Cela peut être fait via:

import pandas as pd

a = pd.DataFrame(data=pd.np.random.randint(0,100,(10,5)),columns=list('ABCED')

# now store an attribute of <a>
a.local_tz = 'US/Eastern'

maintenant, le fuseau horaire local est stocké dans a, mais je ne peux pas sauvegarder cet attribut quand je sauvegarde la dataframe (i.e. après avoir rechargé a il n'y a pas de A. local_tz). Est-il un moyen de sauver ces attributs?

actuellement, Je ne fais que de nouvelles colonnes dans la base de données pour contenir des informations comme le fuseau horaire, la latitude, le longituded, etc. mais cela semble être un peu à l' déchet. En outre, lorsque je fais une analyse des données, je me heurte à des problèmes de devoir exclure ces autres colonnes.

################## COMMENCER À MODIFIER ##################

grâce aux conseils d'unutbu, je stocke maintenant les données au format h5. Comme nous l'avons mentionné, il est risqué de renvoyer les métadonnées en tant qu'attributs de la base de données. Cependant, comme je suis le créateur de ces fichiers (et des algorithmes de traitement), je peux choisir ce qui est stocké comme métadonnées et ce qui ne l'est pas. Lorsque en traitant les données qui vont aller dans les fichiers h5, je choisis de stocker les métadonnées dans un dictionnaire qui est initialisé comme un attribut de mes classes. J'ai créé une classe IO simple pour importer les données h5, et j'ai fait les métadonnées comme attributs de classe. Maintenant, je peux travailler sur mes images de données sans risque de perdre les métadonnées.

class IO():
    def __init__(self):
        self.dtfrmt = 'dummy_str'

    def h5load(self,filename,update=False):
        '''h5load loads the stored HDF5 file.  Both the dataframe (actual data) and 
        the associated metadata are stored in the H5file

        NOTE: This does not load "any" H5 
        file, it loads H5 files specifically created to hold dataframe data and 
        metadata.

        When multi-indexed dataframes are stored in the H5 format the date 
        values (previously initialized with timezone information) lose their
        timezone localization.  Therefore, <h5load> re-localizes the 'DATE' 
        index as UTC.

        Parameters
        ----------
        filename : string/path
            path and filename of H5 file to be loaded.  H5 file must have been 
            created using <h5store> below.

        udatedf : boolean True/False
            default: False
            If the selected dataframe is to be updated then it is imported 
            slightly different.  If update==True, the <metadata> attribute is
            returned as a dictionary and <data> is returned as a dataframe 
            (i.e., as a stand-alone dictionary with no attributes, and NOT an 
            instance of the IO() class).  Otherwise, if False, <metadata> is 
            returned as an attribute of the class instance.

        Output
        ------
        data : Pandas dataframe with attributes
            The dataframe contains only the data as collected by the instrument.  
            Any metadata (e.g. timezone, scaling factor, basically anything that
            is constant throughout the file) is stored as an attribute (e.g. lat 
            is stored as <data.lat>).'''

        with pd.HDFStore(filename,'r') as store:
            self.data = store['mydata']
            self.metadata = store.get_storer('mydata').attrs.metadata    # metadata gets stored as attributes, so no need to make <metadata> an attribute of <self>

            # put metadata into <data> dataframe as attributes
            for r in self.metadata:
                setattr(self,r,self.metadata[r])

        # unscale data
        self.data, self.metadata = unscale(self.data,self.metadata,stringcols=['routine','date'])

        # when pandas stores multi-index dataframes as H5 files the timezone
        # initialization is lost.  Remake index with timezone initialized: only
        # for multi-indexed dataframes
        if isinstance(self.data.index,pd.core.index.MultiIndex):
            # list index-level names, and identify 'DATE' level
            namen = self.data.index.names
            date_lev = namen.index('DATE')

            # extract index as list and remake tuples with timezone initialized
            new_index = pd.MultiIndex.tolist(self.data.index)
            for r in xrange( len(new_index) ):
                tmp = list( new_index[r] )
                tmp[date_lev] = utc.localize( tmp[date_lev] )

                new_index[r] = tuple(tmp)

            # reset multi-index
            self.data.index = pd.MultiIndex.from_tuples( new_index, names=namen )


        if update:
            return self.metadata, self.data
        else:
            return self





    def h5store(self,data, filename, **kwargs):
        '''h5store stores the dataframe as an HDF5 file.  Both the dataframe 
        (actual data) and the associated metadata are stored in the H5file

        Parameters
        ----------
        data : Pandas dataframe NOT a class instance
            Must be a dataframe, not a class instance (i.e. cannot be an instance 
            named <data> that has an attribute named <data> (e.g. the Pandas 
            data frame is stored in data.data)).  If the dataframe is under
            data.data then the input variable must be data.data.

        filename : string/path
            path and filename of H5 file to be loaded.  H5 file must have been 
            created using <h5store> below.

        **kwargs : dictionary
            dictionary containing metadata information.


        Output
        ------
        None: only saves data to file'''

        with pd.HDFStore(filename,'w') as store:
            store.put('mydata',data)
            store.get_storer('mydata').attrs.metadata = kwargs
Les fichiers

H5 sont ensuite chargés via data = IO().h5load('nom du fichier.h5") la base de données est stockée sous data.données Je conserve les métadonnées dictionnaire données.métadonnées et ont créé des attributs de métadonnées individuels (p. ex. des données.lat créé à partir de données.les métadonnées['lat']).

Mon index, les horodateurs sont localisées à pytz.utc (). Cependant, quand une dataframe multi-indexée est stockée à h5 la localisation du fuseau horaire est perdue (en utilisant Pandas 15.2), donc je corrige pour cela dans IO ().h5load.

12
demandé sur tnknepp 2015-03-18 20:43:25

2 réponses

il y a une question ouverte concernant le stockage de métadonnées personnalisées dans NDFrames. Mais en raison de la multitude de façons dont les fonctions pandas peuvent retourner les DataFrames, l'attribut _metadata n'est pas (encore) conservé dans toutes les situations.

Pour le moment, vous aurez juste à stocker les métadonnées dans une variable auxiliaire.

il existe plusieurs options pour stocker des images de données + métadonnées dans des fichiers, selon le format vous souhaitez utiliser -- pickle, JSON, HDF5 sont toutes les possibilités.

Voici comment vous pouvez stocker et charger une base de données avec des métadonnées en utilisant HDF5. La recette pour stocker les métadonnées provient du Pandas Cookbook .

import numpy as np
import pandas as pd

def h5store(filename, df, **kwargs):
    store = pd.HDFStore(filename)
    store.put('mydata', df)
    store.get_storer('mydata').attrs.metadata = kwargs
    store.close()

def h5load(store):
    data = store['mydata']
    metadata = store.get_storer('mydata').attrs.metadata
    return data, metadata

a = pd.DataFrame(
    data=pd.np.random.randint(0, 100, (10, 5)), columns=list('ABCED'))

filename = '/tmp/data.h5'
metadata = dict(local_tz='US/Eastern')
h5store(filename, a, **metadata)
with pd.HDFStore(filename) as store:
    data, metadata = h5load(store)

print(data)
#     A   B   C   E   D
# 0   9  20  92  43  25
# 1   2  64  54   0  63
# 2  22  42   3  83  81
# 3   3  71  17  64  53
# 4  52  10  41  22  43
# 5  48  85  96  72  88
# 6  10  47   2  10  78
# 7  30  80   3  59  16
# 8  13  52  98  79  65
# 9   6  93  55  40   3

print(metadata)

rendements

{'local_tz': 'US/Eastern'}
23
répondu unutbu 2015-03-18 20:01:33

l'approche que j'utilise est d'ajouter des niveaux supplémentaires MultiIndex pour stocker les informations supplémentaires que je veux (j'utilise les colonnes, mais l'un ou l'autre fonctionnerait). Toutes les colonnes ont les mêmes valeurs pour ces paramètres supplémentaires. Ceci est également utile car je peux combiner plusieurs dataframes ou séparer des colonnes individuelles et ces valeurs sont préservées.

>>> col=pd.MultiIndex.from_product([['US/Eastern'], ['A', 'B', 'C', 'E', 'D']], names=['local_tz', 'name'])
>>> a = pd.DataFrame(data=pd.np.random.randint(0,100,(10,5)),columns=col)
>>> print(a)
local_tz US/Eastern                
name              A   B   C   E   D
0                38  93  63  24  55
1                21  25  84  98  62
2                 4  60  78   0   5
3                26  50  82  89  23
4                32  70  80  90   1
5                 6  17   8  60  59
6                95  98  69  19  76
7                71  90  45  45  40
8                94  16  44  60  16
9                53   8  30   4  72
5
répondu TheBlackCat 2015-03-18 18:21:02