Learning Objectives
- 用 LinearRegression 的 fit 與 predict 做多元迴歸,並對照 numpy 的最小平方法
- 用測試資料的 R² 與 RMSE 評估模型,並和「一律猜平均」的基準比較
- 讀懂係數:其他特徵固定時的關聯,會隨放進去的特徵改變,不能當成因果
- 用 StandardScaler 標準化,說明標準化改變了什麼、沒有改變什麼
特徵不只一個的時候
期末成績不會只和一件事有關。讀書時數、睡眠、缺席次數、小考、期中考,都可能有關聯。把這些特徵都放進同一條式子,就是多元迴歸(multiple regression):
預測值 = w1 × 特徵1 + w2 × 特徵2 + … + b
前兩課你用 numpy 親手算過線性迴歸,也用梯度下降走過一次。接下來幾乎每一課都會用 scikit-learn:它把常用的模型包成同一套寫法,換模型時程式幾乎不用改。
這一課要回答三個問題:
- scikit-learn 的
fit與predict怎麼用,算出來的東西和 numpy 一樣嗎? - 模型算出來的係數可以怎麼讀,不可以怎麼讀?
- 數字範圍差很多的特徵要不要先處理?什麼時候一定要處理?
逐步看:fit 與 predict
六位同學、兩個特徵。看 model 在 fit 前後多了什麼,再自己用係數算一次預測,確認 predict 沒有做其他事。
scikit-learn 的固定寫法
scikit-learn 的模型都長一樣,記住這幾個名字,之後每一課都用得到:
| 寫法 | 做什麼 |
|---|---|
model = LinearRegression() |
建立模型,設定超參數 |
model.fit(X_train, y_train) |
用訓練資料學習;回傳模型自己,所以可以寫成一行 LinearRegression().fit(...) |
model.predict(X_new) |
預測 |
model.score(X, y) |
評估;迴歸預設回傳 R²,分類預設回傳準確率 |
model.coef_、model.intercept_ |
fit 學到的東西,名稱結尾有底線 |
最常見的錯誤是 X 只有一維。 只用一個特徵時,df["study_hours"] 是一維的 Series,fit 會回報 ValueError;要寫 df[["study_hours"]](兩層中括號),得到只有一欄的表。numpy 陣列則用 x.reshape(-1, 1)。
逐步看:預測期末成績
接著用 students.csv(程式產生的模擬資料,不是任何學校的真實資料),用五個特徵預測期末成績。流程和第 2 課相同:先切開,只用訓練資料 fit,用測試資料評估。
係數怎麼讀
上一段算出期中考的係數是 0.591。正確的讀法是:
在這份資料裡,其他特徵固定時,期中考多 1 分,模型預測的期末成績多約 0.59 分。
有三件事要小心:
- 這是關聯,不是因果。 係數不能告訴你「多考 1 分會讓期末變高」。這份資料也是模擬的,不要拿來推論真實世界。
- 係數帶著單位。 睡眠的係數是「每多 1 小時」,期中考是「每多 1 分」,兩者不能直接比大小。
- 係數會隨著放進去的特徵改變。 下面這段程式會讓你看到,同一個特徵的係數可以從明顯變成幾乎是 0。
逐步看:同一個特徵,係數可以差很多
只看讀書時數的係數。每一輪多放一個和它有關聯的特徵,看它怎麼變。
為什麼係數會變
只有讀書時數一個特徵時,係數是 0.918;放進小考與期中考後只剩 0.055。
這不是「讀書沒有用」。這兩個係數回答的是不同的問題:
| 模型 | 係數回答的問題 |
|---|---|
| 只有讀書時數 | 讀書時數差 1 小時的同學,期末平均差多少? |
| 加上小考、期中考 | 小考與期中考都一樣的同學,讀書時數差 1 小時,期末平均差多少? |
在這份模擬資料裡,讀書時數和小考、期中考有相關,讀書時數能提供的資訊大多已經包含在那兩個分數裡,所以第二個問題的答案接近 0。
寫報告時,要連同「模型裡還放了哪些特徵」一起說明,不要只寫「某某特徵的係數是多少」。
逐步看:標準化之後的係數
想比較哪個特徵的影響比較大,要先把單位拿掉。標準化(standardization)是減掉平均、除以標準差,轉換後每個特徵的平均是 0、標準差是 1。看表格的兩欄係數,再看最後兩行的 R²。
標準化改變了什麼
標準化之後,最小平方法的預測和 R² 都沒有變,那為什麼還要學?因為很多模型會受尺度影響:
| 模型 | 受尺度影響嗎 | 為什麼 |
|---|---|---|
| 線性迴歸(最小平方法) | 預測不受影響,係數的數字會變 | 直接解方程式,單位變了係數等比例變 |
| 用梯度下降訓練的模型 | 會 | 尺度差很多時,學習率很難選,走得很慢甚至發散 |
| Ridge、Lasso(第 6 課) | 會 | 懲罰係數大小,而係數大小和單位有關 |
| k 近鄰、支援向量機(第 8、11 課) | 會 | 距離會被數字範圍大的特徵主導 |
| 決策樹(第 9 課) | 不會 | 只比大小,不算距離也不算梯度 |
除了標準化,另一種常見的做法是最小最大縮放(min-max scaling,MinMaxScaler):減掉最小值、除以最大值與最小值的差,轉換後每個特徵都落在 0 到 1 之間。它的弱點是只看最大與最小,一個極端值就能把其他資料壓扁。
無論哪一種,都只能用訓練資料 fit。 測試資料代表「模型還沒看過的資料」,平均與標準差如果是連測試資料一起算的,就等於偷看了答案的一部分,這叫資料洩漏(第 14 課會細談)。
下面的小工具用兩個尺度差很多的特徵,讓你看尺度影響的兩件事:k 近鄰找到的鄰居(第 8 課會正式教,現在只要知道它是「找距離最近的幾筆資料,看它們大多是哪一類」),以及第 4 課的梯度下降。
實作:自己寫標準化
完成 standardize(X_train, X_test):平均與標準差只用 X_train 算,回傳轉換後的訓練資料與測試資料。寫好之後,下面的程式會用它訓練線性迴歸並預測。
小測驗:多元迴歸與標準化
下面程式會印出什麼?
import numpy as np
from sklearn.linear_model import LinearRegression
X = np.array([[1.0], [2.0], [3.0]])
y = np.array([3.0, 5.0, 7.0])
m = LinearRegression().fit(X, y)
print(round(m.predict(np.array([[10.0]]))[0], 1))
LinearRegression().fit(df["study_hours"], df["final"]) 會回報 ValueError,要怎麼改?
模型裡有讀書時數、小考、期中考三個特徵,讀書時數的係數是 0.055。最恰當的讀法是?
原始資料的係數裡,睡眠和期中考都是 0.591。可以說兩者一樣重要嗎?
小測驗:標準化改變了什麼
把線性迴歸(最小平方法)的特徵標準化之後,測試 R² 會怎樣?
下面哪一個模型不受特徵尺度影響?
模型上線後要預測一位新同學,他的資料要怎麼標準化?
重點整理
- scikit-learn 的模型都有
fit、predict、score;X 要是二維,只有一個特徵時寫df[["欄"]]。 LinearRegression解的是最小平方法,結果和 numpy 的lstsq相同;學到的東西在coef_、intercept_。- 評估看測試資料的 R² 或 RMSE,並且和「一律猜平均」的基準比。
- 係數是其他特徵固定時的關聯,不是因果;它帶著單位,也會隨放進去的特徵改變。
- 標準化:減掉平均、除以標準差。最小平方法的預測不受影響;梯度下降、Ridge、Lasso、k 近鄰都會受影響。只用訓練資料 fit,否則是資料洩漏。
- 下一課:把特徵擴充成 x²、x³,模型變得更有彈性,也開始記住雜訊,要用正則化把它拉回來。