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

[Pandas] interpolate

· 수정 · 📖 약 2분 · 742자/단어 #python #pandas #null #missing-data #interpolation #timeseries
Pandas interpolate, 결측치 보간, Series interpolate, pandas 보간, 시계열 보간

정의

interpolate() 는 NaN 을 주변 값을 사용해 보간 으로 채운다. 시계열, 센서 측정 데이터처럼 값이 연속적으로 변화하는 경우의 결측을 자연스럽게 채울 때 유용하다.

fillna 가 단일 고정값이나 직전/직후 값으로 채우는 반면, interpolate 는 주변 값들 사이의 보간 곡선 을 따른다.

method 선택 흐름

flowchart TD
    Q1{"index 가 DatetimeIndex?"}
    Q1 -->|"예"| Q2{"시간 간격이 불규칙?"}
    Q2 -->|"예"| TIME["method='time'"]
    Q2 -->|"아니오"| LIN["method='linear'"]
    Q1 -->|"아니오"| Q3{"데이터가 곡선 트렌드?"}
    Q3 -->|"예"| Q4{"scipy 설치됨?"}
    Q4 -->|"예"| SPL["method='spline', order=3"]
    Q4 -->|"아니오"| POL["method='polynomial', order=2"]
    Q3 -->|"아니오"| LIN2["method='linear'"]

    style TIME fill:#1565c0,color:#fff
    style LIN fill:#2e7d32,color:#fff
    style LIN2 fill:#2e7d32,color:#fff
    style SPL fill:#e65100,color:#fff

기본

s.interpolate()                           # 기본 linear
s.interpolate(method='polynomial', order=2)
s.interpolate(method='time')              # DatetimeIndex 필요
s.interpolate(method='spline', order=3)   # scipy 필요

linear 보간 예

python
import pandas as pd
import numpy as np
s = pd.Series([1, np.nan, np.nan, 4, np.nan, 6])
print('original    :', s.tolist())
print('interpolate :', s.interpolate().tolist())
결과
original    : [1.0, nan, nan, 4.0, nan, 6.0]
interpolate : [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]
indexoriginalinterpolate
01.01.0
1NaN2.0
2NaN3.0
34.04.0
4NaN5.0
56.06.0

1 → 4 사이의 NaN 2 개를 직선 보간으로 2, 3 으로 채웠다.

다양한 method

method설명요구사항
linear (기본)직선 보간-
time시간 간격 가중DatetimeIndex
indexindex 값을 X축으로-
nearest가장 가까운 값 복사-
polynomial다항식order 필수
spline스플라인order 필수, scipy
pchip단조 3차 스플라인scipy
akimaAkima 스플라인scipy
from_derivatives기울기 기반scipy

time-based 보간

ts = pd.Series([1, np.nan, np.nan, 10],
    index=pd.date_range('2024-01-01', periods=4, freq='D'))
ts.interpolate()               # 균등 간격 가정 → [1, 4, 7, 10]
ts.interpolate(method='time')  # 같은 결과 (간격이 균일하므로)

# 불균등 시계열에서 차이가 드러남
ts2 = pd.Series([1, np.nan, 10],
    index=pd.to_datetime(['2024-01-01', '2024-01-02', '2024-01-10']))
ts2.interpolate()               # 균등 가정 → [1, 5.5, 10]
ts2.interpolate(method='time')  # 시간 거리 가중 → [1, 2.0, 10]

time method 가 실제 거리 기반이라 불규칙 시계열에 더 자연스럽다.

IMPORTANT

method='time' 은 반드시 DatetimeIndex 가 있어야 한다. 정수 index 나 RangeIndex 에서는 TypeError 가 발생한다.

spline / polynomial

import numpy as np
import pandas as pd

x = pd.Series([0, np.nan, np.nan, np.nan, 16],
    index=[0, 1, 2, 3, 4])

print('linear    :', x.interpolate(method='linear').tolist())
print('polynomial:', x.interpolate(method='polynomial', order=2).tolist())
print('spline    :', x.interpolate(method='spline', order=2).tolist())
indexlinearpolynomial (order=2)spline (order=2)
0000
1411
2844
31299
4161616

제곱 트렌드 데이터에서는 polynomial(order=2) 가 더 정확하다.

양 끝의 NaN

s = pd.Series([np.nan, np.nan, 1, 2, np.nan, np.nan])
s.interpolate()
# [NaN, NaN, 1.0, 2.0, NaN, NaN]  <- 양 끝은 못 채움

s.interpolate(limit_direction='both')
# [1.0, 1.0, 1.0, 2.0, 2.0, 2.0]

s.interpolate(limit_direction='backward')
# [1.0, 1.0, 1.0, 2.0, NaN, NaN]

limit_direction='forward' (기본) / 'backward' / 'both' 로 방향 제어.

limit: 연속 NaN 개수 제한

s = pd.Series([1, np.nan, np.nan, np.nan, np.nan, 10])

# 연속 NaN 2 개까지만 채움
s.interpolate(limit=2)
# [1.0, 4.0, 7.0, NaN, NaN, 10.0]

# backward + limit
s.interpolate(limit=2, limit_direction='backward')
# [1.0, NaN, NaN, 7.0, 8.5, 10.0]

fillna vs interpolate 비교

방법채우는 값적합한 데이터
fillna(0)고정값결측을 0으로 처리해도 되는 경우
fillna(method='ffill')직전 값 반복마지막 관측값 유지 (계단형)
fillna(method='bfill')직후 값 반복다음 관측값으로 채움
fillna(mean)전체 평균간단한 통계 대치
interpolate('linear')직선 보간연속 트렌드, 센서 데이터
interpolate('time')시간 거리 가중불규칙 시계열
interpolate('spline')곡선 보간비선형 변화

실전 예시

센서 데이터 결측 보간

import pandas as pd
import numpy as np

# 온도 센서 (10분 간격, 일부 측정 실패)
idx = pd.date_range('2024-01-01', periods=144, freq='10min')
temp = pd.Series(np.random.randn(144).cumsum() + 20, index=idx)
temp.iloc[30:33] = np.nan    # 30분 연속 결측
temp.iloc[80] = np.nan       # 단일 결측

# 시간 거리 가중 보간 (가장 자연스러움)
temp_filled = temp.interpolate(method='time', limit=6)

# 6개 이상 연속 결측은 그대로 NaN 유지

금융 데이터 (주말/공휴일 결측)

# 거래일 기준 주가 데이터, 주말에 NaN
price = pd.read_csv('price.csv', index_col='date', parse_dates=True)

# 1개까지만 보간 (단기 결측), 나머지는 ffill
price['close'] = (price['close']
    .interpolate(method='time', limit=1)
    .fillna(method='ffill'))

DataFrame 전체 적용

# 모든 수치형 컬럼 보간
df_interp = df.interpolate(method='linear', limit=3)

# 특정 컬럼만
df['temperature'] = df['temperature'].interpolate(method='time')
df['pressure']    = df['pressure'].interpolate(method='spline', order=3)

성능

import time

n = 1_000_000
s = pd.Series(np.where(np.random.rand(n) < 0.1, np.nan, np.random.randn(n)))

t = time.perf_counter()
s.interpolate(method='linear')
print(f'linear   : {time.perf_counter()-t:.4f}s')

t = time.perf_counter()
s.fillna(method='ffill')
print(f'ffill    : {time.perf_counter()-t:.4f}s')

linearffill 은 C 구현이라 대용량에서도 빠르다. spline / polynomial 은 scipy 를 사용하므로 상대적으로 느리다.

함정

1. 잘못된 method 선택

  • outlier 가 많은 경우: linear 가 outlier 사이로 보간해 이상해질 수 있음
  • 시계열: 불규칙 간격이면 time method 가 더 자연스러움
  • 곡선 트렌드: spline 또는 polynomial

2. 연속 NaN 이 너무 많을 때

# 연속 100개 결측을 linear 보간하면 너무 큰 가정
[1, NaN, NaN, ...(98개)..., NaN, 100]
# limit 파라미터로 최대 보간 개수를 제한하는 것이 안전
s.interpolate(method='linear', limit=5)

3. method=‘time’ 인데 DatetimeIndex 없음

s.interpolate(method='time')   # TypeError if not DatetimeIndex
# 해법: index 를 datetime 으로 변환 후 보간
s.index = pd.to_datetime(s.index)
s.interpolate(method='time')

4. inplace 미지원

# interpolate 는 inplace=True 를 지원하지 않음 (pandas 2.0+)
s = s.interpolate()   # 반환값을 재대입

WARNING

interpolate양쪽에 유효한 값이 있을 때만 NaN 을 채울 수 있다. 시작 또는 끝에 NaN 이 있으면 기본적으로 채워지지 않는다. limit_direction='both' 로 외삽(extrapolation) 이 필요하다면 데이터 특성을 먼저 검토하라.

관련 위키

이 글의 용어 (6개)
[Pandas] dropna / fillnapandas
정의 - : NaN 이 있는 행/열 제거 - : NaN 을 특정 값으로 대체 데이터 분석의 가장 기본적인 결측치 처리. 사용 상황 - CSV 로드 후 빈 셀이 NaN 으로 읽혔을…
[Pandas] isin / isna / notnapandas
정의 | 메서드 | 의미 | |:---|:---| | | 각 원소가 values 안에 있는지 (boolean Series) | | | NaN/NaT/None 여부 ( 별칭) | …
[Pandas] resamplepandas
정의 는 시계열 데이터를 다른 빈도 (월별, 일별, 시간별 등) 로 재샘플링하면서 집계한다. 의 시계열 버전. DatetimeIndex (또는 으로 datetime 컬럼) 이 필…
[Pandas] rolling / expandingpandas
정의 - : 고정 크기 슬라이딩 윈도우 (이동 평균 등) - : 시작부터 누적 윈도우 (cumulative) - : 지수 가중 이동 평균 사용 상황 | 상황 | 적합한 방법 | …
[Pandas] shift / diff / pct_changepandas
정의 - : 값을 n 칸 밀기 (lag/lead 생성) - : n 칸 차이 (= ) - : 변화율 (= ) 시계열 분석의 기본 도구. 전일 대비 / 전월 대비 / lag feat…
[Pandas] to_datetimepandas
정의 는 문자열, 정수, dict, DataFrame 컬럼을 타입으로 변환한다. pandas 시계열 작업의 출발점. 사용 상황 - CSV 로드 후 날짜 컬럼이 (문자열) 로 읽혔…

💬 댓글

사이트 검색 / 명령어

검색

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