ทำไม Logistic และ Conditional Logistic Regression จึงให้ Odds Ratio ต่างกัน?

On this page
Read the English version
บทคัดย่อ
Ordinary Logistic Regression และ Conditional Logistic Regression อาจให้ Odds Ratio ต่างกันมากจากข้อมูลชุดเดียวกัน เพราะสองโมเดลตอบคำถามต่างกัน ใน Matched Pairs 20 คู่จากการศึกษาแบบ Nested Case-Control เรื่อง Inadequate Antenatal Care กับ Neonatal Morbidity ภายใน 28 วัน Ordinary Logistic Regression ได้ OR = 1.83 และ Conditional Logistic Regression ได้ OR = 4.00 Control แต่ละรายสุ่มด้วย Risk-Set Sampling จากทารกที่ยังอยู่ในกลุ่มเสี่ยง ณ เวลาที่ Case ของมันเกิด Outcome Design นี้จึงถามคำถามภายใน Set การรวม 40 แถวเข้าด้วยกันเปรียบเทียบ Case ทั้งหมดกับ Control ทั้งหมด: (12/8)/(9/11) = 1.83 ส่วนการวิเคราะห์ภายใน Set เหลือเพียง 5 Discordant Pairs ที่ให้ข้อมูลเกี่ยวกับ Exposure: 4/1 = 4.00 ซึ่งไม่แม่นยำจนช่วงเชื่อมั่น 95% กว้างตั้งแต่ 0.45 ถึง 35.79 ภายใต้การสุ่มที่เหมาะสม Matched OR ประมาณ Hazard Ratio ของ Cox ไม่ใช่ Risk Ratio บทความนี้คำนวณค่าประมาณทั้งสองด้วยมือ แสดงที่มาของ Conditional Likelihood เชื่อม clogit กับ Cox Regression และทำซ้ำทั้งสองโมเดลใน Stata
Matched Pairs ชุดเดียวกัน แต่ได้ Odds Ratio สองค่า: 1.83 และ 4.00
ทีมวิจัยด้านทารกแรกเกิดทีมหนึ่งต้องการทราบว่า Inadequate Antenatal Care (ANC) คือการฝากครรภ์ที่น้อยเกินไปหรือเริ่มช้าเกินไป มีความสัมพันธ์กับการเกิด Neonatal Morbidity ภายใน 28 วันหลังคลอดหรือไม่
ทีมมีข้อมูล Matched Case-Control จำนวน 20 คู่ และทดลองวิเคราะห์ด้วยสองวิธี
- Ordinary Logistic Regression ได้ OR = 1.83
- Conditional Logistic Regression ได้ OR = 4.00
ทั้งสองโมเดลใช้ข้อมูลเดียวกัน Exposure เดียวกัน และ Outcome เดียวกัน แต่กลับให้ผลลัพธ์ต่างกันอย่างชัดเจน
คำถามสำคัญคือ เหตุใดจึงเกิดความแตกต่างนี้ และควรเชื่อผลลัพธ์จากโมเดลใด
การตอบคำถามนี้ต้องเริ่มจาก Study Design ไม่ใช่จากสมการทางสถิติ ข้อมูล 20 คู่ที่ใช้ตลอดบทความเป็นตัวอย่างที่สร้างขึ้นเพื่อให้เห็นความแตกต่างของสองโมเดล ไม่ใช่ข้อมูลจริงจากหน่วยงานใด
เริ่มจาก Study Design: Risk-Set Sampling
สมมติว่าเราติดตามทารกตั้งแต่แรกเกิดจนถึงอายุ 28 วัน โดยสนใจ Time to First Composite Morbidity Event คือเวลาจนถึงภาวะแทรกซ้อนครั้งแรกในกลุ่มภาวะแทรกซ้อนของทารกแรกเกิดที่กำหนดไว้ล่วงหน้า
เมื่อทารกคนหนึ่งเกิด Outcome เช่น ณ วันที่ 5 หลังคลอด ทารกคนนั้นจะถูกจัดเป็น Case
จากนั้นสุ่ม Control จากทารกที่ยังอยู่ในกลุ่มเสี่ยง ณ เวลาที่ Case เกิดเหตุการณ์ คือทารกที่ยังไม่เกิด Outcome การสุ่ม Control แบบนี้เรียกว่า Risk-Set Sampling และทารกที่ยังอยู่ในกลุ่มเสี่ยง ณ เวลานั้นรวมกันเป็น Risk Set ของ Case รายนั้น [1] บทความแยกเรื่องการเลือก Control เปรียบเทียบวิธีนี้กับวิธีอื่น
ตัวอย่างเช่น Case หนึ่งรายกับ Control ของมันอาจเป็นดังนี้
| Case | Control | |
|---|---|---|
| ทารก | A | B |
| ANC | Inadequate | Adequate |
| สถานะวันที่ 5 | เกิด Outcome | ยังไม่เกิด Outcome |
| Risk Set | 1 | 1 |
Matched Pair มีโครงสร้างอย่างไร
ตัวอย่างนี้ใช้การจับคู่แบบ 1:1
- หนึ่ง Risk Set มี Case 1 ราย
- มี Control ที่สุ่มมาให้ Case รายนั้น 1 ราย
- ทั้งสองแถวในคู่มี
set_idเดียวกัน คือรหัสของ Matched Set
ดังนั้น 20 Matched Pairs เท่ากับ 40 Observation Rows ในฐานข้อมูล แต่ในการศึกษาจริงอาจไม่ใช่ทารก 40 คนที่ไม่ซ้ำกัน เพราะทารกคนหนึ่งอาจปรากฏในหลาย Risk Sets
ชุดข้อมูลตัวอย่าง: 20 Matched Pairs
เพื่อให้เห็นความแตกต่างของโมเดล ตัวอย่างนี้ใช้ข้อมูลสมมติ 20 Matched Pairs นับตาม ANC ของ Case และ ANC ของ Control
| ANC ของ Case | ANC ของ Control | จำนวนคู่ |
|---|---|---|
| Inadequate | Inadequate | 8 |
| Adequate | Adequate | 7 |
| Inadequate | Adequate | 4 |
| Adequate | Inadequate | 1 |
| Total | 20 |
Concordant Pairs และ Discordant Pairs
ตรวจสอบจำนวนคู่: 8 + 7 + 4 + 1 = 20 คู่
แต่ละคู่มี Case หนึ่งรายการและ Control หนึ่งรายการเสมอ เราจึงมี Cases 20 รายการ และ Controls 20 รายการ
สังเกตว่าคู่เหล่านี้แบ่งเป็นสองประเภท
Concordant Pairs (15 คู่) คือคู่ที่ ANC เหมือนกัน
- 8 คู่: ทั้ง Case และ Control มี Inadequate ANC
- 7 คู่: ทั้ง Case และ Control มี Adequate ANC
Discordant Pairs (5 คู่) คือคู่ที่ ANC แตกต่างกัน
- 4 คู่: Case มี Inadequate ANC แต่ Control มี Adequate ANC
- 1 คู่: Case มี Adequate ANC แต่ Control มี Inadequate ANC
Ordinary Logistic Regression: ไม่สนใจการจับคู่
Ordinary Logistic Regression ไม่ใช้ข้อมูลว่า Case รายใดถูกจับคู่กับ Control รายใด
โปรแกรมมองข้อมูลเป็น Case 20 รายการ และ Control 20 รายการ แล้วนำมานับเป็นตาราง 2 × 2
| ANC | Case | Control |
|---|---|---|
| Inadequate | 12 | 9 |
| Adequate | 8 | 11 |
| Total | 20 | 20 |
ทีละขั้น: Ordinary Odds Ratio
ตัวเลขแต่ละช่องมาจากตารางคู่เดิม
- Case ที่มี Inadequate ANC = 8 + 4 = 12
- Case ที่มี Adequate ANC = 7 + 1 = 8
- Control ที่มี Inadequate ANC = 8 + 1 = 9
- Control ที่มี Adequate ANC = 7 + 4 = 11
-
ขั้นที่ 1. Exposure Odds ในกลุ่ม Cases
\[ \text{Odds among cases} = \frac{12}{8} = 1.50 \]
ใน Case ทั้งหมด 20 รายการ มีผู้ที่ ANC ไม่เพียงพอ 12 รายการ และเพียงพอ 8 รายการ นี่คือ Odds ของ Inadequate ANC ในกลุ่ม Cases
-
ขั้นที่ 2. Exposure Odds ในกลุ่ม Controls
\[ \text{Odds among controls} = \frac{9}{11} = 0.818 \]
ใน Control ทั้งหมด 20 รายการ มีผู้ที่ ANC ไม่เพียงพอ 9 รายการ และเพียงพอ 11 รายการ นี่คือ Odds ของ Inadequate ANC ในกลุ่ม Controls
-
ขั้นที่ 3. Ordinary Odds Ratio
\[ \mathrm{OR} = \frac{12/8}{9/11} = \frac{1.50}{0.818} = 1.83 \]
นำ Odds ของทั้งสองกลุ่มมาหารกัน
ผลลัพธ์: Ordinary Logistic Regression ให้ OR = 1.83 หมายความว่า Odds ของ Inadequate ANC ในกลุ่ม Cases สูงกว่ากลุ่ม Controls ประมาณ 1.83 เท่า เมื่อวิเคราะห์แบบรวมโดยไม่ใช้ข้อมูลการจับคู่
อย่างไรก็ตาม วิธีนี้ละเลย Risk Sets ที่ถูกกำหนดไว้ในการสุ่มตัวอย่าง จึงไม่ได้เปรียบเทียบผู้ที่อยู่ภายใน Risk Set เดียวกันตามที่ Study Design กำหนด
Conditional Logistic Regression: รักษา Matched Sets ไว้
Conditional Logistic Regression ถามคำถามที่ต่างออกไป
ทำไม Concordant Pairs จึงไม่ช่วยประมาณ ANC Effect
พิจารณาคู่ต่อไปนี้
| Case | Control | |
|---|---|---|
| ANC | Inadequate | Inadequate |
Discordant Pairs ให้ข้อมูลอย่างไร
พิจารณาเฉพาะ 5 คู่ที่ ANC แตกต่างกัน
| ANC ของ Case | ANC ของ Control | จำนวนคู่ |
|---|---|---|
| Inadequate | Adequate | 4 |
| Adequate | Inadequate | 1 |
| Total | 5 |
ทำไม Conditional Logistic Regression จึงทำงานแบบนี้
สิ่งสำคัญไม่ใช่แค่จำสูตร 4/1 แต่ต้องเข้าใจว่าเหตุใด Conditional Likelihood จึงนำไปสู่สูตรนี้
สมมติว่าแต่ละ Matched Pair มี Case เพียงหนึ่งราย Conditional Logistic Regression พิจารณาความน่าจะเป็นที่สมาชิกคนหนึ่งจะเป็น Case โดยมีเงื่อนไขว่าในคู่นั้นเกิด Outcome หนึ่งครั้ง เมื่ออ่านความน่าจะเป็นของ Case ที่สังเกตได้ภายใต้เงื่อนไขนี้เป็นฟังก์ชันของ coefficient จะได้ Conditional Likelihood [2]
กำหนดให้ $X = 1$ หมายถึง Inadequate ANC และ $X = 0$ หมายถึง Adequate ANC ให้ $\beta$ คือ Regression Coefficient ของ ANC และ $\exp(\beta)$ คือ Conditional Odds Ratio
-
คนที่มี Inadequate ANC เป็น Case
\[ P = \frac{\exp(\beta)}{1 + \exp(\beta)} \]
สำหรับคู่ที่ ANC แตกต่างกัน นี่คือความน่าจะเป็นตามโมเดลที่คนมี Inadequate ANC จะเป็น Case
-
คนที่มี Adequate ANC เป็น Case
\[ 1 - P = \frac{1}{1 + \exp(\beta)} \]
ส่วนนี่คือความน่าจะเป็นที่คนมี Adequate ANC จะเป็น Case แทน
-
Conditional Likelihood
\[ L(\beta) \propto P^{4}\,(1 - P)^{1} \]
ในข้อมูลของเรา พบเหตุการณ์รูปแบบแรก 4 คู่ และรูปแบบที่สอง 1 คู่ Conditional Likelihood ของส่วนที่ขึ้นกับ ANC จึงแปรผันตามผลคูณนี้
-
ค่าสูงสุด
\[ P = \frac{4}{5} = 0.80 \]
นี่คือค่า $P$ ที่ทำให้ Likelihood สูงสุด
-
กลับสู่ Odds Ratio
\[ \exp(\beta) = \frac{P}{1 - P} = \frac{0.80}{0.20} = 4.00 \]
นี่คือเหตุผลทางคณิตศาสตร์ที่ Conditional Logistic Regression ให้ OR = 4.00
-
Concordant Pairs
\[ P_{\text{concordant}} = \frac{1}{2} \]
สำหรับ Concordant Pairs ไม่ว่า $\beta$ จะมีค่าเท่าไร ความน่าจะเป็นเชิงเงื่อนไขของรูปแบบที่สังเกตได้เท่ากับ 1/2 จึงไม่ช่วยระบุค่า $\beta$ ในโมเดลตัวแปรเดียวนี้
ผลลัพธ์: กล่าวอีกอย่างคือ Conditional Likelihood ใช้ความแตกต่างภายในคู่ ไม่ใช่เพียงความแตกต่างของจำนวน Exposure ระหว่าง Cases และ Controls ทั้งหมด ซึ่งในที่นี้ให้ OR = 4.00
เปรียบเทียบสองโมเดล
| Feature | Ordinary Logistic | Conditional Logistic |
|---|---|---|
| ข้อมูล | 20 Matched Pairs | 20 Matched Pairs |
| Observation Rows | 40 | 40 |
ใช้ set_id | ไม่ใช้ | ใช้ |
| การเปรียบเทียบ | Pooled Cases vs Controls | Within Matched Sets |
| วิธีประมาณ | Unconditional Likelihood | Conditional Likelihood |
| OR ในตัวอย่าง | 1.83 | 4.00 |
| รองรับ Design นี้โดยตรง | ไม่ใช่ในรูปแบบที่ละเลย Matching | ใช่ |
ความแตกต่างนี้หมายถึงอะไร และไม่ได้หมายถึงอะไร
ความแตกต่างนี้ไม่ได้หมายความว่า Ordinary Logistic Regression เป็นโมเดลที่ผิดเสมอไป
แต่การใช้ Ordinary Logistic Regression โดยไม่คำนึงถึง Matched Risk Sets อาจทำให้ประมาณ Effect ที่ไม่ตรงกับ Study Design และอาจเกิด Bias ได้
นอกจากนี้ ไม่ใช่ทุกการศึกษาที่ Conditional OR จะมากกว่า Ordinary OR เสมอ ความแตกต่างขึ้นกับโครงสร้างข้อมูล การจับคู่ Confounding และคุณสมบัติของ Odds Ratio เอง เช่น Non-collapsibility คือ Odds Ratio ภายในกลุ่มย่อยอาจต่างจาก Odds Ratio ที่เฉลี่ยข้ามกลุ่มย่อยได้แม้ไม่มี Confounding [3] ตอนของชุดบทความนี้ว่าด้วย Conditional และ Marginal Odds Ratio อธิบายคุณสมบัตินี้อย่างละเอียด
ประเด็นขั้นสูง: clogit เกี่ยวข้องกับ Cox Regression อย่างไร
ในการศึกษาแบบ Concurrent หรือ Incidence-Density Sampling เราสุ่ม Controls จากผู้ที่ยังอยู่ใน Risk Set ณ เวลาที่ Case เกิด Outcome
Hazard คืออัตราการเกิดเหตุการณ์ชั่วขณะ ณ เวลา $t$ ในผู้ที่ยังไม่เกิดเหตุการณ์ ภายใต้ Cox Proportional Hazards Model
$$h(t \mid X) = h_0(t) \times \exp(\beta X)$$โดย $h_0(t)$ คือ Baseline Hazard ณ เวลา $t$ และ $\exp(\beta X)$ คือ Relative Hazard ของคนที่มี Exposure $X$
ถ้ามี Event หนึ่งครั้ง ณ เวลา $t$ ส่วนของ Cox Partial Likelihood สำหรับ Case รายหนึ่งจะมีรูปแบบ
$$\text{Likelihood} = \frac{\text{Relative Hazard ของ Case}}{\text{ผลรวม Relative Hazards ของทุกคนใน Risk Set}}$$คือ Relative Hazard ของ Case หารด้วยผลรวม Relative Hazards ของทุกคนใน Risk Set
Conditional Logistic Regression ใช้โครงสร้าง Likelihood ลักษณะเดียวกัน แต่เปรียบเทียบ Case กับ Controls ที่สุ่มมาใน Matched Risk Set ในคู่แบบ 1:1 Risk Set นั้นมีเพียง Case กับ Control ของมัน ความน่าจะเป็น $P$ ข้างบนจึงมีรูปแบบอย่างที่เห็น
ด้วยเหตุนี้ ภายใต้การสุ่มและสมมติฐานที่เหมาะสม ค่า $\exp(\beta)$ จาก Conditional Logistic Regression สามารถใช้ประมาณ Hazard Ratio คืออัตราส่วนของ Hazard สองค่า ที่เป็นเป้าหมายของ Cox Model ใน Full Cohort ได้
หาก Hazard Ratio คงที่ตลอดช่วงติดตาม และการสุ่ม Controls กับการวิเคราะห์สอดคล้องกับเวลาเกิด Event เราสามารถตีความค่าประมาณเป็น Relative Hazard หรือ Instantaneous Incidence Rate Ratio ได้ โดยไม่ต้องอาศัย Rare Disease Assumption คือสมมติฐานว่า Outcome พบน้อยพอที่ Odds Ratio จะใกล้เคียง Risk Ratio [4]
Stata: คู่ชุดเดียวกันในรูป Stratified Cox Model
* the same likelihood as a Cox model stratified by matched set: the case has its event at time 1 and its
* control is censored at time 2, so each risk set holds exactly the pair
generate byte t = 2 - case
stset t, failure(case)
stcox i.inadequate_anc, strata(set_id) nolog
. * the same likelihood as a Cox model stratified by matched set: the case has its event at time 1 and its
. * control is censored at time 2, so each risk set holds exactly the pair
. generate byte t = 2 - case
. stset t, failure(case)
Survival-time data settings
Failure event: case!=0 & case<.
Observed time interval: (0, t]
Exit on or before: failure
--------------------------------------------------------------------------
40 total observations
0 exclusions
--------------------------------------------------------------------------
40 observations remaining, representing
20 failures in single-record/single-failure data
60 total analysis time at risk and under observation
At risk from t = 0
Earliest observed entry t = 0
Last observed exit t = 2
. stcox i.inadequate_anc, strata(set_id) nolog
Failure _d: case
Analysis time _t: t
Stratified Cox regression with no ties
Strata variable: set_id
No. of subjects = 40 Number of obs = 40
No. of failures = 20
Time at risk = 60
LR chi2(1) = 1.93
Log likelihood = -12.89922 Prob > chi2 = 0.1650
----------------------------------------------------------------------------------
_t | Haz. ratio Std. err. z P>|z| [95% conf. interval]
-----------------+----------------------------------------------------------------
1.inadequate_anc | 4 4.472136 1.24 0.215 .4470826 35.78757
----------------------------------------------------------------------------------
| Effect Measure | ความหมาย |
|---|---|
| Odds Ratio (OR) | อัตราส่วนของ Odds |
| Risk Ratio (RR) | อัตราส่วนของ Cumulative Risks ในช่วงเวลาที่กำหนด |
| Incidence Rate Ratio (IRR) | อัตราส่วนของ Event Rates ต่อ Person-Time |
| Hazard Ratio (HR) | อัตราส่วนของ Instantaneous Hazards ณ เวลาที่กำหนด |
สิ่งที่ Conditional Logistic Regression ไม่ได้ทำ
Conditional Logistic Regression ไม่ได้ทำให้ OR กลายเป็น RR โดยอัตโนมัติ
การตีความ OR จาก Risk-Set Sampling เป็น HR หรือ Rate Ratio ต้องอาศัยเงื่อนไขของ Design, Sampling และ Hazard Model โดยเฉพาะการจัดการ Matching ตาม Event Time และสมมติฐานเกี่ยวกับการเปลี่ยนแปลงของ Effect ตามเวลา [5]
หาก Hazard Ratio เปลี่ยนไปตามเวลา ค่าจากโมเดลอาจสะท้อนการเฉลี่ย Effect ตามน้ำหนักของเหตุการณ์ มากกว่าจะเป็น HR คงที่ค่าเดียวที่อธิบายทุกช่วงเวลาได้
ทำซ้ำตัวอย่างใน Stata
เราสามารถสร้างตัวอย่างนี้ได้โดยไม่ต้องใช้ Dataset ภายนอก ต่อไปนี้คือคำสั่งของตัวอย่างที่คำนวณด้วยมือ
clear
* Four patterns of matched pairs
input byte anc_case anc_ctrl n_pairs
1 1 8
0 0 7
1 0 4
0 1 1
end
* Create 20 matched sets
expand n_pairs
gen long set_id = _n
* Reshape to one row per observation
reshape long anc_, i(set_id) j(role) string
rename anc_ inadequate_anc
* Case indicator
gen byte case = (role == "case")
* Check the matched-set structure
bysort set_id: assert _N == 2
bysort set_id: assert case[1] != case[2]
* Pooled 2x2 table
tab inadequate_anc case
* Ordinary logistic regression
logistic case i.inadequate_anc
* Conditional logistic regression
clogit case i.inadequate_anc, ///
group(set_id) orStata อธิบายคำสั่ง clogit ไว้ในคู่มืออ้างอิง [6] และ Stata FAQ อธิบายว่าทำไม clogit จึงตัด Covariate ที่ไม่แปรผันภายใน Matched Set ออกจากโมเดล [7]
| Model | Expected OR |
|---|---|
logistic | 1.83 |
clogit | 4.00 |
set_id ในการศึกษาจริง และผลการรัน
ในการศึกษาจริงให้ใช้ set_id ที่สร้างจากขั้นตอนการสุ่ม Risk-Set Controls ไม่ใช่สร้าง Set ID ใหม่โดยสุ่มจับคู่หลังจากได้ข้อมูลมาแล้ว
แผงด้านล่างรันขั้นตอนเดียวกันด้วยสคริปต์จำลองเบื้องหลังชุดบทความนี้ ใน Stata แล้วตามด้วย R พร้อมผลลัพธ์ที่แต่ละโปรแกรมพิมพ์ออกมา Ordinary Logistic Regression ได้ 1.83 และ Conditional Logistic Regression ได้ 4.00 ตรงกับที่คำนวณด้วยมือ
Stata: ป้อนข้อมูล 20 คู่
clear
input byte anc_case byte anc_ctrl int n_pairs
1 1 8
0 0 7
1 0 4
0 1 1
end
quietly summarize n_pairs
canon pairs.n 0 r(sum)
quietly summarize n_pairs if anc_case == anc_ctrl
canon pairs.concordant 0 r(sum)
quietly summarize n_pairs if anc_case != anc_ctrl
canon pairs.discordant 0 r(sum)
quietly summarize n_pairs if anc_case == 1 & anc_ctrl == 0
canon pairs.case_only_inadequate 0 r(sum)
quietly summarize n_pairs if anc_case == 0 & anc_ctrl == 1
canon pairs.control_only_inadequate 0 r(sum)
expand n_pairs
drop n_pairs
generate int set_id = _n
reshape long anc_, i(set_id) j(role) string
rename anc_ inadequate_anc
generate byte case = role == "case"
bysort set_id: assert _N == 2
bysort set_id (case): assert case[1] == 0 & case[2] == 1
quietly count
canon pairs.rows 0 r(N)
* the pooled 2 x 2 table that ordinary logistic regression sees
tabulate inadequate_anc case
. clear
. input byte anc_case byte anc_ctrl int n_pairs
anc_case anc_ctrl n_pairs
1. 1 1 8
2. 0 0 7
3. 1 0 4
4. 0 1 1
5. end
. quietly summarize n_pairs
. canon pairs.n 0 r(sum)
CANON c7.pairs.n 20
. quietly summarize n_pairs if anc_case == anc_ctrl
. canon pairs.concordant 0 r(sum)
CANON c7.pairs.concordant 15
. quietly summarize n_pairs if anc_case != anc_ctrl
. canon pairs.discordant 0 r(sum)
CANON c7.pairs.discordant 5
. quietly summarize n_pairs if anc_case == 1 & anc_ctrl == 0
. canon pairs.case_only_inadequate 0 r(sum)
CANON c7.pairs.case_only_inadequate 4
. quietly summarize n_pairs if anc_case == 0 & anc_ctrl == 1
. canon pairs.control_only_inadequate 0 r(sum)
CANON c7.pairs.control_only_inadequate 1
. expand n_pairs
(16 observations created)
. drop n_pairs
. generate int set_id = _n
. reshape long anc_, i(set_id) j(role) string
(j = case ctrl)
Data Wide -> Long
-----------------------------------------------------------------------------
Number of observations 20 -> 40
Number of variables 3 -> 3
j variable (2 values) -> role
xij variables:
anc_case anc_ctrl -> anc_
-----------------------------------------------------------------------------
. rename anc_ inadequate_anc
. generate byte case = role == "case"
. bysort set_id: assert _N == 2
. bysort set_id (case): assert case[1] == 0 & case[2] == 1
. quietly count
. canon pairs.rows 0 r(N)
CANON c7.pairs.rows 40
. * the pooled 2 x 2 table that ordinary logistic regression sees
. tabulate inadequate_anc case
inadequate | case
_anc | 0 1 | Total
-----------+----------------------+----------
0 | 11 8 | 19
1 | 9 12 | 21
-----------+----------------------+----------
Total | 20 20 | 40
Stata: Ordinary Logistic Regression กับคู่ที่จับคู่
* ordinary logistic regression ignores the matched sets
logistic case i.inadequate_anc, nolog
. * ordinary logistic regression ignores the matched sets
. logistic case i.inadequate_anc, nolog
Logistic regression Number of obs = 40
LR chi2(1) = 0.91
Prob > chi2 = 0.3413
Log likelihood = -27.27303 Pseudo R2 = 0.0163
----------------------------------------------------------------------------------
case | Odds ratio Std. err. z P>|z| [95% conf. interval]
-----------------+----------------------------------------------------------------
1.inadequate_anc | 1.833333 1.174412 0.95 0.344 .522362 6.434448
_cons | .7272727 .3379347 -0.69 0.493 .292535 1.808076
----------------------------------------------------------------------------------
Note: _cons estimates baseline odds.
Stata: การประมาณแบบรวมด้วย Cluster-Robust Standard Error
* clustering the standard error on the matched set changes the interval, not the odds ratio
logistic case i.inadequate_anc, vce(cluster set_id) nolog
. * clustering the standard error on the matched set changes the interval, not the odds ratio
. logistic case i.inadequate_anc, vce(cluster set_id) nolog
Logistic regression Number of obs = 40
Wald chi2(1) = 1.82
Prob > chi2 = 0.1770
Log pseudolikelihood = -27.27303 Pseudo R2 = 0.0163
(Std. err. adjusted for 20 clusters in set_id)
----------------------------------------------------------------------------------
| Robust
case | Odds ratio std. err. z P>|z| [95% conf. interval]
-----------------+----------------------------------------------------------------
1.inadequate_anc | 1.833333 .823118 1.35 0.177 .7604568 4.419858
_cons | .7272727 .1778604 -1.30 0.193 .4503282 1.174534
----------------------------------------------------------------------------------
Note: _cons estimates baseline odds.
Stata: Conditional Logistic Regression กับคู่ที่จับคู่
* conditional logistic regression compares the case with its own control inside each matched set
clogit case i.inadequate_anc, group(set_id) or nolog
. * conditional logistic regression compares the case with its own control inside each matched set
. clogit case i.inadequate_anc, group(set_id) or nolog
Conditional (fixed-effects) logistic regression Number of obs = 40
LR chi2(1) = 1.93
Prob > chi2 = 0.1650
Log likelihood = -12.89922 Pseudo R2 = 0.0695
----------------------------------------------------------------------------------
case | Odds ratio Std. err. z P>|z| [95% conf. interval]
-----------------+----------------------------------------------------------------
1.inadequate_anc | 4 4.472136 1.24 0.215 .4470826 35.78757
----------------------------------------------------------------------------------
R: ข้อมูลคู่และ Ordinary Logistic Regression
pairs <- data.frame(anc_case = c(1, 0, 1, 0), anc_ctrl = c(1, 0, 0, 1), n_pairs = c(8, 7, 4, 1))
canon("pairs.n", sum(pairs$n_pairs), 0)
canon("pairs.concordant", sum(pairs$n_pairs[pairs$anc_case == pairs$anc_ctrl]), 0)
canon("pairs.discordant", sum(pairs$n_pairs[pairs$anc_case != pairs$anc_ctrl]), 0)
canon("pairs.case_only_inadequate", sum(pairs$n_pairs[pairs$anc_case == 1 & pairs$anc_ctrl == 0]), 0)
canon("pairs.control_only_inadequate", sum(pairs$n_pairs[pairs$anc_case == 0 & pairs$anc_ctrl == 1]), 0)
pp <- pairs[rep(seq_len(nrow(pairs)), pairs$n_pairs), ]
pp$set_id <- seq_len(nrow(pp))
m <- rbind(data.frame(set_id = pp$set_id, case = 1L, inadequate_anc = pp$anc_case),
data.frame(set_id = pp$set_id, case = 0L, inadequate_anc = pp$anc_ctrl))
m <- m[order(m$set_id, m$case), ]
stopifnot(all(table(m$set_id) == 2), all(tapply(m$case, m$set_id, sum) == 1))
canon("pairs.rows", nrow(m), 0)
# the pooled 2 x 2 table that ordinary logistic regression sees
print(table(inadequate_anc = m$inadequate_anc, case = m$case))
a <- sum(m$case == 1 & m$inadequate_anc == 1)
bb <- sum(m$case == 1 & m$inadequate_anc == 0)
cc <- sum(m$case == 0 & m$inadequate_anc == 1)
dd <- sum(m$case == 0 & m$inadequate_anc == 0)
canon("pooled.cases_inadequate", a, 0)
canon("pooled.cases_adequate", bb, 0)
canon("pooled.controls_inadequate", cc, 0)
canon("pooled.controls_adequate", dd, 0)
canon("pooled.odds_cases", a / bb)
canon("pooled.odds_controls", cc / dd)
# ordinary logistic regression ignores the matched sets
fp <- glm(case ~ inadequate_anc, family = binomial, data = m)
print(summary(fp)$coefficients)
bp <- coef(fp)[["inadequate_anc"]]
sp <- sqrt(vcov(fp)["inadequate_anc", "inadequate_anc"])
canon("pooled.or", exp(bp))
canon("pooled.se", sp)
canon("pooled.or_lb", exp(bp - z * sp))
canon("pooled.or_ub", exp(bp + z * sp))
> pairs <- data.frame(anc_case = c(1, 0, 1, 0), anc_ctrl = c(1,
+ 0, 0, 1), n_pairs = c(8, 7, 4, 1))
> canon("pairs.n", sum(pairs$n_pairs), 0)
CANON c7.pairs.n 20
> canon("pairs.concordant", sum(pairs$n_pairs[pairs$anc_case ==
+ pairs$anc_ctrl]), 0)
CANON c7.pairs.concordant 15
> canon("pairs.discordant", sum(pairs$n_pairs[pairs$anc_case !=
+ pairs$anc_ctrl]), 0)
CANON c7.pairs.discordant 5
> canon("pairs.case_only_inadequate", sum(pairs$n_pairs[pairs$anc_case ==
+ 1 & pairs$anc_ctrl == 0]), 0)
CANON c7.pairs.case_only_inadequate 4
> canon("pairs.control_only_inadequate", sum(pairs$n_pairs[pairs$anc_case ==
+ 0 & pairs$anc_ctrl == 1]), 0)
CANON c7.pairs.control_only_inadequate 1
> pp <- pairs[rep(seq_len(nrow(pairs)), pairs$n_pairs),
+ ]
> pp$set_id <- seq_len(nrow(pp))
> m <- rbind(data.frame(set_id = pp$set_id, case = 1,
+ inadequate_anc = pp$anc_case), data.frame(set_id = pp$set_id,
+ case = 0, inadequate_anc = pp$anc_ctrl))
> m <- m[order(m$set_id, m$case), ]
> stopifnot(all(table(m$set_id) == 2), all(tapply(m$case,
+ m$set_id, sum) == 1))
> canon("pairs.rows", nrow(m), 0)
CANON c7.pairs.rows 40
> print(table(inadequate_anc = m$inadequate_anc, case = m$case))
case
inadequate_anc 0 1
0 11 8
1 9 12
> a <- sum(m$case == 1 & m$inadequate_anc == 1)
> bb <- sum(m$case == 1 & m$inadequate_anc == 0)
> cc <- sum(m$case == 0 & m$inadequate_anc == 1)
> dd <- sum(m$case == 0 & m$inadequate_anc == 0)
> canon("pooled.cases_inadequate", a, 0)
CANON c7.pooled.cases_inadequate 12
> canon("pooled.cases_adequate", bb, 0)
CANON c7.pooled.cases_adequate 8
> canon("pooled.controls_inadequate", cc, 0)
CANON c7.pooled.controls_inadequate 9
> canon("pooled.controls_adequate", dd, 0)
CANON c7.pooled.controls_adequate 11
> canon("pooled.odds_cases", a/bb)
CANON c7.pooled.odds_cases 1.5000
> canon("pooled.odds_controls", cc/dd)
CANON c7.pooled.odds_controls 0.8182
> fp <- glm(case ~ inadequate_anc, family = binomial,
+ data = m)
> print(summary(fp)$coefficients)
Estimate Std. Error z value Pr(>|z|)
(Intercept) -0.3184537 0.4646602 -0.6853476 0.4931246
inadequate_anc 0.6061358 0.6405884 0.9462172 0.3440378
> bp <- coef(fp)[["inadequate_anc"]]
> sp <- sqrt(vcov(fp)["inadequate_anc", "inadequate_anc"])
> canon("pooled.or", exp(bp))
CANON c7.pooled.or 1.8333
> canon("pooled.se", sp)
CANON c7.pooled.se 0.6406
> canon("pooled.or_lb", exp(bp - z * sp))
CANON c7.pooled.or_lb 0.5224
> canon("pooled.or_ub", exp(bp + z * sp))
CANON c7.pooled.or_ub 6.4344
R: clogit() กับคู่ที่จับคู่
# conditional logistic regression compares the case with its own control inside each matched set
fc <- clogit(case ~ inadequate_anc + strata(set_id), data = m)
print(summary(fc))
> fc <- clogit(case ~ inadequate_anc + strata(set_id),
+ data = m)
> print(summary(fc))
Call:
coxph(formula = Surv(rep(1, 40L), case) ~ inadequate_anc + strata(set_id),
data = m, method = "exact")
n= 40, number of events= 20
coef exp(coef) se(coef) z Pr(>|z|)
inadequate_anc 1.386 4.000 1.118 1.24 0.215
exp(coef) exp(-coef) lower .95 upper .95
inadequate_anc 4 0.25 0.4471 35.79
Concordance= 0.575 (se = 0.075 )
Likelihood ratio test= 1.93 on 1 df, p=0.2
Wald test = 1.54 on 1 df, p=0.2
Score (logrank) test = 1.8 on 1 df, p=0.2
ความเข้าใจผิดที่พบบ่อย
-
"clogit จับคู่ Cases กับ Controls ให้อัตโนมัติ"
ไม่จริง clogit ใช้ Matched Sets ที่ผู้วิจัยกำหนดไว้ก่อนแล้วผ่าน group(set_id) ไม่ได้ทำ Matching ให้เอง
วิธีแก้: สร้างรหัส Set ตั้งแต่ขั้นตอนการสุ่ม Risk-Set Controls แล้วส่งให้ clogit ผ่าน group(set_id)
-
"clogit ใช้เพียง Discordant Pairs ห้าคู่ แล้วทิ้งข้อมูลที่เหลือ"
ไม่ถูกต้องในความหมายทั่วไป โมเดลใช้ Conditional Likelihood ของ Matched Sets ทั้งหมด แต่ในตัวอย่างนี้ที่มี Binary ANC เพียงตัวเดียว Concordant Pairs 15 คู่เพียงไม่ให้ข้อมูลเกี่ยวกับ ANC coefficient
วิธีแก้: เก็บ Matched Sets ทุกชุดไว้ในข้อมูล และรายงานว่ามีกี่ Set ที่ Discordant ใน Exposure เพราะ Set เหล่านั้นเป็นผู้ให้ข้อมูลเกี่ยวกับ Exposure
-
"OR ที่ใหญ่กว่าแปลว่าโมเดลแม่นยำกว่า"
ไม่จริง OR = 4.00 ไม่ได้พิสูจน์ว่าโมเดลมีความแม่นยำกว่า OR = 1.83 ในที่นี้ค่าประมาณที่ใหญ่กว่ายังมีช่วงเชื่อมั่นกว้างกว่ามาก คือ 0.45 ถึง 35.79 เทียบกับ 0.52 ถึง 6.43
วิธีแก้: เลือกโมเดลจาก Study Design, Estimand, Model Assumptions และความเสี่ยงของ Bias ไม่ใช่จากขนาดของ OR
-
"Risk-Set Sampling ทำให้ OR เท่ากับ Risk Ratio เสมอ"
ไม่จริง วิธีสุ่มแบบนี้ทำให้ Matched OR ประมาณ Relative Hazard หรือ Rate Ratio ได้ภายใต้เงื่อนไขที่เหมาะสม แต่ไม่ได้เท่ากับ 28-day Cumulative Risk Ratio โดยอัตโนมัติ
วิธีแก้: ระบุ Effect Measure ที่ Design และสมมติฐานรองรับ และอย่ารายงาน Matched OR ว่าเป็น Risk Ratio
-
"ใช้ Robust Standard Errors แล้วแก้ปัญหาการละเลย Matching ได้"
ไม่จริง Robust หรือ Cluster-Robust Standard Errors เปลี่ยนวิธีประเมินความไม่แน่นอนของ Coefficient แต่ไม่ได้เปลี่ยน Point Estimate ของ Ordinary Logistic Regression ให้กลายเป็น Conditional Estimate เมื่อ cluster ตามคู่ Pooled OR ยังคงเป็น 1.83 มีเพียงช่วงเชื่อมั่น 95% ที่ขยับจาก 0.52 ถึง 6.43 เป็น 0.76 ถึง 4.42
วิธีแก้: วิเคราะห์ข้อมูลที่จับคู่ด้วย Risk-Set Sampling ด้วย Conditional Logistic Regression Standard Error ที่ต่างไปเปลี่ยนเฉพาะช่วงเชื่อมั่น ไม่เปลี่ยนค่าประมาณหรือคำถามที่ค่าประมาณนั้นตอบ
บทสรุป
Ordinary Logistic Regression และ Conditional Logistic Regression อาจให้ Odds Ratios แตกต่างกันมาก แม้ใช้ข้อมูลเดียวกัน เนื่องจาก Likelihood และโครงสร้างการเปรียบเทียบแตกต่างกัน
ในตัวอย่างนี้
- Ordinary Logistic Regression ได้ OR = 1.83 จาก Exposure Odds ของ Cases เทียบกับ Controls แบบรวม
- Conditional Logistic Regression ได้ OR = 4.00 จากการเปรียบเทียบ Exposure ภายใน Matched Sets
สำหรับการศึกษา Nested Case-Control ที่ใช้ Incidence-Density Sampling การวิเคราะห์ด้วย Conditional Logistic Regression เป็นแนวทางมาตรฐานสำหรับรักษาโครงสร้างการสุ่มแบบ Matched Risk Sets
หากต้องการตีความค่าประมาณเป็น Hazard Ratio ต้องพิจารณาสมมติฐานของ Hazard Model และกระบวนการสุ่มตัวอย่างด้วย
อภิธานศัพท์
- risk-set sampling (การสุ่มกลุ่มควบคุมจากกลุ่มเสี่ยง)
- การสุ่ม Control ของ Case แต่ละรายจากผู้ที่ยังอยู่ในกลุ่มเสี่ยง ณ เวลาที่ Case เกิดเหตุการณ์
- risk set
- ผู้ที่ยังมีโอกาสเกิด Outcome ณ เวลาที่ Case รายหนึ่งเกิดเหตุการณ์
- nested case-control study (การศึกษาแบบ nested case-control)
- การศึกษา Case-Control ที่ดึงมาจาก Cohort ที่กำหนดไว้ โดยสุ่ม Control จากผู้ที่อยู่ในกลุ่มเสี่ยง
- incidence-density sampling (การเลือกกลุ่มควบคุมตามความหนาแน่นของอุบัติการณ์)
- อีกชื่อหนึ่งของ Risk-Set Sampling คือสุ่ม Control จากผู้ที่ยังอยู่ในกลุ่มเสี่ยง ณ เวลาที่ Case แต่ละรายเกิดเหตุการณ์
- matched set (ชุดที่จับคู่)
- Case หนึ่งรายพร้อม Control ที่สุ่มมาให้ ใช้รหัส Set เดียวกัน ในการจับคู่ 1:1 คือหนึ่งคู่
- concordant pair (คู่ที่สอดคล้องกัน)
- Matched Pair ที่ Case และ Control มี Exposure เหมือนกัน เมื่อมี Binary Exposure ตัวเดียว คู่นี้ไม่ให้ข้อมูลเกี่ยวกับ Exposure ใน Conditional Logistic Regression
- discordant pair (คู่ที่ไม่สอดคล้องกัน)
- Matched Pair ที่ Case และ Control มี Exposure ต่างกัน เมื่อจับคู่ 1:1 มี Binary Exposure ตัวเดียวและไม่มี Covariates อื่น Matched OR คืออัตราส่วนของคู่สองชนิดนี้
- conditional likelihood
- ความน่าจะเป็นว่าสมาชิกคนใดของ Matched Set เป็น Case เมื่อกำหนดว่า Set นั้นมี Case เพียงหนึ่งราย อ่านเป็นฟังก์ชันของ coefficient
- conditional logistic regression
- Logistic Model ที่ประมาณผ่าน Conditional Likelihood ทำให้ Case แต่ละรายถูกเปรียบเทียบกับสมาชิกใน Matched Set ของตัวเองเท่านั้น
- non-collapsibility (ความไม่ยุบรวมได้)
- คุณสมบัติของ Odds Ratio และ Hazard Ratio ที่ค่าที่เฉลี่ยข้ามกลุ่มย่อยอาจต่างจากค่าร่วมภายในกลุ่มย่อยได้ แม้ไม่มี Confounding
- hazard (ฮาซาร์ด)
- อัตราการเกิดเหตุการณ์ชั่วขณะ ณ เวลา t ในผู้ที่ยังอยู่ในกลุ่มเสี่ยง
- partial likelihood
- Likelihood ของ Cox Model: สำหรับแต่ละ Event คือ Relative Hazard ของผู้ที่เกิด Event หารด้วยผลรวม Relative Hazards ของทุกคนใน Risk Set
- hazard ratio (อัตราส่วนฮาซาร์ด)
- อัตราส่วนของอัตราการเกิดเหตุการณ์ชั่วขณะระหว่างกลุ่ม ซึ่งไม่ใช่อัตราส่วนของความเสี่ยง
- rare disease assumption
- สมมติฐานว่า Outcome พบน้อยพอที่ Odds Ratio จะใกล้เคียง Risk Ratio Risk-Set Sampling ไม่ต้องใช้สมมติฐานนี้เมื่อตีความเป็น Hazard Ratio
- cluster-robust standard error
- Standard Error ที่ยอมให้ข้อมูลภายใน Cluster เดียวกัน เช่น Matched Pair สัมพันธ์กันได้ เปลี่ยนช่วงเชื่อมั่นแต่ไม่เปลี่ยนค่าประมาณ
เอกสารอ้างอิง
- Langholz B, Goldstein L. Risk set sampling in epidemiologic cohort studies. Stat Sci. 1996;11(1):35-53. doi:10.1214/ss/1032209663 https://doi.org/10.1214/ss/1032209663
- Breslow NE, Day NE. Statistical Methods in Cancer Research, Volume I: The Analysis of Case-Control Studies. IARC Scientific Publications No. 32. Lyon: International Agency for Research on Cancer; 1980. https://publications.iarc.who.int/Book-And-Report-Series/Iarc-Scientific-Publications/Statistical-Methods-In-Cancer-Research-Volume-I-The-Analysis-Of-Case-Control-Studies-1980
- Greenland S, Pearl J, Robins JM. Confounding and collapsibility in causal inference. Stat Sci. 1999;14(1):29-46. doi:10.1214/ss/1009211805 https://doi.org/10.1214/ss/1009211805
- Greenland S, Thomas DC. On the need for the rare disease assumption in case-control studies. Am J Epidemiol. 1982;116(3):547-553. doi:10.1093/oxfordjournals.aje.a113439 https://doi.org/10.1093/oxfordjournals.aje.a113439
- Kerr S, Greenland S, Jeffrey K, et al. Understanding and reporting odds ratios as rate-ratio estimates in case-control studies. J Glob Health. 2023;13:04101. doi:10.7189/jogh.13.04101 https://doi.org/10.7189/jogh.13.04101
- StataCorp. Stata Base Reference Manual: [R] clogit. Stata documentation (PDF) at stata.com. Accessed 11 October 2026. https://www.stata.com/manuals/rclogit.pdf
- Gould W. Within group collinearity in conditional logistic regression. Stata FAQ, StataCorp. Accessed 17 October 2026. https://www.stata.com/support/faqs/statistics/within-group-collinearity-and-clogit/
ประเด็นสำคัญ
- Estimator ตีความแยกจาก Study Design ไม่ได้: 20 Matched Pairs ชุดเดียวกันให้ 1.83 จาก Ordinary Logistic Regression และ 4.00 จาก Conditional Logistic Regression เพราะสองโมเดลตอบคำถามต่างกัน
- ใน Risk-Set Sampling Control แต่ละรายมาจากทารกที่ยังอยู่ในกลุ่มเสี่ยง ณ เวลาที่ Case ของมันเกิด Outcome Control อาจกลายเป็น Case ภายหลังได้ และ Matched Set คือหน่วยของการเปรียบเทียบ
- การรวมให้ (12/8)/(9/11) = 1.50/0.818 = 1.83 ส่วนการวิเคราะห์ภายใน Matched Set เหลือ Discordant Pairs ที่ให้ 4/1 = 4.00 ซึ่ง Conditional Likelihood P ยกกำลัง 4 คูณ (1 - P) มีค่าสูงสุดที่ P = 0.80
- ภายใต้การสุ่มและสมมติฐานที่เหมาะสม Matched OR ประมาณ Hazard Ratio ของ Cox ไม่ใช่ Risk Ratio และไม่จำเป็นต้องเท่ากับค่าประมาณจาก Cox บน Full Cohort เป๊ะ
- เมื่อมี Discordant Pairs เพียง 5 คู่ ต้องรายงาน 4.00 พร้อม 95% Confidence Interval คือ 0.45 ถึง 35.79 และ Robust Standard Error ไม่ได้ทำให้ค่าประมาณแบบรวมกลายเป็นค่าแบบจับคู่
อ่านต่อในวิกิ: [[conditional-vs-marginal-or-th]] [[case-control-sampling-schemes-stata-and-r-th]] [[conditional-logistic-regression]]