Nhân quả 3 — Confounding & DAG

13 thg 7, 2026 2 lượt xem
#bi
#causal-inference
#confounding
#causal-graph
#dag

Vì sao dữ liệu quan sát cần một khung tư duy khác

Trong bài về RCT ta thấy randomization thiết kế ra điều kiện so sánh công bằng: gán treatment ngẫu nhiên nên hai nhóm tương đương về mọi yếu tố, chênh outcome quy hết cho treatment. Nhưng phần cuối bài đó cũng liệt kê rất nhiều tình huống ngân hàng không thể randomize — chính sách áp toàn hệ thống, chuyện đã xảy ra, hay đụng vào quyền lợi tài chính. Khi đó ta chỉ còn dữ liệu quan sát (observational data): khách tự chọn tham gia, hoàn cảnh chọn, chính sách chọn — chứ không phải ta tung đồng xu.

Với dữ liệu quan sát, phép "trừ trung bình hai nhóm" không còn là ATE. Nó lẫn lộn giữa tác động thật của treatment và tác động của những khác biệt sẵn có giữa hai nhóm. Để tách được, ta phải điều chỉnh (adjust / control for) các biến gây lệch. Nhưng điều chỉnh biến nào? Điều chỉnh sai — thêm hoặc thiếu — đều tạo sai lệch. Trả lời câu hỏi này không thể chỉ nhìn dữ liệu; nó đòi hỏi giả định về cấu trúc nhân quả. Công cụ để viết ra những giả định đó một cách minh bạch chính là DAG.


Confounding: gốc rễ của tương quan giả

Confounder (biến gây nhiễu) là biến C vừa ảnh hưởng đến treatment T (ai được/chọn nhận), vừa ảnh hưởng đến outcome Y. Sự tồn tại của C tạo ra một tương quan giả (spurious correlation) giữa T và Y không đến từ quan hệ nhân quả T→Y.

Ví dụ kinh điển trong ngân hàng: một chương trình ưu đãi phí (T) và số lượng giao dịch (Y). Nhìn dữ liệu thô, khách tham gia chương trình giao dịch nhiều hơn hẳn → tưởng chương trình rất hiệu quả. Nhưng thu nhập / độ giàu (C) mới là thủ phạm: khách giàu vừa dễ được mời và dễ đồng ý tham gia chương trình (C→T), vừa vốn dĩ giao dịch nhiều dù có chương trình hay không (C→Y). Phần chênh giao dịch ta thấy là pha trộn giữa tác động thật của ưu đãi và tác động của việc "họ vốn giàu".

Mũi tên đứt T→Y là hiệu ứng nhân quả ta muốn đo. Hai mũi tên liền từ C tạo một đường vòng khác nối T và Y (qua C) — đường này bơm tương quan không nhân quả vào phép so sánh. Muốn ước lượng đúng T→Y ta phải chặn đường qua C, tức điều chỉnh C (so sánh trong từng nhóm thu nhập tương đương). Đây là ý tưởng cốt lõi và ta sẽ hình thức hoá nó bằng backdoor criterion bên dưới.

Điểm quan trọng: confounding gần như luôn có mặt trong dữ liệu quan sát ngân hàng, vì gần như mọi hành vi đều liên quan đến các đặc điểm nền như thu nhập, độ tuổi, thâm niên quan hệ, phân khúc rủi ro.


DAG: viết giả định nhân quả thành hình vẽ

DAG (Directed Acyclic Graph — đồ thị nhân quả có hướng, không chu trình) là một đồ thị trong đó:

  • Mỗi nút (node) là một biến (treatment, outcome, confounder, mediator...).
  • Mỗi cạnh có hướng (mũi tên) X→Y nghĩa là "ta giả định X là một nguyên nhân trực tiếp của Y".
  • Không chu trình (acyclic): không thể đi theo mũi tên rồi quay về chính nút xuất phát — vì một biến không thể là nguyên nhân của chính nó.

DAG không phải mô hình thống kê mà là ngôn ngữ để phát biểu giả định lĩnh vực. Giá trị của nó nằm ở chỗ: một khi ta vẽ ra cấu trúc nhân quả (dựa trên kiến thức nghiệp vụ), có những quy tắc đồ thị máy móc cho biết biến nào cần điều chỉnh, biến nào tuyệt đối không. Ta chuyển câu hỏi mơ hồ "kiểm soát biến gì" thành bài toán đồ thị có lời giải rõ ràng.

Mọi DAG dù phức tạp đều lắp ghép từ ba cấu trúc nền cho ba biến. Hiểu ba cái này là hiểu 80% của inference nhân quả.


Ba cấu trúc nền và quy tắc điều chỉnh

1. Chain (chuỗi) — mediator

Cấu trúc T → M → Y: T ảnh hưởng M, M ảnh hưởng Y. M là mediator (biến trung gian) — kênh mà qua đó T tác động lên Y.

Ví dụ: ưu đãi (T) → mở thêm tài khoản phụ (M) → tăng giao dịch (Y).

  • Nếu ta muốn tổng hiệu ứng (total effect) của T lên Y → KHÔNG điều chỉnh M. Điều chỉnh mediator sẽ chặn mất chính con đường mà T tác động, làm hiệu ứng đo được teo lại (thiếu đi phần đi qua M).
  • Chỉ điều chỉnh M nếu ta cố tình muốn tách hiệu ứng trực tiếp (phần không qua M) — đó là bài toán mediation analysis khác.

Sai lầm phổ biến: đưa vào mô hình một biến xảy ra sau treatment mà không nhận ra nó là mediator, rồi ngạc nhiên vì hiệu ứng "biến mất".

2. Fork (chạc) — confounder

Cấu trúc T ← C → Y: C là nguyên nhân chung của cả T và Y. Đây chính là confounder đã mô tả ở trên.

  • PHẢI điều chỉnh C. Không điều chỉnh → đường sau (backdoor) T←C→Y để mở → tương quan giả trộn vào ước lượng.
  • Điều chỉnh C (stratify, matching, hồi quy thêm C...) đóng đường này, để lại đúng hiệu ứng T→Y.

3. Collider (điểm va chạm) — cái bẫy phản trực giác

Cấu trúc T → K ← Y: cả T và Y cùng chỉ vào K. K được gọi là collider (biến va chạm) vì hai mũi tên "va" vào nó.

  • Ở trạng thái tự nhiên, đường qua collider đã đóng sẵn — T và Y không tương quan giả qua K.
  • TUYỆT ĐỐI KHÔNG điều chỉnh collider. Nghịch lý ở đây: điều chỉnh (hoặc lọc/điều kiện hoá) trên K lại MỞ đường và tạo ra một tương quan giả T-Y vốn không tồn tại. Đây gọi là collider bias — một trong những sai lầm phản trực giác và nguy hiểm nhất của inference nhân quả.

Ví dụ ngân hàng: giả sử được duyệt vay (K) phụ thuộc cả vào thu nhập cao (T)điểm tín dụng tốt (Y) — hai mũi tên chỉ vào K. Trong toàn quần thể, thu nhập và điểm tín dụng có thể độc lập. Nhưng nếu ta chỉ nhìn nhóm đã được duyệt vay (điều kiện hoá trên collider K), ta sẽ thấy một tương quan âm giả tạo: trong nhóm được duyệt, người thu nhập thấp buộc phải có điểm tín dụng rất tốt (nếu không đã bị từ chối), tạo ảo giác "thu nhập thấp đi kèm tín dụng tốt". Tương quan này hoàn toàn do việc lọc mẫu, không phản ánh thực tế.

Bảng gói gọn quy tắc:

Cấu trúcHìnhVai trò biến giữaCó điều chỉnh biến giữa?
ChainT → M → YMediatorKhông (nếu muốn tổng hiệu ứng)
ForkT ← C → YConfounder (bắt buộc)
ColliderT → K ← YColliderKhông (điều chỉnh sẽ tạo bias)

d-separation và backdoor criterion

Ba cấu trúc trên là "viên gạch"; hai khái niệm sau là "cách xây" để xử lý DAG bất kỳ.

d-separation (phân tách theo đồ thị) là quy tắc xác định khi nào hai biến độc lập qua một đường (path) nhất định, cho một tập biến điều chỉnh Z:

  • Một đường bị chặn (blocked) nếu nó đi qua một chain hoặc fork mà biến giữa nằm trong Z, HOẶC đi qua một collider mà biến va chạm (và mọi hậu duệ của nó) không nằm trong Z.
  • Ngược lại đường mở (open) — cho tương quan chảy qua.

Backdoor path (đường sau) là bất kỳ đường nào nối T và Y mà bắt đầu bằng một mũi tên chỉ vào T (dạng T ← ...). Đây chính là các đường "lén" bơm tương quan không nhân quả (như T←C→Y). Đường nhân quả chính đáng T→...→Y thì đi ra khỏi T, không phải backdoor.

Backdoor criterion (tiêu chí đường sau) cho ta cách chọn tập điều chỉnh Z hợp lệ để ước lượng T→Y không chệch:

  1. Z chặn mọi backdoor path giữa T và Y (đóng hết các đường lén), VÀ
  2. Z không chứa hậu duệ của T (không thêm mediator hay biến sau treatment — tránh chặn đường nhân quả và tránh mở collider).

Nếu tìm được Z thoả cả hai, thì so sánh outcome trong từng tầng của Z (rồi tổng hợp) cho ước lượng nhân quả không chệch. Đây là nền tảng lý thuyết của matching / propensity score ở bài sau — propensity score chỉ là một cách gọn để điều kiện hoá trên Z.


Selection bias: điều kiện hoá trên collider mà không biết

Selection bias (thiên lệch chọn mẫu) thường chính là collider bias trá hình: ta điều kiện hoá — vô tình hay cố ý — trên một biến là collider hoặc hậu quả của T và Y.

Nguồn gây selection bias hay gặp trong dữ liệu ngân hàng:

  • Lọc mẫu theo hậu quả: chỉ phân tích khách "đã được duyệt vay", "đã kích hoạt thẻ", "còn hoạt động (không churn)" — nếu biến lọc chịu ảnh hưởng của cả T lẫn Y, ta đã điều kiện hoá trên collider.
  • Survivorship: chỉ nhìn tài khoản còn tồn tại đến hôm nay bỏ qua tài khoản đã đóng.
  • Attrition không đều: khách rời khỏi mẫu phụ thuộc treatment lẫn outcome.

Bài học: cách bạn chọn dòng dữ liệu (mẫu phân tích) cũng là một quyết định điều chỉnh. Một WHERE tưởng vô hại có thể mở một collider và tạo mối liên hệ giả.


Vì sao "kiểm soát càng nhiều biến càng tốt" là SAI

Trực giác phổ biến — và sai — là: cứ nhét mọi biến có sẵn vào mô hình cho "an toàn". DAG cho thấy điều này nguy hiểm. Có những bad controls (biến không nên kiểm soát):

  • Collider: điều chỉnh → tạo bias giả (như phân tích ở trên). Đây là loại tệ nhất vì nó sinh ra sai lệch từ hư không.
  • Mediator: điều chỉnh → chặn mất một phần hiệu ứng nhân quả, làm hiệu ứng đo được sai lệch xuống.
  • Biến sau treatment (post-treatment) nói chung: bất kỳ biến nào chịu ảnh hưởng của T (hậu duệ của T) — kiểm soát nó gần như luôn gây méo (hoặc là mediator, hoặc là collider).

Đối lập, good controls đúng nghĩa là các confounder (và biến chỉ ảnh hưởng Y, giúp giảm phương sai). Nguyên tắc: không phải kiểm soát nhiều hơn là tốt hơn — mà kiểm soát ĐÚNG tập mới tốt hơn. Và "đúng tập" = tập thoả backdoor criterion, chỉ xác định được nếu có DAG + kiến thức lĩnh vực. Đây cũng là một trong những cạm bẫy thống kê kinh điển, và lý do vì sao hồi quy "ném hết biến vào" (xem correlation & regression) không tự động cho hệ số nhân quả.


Dựng DAG cho bài toán ngân hàng

Quy trình thực chiến để chọn biến điều chỉnh:

Với bài toán "chương trình ưu đãi → giao dịch", DAG đầy đủ hơn có thể là:

  • Thu nhậpđộ tuổiconfounder (ảnh hưởng cả việc tham gia lẫn số giao dịch) → thuộc Z, phải điều chỉnh.
  • Số tài khoản mở thêm sau khi tham gia là mediatorkhông đưa vào Z nếu muốn tổng hiệu ứng.
  • Việc khách được xếp hạng VIP sau chương trình (chịu ảnh hưởng cả của độ giàu lẫn của giao dịch nhiều) có thể là colliderkhông lọc / không điều chỉnh.

Kết luận: tập điều chỉnh Z = {thu nhập, độ tuổi}. Chỉ khi so sánh khách tham gia với khách không tham gia trong cùng tầng thu nhập và độ tuổi, phần chênh giao dịch mới xấp xỉ hiệu ứng nhân quả của chương trình.


Minh hoạ stratification bằng SQL

Ý tưởng điều chỉnh confounder ở dạng thô sơ nhất chính là stratification (phân tầng): chia dữ liệu thành các tầng theo confounder, so sánh treatment vs control trong từng tầng, rồi tổng hợp — thay vì so sánh gộp (dễ dính confounding và cả nghịch lý Simpson).

Sandbox không có bảng thí nghiệm thật, nên đây chỉ minh hoạ kỹ thuật phân tầng và so sánh trong tầng. Ta giả lập: "treatment" = tính chẵn/lẻ của id (KHÔNG phải treatment thật, chỉ demo cú pháp), confounder = thành phố (city), outcome = số dư trung bình. So sánh hai nhóm trong từng thành phố:

-- ▶ Chạy được
SELECT
  c.city,
  CASE WHEN c.id % 2 = 0 THEN 'grp_B' ELSE 'grp_A' END       AS grp,
  COUNT(*)                                                    AS n_customers,
  ROUND(AVG(a.balance)::numeric, 2)                           AS avg_balance
FROM customers c
JOIN accounts a ON a.customer_id = c.id
GROUP BY c.city, grp
ORDER BY c.city, grp;

Mỗi hàng là một ô tầng × nhóm. Trong thí nghiệm/quan sát thật, cột grp sẽ là treatment thật, city (hoặc phân khúc thu nhập) là confounder cần phân tầng, và ta so avg_balance giữa hai grp trong cùng một city — chênh trong tầng loại bỏ ảnh hưởng của confounder đó. Nếu muốn một con số tổng hợp, ta lấy trung bình các chênh trong tầng, có trọng số theo cỡ mỗi tầng (đây chính là ước lượng theo backdoor adjustment). Lưu ý spec kỹ thuật: ép ::numeric trước khi ROUND để tránh lỗi kiểu với AVG trả double precision.

Stratification thủ công chỉ khả thi khi có ít confounder rời rạc. Khi confounder nhiều/liên tục, ta chuyển sang propensity score — nén nhiều confounder thành một điểm — chủ đề của bài 4.


Use case thực tế

Bối cảnh. Khối Khách hàng cá nhân NCB tung chương trình miễn phí chuyển khoản cho khách đăng ký (T = có tham gia). Câu hỏi: chương trình có thực sự làm tăng số giao dịch/tháng (Y) không? Không randomize được vì khách tự đăng ký.

Nhìn dữ liệu thô (sai). Nhóm tham gia: trung bình 42 giao dịch/tháng; nhóm không tham gia: 25. Chênh gộp = +17 giao dịch → báo cáo "chương trình cực hiệu quả". Nhưng đây là tương quan giả do confounding.

Vẽ DAG và phân loại biến.

  1. Thu nhập (proxy: số dư/nhóm sản phẩm) và độ tuổi: confounder — khách giàu & trung niên vừa hay đăng ký, vừa vốn giao dịch nhiều → thuộc Z.
  2. Số tài khoản phụ mở sau khi tham gia: mediator → loại khỏi Z.
  3. Nhãn "khách năng động" do hệ thống gán (dựa trên cả độ giàu lẫn số giao dịch): collider → không lọc theo nó.

Stratify theo confounder. Chia khách thành 3 tầng thu nhập × 3 nhóm tuổi = 9 tầng, so sánh T vs không-T trong từng tầng:

Tầng (minh hoạ)Chênh giao dịch trong tầng
Thu nhập cao, trung niên+4
Thu nhập cao, trẻ+5
Thu nhập thấp, trẻ+6
... (các tầng còn lại)+4 đến +6

Tổng hợp có trọng số cho ATE ≈ +5 giao dịch — nhỏ hơn nhiều so với +17 thô. Phần lớn "hiệu ứng" ban đầu là do khách tham gia vốn đã giàu và giao dịch nhiều, không phải do chương trình. Con số +5 (đã chặn backdoor qua thu nhập & tuổi) mới đáng tin để tính ROI.

Bẫy tránh được. Analyst suýt (a) đưa "số tài khoản phụ" vào mô hình như control → sẽ chặn mediator làm hiệu ứng tụt giả tạo; và (b) chỉ phân tích nhóm "khách năng động" → điều kiện hoá trên collider tạo bias. DAG giúp loại cả hai biến này ra khỏi tập điều chỉnh trước khi chạy số.


Ghi nhớ

  • Dữ liệu quan sát: phép "trừ trung bình hai nhóm" không cho ATE — phải điều chỉnh confounder, nhưng điều chỉnh biến nào là câu hỏi nhân quả, không nhìn ra được chỉ từ dữ liệu.
  • Confounder (fork T←C→Y) tạo tương quan giả T-Y qua đường sau → PHẢI điều chỉnh. Ví dụ ngân hàng: thu nhập vừa đẩy khách tham gia ưu đãi vừa đẩy giao dịch.
  • DAG = ngôn ngữ viết giả định nhân quả thành mũi tên; ba cấu trúc nền: chain (mediator), fork (confounder), collider.
  • Mediator (chain T→M→Y): KHÔNG điều chỉnh nếu muốn tổng hiệu ứng — điều chỉnh sẽ chặn mất kênh tác động.
  • Collider (T→K←Y): TUYỆT ĐỐI KHÔNG điều chỉnh — điều chỉnh/lọc trên collider tạo ra bias giả (phản trực giác, sai lầm phổ biến nhất).
  • Backdoor criterion: chọn tập Z chặn mọi backdoor path và không chứa hậu duệ của T → ước lượng T→Y không chệch (nền của matching/propensity).
  • Selection bias thường là collider bias trá hình: một WHERE lọc theo hậu quả (được duyệt, còn hoạt động...) có thể mở collider.
  • "Kiểm soát càng nhiều càng tốt" là SAI: bad controls = collider, mediator, biến sau treatment. Kiểm soát đúng tập (confounder), không phải nhiều tập.
  • Quy trình: DAG + kiến thức lĩnh vực → phân loại biến → backdoor → stratify / matching / propensity. Stratification là dạng thô sơ nhất; nhiều confounder thì chuyển sang bài 4.

Bài viết liên quan

Phân biệt ước lượng điểm và ước lượng khoảng, cách xây khoảng tin cậy (CI) bằng margin of error z*·SE / t*·SE, đánh đổi mức 90/95/99%, và cách DIỄN GIẢI ĐÚNG khoảng tin cậy (95% CI không phải xác suất tham số nằm trong khoảng). Có CI cho trung bình và cho tỷ lệ, ảnh hưởng của cỡ mẫu, cùng ví dụ ngân hàng về tỷ lệ nợ xấu và số dư trung bình.

13 thg 7, 2026 4

Kimball dimensional modeling: bảng fact/dimension, star vs snowflake, grain, và Slowly Changing Dimension.

13 thg 7, 2026 3

Khối OLAP, các thao tác drill-down/roll-up/slice & dice/pivot, OLAP vs OLTP và ROLAP/MOLAP/HOLAP.

13 thg 7, 2026 3

Từ nguồn dữ liệu qua ETL/ELT vào Data Warehouse, Data Mart đến dashboard; staging, ODS, batch vs streaming.

13 thg 7, 2026 3