데이터프레임 인덱스 변경 - deiteopeuleim indegseu byeongyeong

데이터프레임 인덱스 설정 및 제거¶

때로는 데이터프레임에 인덱스로 들어가 있어야 할 데이터가 일반 데이터 열에 들어가 있거나 반대로 일반 데이터 열이어야 할 것이 인덱스로 되어 있을 수 있다. 이 때는 set_index 명령이나 reset_index 명령으로 인덱스와 일반 데이터 열을 교환할 수 있다.

  • set_index : 기존의 행 인덱스를 제거하고 데이터 열 중 하나를 인덱스로 설정

  • reset_index : 기존의 행 인덱스를 제거하고 인덱스를 데이터 열로 추가

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

C1C2C3C4
0A 0.55 0.65 0.79
1B 0.72 0.44 0.53
2C 0.6 0.89 0.57
3D 0.54 0.96 0.93
4E 0.42 0.38 0.07

set_index 메서드로 특정한 열을 인덱스로 설정할 수 있다. 이 때 기존의 인덱스는 없어진다.

df2 = df1.set_index("C1")
df2

C2C3C4
C1
A0.55 0.65 0.79
B0.72 0.44 0.53
C0.6 0.89 0.57
D0.54 0.96 0.93
E0.42 0.38 0.07

마찬가지로 C2열을 인덱스로 지정하면 기존의 인덱스는 사라진다.

C3C4
C2
0.550.65 0.79
0.720.44 0.53
0.60.89 0.57
0.540.96 0.93
0.420.38 0.07

반대로 reset_index 메서드를 쓰면 인덱스를 보통의 자료열로 바꿀 수도 있다. 이 때 인덱스 열은 자료열의 가장 선두로 삽입된다. 데이터프레임의 인덱스는 정수로 된 디폴트 인덱스로 바뀐다.

C1C2C3C4
0A 0.55 0.65 0.79
1B 0.72 0.44 0.53
2C 0.6 0.89 0.57
3D 0.54 0.96 0.93
4E 0.42 0.38 0.07

reset_index 메서드를 호출할 때 인수 drop=True 로 설정하면 인덱스 열을 보통의 자료열로 올리는 것이 아니라 그냥 버리게 된다.

df2.reset_index(drop=True)

C2C3C4
00.55 0.65 0.79
10.72 0.44 0.53
20.6 0.89 0.57
30.54 0.96 0.93
40.42 0.38 0.07

연습 문제 4.5.1

5명의 학생의 국어, 영어, 수학 점수를 나타내는 데이터프레임을 다음과 같이 만든다.

  1. 학생 이름을 나타내는 열을 포함시키지 않고 데이터프레임 df_score1 을 생성한 후, df_score1.index 속성에 학생 이름을 나타내는 열을 지정하여 인덱스를 지정한다. reset_index 명령으로 이 인덱스 열을 명령으로 일반 데이터열로 바꾸여 데이터프레임 df_score2을 만든다.

  2. 학생 이름을 나타내는 열이 일반 데이터 열을 포함하는 데이터프레임 df_score2set_index 명령을 적용하여 다시 학생 이름을 나타내는 열을 인덱스로 변경한다.

다중 인덱스¶

행이나 열에 여러 계층을 가지는 인덱스 즉, 다중 인덱스(multi-index)를 설정할 수도 있다. 데이터프레임을 생성할 때 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

AB
C1C2C1C2
01.76 0.40 0.98 2.24
11.87 -0.98 0.95 -0.15
2-0.10 0.41 0.14 1.45
30.76 0.12 0.44 0.33
41.49 -0.21 0.31 -0.85

다중 인덱스는 이름을 지정하면 더 편리하게 사용할 수 있다. 열 인덱스들의 이름 지정은 columns 객체의 names 속성에 리스트를 넣어서 지정한다.

df3.columns.names = ["Cidx1", "Cidx2"]
df3

Cidx1AB
Cidx2C1C2C1C2
01.76 0.40 0.98 2.24
11.87 -0.98 0.95 -0.15
2-0.10 0.41 0.14 1.45
30.76 0.12 0.44 0.33
41.49 -0.21 0.31 -0.85

마찬가지로 데이터프레임을 생성할 때 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

Cidx1AB
Cidx2CDCD
Ridx1Ridx2
Mid_11.76 0.40 0.98 2.24
id_21.87 -0.98 0.95 -0.15
id_3-0.10 0.41 0.14 1.45
Fid_10.76 0.12 0.44 0.33
id_21.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도 회전한 것과 비슷하다. 인덱스를 지정할 때는 문자열 이름과 순서를 표시하는 숫자 인덱스를 모두 사용할 수 있다.

Cidx2CD
Ridx1Ridx2Cidx1
Mid_1A1.76 0.40
B0.98 2.24
id_2A1.87 -0.98
B0.95 -0.15
id_3A-0.10 0.41
B0.14 1.45
Fid_1A0.76 0.12
B0.44 0.33
id_2A1.49 -0.21
B0.31 -0.85
id_3A-2.55 0.65
B0.86 -0.74

Cidx1AB
Ridx1Ridx2Cidx2
Mid_1C1.76 0.98
D0.40 2.24
id_2C1.87 0.95
D-0.98 -0.15
id_3C-0.10 0.14
D0.41 1.45
Fid_1C0.76 0.44
D0.12 0.33
id_2C1.49 0.31
D-0.21 -0.85
id_3C-2.55 0.86
D0.65 -0.74

Cidx1AB
Cidx2CDCD
Ridx2id_1id_2id_3id_1id_2id_3id_1id_2id_3id_1id_2id_3
Ridx1
F0.76 1.49 -2.55 0.12 -0.21 0.65 0.44 0.31 0.86 0.33 -0.85 -0.74
M1.76 1.87 -0.10 0.40 -0.98 0.41 0.98 0.95 0.14 2.24 -0.15 1.45

Cidx1AB
Cidx2CDCD
Ridx1FMFMFMFM
Ridx2
id_1 0.76 1.76 0.12 0.40 0.44 0.98 0.33 2.24
id_21.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

다중 인덱스가 있는 경우의 인덱싱¶

데이터프레임이 다중 인덱스를 가지는 경우에는 인덱스 값이 하나의 라벨이나 숫자가 아니라 ()로 둘러싸인 튜플이 되어야 한다. 예를 들어 앞에서 만든 df3 데이터프레임의 경우 다음과 같이 인덱싱할 수 있다.

Cidx1AB
Cidx2C1C2C1C2
01.76 0.40 0.98 2.24
11.87 -0.98 0.95 -0.15
2-0.10 0.41 0.14 1.45
30.76 0.12 0.44 0.33
41.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

loc 인덱스를 사용하는 경우에도 마찬가지로 튜플을 써야 한다.

df3.loc[0, ("B", "C1")] = 100
df3

Cidx1AB
Cidx2C1C2C1C2
01.76 0.40 100.00 2.24
11.87 -0.98 0.95 -0.15
2-0.10 0.41 0.14 1.45
30.76 0.12 0.44 0.33
41.49 -0.21 0.31 -0.85

단, iloc 인덱서를 사용하는 경우에는 튜플 형태의 다중인덱스를 사용할 수 없다.

만약 하나의 레벨 값만 넣으면 다중 인덱스 중에서 가장 상위의 값을 지정한 것으로 본다.

Cidx2C1C2
01.76 0.40
11.87 -0.98
2-0.10 0.41
30.76 0.12
41.49 -0.21

df4 데이터프레임은 다음과 같이 인덱싱할 수 있다.

Cidx1AB
Cidx2CDCD
Ridx1Ridx2
Mid_11.76 0.40 0.98 2.24
id_21.87 -0.98 0.95 -0.15
id_3-0.10 0.41 0.14 1.45
Fid_10.76 0.12 0.44 0.33
id_21.49 -0.21 0.31 -0.85
id_3-2.55 0.65 0.86 -0.74

df4.loc[("M", "id_1"), ("A", "C")]

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

Cidx1AB
Cidx2CDCD
Ridx1Ridx2
Mid_11.76 0.40 0.98 2.24
id_21.87 -0.98 0.95 -0.15
id_3-0.10 0.41 0.14 1.45
Fid_10.76 0.12 0.44 0.33
id_21.49 -0.21 0.31 -0.85
id_3-2.55 0.65 0.86 -0.74
AllAll3.23 0.39 3.68 2.28

loc를 사용하는 경우에도 튜플이 아닌 하나의 값만 쓰면 가장 상위의 인덱스를 지정한 것과 같다.

Cidx1AB
Cidx2CDCD
Ridx2
id_11.76 0.40 0.98 2.24
id_21.87 -0.98 0.95 -0.15
id_3-0.10 0.41 0.14 1.45

특정 레벨의 모든 인덱스 값을 인덱싱할 때는 슬라이스를 사용한다. 다만 다중 인덱스의 튜플 내에서는 : 슬라이스 기호를 사용할 수 없고 대신 slice(None) 값을 사용해야 한다.

df4.loc[("M", slice(None)), :]

Cidx1AB
Cidx2CDCD
Ridx1Ridx2
Mid_11.76 0.40 0.98 2.24
id_21.87 -0.98 0.95 -0.15
id_3-0.10 0.41 0.14 1.45

df4.loc[(slice(None), "id_1"), :]

Cidx1AB
Cidx2CDCD
Ridx1Ridx2
Mid_11.76 0.40 0.98 2.24
Fid_10.76 0.12 0.44 0.33

다중 인덱스의 인덱스 순서 교환¶

다중 인덱스의 인덱스 순서를 바꾸고 싶으면 swaplevel 명령을 사용한다.

  • swaplevel(i, j, axis)

ij는 교환하고자 하는 인덱스 라벨(혹은 인덱스 번호)이고 axis는 0일 때 행 인덱스, 1일 때 열 인덱스를 뜻한다. 디폴트는 행 인덱스이다.

df5 = df4.swaplevel("Ridx1", "Ridx2")
df5

Cidx1AB
Cidx2CDCD
Ridx2Ridx1
id_1M1.76 0.40 0.98 2.24
id_2M1.87 -0.98 0.95 -0.15
id_3M-0.10 0.41 0.14 1.45
id_1F0.76 0.12 0.44 0.33
id_2F1.49 -0.21 0.31 -0.85
id_3F-2.55 0.65 0.86 -0.74
AllAll3.23 0.39 3.68 2.28

df6 = df4.swaplevel("Cidx1", "Cidx2", 1)
df6

Cidx2CDCD
Cidx1AABB
Ridx1Ridx2
Mid_11.76 0.40 0.98 2.24
id_21.87 -0.98 0.95 -0.15
id_3-0.10 0.41 0.14 1.45
Fid_10.76 0.12 0.44 0.33
id_21.49 -0.21 0.31 -0.85
id_3-2.55 0.65 0.86 -0.74
AllAll3.23 0.39 3.68 2.28

다중 인덱스가 있는 경우의 정렬¶

다중 인덱스가 있는 데이터프레임을 sort_index로 정렬할 때는 level 인수를 사용하여 어떤 인덱스를 기준으로 정렬하는지 알려주어야 한다.

Cidx1AB
Cidx2CDCD
Ridx2Ridx1
AllAll3.23 0.39 3.68 2.28
id_1F0.76 0.12 0.44 0.33
M1.76 0.40 0.98 2.24
id_2F1.49 -0.21 0.31 -0.85
M1.87 -0.98 0.95 -0.15
id_3F-2.55 0.65 0.86 -0.74
M-0.10 0.41 0.14 1.45

df6.sort_index(axis=1, level=0)

Cidx2CD
Cidx1ABAB
Ridx1Ridx2
Mid_11.76 0.98 0.40 2.24
id_21.87 0.95 -0.98 -0.15
id_3-0.10 0.14 0.41 1.45
Fid_10.76 0.44 0.12 0.33
id_21.49 0.31 -0.21 -0.85
id_3-2.55 0.86 0.65 -0.74
AllAll3.23 3.68 0.39 2.28

연습 문제 4.5.2

A 반 학생 5명과 B반 학생 5명의 국어, 영어, 수학 점수를 나타내는 데이터프레임을 다음과 같이 만든다.

  1. “반”, “번호”, “국어”, “영어”, “수학” 을 열로 가지는 데이터프레임 df_score3을 만든다.

  2. df_score3을 변형하여 1차 행 인덱스로 “반”을 2차 행 인덱스로 “번호”을 가지는 데이터프레임 df_score4을 만든다.

  3. 데이터 프레임 df_score4에 각 학생의 평균을 나타내는 행을 오른쪽에 추가한다.

  4. df_score3을 변형하여 행 인덱스로 “번호”를, 1차 열 인덱스로 “국어”, “영어”, “수학”을, 2차 열 인덱스로 “반”을 가지는 데이터프레임 df_score5을 만든다.

  5. 데이터 프레임 df_score5에 각 반별 각 과목의 평균을 나타내는 행을 아래에 추가한다.