← 所有文章2026.08.16 · CS 513 · 資料清理的理論與實務

清理 17,545 份歷史菜單:改善可用性,但不抹掉證據

回顧 NYPL menu project 的 profiling、canonical city/meal、保守推論、constraint、provenance 與誠實驗證。

Project 問題看起來很簡單:依 city、decade、meal type 計算 historical menu 數量。Raw NYPL menu table 卻讓三個維度都不穩定:place 混合 city、address、hotel、ship 與 route;date 有 missing 和 impossible year;event label 使用多種語言與拼法。

目標不是讓每個 field 看起來整齊,而是讓一個分析問題可回答,同時保留 uncertainty 與 source evidence。

先定義 output,再寫 cleaning rule

17,545 筆 input row 全部保留。Raw column 不覆寫,另加 14 個 derived field 保存 normalized value 與 provenance,包括:

canonical_city, city_source, city_rule, is_transit
menu_year, menu_decade, date_status, date_rule
canonical_event, event_source, event_rule

因此 cleaned dataset (D’) 是 (D) 的 extension,不是假裝原始 ambiguity 從未存在的 replacement。

Pipeline 有兩個層次

Outer workflow 負責 profile、clean、validate、audit inference 與 package evidence。Inner workflow 讓每筆 row 經過九個 conceptual stage:

  1. normalize text;
  2. classify ship、train、en-route record;
  3. 從 place extract city candidate;
  4. tally location evidence,veto ambiguous venue name;
  5. 套 curated gazetteer 與 learned crosswalk;
  6. 依固定 precedence 決定 final city;
  7. parse/repair date;
  8. 將 event text 映射為 meal type;
  9. emit provenance 與 change log。

其中一個 step 必須看 dataset-level evidence:同一 hotel name 若出現在不同 city,就不能安全推成單一 city。只看單 row 的 code 發現不了這種 ambiguity。

白話來說: 某個值單獨看很明顯,看到整張 table 後可能就不再安全。

Canonicalization 改變 analytical grain

Pipeline 將 3,708 個 distinct raw place string 收斂成 233 個 canonical city,1,769 個 event string 收斂成八種 meal type;光 DINNER 就吸收 736 個 raw variant。

Cleaning 前,analysis 回傳 7,559 份 menu、5,049 個 group;最大 group 被 ship 占據,同義 meal label 又把 count 切碎。Cleaning 後,結果是 6,268 份可歸屬 menu、757 個 group。

較少的 row 是刻意結果:

7,559 raw answer rows
- 2,858 transit menus
- 1,259 non-city or unresolved place values
+ 2,825 cities recovered from location
+     1 date repaired into range
= 6,268 cleaned answer rows

Cleaning 沒有最大化 coverage,而是把 population 從「place 有東西的 row」改成「能歸屬 city 的 menu」。

Inference 用量測,不用宣稱

place 不可用時,location 有時能透過 curated venue gazetteer 或 learned majority crosswalk 找回 city。Learned mapping 要求 support 至少 3、confidence 至少 0.75;會指向多個 city 的 generic venue name 會被 veto。

Held-out check 使用兩種信號都存在的 row:

Inference path Checked rows Agreement
Curated gazetteer 381 99.7%
Learned crosswalk,leave-one-out 455 93.6%
Combined 836 96.4%

Caveat 不能省略:test row 有可 parse 的 place,可能比真正需要 inference 的 row 簡單。Measured agreement 是 evidence,不是 target population 的保證。

Constraint 保護 interpretation

八條 denial-style constraint 檢查 transit value 當 city、impossible date、missing ID、meal vocabulary、non-city place 與 derived value 的 provenance;cleaning 後 violation count 全部為零。

Missing date 與 invalid date 分開報告。Cleaning 前有 586 筆 missing date,真正 present 但超出範圍的只有六筆。把兩者混在一起會得到更戲劇化、但不誠實的 improvement。

這個 project 留下的原則

  1. 保存 raw field,interpretation 放 derived column。
  2. 相信 local pattern 前先做 global profile。
  3. Controlled vocabulary 是明確 analytical decision。
  4. 每筆進入或離開 answer set 的 row 都要 reconcile。
  5. 用 held-out evidence 測 inference,並說明 sample bias。
  6. Rule、threshold、test 與 provenance 都是 deliverable。

最後 pipeline 使用 standard-library Python 與 SQLite,配有 44 個 unit test 和 machine-readable audit report。工具選擇不如每個 cleaning decision 都能檢查、能重跑重要。

複習卡

  • 從 analytical question 與 required grain 開始。
  • 保存 raw data;另加 canonical value 與 provenance。
  • Dataset-level ambiguity 可能擊敗 row-local rule。
  • 品質變好時 coverage 合理地下降。
  • 不只比 total,要 reconcile before/after population。
  • Accuracy percentage 必須附 sampling caveat。