搜尋課程與筆記

搜尋筆記

輸入主題、關鍵字或單元編號,例如 Flow Matching、U4。

    按 Esc 關閉 · ⌘ / Ctrl K 開啟搜尋

    L0.0 13 分鐘閱讀 2026年10月

    L0.0 房仲怎麼估價:從例子學規則

    本篇重用1 篇

    房仲為什麼能估價

    一位資深房仲看過幾百間房子的成交價。你帶他去一間他沒看過的房子,他站三分鐘,說「大概 2,850 萬」。三週後成交 2,910 萬。

    他做了什麼?他不是在背——這一間他沒看過。他也說不出一條公式(「每坪加多少、每老一年扣多少」),問他就是「感覺」。但他的感覺顯然帶著資訊:換一個沒看過房子的人來,誤差會大得多。

    你要把他的本領寫成程式。你必須先指定哪些東西?以及,「估得準」到底是什麼意思——準到什麼程度算成功?

    「拿成交資料 fit 一個函數」還沒有說清楚:允許哪些函數?怎樣算估錯?又用哪些成交案例?這三個決定會影響學到的規則,也決定表現不好時要檢查什麼。

    我們先把這三件事寫成數學,再用同一份 toy data 比較訓練點與新位置上的預測。問題是:把看過的例子答得很好,真的代表已經學會估沒看過的房子嗎?

    「訓練誤差低」從來不是結論。

    從例子學規則,你必須先指定哪些東西?
    而「估得準」到底是哪一個數字小——
    它和你能算的那個數字是同一個嗎?

    課堂提問Q1

    把上面那兩個問題翻成數學。你要指定哪三樣東西?「學」這個動作是在對什麼東西求極值?

    先想一想,再展開看整理後的答案

    最常被寫下來的答案是「最小化 ∑i(f(xi)−yi)2\sum_i (f(x_i)-y_i)^2」。式子對,但它同時暗藏了三個決定,而且把「能算的」當成了「想要的」。

    要指定的三樣:

    1. 假設空間 F\mathcal F:你允許的規則長什麼樣。只准直線?可以彎幾次?可以是深度網路?這是「候選答案的集合」。
    2. 損失 ℓ(y^,y)\ell(\hat y,y):單筆估錯要扣多少分。差 10 萬與差 100 萬之間的比例由你宣告,不是天生的(下一篇整篇在講這件事)。
    3. 資料 D={(xi,yi)}i=1nD=\{(x_i,y_i)\}_{i=1}^n:他看過什麼。標準假設是這 nn 筆從某個聯合分佈 p(x,y)p(x,y) 獨立同分佈抽出。

    「學」= 求極值。 在 F\mathcal F 裡挑出讓資料上的平均損失最小的那個 ff:

    f^=arg⁡min⁡f∈F 1n∑i=1nℓ(f(xi),yi).\hat f=\arg\min_{f\in\mathcal F}\ \frac1n\sum_{i=1}^n \ell(f(x_i),y_i).

    「估得準」不是這個數字。 你想要的是下一間房子估得準——對還沒抽到的 (X,Y)(X,Y) 取期望:R(f)=E[ℓ(f(X),Y)]R(f)=\mathbb E[\ell(f(X),Y)]。你能算的是資料上的平均,你想小的是期望。這兩個數字不同,整個系列的判斷力都建立在「它們差多少、什麼時候差很多」上面。

    三個設定,各自控制不同的東西

    把三要素看成三項可以分開調整的選擇:

    • 假設空間是「你允許他考慮哪些答案」。允許得太少(只准直線),再多資料也估不準——彎的東西用直線描不出來。允許得太多(任意曲線),他可以完美穿過看過的每一點,卻對沒看過的點胡說。
    • 損失是「你怎麼替他扣分」。扣分方式一換,同一份資料的最佳答案就換一個位置——天氣預報該報幾度:MSE 的最小值是 Conditional Expectation 那一篇已經把這件事釘死:平方誤差選條件平均,絕對誤差選中位數。
    • 資料是「他看過什麼」。看得少、或看的和考的不是同一種房子,前兩個設定調得再好也沒用。

    所以「模型不夠好」還不是診斷。資料、模型與損失可能互相影響,不能只從一個低分就決定該換哪一項;較大的模型也可能因為合適的結構或 regularization 改善結果。

    同一份資料,三個設定各改一格

    圖說: 假設空間、損失與資料各自壞掉時,會留下不同的形狀;「模型不夠好」還不是診斷。

    能算的那個數字,和想小的那個數字

    固定損失 ℓ\ell 與資料分佈 pp。一個規則 ff 的母體風險(真正想小的)與經驗風險(能算的)分別是

    R(f)=E(X,Y)∼p[ℓ(f(X),Y)],R^n(f)=1n∑i=1nℓ(f(xi),yi).R(f)=\mathbb E_{(X,Y)\sim p}\big[\ell(f(X),Y)\big], \qquad \widehat R_n(f)=\frac1n\sum_{i=1}^n \ell(f(x_i),y_i).

    ERM 就是 f^=arg⁡min⁡f∈FR^n(f)\hat f=\arg\min_{f\in\mathcal F}\widehat R_n(f)。把最終成績拆開,令 f⋆f^\star 是所有函數裡風險最小的那個(貝氏最佳),f†=arg⁡min⁡f∈FR(f)f^\dagger=\arg\min_{f\in\mathcal F}R(f) 是假設空間內最好的:

    R(f^)−R(f⋆)⏟可以怪你的部分=[R(f^)−R(f†)]⏟estimation error:資料有限+[R(f†)−R(f⋆)]⏟approximation error:空間不夠大,\underbrace{R(\hat f)-R(f^\star)}_{\text{可以怪你的部分}} =\underbrace{\big[R(\hat f)-R(f^\dagger)\big]}_{\text{estimation error:資料有限}} +\underbrace{\big[R(f^\dagger)-R(f^\star)\big]}_{\text{approximation error:空間不夠大}},

    再加上 R(f⋆)R(f^\star) 就得到總風險。這裡先假設找到精確 ERM;實際未解到最小值時,還要考慮 optimization。若把 F\mathcal F 放大成包含原空間的集合,approximation error 不會增加,但 estimation error 不保證單調增加:它還受到演算法、regularization 與資料結構影響。

    平方損失下 f⋆f^\star 是誰?M1.2 的三行證明給了答案:f⋆(x)=E[Y∣X=x]f^\star(x)=\mathbb E[Y\mid X=x],而剩下的 R(f⋆)=E[Var(Y∣X)]R(f^\star)=\mathbb E[\mathrm{Var}(Y\mid X)] 就是不可約誤差。這個句子之後會反覆出現。

    在平方損失下,「學習」有一個非常具體的目標:把條件平均這張表估出來。

    注意為什麼不直接把假設空間設成「所有函數」

    把 F\mathcal F 設成所有函數,ERM 有一個完美解:對看過的 xix_i 回答 yiy_i,其他地方隨便。它的經驗風險是 00,母體風險則和亂猜差不多。這不是理論上的怪例——下面的實作會看到 d=n−1d=n-1 的多項式正好是這種東西。

    這說明只要求訓練資料上答對還不夠。我們需要某種 inductive bias,限制或偏好哪些答案;它可以來自假設空間、regularization,也可以來自演算法。統計學習理論用 complexity 等工具分析泛化 [1,2],這個系列則先用可觀察的訓練與驗證結果建立判斷。

    房仲的三個零件各是什麼

    假設空間。 他心裡不是「任意函數」,而是一個相當受限的家族:找幾間可比較的成交案例,再對坪數、樓層、屋齡、面向做加減。這個家族小到讓他幾百筆資料就夠用——限制正是他能學會的原因,不是他的極限。

    損失。 他被市場用什麼方式扣分?如果客戶對「低估」(房子賤賣了)的痛苦遠大於「高估」(多等兩週),那他該報的就不是條件平均,而是一個偏高的分位數。他往往憑經驗做對了這件事卻說不出理由;下一篇會把它寫成式子。

    資料。 他只看過某一區、某一段時間的房子。「新房子與看過的房子同分佈」這個假設,在換城市、換年份、換房型時就破了——那時前兩個設定調得再好都沒用。這是 台北的房仲去台中:風險與經驗風險 的主題。

    這一切依賴什麼假設。 一,(xi,yi)(x_i,y_i) 獨立同分佈,而且測試時面對的是同一個 pp。二,yy 裡的隨機成分不可預測(否則它其實是你漏掉的特徵)。三,損失真的代表你在意的東西——不是因為它好微分。三個假設在真實專案裡都會壞,而且壞法各自有徵狀,這是接下來八篇的內容。

    系列共用的 toy

    這個系列所有實作都用同一組資料,這樣過擬合、資料切分、學習率、架構差異全部在同一張圖上被看見。存成 ml_toy.py:

    import numpy as np
    NOISE = 0.15
    
    def toy_1d(n=30, noise=NOISE, seed=0):        # 主 toy:一維回歸
        rng = np.random.default_rng(seed)
        x = np.sort(rng.uniform(0, 1, n))
        return x, np.sin(2*np.pi*x) + noise*rng.standard_normal(n)
    
    def truth(m=400):                              # 密集網格上的真值,用來近似母體風險
        x = np.linspace(0, 1, m)
        return x, np.sin(2*np.pi*x)
    
    def toy_2d(n=200, noise=0.20, seed=0):         # 副 toy:兩個交纏的月牙,二元分類
        rng = np.random.default_rng(seed)
        t = rng.uniform(0, np.pi, n//2)
        X = np.r_[np.c_[np.cos(t), np.sin(t)], np.c_[1-np.cos(t), 0.4-np.sin(t)]]
        X = X + noise*rng.standard_normal((n, 2))
        return X, np.r_[np.zeros(n//2), np.ones(n//2)].astype(int)

    真實函數是 sin⁡(2πx)\sin(2\pi x),噪聲是標準差 0.150.15 的 Gaussian——所以不可約誤差正好是 0.152=0.02250.15^2=0.0225,任何模型的母體風險都不可能低於它。這個已知的下界之後會一直當作參考線。

    現在做 ERM:假設空間是「次數 ≤d\le d 的多項式」,損失是平方,資料是那 30 個點。

    import numpy as np
    from numpy.polynomial import Polynomial          # 比 np.polyfit 穩定:內部把 x 縮放到 [-1,1]
    from ml_toy import toy_1d, truth, NOISE
    
    x, y = toy_1d()                                   # n = 30
    xs, ys = truth()
    for d in (1, 3, 9, 25):
        f = Polynomial.fit(x, y, d)                   # ERM:這個空間裡經驗風險最小的那個
        print(f"degree {d:2d}  經驗風險 {((f(x)-y)**2).mean():.4f}"
              f"   母體風險 ≈ {((f(xs)-ys)**2).mean() + NOISE**2:.4f}")
    degree  1  經驗風險 0.2118   母體風險 ≈ 0.2679
    degree  3  經驗風險 0.0178   母體風險 ≈ 0.0312
    degree  9  經驗風險 0.0122   母體風險 ≈ 0.0285
    degree 25  經驗風險 0.0016   母體風險 ≈ 8032.3199

    讀這四行:經驗風險單調下降,母體風險先降後爆。 d=1d=1 是 approximation error 主導(直線描不出正弦,兩個風險都大且接近);d=3d=3 到 99 已經逼近不可約誤差 0.02250.0225,多出來的一點是 estimation error;d=25d=25 的經驗風險只有 0.00160.0016——比噪聲的變異數還小,這本身就是警訊,它已經在擬合噪聲——而母體風險是 80328032。

    把空間放大到和資料一樣大,退化得更徹底:

    f = Polynomial.fit(x, y, len(x)-1)                # d = n-1 = 29:剛好能穿過每一個點
    print(f"degree 29  經驗風險 {((f(x)-y)**2).mean():.2e}"
          f"   母體風險 ≈ {((f(xs)-ys)**2).mean()+NOISE**2:.2e}")
    # degree 29  經驗風險 4.28e-04   母體風險 ≈ 1.52e+09

    這是刻意違反「F\mathcal F 要有限制」的結果:經驗風險小到 10−410^{-4},母體風險 1.5×1091.5\times10^9。同一個 print 裡的兩個數字差了十三個數量級,而只有左邊那個是你在訓練時看得到的。房仲版本的翻譯是:一個把每筆成交價背下來、對沒看過的房子就開始亂編的人,在「回答考古題」這個指標上是滿分。

    調整三項要素,看兩條風險怎麼分開

    互動 demo:拉「樣本數 n」看兩條曲線分開多少,拉「模型複雜度」看它們往相反方向走。

    檢查理解

    想一想

    一個團隊的模型在訓練集上 MSE 是 0.0010.001、在驗證集上是 0.90.9。他們決定「換更大的模型」。這個決定:

    想一想

    在 toy 上把噪聲標準差設成 00(yy 就是 sin⁡(2πx)\sin(2\pi x),沒有隨機成分),然後用 d=25d=25 擬合 30 個點。會發生什麼?

    想一想

    「經驗風險 0.00160.0016 比噪聲變異數 0.02250.0225 還小」為什麼是警訊?

    參考文獻

    1. Hastie, T., Tibshirani, R., Friedman, J. The Elements of Statistical Learning, 2nd ed. Springer 2009, Ch. 2, 7.1–7.3.(監督式學習的框架、風險分解、模型複雜度與誤差的關係。)
    2. Shalev-Shwartz, S., Ben-David, S. Understanding Machine Learning: From Theory to Algorithms Cambridge University Press 2014, Ch. 2–5.(ERM 的形式化、為什麼需要限制假設空間、approximation–estimation 分解。)
    3. Vapnik, V. The Nature of Statistical Learning Theory, 2nd ed. Springer 2000.(把「限制假設空間才能學習」變成定量陳述的原始路線。)