機械学習データ前処理の第一歩:欠損値の種類と対処法【Pandas入門】
データ前処理は、機械学習モデルの性能を最大化するために不可欠なステップです。収集された生データは、多くの場合、そのままではモデルに入力できません。その理由の一つとして、「欠損値」の存在が挙げられます。
この記事では、機械学習データ前処理の最初の壁とも言える「欠損値」に焦点を当てます。欠損値とは何か、なぜデータに欠損値が含まれるのか、そしてPythonの代表的なデータ分析ライブラリであるpandasを使って、どのように欠損値を見つけ、適切に処理するのかを、初心者の方にも分かりやすく解説します。
データ分析や機械学習プロジェクトに携わる上で、欠損値処理は避けて通れない重要なスキルです。ぜひこの記事を通じて、欠損値処理の基礎を習得してください。
欠損値とは何か?なぜ発生するのか?
「欠損値」(Missing Value)とは、データセットにおいて、特定の観測値に対応する特定の変数の値が存在しない状態を指します。簡単に言えば、「データがない」「空白になっている」状態です。
データに欠損値が含まれる理由は様々です。一般的な原因としては、以下のようなケースが考えられます。
- データ収集時の問題:
- アンケートの未回答項目
- センサーの故障や一時停止による測定不能
- 手入力時の誤りや抜け漏れ
- システムの記録ミス
- データ結合時の問題:
- 異なるデータソースを結合した際に、一方のデータにしか存在しないキーに対応する値
- データ処理時の問題:
- 計算結果が存在しない(例: ゼロ除算など)
これらの原因により、データセットには意図せず欠損値が含まれてしまうことがあります。
欠損値が機械学習モデルに与える影響
欠損値がそのままデータセットに含まれていると、機械学習モデルの学習や予測に悪影響を及ぼす可能性があります。
- モデルの学習エラー: 多くの機械学習アルゴリズムは、入力データに欠損値が含まれていると正常に動作しません。エラーが発生して学習が進まないか、または予期しない結果を招く可能性があります。
- 精度の低下: 欠損値はデータのパターンを歪ませる可能性があります。不完全なデータで学習されたモデルは、現実のデータに対する予測精度が低下する恐れがあります。
- バイアスの発生: 特定の条件で欠損が発生しやすい場合(例: 所得が低い人ほど特定の質問に答えないなど)、データに偏りが生じ、モデルが不正確な結論を導く可能性があります。
これらの問題を避けるために、データ前処理の段階で欠損値を適切に扱うことが非常に重要になります。
Pandasを使った欠損値の検出
まずは、データセットのどこに、どのくらいの欠損値があるのかを確認することから始めます。Pythonのpandasライブラリを使うと、簡単に欠損値を検出できます。
Pandasでは、欠損値は通常 NaN
(Not a Number) という特殊な値で表現されます。
サンプルデータの準備
欠損値を含むサンプルデータを作成してみましょう。
import pandas as pd
import numpy as np
# 欠損値を含むサンプルデータを作成
data = {
'ID': [1, 2, 3, 4, 5, 6],
'年齢': [25, 30, np.nan, 40, 35, np.nan],
'売上': [1000, 1500, 1200, np.nan, 1800, 1300],
'地域': ['東京', '大阪', '名古屋', '東京', '大阪', '福岡'],
'評価': [5, 4, 5, 3, 4, np.nan]
}
df = pd.DataFrame(data)
print("--- 元のデータフレーム ---")
print(df)
--- 元のデータフレーム ---
ID 年齢 売上 地域 評価
0 1 25.0 1000.0 東京 5.0
1 2 30.0 1500.0 大阪 4.0
2 3 NaN 1200.0 名古屋 5.0
3 4 40.0 NaN 東京 3.0
4 5 35.0 1800.0 大阪 4.0
5 6 NaN 1300.0 福岡 NaN
np.nan
が欠損値を表しています。「年齢」「売上」「評価」の各列に欠損値が含まれていることが分かります。
欠損値の確認方法
Pandas DataFrameには、欠損値であるかどうかを判定する isnull()
または isna()
メソッドが用意されています。これらは欠損値がある場合に True
、ない場合に False
を返す真偽値のDataFrameを生成します。
print("\n--- isnull() の結果 ---")
print(df.isnull())
--- isnull() の結果 ---
ID 年齢 売上 地域 評価
0 False False False False False
1 False False False False False
2 False True False False False
3 False False True False False
4 False False False False False
5 False True False False True
この真偽値のDataFrameに対して sum()
メソッドを使うと、列ごとの欠損値の合計数を簡単に確認できます。True
は数値の1として扱われるため、合計値を算出できます。
print("\n--- 列ごとの欠損値数 ---")
print(df.isnull().sum())
--- 列ごとの欠損値数 ---
ID 0
年齢 2
売上 1
地域 0
評価 1
dtype: int64
この結果から、「年齢」列に2個、「売上」列に1個、「評価」列に1個の欠損値があることが明確に分かります。まずこのステップで、どの列にどれだけ欠損があるかを把握することが、欠損値処理の最初の重要な作業となります。
Pandasを使った欠損値の対処法
欠損値が検出されたら、次にどのように処理するかを検討します。欠損値の対処法はいくつかありますが、ここでは代表的な2つの方法を紹介します。
- 欠損値を含む行や列を削除する
- 欠損値を他の値で補完する(Imputation)
どちらの方法を選択するかは、欠損値の量、データの内容、分析やモデルの目的によって異なります。
1. 欠損値を含む行や列を削除する
欠損値が非常に少ない場合や、特定の列(変数)の欠損値が多すぎる場合は、その行や列を削除するという選択肢があります。
- 欠損値を含む行を削除:
dropna()
メソッドを使います。引数にaxis=0
を指定するか省略すると、行単位で処理が行われます。how='any'
(デフォルト) は1つでも欠損値があればその行を削除、how='all'
は全ての値が欠損値の場合にその行を削除します。
print("\n--- 欠損値を含む行を削除 (any) ---")
df_dropped_rows = df.dropna(how='any')
print(df_dropped_rows)
--- 欠損値を含む行を削除 (any) ---
ID 年齢 売上 地域 評価
0 1 25.0 1000.0 東京 5.0
1 2 30.0 1500.0 大阪 4.0
4 5 35.0 1800.0 大阪 4.0
欠損値が含まれていたインデックス2, 3, 5の行が削除されました。
- 欠損値を含む列を削除:
dropna()
メソッドにaxis=1
を指定します。
print("\n--- 欠損値を含む列を削除 (any) ---")
# サンプルデータ(df)は変更せずにコピーを使用
df_dropped_cols = df.copy().dropna(axis=1, how='any')
print(df_dropped_cols)
--- 欠損値を含む列を削除 (any) ---
ID 地域
0 1 東京
1 2 大阪
2 3 名古屋
3 4 東京
4 5 大阪
5 6 福岡
「年齢」「売上」「評価」列に欠損値があったため、これらの列が削除されました。
削除はシンプルですが、データ量が減ってしまうというデメリットがあります。特にデータ量が少ない場合は、多くの情報を失うことになるため慎重に判断する必要があります。
2. 欠損値を他の値で補完する (Imputation)
欠損値を削除せずに、他の値で埋める(補完する)方法です。これにより、データ量を維持できます。補完する値としては、その列の平均値、中央値、最頻値などがよく使われます。
Pandasでは fillna()
メソッドを使って欠損値を補完できます。
- 特定の定数で補完: 例えば、数値列の欠損値を0で埋めるなど。
print("\n--- 欠損値を0で補完 (売上列) ---")
# 元のデータフレームをコピーして使用
df_filled_zero = df.copy()
df_filled_zero['売上'] = df_filled_zero['売上'].fillna(0)
print(df_filled_zero)
--- 欠損値を0で補完 (売上列) ---
ID 年齢 売上 地域 評価
0 1 25.0 1000.0 東京 5.0
1 2 30.0 1500.0 大阪 4.0
2 3 NaN 1200.0 名古屋 5.0
3 4 40.0 0.0 東京 3.0
4 5 35.0 1800.0 大阪 4.0
5 6 NaN 1300.0 福岡 NaN
- 列の平均値で補完: 数値データの場合によく使われます。
print("\n--- 欠損値を平均値で補完 (年齢列) ---")
df_filled_mean = df.copy()
mean_age = df_filled_mean['年齢'].mean() # 平均値を計算
df_filled_mean['年齢'] = df_filled_mean['年齢'].fillna(mean_age)
print(df_filled_mean)
--- 欠損値を平均値で補完 (年齢列) ---
ID 年齢 売上 地域 評価
0 1 25.000000 1000.0 東京 5.0
1 2 30.000000 1500.0 大阪 4.0
2 3 32.500000 1200.0 名古屋 5.0
3 4 40.000000 NaN 東京 3.0
4 5 35.000000 1800.0 大阪 4.0
5 6 32.500000 1300.0 福岡 NaN
平均値 (25 + 30 + 40 + 35) / 4 = 32.5
で欠損値が補完されていることが分かります。
- 列の中央値で補完: 外れ値の影響を受けにくい補完方法です。
print("\n--- 欠損値を中央値で補完 (売上列を再補完) ---")
df_filled_median = df.copy()
median_sales = df_filled_median['売上'].median() # 中央値を計算
df_filled_median['売上'] = df_filled_median['売上'].fillna(median_sales)
print(df_filled_median)
--- 欠損値を中央値で補完 (売上列を再補完) ---
ID 年齢 売上 地域 評価
0 1 25.0 1000.00 東京 5.0
1 2 30.0 1500.00 大阪 4.0
2 3 NaN 1200.00 名古屋 5.0
3 4 40.0 1300.00 東京 3.0
4 5 35.0 1800.00 大阪 4.0
5 6 NaN 1300.00 福岡 NaN
売上の中央値 (1000, 1200, 1300, 1500, 1800)
は 1300.0 です。欠損値が1300.0で補完されています。
- 列の最頻値で補完: カテゴリデータ(文字列やカテゴリ型)の場合によく使われます。
print("\n--- 欠損値を最頻値で補完 (評価列) ---")
df_filled_mode = df.copy()
mode_rating = df_filled_mode['評価'].mode()[0] # 最頻値を計算 (結果はシリーズなので最初の要素 [0] を取得)
df_filled_mode['評価'] = df_filled_mode['評価'].fillna(mode_rating)
print(df_filled_mode)
--- 欠損値を最頻値で補完 (評価列) ---
ID 年齢 売上 地域 評価
0 1 25.0 1000.0 東京 5.0
1 2 30.0 1500.0 大阪 4.0
2 3 NaN 1200.0 名古屋 5.0
3 4 40.0 NaN 東京 3.0
4 5 35.0 1800.0 大阪 4.0
5 6 NaN 1300.0 福岡 5.0
評価の最頻値は 5.0 と 4.0 ですが、mode()
は複数の最頻値がある場合でもリスト(シリーズ)で返します。ここでは最初の最頻値である 5.0 で補完しています。
補完方法を選ぶ際は、その値がデータ分布に与える影響を考慮する必要があります。平均値や中央値での補完はシンプルですが、実際のデータには存在しない値で埋めることになる場合もあります。より高度な補完方法として、機械学習モデルを使って欠損値を予測する方法などもありますが、入門としてはこれらの基本的な方法を理解することが重要です。
なお、fillna()
メソッドは元のDataFrameを変更しません。変更を反映させたい場合は、結果を新しい変数に代入するか、inplace=True
引数を使用します(ただし、inplace=True
は非推奨になりつつあるため、結果を代入する方が一般的です)。
まとめ
この記事では、機械学習データ前処理における「欠損値」の基本について解説しました。
- 欠損値とは、データが存在しない状態であり、様々な原因で発生します。
- 欠損値は機械学習モデルの精度低下やエラーの原因となるため、適切な処理が必要です。
- Pandasを使うと、
isnull()
やsum()
で欠損値の場所と数を簡単に確認できます。 - 欠損値の対処法としては、
dropna()
による行/列の削除、またはfillna()
による値の補完が基本的な手法です。 - 補完には、平均値、中央値、最頻値などがよく利用されます。
欠損値処理はデータ分析パイプラインの重要な一部です。ここで紹介した基本的な検出方法と処理方法を理解し、ご自身のデータに適用できるようになることが、機械学習活用に向けた大きな一歩となります。
次に、データ前処理の別の重要なステップである「外れ値」や「カテゴリ変数」の処理についても学んでいきましょう。