scikit-learn-machine-learning について
Python で古典的な機械学習モデルを構築する開発者やデータ担当者向けに、scikit-learn のワークフローを解説します。前処理、教師あり・教師なし学習、評価、再現可能なパイプラインを扱います。
主な機能
- 01スケーリング・エンコード・欠損値補完
- 02分類・回帰モデル
- 03クラスタリングと次元削減
- 04交差検証とハイパーパラメータ調整
- 05前処理とモデルのパイプライン
- 06モデル評価と特徴選択
活用シーン
- 01ラベル付きデータで分類器を学習
- 02連続値の結果を予測
- 03クラスタリングで未ラベル標本を分類
- 04交差検証によるモデル比較と調整
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ jaechang-hits/ sciagent-skills --skill scikit-learn-machine-learningインストール後、Claude Code で/scikit-learn-machine-learningを入力して読み込まれたか確認します。
詳細
scikit-learn
概要
scikit-learn は、古典的な機械学習の標準的な Python ライブラリです。教師あり学習(分類、回帰)、教師なし学習(クラスタリング、次元削減)、モデル評価、前処理のための一貫性のある API を提供し、NumPy/pandas のワークフローにシームレスに統合できます。
使用する場面
- ラベル付きデータを使った分類モデルの構築(スパム検出、疾患診断、種の識別)
- 回帰による連続値の予測(価格予測、用量反応モデリング)
- ラベルのないデータをグループにクラスタリング(患者の層別化、遺伝子発現クラスタ)
- 可視化や特徴量エンジニアリングのための次元削減(マルチオミクスデータに対する PCA、t-SNE)
- 交差検証によるモデル性能の評価と比較
- ハイパーパラメーターの体系的な調整(グリッドサーチ、ランダムサーチ)
- 前処理とモデリングのステップを組み合わせた、再現性のある ML パイプラインの構築
- ディープラーニングのタスク(画像、NLP)には、代わりに
pytorchまたはtransformersを使用します - 大規模な勾配ブースティングには、代わりに
xgboostまたはlightgbmを使用します
前提条件
- Python パッケージ:
scikit-learn、numpy、pandas - 任意:可視化には
matplotlib、seaborn - データ:NumPy 配列または pandas DataFrame 形式の表形式データ
pip install scikit-learn numpy pandas matplotlib seaborn
クイックスタート
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score, classification_report
from sklearn.datasets import load_breast_cancer
# Load dataset, split, train, evaluate in 10 lines
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
clf = RandomForestClassifier(n_estimators=100, random_state=42)
clf.fit(X_train, y_train)
y_pred = clf.predict(X_test)
print(f"Accuracy: {accuracy_score(y_test, y_pred):.3f}")
print(classification_report(y_test, y_pred, target_names=["malignant", "benign"]))
コア API
モジュール 1:データの前処理
スケーリング、エンコーディング、欠損値補完、特徴量エンジニアリング。
from sklearn.preprocessing import StandardScaler, MinMaxScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
import numpy as np
# Scaling: zero mean, unit variance
X = np.array([[1, 2], [3, 4], [5, 6]])
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
print(f"Mean: {X_scaled.mean(axis=0)}, Std: {X_scaled.std(axis=0)}")
# Mean: [0. 0.], Std: [1. 1.]
# Imputation: fill missing values
X_missing = np.array([[1, np.nan], [3, 4], [np.nan, 6]])
imputer = SimpleImputer(strategy="median")
X_filled = imputer.fit_transform(X_missing)
print(f"Filled:\n{X_filled}")
from sklearn.preprocessing import OneHotEncoder, OrdinalEncoder, LabelEncoder
# One-hot encoding for nominal categories
enc = OneHotEncoder(sparse_output=False, handle_unknown="ignore")
X_cat = np.array([["red"], ["blue"], ["green"], ["red"]])
X_encoded = enc.fit_transform(X_cat)
print(f"Categories: {enc.categories_}")
print(f"Encoded shape: {X_encoded.shape}") # (4, 3)
モジュール 2:教師あり学習 — 分類
離散的なターゲットを予測する分類器。
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
# Compare classifiers
classifiers = {
"LogisticRegression": LogisticRegression(max_iter=200),
"RandomForest": RandomForestClassifier(n_estimators=100, random_state=42),
"SVM": SVC(kernel="rbf", C=1.0),
"GradientBoosting": GradientBoostingClassifier(n_estimators=100, random_state=42),
}
for name, clf in classifiers.items():
clf.fit(X_train, y_train)
print(f"{name}: accuracy = {clf.score(X_test, y_test):.3f}")
モジュール 3:教師あり学習 — 回帰
連続値のターゲットを予測する回帰器。
from sklearn.linear_model import LinearRegression, Ridge, Lasso, ElasticNet
from sklearn.ensemble import RandomForestRegressor
from sklearn.datasets import make_regression
from sklearn.metrics import mean_squared_error, r2_score
X, y = make_regression(n_samples=200, n_features=10, noise=10, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
models = {
"Linear": LinearRegression(),
"Ridge": Ridge(alpha=1.0),
"Lasso": Lasso(alpha=0.1),
"RandomForest": RandomForestRegressor(n_estimators=100, random_state=42),
}
for name, model in models.items():
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(f"{name}: RMSE={mean_squared_error(y_test, y_pred, squared=False):.2f}, R²={r2_score(y_test, y_pred):.3f}")
モジュール 4:教師なし学習 — クラスタリング
ラベルのないデータに対するクラスタリングアルゴリズム。
from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering
from sklearn.metrics import silhouette_score
from sklearn.datasets import make_blobs
X, y_true = make_blobs(n_samples=300, centers=4, random_state=42)
# K-Means with elbow method
for k in [2, 3, 4, 5, 6]:
km = KMeans(n_clusters=k, random_state=42, n_init=10)
labels = km.fit_predict(X)
sil = silhouette_score(X, labels)
print(f"k={k}: silhouette={sil:.3f}, inertia={km.inertia_:.1f}")
# DBSCAN — no need to specify k
from sklearn.cluster import DBSCAN
db = DBSCAN(eps=0.5, min_samples=5)
labels = db.fit_predict(X)
n_clusters = len(set(labels)) - (1 if -1 in labels else 0)
n_noise = (labels == -1).sum()
print(f"DBSCAN: {n_clusters} clusters, {n_noise} noise points")
モジュール 5:次元削減
可視化や特徴量削減のための PCA、t-SNE などの手法。
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
from sklearn.datasets import load_digits
X, y = load_digits(return_X_y=True)
print(f"Original shape: {X.shape}") # (1797, 64)
# PCA — preserve 95% variance
pca = PCA(n_components=0.95)
X_pca = pca.fit_transform(X)
print(f"PCA: {X_pca.shape[1]} components, explained variance: {pca.explained_variance_ratio_.sum():.3f}")
# t-SNE — 2D visualization
tsne = TSNE(n_components=2, perplexity=30, random_state=42)
X_tsne = tsne.fit_transform(X)
print(f"t-SNE shape: {X_tsne.shape}") # (1797, 2)
モジュール 6:モデルの評価と選択
交差検証、評価指標、ハイパーパラメーター調整。
from sklearn.model_selection import cross_val_score, GridSearchCV, StratifiedKFold
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.datasets import load_iris
X, y = load_iris(return_X_y=True)
# Cross-validation
clf = RandomForestClassifier(n_estimators=100, random_state=42)
scores = cross_val_score(clf, X, y, cv=StratifiedKFold(5), scoring="accuracy")
print(f"CV accuracy: {scores.mean():.3f} ± {scores.std():.3f}")
# Hyperparameter tuning with GridSearchCV
param_grid = {
"n_estimators": [50, 100, 200],
"max_depth": [5, 10, None],
"min_samples_split": [2, 5]
}
grid = GridSearchCV(
RandomForestClassifier(random_state=42),
param_grid, cv=5, scoring="accuracy", n_jobs=-1
)
grid.fit(X, y)
print(f"Best params: {grid.best_params_}")
print(f"Best score: {grid.best_score_:.3f}")
モジュール 7:パイプライン
前処理とモデルを連結し、データリークを防ぎます。
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 GradientBoostingClassifier
# Mixed-type preprocessing
numeric_features = ["age", "income"]
categorical_features = ["gender", "occupation"]
preprocessor = ColumnTransformer([
("num", Pipeline([
("imputer", SimpleImputer(strategy="median")),
("scaler", StandardScaler())
]), numeric_features),
("cat", Pipeline([
("imputer", SimpleImputer(strategy="most_frequent")),
("onehot", OneHotEncoder(handle_unknown="ignore"))
]), categorical_features),
])
pipe = Pipeline([
("preprocessor", preprocessor),
("classifier", GradientBoostingClassifier(random_state=42))
])
# pipe.fit(X_train, y_train); pipe.predict(X_test)
print("Pipeline steps:", [name for name, _ in pipe.steps])
一般的なワークフロー
ワークフロー 1:エンドツーエンドの分類
目的:データの読み込みから評価までを含む、分類の完全なワークフローです。
import pandas as pd
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report
from sklearn.datasets import load_breast_cancer
# Load data
X, y = load_breast_cancer(return_X_y=True, as_frame=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)
# Build pipeline
pipe = Pipeline([
("scaler", StandardScaler()),
("clf", RandomForestClassifier(n_estimators=200, random_state=42))
])
# Cross-validate
cv_scores = cross_val_score(pipe, X_train, y_train, cv=5, scoring="f1")
print(f"CV F1: {cv_scores.mean():.3f} ± {cv_scores.std():.3f}")
# Final evaluation
pipe.fit(X_train, y_train)
y_pred = pipe.predict(X_test)
print(classification_report(y_test, y_pred))
ワークフロー 2:可視化を伴うクラスタリング
目的:データをクラスタリングし、次元削減を使って可視化します。
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
# Generate and scale data
X, _ = make_blobs(n_samples=500, centers=4, random_state=42)
X_scaled = StandardScaler().fit_transform(X)
# Cluster
km = KMeans(n_clusters=4, random_state=42, n_init=10)
labels = km.fit_predict(X_scaled)
print(f"Silhouette: {silhouette_score(X_scaled, labels):.3f}")
# Visualize
X_2d = PCA(n_components=2).fit_transform(X_scaled)
plt.scatter(X_2d[:, 0], X_2d[:, 1], c=labels, cmap="viridis", s=20, alpha=0.7)
plt.title("K-Means Clustering (PCA projection)")
plt.savefig("clustering_result.png", dpi=150, bbox_inches="tight")
print("Saved clustering_result.png")
ワークフロー 3:特徴量選択 + モデルパイプライン
目的:最適な特徴量を選択し、調整済みのモデルを構築します。
from sklearn.datasets import make_classification
from sklearn.feature_selection import SelectKBest, f_classif
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
X, y = make_classification(n_samples=500, n_features=50, n_informative=10, random_state=42)
pipe = Pipeline([
("scaler", StandardScaler()),
("selector", SelectKBest(f_classif)),
("svm", SVC(kernel="rbf"))
])
param_grid = {
"selector__k": [5, 10, 20],
"svm__C": [0.1, 1, 10],
"svm__gamma": ["scale", "auto"]
}
grid = GridSearchCV(pipe, param_grid, cv=5, scoring="accuracy", n_jobs=-1)
grid.fit(X, y)
print(f"Best params: {grid.best_params_}")
print(f"Best accuracy: {grid.best_score_:.3f}")
主なパラメーター
| パラメーター | モジュール | デフォルト | 範囲/オプション | 効果 |
|---|---|---|---|---|
n_estimators | RandomForest, GradientBoosting | 100 | 50-1000 | 木の数。増やすと性能は向上しますが、処理は遅くなります |
max_depth | Tree-based models | None | 1-50、None | 木の深さ。None は上限なし(過学習する可能性があります) |
C | SVM, LogisticRegression | 1.0 | 0.001-1000 | 正則化の強さ(逆数)。小さいほど正則化が強くなります |
alpha | Ridge, Lasso | 1.0 | 0.001-100 | 正則化の強さ。大きいほど正則化が強くなります |
n_clusters | KMeans | 必須 | 2-N | 形成するクラスタの数 |
eps | DBSCAN | 0.5 | 0.01-10 | 近傍の半径。小さいほどクラスタ数が増えます |
n_components | PCA | 必須 | 1-N または 0.0-1.0 | 残す成分。浮動小数点数の場合は分散比を表します |
perplexity | t-SNE | 30 | 5-50 | 局所構造と大域構造のバランスを調整します |
cv | GridSearchCV | 5 | 2-10 | 交差検証の分割数 |
scoring | GridSearchCV, cross_val_score | さまざま | accuracy、f1、roc_auc など | 評価指標 |
一般的なレシピ
レシピ:特徴量重要度の分析
使用する場面:モデルの予測にどの特徴量が影響しているかを把握します。
import numpy as np
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
X, y = load_iris(return_X_y=True)
clf = RandomForestClassifier(n_estimators=200, random_state=42).fit(X, y)
importances = clf.feature_importances_
indices = np.argsort(importances)[::-1]
feature_names = load_iris().feature_names
for i in range(X.shape[1]):
print(f"{feature_names[indices[i]]}: {importances[indices[i]]:.4f}")
レシピ:学習曲線による診断
使用する場面:過学習と未学習を診断します。
from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt
import numpy as np
train_sizes, train_scores, val_scores = learning_curve(
clf, X, y, cv=5, train_sizes=np.linspace(0.1, 1.0, 10), scoring="accuracy"
)
plt.plot(train_sizes, train_scores.mean(axis=1), label="Train")
plt.plot(train_sizes, val_scores.mean(axis=1), label="Validation")
plt.xlabel("Training size"); plt.ylabel("Accuracy"); plt.legend()
plt.savefig("learning_curve.png", dpi=150, bbox_inches="tight")
print("Saved learning_curve.png")
レシピ:モデルの保存と読み込み
使用する場面:学習済みモデルを保存し、後で使用します。
import joblib
# Save
joblib.dump(pipe, "model_pipeline.joblib")
print("Model saved to model_pipeline.joblib")
# Load
loaded_pipe = joblib.load("model_pipeline.joblib")
y_pred = loaded_pipe.predict(X_test)
print(f"Loaded model predictions: {y_pred[:5]}")
トラブルシューティング
| 問題 | 原因 | 解決策 |
|---|---|---|
ConvergenceWarning | モデルが収束しませんでした | max_iter を増やす(例:1000)か、StandardScaler で特徴量をスケーリングします |
| 訓練精度が高く、テスト精度が低い | 過学習 | 正則化を追加し、max_depth を小さくして、交差検証を使用します |
ValueError: unknown categories | テストデータに新しいカテゴリが含まれています | OneHotEncoder(handle_unknown='ignore') を使用します |
大規模データで MemoryError が発生する | データセット全体をメモリに読み込んでいます | インクリメンタル学習には SGDClassifier/MiniBatchKMeans を使用します |
| クラスタリング結果が良くない | 特徴量がスケーリングされていない、または k が適切でない | まず特徴量をスケーリングし、シルエットスコアを使って最適な k を見つけます |
NotFittedError | fit の前に予測しています | まず model.fit(X_train, y_train) を呼び出します |
| 実行ごとに結果が異なる | random_state が設定されていません | モデルと train_test_split で random_state=42 を設定します |
| GridSearchCV の処理が遅い | パラメーターグリッドが大きすぎます | RandomizedSearchCV または HalvingGridSearchCV を使用し、n_jobs=-1 を追加します |
参考資料
- scikit-learn ユーザーガイド — 公式ドキュメント
- scikit-learn API リファレンス — API 全般
- scikit-learn サンプルギャラリー — チュートリアル
- Pedregosa et al. (2011). Scikit-learn: Machine Learning in Python. JMLR 12:2825-2830.
コメント
Markdown 対応