4.3 데이터프레임 고급 인덱싱

데이터프레임에서 특정한 데이터만 골라내는 것을 인덱싱(indexing)이라고 한다. 앞 절에서는 라벨, 라벨 리스트, 인덱스데이터(정수) 슬라이스의 3가지 인덱싱 값을 사용하여 인덱싱을 하는 방법을 공부하였다. 그런데 Pandas는 numpy행렬과 같이 쉼표를 사용한 (행 인덱스, 인덱스) 형식의 2차원 인덱싱을 지원하기 위해 다음과 같은 특별한 인덱서(indexer) 속성도 제공한다.

  • loc : 라벨값 기반의 2차원 인덱싱

  • iloc : 순서를 나타내는 정수 기반의 2차원 인덱싱

loc 인덱서

loc 인덱서는 다음처럼 사용한다.

df.loc[ 인덱싱값]

또는

df.loc[ 인덱싱값,  인덱싱값]

이 때 인덱싱 값은 다음 중 하나이다. 행 인덱싱값은 정수 또는 행 인덱스데이터이고 열 인덱싱값은 라벨 문자열이다.

  • 인덱스데이터

  • 인덱스데이터 슬라이스

  • 인덱스데이터 리스트

  • 같은 행 인덱스를 가지는 불리언 시리즈 (행 인덱싱의 경우)

  • 또는 위의 값들을 반환하는 함수

다음과 같은 데이터프레임을 예로 들자.

df = pd.DataFrame(np.arange(10, 22).reshape(3, 4),
                  index=["a", "b", "c"],
                  columns=["A", "B", "C", "D"])
df
A B C D
a 10 11 12 13
b 14 15 16 17
c 18 19 20 21

인덱싱값을 하나만 받는 경우

만약 loc 인덱서를 사용하면서 인덱스를 하나만 넣으면 행(row)을 선택한다.

인덱스데이터가 “a”인 행을 고르면 해당하는 행이 시리즈로 출력된다. 시리즈라서 상하로 길게 출력되기는 했지만 행을 가져오고 있다.

df.loc["a"]
A    10
B    11
C    12
D    13
Name: a, dtype: int64

인덱스데이터의 슬라이스도 가능하다.

df.loc["b":"c"]
A B C D
b 14 15 16 17
c 18 19 20 21

이 때는 사실 loc를 쓰지 않는 경우과 같다.

df["b":"c"]
A B C D
b 14 15 16 17
c 18 19 20 21

인덱스데이터의 리스트도 된다.

df.loc[["b", "c"]]
A B C D
b 14 15 16 17
c 18 19 20 21

이 때는 loc를 쓰지 않으면 KeyError 오류가 발생한다..

# df[["b", "c"]]  # KeyError

데이터베이스와 같은 인덱스를 가지는 불리언 시리즈도 행을 선택하는 인덱싱값으로 쓸 수 있다.

df.A > 15
a    False
b    False
c     True
Name: A, dtype: bool
df.loc[df.A > 15]
A B C D
c 18 19 20 21

인덱스 대신 인덱스 값을 반환하는 함수를 사용할 수도 있다. 다음 함수는 A열의 값이 12보다 큰 행만 선택한다.

def select_rows(df):
    return df.A > 15
select_rows(df)
a    False
b    False
c     True
Name: A, dtype: bool
df.loc[select_rows(df)]
A B C D
c 18 19 20 21

loc 인덱서가 없는 경우에 사용했던 라벨 인덱싱이나 라벨 리스트 인덱싱은 불가능하다.

# df.loc["A"]  # KeyError
# df.loc[["A", "B"]]  # KeyError

원래 (행) 인덱스값이 정수인 경우에는 슬라이싱도 라벨 슬라이싱 방식을 따르게 된다. 즉, 슬라이스의 마지막 값이 포함된다.

df2 = pd.DataFrame(np.arange(10, 26).reshape(4, 4), columns=["A", "B", "C", "D"])
df2
A B C D
0 10 11 12 13
1 14 15 16 17
2 18 19 20 21
3 22 23 24 25
df2.loc[1:2]
A B C D
1 14 15 16 17
2 18 19 20 21

정리하면 다음과 같다.

인덱싱 값

가능

결과

자료형

추가사항

행 인덱스값(정수)

O

시리즈

행 인덱스값(정수) 슬라이스

O

데이터프레임

loc가 없는 경우와 같음

행 인덱스값(정수) 리스트

O

데이터프레임

불리언 시리즈

O

데이터프레임

시리즈의 인덱스가 데이터프레임의 행 인덱스와 같아야 한다.

불리언 시리즈를 반환하는 함수

O

데이터프레임

열 라벨

X

loc가 없는 경우에만 쓸 수 있다.

열 라벨 리스트

X

loc가 없는 경우에만 쓸 수 있다.

인덱싱값을 행과 열 모두 받는 경우

인덱싱값을 행과 열 모두 받으려면 df.loc[행 인덱스, 인덱스]와 같은 형태로 사용한다. 행 인덱스 라벨값이 a, 열 인덱스 라벨값이 A인 위치의 값을 구하는 것은 다음과 같다.

df.loc["a", "A"]
10

인덱싱값으로 라벨 데이터의 슬라이싱 또는 리스트를 사용할 수도 있다.

df.loc["b":, "A"]
b    14
c    18
Name: A, dtype: int64
df.loc["a", :]
A    10
B    11
C    12
D    13
Name: a, dtype: int64
df.loc[["a", "b"], ["B", "D"]]
B D
a 11 13
b 15 17

행 인덱스가 같은 불리언 시리즈나 이러한 불리언 시리즈를 반환하는 함수도 행의 인덱싱값이 될 수 있다.

df.loc[df.A > 10, ["C", "D"]]
C D
b 16 17
c 20 21

iloc 인덱서

iloc 인덱서는 loc 인덱서와 반대로 라벨이 아니라 순서를 나타내는 정수(integer) 인덱스만 받는다. 다른 사항은 loc 인덱서와 같다.

df.iloc[0, 1]
11
df.iloc[:2, 2]
a    12
b    16
Name: C, dtype: int64
df.iloc[0, -2:]
C    12
D    13
Name: a, dtype: int64
df.iloc[2:3, 1:3]
B C
c 19 20

loc 인덱서와 마찬가지로 인덱스가 하나만 들어가면 행을 선택한다.

df.iloc[-1]
A    18
B    19
C    20
D    21
Name: c, dtype: int64
df.iloc[-1] = df.iloc[-1] * 2
df
A B C D
a 10 11 12 13
b 14 15 16 17
c 36 38 40 42

연습 문제 4.3.1

  1. 모든 행과 열에 라벨을 가지는 5 x 5 이상의 크기를 가지는 데이터프레임을 만든다.

  2. 10가지 이상의 방법으로 특정한 행과 열을 선택한다.