前兩節我們學了兩種「超越線性」的方法:§7.1 多項式迴歸用 x, x², x³, … 來擬合曲線;§7.2 階梯函數把資料切成分段常數區間。這兩種方法看起來很不一樣,但它們其實共享同一個數學骨架——這就是本節要介紹的 基底函數(basis functions) 框架。
想想看:你想用積木蓋房子。有些積木是長方形的(多項式項)、有些是階梯狀的(分段常數)、還有些是波浪狀的(傅立葉級數)。不管積木的形狀怎麼變,蓋房子的邏輯是一樣的:把積木疊起來,調整每塊積木的高度。基底函數就是這些「積木」——你選好形狀,交給線性迴歸去算出最佳高度。
基底函數方法的通用模型是:
這裡的 bⱼ(·) 是「預先選定」的函數(不是從資料中學出來的),而 βⱼ 是我們要用最小平方法估計的係數。重點來了:
這個框架的美妙之處在於:你在做非線性建模,但用的是線性模型的推論引擎。這就是為什麼基底函數方法既靈活又可靠。
把 x 的冪次當作基底:
這就得到了我們在 §7.1 中的多項式模型:y = β₀ + β₁x + β₂x² + … + βdxᵈ + ε。
用指示函數(indicator function)當基底:
這表示當 xᵢ 落在第 j 個區間時,bⱼ(xᵢ) = 1;否則為 0。我們在 §7.2 中用它來做分段常數擬合。
以下程式碼展示同一組 Wage 資料,用三種基底函數(多項式、分段常數、以及自然樣條作為預告)擬合的結果:
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 matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from ISLP import load_data
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import SplineTransformer
# Load Wage data
wage = load_data('Wage')
X = wage[['age']].values
y = wage['wage'].values
# Sort for plotting
sort_idx = np.argsort(X.ravel())
X_sorted = X[sort_idx]
fig, axes = plt.subplots(1, 3, figsize=(14, 4.5))
# --- Polynomial basis: b_j(x) = x^j ---
poly_deg = 4
X_poly = np.column_stack([X.ravel()**j for j in range(1, poly_deg + 1)])
model_poly = LinearRegression().fit(X_poly, y)
y_poly_pred = model_poly.predict(X_poly[sort_idx])
axes[0].scatter(X.ravel(), y, alpha=0.25, s=8, color='#8b949e')
axes[0].plot(X_sorted, y_poly_pred, color='#58a6ff', lw=2)
axes[0].set_title('Polynomial (d=4)', fontsize=11, color='#f0f6fc')
axes[0].set_xlabel('Age'); axes[0].set_ylabel('Wage (k$)')
# --- Step function basis ---
n_bins = 6
bins = np.linspace(X.min(), X.max(), n_bins + 1)
X_binned = np.zeros((len(X), n_bins))
for j in range(n_bins):
X_binned[:, j] = ((X.ravel() >= bins[j]) & (X.ravel() < bins[j+1])).astype(float)
X_binned[-1, -1] = 1.0
model_step = LinearRegression().fit(X_binned, y)
y_step_pred = model_step.predict(X_binned[sort_idx])
axes[1].scatter(X.ravel(), y, alpha=0.25, s=8, color='#8b949e')
axes[1].plot(X_sorted, y_step_pred, color='#d2991d', lw=2)
for b in bins[1:-1]:
axes[1].axvline(b, color='#484f58', ls='--', lw=0.8)
axes[1].set_title('Step Function (6 bins)', fontsize=11, color='#f0f6fc')
axes[1].set_xlabel('Age')
# --- Natural cubic spline basis (preview §7.4) ---
n_knots = 4
spline = SplineTransformer(n_knots=n_knots, degree=3, extrapolation='linear')
X_spline = spline.fit_transform(X)
model_spline = LinearRegression().fit(X_spline, y)
y_spline_pred = model_spline.predict(X_spline[sort_idx])
axes[2].scatter(X.ravel(), y, alpha=0.25, s=8, color='#8b949e')
axes[2].plot(X_sorted, y_spline_pred, color='#3fb950', lw=2)
axes[2].set_title('Natural Cubic Spline (4 knots)', fontsize=11, color='#f0f6fc')
axes[2].set_xlabel('Age')
plt.tight_layout()
plt.savefig('/tmp/basis_demo.png', dpi=120, bbox_inches='tight',
facecolor='#0d1117', edgecolor='none')
plt.show()
from math import comb
print('Polynomial R2: %.4f' % model_poly.score(X_poly, y))
print('Step Function R2: %.4f' % model_step.score(X_binned, y))
print('Spline R2: %.4f' % model_spline.score(X_spline, y))
print('All three are linear in beta — same OLS engine, different basis.')
課本 §7.2 的 Figure 7.2 展示了階梯函數在生物統計學中的經典應用:以 5 年為一組分析疾病發生率。用指示函數當基底,每個年齡組就是一個 bⱼ(X)。這種方法在 cohort study 中極其常見——雖然粗糙,但解釋性強:「40-44 歲族群的心血管疾病風險是 20-24 歲族群的 3.2 倍」。
課文提到,除了多項式和分段常數之外,傅立葉級數(sine/cosine)和 wavelet 也可以當基底函數。在時間序列分析中,用 sine/cosine 基底來建模季節效應是標準做法——無需手動標記「一月、二月…」,基底函數自動捕捉週期性波動。
基底函數框架給我們的啟發遠超出統計:把複雜問題拆成「固定的變換模組 + 線性組合」,是軟體架構中反覆出現的模式。就像 Hermes Agent 系統中的 skill 機制——每個 skill 是一個「基底函數」(固定的能力模組),Agent 根據任務需求動態組合這些模組(相當於學習 β 係數)。這解釋了為什麼 skill 架構既靈活(能處理多樣任務)又可控(每個 skill 的行為是確定的):它本質上是一個基底函數方法!
| 基底類型 | bⱼ(x) 形式 | 全域/局部 | 平滑度 | 典型應用 |
|---|---|---|---|---|
| 多項式 | xʲ | 全域 | 平滑 | 簡單的非線性趨勢(§7.1) |
| 分段常數 | I(cⱼ ≤ x < cⱼ₊₁) | 局部 | 不連續 | 類別化分析、流行病學(§7.2) |
| 迴歸樣條 | 截斷冪基底 | 局部 | 平滑(可微) | 靈活曲線擬合(§7.4) |
| 自然樣條 | 邊界線性約束的樣條基底 | 局部 | 平滑 + 邊界穩定 | 邊界行為重要的場景(§7.4) |
| 傅立葉級數 | sin(ωⱼx), cos(ωⱼx) | 全域 | 平滑(週期性) | 時間序列季節性、信號處理 |
| Wavelet | ψⱼₖ(x),多尺度局部基底 | 局部 | 可調 | 影像壓縮、突變點偵測 |
基底函數框架給了我們一個統一的語言來描述非線性模型。但問題來了:如何選擇既靈活又穩定的基底? 多項式在邊界不穩定、分段常數缺乏平滑性。§7.4 要介紹的 迴歸樣條(regression splines) 正是解決這個問題的答案——它把區間分段,每段用低階多項式,並在節點處強制平滑連接。這是基底函數框架中最實用的變體。