深層学習②回帰

Categories:

第2章 機械学習:回帰

📚 この章の学習目標

  • 分類と回帰の違いを理解する
  • 線形回帰の基本原理とコスト関数を学ぶ
  • 勾配降下法による最適化手法を習得する
  • RSSとMSEの意味と計算方法を理解する
  • scikit-learnを用いた回帰モデルの実装を学ぶ
  • SGDRegressorによる確率的勾配降下法を実践する

🚀 イントロダクション

💡 分類から回帰へ

第1章では「カテゴリ」を予測する分類問題を学びました。第2章では「連続的な数値」を予測する回帰問題を学びます。

例:

  • 分類:この患者は病気か健康か?(カテゴリ)
  • 回帰:この患者の血糖値は何mg/dLか?(数値)

🔍 分類 vs 回帰

📊 分類(Classification)

分類の特徴

  • 目的:カテゴリやクラスにデータを分けること
  • ターゲット値:離散的なクラス(カテゴリ)を予測
  • 例:
  • メールがスパムかどうか(スパム or 正常)
  • 画像が犬か猫か(犬 or 猫)
  • がんの診断(悪性 or 良性)
  • 使用アルゴリズム:決定木、SVM、k-NN、ロジスティック回帰など

📈 回帰(Regression)

回帰の特徴

  • 目的:連続的な数値を予測すること
  • ターゲット値:連続的な数値を予測
  • 例:
  • 家の価格を予測(具体的な金額)
  • 将来の気温を予測(摂氏何度か)
  • 株価の予測(数値)
  • 使用アルゴリズム:線形回帰、リッジ回帰、ラッソ回帰、SVRなど

🔄 分類と回帰の違いまとめ

観点分類回帰
予測対象カテゴリ・ラベル連続的な数値
出力例「病気」「健康」「120mg/dL」
医療例病気の有無判定血糖値の予測
不動産例物件タイプ分類価格予測

📐 線形回帰(Linear Regression)

💡 線形回帰とは?

線形回帰は、1つまたは複数の特徴量(入力変数)とターゲット(出力変数)の間に線形関係があると仮定して、その関係を数式として表現する手法です。

線形回帰の基本数式

単純線形回帰(1つの特徴量):

y = w₀ + w₁·x

重回帰(複数の特徴量):

y = w₀ + w₁·x₁ + w₂·x₂ + w₃·x₃ + ... + wₙ·xₙ

変数の意味

  • y:予測したい値(従属変数)
  • x₁, x₂, …, xₙ:入力特徴量(独立変数)
  • w₀:切片(バイアス)
  • w₁, w₂, …, wₙ:回帰係数(重み)

🏠 マンション価格予測の例

単純線形回帰の例

マンション価格が面積のみで決定されると仮定すると:

価格 = w₀ + w₁ × 面積

目標:実際の価格と予測価格の誤差を最小化するw₀とw₁を見つけること

マンション価格
    ↑
    |        ● 実測値
    |     ●     /
    |  ●     / 予測線: y = w₀ + w₁·x
    | ●   /
    |● /
    |/____________→ 面積(m²)

💡 回帰の核心

最適な回帰モデルを作るということは、データ全体の残差(誤差値)の合計が最小になるモデルを作ることを意味します。

📉 誤差測定:RSSとMSE

RSS(Residual Sum of Squares):残差平方和

💡 RSSとは?

回帰モデルにおいて、予測値と実際の観測値との間の誤差の大きさを表す指標です。

各データポイントの誤差を二乗して合計します。

RSS の計算式:

RSS = Σ (実測値ᵢ - 予測値ᵢ)²
    = Σ (yᵢ - (w₀ + w₁·xᵢ))²

マンション価格の例:

RSS = (マンション1の実際価格 - 予測価格)²
    + (マンション2の実際価格 - 予測価格)²
    + (マンション3の実際価格 - 予測価格)²
    + ... (すべてのデータについて実行)

MSE(Mean Squared Error):平均二乗誤差

💡 MSEとは?

RSSを学習データの件数で割った値です。データ量が異なるモデルを比較する際に便利です。

MSE の計算式:

MSE = RSS / N = (1/N) × Σ (yᵢ - ŷᵢ)²

⚠️ 重要な理解

  • RSSとMSEは、w₀, w₁(回帰係数)を変数とする関数です
  • 学習データのxとyは定数として扱われます
  • 学習の目的は、RSSまたはMSEを最小化するw値を見つけることです

🧪 実習:糖尿病進行予測

🔬 糖尿病データセットの概要

scikit-learnに含まれる糖尿病データセットを使用して、1年後の糖尿病の進行状態を予測します。

データセットの詳細

項目内容
サンプル数442件
特徴量数10個(すべて正規化済み)
ターゲット糖尿病の進行度(連続値)

特徴量一覧:

  1. 年齢(Age)
  2. 性別(Sex)
  3. BMI(Body Mass Index:体格指数)
  4. 血圧(Blood Pressure)
  5. S1, S2, S3, S4, S5, S6(6つの血液検査結果)

📥 データセットの読み込み

from sklearn.datasets import load_diabetes
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
import numpy as np
import pandas as pd

# データセットの読み込み
diabetes = load_diabetes()
keys = diabetes.keys()
print('diabetes dataset keys:', keys)
# 出力結果
diabetes dataset keys: dict_keys(['data', 'target', 'frame', 'DESCR', 
'feature_names', 'data_filename', 'target_filename', 'data_module'])
features = diabetes.data
label = diabetes.target

print(type(features), features.shape)  # (442, 10)
print(type(label), label.shape)        # (442,)

📊 データフレームへの変換

# 特徴量をデータフレームに変換
X = pd.DataFrame(diabetes.data, columns=diabetes.feature_names)

# ターゲット値をSeriesに変換
y = pd.Series(diabetes.target)

print(X.head())  # 最初の5行を表示
print("--------------------------------")
print(y.head(10))  # 最初の10個のターゲット値を表示
# 出力例
        age       sex       bmi        bp        s1        s2        s3  \
0  0.038076  0.050680  0.061696  0.021872 -0.044223 -0.034821 -0.043401   
1 -0.001882 -0.044642 -0.051474 -0.026328 -0.008449 -0.019163  0.074412   
2  0.085299  0.050680  0.044451 -0.005670 -0.045599 -0.034194 -0.032356   
...

🎯 データの分離

X_train, X_test, y_train, y_test = train_test_split(
    X, y, 
    test_size=0.2,  # 20%をテストデータに
    random_state=11
)

🤖 モデルの学習と評価

# 線形回帰モデルの作成
lr_model = LinearRegression()

# モデルの学習
lr_model.fit(X_train, y_train)

# 予測
pred = lr_model.predict(X_test)

# 評価
mse = mean_squared_error(y_test, pred)
rmse = np.sqrt(mse)

print("Mean Squared Error (MSE):", round(mse, 2))
print("Root Mean Squared Error (RMSE):", round(rmse, 2))
# 出力結果
Mean Squared Error (MSE): 3212.59
Root Mean Squared Error (RMSE): 56.68

🔄 K-Fold交差検証による評価

from sklearn.model_selection import KFold

# K-Fold分割
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
cv_mse = []

# K-Fold交差検証
n_iter = 0
for train_index, test_index in kfold.split(features):
    X_train, X_test = features[train_index], features[test_index]
    y_train, y_test = label[train_index], label[test_index]

    # モデルの学習と予測
    lr_model = LinearRegression()
    lr_model.fit(X_train, y_train)
    pred = lr_model.predict(X_test)

    # MSE評価
    mse = mean_squared_error(y_test, pred)
    rmse = np.sqrt(mse)
    cv_mse.append(mse)

    n_iter += 1
    print(f'#{n_iter} Fold MSE: {round(mse, 2)}, RMSE: {round(rmse, 2)}')

# 全体の平均MSE
mean_mse = np.mean(cv_mse)
print(f"\nAverage MSE across all folds: {round(mean_mse, 2)}")

🎯 勾配降下法(Gradient Descent)

💡 勾配降下法とは?

コスト関数(MSEなど)を最小化するために、パラメータを反復的に更新していく最適化アルゴリズムです。

「山を下る」ように、誤差が小さくなる方向へ少しずつパラメータを調整します。

勾配降下法の仕組み

コスト関数
    ↑
    |     ●初期W
    |    /  \
    |   /    \勾配に沿って降下
    |  /      \
    | /        ●
    |/          \●
    |____________\●最小点→ w

勾配降下法のポイント

  1. 初期値:ランダムまたは0でwを初期化
  2. 勾配計算:コスト関数を微分して勾配を求める
  3. 更新:勾配の逆方向に少しずつwを移動
  4. 反復:収束するまで2-3を繰り返す

微分による最小値の探索

💡 なぜ微分を使うのか?

  • 微分は関数の増加・減少の方向性を示します
  • コスト関数を微分すると、どちらの方向に進めば誤差が減るかがわかります
  • 微分値が0に近づく点が、コスト関数の最小点です

更新式:

w_new = w_old - α × (∂MSE/∂w)

学習率(α)

  • 学習率が大きすぎると、最小点を飛び越えてしまう
  • 学習率が小さすぎると、収束に時間がかかる
  • 適切な学習率の設定が重要

🔀 SGDとMini-Batch GD

勾配降下法の3つのタイプ

タイプデータ使用量特徴
GD(Gradient Descent)全データ正確だが計算コストが高い
SGD(Stochastic GD)1サンプル高速だがノイズが多い
Mini-Batch GDバッチサイズ分バランスが良く、最も実用的

💡 実務での選択

一般的に、Mini-Batch GDがほとんどのディープラーニングフレームワークで採用されています。

Mini-Batchの動作

全体学習データ(400件)
    ↓
┌─────────────────────────────┐
│ Batch 1 (100件) → GD計算 → 更新 │
│ Batch 2 (100件) → GD計算 → 更新 │
│ Batch 3 (100件) → GD計算 → 更新 │
│ Batch 4 (100件) → GD計算 → 更新 │
└─────────────────────────────┘
          ↓
    1エポック完了

🔧 SGDRegressorによる実装

💡 SGDRegressorとは?

scikit-learnに含まれる確率的勾配降下法を使った回帰モデルです。

  • 大規模データセットに効率的
  • パラメータの細かい調整が可能
  • 学習率やイテレーション数を設定できる

基本的な実装

from sklearn.linear_model import SGDRegressor
from sklearn.model_selection import KFold

# K-Fold分割
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
cv_mse = []

# K-Fold交差検証
n_iter = 0
for train_index, test_index in kfold.split(X):
    X_train, X_test = X.iloc[train_index], X.iloc[test_index]
    y_train, y_test = y.iloc[train_index], y.iloc[test_index]

    # SGDRegressorモデル
    sgd_regressor = SGDRegressor(
        max_iter=2000,      # 最大イテレーション数
        tol=1e-3,           # 収束判定の閾値
        random_state=42
    )

    sgd_regressor.fit(X_train, y_train)
    pred = sgd_regressor.predict(X_test)

    # MSE評価
    mse = mean_squared_error(y_test, pred)
    rmse = np.sqrt(mse)
    cv_mse.append(mse)

    n_iter += 1
    print(f'#{n_iter} Fold MSE: {round(mse, 2)}, RMSE: {round(rmse, 2)}')

# 平均MSE
mean_mse = np.mean(cv_mse)
print(f"\nAverage MSE across all folds: {round(mean_mse, 2)}")

⚠️ 収束警告への対処

⚠️ ConvergenceWarning

「最大イテレーション回数に達しても収束しなかった」という警告が出る場合があります。

原因と対策:

  1. max_iterの増加
   SGDRegressor(max_iter=8000)
  1. 学習率の調整
   SGDRegressor(learning_rate='constant', eta0=0.001)
  1. 特徴量の標準化
   from sklearn.preprocessing import StandardScaler

   scaler = StandardScaler()
   X_scaled = scaler.fit_transform(X)

📊 特徴量標準化を含む改善版

from sklearn.preprocessing import StandardScaler

# 特徴量の標準化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# K-Fold交差検証
kfold = KFold(n_splits=5, shuffle=True, random_state=42)
cv_mse = []
n_iter = 0

for train_index, test_index in kfold.split(X_scaled):
    X_train, X_test = X_scaled[train_index], X_scaled[test_index]
    y_train, y_test = y.iloc[train_index], y.iloc[test_index]

    # 改善されたSGDRegressor
    sgd_regressor = SGDRegressor(
        max_iter=8000,
        tol=1e-3,
        learning_rate='constant',
        eta0=0.001,
        random_state=42
    )

    sgd_regressor.fit(X_train, y_train)
    pred = sgd_regressor.predict(X_test)

    mse = mean_squared_error(y_test, pred)
    rmse = np.sqrt(mse)
    cv_mse.append(mse)

    n_iter += 1
    print(f'#{n_iter} Fold MSE: {round(mse, 2)}, RMSE: {round(rmse, 2)}')

mean_mse = np.mean(cv_mse)
print(f"\nAverage MSE across all folds: {round(mean_mse, 2)}")

📊 結果の比較

LinearRegression vs SGDRegressor

モデル平均MSE特徴
LinearRegression約2900-3000正確、小規模データ向き
SGDRegressor(標準化なし)約3250収束しにくい
SGDRegressor(標準化あり)約2900-3000大規模データに効率的

💡 実務での選択

  • 小規模データ:LinearRegression(シンプルで高精度)
  • 大規模データ:SGDRegressor(メモリ効率が良い)
  • 必ず特徴量を標準化する(SGD系アルゴリズムでは必須)

🎯 実習課題

🎯 課題:カリフォルニア住宅価格の予測

課題内容:

California Housing Datasetを読み込んで、住宅価格を予測するSGDRegressorモデルを作成してください。

参考URL:
https://scikit-learn.org/1.5/modules/generated/sklearn.datasets.fetch_california_housing.html

要件:

  1. データセットの読み込みと基本情報の確認
  2. 特徴量の標準化処理
  3. LinearRegressionとSGDRegressorの両方で実装
  4. 5-fold交差検証による性能評価
  5. 両モデルの結果を比較・考察

ヒント:

from sklearn.datasets import fetch_california_housing

housing = fetch_california_housing()
print(housing.DESCR)  # データセットの説明を確認

評価指標:

  • MSE(Mean Squared Error)
  • RMSE(Root Mean Squared Error)
  • 各Foldごとの結果と平均値

📚 第2章のまとめ

🎯 第2章の重要ポイント

  • 回帰は連続的な数値を予測する機械学習手法
  • 線形回帰は入力と出力の線形関係をモデル化
  • RSS/MSEは誤差を測定するための指標
  • 勾配降下法はコスト関数を最小化する最適化手法
  • SGDは大規模データに効率的な学習アルゴリズム
  • 特徴量の標準化はSGD系アルゴリズムで重要

💡 次章への繋がり

第2章では数値予測のための回帰を学びました。次の第3章では、画像データを扱うための畳み込みニューラルネットワーク(CNN)の基礎を学びます。


→ 第3章 深層学習:CNN Ⅰ