L1.1 十個房仲各看一百間房:Bias 與 Variance
本篇重用3 篇
十個房仲,同一間房
台北有十位資深房仲,本領一樣、方法一樣。差別只在他們各自看過的一百間房子不同——同一個市場裡隨機抽的一百間。
現在把同一間房子帶去給十個人估。你會得到十個數字。
問題一:這十個數字散得多開? 如果從 2,700 萬到 3,100 萬,那表示「他看過哪一百間」對答案影響很大——換一份資料就換一個答案。
問題二:這十個數字的平均,會偏嗎? 如果十個人平均起來是 2,880 萬而真實價值是 2,900 萬,那有一個 20 萬的系統性偏差——這個偏差不會因為找第十一個房仲而消失,因為它是「這套方法」本身的偏差,不是誰的運氣。
兩個問題是獨立的。一個方法可以很穩定但一直偏(十個人都說 2,600 萬);也可以平均起來很準但每個人差很多(平均 2,900 但散佈 ±400 萬)。兩種都不好,但要修的東西完全不同。
上一篇的分數提供了線索,但還沒有說清楚誤差怎麼來。若同一套方法換一批案例就換一個答案,我們要量的是「平均偏多少」,還是「每次變多少」? 我們先固定一間房子,把這兩種變動分開。
十個房仲對同一間房的估價,會散得多開?
平均起來會偏嗎?
這兩個問題為什麼一定要分開問?
課堂提問Q1
「十個房仲」在數學上是什麼?期望是對什麼取的?把 拆成三塊——每一塊分別對應上面的哪個問題?
先想一想,再展開看整理後的答案
十個房仲 = 十份訓練資料。 訓練集 本身是隨機的(從 抽 筆),所以 是一個隨機函數:換一份資料就換一個模型。房仲的「本領」是演算法(假設空間+損失+最佳化),十個人共用;不同的是餵給它的資料。
期望對兩件事取。 固定一個查詢點 : 的隨機(同一個 的實際成交價本來就有波動)與 的隨機(抽到哪一百間)。兩者獨立。
三項分解。 令 (十個房仲的平均答案, 的版本),(M1.2 說的最佳答案):
bias 是「平均起來偏多少」,variance 是「換一份資料會抖多少」,不可約是「同一個 的 本身就會變」。 三項都非負,所以每一項都是總誤差的下界之一——想要總誤差小,三項都得小。
三塊,各由不同的設定控制
- 不可約誤差 :由問題本身決定。換模型沒用,加資料沒用。唯一能動它的方式是換問題——加入新的特徵,讓原本「隨機」的部分變成可預測的(房子的漏水史、賣方的急迫程度)。這一項在共用 toy 裡正好是 。
- bias²:整套學習方法在這個 下的平均預測,離條件平均多遠。它受到模型、regularization、最佳化與有限資料影響,不只是 approximation error;增加資料也可能改變它。
- variance:換一份訓練資料後,預測離平均預測多遠。它不是 estimation error 的另一個名字;兩者的基準不同。更多資料常能減少它,但一般演算法沒有單調保證。
三個設定解釋了為什麼「模型不夠好」需要先診斷。同樣的症狀(測試誤差高),bias 主導時要加容量,variance 主導時要加資料或減容量,不可約主導時該做的是接受它並停止投入——很多專案在這一格燒掉幾個月。
若十個房仲的誤差不完全同步,平均預測可以降低散佈;但若每個人都只會畫直線,平均仍是直線。這是 ensembling 的直覺。平均預測與平均參數不是同一件事:對非線性網路,一般有 ,不能直接把這個計算當成權重平均的保證。
平均同分布模型的預測,保留它們的平均 bias;能壓多少 variance,還要看彼此的相關性。
圖說: bias 是多次擬合的平均離真值多遠;variance 是每次擬合離那條平均曲線多遠。
把總誤差拆成三塊,再算出 variance 的量級
固定 ,寫 、、。把 拆成三段:
平方後取期望。三個交叉項都是零:第一段對 的條件期望為零且與 獨立;第三段對 的期望為零;第二段是常數。於是
這與 天氣預報該報幾度:MSE 的最小值是 Conditional Expectation 的三行證明是同一個技巧(拆成「均值為零的部分」加「常數部分」,交叉項消失),只是那裡對 分解,這裡多了一層對 的分解。
線性模型有一個乾淨的量級公式。設計矩陣固定、噪聲變異數 、參數個數 (本篇的 一律留給分布),最小平方估計在訓練點上的平均 variance 是
兩個依賴一目了然:參數越多,variance 線性上升;資料越多,線性下降。 這是「 要跟 一起長」這句老話的來源,也是下面實測會驗證的公式。
注意這個分解只對平方損失這麼漂亮
三項分解依賴平方損失的代數(交叉項為零)。換成 0–1 損失或 cross-entropy,「bias」與「variance」仍然可以定義(Domingos 2000 給了一個統一的框架),但它們不再單純相加:分類問題裡 variance 有時幫得上忙——一個平均起來偏向錯誤類別的預測,只要抖得夠厲害,仍然可能有一半的時間落在正確的那一邊。
所以在分類任務上,請把 bias–variance 當成思考工具(是「方法本身偏了」還是「換份資料就變」)而不是可以逐項相加的帳。要量化,直接量你在意的那個指標在多次重抽下的平均與散佈——這也正是 同一個實驗跑三次結果都不同,該報哪一個? 要做的事。
三種處方,與「加資料」的極限
回到十個房仲。如果十個人的估價彼此差很多(高 variance):他們的方法對「看過哪一百間」太敏感。修法是讓每個人多看一些(加資料)、或讓方法更受限(減容量、加正則化),或把十個人的答案平均起來(ensembling)。
如果十個人很一致但一起偏低(高 bias):多找一百個房仲、每人多看一千間,都不會改善。要換方法——加入他們現在沒在看的特徵,或允許更豐富的調整規則。
如果十個人一致、也不偏,但每次的實際成交價本來就在 ±5% 之間跳(不可約):這是市場本身的隨機。此時該做的是改變目標——報一個區間而不是一個數字,或者去找能解釋那 5% 的新資訊。
這一切依賴什麼。 一,十份資料真的是獨立同分佈抽的;若十個房仲其實共用一半的案例,variance 會被低估。二,這裡的 是「無限多份資料的平均模型」,實務上只能用有限次重抽估計,重抽次數不夠時 bias 與 variance 的估計本身就有 variance。三,平方損失(見上面的 Details)。
把三塊量出來
固定 30 個位置(只重抽噪聲,這樣分解裡沒有「設計也在變」這個額外來源),每個 degree 重抽 300 份資料:
import numpy as np, warnings; warnings.filterwarnings("ignore")
from numpy.polynomial import Polynomial
from ml_toy import truth, NOISE
xs, ys = truth()
x = np.linspace(0, 1, 30) # 固定的 30 個位置
Y = np.sin(2*np.pi*x) + NOISE*np.random.default_rng(0).standard_normal((300, 30))
for d in (1, 2, 3, 5, 7, 9, 12):
P = np.array([Polynomial.fit(x, yy, d)(xs) for yy in Y]) # 300 條擬合曲線
bias2 = ((P.mean(0) - ys)**2).mean() # 平均曲線離真值多遠
var = P.var(0).mean() # 每條離平均曲線多遠
print(f"degree {d:2d} bias² {bias2:.4f} variance {var:.4f}"
f" noise {NOISE**2:.4f} 總和 {bias2+var+NOISE**2:.4f}")
degree 1 bias² 0.2004 variance 0.0016 noise 0.0225 總和 0.2245
degree 2 bias² 0.2004 variance 0.0022 noise 0.0225 總和 0.2251
degree 3 bias² 0.0048 variance 0.0028 noise 0.0225 總和 0.0301
degree 5 bias² 0.0000 variance 0.0041 noise 0.0225 總和 0.0266
degree 7 bias² 0.0000 variance 0.0053 noise 0.0225 總和 0.0278
degree 9 bias² 0.0000 variance 0.0069 noise 0.0225 總和 0.0294
degree 12 bias² 0.0000 variance 0.0095 noise 0.0225 總和 0.0320
兩欄的方向完全相反,一如理論。 bias² 從 一路掉到 ( 之後,多項式已經足以逼近 到量測不出的程度);variance 從 單調爬到 。總和的谷底在 (),與上一篇 U 形的谷底一致——U 形不是一個經驗現象,它是這兩欄相加的結果。
三個細節直接看這裡:
- 與 的 bias² 完全相同():二次項對 在 上幫不上忙,所以「加容量」在這一步只買到 variance、沒買到 bias。加錯方向的容量比不加更糟。
- 之後 bias² 是 :這時再減 degree 只會傷害,再加 degree 只買 variance。這一格的正確判斷是「停」,而不是繼續調。
- 不可約誤差那一欄從頭到尾是 :它不是被模型影響的量。總和永遠 ——這條地板線在讀任何訓練曲線時都該先畫出來。
驗證量級公式。 理論說 variance 。固定 ,改變 :
for n in (30, 100, 300):
x = np.linspace(0, 1, n)
Y = np.sin(2*np.pi*x) + NOISE*np.random.default_rng(0).standard_normal((300, n))
P = np.array([Polynomial.fit(x, yy, 9)(xs) for yy in Y])
print(f"degree 9, n={n:3d}: variance {P.var(0).mean():.4f}"
f" (理論 σ²(d+1)/n = {NOISE**2*10/n:.4f})")
degree 9, n= 30: variance 0.0069 (理論 σ²(d+1)/n = 0.0075)
degree 9, n=100: variance 0.0021 (理論 σ²(d+1)/n = 0.0022)
degree 9, n=300: variance 0.0008 (理論 σ²(d+1)/n = 0.0007)
這裡 dense grid 上的 variance 與訓練點平均公式量級接近,但不是同一個量。精確的 grid variance 是 再對 grid 平均;只有在原訓練點平均,才直接等於 。
加資料會影響整個估計器;固定特徵與問題後,不可約誤差才是不隨樣本數改變的部分。
刻意違反:把噪聲關掉。 令 ,不可約誤差變 、公式預測 variance 也變 。但這個結論只在「資料位置固定」時成立——若每次重抽連 的位置一起重抽(更接近真實的重新蒐集資料),高次多項式仍然抖得很厲害,因為設計本身的隨機也是 variance 的來源,而它不隨 消失。這解釋了上一篇的觀察:噪聲為零時仍然可以過擬合。做這個分解時把「什麼在重抽」講清楚,比記住公式更重要。
拖設定,看三塊怎麼此消彼長
互動 demo:三塊各自由不同的設定控制:加資料壓 variance、換假設空間壓 bias、雜訊那塊誰也動不了。
檢查理解
參考文獻
- Geman, S., Bienenstock, E., Doursat, R. Neural Networks and the Bias/Variance Dilemma. Neural Computation 1992.(把分解系統地用在學習演算法上的經典來源。)
- Hastie, T., Tibshirani, R., Friedman, J. The Elements of Statistical Learning, 2nd ed. Springer 2009, Ch. 7.3.(分解、線性模型的 、以及它與模型選擇準則的關係。)
- Domingos, P. A Unified Bias-Variance Decomposition and its Applications. ICML 2000.(0–1 損失等非平方損失下的推廣,以及 variance 在分類裡為何可能有益。)