본문으로 건너뛰기
김신건의 로그

[Pandas] replace / astype

· 수정 · 📖 약 1분 · 490자/단어 #python #pandas #replace #astype #dtype #type-casting
Pandas replace / astype, Pandas replace, Pandas astype, 값 치환 pandas, dtype 변환

정의

  • replace(...) : 특정 값을 다른 값으로 치환
  • astype(...) : dtype 변환

dtype 변환 경로

flowchart LR
    OBJ["object/str"] -->|"astype"| INT["int64 / Int64"]
    OBJ -->|"astype"| FLT["float64"]
    OBJ -->|"astype"| CAT["category"]
    OBJ -->|"pd.to_datetime"| DT["datetime64[ns]"]
    OBJ -->|"replace"| OBJ2["새 object 값"]

    INT -->|"astype"| FLT
    FLT -->|"astype"| INT
    INT -->|"astype"| BOOL["bool / boolean"]
    CAT -->|"cat.codes"| INT
    DT -->|"dt.year"| INT

replace 기본

s.replace('A', 'X')                       # 단일 값
s.replace(['A', 'B'], 'X')                # 여러 값을 하나로
s.replace(['A', 'B'], ['X', 'Y'])         # 매핑
s.replace({'A': 'X', 'B': 'Y'})           # dict 매핑
python
import pandas as pd
s = pd.Series(['A', 'B', 'C', 'A', 'B'])
print(s.replace({'A': 1, 'B': 2, 'C': 3}).tolist())
결과
[1, 2, 3, 1, 2]

정규식

s.replace(r'^\s+', '', regex=True)        # 앞 공백 제거
s.replace({r'\d+': 'NUM'}, regex=True)    # 숫자 → 'NUM'

IMPORTANT

pandas 2.0+ 에서 replaceregex 기본값이 False. 정규식 쓰려면 regex=True 명시.

DataFrame.replace

df.replace('?', pd.NA)                                    # 모든 셀
df.replace({'A': {'old': 'new'}})                         # 컬럼별 매핑
df.replace({'name': 'unknown', 'city': 'N/A'}, pd.NA)

NaN 으로 치환

df.replace('', pd.NA)
df.replace(['', '?', '-', 'N/A'], pd.NA)
# [[Pandas dropna / fillna]] 와 조합

str.replace 와의 차이

  • Series.replace : 전체 값 매칭 (정확히 일치)
  • Series.str.replace : 부분 문자열 매칭
s = pd.Series(['hello world', 'world cup'])
s.replace('world', 'X')               # 그대로 (전체 일치 안 함)
s.str.replace('world', 'X')           # 'hello X', 'X cup'

astype 기본

df['age'] = df['age'].astype('int32')
df['code'] = df['code'].astype(str)
df['city'] = df['city'].astype('category')
df['flag'] = df['flag'].astype(bool)

여러 컬럼 한 번에

df = df.astype({
    'id': 'int32',
    'name': 'string[pyarrow]',
    'age': 'Int8',
    'is_active': 'boolean',
})

자주 쓰는 dtype

dtype의미NaN 허용
int8, int16, int32, int64정수
Int8, Int16, Int32, Int64nullable 정수
float32, float64실수✅ (NaN = float)
boolTrue/False
booleannullable bool
object임의 Python 객체 (보통 str)
string[pyarrow]pyarrow 문자열 (효율적)
category카테고리
datetime64[ns]날짜✅ (NaT)
timedelta64[ns]시간 차이✅ (NaT)

int64 vs Int64 (nullable 정수)

import pandas as pd

s_with_nan = pd.Series([1, 2, None, 4])

# int64: NaN 은 float 로 자동 강등
print(s_with_nan.dtype)             # float64 (NaN 때문에)

# Int64: NaN 그대로 유지 가능
s_int64 = s_with_nan.astype('Int64')
print(s_int64.dtype)                # Int64
print(s_int64)                      # 1, 2, <NA>, 4
항목int64Int64
NaN 처리float 로 강등됨pd.NA 유지
메모리동일 (8 bytes)약간 큼 (mask 포함)
연산 속도약간 빠름약간 느림
권장NaN 없는 정수 컬럼NaN 이 있을 수 있는 정수

변환 함정 (errors)

df['x'].astype('int64')               # 변환 실패 시 ValueError
pd.to_numeric(df['x'], errors='coerce')   # 실패 시 NaN
pd.to_numeric(df['x'], errors='ignore')   # 원본 반환

to_numeric, to_datetime, to_timedelta 에는 errors 옵션이 있다.

astype vs to_numeric / to_datetime

# 같은 결과지만 처리 방식 다름
df['x'].astype('int64')                   # 엄격, 실패 시 throw
pd.to_numeric(df['x'], errors='coerce')   # 관대, 실패 → NaN

데이터 클리닝에는 to_numeric / to_datetime 권장.

datetime64 변환

날짜 문자열 컬럼을 datetime 으로 변환하는 패턴:

import pandas as pd

df = pd.DataFrame({'date_str': ['2024-01-01', '2024-02-15', '2024-12-31']})

# 방법 1: pd.to_datetime (권장)
df['date'] = pd.to_datetime(df['date_str'])

# 방법 2: astype (포맷이 표준이면 동작)
df['date'] = df['date_str'].astype('datetime64[ns]')

# 포맷 지정 (비표준 날짜)
df['date'] = pd.to_datetime(df['date_str'], format='%Y-%m-%d')

# 여러 포맷 혼재 (느리지만 안전)
df['date'] = pd.to_datetime(df['date_str'], infer_datetime_format=True)

datetime 변환 후 dt accessor 로 다양한 추출:

df['year']    = df['date'].dt.year
df['month']   = df['date'].dt.month
df['weekday'] = df['date'].dt.day_name()
df['quarter'] = df['date'].dt.quarter

category dtype 으로 메모리 절약

# 실제 메모리 비교
import pandas as pd
import numpy as np

n = 1_000_000
cities = np.random.choice(['Seoul', 'Busan', 'Incheon', 'Daegu'], n)
s_obj = pd.Series(cities)
s_cat = s_obj.astype('category')

print(f'object:   {s_obj.memory_usage(deep=True) / 1e6:.1f} MB')
print(f'category: {s_cat.memory_usage(deep=True) / 1e6:.1f} MB')
# object:   65.0 MB
# category:  4.0 MB (약 16배 절약)

고유값이 적은 문자열 컬럼에 category 를 쓰면 메모리와 groupby 성능 모두 개선된다.

Pandas Categorical 참고.

자주 쓰는 패턴

category 로 메모리 절약

df['city'] = df['city'].astype('category')
df.memory_usage(deep=True)

NaN-aware 정수

df['count'] = df['count'].astype('Int64')   # NaN 가능 정수

bool → 0/1

df['flag_int'] = df['flag'].astype(int)

정수 → 문자 (zfill)

df['code_str'] = df['code'].astype(str).str.zfill(8)
# 12345 → '00012345'

실전 데이터 클리닝 파이프라인

원본 CSV 데이터를 로드하면 대부분 컬럼이 object 로 들어온다. 아래 패턴으로 한 번에 정리:

import pandas as pd

df = pd.read_csv('sales.csv')

# 1. 더미 결측값 교체
df.replace(['', 'N/A', '-', 'null', 'NULL'], pd.NA, inplace=True)

# 2. 수치형 변환 (실패 시 NaN)
df['age']    = pd.to_numeric(df['age'], errors='coerce')
df['price']  = pd.to_numeric(df['price'], errors='coerce')

# 3. 날짜 변환
df['date'] = pd.to_datetime(df['date'], errors='coerce')

# 4. 정수 변환 (NaN 있을 수 있으면 Int64)
df['quantity'] = df['quantity'].astype('Int64')

# 5. 카테고리 최적화
for col in ['city', 'category', 'status']:
    if df[col].nunique() < 100:
        df[col] = df[col].astype('category')

# 6. bool 변환
df['is_active'] = df['is_active'].map({'Y': True, 'N': False}).astype('boolean')

print(df.dtypes)
print(df.memory_usage(deep=True).sum() / 1e6, 'MB')

함정

1. NaN 이 있는 int 컬럼

df['age'].astype('int64')      # NaN 있으면 ValueError
df['age'].astype('Int64')      # ✓ nullable
df['age'].fillna(0).astype('int64')   # NaN → 0 후 변환

2. astype(‘category’) 후 새 카테고리 추가

df['city'] = df['city'].astype('category')
df.loc[100, 'city'] = 'NewCity'   # ❌ categories 에 없음
df['city'] = df['city'].cat.add_categories('NewCity')

3. dtype 강등 (object)

df['x'] = df['x'].where(cond, 'fallback')
# x 가 int 였어도 결과는 object

4. replace 와 str.replace 혼동

s = pd.Series(['Seoul City', 'Busan Town'])

# 전체 값 매칭 (없음)
s.replace('City', 'Metro')     # 그대로 유지

# 부분 문자열 교체
s.str.replace('City', 'Metro') # 'Seoul Metro', 'Busan Town'

5. 대규모 DataFrame 에서 astype 체이닝

# ❌ 매번 중간 복사본 생성
df['a'] = df['a'].astype('int32')
df['b'] = df['b'].astype('float32')

# ✓ 한 번에 처리 (더 효율적)
df = df.astype({'a': 'int32', 'b': 'float32'})

관련 위키

이 글의 용어 (6개)
[Pandas] .str accessorpandas
정의 는 Series 의 각 문자열 원소에 벡터화된 문자열 메서드 를 적용하는 accessor. Python 의 거의 모든 메서드를 NaN-aware 로 제공한다. accesso…
[Pandas] 성능 / 메모리 최적화pandas
정의 pandas 의 흔한 성능 함정과 최적화 패턴. 벡터화 + dtype 선택 + 알고리즘 의 조합이 핵심. 사용 상황 | 상황 | 권장 접근 | |:---|:---| | 단순…
[Pandas] Categoricalpandas
정의 Categorical 은 제한된 고유값 만 가질 수 있는 dtype. 내부적으로 정수 코드로 저장되어 메모리 절약 과 속도 향상 을 동시에 달성한다. 고유값 수가 적고(lo…
[Pandas] dropna / fillnapandas
정의 - : NaN 이 있는 행/열 제거 - : NaN 을 특정 값으로 대체 데이터 분석의 가장 기본적인 결측치 처리. 사용 상황 - CSV 로드 후 빈 셀이 NaN 으로 읽혔을…
[Pandas] Nullable Types (Int64, boolean, string[pyarrow])pandas
정의 Nullable dtypes 는 NaN/None 을 타입 그대로 표현할 수 있는 pandas 의 새 타입 시스템. NumPy 기반의 (NaN 미허용) 의 한계를 극복. - …
[Pandas] to_datetimepandas
정의 는 문자열, 정수, dict, DataFrame 컬럼을 타입으로 변환한다. pandas 시계열 작업의 출발점. 사용 상황 - CSV 로드 후 날짜 컬럼이 (문자열) 로 읽혔…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기