2016-08-02 18 views
3

集計を実行せずに、操作によるグループをPandas DataFrameに適用したいと考えています。代わりに、階層構造をMultiIndexに反映させたいだけです。数値マルチインデックスを生成するためのPandas DataFrameグループ化

import pandas as pd 

def multi_index_group_by(df, columns): 
    # TODO: How to write this? (Hard-coded to give the desired result for the example.) 
    if columns == ["b"]: 
     df.index = pd.MultiIndex(levels=[[0,1],[0,1,2]], labels=[[0,1,0,1,0],[0,0,1,1,2]]) 
     return df 
    if columns == ["c"]: 
     df.index = pd.MultiIndex(levels=[[0,1],[0,1],[0,1]], labels=[[0,1,0,1,0],[0,0,0,1,1],[0,0,1,0,0]]) 
     return df 

if __name__ == '__main__': 
    df = pd.DataFrame({ 
     "a": [0,1,2,3,4], 
     "b": ["b0","b1","b0","b1","b0"], 
     "c": ["c0","c0","c0","c1","c1"], 
    }) 
    print(df.index.values) # [0,1,2,3,4] 


    # Add level of grouping 
    df = multi_index_group_by(df, ["b"]) 
    print(df.index.values) # [(0, 0) (1, 0) (0, 1) (1, 1) (0, 2)] 

    # Examples 
    print(df.loc[0]) # Group 0 
    print(df.loc[1,1]) # Group 1, Item 1 


    # Add level of grouping 
    df = multi_index_group_by(df, ["c"]) 
    print(df.index.values) # [(0, 0, 0) (1, 0, 0) (0, 0, 1) (1, 1, 0) (0, 1, 0)] 

    # Examples 
    print(df.loc[0]) # Group 0 
    print(df.loc[0,0]) # Group 0, Sub-Group 0 
    print(df.loc[0,0,1]) # Group 0, Sub-Group 0, Item 1 

multi_index_group_byを実装する最良の方法は何ですか?以下はほとんど動作しますが、結果のインデックスが数値ではありません。

index_columns = [] 
# Add level of grouping 
index_columns += ["b"] 
print(df.set_index(index_columns, drop=False)) 
# Add level of grouping 
index_columns += ["c"] 
print(df.set_index(index_columns, drop=False)) 

は編集:

[ 
    [ #b0 
     [ #c0 
      {"a": 0, "b": "b0", "c": "c0"}, 
      {"a": 2, "b": "b0", "c": "c0"}, 
     ], 
     [ #c1 
      {"a": 4, "b": "b0", "c": "c1"}, 
     ] 
    ], 
    [ #b1 
     [ #c0 
      {"a": 1, "b": "b1", "c": "c0"}, 
     ], 
     [ #c1 
      {"a": 3, "b": "b1", "c": "c1"}, 
     ] 
    ] 
] 

編集:は明確にするため、例では、最後のインデックスはと同等でなければなりません。最後leveのを除いて、

def autoincrement(value=0): 
    def _autoincrement(*args, **kwargs): 
     nonlocal value 
     result = value 
     value += 1 
     return result 
    return _autoincrement 

def swap_levels(df, i, j): 
    order = list(range(len(df.index.levels))) 
    order[i], order[j] = order[j], order[i] 
    return df.reorder_levels(order) 

def multi_index_group_by(df, columns): 
    new_index = df.groupby(columns)[columns[0]].aggregate(autoincrement()) 

    result = df.join(new_index.rename("_new_index"), on=columns) 
    result.set_index('_new_index', append=True, drop=True, inplace=True) 
    result.index.name = None 
    result = swap_levels(result, -2, -1) 
    return result 

それは正しい結果を与える:ここで私はこれまで持って最善の方法ですlは変わらない。改善の余地がかなりあるような気がします。

+0

を与えますか? – desiato

+0

@desiatoこれは着実に増加するndインデックスです(例を参照)。たとえば、(0,1,2、...)は、グループ0、サブグループ1、サブグループ2などを意味します。 – kloffy

+0

本質的には、インデックス付けするのと同じ方法で行をアドレス指定できるようにしたいネストされたリスト – kloffy

答えて

2

あなたがLabelEncoderを使用することができsklearnパッケージを使用して喜んでいる場合:

from sklearn.preprocessing import LabelEncoder 
le = LabelEncoder() 

def multi_index_group_by(df, columns): 
    df.index = pd.MultiIndex.from_tuples(zip(*[ le.fit_transform(df[col]) for col in columns ])) 
    return df 

これは、0の間の値で各列のラベルを符号化しますそしてn_classes-1

を呼び出します

は、あなたのハードコーディングマルチインデックスの意味は何ですか

 a b c 
0 0 0 b0 c0 
1 0 1 b1 c0 
0 0 2 b0 c0 
1 1 3 b1 c1 
0 1 4 b0 c1 
+0

うわー、ええ、私の結末とかなり近いようです(私の質問の最新の編集を見てください)。それはsklearnに依存する価値があるかどうか分からないが、面白い提案、ありがとう! – kloffy

+0

私はこの答えを受け入れるでしょう。なぜなら、ほとんど私が望むことを実行するからです。誰かがsklearnに依存せずに代替案を必要とする場合、私の質問の編集を見てください。 – kloffy

1

このコードは何をしたいん:

index_columns = [] 
replace_values = {} 

index_columns += ["b"] 
replace_values.update({'b0':0, 'b1':1}) 

df[['idx_{}'.format(i) for i in index_columns]] = df[index_columns].replace(replace_values) 
print(df.set_index(['idx_{}'.format(i) for i in index_columns], drop=True)) 

index_columns += ["c"] 
replace_values.update({'c0':0, 'c1':1}) 

df[['idx_{}'.format(i) for i in index_columns]] = df[index_columns].replace(replace_values) 
print(df.set_index(['idx_{}'.format(i) for i in index_columns], drop=True)) 

# If you want the 3rd ('c') level MultiIndex: 
df['d'] = [0,0,1,0,0] 
print(df.set_index(['idx_{}'.format(i) for i in index_columns] + ['d'], drop=True)) 
+0

はい、似たようなもので悩んでいましたが、手動でインデックスを把握する必要がないといいですね。しかし、提案してくれてありがとう、何も良いことがなければ、私はそれを受け入れるだろう。 – kloffy

関連する問題