論文・記事に 「教師あり学習」「教師なし学習」「強化学習」「分類」「回帰」「特徴量」「過学習」「汎化」「バイアス-バリアンス」「損失関数」「ハイパーパラメータ」「交差検証」「訓練/検証/テスト」 として登場する機械学習の中核概念群。 個別のモデル(決定木・SVM・NN等)を学ぶ前に押さえるべき基礎の集合体です。
論文記事から各用語のリンクをクリックすると、 該当箇所が開きます:
機械学習は「データからパターンを学習する」技術。 古典統計と異なり、 「予測精度」を最優先し、 大量のデータと計算資源を使うのが特徴。 タスクの種類で大きく 3 つに分類されます。
| 学習タイプ | 入力 | 出力 | 代表タスク |
|---|---|---|---|
| 教師あり | $(\boldsymbol{x}_i, y_i)$ ペア | $\hat{y}$ の予測 | 分類・回帰 |
| 教師なし | $\boldsymbol{x}_i$ のみ | 構造の発見 | クラスタリング・次元削減 |
| 強化学習 | 状態 $s$、 行動 $a$ | 方策 $\pi(a|s)$ | ロボット制御、ゲーム |
| 半教師あり | 少数 $(x,y)$ + 多数 $x$ | 同上 | ラベル付けコスト削減 |
| 自己教師あり | $\boldsymbol{x}_i$ のみ | x 内部から擬似ラベル | 事前学習(BERT/GPT等) |
入力 $\boldsymbol{x}$ と正解ラベル $y$ のペアから、 $\boldsymbol{x} \to y$ の写像を学ぶ。 機械学習の最も基本的かつ実用的なパラダイム。
データセット $\mathcal{D} = \{(\boldsymbol{x}_i, y_i)\}_{i=1}^N$ から、 損失 $L(y, f(\boldsymbol{x}))$ を最小化するモデル $f$ を学ぶ:
$$ \hat{f} = \arg\min_f \frac{1}{N}\sum_{i=1}^N L(y_i, f(\boldsymbol{x}_i)) + \lambda \Omega(f) $$
$\Omega(f)$ は正則化項(次節)。 教師ありの「種類」は y の型で決まります:
| タスク | $y$ の型 | 代表手法 | 代表的損失 |
|---|---|---|---|
| 回帰 | 連続値 | 線形回帰、 Ridge、 LASSO、 GBM | MSE、 MAE |
| 2値分類 | {0, 1} | Logistic、 SVM、 RF、 XGBoost | クロスエントロピー、 Hinge |
| 多クラス分類 | {1, ..., K} | Softmax 回帰、 NN | カテゴリカル交差エントロピー |
| 順序回帰 | 順序付きラベル | Ordinal Logistic | 専用損失 |
ラベルなしのデータ $\boldsymbol{x}_i$ から、 「データの構造」を発見する。 「何を予測するか」が明示されない探索的タスク。
エージェントが環境と相互作用して、 累積報酬を最大化する方策を学ぶ。 ゲーム AI、 ロボット制御、 推薦システムなどで活躍。
代表アルゴリズム:Q学習、 SARSA、 DQN、 Policy Gradient、 PPO、 Actor-Critic。 多腕バンディット問題(UCB、 Thompson Sampling)は強化学習の最も基本的な定式化。
機械学習の最重要規律。 データを 3 つに分けて、 役割を明確にします:
| 分割 | 用途 | 通常の割合 |
|---|---|---|
| 訓練(train) | モデルパラメータの学習 | 60〜80% |
| 検証(validation) | ハイパラ調整、 モデル選択 | 10〜20% |
| テスト(test) | 最終評価(1回だけ) | 10〜20% |
⚠️ テストデータでハイパラ調整するのは禁忌(データリーク)。 テストデータは「公開モデルの最終評価のために 1 回だけ触る」。 何度も使うと「テストにフィットしたモデル」になり、 真の汎化性能が分からなくなる。
k-fold 交差検証は、 train/validation を k 回ローテーションして安定したハイパラ調整を行う手法(詳細は 評価指標 #cv)。
1 2 3 4 5 6 7 8 9 | from sklearn.model_selection import train_test_split # 80% train+valid, 20% test X_temp, X_test, y_temp, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y) # 上の 80% を 75% train, 25% valid に分割(全体の 60/20/20 になる) X_train, X_valid, y_train, y_valid = train_test_split(X_temp, y_temp, test_size=0.25, random_state=42, stratify=y_temp) print(f'train={{len(X_train)}}, valid={{len(X_valid)}}, test={{len(X_test)}}') |
機械学習の中核問題。 訓練データだけで完璧に予測できても、 未知データで失敗するモデルは無価値。
原因:(1) モデルが複雑すぎる、 (2) 訓練データが少なすぎる、 (3) ノイズに過剰適合、 (4) 特徴量が多すぎる(次元の呪い)。
| 状態 | 訓練誤差 | 検証誤差 | 対策 |
|---|---|---|---|
| 未学習 | 高 | 高 | モデル複雑化、 特徴量増、 学習時間延長 |
| 良好 | 低 | 低 | そのまま |
| 過学習 | 低 | 高 | 正則化、 データ増、 早期停止、 シンプル化 |
予測誤差は数学的に 3 成分に分解できます:
$$ \mathbb{E}[(y - \hat{f}(\boldsymbol{x}))^2] = \underbrace{(\mathbb{E}[\hat{f}] - f)^2}_{\text{Bias}^2} + \underbrace{\mathrm{Var}(\hat{f})}_{\text{Variance}} + \underbrace{\sigma^2_\varepsilon}_{\text{Noise}} $$
これがいわゆるバイアス-バリアンスのトレードオフ。 モデルを複雑にすれば バイアス↓ だが バリアンス↑。 シンプルにすれば バイアス↑ だが バリアンス↓。 最適は両者の和が最小になる点。
「予測 $\hat{y}$ と正解 $y$ のズレ」を測る関数。 機械学習は損失を最小化する最適化問題として定式化されます。
| タスク | 損失 | 公式 |
|---|---|---|
| 回帰 | MSE | $\frac{1}{n}\sum (y_i - \hat{y}_i)^2$ |
| 回帰(ロバスト) | MAE、 Huber | $\frac{1}{n}\sum |y_i - \hat{y}_i|$ |
| 2値分類 | クロスエントロピー(Log Loss) | $-\sum [y \log \hat{p} + (1-y)\log(1-\hat{p})]$ |
| 多クラス分類 | Categorical Cross-Entropy | $-\sum_k y_k \log \hat{p}_k$ |
| SVM | ヒンジ損失 | $\max(0, 1 - y \hat{f})$ |
| ランキング | Pairwise / NDCG 損失 | 専用 |
勾配降下法で損失を最小化します。 学習率 $\eta$、 勾配 $\nabla L$ で:$\boldsymbol{\theta} \leftarrow \boldsymbol{\theta} - \eta \nabla L$。
モデル学習前に決める「設定値」。 学習中に最適化されるパラメータ(重み $\boldsymbol{w}$ など)と区別。 例:
ハイパラ探索手法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | from sklearn.model_selection import GridSearchCV, RandomizedSearchCV from sklearn.ensemble import RandomForestClassifier param_grid = {{ 'n_estimators': [100, 200, 500], 'max_depth': [3, 5, 10, None], 'min_samples_split': [2, 5, 10] }} gs = GridSearchCV(RandomForestClassifier(), param_grid, cv=5, scoring='f1', n_jobs=-1) gs.fit(X_train, y_train) print(gs.best_params_, gs.best_score_) # Optuna でベイズ最適化 import optuna def objective(trial): params = {{ 'n_estimators': trial.suggest_int('n_estimators', 50, 500), 'max_depth': trial.suggest_int('max_depth', 2, 32), }} return cross_val_score(RandomForestClassifier(**params), X, y, cv=5).mean() study = optuna.create_study(direction='maximize') study.optimize(objective, n_trials=100) |
過学習を防ぐ最も基本的な手法。 損失関数に「モデルの複雑さペナルティ」を加える:
$$ L_{\text{total}} = L_{\text{data}} + \lambda \Omega(\boldsymbol{w}) $$
詳細は regularization グループ、 Ridge、 LASSO。
| ❌ 誤解 | ✅ 正しい理解 |
|---|---|
| 訓練データの精度が高ければ良いモデル | 過学習を疑う。 検証データ・テストデータで評価必須 |
| 複雑なモデルほど良い | バリアンスが増え、 汎化性能が下がる |
| ハイパラ調整はテストデータでやる | データリーク。 検証データ or CV を使う |
| 機械学習=何でも学習できる | 良いデータ・特徴量・問題設計が前提 |
| 教師なし学習は教師ありの劣化版 | 役割が違う。 探索・発見のための強力な道具 |
| 特徴量は機械的に作れば良い | ドメイン知識に基づく特徴量エンジニアリングが性能に直結 |
| 深層学習なら常に最強 | テーブルデータでは GBM(XGBoost等)が勝つことが多い |
過学習の典型例。 対策:(1) モデル複雑度を下げる(決定木なら深さ制限)、 (2) 正則化を強める、 (3) 訓練データを増やす、 (4) 特徴量を減らす、 (5) Early Stopping、 (6) アンサンブル化(バギング等)、 (7) クロスバリデーションで安定性確認。
必ずしも。 確認事項:(1) 解釈性が必要なら LR の方が良い、 (2) 本番推論時間を考慮、 (3) 標準偏差も見る(0.85±0.05 vs 0.72±0.01 なら微妙)、 (4) ドメイン知識から見て予測根拠が妥当か、 (5) 過学習していないか。 ML は「精度だけ」ではなく実務制約を含めて判断。
モデルは平均的には正しい答えに近い予測をするが、 訓練データが変わると予測が大きく揺れる。 つまり過学習傾向。 対策:シンプルなモデル、 正則化、 データ増加、 アンサンブル(特にバギングはバリアンスを下げる)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import pandas as pd from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.cluster import KMeans from sklearn.model_selection import cross_val_score df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932') # 前処理... X = df[['L322101','L322108','L322102']].values # 家計3項目 X_std = StandardScaler().fit_transform(X) # 教師あり:東日本/西日本 を予測 # y = ... # scores = cross_val_score(LogisticRegression(), X_std, y, cv=5, scoring='f1') # 教師なし:47県を3クラスタに km = KMeans(n_clusters=3, random_state=42, n_init=10).fit(X_std) print(km.labels_) |
「教師あり 2値分類タスク(n=1500、 陽性比率 12%)に対し、 Logistic Regression、 Random Forest、 XGBoost を比較。 train/valid/test = 60/20/20 で分割(stratify)。 検証データでハイパラを Optuna で 100 trial 探索後、 5-fold CV による評価:XGBoost AUC=0.87±0.02、 RF=0.84±0.02、 LR=0.78±0.01。 最終テストでは XGBoost が AUC=0.86、 F1=0.62。 バイアス・バリアンス的に XGBoost は他より高いバリアンスが疑われたため、 アーリーストッピング適用。」
研究や PoC を超えて本番運用まで考えると、 ライフサイクルは長くなります。
これら全体を回す技術が MLOps。
SSDSE-B-2026(47都道府県、 2023年)から、 家計消費3項目(魚介・肉・野菜)を使い、 教師あり分類(東日本/西日本)と教師なしクラスタリング(3群)を実行して比較します。 ここでは scikit-learn の標準API でパイプラインを組みます。
1 2 3 4 5 6 7 8 9 10 11 12 | import pandas as pd from sklearn.preprocessing import StandardScaler df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', header=1) # 2023年のみ抽出 df23 = df[df['年度']==2023].copy() X = df23[['L322101', 'L322102', 'L322108']].values X_std = StandardScaler().fit_transform(X) # 西日本(関西以西)を1、東日本を0としてラベル化(仮の例) west = ['京都府','大阪府','兵庫県','奈良県','和歌山県','鳥取県','島根県','岡山県','広島県','山口県','徳島県','香川県','愛媛県','高知県','福岡県','佐賀県','長崎県','熊本県','大分県','宮崎県','鹿児島県','沖縄県'] y = df23['都道府県'].isin(west).astype(int).values print(X_std.shape, y.sum()) # (47,3) 22 |
SSDSE-B 47県の家計消費(魚介・肉・野菜)から「西日本かどうか」を予測した場合、 5-fold CV の F1 はおよそ 0.62〜0.70 程度。 47サンプルと小さいため標準偏差が大きく出ます。 過学習を防ぐため LogisticRegression(C=1.0) のような弱い正則化が安全です。
3クラスタに分けると、 都市圏グループ(東京・大阪等)、 北海道・東北グループ、 西日本郊外グループの3群が抽出されることが多い。 シルエット係数(sklearn.metrics.silhouette_score)が 0.3 を超えれば、 ある程度クラスタが分離できていると判断できる。
| 観点 | 教師あり(Logistic) | 教師なし(KMeans) |
|---|---|---|
| 目的 | 西/東 を当てる | 県の自然なグループを発見 |
| 評価 | F1, AUC, accuracy | シルエット係数、 Davies-Bouldin |
| サンプル数依存 | 小さいと不安定(n=47) | クラスタ数依存だが教師ありより頑健 |
| 解釈 | 係数で「どの食品が西日本性に効くか」分かる | クラスタ中心で「各群の食生活の特徴」が分かる |
💡 得られる洞察:47県という小データの場合、 教師ありは小サンプルゆえに過学習しやすく、 むしろ教師なしクラスタリングのほうが「県の食文化の構造」を素直に表現することが多い。 これはまさにML設計の核心。
「複数のハイパラ設定をテストデータで評価し、 最も良いものを選ぶ」のは典型的なデータリーク。 テストデータが間接的に学習に使われ、 報告する精度が楽観バイアスを持ちます。 対策は train / valid / test の 3分割 または nested CV。 validで選び、 testは最後に1度だけ評価。 Kaggle で「ローカル CV と public LB の差が大きい」現象も、 多くはこれが原因。
StandardScaler().fit_transform(X_all) → 分割、 は テストデータの平均・分散が学習に漏れる 古典的バグ。 必ず train で fit してtestには transform のみ。 scikit-learn の Pipeline + cross_val_score を使えば自動的に正しい順序で実行される。 これは時系列CVでも同じ。
陽性率 1% のデータで「全て陰性」と予測するモデルでも accuracy = 99%。 一見高精度に見えても完全に無能。 不均衡データでは F1, AUC-ROC, AUC-PR, balanced accuracy を使う。 また、 訓練時には class_weight='balanced' や SMOTE / undersampling を検討。 業務指標(コストマトリクス)に直結する評価軸を選ぶことが大事。
時系列で train_test_split(shuffle=True) を使うと、 未来の情報で過去を予測するという「タイムトラベル」が発生し、 精度が異常に高く見える。 必ず TimeSeriesSplit や Walk-Forward Validation を使い、 train は test より時間的に前のデータだけにする。 同様の問題は「同じユーザーが train/test 両方に出る」場合にも発生し、 GroupKFold が必要。
本番運用では、 推論速度・モデルサイズ・解釈性・公平性(fairness)・データドリフト耐性も同じくらい重要。 例:医療診断 AI で AUC が高くても、 黒人患者に対する性能が極端に低い場合、 倫理的に運用できない。 「精度シングルメトリック思考」を脱却し、 多次元評価ダッシュボードを作るのがプロの態度です。
論文ベンチで SOTA な Transformer も、 中小企業の 1万行テーブルデータでは XGBoost に負けることが多い。 まずはベースライン(線形回帰・決定木)から始め、 段階的に複雑化するのが鉄則。 各段階で「複雑化のコスト(学習時間・解釈不能性)」と「精度向上」を天秤にかける。 Occam's Razor は ML でも有効です。
「深層学習は特徴量を自動的に学ぶ」は画像・音声・自然言語では真。 しかしテーブルデータでは人間の知識による特徴設計(比率・差分・対数変換・カテゴリ変数の集約・時間ラグ等)が予測精度に最も効きます。 ドメイン知識を持つ人と協働するのが、 結局のところ最強の戦略です。
同じ「教師あり 2値分類」でも、 ライブラリと API スタイルによって書き方が大きく変わります。 ここでは scikit-learn / xgboost / lightgbm / pytorch の4種類の最小コードを示します。
1 2 3 4 5 6 7 8 9 10 11 | from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.model_selection import GridSearchCV pipe = Pipeline([('sc', StandardScaler()), ('clf', LogisticRegression(max_iter=1000))]) grid = GridSearchCV(pipe, {'clf__C': [0.01, 0.1, 1, 10]}, cv=5, scoring='f1') grid.fit(X_train, y_train) print(grid.best_params_, grid.best_score_) |
1 2 3 4 5 6 7 | import xgboost as xgb model = xgb.XGBClassifier(n_estimators=500, max_depth=4, learning_rate=0.05, eval_metric='logloss', early_stopping_rounds=20) model.fit(X_train, y_train, eval_set=[(X_valid, y_valid)], verbose=False) print(model.best_iteration, model.best_score) |
1 2 3 4 5 | import lightgbm as lgb model = lgb.LGBMClassifier(n_estimators=500, learning_rate=0.05) model.fit(X_train, y_train, categorical_feature=['region'], eval_set=[(X_valid, y_valid)]) print(model.feature_importances_) |
MLの予測結果を、 統計検定で「ベースラインより有意に良いか」確かめたい場面では scipy.stats が活躍。
1 2 3 4 5 | from scipy import stats # 2つのモデルの CV スコア(5回ずつ)を Wilcoxon 検定で比較 scores_a = [0.82, 0.85, 0.83, 0.84, 0.86] scores_b = [0.78, 0.80, 0.79, 0.81, 0.80] print(stats.wilcoxon(scores_a, scores_b)) |
テーブルデータでも、 特徴量が多くなったら PyTorch でカスタムNNを書く価値があります。
1 2 3 4 5 6 7 8 9 | import torch, torch.nn as nn class MLP(nn.Module): def __init__(self, d): super().__init__() self.net = nn.Sequential(nn.Linear(d, 64), nn.ReLU(), nn.Dropout(0.3), nn.Linear(64, 1)) def forward(self, x): return self.net(x).squeeze(-1) model = MLP(d=10) |