본문 바로가기
목차
Python/pandas

[Pandas] Indexer - loc, iloc, at, iat

by ds31x 2025. 8. 22.
728x90
반응형

Pandas의 Indexer란?

Indexer(인덱서)는

  • "값(value) 그 자체를 조건으로 삼아 접근하거나 필터링하는 방식"과는 달리,
  • 라벨(label)이나 정수 위치(index 번호)를 기반으로 해석하여 데이터를 선택하거나 필터링하는 도구임.

다시 말해, DataFrame/Series에 부착된 indexing에 사용되는 일종의 accessor로,

라벨(label)이나 정수 위치(index 번호)를 해석해 데이터를 선택하거나 필터링하는 데 사용(indexing)된다.

  • 주요 역할: 사용자가 지정한 키(key)를 어떤 규칙(라벨 기반 또는 위치 기반)으로 해석할지 결정.
  • 종류: loc, iloc, at, iat 등이 있으며, 각각 라벨 기반/위치 기반, 단일/다중 접근 용도로 나뉨.

 

Pandas의 공식 문서 기준으로 정리하면:

  • Indexer는 인덱싱 동작에 사용되는 accessor로, loc, iloc, at, iat 등이 해당.
  • Pandas에서 애기하는 Accessor는 특정 dtype 전용 메서드를 제공하는 인터페이스로, .str, .dt, .cat 등이 있음.

따라서 Indexer는 넓은 의미에서 accessor의 한 종류이지만, pandas 문서에서는 인덱싱 인터페이스로 따로 구분하고 있음.


0. 기본 준비

다음 코드는 실습에 사용할 간단한 DataFrame을 생성함.
이후의 예제들은 모두 이 DataFrame을 기반으로 동작함.

import pandas as pd

# (예제 공통) 테스트용 DataFrame 생성
df = pd.DataFrame(
    {
        "name": ["A", "B", "C", "D"],   # column 라벨 'name'
        "score": [10, 20, 30, 40],      # column 라벨 'score'
        "grp": ["x", "x", "y", "y"],    # column 라벨 'grp'
    }
)
# 별도의 인덱스를 주지 않았으므로 df.index에는 RangeIndex 객체가 자동 부여됨 (0,1,2,3)

맨 왼쪽의 숫자로 구성된 이름없는 column이 RangeIndex객체로 설정된 df.index

 


1. Index와 Indexer

Pandas의 indexer인 loc, iloc, at, iat 를 이해하기 위해 필요한 기본 개념들은 다음과 같음:

1-1. Index (인덱스)

DataFrame/Series의 axis(축)에 붙은 라벨들의 집합을 표현하는 클래스(Index 및 그 서브클래스).
이 클래스는 DataFrame의 row와 column을 구분하기 위해 사용되는 라벨 시스템을 제공한다.

Pandas에서 Index클래스 객체의 예를 들면,

  • df.indexrow 라벨들의 Index 객체 이며,
  • df.columnscolumn 라벨들의 Index 객체 임.

Index클래스의 요소인 label은 중복 허용 임: 같은 라벨이 Index 내에서 여러 번 등장할 수 있으며, 반드시 고유할 필요는 없음.

  • 대표적인 Index 서브클래스 (모두 Index 슈퍼클래스를 상속):
    • RangeIndex: 0..n-1 등 단조 증가 정수일 때 자동 생성되는 특수 인덱스(메모리 효율)
    • Int64Index: 임의의 정수 라벨
    • Float64Index: 실수 라벨
    • Index(object): 문자열 등 일반 객체 라벨 (별도의 서브클래스가 아니라 기본 Index 클래스의 인스턴스)
    • DatetimeIndex: 시계열 라벨
    • CategoricalIndex: 범주형 라벨
    • MultiIndex: 계층적 라벨
type(df.index) # pandas.core.indexes.range.RangeIndex 
               # (명시적 index 지정하지 않은 경우, 기본index)

df2 = df.set_index("name")  # 'name' column을 row 인덱스로 사용
type(df2.index)             # pandas.core.indexes.base.Index 
                            # (dtype=object; 문자열 라벨)

1-2. Label (라벨)

라벨(Label) 은 DataFrame/Series의 각 축(Columns, Index)에 붙은 개별 이름값을 의미함.

  • 정수, 문자열, 날짜 등 해시 가능한 값이어야 Label로 사용 가능: Immutable and Hashable.
  • row와 column을 구분하고 접근할 때 사용됨.
  • 단, 중복을 허용함.

2024.05.21 - [개발환경] - [CE] Hash Algorithm

 

[CE] Hash Algorithm

Hash란?Hash 는 임의의 크기를 가진 데이터를 고정된 크기의 (고유한) 데이터로 변환하는 방법 임.이 변환 과정은 Hash Algorithm에 의해 명확하게 정의됨.Hash Algorithm을 통해 생성된 해시 값(Hash, Hash Valu

ds31x.tistory.com


1-3. Indexer (인덱서)

DataFrame/Series에 부착된 indexing을 위한 특수한 접근자 객체.

  • [] 안에 들어온 키(key)
  • row/column 선택 연산으로 변환 한다.

종류는 다음과 같음:

  • loc: 라벨(label) 기반 multi-axis(다축) 선택 (슬라이스 끝 포함)
  • iloc: 정수 위치(position) 기반 multi-axis(다축) 선택 (슬라이스 끝 제외)
  • at: 라벨 기반 단일 스칼라 최적화(읽기/쓰기)
  • iat: 위치 기반 단일 스칼라 최적화(읽기/쓰기)

각각의 클래스는 다음과 같음:

print(type(df.loc))    # <pandas.core.indexing._LocIndexer>  object
print(type(df.iloc))   # <pandas.core.indexing._iLocIndexer>  object

1-4. df[...] (__getitem__()) : Column에 접근 및 추출

위 제목에서 [...]는 square brackets 를 이용하는 indexing key를 의미함.

  • df['col']DataFrame 객체의 __getitem__()이 구현한 “column 선택”임: Indexer가 아님.
  • df.loc[...]/df.iloc[...]Indexer 객체의 __getitem__() special method가 동작함.

아래의 5번 항목을 참고.

주의할 점은 Indexer에선 row에 대한 지정이 요구된다는 점임.

 


2. loc — 라벨(label) 기반 인덱서

loc은
기존 데이터의 수정 및 편집,
새로운 레코드(행) 추가가 가능하다.

  • 라벨(label): 인덱스/column 축에 붙은 이름값(정수/문자열/날짜 등).
    • df.index에 기본 할당된 RangeIndex의 0,1,2,…도 라벨 임!
  • 주의할 점은 slicing에서 끝 라벨 포함(inclusive).

주요 용도:

  • label을 기반으로 특정 row나 column에 접근하거나,
  • label을 기반으로 조건에 맞는 row들을 필터링.
  • 새로운 레코드 추가 가능: 새로운 라벨에 값을 할당하면 존재하지 않던 row가 추가됨.

딱히 다른 label을 사용하도록 특정 column을 index로 지정하거나, 생성시 index를 따로 지정하지 않은 경우 RangeIndex가 index임.

이 경우, 새로운 record(or row) 의 추가는 다음과 같이 len()함수를 이용하면 됨.

복수 개의 row를 추가하는 경우는 concat() 함수 또는 메서드 를 사용한다.

 

다음은 맨 끝의 row를 복제하여 새로운 row로 추가하는 코드임:

df.loc[len(df)] = df.iloc[-1].copy() # 권장.
df.loc[len(df)] = df.iloc[-1]  # 일반적으로 사용가능하나,
                               # SettingWithCopyWarning이 발생할 수도 있음.

2-1. 사용 패턴

# 단일 row·단일 column (라벨 기반)
df.loc[1, "score"]    # 라벨 1 row의 'score' 값 → 20

# 단일 row·다중 column (column 라벨 리스트)
df.loc[2, ["name", "grp"]]   # 라벨 2 row의 'name','grp' column 선택

# 다중 row·다중 column (row/column 라벨 리스트)
df.loc[[1, 3], ["name", "score"]]   # 라벨 1,3 row의 'name','score' column 선택

 

# 라벨 slicing (끝 포함)
df.loc[1:2, "name":"grp"]   # 라벨 1~2 row × 'name'~'grp' column 선택

 

# boolean mask or boolean indexing
mask = df["score"] >= 20 # masks는 Series객체임.
df.loc[mask, ["name", "score"]]   # 'score'>=20 조건 만족 row × 'name','score' column 선택

loc라벨기반 인덱서이기 때문에 boolean mask는 boolean 값들을 가지는 Series객체로 처리됨. 

 

주의:

  • 복수의 조건을 사용시 and가 아닌 bitwise연산자(Series객체의 bit는 element가 됨)로 &,| 를 사용해야함:
  • df[(df["grp"]=="x")& (df["score"]>20)]
# boolean mask 는 보통 row 선택에 많이 쓰이지만, 
# column 선택에도 boolean mask를 지정해 활용할 수 있다.
col_mask = [True, False, True]  # 'name'과 'grp'만 선택. ndarray나 list객체도 boolean mask가능.
df.loc[:, col_mask]             # 특정 column 선택 (column 마스크)

# 새로운 row 추가
df.loc[4] = ["E", 50, "z"]   # 라벨 4가 없으므로 새로운 row 추가
df


2-2. 값 할당

# 단일 값 쓰기
df.loc[1, "score"] = 25   # 라벨 1 row의 'score'를 25로 수정

 

# 조건부 쓰기
df.loc[df["grp"] == "y", "score"] += 100   # 'grp'가 y인 row들의 'score' 값에 100 더하기

# 새 column 추가
df.loc[:, "passed"] = df["score"] >= 30   # 'score'>=30 여부를 새로운 column 'passed'로 추가

 

 

2-5. 중복 라벨

g = df.set_index("grp")
g.loc["x"]   # 라벨 'x'인 모든 row 반환 (2행: name=A,B)

가능하지만, 가급적 중복 라벨은 권하지 않음.


3. iloc — 위치(position) 기반 인덱서

iloc은
기존 데이터의 수정 및 편집이 가능하나,
새로운 row 추가는 불가.

  • row/column의 0부터 시작하는 정수 위치(position)를 사용.
    • loc에서 사용하는 인덱스 라벨과 무관.
  • slicing에서 끝 제외 모드임(exclusive로 python의 slicing과 동일).

주요 용도:

  • 정수 위치(integer position)를 기반으로 특정 row나 column에 접근하거나,
  • 정수 위치를 기반으로 조건에 맞는 row들을 필터링하는 데 사용됨.
  • 존재하지 않는 위치에는 접근할 수 없어 새로운 row 추가는 불가능: loc과의 가장 큰 차이점 중 하나임.

3-1. 사용 패턴

# 단일 위치
df.iloc[1, 1]       # row 위치 1 × column 위치 1

# 위치 슬라이스
df.iloc[0:2, 0:2]   # row 위치 0,1 × column 위치 0,1 → 부분 DataFrame(name,score)

# boolean mask (numpy ndarray)
mask = (df["score"] >= 20).values
df.iloc[mask, [0, 1]]   # 'score'>=20 조건 만족 row × column 위치 0,1(name,score)

3-2. 값 할당

df.iloc[1, 1] = 26   # row 위치 1, column 위치 1의 값을 26으로 수정

 

iloc은
새로운 row 추가는 불가하지만,
기존 데이터의 편집은 가능하다.

3-3. 새로운 row 추가 불가

df.iloc[2] = ["C", 30, "z"]   # 존재하지 않는 위치 2 → IndexError 발생


4. at / iat — 단일 스칼라 값 접근에 최적화

at/iat 역시
기존 데이터의 수정 및 편집에 사용가능.

단일 원소에 대한 잦은 접근/수정은 at/iat가 대체로 loc/iloc보다 빠르다.
(하지만 많이 이용되는 편은 아님.)

 

주요 용도:

  • 단일 스칼라 원소에 빠르게 접근하거나 수정할 때 사용된다.
  • 반드시 존재하는 라벨(at)이나 위치(iat)에 대해서만 동작한다.
# at: 라벨 기반 단일 원소
df.at[1, "score"]        # 라벨 1 row의 'score' 읽기
df.at[1, "score"] = 27   # 라벨 1 row의 'score'를 27로 수정

# iat: 위치 기반 단일 원소
df.iat[0, 1]             # row 위치 0, column 위치 1의 값 읽기
df.iat[0, 1] = 11        # row 위치 0, column 위치 1의 값을 11로 수정

5. df[...] — column 선택 (getitem())

DataFrame객체에서 [...]column 선택 및 추출에 사용된다. 주의할 것.

  • df["col"]: 단일 column 선택 → Series 반환
  • df[["c1", "c2"]]: 여러 column 선택 → DataFrame 반환
  • df[mask]: mask는 row와 길이가 같은 boolean mask로 row 필터링에 사용됨.
df["name"]             # 'name' column만 Series로 반환

df[["name", "score"]]  # 'name','score' column을 DataFrame으로 반환

df[df["score"]>=20]    # 'score'>=20 조건 만족 row 필터링 **

row 선택에 일반 [...]는 권장하지 않음.
단, boolean mask의 경우 예외임.
주로 column 선택임을 기억할 것.


6. RangeIndex와 set_index/reset_index

RangeIndex: DataFrame 생성 시 자동 부여되는 특수 인덱스 객체의 클래스.

  • 단, 명시적으로 특정 column을 인덱스(=df.index)로 지정하면 RangeIndex는 사라지고 dtype에 맞는 Index로 교체.
    • set_index(column_label_str): 인자로 주어진 column name(or label)을 df.index로 지정.
  • reset_index(): 현재 인덱스를 일반 column으로 되돌리거나(default) 또는 삭제(drop=True 로 argument넘긴 경우)하고, 새 RangeIndex를 부여.
df.index   # RangeIndex(start=0, stop=4, step=1)

 

df2 = df.set_index("score")   # 'score' column을 인덱스로 지정
type(df2.index)               # Int64Index (정수 인덱스)

# reset_index() 사용 예
df3 = df2.reset_index()       # 'score'가 다시 일반 column으로 이동하고 RangeIndex 부여
df3.head()                    # 확인용 미리보기

 

2023.09.20 - [Python/pandas] - [Pandas] Index 지정 관련 메서드 : reset_index, set_index

 

[Pandas] Index 지정 관련 메서드 : reset_index, set_index

DataFrame 인스턴스에서 index를 새로 만들거나 다른 columns 를 index로 지정하는데 사용된다.reset_indexDataFrame 인스턴스에서 기존 index 대신하는 새로운 index를 만든다.drop 파라메터의 값을True로 지정한

ds31x.tistory.com


7. 삭제 (row/column)

인덱서를 직접 사용해 삭제하는 기능은 없음.

drop() 메서드를 사용해 라벨을 기준으로 row/column을 삭제하는 방법이 일반적

대신 인덱서의 경우,
특정 조건이나 슬라이싱을 통해 원하는 row/column을 선택한 후,
그 결과를 다시 df에 덮어쓰는 방식으로 사실상 삭제 효과를 낼 수 있음.

# 조건 기반으로 특정 row 삭제 효과 (score < 20 인 row 제거)
df = df.loc[df["score"] >= 20]
df

# iloc을 이용한 row 삭제 효과 (첫 번째 row 제거)
df = df.iloc[1:]
df

다음은 drop() 메서드를 사용하는 예임:

# 조건 기반으로 특정 row 삭제 효과 (score < 20 인 row 제거)
df = df.loc[df["score"] >= 20]

# iloc을 이용한 row 삭제 효과 (첫 번째 row 제거)
df = df.iloc[1:]

# drop() 메서드를 이용한 row 삭제
df = df.drop(1, axis=0)   # 라벨 1 row 삭제

# drop() 메서드를 이용한 column 삭제
df = df.drop("score", axis=1)   # 'score' column 삭제

2024.01.09 - [Python/pandas] - [pandas] Column (or rows) 제거하기

 

[pandas] Column (or rows) 제거하기

DataFrame 에서 column을 제거하는데에 사용되는 idiomatic approach는 drop 메서드를 사용하는 것임. 사실 drop은 axis라는 parameter를 가지고 있고,0이 주어지면 row를 지우고,1이 주어지면 column을 지움.첫번째

ds31x.tistory.com


8. loc/iloc/at/iat 패턴 정리

  • 단일 원소
    • loc[r, c], iloc[i, j]
    • 최적화: at[r, c], iat[i, j]
  • 다중 원소(리스트)
    • 라벨: df.loc[[r1, r2], [c1, c2]]
    • 위치: df.iloc[[i1, i2], [j1, j2]]
  • slicing
    • loc[r1:r2, c1:c2] (끝 포함, inclusive)
    • iloc[i1:i2, j1:j2] (끝 제외, exclusive)
  • boolean mask
    • df.loc[mask, cols]
    • df.iloc[mask.values, pos]
  • 쓰기(할당)
    • df.loc[cond, col] = val
    • df.iloc[i, j] = val
  • 중복 라벨의 경우
    • loc["dup"]는 여러 row 반환 가능
    • iloc은 위치 기반이라 중복 라벨에 상관 없음

9. MultiIndex 예시

MultiIndex여러 column을 조합하여 계층적인 인덱스를 구성하는 기능을 가리킴.

  • 복잡한 데이터 구조를 표현
  • 다차원 인덱싱 을 지원.
df = pd.DataFrame(
    {
        "name": ["A", "B", "C", "D"],   # column 라벨 'name'
        "score": [10, 20, 30, 40],      # column 라벨 'score'
        "grp": ["x", "x", "y", "y"],    # column 라벨 'grp'
    }
)

h = df.set_index(["grp", "name"])   # 두 column을 계층적 인덱스로 설정
h.loc[("x", "A")]                   # (grp='x', name='A') row 선택 (라벨 튜플)
h.iloc[0]                           # 첫 번째 row 선택 (위치)

 

# 상위 라벨 'y' 전체 선택 (하위는 모두)
h.loc[("y", slice(None)), :]

 


10. 시각 자료 (ASCII 다이어그램)

          +-------------------+
DataFrame |        df         |
          +-------------------+
            |             |
            v             v
        df.index      df.columns
     (row 라벨 집합)    (column 라벨 집합)
            |             |
     <Index subclass> <Index subclass>
   (RangeIndex, ...)   (Index, ...)
            ^
            |
   set_index(...)로 column을
   row 라벨로 승격시키면
   해당 dtype에 맞는 Index로 변환

11. 요약

  • df.index = row 라벨(Index 클래스 인스턴스)
  • df.columns = column 라벨(Index 클래스 인스턴스)
  • loc: 라벨 기반, 슬라이스 끝 포함, 기존 데이터 편집 가능, 새로운 row 추가 가능
  • iloc: 위치 기반, 슬라이스 끝 제외, 기존 데이터 편집 가능, 새로운 row 추가 불가
  • at/iat: 단일 스칼라 최적화(읽기/쓰기), 기존 데이터 편집 가능, 새로운 row/column 추가 불가
  • df[...]: column 선택을 담당하는 __getitem__ 규칙(인덱서 아님). row 선택은 주로 boolean mask 또는 loc/iloc 사용
  • 인덱스 라벨 중복 가능: loc은 여러 row를 반환할 수 있으며, iloc은 위치 기반이라 영향 없음
  • set_index/reset_index: 라벨 구조 전환과 복구
  • 삭제: 인덱서를 직접 이용한 삭제는 불가. 조건/슬라이싱 후 재할당 또는 drop() 메서드 사용
728x90