본문 바로가기
목차
Python/pandas

[Pandas] .map() 과 .apply() 메서드

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

1) DataFrame.map() 메서드: element-wise(요소 단위) 적용

  • 목적:
    • DataFrame각 스칼라 요소에 함수를 적용
    • element-wise 변환.
  • 반환:
    • 입력과 동일한 shape의 DataFrame.
  • 주요 파라미터
    • func: 각 요소에 적용할 함수(호출 가능 객체).
    • na_action='ignore': 결측값(NA)에는 함수를 적용하지 않음.
      • na_action=None:
        • 기본값으로, 이 경우 NA값에도 함수 적용이 되며,
        • 보통 NaN이 반환되지만 에러가 날 수도 있음.
  • 비고:
    • 이전에 사용되던 applymapdeprecated.
    • 새 코드에서는 반드시 map 사용해야 함.
import pandas as pd
import numpy as np

df = pd.DataFrame({"A": [1, 2, np.nan], "B": [10, 20, 30]})

# 요소 단위로 제곱: 각 셀의 스칼라 값이 lambda의 인자로 전달됨
df_sq = df.map(lambda x: x**2)

# 결측값(NA)은 건너뛰기: NA에는 함수를 적용하지 않음
df_sq_skipna = df.map(lambda x: x**2, na_action="ignore")

위의 예에서는 na_action의 차이가 없음.

다음은 차이가 있는 예임.

import pandas as pd
import numpy as np

s = pd.Series(["Alice", None, "Bob"])

# 기본값 (na_action=None) → None도 함수에 넘어가므로 에러 발생
try:
    print(s.map(lambda x: x.upper()))
except Exception as e:
    print("Error with na_action=None:", e)

# na_action='ignore' → None은 함수에 넘기지 않고 그대로 둠
print(s.map(lambda x: x.upper(), na_action="ignore"))


2) DataFrame.apply() 메서드: row-wise / column-wise(행/열 단위) 적용

  • 목적:
    • column 또는 row 에 해당하는 Series(또는ndarray)를
    • 인자로 넘겨진 함수에 전달하여 변환/집계 처리.
  • 동작 축(axis):
    • axis=0(기본):
      • column에 해당하는 Series가 함수 인자로 전달됨.
      • column 별로 처리가 이루어짐.
    • axis=1:
      • row에 해당하는 Series가 함수 인자로 전달.
      • row 별로 처리가 이루어짐.
  • 주요 파라미터
    • axis: 0(열 기준), 1(행 기준).
    • raw=True
      • Series 대신 ndarray를 인자로 전달
      • 보다 빠른 처리가 가능
    • result_type: 결과 형식 제어
      • 'reduce' :
        • 하나의 scalar값을 함수가 반환(각 Series마다 하나의 scalar).
        • 기본모드.
      • 'broadcast':
        • 각 Series마다 하나의 scalar값이 계산되나, Series의 shape에 맞추어짐.
        • 즉 DataFraem의 shape가 입력과 같이 유지됨.
      • 'expand':
        • 각 Series가 list,Series,배열 등의 여러 값을 반환할 경우,
        • DataFrame 열/행이 확장됨.

다음은 간단한 예제임.

import pandas as pd

df = pd.DataFrame({"A": [1, 2, 3], "B": [10, 20, 30]})

# column-wise: 각 열(Series)이 lambda의 인자로 들어옴
col_sums = df.apply(lambda col: col.sum(), axis=0)  # A=6, B=60

# row-wise: 각 행(Series)이 lambda의 인자로 들어옴
row_sums = df.apply(lambda row: row.sum(), axis=1)  # [11, 22, 33]

# raw=True: 각 행의 값 배열(ndarray)이 인자로 들어옴 → 오버헤드 감소 가능
row_sums_fast = df.apply(lambda row_vals: row_vals.sum(), axis=1, raw=True)

df, col_sums, row_sums, row_sums_fast 의 결과

 

result_type 에 대한 예제는 다음을 참고:

import pandas as pd

df = pd.DataFrame({
    "A": [1, 2, 3, 4],
    "B": [10, 20, 30, 40],
    "C": [100, 200, 300, 400]
})

# reduce: 각 행에서 [min, max] 리스트 반환 → 리스트 전체가 하나의 값
reduce_res = df.apply(lambda row: [row.min(), row.max()],
                      axis=1, result_type="reduce")

# expand: 리스트의 각 요소를 열(column)로 확장
expand_res = df.apply(lambda row: [row.min(), row.median(), row.max()],
                      axis=1, result_type="expand")
expand_res.columns = ["min", "median", "max"]

# broadcast: 스칼라(min)을 행 전체에 broadcast
broadcast_res = df.apply(lambda row: row.min(),
                         axis=1, result_type="broadcast")

print("=== reduce ===", f"{type(reduce_res) = }")
print(reduce_res, end="\n\n")

print("=== expand ===", f"{type(expand_res) = }")
print(expand_res, end="\n\n")

print("=== broadcast ===", f"{type(broadcast_res) = }")
print(broadcast_res)


3) Series.apply() 메서드: element-wise(요소 단위) 적용

  • 목적:
    • Series의 각 원소(스칼라)에 함수를 적용
    • element-wise 변환.
  • 주요 파라미터
    • convert_dtype=True: 결과 dtype 자동 변환 시도.
    • args, **kwargs: 함수에 추가 인자 전달.
import pandas as pd

s = pd.Series(["alice", "Bob", "CHARLIE"])
# 각 원소가 lambda의 인자로 들어옴 → 문자열 전처리에 적합
s_upper = s.apply(lambda x: x.upper())  # ['ALICE','BOB','CHARLIE']

nums = pd.Series([1, 2, 3, 4])
squared = nums.apply(lambda x: x**2)    # [1,4,9,16]


4) GroupBy.apply() 메서드: group-wise(그룹 단위) 적용

  • 목적:
    • 그룹화 후 각 그룹의 부분 DataFrame/Series를 함수에 전달
    • 각 그룹별로 맞춤 연산 수행.
  • 핵심:
    • 함수에 넘어가는 첫 인자는 GroupBy 객체가 아니라
    • "그룹으로 나뉘어진(원문에선 split이라 "잘린" 으로 생각해도됨) 실제 데이터(부분 DataFrame/Series)"가 인자로 넘겨짐.
  • 최신 동작(중요):include_groups=False 파라미터를 명시하지 않으면 FutureWarning 발생 (Pandas 2.1+).
    • include_groups=True: 그룹 기준 열/키 포함(현재 동작과 동일)된 상태로 함수에 넘겨짐.
    • include_groups=False: 그룹 기준 열/키 제외(권장, 향후 기본값 예정)된 상태로 함수에 넘겨짐.
    • 경고 메시지 예: FutureWarning: The default of include_groups will change to False in a future version.
  • 그 밖의 자주 쓰는 옵션:
    • sort(그룹 키 정렬),
    • dropna(NA 키 제외),
    • observed(category 처리).
import pandas as pd

df2 = pd.DataFrame({
    "team": ["A", "A", "B", "B", "B"],
    "score": [10, 20, 30, 40, 50],
    "round": [1, 2, 1, 2, 3],
})

# 예1) 최신 라운드 점수만 추출: g는 'team'별 부분 DataFrame
latest_score = (
    df2.groupby("team")
       .apply(lambda g: g.sort_values("round").iloc[-1]["score"],
              include_groups=False)  # 권장: 그룹 기준 키 제외
)

# 예2) 각 그룹에서 점수 상위 1개 행만 반환: 복합 구조 반환 가능
top1_each = (
    df2.groupby("team")
       .apply(lambda g: g.nlargest(1, "score"),
              include_groups=False)  # 경고 회피 및 향후 호환성
)

# 예3) include_groups=True로 전달하면 그룹 기준 열이 함께 옴(비권장, 향후 기본 False)
with_keys = df2.groupby("team").apply(lambda g: g, include_groups=True)

FutureWarning 이 발생됨.
with_keys 형태임.


핵심 요약 표

메서드 적용 단위(unit) 함수 인자 주요 파라미터 비고
DataFrame.map element-wise
(요소 단위)
스칼라 func,
na_action
applymap 대체
(신규 권장)
DataFrame.apply column-wise / row-wise
(열/행 단위)
Series
또는 ndarray
(if raw=True)
axis,
raw,
result_type
축 단위 집계/가공
Series.apply element-wise
(요소 단위)
스칼라 convert_dtype,
args
문자열/값 전처리
GroupBy.apply group-wise
(그룹 단위)
부분
DataFrame/
Series
include_groups,
sort,
dropna,
observed
include_groups=False 권장

 

728x90