[데이터 분석] 데이터 준비하기: 조인, 병합, 변형

JY·2022년 5월 11일
0

데이터분석

목록 보기
1/1

계층적 색인: 축에 대해 다중 색인 단계를 지정할 수 있도록 함.
                    높은 차원의 데이터를 낮은 차원의 형식으로 다룰 수 있게 해주는 기능

import pandas as pd
import numpy as np

계층적 색인

data = pd.Series(np.random.randn(9), #리스트의 리스트를 색인으로 하는 Series 생성
                index = [['a','a','a','b','b','c','c','d','d'],[1,2,3,1,3,1,2,2,3]])
data
a  1   -0.718279
   2   -1.293206
   3    0.838317
b  1    0.587797
   3    0.416080
c  1    2.074077
   2   -1.228737
d  2   -0.503776
   3    1.030454
dtype: float64

MultiIndex를 색인으로 하는 Series. 색인의 계층을 보여주고 있음

data.index #바로 위 단계의 색인 이용하여 하위 계층 직접 접근 가능
MultiIndex([('a', 1),
            ('a', 2),
            ('a', 3),
            ('b', 1),
            ('b', 3),
            ('c', 1),
            ('c', 2),
            ('d', 2),
            ('d', 3)],
           )

계층적으로 색인된 객체는 데이터의 부분집합을 부분적 색인으로 접근 가능

data['b']
1    0.587797
3    0.416080
dtype: float64
data['b':'c']
b  1    0.587797
   3    0.416080
c  1    2.074077
   2   -1.228737
dtype: float64
data.loc[['b','d']]
b  1    0.587797
   3    0.416080
d  2   -0.503776
   3    1.030454
dtype: float64
data.loc[:,2]  #하위 계층의 객체 선택 가능
a   -1.293206
c   -1.228737
d   -0.503776
dtype: float64

계층적 색인은 데이터를 재형성하고 피벗테이블 생성 같은 그룹 기반의 작업할 때 중요하게 사용

data.unstack()  #unstack 메서드 이용하여 데이터 새롭게 배열
1 2 3
a -0.718279 -1.293206 0.838317
b 0.587797 NaN 0.416080
c 2.074077 -1.228737 NaN
d NaN -0.503776 1.030454
data.unstack().stack()  #stack 메서드는 unstack 메서드의 반대 작업
a  1   -0.718279
   2   -1.293206
   3    0.838317
b  1    0.587797
   3    0.416080
c  1    2.074077
   2   -1.228737
d  2   -0.503776
   3    1.030454
dtype: float64
frame = pd.DataFrame(np.arange(12).reshape((4,3)),
                    index = [['a','a','b','b'],[1,2,1,2]],
                    columns = [['Ohio','Ohio','Colorado'],['Green','Red','Green']])
frame  # 두 축 모두 계층적 색인
Ohio Colorado
Green Red Green
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
frame.index.names = ['key1','key2']  #색인 이름 설정
frame.columns.names = ['state','color']
frame
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11
frame['Ohio'] #부분적 색인
color Green Red
key1 key2
a 1 0 1
2 3 4
b 1 6 7
2 9 10

MultiIndex는 따로 생성한 다음에 재사용 가능

계층의 순서를 바꾸고 정렬

swaplevel: 넘겨받은 두 개의 계층 번호나 이름이 뒤바뀐 새로운 객체 반환 (but 데이터는 변경되지 x)

frame.swaplevel('key1','key2')
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
2 a 3 4 5
1 b 6 7 8
2 b 9 10 11

sort_index: 단일 계층에 속한 데이터 정렬

frame.sort_index(level=1)
state Ohio Colorado
color Green Red Green
key1 key2
a 1 0 1 2
b 1 6 7 8
a 2 3 4 5
b 2 9 10 11
frame.swaplevel(0,1).sort_index(level=0)
state Ohio Colorado
color Green Red Green
key2 key1
1 a 0 1 2
b 6 7 8
2 a 3 4 5
b 9 10 11

계층별 요약 통계

level 옵션: 어떤 한 축에 대해 합을 구하고 싶은 단계 지정

frame.sum(level='key2')
/var/folders/1b/6fw3j9nd4_qgymn82k3hygww0000gn/T/ipykernel_4080/2004046222.py:1: FutureWarning: Using the level keyword in DataFrame and Series aggregations is deprecated and will be removed in a future version. Use groupby instead. df.sum(level=1) should use df.groupby(level=1).sum().
  frame.sum(level='key2')
state Ohio Colorado
color Green Red Green
key2
1 6 8 10
2 12 14 16

원하는 출력은 나오지만 warning이 있다..

frame.sum(level='color', axis=1)
/var/folders/1b/6fw3j9nd4_qgymn82k3hygww0000gn/T/ipykernel_4080/4133796543.py:1: FutureWarning: Using the level keyword in DataFrame and Series aggregations is deprecated and will be removed in a future version. Use groupby instead. df.sum(level=1) should use df.groupby(level=1).sum().
  frame.sum(level='color', axis=1)
color Green Red
key1 key2
a 1 2 1
2 8 4
b 1 14 7
2 20 10

DataFrame에서 로우나 컬럼을 계층별로 합할 수 있음

DataFrame의 컬럼 사용하기

frame = pd.DataFrame({'a':range(7), 'b':range(7,0,-1),
                     'c':['one','one','one','two','two','two','two'], 'd':[0,1,2,0,1,2,3]})
frame
a b c d
0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
3 3 4 two 0
4 4 3 two 1
5 5 2 two 2
6 6 1 two 3

set_index: 하나 이상의 컬럼을 색인으로 하는 새로운 DataFrame 생성

frame2 = frame.set_index(['c','d'])
frame2
a b
c d
one 0 0 7
1 1 6
2 2 5
two 0 3 4
1 4 3
2 5 2
3 6 1

컬럼을 명시적으로 남겨두지 않으면 DataFrame에서 삭제됨

frame.set_index(['c','d'], drop=False)
a b c d
c d
one 0 0 7 one 0
1 1 6 one 1
2 2 5 one 2
two 0 3 4 two 0
1 4 3 two 1
2 5 2 two 2
3 6 1 two 3

reset_index: 계층적 색인 단계가 컬럼으로 이동

frame2.reset_index()
c d a b
0 one 0 0 7
1 one 1 1 6
2 one 2 2 5
3 two 0 3 4
4 two 1 4 3
5 two 2 5 2
6 two 3 6 1

데이터 합치기

  • pandas.merge: 하나 이상의 키를 기준으로 DataFrame의 로우를 합침. SQL 또는 다른 관계형 데이터베이스의 join 연산과 유사
  • pandas.concat: 하나의 축을 따라 객체를 이어 붙임
  • combine_first: 두 객체를 포개서 한 객체에서 누락된 데이터를 다른 객체에 있는 값으로 채울 수 있도록 함

데이터베이스 스타일로 DataFrame 합치기

병합, 조인 연산: 하나 이상의 키를 사용하여 데이터 집합의 로우를 합칩

df1 = pd.DataFrame({'key':['b','b','a','c','a','a','b'],'data1':range(7)})
df2 = pd.DataFrame({'key':['a','b','d'], 'data2':range(3)})
df1 #key 컬럼에 여러 개의 a,b 로우
key data1
0 b 0
1 b 1
2 a 2
3 c 3
4 a 4
5 a 5
6 b 6
df2 #key 컬럼에 유일한 로우
key data2
0 a 0
1 b 1
2 d 2
pd.merge(df1,df2) #merge 함수는 중복된 컬럼 이름을 키로 사용 but 지정해주는 것이 좋음
key data1 data2
0 b 0 1
1 b 1 1
2 b 6 1
3 a 2 0
4 a 4 0
5 a 5 0

만약, 두 객체에 중복된 컬럼 이름이 없다면 따로 지정.

df3 = pd.DataFrame({'1key':['b','b','a','c','a','a','b'], 'data1':range(7)})
df4 = pd.DataFrame({'rkey':['a','b','d'],'data2':range(3)})
pd.merge(df3, df4, left_on = '1key', right_on = 'rkey')
1key data1 rkey data2
0 b 0 b 1
1 b 1 b 1
2 b 6 b 1
3 a 2 a 0
4 a 4 a 0
5 a 5 a 0

merge 함수는 기본적으로 내부 조인을 수행하여 교집합인 결과를 반환

외부 조인은 합집합인 결과 반환(how 인자 사용)

pd.merge(df1, df2, how = 'outer')  #how = 'outer' : 양쪽 테이블에 존재하는 모든 키 조합 사용
key data1 data2
0 b 0.0 1.0
1 b 1.0 1.0
2 b 6.0 1.0
3 a 2.0 0.0
4 a 4.0 0.0
5 a 5.0 0.0
6 c 3.0 NaN
7 d NaN 2.0

다대다 병합은 직관적이지 않음.

df1 = pd.DataFrame({'key':['b','b','a','c','a','b'],'data1':range(6)})
df2 = pd.DataFrame({'key':['a','b','a','b','d'],'data2':range(5)})
df1
key data1
0 b 0
1 b 1
2 a 2
3 c 3
4 a 4
5 b 5
df2
key data2
0 a 0
1 b 1
2 a 2
3 b 3
4 d 4
pd.merge(df1, df2, on = 'key', how = 'left')  #how = 'left' : 왼쪽 테이블에 존재하는 모든 키 조합 사용
key data1 data2
0 b 0 1.0
1 b 0 3.0
2 b 1 1.0
3 b 1 3.0
4 a 2 0.0
5 a 2 2.0
6 c 3 NaN
7 a 4 0.0
8 a 4 2.0
9 b 5 1.0
10 b 5 3.0

다대다 조인은 두 로우의 데카르트 곱 반환 => 조인 메서드는 결과에 나타나는 구별되는 키에 대해서만 적용

pd.merge(df1, df2, how = 'inner')
key data1 data2
0 b 0 1
1 b 0 3
2 b 1 1
3 b 1 3
4 b 5 1
5 b 5 3
6 a 2 0
7 a 2 2
8 a 4 0
9 a 4 2

겹치는 컬럼 이름에 대한 처리

  • 축 이름 변경하여 수동으로 컬럼 이름 겹치게 하기
  • suffixes 인자로 DataFrame 객체에서 겹치는 컬럼 이름 뒤에 붙일 문자열 지정
left = pd.DataFrame({'key1':['foo','foo','bar'],
                    'key2':['one','two','one'],
                    'lval':[1,2,3]})
right = pd.DataFrame({'key1':['foo','foo','bar','bar'],
                    'key2':['one','one','one','two'],
                    'rval':[4,5,6,7]})
pd.merge(left, right, on = 'key1')
key1 key2_x lval key2_y rval
0 foo one 1 one 4
1 foo one 1 one 5
2 foo two 2 one 4
3 foo two 2 one 5
4 bar one 3 one 6
5 bar one 3 two 7
pd.merge(left, right, on = 'key1', suffixes=('_left','_right'))
key1 key2_left lval key2_right rval
0 foo one 1 one 4
1 foo one 1 one 5
2 foo two 2 one 4
3 foo two 2 one 5
4 bar one 3 one 6
5 bar one 3 two 7

색인 병합하기

병합하는 키가 DataFrame의 색인일 경우

left_index = True 혹은 right_index = True 옵션 사용하여 해당 색인을 병합 키로 사용

left1 = pd.DataFrame({'key':['a','b','a','a','b','c'], 'value':range(6)})
right1 = pd.DataFrame({'group_val':[3.5, 7]}, index = ['a','b'])
left1
key value
0 a 0
1 b 1
2 a 2
3 a 3
4 b 4
5 c 5
right1
group_val
a 3.5
b 7.0
pd.merge(left1, right1, left_on = 'key', right_index = True)
key value group_val
0 a 0 3.5
2 a 2 3.5
3 a 3 3.5
1 b 1 7.0
4 b 4 7.0
pd.merge(left1, right1, left_on = 'key', right_index = True, how = 'outer') #외부 조인 실행하여 합집합
key value group_val
0 a 0 3.5
2 a 2 3.5
3 a 3 3.5
1 b 1 7.0
4 b 4 7.0
5 c 5 NaN

계층 색인된 데이터는 암묵적으로 여러 키 병합

lefth = pd.DataFrame({'key1': ['Ohio','Ohio','Ohio','Nevada','Nevada'], 
                     'key2': [2000, 2001, 2002, 2001, 2002],
                     'data': np.arange(5.)})
righth = pd.DataFrame(np.arange(12).reshape((6,2)),
                     index = [['Nevada','Nevada','Ohio','Ohio','Ohio','Ohio'], 
                     [2001, 2000, 2000, 2000, 2001, 2002]], columns = ['event1', 'event2'])
lefth
key1 key2 data
0 Ohio 2000 0.0
1 Ohio 2001 1.0
2 Ohio 2002 2.0
3 Nevada 2001 3.0
4 Nevada 2002 4.0
righth
event1 event2
Nevada 2001 0 1
2000 2 3
Ohio 2000 4 5
2000 6 7
2001 8 9
2002 10 11

=> 리스트로 여러 개의 컬럼을 지정해서 병합해야함. (how = 'outer' 사용)

pd.merge(lefth, righth, left_on = ['key1','key2'], right_index = True)
key1 key2 data event1 event2
0 Ohio 2000 0.0 4 5
0 Ohio 2000 0.0 6 7
1 Ohio 2001 1.0 8 9
2 Ohio 2002 2.0 10 11
3 Nevada 2001 3.0 0 1
pd.merge(lefth, righth, left_on = ['key1','key2'], right_index = True, how = 'outer')
key1 key2 data event1 event2
0 Ohio 2000 0.0 4.0 5.0
0 Ohio 2000 0.0 6.0 7.0
1 Ohio 2001 1.0 8.0 9.0
2 Ohio 2002 2.0 10.0 11.0
3 Nevada 2001 3.0 0.0 1.0
4 Nevada 2002 4.0 NaN NaN
4 Nevada 2000 NaN 2.0 3.0
left2 = pd.DataFrame([[1.,2.], [3.,4.], [5.,6.]], index = ['a','c','e'], columns = ['Ohio', 'Nevada'])
right2 = pd.DataFrame([[7.,8.], [9.,10.], [11.,12.], [13,14]], index = ['b','c','d','e'], 
                      columns = ['Missouri', 'Alabama'])
left2
Ohio Nevada
a 1.0 2.0
c 3.0 4.0
e 5.0 6.0
right2
Missouri Alabama
b 7.0 8.0
c 9.0 10.0
d 11.0 12.0
e 13.0 14.0
pd.merge(left2, right2, how = 'outer', left_index = True, right_index = True)
Ohio Nevada Missouri Alabama
a 1.0 2.0 NaN NaN
b NaN NaN 7.0 8.0
c 3.0 4.0 9.0 10.0
d NaN NaN 11.0 12.0
e 5.0 6.0 13.0 14.0

색인으로 병합할 때 join 메서드 이용하면 편리.

join 메서드는 컬럼이 겹치지 않으며 완전히 같거나 유사한 색인 구조를 가진 여러 개의 DataFrame 객체를 병합할 때 사용 가능

left2.join(right2, how='outer')
Ohio Nevada Missouri Alabama
a 1.0 2.0 NaN NaN
b NaN NaN 7.0 8.0
c 3.0 4.0 9.0 10.0
d NaN NaN 11.0 12.0
e 5.0 6.0 13.0 14.0
left1.join(right1, on='key')
key value group_val
0 a 0 3.5
1 b 1 7.0
2 a 2 3.5
3 a 3 3.5
4 b 4 7.0
5 c 5 NaN

색인 대 색인으로 두 DataFrame 병합

another = pd.DataFrame([[7.,8.], [9.,10.], [11.,12.], [16.,17.]], index = ['a','c','e','f'], 
                      columns = ['New York', 'Oregon'])
another
New York Oregon
a 7.0 8.0
c 9.0 10.0
e 11.0 12.0
f 16.0 17.0
left2.join([right2, another])
Ohio Nevada Missouri Alabama New York Oregon
a 1.0 2.0 NaN NaN 7.0 8.0
c 3.0 4.0 9.0 10.0 9.0 10.0
e 5.0 6.0 13.0 14.0 11.0 12.0
left2.join([right2, another], how='outer')
Ohio Nevada Missouri Alabama New York Oregon
a 1.0 2.0 NaN NaN 7.0 8.0
c 3.0 4.0 9.0 10.0 9.0 10.0
e 5.0 6.0 13.0 14.0 11.0 12.0
b NaN NaN 7.0 8.0 NaN NaN
d NaN NaN 11.0 12.0 NaN NaN
f NaN NaN NaN NaN 16.0 17.0

축 따라 이어 붙이기

numpy에서는 ndarray를 이어붙이는 concatenate 함수 이용

arr = np.arange(12).reshape((3,4))
arr
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
np.concatenate([arr,arr], axis = 1)
array([[ 0,  1,  2,  3,  0,  1,  2,  3],
       [ 4,  5,  6,  7,  4,  5,  6,  7],
       [ 8,  9, 10, 11,  8,  9, 10, 11]])

at pandas.. => 축마다 이름이 있어서 배열을 쉽게 이어붙일 수 있도록 구성



고려사항

  • 만약 연결하려는 두 객체의 색인이 서로 다르면 결과는 그 색인의 교집합? 합집합?
  • 합쳐진 결과에서 합쳐지기 전 객체의 데이터 구분할 수 있어야할까?
  • 어떤 축으로 연결할 것인지 고려해야하나? (많을 경우 DataFrame의 기본 정수 라벨이 가장 먼저 무시)



    pandas에서는 concat 함수 이용
s1 = pd.Series([0,1], index=['a','b'])
s2 = pd.Series([2,3,4], index=['c','d','e'])
s3 = pd.Series([5,6], index=['f','g'])
pd.concat([s1,s2,s3])
a    0
b    1
c    2
d    3
e    4
f    5
g    6
dtype: int64

concat 함수는 axis=0을 기본값으로 하며 새로운 Series 객체 생성

만약 axis=1 이상이라면 결과는 Series가 아닌 DataFrame (axis=1은 칼럼 의미)

pd.concat([s1,s2,s3], axis=1)
0 1 2
a 0.0 NaN NaN
b 1.0 NaN NaN
c NaN 2.0 NaN
d NaN 3.0 NaN
e NaN 4.0 NaN
f NaN NaN 5.0
g NaN NaN 6.0
s4 = pd.concat([s1,s3])
s4
a    0
b    1
f    5
g    6
dtype: int64
pd.concat([s1,s4], axis=1)
0 1
a 0.0 0
b 1.0 1
f NaN 5
g NaN 6
pd.concat([s1,s4], axis=1, join='inner')
0 1
a 0 0
b 1 1

join_axes: 병합하려는 축을 직접 지정 가능

pd.concat([s1,s4], axis=1, join_axes = [['a','c','b','e']])
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

/var/folders/1b/6fw3j9nd4_qgymn82k3hygww0000gn/T/ipykernel_4080/1941623965.py in <module>
----> 1 pd.concat([s1,s4], axis=1, join_axes = [['a','c','b','e']])


~/opt/anaconda3/lib/python3.9/site-packages/pandas/util/_decorators.py in wrapper(*args, **kwargs)
    309                     stacklevel=stacklevel,
    310                 )
--> 311             return func(*args, **kwargs)
    312 
    313         return wrapper


TypeError: concat() got an unexpected keyword argument 'join_axes'

join_axes를 지원하지 않는다는 것 같다... => reindex 사용!

pd.concat([s1,s4], axis=1).reindex(['a','c','b','e'])
0 1
a 0.0 0.0
c NaN NaN
b 1.0 1.0
e NaN NaN

계층적 색인을 생성하려면 keys 인자 사용

Series를 이어붙이기 전의 개별 Series를 구분할 수 없으므로 이어 붙인 축에 대해 계층적 색인 생성하여 식별 가능하도록 함!)

result = pd.concat([s1,s1,s3], keys=['one','two','three'])
result
one    a    0
       b    1
two    a    0
       b    1
three  f    5
       g    6
dtype: int64
result.unstack()
a b f g
one 0.0 1.0 NaN NaN
two 0.0 1.0 NaN NaN
three NaN NaN 5.0 6.0

Series를 axis=1로 병합하게 되면 keys는 DataFrame의 컬럼 제목이 됨

pd.concat([s1,s2,s3], axis=1, keys=['one','two','three'])
one two three
a 0.0 NaN NaN
b 1.0 NaN NaN
c NaN 2.0 NaN
d NaN 3.0 NaN
e NaN 4.0 NaN
f NaN NaN 5.0
g NaN NaN 6.0

DataFrame 객체에 대해서도 이와 같음

df1 = pd.DataFrame(np.arange(6).reshape(3,2), index=['a','b','c'], columns=['one','two'])
df2 = pd.DataFrame(5+np.arange(4).reshape(2,2), index=['a','c'], columns=['three','four'])
df1
one two
a 0 1
b 2 3
c 4 5
df2
three four
a 5 6
c 7 8
pd.concat([df1,df2], axis=1, keys=['level1','level2'])
level1 level2
one two three four
a 0 1 5.0 6.0
b 2 3 NaN NaN
c 4 5 7.0 8.0

리스트 대신 객체의 사전을 넘기면 사전의 키가 keys 옵션으로 사용

pd.concat({'level1':df1, 'level2':df2}, axis=1)
level1 level2
one two three four
a 0 1 5.0 6.0
b 2 3 NaN NaN
c 4 5 7.0 8.0
pd.concat([df1,df2], axis=1, keys=['level1','level2'], names=['upper','lower'])  #names인자=> 새로 생성된 계층 이름 지정
upper level1 level2
lower one two three four
a 0 1 5.0 6.0
b 2 3 NaN NaN
c 4 5 7.0 8.0
df1 = pd.DataFrame(np.random.randn(3,4), columns=['a','b','c','d'])
df2 = pd.DataFrame(np.random.randn(2,3), columns=['b','d','a'])
df1
a b c d
0 -0.031695 -0.074865 -0.567876 -0.106580
1 0.175408 -0.300737 1.752298 0.311653
2 0.383386 0.625466 -0.717174 0.603836
df2
b d a
0 -0.865482 -0.811584 0.205644
1 0.506437 0.279058 -1.258077

=>DataFrame의 로우 색인이 분석에 필요한 데이터를 포함하고 있지 않을 때

ignore_index=True 옵션 사용

pd.concat([df1,df2], ignore_index=True)
a b c d
0 -0.031695 -0.074865 -0.567876 -0.106580
1 0.175408 -0.300737 1.752298 0.311653
2 0.383386 0.625466 -0.717174 0.603836
3 0.205644 -0.865482 NaN -0.811584
4 -1.258077 0.506437 NaN 0.279058

겹치는 데이터 합치기

a = pd.Series([np.nan, 2.5, np.nan, 3.5, 4.5, np.nan], index=['f','e','d','c','b','a'])
b = pd.Series(np.arange(len(a), dtype=np.float64), index=['f','e','d','c','b','a'])
b[-1] = np.nan
a
f    NaN
e    2.5
d    NaN
c    3.5
b    4.5
a    NaN
dtype: float64
b
f    0.0
e    1.0
d    2.0
c    3.0
b    4.0
a    NaN
dtype: float64
np.where(pd.isnull(a), b, a) 
array([0. , 2.5, 2. , 3.5, 4.5, nan])
b[:-2].combine_first(a[2:])
a    NaN
b    4.5
c    3.0
d    2.0
e    1.0
f    0.0
dtype: float64
df1 = pd.DataFrame({'a':[1., np.nan, 5., np.nan], 'b':[np.nan, 2., np.nan, 6.], 'c': range(2,18,4)})
df2 = pd.DataFrame({'a':[5., 4., np.nan, 3., 7.], 'b':[np.nan, 3., 4., 6., 8.]})
df1
a b c
0 1.0 NaN 2
1 NaN 2.0 6
2 5.0 NaN 10
3 NaN 6.0 14
df2
a b
0 5.0 NaN
1 4.0 3.0
2 NaN 4.0
3 3.0 6.0
4 7.0 8.0
df1.combine_first(df2)
a b c
0 1.0 NaN 2.0
1 4.0 2.0 6.0
2 5.0 4.0 10.0
3 3.0 6.0 14.0
4 7.0 8.0 NaN

재형성과 피벗

: 표 형식의 데이터를 재배치하는 기본 연산

계층적 색인으로 재형성하기

  • stack: 데이터의 컬럼을 로우로 피벗(또는 회전) 시킨다.
  • unstack: 로우를 컬럼으로 피벗시킨다.
data = pd.DataFrame(np.arange(6).reshape((2,3)), index = pd.Index(['Ohio','Colorado'], name='state'),
                                         columns = pd.Index(['one','two','three'], name='number'))
data
number one two three
state
Ohio 0 1 2
Colorado 3 4 5
result = data.stack() #컬럼이 로우로 피벗되어서 Series 객체 반환
result
state     number
Ohio      one       0
          two       1
          three     2
Colorado  one       3
          two       4
          three     5
dtype: int64
result.unstack()  #계층적 색인을 가진 Series로부터 다시 DataFrame 얻을 수 있음
number one two three
state
Ohio 0 1 2
Colorado 3 4 5
result.unstack(0)
state Ohio Colorado
number
one 0 3
two 1 4
three 2 5
result.unstack('state')
state Ohio Colorado
number
one 0 3
two 1 4
three 2 5

해당 레벨에 있는 모든 값이 하위 그룹에 속하지 않을 경우 => unstack을 하게 되면 누락된 데이터 생길 수 있음

s1 = pd.Series([0,1,2,3], index=['a','b','c','d'])
s2 = pd.Series([4,5,6], index=['c','d','e'])
data2 = pd.concat([s1,s2], keys=['one','two'])
data2
one  a    0
     b    1
     c    2
     d    3
two  c    4
     d    5
     e    6
dtype: int64
data2.unstack()
a b c d e
one 0.0 1.0 2.0 3.0 NaN
two NaN NaN 4.0 5.0 6.0

stack 메서드는 누락된 데이터를 자동으로 걸러냄 => 연산을 쉽게 원상 복구 가능

data2.unstack().stack()
one  a    0.0
     b    1.0
     c    2.0
     d    3.0
two  c    4.0
     d    5.0
     e    6.0
dtype: float64
data2.unstack().stack(dropna=False)
one  a    0.0
     b    1.0
     c    2.0
     d    3.0
     e    NaN
two  a    NaN
     b    NaN
     c    4.0
     d    5.0
     e    6.0
dtype: float64

DataFrame을 unstack()할 때 unstack 레벨은 결과에서 가장 낮은 단계가 됨

df = pd.DataFrame({'left': result, 'right': result+5}, columns = pd.Index(['left','right'], name='side'))
df
side left right
state number
Ohio one 0 5
two 1 6
three 2 7
Colorado one 3 8
two 4 9
three 5 10
df.unstack('state')
side left right
state Ohio Colorado Ohio Colorado
number
one 0 3 5 8
two 1 4 6 9
three 2 5 7 10

stack 호출할 때 쌀을 축의 이름 지정 가능

df.unstack('state').stack('side')
state Colorado Ohio
number side
one left 3 0
right 8 5
two left 4 1
right 9 6
three left 5 2
right 10 7

긴 형식에서 넓은 형식으로 피벗하기

db 또는 csv 파일에 여러 개의 시게열 데이터를 저장하는 일반적인 방법: 시간 순서대로 나열

data = pd.read_csv('/Users/cha/Desktop/숙명 데분 스터디/data/macrodata.csv')
data.head()
year quarter realgdp realcons realinv realgovt realdpi cpi m1 tbilrate unemp pop infl realint
0 1959.0 1.0 2710.349 1707.4 286.898 470.045 1886.9 28.98 139.7 2.82 5.8 177.146 0.00 0.00
1 1959.0 2.0 2778.801 1733.7 310.859 481.301 1919.7 29.15 141.7 3.08 5.1 177.830 2.34 0.74
2 1959.0 3.0 2775.488 1751.8 289.226 491.260 1916.4 29.35 140.5 3.82 5.3 178.657 2.74 1.09
3 1959.0 4.0 2785.204 1753.7 299.356 484.052 1931.3 29.37 140.0 4.33 5.6 179.386 0.27 4.06
4 1960.0 1.0 2847.699 1770.5 331.722 462.199 1955.5 29.54 139.6 3.50 5.2 180.007 2.31 1.19
periods = pd.PeriodIndex(year = data.year, quarter = data.quarter, name = 'date')
columns = pd.Index(['realgdp', 'infl','unemp'], name='item')
data = data.reindex(columns = columns)
data.index = periods.to_timestamp('D','end')
ldata = data.stack().reset_index().rename(columns={0: 'value'})
ldata[:10]
date item value
0 1959-03-31 23:59:59.999999999 realgdp 2710.349
1 1959-03-31 23:59:59.999999999 infl 0.000
2 1959-03-31 23:59:59.999999999 unemp 5.800
3 1959-06-30 23:59:59.999999999 realgdp 2778.801
4 1959-06-30 23:59:59.999999999 infl 2.340
5 1959-06-30 23:59:59.999999999 unemp 5.100
6 1959-09-30 23:59:59.999999999 realgdp 2775.488
7 1959-09-30 23:59:59.999999999 infl 2.740
8 1959-09-30 23:59:59.999999999 unemp 5.300
9 1959-12-31 23:59:59.999999999 realgdp 2785.204

pivot 메서드

pivoted = ldata.pivot('date','item','value')
pivoted
item infl realgdp unemp
date
1959-03-31 23:59:59.999999999 0.00 2710.349 5.8
1959-06-30 23:59:59.999999999 2.34 2778.801 5.1
1959-09-30 23:59:59.999999999 2.74 2775.488 5.3
1959-12-31 23:59:59.999999999 0.27 2785.204 5.6
1960-03-31 23:59:59.999999999 2.31 2847.699 5.2
... ... ... ...
2008-09-30 23:59:59.999999999 -3.16 13324.600 6.0
2008-12-31 23:59:59.999999999 -8.79 13141.920 6.9
2009-03-31 23:59:59.999999999 0.94 12925.410 8.1
2009-06-30 23:59:59.999999999 3.37 12901.504 9.2
2009-09-30 23:59:59.999999999 3.56 12990.341 9.6

203 rows × 3 columns

ldata['value2'] = np.random.randn(len(ldata))
ldata[:10]
date item value value2
0 1959-03-31 23:59:59.999999999 realgdp 2710.349 0.244226
1 1959-03-31 23:59:59.999999999 infl 0.000 0.962365
2 1959-03-31 23:59:59.999999999 unemp 5.800 0.404761
3 1959-06-30 23:59:59.999999999 realgdp 2778.801 0.471211
4 1959-06-30 23:59:59.999999999 infl 2.340 -0.817099
5 1959-06-30 23:59:59.999999999 unemp 5.100 -0.114613
6 1959-09-30 23:59:59.999999999 realgdp 2775.488 -0.432555
7 1959-09-30 23:59:59.999999999 infl 2.740 -0.918431
8 1959-09-30 23:59:59.999999999 unemp 5.300 0.523383
9 1959-12-31 23:59:59.999999999 realgdp 2785.204 1.649171
pivoted = ldata.pivot('date','item')
pivoted[:5]
value value2
item infl realgdp unemp infl realgdp unemp
date
1959-03-31 23:59:59.999999999 0.00 2710.349 5.8 0.962365 0.244226 0.404761
1959-06-30 23:59:59.999999999 2.34 2778.801 5.1 -0.817099 0.471211 -0.114613
1959-09-30 23:59:59.999999999 2.74 2775.488 5.3 -0.918431 -0.432555 0.523383
1959-12-31 23:59:59.999999999 0.27 2785.204 5.6 0.672839 1.649171 1.146470
1960-03-31 23:59:59.999999999 2.31 2847.699 5.2 -1.015282 1.491567 -0.210033
pivoted['value'][:5]
item infl realgdp unemp
date
1959-03-31 23:59:59.999999999 0.00 2710.349 5.8
1959-06-30 23:59:59.999999999 2.34 2778.801 5.1
1959-09-30 23:59:59.999999999 2.74 2775.488 5.3
1959-12-31 23:59:59.999999999 0.27 2785.204 5.6
1960-03-31 23:59:59.999999999 2.31 2847.699 5.2
unstacked = ldata.set_index(['date','item']).unstack('item')
unstacked[:7]
value value2
item infl realgdp unemp infl realgdp unemp
date
1959-03-31 23:59:59.999999999 0.00 2710.349 5.8 0.962365 0.244226 0.404761
1959-06-30 23:59:59.999999999 2.34 2778.801 5.1 -0.817099 0.471211 -0.114613
1959-09-30 23:59:59.999999999 2.74 2775.488 5.3 -0.918431 -0.432555 0.523383
1959-12-31 23:59:59.999999999 0.27 2785.204 5.6 0.672839 1.649171 1.146470
1960-03-31 23:59:59.999999999 2.31 2847.699 5.2 -1.015282 1.491567 -0.210033
1960-06-30 23:59:59.999999999 0.14 2834.390 5.2 1.492080 0.398274 -1.866305
1960-09-30 23:59:59.999999999 2.70 2839.022 5.6 2.580628 0.629838 -0.291634

긴 형식에서 긴 형식으로 피벗하기

pandas.melt: pivot과 반대되는 연산, 반드시 어떤 컬럼을 그룹 구분자로 사용할 것인지 지정.

df = pd.DataFrame({'key': ['foo','bar','baz'], 'A':[1,2,3], 'B':[4,5,6], 'C':[7,8,9]})
df
key A B C
0 foo 1 4 7
1 bar 2 5 8
2 baz 3 6 9
melted = pd.melt(df,['key'])
melted
key variable value
0 foo A 1
1 bar A 2
2 baz A 3
3 foo B 4
4 bar B 5
5 baz B 6
6 foo C 7
7 bar C 8
8 baz C 9
reshaped = melted.pivot('key', 'variable', 'value')
reshaped
variable A B C
key
bar 2 5 8
baz 3 6 9
foo 1 4 7
reshaped.reset_index()
variable key A B C
0 bar 2 5 8
1 baz 3 6 9
2 foo 1 4 7
pd.melt(df,id_vars=['key'], value_vars=['A','B'])
key variable value
0 foo A 1
1 bar A 2
2 baz A 3
3 foo B 4
4 bar B 5
5 baz B 6
pd.melt(df, value_vars=['A','B','C'])
variable value
0 A 1
1 A 2
2 A 3
3 B 4
4 B 5
5 B 6
6 C 7
7 C 8
8 C 9
pd.melt(df, value_vars=['key','A','B'])
variable value
0 key foo
1 key bar
2 key baz
3 A 1
4 A 2
5 A 3
6 B 4
7 B 5
8 B 6

0개의 댓글