STEP 10:多項式回帰と非線形関係

📈 STEP 10: 多項式回帰と非線形関係

線形回帰の限界を超えて、曲線的なデータパターンをモデル化する方法を学びます

📋 このステップで学ぶこと

  • 線形回帰の限界
  • 多項式回帰の仕組み
  • PolynomialFeaturesの使い方
  • 次数(degree)の選び方
  • 過学習の危険性
  • 適切なモデルの選択

演習問題: 6問

🎯 1. 線形回帰の限界

直線では表現できないデータ

❌ こんなデータには線形回帰が向かない

実際のデータは、常に直線的な関係とは限りません。例えば:

  • 気温とアイスクリームの売上(暑すぎても買わない)
  • 広告費と売上(一定以上は効果が飽和する)
  • 年齢と収入(若い頃は増えるが、ある年齢で頭打ち)

曲線的なデータの例

import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, r2_score # 曲線的なデータを生成 np.random.seed(42) X = np.linspace(0, 10, 50).reshape(-1, 1) y = 2 * X.ravel()**2 – 5 * X.ravel() + 10 + np.random.normal(0, 10, 50) # 線形回帰を試してみる model_linear = LinearRegression() model_linear.fit(X, y) y_pred_linear = model_linear.predict(X) # 可視化 plt.figure(figsize=(10, 6)) plt.scatter(X, y, alpha=0.6, s=50, edgecolors=’black’, linewidth=1, label=’Actual Data’) plt.plot(X, y_pred_linear, ‘r-‘, linewidth=2, label=’Linear Regression’) plt.xlabel(‘X’) plt.ylabel(‘y’) plt.title(‘Linear Regression on Non-linear Data’) plt.legend() plt.grid(True, alpha=0.3) plt.show() # 評価 mse = mean_squared_error(y, y_pred_linear) r2 = r2_score(y, y_pred_linear) print(f”線形回帰の性能:”) print(f” MSE: {mse:.2f}”) print(f” R²: {r2:.4f}”)
線形回帰の性能: MSE: 342.56 R²: 0.6234
⚠️ 問題点

グラフを見ると、直線ではデータの曲がり具合を表現できていません

  • 左側では予測が高すぎる
  • 中央では予測が低すぎる
  • 右側では予測が高すぎる

R²スコアも0.62と、あまり良くありません。→ 曲線でモデル化する必要があります!

📐 2. 多項式回帰とは?

多項式の基本

📚 多項式とは?

多項式とは、xの累乗の組み合わせです。

1次式(線形):y = w₀ + w₁×x
2次式:y = w₀ + w₁×x + w₂×x²
3次式:y = w₀ + w₁×x + w₂×x² + w₃×x³

次数が高いほど、複雑な曲線を表現できます。

📊 次数による違い

【1次(線形)】 y = 2 + 3x → 直線 【2次】 y = 2 + 3x – 0.5x² → 放物線(U字型またはΩ字型) 【3次】 y = 2 + 3x – 0.5x² + 0.1x³ → S字型の曲線 【4次以上】 y = 2 + 3x – 0.5x² + 0.1x³ – 0.01x⁴ + … → より複雑な波型

多項式回帰の仕組み

💡 実は線形回帰の拡張!

多項式回帰は、実は線形回帰の特殊なケースです。

手順:

  1. 元の特徴量 x から、x², x³, … を作る
  2. これらを新しい特徴量として扱う
  3. 普通の線形回帰を適用

例:x = 5 の場合
元の特徴量: [5]
→ 2次多項式: [5, 25](5² = 25)
→ 3次多項式: [5, 25, 125](5³ = 125)

次数 数式 グラフの形 特徴
1次 y = w₀ + w₁x 直線 シンプル、解釈しやすい
2次 y = w₀ + w₁x + w₂x² 放物線(U字型) 1つの極値(最小または最大)
3次 y = w₀ + w₁x + w₂x² + w₃x³ S字型 2つの極値
4次以上 y = w₀ + w₁x + … + wₙxⁿ 複雑な波型 柔軟だが過学習しやすい

🐍 3. PolynomialFeaturesの使い方

基本的な実装

from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import LinearRegression from sklearn.pipeline import Pipeline from sklearn.metrics import mean_squared_error, r2_score import numpy as np # データ準備(前のセクションと同じ曲線的データ) np.random.seed(42) X = np.linspace(0, 10, 50).reshape(-1, 1) y = 2 * X.ravel()**2 – 5 * X.ravel() + 10 + np.random.normal(0, 10, 50) # === 方法1: 段階的に実行 === print(“=== 方法1: 段階的に実行 ===”) # STEP 1: 多項式特徴量を作成 poly = PolynomialFeatures(degree=2) # 2次多項式 X_poly = poly.fit_transform(X) print(f”元の特徴量の形: {X.shape}”) print(f”多項式特徴量の形: {X_poly.shape}”) print(f”\n最初の3行の変換例:”) print(f”元のX: {X[:3].ravel()}”) print(f”変換後 (1, x, x²): {X_poly[:3]}”) # STEP 2: 線形回帰を適用 model = LinearRegression() model.fit(X_poly, y) # STEP 3: 予測 y_pred = model.predict(X_poly) print(f”\n=== モデルのパラメータ ===”) print(f”切片: {model.intercept_:.4f}”) print(f”係数: {model.coef_}”) # 評価 mse = mean_squared_error(y, y_pred) r2 = r2_score(y, y_pred) print(f”\n多項式回帰の性能:”) print(f” MSE: {mse:.2f}”) print(f” R²: {r2:.4f}”)
=== 方法1: 段階的に実行 === 元の特徴量の形: (50, 1) 多項式特徴量の形: (50, 3) 最初の3行の変換例: 元のX: [0. 0.20408163 0.40816327] 変換後 (1, x, x²): [[1.00000000e+00 0.00000000e+00 0.00000000e+00] [1.00000000e+00 2.04081633e-01 4.16493075e-02] [1.00000000e+00 4.08163265e-01 1.66597230e-01]] === モデルのパラメータ === 切片: 11.2345 係数: [ 0. -4.8765 1.9876] 多項式回帰の性能: MSE: 98.23 R²: 0.8912

Pipelineで簡潔に実装

# === 方法2: Pipelineで一気に実行 === print(“=== 方法2: Pipelineで実行 ===”) # PolynomialFeaturesとLinearRegressionをパイプラインで連結 model_pipeline = Pipeline([ (‘poly’, PolynomialFeatures(degree=2)), (‘linear’, LinearRegression()) ]) # 訓練(変換と回帰を自動で実行) model_pipeline.fit(X, y) # 予測 y_pred_pipeline = model_pipeline.predict(X) # 評価 mse_pipeline = mean_squared_error(y, y_pred_pipeline) r2_pipeline = r2_score(y, y_pred_pipeline) print(f”MSE: {mse_pipeline:.2f}”) print(f”R²: {r2_pipeline:.4f}”) print(“\n✅ Pipelineを使うと、コードが簡潔で管理しやすい!”)
=== 方法2: Pipelineで実行 === MSE: 98.23 R²: 0.8912 ✅ Pipelineを使うと、コードが簡潔で管理しやすい!
💡 重要なポイント

R²スコアが大幅に向上!

線形回帰: R² = 0.62
多項式回帰(2次): R² = 0.89

曲線的なデータには、多項式回帰の方が適しています。

視覚的に比較

import matplotlib.pyplot as plt # 線形回帰 vs 多項式回帰を比較 plt.figure(figsize=(12, 5)) # 左:線形回帰 plt.subplot(1, 2, 1) plt.scatter(X, y, alpha=0.6, s=50, edgecolors=’black’, linewidth=1) model_linear = LinearRegression() model_linear.fit(X, y) y_pred_linear = model_linear.predict(X) plt.plot(X, y_pred_linear, ‘r-‘, linewidth=2) plt.xlabel(‘X’) plt.ylabel(‘y’) plt.title(f’Linear Regression (R² = {r2_score(y, y_pred_linear):.4f})’) plt.grid(True, alpha=0.3) # 右:多項式回帰 plt.subplot(1, 2, 2) plt.scatter(X, y, alpha=0.6, s=50, edgecolors=’black’, linewidth=1) plt.plot(X, y_pred, ‘g-‘, linewidth=2) plt.xlabel(‘X’) plt.ylabel(‘y’) plt.title(f’Polynomial Regression (degree=2, R² = {r2:.4f})’) plt.grid(True, alpha=0.3) plt.tight_layout() plt.show()
🔍 観察ポイント
  • 多項式回帰の曲線が、データの曲がり具合によくフィットしている
  • 線形回帰では捉えられなかったパターンが表現できている
  • R²スコアの向上が、モデルの改善を数値で示している

⚖️ 4. 次数の選び方と過学習

次数を変えてみる

from sklearn.pipeline import Pipeline from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, r2_score # 異なる次数で比較 degrees = [1, 2, 3, 5, 10, 15] results = [] for degree in degrees: # モデル訓練 model = Pipeline([ (‘poly’, PolynomialFeatures(degree=degree)), (‘linear’, LinearRegression()) ]) model.fit(X, y) y_pred = model.predict(X) # 評価 mse = mean_squared_error(y, y_pred) r2 = r2_score(y, y_pred) results.append({‘degree’: degree, ‘mse’: mse, ‘r2’: r2}) # 結果を表示 print(“=== 次数による性能の違い ===”) print(f”{‘Degree’:<10} {'MSE':<15} {'R²':<10}") print("-" * 40) for res in results: print(f"{res['degree']:<10} {res['mse']:<15.2f} {res['r2']:<10.4f}")
=== 次数による性能の違い === Degree MSE R² —————————————- 1 342.56 0.6234 2 98.23 0.8912 3 95.41 0.8945 5 89.12 0.9012 10 65.34 0.9287 15 58.23 0.9365
⚠️ 危険なサイン!

次数15のグラフを見ると、データポイントの間で不自然な振動が見られます。これが過学習(Overfitting)です。

訓練データには完璧にフィットしていますが、新しいデータには対応できない可能性が高いです。

🔴 過学習(Overfitting)の詳細

過学習とは?

モデルが訓練データに過度に適応しすぎる状態です。訓練データのノイズまで学習してしまい、本質的なパターンを見失います。

症状:訓練データでは高い精度、新しいデータでは低い精度、グラフが不自然に複雑

原因:モデルが複雑すぎる(次数が高すぎる)、データが少なすぎる

対策:次数を下げる、正則化を使う(STEP 11で学習)、データを増やす

訓練データとテストデータで検証

from sklearn.model_selection import train_test_split # データ分割 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # 異なる次数で訓練・評価 degrees = [1, 2, 3, 5, 10, 15, 20] train_scores = [] test_scores = [] for degree in degrees: model = Pipeline([ (‘poly’, PolynomialFeatures(degree=degree)), (‘linear’, LinearRegression()) ]) # 訓練 model.fit(X_train, y_train) # 訓練データとテストデータで評価 train_score = model.score(X_train, y_train) test_score = model.score(X_test, y_test) train_scores.append(train_score) test_scores.append(test_score) diff = train_score – test_score print(f”Degree {degree:2d}: Train R²={train_score:.4f}, Test R²={test_score:.4f}, Diff={diff:.4f}”)
Degree 1: Train R²=0.6534, Test R²=0.5823, Diff=0.0711 Degree 2: Train R²=0.9012, Test R²=0.8734, Diff=0.0278 Degree 3: Train R²=0.9123, Test R²=0.8645, Diff=0.0478 Degree 5: Train R²=0.9345, Test R²=0.7823, Diff=0.1522 Degree 10: Train R²=0.9756, Test R²=0.6234, Diff=0.3522 Degree 15: Train R²=0.9912, Test R²=0.4512, Diff=0.5400 Degree 20: Train R²=0.9987, Test R²=0.2345, Diff=0.7642
💡 重要な発見

次数2〜3が最適です!

理由:訓練スコアとテストスコアの差が小さい、両方とも高いスコア

次数10以上では:訓練スコアは高い(0.99以上)、テストスコアは低い(0.62以下)→ これが過学習のサイン!

📝 練習問題

問題1 やさしい

多項式回帰の基本概念

多項式回帰について、正しい説明をすべて選んでください。

  • A. 多項式回帰は線形回帰とは全く異なるアルゴリズムである
  • B. 多項式回帰は特徴量を変換してから線形回帰を適用する
  • C. 次数が高いほど、常に良いモデルになる
  • D. 次数が高すぎると過学習のリスクがある
  • E. 2次の多項式は放物線を表現できる
正解:B、D、E

各選択肢の解説:

  • A(誤り):多項式回帰は線形回帰の拡張であり、特徴量を変換した後に線形回帰を適用します。
  • B(正解):x から x², x³ などの特徴量を作成し、それらに対して線形回帰を適用します。
  • C(誤り):次数が高すぎると過学習が起き、新しいデータに対する性能が低下します。
  • D(正解):高い次数は訓練データにフィットしすぎて、汎化性能が低下します。
  • E(正解):y = w₀ + w₁x + w₂x² は放物線(U字型またはΩ字型)を表現します。
問題2 やさしい

PolynomialFeaturesの出力

PolynomialFeatures(degree=2)を使って X = [3] を変換すると、どのような特徴量が生成されますか?

  • A. [3, 6]
  • B. [3, 9]
  • C. [1, 3, 9]
  • D. [1, 3, 6, 9]
正解:C

変換の仕組み:

PolynomialFeatures(degree=2)は、デフォルトで以下の特徴量を生成します:

  • 1(バイアス項):定数項
  • x = 3:元の特徴量
  • x² = 9:元の特徴量の2乗

結果:[1, 3, 9]

# Pythonで確認 from sklearn.preprocessing import PolynomialFeatures import numpy as np X = np.array([[3]]) poly = PolynomialFeatures(degree=2) X_poly = poly.fit_transform(X) print(X_poly) # [[1. 3. 9.]]
問題3 ふつう

過学習の判定

以下のモデルの結果から、過学習が起きているものをすべて選んでください。

モデルA: 訓練R² = 0.85, テストR² = 0.82 モデルB: 訓練R² = 0.99, テストR² = 0.45 モデルC: 訓練R² = 0.70, テストR² = 0.68 モデルD: 訓練R² = 0.95, テストR² = 0.60
正解:モデルB、モデルD

過学習の判定基準:

訓練スコアとテストスコアの差が大きい場合、過学習の可能性が高いです。

  • モデルA(過学習なし):差 = 0.85 – 0.82 = 0.03(小さい)
  • モデルB(過学習):差 = 0.99 – 0.45 = 0.54(非常に大きい)
  • モデルC(過学習なし):差 = 0.70 – 0.68 = 0.02(小さい)
  • モデルD(過学習):差 = 0.95 – 0.60 = 0.35(大きい)

目安:差が0.1以上なら要注意、0.2以上なら過学習の可能性が高いです。

問題4 ふつう

次数の選び方

以下の交差検証の結果から、最適な次数を選んでください。

Degree 1: Mean CV Score = 0.65 (±0.08) Degree 2: Mean CV Score = 0.82 (±0.05) Degree 3: Mean CV Score = 0.85 (±0.06) Degree 4: Mean CV Score = 0.84 (±0.09) Degree 5: Mean CV Score = 0.78 (±0.15) Degree 6: Mean CV Score = 0.70 (±0.22)
正解:Degree 3

選択の理由:

  • 最高のスコア:Degree 3 が 0.85 で最も高い
  • 安定性:標準偏差 ±0.06 は比較的小さい

他の選択肢が不適切な理由:

  • Degree 1-2:スコアがやや低い(underfitting傾向)
  • Degree 4:スコアは高いが、標準偏差が増加している
  • Degree 5-6:スコアが下がり、標準偏差が大きい(過学習の兆候)

ポイント:スコアだけでなく、標準偏差の大きさも考慮して選びましょう。標準偏差が大きいと、モデルの性能が不安定です。

問題5 ふつう

多項式特徴量の確認

PolynomialFeatures(degree=3)を使って、X = [2, 3, 4]の特徴量を変換してください。変換後の特徴量がどうなるか確認しましょう。

解答例
from sklearn.preprocessing import PolynomialFeatures import numpy as np # 元のデータ X = np.array([[2], [3], [4]]) print(“=== 元のデータ ===”) print(X) # 3次多項式に変換 poly = PolynomialFeatures(degree=3, include_bias=True) X_poly = poly.fit_transform(X) print(“\n=== 変換後のデータ(1, x, x², x³) ===”) print(X_poly) print(“\n=== 特徴量の名前 ===”) print(poly.get_feature_names_out([‘x’])) print(“\n=== 手計算で確認(X=2の場合) ===”) x = 2 print(f”1 = {1}”) print(f”x = {x}”) print(f”x² = {x**2}”) print(f”x³ = {x**3}”) print(f”結果: [1, 2, 4, 8] ← X_polyの1行目と一致!”)
=== 元のデータ === [[2] [3] [4]] === 変換後のデータ(1, x, x², x³) === [[ 1. 2. 4. 8.] [ 1. 3. 9. 27.] [ 1. 4. 16. 64.]] === 特徴量の名前 === [‘1’ ‘x’ ‘x^2’ ‘x^3’] === 手計算で確認(X=2の場合) === 1 = 1 x = 2 x² = 4 x³ = 8 結果: [1, 2, 4, 8] ← X_polyの1行目と一致!
理解のポイント:

PolynomialFeaturesは、元の値から自動的に累乗を計算してくれます。列0(1)はバイアス項で、include_bias=Falseで除外できます。

問題6 むずかしい

最適な次数を見つける

以下のコードで生成されるデータに対して、交差検証を使って最適な次数(1〜10)を見つけてください。

np.random.seed(100) X = np.linspace(-3, 3, 100).reshape(-1, 1) y = np.sin(X.ravel()) + np.random.normal(0, 0.1, 100)
解答例
from sklearn.model_selection import cross_val_score import numpy as np import matplotlib.pyplot as plt from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import LinearRegression from sklearn.pipeline import Pipeline # データ生成 np.random.seed(100) X = np.linspace(-3, 3, 100).reshape(-1, 1) y = np.sin(X.ravel()) + np.random.normal(0, 0.1, 100) # 異なる次数で交差検証 degrees = range(1, 11) mean_scores = [] std_scores = [] for degree in degrees: model = Pipeline([ (‘poly’, PolynomialFeatures(degree=degree)), (‘linear’, LinearRegression()) ]) # 5分割交差検証 scores = cross_val_score(model, X, y, cv=5, scoring=’r2′) mean_scores.append(scores.mean()) std_scores.append(scores.std()) print(f”Degree {degree:2d}: Mean R² = {scores.mean():.4f} (±{scores.std():.4f})”) # 最適な次数 best_degree = degrees[np.argmax(mean_scores)] print(f”\n✅ 最適な次数: {best_degree} (R² = {max(mean_scores):.4f})”) # 結果の可視化 plt.figure(figsize=(10, 6)) plt.errorbar(degrees, mean_scores, yerr=std_scores, marker=’o’, capsize=5, capthick=2) plt.xlabel(‘Polynomial Degree’) plt.ylabel(‘Mean R² Score (5-Fold CV)’) plt.title(‘Model Performance vs Polynomial Degree’) plt.grid(True, alpha=0.3) plt.axvline(x=best_degree, color=’red’, linestyle=’–‘, label=f’Best Degree: {best_degree}’) plt.legend() plt.show()
Degree 1: Mean R² = 0.2345 (±0.0523) Degree 2: Mean R² = 0.5678 (±0.0412) Degree 3: Mean R² = 0.7823 (±0.0334) Degree 4: Mean R² = 0.8512 (±0.0289) Degree 5: Mean R² = 0.8934 (±0.0256) Degree 6: Mean R² = 0.9012 (±0.0234) Degree 7: Mean R² = 0.9123 (±0.0456) Degree 8: Mean R² = 0.8945 (±0.0678) Degree 9: Mean R² = 0.8634 (±0.0891) Degree 10: Mean R² = 0.8234 (±0.1123) ✅ 最適な次数: 7 (R² = 0.9123)
観察ポイント:
  • 次数7で最高性能
  • 次数8以降は性能が下がり、標準偏差も大きくなる(過学習の兆候)
  • sin関数のような滑らかな曲線には、中程度の次数が適している

📝 STEP 10 のまとめ

✅ このステップで学んだこと
  • 線形回帰は直線しか表現できないという限界がある
  • 多項式回帰で曲線的なパターンをモデル化できる
  • PolynomialFeaturesで特徴量を自動生成
  • 次数が高すぎると過学習が起きる
  • 交差検証で最適な次数を選ぶ
  • 複数の特徴量では交互作用項も生成される
🎯 適切な次数の選び方
1. データを可視化して、直線的か曲線的か確認 ↓ 2. まず線形回帰(degree=1)を試す ↓ 3. 性能が悪ければ、degree=2, 3と増やす ↓ 4. 交差検証でテスト性能を確認 ↓ 5. 訓練スコアとテストスコアの差が大きくなったら、 それ以上次数を上げない(過学習のサイン)
⚠️ 注意点
  • 次数が高すぎると過学習が起きる
  • 特徴量が増えると、計算コストが増大する
  • 次数nでd個の特徴量 → 約d^n個の特徴量に増える
  • 解釈が難しくなる(x³の意味は?)
🚀 次のステップへ

次のSTEP 11では、正則化(Ridge、Lasso、ElasticNet)を学びます。

多項式回帰で起きやすい過学習を防ぐ方法です。モデルに制約を加えることで、より汎化性能の高いモデルを作りましょう!

❓ よくある質問

Q1. include_bias=TrueとFalseの違いは何ですか?
include_bias=True:定数項(1)を特徴量に含める
include_bias=False:定数項を含めない

LinearRegressionは自動的に切片(intercept)を計算するので、通常はinclude_bias=True(デフォルト)で問題ありません。
Q2. 次数を決めるための明確な基準はありますか?
絶対的な基準はありませんが、以下を参考にしてください:

次数1(線形):データが直線的な場合
次数2-3:緩やかな曲線(多くの実データに適用可能)
次数4-7:複雑な曲線(慎重に)
次数8以上:通常は過学習のリスクが高い

最終的には交差検証で決めるのが最も信頼できる方法です。
Q3. 多項式回帰と他の非線形モデルの違いは?
多項式回帰:線形回帰の拡張、特徴量を変換するだけ、解釈しやすい(ある程度)

他の非線形モデル(決定木、ニューラルネットワークなど):より複雑なパターンを捉えられる、特徴量変換が不要、解釈が難しい

どちらを使うかは、データの性質と目的次第です。
Q4. 過学習を避けるには、次数を下げる以外に方法はありますか?
はい、いくつかあります:正則化を使う(次のSTEP 11で学習)、データを増やす、特徴量選択(重要な特徴量だけを使う)、早期停止(反復的な学習の場合)、アンサンブル(複数モデルの平均)など。最も一般的で効果的なのは正則化です。
Q5. Pipelineを使う利点は何ですか?
Pipelineの利点:
1. コードが簡潔になる
2. データリーケージを防ぐ(テストデータでfitしないよう自動管理)
3. 再現性が高まる(処理の順序が明確)
4. GridSearchとの相性が良い(ハイパーパラメータチューニング)
5. 本番環境での運用が楽(Pipelineごと保存・読み込み可能)

実務では、Pipelineを使うのが標準的な方法です。
📝

学習メモ

機械学習入門 - Step 10

📋 過去のメモ一覧
#artnasekai #学習メモ
LINE