フリーキーズ | 独学プログラミング

重回帰分析入門!複数の要因を組み合わせて予測精度を上げる方法を解説

リンドくん

リンドくん

たなべ先生、単回帰分析は理解できたんですけど、実際のビジネスって一つの要因だけじゃ説明できないことが多いですよね?

たなべ

たなべ

その通り!鋭い気づきだね。
たとえば家の価格を予測するとき、広さだけじゃなくて築年数や駅からの距離、部屋数なんかも関係してくるよね。そういう複数の要因を同時に考えるのが重回帰分析なんだ。

データ分析を学び始めると、単回帰分析で一つの要因から結果を予測する方法を学びます。
しかし、実際のビジネスや研究の現場では、一つの要因だけで物事が決まることはほとんどありません。

たとえば、商品の売上を予測したいとき、価格だけでなく広告費や季節、競合の状況など、様々な要因が絡み合っています。
こうした複数の要因を同時に考慮して予測する手法が重回帰分析です。

この記事では、データサイエンス初心者の方でも理解できるよう、重回帰分析の基本概念から実装方法、注意点まで、段階的に解説していきます。

重回帰分析とは?単回帰分析との違いを理解しよう

リンドくん

リンドくん

重回帰分析って、単回帰分析と何が違うんですか?

たなべ

たなべ

一番大きな違いは説明変数の数なんだ。
単回帰分析が「一つの要因で結果を説明する」のに対して、重回帰分析は「複数の要因を組み合わせて結果を説明する」んだよ。

重回帰分析の基本概念

重回帰分析は、複数の説明変数(独立変数)を使って、目的変数(従属変数)を予測する統計手法です。
数式で表すと以下のようになります。

y = β₀ + β₁x₁ + β₂x₂ + β₃x₃ + ... + βₙxₙ + ε

ここで、各項目を説明すると以下のようになります。

  • y: 目的変数(予測したい値)
  • x₁, x₂, x₃, ..., xₙ: 説明変数(予測に使う要因)
  • β₀: 切片(定数項)
  • β₁, β₂, β₃, ..., βₙ: 回帰係数(各説明変数の影響度)
  • ε: 誤差項(モデルで説明できない部分)

単回帰分析との違い

単回帰分析と重回帰分析の違いを具体例で見てみましょう。

単回帰分析の例: 広さだけで家の価格を予測

価格 = 切片 + (係数 × 広さ)

重回帰分析の例: 複数の要因で家の価格を予測

価格 = 切片 + (係数₁ × 広さ) + (係数₂ × 築年数) + (係数₃ × 駅からの距離)

このように、重回帰分析では複数の角度から対象を見ることで、より現実に近い予測が可能になるのです。

なぜ重回帰分析が必要なのか

実際のビジネスや研究では、一つの要因だけで結果が決まることはほとんどありません。
重回帰分析を使うことで、以下のようなメリットが得られます。

  • 予測精度の向上 - 複数の要因を考慮することで、より正確な予測が可能
  • 要因の相対的な重要性の把握 - どの要因がどれだけ影響しているかがわかる
  • 交絡因子の制御 - 他の要因の影響を除いた、純粋な効果を測定できる

たとえば、「広告費を増やすと売上が上がる」という関係を調べるとき、季節性の影響を考慮しないと正確な判断ができません。
重回帰分析なら、季節の影響を考慮しつつ、広告費の純粋な効果を測定できるのです。

Pythonで重回帰分析を実装してみよう

リンドくん

リンドくん

実際にPythonでやってみたいです!どうやって始めればいいですか?

たなべ

たなべ

まずはシンプルな例から始めよう
身近な例として、学生の成績を予測するモデルを作ってみるよ。勉強時間、睡眠時間、出席率の3つの要因から、テストの点数を予測してみよう!

必要なライブラリのインポート

まずは必要なライブラリをインポートします。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import r2_score, mean_squared_error

# 日本語表示の設定
plt.rcParams['font.sans-serif'] = ['DejaVu Sans']

サンプルデータの作成

実際のデータを想定して、学生の学習データを作成してみましょう。

# サンプルデータの作成
np.random.seed(42)
n_samples = 100

# 説明変数の生成
study_hours = np.random.uniform(1, 10, n_samples)      # 勉強時間(時間/日)
sleep_hours = np.random.uniform(5, 9, n_samples)       # 睡眠時間(時間/日)
attendance_rate = np.random.uniform(60, 100, n_samples) # 出席率(%)

# 目的変数の生成(テストの点数)
# 勉強時間が多いほど点数が上がり、睡眠時間も適度に必要、出席率も影響する
test_score = (
    30 +                              # ベースライン
    5 * study_hours +                 # 勉強時間の影響
    2 * sleep_hours +                 # 睡眠時間の影響
    0.3 * attendance_rate +           # 出席率の影響
    np.random.normal(0, 5, n_samples) # ランダムなノイズ
)

# データフレームの作成
df = pd.DataFrame({
    '勉強時間': study_hours,
    '睡眠時間': sleep_hours,
    '出席率': attendance_rate,
    'テスト点数': test_score
})

print(df.head())
print(f"\nデータの形状: {df.shape}")

重回帰モデルの構築

次に、実際に重回帰モデルを構築していきます。

# 説明変数と目的変数に分割
X = df[['勉強時間', '睡眠時間', '出席率']]
y = df['テスト点数']

# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

# 重回帰モデルの作成と学習
model = LinearRegression()
model.fit(X_train, y_train)

# 予測の実行
y_pred = model.predict(X_test)

print("=== モデルの係数 ===")
print(f"切片: {model.intercept_:.2f}")
for feature, coef in zip(X.columns, model.coef_):
    print(f"{feature}の係数: {coef:.2f}")

モデルの評価

構築したモデルの性能を評価してみましょう。

# モデルの評価
r2 = r2_score(y_test, y_pred)
rmse = np.sqrt(mean_squared_error(y_test, y_pred))

print(f"\n=== モデルの評価 ===")
print(f"決定係数(R²): {r2:.4f}")
print(f"RMSE: {rmse:.2f}")

# 予測値と実測値の比較
plt.figure(figsize=(10, 6))
plt.scatter(y_test, y_pred, alpha=0.6)
plt.plot([y_test.min(), y_test.max()], 
         [y_test.min(), y_test.max()], 
         'r--', linewidth=2)
plt.xlabel('Actual Test Score')
plt.ylabel('Predicted Test Score')
plt.title('Multiple Regression: Actual vs Predicted')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

このコードを実行すると、以下のようなことがわかります。

  • 各説明変数の係数: それぞれの要因がテスト点数にどれだけ影響しているか
  • 決定係数(R²): モデルがどれだけデータを説明できているか(1に近いほど良い)
  • RMSE: 予測誤差の大きさ(小さいほど良い)

新しいデータでの予測

モデルが完成したら、新しいデータで予測してみましょう。

# 新しい学生のデータで予測
new_student = pd.DataFrame({
    '勉強時間': [6.5],
    '睡眠時間': [7.0],
    '出席率': [85.0]
})

predicted_score = model.predict(new_student)
print(f"\n=== 新しい学生の予測 ===")
print(f"勉強時間: {new_student['勉強時間'].values[0]}時間/日")
print(f"睡眠時間: {new_student['睡眠時間'].values[0]}時間/日")
print(f"出席率: {new_student['出席率'].values[0]}%")
print(f"予測されるテスト点数: {predicted_score[0]:.1f}点")

このように、重回帰分析を使えば、複数の要因から目的変数を予測するモデルを簡単に構築できます。

重回帰分析の結果を正しく解釈する

リンドくん

リンドくん

係数の数値が出ましたけど、これってどう読み取ればいいんですか?

たなべ

たなべ

係数の解釈はとても重要だね。
たとえば「勉強時間の係数が5.0」だったら、他の条件が同じなら、勉強時間が1時間増えるとテスト点数が5点上がるという意味なんだ。

回帰係数の意味

重回帰分析で得られる各説明変数の係数は、他の説明変数を固定したときの、その変数の影響度を表します。

たとえば、以下のような結果が得られたとします。

テスト点数 = 30 + 5.0×勉強時間 + 2.0×睡眠時間 + 0.3×出席率

これは以下のように解釈できます。

  • 勉強時間の係数が5.0: 睡眠時間と出席率が同じなら、勉強時間が1時間増えると点数が5点上がる
  • 睡眠時間の係数が2.0: 勉強時間と出席率が同じなら、睡眠時間が1時間増えると点数が2点上がる
  • 出席率の係数が0.3: 勉強時間と睡眠時間が同じなら、出席率が1%増えると点数が0.3点上がる

決定係数(R²)の解釈

決定係数はモデルがどれだけデータのばらつきを説明できているかを示す指標です。

  • R² = 0.8: データのばらつきの80%をモデルで説明できている
  • R² = 0.5: データのばらつきの50%をモデルで説明できている

一般的に、R²が0.7以上であれば良いモデルと言えますが、分野によって基準は異なります。
社会科学では0.3〜0.5でも受け入れられることがありますし、物理実験では0.9以上が期待されることもあります。

係数の統計的有意性

実際の分析では、係数が統計的に有意かどうかも重要です。
これは、その変数が本当に目的変数に影響を与えているのか、それとも偶然なのかを判定します。

import statsmodels.api as sm

# statsmodelsを使った詳細な統計情報の取得
X_with_const = sm.add_constant(X_train)
model_sm = sm.OLS(y_train, X_with_const).fit()
print(model_sm.summary())

このコードを実行すると、各係数のp値が表示されます。
p値が0.05未満であれば、その変数は統計的に有意と判断できます。

重回帰分析で注意すべきポイント

リンドくん

リンドくん

何か気をつけないといけないことってありますか?

たなべ

たなべ

実はいくつか重要な注意点があるんだ。
特に多重共線性という問題には気をつける必要があるよ。説明変数同士が強く相関していると、係数の解釈がおかしくなっちゃうんだ。

多重共線性の問題

多重共線性とは、説明変数同士が強く相関している状態のことです。
これが起こると、以下のような問題が発生します。

  • 係数の推定が不安定になる
  • 係数の解釈が難しくなる
  • モデルの信頼性が低下する

たとえば、「身長」と「体重」の両方を説明変数に入れると、これらは強く相関しているため多重共線性が発生しやすくなります。

多重共線性の確認方法

VIF(Variance Inflation Factor: 分散拡大係数)を使って多重共線性を確認できます。

from statsmodels.stats.outliers_influence import variance_inflation_factor

# VIFの計算
vif_data = pd.DataFrame()
vif_data["説明変数"] = X.columns
vif_data["VIF"] = [variance_inflation_factor(X.values, i) 
                   for i in range(len(X.columns))]

print("\n=== 多重共線性のチェック(VIF) ===")
print(vif_data)
print("\nVIFの目安:")
print("- VIF < 5: 問題なし")
print("- 5 ≤ VIF < 10: 注意が必要")
print("- VIF ≥ 10: 多重共線性の可能性が高い")

VIFが10以上の変数がある場合は、以下のような対処が必要です。

  • 相関の強い変数のどちらかを削除する
  • 主成分分析などで変数を統合する
  • 正則化回帰(Ridge回帰やLasso回帰)を使用する

外れ値の影響

重回帰分析は外れ値の影響を受けやすい手法です。
データに極端な値が含まれていると、モデル全体が歪んでしまう可能性があります。

# 外れ値の確認
print("\n=== データの基本統計量 ===")
print(df.describe())

# 箱ひげ図で外れ値を視覚化
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
for idx, column in enumerate(df.columns):
    row = idx // 2
    col = idx % 2
    axes[row, col].boxplot(df[column])
    axes[row, col].set_title(column)
    axes[row, col].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

外れ値が見つかった場合は、以下のような対処を検討しましょう。

  • データ入力ミスがないか確認する
  • 業務知識から妥当性を判断する
  • 外れ値を除外するか、頑健な手法(ロバスト回帰)を使用する

説明変数の選択

すべての変数をモデルに入れればいいわけではありません。
不要な変数を入れすぎると、以下の問題が起こります。

  • 過学習(オーバーフィッティング): 訓練データには合うが、新しいデータでの予測精度が落ちる
  • 解釈の困難さ: 変数が多すぎるとモデルの意味が分かりにくくなる

変数選択の方法には以下のようなものがあります。

  • 前進選択法: 変数を一つずつ追加していく
  • 後退選択法: すべての変数から始めて、不要なものを削除していく
  • ステップワイズ法: 追加と削除を繰り返す

Pythonでの実装例:

from sklearn.feature_selection import RFE

# 重要な変数の選択(RFE: Recursive Feature Elimination)
selector = RFE(model, n_features_to_select=2)
selector.fit(X_train, y_train)

print("\n=== 変数の重要度 ===")
for feature, selected in zip(X.columns, selector.support_):
    print(f"{feature}: {'選択' if selected else '非選択'}")

まとめ

リンドくん

リンドくん

重回帰分析って、複雑そうに見えて実は理にかなってるんですね!

たなべ

たなべ

そうなんだよ!現実世界は複雑だから、複数の要因を同時に考える必要があるんだ。
重回帰分析を使いこなせるようになると、データ分析の幅がグッと広がるよ。ぜひ実際のデータで試してみてね!

重回帰分析は、データサイエンスにおける基本的かつ強力なツールです。
この記事で学んだ内容を振り返ってみましょう。

  • 重回帰分析とは: 複数の説明変数を使って目的変数を予測する統計手法
  • 単回帰分析との違い: 一つではなく複数の要因を同時に考慮できる
  • 実装方法: Pythonのscikit-learnを使えば数行のコードで実装可能
  • 結果の解釈: 回帰係数は「他の条件が同じときの影響度」を表す
  • 注意点: 多重共線性、外れ値、変数選択に気をつける必要がある

理論を学ぶことも大切ですが、実際に手を動かしてデータ分析を行うことが最も重要です。
まずは身近なデータを使って、今日学んだ重回帰分析を試してみましょう。

Kaggleなどの公開データセットを使って練習するのもおすすめです。
最初は小さなデータセットから始めて、徐々に複雑な問題に挑戦していくと良いでしょう。

データサイエンスは奥が深く、学ぶべきことはたくさんあります。
しかし、一歩一歩着実に進んでいけば、必ずスキルは向上します。重回帰分析は、その重要な一歩となるはずです。

この記事をシェア

関連するコンテンツ