跳到主要內容

DS 102 · 模組 2

資料品質:驗證、整合與可追溯性

把整理好的資料變成可以被驗證、可以被追溯、可以交給別人重現的分析資料。

開始第一節
已完成 0 / 5
同步我的進度加入梯次後,進度可跨裝置保存,講師也能看到

資訊

加入後,你已完成的模組編號會連同「學員代碼」傳送給講師,講師可以看到你的進度。請使用講師提供的代碼,不要輸入姓名、公司機密或其他個資。進度資料與該梯次的其他資料一起保存。

學習目標

  • 使用 1:1、1:N、N:1 合併,辨識 many-to-many row explosion
  • 只有在有明確換算規則時統一單位;辨識同名但不同定義的欄位
  • 建立範圍、允許值、唯一性、參照完整性與 schema 驗證
  • 記錄欄位定義、來源、轉換、假設、未解問題與責任人
  • 產出 clean dataset、驗證摘要、data dictionary 與可稽核 cleaning report

Merge / Join

35 分鐘

Merge / Join 與資料關係

學習目標:使用 1:1、1:N、N:1 合併,辨識 many-to-many row explosion。

合併兩個表之前,最重要的問題不是「程式怎麼寫」,而是「這個 join 預期是什麼關係」。關係想錯了,程式一樣會跑,但結果的列數與意義會完全不對。

三種常見的 join 關係
關係意思範例
1:1兩個表在 join 鍵上都各只有一列一家公司對應一筆最新的公司基本資料
1:N一個表的一列對應另一個表的多列一家公司主檔對應它多個月份的月資料
N:1多列對應到另一個表的一列(1:N 反過來看)多個月份的月資料對應到同一家公司的主檔
用正確的 join 鍵,並用 validate 參數強制檢查關係
master = pd.read_csv("DS102_Company_Master.csv")

# site_id 本身會在不同公司間重複,必須搭配 company_id 才是唯一的據點
joined = site_long.merge(master, on="company_id", how="left", validate="m:1")
joined.shape[0] == site_long.shape[0]  # 1:N/N:1 的正確合併不應改變列數

注意

Many-to-many 陷阱:如果兩個表在同一個 join 鍵上都各自出現重複值(例如兩個表都有多列 site_id = S01,卻分屬不同公司),直接 join 會產生未預期的 many-to-many,列數會爆增,且原本的指標會被重複計算。
列數爆增的實際樣子(模擬情境)

假設 site_long 有 48 列,master 本來應該每個 company_id 只有一列。如果 master 不小心重複了同一個 company_id 兩次(例如同一家公司被匯入了兩次主檔),merge 之後的列數會變成 96 列而不是 48 列,每一筆月資料都被複製了一次,之後的加總會是正確答案的兩倍。

  • 合併前先問:這應該是 1:1、1:N 還是 N:1?
  • 在程式碼中用 merge(..., validate="1:1" / "1:m" / "m:1") 讓 pandas 幫你檢查,關係不符會直接報錯
  • 合併後一定要檢查列數,並和「合併前的預期列數」核對,不能只看有沒有報錯
  • 看到列數比預期多很多,先懷疑 join 鍵是否唯一,而不是急著使用結果
自我檢測

兩個表在同一個 join 鍵上都各自出現重複值,卻直接拿它們做 join。這樣做最主要的風險是什麼?

兩個表在同一個 join 鍵上都各自出現重複值,卻直接拿它們做 join。這樣做最主要的風險是什麼?

重點: 合併資料前先確認關係,合併後一定要核對列數,不能只看程式有沒有報錯。

Units 與 Definitions

30 分鐘

Units、Definitions 與可比性

學習目標:只有在有明確換算規則時統一單位;辨識同名但不同定義的欄位。

兩份資料的欄位名稱相同,不代表它們可以直接合併或比較。單位不同(公噸 vs 公斤)與定義不同(含稅 vs 未稅營收)是兩種最常見、卻最容易被忽略的問題。

單位不同

  • 例如廢棄物量一個用公噸、一個用公斤
  • 數值差 1000 倍,但欄位名稱看起來一樣
  • 有明確換算規則(1 公噸 = 1000 公斤)時才能統一

定義不同

  • 例如 employees 一個只算正職、一個含兼職
  • 數字範圍可能接近,容易被忽略
  • 沒有明確且一致的定義前,不應直接合併使用
單位統一:使用已記錄的換算規則,並保留原始單位
# 假設另一個來源用公斤記錄廢棄物量
waste_kg_source["waste_tonnes"] = waste_kg_source["waste_kg"] / 1000
waste_kg_source["original_unit"] = "kg"  # 保留原始單位,供日後追溯

注意

欄位名稱相同只是「看起來」可以合併。合併前一定要對照資料字典,確認單位與定義範圍是否一致;否則會混合兩種不可比的數字,卻不會有任何錯誤訊息提醒你。
單位沒有對齊時的實際影響(模擬情境)

一個來源記錄某據點廢棄物為 12(單位公噸),另一個來源記錄同一個月為 12000(單位公斤)。兩個數字換算後其實一致,但如果有人只看到欄位名稱都叫 waste_amount 就直接拿來加總或比較,會以為後者是前者的一千倍異常值,進而做出錯誤判斷。

  • 合併不同來源前,先列出每個來源對同一個欄位的定義與單位
  • 單位轉換只能用已經記錄下來、可查證的換算規則,不能憑感覺假設
  • 保留原始單位或原始定義的欄位,方便日後追溯與核對
  • 如果無法確認兩個來源的定義是否一致,寧可分開呈現,也不要強行合併
自我檢測

兩個資料來源都有一欄叫 revenue,但一個是含稅營收、一個是未稅營收。下列哪一種做法最正確?

兩個資料來源都有一欄叫 revenue,但一個是含稅營收、一個是未稅營收。下列哪一種做法最正確?

重點: 欄位名稱相同不代表可以直接合併;單位與定義都要先核對,才有可比性。

Validation Rules

40 分鐘

Validation Rules 與 Data Contracts

學習目標:建立範圍、允許值、唯一性、參照完整性與 schema 驗證。

清理完的資料,如果沒有明確的驗證規則,很容易在下一次資料更新時悄悄壞掉。把預期規則寫成可執行的檢查,就是一份簡單的 data contract:資料如果不符合,應該被攔下來,而不是被默默接受。

五種基本驗證規則
規則類型檢查什麼範例
Range check(範圍檢查)數值是否落在合理區間employees 必須大於等於 0
Allowed-values check(允許值檢查)類別值是否在合法清單內sector 只能是 Manufacturing、Food & Beverage、Retail、Logistics
Uniqueness constraint(唯一性檢查)欄位或欄位組合是否重複company_id + year 不可重複
Referential-integrity check(參照完整性檢查)外鍵是否存在於另一個表site_monthly 的 company_id 必須存在於 company_master
Schema check(結構檢查)欄位名稱、數量與型態是否符合預期欄位順序、名稱與型態必須與資料字典一致
把驗證規則寫成可重複執行的檢查
checks = {
    "unique_company_year_key": clean["company_year_key"].is_unique,
    "employees_non_negative": bool((clean["employees"] >= 0).all()),
    "sector_allowed": master["sector"].isin(["Manufacturing", "Food & Beverage", "Retail", "Logistics"]).all(),
    "site_company_id_exists": site_long["company_id"].isin(master["company_id"]).all()
}
checks

資訊

驗證規則要能「失敗」。如果一條規則永遠是 True,它可能沒有真正檢查到問題;先用已知有問題的練習資料試跑一次,確認規則真的能抓到錯誤。
  • 每一條規則都先用已知有問題的練習資料測試過一次,確認它真的會回傳 False
  • 規則的訊息要清楚說明哪一欄、哪個條件不符合,而不是只回傳 True / False
  • 範圍檢查要同時考慮下限與上限,不要只檢查其中一邊
  • 允許值清單要和資料字典上的分類保持一致,新增分類時要同步更新清單

注意

驗證不是做一次就結束。資料來源更新、欄位定義調整或新增資料時,都應該重新跑一次同樣的檢查,才能及早發現資料契約被打破。
自我檢測

「company_id 這一欄不可以重複」屬於下列哪一類資料驗證規則?

「company_id 這一欄不可以重複」屬於下列哪一類資料驗證規則?

重點: 把預期規則寫成可執行的檢查,資料不符合時就該被攔下來,而不是被默默接受。

Lineage 與 Cleaning Log

30 分鐘

Data Dictionary、Lineage 與 Cleaning Log

學習目標:記錄欄位定義、來源、轉換、假設、未解問題與責任人。

Data dictionary 說明「每個欄位是什麼」;cleaning log 說明「實際上對資料做了什麼」。兩者一起使用,才能讓別人(或未來的自己)重現你的判斷,而不是只能相信最終的數字。

Cleaning log 的最小必要欄位
欄位要記錄什麼
Issue(問題)發現了什麼樣的資料品質問題
Evidence(證據)怎麼發現的:檢查了哪個欄位、哪一列、什麼條件
Decision(決策)最後怎麼處理:修正、排除、標記,還是保留不動
Reason(理由)為什麼選這個處理方式,而不是其他方式
Residual uncertainty(未解問題)這個處理方式之後,還有什麼不確定或需要人工再確認的地方
一則 cleaning log 紀錄的範例結構
cleaning_log.append({
    "issue": "revenue_m_ntd stored as text with a thousands comma",
    "evidence": "column dtype was object before this step",
    "decision": "stripped commas and converted to float",
    "reason": "the underlying value is numeric; comma is formatting only",
    "residual_uncertainty": "assumes every comma is a thousands separator"
})

資訊

Lineage(可追溯性)回答的是:這個數字最初從哪個檔案來、經過哪些轉換、誰做的決定。沒有 lineage,之後想要重新驗證或修正時,只能整個重做一次。
一條 lineage 紀錄回答的問題(模擬情境)

某張報表上的用水量數字,如果有完整的 lineage,應該能回答:這個數字原本來自哪一個 CSV 檔、經過哪一次單位換算、是哪一次 cleaning log 的哪一筆決策處理過。如果答不出其中任何一個問題,這個數字目前還不算可追溯。

注意

不要用「反正之後還會再清理一次」當作省略紀錄的理由。沒有記錄下來的判斷,通常也無法向別人解釋,也無法在下一次資料更新時重複使用。
自我檢測

Cleaning log(清理紀錄)對一份分析最重要的價值是什麼?

Cleaning log(清理紀錄)對一份分析最重要的價值是什麼?

重點: Data dictionary 說明欄位是什麼;cleaning log 說明實際做了什麼;兩者一起,別人才能重現你的判斷。

Independent Lab

45 分鐘

Independent Lab:建立可信的 Clean Dataset

學習目標:獨立完成 inspect、clean、reshape、integrate、validate、document 的完整流程,產出 clean dataset、驗證摘要與可稽核 cleaning report。

資訊

Lab 任務:使用練習資料,獨立找出並處理資料品質問題,計算候選鍵是否唯一,寫出至少三項驗證檢查,並完成一份 cleaning log。不會告訴你總共有幾個問題,也不公布標準答案。
  1. 載入並檢查
    載入練習資料,檢查 shape、dtypes、缺失值與重複列。
  2. 清理並記錄
    處理每一個發現的問題,同時在 cleaning log 寫下 Issue、Evidence、Decision、Reason 與 Residual uncertainty。
  3. 建立候選鍵
    建立 company_year_key,確認清理後沒有重複。
  4. 寫驗證檢查
    至少寫三項驗證檢查:一項唯一性、一項範圍或允許值,以及至少一項你自己決定的檢查。
  5. 整理輸出
    產出清理後的資料、驗證摘要(validation summary)與完整的 cleaning log。
  6. 寫下限制
    寫一句這份清理後的資料仍然無法回答的問題。
  7. AI 協助紀錄
    如果使用了 AI,寫下 AI 協助了什麼,以及你自己驗證了什麼。
  • 一份可以從上到下重新執行的 Notebook
  • 一份記錄至少四個處理決策的 cleaning log
  • 至少三項驗證檢查與其結果
  • 一份驗證摘要(列數、唯一性、缺失值數量等)
  • 至少一項限制或未解問題
  • AI 協助紀錄(若有使用)
  • 確認 company_year_key 在清理後確實沒有重複
  • 確認至少一項驗證規則曾經在故意製造的錯誤資料上失敗過
  • 確認 cleaning log 中的每一筆決策都寫了 Reason,而不是只有 Decision

注意

完成的標準不是「程式沒有報錯」,而是每一個處理決策都有記錄理由、驗證檢查真的能抓到問題,而且結論沒有超出資料能支持的範圍。

完成

如果用 AI 協助撰寫清理或驗證程式碼,請逐項確認:欄位名稱存在、處理方式與課程原則一致、驗證規則真的會在資料有問題時失敗。AI 可以協助撰寫;驗證與最終判斷的責任在你。

重點: 一份可信的 clean dataset,除了乾淨的數字,還要有能重現的清理過程與能失敗的驗證規則。

接下來做什麼?