2017-05-22 2 views
-1

Comment créer une classe mixin pour pandas DataFrame et Python natif dict de telle sorte que les colonnes de dataframe puissent être accédées comme un dictionnaire imbriqué?Création d'une classe Mixin pour pandas DataFrame et Python natif dict

À partir de Accessing pandas DataFrame as a nested list, en utilisant la fonction df.loc() est le moyen d'accéder à la rangée/colonne/tranches désirées. Mais le but est d'accéder à l'image-données 2-D en utilisant la même syntaxe qu'un dicton Python natif. Par exemple.

>>> import pandas as pd 
>>> df = pd.DataFrame([['x', 1,2,3,4,5], ['y', 6,7,8,9,10], ['z', 11,12,13,14,15]]) 
>>> df.columns = ['index', 'a', 'b', 'c', 'd', 'e'] 
>>> df = df.set_index(['index']) 
>>> df 
     a b c d e 
index      
x  1 2 3 4 5 
y  6 7 8 9 10 
z  11 12 13 14 15 

>>> df['x'] 
[1, 2, 3, 4, 5] 

>>> df['x']['a'] 
1 

>>> df['x']['a', 'b'] 
(1, 2) 

>>> df['x']['a', 'd', 'c'] 
(1, 4, 3) 

J'ai essayé de créer une classe mixin en tant que tel:

from pandas import DataFrame 

class VegeTable(DataFrame, dict): 
    def __init__(self, *args, **kwargs): 
     DataFrame.__init__(self, *args, **kwargs) 
    def __getitem__(self, row_key, column_key): 
     if type(row_key) != list: 
      row_key = [row_key] 
     if type(column_key) != list: 
      column_key = [column_key] 
     return df.loc[row_key, column_key] 

Mais je pense qu'il ya quelque chose qui manque tel que l'accès clé dictionnaire ne fonctionne pas et le dict.get retourne une des valeurs étranges:

>>> from pandas import DataFrame 
>>> 
>>> 
>>> class VegeTable(DataFrame, dict): 
...  def __init__(self, *args, **kwargs): 
...   DataFrame.__init__(self, *args, **kwargs) 
...  def __getitem__(self, row_key, column_key): 
...   if type(row_key) != list: 
...    row_key = [row_key] 
...   if type(column_key) != list: 
...    column_key = [column_key] 
...   return df.loc[row_key, column_key] 
... 
>>> 
>>> vt = VegeTable([['x', 1,2,3,4,5], ['y', 6,7,8,9,10], ['z', 11,12,13,14,15]]) 
>>> vt.columns = ['index', 'a', 'b', 'c', 'd', 'e'] 
>>> vt = vt.set_index(['index']) 
>>> vt 
     a b c d e 
index      
x  1 2 3 4 5 
y  6 7 8 9 10 
z  11 12 13 14 15 
>>> vt['x'] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/local/lib/python2.7/site-packages/pandas/core/frame.py", line 2062, in __getitem__ 
    return self._getitem_column(key) 
    File "/usr/local/lib/python2.7/site-packages/pandas/core/frame.py", line 2069, in _getitem_column 
    return self._get_item_cache(key) 
    File "/usr/local/lib/python2.7/site-packages/pandas/core/generic.py", line 1534, in _get_item_cache 
    values = self._data.get(item) 
    File "/usr/local/lib/python2.7/site-packages/pandas/core/internals.py", line 3590, in get 
    loc = self.items.get_loc(item) 
    File "/usr/local/lib/python2.7/site-packages/pandas/core/indexes/base.py", line 2395, in get_loc 
    return self._engine.get_loc(self._maybe_cast_indexer(key)) 
    File "pandas/_libs/index.pyx", line 132, in pandas._libs.index.IndexEngine.get_loc (pandas/_libs/index.c:5239) 
    File "pandas/_libs/index.pyx", line 154, in pandas._libs.index.IndexEngine.get_loc (pandas/_libs/index.c:5085) 
    File "pandas/_libs/hashtable_class_helper.pxi", line 1207, in pandas._libs.hashtable.PyObjectHashTable.get_item (pandas/_libs/hashtable.c:20405) 
    File "pandas/_libs/hashtable_class_helper.pxi", line 1215, in pandas._libs.hashtable.PyObjectHashTable.get_item (pandas/_libs/hashtable.c:20359) 
KeyError: 'x' 
>>> vt.get(['x']) 
>>> vt.get('x') 
>>> vt.get('x', 'a') 
'a' 
>>> vt.get('x', ['a', 'b']) 
['a', 'b'] 
>>> vt.get('x', ['a', 'b']) 

Comment créer une classe mixin pour pandas géants et dataframe dict Python natif telles que les colonnes de trame de données sont accessibles comme un Dict imbriqué? Est-ce possible? Si c'est le cas, comment?

+0

Si vous deviez utiliser '__getitem__' pour la ligne accès, au lieu de l'accès de la colonne en cours, comment proposez-vous de faire l'accès aux colonnes? –

+0

Identique à l'accès à un dict imbriqué 'defaultdict (dict)', c'est-à-dire 'vt [row_ids, column_ids]' Et pour l'accès aux lignes, 'vt [row_ids]'. – alvas

Répondre

1

Erreur lors du raisonnement.

  1. vt = vt.set_index(['index'])
    Cette redéfinira df à <class 'pandas.core.frame.DataFrame'>.
    Vous devez le surcharger ou Typecast le résultat df.

  2. def __getitem__(self, row_key, column_key=None):
    Seulement un paramètre est passé à def __getitem__(....
    Plusieurs paramètres doivent être à l'intérieur [...], par exemple. vt [ 'x', [ 'a', 'b', 'c']]

Si vous acceptez cette notation légèrement différente, cette mise en œuvre ne ce que vous voulez:

class DataFrame2(DataFrame): 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 

    def __getitem__(self, item): 
     if isinstance(item, tuple): 
      row = self.loc[item[0]] 
      sub_item = item[1] 
      if isinstance(sub_item, list): 
       r = [row.loc[key] for key in sub_item] 
       if len(r) == 1: 
        return r[0] 
       else: 
        return tuple(r) 
      else: 
       # NotImplemented, Parameter other than tuple('x', [list]) 
       raise Exception(NotImplemented) 
     else: 
      return tuple(self.loc[item]) 

    def set_index(self, index): 
     return DataFrame2(super().set_index(index)) 

# Usage: 
df = DataFrame2(data) 
df.columns = ['index', 'a', 'b', 'c', 'd', 'e'] 
df = df.set_index(['index']) 

print('df[\'x\']={}\n'.format(df['x'])) 
print('df[\'x\'][\'a\']={}\n'.format(df['x',['a']])) 
print('df[\'x\'][\'a\', \'b\']={}\n'.format(df['x', ['a', 'b']])) 
print('df[\'x\'][\'a\', \'b\', \'c\']={}\n'.format(df['x', ['a', 'b', 'c']])) 

sortie:

df['x']=(1, 2, 3, 4, 5) 
df['x']['a']=1 
df['x']['a', 'b']=(1, 2) 
df['x']['a', 'b', 'c']=(1, 2, 3) 

Testé avec Python: 3.4.2

0

Je ne pense pas que c'est une bonne idée de créer créer une classe mixin. Lorsque vous utilisez des pandas, vous devriez penser de façon pandas.Et je doute aussi que dict imbriquées Python natif peut être évaluer de cette façon:

In []: df['x']['a', 'b'] 

Mais, si vous insistez, essayez ce code premier:

In []: df.T.to_dict() 
Out[]: 
{'x': {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}, 
'y': {'a': 6, 'b': 7, 'c': 8, 'd': 9, 'e': 10}, 
'z': {'a': 11, 'b': 12, 'c': 13, 'd': 14, 'e': 15}}