2016-08-02 2 views
3

집계를 수행하지 않고 팬더 데이터 프레임에 작업 그룹을 적용하고 싶습니다. 대신 계층 적 구조를 MultiIndex에 반영하기 만하면됩니다.숫자 다중 인덱스를 생성하기위한 팬더 데이터 프레임 그룹화

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 꾸준히 증가하는 색인입니다 (예제 참조). 예를 들어 (0,1,2, ...)는 그룹 0, 하위 그룹 1, 하위 - 하위 그룹 2 등을 의미합니다. – kloffy

+0

기본적으로 색인을 생성하는 것과 같은 방식으로 행을 주소 지정하고 싶습니다. 중첩 목록. – kloffy

답변

2

당신이 사용할 수있는 LabelEncoder :

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

는 당신에게 당신의 하드 코딩 MultiIndex의 의미는 무엇입니까

 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

이 코드는 당신이 원하는 것을 : 당신이 sklearn 패키지를 사용하고자하는 경우

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