csc20021001 GitHub ↗
Project 01 · Deep divePython · Statistical rules · XAI

Explainable Transaction Anomaly Detector

不要只告訴分析師「這筆交易分數很高」;要讓他知道交易偏離了什麼歷史行為、哪些統計證據同時成立,以及接下來該查什麼。

先用一句話理解這個專案

它把「這筆交易看起來不尋常」拆成一組分析師能核對的統計證據與原因代碼,並用時間切分的合成標籤檢查規則到底抓對多少、漏掉多少。

它不是什麼?

不是犯罪分類器,也不是自動封鎖帳戶的系統。異常只代表行為偏離歷史基準,可能是旅行、換裝置、薪資入帳或其他合理原因。

專案目的:讓異常警示可以被理解、挑戰與重現

交易風控真正困難的地方,往往不是產生一個高分,而是回答後續問題:為什麼是這筆?和這個帳戶平常的行為差多少?是金額、頻率、裝置還是地理位置造成?如果門檻改變,案件量會怎麼變?

如果系統只輸出一個黑箱分數,分析師無法快速判斷它是否合理,稽核人員也難以追溯,工程師更不知道誤報應該從哪一條規則開始修。這個專案的目的,就是建立一條從原始交易、帳戶歷史、統計證據到人工警示的透明路徑。

因此,它選擇可重現的統計方法而不是追求複雜模型:每筆警示都有 reason code、數值證據與當下使用的歷史基準;每次評估都保留 false positive、false negative 與三組固定門檻的比較。

要解決的問題,不只是「找出大額交易」

固定金額門檻很容易理解,但它忽略了帳戶差異。對每天交易數十萬美元的帳戶,9,000 美元也許很普通;對長期只交易幾百美元的帳戶,同樣金額可能是重大變化。真正有用的比較對象,通常是「這個帳戶在這個時間點之前的自己」。

Problem A

個體基準不同

不能用單一全域平均值解釋所有帳戶;需要依帳戶建立歷史金額、速度、裝置與地理基準。

Problem B

未來資訊洩漏

若特徵偷看到事件之後的交易或測試標籤,離線成績會很好看,但真實上線時無法重現。

Problem C

誤報沒有脈絡

旅行、換手機、薪資日與資金調度都可能看似異常。系統要保留證據,不能直接替人下結論。

所以專案採用 chronological split:前 60% 時間資料作為訓練基準,中間 20% 驗證,最後 20% 測試。每一列特徵只使用當下或更早事件,ground-truth label 絕不進入規則與特徵。

解法:把偏離行為拆成四層透明證據

Layer 1

資料品質與時間點

驗證欄位、UTC 時間、重複交易與缺值;保留 outlier,不在清理階段把真正要檢查的異常刪掉。

Layer 2

帳戶歷史特徵

計算過去平均金額、24 小時交易量、每小時筆數、新裝置比例、休眠天數與對手方多樣性。

Layer 3

多方法統計共識

同時比較 Z-score、Modified Z-score、MAD、IQR、歷史 p99 與 rolling statistics;金額規則至少要兩種方法同意。

Layer 4

原因與可查證數值

輸出 reason code、severity、交易值、歷史中位數與方法分數,讓分析師能指出觸發原因。

CSV input交易與帳戶欄位
Validation清理與稽核紀錄
Point-in-time features只看過去
Explainable rules統計與行為規則
Analyst outputs警示、誤報與圖表

它可以辨識哪些模式?

規則不只看金額。偵測目錄包括交易速度突然增加、快速進出、休眠帳戶重新啟動、地理登入變化、新裝置提款、24 小時高對手方多樣性、行為突然改變、門檻下重複提款與不尋常時段。每一種模式都有明確 reason code,避免所有情況都被模糊地稱為「高風險」。

一筆警示是怎麼產生的?

假設帳戶過去的交易中位數約為 240 美元,這次卻提款 9,800 美元,而且剛好使用第一次出現的裝置。系統不是因為「9,800」這個數字本身就宣判可疑,而是分開建立兩條證據:

  1. 金額相對帳戶歷史分布大幅偏離,Modified Z-score 達 9.4,並有其他統計方法同意。
  2. 提款裝置過去從未出現在這個帳戶的事件歷史中。
  3. 兩個獨立理由合併成一筆較高優先級的人工複核訊號。
Example alert
{
  "transaction_id": "TX-0001824",
  "account_id": "ACC-00001",
  "anomaly_score": 0.87,
  "severity": "high",
  "reason_codes": [
    "AMOUNT_STATISTICAL_OUTLIER",
    "NEW_DEVICE_WITHDRAWAL"
  ],
  "explanation": {
    "transaction_amount": 9800,
    "account_median_amount": 240,
    "modified_zscore": 9.4
  }
}
重要解讀

0.87 是規則強度的可稽核排序,不是「87% 犯罪機率」。它只表示這筆交易值得比其他交易更早被查看。

如何實際執行這個專案

環境建立與套件安裝方式保留在專案 README;這裡只列真正影響分析流程的五個 CLI 階段,讓讀者把注意力放在資料如何一路變成可解釋警示。

Core analysis workflow
python -m anomaly_detector validate-data
python -m anomaly_detector build-features
python -m anomaly_detector detect
python -m anomaly_detector evaluate
python -m anomaly_detector generate-report

這五步各自在做什麼?

  1. validate-data:確認必要欄位、時間格式、重複 ID、缺值與金額範圍,並寫出 validation report。
  2. build-features:依帳戶與時間排序,建立只使用當下及過去事件的 rolling / expanding features。
  3. detect:套用 Conservative、Balanced、Sensitive 三組固定門檻,產生逐筆警示與解釋。
  4. evaluate:在未參與門檻調整的 chronological test split 上計算 precision、recall、F1 與混淆矩陣。
  5. generate-report:一次輸出 JSON、CSV、誤報/漏報案例、Markdown 分析與七張圖。

若要接到另一個專案匯出的交易 CSV,可使用 --input path/to/transactions.csv 指定來源,不需要修改偵測核心。

本次實際執行的操作截圖

以下不是示意圖,也不是重新編造的數值;畫面內容來自本次在專案環境中實際執行 CLI 後擷取的 stdout。每張圖對應一個可重現階段,方便把指令、輸出與後面的分析結果接起來。

Operation 1. validate-data 實際驗證 1,974 列資料。
Operation 2. build-features 建立 1,974 列 point-in-time features。
Operation 3. detect 以 Balanced profile 產生 267 筆警示。
Operation 4. evaluate 比較 Conservative、Balanced、Sensitive 三組門檻。
Operation 5. generate-report 寫出完整報告、評估檔案與七張分析圖。

怎麼讀實測結果,而不是只看最高 F1

三組 operating profile 代表三種營運選擇。Conservative 讓案件較少,但會漏掉更多已植入情境;Sensitive 盡量涵蓋異常,但分析師需要處理更多誤報;Balanced 是示範中的預設人工隊列。

Seed 42 合成資料的 untouched chronological test split
ProfilePrecisionRecallF1營運意義
Conservative0.8820.4880.628案件少,但遺漏較多
Balanced0.9200.8930.906預設人工複核隊列
Sensitive0.8880.9880.935涵蓋廣,審查負荷增加
46pytest tests passed
0.920Balanced precision
0.893Balanced recall
7standalone figures

這些數字證明程式在已知的合成情境上按設計運作,不能直接當成真實環境的詐欺偵測成績。更重要的是,報告會把 false positive 與 false negative 個案完整留下:例如旅行、換裝置與資金調度可能造成誤報;早期 burst 事件則可能因 rolling count 尚未跨過門檻而漏報。

程式依本次輸出資料產生的分析圖表

這一節與上面的操作截圖不同:以下七張圖是專案的 reporting 程式依本次實際執行所產生的資料繪製,用來解讀門檻取捨、錯誤類型與帳戶行為,不是手動另外畫出的示意圖。

Figure 1. 三組 operating profile 的 precision / recall 取捨。
Figure 2. Balanced profile 的 TN、FP、FN、TP。
Figure 3. 交易金額分布;顯示時截到 p99。
Figure 4. 可解釋異常分數如何分布。
Figure 5. Balanced profile 的每日警示量。
Figure 6. 哪些 reason code 產生最多誤報。
Figure 7. 單一帳戶在第一個 labelled anomaly 前後的行為變化。

限制、誤報,以及人工判斷留在哪裡

這套方法刻意保持透明,但透明不代表沒有盲點。新帳戶的歷史很短,規則會比較保守;帳戶層級特徵看不到多跳錢包網路;國家與裝置變化缺乏登入驗證脈絡;固定美元門檻也不一定符合不同組織或法域。

  • 合成標籤只能驗證已設計的情境,無法代表真實對手的適應行為。
  • anomaly score 沒有校準成犯罪或詐欺機率。
  • 同一個 reason code 可能同時有風險與合理商業解釋。
  • 門檻調整必須同時看漏報、誤報、案件量與分析師 SLA。
Responsible use

警示只啟動人工複核。分析師仍要查資料品質、客戶背景、錢包來源、預期商業活動與適用政策,才能決定是否升級案件。

圖片放大預覽