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 |
행 |
데이터프레임 |
|
행 인덱스값(정수) 리스트 |
O |
행 |
데이터프레임 |
|
불리언 시리즈 |
O |
행 |
데이터프레임 |
시리즈의 인덱스가 데이터프레임의 행 인덱스와 같아야 한다. |
불리언 시리즈를 반환하는 함수 |
O |
행 |
데이터프레임 |
|
열 라벨 |
X |
|
||
열 라벨 리스트 |
X |
|
인덱싱값을 행과 열 모두 받는 경우¶
인덱싱값을 행과 열 모두 받으려면 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
모든 행과 열에 라벨을 가지는 5 x 5 이상의 크기를 가지는 데이터프레임을 만든다.
10가지 이상의 방법으로 특정한 행과 열을 선택한다.