다운로드
작성자: admin 작성일시: 2016-07-08 23:58:23 조회수: 29447 다운로드: 469
카테고리: Python 태그목록:

데이터프레임 고급 인덱싱

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

  • loc : 라벨값 기반의 2차원 인덱싱
  • iloc : 순서를 나타내는 정수 기반의 2차원 인덱싱
  • at: 라벨값 기반의 2차원 인덱싱 (한개의 스칼라 값만 찾는다)
  • iat : 순서를 나타내는 정수 기반의 2차원 인덱싱 (한개의 스칼라 값만 찾는다)

loc 인덱서

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

df.loc[행 인덱싱값]

또는

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

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

  • 인덱스데이터
  • 인덱스데이터 슬라이스
  • 인덱스데이터 리스트
  • 같은 행 인덱스를 가지는 불리언 시리즈 (행 인덱싱의 경우)
  • 또는 위의 값들을 반환하는 함수

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

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

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

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

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

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

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

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

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

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

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

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

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

In [6]:
# df[["b", "c"]]  # KeyError

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

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

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

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

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

In [12]:
# df.loc["A"]  # KeyError
In [13]:
# df.loc[["A", "B"]]  # KeyError

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

In [14]:
df2 = pd.DataFrame(np.arange(10, 26).reshape(4, 4), columns=["A", "B", "C", "D"])
df2
Out:
A B C D
0 10 11 12 13
1 14 15 16 17
2 18 19 20 21
3 22 23 24 25
In [15]:
df2.loc[1:2]
Out:
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인 위치의 값을 구하는 것은 다음과 같다.

In [16]:
df.loc["a", "A"]
Out:
10

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

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

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

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

iloc 인덱서

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

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

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

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

연습 문제 1

  1. 모든 행과 열에 라벨을 가지는 5 x 5 이상의 크기를 가지는 데이터프레임을 만든다.
  2. 10가지 이상의 방법으로 특정한 행과 열을 선택한다.

at, iat 인덱서

at, iat 인덱서는 loc, iloc 인덱서와 비슷하지만 하나의 스칼라 값을 뽑을 때만 사용한다. 빠른 인덱싱 속도가 요구되는 경우에 사용한다.

In [27]:
%timeit df.loc["a", "A"]
8.63 µs ± 368 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [28]:
%timeit df.at["a", "A"]
5.33 µs ± 197 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [29]:
%timeit df.iloc[0, 0]
9.69 µs ± 408 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [30]:
%timeit df.iat[0, 0]
6.15 µs ± 126 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

질문/덧글

label 미지정시 than*** 2016년 7월 19일 5:40 오후

Label이 지정되지 않는 경우에는 integer slicing을 label slicing으로 간주하여 마지막 값을 포함한다

df.columns = ["c1", "c2", "c3"]
df.ix[0:2, 1:2]

이렇게 코딩을 한 경우 마지막값을 포함하려면
row는 0,1,2 <-- 이렇게 표기되고
column은 1,2 <-- 이렇게 표기되는게 맞는거같은데

column의 경우 마지막값인 2만 나오고 1은 출력되지 않는데 제가 무얼 놓치고 있는건가요?

답변: label 미지정시 관리자 2016년 7월 19일 9:38 오후

row index 의 경우에는 인덱스가 라벨인지 정수인지 알 수 없기 때문에 라벨로 가정하여 0, 1, 2 행이 표시됩니다.
column index 의 경우에는 라벨일 아니라 정수라는 것이 명확하므로 하나만 나오게 됩니다.