EN 中文
← 回文章列表
機器學習 · 房地產估價

估價模型的資訊天花板:用實價登錄做 AVM,為什麼 MdAPE 卡在 12% 就上不去

我用實價登錄建了一個房價估價模型,線上 10.7 萬筆實測 MdAPE 約 12%。然後我證明它不可能更準——殘差是這份資料裡根本沒有的東西。知道何時停手,比硬榨 1pp 更值錢。

2026-06-25 myps6415 realping.tw
~12%
MdAPE — LVR-only 天花板
~42%
PE10(成熟 AVM 有 comps 約 60–70%)
10.7 萬
線上 out-of-time 實測筆數

背景

我在做一個叫 RealPing 的側專案:把內政部實價登錄(LVR)的批次資料,清成「去車位、去公設後的實坪每坪成交價」。台灣的官方單價分母含公設、含車位,灌出來的數字普遍比真實使用成本低約 45%,所以「去公設實坪單價」這個乾淨層本身就是別人沒有的東西。

清洗層穩了之後,下一個顯而易見的念頭是:做一個估價模型(AVM),給一個物件的特徵就吐一個實坪單價估值。Zillow 的 Zestimate、台灣的好時價都是這個東西。我建了,量了,然後得到一個比「我做出 X% 準度 🎉」有趣得多的結論——這份資料估不準,而且我能證明為什麼。

這篇就是那個負結果。

怎麼建的

目標變數取 log(實坪單價),模型是梯度提升樹(預設 sklearn 的 HistGradientBoostingRegressor,偵測到 lightgbm 可用就自動切過去)。特徵全部用現成欄位、不需要任何外部資料:

  • 類別:縣市、建物型態、主要用途、有無電梯、總樓層數
  • 數值:屋齡、房 / 廳 / 衛、公設比、實坪坪數、交易年月

唯一的眉角是行政區——全台約 370 個,遠超 sklearn 原生類別的上限,而且「區」是房價最強的單一訊號。所以我把區做目標編碼:用「訓練集中該區的中位 log 單價」把區換成一個數值。這裡最容易踩到時間洩漏,所以編碼表只在訓練集上算、序列化進 artifact,沒見過的區退回縣市中位、再退全台中位。

驗證一律走 out-of-time 切分:留最新一季當測試集,模擬「用過去的成交去估未來的成交」——而不是隨機切分。隨機切分會讓模型偷看到未來、把分數灌漂亮。

結果

線上 10.7 萬筆、out-of-time(train 105,579 → test 2026 Q1 共 1,885 筆)。我逐步加特徵,看每一塊的增量:

模型                    MdAPE    PE10     PE20     MAPE     bias
─────────────────────   ─────    ─────    ─────    ─────    ─────
區級 baseline           13.2%    41.8%    66.4%    29.8%    +0.8%
+ 路級 location         12.4%    42.1%    67.5%    27.9%    +1.0%
+ 樓層                  12.7%    42.3%    68.5%    27.5%    +1.0%
      逐步加特徵的指標(越往下特徵越多)
    

分六都看 MdAPE 落在 10–13%、沒有任何單一縣市崩盤、偏誤近乎零。聽起來不差——直到你把它放到業界基準旁邊:成熟的 comps 型 AVM,PE10 大約 60–70%、MdAPE 5–8%。 我的 PE10 只有 42%,意思是每估十間、只有四間落在實際的 ±10% 內。

這個落差不是 bug,是這篇的重點。

兩個負結果

我花最多力氣的,是想把那個數字推下去。兩條最直覺的路,兩條都撞牆。

一、把 location 做細,幾乎沒用。 從「區級」細化到「路級」(解析門牌路名、做階層平滑編碼),MdAPE 只從 13.2% 動到 12.4%。更關鍵的是它對平滑強度完全不敏感——我把平滑係數從 3 掃到 40,MdAPE 一直在 12.4–12.7% 之間晃。如果是訊號被過度平滑掉,調這個係數應該要有反應;它沒反應,代表區內的 location 變異本來就不是主要殘差

二、加樓層,等於沒加。 我從門牌解析出戶別樓層、總樓層、相對樓層加進去,PE10 / MdAPE 全在雜訊範圍內動(MdAPE 甚至微升)。樓層不是主殘差。

「那補外部資料呢?」——也救不了

每次講到這,對方都會說:那去 geocoding、串 POI、接外部資料啊。我認真查證過(對抗式地查,刻意找反證),結論是:對這個題目,沒有一條外部資料路線划算。

  • geocoding 技術上完全可行但沒用:我實測輸入端約 100% 的門牌都有完整門牌號、輸出端官方門牌底圖約 100% 能解到建物級(連離島鄉下地名門牌都行)。但既然「區內 location 變異不是主殘差」,把座標精確到經緯度的增量是 <1pp。降級為 backlog。
  • POI / 生活機能在「模型已有 location」時增量趨近 0:這有文獻支撐——一旦模型已經知道鄰近成交價,再加便利商店密度、捷運距離這類特徵,幾乎沒有增量。我的 location 已經飽和了。
  • 真正能補的是室內照片 / 屋況——但唯一資料夠豐富的來源是 591,而爬它的公開 listing 建庫在台灣是法律禁區(公平交易法第 25 條,有 FTC 處分前例)。法律安全的沒用,有用的不合法。
  • 連 repeat-sales(同屋多次成交)都做不了:含「樓之 X」的門牌是戶級唯一,但平均每個門牌只有 1.04 筆成交、只有 2.9% 的門牌有 ≥2 筆。同址重複成交太稀,撐不起這個方法。

所以我停手了

模型建好、測過、文件齊。換成另一個版本的我,這時候會開始加 MLflow、接 model registry、上 serving、排自動重訓——把一整套 MLOps 機器蓋在這個模型外面。

我沒有。因為那套機器的核心假設是「模型會持續變好,所以需要監控、重訓、迭代」——而我剛剛證明它不會變好。重訓救不了一個瓶頸在「資料缺欄位」而非「模型過時」的問題。為一個你沒有的問題蓋基建,就是工程上的白工。

這次學到什麼

負結果也是結果——而且常常更值錢

「我做了一個模型、達到 X% 準度」是最常見、也最廉價的敘事。「我做了一個模型、用嚴謹方法證明 它不可能更準、然後停手」稀有得多。證明一份資料的天花板在哪、知道何時該停,比再硬榨 1pp 的 分數,對工程判斷的展現更強。

缺的特徵不在資料裡,再多模型也生不出來

我的殘差是裝潢、議價、屋況——這些 LVR 沒有記。沒有任何模型架構、任何超參數、任何 ensemble 能從不存在的欄位裡變出訊號。在燒錢調模型之前,先問一句:我還沒用到的訊號,到底在不在這份 資料裡?如果不在,模型再花俏也到頂了。

用業界指標,不要用你方便的指標

如果我只報 RMSE 或 R²,這個模型看起來會「還行」,我可能就上線了。是 PE10 只有 42%(對照 comps 型 AVM 的 60–70%)逼我面對真相。挑一把這個領域的人真的在用的尺,它會告訴你你其實在 哪、而不是你希望你在哪。