본문 바로가기
C.W.K.
Stream
Lesson 04 of 07 · published

Selection, Filtering, 그리고 .loc / .iloc 함정

~13 min · pandas, indexing, loc, iloc, gotcha

Level 0구경꾼
0 XP0/47 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

Pandas 에서 제일 헷갈리는 게 뭐냐면 원하는 row 와 column 을 어떻게 고르느냐야. 라이브러리는 indexing 스타일을 세 가지나 내놓고, 초보자는 그걸 머릿속에서 섞다가 에러 한 줄 없이 틀린 답을 만들어. 기준 하나 줄게.

세 indexer

  • df['col'] — label 로 column 하나 집기. Series 반환.
  • df.loc[row_label, col_label]label 기반 selection. Row 와 column 둘 다 label (또는 boolean mask) 로 지정.
  • df.iloc[row_pos, col_pos]position 기반 selection. Row 와 column 둘 다 정수 위치로 지정 — NumPy 배열 다루듯이.

.loc 은 label, .iloc 은 position — 머릿속에서 절대 섞지 마. Legacy df.ix 는 사라졌어. df[df.col > 0]['other'] = ... 같은 chained indexing 은 SettingWithCopyWarning 의 원조인데, Pandas 3.0 이 Copy-on-Write 의미론으로 그 나사를 한층 더 죄었어.

Copy-on-Write 시대

Pandas 3.0 은 Copy-on-Write (CoW) 를 기본으로 켰어. 실제 효과는 이래: 부모 DataFrame 을 몰래 고치던 chained 할당이 이제는 copy 를 고치거나 (그래서 변경이 증발하거나) 명확한 에러를 raise 해. 고치는 방법은 예나 지금이나 하나야 — 할당의 왼쪽에 row 와 column 이 둘 다 들어간 단일 .loc.

Code

Filter 와 할당의 옳고 그른 방법·python
import pandas as pd

df = pd.DataFrame({
    'order_id':   ['A001', 'A002', 'A003', 'A004'],
    'amount_usd': [120.50,   87.30, 215.00,    9.99],
    'status':     ['shipped', 'pending', 'shipped', 'cancelled'],
})

# Label 기반 row select (boolean mask 도 label index 의 일종)
shipped = df.loc[df['status'] == 'shipped']                       # status 가 'shipped' 인 row
shipped_amounts = df.loc[df['status'] == 'shipped', 'amount_usd'] # amount column 만

# Position 기반 — 첫 2 row, 첫 2 column
topleft = df.iloc[:2, :2]

# WRONG — chained 할당, Pandas 3.0 CoW 아래에서 fail 또는 no-op
# df[df['status'] == 'pending']['amount_usd'] = 0      # ← 이러지 마

# RIGHT — row 와 column 둘 다 주소된 단일 .loc
df.loc[df['status'] == 'pending', 'amount_usd'] = 0

# Boolean mask 결합은 & | (괄호 필수)
big_or_pending = df.loc[(df['amount_usd'] > 100) | (df['status'] == 'pending')]

External links

Exercise

위 예시 DataFrame 을 만들어. .loc 만 써서 (chained indexing 없이) status'cancelled' 인 모든 row 의 amount_usd0 으로 바꿔 봐. 그다음 df.query() 로 amount 가 50 ~ 200 사이인 row 를 전부 가져와.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.