簡單線性迴歸是監督式學習中最基礎的方法。它假設反應變數 \(Y\) 與單一預測變數 \(X\) 之間存在線性關係。雖然簡單,但它幾乎是所有複雜統計模型的基石。
簡單線性迴歸假設反應變數 \(Y\) 可以被單一預測變數 \(X\) 以線性方式近似:
其中 \(\beta_0\) 為截距(intercept),代表 \(X=0\) 時期望的 \(Y\) 值;\(\beta_1\) 為斜率(slope),代表 \(X\) 每變動一單位時 \(Y\) 的平均變化量。兩者合稱模型係數(coefficients)或參數(parameters)。
有了係數的估計值 \(\hat{\beta}_0, \hat{\beta}_1\),我們即可對新的 \(x\) 值進行預測:
這裡的「帽子」符號 \(\hat{\ }\) 代表估計值或預測值。
課本中經典的 Advertising 資料集包含 200 個市場的電視、廣播、報紙廣告支出與對應的銷售額。如果我們想知道「多花 $1,000 在電視廣告上,能多賣多少產品?」——簡單線性迴歸就是回答這個問題的首選工具。
在實務中 \(\beta_0\) 和 \(\beta_1\) 是未知的。我們需要從 \(n\) 組觀測值 \(\{(x_1, y_1), (x_2, y_2), \ldots, (x_n, y_n)\}\) 中估計它們。最小平方法(Least Squares)是最常見的做法:選擇 \(\hat{\beta}_0, \hat{\beta}_1\) 使得殘差平方和(Residual Sum of Squares, RSS)最小化。
定義第 \(i\) 個殘差(residual)為觀測值與預測值的差距:
最小平方法的目標函數:
透過微積分求極值,可得最小平方估計:
其中 \(\bar{x} = \frac{1}{n}\sum x_i\),\(\bar{y} = \frac{1}{n}\sum y_i\) 為樣本平均數。
try:
from google.colab import drive
drive.mount('/content/drive')
DATA_PATH = '/content/drive/MyDrive/ISLP_data/'
except ImportError:
DATA_PATH = '/tmp/'
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
# 載入 Advertising 資料集
ad = pd.read_csv(DATA_PATH + 'Advertising.csv', index_col=0)
# === 手刻最小平方法 ===
x = ad['TV'].values
y = ad['sales'].values
n = len(x)
x_bar = np.mean(x)
y_bar = np.mean(y)
# 方程式 3.4
beta1_hat = np.sum((x - x_bar) * (y - y_bar)) / np.sum((x - x_bar)**2)
beta0_hat = y_bar - beta1_hat * x_bar
print(f"β₀ (截距) = {beta0_hat:.4f}")
print(f"β₁ (斜率) = {beta1_hat:.4f}")
print(f"解讀:TV 廣告每增加 $1,000,銷售預期增加 {beta1_hat*1000:.1f} 單位")
# 繪圖
x_line = np.linspace(x.min(), x.max(), 100)
y_line = beta0_hat + beta1_hat * x_line
fig, ax = plt.subplots(figsize=(9, 6))
ax.scatter(x, y, alpha=0.5, s=30, c='#58a6ff', edgecolors='none')
ax.plot(x_line, y_line, color='#f85149', linewidth=2, label='最小平方配適線')
# 標示幾條殘差
for i in [0, 50, 100, 150]:
ax.plot([x[i], x[i]], [y[i], beta0_hat + beta1_hat * x[i]],
color='#8b949e', linewidth=0.8, linestyle='--')
ax.set_xlabel('TV 廣告支出 ($K)', fontsize=12)
ax.set_ylabel('銷售額 (千單位)', fontsize=12)
ax.set_title('Advertising 資料:TV vs Sales 最小平方迴歸', fontsize=14)
ax.legend()
plt.tight_layout()
plt.show()
課本假設觀測資料背後存在一個「真實」的線性關係:
其中 \(\epsilon\) 是平均數為零的隨機誤差項,概括了所有模型未捕捉到的變異(非線性效應、遺漏變數、測量誤差等)。\(\beta_0 + \beta_1 X\) 定義了母體迴歸線(population regression line)——它是 \(X\) 與 \(Y\) 之間的最佳線性近似。我們透過資料算出的 \(\hat{\beta}_0 + \hat{\beta}_1 X\) 則是最小平方線(least squares line)。
單一估計值可能偏離真實值多遠?答案取決於標準誤。課本透過與樣本平均數的標準誤 \(\mathrm{SE}(\hat{\mu}) = \sigma / \sqrt{n}\) 類比,引出迴歸係數的標準誤公式:
其中 \(\sigma^2 = \mathrm{Var}(\epsilon)\)。實務中 \(\sigma\) 未知,以殘差標準誤 \(\mathrm{RSE} = \sqrt{\mathrm{RSS} / (n-2)}\) 估計。
課本例題:Advertising 資料中:
最常見的檢定問題:「\(X\) 與 \(Y\) 之間有關係嗎?」這對應到:
我們計算 t 統計量:
t 統計量衡量 \(\hat{\beta}_1\) 距離 0 有多少個標準差。在 \(H_0\) 為真之下,t 服從自由度 \(n-2\) 的 t 分布。p 值是觀察到 \(|t|\) 或更極端的機率——p 值愈小,證據愈強。典型的 cutoff 為 5%(對應 \(|t| \approx 2\))或 1%。
try:
from google.colab import drive
drive.mount('/content/drive')
DATA_PATH = '/content/drive/MyDrive/ISLP_data/'
except ImportError:
DATA_PATH = '/tmp/'
import numpy as np
import pandas as pd
from scipy import stats
ad = pd.read_csv(DATA_PATH + 'Advertising.csv', index_col=0)
x = ad['TV'].values
y = ad['sales'].values
n = len(x)
# 最小平方估計
x_bar, y_bar = np.mean(x), np.mean(y)
beta1_hat = np.sum((x - x_bar) * (y - y_bar)) / np.sum((x - x_bar)**2)
beta0_hat = y_bar - beta1_hat * x_bar
# 殘差與 RSE
y_hat = beta0_hat + beta1_hat * x
residuals = y - y_hat
RSS = np.sum(residuals**2)
RSE = np.sqrt(RSS / (n - 2))
# 標準誤(方程式 3.8)
SE_beta1 = RSE / np.sqrt(np.sum((x - x_bar)**2))
SE_beta0 = RSE * np.sqrt(1/n + x_bar**2 / np.sum((x - x_bar)**2))
# t 統計量與 p 值
t1 = beta1_hat / SE_beta1
t0 = beta0_hat / SE_beta0
p1 = 2 * stats.t.sf(abs(t1), df=n-2)
p0 = 2 * stats.t.sf(abs(t0), df=n-2)
# 95% 信賴區間
alpha = 0.05
t_crit = stats.t.ppf(1 - alpha/2, df=n-2)
ci1 = (beta1_hat - t_crit * SE_beta1, beta1_hat + t_crit * SE_beta1)
ci0 = (beta0_hat - t_crit * SE_beta0, beta0_hat + t_crit * SE_beta0)
print("=== 簡單線性迴歸:sales ~ TV ===")
print(f"{'':<12} {'係數':>10} {'Std.Err':>10} {'t':>10} {'p值':>12}")
print(f"{'Intercept':<12} {beta0_hat:>10.4f} {SE_beta0:>10.4f} {t0:>10.2f} {p0:>12.6f}")
print(f"{'TV':<12} {beta1_hat:>10.4f} {SE_beta1:>10.4f} {t1:>10.2f} {p1:>12.6f}")
print(f"\n95% CI for β₀: [{ci0[0]:.3f}, {ci0[1]:.3f}]")
print(f"95% CI for β₁: [{ci1[0]:.4f}, {ci1[1]:.4f}]")
print(f"\n解讀:β₁ 的 p 值 {p1:.2e},遠小於 0.05,有力證據支持 TV 與 sales 有關聯。")
RSE 估計的是誤差項 \(\epsilon\) 的標準差 \(\sigma\)。它衡量模型「平均偏離真實迴歸線多少」——也就是即使模型完全正確、係數精確已知,預測仍會有的典型誤差。
課本例題:Advertising 資料的 RSE = 3.26(千單位)。由於平均銷售額約 14,000 單位,這代表百分比誤差約 23%(3,260 / 14,000)。
RSE 是絕對量,難以跨問題比較。\(R^2\) 提供一個相對的尺度:
其中 \(\mathrm{TSS} = \sum (y_i - \bar{y})^2\) 為總平方和(Total Sum of Squares),代表迴歸前 \(Y\) 的總變異。RSS 是迴歸後殘留的變異。因此 \(\mathrm{TSS} - \mathrm{RSS}\) 是迴歸所解釋的變異。
在簡單線性迴歸中,有一個優雅的關係:
這意味著簡單迴歸的 \(R^2\) 是 \(X\) 與 \(Y\) 的相關係數平方。但這個關係僅限於簡單線性迴歸——進入多元迴歸後,\(R^2\) 仍然適用但相關性的概念就無法直接推廣了。
try:
from google.colab import drive
drive.mount('/content/drive')
DATA_PATH = '/content/drive/MyDrive/ISLP_data/'
except ImportError:
DATA_PATH = '/tmp/'
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
ad = pd.read_csv(DATA_PATH + 'Advertising.csv', index_col=0)
# === 使用 sklearn 快速建模 ===
from sklearn.linear_model import LinearRegression
X = ad[['TV']].values
y = ad['sales'].values
model = LinearRegression().fit(X, y)
y_hat = model.predict(X)
# RSS, TSS, RSE, R²
RSS = np.sum((y - y_hat)**2)
TSS = np.sum((y - np.mean(y))**2)
R_squared = 1 - RSS / TSS
n = len(y)
RSE = np.sqrt(RSS / (n - 2))
print(f"RSE = {RSE:.2f} 千單位")
print(f"R² = {R_squared:.4f}")
print(f"相關係數 r = {np.corrcoef(ad['TV'], y)[0,1]:.4f}")
print(f"r² = {np.corrcoef(ad['TV'], y)[0,1]**2:.4f} ← 與 R² 一致!")
# 可視化:三種媒體的簡單迴歸比較
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
media = ['TV', 'radio', 'newspaper']
colors = ['#58a6ff', '#3fb950', '#d2991d']
for ax, med, c in zip(axes, media, colors):
X_m = ad[[med]].values
m = LinearRegression().fit(X_m, y)
y_pred = m.predict(X_m)
r2 = m.score(X_m, y)
ax.scatter(X_m, y, alpha=0.4, s=20, c=c)
x_line = np.linspace(X_m.min(), X_m.max(), 100).reshape(-1, 1)
ax.plot(x_line, m.predict(x_line), color='#f85149', lw=2)
ax.set_title(f'{med}\nR² = {r2:.3f}', fontsize=12)
ax.set_xlabel(f'{med} 支出 ($K)')
if med == 'TV': ax.set_ylabel('Sales (千單位)')
plt.suptitle('三種媒體的簡單線性迴歸比較', fontsize=14, y=1.02)
plt.tight_layout()
plt.show()
| 方法 | 適用情境 | 可解釋性 | 靈活度 | 何時用 |
|---|---|---|---|---|
| 簡單線性迴歸 | 單一預測變數,線性關係 | ⭐⭐⭐⭐⭐ | ⭐ | 基準線、快速探索、推論 |
| 多元線性迴歸 (§3.2) | 多個預測變數,線性關係 | ⭐⭐⭐⭐ | ⭐⭐ | 控制混淆變數、聯合效應 |
| 多項式迴歸 (§7) | 單變數但非線性 | ⭐⭐⭐ | ⭐⭐⭐ | 曲線關係但仍需參數形式 |
| KNN 迴歸 (§3.5) | 無需假設函數形式 | ⭐ | ⭐⭐⭐⭐⭐ | 高度非線性、大量資料 |
| 相關係數 | 僅衡量線性關聯強度 | ⭐⭐⭐⭐ | — | 探索性分析、不涉及預測 |
金融學中最著名的簡單線性迴歸:\(R_i - R_f = \alpha + \beta (R_m - R_f) + \epsilon\)。斜率 \(\beta\) 衡量個股對市場風險的曝險程度。\(\beta = 1\) 表示個股與大盤同步;\(\beta > 1\) 表示波動大於大盤。
臨床試驗中,研究者用簡單線性迴歸分析藥物劑量與療效指標(如血壓降幅)的關係。斜率代表「每增加一單位劑量,療效的預期改變量」,這是 FDA 審查新藥的關鍵統計證據。
使用單一因子(降雨量或施肥量)預測作物產量。雖然真實關係複雜,簡單迴歸提供易於理解的決策參考:每額外 1cm 降雨,產量增加約 X 公斤。
最直覺的迴歸應用——房價與坪數的關係。斜率即為「每坪單價」。當然真實房價還受區位、屋齡、樓層影響(這就進入多元迴歸範疇),但簡單迴歸給出第一層直觀理解。
| 公式 | 名稱 | 用途 |
|---|---|---|
| \(Y \approx \beta_0 + \beta_1 X\) | 簡單線性模型 | 定義模型結構 |
| \(\hat{y} = \hat{\beta}_0 + \hat{\beta}_1 x\) | 預測方程式 | 對新觀測值進行預測 |
| \(\mathrm{RSS} = \sum (y_i - \hat{y}_i)^2\) | 殘差平方和 | 最小化的目標函數 |
| \(\hat{\beta}_1 = \frac{\sum (x_i - \bar{x})(y_i - \bar{y})}{\sum (x_i - \bar{x})^2}\) | 斜率估計 | 最小平方解析解 |
| \(\mathrm{SE}(\hat{\beta}_1)^2 = \frac{\sigma^2}{\sum (x_i - \bar{x})^2}\) | 斜率標準誤 | 衡量估計精確度 |
| \(\hat{\beta}_1 \pm 2\cdot\mathrm{SE}(\hat{\beta}_1)\) | 信賴區間 | 參數的區間估計 |
| \(t = \hat{\beta}_1 / \mathrm{SE}(\hat{\beta}_1)\) | t 統計量 | 假設檢定 |
| \(\mathrm{RSE} = \sqrt{\mathrm{RSS}/(n-2)}\) | 殘差標準誤 | 模型缺乏配適度的量尺 |
| \(R^2 = 1 - \mathrm{RSS}/\mathrm{TSS}\) | 判定係數 | 解釋變異的比例 |