0Pricing
Pandas & NumPy Academy · レッスン

補間と高度な欠測値補完

interpolate()を使って時間に基づくデータを滑らかに補完し、平均値と中央値のどちらによる補完が適切かを理解します。

「補間と高度な欠測値補完」はCoddyKit上の無料Pandas & NumPy Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPandas & NumPy Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

補間がfillna()より適している場合

前方補完と後方補完は、データの傾向を考慮せず、最も近い既知の値を引き継ぎます。補間は、既知の値の間が滑らかに変化すると仮定して欠損値を推定します。たとえば、月曜日の気温が20℃、金曜日が30℃だった場合、水曜日は25℃と推定します。この方法は、センサーデータ、価格、人口など、滑らかに変化する信号をより現実的に補完できます。

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'day': [1, 2, 3, 4, 5],
    'temp': [20.0, np.nan, np.nan, np.nan, 30.0]
})

# Linear interpolation fills gaps smoothly
df['temp_interp'] = df['temp'].interpolate(method='linear')
print(df)
#    day  temp  temp_interp
# 0    1  20.0         20.0
# 1    2   NaN         22.5
# 2    3   NaN         25.0
# 3    4   NaN         27.5
# 4    5  30.0         30.0

interpolate()のメソッド

Pandasのinterpolate()は複数のメソッドに対応しています。代表的なものは、'linear'(既知の値の間を等間隔に補間)、'time'(DatetimeIndexが設定されている場合に時間間隔の不均一さを考慮)、'polynomial'(多項式曲線を当てはめ、order引数が必要)、'spline'(滑らかな区分多項式)です。linearが最も安全なデフォルトであり、高次のメソッドは短い欠損区間に過剰適合する可能性があります。

import pandas as pd
import numpy as np

s = pd.Series([0, np.nan, np.nan, 8.0])

print('linear:', s.interpolate('linear').tolist())
# [0.0, 2.6666..., 5.3333..., 8.0]

print('polynomial(2):', s.interpolate('polynomial', order=2).tolist())
# [0.0, 2.222..., 5.111..., 8.0]

DatetimeIndexを使ったtime補間

Seriesに不均一な時間間隔のDatetimeIndex(例:平日のみで週末が欠けている場合)があるとき、method='time'は位置ではなく実際の経過時間に比例して補間します。各行をカレンダー上の間隔に関係なく等間隔として扱う線形補間よりも正確です。

import pandas as pd
import numpy as np

# Unequal gaps: Jan 1, Jan 3, Jan 10
idx = pd.to_datetime(['2024-01-01', '2024-01-03', '2024-01-10'])
s = pd.Series([100.0, np.nan, 170.0], index=idx)

# linear treats gaps as equal (position-based)
print(s.interpolate('linear').tolist())  # [100.0, 135.0, 170.0]

# time accounts for actual day count
# Jan 1 to Jan 3 = 2 days, Jan 1 to Jan 10 = 9 days
# fraction: 2/9 of the way from 100 to 170
print(s.interpolate('time').tolist())   # [100.0, 115.55..., 170.0]

補間範囲を制限する

ffill()と同様に、interpolate()は連続するNaN位置のうち補完する個数を制限するlimitパラメータを受け取ります。limitを超えた部分のNaNは欠損のまま残ります。これにより、真の値が何であってもおかしくない非常に長い欠損区間に対して補間が行われるのを防げます。長い欠損区間は手動確認の対象として記録してください。

import pandas as pd
import numpy as np

s = pd.Series([1.0, np.nan, np.nan, np.nan, np.nan, 10.0])

# Only fill the first 2 NaN positions
filled = s.interpolate('linear', limit=2)
print(filled.tolist())
# [1.0, 2.8, 4.6, NaN, NaN, 10.0]

平均値と中央値のどちらで補完するか

平均値と中央値による補完は簡単ですが、重要なトレードオフがあります。平均値は外れ値の影響を受けやすく、非常に大きな値が少数あるだけで上方に引っ張られるため、所得や住宅価格のように右に歪んだ分布の補完には適していません。中央値は外れ値に対して頑健で、歪んだ列にはより適しています。平均値は、データが概ね対称で極端な外れ値を含まない場合にのみ使用してください。

import pandas as pd
import numpy as np

# Skewed income data with an outlier
income = pd.Series([30000, 35000, 32000, 1_000_000, np.nan])

print('Mean:  ', income.mean())    # ~274000 — pulled by outlier
print('Median:', income.median())  # ~33500 — robust choice

# Prefer median for skewed data
filled = income.fillna(income.median())
print(filled.tolist())
# [30000, 35000, 32000, 1000000, 33500.0]

KNN補完の概念

K-Nearest Neighbour(KNN)補完は、欠損値を、欠損していない特徴量間の距離で測った最も類似するk行の平均値(または重み付き平均値)に置き換えます。これは多変量の方法であり、他の列の情報を補完に利用します。そのため、特徴量同士に相関がある場合は、1列だけを使う平均値補完よりも正確です。

Scikit-learnのKNNImputerは、NumPy配列やPandas DataFrameに直接組み込んで使用できます。

import pandas as pd
import numpy as np
from sklearn.impute import KNNImputer

df = pd.DataFrame({
    'age': [25, 35, np.nan, 45],
    'income': [50000, 70000, 60000, np.nan]
})

imputer = KNNImputer(n_neighbors=2)
df_imputed = pd.DataFrame(
    imputer.fit_transform(df),
    columns=df.columns
)
print(df_imputed.round(1))
#     age   income
# 0  25.0  50000.0
# 1  35.0  70000.0
# 2  30.0  60000.0   <- filled from neighbours
# 3  45.0  65000.0   <- filled from neighbours

IterativeImputerによる多重代入

多重代入は、統計研究における欠損データ処理の標準的な方法です。Scikit-learnのIterativeImputerは、MICE(Multiple Imputation by Chained Equations)方式を実装しています。これは、欠損値を含む各列を他の列の関数としてモデル化し、値が収束するまで補完を繰り返す方法です。1列だけを使う方法よりも、特徴量間の関係を適切に捉えられます。

import pandas as pd
import numpy as np
from sklearn.experimental import enable_iterative_imputer  # noqa
from sklearn.impute import IterativeImputer

df = pd.DataFrame({
    'x1': [1, 2, np.nan, 4, 5],
    'x2': [2, np.nan, 6, 8, 10],
    'y':  [3, 5, 7, np.nan, 11]
})

imp = IterativeImputer(max_iter=10, random_state=0)
df_filled = pd.DataFrame(imp.fit_transform(df), columns=df.columns)
print(df_filled.round(2))

欠損データ用のインジケーター列

値が補完された事実を隠すのではなく、補完前にどの行に欠損値があったかを示すバイナリインジケーター列を追加するのがよい方法です。これにより、後続のモデルは欠損パターンそのものから学習できます。場合によっては、値そのものと同じくらい、値が欠損しているかどうかが予測に役立ちます。

import pandas as pd
import numpy as np

df = pd.DataFrame({'salary': [50000, np.nan, 70000, np.nan, 90000]})

# Add indicator before filling
df['salary_was_missing'] = df['salary'].isna().astype(int)

# Then fill
df['salary'] = df['salary'].fillna(df['salary'].median())
print(df)
#    salary  salary_was_missing
# 0  50000.0                   0
# 1  70000.0                   1
# 2  70000.0                   0
# 3  70000.0                   1
# 4  90000.0                   0

補完とデータリーク

機械学習パイプラインにおける重要な原則は、補完に使う統計量(平均値、中央値、最頻値)を訓練セットのみで計算し、その値をテストセットにも適用することです。分割前にデータセット全体で統計量を計算するとデータリークが発生します。モデルが訓練中に間接的にテストデータを見てしまい、性能の推定値が実際より高くなるためです。必ず補完器は訓練データでfitし、訓練データとテストデータの両方にtransformを適用してください。

import pandas as pd
import numpy as np
from sklearn.impute import SimpleImputer
from sklearn.model_selection import train_test_split

df = pd.DataFrame({'feature': [1, 2, np.nan, 4, np.nan, 6, 7, 8]})
train, test = train_test_split(df, test_size=0.25, random_state=0)

# Fit ONLY on training data
imp = SimpleImputer(strategy='mean')
train['feature'] = imp.fit_transform(train[['feature']])

# Transform test using training statistics
test['feature'] = imp.transform(test[['feature']])
print('Train mean used:', imp.statistics_[0])

補完方法を視覚的に比較する

複数の補完方法を適用した後は、補完前の列と補完後の列の分布を横に並べてプロットし、その影響を比較します。適切な補完では、元の分布の形状(平均、分散、歪度)ができるだけ保たれます。平均値補完では分布の幅が狭くなりますが、KNNやMICEでは分布がよりよく維持される傾向があります。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(0)
original = np.random.exponential(scale=5, size=200)
with_nan = original.copy()
with_nan[np.random.choice(200, 40, replace=False)] = np.nan

s = pd.Series(with_nan)

fig, axes = plt.subplots(1, 2, figsize=(10, 4))
s.dropna().hist(ax=axes[0], bins=20, title='Original (no NaN)')
s.fillna(s.mean()).hist(ax=axes[1], bins=20, title='Mean-imputed')
plt.tight_layout()
plt.savefig('imputation_comparison.png')
print('Saved comparison chart')

適切な補完方法を選ぶ

すべての状況に最適な補完方法はありません。適切な選択は状況によって異なります。欠損が少ない単変量の単純なケースでは平均値・中央値を使用します。傾向が安定した時系列にはffill/bfillを使用します。特徴量に相関があり、その関係を利用したい場合はKNNまたはIterativeImputerを使用します。欠損値に明確なビジネス上の意味がある場合は、ドメイン固有の定数(例:存在しない場合は0、不明な場合は-1)を使用します。選択した方法は必ず記録してください。

# Decision guide (no runnable code)
#
# Missing < 5%  AND data is MCAR?  -> Mean/median fill is fine
# Time series with stable trend?   -> ffill() with limit
# Features are correlated?         -> KNNImputer or IterativeImputer
# Categorical column?              -> Mode fill or 'Unknown' sentinel
# Going into ML model?             -> Add indicator column + fill
# Research / publication quality?  -> Multiple imputation (MICE)
print('Strategy selected based on context')

クイックチェック

補間と高度な補完について、理解度を確認しましょう。

レッスンのまとめ

このレッスンでは、interpolate()は既知の値の間が滑らかに変化すると仮定して欠損値を推定すること、method='time'はDatetimeIndexの不均一な間隔に対応すること、KNNImputerやIterativeImputerなどの高度な方法は他の列の情報を使って補完することを学びました。データリークを避けるため、補完前に必ずインジケーター列を追加し、統計量は訓練セットだけで計算してください。次は、DataFrameの列のデータ型を確認して変換します。

よくある質問

「補間と高度な欠測値補完」レッスンは無料ですか?

はい。「補間と高度な欠測値補完」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Pandas & NumPy Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

「補間と高度な欠測値補完」で何を学びますか?

interpolate()を使って時間に基づくデータを滑らかに補完し、平均値と中央値のどちらによる補完が適切かを理解します。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Pandas & NumPy Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPandas & NumPy Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「補間と高度な欠測値補完」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPandas & NumPy Academyレッスンでコードを書いて実行できますか?

はい。すべてのPandas & NumPy Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 欠損値の検出
  2. 欠損値の削除
  3. 欠損値の補完
  4. 補間と高度な欠測値補完
← Pandas & NumPy Academyに戻る