본문 바로가기

IT/Python

Python에서 행을 열로 바꾸는 Pivoting 하기 - 2탄

이번에는 조금 다른 pivot 사례를 가져왔습니다. 

이전 다룬 Pivot 사례는  group 기준이되는 index가 1개 이상이거나, value가 1개일 경우에 pivot하는 방법이였다면,

 

[IT/Python] - Python에서 행을 열로 변환하기 - pandas Pivot 메소드

 

Python에서 행을 열로 변환하기 - pandas Pivot 메소드

다음과 같이 데이터가 존재할 때 한 열을 컬럼명으로하고 한 열은 값으로 보여주고 싶을때 하는 기능이 Pivot 기능이죠. Sample   group key   val 0    01   A    10 1    01   B   ..

h-a-i.tistory.com

이번에는 group 기준이 되는 index도 1개 이상이고, value값도 1개 이상일 경우에 pivot 하는 방법에 대해 알아보도록하겠습니다. 

 

다음과 같은 샘플데이터가 있을때 

  meta1 meta2 para val1 val2
0     A     B    1   AA   AB
1     A     B    2   BA   BB
2     A     B    3   AA   BB
3     C     D    1   CC   CD
4     C     D    2   DC   DD
5     C     D    3   CC   DD

 

 

아래와 같은 결과를 얻고 싶을때가 있습니다. 

  meta1   meta2 1_val1 1_val2  2_val1  2_val2   3_val1  3_val2
0     A     B        AA     AB      BA      BB       AA       BB
1     C     D        CC     CD      DC     DD      CC        DD

 

이런 경우는 데이터가 많을때 주로 DB에 이렇게 적재가 되는데요.

데이터 분석을 할때는 옆으로 이렇게 쭉 있어야지

X 값으로 두고 분석을 할 수 있잖아요? 

 

이럴때 Pivot을 하면됩니다.

방법은 2가지가 있어요.

 

1. Pandas Pivot 메소드를 사용한다.

 

2. Dict와 List를 이용해서 Pivot 할 수 있도록 만든다. 

 

 

1. Pandas Pivot 메소드를 사용한다.

pivot 메소드를 사용하는 방법은 매우 간단합니다. 

import pandas as pd


sample_df = pd.DataFrame(
    [
    {'meta1' : 'A', 'meta2': 'B', 'para' : '1', 'val1' : 'AA', 'val2' : 'AB' } ,
    {'meta1':'A', 'meta2':'B',  'para': '2', 'val1':'BA', 'val2':'BB'},
    {'meta1':'A', 'meta2':'B',  'para': '3', 'val1':'AA', 'val2':'BB'},
    {'meta1': 'C', 'meta2': 'D', 'para': '1', 'val1': 'CC', 'val2': 'CD'},
    {'meta1': 'C', 'meta2': 'D', 'para': '2', 'val1': 'DC', 'val2': 'DD'},
    {'meta1': 'C', 'meta2': 'D', 'para': '3', 'val1': 'CC', 'val2': 'DD'}
    ])

print(sample_df)

#   meta1 meta2 para val1 val2
# 0     A     B    1   AA   AB
# 1     A     B    2   BA   BB
# 2     A     B    3   AA   BB
# 3     C     D    1   CC   CD
# 4     C     D    2   DC   DD
# 5     C     D    3   CC   DD


pivot_df = sample_df.pivot(index=['meta1', 'meta2'],
               columns= 'para',
               values=['val1', 'val2']
               )
print(pivot_df)

#             val1         val2        
# para           1   2   3    1   2   3
# meta1 meta2                          
# A     B       AA  BA  AA   AB  BB  BB
# C     D       CC  DC  CC   CD  DD  DD

 

 

이렇게 하면 데이터가 pivoting이 되지만 

만약에 데이터가 중복된다면 에러가 생깁니다.

ValueError: Index contains duplicate entries, cannot reshape

 

그럼 중복제거를 하고 pivoting을 하면됩니다. 

 

import pandas as pd 

sample_df = pd.DataFrame(
    [
    {'meta1' : 'A', 'meta2': 'B', 'para' : '1', 'val1' : 'AA', 'val2' : 'AB' } ,
    {'meta1':'A', 'meta2':'B',  'para': '2', 'val1':'BA', 'val2':'BB'},
    {'meta1':'A', 'meta2':'B',  'para': '3', 'val1':'AA', 'val2':'BB'},
    {'meta1': 'C', 'meta2': 'D', 'para': '1', 'val1': 'CC', 'val2': 'CD'},
    {'meta1': 'C', 'meta2': 'D', 'para': '2', 'val1': 'DC', 'val2': 'DD'},
    {'meta1': 'C', 'meta2': 'D', 'para': '3', 'val1': 'CC', 'val2': 'DD'},
    {'meta1': 'C', 'meta2': 'D', 'para': '3', 'val1': 'CC', 'val2': 'DD'}
    ])

print(sample_df)
#   meta1 meta2 para val1 val2
# 0     A     B    1   AA   AB
# 1     A     B    2   BA   BB
# 2     A     B    3   AA   BB
# 3     C     D    1   CC   CD
# 4     C     D    2   DC   DD
# 5     C     D    3   CC   DD
# 6     C     D    3   CC   DD



sample_df = sample_df.drop_duplicates()

pivot_df = sample_df.pivot(index=['meta1', 'meta2'],
               columns= 'para',
               values=['val1', 'val2']
               )
print(pivot_df)
#             val1         val2
# para           1   2   3    1   2   3
# meta1 meta2
# A     B       AA  BA  AA   AB  BB  BB
# C     D       CC  DC  CC   CD  DD  DD

 

 

자.. 여기에서 이렇게 데이터가 pivoting 되면 컬럼명이

참.. 마음에 안듭니다. 

원하는 컬럼명은 이렇게 되야하는데.. 

meta1   meta2 1_val1 1_val2  2_val1  2_val2   3_val1  3_val2 

 

저렇게하면 어쩌지? 

생각이 들어서 그냥 짜보자. 해서 그냥  짜봤습니다.

 

2. Dict와 List를 이용해서 Pivot 할 수 있도록 만든다. 

프로세스  

1. 데이터프레임 row 한줄씩 처리한다.

2. pivot에서 index 역할을 하는 meta dict를 key로 생성한다. 이때 key는 hash 값으로 생성

3. pivot 대상 데이터의 컬럼명과 값을 dictionary에 담는다. : para_dict - key는 meta key, value는 col_name: col_value 형식의 dict 

4. para_dict에 meta key 정보가 있으면 업데이트한다. 없으면 새로 생성한다. 

5. meta_dict와 p_dict를 연결해서 data_list 에 담는다.

6. data_list를 데이터프레임으로 변경한다. 

 

sample_df = pd.DataFrame(
    [
    {'meta1' : 'A', 'meta2': 'B', 'para' : '1', 'val1' : 'AA', 'val2' : 'AB' } ,
    {'meta1':'A', 'meta2':'B',  'para': '2', 'val1':'BA', 'val2':'BB'},
    {'meta1':'A', 'meta2':'B',  'para': '3', 'val1':'AA', 'val2':'BB'},
    {'meta1': 'C', 'meta2': 'D', 'para': '1', 'val1': 'CC', 'val2': 'CD'},
    {'meta1': 'C', 'meta2': 'D', 'para': '2', 'val1': 'DC', 'val2': 'DD'},
    {'meta1': 'C', 'meta2': 'D', 'para': '3', 'val1': 'CC', 'val2': 'DD'},
    {'meta1': 'C', 'meta2': 'D', 'para': '3', 'val1': 'CC', 'val2': 'DD'}
    ])

print(sample_df)



p_dict = dict()
meta_dict = dict()

for i, row in sample_df.iterrows():
	# hash key 생성 
    key = hash(str(list(row[['meta1', 'meta2']])))
	
    # meta dict 생성
    meta_col_list = ['meta1', 'meta2']
    meta_val_list = list(row[['meta1', 'meta2']])
    meta_dict[key] = dict(zip(meta_col_list, meta_val_list))

	# para dict 생성 
    para_col_list = [row['para']+'_'+val for val in ['val1', 'val2']]
    para_val_list = list(row[['val1', 'val2']])

    try:
        p_dict[key].update(dict(zip(para_col_list, para_val_list)))
    except KeyError as e:
        p_dict[key] = dict(zip(para_col_list, para_val_list))

data_list = []
for key, val in meta_dict.items():
	# meta, para 합치기 
    data_list.append({**val, **p_dict[key]})

print(pd.DataFrame(data_list))

#  meta1 meta2 1_val1 1_val2 2_val1 2_val2 3_val1 3_val2
#0     A     B     AA     AB     BA     BB     AA     BB
#1     C     D     CC     CD     DC     DD     CC     DD

 

이렇게 진행했을 때의 장점은

대용량데이터 처리가 가능합니다.

그 이유는 모든데이터를 올려서 처리하는게 아니라 한줄한줄 처리가 가능하기때문에

메모리를 적게 사용하고 안정적으로 처리할 수 가 있습니다. 

 

 

반응형