-/Pandas

Pandas: 데이터 결측 처리 전략 및 시계열 보간

106. 2026. 8. 30. 20:57

missing

이상치 처리 과정에서 NaN으로 변환된 결측치(OHLC 가격 데이터 및 거래량)를 데이터 특성에 맞게 처리하는 절차와 종목별 그룹 보간(interpolate)의 중요성을 정리한다.

 

📌 결측 처리 3가지 전략 비교

전략 핵심 메서드 선택 기준 및 주요 특징
삭제 dropna(subset=, how=, thresh=) 삭제할 행 없이도 분석이 가능한가? 결측이 있는 행을 걸러낸다.
대치 fillna(값 / 평균 / 중앙값) 대표값으로 적절한 것이 있는가? 결측자리를 지정한 값으로 채운다.
보간 interpolate() 시계열 데이터에 적합. 앞뒤 값 사이를 직선으로 이어 빈칸(중중간값)을 추정한다.

 

1. 종목별 그룹 보간(groupby + interpolate)의 필요성

시계열 데이터의 중간값을 추정해서 채워 넣는 보간(interpolate) 작업은 반드시 종목별로 진행해야 한다.

# 종목이 바뀌는 경계 지점 데이터 준비
edge = df.index[df["code"] != df["code"].shift()][1]
demo = df.loc[edge - 2: edge + 2, ["code", "date", "close"]].copy()
demo.loc[edge, "close"] = pd.NA
demo["close"] = pd.to_numeric(demo["close"], errors="coerce")

print("종목이 바뀌는 지점에 결측이 있다고 하자:")
print(demo.to_string(index=False))

# groupby 없이 보간 vs 종목별 groupby 보간
wrong = demo["close"].interpolate()
right = demo.groupby("code")["close"].transform(lambda s: s.interpolate())

print(f" w :\n {wrong.to_string(index=False)}")
print(f" r :\n {right.to_string(index=False)}")

 

💡 보간 적용 시 주의점

  • df.groupby("code")["close"].transform(lambda s: s.interpolate()) 형태를 사용한다. 그룹 하나의 Series가 s로 들어가고, 보간 처리된 Series가 그 그룹의 자리에 채워진다. 원본과 길이가 같은 Series를 반환해서 옆에 그대로 대입한다.
  • 잘못된 적용 (wrong): groupby 없이 보간하면 앞 종목의 마지막 종가와 뒷 종목의 다음 종가 사이를 이어버리는 치명적인 오류가 발생한다.
  • 올바른 적용 (right): groupby를 적용하면 해당 종목 내부의 앞뒤 값으로만 보간을 수행한다.

2. 컬럼별 결측 처리 전략 및 실행

데이터의 성격에 맞춰 열별로 각기 다른 전략을 적용한다.

  • 시가, 고가, 저가, 종가 (OHLC): 종목별 보간 처리 (시계열 연속성 유지)
  • 거래량 (volume): 결측 유지 ( 함부로 0이나 추정치로 채우면 안 됨)
OHLC = ["open", "high", "low", "close"]
before = df[OHLC].isna().sum().sum()

# 1차: 종목별 linear interpolate 적용
for col in OHLC:
    df[col] = df.groupby("code")[col].transform(lambda s: s.interpolate())

mid = df[OHLC].isna().sum().sum()

# 2차: 종목 양 끝단 결측 처리 (ffill + bfill)
for col in OHLC:
    df[col] = df.groupby("code")[col].transform(lambda s: s.ffill().bfill())

after = df[OHLC].isna().sum().sum()

print(f"OHLC 결측 : {before}건")
print(f"종목별 interpolate 후 : {mid}건")
print(f"ffill + bfill : {after}건")

# 거래량은 채우지 않고 그냥 둔다.
print(f" 거래량 결측 : {df['volume'].isna().sum()}건")

 

💡 양 끝단 결측치 처리 (ffill & bfill)

  • 종목의 맨 앞이나 맨 뒤에 존재하는 결측치는 앞/뒤에 이을 값이 없어 interpolate()로 채워지지 않는다.
  • 이 경우 가장 가까운 값으로 채워주는 방식을 조합하여 완전히 해결한다.
    • s.ffill(): 결측을 바로 앞의 값으로 채움 (Forward Fill)
    • s.bfill(): 결측을 바로 뒤의 값으로 채움 (Backward Fill)

3. 주요 메서드 및 기능 요약

메서드 역할 및 작동 원리 적용 대상
transform(lambda s: s.interpolate()) 그룹 내 시계열 흐름에 따라 연속된 값으로 결측 보간 OHLC 중간 결측치
transform(lambda s: s.ffill().bfill()) 양 끝단 결측을 이전/이후 존재하는 가장 가까운 값으로 전파 대치 OHLC 양 끝단 결측치
미처리 유지 원본 NaN 상태 유지 (0 채우기 금지) volume (거래량)