加入更多預測變數:為什麼,又該怎麼做
在前兩篇指南裡,你用單一個預測變數配出一條線:一個輸入(例如一間房子的樓地板面積)對上一個結果(它的價格)。那一條線很有威力,但真實世界很少這麼乾淨。兩間面積完全相同的房子,可能因為一間是全新、另一間屋齡五十年,或因為一間緊鄰捷運站、另一間要走很久,而賣出非常不同的價格。光靠面積,根本看不到這些差異。
多元迴歸(multiple regression)是很自然的解法:我們不再只用一個預測變數,而是讓好幾個預測變數同時來解釋結果。作法正是你已經熟悉的那一套——最小平方法仍然挑出那組讓預測誤差盡可能小的數字——只是現在每一個預測變數都各有一個數字(一個係數)。
把它寫出來,這個模型說:結果 y 等於一個基準值,加上每個預測變數各自的貢獻,再加上一個誤差項,用來涵蓋模型沒能捕捉到的一切:
多元迴歸模型:一個基準值 β₀,加上每個預測變數 x 各乘上一個係數 β,再加上一個涵蓋其餘部分的誤差項 ε。
這裡每個 x 是一個預測變數,β₀(讀作「beta-zero」)是截距或基準值,而每個 β 是某一個預測變數的係數。為了有具體的感覺,假設我們用樓地板面積(平方公尺)、屋齡(年),以及是否鄰近捷運站(一個 0/1 旗標)來配一個公寓價格(以千美元計)的模型。最小平方法可能會傳回:
本篇指南全程都會用到的公寓模型範例。「price」上面那頂小帽子,標示它是一個預測值。
接下來整篇指南,我們都會待在這個例子裡。注意:現在我們不僅得到更豐富的預測,而且同樣重要的是——每個係數都變成對某一個因素更乾淨的陳述,正是因為其他因素也都在模型裡。第二項好處正是下一節的全部重點。這一切的深入詞條是多元迴歸。
一個互動式散布圖,當點被拖動時,那條最佳配適直線會跟著更新。
「在其他條件不變下」
這裡是整篇指南最重要的一句話:在多元迴歸裡,每個係數告訴你的是——在其他所有預測變數都保持不變的情況下——它那個預測變數的效果。統計學家把這稱為 ceteris paribus 的詮釋——拉丁文「其他條件相同」之意。
拿屋齡的係數 −1.5 來說。它並不是含糊地說「屋齡較老的公寓比較便宜」。它說的是一件很精確的事:在面積相同、且鄰站狀態相同的公寓之間,屋齡每多一年,價格大約低 1.5 千美元。實際上,模型等於把面積與地點都相符的公寓排在一起,再問:在這個相符的群組裡,光是屋齡會帶來什麼。
更正式地說,在其他預測變數保持不變下,預測變數 x_j 每增加一單位,預測結果就恰好改變它的係數 β_j:
在其他變數不動的情況下,每個係數就是「它自己的預測變數變動一單位時,預測值會改變多少」。
為什麼這這麼重要?因為來自單一預測變數的簡單迴歸,它的係數是混在一起的。如果較新的公寓往往也比較大,那麼只放面積的模型,會悄悄把面積一部分的效果記到「新」的頭上,反之亦然。把兩者都放進模型,多元迴歸就會在統計上「移除」每個預測變數中能被其他變數解釋的部分,只回報那個獨特的、剩下的貢獻。這正是人們說某個結果「控制了」屋齡,或「校正了」地點時的意思。
類別型預測變數:虛擬變數
到目前為止,每個預測變數都是一個可以乘上係數的數字。但許多最有用的預測變數其實是類別,而不是數字:行政區、房型、品牌、是/否旗標。你沒辦法真的把一個係數乘上「市中心」這個詞。你得先把類別轉成數字。
標準的技巧是虛擬變數(dummy variable,也叫指示變數,indicator variable):一個在某條件成立時為 1、否則為 0 的欄位。我們的 near_station 預測變數本身就是一個虛擬變數——鄰站為 1、不鄰站為 0。它的係數 +8 讀作:在面積與屋齡保持不變下,鄰近捷運站的公寓,預測價格會比其他條件都相同、但不鄰站的公寓高出大約 8 千美元。
那麼超過兩個層級的類別呢?例如行政區 A、B、C。你會替每個層級各做一個虛擬變數,但刻意留下一個當作參考(基準)類別。以 A 當參考,你就建立兩欄:「是 B 嗎?」與「是 C 嗎?」。這時 B 虛擬變數的係數若是 +12,就表示:在其他條件不變下,行政區 B 的預測價格比行政區 A 高 12 千美元。每個類別都被讀成「與你拿掉的那一個之間的比較」。
- 列出該變數的所有類別(例如:A、B、C)。
- 挑一個當參考類別——通常是最常見的層級,或一個自然的基準。
- 為其餘每一個類別各建立一個 0/1 的虛擬欄位。
- 把每個虛擬變數的係數讀成「相對於參考類別的差距」,且在其他預測變數保持不變下。
import pandas as pd # turn the 'neighborhood' column (A, B, C) into 0/1 dummy columns, # dropping the first level (A) as the reference category dummies = pd.get_dummies(df['neighborhood'], prefix='nb', drop_first=True) # -> new columns: nb_B, nb_C (neighborhood A is the baseline)
交互作用
在目前的模型裡,每個係數都是一個固定的數字:每多一平方公尺就值 +2.5,就這樣,不管公寓在市中心還是在郊區。但這個假設往往是錯的。鄰近繁忙車站的空間,每平方公尺的溢價可能比遠處的空間更高。當一個預測變數的效果取決於另一個預測變數的水準時,我們就說這兩個預測變數有交互作用(interaction)。
我們捕捉交互作用的方法,是加入一個新的預測變數,它是原本兩個變數的乘積——在這裡就是面積乘上 near_station 旗標:
交互作用項其實就是兩個預測變數的乘積,並給它自己的一個係數 β₃。
現在面積的斜率不再是單一數字。當 near_station = 0 時,乘積項消失,每平方公尺值 β₁;當 near_station = 1 時,乘積項啟動,每平方公尺值 β₁ + β₃。所以面積的效果本身就是一道小公式:
有了交互作用,「面積的效果」就取決於鄰站旗標——它是兩條不同的斜率,而不是一條。
代入實際數字,假設 β₁ = 2.0、β₃ = 1.0。那麼遠離車站時,每平方公尺增加 2.0 千美元;鄰近車站時,增加 2.0 + 1.0 = 3.0。交互作用係數 β₃ 正是那個差距——當你把鄰站旗標打開時,面積效果會多出(或少掉)多少。
一個有兩條輸入軸的二維平面,一條分界線把不同預測結果的區域分開;在單純的可加性情況下這條線是直的,加入交互作用後則彎曲。
多元共線性:當預測變數彼此重疊
當每個預測變數都帶來自己的資訊時,多元迴歸表現得最好;當兩個以上的預測變數帶著幾乎相同的資訊時——也就是它們彼此高度相關時——它就會陷入困境。這個情況稱為多元共線性(multicollinearity),它是迴歸最安靜地誤導你的方式之一。
想像那個極端的情形。假設你不小心同時放進了以平方公尺計的樓地板面積,以及完全相同、但以坪計的面積(坪是台灣的單位,約 3.3 平方公尺)。這兩欄完全多餘——一欄只是另一欄乘上一個常數。模型根本無法決定要怎麼在它們之間分配功勞:它可以把所有權重放在其中一個、全放在另一個,或任何介於中間的組合,配適得一樣好。軟體要嘛直接拒絕,要嘛傳回狂亂、毫無意義的係數。日常的版本則更微妙:臥室數與樓地板面積往往一起上升,所以它們會部分地互相踩到對方。
幾個明顯的徵兆:標準誤暴增,使得信賴區間變得非常寬;係數出現出乎意料或翻轉的正負號;而且當你加入或拿掉單一一個變數時,估計值會劇烈擺盪。這些其實都是模型誠實地承認:「我分不出這些重疊的預測變數中,是哪一個值得這份功勞。」常用的診斷是變異數膨脹因子(variance inflation factor, VIF),它針對每個預測變數計算一個數值,當那個預測變數能被其他變數充分解釋時,這個數值就會變大。
像專家一樣讀懂迴歸報表
當你配好一個模型,你的軟體會印出一張表——對初學者來說,它看起來就像一面數字牆。我們來配出我們的公寓模型,再一欄一欄地把每一欄解碼。
import statsmodels.formula.api as smf
model = smf.ols('price ~ area + age + near_station', data=df).fit()
print(model.summary())term coef std err t p>|t| 95% CI intercept 30.20 8.10 3.73 0.000 [ 14.3, 46.1] area 2.48 0.21 11.81 0.000 [ 2.07, 2.89] age -1.52 0.34 -4.47 0.000 [-2.19, -0.85] near_station 7.90 2.60 3.04 0.003 [ 2.80, 13.00] R-squared = 0.78 Adjusted R-squared = 0.77 n = 240
一欄一欄看:coef 是估計的係數——也就是我們一路在詮釋的那個偏效果(partial effect)。std err(標準誤)衡量這個估計值在不同樣本之間會擺盪多少;越小越確定。t 這一欄就是 coef 除以它的標準誤——這個估計值離零有幾個標準誤那麼遠。
p>|t| 這一欄是p 值,對應的假設是「真正的係數恰好為零」(也就是在考慮其他變數後,這個預測變數沒有效果)。p 值很小(這裡遠低於 0.05)表示:如果那個係數真的是零,這份資料會令人意外。不過要小心:p 值不是「係數為零的機率」,它也完全沒說效果有多大或多重要——它只說資料與「零效果」有多相容。95% CI 是信賴區間:真正係數的一段合理數值範圍。誠實的讀法是關於程序的——如果我們把整個研究重複很多次,用這種方式建出的區間大約有 95% 會包含真值——而不是「真值有 95% 的機率落在這個特定範圍裡」。
最後是最底下那行。R-squared(R²)是模型解釋掉的價格變異的比例——0.78 表示 78%。但每加一個預測變數,R² 永遠不會下降,連加一個沒用的隨機變數也一樣,所以它會悄悄獎勵臃腫的模型。Adjusted R-squared(調整後 R²)藉由對每個額外的預測變數施加懲罰來修正這點;如果你加一個變數後,調整後 R² 幾乎不動(或下降),那這個變數大概沒掙到它的位置。而 n 就只是模型配適時所用的觀測值數目。
一張殘差散布圖:健康的情況下,點隨機散布在一條水平的零線周圍;不健康的情況下,則出現明顯的曲線或扇形擴散的形態。
要避開的詮釋陷阱
你現在會讀多元迴歸了。最後、也最有價值的一項技能,是知道它會怎麼騙你。以下是連經驗豐富的分析師都會中招的陷阱。
與此密切相關的是遺漏變數偏誤(omitted-variable bias):漏掉一個既影響結果、又與你保留的某個預測變數相關的變數,會扭曲那個預測變數的係數。這是「控制」的另一面——控制得太少,你的數字就會有偏誤。
不要把係數比較大,讀成那個預測變數比較重要。係數帶著各自預測變數的單位:每平方公尺 2.5 的係數,和每個鄰站旗標 8 的係數,活在完全不同的尺度上,所以它們的原始大小並不能直接比較。要公平比較重要性,先把預測變數放到共同的基準上——例如在配適前把它們標準化到相同的尺度。
再快速講兩點。統計上的顯著不等於實務上的重要:只要樣本夠大,一個微不足道的小效果也能有極小的 p 值;而在小樣本裡,一個很大、與業務切身相關的效果,卻可能達不到顯著——永遠去看係數的大小與它的信賴區間,而不是只看那幾顆星號。還要當心外推(extrapolation):一個用 20 到 120 平方公尺公寓配出的模型,對一間 500 平方公尺的頂樓豪宅幾乎沒什麼話可說。相信你資料範圍內的預測,對範圍之外的則要非常謹慎。
- 先講清楚問題:你是要做預測,還是想詮釋某一個係數?目標不同,重點就不同。
- 把每個係數詮釋成偏效果——「在其他預測變數保持不變下」。
- 在信任任何個別係數之前,先檢查多元共線性。
- 畫殘差圖;確認模型的形狀與假設看起來合理。
- 回報係數時要附上信賴區間,而不是只給 p 值。
- 除非你的設計(而不只是你的控制變數)撐得起因果語言,否則就忍住別用。
這就是多元迴歸:一次放進多個預測變數,每個係數都是一句謹慎的「其他條件相同」陳述,用虛擬變數處理類別、用交互作用處理會變動的效果,並對重疊與過度延伸保持健康的懷疑。在這個單元接下來,邏輯迴歸會把同樣這些想法,套用到「是/否」的結果上;而關於過度配適與正則化的那篇指南,則會告訴你如何讓一個有很多預測變數的模型保持誠實。你在這裡建立的詮釋紀律,會一路帶進那些主題。