데이터 변형(Data Wrangling)

In [1]:
import pandas as pd
import numpy as np

rng = np.random.RandomState(1234)

계층적 인덱싱

판다스는 계층적 인덱싱을 통하여 한 축에 여러 개의 인덱스 수준을 갖도록한다. 약간 추상적으로 말하면 고차원 자료를 저차원 자료로 변형해서 작업할 수 있게 한다. 다음은 인덱스를 리스트의 리스트로 갖는 시리즈이다.

In [2]:
ser = pd.Series(rng.randn(9), index=[['a', 'a', 'a', 'b', 'b', 'c', 'c', 'd', 'd'], [1, 2, 3, 1, 3, 1, 2, 2, 3]])
ser
Out[2]:
a  1    0.471435
   2   -1.190976
   3    1.432707
b  1   -0.312652
   3   -0.720589
c  1    0.887163
   2    0.859588
d  2   -0.636524
   3    0.015696
dtype: float64

인덱스는 상위 인덱스 'a', 'b', 'c', 'd'와 하위 인덱스 1, 2, 3으로 구성된 다중 인덱스이다.

In [3]:
ser.index
Out[3]:
MultiIndex(levels=[['a', 'b', 'c', 'd'], [1, 2, 3]],
           labels=[[0, 0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 2, 0, 2, 0, 1, 1, 2]])

계층적 인덱스 객체는 부분 인덱싱을 통해서 자료를 선택할 수 있다. 다음은 인덱스 'b'에 속해있는 자료를 골라낸 것이다.

In [4]:
ser['b']
Out[4]:
1   -0.312652
3   -0.720589
dtype: float64

슬라이싱을 이용해서 골라낼 수 있다.

In [5]:
ser['b':'c']
Out[5]:
b  1   -0.312652
   3   -0.720589
c  1    0.887163
   2    0.859588
dtype: float64

loc 속성을 이용해도 된다.

In [6]:
ser.loc[['a', 'd']]
Out[6]:
a  1    0.471435
   2   -1.190976
   3    1.432707
d  2   -0.636524
   3    0.015696
dtype: float64

하위 수준의 인덱스를 이용해서 골라낼 수도 있다. loc[up, lo]에서 up은 상위 수준 인덱스이고 lo는 하위 수준 인덱스를 의미한다.

In [7]:
ser.loc[:, 2]
Out[7]:
a   -1.190976
c    0.859588
d   -0.636524
dtype: float64

계층적 인덱싱은 기준축 표(pivot table)를 만드는 것과 같은 그룹형식의 연산이나 자료를 변형하는 작업과 같은 중요한 역할을 한다. 예를 들어 unstack 메소드를 이용해 시리즈를 데이터프레임으로 변형할 수 있다. unstack은 행 인덱스의 지정된 수준을 열 인덱스의 가장 안쪽 수준으로 변경하는 메소드이다. unstacklevel= 인자를 이용해 원하는 수준의 인덱스를 열 인덱스로 보낼 수 있다.

In [8]:
ser.unstack()
Out[8]:
1 2 3
a 0.471435 -1.190976 1.432707
b -0.312652 NaN -0.720589
c 0.887163 0.859588 NaN
d NaN -0.636524 0.015696

역으로 unstack 자료를 원래 자료로 stack을 이용해 만들 수 있다. stack은 역으로 열 인덱스중에서 지정된 수준을 행 인덱스의 가장 안쪽 수준으로 변경한다.

In [9]:
ser.unstack().stack()
Out[9]:
a  1    0.471435
   2   -1.190976
   3    1.432707
b  1   -0.312652
   3   -0.720589
c  1    0.887163
   2    0.859588
d  2   -0.636524
   3    0.015696
dtype: float64

데이터프레임은 열 또는 행 인덱스를 다중 인덱스로 사용할 수 있다.

In [10]:
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']])
In [11]:
frame
Out[11]:
Ohio Colorado
Green Red Green
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11

문자열 또는 어떠한 파이썬 객체도 계층적 인덱스 수준의 이름이 될 수 있다.

In [12]:
frame.index.names = ['key1', 'key2']
In [13]:
frame.columns.names = ['state', 'color']
In [14]:
frame
Out[14]:
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

부분적 열 인덱싱을 통해 열들의 그룹을 선택할 수 있다.

In [15]:
frame['Ohio']
Out[15]:
color Green Red
key1 key2
a 1 0 1
2 3 4
b 1 6 7
2 9 10

다중인덱스 객체를 만들어서 필요할 때 재사용할 수 있다. 열 인덱스는 다음과 같이 다중 인덱스 객체의 from_arrays를 이용해서 만들수도 있다.

In [16]:
col_index = pd.MultiIndex.from_arrays([['Ohio', 'Ohio', 'Colorado'], ['Green', 'Red', 'Green']], names=['state', 'color'])
In [17]:
col_index
Out[17]:
MultiIndex(levels=[['Colorado', 'Ohio'], ['Green', 'Red']],
           labels=[[1, 1, 0], [0, 1, 0]],
           names=['state', 'color'])
In [18]:
pd.DataFrame(np.arange(4 * 3).reshape(4, 3), columns=col_index)
Out[18]:
state Ohio Colorado
color Green Red Green
0 0 1 2
1 3 4 5
2 6 7 8
3 9 10 11

다음과 같이 행 인덱스를 만들어 사용할 수도 있다.

In [19]:
row_index = pd.MultiIndex.from_product([['a', 'b'], [1, 2]], names=['key1', 'key2'])
row_index
Out[19]:
MultiIndex(levels=[['a', 'b'], [1, 2]],
           labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
           names=['key1', 'key2'])

from_product([[상위 수준 인덱스], [하위 수준 인덱스]])상위 수준 인덱스 각각에 하위 수준 인덱스가 만들어 진다. 여기서는 'a' 상위 수준에 1, 2 하위 수준이 만들어지고 'b'에 대해서도 마찬가지이다.

In [20]:
pd.DataFrame(np.arange(4 * 3).reshape(4, 3), index=row_index)
Out[20]:
0 1 2
key1 key2
a 1 0 1 2
2 3 4 5
b 1 6 7 8
2 9 10 11

다음은 행, 열에 대한 인덱스를 모두 사용한 경우이다.

In [21]:
pd.DataFrame(np.arange(4 * 3).reshape(4, 3), columns=col_index, index=row_index)
Out[21]:
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

수준별 정렬

가끔씩 특정 축에서 특정 수준에 대해서 정렬을 할 필요가 생기거나 특정 수준에 대한 값으로 정렬을 할 필요가 생긴다. swaplevel은 두 개의 수준을 인자로 받아 두 수준을 서로 바꾼 형태의 새로운 객체를 반환한다.

In [22]:
frame.swaplevel('key1', 'key2')
Out[22]:
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를 사용하여 특정 수준에 대한 정렬을 시행할 수 있다.

In [23]:
frame.sort_index(level=1)
Out[23]:
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

axis= 선택인자를 이용해 열에 대해서도 정렬이 가능하다.

In [24]:
frame.sort_index(axis='columns', level=1)
Out[24]:
state Colorado Ohio
color Green Green Red
key1 key2
a 1 2 0 1
2 5 3 4
b 1 8 6 7
2 11 9 10

Summary Statistics by Level

데이터프레임과 시리즈는 특정 축과 지정된 수준에 대해서 집계할 수 있는 level= 인자를 제공한다. 행 이름 수준이 key2인 것에 대해서 합을 구하면 다음과 같다.

In [25]:
frame.sum(level='key2')
Out[25]:
state Ohio Colorado
color Green Red Green
key2
1 6 8 10
2 12 14 16

다음은 열이름 수준이 color인 것에 대해서 합을 구한 것이다.

In [26]:
frame.sum(level='color', axis='columns')
Out[26]:
color Green Red
key1 key2
a 1 2 1
2 8 4
b 1 14 7
2 20 10

판다스 groupby 연산 부분에서 더 자세히 다룬다.

Indexing with a DataFrame’s columns

자료의 열 인덱스를 행 인덱스로 설정하고 싶을 때가 있다. 또는 반대로 행 인덱스를 열 인덱스로 나타내고 싶을 때가 있을 것이다.

In [27]:
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
Out[27]:
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 메소드는 데이터프레임 열들을 행 인덱스로 설정할 수 있게 한다.

In [28]:
frame2 = frame.set_index(['c', 'd'])
frame2
Out[28]:
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

기본적으로 열이름을 제거하면서 행 인덱스를 설정하지만 drop=False 옵션을 이용해서 제거하지 않을 수도 있다.

In [29]:
frame.set_index(['c', 'd'], drop=False)
Out[29]:
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 메소드를 이용해서 원래 상태로 되돌릴 수 있다. reset_index는 행 인덱스들을 열 이름으로 변경한다. level= 인자를 이용해 지정된 수준에 대해서만 열로 만들 수 있다.

In [30]:
frame2.reset_index()
Out[30]:
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

Combining and Merging Datasets

데이터프레임들을 병합하기 위해서 판다스는 두가지 함수 pandas.mergepandas.concat를 제공한다. merge는 두 데이터프레임들을 데이터베이스 형식의 병합 방법을 사용하고 concat는 여러 개의 데이터프레임을 이어 붙일 때 사용한다.

Database-Style DataFrame Joins

두 데이터프레임을 merge 메소드를 이용해서 병합하기 위해서는 두 데이터프레임이 적어도 한 개 이상의 같은 열이름을 갖고 있어야 한다. 병합할 때 병합하는 축들(열이름)과 병합하는 방법을 지정할 수 있다. 병합 축은 on= 인자를 이용하고 병합 방법은 how= 인자를 사용한다. how 인자에 지정될 수 있는 방법으로는 inner, outer, left, right 등이 있다.

In [31]:
df1 = pd.DataFrame({'A': ['A'+str(i) for i in range(4)]})
df1
Out[31]:
A
0 A0
1 A1
2 A2
3 A3
In [32]:
df2 = pd.DataFrame({'B': ['B'+str(i) for i in range(4)]})
df2
Out[32]:
B
0 B0
1 B1
2 B2
3 B3

두 데이터프레임을 병합하면 일치하는 열이름이 없기 때문에 에러가 발생한다.

In [33]:
pd.merge(df1, df2)
---------------------------------------------------------------------------
MergeError                                Traceback (most recent call last)
<ipython-input-33-bf676d91be05> in <module>()
----> 1 pd.merge(df1, df2)

~\Anaconda3\lib\site-packages\pandas\core\reshape\merge.py in merge(left, right, how, on, left_on, right_on, left_index, right_index, sort, suffixes, copy, indicator, validate)
     58                          right_index=right_index, sort=sort, suffixes=suffixes,
     59                          copy=copy, indicator=indicator,
---> 60                          validate=validate)
     61     return op.get_result()
     62

~\Anaconda3\lib\site-packages\pandas\core\reshape\merge.py in __init__(self, left, right, how, on, left_on, right_on, axis, left_index, right_index, sort, suffixes, copy, indicator, validate)
    543             warnings.warn(msg, UserWarning)
    544
--> 545         self._validate_specification()
    546
    547         # note this function has side effects

~\Anaconda3\lib\site-packages\pandas\core\reshape\merge.py in _validate_specification(self)
   1027                         'left_index={lidx}, right_index={ridx}'
   1028                         .format(lon=self.left_on, ron=self.right_on,
-> 1029                                 lidx=self.left_index, ridx=self.right_index))
   1030                 if not common_cols.is_unique:
   1031                     raise MergeError("Data columns not unique: {common!r}"

MergeError: No common columns to perform merge on. Merge options: left_on=None, right_on=None, left_index=False, right_index=False

다음과 같이 데이터프레임 df3을 만들자.

In [34]:
df3 = pd.DataFrame({'B': ['B'+str(i) for i in range(4)],
                    'C': ['C'+str(i) for i in range(4)]})
df3.loc[4] = ['BX', 'C4']
df3
Out[34]:
B C
0 B0 C0
1 B1 C1
2 B2 C2
3 B3 C3
4 BX C4

df2, df3는 열이름 B가 공통이기 때문에 판다스는 공통인 이름에 대해서 병합을 한다.

In [35]:
pd.merge(df2, df3)
Out[35]:
B C
0 B0 C0
1 B1 C1
2 B2 C2
3 B3 C3

df2df3의 병합 축 B에서 교집합에 해당하는 행들만 골라낸다. how 기본 설정은 'inner'이다. 만일 공통인 부분이 여러개 있으면 공통인 것에 대한 모든 경우에 해당되는 행들을 골라낸다.

In [36]:
df4 = df2.copy()
df4.loc[3] = 'B0'
df4
Out[36]:
B
0 B0
1 B1
2 B2
3 B0
In [37]:
df5 = df3.copy()
df5.loc[4, 'B'] = 'B0'
df5
Out[37]:
B C
0 B0 C0
1 B1 C1
2 B2 C2
3 B3 C3
4 B0 C4

df4, df5B 열에 각각 2개씩 B0를 가지고 있는 것을 알 수 있다. 따라서 2 x 2 = 4 개의 B0 행이 만들어진다. 즉, df4의 0번째 행 B0에 대해서 df5의 0, 4번째 행의 B0에 해당하는 경우를 만들고 df4의 3번째 행의 B0에 대해 마찬가지로 df50, 4번째 행의 B0 경우에 대해서 만든다.

In [38]:
pd.merge(df4, df5)
Out[38]:
B C
0 B0 C0
1 B0 C4
2 B0 C0
3 B0 C4
4 B1 C1
5 B2 C2

merge의 대상은 병합축에 대한 조건(how=)을 만족하는 행들이다. how='outer'는 병합축에 해당하는 열들의 합집합을 만들어 생각한다. 'inner'와 마찬가지로 같은 이름에 대해서는 곱하기 갯수만큼을 만든다.

In [39]:
pd.merge(df4, df5, how='outer')
Out[39]:
B C
0 B0 C0
1 B0 C4
2 B0 C0
3 B0 C4
4 B1 C1
5 B2 C2
6 B3 C3

합집합이므로 'inner'에서 없었던 B3 행이 추가되었다. how='left'는 왼쪽 데이터프레임의 병합축만 사용한다.

In [40]:
pd.merge(df4, df5, how='left')
Out[40]:
B C
0 B0 C0
1 B0 C4
2 B1 C1
3 B2 C2
4 B0 C0
5 B0 C4

여기서도 공통되는 항목에 대해서는 모든 경우의 수가 포함되는 것을 알 수 있다. how='right'은 오른쪽 데이터프레임의 병합축만 사용한다.

In [41]:
pd.merge(df4, df5, how='right')
Out[41]:
B C
0 B0 C0
1 B0 C0
2 B0 C4
3 B0 C4
4 B1 C1
5 B2 C2
6 B3 C3
선택인자 SQL JOIN 이름 설명
'inner' INNER JOIN 두 데이터프레임의 키들의 교집합을 사용한다.
'outer' FULL OUTER JOIN 두 데이터프레임의 키들의 합집합을 사용한다.
'left' LEFT OUTER JOIN 왼쪽 데이터프레임의 키만 사용한다.
'right' RIGHT OUTER JOIN 오른쪽 데이터프레임의 키만 사용한다.

여러 개의 키들을 이용해서 병합할 수 있다.

In [42]:
left = pd.DataFrame({'key1': ['foo', 'foo', 'bar'],
                     'key2': ['one', 'two', 'one'],
                     'lval': [1, 2, 3]})
In [43]:
right = pd.DataFrame({'key1': ['foo', 'foo', 'bar', 'bar'],
                      'key2': ['one', 'one', 'one', 'two'],
                      'rval': [4, 5, 6, 7]})
In [44]:
left
Out[44]:
key1 key2 lval
0 foo one 1
1 foo two 2
2 bar one 3
In [45]:
right
Out[45]:
key1 key2 rval
0 foo one 4
1 foo one 5
2 bar one 6
3 bar two 7

병합키를 지정하려면 on= 인자를 사용하면 된다.

In [46]:
pd.merge(left, right, on=['key1', 'key2'], how='outer')
Out[46]:
key1 key2 lval rval
0 foo one 1.0 4.0
1 foo one 1.0 5.0
2 foo two 2.0 NaN
3 bar one 3.0 6.0
4 bar two NaN 7.0

'outer'이므로 두 개의 키 조합의 합집합을 찾는다.

Caution

`pd.merge`를 이용해서 나온 결과 데이터프레임은 인덱스는 이전 데이터프레임의 인덱스와 상관없다.

중복되는 열이름이 있을 경우 suffixes= 선택인자를 이용해서 열이름 첨자를 지정할 수 있다. suffixes를 설정하지 않으면 왼쪽은 _x, 오른쪽은 _y를 붙인다.

In [47]:
pd.merge(left, right, on='key1')
Out[47]:
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
In [48]:
pd.merge(left, right, on='key1', suffixes=('_left', '_right'))
Out[48]:
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

다음은 merge 함수의 인자들이다.

Argument Description
left DataFrame to be merged on the left side.
right DataFrame to be merged on the right side.
how One of ‘inner’, ‘outer’, ‘left’, or ‘right’; defaults to ‘inner’.
on Column names to join on. Must be found in both DataFrame objects. If not specified and no other join keys given, will use the intersection of the column names in left and right as the join keys.
left_on Columns in left DataFrame to use as join keys.
right_on Analogous to left_on for left DataFrame.
left_index Use row index in left as its join key (or keys, if a MultiIndex).
right_index Analogous to left_index.
sort Sort merged data lexicographically by join keys; True by default (disable to get better performance in some cases on large datasets).
suffixes Tuple of string values to append to column names in case of overlap; defaults to (‘_x’, ‘_y’) (e.g., if ‘data’ in both DataFrame objects, would appear as ‘data_x’ and ‘data_y’ in result).
copy If False, avoid copying data into resulting data structure in some exceptional cases; by default always copies.
indicator Adds a special column _merge that indicates the source of each row; values will be ‘left_only’, ‘right_only’, or ‘both’ based on the origin of the joined data in each row.

Merging on Index

데이터프레임의 인덱스를 병합키로 사용하려면 left_index=True, right_index=True를 사용한다.

In [49]:
left1 = pd.DataFrame({'key': ['a', 'b', 'a', 'a', 'b', 'c'],
                      'value': range(6)})
left1
Out[49]:
key value
0 a 0
1 b 1
2 a 2
3 a 3
4 b 4
5 c 5
In [50]:
right1 = pd.DataFrame({'group_val': [3.5, 7]}, index=['a', 'b'])
right1
Out[50]:
group_val
a 3.5
b 7.0

right_index=True는 오른쪽 데이터프레임의 병합키는 인덱스를 사용하고 left_on='key'는 왼쪽 병합키는 'key'를 사용한다는 뜻이다.

In [51]:
pd.merge(left1, right1, left_on='key', right_index=True)
Out[51]:
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

다중 인덱스를 갖는 데이터프레임도 인덱스를 키로 사용해서 병합할 수 있다.

In [52]:
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'])
In [53]:
lefth
Out[53]:
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
In [54]:
righth
Out[54]:
event1 event2
Nevada 2001 0 1
2000 2 3
Ohio 2000 4 5
2000 6 7
2001 8 9
2002 10 11

다중 인덱스를 키로 사용하려면 다음과 같이 병합키를 리스트로 지정해야 한다.

In [55]:
pd.merge(lefth, righth, left_on=['key1', 'key2'], right_index=True)
Out[55]:
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

두 데이터프레임의 인덱스 모두를 사용해도 된다.

In [56]:
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'])
In [57]:
left2
Out[57]:
Ohio Nevada
a 1.0 2.0
c 3.0 4.0
e 5.0 6.0
In [58]:
right2
Out[58]:
Missouri Alabama
b 7.0 8.0
c 9.0 10.0
d 11.0 12.0
e 13.0 14.0
In [59]:
pd.merge(left2, right2, left_index=True, right_index=True, how='outer')
Out[59]:
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은 병합키로 자신은 지정된 열을 사용할 수 있는 반면에 다른 데이터프레임의 키는 반드시 인덱스를 사용해야한다.

In [60]:
left2.join(right2)
Out[60]:
Ohio Nevada Missouri Alabama
a 1.0 2.0 NaN NaN
c 3.0 4.0 9.0 10.0
e 5.0 6.0 13.0 14.0

join 메소드의 how 기본값은 left이고 병합키는 기본적으로 둘 다 인덱스를 사용한다. 호출 데이터프레임(join 메소드를 호출하는 데이터프레임)은 다른 병합키를 사용할 수 있다.

다음은 left1의 키는 key 열을 사용하고 right1의 키는 인덱스를 사용한 예이다.

In [61]:
left1.join(right1, on='key')
Out[61]:
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

데이터프레임들의 리스트를 이용해서 여러 개의 데이터프레임들을 결합할 수 있다.

In [62]:
another = pd.DataFrame([[7., 8.], [9., 10.], [11., 12.], [16., 17.]],
                       index=['a', 'c', 'e', 'f'],
                       columns=['New York', 'Oregon'])
In [63]:
left2.join([right2, another])
Out[63]:
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
In [64]:
left2.join([right2, another], how='outer')
C:\Users\dyoon\Anaconda3\lib\site-packages\pandas\core\frame.py:6359: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=True'.

To retain the current behavior and silence the warning, pass sort=False

  verify_integrity=True)
Out[64]:
Ohio Nevada Missouri Alabama New York Oregon
a 1.0 2.0 NaN NaN 7.0 8.0
b NaN NaN 7.0 8.0 NaN NaN
c 3.0 4.0 9.0 10.0 9.0 10.0
d NaN NaN 11.0 12.0 NaN NaN
e 5.0 6.0 13.0 14.0 11.0 12.0
f NaN NaN NaN NaN 16.0 17.0

Concatenating Along an Axis

자료 합치는 또 다른 연산으로 붙이기(concatenation)가 있다. pandas.concat 함수를 사용해서 주어진 축 방향으로 자료들을 합칠 수 있다.

In [65]:
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'])

concat 함수의 인자로 시리즈 리스트를 대입하면 행 방향으로 차례로 시리즈들을 합친다.

In [66]:
pd.concat([s1, s2, s3])
Out[66]:
a    0
b    1
c    2
d    3
e    4
f    5
g    6
dtype: int64

기본적으로 axis=0 값으로 지정되어 있다. 열방향으로 자료들을 붙이기 위해서는 axis=1을 지정하면 된다.

In [67]:
pd.concat([s1, s2, s3], axis=1)
C:\Users\dyoon\Anaconda3\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=True'.

To retain the current behavior and silence the warning, pass sort=False

  """Entry point for launching an IPython kernel.
Out[67]:
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

다른 축(행방향)방향으로는 공통되는 항목이 없기 때문에 NaN으로 채우는 것을 알 수 있다. 이것은 다른 축방향으로 outer 병합하는 것과 같다. 여기서 inner 병합을 하고 싶으면 join='inner' 인자를 건네 주면 된다.

In [68]:
s4 = pd.concat([s1, s3])
s4
Out[68]:
a    0
b    1
f    5
g    6
dtype: int64
In [69]:
pd.concat([s1, s4], axis=1, join='inner')
Out[69]:
0 1
a 0 0
b 1 1

여기서 주의해야 할 점은 join 방법은 붙이기 하는 축(axis=1)인 열방향이 아닌 다른 축(행방향)으로 적용이 된다는 것이다. 따라서 f, g가 사라지고 공통인 항목 a, b만 나오는 것을 볼 수 있다.

join_axes= 선택인자를 사용하면 다른 축방향의 인덱스들을 선택적으로 사용할 수 있다.

In [70]:
pd.concat([s1, s4], axis=1, join_axes=[['a', 'c', 'b', 'd']])
Out[70]:
0 1
a 0.0 0.0
c NaN NaN
b 1.0 1.0
d NaN NaN

붙이기를 하면 자료들의 정체성을 잃어버리게 된다. 이러한 것을 위해서 keys= 인자를 지정하면 원래 자료에 인덱스를 부여할 수 있다.

In [71]:
res = pd.concat([s1, s1, s3], keys=['one', 'two', 'three'])
res
Out[71]:
one    a    0
       b    1
two    a    0
       b    1
three  f    5
       g    6
dtype: int64

unstack 메소드를 이용해서 데이터프레임으로 변경할 수 있다. unstack 메소드는 인덱스(행) 레벨 중 하나를 선택해서(기본값은 level=-1, 즉 가장 안쪽 레벨) 행 수준의 가장 안쪽 수준으로 설정한다.

In [72]:
res.unstack()
Out[72]:
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

시리즈를 합치면서 axis=1keys= 인자를 사용하면 열이름으로 설정할 수 있다.

In [73]:
pd.concat([s1, s2, s3], axis=1, keys=['one', 'two', 'three'])
C:\Users\dyoon\Anaconda3\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=True'.

To retain the current behavior and silence the warning, pass sort=False

  """Entry point for launching an IPython kernel.
Out[73]:
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

데이터프레임에 대해서도 마찬가지로 적용할 수 있다.

In [74]:
df1 = pd.DataFrame(np.arange(6).reshape(3, 2), index=['a', 'b', 'c'],
                   columns=['one', 'two'])
df1
Out[74]:
one two
a 0 1
b 2 3
c 4 5
In [75]:
df2 = pd.DataFrame(5 + np.arange(4).reshape(2, 2), index=['a', 'c'],
                   columns=['three', 'four'])
df2
Out[75]:
three four
a 5 6
c 7 8
In [76]:
pd.concat([df1, df2], axis=1, keys=['key1', 'key2'])
C:\Users\dyoon\Anaconda3\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=True'.

To retain the current behavior and silence the warning, pass sort=False

  """Entry point for launching an IPython kernel.
Out[76]:
key1 key2
one two three four
a 0 1 5.0 6.0
b 2 3 NaN NaN
c 4 5 7.0 8.0

리스트가 아닌 사전 객체를 입력하면 열쇠가 keys= 인자에 대응된다.

In [77]:
pd.concat({'key1': df1, 'key2': df2}, axis=1)
C:\Users\dyoon\Anaconda3\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=True'.

To retain the current behavior and silence the warning, pass sort=False

  """Entry point for launching an IPython kernel.
Out[77]:
key1 key2
one two three four
a 0 1 5.0 6.0
b 2 3 NaN NaN
c 4 5 7.0 8.0

names= 인자를 이용해서 수준의 이름을 설정할 수 있다.

In [78]:
pd.concat([df1, df2], axis=1, keys=['key1', 'key2'], names=['level0', 'level1'])
C:\Users\dyoon\Anaconda3\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=True'.

To retain the current behavior and silence the warning, pass sort=False

  """Entry point for launching an IPython kernel.
Out[78]:
level0 key1 key2
level1 one two three four
a 0 1 5.0 6.0
b 2 3 NaN NaN
c 4 5 7.0 8.0

데이터프레임의 행이름들이 의미가 없을 때는 ignore_index=True를 이용해서 무시할 수 있다.

In [79]:
df1 = pd.DataFrame(np.random.randn(3, 4), columns=['a', 'b', 'c', 'd'])
df1
Out[79]:
a b c d
0 0.897854 -0.121771 1.337716 -1.263141
1 0.812211 -1.965854 0.232949 1.840888
2 0.281830 1.444992 0.525127 -0.564983
In [80]:
df2 = pd.DataFrame(np.random.randn(2, 3), columns=['b', 'd', 'a'])
df2
Out[80]:
b d a
0 -0.456583 0.598502 -0.669677
1 -0.558903 0.293322 -1.450108
In [81]:
pd.concat([df1, df2], ignore_index=True)
C:\Users\dyoon\Anaconda3\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=True'.

To retain the current behavior and silence the warning, pass sort=False

  """Entry point for launching an IPython kernel.
Out[81]:
a b c d
0 0.897854 -0.121771 1.337716 -1.263141
1 0.812211 -1.965854 0.232949 1.840888
2 0.281830 1.444992 0.525127 -0.564983
3 -0.669677 -0.456583 NaN 0.598502
4 -1.450108 -0.558903 NaN 0.293322
Argument Description
objs List or dict of pandas objects to be concatenated; this is the only required argument
axis Axis to concatenate along; defaults to 0 (along rows)
join Either ‘inner’ or ‘outer’ (‘outer’ by default); whether to intersection (inner) or union (outer) together indexes along the other axes
join_axes Specific indexes to use for the other n–1 axes instead of performing union/intersection logic
keys Values to associate with objects being concatenated, forming a hierarchical index along the concatenation axis; can either be a list or array of arbitrary values, an array of tuples, or a list of arrays (if multiple-level arrays passed in levels)
levels Specific indexes to use as hierarchical index level or levels if keys passed
names Names for created hierarchical levels if keys and/or levels passed
verify_integrity Check new axis in concatenated object for duplicates and raise exception if so; by default (False) allows duplicates
ignore_index Do not preserve indexes along concatenation axis, instead producing a new range(total_length) index

Combining Data with Overlap

행 또는 열이름들이 중복되는 두 자료들의 값들을 합치기를 원할 경우가 있다. 넘파이 배열의 where 함수가 비슷한 작업을 할 수있다.

In [82]:
a = pd.Series([np.nan, 2.5, 0.0, 3.5, 4.5, np.nan],
              index=['f', 'e', 'd', 'c', 'b', 'a'])
a
Out[82]:
f    NaN
e    2.5
d    0.0
c    3.5
b    4.5
a    NaN
dtype: float64
In [83]:
b = pd.Series([0., np.nan, 2., np.nan, np.nan, 5.],
              index=['a', 'b', 'c', 'd', 'e', 'f'])
b
Out[83]:
a    0.0
b    NaN
c    2.0
d    NaN
e    NaN
f    5.0
dtype: float64
In [84]:
np.where(pd.isnull(a), b, a)
Out[84]:
array([0. , 2.5, 0. , 3.5, 4.5, 5. ])

a 성분 중 NaN이 있으면 대응되는 위치의 b의 값으로 설정하는 것이다. 하지만 이것은 인덱스와 상관없이 배열의 위치로만 값을 대입하는 것을 알 수 있다.

시리즈의 인덱스에 대응해서 값을 지정하려면 combine_first 메소드를 사용하면 된다.

In [85]:
b.combine_first(a)
Out[85]:
a    0.0
b    4.5
c    2.0
d    0.0
e    2.5
f    5.0
dtype: float64

데이터프레임에서는 열별로 연산을 한다.

In [86]:
df1 = pd.DataFrame({'a': [1., np.nan, 5., np.nan],
                    'b': [np.nan, 2., np.nan, 6.],
                    'c': range(2, 18, 4)})
df1
Out[86]:
a b c
0 1.0 NaN 2
1 NaN 2.0 6
2 5.0 NaN 10
3 NaN 6.0 14
In [87]:
df2 = pd.DataFrame({'a': [5., 4., np.nan, 3., 7.],
                    'b': [np.nan, 3., 4., 6., 8.]})
df2
Out[87]:
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

새로 만들어진 데이터프레임의 행, 열 인덱스는 두 데이터프레임의 합집합이다.

In [88]:
df1.combine_first(df2)
Out[88]:
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

Reshaping and Pivoting

계층적 인덱싱을 이용한 변형(Reshaping with Hierarchical Indexing)

다음과 같은 두 개의 메소드를 이용해서 데이터프레임의 형태를 변경할 수 있다.

  • stack: 지정된 열 수준을 행의 가장 안쪽 수준으로 변경한다.
  • unstack: 지정된 행 수준을 열의 가장 안쪽 수준으로 변경한다.
In [89]:
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
Out[89]:
number one two three
state
Ohio 0 1 2
Colorado 3 4 5

stack 은 열축(number)을 행축의 가장 안쪽으로 위치시킨다. 그러면서 열축이 없어지기 때문에 결과는 시리즈가 된다.

In [90]:
res = data.stack()
res
Out[90]:
state     number
Ohio      one       0
          two       1
          three     2
Colorado  one       3
          two       4
          three     5
dtype: int32

unstack을 이용하면 역으로 행축의 가장 안쪽 수준인 number를 열축으로 위치시킨다. 따라서 원래 모양으로 돌아온다.

In [91]:
res.unstack()
Out[91]:
number one two three
state
Ohio 0 1 2
Colorado 3 4 5

다음과 같이 다중 인덱스의 경우 stack의 경우 기본적으로 열축의 가장 안쪽의 수준을 행축의 가장 안쪽 수준으로 변경한다.

In [92]:
df_multi_level = pd.DataFrame([[1.0, 2.0], [3.0, 4.0]],
                              index=['cat', 'dog'],
                              columns=pd.MultiIndex([['weight', 'height'], ['kg', 'm']], labels=[[0, 1], [0, 1]], names=['parts', 'units']))
df_multi_level
Out[92]:
parts weight height
units kg m
cat 1.0 2.0
dog 3.0 4.0

즉, 가장 안쪽 수준인 kg, m을 행축의 가장 안쪽으로 위치시킨다.

In [93]:
df_multi_level.stack()
Out[93]:
parts weight height
units
cat kg 1.0 NaN
m NaN 2.0
dog kg 3.0 NaN
m NaN 4.0

변형을 했을 때 값이 대응되지 않으면 NaN 값이 설정된다.

level= 인자를 이용해서 변경하고자하는 수준을 직접 지정할 수 있다. 수준은 위에서부터 0, 1, … 이다.

In [94]:
stck_df = df_multi_level.stack(level=0)
stck_df
Out[94]:
units kg m
parts
cat weight 1.0 NaN
height NaN 2.0
dog weight 3.0 NaN
height NaN 4.0

unstack의 경우도 수준을 직접 지정해서 변경할 수 있다. 행 수준은 왼쪽부터 0, 1, …이다.

In [95]:
stck_df.unstack(level=0)
Out[95]:
units kg m
cat dog cat dog
parts
weight 1.0 3.0 NaN NaN
height NaN NaN 2.0 4.0

stackunstack 메소드 사용시 level= 인자에 수준 이름을 대입해도 된다.

In [96]:
df_multi_level.stack(level='units')
Out[96]:
parts weight height
units
cat kg 1.0 NaN
m NaN 2.0
dog kg 3.0 NaN
m NaN 4.0
In [97]:
s1 = pd.Series([0, 1, 2, 3], index=['a', 'b', 'c', 'd'])
s1
Out[97]:
a    0
b    1
c    2
d    3
dtype: int64
In [98]:
s2 = pd.Series([4, 5, 6], index=['c', 'd', 'e'])
s2
Out[98]:
c    4
d    5
e    6
dtype: int64
In [99]:
data2 = pd.concat([s1, s2], keys=['one', 'two'])
data2
Out[99]:
one  a    0
     b    1
     c    2
     d    3
two  c    4
     d    5
     e    6
dtype: int64

변형했을 때 값이 대응되지 않으면 NaN이 설정된다.

In [100]:
data2.unstack()
Out[100]:
a b c d e
one 0.0 1.0 2.0 3.0 NaN
two NaN NaN 4.0 5.0 6.0

unstack한 것을 다시 stack 하면 NaN 값은 자동으로 제거한다.

In [101]:
data2.unstack().stack()
Out[101]:
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

하지만 dropna=False 인자를 건네면 NaN 값이 그대로 나오는 것을 알 수 있다.

In [102]:
data2.unstack().stack(dropna=False)
Out[102]:
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

Pivoting “Long” to “Wide” Format

In [103]:
url = 'https://raw.githubusercontent.com/wesm/pydata-book/2nd-edition/examples/'
data = pd.read_csv(url + 'macrodata.csv')
In [104]:
data.head()
Out[104]:
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

시간 주기 인덱스를 PeriodIndex를 이용해서 만든다.

In [105]:
periods = pd.PeriodIndex(year=data.year, quarter=data.quarter, name='date')
periods
Out[105]:
PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2',
             '1960Q3', '1960Q4', '1961Q1', '1961Q2',
             ...
             '2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3',
             '2008Q4', '2009Q1', '2009Q2', '2009Q3'],
            dtype='period[Q-DEC]', name='date', length=203, freq='Q-DEC')

1959Q1은 1959년 1사분기라는 뜻이다. freq='Q-DEC'는 매년 분기의 마지막 달이 12월이란 뜻이다. 자세한 설명은 이곳을 참조한다. 시간 객체에 대해서는 시계열 부분에서 자세히 다룬다.

다음과 같이 열 인덱스를 만든다.

In [106]:
columns = pd.Index(['realgdp', 'infl', 'unemp'], name='item')
columns
Out[106]:
Index(['realgdp', 'infl', 'unemp'], dtype='object', name='item')

위에서 만든 data 중에서 새로 만든 열 인덱스에 맞춰 조정한다.

In [107]:
data = data.reindex(columns=columns)
data.head()
Out[107]:
item realgdp infl unemp
0 2710.349 0.00 5.8
1 2778.801 2.34 5.1
2 2775.488 2.74 5.3
3 2785.204 0.27 5.6
4 2847.699 2.31 5.2

data의 행 인덱스를 위에서 만든 시간 주기 인덱스를 이용하여 시간도장(Timestamp)으로 변경한다. D는 일자로 end 주기의 끝을 표시하라는 뜻이다. 즉 분기의 끝 날짜로 표시하라는 뜻이다.

In [108]:
data.index = periods.to_timestamp('D', 'end')
data.head()
Out[108]:
item realgdp infl unemp
date
1959-03-31 2710.349 0.00 5.8
1959-06-30 2778.801 2.34 5.1
1959-09-30 2775.488 2.74 5.3
1959-12-31 2785.204 0.27 5.6
1960-03-31 2847.699 2.31 5.2

stack을 이용해 열축을 행축의 가장 안쪽 수준으로 변경하여 시리즈를 만든다. 이 시리즈를 reset_index를 이용해서 다중 인덱스를 열이름으로 변경해서 데이터프레임을 만든다. rename은 데이터프레임 열이름 중에서 0value로 변경한다.

In [109]:
ldata = data.stack().reset_index().rename(columns={0: 'value'})
ldata.head()
Out[109]:
date item value
0 1959-03-31 realgdp 2710.349
1 1959-03-31 infl 0.000
2 1959-03-31 unemp 5.800
3 1959-06-30 realgdp 2778.801
4 1959-06-30 infl 2.340

만들어지 ldata는 긴 형식의 자료라고 부른다. 이러한 형식은 데이터베이스 자료 구조에서 흔히 볼 수 있다. 데이터베이스에서 dateitem을 주키(primary key)라고 부르며 자료를 빠르고 효율적으로 처리할 수 있도록 한다. 이러한 자료는 같은 날짜(date)에 대해서 항목(item)이 반복되는 구조로 분석하기 불편할 수 있다. item 열을 데이터프레임의 열이름으로 바꾸면 계산하기 편리한 구조로 변경된다. 이러한 용도로 사용될 수 있는 메소드가 pivot 이다.

In [110]:
pivoted = ldata.pivot(index='date', columns='item', values='value')
pivoted.head()
Out[110]:
item infl realgdp unemp
date
1959-03-31 0.00 2710.349 5.8
1959-06-30 2.34 2778.801 5.1
1959-09-30 2.74 2775.488 5.3
1959-12-31 0.27 2785.204 5.6
1960-03-31 2.31 2847.699 5.2

pivot은 첫번째 인자로 인덱스가 될 열을 입력하고 두번째 인자로 열 이름들이 될 열을 입력하고 세번째 인자는 각 열에 대응되는 값의 열을 선택하면 된다.

만일 값이 될 열이 여러 개일 때는 계층적 열 인덱스를 가진 자료를 만들 수 있다.

In [111]:
ldata['value2'] = np.random.randn(len(ldata))
ldata.head()
Out[111]:
date item value value2
0 1959-03-31 realgdp 2710.349 -0.690426
1 1959-03-31 infl 0.000 -0.034682
2 1959-03-31 unemp 5.800 -0.641208
3 1959-06-30 realgdp 2778.801 1.658025
4 1959-06-30 infl 2.340 -0.930612

다음과 같이 values=에 값에 해당하는 열을 리스트로 입력하면 다중 인덱스 열을 갖는 데이터프레임이 된다.

In [112]:
ldata.pivot(index='date', columns='item', values=['value', 'value2']).head()
Out[112]:
value value2
item infl realgdp unemp infl realgdp unemp
date
1959-03-31 0.00 2710.349 5.8 -0.034682 -0.690426 -0.641208
1959-06-30 2.34 2778.801 5.1 -0.930612 1.658025 -0.896335
1959-09-30 2.74 2775.488 5.3 -1.207501 0.338003 -0.258428
1959-12-31 0.27 2785.204 5.6 0.918907 1.102117 -0.216872
1960-03-31 2.31 2847.699 5.2 0.625715 -0.037569 -0.479985

Pivoting “Wide” to “Long” Format

meltpivot의 반대 개념으로 가로 넓은 자료를 세로로 길게 만드는데 사용한다. melt는 자료를 변형했을 때 키에 해당되는 id_vars과 살펴보고자 하는 값에 대응되는 value_vars들로 구분된다. 변형된 자료는 variablevalue라는 새로운 열이름이 추가된 데이터프레임을 만든다.

In [114]:
df = pd.DataFrame({'A': {0: 'a', 1: 'b', 2: 'c'},
                   'B': {0: 1, 1: 3, 2: 5},
                   'C': {0: 2, 1: 4, 2: 6}})
df
Out[114]:
A B C
0 a 1 2
1 b 3 4
2 c 5 6

아무것도 설정하지 않으면 모든 열이름들을 value_vars로 간주하여 변형을 한다.

In [115]:
df.melt()
Out[115]:
variable value
0 A a
1 A b
2 A c
3 B 1
4 B 3
5 B 5
6 C 2
7 C 4
8 C 6

id_vars= 만 설정하면 나머지 열이름들은 모두 value_vars로 설정된다.

In [116]:
df.melt(id_vars=['A'])
Out[116]:
A variable value
0 a B 1
1 b B 3
2 c B 5
3 a C 2
4 b C 4
5 c C 6

value_vars=만 설정하면 설정된 열이름들에 대해서만 자료를 만든다.

In [118]:
df.melt(value_vars=['A', 'B'])
Out[118]:
variable value
0 A a
1 A b
2 A c
3 B 1
4 B 3
5 B 5

id_vars=value_vars=를 동시에 설정할 수 있다.

In [121]:
melted = df.melt(id_vars=['A'], value_vars=['B', 'C'])
melted
Out[121]:
A variable value
0 a B 1
1 b B 3
2 c B 5
3 a C 2
4 b C 4
5 c C 6

pivot 메소드를 이용해서 원 자료로 되돌릴 수 있다.

In [127]:
restored = melted.pivot(index='A', columns='variable', values='value')
restored
Out[127]:
variable B C
A
a 1 2
b 3 4
c 5 6
In [128]:
restored.reset_index()
Out[128]:
variable A B C
0 a 1 2
1 b 3 4
2 c 5 6

첫번째 인자를 데이터프레임으로 건네주어 pd.melt 함수를 이용해서도 똑같은 결과를 낼 수 있다.

In [130]:
pd.melt(df, id_vars='A', value_vars=['B', 'C'])
Out[130]:
A variable value
0 a B 1
1 b B 3
2 c B 5
3 a C 2
4 b C 4
5 c C 6