22. 다중 인덱스#
import numpy as np
import pandas as pd
pd.options.display.max_rows = 20
pd.options.display.max_colwidth = 80
pd.options.display.max_columns = 20
np.random.seed(12345)
import matplotlib.pyplot as plt
plt.rc("figure", figsize=(10, 6))
np.set_printoptions(precision=4, suppress=True)
22.1. 시리즈 계층 인덱싱#
다중 인덱스 사용 시리즈
data = pd.Series(np.random.uniform(size=9),
index=[["a", "a", "a", "b", "b", "c", "c", "d", "d"],
[1, 2, 3, 1, 3, 1, 2, 2, 3]])
data
a 1 0.929616
2 0.316376
3 0.183919
b 1 0.204560
3 0.567725
c 1 0.595545
2 0.964515
d 2 0.653177
3 0.748907
dtype: float64
data.index
MultiIndex([('a', 1),
('a', 2),
('a', 3),
('b', 1),
('b', 3),
('c', 1),
('c', 2),
('d', 2),
('d', 3)],
)
시리즈 인덱싱/슬라이싱
0-레벨 인덱싱
data["b"]
1 0.204560
3 0.567725
dtype: float64
0-레벨 슬라싱
data["b":"c"]
b 1 0.204560
3 0.567725
c 1 0.595545
2 0.964515
dtype: float64
0-레벨 팬시 인덱싱
data.loc[["b", "d"]]
b 1 0.204560
3 0.567725
d 2 0.653177
3 0.748907
dtype: float64
0-레벨과 1-레벨 동시 인덱싱/슬라이싱:
loc
속성과 쉼표로 구분되는 레벨 별 인덱싱/슬라이싱 적용
data.loc[:, 2]
a 0.316376
c 0.964515
d 0.653177
dtype: float64
스택과 언스택
언스택은 행 인덱스의 가장 깊은 라벨을 열 인덱스의 가장 깊은 라벨로 변환한다.
data.unstack()
1 | 2 | 3 | |
---|---|---|---|
a | 0.929616 | 0.316376 | 0.183919 |
b | 0.204560 | NaN | 0.567725 |
c | 0.595545 | 0.964515 | NaN |
d | NaN | 0.653177 | 0.748907 |
스택은 열 인덱스의 가장 깊은 라벨을 행 인덱스의 가장 깊은 라벨로 변환한다.
data.unstack().stack()
a 1 0.929616
2 0.316376
3 0.183919
b 1 0.204560
3 0.567725
c 1 0.595545
2 0.964515
d 2 0.653177
3 0.748907
dtype: float64
22.2. 데이터프레임 계층 인덱싱#
다중 행/열 인덱스 사용 데이터프레임
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 |
행 인덱스는 2개의 레벨로 구성
frame.index.nlevels
2
기본 인덱싱은 열 인덱스의 0-레벨에 적용
frame["Ohio"]
color | Green | Red | |
---|---|---|---|
key1 | key2 | ||
a | 1 | 0 | 1 |
2 | 3 | 4 | |
b | 1 | 6 | 7 |
2 | 9 | 10 |
22.2.1. 다중 인덱스 레벨 교환과 인덱스 라벨 정렬#
레벨 교환
레벨 이름 활용
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 |
정수 레벨 활용
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.swaplevel(0, 1)
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 |
인덱스 라벨 정렬
먼저 1-레벨의 라벨을 정렬한다.
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 |
22.2.2. 레벨 단위 그룹화#
frame.groupby(level="key2").sum()
state | Ohio | Colorado | |
---|---|---|---|
color | Green | Red | Green |
key2 | |||
1 | 6 | 8 | 10 |
2 | 12 | 14 | 16 |
레벨과 축을 활용한 그룹화
level="color"
: 열 인덱스의 1-레벨 기준axis="columns"
: 열에 사용된 라벨 단위로 그룹화
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.groupby(level="color", axis="columns").sum()
color | Green | Red | |
---|---|---|---|
key1 | key2 | ||
a | 1 | 2 | 1 |
2 | 8 | 4 | |
b | 1 | 14 | 7 |
2 | 20 | 10 |
22.2.3. 인덱스 지정과 초기화#
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()
메서드: 열의 특정 라벨을 이용하여 (멀티)인덱스를 지정한다.
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 |
인덱스에 사용된 열을 그대로 둘 수도 있다.
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 |
drop=True
옵션: 인덱스로 사용된 라벨을 모두 삭제
frame2.reset_index(drop=True)
a | b | |
---|---|---|
0 | 0 | 7 |
1 | 1 | 6 |
2 | 2 | 5 |
3 | 3 | 4 |
4 | 4 | 3 |
5 | 5 | 2 |
6 | 6 | 1 |
22.3. 모양 변환#
22.3.1. 항목 재배열#
스택
언스택
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()
result
state number
Ohio one 0
two 1
three 2
Colorado one 3
two 4
three 5
dtype: int64
result.unstack()
number | one | two | three |
---|---|---|---|
state | |||
Ohio | 0 | 1 | 2 |
Colorado | 3 | 4 | 5 |
result.unstack(level=0)
state | Ohio | Colorado |
---|---|---|
number | ||
one | 0 | 3 |
two | 1 | 4 |
three | 2 | 5 |
result.unstack(level="state")
state | Ohio | Colorado |
---|---|---|
number | ||
one | 0 | 3 |
two | 1 | 4 |
three | 2 | 5 |
s1 = pd.Series([0, 1, 2, 3], index=["a", "b", "c", "d"], dtype="Int64")
s2 = pd.Series([4, 5, 6], index=["c", "d", "e"], dtype="Int64")
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 | 1 | 2 | 3 | <NA> |
two | <NA> | <NA> | 4 | 5 | 6 |
data2.unstack().stack()
one a 0
b 1
c 2
d 3
two c 4
d 5
e 6
dtype: Int64
dropna=False
키워드 인자: 항목 재배치 과정에서 발생하는 결측치를 그대로 둚
data2.unstack().stack(dropna=False)
one a 0
b 1
c 2
d 3
e <NA>
two a <NA>
b <NA>
c 4
d 5
e 6
dtype: Int64
레벨 활용 스택/언스택
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(level="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 |
df.unstack(level="state").stack(level="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 |
테이블 데이텃세에서 긴 모양 데이터프레임 생성
예제: 거시경제 데이터셋 활용
데이터셋 다운로드
base_url = "https://raw.githubusercontent.com/codingalzi/datapy/master/jupyter-book/examples/"
file = "macrodata.csv"
data = pd.read_csv(base_url + file)
1959년부터 2009년까지 총 203개의 분기quarter별 데이터 샘플 포함
data.shape
(203, 14)
head()
메서드: 처음 5행 확인. 열 라벨도 확인 가능
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 |
열 라벨은 거시경제 지표 14개
data.columns
Index(['year', 'quarter', 'realgdp', 'realcons', 'realinv', 'realgovt',
'realdpi', 'cpi', 'm1', 'tbilrate', 'unemp', 'pop', 'infl', 'realint'],
dtype='object')
열 일부 데이터만 사용
data = data.loc[:, ["year", "quarter", "realgdp", "infl", "unemp"]]
data.head()
year | quarter | realgdp | infl | unemp | |
---|---|---|---|---|---|
0 | 1959.0 | 1.0 | 2710.349 | 0.00 | 5.8 |
1 | 1959.0 | 2.0 | 2778.801 | 2.34 | 5.1 |
2 | 1959.0 | 3.0 | 2775.488 | 2.74 | 5.3 |
3 | 1959.0 | 4.0 | 2785.204 | 0.27 | 5.6 |
4 | 1960.0 | 1.0 | 2847.699 | 2.31 | 5.2 |
기간 인덱스:
pd.PeriodIndex
객체 활용. 년도(year
)와 분기(quarter
) 결합
주의사항: pop()
메서드를 사용하기에 data
데이터프레임에서 해당 열 삭제됨
periods = pd.PeriodIndex(year=data.pop("year"), # pop()
quarter=data.pop("quarter"), # pop()
name="date") # 인덱스 이름
periods
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)
to_timestamp("D")
: 일 단위의DatetimeIndex
로 변환
data.index = periods.to_timestamp("D")
data.index
DatetimeIndex(['1959-01-01', '1959-04-01', '1959-07-01', '1959-10-01',
'1960-01-01', '1960-04-01', '1960-07-01', '1960-10-01',
'1961-01-01', '1961-04-01',
...
'2007-04-01', '2007-07-01', '2007-10-01', '2008-01-01',
'2008-04-01', '2008-07-01', '2008-10-01', '2009-01-01',
'2009-04-01', '2009-07-01'],
dtype='datetime64[ns]', name='date', length=203, freq='QS-OCT')
data.head()
realgdp | infl | unemp | |
---|---|---|---|
date | |||
1959-01-01 | 2710.349 | 0.00 | 5.8 |
1959-04-01 | 2778.801 | 2.34 | 5.1 |
1959-07-01 | 2775.488 | 2.74 | 5.3 |
1959-10-01 | 2785.204 | 0.27 | 5.6 |
1960-01-01 | 2847.699 | 2.31 | 5.2 |
리인덱싱
data = data.reindex(columns=["realgdp", "infl", "unemp"])
열 인덱스에 이름 지정
data.columns.name = "item"
data.head()
item | realgdp | infl | unemp |
---|---|---|---|
date | |||
1959-01-01 | 2710.349 | 0.00 | 5.8 |
1959-04-01 | 2778.801 | 2.34 | 5.1 |
1959-07-01 | 2775.488 | 2.74 | 5.3 |
1959-10-01 | 2785.204 | 0.27 | 5.6 |
1960-01-01 | 2847.699 | 2.31 | 5.2 |
항목 재배열: 스택/언스택 활용
data.stack()
date item
1959-01-01 realgdp 2710.349
infl 0.000
unemp 5.800
1959-04-01 realgdp 2778.801
infl 2.340
...
2009-04-01 infl 3.370
unemp 9.200
2009-07-01 realgdp 12990.341
infl 3.560
unemp 9.600
Length: 609, dtype: float64
data.stack().reset_index()
date | item | 0 | |
---|---|---|---|
0 | 1959-01-01 | realgdp | 2710.349 |
1 | 1959-01-01 | infl | 0.000 |
2 | 1959-01-01 | unemp | 5.800 |
3 | 1959-04-01 | realgdp | 2778.801 |
4 | 1959-04-01 | infl | 2.340 |
... | ... | ... | ... |
604 | 2009-04-01 | infl | 3.370 |
605 | 2009-04-01 | unemp | 9.200 |
606 | 2009-07-01 | realgdp | 12990.341 |
607 | 2009-07-01 | infl | 3.560 |
608 | 2009-07-01 | unemp | 9.600 |
609 rows × 3 columns
long_data = (data.stack()
.reset_index()
.rename(columns={0: "value"}))
long_data[:10]
date | item | value | |
---|---|---|---|
0 | 1959-01-01 | realgdp | 2710.349 |
1 | 1959-01-01 | infl | 0.000 |
2 | 1959-01-01 | unemp | 5.800 |
3 | 1959-04-01 | realgdp | 2778.801 |
4 | 1959-04-01 | infl | 2.340 |
5 | 1959-04-01 | unemp | 5.100 |
6 | 1959-07-01 | realgdp | 2775.488 |
7 | 1959-07-01 | infl | 2.740 |
8 | 1959-07-01 | unemp | 5.300 |
9 | 1959-10-01 | realgdp | 2785.204 |
22.3.2. 피버팅#
긴 모양 데이터프레임을 넓은 모양 데이터프레임으로 변환하는 과정을 살펴 본다.
한 개의 열로 구성된 갑을 사용하는 피버팅
pivoted = long_data.pivot(index="date", columns="item", values="value")
pivoted.head()
item | infl | realgdp | unemp |
---|---|---|---|
date | |||
1959-01-01 | 0.00 | 2710.349 | 5.8 |
1959-04-01 | 2.34 | 2778.801 | 5.1 |
1959-07-01 | 2.74 | 2775.488 | 5.3 |
1959-10-01 | 0.27 | 2785.204 | 5.6 |
1960-01-01 | 2.31 | 2847.699 | 5.2 |
여러 개의 열로 구성된 갑을 사용하는 피버팅
long_data["value2"] = np.random.standard_normal(len(long_data))
long_data[:10]
date | item | value | value2 | |
---|---|---|---|---|
0 | 1959-01-01 | realgdp | 2710.349 | 1.248804 |
1 | 1959-01-01 | infl | 0.000 | 0.774191 |
2 | 1959-01-01 | unemp | 5.800 | -0.319657 |
3 | 1959-04-01 | realgdp | 2778.801 | -0.624964 |
4 | 1959-04-01 | infl | 2.340 | 1.078814 |
5 | 1959-04-01 | unemp | 5.100 | 0.544647 |
6 | 1959-07-01 | realgdp | 2775.488 | 0.855588 |
7 | 1959-07-01 | infl | 2.740 | 1.343268 |
8 | 1959-07-01 | unemp | 5.300 | -0.267175 |
9 | 1959-10-01 | realgdp | 2785.204 | 1.793095 |
값으로 사용되는 열 별로 열 인덱스 지정. 따라서 다중 인덱스가 열 인덱스로 사용됨.
pivoted = long_data.pivot(index="date", columns="item")
pivoted.head()
value | value2 | |||||
---|---|---|---|---|---|---|
item | infl | realgdp | unemp | infl | realgdp | unemp |
date | ||||||
1959-01-01 | 0.00 | 2710.349 | 5.8 | 0.774191 | 1.248804 | -0.319657 |
1959-04-01 | 2.34 | 2778.801 | 5.1 | 1.078814 | -0.624964 | 0.544647 |
1959-07-01 | 2.74 | 2775.488 | 5.3 | 1.343268 | 0.855588 | -0.267175 |
1959-10-01 | 0.27 | 2785.204 | 5.6 | -0.652929 | 1.793095 | -1.886837 |
1960-01-01 | 2.31 | 2847.699 | 5.2 | 0.644448 | 1.059626 | -0.007799 |
pivoted["value"].head()
item | infl | realgdp | unemp |
---|---|---|---|
date | |||
1959-01-01 | 0.00 | 2710.349 | 5.8 |
1959-04-01 | 2.34 | 2778.801 | 5.1 |
1959-07-01 | 2.74 | 2775.488 | 5.3 |
1959-10-01 | 0.27 | 2785.204 | 5.6 |
1960-01-01 | 2.31 | 2847.699 | 5.2 |
피버팅은 set_index()
메서드와 unstack()
메서드를 연속적으로 적용하는 것과 동일한 결과를 낸다.
long_data.head(10)
date | item | value | value2 | |
---|---|---|---|---|
0 | 1959-01-01 | realgdp | 2710.349 | 1.248804 |
1 | 1959-01-01 | infl | 0.000 | 0.774191 |
2 | 1959-01-01 | unemp | 5.800 | -0.319657 |
3 | 1959-04-01 | realgdp | 2778.801 | -0.624964 |
4 | 1959-04-01 | infl | 2.340 | 1.078814 |
5 | 1959-04-01 | unemp | 5.100 | 0.544647 |
6 | 1959-07-01 | realgdp | 2775.488 | 0.855588 |
7 | 1959-07-01 | infl | 2.740 | 1.343268 |
8 | 1959-07-01 | unemp | 5.300 | -0.267175 |
9 | 1959-10-01 | realgdp | 2785.204 | 1.793095 |
long_data.set_index(["date", "item"])
value | value2 | ||
---|---|---|---|
date | item | ||
1959-01-01 | realgdp | 2710.349 | 1.248804 |
infl | 0.000 | 0.774191 | |
unemp | 5.800 | -0.319657 | |
1959-04-01 | realgdp | 2778.801 | -0.624964 |
infl | 2.340 | 1.078814 | |
... | ... | ... | ... |
2009-04-01 | infl | 3.370 | 0.904582 |
unemp | 9.200 | 1.374036 | |
2009-07-01 | realgdp | 12990.341 | 1.132698 |
infl | 3.560 | 0.314682 | |
unemp | 9.600 | 1.515960 |
609 rows × 2 columns
unstacked = long_data.set_index(["date", "item"]).unstack(level="item")
unstacked.head()
value | value2 | |||||
---|---|---|---|---|---|---|
item | infl | realgdp | unemp | infl | realgdp | unemp |
date | ||||||
1959-01-01 | 0.00 | 2710.349 | 5.8 | 0.774191 | 1.248804 | -0.319657 |
1959-04-01 | 2.34 | 2778.801 | 5.1 | 1.078814 | -0.624964 | 0.544647 |
1959-07-01 | 2.74 | 2775.488 | 5.3 | 1.343268 | 0.855588 | -0.267175 |
1959-10-01 | 0.27 | 2785.204 | 5.6 | -0.652929 | 1.793095 | -1.886837 |
1960-01-01 | 2.31 | 2847.699 | 5.2 | 0.644448 | 1.059626 | -0.007799 |
22.3.3. 언피버팅#
넓은 모양 데이터프레임을 긴 모양 데이터프레임으로 변환하는 과정을 살펴 본다.
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 |
set_index()
메서드와stack()
메서드를 연속적용하면 여러 개의 열이 하나의 열로 구성된 긴 모양 데이터프레임 생성 가능
df.set_index(["key"])
A | B | C | |
---|---|---|---|
key | |||
foo | 1 | 4 | 7 |
bar | 2 | 5 | 8 |
baz | 3 | 6 | 9 |
df.set_index(["key"]).stack()
key
foo A 1
B 4
C 7
bar A 2
B 5
C 8
baz A 3
B 6
C 9
dtype: int64
reshaped = df.set_index(["key"]).stack().reset_index()
reshaped
key | level_1 | 0 | |
---|---|---|---|
0 | foo | A | 1 |
1 | foo | B | 4 |
2 | foo | C | 7 |
3 | bar | A | 2 |
4 | bar | B | 5 |
5 | bar | C | 8 |
6 | baz | A | 3 |
7 | baz | B | 6 |
8 | baz | C | 9 |
reshaped.columns = ["key", "variable", "value"]
reshaped.sort_values("key")
key | variable | value | |
---|---|---|---|
3 | bar | A | 2 |
4 | bar | B | 5 |
5 | bar | C | 8 |
6 | baz | A | 3 |
7 | baz | B | 6 |
8 | baz | C | 9 |
0 | foo | A | 1 |
1 | foo | B | 4 |
2 | foo | C | 7 |
pd.melt()
함수: 위 과정을 한 번에 처리한다.id_vars
키워드 인자: 그룹 식별자 사용될 값들의 열 지정.
melted = pd.melt(df, id_vars="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 |
melted = melted.sort_values("key")
melted
key | variable | value | |
---|---|---|---|
1 | bar | A | 2 |
4 | bar | B | 5 |
7 | bar | C | 8 |
2 | baz | A | 3 |
5 | baz | B | 6 |
8 | baz | C | 9 |
0 | foo | A | 1 |
3 | foo | B | 4 |
6 | foo | C | 7 |
pivot()
메서드를 적용하면 다시 넓은 모양 데이터프레임으로 변환
reshaped = melted.pivot(index="key", columns="variable",
values="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 |
value_vars=["A", "B"]
키워드 인자:value
열에 사용되는 값과 연관된 열 지정. 여기서는A
,B
열의 값만 사용.
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 |
id_vars
키워드 인자 생략: 그룹 식별자 사용하지 않음
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 |