📋 このステップで学ぶこと
- 線形回帰の限界
- 多項式回帰の仕組み
- 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⁴ + …
→ より複雑な波型
多項式回帰の仕組み
💡 実は線形回帰の拡張!
多項式回帰は、実は線形回帰の特殊なケースです。
手順:
- 元の特徴量 x から、x², x³, … を作る
- これらを新しい特徴量として扱う
- 普通の線形回帰を適用
例: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を使うのが標準的な方法です。
artnasekai
#artnasekai #学習メモ