DataFrame 인덱스 설정 및 제거
DataFrame에 인덱스로 들어가 있어야 할 데이터가 일반 데이터 열에 들어가 있거나 반대로 일반 데이터 열이어야 할 것이 인덱스로 되어 있을 수 있다. 이 때는 set_index
명령이나 reset_index
명령으로 인덱스와 일반 데이터 열을 교환할 수 있다.
- set_index : 기존의 행 인덱스를 제거하고 데이터 열 중 하나를 인덱스로 설정
- reset_index : 기존의 행 인덱스를 제거하고 인덱스를 데이터 열로 추가
import numpy as np
np.vstack([list('ABCDE'), np.round(np.random.rand(3,5), 2)])
array([['A', 'B', 'C', 'D', 'E'],
['0.67', '0.21', '0.13', '0.32', '0.36'],
['0.57', '0.44', '0.99', '0.1', '0.21'],
['0.16', '0.65', '0.25', '0.47', '0.24']], dtype='<U32')
import pandas as pd
np.random.seed(0)
df1 = pd.DataFrame(
np.vstack([list('ABCDE'), np.round(np.random.rand(3,5), 2)]).T,
columns=["C1","C2","C3","C4"])
df1
|
C1 |
C2 |
C3 |
C4 |
0 |
A |
0.55 |
0.65 |
0.79 |
1 |
B |
0.72 |
0.44 |
0.53 |
2 |
C |
0.6 |
0.89 |
0.57 |
3 |
D |
0.54 |
0.96 |
0.93 |
4 |
E |
0.42 |
0.38 |
0.07 |
set_index
명령으로 C1열을 인덱스로 설정할 수 있다. 이때 기존 인덱스는 없어진다.
df2 = df1.set_index("C1")
df2
|
C2 |
C3 |
C4 |
C1 |
|
|
|
A |
0.55 |
0.65 |
0.79 |
B |
0.72 |
0.44 |
0.53 |
C |
0.6 |
0.89 |
0.57 |
D |
0.54 |
0.96 |
0.93 |
E |
0.42 |
0.38 |
0.07 |
마찬가지로 C2열을 인덱스로 지정하면 기존의 인덱스는 사라진다.
|
C3 |
C4 |
C2 |
|
|
0.55 |
0.65 |
0.79 |
0.72 |
0.44 |
0.53 |
0.6 |
0.89 |
0.57 |
0.54 |
0.96 |
0.93 |
0.42 |
0.38 |
0.07 |
reset_index
명령으로 인덱스를 보통의 자료형으로 바꿀 수도 있다. 이 때 인덱스 열은 자료형의 가장 선두로 삽입된다. DataFrame의 인덱스는 정수로 된 디폴트 인덱스로 바뀌게 된다.
|
C1 |
C2 |
C3 |
C4 |
0 |
A |
0.55 |
0.65 |
0.79 |
1 |
B |
0.72 |
0.44 |
0.53 |
2 |
C |
0.6 |
0.89 |
0.57 |
3 |
D |
0.54 |
0.96 |
0.93 |
4 |
E |
0.42 |
0.38 |
0.07 |
reset_index
명령 사용시에 drop=True
로 설정하면 인덱스 열을 보통의 자료열로 올리는 것이 아니라 그냥 버리게 된다.
df2.reset_index(drop=True)
|
C2 |
C3 |
C4 |
0 |
0.55 |
0.65 |
0.79 |
1 |
0.72 |
0.44 |
0.53 |
2 |
0.6 |
0.89 |
0.57 |
3 |
0.54 |
0.96 |
0.93 |
4 |
0.42 |
0.38 |
0.07 |
다중 인덱스
행이나 열에 여러 계층을 가지는 인덱스 즉, 다중 인덱스(multi-index)를 설정할 수도 있다. DataFrame을 생성할 때 columns
인수에 다음 예제처럼 리스트의 리스트(행렬) 형태로 인덱스를 넣으면 다중 열 인덱스를 가지게 된다.
np.random.seed(0)
df3 = pd.DataFrame(
np.round(np.random.randn(5,4), 2),
columns=[["A","A","B","B"],
["C1","C2","C1","C2"]]
)
df3
|
A |
B |
|
C1 |
C2 |
C1 |
C2 |
0 |
1.76 |
0.40 |
0.98 |
2.24 |
1 |
1.87 |
-0.98 |
0.95 |
-0.15 |
2 |
-0.10 |
0.41 |
0.14 |
1.45 |
3 |
0.76 |
0.12 |
0.44 |
0.33 |
4 |
1.49 |
-0.21 |
0.31 |
-0.85 |
다중 인덱스는 이름을 지정하면 더 편리하게 사용할 수 있다. 열 인덱스들의 이름 지정은 columns
객체의 names
속성에 리스트를 넣어서 지정한다.
df3.columns.names = ["Cidx1", "Cidx2"]
df3
Cidx1 |
A |
B |
Cidx2 |
C1 |
C2 |
C1 |
C2 |
0 |
1.76 |
0.40 |
0.98 |
2.24 |
1 |
1.87 |
-0.98 |
0.95 |
-0.15 |
2 |
-0.10 |
0.41 |
0.14 |
1.45 |
3 |
0.76 |
0.12 |
0.44 |
0.33 |
4 |
1.49 |
-0.21 |
0.31 |
-0.85 |
마찬가지로 DataFrame을 생성할 때 index
인수에 리스트의 리스트(행렬) 형태로 인덱스를 넣으면 다중 (행) 인덱스를 가진다. 행 인덱스들의 이름 지정은 index
객체의 names
속성에 리스트를 넣어서 지정한다.
np.random.seed(0)
df4 = pd.DataFrame(np.round(np.random.randn(6, 4), 2),
columns=[["A", "A", "B", "B"],
["C", "D", "C", "D"]],
index=[["M", "M", "M", "F", "F", "F"],
["id_" + str(i + 1) for i in range(3)] * 2])
df4.columns.names = ["Cidx1", "Cidx2"]
df4.index.names = ["Ridx1", "Ridx2"]
df4
|
Cidx1 |
A |
B |
|
Cidx2 |
C |
D |
C |
D |
Ridx1 |
Ridx2 |
|
|
|
|
M |
id_1 |
1.76 |
0.40 |
0.98 |
2.24 |
id_2 |
1.87 |
-0.98 |
0.95 |
-0.15 |
id_3 |
-0.10 |
0.41 |
0.14 |
1.45 |
F |
id_1 |
0.76 |
0.12 |
0.44 |
0.33 |
id_2 |
1.49 |
-0.21 |
0.31 |
-0.85 |
id_3 |
-2.55 |
0.65 |
0.86 |
-0.74 |
행 인덱스와 열 인덱스 교환
stack
명령이나 unstack
명령을 쓰면 열 인덱스를 행 인덱스로 바꾸거나 반대로 행 인덱스를 열 인덱스로 바꿀 수 있다.
stack()
: 열 인덱스 -> 행 인덱스로 변환
unstack()
: 행 인덱스 -> 열 인덱스로 변환
stack
명령을 실행하면 열 인덱스가 반시계 방향으로 90도 회전한 것과 비슷한 모양이 된다. 마찬가지로 unstack 명령을 실행하면 행 인덱스가 시계 방향으로 90도 회전한 것과 비슷하다. 인덱스를 지정할 때는 문자열 이름과 순서를 표시하는 숫자 인덱스를 모두 사용할 수 있다.
|
|
Cidx2 |
C |
D |
Ridx1 |
Ridx2 |
Cidx1 |
|
|
M |
id_1 |
A |
1.76 |
0.40 |
B |
0.98 |
2.24 |
id_2 |
A |
1.87 |
-0.98 |
B |
0.95 |
-0.15 |
id_3 |
A |
-0.10 |
0.41 |
B |
0.14 |
1.45 |
F |
id_1 |
A |
0.76 |
0.12 |
B |
0.44 |
0.33 |
id_2 |
A |
1.49 |
-0.21 |
B |
0.31 |
-0.85 |
id_3 |
A |
-2.55 |
0.65 |
B |
0.86 |
-0.74 |
|
|
Cidx1 |
A |
B |
Ridx1 |
Ridx2 |
Cidx2 |
|
|
M |
id_1 |
C |
1.76 |
0.98 |
D |
0.40 |
2.24 |
id_2 |
C |
1.87 |
0.95 |
D |
-0.98 |
-0.15 |
id_3 |
C |
-0.10 |
0.14 |
D |
0.41 |
1.45 |
F |
id_1 |
C |
0.76 |
0.44 |
D |
0.12 |
0.33 |
id_2 |
C |
1.49 |
0.31 |
D |
-0.21 |
-0.85 |
id_3 |
C |
-2.55 |
0.86 |
D |
0.65 |
-0.74 |
Cidx1 |
A |
B |
Cidx2 |
C |
D |
C |
D |
Ridx2 |
id_1 |
id_2 |
id_3 |
id_1 |
id_2 |
id_3 |
id_1 |
id_2 |
id_3 |
id_1 |
id_2 |
id_3 |
Ridx1 |
|
|
|
|
|
|
|
|
|
|
|
|
F |
0.76 |
1.49 |
-2.55 |
0.12 |
-0.21 |
0.65 |
0.44 |
0.31 |
0.86 |
0.33 |
-0.85 |
-0.74 |
M |
1.76 |
1.87 |
-0.10 |
0.40 |
-0.98 |
0.41 |
0.98 |
0.95 |
0.14 |
2.24 |
-0.15 |
1.45 |
Cidx1 |
A |
B |
Cidx2 |
C |
D |
C |
D |
Ridx1 |
F |
M |
F |
M |
F |
M |
F |
M |
Ridx2 |
|
|
|
|
|
|
|
|
id_1 |
0.76 |
1.76 |
0.12 |
0.40 |
0.44 |
0.98 |
0.33 |
2.24 |
id_2 |
1.49 |
1.87 |
-0.21 |
-0.98 |
0.31 |
0.95 |
-0.85 |
-0.15 |
id_3 |
-2.55 |
-0.10 |
0.65 |
0.41 |
0.86 |
0.14 |
-0.74 |
1.45 |
다중 인덱스가 있는 경우 인덱싱
DataFrame이 다중 인덱스를 가지는 경우에는 인덱스가 하나의 라벨이나 숫자가 아니라 ()
로 둘러싸인 튜플이 되어야 한다. 예를 들어 앞에서 만든 df3
DataFrame의 경우 다음과 같이 인덱싱할 수 있다.
Cidx1 |
A |
B |
Cidx2 |
C1 |
C2 |
C1 |
C2 |
0 |
1.76 |
0.40 |
0.98 |
2.24 |
1 |
1.87 |
-0.98 |
0.95 |
-0.15 |
2 |
-0.10 |
0.41 |
0.14 |
1.45 |
3 |
0.76 |
0.12 |
0.44 |
0.33 |
4 |
1.49 |
-0.21 |
0.31 |
-0.85 |
0 0.98
1 0.95
2 0.14
3 0.44
4 0.31
Name: (B, C1), dtype: float64
df3.loc[0, ("B", "C1")] = 100
df3
Cidx1 |
A |
B |
Cidx2 |
C1 |
C2 |
C1 |
C2 |
0 |
1.76 |
0.40 |
100.00 |
2.24 |
1 |
1.87 |
-0.98 |
0.95 |
-0.15 |
2 |
-0.10 |
0.41 |
0.14 |
1.45 |
3 |
0.76 |
0.12 |
0.44 |
0.33 |
4 |
1.49 |
-0.21 |
0.31 |
-0.85 |
만약 하나의 레벨 값만 넣으면 다중 인덱스 중에서 가장 상위의 값을 지정한 것으로 본다.
Cidx2 |
C1 |
C2 |
0 |
1.76 |
0.40 |
1 |
1.87 |
-0.98 |
2 |
-0.10 |
0.41 |
3 |
0.76 |
0.12 |
4 |
1.49 |
-0.21 |
df4
DataFrame은 다음과 같이 인덱싱할 수 있다.
|
Cidx1 |
A |
B |
|
Cidx2 |
C |
D |
C |
D |
Ridx1 |
Ridx2 |
|
|
|
|
M |
id_1 |
1.76 |
0.40 |
0.98 |
2.24 |
id_2 |
1.87 |
-0.98 |
0.95 |
-0.15 |
id_3 |
-0.10 |
0.41 |
0.14 |
1.45 |
F |
id_1 |
0.76 |
0.12 |
0.44 |
0.33 |
id_2 |
1.49 |
-0.21 |
0.31 |
-0.85 |
id_3 |
-2.55 |
0.65 |
0.86 |
-0.74 |
Ridx1 Ridx2
M id_1 1.76
id_2 1.87
id_3 -0.10
F id_1 0.76
id_2 1.49
id_3 -2.55
Name: (A, C), dtype: float64
df4.loc[("M", "id_1"), :]
Cidx1 Cidx2
A C 1.76
D 0.40
B C 0.98
D 2.24
Name: (M, id_1), dtype: float64
df4.loc[("All", "All"), :] = df4.sum()
df4
|
Cidx1 |
A |
B |
|
Cidx2 |
C |
D |
C |
D |
Ridx1 |
Ridx2 |
|
|
|
|
M |
id_1 |
1.76 |
0.40 |
0.98 |
2.24 |
id_2 |
1.87 |
-0.98 |
0.95 |
-0.15 |
id_3 |
-0.10 |
0.41 |
0.14 |
1.45 |
F |
id_1 |
0.76 |
0.12 |
0.44 |
0.33 |
id_2 |
1.49 |
-0.21 |
0.31 |
-0.85 |
id_3 |
-2.55 |
0.65 |
0.86 |
-0.74 |
All |
All |
6.46 |
0.78 |
7.36 |
4.56 |
다중 인덱스의 인덱스 순서 교환
다중 인덱스의 인덱스 순서를 바꾸고 싶으면 swaplevel
명령을 사용한다.
i
와 j
는 교환하고자 하는 인덱스 라벨(혹은 인덱스 번호)이고 axis
는 0일 때 행 인덱스, 1일때는 열 인덱스를 뜻한다.(기본값은 0)
df5 = df4.swaplevel("Ridx1", "Ridx2")
df5
|
Cidx1 |
A |
B |
|
Cidx2 |
C |
D |
C |
D |
Ridx2 |
Ridx1 |
|
|
|
|
id_1 |
M |
1.76 |
0.40 |
0.98 |
2.24 |
id_2 |
M |
1.87 |
-0.98 |
0.95 |
-0.15 |
id_3 |
M |
-0.10 |
0.41 |
0.14 |
1.45 |
id_1 |
F |
0.76 |
0.12 |
0.44 |
0.33 |
id_2 |
F |
1.49 |
-0.21 |
0.31 |
-0.85 |
id_3 |
F |
-2.55 |
0.65 |
0.86 |
-0.74 |
All |
All |
6.46 |
0.78 |
7.36 |
4.56 |
df6 = df4.swaplevel("Cidx1", "Cidx2", 1)
df6
|
Cidx2 |
C |
D |
C |
D |
|
Cidx1 |
A |
A |
B |
B |
Ridx1 |
Ridx2 |
|
|
|
|
M |
id_1 |
1.76 |
0.40 |
0.98 |
2.24 |
id_2 |
1.87 |
-0.98 |
0.95 |
-0.15 |
id_3 |
-0.10 |
0.41 |
0.14 |
1.45 |
F |
id_1 |
0.76 |
0.12 |
0.44 |
0.33 |
id_2 |
1.49 |
-0.21 |
0.31 |
-0.85 |
id_3 |
-2.55 |
0.65 |
0.86 |
-0.74 |
All |
All |
6.46 |
0.78 |
7.36 |
4.56 |
다중 인덱스가 있는 경우의 정렬
다중 인덱스가 있는 데이터프레임을 sort_index
로 정렬할 때는 level
인수를 사용하여 어떤 인덱스를 기준으로 정렬하는지 알려주어야 한다.
|
Cidx1 |
A |
B |
|
Cidx2 |
C |
D |
C |
D |
Ridx2 |
Ridx1 |
|
|
|
|
All |
All |
6.46 |
0.78 |
7.36 |
4.56 |
id_1 |
F |
0.76 |
0.12 |
0.44 |
0.33 |
M |
1.76 |
0.40 |
0.98 |
2.24 |
id_2 |
F |
1.49 |
-0.21 |
0.31 |
-0.85 |
M |
1.87 |
-0.98 |
0.95 |
-0.15 |
id_3 |
F |
-2.55 |
0.65 |
0.86 |
-0.74 |
M |
-0.10 |
0.41 |
0.14 |
1.45 |
df6.sort_index(axis=1, level=0)
|
Cidx2 |
C |
D |
|
Cidx1 |
A |
B |
A |
B |
Ridx1 |
Ridx2 |
|
|
|
|
M |
id_1 |
1.76 |
0.98 |
0.40 |
2.24 |
id_2 |
1.87 |
0.95 |
-0.98 |
-0.15 |
id_3 |
-0.10 |
0.14 |
0.41 |
1.45 |
F |
id_1 |
0.76 |
0.44 |
0.12 |
0.33 |
id_2 |
1.49 |
0.31 |
-0.21 |
-0.85 |
id_3 |
-2.55 |
0.86 |
0.65 |
-0.74 |
All |
All |
6.46 |
7.36 |
0.78 |
4.56 |
출처 : 데이터사이언스 스쿨(datascienceschool.net)