Chuỗi thời gian 7 — Phát hiện bất thường
Chuỗi thời gian 7 — Phát hiện bất thường
Sáu bài trước xoay quanh dự báo — đoán giá trị tương lai của một chuỗi. Bài này lật ngược góc nhìn: thay vì hỏi "ngày mai bằng bao nhiêu", ta hỏi "điểm nào không nên xuất hiện". Đó là bài toán phát hiện bất thường (anomaly detection): tìm những quan sát lệch đủ xa khỏi hành vi bình thường để đáng nghi ngờ. Trong ngân hàng, đây là xương sống của giám sát giao dịch gian lận, cảnh báo sụt/tăng đột biến khối lượng, observability hệ thống và kiểm soát chất lượng dữ liệu.
Điểm mấu chốt cần khắc cốt ngay từ đầu: anomaly detection là bài toán bất cân bằng cực đoan và thiếu nhãn. Bất thường theo định nghĩa là hiếm (thường < 1%, có khi 0.01%), và phần lớn thời gian bạn không biết chắc điểm nào thật sự bất thường. Vì vậy phần lớn phương pháp là unsupervised (không nhãn), và thách thức lớn nhất không phải "bắt được bất thường" mà là "không làm ngập cán bộ nghiệp vụ trong cảnh báo giả".
1. Ba loại bất thường
Trước khi chọn phương pháp, phải phân loại đúng loại bất thường đang săn — vì mỗi loại cần cách tiếp cận khác nhau.
| Loại | Định nghĩa | Ví dụ ngân hàng |
|---|---|---|
| Point (điểm) | Một điểm riêng lẻ lệch xa khỏi phần còn lại | Một giao dịch 500 triệu trên tài khoản thường chỉ vài triệu |
| Contextual (theo ngữ cảnh) | Điểm bình thường về giá trị tuyệt đối nhưng bất thường trong ngữ cảnh (thời điểm, mùa vụ) | Khối lượng giao dịch cao lúc 3h sáng — cao không lạ ban ngày nhưng lạ vào đêm |
| Collective (cụm) | Một chuỗi liên tiếp các điểm mà từng điểm không lạ, nhưng cả cụm thì lạ | Số dư giữ nguyên bất động 10 ngày liền (bình thường dao động mỗi ngày) |
- Point dễ nhất, xử lý được bằng thống kê đơn giản.
- Contextual đòi hỏi mô hình phải "biết" ngữ cảnh — thường phải khử mùa vụ/trend trước, vì một giá trị chỉ bất thường so với kỳ vọng của thời điểm đó.
- Collective khó nhất: phải nhìn cửa sổ nhiều điểm, hợp với phương pháp dựa trên phân rã hoặc dự báo.
Sai lầm phổ biến là dùng ngưỡng tĩnh (point) cho bài toán vốn là contextual. Ví dụ đặt ngưỡng "báo động nếu khối lượng > X giao dịch/giờ" sẽ báo động sai mỗi giờ cao điểm ban ngày và bỏ lọt tấn công đêm khuya.
2. Phương pháp thống kê — nền tảng luôn nên thử trước
2.1. Z-score / quy tắc 3-sigma
Ý tưởng cổ điển: giả sử dữ liệu phân phối gần chuẩn, tính z-score z = (x − μ) / σ, gắn cờ điểm có |z| > 3 (nằm ngoài 3 độ lệch chuẩn — chỉ ~0.27% dữ liệu chuẩn rơi ngoài vùng này).
Cảnh báo lớn: μ và σ thông thường (mean, std) đều không bền vững với outlier — chính những điểm bạn muốn bắt lại kéo μ và σ ra, khiến ngưỡng phồng lên và bỏ lọt. Giải pháp: dùng phiên bản robust — thay bằng median và MAD (Median Absolute Deviation):
modified_z = 0.6745 * (x − median) / MAD
với MAD = median(|xᵢ − median|). Ngưỡng thường dùng |modified_z| > 3.5. Đây gần như luôn là lựa chọn tốt hơn z-score thuần.
2.2. IQR (Interquartile Range)
Không giả định phân phối chuẩn: tính tứ phân vị Q1, Q3, IQR = Q3 − Q1, gắn cờ điểm ngoài khoảng [Q1 − 1.5·IQR, Q3 + 1.5·IQR] (biên "boxplot" quen thuộc; dùng hệ số 3 thay vì 1.5 cho outlier "cực đoan"). Đơn giản, robust, dễ giải thích cho nghiệp vụ — nhưng vẫn là phương pháp tĩnh, toàn cục, không nhìn thời gian.
2.3. Rolling z-score — cho chuỗi có trend
Chuỗi thời gian ngân hàng hầu như luôn có trend và mùa vụ, nên μ/σ toàn cục vô nghĩa. Rolling z-score tính μ và σ trên cửa sổ trượt gần nhất (ví dụ 30 điểm) rồi so điểm hiện tại với thống kê cục bộ đó. Điều này biến quy tắc tĩnh thành thích nghi (adaptive) — ngưỡng tự trôi theo mức nền. Lưu ý dùng cửa sổ trước điểm đang xét để tránh rò rỉ tương lai (lookahead bias).
2.4. EWMA / control chart (SPC)
SPC (Statistical Process Control) vốn từ kiểm soát chất lượng sản xuất, rất hợp giám sát metric theo thời gian thực. Hai công cụ chính:
- EWMA (Exponentially Weighted Moving Average): trung bình có trọng số giảm dần theo thời gian,
EWMA_t = λ·x_t + (1−λ)·EWMA_{t−1}. Nhạy với dịch chuyển nhỏ, kéo dài của mức nền — tốt để bắt drift từ từ. λ nhỏ (0.1–0.3) mượt hơn, phản ứng chậm hơn. - Control chart: vẽ metric với đường trung tâm (CL) và hai đường kiểm soát UCL/LCL đặt tại ±3σ. Điểm vượt biên hoặc chuỗi điểm cùng phía (theo quy tắc Western Electric) → tín hiệu bất thường.
EWMA/CUSUM đặc biệt mạnh cho change-point detection (phát hiện điểm gãy) — khi phân phối dịch chuyển thay vì chỉ một điểm nhảy vọt.
3. Phương pháp dựa trên dự báo (forecast-based)
Đây là cầu nối trực tiếp với các bài trước và là cách tiếp cận được ưa dùng nhất cho chuỗi thời gian ngân hàng. Quy trình:
- Huấn luyện một mô hình dự báo (Holt-Winters/SARIMA từ Chuỗi thời gian 3, hoặc Prophet/LSTM từ Chuỗi thời gian 5, hoặc mô hình ML feature-based từ Chuỗi thời gian 4) trên hành vi bình thường.
- Dự báo giá trị kỳ vọng
ŷ_tcho từng thời điểm. - Tính residual (phần dư)
e_t = y_t − ŷ_t. - Gắn cờ bất thường khi residual vượt ngưỡng — hoặc
|e_t| > k·σ_e, hoặc điểm rơi ngoài khoảng dự báo (prediction interval) mà mô hình tự cho.
Ưu điểm lớn: mô hình dự báo tốt đã tự khử trend và mùa vụ, nên residual gần như dừng và trung tâm 0 — biến bài toán contextual thành point trên phần dư, dễ đặt ngưỡng. Đây chính là lý do bước dự báo là "công đoạn khử ngữ cảnh" trước khi phát hiện.
4. Dựa trên phân rã (STL residual)
Nếu chỉ cần khử mùa vụ + trend mà không cần dự báo tương lai, STL (Seasonal-Trend decomposition using Loess) — đã trình bày ở Chuỗi thời gian 2 — là công cụ gọn nhẹ:
y_t = Trend_t + Seasonal_t + Residual_t
Sau khi tách, phần Residual đã sạch trend và mùa vụ; áp z-score robust hoặc IQR lên residual này để bắt bất thường. Biến thể nổi tiếng là S-H-ESD (Seasonal Hybrid ESD) của Twitter/X: kết hợp phân rã STL với kiểm định ESD (Extreme Studentized Deviate) — một kiểm định thống kê phát hiện nhiều outlier lặp lại, dùng median thay mean để robust. Rất hợp chuỗi có mùa vụ mạnh như lưu lượng giao dịch theo ngày trong tuần.
5. Mô hình chuyên biệt (khái quát)
Khi dữ liệu đa biến (nhiều feature cùng lúc) hoặc quan hệ phi tuyến phức tạp, phương pháp thống kê đơn biến hụt hơi. Bốn họ mô hình thường gặp:
| Mô hình | Ý tưởng cốt lõi | Khi nào dùng |
|---|---|---|
| Isolation Forest | Xây cây ngẫu nhiên; điểm bất thường bị "cô lập" bằng ít lần cắt hơn → độ sâu nhỏ hơn | Đa biến, dữ liệu lớn, nhanh; baseline unsupervised mặc định tốt |
| LOF (Local Outlier Factor) | So mật độ cục bộ của điểm với hàng xóm; mật độ thấp bất thường → outlier | Cụm có mật độ khác nhau; bắt outlier "cục bộ" |
| S-H-ESD | STL + kiểm định ESD trên residual | Chuỗi đơn biến mùa vụ mạnh |
| Autoencoder | Mạng nén–giải nén học tái tạo dữ liệu bình thường; reconstruction error cao → bất thường | Đa biến chiều cao, phi tuyến; cần nhiều dữ liệu bình thường |
Với autoencoder, ý tưởng là mạng chỉ được huấn luyện trên dữ liệu bình thường nên tái tạo tốt các mẫu quen; gặp mẫu lạ nó tái tạo kém, sai số tái tạo (reconstruction error) tăng vọt → dùng chính sai số này làm điểm bất thường. Đây là hướng mạnh cho gian lận đa chiều (kết hợp amount, giờ, địa điểm, thiết bị, tần suất...). Với chuỗi thời gian thuần, biến thể LSTM-autoencoder học được cả phụ thuộc thời gian (liên hệ Deep Learning – Sequence & RNN).
Quan trọng: mô hình phức tạp KHÔNG tự động thắng. Trên một chuỗi đơn biến, một rolling z-score robust cộng phân rã STL thường ngang hoặc thắng Isolation Forest, mà lại giải thích được cho kiểm toán và nghiệp vụ. Luôn bắt đầu từ baseline thống kê.
6. Khử mùa vụ & trend TRƯỚC khi phát hiện
Đây là nguyên tắc bị bỏ quên nhiều nhất và gây ra phần lớn cảnh báo sai. Nếu chuỗi có trend/mùa vụ mà bạn áp thẳng ngưỡng tĩnh:
- Trend tăng → cuối kỳ mọi điểm đều "vượt ngưỡng" (báo động ngập).
- Mùa vụ → mọi đỉnh mùa vụ (lương cuối tháng, Tết) bị gắn cờ nhầm.
Do đó luồng đúng gần như luôn là: khử mùa vụ + trend → còn lại residual dừng → phát hiện trên residual. Cả ba hướng ở mục 3–5 đều thực hiện bước khử này (dự báo, STL, hoặc feature ngữ cảnh). Riêng dữ liệu có nhiều mùa vụ chồng nhau (ngày trong tuần + tháng + lễ), Prophet hoặc STL đa mùa vụ xử lý gọn nhất.
7. Đánh đổi precision/recall, ngưỡng & alert fatigue
Đây là phần "sống còn" khi triển khai thật. Do bất thường cực hiếm, accuracy vô nghĩa (mô hình "luôn báo bình thường" đã đạt 99.9% accuracy). Chỉ quan tâm (liên hệ ML – Evaluation Metrics):
- Precision = trong các cảnh báo, bao nhiêu % là thật. Precision thấp → alert fatigue: cán bộ bị ngập cảnh báo giả, chai lì, bỏ qua cả cảnh báo thật.
- Recall = trong các bất thường thật, bắt được bao nhiêu %. Recall thấp → lọt gian lận, mất tiền/rủi ro pháp lý.
Ngưỡng cảnh báo chính là núm xoay đánh đổi hai chỉ số này: hạ ngưỡng → recall tăng, precision giảm (nhiều cảnh báo hơn); nâng ngưỡng → ngược lại.
Chiến lược chống alert fatigue trong thực tế:
- Ngưỡng phân tầng theo severity: ví dụ z > 3 → cảnh báo mềm (ghi log), z > 5 → cảnh báo cứng (báo người). Ưu tiên nguồn lực cho tầng cao.
- Giới hạn tần suất (rate limiting / dedup): gộp nhiều cảnh báo cùng nguyên nhân trong một cửa sổ thời gian thành một sự kiện.
- Ngân sách cảnh báo (alert budget): cố định số cảnh báo/ngày mà đội có thể xử lý (ví dụ 50 case/ngày cho đội fraud), rồi chỉnh ngưỡng để chỉ đẩy top-N nghi ngờ cao nhất.
- Đặt ngưỡng theo chi phí: cân chi phí false positive (thời gian điều tra + phiền khách) với false negative (tiền thất thoát). Đây là bài toán tối ưu chi phí, không phải tối đa hóa một metric đơn.
Đánh giá khi nhãn hiếm: vì hầu như không có nhãn đầy đủ, thực tế thường dùng:
- PR-AUC (Precision-Recall AUC) thay ROC-AUC — nhạy hơn trên dữ liệu bất cân bằng cực đoan.
- Precision@k — đo tỷ lệ đúng trong top-k cảnh báo mà đội thật sự điều tra (khớp với ngân sách).
- Nhãn hồi cứu (backtest): dùng các vụ gian lận đã xác nhận trong quá khứ làm nhãn để chấm điểm mô hình.
8. SQL minh hoạ — bắt giao dịch vượt ngưỡng z-score
Ví dụ đơn giản trên sandbox: với mỗi giao dịch, so amount với trung bình và độ lệch chuẩn của chính tài khoản đó (window theo account_id), gắn cờ điểm có |z| > 3. Đây là point-anomaly per-account, chưa khử thời gian nhưng đủ minh hoạ ý tưởng z-score bằng AVG/STDDEV:
-- ▶ Chạy được
WITH stats AS (
SELECT
t.id,
t.account_id,
t.amount,
t.created_at,
AVG(t.amount) OVER (PARTITION BY t.account_id) AS mu,
STDDEV(t.amount) OVER (PARTITION BY t.account_id) AS sigma
FROM transactions t
)
SELECT
id,
account_id,
amount,
ROUND(mu::numeric, 2) AS avg_amount,
ROUND(sigma::numeric, 2) AS std_amount,
ROUND(((amount - mu) / NULLIF(sigma, 0))::numeric, 2) AS z_score
FROM stats
WHERE sigma > 0
AND ABS((amount - mu) / sigma) > 3
ORDER BY z_score DESC;
Lưu ý: NULLIF(sigma, 0) tránh chia 0 với tài khoản chỉ có một giao dịch; ::numeric để ROUND chạy đúng trong PostgreSQL (ROUND(double precision, int) không tồn tại). Trong thực tế bạn sẽ dùng cửa sổ trượt theo thời gian và loại chính điểm đang xét khỏi thống kê (leave-one-out) để robust hơn.
Use case thực tế
Bối cảnh: Đội giám sát giao dịch NCB cần cảnh báo sụt đột biến khối lượng giao dịch trên kênh Internet Banking — dấu hiệu sự cố hạ tầng (cổng thanh toán lỗi) hoặc tấn công. Khối lượng có mùa vụ mạnh: cao ban ngày/ngày thường, thấp đêm/cuối tuần → ngưỡng tĩnh vô dụng.
Cách làm (forecast-based, khớp mục 3):
- Tổng hợp số giao dịch thành công theo từng giờ trong 90 ngày gần nhất.
- Huấn luyện SARIMA/Prophet nắm mùa vụ giờ-trong-ngày và ngày-trong-tuần → dự báo khối lượng kỳ vọng
ŷ_t+ khoảng tin cậy 99% cho giờ tiếp theo. - Mỗi giờ, so thực tế
y_tvới khoảng: nếuy_trớt dưới cận dưới của khoảng (residual âm lớn) → cảnh báo sụt. - Phân tầng: rớt dưới 1 giờ → soft alert; rớt ≥ 2 giờ liên tiếp (collective) → page trực ca.
Kết quả điển hình khi tuning: Ban đầu ngưỡng ±2σ cho ~40 cảnh báo/ngày, precision chỉ ~15% (đội bỏ qua hết — alert fatigue kinh điển). Nâng lên khoảng dự báo 99% + yêu cầu 2 giờ liên tiếp: còn ~3 cảnh báo/ngày, precision ~70%, và đội bắt được sự cố cổng thanh toán trong vòng 2 giờ thay vì phát hiện qua khiếu nại khách hàng ngày hôm sau. Đây minh hoạ trực tiếp việc hy sinh một chút recall để cứu precision là đánh đổi đúng khi đội có ngân sách xử lý hữu hạn.
Với gian lận giao dịch (fraud), quy trình chi tiết hơn — phối hợp luật cứng, mô hình điểm nghi ngờ và điều tra — được trình bày riêng ở AML — Giám sát giao dịch. Phần production hóa pipeline phát hiện (serving, retrain, drift) xem Chuỗi thời gian 8.
Ghi nhớ
- Ba loại bất thường: point (điểm lệch), contextual (lệch theo ngữ cảnh mùa vụ/thời điểm), collective (cụm liên tiếp bất thường). Chọn phương pháp theo loại — dùng ngưỡng tĩnh cho bài contextual là sai lầm số một.
- Luôn khử trend + mùa vụ trước khi phát hiện. Phát hiện trên residual (qua dự báo, STL, hoặc feature ngữ cảnh) mới đúng; áp ngưỡng thẳng lên chuỗi thô gây ngập cảnh báo giả.
- Thống kê trước, mô hình sau. Z-score robust (median/MAD), IQR, rolling z-score, EWMA/SPC là baseline mạnh và giải thích được — bắt buộc cho kiểm toán ngân hàng. Isolation Forest/LOF/autoencoder chỉ đáng dùng khi đa biến/phi tuyến và luôn phải so với baseline.
- Forecast-based là hướng chủ đạo cho chuỗi thời gian: dự báo → residual → so ngưỡng/prediction interval. Tận dụng lại mọi mô hình ở các bài trước.
- Bất thường hiếm ⇒ accuracy vô nghĩa. Đo bằng precision/recall, PR-AUC, Precision@k. Đánh giá bằng nhãn hồi cứu từ vụ đã xác nhận.
- Alert fatigue giết chết hệ thống tốt. Precision thấp làm cán bộ chai lì. Chống bằng ngưỡng phân tầng, rate-limit/dedup, alert budget, và đặt ngưỡng theo chi phí FP/FN.
- Ứng dụng ngân hàng: gian lận giao dịch, giám sát sụt/tăng khối lượng, observability hệ thống, và phát hiện điểm gãy dữ liệu (data quality). Cùng một bộ công cụ, khác nhau ở dữ liệu đầu vào và chi phí sai lầm.
Bài viết liên quan
Phân biệt AI/ML/DL, các kiểu học máy, quy trình ML end-to-end và thuật ngữ nền tảng.
Chất lượng dữ liệu, xử lý thiếu/ngoại lai, mã hoá, chuẩn hoá, tạo đặc trưng và tránh data leakage.
Mô hình ngôn ngữ lớn hoạt động ra sao, token, context window, tham số sinh, và kỹ thuật viết prompt.
Retrieval-Augmented Generation, vector database, tool calling, agent và MCP để xây ứng dụng LLM thực tế.