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

데이터프레임 인덱서

Pandas는 numpy행렬과 같이 쉼표를 사용한 (행 인덱스, 열 인덱스) 형식의 2차원 인덱싱을 지원하기 위해 다음과 같은 특별한 인덱서(indexer)를 제공한다.

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

loc 인덱서

loc 인덱서를 사용할 때는 행/열 인덱스들이 모두 다음 중 하나이어야 한다.

  • 정수 인덱스가 아닌 라벨 값(원래 인덱스 자체가 정수 인덱스인 경우는 예외적으로 허용)
  • 라벨 값의 리스트나 슬라이싱
  • 불리언 리스트, 1차원 배열, 시리즈 (데이터프레임은 안된다.)
  • 또는 데이터프레임을 입력으로 받고 위의 값을 반환하는 함수

다음과 같은 데이터프레임이 있을 때,

In:
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 인덱서를 사용하려면 df.loc[행 인덱스, 열 인덱스]와 같은 형태로 사용한다. 행 인덱스 라벨값이 a, 열 인덱스 라벨값이 A인 위치의 값을 구하는 것은 다음과 같다.

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

라벨값의 슬라이싱 또는 리스트를 사용할 수도 있다.

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

loc 인덱서를 사용하면 하나의 행을 시리즈 자료형으로 뽑아낼 수도 있다.

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

만약 loc 인덱서를 사용하지 않고 하나의 행을 뽑으려면 다음처럼 슬라이싱을 해야 하는데 이때는 데이터프레임 자료형을 반환한다.

In:
df[:1]  # loc 인덱서를 사용하지 않는 경우
Out:
A B C D
a 10 11 12 13

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

In:
def select_rows(df):
    return df.A > 12
In:
select_rows(df)
Out:
a    False
b     True
c     True
Name: A, dtype: bool
In:
df.loc[select_rows(df), ["B"]]
Out:
B
b 15
c 19

인덱서 내의 인덱스 하나로는 1차원 리스트 혹은 시리즈만을 받는다. 데이터프레임과 같은 2차원 데이터는 받을 수 없다.

In:
# df.loc[:, df[:1] <= 11]  # 데이터프레임은 loc 인덱서에 넣을 수 없으므로 에러!
df.loc[:, df.loc["a", :] <= 11] # 이렇게 해야 한다.
Out:
A B
a 10 11
b 14 15
c 18 19

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

In:
df.loc["a"]
Out:
A    10
B    11
C    12
D    13
Name: a, dtype: int64
In:
df.loc["e"] = [90, 91, 92, 93]
df
Out:
A B C D
a 10 11 12 13
b 14 15 16 17
c 18 19 20 21
e 90 91 92 93

원래 인덱스 자체가 정수값을 가지는 경우에는 loc 인덱서의 인덱스로 정수를 쓸 수 있다. 이때는 정수가 순서를 나타내는 값이 아닐 수 있다.

In:
df2 = pd.DataFrame(np.arange(10, 26).reshape(4, 4), columns=np.arange(1, 8, 2))
df2
Out:
1 3 5 7
0 10 11 12 13
1 14 15 16 17
2 18 19 20 21
3 22 23 24 25
In:
df2.loc[1, 1]
Out:
14

이 때는 슬라이싱도 라벨 슬라이싱 방법을 따르게 된다. 즉, 슬라이스의 마지막 값이 포함된다.

In:
df2.loc[1:2, :]
Out:
1 3 5 7
1 14 15 16 17
2 18 19 20 21

iloc 인덱서

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

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

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

In:
df.iloc[-1]
Out:
A    90
B    91
C    92
D    93
Name: e, dtype: int64
In:
df.iloc[-1] = df.iloc[-1] * 2
df
Out:
A B C D
a 10 11 12 13
b 14 15 16 17
c 18 19 20 21
e 180 182 184 186

연습 문제 1

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

at, iat 인덱서

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

In:
%timeit df.loc["a", "A"]
8.06 µs ± 1.84 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In:
%timeit df.at["a", "A"]
5.91 µs ± 1.2 µs per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In:
%timeit df.iloc[0, 0]
8.91 µs ± 839 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In:
%timeit df.iat[0, 0]
5.27 µs ± 135 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 의 경우에는 라벨일 아니라 정수라는 것이 명확하므로 하나만 나오게 됩니다.