2017-05-22 3 views
-1

pandas DataFrameとネイティブPython dictのmixinクラスを作成して、ネストされたdictのようにデータフレーム列にアクセスできるようにするにはどうすればいいですか? Accessing pandas DataFrame as a nested listから、df.loc()機能を使用すると、目的の行/列/スライスにアクセスする方法です。pandas DataFrameとネイティブPython用Mixinクラスの作成dict

しかし、目標は、ネイティブのPython dictと同じ構文を使用して2-Dデータフレームにアクセスすることです。例えば。

>>> 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) 

は私のようなミックスインクラスを作成しようとしました:

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] 

をしかし、私は辞書のキーアクセスが機能しなかったように欠けている何かがあると思うとdict.getは奇妙な値を返します。パンダのデータフレームとデータフレームの列は次のようにアクセスすることができるようなネイティブのPythonの辞書のためのミックスインクラスを作成する方法

>>> 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']) 

入れ子にされたdict?それはまったく可能ですか?もしそうなら、どうですか?

+0

あなたが行の '__getitem__'を使用した場合、私はまた、ネイティブのPythonネストされた辞書は、この方法で評価することができることを疑いますアクセス、現在の列アクセスの代わりに、どのように列アクセスを提案するのですか? –

+0

'vt [row_ids、column_ids]'と 'vt [row_ids]'行のアクセスに対してネストされたdict 'defaultdict(dict)'がアクセスされる方法と同じです。 – alvas

答えて

1

推論の誤り

  1. vt = vt.set_index(['index'])

    これは<class 'pandas.core.frame.DataFrame'>dfを再定義します。
    オーバーロードするか、結果としてTypecastとなります。df

  2. def __getitem__(self, row_key, column_key=None):
    だけパラメータがdef __getitem__(...に渡されます。
    複数のパラメータは、[...]、 の内部にある必要があります。 VT [ 'X'、[ 'A'、 'B'、 'C​​']]

あなたはこのわずかに異なる表記を受け入れる場合は、 この実装は、あなたがやりたいこと:

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']])) 

出力

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) 
パイソンでテスト

:3.4.2

0

私はそれがミックスインクラスを作成作成するために、良いアイデアだとは思いません。あなたがパンダを使うとき、あなたはパンダのように考えるべきです。

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

しかし、あなたが主張する場合は、最初にこのコードを試してください:

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}} 
関連する問題