Machine Learning: Scikit-learn入門 — 統一APIと初めての機械学習モデル完全ガイド
最終更新:2026-08-26
Scikit-learnの統一APIのおかげで、すべてのアルゴリズムは同じ方法で呼び出せます。1つ覚えれば、すべて使いこなせます。
1. この章で学ぶこと
- Scikit-learnの設計思想と統一API:fit → predict → score
- 3つのコアインターフェース:推定器(Estimator)、変換器(Transformer)、予測器(Predictor)
- 初めてのモデル:Irisデータセットで決定木分類器を訓練し、訓練-テスト分割 → fit → predict → 評価のフルワークフローを体験
- データ前処理パイプライン:StandardScaler + モデルを1つのオブジェクトにまとめる
- Bobの初挑戦:sklearnを使ってSalesPredictの小規模サンプルデータセットで簡単な予測を行う
2. 機械学習初心者のリアルな体験談
(1) 痛点:ライブラリごとにAPIが違う
Bobは3つの異なる機械学習ライブラリを試しましたが、それぞれ独自の呼び出し規約がありました。あるライブラリはtrain()を使い、別のライブラリはfit_model()を使い、さらにもう1つはlearn()を使っていました。呼び出し方を理解するだけでドキュメントを読むのに2日間もかかり、アルゴリズムを切り替えるたびに最初からやり直しでした。APIの不統一は、機械学習を始める上での最大の障壁です。
(2) Scikit-learnの解決策
Scikit-learnは統一されたAPI設計を定義しています。すべてのアルゴリズムがfit → predict → scoreのパターンに従います。アルゴリズムの切り替えは、たった1行の変更で済みます。
PYTHON
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
# Same API, different algorithm - just change the model class
models = {
"LinearRegression": LinearRegression(),
"RandomForest": RandomForestRegressor(n_estimators=100),
}
for name, model in models.items():
model.fit(X_train, y_train)
score = model.score(X_test, y_test)
print(f"{name}: R² = {score:.3f}")
(3) 効果:1つのAPIで30以上のアルゴリズムをカバー
Bobがsklearnの統一APIを習得したところ、30以上のアルゴリズムの呼び出し規約がすべて同じになりました。LinearRegressionからXGBoostまで、クラス名を入れ替えるだけで使えます。
3. Scikit-learnの設計思想と統一API
(1) 統一APIのパターン
graph LR
A[Estimator<br/>Base Class] --> B[Transformer<br/>fit + transform]
A --> C[Predictor<br/>fit + predict]
A --> D[Model<br/>fit + predict + score]
B --> E[StandardScaler<br/>PCA<br/>OneHotEncoder]
C --> F[KMeans<br/>DBSCAN]
D --> G[LinearRegression<br/>RandomForest<br/>SVM]
(2) 3つのコアインターフェース
| インターフェース | コアメソッド | 目的 | 例 |
|---|---|---|---|
| 推定器(Estimator) | fit(X, y) |
データからパラメータを学習する | すべてのモデルの基底クラス |
| 変換器(Transformer) | fit() + transform() + fit_transform() |
データ前処理 | StandardScaler, PCA |
| 予測器(Predictor) | fit() + predict() |
予測を生成する | LinearRegression, SVM |
▶ サンプル:推定器/変換器/予測器の使い方パターン
PYTHON
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
import numpy as np
# Generate sample data
rng = np.random.default_rng(42)
X = rng.uniform(0, 100, (200, 3))
y = 50 + 0.8 * X[:, 0] + 1.2 * X[:, 1] - 0.5 * X[:, 2] + rng.normal(0, 5, 200)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Transformer: StandardScaler
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train) # fit + transform in one step
X_test_scaled = scaler.transform(X_test) # only transform (use training stats)
# Predictor: LinearRegression
model = LinearRegression()
model.fit(X_train_scaled, y_train)
predictions = model.predict(X_test_scaled)
score = model.score(X_test_scaled, y_test)
print(f"R² score: {score:.4f}")
print(f"Coefficients: {model.coef_}")
print(f"Intercept: {model.intercept_:.2f}")
出力:
TEXT
📖 参照専用
# Executed successfully
4. 初めての機械学習モデル:Iris分類
(1) 機械学習の完全なワークフロー
▶ サンプル:Iris決定木分類のフルパイプライン
PYTHON
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
# Step 1: Load data
iris = load_iris()
X, y = iris.data, iris.target
print(f"Features: {iris.feature_names}")
print(f"Classes: {iris.target_names}")
print(f"Shape: {X.shape}")
# Step 2: Split train/test
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.3, random_state=42, stratify=y
)
print(f"Train: {X_train.shape[0]}, Test: {X_test.shape[0]}")
# Step 3: Train model
model = DecisionTreeClassifier(max_depth=3, random_state=42)
model.fit(X_train, y_train)
# Step 4: Predict
y_pred = model.predict(X_test)
# Step 5: Evaluate
acc = accuracy_score(y_test, y_pred)
print(f"\nAccuracy: {acc:.4f}")
print(f"\nClassification Report:\n{classification_report(y_test, y_pred, target_names=iris.target_names)}")
print(f"Confusion Matrix:\n{confusion_matrix(y_test, y_pred)}")
出力:
TEXT
📖 参照専用
Features: ['sepal length (cm)', 'sepal width (cm)', ...]
Classes: ['setosa' 'versicolor' 'virginica']
Shape: (150, 4)
Train: 105, Test: 45
Accuracy: 1.0000
▶ サンプル:決定木の可視化
PYTHON
from sklearn.tree import plot_tree
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(12, 8))
plot_tree(model, feature_names=iris.feature_names,
class_names=iris.target_names, filled=True, ax=ax)
plt.title("Iris Decision Tree (max_depth=3)")
plt.tight_layout()
plt.savefig("iris_tree.png", dpi=150)
出力:
TEXT
📖 参照専用
# Executed successfully
(2) train_test_splitの詳細な理解
| パラメータ | 意味 | 推奨値 |
|---|---|---|
| test_size | テストセットの割合 | 0.2〜0.3 |
| random_state | 乱数シード | 42(再現性のため) |
| stratify | 層化抽出 | 分類タスクでは必須 |
| shuffle | データをシャッフルするかどうか | デフォルトでTrue |
5. データ前処理パイプライン
(1) パイプラインが必要な理由
パイプラインは前処理とモデルを1つのユニットとしてまとめ、データリーク(テストセットの情報が訓練プロセスに漏洩すること)を防止します。
▶ サンプル:StandardScaler + モデルのパイプライン
PYTHON
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_iris
iris = load_iris()
X, y = iris.data, iris.target
# Build pipeline
pipe = Pipeline([
("scaler", StandardScaler()),
("classifier", LogisticRegression(max_iter=200)),
])
# Cross-validation with pipeline (no data leakage!)
scores = cross_val_score(pipe, X, y, cv=5, scoring="accuracy")
print(f"CV Accuracy: {scores.mean():.4f} +/- {scores.std():.4f}")
# Fit on full data and predict
pipe.fit(X, y)
new_sample = [[5.1, 3.5, 1.4, 0.2]]
prediction = pipe.predict(new_sample)
print(f"Prediction: {iris.target_names[prediction[0]]}")
出力:
TEXT
📖 参照専用
# Executed successfully
(2) パイプライン vs. 手動前処理
| 観点 | 手動前処理 | パイプライン |
|---|---|---|
| データリークのリスク | 高い(スケーラーをテストデータに誤ってfitしやすい) | 低い(パイプラインが自動的に分離) |
| コードの可読性 | 複数のステップに分散 | 1つのオブジェクトに集約 |
| 交差検証 | 手動でループが必要 | cross_val_score(pipe) |
| デプロイの容易さ | スケーラーとモデルを別々に保存する必要あり | 単一のパイプラインオブジェクトを保存 |
▶ サンプル:SalesPredictベースラインパイプライン
PYTHON
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
import pandas as pd
import numpy as np
# Simulate SalesPredict data
rng = np.random.default_rng(42)
n = 500
df = pd.DataFrame({
"ad_spend": rng.uniform(10, 100, n),
"traffic": rng.uniform(100, 1000, n),
"category": rng.choice(["Elec", "Cloth", "Food"], n),
"is_weekend": rng.choice([0, 1], n),
})
df["revenue"] = 50 + 0.8 * df["ad_spend"] + 0.1 * df["traffic"] + rng.normal(0, 10, n)
# Define feature groups
num_features = ["ad_spend", "traffic"]
cat_features = ["category", "is_weekend"]
# ColumnTransformer for mixed preprocessing
preprocessor = ColumnTransformer([
("num", StandardScaler(), num_features),
("cat", OneHotEncoder(drop="first"), cat_features),
])
# Full pipeline
pipe = Pipeline([
("preprocessor", preprocessor),
("model", LinearRegression()),
])
X = df.drop(columns=["revenue"])
y = df["revenue"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
pipe.fit(X_train, y_train)
score = pipe.score(X_test, y_test)
print(f"SalesPredict Baseline R²: {score:.4f}")
# Predict
sample = pd.DataFrame({"ad_spend": [50], "traffic": [500], "category": ["Elec"], "is_weekend": [1]})
pred = pipe.predict(sample)
print(f"Predicted revenue: {pred[0]:.1f} thousand USD")
出力:
TEXT
📖 参照専用
# Executed successfully
6. モデル評価の基本
(1) 分類 vs. 回帰の評価指標
| タスク | 指標 | 意味 | sklearnの関数 |
|---|---|---|---|
| 分類 | Accuracy | 正しく予測された割合 | accuracy_score |
| 分類 | Precision | 陽性と予測したうち真の陽性の割合 | precision_score |
| 分類 | Recall | 実際の陽性のうち正しく陽性と予測された割合 | recall_score |
| 分類 | F1 | PrecisionとRecallの調和平均 | f1_score |
| 回帰 | MAE | 平均絶対誤差 | mean_absolute_error |
| 回帰 | MSE | 平均二乗誤差 | mean_squared_error |
| 回帰 | R² | 決定係数 | r2_score |
▶ サンプル:回帰モデルの総合評価
PYTHON
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
import numpy as np
y_true = np.array([100, 150, 200, 250, 300])
y_pred = np.array([95, 160, 190, 260, 310])
mae = mean_absolute_error(y_true, y_pred)
mse = mean_squared_error(y_true, y_pred)
rmse = np.sqrt(mse)
r2 = r2_score(y_true, y_pred)
mape = np.mean(np.abs((y_true - y_pred) / y_true)) * 100
print(f"MAE: {mae:.2f} thousand USD")
print(f"RMSE: {rmse:.2f} thousand USD")
print(f"R²: {r2:.4f}")
print(f"MAPE: {mape:.1f}%")
出力:
TEXT
📖 参照専用
# Executed successfully
❓ よくある質問
Q fit_transformとtransformの違いは何ですか?
A fit_transform = fit + transformです。訓練セットで使用します(パラメータを学習し、変換を適用します)。transformは学習済みのパラメータを適用するだけで、テストセットに使用します。テストセットに対してfitを呼んではいけません。データリークの原因になります。
Q パイプラインを使うメリットは何ですか?
A 主なメリットは3つあります。1) データリークの防止(交差検証時にfit/transformを自動的に分離);2) コードの簡潔化(1つのオブジェクトにすべてのステップを包含);3) デプロイの容易化(pickleファイル1つの保存で済む)。
Q random_state=42とはどういう意味ですか?
A 再現性を確保するために乱数シードを設定しています。42は『銀河ヒッチハイク・ガイド』の「生命、宇宙、そして万物についての究極の疑問の答え」に由来するプログラミング文化の引用で、結果の品質には影響しません。
Q stratifyパラメータはいつ必要ですか?
A 分類タスクで必要です。stratify=yを指定すると、訓練セットとテストセットの両方でクラス分布が元のデータと一致するようになり、少数クラスがすべてテストセットに入ってしまうことを防ぎます。
Q cross_val_scoreのcv=5とはどういう意味ですか?
A 5分割交差検証を意味します。データを5つのフォールドに分割し、4つのフォールドで訓練、残りの1つのフォールドで検証を順番に行います。最終スコアは5つのフォールドすべての平均です。単一の訓練-テスト分割よりも信頼性が高いです。
Q ColumnTransformerとPipelineの違いは何ですか?
A Pipelineはステップを直列に連結します(あるステップの出力が次のステップの入力になる)。一方、ColumnTransformerは異なる列に対して異なる変換器を並列に適用し、結果を結合します。通常は両方を組み合わせて使用します。
📖 まとめ
- sklearnの統一API:推定器(fit) → 変換器(fit+transform) → 予測器(fit+predict+score)
- 機械学習の完全なワークフロー:データ読み込み → 訓練/テストに分割 → fitで訓練 → predictで予測 → scoreで評価
- パイプラインは前処理 + モデルを1つのユニットにまとめ、データリークを防止しデプロイを簡素化する
- ColumnTransformerは混合型の前処理を扱う(数値列にはStandardScaler、カテゴリ列にはOneHotEncoder)
- 分類の評価にはaccuracy/適合率/再現率/F1を、回帰の評価にはMAE/RMSE/R²/MAPEを使用する
- cross_val_scoreで交差検証を実行でき、単一の訓練/テスト分割よりも信頼性が高い
📝 練習問題
- 基礎(難易度 ⭐):sklearnでIrisデータセットを読み込み、LogisticRegression分類器を訓練してaccuracyを出力してください。ヒント:第4章の完全なワークフローに従ってください。
- 中級(難易度 ⭐⭐):パイプライン(StandardScaler + LogisticRegression)を構築し、5分割交差検証でスケーラーあり/なしのaccuracyを比較してください。ヒント:パイプラインと単体モデルのそれぞれでcross_val_scoreを実行してください。
- 挑戦(難易度 ⭐⭐⭐):ColumnTransformerを使ってSalesPredictデータの混合型パイプライン(数値列の標準化 + カテゴリ列のワンホットエンコーディング)を構築し、LinearRegressionモデルを訓練してR²とMAEを計算してください。ヒント:第5章のSalesPredictパイプラインのサンプルを参照してください。