BioPlayground

🧬
목록으로

apply, map, applymap — 데이터 변환의 세 도구

pandas의 apply, map, applymap 세 함수의 차이를 명확히 이해하고, 상황별로 올바른 도구를 고릅니다.

중급
|
10
|
검증 완료 (2026-07)
applymapapplymap데이터 변환벡터 연산
진행률0/8 (0%)

apply, map, applymap — 데이터 변환의 세 도구

이 토픽을 마치면

apply, map, applymap 세 함수의 차이를 명확히 구분하고, 상황에 맞는 도구를 선택할 수 있으며, 성능 차이를 이해합니다.


왜 세 개나 있는가

pandas에서 데이터를 변환하는 함수가 세 개 있어서 처음에는 혼란스럽습니다. 각각 적용 범위가 다릅니다.

함수대상적용 단위
map()Series (1차원)개별 값 하나씩
apply()Series 또는 DataFrame행 또는 열 단위
applymap()DataFrame (2차원)개별 값 하나씩

한 문장으로: map은 Series의 각 값에, applymap은 DataFrame의 각 값에, apply는 행/열 전체에 함수를 적용합니다.


map — Series의 각 값을 변환

map()은 Series 전용입니다. 각 값에 함수를 적용하거나, 딕셔너리로 매핑합니다.

함수 매핑

python
import pandas as pd
df = pd.DataFrame({
"name": ["Alice", "Bob", "Carol"],
"score": [85.7, 92.3, 78.1]
})
# 각 이름을 대문자로
df["name"].map(str.upper)
# 0 ALICE
# 1 BOB
# 2 CAROL
# 각 점수를 반올림
df["score"].map(round)
# 0 86
# 1 92
# 2 78

딕셔너리 매핑

python
grade_map = {
"A": "Excellent",
"B": "Good",
"C": "Average"
}
grades = pd.Series(["A", "B", "C", "A", "B"])
grades.map(grade_map)
# 0 Excellent
# 1 Good
# 2 Average
# 3 Excellent
# 4 Good

딕셔너리에 없는 값은 NaN이 됩니다. 이것은 실무에서 카테고리 인코딩에 자주 사용됩니다.

lambda와 함께

python
df["score"].map(lambda x: "Pass" if x >= 80 else "Fail")
# 0 Pass
# 1 Pass
# 2 Fail

apply — 행 또는 열 단위로 함수 적용

apply()는 Series와 DataFrame 모두에서 사용할 수 있습니다.

Series.apply — map과 비슷

python
df["score"].apply(lambda x: round(x, 1))
# map()과 동일한 결과

Series에서는 map()과 거의 같습니다. 차이는 apply()가 추가 인자를 넘길 수 있다는 정도입니다.

DataFrame.apply — 열(또는 행) 단위

python
df = pd.DataFrame({
"math": [85, 92, 78],
"english": [90, 88, 95],
"science": [88, 91, 82]
})
# 각 과목(열)의 평균
df.apply("mean") # axis=0 (기본값, 열 방향)
# math 85.0
# english 91.0
# science 87.0
# 각 학생(행)의 평균
df.apply("mean", axis=1) # axis=1 (행 방향)
# 0 87.666667
# 1 90.333333
# 2 85.000000

axis=0은 "위에서 아래로" (각 열에 함수 적용), axis=1은 "왼쪽에서 오른쪽으로" (각 행에 함수 적용)입니다.

행 단위로 여러 컬럼 참조

python
df = pd.DataFrame({
"name": ["Alice", "Bob", "Carol"],
"math": [85, 92, 78],
"english": [90, 88, 95]
})
# 각 학생의 두 과목 중 높은 점수
df.apply(lambda row: max(row["math"], row["english"]), axis=1)
# 0 90
# 1 92
# 2 95

행(axis=1) 단위 apply에서 row는 해당 행의 Series입니다. 여러 컬럼을 참조해서 복합 계산을 할 수 있습니다.


applymap — DataFrame의 모든 값을 변환

applymap()은 DataFrame 전용이며, 모든 셀에 함수를 적용합니다.

python
df = pd.DataFrame({
"math": [85.7, 92.3, 78.1],
"english": [90.2, 88.9, 95.4],
"science": [88.1, 91.7, 82.3]
})
# 모든 값을 정수로
df.applymap(int)
# math english science
# 0 85 90 88
# 1 92 88 91
# 2 78 95 82
# 모든 값에 포맷 적용
df.applymap(lambda x: f"{x:.1f}%")
# math english science
# 0 85.7% 90.2% 88.1%
# 1 92.3% 88.9% 91.7%
# 2 78.1% 95.4% 82.3%

참고: pandas 2.1+에서 applymap()map()으로 통합되었습니다. DataFrame.map()으로 같은 작업을 할 수 있습니다. 하지만 많은 코드베이스에서 아직 applymap()을 사용하므로 알아둘 필요가 있습니다.


세 함수 비교 — 한눈에

python
import pandas as pd
df = pd.DataFrame({
"A": [1, 2, 3],
"B": [4, 5, 6]
})
# map: Series 각 값 → 값
df["A"].map(lambda x: x * 10) # Series → Series
# 0 10
# 1 20
# 2 30
# apply (Series): map과 비슷
df["A"].apply(lambda x: x * 10) # Series → Series (동일 결과)
# apply (DataFrame, axis=0): 열 단위
df.apply(sum) # DataFrame → Series
# A 6
# B 15
# apply (DataFrame, axis=1): 행 단위
df.apply(sum, axis=1) # DataFrame → Series
# 0 5
# 1 7
# 2 9
# applymap: DataFrame 각 값 → 값
df.applymap(lambda x: x * 10) # DataFrame → DataFrame
# A B
# 0 10 40
# 1 20 50
# 2 30 60

성능 — 벡터 연산을 먼저

apply, map, applymap은 내부적으로 Python 루프를 돕니다. pandas의 내장 연산(벡터 연산)이 훨씬 빠릅니다.

python
import numpy as np
df = pd.DataFrame({"value": range(1_000_000)})
# Slow — apply (Python 루프)
%timeit df["value"].apply(lambda x: x * 2)
# ~200ms
# Fast — 벡터 연산 (C로 실행)
%timeit df["value"] * 2
# ~2ms (100배 빠름)

규칙: 단순 산술, 비교, 문자열 메서드는 벡터 연산을 씁니다. apply()는 벡터 연산으로 표현할 수 없는 복잡한 로직에서만 사용합니다.

python
# Bad — apply로 조건 분기
df["label"] = df["value"].apply(lambda x: "high" if x > 500000 else "low")
# Good — np.where (벡터 연산)
df["label"] = np.where(df["value"] > 500000, "high", "low")
# Bad — apply로 문자열 처리
df["upper"] = df["name"].apply(str.upper)
# Good — str accessor (벡터 연산)
df["upper"] = df["name"].str.upper()

실전 패턴 — 복합 변환

벡터 연산으로 불가능한 경우에 apply를 씁니다:

python
df = pd.DataFrame({
"name": ["Alice Smith", "Bob Lee", "Carol Park"],
"birth": ["1995-03-15", "1988-11-22", "2001-07-08"],
"department": ["Sales", "Dev", "HR"]
})
def create_employee_id(row):
dept_code = row["department"][:2].upper()
last_name = row["name"].split()[-1].upper()
year = row["birth"][:4]
return f"{dept_code}-{last_name}-{year}"
df["emp_id"] = df.apply(create_employee_id, axis=1)
print(df["emp_id"])
# 0 SA-SMITH-1995
# 1 DE-LEE-1988
# 2 HR-PARK-2001

여러 컬럼을 참조해서 복잡한 문자열을 만드는 작업 — 이것은 벡터 연산으로 표현하기 어렵고, apply(axis=1)이 적절합니다.


핵심 정리

상황도구
Series 각 값 변환map() 또는 apply()
딕셔너리로 값 매핑map(dict)
DataFrame 각 셀 변환applymap() (또는 pandas 2.1+ map())
열 단위 집계apply(func, axis=0)
행 단위 복합 계산apply(func, axis=1)
단순 산술/비교벡터 연산 (apply 쓰지 말 것)

세 함수를 고르는 순서: 1) 벡터 연산으로 되는가? → 벡터 연산. 2) Series 각 값? → map. 3) DataFrame 각 셀? → applymap. 4) 행/열 단위 복합 로직? → apply. 이 순서를 기억하면 성능과 가독성 모두 챙길 수 있습니다.


자주 하는 실수

실수문제해결
df.map(func) (pandas < 2.1)AttributeErrordf.applymap(func) 또는 pandas 업그레이드
df.apply(func) 에 스칼라 반환기대와 다른 결과axis 확인 — 0은 열, 1은 행
단순 산술에 apply 사용100배 느림벡터 연산으로 교체
map에 없는 키NaN 발생fillna()로 기본값 지정