付録A. 前処理と特徴量選択¶
本付録では、機械学習モデルの性能を大きく左右する 前処理 と 特徴量選択 について学びます。実務では、モデルの選択よりもデータの前処理に多くの時間を費やすことが一般的です。
A.1 前処理の重要性¶
A.1.1 なぜ前処理が必要か¶
実世界のデータは、そのままでは機械学習モデルに適用できないことがほとんどです。
graph LR
A[生データ] --> B[前処理]
B --> C[学習可能なデータ]
C --> D[機械学習モデル]
B --> B1[欠損値処理]
B --> B2[スケーリング]
B --> B3[エンコーディング]
B --> B4[特徴量選択]
style A fill:#ffcccc
style B fill:#ffffcc
style C fill:#ccffcc
style D fill:#e6f3ff
前処理が必要な理由
- 欠損値:データに空白や NaN が含まれていると、多くのモデルはエラーになる
- スケールの違い:特徴量ごとに値の範囲が大きく異なると、学習が不安定になる
- カテゴリ変数:文字列データは数値に変換しないとモデルが扱えない
- 外れ値:極端な値がモデルの学習を歪める可能性がある
前処理にかかる時間
一般的に、機械学習プロジェクトの 60〜80% の時間はデータの収集と前処理に費やされると言われています。
A.2 欠損値処理¶
A.2.1 欠損値の確認¶
欠損値を確認するためには、pandas の pd.DataFrame.isnull() メソッドを使用します。
import pandas as pd
import numpy as np
# 欠損値を含むサンプルデータ
df = pd.DataFrame({
'age': [25, 30, np.nan, 35, 40],
'salary': [300, np.nan, 400, 450, np.nan],
'city': ['Tokyo', 'Osaka', None, 'Tokyo', 'Fukuoka']
})
# 欠損値の確認
print(df.isnull().sum())
print(df.isnull().mean() * 100)
A.2.2 欠損値の削除¶
欠損値を含む行を削除するには pd.DataFrame.dropna() を使用します。
削除の注意点
欠損値の削除はデータ量を減らすため、データが少ない場合は慎重に判断が必要です。
A.2.3 欠損値の補完¶
欠損値を特定の値で埋めるには pd.DataFrame.fillna() を使用します。
# 数値列を平均値で補完
df['age'] = df['age'].fillna(df['age'].mean())
# 数値列を中央値で補完
df['salary'] = df['salary'].fillna(df['salary'].median())
# カテゴリ列を最頻値で補完
df['city'] = df['city'].fillna(df['city'].mode()[0])
A.2.4 scikit-learn による欠損値処理¶
scikit-learn の sklearn.impute.SimpleImputer() を使うと、より体系的に欠損値を処理できます。
from sklearn.impute import SimpleImputer
# 平均値で補完
imputer = SimpleImputer(strategy='mean')
df_imputed = imputer.fit_transform(df[['age', 'salary']])
A.3 スケーリング¶
A.3.1 スケーリングの必要性¶
特徴量のスケール(値の範囲)が大きく異なると、機械学習モデルの学習に悪影響を与えることがあります。
graph TB
A[スケーリング] --> B[標準化<br/>StandardScaler]
A --> C[正規化<br/>MinMaxScaler]
B --> B1[平均=0, 標準偏差=1<br/>に変換]
C --> C1[0〜1 の範囲<br/>に変換]
style A fill:#e6ccff
style B fill:#ccffcc
style C fill:#ffffcc
A.3.2 標準化(StandardScaler)¶
標準化は、データを平均 0、標準偏差 1 に変換します。
scikit-learn では sklearn.preprocessing.StandardScaler() を使います。
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
A.3.3 正規化(MinMaxScaler)¶
正規化は、データを 0〜1 の範囲に変換します。
scikit-learn では sklearn.preprocessing.MinMaxScaler() を使います。
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
X_scaled = scaler.fit_transform(X)
スケーリングの選び方
- StandardScaler:外れ値が少ない場合、多くの機械学習アルゴリズムで有効
- MinMaxScaler:外れ値がない場合、ニューラルネットワークでよく使用
A.4 エンコーディング¶
A.4.1 カテゴリ変数のエンコーディング¶
機械学習モデルは数値データしか扱えないため、カテゴリ変数を数値に変換する必要があります。
graph TB
A[エンコーディング] --> B[ラベルエンコーディング]
A --> C[One-Hot エンコーディング]
B --> B1["各カテゴリに整数を割り当て<br/>例: A→0, B→1, C→2"]
C --> C1["各カテゴリをバイナリ列に展開<br/>例: A→[1,0,0], B→[0,1,0]"]
style A fill:#e6ccff
style B fill:#ccffcc
style C fill:#ffffcc
A.4.2 ラベルエンコーディング¶
scikit-learn では sklearn.preprocessing.LabelEncoder() を使います。
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
df['city_encoded'] = le.fit_transform(df['city'])
A.4.3 One-Hot エンコーディング¶
pandas の pd.get_dummies() または scikit-learn の sklearn.preprocessing.OneHotEncoder() を使います。
import pandas as pd
# pandas の get_dummies を使用
df_encoded = pd.get_dummies(df, columns=['city'], drop_first=True)
from sklearn.preprocessing import OneHotEncoder
# scikit-learn の OneHotEncoder を使用
encoder = OneHotEncoder(sparse_output=False, drop='first')
encoded = encoder.fit_transform(df[['city']])
どちらを使うべきか
- ラベルエンコーディング:順序があるカテゴリ(小・中・大など)
- One-Hot エンコーディング:順序がないカテゴリ(色、地域など)
A.5 特徴量選択¶
A.5.1 特徴量選択とは¶
すべての特徴量が予測に役立つわけではありません。不要な特徴量を削除することで、モデルの性能向上や計算時間の短縮が期待できます。
A.5.2 分散による特徴量選択¶
分散が小さい(ほとんど同じ値)特徴量は予測に貢献しにくいため、削除候補となります。scikit-learn では sklearn.feature_selection.VarianceThreshold() を使います。
from sklearn.feature_selection import VarianceThreshold
selector = VarianceThreshold(threshold=0.1)
X_selected = selector.fit_transform(X)
A.5.3 相関による特徴量選択¶
目的変数との相関が高い特徴量を選択する方法です。
import pandas as pd
# 相関行列の計算
correlation = df.corr()
# 目的変数との相関を確認
print(correlation['target'].sort_values(ascending=False))
A.6 機械学習パイプライン¶
A.6.1 パイプラインとは¶
複数の前処理ステップとモデルを一連の流れとして管理できる仕組みです。
graph LR
A[生データ] --> B[欠損値処理]
B --> C[スケーリング]
C --> D[モデル学習]
D --> E[予測]
style A fill:#ffcccc
style B fill:#ffffcc
style C fill:#ffffcc
style D fill:#ccffcc
style E fill:#e6f3ff
A.6.2 scikit-learn の Pipeline¶
scikit-learn の sklearn.pipeline.Pipeline を使うと、複数の処理ステップを 1 つのオブジェクトにまとめられます。
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.impute import SimpleImputer
from sklearn.linear_model import LogisticRegression
# パイプラインの作成
pipeline = Pipeline([
('imputer', SimpleImputer(strategy='mean')),
('scaler', StandardScaler()),
('classifier', LogisticRegression())
])
# 学習
pipeline.fit(X_train, y_train)
# 予測
y_pred = pipeline.predict(X_test)
パイプラインの利点
- コードがすっきりする
- データ漏洩(data leakage)を防げる
- 交差検証との相性が良い
A.7 評価とモデル選択¶
A.7.1 交差検証¶
データを複数に分割し、それぞれで学習・評価を行うことで、モデルの汎化性能をより正確に評価できます。scikit-learn では sklearn.model_selection.cross_val_score() を使います。
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=5)
print(f"平均スコア: {scores.mean():.4f} (+/- {scores.std() * 2:.4f})")
A.7.2 グリッドサーチ¶
ハイパーパラメータの最適な組み合わせを探索する方法です。scikit-learn では sklearn.model_selection.GridSearchCV を使います。
from sklearn.model_selection import GridSearchCV
param_grid = {
'C': [0.1, 1, 10],
'kernel': ['linear', 'rbf']
}
grid_search = GridSearchCV(SVC(), param_grid, cv=5)
grid_search.fit(X_train, y_train)
print(f"最適なパラメータ: {grid_search.best_params_}")
A.8 まとめ¶
本付録では、機械学習における前処理と特徴量選択について学びました。
付録 A のまとめ
欠損値処理
.isnull()で欠損値を確認.dropna()で削除、.fillna()で補完SimpleImputerで体系的に処理
スケーリング
StandardScaler:標準化(平均0、標準偏差1)MinMaxScaler:正規化(0〜1の範囲)
エンコーディング
- ラベルエンコーディング:順序があるカテゴリ向け
- One-Hot エンコーディング:順序がないカテゴリ向け
パイプライン
- 複数の前処理とモデルを一連の流れで管理
- データ漏洩を防ぎ、コードを整理できる
モデル選択
- 交差検証で汎化性能を評価
- グリッドサーチでハイパーパラメータを最適化