Pythonで欠損値を補完する手法とコード

プログラミング

Pythonにおける欠損値補完手法

欠損値補完の重要性

データ分析や機械学習モデルの構築において、欠損値の扱いは非常に重要です。欠損値が存在するまま分析を行うと、統計量の偏り、モデルの性能低下、さらには分析結果の誤解につながる可能性があります。そのため、適切な欠損値補完手法を選択し、適用することが不可欠です。

Pythonにおける欠損値の表現

Pythonでは、主にNumPyライブラリのnp.nan(Not a Number)を用いて欠損値を表現します。Pandasライブラリでも、NaNは欠損値として自動的に認識され、多くの関数で適切に処理されます。

主要な欠損値補完手法

1. 削除による補完

最も単純な手法は、欠損値を含む行または列を削除する方法です。しかし、この手法はデータ量が大幅に減少する可能性があり、有用な情報が失われるリスクがあります。そのため、欠損値の割合が非常に少ない場合に限定して検討すべきです。

コード例 (Pandas):

import pandas as pd
import numpy as np

# サンプルデータフレームの作成
data = {'A': [1, 2, np.nan, 4, 5],
        'B': [np.nan, 2, 3, 4, 5],
        'C': [1, 2, 3, np.nan, 5]}
df = pd.DataFrame(data)

# 欠損値を含む行を削除
df_dropped_rows = df.dropna()
print("行削除後:n", df_dropped_rows)

# 欠損値を含む列を削除
df_dropped_cols = df.dropna(axis=1)
print("列削除後:n", df_dropped_cols)

dropna()メソッドを使用します。axis=0(デフォルト)で行を、axis=1で列を削除します。

2. 平均値/中央値/最頻値による補完

数値データの場合、欠損値をその列の平均値、中央値、または最頻値で補完する方法が一般的です。これらの手法は実装が容易で、計算コストも低いです。ただし、データの分布によっては、これらの統計量で補完することがデータの特性を歪める可能性があります。

  • 平均値補完: 分布が正規分布に近い場合に有効ですが、外れ値の影響を受けやすいという欠点があります。
  • 中央値補完: 外れ値の影響を受けにくいため、データの分布が歪んでいる場合や外れ値が存在する場合に有効です。
  • 最頻値補完: カテゴリカルデータに特に有効ですが、数値データにも適用可能です。

コード例 (Pandas):

# 平均値で補完
df_filled_mean = df.fillna(df.mean())
print("平均値補完後:n", df_filled_mean)

# 中央値で補完
df_filled_median = df.fillna(df.median())
print("中央値補完後:n", df_filled_median)

# 最頻値で補完 (カテゴリカルデータや数値データに適用可能)
# 例として、'A'列の最頻値で補完
mode_a = df['A'].mode()[0] # mode()はSeriesを返すので[0]で最初の値を取得
df_filled_mode_a = df.copy()
df_filled_mode_a['A'].fillna(mode_a, inplace=True)
print("最頻値補完後 (A列):n", df_filled_mode_a)

fillna()メソッドを使用します。補完したい値として、df.mean()df.median()、またはdf['列名'].mode()[0]などを指定します。

3. 前の値/後の値による補完

時系列データなど、データの順序が意味を持つ場合に有効な手法です。欠損値を直前の観測値(Forward Fill)または直後の観測値(Backward Fill)で補完します。

  • Forward Fill (ffill): 欠損値を直前の有効な値で埋めます。
  • Backward Fill (bfill): 欠損値を直後の有効な値で埋めます。

コード例 (Pandas):

# Forward Fillで補完
df_ffill = df.fillna(method='ffill')
print("Forward Fill補完後:n", df_ffill)

# Backward Fillで補完
df_bfill = df.fillna(method='bfill')
print("Backward Fill補完後:n", df_bfill)

fillna()メソッドのmethod引数に'ffill'または'bfill'を指定します。

4. 線形補間による補完

数値データで、隣接する観測値の間で値が線形に変化すると仮定して補完する手法です。時系列データや連続的なデータに対して有効です。

コード例 (Pandas):

# 線形補間による補完
df_interpolated = df.interpolate(method='linear')
print("線形補間補完後:n", df_interpolated)

interpolate()メソッドを使用します。method='linear'を指定することで線形補間が実行されます。

5. 機械学習モデルを用いた補完

より高度な手法として、他の特徴量を用いて欠損値を予測し、補完する方法があります。K近傍法(KNN)、回帰モデル(線形回帰、ランダムフォレストなど)などが利用されます。この手法は、特徴量間の関係性を考慮するため、より精度の高い補完が期待できますが、計算コストが増加し、実装も複雑になります。

K近傍法 (KNN) による補完 (scikit-learn):

from sklearn.impute import KNNImputer

# サンプルデータフレームの作成 (数値データのみ)
data_knn = {'A': [1, 2, np.nan, 4, 5],
            'B': [np.nan, 2, 3, 4, 5],
            'C': [1, 2, 3, np.nan, 5]}
df_knn = pd.DataFrame(data_knn)

# KNNImputerの初期化と実行
# n_neighbors: 近傍点の数
imputer = KNNImputer(n_neighbors=2)
df_imputed_knn = pd.DataFrame(imputer.fit_transform(df_knn), columns=df_knn.columns)
print("KNN補完後:n", df_imputed_knn)

sklearn.impute.KNNImputerを使用します。n_neighborsで近傍点の数を指定します。

6. 特定の値による補完

欠損値が特定の意味を持つ場合(例: 「不明」「該当なし」など)、それらの値で直接補完することも有効です。

コード例 (Pandas):

# 特定の値で補完 (例: -1で補完)
df_filled_specific = df.fillna(-1)
print("特定の値(-1)で補完後:n", df_filled_specific)

fillna()メソッドに補完したい値を直接指定します。

補完手法の選択

どの補完手法を選択するかは、データの性質、欠損のパターン、分析の目的によって異なります。以下の点を考慮して選択することが推奨されます。

  • データの種類: 数値データかカテゴリカルデータか。
  • 欠損のパターン: ランダムに発生しているか、特定の条件で発生しているか。
  • データの分布: 外れ値の有無、正規分布からの乖離度。
  • データの量: データ量が少ない場合は、削除は避けるべきです。
  • 分析の目的: 探索的データ分析か、精度の高い予測モデル構築か。

一般的には、まず単純な手法(平均値、中央値、最頻値)から試し、結果が芳しくなければより複雑な手法(時系列補間、機械学習モデル)を検討するというステップを踏むのが良いでしょう。

まとめ

Pythonには、欠損値を補完するための多様な手法が用意されています。Pandasライブラリのfillna()interpolate()、Scikit-learnライブラリのKNNImputerなどを活用することで、データ分析の質を向上させることができます。各手法の特性を理解し、データセットに最適な方法を選択することが、データサイエンスにおける重要なスキルとなります。