データの前処理の重要性
Il 特徴エンジニアリング そして データの前処理 これらは最も重要な段階です あらゆる機械学習プロジェクトの。不文律によると、データ サイエンティストの時間の 80% は はデータの準備に費やされ、モデリングには 20% のみが費やされます。どれだけ洗練されているかは関係ありません アルゴリズム: 入力データが汚い、不完全、または表現が不十分な場合、モデルは出力を行います。 悪い結果。ゴミが入って、ゴミが出る。
前処理では、生データをアルゴリズムに適した形式に変換します。特徴量エンジニアリングは次のものを超えます。 ドメインの知識を使用して既存の変数から新しい変数を作成してキャプチャします アルゴリズムだけでは見つけられない関係。これらの段階が一体となって成功を決定します または ML プロジェクトの失敗。
この記事で学べること
- 欠損値を処理するためのテクニック
- カテゴリ変数のエンコーディング
- 数値特徴のスケーリングと正規化
- 外れ値の検出と管理
- ドメインの知識を活用して新しい機能を作成する
- scikit-learn を使用したパイプラインの前処理
欠損値の処理
実際のデータには、ほとんどの場合次のものが含まれます。 欠損値 (NaN、null)。主な戦略 3つあります: 除去 (欠損値が多すぎる行または列を削除します)、 統計的補完 (平均、中央値、または最頻値に置き換えます) e 予測代入 (モデルを使用して欠損値を予測します)。選択は欠落データの量によって決まります そして、欠落しているパターン(ランダムまたは系統的)によっても異なります。
import pandas as pd
import numpy as np
from sklearn.impute import SimpleImputer, KNNImputer
# Dataset con valori mancanti
data = pd.DataFrame({
'eta': [25, 30, np.nan, 45, 35, np.nan, 28, 50],
'reddito': [30000, np.nan, 45000, 60000, np.nan, 55000, 32000, 70000],
'categoria': ['A', 'B', 'A', np.nan, 'B', 'A', 'B', 'A'],
'target': [0, 1, 0, 1, 1, 0, 1, 0]
})
print("Valori mancanti per colonna:")
print(data.isnull().sum())
print(f"\nPercentuale mancanti:\n{(data.isnull().mean() * 100).round(1)}")
# Strategia 1: Imputazione con media/mediana
imputer_mean = SimpleImputer(strategy='mean')
data['eta_imputed'] = imputer_mean.fit_transform(data[['eta']])
imputer_median = SimpleImputer(strategy='median')
data['reddito_imputed'] = imputer_median.fit_transform(data[['reddito']])
# Strategia 2: Imputazione con KNN (usa i vicini)
knn_imputer = KNNImputer(n_neighbors=3)
numeric_cols = data[['eta', 'reddito']].values
imputed_knn = knn_imputer.fit_transform(numeric_cols)
# Strategia 3: Imputazione categoriche con moda
imputer_mode = SimpleImputer(strategy='most_frequent')
data['categoria_imputed'] = imputer_mode.fit_transform(data[['categoria']])
print("\nDopo imputazione:")
print(data[['eta_imputed', 'reddito_imputed', 'categoria_imputed']].head())
カテゴリ変数のエンコーディング
ML アルゴリズムは文字列ではなく数値を処理します。カテゴリ変数は変換する必要があります 数値形式で。の ラベルエンコーディング 各カテゴリに整数を割り当てます (A=0、B=1、C=2): シンプルですが、存在しない順序が導入されます。の ワンホットエンコーディング バイナリ列を作成します カテゴリごとに: 順序は導入されませんが、高いカテゴリを持つ多数の列が生成されます。 カーディナリティ。の ターゲットエンコーディング 各カテゴリを目標平均値に置き換えます そのカテゴリの場合: 強力ですが、過剰適合の危険があります。
from sklearn.preprocessing import (
LabelEncoder, OneHotEncoder, OrdinalEncoder,
StandardScaler, MinMaxScaler, RobustScaler
)
from sklearn.compose import ColumnTransformer
import pandas as pd
import numpy as np
# Dataset di esempio
df = pd.DataFrame({
'colore': ['rosso', 'blu', 'verde', 'rosso', 'blu'],
'taglia': ['S', 'M', 'L', 'XL', 'M'],
'prezzo': [10.5, 25.0, 45.0, 80.0, 22.0],
'peso': [100, 500, 1200, 3000, 450]
})
# One-Hot per colore (nominale, no ordine)
ohe = OneHotEncoder(sparse_output=False, drop='first')
colore_encoded = ohe.fit_transform(df[['colore']])
print(f"One-Hot colore:\n{colore_encoded}")
# Ordinal per taglia (ordinale, ha un ordine)
oe = OrdinalEncoder(categories=[['S', 'M', 'L', 'XL']])
taglia_encoded = oe.fit_transform(df[['taglia']])
print(f"\nOrdinal taglia: {taglia_encoded.flatten()}")
# --- SCALING ---
# StandardScaler: media=0, std=1 (per distribuzioni normali)
ss = StandardScaler()
prezzo_standard = ss.fit_transform(df[['prezzo']])
# MinMaxScaler: range [0,1] (per distribuzioni non normali)
mms = MinMaxScaler()
prezzo_minmax = mms.fit_transform(df[['prezzo']])
# RobustScaler: usa mediana e IQR (robusto a outlier)
rs = RobustScaler()
peso_robust = rs.fit_transform(df[['peso']])
print(f"\nStandard: {prezzo_standard.flatten().round(2)}")
print(f"MinMax: {prezzo_minmax.flatten().round(2)}")
print(f"Robust: {peso_robust.flatten().round(2)}")
外れ値の検出
Gli 外れ値 それらは、残りのデータから大きく逸脱した外れ値です。 それらは、測定エラー、破損したデータ、または真の極値である可能性があります。方法 IQR (四分位間 範囲) 第 1 四分位または第 3 四分位の IQR の 1.5 倍を超えるポイントとして外れ値を識別します。 方法 Zスコア しきい値 (通常は 3) を超える標準化された値を持つポイントを識別します。 ザ」孤立の森 デシジョン ツリーを使用して外れ値を分離する ML アプローチです。 ランダム。
機能の選択
すべての機能がモデルにプラスに寄与するわけではありません。無関係または冗長な機能は、 パフォーマンスが低下し、トレーニングが遅くなります。そこには 機能の選択 それらを識別します より有益な変数。方法には次のようなものがあります。 相関 (機能を大幅に削除 相互に関連しています)、 分散しきい値 (分散の低い特徴を削除)、 セレクトKベスト (統計的検定に従って最適な K を選択します) と特徴の重要度 ランダムフォレスト著。
scikit-learn を使用したパイプラインの前処理
Le パイプライン scikit-learn の前処理とモデリングのステップを 1 つに連結します オブジェクト。これにより、 データ漏洩 (テストセットからの情報が汚染した場合) トレーニング)、相互検証と導入を簡素化します。の 列トランスフォーマー 許可します 異なる列に異なる変換を適用します。
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score
import pandas as pd
import numpy as np
# Dataset realistico
np.random.seed(42)
n = 200
df = pd.DataFrame({
'eta': np.random.randint(18, 70, n).astype(float),
'reddito': np.random.normal(40000, 15000, n),
'esperienza': np.random.randint(0, 30, n).astype(float),
'citta': np.random.choice(['Milano', 'Roma', 'Napoli', 'Torino'], n),
'titolo_studio': np.random.choice(['Diploma', 'Laurea', 'Master'], n),
'target': np.random.randint(0, 2, n)
})
# Inserire valori mancanti random
for col in ['eta', 'reddito', 'esperienza']:
mask = np.random.random(n) < 0.1
df.loc[mask, col] = np.nan
# Definire colonne per tipo
numeric_features = ['eta', 'reddito', 'esperienza']
categorical_features = ['citta', 'titolo_studio']
# Preprocessing per numeriche: imputa + scala
numeric_transformer = Pipeline([
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
# Preprocessing per categoriche: imputa + one-hot
categorical_transformer = Pipeline([
('imputer', SimpleImputer(strategy='most_frequent')),
('onehot', OneHotEncoder(drop='first', handle_unknown='ignore'))
])
# ColumnTransformer combina tutto
preprocessor = ColumnTransformer(transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)
])
# Pipeline completa: preprocessing + modello
full_pipeline = Pipeline([
('preprocessor', preprocessor),
('classifier', RandomForestClassifier(n_estimators=100, random_state=42))
])
# Cross-validation (il preprocessing avviene DENTRO ogni fold)
X = df.drop('target', axis=1)
y = df['target']
scores = cross_val_score(full_pipeline, X, y, cv=5, scoring='accuracy')
print(f"Accuracy: {scores.mean():.3f} (+/- {scores.std():.3f})")
漏洩日: 前処理 (スケーリング、代入) が必要です dopo の これまでにない、トレーニングとテストの分割。データセット全体にスケールする場合、テスト セットはスケーラー パラメーターに影響します。 scikit-learn パイプラインは、fit_transform を トレーニング セットとテスト セットでの変換。
重要なポイント
- 前処理は最も重要なフェーズです。時間の 80% がデータの準備に費やされます。
- 欠損値: コンテキストに応じた削除、統計的または予測的代入
- エンコーディング: 名詞の場合は One-Hot、序数の場合は Ordinal、ターゲット エンコーディングは注意が必要です
- スケーリング: 正規分布の場合は StandardScaler、外れ値の場合は RobustScaler
- Pipeline + ColumnTransformer でデータ漏洩を防ぎ、コードを簡素化
- 多くの場合、アルゴリズムの選択よりも、ドメイン知識を備えた特徴量エンジニアリングの方が違いを生みます。







