JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

簡單線性迴歸

一個預測變數、一個結果,以及一條你能詮釋、也信得過的線——斜率、截距、殘差、R²,以及底下的假設。

模型:y = a + b·x + 誤差

在上一篇裡,我們盯著一張散布圖(scatter plot)——一團散點——並認識了「穿過這團點、最貼合的那條線」這個想法。這一篇要替那條線安排一份工作。只要能把這條線寫成一條公式,我們就能直接從中讀出一段關係、預測一個新值,並判斷整件事有多值得信任。那條公式就叫做簡單線性迴歸(simple linear regression)模型:一個預測變數、一個結果、一條直線。

來看一個具體場景。你正在找房子,順手記下五個物件,每個都有它的坪數(坪是台灣的面積單位,約 3.3 平方公尺)與月租。大一點的地方顯然比較貴——但每多一坪到底貴多少?迴歸能把這種模糊的感覺,變成一個你真的用得上的數字。

用白話說,這個模型主張:結果等於一個起始值,加上每增加一單位預測變數就固定增加的量,再加上一個誤差項,用來吸收直線無法解釋的所有東西。寫成公式就是:

y = \beta_0 + \beta_1 x + \varepsilon

簡單線性迴歸模型的符號寫法。

我們一塊一塊讀。y 是結果(或稱反應變數,response)——我們想解釋或預測的東西,在這裡是租金。x 是預測變數(或稱解釋變數,explanatory variable)——在這裡是坪數。β₀(beta-nought)是截距(intercept):直線與縱軸相交的位置。β₁(beta-one)是斜率(slope):直線上升得多陡。而 ε(epsilon)是誤差——它誠實地承認,真實的點永遠不會剛好落在任何一條線上。

\hat{y} = \hat{\beta}_0 + \hat{\beta}_1 x

我們從樣本估出的配適線;帽子符號代表估計值。

那個小小的「+ ε」,是整條公式裡最誠實的符號。它大聲地說出:模型是一種簡化——租金還取決於地段、屋齡、樓層、採光,以及運氣。迴歸從不宣稱能捕捉到這一切。它只宣稱捕捉到故事中「直線」的那一部分,並對其餘部分坦白以告。

穿過一團散點的一條直線:模型把整片散布,濃縮成一個斜率與一個截距。

一張散布圖,點呈上升趨勢,一條直線迴歸線穿過散點雲的中央。

配適並詮釋斜率(記得帶單位!)

我們怎麼挑出定義這條線的兩個數字——斜率與截距呢?讓資料投票。對任何一條候選的線,每個資料點都在它上方或下方某段垂直距離處;那段間距,就是這個點的殘差(residual)最小平方法(ordinary least squares,OLS)會挑出讓所有間距平方總和最小的那一條線。平方能讓正、負間距不互相抵消,也讓大失誤受到比小失誤重得多的懲罰。

\hat{\beta}_1 = \frac{\sum (x_i - \bar{x})(y_i - \bar{y})}{\sum (x_i - \bar{x})^2}

最小平方法的斜率:把 x 與 y 的共同變動,除以 x 自己的散布。

把這套做法套用到我們五間公寓上,斜率算出來是 1.5,單位是「千元新台幣/坪」。現在來詮釋它——而且絕對不要報一個沒有單位的斜率。它的意思是:每多一坪樓地板面積,平均而言大約對應到每月多 1,500 元新台幣的租金。斜率是一個比率:它帶著「每一單位 x 對應多少 y」的單位。

請留意「對應到」與「平均而言」這兩組小心翼翼的字眼。斜率描述的是在這份資料裡租金與坪數如何一起變動;它並沒有證明,硬替一間公寓加上一坪就會讓它的租金上漲 1,500 元。大公寓和小公寓往往同時在許多方面都不一樣。這就是那句著名的警語:相關不等於因果——要確立真正的因果(causation),遠不只需要一條傾斜的線,我們在這個系列裡會一再回到它。

還有一個誠實的提醒。我們這個 1.5 的斜率,只來自五間公寓;換另外五間,數字就會略有不同。斜率是一個估計,而每個估計都帶著不確定性。好的迴歸報表會給出斜率的標準誤(standard error)信賴區間(confidence interval),常常還附上一個p 值,用來檢定斜率是否有可能其實為零(也就是兩者根本沒有關係)。請把這單一數字當成一個範圍的中心,而不是刻在石頭上的事實。

拖動這條線,看著各個平方間距時大時小——最小平方法就是讓這些間距總和最小的那一條線。

一張互動散布圖,你可以傾斜與平移一條線;小方塊代表每個殘差,移動時平方殘差的總和會即時更新。

截距,以及它何時才有意義

截距 β₀ 很單純,就是當預測變數為零時的預測結果——直線與縱軸相交的高度。在我們配適出的線裡,截距是 0.7,也就是大約 700 元新台幣。照字面解讀,那就是一間「零坪」公寓的預測租金。

這當然是胡說八道——根本沒有零坪的公寓,而且零離我們的資料很遠(我們的資料落在 10 到 20 坪)。這就是外推(extrapolation)的陷阱:迴歸線只在你真正觀測過的 x 範圍內才值得信任。把它硬推到那個範圍之外,它會很樂意回給你一堆自信滿滿、卻毫無意義的數字。

\hat{\beta}_0 = \bar{y} - \hat{\beta}_1 \bar{x}

截距是這樣定出來的:讓直線通過平均點 (x̄, ȳ)。

那截距到底有沒有可能有意義?有——只要 x = 0 是真實的、而且落在你的資料範圍之內。假如 x 是每日廣告花費,那麼「零花費」就是一個貨真價實、可以詮釋的情況,截距就是「完全不打廣告時的基準銷售量」。當零這個值很不自然時,一個常見的小技巧是把預測變數置中(centering)——把每個 x 都減去它的平均——這樣新的截距就變成「在平均 x 處的預測 y」(在這裡是一間典型 15 坪公寓的租金,約 23,200 元),讀起來容易多了。

殘差:直線沒能抓住的部分

殘差就是直線沒抓住的那一塊現實:實際值減去預測值。它是整個迴歸裡資訊量最大的一個量,因為後面所有的判斷——配適得好不好、假設成不成立——其實都只是把殘差放在不同的燈光下端詳而已。

e_i = y_i - \hat{y}_i

殘差:對每個資料點 i,實際值減去預測值。

看那間 12 坪的公寓。我們的線預測 0.7 + 1.5 × 12 = 18.7,也就是 18,700 元。它實際租金是 20(20,000 元)。它的殘差是 +1.3:比線所預期的貴了大約 1,300 元——也許它剛裝修過,或就在捷運站旁邊。正殘差落在線的上方,負殘差落在下方。以下是全部五間:

\begin{array}{c|c|c|c} x\,(\text{size}) & y\,(\text{rent}) & \hat{y} & e_i \\ \hline 10 & 15 & 15.7 & -0.7 \\ 12 & 20 & 18.7 & +1.3 \\ 15 & 22 & 23.2 & -1.2 \\ 18 & 29 & 27.7 & +1.3 \\ 20 & 30 & 30.7 & -0.7 \end{array}

每間公寓的預測值與殘差(租金以千元計);殘差總和為零。

兩個事實讓殘差與眾不同。第一,正因為最小平方法是這樣建構出來的,殘差的總和永遠(基本上)等於零——高估與低估會相互抵消。第二,最小平方法正是那條「讓殘差平方總和最小」的規則;以這個標準衡量,在這份資料上沒有別條直線贏得了它。把殘差這一欄放在眼前——接下來兩節做的事,就只是不斷盤問它而已。

殘差就是每個點到直線之間的垂直間距——模型沒抓到的那一部分。

一條已配適的迴歸線,每個資料點以垂直虛線連到線上,有的在上、有的在下,說明正殘差與負殘差。

R²:解釋了多少變異

這條線到底好不好?這就是定義 R² 的那個巧思。想像你根本沒有任何一條線,而有人要你猜任何一間公寓的租金。你最好的單一猜測,就是整體的平均租金 ȳ(在這裡是 23.2,約 23,200 元)。各個點仍然會散落在那條水平的平均線周圍,而那整片散布,就是你想要解釋的變異。

迴歸線解釋掉那片散布的一部分;剩下、化為殘差散布的,就是它解釋不了的部分。判定係數(R²,coefficient of determination)很單純,就是直線解釋掉的變異佔總變異的比例:

R^2 = 1 - \frac{SS_{\text{res}}}{SS_{\text{tot}}} = 1 - \frac{\sum (y_i - \hat{y}_i)^2}{\sum (y_i - \bar{y})^2}

R²:一減去(剩下的散布除以總散布)。

把我們的數字代進去——總散布 SS_tot = 158.8、剩下的散布 SS_res = 5.8——得到 R² ≈ 0.96。白話說:光是坪數,就解釋了這些公寓租金約 96% 的變異。這是很強的配適。(R² 永遠落在 0 與 1 之間;對一個只有單一預測變數的簡單迴歸而言,它剛好等於相關係數(correlation coefficient)的平方。)

  1. 高 R² 不代表模型是對的。一段嚴重彎曲的關係,仍可能交出很高的 R²,但那條直線的形狀明明就是錯的——一定要看殘差圖(見下一節)。
  2. R² 對因果隻字未提。坪數解釋了租金 96% 的變異,並不能證明是坪數決定了租金。
  3. 低 R² 不見得就是壞事。人的行為充滿雜訊;一個真實又有用的效果,完全可能安住在 0.1 的 R² 之中。
  4. 每多加一個預測變數,R² 永遠不會下降,所以在多元迴歸(multiple regression)裡,它是個不該追逐的目標——那條路會直通過度配適(overfitting)

用殘差圖檢查假設

上面的每個數字——斜率、截距、R²、標準誤——都建立在一組小小的假設之上。假設成立時,這條線與它的不確定性才值得信任;假設崩壞時,同樣這些數字會悄悄地把你帶偏。對簡單線性迴歸而言,用白話講,重要的假設有這幾個:

  1. 線性——真正的關係確實大致是一條直線,而不是一條偽裝過的曲線。
  2. 獨立——各個觀測值彼此不互相牽連(一間公寓的租金,不是由它隔壁那間決定的)。
  3. 變異數固定,即同質變異(homoscedasticity)——線周圍的散布在各處大致一樣大,而不是左邊很緊、右邊散開成喇叭狀。
  4. 殘差大致呈常態——剩下的誤差不會嚴重偏斜,也不會充斥離群值。這一點影響的是標準誤、信賴區間與 p 值,而不是斜率估計本身;這裡指的鐘形就是常態分配(normal distribution)

檢查這些,靠的多半是一張不起眼的圖:殘差圖——縱軸放殘差,橫軸放配適值。如果假設成立,你應該看到一團毫無形狀、毫無規律、在零附近徘徊的雲。經典的警訊有:一條曲線或微笑形(關係其實是非線性的)、一側逐漸張開的喇叭口(變異數不固定),以及一個孤零零、遠離其他點的點(離群值(outlier),或一個影響力異常大的觀測)。

這正是整個領域堅持「你一定要先畫圖」的最深層理由。安斯庫姆四重奏(Anscombe's quartet)——四組小資料,平均數、變異數、相關與迴歸線幾乎一模一樣,形狀卻完全不同——是每位分析師都要學到的警世故事。摘要數字彼此吻合,唯有圖像說出了真相。請把檢查假設當成探索性資料分析(exploratory data analysis)的一部分,而不是事後勾選的形式。

安斯庫姆四重奏:四組資料的平均數、相關與迴歸線幾乎一模一樣——形狀卻完全不同。所以一定要先畫圖。

四張共用同一條配適線與統計量的小散布圖:一張大致線性、一張明顯彎曲、一張是緊密直線但有一個遠處離群點、一張是垂直堆疊外加一個遙遠的點。

一個完整的範例

讓我們把整條流程,從頭到尾在這五間公寓上跑一遍——這樣你就能親手自己做一次。資料是:坪數 10、12、15、18、20(坪),租金 15、20、22、29、30(以千元新台幣計)。以下是每次都該遵循的步驟:

  1. 先畫圖。畫一張「租金對坪數」的散布圖,在配適任何東西之前,先確認這團點看起來大致是直的。
  2. 找出中心。算出平均坪數 x̄ 與平均租金 ȳ。
  3. 用最小平方法公式,從各點對平均的偏差算出斜率。
  4. 算出截距,讓直線通過平均點 (x̄, ȳ)。
  5. 寫出方程式並做預測——但只在觀測到的 x 範圍之內。
  6. 算出殘差,並檢視它們的圖,看看有沒有曲線、喇叭口或離群值。
  7. 報告 R²,而且同樣重要的是,報告斜率的不確定性(它的標準誤或信賴區間)。
  8. 用白話詮釋,帶上單位,並牢牢附上「相關不等於因果」這個但書。
\bar{x} = \frac{10+12+15+18+20}{5} = 15, \qquad \bar{y} = \frac{15+20+22+29+30}{5} = 23.2

步驟二:x 與 y 的中心。

\hat{\beta}_1 = \frac{102}{68} = 1.5, \qquad \hat{\beta}_0 = \bar{y} - \hat{\beta}_1\bar{x} = 23.2 - 1.5\times 15 = 0.7

步驟三、四:先算斜率,再算截距。

\hat{y} = 0.7 + 1.5\,x

我們五間公寓最終的模型。

現在來預測一間新的 16 坪公寓的租金:0.7 + 1.5 × 16 = 24.7,也就是約 24,700 元。因為 16 舒舒服服地落在我們最小(10)與最大(20)的公寓之間,這是誠實的內插(interpolation)。但若拿同一條線去問一間 40 坪的豪宅,那就是外推(extrapolation)了——超出我們看過的資料範圍,不值得信任。

import pandas as pd
import statsmodels.formula.api as smf

df = pd.DataFrame({
    "size_ping": [10, 12, 15, 18, 20],
    "rent_k":    [15, 20, 22, 29, 30],
})

fit = smf.ols("rent_k ~ size_ping", data=df).fit()
print(fit.params)      # Intercept 0.7,  size_ping 1.5
print(fit.rsquared)    # 0.963...
print(fit.conf_int())  # a confidence interval for each coefficient
用 Python(pandas + statsmodels)做同一個配適——三行程式就替你算完,而 conf_int() 會提醒你:斜率是一個範圍,不是一個點。

從這裡開始,路會自然地分成兩條。真實的結果通常同時取決於不只一件事——那就是多元迴歸,在那裡我們還會遇上多元共線性(multicollinearity),以及「在其他條件不變下」這句微妙的話。而當一個模型有許多旋鈕可調時,它就可能開始死背雜訊、而非學會規律——這就是過度配適的問題,靠交叉驗證(cross-validation)來加以節制。這兩條路,都直接建立在你剛學會解讀、也學會信任的這一條線之上。