🧪 วิธีทำซ้ำผลในคู่มือนี้How to reproduce the results in this guide
- ใน DAPH เปลี่ยนภาษาของโปรแกรมเป็น English แล้วเลือก File → Example Dataset โปรแกรมจะเปิดชุดข้อมูล
DAPH-Data-(EN): ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย 41 ตัวแปร (ชุดข้อมูลภาษาไทยมีค่าเหมือนกันทุกตัวแปร ยกเว้นรหัสอำเภอampและรหัสโรงพยาบาลhos,hos2ที่เรียงตามชื่อภาษาไทย ผลที่ใช้ตัวแปรเหล่านี้จึงต้องใช้ชุดภาษาอังกฤษ)In DAPH, switch the language to English and choose File → Example Dataset. DAPH opensDAPH-Data-(EN): 1,300 peritoneal-dialysis patients, 41 variables. (The Thai dataset holds the same values except the district codeampand the hospital codeshosandhos2, which are numbered in Thai alphabetical order; analyses that use these variables need the English dataset.) - เลือก File → Export → Export CSV (.csv) แล้วบันทึกเป็น
example_en.csvในโฟลเดอร์ทำงานของ RChoose File → Export → Export CSV (.csv) and save it asexample_en.csvin R's working folder. - ใช้ R 4.3.3 ขึ้นไป ติดตั้งแพ็กเกจที่ระบุเหนือสคริปต์ด้วย
install.packages()แล้วรันสคริปต์ของหัวข้อนั้นทั้งชุดตามลำดับ ทุกหัวข้ออ่านข้อมูลเองตั้งแต่บรรทัดแรก ไม่ต้องใช้ผลจากหัวข้ออื่นUse R 4.3.3 or newer, install the packages named above each script withinstall.packages(), and run the section's scripts in order. Every section reads the data in its first lines and needs nothing from other sections. - ข้อมูลตัวอย่างไม่มีแผนที่ หัวข้อเชิงพื้นที่จึงใช้ข้อมูลแผนที่สาธารณะที่ติดมากับแพ็กเกจ R ตามที่ระบุในหัวข้อนั้น สคริปต์ของหัวข้อสร้างไฟล์
.zipให้นำเข้า DAPH ด้วย File → Import → Shapefile (.zip)The example data have no map, so the spatial sections use public map data that ship with R packages, named in each section; the section's script writes a.zipfile to import into DAPH with File → Import → Shapefile (.zip). - ตารางทวนสอบของทุกหัวข้อเทียบค่าที่ DAPH คำนวณกับค่าที่ R คำนวณบนข้อมูลชุดเดียวกัน ค่าในคอลัมน์ DAPH มาจากการรันโปรแกรมจริง สถิติที่ใช้การสุ่ม (permutation, bootstrap, MCMC, machine learning) เทียบภายในความคลาดเคลื่อนจากการสุ่มที่ระบุไว้ในหัวข้อนั้นEvery verification table compares DAPH's output with R on the same data; the DAPH column comes from running DAPH. Statistics that use random numbers (permutation tests, bootstrap, MCMC, machine learning) are compared within the Monte Carlo error stated in the section.
บทที่ 1 — ตัวแปรต่อเนื่องChapter 1 — Continuous Outcomes ✓ Verified
สถิติสำหรับตัวแปรผลลัพธ์ที่เป็นตัวเลขต่อเนื่อง เช่น คะแนนคุณภาพชีวิต ความดันโลหิต ระดับน้ำตาลในเลือด หรือ BMI · บทนี้ครอบคลุมการเปรียบเทียบค่าเฉลี่ยของสองกลุ่มและของค่าก่อน-หลัง (t-test หัวข้อ 1.1) หลายกลุ่ม (One-way ANOVA หัวข้อ 1.2) สองปัจจัยพร้อมกัน (Two-way ANOVA หัวข้อ 1.3) การปรับตัวแปรร่วม (ANCOVA หัวข้อ 1.4) การวัดซ้ำในคนเดียวกัน (Repeated-Measures ANOVA หัวข้อ 1.5, GEE หัวข้อ 1.6 และ Mixed-Effect Linear Regression หัวข้อ 1.7) ความสัมพันธ์ระหว่างตัวแปร (Pearson และ Spearman correlation หัวข้อ 1.8) วิธีที่ใช้อันดับเมื่อข้อมูลไม่เป็นไปตามข้อตกลง (หัวข้อ 1.9 ถึง 1.11) และ Linear Regression (หัวข้อ 1.12) · ทุกหัวข้อใช้ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย) มีสคริปต์ R ที่รันได้กับไฟล์ example_en.csv ที่ส่งออกจาก DAPH และมีตารางเทียบผลของ DAPH กับ R ทีละค่า ซึ่งระบุว่าค่าใดตรงกัน (PASS) และค่าใดยังไม่ตรง (FAIL)
Methods for continuous outcomes such as a quality-of-life score, blood pressure, blood glucose or BMI. The chapter covers comparing the means of two groups and of before-after measurements (t-test, section 1.1), several groups (One-way ANOVA, 1.2), two factors at once (Two-way ANOVA, 1.3), adjustment for covariates (ANCOVA, 1.4), repeated measurements on the same people (Repeated-Measures ANOVA 1.5, GEE 1.6 and Mixed-Effect Linear Regression 1.7), association between variables (Pearson and Spearman correlation, 1.8), rank-based tests for data that do not meet the assumptions (1.9 to 1.11) and Linear Regression (1.12). Every section uses the DAPH example data (1,300 peritoneal-dialysis patients), gives an R script that runs on the example_en.csv file exported from DAPH, and compares DAPH with R value by value, marking each value that agrees (PASS) or does not yet agree (FAIL).
1.1Independent & Paired t-test
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
t-test ใช้เปรียบเทียบค่าเฉลี่ยของตัวแปรผลลัพธ์ที่เป็นตัวเลขต่อเนื่องระหว่างสองชุดข้อมูล มีสองแบบ · Independent t-test เทียบสองกลุ่มที่เป็นคนละคนกัน เช่น ผู้ป่วยที่ล้างไตทางช่องท้องแบบ CAPD กับแบบ APD · Paired t-test เทียบค่าที่วัดสองครั้งในคนเดียวกัน (หรือในคู่ที่จับคู่กันไว้) เช่น คะแนนก่อนและหลังการรักษา โดยวิเคราะห์ผลต่างของแต่ละคน · W. S. Gosset เสนอวิธีนี้ในนามแฝง "Student" (Student, 1908) และ Welch (1947) ขยายให้ใช้ได้เมื่อความแปรปรวนของสองกลุ่มไม่เท่ากัน (Welch's t-test)
The t-test compares the mean of a continuous outcome between two sets of measurements. The independent t-test compares two groups of different people, for example patients on CAPD and patients on APD peritoneal dialysis. The paired t-test compares two measurements taken on the same people (or on matched pairs), for example a score before and after treatment, by analysing each person's difference. W. S. Gosset introduced the test writing as "Student" (Student, 1908); Welch (1947) extended it to groups whose variances differ (Welch's t-test).
ใช้เมื่อ ผลลัพธ์เป็นตัวเลขต่อเนื่อง มีสองกลุ่มพอดี (หรือวัดซ้ำสองครั้ง) ข้อมูลของแต่ละคนเป็นอิสระต่อกัน และข้อมูลแต่ละกลุ่ม (หรือผลต่างของคู่) ใกล้เคียงการแจกแจงปกติ หรือมีอย่างน้อยประมาณ 30 รายต่อกลุ่ม · ไม่ควรใช้เมื่อ มีมากกว่าสองกลุ่ม (ใช้ One-way ANOVA หัวข้อ 1.2) ต้องการปรับอิทธิพลของตัวแปรอื่น เช่น คะแนนก่อนการรักษา (ใช้ ANCOVA หัวข้อ 1.4) หรือกลุ่มเล็กและข้อมูลเบ้มาก (ใช้ Mann-Whitney U test หัวข้อ 1.9 หรือ Wilcoxon Signed-Rank test หัวข้อ 1.11)
Use it when the outcome is continuous, there are exactly two groups (or two measurements), observations from different people are independent, and each group (or the paired differences) is roughly normal or has about 30 or more observations. Do not use it for more than two groups (use One-way ANOVA, section 1.2), when another variable such as the pre-treatment score must be adjusted for (use ANCOVA, section 1.4), or for small, very skewed samples (use the Mann-Whitney U test, section 1.9, or the Wilcoxon signed-rank test, section 1.11).
qolscore3) ของผู้ป่วยกลุ่ม CAPD (656 ราย) กับกลุ่ม APD (644 ราย) ตามตัวแปร Treatment Group (group: 1 = CAPD, 2 = APD) ต่างกันหรือไม่ · คำถามที่ 2 (Paired t-test): ในผู้ป่วย 1,300 รายเดียวกัน คะแนนหลังการรักษาเปลี่ยนไปจากคะแนนก่อนการรักษา (Quality of Life Score (Pre), qolscore1) เท่าใด · ผลอยู่ในส่วนที่ 3 และการแปลผลในส่วนที่ 4qolscore3) differ between CAPD patients (656) and APD patients (644), Treatment Group (group: 1 = CAPD, 2 = APD)? Question 2 (paired t-test): in the same 1,300 patients, how much did the score change from before treatment (Quality of Life Score (Pre), qolscore1) to after treatment? The results are in part 3 and their interpretation in part 4.2หลักการและสูตรLogic and Formula
- x̄_j, s_j, n_j
- ค่าเฉลี่ย ส่วนเบี่ยงเบนมาตรฐาน และจำนวนของกลุ่ม j (กลุ่ม 1 คือกลุ่มที่รหัสน้อยกว่า)mean, standard deviation and size of group j (group 1 is the group with the lower code)
- s_p
- ส่วนเบี่ยงเบนมาตรฐานร่วมของสองกลุ่ม (pooled SD)pooled standard deviation of the two groups
- T_df, t_0.975,df
- การแจกแจง t ที่องศาอิสระ df และค่าวิกฤตสำหรับช่วงเชื่อมั่น 95% (ประมาณ 1.96 เมื่อ df มาก)t distribution with df degrees of freedom and its critical value for a 95% interval (about 1.96 for large df)
- x̃_j, z_ij, N, k
- มัธยฐานของกลุ่ม j, ระยะห่างจากมัธยฐานของแต่ละค่า, จำนวนทั้งหมด, จำนวนกลุ่ม (k = 2)median of group j, absolute distance of each value from that median, total size, number of groups (k = 2)
- d_i, d̄, s_d, n
- ผลต่างของคนที่ i (หลัง − ก่อน), ค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานของผลต่าง, จำนวนคู่difference for person i (post − pre), mean and standard deviation of the differences, number of pairs
สิ่งที่ DAPH ทำใน Independent t-test · ตัวแปรกลุ่มคือตัวแปรที่เลือกเป็น Intervention (ถ้าไม่ได้เลือก ใช้ตัวแปรแรกในช่อง Independent Variables) ใช้แถวที่มีค่าครบทั้งตัวแปรตามและตัวแปรกลุ่ม เรียงกลุ่มตามรหัส กลุ่มรหัสน้อยเป็นกลุ่ม 1 ผลต่างค่าเฉลี่ยจึงเป็น กลุ่มรหัสน้อย − กลุ่มรหัสมาก (ข้อมูลตัวอย่าง: CAPD − APD) · ตรวจข้อตกลงเบื้องต้นสามข้อ: จำนวนในแต่ละกลุ่ม (อย่างน้อย 30 รายถือว่าพอตามทฤษฎีบทขีดจำกัดกลาง หรือ Central Limit Theorem) · Shapiro-Wilk ในแต่ละกลุ่ม (Shapiro & Wilk, 1965) · Levene's test แบบใช้มัธยฐานเป็นจุดกลาง (Levene, 1960; Brown & Forsythe, 1974) · กฎการเลือก: ถ้า Levene p < 0.05 DAPH รายงาน Welch's t-test (สูตรที่สอง: ค่า t, df แบบ Welch-Satterthwaite ซึ่งไม่จำเป็นต้องเป็นจำนวนเต็ม, p และ 95% CI จาก SE ที่ไม่รวมความแปรปรวน) ถ้า Levene p ≥ 0.05 รายงาน Student's t-test (สูตรแรก) · หมายเหตุใต้ตาราง หน้าสรุป และรายงาน Word ระบุชื่อการทดสอบที่ใช้ เช่น "Welch's t = −1.977, df = 1291.8" · Cohen's d ใช้ส่วนเบี่ยงเบนมาตรฐานร่วมและแสดงเป็นค่าสัมบูรณ์ ทิศทางให้ดูจากผลต่างค่าเฉลี่ย · เกณฑ์ที่ DAPH ใช้: |d| < 0.2 เล็กมาก (negligible), 0.2 ถึงน้อยกว่า 0.5 เล็ก, 0.5 ถึงน้อยกว่า 0.8 ปานกลาง, ตั้งแต่ 0.8 ใหญ่ (Cohen, 1988) · ค่า p เป็นแบบสองทาง
What DAPH does in the independent t-test. The grouping variable is the one marked as the Intervention (otherwise the first Independent Variable). It uses the rows where both the outcome and the grouping variable are present and orders the groups by code, so group 1 is the lower code and the mean difference is lower code − higher code (example data: CAPD − APD). It checks three assumptions: the size of each group (30 or more is treated as enough by the central limit theorem), the Shapiro-Wilk test in each group (Shapiro & Wilk, 1965) and Levene's test centred on the median (Levene, 1960; Brown & Forsythe, 1974). Rule: when Levene's p < 0.05 DAPH reports Welch's t-test (second formula: t, the Welch-Satterthwaite df, which need not be a whole number, p and the 95% CI from the unpooled SE); when p ≥ 0.05 it reports Student's t-test (first formula). The note under the table, the summary and the Word report name the test used, for example "Welch's t = −1.977, df = 1291.8". Cohen's d uses the pooled SD and is shown as an absolute value; read the direction from the mean difference. DAPH labels |d| < 0.2 negligible, 0.2 to below 0.5 small, 0.5 to below 0.8 medium and 0.8 or more large (Cohen, 1988). The p-value is two-sided.
สิ่งที่ DAPH ทำใน Paired t-test · Dependent Variable คือค่าหลัง (Post-test) และ Matching Variable คือค่าก่อน (Pre-test) ซึ่งต้องเป็นตัวแปรตัวเลข ผลต่างของแต่ละคน = Dependent − Matching (หลัง − ก่อน) ใช้เฉพาะคนที่มีค่าครบทั้งสองตัว · ตรวจจำนวนคู่ (อย่างน้อย 30 คู่) และ Shapiro-Wilk ของผลต่าง · หน้าสรุปแสดง t(df), p, ผลต่างเฉลี่ย และ dz · Cohen's dz = |ผลต่างเฉลี่ย| ÷ ส่วนเบี่ยงเบนมาตรฐานของผลต่าง ใช้เกณฑ์เดียวกับ d
What DAPH does in the paired t-test. The Dependent Variable is the post-test value and the Matching Variable is the pre-test value, which must be numeric. Each person's difference is Dependent − Matching (post − pre), using only people with both values. DAPH checks the number of pairs (30 or more) and the Shapiro-Wilk test of the differences, and the summary shows t(df), p, the mean difference and dz. Cohen's dz = |mean difference| ÷ SD of the differences, read with the same labels as d.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
library(car)
# n, mean and SD per group (the Tab 3 table)
aggregate(qolscore3 ~ group, data = d, FUN = function(x) c(n = length(x), mean = mean(x), sd = sd(x)))
# assumption checks that DAPH prints: Shapiro-Wilk per group, Levene's test centred on the median
sapply(split(d$qolscore3, d$group), function(x) shapiro.test(x)$statistic)
leveneTest(qolscore3 ~ group, data = d)
# Welch's t-test: what DAPH reports when Levene's p < 0.05 (here p = 0.040)
t.test(qolscore3 ~ group, data = d, var.equal = FALSE)
# Cohen's d on the pooled SD (DAPH shows its absolute value)
m <- tapply(d$qolscore3, d$group, mean); s <- tapply(d$qolscore3, d$group, sd); n <- table(d$group)
sp <- sqrt(((n[1] - 1) * s[1]^2 + (n[2] - 1) * s[2]^2) / (sum(n) - 2))
c(diff = unname(m[1] - m[2]), d = unname((m[1] - m[2]) / sp))
# Levene's p >= 0.05 gives Student's t-test (pooled variance): Employment Status
d$occupation <- factor(d$occupation, 1:2, c("Employed", "Unemployed"))
leveneTest(qolscore3 ~ occupation, data = d)
t.test(qolscore3 ~ occupation, data = d, var.equal = TRUE)
# the same comparison before treatment: Quality of Life Score (Pre)
t.test(qolscore1 ~ group, data = d, var.equal = FALSE)
# group qolscore3.n qolscore3.mean qolscore3.sd
# 1 CAPD 656.00000 74.88643 17.37379
# 2 APD 644.00000 76.84239 18.27674
# CAPD.W APD.W
# 0.9747622 0.9715946
# Levene's Test (center = median): F value 4.2336, Pr(>F) 0.03983 (Df 1, 1298)
# Welch Two Sample t-test: t = -1.977, df = 1291.8, p-value = 0.04825
# 95 percent confidence interval: -3.89688314 -0.01503361
# diff d
# -1.9559584 -0.1097201
# Levene's Test (center = median), occupation: F value 0.6146, Pr(>F) 0.4332
# Two Sample t-test (occupation): t = 5.0785, df = 1298, p-value = 4.359e-07
# 95 percent confidence interval: 3.197574 7.222939
# mean in group Employed 77.69501, mean in group Unemployed 72.48475
# qolscore1 by group (Welch): t = -1.968, df = 1291.8, p-value = 0.04929
# 95 percent confidence interval: -3.887683357 -0.006082739
# mean in group CAPD 67.39939, mean in group APD 69.34627
# Paired t-test: Quality of Life Score (Post) minus (Pre) in the same patients
c(pre_mean = mean(d$qolscore1), pre_sd = sd(d$qolscore1), post_mean = mean(d$qolscore3), post_sd = sd(d$qolscore3))
t.test(d$qolscore3, d$qolscore1, paired = TRUE)
dif <- d$qolscore3 - d$qolscore1
c(mean = mean(dif), sd = sd(dif), dz = mean(dif) / sd(dif))
shapiro.test(dif)
table(dif) # change per patient: almost everyone rose by exactly 7.5 points
# pre_mean pre_sd post_mean post_sd
# 68.36385 17.84539 75.85538 17.84678
# Paired t-test: t = 581.37, df = 1299, p-value < 2.2e-16
# 95 percent confidence interval: 7.466259 7.516818
# mean difference 7.491538
# mean sd dz
# 7.4915385 0.4646113 16.1243131
# Shapiro-Wilk normality test: W = 0.043651, p-value < 2.2e-16
# dif: -4 1 4 7.5 8 9 10 16
# 1 1 2 1290 3 1 1 1
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| CAPD: n / mean / SD | 656 / 74.88643 / 17.37379 | 656 / 74.88643 / 17.37379 | < 1e−5 | ✓ PASS |
| APD: n / mean / SD | 644 / 76.84239 / 18.27674 | 644 / 76.84239 / 18.27674 | < 1e−5 | ✓ PASS |
| Shapiro-Wilk W: CAPD / APD | 0.97476 / 0.97159 | 0.9748 / 0.9716 | < 5e−5 | ✓ PASS |
| Levene's test แบบใช้มัธยฐาน: F / pLevene's test centred on the median: F / p | 4.2336 / 0.03983 | 4.234 / 0.040 | < 0.0005 | ✓ PASS |
| ผลต่างค่าเฉลี่ย CAPD − APDMean difference CAPD − APD | −1.95596 | −1.95596 | < 1e−5 | ✓ PASS |
| การทดสอบที่รายงาน (Levene p < 0.05) · Welch's tTest reported (Levene's p < 0.05) · Welch's t | Welch · −1.97700 | Welch · −1.97700 | < 1e−10 | ✓ PASS |
| Welch's df | 1291.8 | 1291.8364 | < 1e−6 | ✓ PASS |
| Welch's p | 0.04825 | 0.048254 | < 1e−10 | ✓ PASS |
| Welch's 95% CI | −3.89688 to −0.01503 | −3.89688 to −0.01503 | < 5e−6 | ✓ PASS |
| Employment Status: Levene F / p (≥ 0.05 จึงรายงาน Student's t)Employment Status: Levene F / p (≥ 0.05, so Student's t is reported) | 0.6146 / 0.4332 | 0.615 / 0.433 | < 0.0005 | ✓ PASS |
| Employment Status: Student's t / df / pEmployment Status: Student's t / df / p | 5.0785 / 1298 / 4.359e−07 | 5.07852 / 1298 / 4.3586e−07 | < 1e−10 | ✓ PASS |
| Employment Status: ผลต่าง Employed − Unemployed (95% CI)Employment Status: difference Employed − Unemployed (95% CI) | 5.21026 (3.19757 to 7.22294) | 5.21026 (3.19757 to 7.22294) | < 5e−6 | ✓ PASS |
| Cohen's d (DAPH แสดงค่าสัมบูรณ์)Cohen's d (DAPH shows the absolute value) | −0.10972 | 0.10972 | < 1e−10 (|d|) | ✓ PASS |
| Paired: จำนวนคู่ · Pre mean (SD) · Post mean (SD)Paired: pairs · pre mean (SD) · post mean (SD) | 1300 · 68.36385 (17.84539) · 75.85538 (17.84678) | 1300 · 68.36385 (17.84539) · 75.85538 (17.84678) | < 1e−5 | ✓ PASS |
| Paired: ผลต่างเฉลี่ย (95% CI)Paired: mean difference (95% CI) | 7.49154 (7.46626 to 7.51682) | 7.49154 (7.46626 to 7.51682) | < 1e−5 | ✓ PASS |
| Paired: t / df | 581.37 / 1299 | 581.3704 / 1299 | < 1e−6 | ✓ PASS |
| Paired: SD ของผลต่าง / dzPaired: SD of the differences / dz | 0.46461 / 16.124 | 0.46461 / 16.124 | < 5e−6 / < 1e−6 | ✓ PASS |
| Paired: Shapiro-Wilk W ของผลต่างPaired: Shapiro-Wilk W of the differences | 0.043651 | 0.0437 | < 5e−5 | ✓ PASS |
Levene p = 0.040 (น้อยกว่า 0.05) DAPH จึงรายงาน Welch's t-test หมายเหตุใต้ตารางเขียนว่า "Welch's t = −1.977, df = 1291.8" และค่า t, df, p และ 95% CI ตรงกับ t.test(..., var.equal = FALSE) · กรณี Levene p ≥ 0.05 ตรวจด้วยตัวแปร Employment Status (Levene p = 0.433) ซึ่ง DAPH รายงาน Student's t-test ("Student's t = 5.079, df = 1298") ตรงกับ t.test(..., var.equal = TRUE)
Levene's p = 0.040 (below 0.05), so DAPH reports Welch's t-test: the note under the table reads "Welch's t = −1.977, df = 1291.8", and t, df, p and the 95% CI match t.test(..., var.equal = FALSE). The branch for Levene's p ≥ 0.05 is checked on Employment Status (Levene's p = 0.433), where DAPH reports Student's t-test ("Student's t = 5.079, df = 1298"), matching t.test(..., var.equal = TRUE).
4การแปลผลและตัวอย่างInterpretation and Example
คำถามที่ 1: คะแนนคุณภาพชีวิตหลังการรักษาเฉลี่ยของกลุ่ม CAPD เท่ากับ 74.89 (SD 17.37) และกลุ่ม APD เท่ากับ 76.84 (SD 18.28) ผลต่าง CAPD − APD = −1.96 คะแนน (95% CI −3.90 ถึง −0.02) Welch's t(1291.8) = −1.98, p = 0.048 · ความต่างมีนัยสำคัญที่ระดับ 0.05 แบบเฉียดฉิว ช่วงเชื่อมั่นเกือบแตะ 0 และ Cohen's d = −0.11 อยู่ในระดับเล็กมาก (negligible) คือ 2 คะแนนบนมาตรวัดที่ส่วนเบี่ยงเบนมาตรฐานประมาณ 18 คะแนน จึงมีความหมายในทางปฏิบัติน้อย · ข้อตกลงเบื้องต้น: Shapiro-Wilk ไม่ผ่านทั้งสองกลุ่ม (p < 0.001) แต่แต่ละกลุ่มมีมากกว่า 600 ราย t-test จึงยังใช้ได้ตามทฤษฎีบทขีดจำกัดกลาง · Levene p = 0.040 ความแปรปรวนต่างกันเล็กน้อย จึงควรใช้ Welch's t-test · ข้อจำกัด: ข้อมูลนี้เป็นการศึกษาเชิงสังเกต ไม่ได้สุ่มวิธีการรักษา ผลจึงบอกความสัมพันธ์ ไม่ใช่ผลของวิธีการรักษา และผลต่างขนาดเดียวกันมีอยู่แล้วก่อนการรักษา (Quality of Life Score (Pre): CAPD 67.40 กับ APD 69.35, Welch p = 0.049) ความต่างหลังการรักษาจึงสะท้อนความต่างของผู้ป่วยที่เลือกแต่ละวิธีตั้งแต่ต้น ถ้าต้องการเทียบหลังการรักษาโดยปรับคะแนนก่อนการรักษา ให้ใช้ ANCOVA (หัวข้อ 1.4)
Question 1: the mean post-treatment quality-of-life score was 74.89 (SD 17.37) in CAPD and 76.84 (SD 18.28) in APD patients; the difference CAPD − APD was −1.96 points (95% CI −3.90 to −0.02), Welch's t(1291.8) = −1.98, p = 0.048. The difference is only just significant at the 0.05 level, its interval nearly reaches 0, and Cohen's d = −0.11 is negligible: 2 points on a scale whose SD is about 18 points, so it has little practical meaning. Assumptions: the Shapiro-Wilk test rejects normality in both groups (p < 0.001), but each group has more than 600 patients, so the t-test remains valid by the central limit theorem; Levene's p = 0.040 shows slightly unequal variances, so Welch's t-test is the appropriate one. Limitations: these are observational data, the treatment was not randomised, so the result is an association, not an effect of the dialysis mode. A difference of the same size already existed before treatment (Quality of Life Score (Pre): CAPD 67.40 vs APD 69.35, Welch p = 0.049), so the post-treatment difference reflects who received each mode from the start. To compare the post-treatment scores adjusted for the pre-treatment score, use ANCOVA (section 1.4).
คำถามที่ 2: คะแนนหลังการรักษาสูงกว่าก่อนการรักษาเฉลี่ย 7.49 คะแนน (95% CI 7.47 ถึง 7.52) t(1299) = 581.37, p < 0.001, Cohen's dz = 16.12 · ค่า t และ dz สูงผิดปกติเพราะในข้อมูลตัวอย่างนี้ผู้ป่วย 1,290 จาก 1,300 รายมีคะแนนเพิ่มขึ้น 7.5 คะแนนเท่ากันพอดี ส่วนเบี่ยงเบนมาตรฐานของผลต่างจึงมีเพียง 0.46 คะแนน (Paired t-test หารผลต่างเฉลี่ยด้วยความแปรผันของผลต่าง ไม่ใช่ความแปรผันของคะแนน) ข้อมูลจริงมักมีผลต่างที่แปรผันมากกว่านี้มาก · Shapiro-Wilk ของผลต่าง W = 0.044 (p < 0.001) ไม่ผ่าน แต่มี 1,300 คู่ DAPH จึงแจ้งว่ายังใช้ได้ · ข้อจำกัด: การเปรียบเทียบก่อน-หลังโดยไม่มีกลุ่มเปรียบเทียบ บอกได้ว่าคะแนนเปลี่ยนไป แต่บอกไม่ได้ว่าการรักษาเป็นสาเหตุ เพราะคะแนนอาจเปลี่ยนตามเวลา หรือจากการถดถอยเข้าหาค่าเฉลี่ย (regression to the mean) · ถ้าผลไม่มีนัยสำคัญ ให้เขียนว่า "ไม่พบความแตกต่างอย่างมีนัยสำคัญ" พร้อมช่วงเชื่อมั่น ไม่ใช่ "ไม่แตกต่างกัน"
Question 2: scores were on average 7.49 points higher after treatment than before (95% CI 7.47 to 7.52), t(1299) = 581.37, p < 0.001, Cohen's dz = 16.12. The t and dz are unusually large because in this example dataset 1,290 of the 1,300 patients rose by exactly 7.5 points, so the SD of the differences is only 0.46 points (the paired t-test divides the mean difference by the variability of the differences, not of the scores); real data usually vary far more. The Shapiro-Wilk test of the differences fails (W = 0.044, p < 0.001), but with 1,300 pairs DAPH reports that the test is still reasonable. Limitations: a before-after comparison without a comparison group shows that the score changed, not that the treatment caused the change; scores can drift over time or regress toward the mean. When a result is not significant, write "no statistically significant difference" with its confidence interval, never "no difference".
📖 References
- Brown, M. B., & Forsythe, A. B. (1974). Robust tests for the equality of variances. Journal of the American Statistical Association, 69(346), 364–367. doi:10.1080/01621459.1974.10482955
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
- Levene, H. (1960). Robust tests for equality of variances. In I. Olkin (Ed.), Contributions to probability and statistics (pp. 278–292). Stanford University Press.
- Shapiro, S. S., & Wilk, M. B. (1965). An analysis of variance test for normality (complete samples). Biometrika, 52(3–4), 591–611. doi:10.1093/biomet/52.3-4.591
- Student [Gosset, W. S.]. (1908). The probable error of a mean. Biometrika, 6(1), 1–25. doi:10.1093/biomet/6.1.1
- Welch, B. L. (1947). The generalization of "Student's" problem when several different population variances are involved. Biometrika, 34(1-2), 28–35. doi:10.1093/biomet/34.1-2.28
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
1.2One-way ANOVA
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
One-way ANOVA (การวิเคราะห์ความแปรปรวนทางเดียว) เปรียบเทียบค่าเฉลี่ยของตัวแปรผลลัพธ์ที่เป็นตัวเลขต่อเนื่องระหว่างกลุ่มของตัวแปรกลุ่มหนึ่งตัว โดยทดสอบ H₀: μ₁ = μ₂ = … = μ_k (ทุกกลุ่มมีค่าเฉลี่ยเท่ากัน) มักใช้กับ 3 กลุ่มขึ้นไป (ถ้ามี 2 กลุ่ม F เท่ากับ t² ของ Student's t-test ในหัวข้อ 1.1) · ถ้าการทดสอบรวมมีนัยสำคัญ จะเปรียบเทียบทีละคู่ (post hoc) เพื่อบอกว่าคู่ใดต่างกัน DAPH เลือกวิธี post hoc ให้อัตโนมัติจากข้อมูล หรือให้ผู้ใช้เลือกเอง (ส่วนที่ 2) · R. A. Fisher เป็นผู้พัฒนาการวิเคราะห์ความแปรปรวน (Fisher, 1925)
One-way ANOVA (analysis of variance) compares the mean of a continuous outcome across the groups of one categorical variable, testing H₀: μ₁ = μ₂ = … = μ_k (all group means are equal). It is usually used for 3 or more groups (with 2 groups F equals t² of Student's t-test, section 1.1). When the overall test is significant, pairs of groups are compared (post hoc tests) to show which pairs differ; DAPH chooses the post hoc method from the data or lets you choose it (part 2). R. A. Fisher developed the analysis of variance (Fisher, 1925).
ใช้เมื่อ กลุ่มเป็นคนละคนกัน ผลลัพธ์เป็นตัวเลขต่อเนื่อง และข้อมูลแต่ละกลุ่มใกล้เคียงการแจกแจงปกติหรือมีกลุ่มละประมาณ 30 รายขึ้นไป · ไม่ควรใช้เมื่อ มีตัวแปรกลุ่มสองตัวพร้อมกัน (ใช้ Two-way ANOVA หัวข้อ 1.3) ต้องการปรับตัวแปรต่อเนื่องอื่น (ใช้ ANCOVA หัวข้อ 1.4) วัดซ้ำในคนเดียวกัน (ใช้ Repeated-Measures ANOVA หัวข้อ 1.5) หรือกลุ่มเล็กและข้อมูลเบ้มาก (ใช้ Kruskal-Wallis H test หัวข้อ 1.10)
Use it when the groups contain different people, the outcome is continuous, and each group is roughly normal or has about 30 or more observations. Do not use it for two grouping variables at once (use Two-way ANOVA, section 1.3), to adjust for a continuous covariate (use ANCOVA, section 1.4), for repeated measurements on the same people (use Repeated-Measures ANOVA, section 1.5), or for small, very skewed groups (use the Kruskal-Wallis H test, section 1.10).
qolscore3) ต่างกันตามรายได้ครัวเรือนหรือไม่ (Household Income, fam_income: 1 = < 10,000 บาท/เดือน 380 ราย, 2 = 10,000-30,000 บาท/เดือน 338 ราย, 3 = > 30,000 บาท/เดือน 582 ราย) ถ้าต่าง คู่ใดต่างกัน · คำถามที่สอง (ความแปรปรวนไม่เท่ากัน): คะแนนเดียวกันต่างกันระหว่าง 10 อำเภอหรือไม่ (District, amp) · ผลอยู่ในส่วนที่ 3 และการแปลผลในส่วนที่ 4qolscore3) differ by household income (Household Income, fam_income: 1 = < 10,000 Baht/month, 380 patients; 2 = 10,000-30,000, 338; 3 = > 30,000, 582), and if so, which pairs differ? Second question (unequal variances): does the same score differ between the 10 districts (District, amp)? The results are in part 3 and their interpretation in part 4.2หลักการและสูตรLogic and Formula
- k, N, n_j
- จำนวนกลุ่ม, จำนวนทั้งหมด, จำนวนในกลุ่ม jnumber of groups, total size, size of group j
- x̄_j, x̄, s_j
- ค่าเฉลี่ยของกลุ่ม j, ค่าเฉลี่ยรวม, ส่วนเบี่ยงเบนมาตรฐานของกลุ่ม jmean of group j, grand mean, standard deviation of group j
- SS_B, SS_W, MS_W
- ผลรวมกำลังสองระหว่างกลุ่ม, ภายในกลุ่ม, และค่าเฉลี่ยกำลังสองภายในกลุ่ม (ความแปรปรวนร่วม)between-group and within-group sums of squares, and the within-group mean square (pooled variance)
- F′(λ)
- การแจกแจง F แบบ noncentral ที่มีพารามิเตอร์ λ (Steiger, 2004) · ขอบเขตเป็น 0 เมื่อ F ต่ำกว่าควอนไทล์ของ F ปกติnoncentral F distribution with noncentrality λ (Steiger, 2004); a bound is 0 when F is below the matching quantile of the central F
- x̃_j, z_ij
- มัธยฐานของกลุ่ม j และระยะห่างของแต่ละค่าจากมัธยฐานนั้นmedian of group j and each value's absolute distance from it
- Q_k,df
- การแจกแจง studentized range (พิสัยของค่าเฉลี่ย k กลุ่มหารด้วยความคลาดเคลื่อนมาตรฐาน)studentized range distribution (range of k means divided by their standard error)
- m, p_(s)
- จำนวนคู่ที่เปรียบเทียบ และค่า p ที่ยังไม่ปรับเรียงจากน้อยไปมาก (ใช้กับ Holm)number of pairs compared, and the unadjusted p-values sorted from smallest (used by Holm)
- T_1 … T_k−1, c_0.95
- ค่า t ของทุกกลุ่มที่เทียบกับกลุ่มอ้างอิง ซึ่งสัมพันธ์กันเพราะใช้กลุ่มอ้างอิงร่วมกัน (df = N − k) และค่าวิกฤตที่ทำให้ P(max|T| ≤ c) = 0.95 · DAPH คำนวณความน่าจะเป็นร่วมนี้แบบแม่นตรง ไม่ใช้การสุ่มจำลองthe t values of all groups versus the reference, correlated because they share the reference group (df = N − k), and the critical value with P(max|T| ≤ c) = 0.95; DAPH computes this joint probability exactly, not by simulation
ขั้นตอนที่ DAPH ทำ · (1) ใช้เฉพาะแถวที่มีค่าครบทั้งตัวแปรตามและตัวแปรกลุ่ม เรียงกลุ่มตามรหัส ทุกกลุ่มต้องมีอย่างน้อย 2 ค่า · (2) ตรวจข้อตกลงเบื้องต้น: จำนวนต่อกลุ่ม (อย่างน้อย 20 ถือว่าเพียงพอ), Shapiro-Wilk ในแต่ละกลุ่ม (Shapiro & Wilk, 1965) และ Levene's test แบบใช้มัธยฐานเป็นจุดกลาง (Levene, 1960; Brown & Forsythe, 1974) ซึ่งทนต่อข้อมูลเบ้ · ถ้าบางกลุ่มไม่ปกติแต่ทุกกลุ่มมีอย่างน้อย 30 ค่า ระบบแจ้งว่าการทดสอบ F ยังใช้ได้ ถ้ามีกลุ่มที่น้อยกว่า 30 ค่า ระบบแนะนำ Kruskal-Wallis (หัวข้อ 1.10) · (3) ถ้า Levene p ≥ 0.05 รายงาน F แบบเดิม ถ้า Levene p < 0.05 รายงาน Welch's ANOVA (Welch, 1951) แทน แถว "ผลการทดสอบ" ใน Tab 3 และ Word จะเขียน Welch's F(df1, df2) โดย df2 เป็นทศนิยม และหน้าสรุปแสดง F แบบเดิมไว้อ้างอิง · (4) ขนาดอิทธิพล η² คำนวณจากผลรวมกำลังสองของ ANOVA แบบเดิมเสมอ (Welch's ANOVA ไม่ได้แยกผลรวมกำลังสอง) เกณฑ์ < 0.01 เล็กมาก (negligible), 0.01 ถึงน้อยกว่า 0.06 เล็ก, 0.06 ถึงน้อยกว่า 0.14 ปานกลาง, ตั้งแต่ 0.14 ใหญ่ (Cohen, 1988) · รายงาน Word เพิ่มช่วงเชื่อมั่น 95% ของ η² จากการผกผันการแจกแจง F แบบ noncentral ของ F แบบเดิม (Steiger, 2004) ขอบเขต = λ/(λ + df₂) แบบเดียวกับแพ็กเกจ effectsize ของ R · ω² คำนวณภายในแต่ไม่แสดงในรายงาน
The DAPH procedure. (1) It uses the rows with both the outcome and the grouping variable present, orders the groups by code, and needs at least 2 values in every group. (2) It checks the assumptions: the size of each group (20 or more is treated as enough), the Shapiro-Wilk test in each group (Shapiro & Wilk, 1965) and Levene's test centred on the median (Levene, 1960; Brown & Forsythe, 1974), which is robust to skewed data. If some groups are not normal but every group has at least 30 values, DAPH reports that the F test remains reasonable; with a group below 30 it suggests the Kruskal-Wallis test (section 1.10). (3) With Levene's p ≥ 0.05 it reports the ordinary F; with Levene's p < 0.05 it reports Welch's ANOVA (Welch, 1951) instead: the "Test Results" row in Tab 3 and Word then reads Welch's F(df1, df2) with a decimal df2, and the summary page shows the ordinary F for reference. (4) The effect size η² always comes from the sums of squares of the ordinary ANOVA (Welch's ANOVA does not split the sums of squares), labelled < 0.01 negligible, 0.01 to below 0.06 small, 0.06 to below 0.14 medium and 0.14 or more large (Cohen, 1988). The Word report adds the 95% CI of η² by inverting the noncentral F of the ordinary F test (Steiger, 2004), with bounds λ/(λ + df₂) as in the R package effectsize. ω² is computed internally but not shown.
Post hoc ใน DAPH (ช่อง "Post Hoc ⓘ" ใน Tab 2 ติ๊กไว้ตั้งแต่แรก และดรอปดาวน์ตั้งไว้ที่ "อัตโนมัติ (แนะนำ)"): เมื่อเปรียบเทียบหลายคู่พร้อมกัน โอกาสพบ "ความต่าง" โดยบังเอิญจะสูงขึ้น เช่น ถ้าทดสอบ 3 คู่ที่เป็นอิสระต่อกันที่ระดับ 0.05 โอกาสสรุปผิดอย่างน้อยหนึ่งคู่เท่ากับ 1 − 0.95³ ≈ 14% วิธี post hoc จึงปรับค่า p และช่วงเชื่อมั่นให้โอกาสนี้รวมทุกคู่ไม่เกิน 5% · DAPH ทำ post hoc เมื่อการทดสอบรวมมีนัยสำคัญ (p < 0.05 โดยใช้ค่า p ของ Welch's ANOVA เมื่อรายงาน Welch) ถ้าไม่มีนัยสำคัญ ระบบไม่ทำและเขียนเหตุผลไว้ · ตัวแปรที่มี 2 กลุ่มได้คู่เดียว ไม่ต้องปรับค่า p · กฎการเลือกอัตโนมัติ: (1) Levene p < 0.05 ใช้ Games-Howell (Games & Howell, 1976) ซึ่งคิดความคลาดเคลื่อนของแต่ละคู่จากความแปรปรวนของสองกลุ่มนั้นเอง (2) Levene p ≥ 0.05 และทุกกลุ่มมีจำนวนเท่ากัน ใช้ Tukey HSD (honestly significant difference; Tukey, 1949) (3) Levene p ≥ 0.05 แต่จำนวนในแต่ละกลุ่มไม่เท่ากัน ใช้ Tukey-Kramer (Kramer, 1956) ซึ่งเป็นสูตรเดียวกับ Tukey HSD ที่ใช้จำนวนของแต่ละคู่ · ข้อมูลตัวอย่าง: รายได้ครัวเรือน Levene p = 0.943 และกลุ่มมี 380, 338, 582 ราย ระบบจึงเลือก Tukey-Kramer · อำเภอ Levene p < 0.001 ระบบจึงเลือก Games-Howell · เหตุผลของการเลือกเขียนไว้ในหน้าผลลัพธ์และรายงาน Word
Post hoc in DAPH (the "Post Hoc ⓘ" box in Tab 2 is ticked from the start and its dropdown is set to "Automatic (recommended)"): comparing many pairs raises the chance of finding a "difference" by luck; with 3 independent tests at the 0.05 level the chance of at least one false conclusion would be 1 − 0.95³ ≈ 14%, so post hoc methods adjust the p-values and confidence intervals to keep that chance at 5% or less over all pairs. DAPH runs post hoc tests when the overall test is significant (p < 0.05, using Welch's p when Welch's ANOVA is reported); otherwise it does not run them and says why. A variable with 2 groups gives a single pair, so no adjustment is needed. Automatic rule: (1) Levene's p < 0.05 gives Games-Howell (Games & Howell, 1976), which takes each pair's standard error from the variances of those two groups; (2) Levene's p ≥ 0.05 with equal group sizes gives Tukey HSD (honestly significant difference; Tukey, 1949); (3) Levene's p ≥ 0.05 with unequal sizes gives Tukey-Kramer (Kramer, 1956), the same formula using the sizes of each pair. Example data: household income has Levene's p = 0.943 and groups of 380, 338 and 582, so DAPH chooses Tukey-Kramer; district has Levene's p < 0.001, so DAPH chooses Games-Howell. The reason is written on the results page and in the Word report.
เลือกวิธีเองจากดรอปดาวน์ เมื่อมีเหตุผลเฉพาะ: Tukey เปรียบเทียบครบทุกคู่บนความแปรปรวนร่วม (ระบบตั้งชื่อ Tukey HSD หรือ Tukey-Kramer ตามขนาดกลุ่มให้เอง) · Games-Howell เมื่อทราบอยู่แล้วว่าความแปรปรวนต่างกันแม้ Levene ไม่มีนัยสำคัญ เช่น กลุ่มเล็กมากจน Levene ตรวจไม่พบ · Bonferroni (Dunn, 1961) คูณค่า p ด้วยจำนวนคู่ เข้าใจง่ายแต่เข้มเกินไปเมื่อมีหลายคู่ · Holm (Holm, 1979) ควบคุมโอกาสสรุปผิดได้เท่า Bonferroni แต่พบความต่างที่มีจริงได้มากกว่าหรือเท่ากันเสมอ (Holm ไม่มีช่วงเชื่อมั่นของตัวเอง DAPH จึงแสดงช่วงเชื่อมั่นระดับ Bonferroni) · Šidák (Šidák, 1967) หลวมกว่า Bonferroni เล็กน้อย · Scheffé (Scheffé, 1953) เข้มที่สุด เหมาะเมื่อจะเปรียบเทียบแบบซับซ้อนกว่าทีละคู่ เช่น ค่าเฉลี่ยของสองกลุ่มรวมกันเทียบกับกลุ่มที่สาม · Fisher's LSD (least significant difference; Fisher, 1935) ไม่ปรับค่า p เลย ควบคุมโอกาสสรุปผิดรวมได้เฉพาะเมื่อมี 3 กลุ่มพอดีและการทดสอบรวมมีนัยสำคัญแล้ว (Hayter, 1986) · Dunnett (Dunnett, 1955) เทียบทุกกลุ่มกับกลุ่มอ้างอิงกลุ่มเดียว เช่น กลุ่มควบคุม เลือกกลุ่มอ้างอิงในดรอปดาวน์ที่สองที่ปรากฏขึ้น (ถ้าไม่เลือก ใช้กลุ่มรหัสน้อยสุด) เทียบน้อยคู่กว่าจึงมีกำลังมากกว่าการเทียบทุกคู่ · ถ้าไม่ต้องการเปรียบเทียบรายคู่ ให้เอาเครื่องหมายถูกที่ช่อง Post Hoc ออก
Choosing a method yourself when there is a specific reason: Tukey compares every pair on the pooled variance (DAPH names it Tukey HSD or Tukey-Kramer from the group sizes); Games-Howell when you already know the variances differ although Levene's test is not significant, for example with very small groups; Bonferroni (Dunn, 1961) multiplies each p-value by the number of pairs, simple but too strict with many pairs; Holm (Holm, 1979) controls the chance of a false conclusion as Bonferroni does but always finds at least as many real differences (Holm has no interval of its own, so DAPH shows the Bonferroni-level interval); Šidák (Šidák, 1967) is slightly less strict than Bonferroni; Scheffé (Scheffé, 1953) is the strictest and suits comparisons more complex than pairs, such as two groups together versus a third; Fisher's LSD (least significant difference; Fisher, 1935) does not adjust at all and controls the overall chance of a false conclusion only with exactly 3 groups after a significant overall test (Hayter, 1986); Dunnett (Dunnett, 1955) compares every group with one reference group, such as a control, chosen in the second dropdown that appears (the lowest code if none is chosen); fewer comparisons give it more power than comparing all pairs. To skip pairwise comparisons, untick the Post Hoc box.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
# Household Income: 1 = < 10,000, 2 = 10,000-30,000, 3 = > 30,000 Baht/month
d$fam_income <- factor(d$fam_income, 1:3, c("Low", "Middle", "High"))
library(car)
aggregate(qolscore3 ~ fam_income, data = d, FUN = function(x) c(n = length(x), mean = mean(x), sd = sd(x)))
fit <- aov(qolscore3 ~ fam_income, data = d)
summary(fit)
tab <- summary(fit)[[1]]; tab[1, "F value"]; tab[1, "Pr(>F)"]
ssb <- tab[1, 2]; ssw <- tab[2, 2]; msw <- tab[2, 3]
c(eta2 = ssb / (ssb + ssw), omega2 = (ssb - tab[1, 1] * msw) / (ssb + ssw + msw))
# 95% CI of eta2 (Word report): invert the noncentral F, bound = ncp / (ncp + df2)
bound <- function(F, d1, d2, p) { if (pf(F, d1, d2) <= p) return(0)
uniroot(function(x) pf(F, d1, d2, x) - p, c(0, 10 * F * d1 + 100), tol = 1e-12)$root }
lo <- bound(tab[1, 4], 2, 1297, 0.975); hi <- bound(tab[1, 4], 2, 1297, 0.025)
c(lower = lo / (lo + 1297), upper = hi / (hi + 1297))
# assumption checks behind the automatic choice
leveneTest(qolscore3 ~ fam_income, data = d) # centre = median
sapply(split(d$qolscore3, d$fam_income), function(x) shapiro.test(x)$statistic)
# fam_income qolscore3.n qolscore3.mean qolscore3.sd
# 1 Low 380.00000 79.36842 17.60756
# 2 Middle 338.00000 75.69379 17.61440
# 3 High 582.00000 73.65550 17.80397
# [1] 11.99721 (F, df 2 and 1297)
# [1] 6.875246e-06 (p)
# eta2 omega2
# 0.0181639 0.0166373
# lower upper
# 0.00597934 0.03422676
# Levene's Test (center = median): F value 0.0591, Pr(>F) 0.9426
# Low.W Middle.W High.W
# 0.9584394 0.9763782 0.9790997
library(emmeans); library(multcomp)
emm <- emmeans(fit, ~ fam_income)
# "tukey" = Tukey-Kramer here (unequal n), "none" = Fisher's LSD; Holm CIs are at the Bonferroni level
for (adj in c("tukey", "bonferroni", "holm", "sidak", "scheffe", "none")) {
s <- summary(pairs(emm, adjust = adj), infer = TRUE)
cat("--", adj, "\n")
print(data.frame(pair = s$contrast, diff = s$estimate, SE = s$SE, lower = s$lower.CL, upper = s$upper.CL,
t = s$t.ratio, p = s$p.value), digits = 7)
}
# Games-Howell: each pair's own variances, Welch df, studentized range
gh <- function(y, g) {
lv <- levels(g); k <- length(lv); m <- tapply(y, g, mean); v <- tapply(y, g, var); n <- tapply(y, g, length)
out <- NULL
for (i in 1:(k - 1)) for (j in (i + 1):k) {
a <- v[i] / n[i]; b <- v[j] / n[j]; se <- sqrt(a + b)
df <- (a + b)^2 / (a^2 / (n[i] - 1) + b^2 / (n[j] - 1)); dif <- m[i] - m[j]
q <- sqrt(2) * abs(dif) / se; h <- qtukey(0.95, k, df) / sqrt(2) * se
out <- rbind(out, data.frame(pair = paste(lv[i], "-", lv[j]), diff = dif, SE = se, df = df,
lower = dif - h, upper = dif + h, q = q, p = ptukey(q, k, df, lower.tail = FALSE)))
}
out
}
gh(d$qolscore3, d$fam_income)
# Dunnett: every group against the reference Low (the first group, DAPH's default)
g <- glht(fit, linfct = mcp(fam_income = "Dunnett"))
summary(g)$test$pvalues
set.seed(1); confint(g)$confint
# Hedges' g of each pair (pooled SD of the two groups, small-sample correction)
hg <- function(x, y) { nx <- length(x); ny <- length(y)
sp <- sqrt(((nx - 1) * var(x) + (ny - 1) * var(y)) / (nx + ny - 2))
(mean(x) - mean(y)) / sp * (1 - 3 / (4 * (nx + ny) - 9)) }
s <- split(d$qolscore3, d$fam_income)
c(LowMiddle = hg(s$Low, s$Middle), LowHigh = hg(s$Low, s$High), MiddleHigh = hg(s$Middle, s$High))
# -- tukey (Tukey-Kramer)
# pair diff SE lower upper t p
# 1 Low - Middle 3.674634 1.323202 0.5698745 6.779394 2.777078 1.535475e-02
# 2 Low - High 5.712923 1.167208 2.9741869 8.451659 4.894521 3.314807e-06
# 3 Middle - High 2.038289 1.210286 -0.8015258 4.878103 1.684138 2.116427e-01
# -- bonferroni p: 1.669191e-02 3.327588e-06 2.771868e-01 Low - Middle CI 0.5028011 to 6.846467
# -- holm p: 1.112794e-02 3.327588e-06 9.239561e-02 (CI as Bonferroni)
# -- sidak p: 1.659921e-02 3.327584e-06 2.523648e-01 Low - Middle CI 0.5110893 to 6.838179
# -- scheffe p: 2.139364e-02 7.004993e-06 2.425343e-01 Low - Middle CI 0.4320274 to 6.917241
# -- none (LSD) p: 5.563969e-03 1.109196e-06 9.239561e-02 Low - Middle CI 1.0787841 to 6.270484
# Games-Howell
# Low - Middle diff 3.674634 SE 1.316742 df 706.2092 0.5820539 to 6.767214 q 3.946649 p 1.491232e-02
# Low - High diff 5.712923 SE 1.166405 df 816.5431 2.9742164 to 8.451629 q 6.926664 p 3.489799e-06
# Middle - High diff 2.038289 SE 1.209377 df 710.4645 -0.8020913 to 4.878669 q 2.383522 p 2.114754e-01
# Dunnett p: [1] 1.060309e-02 2.212029e-06
# Estimate lwr upr
# Middle - Low -3.674634 -6.599659 -0.7496091
# High - Low -5.712923 -8.293113 -3.1327324
# LowMiddle LowHigh MiddleHigh
# 0.2084396 0.3220262 0.1148389
# District (10 districts): very different spreads between districts
d$amp <- factor(d$amp, 1:10, c("Kamalasai", "Kham Muang", "Khao Wong", "Khong Chai", "Kuchinarai",
"Mueang", "Na Mon", "Sahatsakhan", "Tha Khantho", "Yang Talat"))
leveneTest(qolscore3 ~ amp, data = d) # centre = median
oneway.test(qolscore3 ~ amp, data = d, var.equal = FALSE) # Welch's ANOVA
fit_a <- aov(qolscore3 ~ amp, data = d); summary(fit_a) # ordinary F, for reference
ta <- summary(fit_a)[[1]]; ta[1, 2] / sum(ta[, 2]) # eta2
lo <- bound(ta[1, 4], 9, 1290, 0.975); hi <- bound(ta[1, 4], 9, 1290, 0.025)
c(lower = lo / (lo + 1290), upper = hi / (hi + 1290)) # 95% CI of eta2, from the ordinary F
round(sort(tapply(d$qolscore3, d$amp, mean)), 2)
g_a <- gh(d$qolscore3, d$amp)
sum(g_a$p < 0.05) # pairs that differ, of 45
g_a[which.min(g_a$p), ]
g_a[g_a$pair == "Kuchinarai - Mueang", ]
# Two groups (Employment Status): the single pair has the same p as the F test
d$occupation <- factor(d$occupation, 1:2, c("Employed", "Unemployed"))
fit_o <- aov(qolscore3 ~ occupation, data = d); summary(fit_o)
summary(fit_o)[[1]][1, "Pr(>F)"]
s_o <- summary(pairs(emmeans(fit_o, ~ occupation)), infer = TRUE) # Tukey with one pair = no adjustment
print(data.frame(pair = s_o$contrast, diff = s_o$estimate, lower = s_o$lower.CL, upper = s_o$upper.CL, p = s_o$p.value), digits = 7)
# Levene's Test (center = median): F value 8.0684, Pr(>F) 1.044e-11 (Df 9, 1290)
# F = 10.014, num df = 9.00, denom df = 362.61, p-value = 9.095e-14
# amp 9 18925 2102.8 6.871 1.04e-09 (ordinary F, for reference)
# [1] 0.04574193
# lower upper
# 0.02097716 0.06385414
# Khong Chai Kuchinarai Kham Muang Yang Talat Khao Wong Na Mon
# 66.63 73.09 73.55 74.00 74.45 74.74
# Tha Khantho Kamalasai Mueang Sahatsakhan
# 75.73 78.50 79.04 85.06
# [1] 13
# Khong Chai - Sahatsakhan -18.42793 2.23199 138.999 -25.60549 -11.25037 11.67614 4.787726e-12
# Kuchinarai - Mueang -5.949621 1.671053 470.2419 -11.26191 -0.6373342 5.035168 0.01475565
# occupation 1 8061 8061 25.79 4.36e-07
# [1] 4.358639e-07
# 1 Employed - Unemployed 5.210256 3.197574 7.222939 4.358639e-07
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Household Income · n / mean / SD: < 10,000 · 10,000-30,000 · > 30,000 | 380 / 79.36842 / 17.60756 · 338 / 75.69379 / 17.61440 · 582 / 73.65550 / 17.80397 | 380 / 79.36842 / 17.60756 · 338 / 75.69379 / 17.61440 · 582 / 73.65550 / 17.80397 | < 1e−5 | ✓ PASS |
| F(2, 1297) / p | 11.99721 / 6.875246e−06 | 11.99721 / 6.875246e−06 | < 1e−5 | ✓ PASS |
| η² / ω² (ω² ค่าภายใน ไม่แสดงในรายงาน)(ω² internal, not shown) | 0.0181639 / 0.0166373 | 0.0181639 / 0.0166373 | < 1e−7 | ✓ PASS |
| 95% CI ของ η² (รายงาน Word)95% CI of η² (Word report) | 0.00598 to 0.03423 | 0.006 to 0.034 | < 0.0005 | ✓ PASS |
| Levene's test แบบใช้มัธยฐาน: F / pLevene's test centred on the median: F / p | 0.0591 / 0.9426 | 0.05912 / 0.94260 | < 5e−5 | ✓ PASS |
| Shapiro-Wilk W: < 10,000 · 10,000-30,000 · > 30,000 | 0.9584394 · 0.9763782 · 0.9790997 | 0.9584394 · 0.9763782 · 0.9790997 | < 1e−7 | ✓ PASS |
| วิธีที่เลือกอัตโนมัติ (Levene p ≥ 0.05, ขนาดกลุ่มไม่เท่ากัน)Automatic choice (Levene p ≥ 0.05, unequal group sizes) | Tukey-Kramer | Tukey-Kramer | — | ✓ PASS |
| Tukey-Kramer · ผลต่าง (95% CI)difference (95% CI): Low−Middle · Low−High · Middle−High | 3.674634 (0.569875 to 6.779394) · 5.712923 (2.974187 to 8.451659) · 2.038289 (−0.801526 to 4.878103) | 3.674634 (0.569875 to 6.779394) · 5.712923 (2.974187 to 8.451659) · 2.038289 (−0.801526 to 4.878103) | < 1e−6 | ✓ PASS |
| Tukey-Kramer · adjusted p | 0.01535475 · 3.314807e−06 · 0.2116427 | 0.01535475 · 3.314808e−06 · 0.2116427 | < 1e−8 | ✓ PASS |
| Games-Howell · adjusted p · df | 0.01491232 · 3.489799e−06 · 0.2114754 · df 706.2092 · 816.5431 · 710.4645 | 0.01491232 · 3.489799e−06 · 0.2114754 · df 706.2092 · 816.5431 · 710.4645 | < 1e−8 · < 1e−4 | ✓ PASS |
| Games-Howell · 95% CI Low−Middle | 0.582054 to 6.767214 | 0.582054 to 6.767214 | < 1e−6 | ✓ PASS |
| Bonferroni · adjusted p · 95% CI Low−Middle | 0.01669191 · 3.327588e−06 · 0.2771868 · 0.502801 to 6.846467 | 0.01669191 · 3.327588e−06 · 0.2771868 · 0.502801 to 6.846467 | < 1e−8 | ✓ PASS |
| Holm · adjusted p (95% CI ระดับ Bonferroni)(95% CI at the Bonferroni level) | 0.01112794 · 3.327588e−06 · 0.09239561 | 0.01112794 · 3.327588e−06 · 0.09239562 | < 1e−8 | ✓ PASS |
| Šidák · adjusted p · 95% CI Low−Middle | 0.01659921 · 3.327584e−06 · 0.2523648 · 0.511089 to 6.838179 | 0.01659921 · 3.327584e−06 · 0.2523648 · 0.511089 to 6.838179 | < 1e−8 | ✓ PASS |
| Scheffé · adjusted p · 95% CI Low−Middle | 0.02139364 · 7.004993e−06 · 0.2425343 · 0.432027 to 6.917241 | 0.02139364 · 7.004993e−06 · 0.2425343 · 0.432027 to 6.917241 | < 1e−8 | ✓ PASS |
| Fisher's LSD · p (ไม่ปรับunadjusted) · 95% CI Low−Middle | 0.005563969 · 1.109196e−06 · 0.09239561 · 1.078784 to 6.270484 | 0.005563969 · 1.109196e−06 · 0.09239561 · 1.078784 to 6.270484 | < 1e−8 | ✓ PASS |
| Dunnett (อ้างอิงreference < 10,000) · adjusted p: Middle−Low · High−Low | 0.01060309 · 2.212029e−06 | 0.01060309 · 2.212029e−06 | < 1e−8 | ✓ PASS |
| Dunnett · 95% CI Middle−Low (เกณฑ์ยอมรับ 2e−4 ดูหมายเหตุ)(tolerance 2e−4, see note) | −6.599659 to −0.749609 | −6.599559 to −0.749709 | 1.0e−4 | ✓ PASS |
| Hedges' g: Low−Middle · Low−High · Middle−High | 0.2084396 · 0.3220262 · 0.1148389 | 0.2084396 · 0.3220262 · 0.1148389 | < 1e−7 | ✓ PASS |
| District · Levene F / p | 8.0684 / 1.044e−11 | 8.06842 / 1.0436e−11 | < 5e−5 | ✓ PASS |
| District · การทดสอบที่รายงาน (Levene p < 0.05)test reported (Levene p < 0.05) | Welch's ANOVA | Welch's ANOVA | — | ✓ PASS |
| District · Welch's F / df2 / p | 10.014 / 362.61 / 9.095e−14 | 10.01436 / 362.6128 / 9.0954e−14 | < 0.0005 | ✓ PASS |
| District · F แบบเดิม / p / η² / 95% CI ของ η²ordinary F / p / η² / 95% CI of η² | 6.871 / 1.04e−09 / 0.04574193 / 0.02098 to 0.06385 | 6.870618 / 1.044469e−09 / 0.04574193 / 0.021 to 0.064 | < 0.0005 | ✓ PASS |
| District · วิธีอัตโนมัติ · จำนวนคู่ที่ต่างกันautomatic method · pairs that differ | Games-Howell · 13 of 45 | Games-Howell · 13 of 45 | — | ✓ PASS |
| District · Games-Howell Kuchinarai−Mueang: ผลต่าง / df / 95% CI / pdifference / df / 95% CI / p | −5.949621 / 470.2419 / −11.26191 to −0.63733 / 0.01475565 | −5.949621 / 470.2419 / −11.26191 to −0.63733 / 0.01475565 | < 1e−6 | ✓ PASS |
| Employment Status (2 กลุ่มgroups) · Employed − Unemployed/Retired ผลต่าง (95% CI) / p ของคู่ / p ของ Fdifference (95% CI) / pair p / F-test p | 5.210256 (3.197574 to 7.222939) / 4.358639e−07 / 4.358639e−07 | 5.210256 (3.197574 to 7.222939) / 4.358647e−07 / 4.358639e−07 | < 1e−6 / 8e−13 | ✓ PASS |
ทุกแถวเทียบที่ทศนิยมเต็ม · R แสดงคู่แบบ "กลุ่มแรก − กลุ่มหลัง" ตรงกับ DAPH (Low = < 10,000, Middle = 10,000-30,000, High = > 30,000 บาท/เดือน) · ค่า q ของ Tukey และ Games-Howell ในตาราง DAPH เท่ากับ √2 × |t| และค่า F ของ Scheffé เท่ากับ t²/(k − 1) · Games-Howell ทั้ง 45 คู่ของอำเภอตรงกับ R ทุกคู่ (ค่า p ต่างกันไม่เกิน 3e−9) ยกเว้นคู่ Khong Chai − Sahatsakhan ที่ค่า p เล็กมาก (R 4.79e−12, DAPH 4.68e−12) ซึ่งต่างกันที่ความแม่นของการคำนวณหางของการแจกแจง studentized range ทั้งคู่รายงานเป็น p < 0.001 · ช่วงเชื่อมั่นของ Dunnett จาก confint() ของ multcomp หาค่าวิกฤตด้วยการอินทิเกรตเชิงสุ่ม (ได้ 2.210566) ส่วน DAPH คำนวณแบบแม่นตรง ขอบเขตจึงต่างกันที่ทศนิยมตำแหน่งที่ 4 ค่า p ตรงกันทุกตำแหน่ง
Every row is compared at full precision. R lists pairs as "first group − second group", as DAPH does (Low = < 10,000, Middle = 10,000-30,000, High = > 30,000 Baht/month). The q of Tukey and Games-Howell in the DAPH table equals √2 × |t|, and Scheffé's F equals t²/(k − 1). All 45 Games-Howell pairs of the district run agree with R (p-values within 3e−9) except the pair Khong Chai − Sahatsakhan, whose tiny p (R 4.79e−12, DAPH 4.68e−12) differs in the accuracy of the far tail of the studentized range; both report p < 0.001. multcomp's confint() finds Dunnett's critical value by randomised integration (2.210566), whereas DAPH computes it exactly, so the limits differ in the 4th decimal; the p-values agree in every digit shown.
4การแปลผลและตัวอย่างInterpretation and Example
คำถามหลัก: คะแนนคุณภาพชีวิตหลังการรักษาเฉลี่ยเท่ากับ 79.37 (SD 17.61) ในกลุ่มรายได้ครัวเรือน < 10,000 บาท/เดือน, 75.69 (SD 17.61) ในกลุ่ม 10,000-30,000 และ 73.66 (SD 17.80) ในกลุ่ม > 30,000 การทดสอบรวมมีนัยสำคัญ F(2, 1297) = 12.00, p < 0.001, η² = 0.018 (95% CI 0.006 ถึง 0.034) คือรายได้ครัวเรือนอธิบายความแปรผันของคะแนนได้ราว 1.8% ซึ่งเป็นขนาดเล็ก · ข้อตกลงเบื้องต้น: Shapiro-Wilk ไม่ผ่านทุกกลุ่ม แต่ทุกกลุ่มมีมากกว่า 300 ราย การทดสอบ F จึงยังใช้ได้ และ Levene p = 0.943 ไม่พบความแปรปรวนที่ไม่เท่ากัน · Tukey-Kramer พบความต่าง 2 จาก 3 คู่: < 10,000 สูงกว่า 10,000-30,000 อยู่ 3.67 คะแนน (95% CI 0.57 ถึง 6.78, p = 0.015, Hedges' g = 0.21) และสูงกว่า > 30,000 อยู่ 5.71 คะแนน (95% CI 2.97 ถึง 8.45, p < 0.001, g = 0.32) ส่วน 10,000-30,000 กับ > 30,000 ไม่พบความแตกต่างอย่างมีนัยสำคัญ (2.04, 95% CI −0.80 ถึง 4.88, p = 0.212) · ทิศทางที่พบคือรายได้ครัวเรือนต่ำมีคะแนนสูงกว่า ซึ่งเป็นความสัมพันธ์จากข้อมูลเชิงสังเกต ไม่ได้แปลว่ารายได้เป็นสาเหตุ และอาจเกิดจากตัวแปรอื่น เช่น การมีงานทำหรืออายุ
Main question: the mean post-treatment quality-of-life score was 79.37 (SD 17.61) in households earning < 10,000 Baht/month, 75.69 (SD 17.61) at 10,000-30,000 and 73.66 (SD 17.80) above 30,000. The overall test was significant, F(2, 1297) = 12.00, p < 0.001, η² = 0.018 (95% CI 0.006 to 0.034): household income explains about 1.8% of the variation in the score, a small effect. Assumptions: the Shapiro-Wilk test rejects normality in every group, but every group has more than 300 patients, so the F test remains reasonable; Levene's p = 0.943 shows no evidence of unequal variances. Tukey-Kramer found 2 of 3 pairs different: the < 10,000 group scored 3.67 points higher than 10,000-30,000 (95% CI 0.57 to 6.78, p = 0.015, Hedges' g = 0.21) and 5.71 points higher than > 30,000 (95% CI 2.97 to 8.45, p < 0.001, g = 0.32); 10,000-30,000 versus > 30,000 showed no statistically significant difference (2.04, 95% CI −0.80 to 4.88, p = 0.212). Lower household income went with higher scores; this is an association in observational data, not evidence that income causes the difference, and other variables such as employment or age may explain it.
การอ่านตาราง post hoc (Tab 3 และ Word ตารางที่ 2 แยกจากตารางสถิติเชิงพรรณนา): แต่ละแถวคือคู่ของกลุ่ม มีผลต่างค่าเฉลี่ย (กลุ่มแรก − กลุ่มหลัง), SE ของผลต่าง, ช่วงเชื่อมั่น 95% ที่ปรับแล้ว, ค่าสถิติตามวิธี (q สำหรับ Tukey และ Games-Howell, t สำหรับ Bonferroni/Holm/Šidák/LSD/Dunnett, F สำหรับ Scheffé), df (Games-Howell ใช้ df แบบ Welch ของแต่ละคู่), ค่า p ที่ปรับแล้ว และ Hedges' g (0.2 เล็ก, 0.5 ปานกลาง, 0.8 ใหญ่) ใต้ตารางมีหมายเหตุบอกวิธีปรับทุกครั้ง · ค่า p ที่ปรับแล้ว ได้เข้มขึ้นตามจำนวนคู่แล้ว คู่ใดต่ำกว่า 0.05 คือคู่ที่ต่างกันอย่างมีนัยสำคัญ ไม่ต้องหารด้วยจำนวนคู่ซ้ำ และคู่ที่ช่วงเชื่อมั่นไม่คร่อม 0 คือคู่ที่ต่างกัน · อ่านคู่เฉพาะเมื่อการทดสอบรวมมีนัยสำคัญ: ถ้า F (หรือ Welch's F) ไม่มีนัยสำคัญ แปลว่ายังไม่มีหลักฐานว่ากลุ่มใดต่างกัน (ไม่ใช่หลักฐานว่าทุกกลุ่มเท่ากัน) DAPH จึงไม่ทำ post hoc · กลับกัน การทดสอบรวมมีนัยสำคัญแต่ไม่มีคู่ใดผ่านหลังปรับก็เกิดได้เมื่อความต่างเล็ก ๆ กระจายหลายคู่ ให้รายงานตามจริง · ถ้าเลือกวิธีเอง หน้าผลลัพธ์จะเขียนว่าผู้ใช้เลือกวิธีนั้นแทนวิธีที่ระบบแนะนำ และ Word ระบุชื่อวิธีพร้อมเอกสารอ้างอิง
Reading the post hoc table (Tab 3 and Word Table 2, separate from the descriptive table): each row is a pair of groups with the mean difference (first group − second), its SE, the adjusted 95% CI, the statistic of the method (q for Tukey and Games-Howell, t for Bonferroni/Holm/Šidák/LSD/Dunnett, F for Scheffé), the df (Games-Howell uses each pair's Welch df), the adjusted p-value and Hedges' g (0.2 small, 0.5 medium, 0.8 large); the note under the table always names the adjustment. The adjusted p-value is already stricter for the number of pairs: a pair below 0.05 differs significantly, with no further division by the number of pairs, and a pair whose interval does not cover 0 differs. Read pairs only after a significant overall test: if F (or Welch's F) is not significant there is no evidence that any group differs (which is not evidence that all groups are equal), so DAPH does not run post hoc tests. The reverse also happens, a significant overall test with no pair significant after adjustment when small differences are spread over several pairs; report it as it is. When you choose a method yourself, the results page says you chose it instead of the recommended one, and the Word report names that method with its reference.
คำถามที่สอง (ความแปรปรวนไม่เท่ากัน): ค่าเฉลี่ยของ 10 อำเภออยู่ระหว่าง 66.63 (Khong Chai) ถึง 85.06 (Sahatsakhan) Levene p < 0.001 DAPH จึงรายงาน Welch's ANOVA: Welch's F(9, 362.61) = 10.01, p < 0.001 (F แบบเดิมเพื่ออ้างอิง F(9, 1290) = 6.87, p < 0.001) η² = 0.046 (95% CI 0.021 ถึง 0.064) และเปรียบเทียบรายคู่ด้วย Games-Howell อัตโนมัติ พบความต่าง 13 จาก 45 คู่ เช่น Kuchinarai − Mueang = −5.95 คะแนน (95% CI −11.26 ถึง −0.64, p = 0.015) · η² ยังมาจากผลรวมกำลังสองของ ANOVA แบบเดิม ใช้บอกขนาดความต่าง ไม่ใช่ผลการทดสอบ · ค่า p ที่ใช้ตัดสินว่าจะเปรียบเทียบรายคู่ต่อหรือไม่คือค่าของ Welch
Second question (unequal variances): the 10 district means range from 66.63 (Khong Chai) to 85.06 (Sahatsakhan). Levene's p < 0.001, so DAPH reports Welch's ANOVA: Welch's F(9, 362.61) = 10.01, p < 0.001 (ordinary F for reference F(9, 1290) = 6.87, p < 0.001), η² = 0.046 (95% CI 0.021 to 0.064), and compares pairs automatically with Games-Howell: 13 of 45 pairs differ, for example Kuchinarai − Mueang = −5.95 points (95% CI −11.26 to −0.64, p = 0.015). η² still comes from the sums of squares of the ordinary ANOVA and describes the size of the difference, not the test; Welch's p is the one that decides whether pairwise comparisons follow.
📖 References
- Brown, M. B., & Forsythe, A. B. (1974). Robust tests for the equality of variances. Journal of the American Statistical Association, 69(346), 364–367. doi:10.1080/01621459.1974.10482955
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
- Dunn, O. J. (1961). Multiple comparisons among means. Journal of the American Statistical Association, 56(293), 52–64. doi:10.1080/01621459.1961.10482090
- Dunnett, C. W. (1955). A multiple comparison procedure for comparing several treatments with a control. Journal of the American Statistical Association, 50(272), 1096–1121. doi:10.1080/01621459.1955.10501294
- Fisher, R. A. (1925). Statistical methods for research workers. Oliver and Boyd.
- Fisher, R. A. (1935). The design of experiments. Oliver and Boyd.
- Games, P. A., & Howell, J. F. (1976). Pairwise multiple comparison procedures with unequal n's and/or variances: A Monte Carlo study. Journal of Educational Statistics, 1(2), 113–125. doi:10.3102/10769986001002113
- Hayter, A. J. (1986). The maximum familywise error rate of Fisher's least significant difference test. Journal of the American Statistical Association, 81(396), 1000–1004. doi:10.1080/01621459.1986.10478364
- Holm, S. (1979). A simple sequentially rejective multiple test procedure. Scandinavian Journal of Statistics, 6(2), 65–70.
- Kramer, C. Y. (1956). Extension of multiple range tests to group means with unequal numbers of replications. Biometrics, 12(3), 307–310. doi:10.2307/3001469
- Levene, H. (1960). Robust tests for equality of variances. In I. Olkin (Ed.), Contributions to probability and statistics (pp. 278–292). Stanford University Press.
- Scheffé, H. (1953). A method for judging all contrasts in the analysis of variance. Biometrika, 40(1–2), 87–110. doi:10.1093/biomet/40.1-2.87
- Shapiro, S. S., & Wilk, M. B. (1965). An analysis of variance test for normality (complete samples). Biometrika, 52(3–4), 591–611. doi:10.1093/biomet/52.3-4.591
- Šidák, Z. (1967). Rectangular confidence regions for the means of multivariate normal distributions. Journal of the American Statistical Association, 62(318), 626–633. doi:10.1080/01621459.1967.10482935
- Steiger, J. H. (2004). Beyond the F test: Effect size confidence intervals and tests of close fit in the analysis of variance and contrast analysis. Psychological Methods, 9(2), 164–182. doi:10.1037/1082-989X.9.2.164
- Tukey, J. W. (1949). Comparing individual means in the analysis of variance. Biometrics, 5(2), 99–114. doi:10.2307/3001913
- Welch, B. L. (1951). On the comparison of several mean values: An alternative approach. Biometrika, 38(3–4), 330–336. doi:10.1093/biomet/38.3-4.330
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
1.3Two-way ANOVA (factorial, with interaction)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Two-way ANOVA (การวิเคราะห์ความแปรปรวนสองทาง) เปรียบเทียบค่าเฉลี่ยของตัวแปรผลลัพธ์ที่เป็นตัวเลขต่อเนื่องตามตัวแปรกลุ่ม สองตัวพร้อมกัน ในแบบจำลองเดียว และทดสอบ ปฏิสัมพันธ์ (interaction) ระหว่างสองปัจจัย จึงตอบได้ 3 คำถาม: ปัจจัย A สัมพันธ์กับผลลัพธ์หรือไม่, ปัจจัย B สัมพันธ์หรือไม่ และ ความต่างตามปัจจัยหนึ่งขึ้นกับระดับของอีกปัจจัยหรือไม่ คำถามที่สามคือสิ่งที่การรัน One-way ANOVA (หัวข้อ 1.2) แยกสองครั้งตอบไม่ได้ และพบบ่อยในงานสาธารณสุข เช่น ปัจจัยหนึ่งอาจสัมพันธ์กับผลลัพธ์ในกลุ่มหนึ่งแต่ไม่สัมพันธ์ในอีกกลุ่ม (effect modification)
Two-way ANOVA compares the mean of a continuous outcome across two categorical factors at once in one model and tests the interaction between them. It answers three questions: is factor A related to the outcome, is factor B, and does the difference by one factor depend on the level of the other. The third question is what two separate one-way ANOVAs (section 1.2) cannot answer, and it is common in public health: a factor may be related to the outcome in one subgroup but not in another (effect modification).
ใช้เมื่อ ผลลัพธ์เป็นตัวเลขต่อเนื่อง มีตัวแปรกลุ่มสองตัว (ตัวละไม่เกิน 20 ระดับ) ทุกเซลล์ (ทุกคู่ระดับ) มีข้อมูล และข้อมูลแต่ละคนเป็นอิสระต่อกัน · ไม่ควรใช้เมื่อ ต้องการปรับตัวแปรต่อเนื่อง (ใช้ ANCOVA หัวข้อ 1.4) วัดซ้ำในคนเดียวกัน (ใช้ Repeated-Measures ANOVA หัวข้อ 1.5) หรือมีตัวแปรอธิบายหลายตัวหรือเป็นตัวเลขต่อเนื่อง (ใช้ Linear Regression หัวข้อ 1.12)
Use it when the outcome is continuous, there are two categorical factors (at most 20 levels each), every cell (every combination of levels) has data, and observations are independent. Do not use it to adjust for a continuous covariate (use ANCOVA, section 1.4), for repeated measurements on the same people (use Repeated-Measures ANOVA, section 1.5), or with many or continuous explanatory variables (use Linear Regression, section 1.12).
qolscore3) ต่างกันตามรายได้ส่วนบุคคล (Personal Income, income: 1 = ไม่มีรายได้, 2 = < 10,000, 3 = ≥ 10,000 บาท/เดือน) และตามการมีโรคเรื้อรัง (Chronic Disease, chronic: 0 = ไม่มี, 1 = มี) หรือไม่ และความต่างตามรายได้ขึ้นกับการมีโรคเรื้อรังหรือไม่ (แบบ 3 × 2 เซลล์ละ 78 ถึง 494 ราย) · คำถามที่สอง (ความแปรปรวนของเซลล์ไม่เท่ากัน): คะแนนเดียวกันตามเพศ (Gender) และประเภทโรงพยาบาล (Hospital Type: รัฐ/เอกชน) · ผลอยู่ในส่วนที่ 3 และการแปลผลในส่วนที่ 4qolscore3) differ by personal income (Personal Income, income: 1 = no income, 2 = < 10,000, 3 = ≥ 10,000 Baht/month) and by chronic disease (Chronic Disease, chronic: 0 = no, 1 = yes), and does the income difference depend on chronic disease? (a 3 × 2 design, 78 to 494 patients per cell). Second question (unequal cell variances): the same score by Gender and Hospital Type (public/private). The results are in part 3 and their interpretation in part 4.2หลักการและสูตรLogic and Formula
- α_i, β_j, (αβ)_ij
- อิทธิพลหลักของปัจจัย A ระดับ i, ของปัจจัย B ระดับ j และปฏิสัมพันธ์ของเซลล์ ij (กำหนดให้ผลรวมเป็น 0 คือ sum-to-zero contrasts)main effect of A at level i, of B at level j, and the interaction of cell ij (constrained to sum to zero, the sum-to-zero contrasts)
- a, b, k, N, n_ij
- จำนวนระดับของ A และ B, จำนวนระดับของอีกปัจจัย (ในสูตร EM), จำนวนทั้งหมด, จำนวนในเซลล์ ijlevels of A and of B, levels of the other factor (in the EM formula), total size, size of cell ij
- SS_E, MS_E, df_E
- ผลรวมกำลังสอง ค่าเฉลี่ยกำลังสอง และองศาอิสระของความคลาดเคลื่อนerror sum of squares, mean square and degrees of freedom
- η²_p, ω²_p
- สัดส่วนความแปรปรวนที่ผลนั้นอธิบายได้หลังกันผลอื่นออก · ω²_p แก้ความเอนเอียงจึงต่ำกว่าเล็กน้อย (Olejnik & Algina, 2003; Lakens, 2013)proportion of variance an effect explains once the other effects are held out; ω²_p is bias-corrected and so slightly lower (Olejnik & Algina, 2003; Lakens, 2013)
- F′(λ)
- การแจกแจง F แบบ noncentral (Steiger, 2004) · ขอบเขตเป็น 0 เมื่อ F ต่ำกว่าควอนไทล์ของ F ปกติnoncentral F distribution (Steiger, 2004); a bound is 0 when F is below the matching quantile of the central F
Sum of squares แบบ Type III (ค่าเริ่มต้นของ DAPH) · เมื่อขนาดเซลล์ไม่เท่ากัน อิทธิพลของสองปัจจัยไม่ตั้งฉากกัน Type III ทดสอบแต่ละผลหลังปรับผลอื่นทั้งหมด รวมทั้งปฏิสัมพันธ์ และทดสอบอิทธิพลหลักบนค่าเฉลี่ยชายขอบแบบถ่วงน้ำหนักเท่ากัน · ข้อควรระวัง: Type III ถูกต้องเฉพาะเมื่อใช้ contrast แบบ sum-to-zero (ใน R คือ options(contrasts = c("contr.sum", "contr.poly"))) DAPH ใช้แบบนี้ ถ้าใช้ treatment coding ซึ่งเป็นค่าเริ่มต้นของ R แถวอิทธิพลหลักจะกลายเป็นการทดสอบที่ระดับอ้างอิงของอีกปัจจัย ซึ่งเป็นคนละสมมติฐาน · Type II (เลือกได้ในช่อง "ผลรวมกำลังสอง") ทดสอบอิทธิพลหลักแต่ละตัวหลังปรับอิทธิพลหลักอีกตัวเท่านั้น มีกำลังมากกว่าเมื่อไม่มีปฏิสัมพันธ์ ให้ผลเท่ากับ Type III เมื่อทุกเซลล์มีขนาดเท่ากัน และเมื่อมีปฏิสัมพันธ์ อิทธิพลหลักของสองแบบตอบคนละคำถาม (ตัวอย่างในส่วนที่ 4) · แถวปฏิสัมพันธ์เหมือนกันทั้งสองแบบ (Maxwell et al., 2018)
Type III sums of squares (the DAPH default). With unequal cell sizes the two factors are not orthogonal; Type III tests each effect after all the others, including the interaction, and tests each main effect on the equally weighted marginal means. Caution: Type III is correct only with sum-to-zero contrasts (in R, options(contrasts = c("contr.sum", "contr.poly"))), which DAPH uses; with R's default treatment coding the main-effect rows test the effect at the reference level of the other factor, a different hypothesis. Type II (selectable in the "Sums of squares" box) tests each main effect after the other main effect only; it has more power when there is no interaction, equals Type III when all cells have the same size, and when there is an interaction its main effects answer a different question (example in part 4). The interaction row is the same in both (Maxwell et al., 2018).
ขั้นตอนที่ DAPH ทำ · (1) ใช้แถวที่มีค่าครบทั้งสามตัวแปร ตัวแปรตามต้องเป็นตัวเลข ปัจจัยต้องเป็นตัวแปรกลุ่ม ถ้ามีเซลล์ว่างระบบไม่วิเคราะห์ (ประมาณปฏิสัมพันธ์ไม่ได้) และเตือนเมื่อเซลล์ใดมีน้อยกว่า 5 ราย · (2) ตรวจข้อตกลงเบื้องต้น: Levene's test แบบใช้มัธยฐานข้ามทุกเซลล์ (Levene, 1960; Brown & Forsythe, 1974) และ Shapiro-Wilk ของส่วนเหลือของแบบจำลอง (Shapiro & Wilk, 1965) ไม่ใช่รายกลุ่ม เพราะข้อตกลงเรื่องการแจกแจงปกติเป็นของความคลาดเคลื่อน · (3) ตาราง ANOVA: SS, df, MS, F, p, partial η² และ partial ω² (เกณฑ์ partial η²: < 0.01 เล็กมาก, 0.01 ถึงน้อยกว่า 0.06 เล็ก, 0.06 ถึงน้อยกว่า 0.14 ปานกลาง, ตั้งแต่ 0.14 ใหญ่; Cohen, 1988) พร้อม R² และ adjusted R² · Word เพิ่มช่วงเชื่อมั่น 95% ของ partial η² · (4) ถ้า Levene p < 0.05 Word รายงานการทดสอบ F ซ้ำด้วยความคลาดเคลื่อนมาตรฐานแบบ HC3 (MacKinnon & White, 1985) แบบ Wald F (Type III: ทุกผล · Type II: เฉพาะปฏิสัมพันธ์) และบอกว่าข้อสรุปของผลใดเปลี่ยน · (5) ค่าเฉลี่ยชายขอบที่ประมาณจากแบบจำลอง (EM means) · (6) ลำดับการอ่าน: ดูปฏิสัมพันธ์ก่อน ถ้ามีนัยสำคัญ และติ๊กช่อง "Simple effects" ไว้ (ค่าเริ่มต้น) DAPH ทดสอบ simple main effects คือผลของปัจจัยหนึ่ง ณ แต่ละระดับของอีกปัจจัย ด้วย MS_E ของแบบจำลองเต็ม และปรับค่า p แบบ Bonferroni ตามจำนวนระดับในครอบครัวนั้น (สูตรสุดท้ายในกรอบ) แล้วเปรียบเทียบรายคู่ภายในระดับที่มีนัยสำคัญด้วยวิธีเดียวกับที่เลือก โดยปรับเฉพาะคู่ภายในระดับนั้น · สำหรับปัจจัยสองระดับที่ simple effect มีนัยสำคัญทุกระดับ Word บอกช่วงของผลต่างข้ามระดับของอีกปัจจัย
The DAPH procedure. (1) It uses rows with all three variables present; the outcome must be numeric and the factors categorical; it refuses the analysis when a cell is empty (the interaction cannot be estimated) and warns when a cell has fewer than 5 observations. (2) Assumptions: Levene's test centred on the median across all cells (Levene, 1960; Brown & Forsythe, 1974) and the Shapiro-Wilk test of the model residuals (Shapiro & Wilk, 1965), not per group, because the normality assumption belongs to the errors. (3) The ANOVA table: SS, df, MS, F, p, partial η² and partial ω² (partial η² labels: < 0.01 negligible, 0.01 to below 0.06 small, 0.06 to below 0.14 medium, 0.14 or more large; Cohen, 1988), with R² and adjusted R²; the Word report adds the 95% CI of partial η². (4) When Levene's p < 0.05 the Word report repeats each F test as a Wald F with HC3 standard errors (MacKinnon & White, 1985; Type III: every effect, Type II: the interaction only) and says whose conclusion changes. (5) The estimated marginal means (EM means). (6) Reading order: the interaction first. When it is significant and the "Simple effects" box is ticked (the default), DAPH tests the simple main effects, the effect of one factor at each level of the other, on the MS_E of the full model with a Bonferroni adjustment over the levels in that family (last formula in the box), then compares pairs inside each significant level with the chosen method, adjusted over the pairs within that level. For a two-level factor whose simple effect is significant at every level, the Word report gives the range of its difference across the other factor.
- a, k, m
- จำนวนระดับของปัจจัยที่เปรียบเทียบ, จำนวนระดับของอีกปัจจัย, จำนวนคู่levels of the factor being compared, levels of the other factor, number of pairs
- c, s_c², n_c
- เซลล์ของสองระดับที่เปรียบเทียบ (2k เซลล์) กับความแปรปรวนและจำนวนในเซลล์นั้นthe cells of the two levels compared (2k cells), with their variance and size
- s_p, n_1, n_2
- ส่วนเบี่ยงเบนมาตรฐานร่วมและจำนวนของสองเซลล์ที่เปรียบเทียบภายในระดับเดียวกันpooled SD and sizes of the two cells compared within one level
Post hoc ของ Two-way ANOVA (ช่อง "Post Hoc ⓘ" ใน Tab 2 ค่าเริ่มต้น "อัตโนมัติ (แนะนำ)"): ทำแยกทีละปัจจัย เฉพาะปัจจัยที่อิทธิพลหลักมีนัยสำคัญ (F แบบเดิม) และเปรียบเทียบบนค่าเฉลี่ยชายขอบที่ประมาณจากแบบจำลอง ซึ่งเป็นค่าชุดเดียวกับที่การทดสอบ F ของอิทธิพลหลักใช้ ไม่ใช่ค่าเฉลี่ยดิบที่ถูกดึงไปทางระดับที่มีคนมาก · กฎอัตโนมัติ เหมือน One-way ANOVA (หัวข้อ 1.2) ต่างกันสองจุด คือ Levene ตรวจข้ามทุกเซลล์ และ "ขนาดเท่ากัน" หมายถึงทุกเซลล์มีจำนวนเท่ากัน: Levene p < 0.05 ใช้วิธีแบบ Games-Howell ที่ปรับใช้กับค่าเฉลี่ยชายขอบ (Games & Howell, 1976) · p ≥ 0.05 และทุกเซลล์เท่ากัน ใช้ Tukey HSD (Tukey, 1949) · p ≥ 0.05 แต่เซลล์ไม่เท่ากัน ใช้ Tukey-Kramer (Kramer, 1956) · เลือกเองได้: Tukey, Games-Howell, Bonferroni (Dunn, 1961), Holm (Holm, 1979), Šidák (Šidák, 1967), Scheffé (Scheffé, 1953) และ Fisher's LSD (Fisher, 1935) ซึ่งเหมาะกับกรณีใดอธิบายไว้ในหัวข้อ 1.2 · สถิตินี้ไม่มี Dunnett · Games-Howell ต้องมีอย่างน้อย 2 ค่าในทุกเซลล์ ถ้ามีเซลล์ที่มีค่าเดียว ระบบใช้ Tukey-Kramer แทนและบอกเหตุผล · ปัจจัยสองระดับมีคู่เดียว · ถ้าปฏิสัมพันธ์มีนัยสำคัญ ตารางคู่ของอิทธิพลหลักยังแสดงพร้อมหมายเหตุว่าเป็นการเฉลี่ยข้ามระดับของอีกปัจจัยที่ให้ผลต่างกัน ควรอ่านคู่กับ simple main effects · ถ้าเอาเครื่องหมายถูกที่ช่อง Post Hoc ออก ระบบยังทดสอบ simple main effects แต่ไม่เปรียบเทียบรายคู่
Post hoc for Two-way ANOVA (the "Post Hoc ⓘ" box in Tab 2, default "Automatic (recommended)"): run separately for each factor, only for a factor whose main effect is significant (ordinary F), and on the estimated marginal means, the same means the main-effect F test compares, not the raw marginal means, which lean toward the levels with more people. The automatic rule is that of One-way ANOVA (section 1.2) with two differences: Levene's test is run across all cells, and "equal sizes" means every cell has the same size. Levene's p < 0.05 gives a Games-Howell-type procedure adapted to the marginal means (Games & Howell, 1976); p ≥ 0.05 with all cells equal gives Tukey HSD (Tukey, 1949); p ≥ 0.05 with unequal cells gives Tukey-Kramer (Kramer, 1956). You can also choose Tukey, Games-Howell, Bonferroni (Dunn, 1961), Holm (Holm, 1979), Šidák (Šidák, 1967), Scheffé (Scheffé, 1953) or Fisher's LSD (Fisher, 1935); section 1.2 explains when each suits. Dunnett is not offered here. Games-Howell needs at least 2 observations in every cell; when a cell has a single observation DAPH uses Tukey-Kramer instead and says why. A two-level factor has a single pair. When the interaction is significant the main-effect pairs are still shown, with a note that they average over levels of the other factor that behave differently and should be read with the simple main effects. With the Post Hoc box unticked, the simple main effects are still tested but no pairs are compared.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
# Personal Income: 1 = no income, 2 = < 10,000, 3 = >= 10,000 Baht/month; Chronic Disease: 0 = no, 1 = yes
d$income <- factor(d$income, 1:3, c("None", "Under10k", "Over10k"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
library(car)
with(d, table(income, chronic)) # cell sizes
with(d, round(tapply(qolscore3, list(income, chronic), mean), 2)) # cell means
options(contrasts = c("contr.sum", "contr.poly")) # Type III needs sum-to-zero contrasts
m <- lm(qolscore3 ~ income * chronic, data = d)
a3 <- Anova(m, type = 3); a3
sse <- a3["Residuals", "Sum Sq"]; dfe <- a3["Residuals", "Df"]; mse <- sse / dfe; N <- nrow(d)
eff <- c("income", "chronic", "income:chronic"); ss <- a3[eff, "Sum Sq"]; df <- a3[eff, "Df"]
cbind(SS = ss, F = a3[eff, "F value"], p = a3[eff, "Pr(>F)"], partial_eta2 = ss / (ss + sse),
partial_omega2 = pmax(0, (ss - df * mse) / (ss + (N - df) * mse)))
c(SSE = sse, MSE = mse, R2 = summary(m)$r.squared, adjR2 = summary(m)$adj.r.squared)
# 95% CI of partial eta2 (Word report): invert the noncentral F, bound = ncp / (ncp + df_error)
bound <- function(F, d1, d2, p) { if (pf(F, d1, d2) <= p) return(0)
uniroot(function(x) pf(F, d1, d2, x) - p, c(0, 10 * F * d1 + 100), tol = 1e-12)$root }
t(sapply(eff, function(e) { F <- a3[e, "F value"]; lo <- bound(F, a3[e, "Df"], dfe, 0.975)
hi <- bound(F, a3[e, "Df"], dfe, 0.025); c(lower = lo / (lo + dfe), upper = hi / (hi + dfe)) }))
leveneTest(qolscore3 ~ income * chronic, data = d) # across the 6 cells, centre = median
shapiro.test(residuals(m)) # normality of the residuals
a2 <- Anova(m, type = 2); a2[, c("Sum Sq", "F value", "Pr(>F)")] # Type II, for comparison
# chronic
# income No Yes
# None 82 81
# Under10k 105 78
# Over10k 460 494
# No Yes
# None 79.44 80.81
# Under10k 75.63 78.18
# Over10k 76.77 73.28
# SS F p partial_eta2 partial_omega2
# [1,] 3818.756138 6.07643958 0.002362387 9.304331e-03 0.007749385
# [2,] 3.607939 0.01148197 0.914683451 8.873160e-06 0.000000000
# [3,] 1918.631984 3.05294471 0.047559941 4.696455e-03 0.003148433
# SSE MSE R2 adjR2
# 4.066090e+05 3.142265e+02 1.723850e-02 1.344112e-02
# lower upper
# income 0.001275311 0.021513567
# chronic 0.000000000 0.001900863
# income:chronic 0.000000000 0.013948339
# Levene's Test (center = median): F value 0.3074, Pr(>F) 0.9087 (Df 5, 1294)
# Shapiro-Wilk of the residuals: W = 0.9771, p-value = 1.655e-13
# Type II: income F 5.9611, p 0.002648 · chronic F 4.3037, p 0.038227 · income:chronic F 3.0529, p 0.047560
library(emmeans)
emm <- emmeans(m, ~ income) # estimated marginal means (equal weights)
e <- summary(emm); data.frame(income = e$income, emmean = e$emmean, SE = e$SE, lower = e$lower.CL, upper = e$upper.CL)
# "tukey" = Tukey-Kramer here (unequal cells), "none" = Fisher's LSD; Holm CIs are at the Bonferroni level
for (adj in c("tukey", "bonferroni", "holm", "sidak", "scheffe", "none")) {
s <- summary(pairs(emm, adjust = adj), infer = TRUE)
cat("--", adj, "\n")
print(data.frame(pair = s$contrast, diff = s$estimate, SE = s$SE, lower = s$lower.CL, upper = s$upper.CL,
t = s$t.ratio, p = s$p.value), digits = 7)
}
# Hedges' g on the marginal means: difference / sqrt(MSE), small-sample correction with df_error
s <- summary(pairs(emm)); s$estimate / sqrt(mse) * (1 - 3 / (4 * dfe - 1))
# Games-Howell-type comparison of marginal means: each cell's own variance, Welch-Satterthwaite df
gh_em <- function(y, f, o) {
a <- nlevels(f); k <- nlevels(o); out <- NULL
cm <- tapply(y, list(f, o), mean); cv <- tapply(y, list(f, o), var); cn <- tapply(y, list(f, o), length)
em <- rowMeans(cm); v <- cv / (cn * k^2)
for (i in 1:(a - 1)) for (j in (i + 1):a) {
vv <- c(v[i, ], v[j, ]); nn <- c(cn[i, ], cn[j, ]); se <- sqrt(sum(vv))
dff <- sum(vv)^2 / sum(vv^2 / (nn - 1)); dif <- em[i] - em[j]
q <- sqrt(2) * abs(dif) / se; h <- qtukey(0.95, a, dff) / sqrt(2) * se
out <- rbind(out, data.frame(pair = paste(levels(f)[i], "-", levels(f)[j]), diff = dif, SE = se, df = dff,
lower = dif - h, upper = dif + h, q = q, p = ptukey(q, a, dff, lower.tail = FALSE)))
}
out
}
gh_em(d$qolscore3, d$income, d$chronic)
# income emmean SE lower upper
# 1 None 80.12383 1.3884676 77.39994 82.84773
# 2 Under10k 76.90403 1.3248752 74.30489 79.50317
# 3 Over10k 75.02395 0.5742793 73.89733 76.15057
# -- tukey (Tukey-Kramer)
# pair diff SE lower upper t p
# 1 None - Under10k 3.219804 1.919150 -1.283300 7.722908 1.677724 0.214139986
# 2 None - Over10k 5.099881 1.502544 1.574302 8.625459 3.394163 0.002047734
# 3 Under10k - Over10k 1.880077 1.443984 -1.508097 5.268250 1.302006 0.394286780
# -- bonferroni p 0.280927455 0.002127648 0.579437959 None - Under10k CI -1.380585 7.820192
# -- holm p 0.187284970 0.002127648 0.193145986 (CI as Bonferroni)
# -- sidak p 0.255441853 0.002126139 0.474727226 None - Under10k CI -1.368563 7.808171
# -- scheffe p 0.245158487 0.003231907 0.428675385 None - Under10k CI -1.483232 7.92284
# -- none (LSD) p 0.0936424849 0.0007092158 0.1931459862 None - Under10k CI -0.5451825 6.984790
# [1] 0.1815333 0.2875324 0.1059991 (Hedges' g of the three pairs)
# Games-Howell-type:
# None - Under10k 3.219804 1.885427 333.3773 -1.218924 7.658531 2.415098 0.203773988
# None - Over10k 5.099881 1.476729 220.6778 1.615336 8.584425 4.883984 0.001911561
# Under10k - Over10k 1.880077 1.427834 250.5163 -1.486369 5.246522 1.862143 0.387183148
# Simple main effects: one factor within each level of the other, tested on the pooled MSE of the full model;
# DAPH multiplies each p by the number of levels in that family (Bonferroni)
simple <- function(f, at) sapply(levels(d[[at]]), function(l) {
x <- d[d[[at]] == l, ]; mj <- tapply(x$qolscore3, x[[f]], mean); nj <- table(x[[f]])
ss <- sum(nj * (mj - mean(x$qolscore3))^2); df1 <- nlevels(d[[f]]) - 1; F <- ss / df1 / mse
p <- pf(F, df1, dfe, lower.tail = FALSE)
c(F = F, p = p, p_bonferroni = min(1, nlevels(d[[at]]) * p), partial_eta2 = ss / (ss + sse)) })
simple("income", "chronic") # effect of income at each chronic level
simple("chronic", "income") # effect of chronic disease at each income level
joint_tests(m, by = "chronic") # the same F tests in emmeans (F rounded to 3 decimals)
# pairs inside a significant simple effect, adjusted over the pairs within that level (Tukey-Kramer here)
s1 <- summary(pairs(emmeans(m, ~ income | chronic)), infer = TRUE); s1 <- s1[s1$chronic == "Yes", ]
data.frame(pair = s1$contrast, diff = s1$estimate, lower = s1$lower.CL, upper = s1$upper.CL, p = s1$p.value)
s2 <- summary(pairs(emmeans(m, ~ chronic | income)), infer = TRUE); s2 <- s2[s2$income == "Over10k", ]
data.frame(pair = s2$contrast, diff = s2$estimate, lower = s2$lower.CL, upper = s2$upper.CL, p = s2$p.value)
# Hedges' g of a pair inside a simple effect: pooled SD of the two cells
hg <- function(x, y) { nx <- length(x); ny <- length(y)
(mean(x) - mean(y)) / sqrt(((nx - 1) * var(x) + (ny - 1) * var(y)) / (nx + ny - 2)) * (1 - 3 / (4 * (nx + ny) - 9)) }
with(d[d$chronic == "Yes", ], hg(qolscore3[income == "None"], qolscore3[income == "Over10k"]))
# No Yes
# F 1.123159238 7.8909136255
# p 0.325567492 0.0003924184
# p_bonferroni 0.651134983 0.0007848368
# partial_eta2 0.001732941 0.0120492031
# None Under10k Over10k
# F 0.2432580203 0.92679204 9.239519188
# p 0.6219465289 0.33587776 0.002416011
# p_bonferroni 1.0000000000 1.00000000 0.007248033
# partial_eta2 0.0001879539 0.00071571 0.007089655
# joint_tests: chronic = No F.ratio 1.123, p.value 0.3256 · chronic = Yes F.ratio 7.891, p.value 0.0004
# pair diff lower upper p
# 1 None - Under10k 2.629155 -3.9691630 9.227473 0.61824607
# 2 None - Over10k 7.530302 2.5443003 12.516304 0.00118787
# 3 Under10k - Over10k 4.901147 -0.1665625 9.968857 0.06055012
# 1 No - Yes 3.491225 1.237984 5.744466 0.002416011
# [1] 0.4373802
# Unequal cell variances: Gender x Hospital Type (Hospital Type has 3 missing values, so N = 1297)
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$type <- factor(d$type, 1:2, c("Public", "Private"))
d2 <- d[!is.na(d$type), ]
m2 <- lm(qolscore3 ~ gender * type, data = d2)
Anova(m2, type = 3)
leveneTest(qolscore3 ~ gender * type, data = d2) # 4 cells, centre = median
Anova(m2, type = 3, white.adjust = "hc3") # F tests with HC3 standard errors
gh_em(d2$qolscore3, d2$type, d2$gender) # automatic choice: Games-Howell-type
# Type III: gender F 0.1276, p 0.72095 · type F 4.4125, p 0.03587 · gender:type F 1.2178, p 0.27000
# Levene's Test (center = median): F value 4.0541, Pr(>F) 0.007015 (Df 3, 1293)
# HC3: gender F 0.0965, p 0.75607 · type F 3.3375, p 0.06795 · gender:type F 0.9211, p 0.33736
# Public - Private 2.817936 1.53529 194.4864 -0.2100182 5.84589 2.595708 0.06796727
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| ขนาดเซลล์ (None, Under10k, Over10k × No, Yes)Cell sizes (None, Under10k, Over10k × No, Yes) | 82, 81 · 105, 78 · 460, 494 | 82, 81 · 105, 78 · 460, 494 | 0 | ✓ PASS |
| Type III SS: income · chronic · income × chronic | 3818.756138 · 3.607939 · 1918.631984 | 3818.756138 · 3.607939 · 1918.631984 | < 1e−6 | ✓ PASS |
| F | 6.076440 · 0.011482 · 3.052945 | 6.076440 · 0.011482 · 3.052945 | < 1e−6 | ✓ PASS |
| p | 0.002362387 · 0.914683451 · 0.047559941 | 0.002362387 · 0.914683451 · 0.047559941 | < 1e−9 | ✓ PASS |
| partial η² · partial ω² | 0.0093043 · 0.0000089 · 0.0046965 | 0.0077494 · 0 · 0.0031484 | 0.0093043 · 0.0000089 · 0.0046965 | 0.0077494 · 0 · 0.0031484 | < 1e−7 | ✓ PASS |
| SS_E / df_E / MS_E · R² / adjusted R² | 406609.0 / 1294 / 314.2265 · 0.01723850 / 0.01344112 | 406609.0 / 1294 / 314.2265 · 0.01723850 / 0.01344112 | < 1e−4 | ✓ PASS |
| 95% CI ของ partial η² (Word)95% CI of partial η² (Word) | 0.00128 to 0.02151 · 0 to 0.00190 · 0 to 0.01395 | 0.001 to 0.022 · 0.000 to 0.002 · 0.000 to 0.014 | < 0.0005 | ✓ PASS |
| Levene ข้าม 6 เซลล์ (มัธยฐาน): F / p · Shapiro-Wilk ของส่วนเหลือ: W / pLevene across 6 cells (median): F / p · Shapiro-Wilk of residuals: W / p | 0.3074 / 0.9087 · 0.9771 / 1.655e−13 | 0.30736 / 0.90868 · 0.97710 / 1.6551e−13 | < 5e−5 | ✓ PASS |
| Type II F / p: income · chronic · income × chronic | 5.9611 / 0.002648 · 4.3037 / 0.038227 · 3.0529 / 0.047560 | 5.96113 / 0.0026483 · 4.30368 / 0.0382273 · 3.05295 / 0.0475599 | < 5e−5 | ✓ PASS |
| EM mean (SE) ของรายได้: None · Under10k · Over10kEM mean (SE) of income: None · Under10k · Over10k | 80.12383 (1.38847) · 76.90403 (1.32488) · 75.02395 (0.57428) | 80.12383 (1.38847) · 76.90403 (1.32488) · 75.02395 (0.57428) | < 1e−5 | ✓ PASS |
| วิธีที่เลือกอัตโนมัติ (Levene p ≥ 0.05, เซลล์ไม่เท่ากัน) · หมายเหตุเตือนเพราะปฏิสัมพันธ์มีนัยสำคัญAutomatic choice (Levene p ≥ 0.05, unequal cells) · caution note because the interaction is significant | Tukey-Kramer · yes | Tukey-Kramer · yes | — | ✓ PASS |
| Tukey-Kramer · ผลต่าง (95% CI) / pdifference (95% CI) / p: None−Under10k · None−Over10k · Under10k−Over10k | 3.219804 (−1.283300 to 7.722908) / 0.2141400 · 5.099881 (1.574302 to 8.625459) / 0.002047734 · 1.880077 (−1.508097 to 5.268250) / 0.3942868 | 3.219804 (−1.283300 to 7.722908) / 0.2141400 · 5.099881 (1.574302 to 8.625459) / 0.002047734 · 1.880077 (−1.508097 to 5.268250) / 0.3942868 | < 1e−6 | ✓ PASS |
| Hedges' g (EM): None−Under10k · None−Over10k · Under10k−Over10k | 0.1815333 · 0.2875324 · 0.1059991 | 0.181533 · 0.287532 · 0.105999 | < 5e−7 | ✓ PASS |
| Bonferroni · Holm · Šidák · Scheffé · LSD: p ของ None−Over10kp of None−Over10k | 0.002127648 · 0.002127648 · 0.002126139 · 0.003231907 · 0.0007092158 | 0.002127648 · 0.002127648 · 0.002126139 · 0.003231907 · 0.0007092158 | < 1e−9 | ✓ PASS |
| Bonferroni · Holm · Šidák · Scheffé · LSD: p ของ None−Under10k และ Under10k−Over10kp of None−Under10k and Under10k−Over10k | 0.2809275, 0.5794380 · 0.1872850, 0.1931460 · 0.2554419, 0.4747272 · 0.2451585, 0.4286754 · 0.0936425, 0.1931460 | 0.2809275, 0.5794380 · 0.1872850, 0.1931460 · 0.2554419, 0.4747272 · 0.2451585, 0.4286754 · 0.0936425, 0.1931460 | < 1e−8 | ✓ PASS |
| 95% CI ของ None−Under10k95% CI of None−Under10k: Bonferroni (= Holm) · Šidák · Scheffé · LSD | −1.380585 to 7.820192 · −1.368563 to 7.808171 · −1.483232 to 7.922840 · −0.545183 to 6.984790 | −1.380585 to 7.820192 · −1.368563 to 7.808171 · −1.483232 to 7.922840 · −0.545182 to 6.984790 | < 1e−6 | ✓ PASS |
| วิธีแบบ Games-Howell (เลือกเอง): p · dfGames-Howell-type (chosen by hand): p · df | 0.2037740 · 0.001911561 · 0.3871831 · df 333.3773 · 220.6778 · 250.5163 | 0.2037740 · 0.001911561 · 0.3871832 · df 333.3773 · 220.6778 · 250.5163 | < 1e−7 · < 1e−4 | ✓ PASS |
| Simple effect of income · F / p (Bonferroni ×2) / partial η²F / p (Bonferroni ×2) / partial η²: chronic = No · Yes | 1.123159 / 0.6511350 / 0.0017329 · 7.890914 / 0.0007848368 / 0.0120492 | 1.123159 / 0.6511350 / 0.0017329 · 7.890914 / 0.0007848368 / 0.0120492 | < 1e−7 | ✓ PASS |
| Simple effect of chronic · F / p (Bonferroni ×3)F / p (Bonferroni ×3): None · Under10k · Over10k | 0.243258 / 1 · 0.926792 / 1 · 9.239519 / 0.007248033 | 0.243258 / 1 · 0.926792 / 1 · 9.239519 / 0.007248033 | < 1e−7 | ✓ PASS |
| คู่ของรายได้ที่ chronic = Yes (Tukey-Kramer): ผลต่าง (95% CI) / pIncome pairs at chronic = Yes (Tukey-Kramer): difference (95% CI) / p | 2.629155 (−3.969163 to 9.227473) / 0.6182461 · 7.530302 (2.544300 to 12.516304) / 0.00118787 · 4.901147 (−0.166563 to 9.968857) / 0.06055012 | 2.629155 (−3.969163 to 9.227473) / 0.6182461 · 7.530302 (2.544300 to 12.516304) / 0.00118787 · 4.901147 (−0.166562 to 9.968857) / 0.06055012 | < 1e−6 | ✓ PASS |
| คู่ No − Yes ที่ income = Over10k · Hedges' g ของ None − Over10k ที่ chronic = YesPair No − Yes at income = Over10k · Hedges' g of None − Over10k at chronic = Yes | 3.491225 (1.237984 to 5.744466) / 0.002416011 · 0.4373802 | 3.491225 (1.237984 to 5.744466) / 0.002416011 · 0.4373802 | < 1e−6 | ✓ PASS |
| Gender × Hospital Type · Type III F / p: gender · type · gender × type | 0.1276 / 0.72095 · 4.4125 / 0.03587 · 1.2178 / 0.27000 | 0.12764 / 0.72095 · 4.41253 / 0.03587 · 1.21778 / 0.27000 | < 5e−5 | ✓ PASS |
| Gender × Hospital Type · Levene (4 เซลล์cells): F / p | 4.0541 / 0.007015 | 4.05412 / 0.0070150 | < 5e−5 | ✓ PASS |
| Gender × Hospital Type · HC3 F / p | 0.0965 / 0.75607 · 3.3375 / 0.06795 · 0.9211 / 0.33736 | 0.09654 / 0.75607 · 3.33754 / 0.06795 · 0.92110 / 0.33737 | < 5e−5 | ✓ PASS |
| วิธีอัตโนมัติ (Levene p < 0.05) · คู่ Public − Private: ผลต่าง / df / 95% CI / pAutomatic choice (Levene p < 0.05) · pair Public − Private: difference / df / 95% CI / p | Games-Howell-type · 2.817936 / 194.4864 / −0.210018 to 5.845890 / 0.06796727 | Games-Howell-type · 2.817936 / 194.4864 / −0.210018 to 5.845890 / 0.06796727 | < 1e−6 | ✓ PASS |
ทุกแถวเทียบที่ทศนิยมเต็ม (None = ไม่มีรายได้, Under10k = < 10,000, Over10k = ≥ 10,000 บาท/เดือน) · ลำดับคู่และเครื่องหมายเหมือนกัน (ระดับแรก − ระดับหลัง) · ค่า q ในตาราง DAPH เท่ากับ √2 × |t| · emmeans ไม่มีวิธีแบบ Games-Howell สำหรับค่าเฉลี่ยชายขอบ สคริปต์จึงคำนวณจากสูตรในส่วนที่ 2 · คู่ภายใน simple effect (chronic = Yes) ตรวจครบทุกตัวเลือกแล้ว (Bonferroni, Holm, Šidák, Scheffé และ LSD เทียบกับ pairs(emmeans(m, ~ income | chronic), adjust = ...) และ Games-Howell เทียบกับสูตรของหัวข้อ 1.2 บนสองเซลล์) ต่างกันไม่เกิน 2e−9 · joint_tests ของ emmeans ปัดค่า F เป็น 3 ตำแหน่ง สคริปต์จึงคำนวณ F ของ simple effect จากสูตรโดยตรง
Every row is compared at full precision (None = no income, Under10k = < 10,000, Over10k = ≥ 10,000 Baht/month), with the same pair order and sign (first level − second). The q in the DAPH table equals √2 × |t|. emmeans has no Games-Howell-type method for marginal means, so the script computes it from the formula in part 2. The pairs inside the simple effect (chronic = Yes) were checked for every option (Bonferroni, Holm, Šidák, Scheffé and LSD against pairs(emmeans(m, ~ income | chronic), adjust = ...), and Games-Howell against the formula of section 1.2 on the two cells): all within 2e−9. emmeans' joint_tests rounds F to 3 decimals, so the script computes the simple-effect F from its formula.
4การแปลผลและตัวอย่างInterpretation and Example
คำถามหลัก: ข้อตกลงเบื้องต้น Levene p = 0.909 ไม่พบความแปรปรวนที่ไม่เท่ากัน Shapiro-Wilk ของส่วนเหลือไม่ผ่าน (p < 0.001) แต่ทุกเซลล์มีอย่างน้อย 78 ราย การทดสอบ F จึงยังใช้ได้ · ปฏิสัมพันธ์มีนัยสำคัญ F(2, 1294) = 3.05, p = 0.048, partial η² = 0.005 (95% CI 0.000 ถึง 0.014) จึงอ่านจาก simple main effects เป็นหลัก: ในผู้ที่มีโรคเรื้อรัง คะแนนต่างกันตามรายได้ F(2, 1294) = 7.89, p < 0.001 (หลังปรับ Bonferroni) partial η² = 0.012 โดยผู้ที่ไม่มีรายได้มีคะแนนเฉลี่ย 80.81 สูงกว่าผู้มีรายได้ ≥ 10,000 บาทซึ่งมี 73.28 อยู่ 7.53 คะแนน (95% CI 2.54 ถึง 12.52, p = 0.001, Hedges' g = 0.44) ส่วนในผู้ที่ไม่มีโรคเรื้อรังไม่พบความต่างตามรายได้ (F = 1.12, p = 0.651) · มองอีกทาง: ผู้มีโรคเรื้อรังมีคะแนนต่ำกว่าผู้ไม่มีเฉพาะในกลุ่มรายได้ ≥ 10,000 บาท (ไม่มี − มี = 3.49, 95% CI 1.24 ถึง 5.74; F(1, 1294) = 9.24, p = 0.007 หลังปรับ) · อิทธิพลหลักของรายได้ F(2, 1294) = 6.08, p = 0.002, partial η² = 0.009 และ Tukey-Kramer บนค่าเฉลี่ยชายขอบพบ None − Over10k = 5.10 (95% CI 1.57 ถึง 8.63, p = 0.002) แต่ตารางนี้มีหมายเหตุเตือน เพราะความต่างนี้เกิดในผู้มีโรคเรื้อรังเป็นหลัก · อิทธิพลหลักของโรคเรื้อรังไม่มีนัยสำคัญแบบ Type III (p = 0.915) แต่มีนัยสำคัญแบบ Type II (p = 0.038) เพราะเมื่อมีปฏิสัมพันธ์ สองแบบทดสอบคนละสมมติฐาน รายงาน Type III ตามที่ตั้งไว้ · ข้อจำกัด: ขนาดอิทธิพลทุกตัวเล็กมาก (partial η² ไม่เกิน 0.012) ค่า p ของปฏิสัมพันธ์ใกล้ 0.05 และเป็นข้อมูลเชิงสังเกต ผลจึงเป็นความสัมพันธ์ ไม่ใช่เหตุและผล และควรยืนยันในข้อมูลชุดอื่น
Main question: assumptions: Levene's p = 0.909 shows no evidence of unequal variances; the Shapiro-Wilk test of the residuals fails (p < 0.001), but every cell has at least 78 patients, so the F test remains reasonable. The interaction is significant, F(2, 1294) = 3.05, p = 0.048, partial η² = 0.005 (95% CI 0.000 to 0.014), so the simple main effects carry the finding: among patients with a chronic disease the score differed by income, F(2, 1294) = 7.89, p < 0.001 (Bonferroni-adjusted), partial η² = 0.012, with patients without income scoring 80.81 on average, 7.53 points above those earning ≥ 10,000 Baht (73.28; 95% CI 2.54 to 12.52, p = 0.001, Hedges' g = 0.44); among patients without a chronic disease there was no significant income difference (F = 1.12, p = 0.651). Seen the other way, patients with a chronic disease scored lower than those without only in the ≥ 10,000 Baht group (no − yes = 3.49, 95% CI 1.24 to 5.74; F(1, 1294) = 9.24, adjusted p = 0.007). The main effect of income, F(2, 1294) = 6.08, p = 0.002, partial η² = 0.009, with Tukey-Kramer on the marginal means giving None − Over10k = 5.10 (95% CI 1.57 to 8.63, p = 0.002), carries a caution note because this difference arises mainly among patients with a chronic disease. The main effect of chronic disease is not significant with Type III (p = 0.915) but is with Type II (p = 0.038): with an interaction the two test different hypotheses; report the Type III result as planned. Limitations: every effect is very small (partial η² at most 0.012), the interaction p is close to 0.05, and the data are observational, so these are associations, not causes, and should be confirmed in other data.
ประโยคในรายงาน Word: DAPH เขียนข้อตกลงเบื้องต้นพร้อมเอกสารอ้างอิงในย่อหน้าแรก แล้วเขียนวิธี post hoc เหตุผล และชี้มาที่หัวข้อนี้ เช่น "เนื่องจากความแปรปรวนไม่ต่างกัน (Levene's test แบบใช้มัธยฐาน p = 0.909; Levene, 1960; Brown & Forsythe, 1974) แต่ขนาดเซลล์ไม่เท่ากัน จึงเปรียบเทียบรายคู่ด้วย Tukey-Kramer (Tukey, 1949; Kramer, 1956) ขั้นตอน เกณฑ์การเลือกวิธี post hoc และเกณฑ์การแปลผลอธิบายไว้ใน DAPH Guide หัวข้อ 1.3 (Sornlorm, 2026b)" · ตาราง post hoc ของอิทธิพลหลักแสดงผลต่างของค่าเฉลี่ยชายขอบ ไม่ใช่ค่าเฉลี่ยดิบ · ปัจจัยที่มี 2 ระดับมีคู่เดียว ค่า p ของคู่นั้นเท่ากับค่า p ของการทดสอบ F ของปัจจัยนั้นเมื่อใช้ Tukey (และวิธีที่ใช้ t) · ถ้าเลือกวิธีเอง หน้าผลลัพธ์บอกว่าผู้ใช้เลือกวิธีนั้นแทนวิธีที่ระบบแนะนำ
The Word report states the assumption checks with their references in the first paragraph, then the post hoc method, the reason and a pointer to this section, for example: "Because the variances did not differ (Levene's test centred on the median, p = 0.909; Levene, 1960; Brown & Forsythe, 1974) but the cell sizes were unequal, pairwise comparisons used the Tukey-Kramer procedure (Tukey, 1949; Kramer, 1956). The procedure, the rule for choosing the post hoc method and the interpretation criteria are documented in DAPH Guide, section 1.3 (Sornlorm, 2026b)." The main-effect post hoc table shows differences of marginal means, not raw means. A two-level factor has a single pair, whose p equals the p of that factor's F test with Tukey (and the t-based methods). When you choose a method yourself, the results page says you chose it instead of the recommended one.
คำถามที่สอง (ความแปรปรวนของเซลล์ไม่เท่ากัน): Levene ข้าม 4 เซลล์ F = 4.05, p = 0.007 · การทดสอบ F แบบเดิมพบอิทธิพลหลักของประเภทโรงพยาบาล F(1, 1293) = 4.41, p = 0.036 แต่เมื่อทดสอบซ้ำด้วย HC3 ได้ F(1, 1293) = 3.34, p = 0.068 ข้อสรุปจึงเปลี่ยน และ DAPH เลือกวิธีแบบ Games-Howell อัตโนมัติ ได้ Public − Private = 2.82 คะแนน (95% CI −0.21 ถึง 5.85, p = 0.068) สอดคล้องกับ HC3 · ปฏิสัมพันธ์ไม่มีนัยสำคัญ (p = 0.270) จึงอ่านอิทธิพลหลักได้ตรง ๆ · สรุป: ความต่างของคะแนนระหว่างโรงพยาบาลรัฐกับเอกชนขึ้นกับข้อตกลงเรื่องความแปรปรวน ควรรายงานทั้งสองผลและถือว่ายังไม่ชัดเจน Word เขียนข้อความนี้ให้เอง
Second question (unequal cell variances): Levene's test across the 4 cells gives F = 4.05, p = 0.007. The ordinary F test finds a main effect of hospital type, F(1, 1293) = 4.41, p = 0.036, but repeated with HC3 standard errors it gives F(1, 1293) = 3.34, p = 0.068, so the conclusion changes; the automatic Games-Howell-type comparison gives Public − Private = 2.82 points (95% CI −0.21 to 5.85, p = 0.068), in line with HC3. The interaction is not significant (p = 0.270), so the main effects can be read directly. Conclusion: the public-private difference depends on the equal-variance assumption; report both tests and treat it as uncertain, which is what the Word report says.
📖 References
- Brown, M. B., & Forsythe, A. B. (1974). Robust tests for the equality of variances. Journal of the American Statistical Association, 69(346), 364–367. doi:10.1080/01621459.1974.10482955
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
- Dunn, O. J. (1961). Multiple comparisons among means. Journal of the American Statistical Association, 56(293), 52–64. doi:10.1080/01621459.1961.10482090
- Fisher, R. A. (1935). The design of experiments. Oliver and Boyd.
- Games, P. A., & Howell, J. F. (1976). Pairwise multiple comparison procedures with unequal n's and/or variances: A Monte Carlo study. Journal of Educational Statistics, 1(2), 113–125. doi:10.3102/10769986001002113
- Holm, S. (1979). A simple sequentially rejective multiple test procedure. Scandinavian Journal of Statistics, 6(2), 65–70.
- Kramer, C. Y. (1956). Extension of multiple range tests to group means with unequal numbers of replications. Biometrics, 12(3), 307–310. doi:10.2307/3001469
- Lakens, D. (2013). Calculating and reporting effect sizes to facilitate cumulative science: A practical primer for t-tests and ANOVAs. Frontiers in Psychology, 4, 863. doi:10.3389/fpsyg.2013.00863
- Levene, H. (1960). Robust tests for equality of variances. In I. Olkin (Ed.), Contributions to probability and statistics (pp. 278–292). Stanford University Press.
- MacKinnon, J. G., & White, H. (1985). Some heteroskedasticity-consistent covariance matrix estimators with improved finite sample properties. Journal of Econometrics, 29(3), 305–325. doi:10.1016/0304-4076(85)90158-7
- Maxwell, S. E., Delaney, H. D., & Kelley, K. (2018). Designing experiments and analyzing data: A model comparison perspective (3rd ed.). Routledge.
- Olejnik, S., & Algina, J. (2003). Generalized eta and omega squared statistics: Measures of effect size for some common research designs. Psychological Methods, 8(4), 434–447. doi:10.1037/1082-989X.8.4.434
- Scheffé, H. (1953). A method for judging all contrasts in the analysis of variance. Biometrika, 40(1–2), 87–110. doi:10.1093/biomet/40.1-2.87
- Shapiro, S. S., & Wilk, M. B. (1965). An analysis of variance test for normality (complete samples). Biometrika, 52(3–4), 591–611. doi:10.1093/biomet/52.3-4.591
- Šidák, Z. (1967). Rectangular confidence regions for the means of multivariate normal distributions. Journal of the American Statistical Association, 62(318), 626–633. doi:10.1080/01621459.1967.10482935
- Steiger, J. H. (2004). Beyond the F test: Effect size confidence intervals and tests of close fit in the analysis of variance and contrast analysis. Psychological Methods, 9(2), 164–182. doi:10.1037/1082-989X.9.2.164
- Tukey, J. W. (1949). Comparing individual means in the analysis of variance. Biometrics, 5(2), 99–114. doi:10.2307/3001913
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
1.4ANCOVA — Analysis of Covariance
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
ANCOVA (analysis of covariance, การวิเคราะห์ความแปรปรวนร่วม; Fisher, 1932) เปรียบเทียบค่าเฉลี่ยของผลลัพธ์ที่เป็นตัวเลขต่อเนื่องระหว่างกลุ่ม หลังปรับด้วยตัวแปรร่วม (covariate) เช่น ค่าของผลลัพธ์ก่อนเริ่ม อายุ หรือเพศ ค่าเฉลี่ยที่ได้เรียกว่าค่าเฉลี่ยปรับ (adjusted mean) คือค่าเฉลี่ยที่คาดว่าแต่ละกลุ่มจะได้ถ้าทุกกลุ่มมีตัวแปรร่วมเท่ากัน · ใช้เมื่อกลุ่มเริ่มต้นไม่เท่ากันในตัวแปรที่เกี่ยวกับผลลัพธ์ ในการทดลองแบบสุ่ม (RCT) การปรับค่าก่อนเริ่มยังช่วยเพิ่มกำลังการทดสอบ · ในการศึกษาเชิงสังเกต ANCOVA ปรับได้เฉพาะตัวแปรที่วัดและใส่ในแบบจำลอง จึงบอกความสัมพันธ์ที่ปรับแล้ว ไม่ใช่ผลเชิงเหตุ · ไม่เหมาะเมื่อความชันของตัวแปรร่วมต่างกันระหว่างกลุ่ม (ผลต่างของกลุ่มขึ้นกับค่าตัวแปรร่วม) เมื่อผลลัพธ์ไม่ใช่ตัวเลขต่อเนื่อง หรือเมื่อต้องการดูการเปลี่ยนแปลงของค่าที่วัดซ้ำหลายครั้ง (ใช้หัวข้อ 1.5 ถึง 1.7)
ANCOVA (analysis of covariance; Fisher, 1932) compares the mean of a continuous outcome between groups after adjusting for covariates such as the baseline value of the outcome, age or sex. The result is the adjusted mean: the mean each group would be expected to have if all groups had the same covariate values. Use it when the groups start out different on variables related to the outcome; in a randomised trial, adjusting for the baseline value also increases power. In an observational study ANCOVA adjusts only for the covariates that were measured and entered, so it gives an adjusted association, not a causal effect. It is not suitable when the covariate slopes differ between groups (the group difference then depends on the covariate value), when the outcome is not a continuous number, or when the aim is the change of a repeatedly measured value over time (use sections 1.5 to 1.7).
qolscore3) ของกลุ่ม APD (Automated PD) ต่างจากกลุ่ม CAPD (Continuous Ambulatory PD) หรือไม่ เมื่อปรับด้วยคุณภาพชีวิตก่อนการรักษา (Quality of Life Score (Pre), qolscore1) อายุ (age) และเพศ (gender) · ค่าเฉลี่ยดิบหลังการรักษา APD 76.84 เทียบ CAPD 74.89 แต่ก่อนการรักษา APD สูงกว่าอยู่แล้ว (69.35 เทียบ 67.40) ANCOVA จึงถามว่าเมื่อเริ่มจากจุดเดียวกัน ความต่างหลังการรักษายังเหลืออยู่เท่าไรqolscore3) differ between APD (Automated PD) and CAPD (Continuous Ambulatory PD) after adjusting for quality of life before treatment (Quality of Life Score (Pre), qolscore1), age (age) and sex (gender)? The raw post-treatment means are 76.84 for APD and 74.89 for CAPD, but APD patients already scored higher before treatment (69.35 against 67.40), so ANCOVA asks how much of the post-treatment difference remains when both groups start from the same point.2หลักการและสูตรLogic and Formula
- D_gj, x_cj, E_mlj
- ตัวแปรหุ่นของกลุ่ม g (กลุ่มอ้างอิง = รหัสต่ำสุด) ค่าตัวแปรร่วมต่อเนื่อง c และตัวแปรหุ่นของระดับ l ของตัวแปรร่วมแบบกลุ่ม m (ระดับอ้างอิง = รหัสต่ำสุด) ของรายที่ jdummy of group g (reference = lowest code), value of continuous covariate c, and dummy of level l of categorical covariate m (reference = lowest code) for observation j
- n, p, k
- จำนวนรายที่วิเคราะห์ จำนวนสัมประสิทธิ์รวมค่าคงที่ และจำนวนกลุ่มnumber of observations analysed, number of coefficients including the intercept, and number of groups
- x_r(g), w_r
- แถวของตารางทำนาย: กลุ่ม g ตัวแปรร่วมต่อเนื่องที่ค่าเฉลี่ยของทั้งตัวอย่าง และทุกชุดระดับของตัวแปรร่วมแบบกลุ่ม ถ่วงน้ำหนักด้วยผลคูณของสัดส่วนของแต่ละระดับในตัวอย่าง (Searle et al., 1980)rows of the prediction grid: group g, continuous covariates at their sample means, and every combination of categorical-covariate levels weighted by the product of each level's sample proportion (Searle et al., 1980)
- V
- เมทริกซ์ความแปรปรวนร่วมของสัมประสิทธิ์ทั้งหมด (รวมความแปรปรวนร่วมระหว่างสัมประสิทธิ์)covariance matrix of all coefficients, covariances included
- SSIII, SS_res
- ผลรวมกำลังสองแบบ Type III (ทดสอบแต่ละพจน์หลังปรับพจน์อื่นทั้งหมด; Yates, 1934; Searle, 1971) และผลรวมกำลังสองของส่วนเหลือType III sum of squares (each term tested after all others; Yates, 1934; Searle, 1971) and the residual sum of squares
- λ_L, λ_U
- ค่า noncentrality ของการแจกแจง F แบบไม่ศูนย์กลางที่ทำให้ F ที่สังเกตได้อยู่ที่เปอร์เซ็นไทล์ 97.5 และ 2.5 (Steiger, 2004)noncentrality parameters of the noncentral F distribution that place the observed F at its 97.5th and 2.5th percentiles (Steiger, 2004)
- z_ij, ỹ_i
- ระยะห่างสัมบูรณ์จากมัธยฐานของกลุ่ม i (Levene, 1960; Brown & Forsythe, 1974)absolute deviation from the median of group i (Levene, 1960; Brown & Forsythe, 1974)
- e_j, h_jj
- ส่วนเหลือและ leverage ของรายที่ j (MacKinnon & White, 1985)residual and leverage of observation j (MacKinnon & White, 1985)
ขั้นตอนของ DAPH: (1) ตัดแถวที่มีค่าว่างในตัวแปรตาม ตัวแปรกลุ่ม หรือตัวแปรร่วมตัวใดตัวหนึ่ง (2) ตัวแปรร่วมที่กำหนดชนิดเป็นตัวแปรกลุ่ม (nominal, binominal, ordinal) หรือเป็นตัวเลขที่มีค่าต่างกันไม่เกิน 5 ค่า ใส่เป็นหมวดหมู่ ที่เหลือใส่เป็นเส้นตรง (3) ตรวจข้อตกลง: ความชันเท่ากันของตัวแปรร่วมต่อเนื่องทีละตัว Levene แบบมัธยฐานของตัวแปรตามระหว่างกลุ่ม และ Shapiro-Wilk ของส่วนเหลือ (Shapiro & Wilk, 1965) (4) ถ้าการทดสอบความชันตัวใดหรือ Levene ได้ p < 0.05 จะใช้ HC3 กับค่าเฉลี่ยปรับ ผลต่างจากกลุ่มอ้างอิง และผลของตัวแปรร่วม (ค่า p และช่วงเชื่อมั่นทั้งหมดใช้การแจกแจง t ที่ df = n − p) ส่วนการทดสอบ F รวม partial η² และ Cohen's d ใช้ความแปรปรวนแบบปกติ (5) Shapiro-Wilk ไม่เปลี่ยนวิธี เพียงเตือน และบอกว่าการทดสอบ F ทนต่อการละเมิดเมื่อกลุ่มเล็กที่สุดมีอย่างน้อย 30 ราย · HC3 แก้ปัญหาความแปรปรวนไม่เท่ากัน ไม่ได้แก้ความชันต่างกัน เมื่อความชันต่างกัน ผลต่างระหว่างกลุ่มขึ้นกับค่าของตัวแปรร่วม รายงาน Word จึงเตือนให้ตีความด้วยความระมัดระวังและพิจารณาแบบจำลองที่มีปฏิสัมพันธ์ · ในแบบจำลองที่ไม่มีปฏิสัมพันธ์ ผลรวมกำลังสอง Type II กับ Type III เท่ากันทุกพจน์ · ค่า p ของผลต่างเทียบกับกลุ่มอ้างอิงเท่านั้น และไม่ได้ปรับสำหรับการเปรียบเทียบหลายคู่ (ตารางและ Word บอกไว้) · Cohen's d และ f แปลตามเกณฑ์ของ Cohen (1988) · รายงาน Word มีตาราง Type III ค่า VIF ค่า β มาตรฐานของตัวแปรร่วมต่อเนื่อง Cook's distance และ studentized residual ด้วย
What DAPH does: (1) rows with a missing value in the outcome, the group or any covariate are dropped; (2) a covariate whose DAPH type is categorical (nominal, binominal, ordinal), or a number with at most 5 distinct values, enters as categories, and the others enter as straight lines; (3) the assumption checks are equal slopes for each continuous covariate, Levene's test centred on the median applied to the outcome between groups, and Shapiro-Wilk on the residuals (Shapiro & Wilk, 1965); (4) if any slope test or Levene's test gives p < 0.05, HC3 standard errors are used for the adjusted means, the differences from the reference group and the covariate effects (every p-value and interval on the t distribution with df = n − p), while the omnibus F tests, partial η² and Cohen's d keep the classical variance; (5) Shapiro-Wilk changes nothing: it only warns, and says the F test is robust when the smallest group has at least 30 observations. HC3 corrects unequal variances, not unequal slopes: when the slopes differ the group difference depends on the covariate value, so the Word report warns to interpret with caution and to consider a model with the interaction. In a model without interactions the Type II and Type III sums of squares are equal for every term. The p-value of each group difference is against the reference group only and is not adjusted for multiple comparisons (the table and the Word report say so). Cohen's d and f are read with Cohen's (1988) benchmarks. The Word report also gives the Type III table, VIFs, standardised β for continuous covariates, Cook's distance and studentised residuals.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
car, emmeans, sandwich, lmtest, effectsize บนข้อมูลตัวอย่าง DAPHpackages car, emmeans, sandwich, lmtest, effectsize on the DAPH example data# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
suppressPackageStartupMessages({library(car); library(emmeans); library(sandwich); library(lmtest); library(effectsize)})
d$group <- factor(d$group, 1:2, c("CAPD", "APD")) # reference = CAPD (lowest code), as in DAPH
d$gender <- factor(d$gender, 1:2, c("Male", "Female")) # categorical covariate
m <- aggregate(cbind(qolscore1, qolscore3) ~ group, data = d, FUN = mean); m # raw means: pre and post
m[2, -1] - m[1, -1] # APD minus CAPD, before adjustment
fit <- lm(qolscore3 ~ group + qolscore1 + age + gender, data = d) # the ANCOVA DAPH fits, n = 1300
# 1. Assumption checks
anova(fit, update(fit, . ~ . + group:qolscore1)) # equal slopes: baseline QoL, inside the reported model
anova(fit, update(fit, . ~ . + group:age)) # equal slopes: age
leveneTest(qolscore3 ~ group, data = d, center = median) # Levene (median) on the outcome, as DAPH runs it
leveneTest(resid(fit) ~ d$group, center = median) # the same test on the ANCOVA residuals (for comparison)
shapiro.test(resid(fit))
c(n_abs_rstudent_over_3 = sum(abs(rstudent(fit)) > 3), max_abs_rstudent = max(abs(rstudent(fit))),
max_cooks_d = max(cooks.distance(fit))); vif(fit)
# 2. Omnibus tests (classical variance), partial eta squared and its 95% CI
a3 <- Anova(fit, type = 3); a3
a3["group", "Sum Sq"] / (a3["group", "Sum Sq"] + a3["Residuals", "Sum Sq"])
e <- F_to_eta2(a3["group", "F value"], 1, fit$df.residual, ci = 0.95, alternative = "two.sided")
c(partial_eta2 = e$Eta2_partial, CI_low = e$CI_low, CI_high = e$CI_high)
# 3. Levene p < 0.05, so DAPH uses HC3 for the adjusted means, the difference and the covariate effects (t, df = 1295)
V <- vcovHC(fit, type = "HC3")
print(summary(emmeans(fit, ~ group, vcov. = V, weights = "outer")), digits = 7) # covariates at their means; gender weighted by its proportions
coeftest(fit, vcov. = V)
coefci(fit, vcov. = V)
unname(coef(fit)["groupAPD"] / sigma(fit)) # Cohen's d = adjusted difference / sqrt(MSE)
c(R2 = summary(fit)$r.squared, adjR2 = summary(fit)$adj.r.squared, AIC = AIC(fit))
# raw means (pre, post)
group qolscore1 qolscore3
1 CAPD 67.39939 74.88643
2 APD 69.34627 76.84239
qolscore1 qolscore3
2 1.946883 1.955958
# equal slopes inside the reported model: + group:qolscore1, then + group:age
2 1294 280.31 1 0.0095828 0.0442 0.8334
2 1294 280.31 1 0.0080388 0.0371 0.8473
# Levene (median): outcome by group, then ANCOVA residuals by group
group 1 4.2336 0.03983 *
group 1 0.0192 0.8898
W = 0.050869, p-value < 2.2e-16
n_abs_rstudent_over_3 max_abs_rstudent max_cooks_d
7.0000000 34.0189949 0.2555098
group qolscore1 age gender
1.004290 1.018362 1.018118 1.002098
# Anova Table (Type III tests)
group 0 1 1.4030e-01 0.7081
qolscore1 406013 1 1.8756e+06 <2e-16 ***
age 0 1 7.5100e-02 0.7842
gender 0 1 5.2300e-02 0.8192
Residuals 280 1295
partial_eta2 CI_low CI_high
0.0001082967 0.0000000000 0.0039581890
# adjusted means (HC3)
group emmean SE df lower.CL upper.CL
CAPD 75.85059 0.01335416 1295 75.82439 75.87678
APD 75.86027 0.02235657 1295 75.81641 75.90413
# coefficients with HC3 standard errors, then their 95% CI
groupAPD 0.00968649 0.02615170 0.3704 0.7111
qolscore1 0.99974730 0.00023350 4281.5333 <2e-16 ***
age 0.00050715 0.00087637 0.5787 0.5629
genderFemale -0.00622099 0.02166006 -0.2872 0.7740
groupAPD -0.04161786 0.060990834
[1] 0.0208196
R2 adjR2 AIC
0.9993225 0.9993204 1706.8065008
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Equal slopes, Quality of Life Score (Pre): F · df · p | 0.0442 · 1, 1294 · 0.8334 | 0.0442 · 1, 1294 · 0.8334 | < 5e−5 | ✓ PASS |
| Equal slopes, Age: F · df · p | 0.0371 · 1, 1294 · 0.8473 | 0.0371 · 1, 1294 · 0.8473 | < 5e−5 | ✓ PASS |
| Levene (median), outcome by group: F · p | 4.2336 · 0.03983 | 4.2336 · 0.03983 | < 5e−5 | ✓ PASS |
| Shapiro-Wilk W (residuals) | 0.050869 | 0.0509 | < 5e−5 | ✓ PASS |
| Group (Type III): F(1, 1295) · p | 0.1403 · 0.7081 | 0.1403 · 0.7081 | < 5e−5 | ✓ PASS |
| Group: partial η² (95% CI) | 0.0001 (0.000 to 0.004) | 0.0001 (0.000 to 0.004) | < 5e−5 | ✓ PASS |
| Adjusted mean CAPD · SE (HC3) · 95% CI | 75.85059 · 0.01335416 · 75.82439 to 75.87678 | 75.85059 · 0.01335416 · 75.82439 to 75.87678 | < 1e−5 | ✓ PASS |
| Adjusted mean APD · SE (HC3) · 95% CI | 75.86027 · 0.02235657 · 75.81641 to 75.90413 | 75.86027 · 0.02235657 · 75.81641 to 75.90413 | < 1e−5 | ✓ PASS |
| APD − CAPD: adjusted difference · 95% CI (HC3) · p | 0.00968649 · −0.04161786 to 0.06099083 · 0.7111 | 0.00968649 · −0.04161786 to 0.06099083 · 0.7111 | < 1e−8 | ✓ PASS |
| Cohen's d (difference / √MSE) | 0.0208196 | 0.0208196 | < 1e−7 | ✓ PASS |
| Quality of Life Score (Pre): B · SE (HC3) | 0.99974730 · 0.00023350 | 0.99974730 · 0.00023350 | < 1e−8 | ✓ PASS |
| Female vs Male: B · SE (HC3) · p | −0.00622099 · 0.02166006 · 0.7740 | −0.00622099 · 0.02166006 · 0.7740 | < 1e−8 | ✓ PASS |
| R² · VIF (Pre, age, gender) · max Cook's D · max |studentised residual| | 0.9993 · 1.018, 1.018, 1.002 · 0.2555 · 34.019 | 0.9993 · 1.018, 1.018, 1.002 · 0.2555 · 34.019 | < 5e−4 | ✓ PASS |
| AIC (Word model note) | 1706.81 | 1704.81 | 2.00 | ✗ FAIL |
แถวที่ไม่ผ่าน: AIC ของ DAPH ไม่นับความแปรปรวนของส่วนเหลือเป็นพารามิเตอร์ จึงต่ำกว่า AIC() ของ R อยู่ 2 พอดี (BIC ต่ำกว่า ln n) การเปรียบเทียบ AIC ระหว่างแบบจำลอง ANCOVA ใน DAPH ด้วยกันไม่เปลี่ยน แต่อย่าเทียบตัวเลขนี้กับ AIC จาก R หรือจากแบบจำลองชนิดอื่น · ส่วนค่าอื่นทุกค่าตรงกับ R
The failing row: DAPH's AIC does not count the residual variance as a parameter, so it is exactly 2 lower than R's AIC() (BIC is lower by ln n). Comparisons between ANCOVA models within DAPH are unaffected, but do not compare this number with an AIC from R or from another kind of model. Every other value agrees with R.
4การแปลผลและตัวอย่างInterpretation and Example
รายงานค่าเฉลี่ยปรับของแต่ละกลุ่มพร้อม SE และ 95% CI ผลทดสอบรวม F(df1, df2) ค่า p และ partial η² พร้อม 95% CI ผลต่างจากกลุ่มอ้างอิงพร้อม 95% CI ผลของตัวแปรร่วม และผลตรวจข้อตกลงทุกข้อพร้อมค่าสถิติ บอกด้วยว่าใช้ HC3 หรือไม่ · ถ้าความชันต่างกัน อย่าสรุปผลต่างของกลุ่มเป็นค่าเดียว ให้รายงานว่าผลขึ้นกับค่าของตัวแปรร่วม และพิจารณาแบบจำลองที่มีปฏิสัมพันธ์ · ถ้ามีตั้งแต่ 3 กลุ่มและต้องการเปรียบเทียบทุกคู่ ให้ปรับค่า p สำหรับการเปรียบเทียบหลายคู่เอง (เช่น Holm) เพราะค่า p ในตารางไม่ได้ปรับ · ผลที่ "ไม่มีนัยสำคัญ" ไม่ได้แปลว่า "ไม่ต่างกัน" ให้ดูความกว้างของ 95% CI ว่าความต่างที่ข้อมูลยังเข้ากันได้ใหญ่เพียงใด · Levene ของ DAPH ทดสอบการกระจายของตัวแปรตามเอง ไม่ใช่ของส่วนเหลือ ซึ่งเป็นข้อตกลงของ ANCOVA จึงอาจเลือกใช้ HC3 ทั้งที่ส่วนเหลือกระจายเท่ากัน (ดูตัวอย่าง) ผลกระทบมีน้อยเพราะ HC3 ยังใช้ได้เมื่อความแปรปรวนเท่ากัน
Report each group's adjusted mean with SE and 95% CI, the omnibus F(df1, df2), p and partial η² with its 95% CI, the differences from the reference group with 95% CIs, the covariate effects and every assumption check with its statistic, and say whether HC3 was used. If the slopes differ, do not summarise the group difference as a single number: report that it depends on the covariate and consider a model with the interaction. With three or more groups, if every pair is to be compared, adjust the p-values for multiple comparisons yourself (for example Holm), because the p-values in the table are unadjusted. "Not significant" does not mean "no difference": look at how wide the 95% CI is to see how large a difference the data are still compatible with. DAPH's Levene test looks at the spread of the outcome itself, not of the residuals, which is what the ANCOVA assumption concerns, so it can switch to HC3 when the residual spread is equal (see the example); the cost is small because HC3 remains valid when the variances are equal.
📖 References
- Brown, M. B., & Forsythe, A. B. (1974). Robust tests for the equality of variances. Journal of the American Statistical Association, 69(346), 364–367. doi:10.1080/01621459.1974.10482955
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
- Fisher, R. A. (1932). Statistical methods for research workers (4th ed.). Oliver & Boyd.
- Levene, H. (1960). Robust tests for equality of variances. In I. Olkin (Ed.), Contributions to probability and statistics (pp. 278–292). Stanford University Press.
- MacKinnon, J. G., & White, H. (1985). Some heteroskedasticity-consistent covariance matrix estimators with improved finite sample properties. Journal of Econometrics, 29(3), 305–325. doi:10.1016/0304-4076(85)90158-7
- Searle, S. R. (1971). Linear models. Wiley.
- Searle, S. R., Speed, F. M., & Milliken, G. A. (1980). Population marginal means in the linear model: An alternative to least squares means. The American Statistician, 34(4), 216–221. doi:10.1080/00031305.1980.10483031
- Shapiro, S. S., & Wilk, M. B. (1965). An analysis of variance test for normality (complete samples). Biometrika, 52(3–4), 591–611. doi:10.1093/biomet/52.3-4.591
- Steiger, J. H. (2004). Beyond the F test: Effect size confidence intervals and tests of close fit in the analysis of variance and contrast analysis. Psychological Methods, 9(2), 164–182. doi:10.1037/1082-989X.9.2.164
- Yates, F. (1934). The analysis of multiple classifications with unequal numbers in the different classes. Journal of the American Statistical Association, 29(185), 51–66. doi:10.1080/01621459.1934.10502686
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
1.5Repeated-Measures ANOVA
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Repeated-Measures ANOVA (RM-ANOVA, การวิเคราะห์ความแปรปรวนแบบวัดซ้ำ) เปรียบเทียบค่าเฉลี่ยของผลลัพธ์ที่เป็นตัวเลขต่อเนื่องซึ่งวัดซ้ำในคนเดียวกันตั้งแต่ 2 ช่วงเวลาขึ้นไป แต่ละคนเป็นตัวเปรียบเทียบของตัวเอง ความแปรปรวนระหว่างคนจึงถูกแยกออก และทดสอบการเปลี่ยนแปลงได้ไวกว่าการเปรียบเทียบคนละกลุ่ม · ใส่ตัวแปรกลุ่ม (between-subject factor) ได้ เรียกว่าแบบ split-plot หรือ mixed design เพื่อถามว่าการเปลี่ยนแปลงตามเวลาต่างกันระหว่างกลุ่มหรือไม่ (ปฏิสัมพันธ์เวลา × กลุ่ม) · ข้อตกลงสำคัญคือ sphericity (ความแปรปรวนของผลต่างระหว่างทุกคู่ของช่วงเวลาเท่ากัน) ซึ่ง DAPH ตรวจด้วย Mauchly's test (Mauchly, 1940) และแก้ df ด้วย Greenhouse-Geisser (Greenhouse & Geisser, 1959) หรือ Huynh-Feldt (Huynh & Feldt, 1976) · วิธีนี้ใช้เฉพาะคนที่มีค่าครบทุกช่วงเวลา และไม่ปรับตัวแปรร่วม ถ้ามีข้อมูลขาดหายมาก หรือต้องการปรับตัวแปรร่วม ให้ใช้ GEE (หัวข้อ 1.6) ซึ่งใช้ทุกค่าที่วัดได้
Repeated-Measures ANOVA (RM-ANOVA) compares the means of a continuous outcome measured repeatedly in the same people at two or more time points. Each person serves as their own comparison, so the variation between people is removed and changes are detected more sensitively than by comparing different people. A grouping variable (a between-subject factor) can be added, giving a split-plot or mixed design that asks whether the change over time differs between groups (the time × group interaction). The key assumption is sphericity (equal variances of the differences between every pair of time points), which DAPH checks with Mauchly's test (Mauchly, 1940) and corrects with the Greenhouse-Geisser (Greenhouse & Geisser, 1959) or Huynh-Feldt (Huynh & Feldt, 1976) adjustment of the degrees of freedom. The method uses only the people measured at every time point and cannot adjust for covariates; with much missing data, or to adjust for covariates, use GEE (section 1.6), which uses every available measurement.
qolscore1) ระหว่าง (qolscore2) และหลังการรักษา (qolscore3) · คำถาม (ก) คุณภาพชีวิตเปลี่ยนตามเวลาหรือไม่ และเปลี่ยนในช่วงใด (ข) การเปลี่ยนแปลงต่างกันระหว่าง CAPD (Continuous Ambulatory PD) กับ APD (Automated PD) หรือไม่ (ตัวแปรกลุ่ม Treatment Group) และ (ค) ตัวอย่างสามกลุ่ม: รายได้ส่วนตัว (Personal Income) เพื่อแสดงการเปรียบเทียบทุกคู่ของกลุ่มqolscore1), during (qolscore2) and after treatment (qolscore3). Questions: (a) did quality of life change over time, and between which time points; (b) did the change differ between CAPD (Continuous Ambulatory PD) and APD (Automated PD) (grouping variable Treatment Group); and (c) a three-group example, Personal Income, to show how every pair of groups is compared.2หลักการและสูตรLogic and Formula
- T, N, G
- จำนวนช่วงเวลา จำนวนคนที่มีค่าครบทุกช่วงเวลา และจำนวนกลุ่ม (G = 1 เมื่อไม่มีตัวแปรกลุ่ม)number of time points, number of people measured at every time point, and number of groups (G = 1 without a grouping variable)
- Σ̂
- เมทริกซ์ความแปรปรวนร่วม (q × q) ของคะแนนตามเวลาที่แปลงด้วย orthonormal contrasts รวมภายในกลุ่ม (ลบค่าเฉลี่ยของแต่ละกลุ่มออกก่อน)q × q covariance matrix of the time-point scores transformed by orthonormal contrasts, pooled within groups (group means removed first)
- ε̂, ε̃
- ค่าแก้ sphericity ของ Greenhouse-Geisser และ Huynh-Feldt (Lecoutre, 1991) อยู่ระหว่าง 1/(T − 1) ถึง 1Greenhouse-Geisser and Huynh-Feldt (Lecoutre, 1991) sphericity corrections, between 1/(T − 1) and 1
- m_s, MSE_m, α*
- ค่าเฉลี่ยของคนที่ s ทุกช่วงเวลา ความแปรปรวนของค่าเฉลี่ยรายคนภายในกลุ่ม (รวมทุกกลุ่ม df = N − G) และระดับนัยสำคัญที่ใช้: 0.05 เมื่อมี 2 กลุ่ม หรือ 0.05/จำนวนคู่ (Bonferroni) เมื่อมีตั้งแต่ 3 กลุ่มperson s's mean over the time points, the within-group variance of these person means (pooled over all groups, df = N − G), and the level used: 0.05 with two groups, or 0.05/number of pairs (Bonferroni) with three or more
ขั้นตอนของ DAPH: ข้อมูลแบบ Wide (หนึ่งแถวต่อคน คอลัมน์ละช่วงเวลา) ถูกแปลงเป็นแบบ Long ให้อัตโนมัติ ช่วงเวลาเรียงตามลำดับคอลัมน์ที่เลือก · ใช้เฉพาะคนที่มีค่าครบทุกช่วงเวลาในทุกตาราง (ตัดคนที่ค่าไม่ครบออกและบอกจำนวนในหมายเหตุ) ถ้าคนเดียวกันมีหลายค่าในช่วงเวลาเดียวกันจะใช้ค่าเฉลี่ย · ผลภายในผู้ถูกวัด (เวลา และเวลา × กลุ่ม) ทดสอบกับความคลาดเคลื่อนเวลา × คนภายในกลุ่ม ผลของกลุ่มทดสอบกับความแปรปรวนระหว่างคนภายในกลุ่ม แบบ Type III เมื่อกลุ่มขนาดไม่เท่ากัน · ค่า p ของ Mauchly รวมพจน์อันดับสองแบบ stats::mauchly.test ของ R · แถวที่แก้ด้วย ε คำนวณจาก F และ ε ที่ไม่ปัดเศษ · การเปรียบเทียบระหว่างกลุ่ม ณ แต่ละช่วงเวลาใช้ t-test แบบความแปรปรวนร่วม (pooled) ของสองกลุ่มนั้น ปรับค่า p และช่วงเชื่อมั่นแบบ Bonferroni ตามจำนวนช่วงเวลา (× จำนวนคู่เมื่อมีตั้งแต่ 3 กลุ่ม) พร้อม Hedges' g (Hedges, 1981) · เมื่อผลของกลุ่มมีนัยสำคัญ DAPH บอกผลต่างของค่าเฉลี่ยรายคน (เฉลี่ยทุกช่วงเวลา) พร้อม 95% CI (สองกลุ่ม t² = F ของ Group; ตั้งแต่ 3 กลุ่มทุกคู่ ปรับแบบ Bonferroni) และ Word อธิบายความหมายของปฏิสัมพันธ์เวลา × กลุ่ม
What DAPH does: Wide data (one row per person, one column per time point) are reshaped to long automatically, with the time points in the order of the selected columns. Every table uses only the people measured at every time point (the others are excluded and counted in the table note); several values for the same person at the same time point are averaged. The within-subject effects (Time, Time × Group) are tested against the time × subjects-within-groups error and the Group effect against the variation between subjects within groups, Type III when the groups have unequal sizes. The Mauchly p-value includes the second-order term of R's stats::mauchly.test, and the corrected rows are computed from the unrounded F and ε. Between-group comparisons at each time point are pooled-variance t-tests of the two groups concerned, with p and CI Bonferroni-adjusted for the number of time points (× the number of pairs with three or more groups), and Hedges' g (Hedges, 1981). When the Group effect is significant, DAPH reports the difference in person means (averaged over time) with its 95% CI (with two groups t² equals the Group F; with three or more every pair, Bonferroni-adjusted), and the Word report explains what the time × group interaction means.
- d_s, n_ab
- ผลต่างของคนที่ s (ช่วงหลังลบช่วงก่อน) และจำนวนคนที่มีข้อมูลทั้งสองช่วงdifference for person s (later minus earlier) and the number of people measured at both time points
- d̄, s_d, d_z
- ค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานของผลต่าง และขนาดผลแบบจับคู่ (เว้นว่างเมื่อ s_d = 0)mean and standard deviation of the differences, and the paired effect size (left blank when s_d = 0)
- p_(s), m
- ค่า p ที่ยังไม่ปรับเรียงจากน้อยไปมาก และจำนวนคู่unadjusted p-values sorted from smallest, and the number of pairs
Post hoc ของ Repeated-Measures ANOVA (ช่อง "Post Hoc ⓘ" ใน Tab 2 ค่าเริ่มต้น "อัตโนมัติ (แนะนำ)"): เปรียบเทียบช่วงเวลาทีละคู่ด้วย paired t-test ซึ่งใช้เฉพาะผลต่างของคนเดียวกันระหว่างสองช่วงเวลานั้น ไม่ใช้ความคลาดเคลื่อนรวมของทั้งแบบจำลอง เพราะความคลาดเคลื่อนรวมอาศัยข้อตกลง sphericity ซึ่งในข้อมูลวัดซ้ำมักไม่เป็นจริง และทำให้ค่า p เพี้ยน เช่น บางคู่ได้ค่า p เล็กเกินจริง (Maxwell, 1980) · จากนั้นปรับค่า p ด้วย Holm (Holm, 1979): เรียงค่า p จากน้อยไปมาก คูณค่าที่น้อยที่สุดด้วยจำนวนคู่ m ค่าถัดไปด้วย m − 1 ไปเรื่อย ๆ (ค่าที่ได้ต้องไม่ลดลงตามลำดับ) จึงควบคุมโอกาสสรุปผิดได้เท่า Bonferroni แต่พบความต่างที่มีจริงได้มากกว่าหรือเท่ากันเสมอ เช่น วัด 3 ครั้งมี 3 คู่ ค่า p ที่เล็กที่สุดคูณ 3 ค่าถัดไปคูณ 2 ค่าที่ใหญ่ที่สุดคูณ 1 · ช่วงเชื่อมั่นของ Holm ใช้ระดับของ Bonferroni (α/m) เพราะ Holm ไม่มีช่วงเชื่อมั่นพร้อมกันแบบมาตรฐาน · เลือกเองได้: Bonferroni (Dunn, 1961) คูณทุกคู่ด้วย m · Šidák (Šidák, 1967) ใกล้เคียง Bonferroni แต่เข้มน้อยกว่าเล็กน้อย · ไม่ปรับค่า p ใช้เมื่อวางแผนเปรียบเทียบไว้ล่วงหน้าเพียงคู่เดียว และต้องเขียนในรายงานว่าไม่ได้ปรับ · ในแบบที่มีตัวแปรกลุ่ม วิธีที่เลือกใช้กับการเปรียบเทียบช่วงเวลาภายในแต่ละกลุ่ม ส่วนการเปรียบเทียบระหว่างกลุ่ม ณ แต่ละช่วงเวลายังปรับด้วย Bonferroni เสมอ · ถ้าไม่ต้องการตารางเปรียบเทียบรายคู่ ให้เอาเครื่องหมายถูกที่ช่อง Post Hoc ออก
Post hoc for Repeated-Measures ANOVA (the "Post Hoc ⓘ" box in Tab 2, default "Automatic (recommended)"): time points are compared two at a time with a paired t-test, which uses only each person's own differences between those two time points rather than the error term of the whole model. That error term relies on sphericity, which rarely holds in repeated-measures data and distorts the p-values, for example making some pairs look significant when they are not (Maxwell, 1980). The p-values are then adjusted with Holm (Holm, 1979): sort the p-values from smallest, multiply the smallest by the number of pairs m, the next by m − 1, and so on (never letting a later value fall below an earlier one). This controls the chance of a false conclusion as Bonferroni does but always finds at least as many real differences; with 3 measurements there are 3 pairs, so the smallest p is multiplied by 3, the next by 2 and the largest by 1. The Holm CI uses the Bonferroni level (α/m), because Holm has no standard simultaneous interval. You can also choose Bonferroni (Dunn, 1961), which multiplies every pair by m; Šidák (Šidák, 1967), close to Bonferroni but slightly less strict; or no adjustment, for a single comparison planned in advance, which must be reported as unadjusted. With a grouping variable, the chosen method applies to the time comparisons within each group, while the comparison between groups at each time point is always Bonferroni-adjusted. To skip the pairwise tables, untick the Post Hoc box.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
afex (Type III, Mauchly, Greenhouse-Geisser, Huynh-Feldt) และ emmeans บนข้อมูลตัวอย่าง DAPHpackages afex (Type III, Mauchly, Greenhouse-Geisser, Huynh-Feldt) and emmeans on the DAPH example data# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
suppressPackageStartupMessages(library(afex))
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
qol <- c(Pre = "qolscore1", Mid = "qolscore2", Post = "qolscore3")
long <- reshape(d[, c("id", "group", qol)], direction = "long", varying = unname(qol), v.names = "qol",
timevar = "time", times = names(qol), idvar = "id")
long$time <- factor(long$time, levels = names(qol))
mauchly_chi2 <- function(W, df_error, k) { # chi-square of Mauchly's test (as stats::mauchly.test)
p <- k - 1; rho <- 1 - (2 * p^2 + p + 2) / (6 * p * df_error); -df_error * rho * log(W) }
eta2_ci <- function(F, df1, df2) { # partial eta squared and its 95% CI, inverting the noncentral F (Steiger, 2004)
ncp <- function(q) if (pf(F, df1, df2) < q) 0 else
uniroot(function(l) pf(F, df1, df2, ncp = l) - q, c(0, 10 * F * df1 + 100), tol = 1e-10)$root
l <- c(ncp(0.975), ncp(0.025)); c(eta2p = F * df1 / (F * df1 + df2), low = l[1] / (l[1] + df2), high = l[2] / (l[2] + df2)) }
## A. One group: did quality of life change between the three time points? (all 1,300 patients)
s1 <- summary(aov_ez(id = "id", dv = "qol", data = long, within = "time", type = 3))
print(s1$univariate.tests[-1, ], digits = 8) # F assuming sphericity
print(s1$sphericity.tests, digits = 6) # Mauchly W and p
mauchly_chi2(s1$sphericity.tests[1, 1], df_error = 1300 - 1, k = 3)
print(s1$pval.adjustments, digits = 6) # Greenhouse-Geisser and Huynh-Feldt epsilons
eps <- s1$pval.adjustments[1, "GG eps"]; c(df1 = 2 * eps, df2 = 2598 * eps)
eta2_ci(s1$univariate.tests["time", "F value"], 2 * eps, 2598 * eps)
sapply(qol, function(v) { y <- d[[v]]; n <- length(y); se <- sd(y) / sqrt(n) # means, SE, t-based 95% CI
c(mean = mean(y), SE = se, low = mean(y) - qt(0.975, n - 1) * se, high = mean(y) + qt(0.975, n - 1) * se) })
# Post hoc (automatic): paired t-tests, Holm-adjusted p, 95% CI at the Bonferroni level (m = 3 pairs), dz
pairs <- list(c("Mid", "Pre"), c("Post", "Pre"), c("Post", "Mid"))
ph <- t(sapply(pairs, function(ab) {
x <- d[[qol[ab[1]]]]; y <- d[[qol[ab[2]]]]; dif <- x - y
tt <- t.test(x, y, paired = TRUE, conf.level = 1 - 0.05 / 3)
c(diff = mean(dif), low = tt$conf.int[1], high = tt$conf.int[2], p_raw = tt$p.value, dz = mean(dif) / sd(dif)) }))
rownames(ph) <- sapply(pairs, paste, collapse = "-"); ph <- cbind(ph, p_holm = p.adjust(ph[, "p_raw"], "holm"))
print(ph, digits = 8)
mid_pre <- d$qolscore2 - d$qolscore1 # the CI under the other choices, Mid - Pre
rbind(sidak = t.test(mid_pre, conf.level = (1 - 0.05)^(1 / 3))$conf.int,
no_adjustment = t.test(mid_pre)$conf.int)
## B. Two groups: did the change differ between CAPD and APD? (split-plot design)
s2 <- summary(aov_ez(id = "id", dv = "qol", data = long, within = "time", between = "group", type = 3))
print(s2$univariate.tests[-1, ], digits = 8)
print(s2$sphericity.tests, digits = 6)
mauchly_chi2(s2$sphericity.tests[1, 1], df_error = 1300 - 2, k = 3)
print(s2$pval.adjustments, digits = 6)
eps2 <- s2$pval.adjustments[1, "GG eps"]
rbind(group = eta2_ci(s2$univariate.tests["group", "F value"], 1, 1298),
time = eta2_ci(s2$univariate.tests["time", "F value"], 2 * eps2, 2596 * eps2),
time_x_group = eta2_ci(s2$univariate.tests["group:time", "F value"], 2 * eps2, 2596 * eps2))
# Group main effect as a difference: each patient's mean over the three time points
m <- rowMeans(d[, qol])
tt <- t.test(m[d$group == "APD"], m[d$group == "CAPD"], var.equal = TRUE)
c(diff = unname(diff(rev(tt$estimate))), low = tt$conf.int[1], high = tt$conf.int[2], t = unname(tt$statistic))
# Between groups at each time point: pooled t, CI and p at the Bonferroni level (3 time points), Hedges' g
print(sapply(qol, function(v) {
a <- d[[v]][d$group == "APD"]; b <- d[[v]][d$group == "CAPD"]; dfp <- length(a) + length(b) - 2
tt <- t.test(a, b, var.equal = TRUE, conf.level = 1 - 0.05 / 3)
sp <- sqrt(((length(a) - 1) * var(a) + (length(b) - 1) * var(b)) / dfp)
c(diff = mean(a) - mean(b), low = tt$conf.int[1], high = tt$conf.int[2], p_bonf = min(1, 3 * tt$p.value),
g = (mean(a) - mean(b)) / sp * (1 - 3 / (4 * dfp - 1))) }), digits = 7)
# Within each group: two pairs have the same difference for every patient (SD = 0), so no t-test exists for them
sapply(split(d, d$group), function(g) c(sd_mid_pre = sd(g$qolscore2 - g$qolscore1), sd_post_mid = sd(g$qolscore3 - g$qolscore2)))
within_pair <- function(g, a, b) { dif <- g[[a]] - g[[b]]; tt <- t.test(g[[a]], g[[b]], paired = TRUE, conf.level = 1 - 0.05 / 3)
c(diff = mean(dif), low = tt$conf.int[1], high = tt$conf.int[2], dz = mean(dif) / sd(dif)) }
print(rbind(CAPD_post_pre = within_pair(d[d$group == "CAPD", ], "qolscore3", "qolscore1"),
CAPD_post_mid = within_pair(d[d$group == "CAPD", ], "qolscore3", "qolscore2"),
APD_mid_pre = within_pair(d[d$group == "APD", ], "qolscore2", "qolscore1"),
APD_post_pre = within_pair(d[d$group == "APD", ], "qolscore3", "qolscore1")), digits = 8)
## C. Three groups (Personal Income): every pair is compared, Bonferroni-adjusted
suppressPackageStartupMessages(library(emmeans))
d$income <- factor(d$income, 1:3, c("No income", "< 10,000", ">= 10,000")); long$income <- d$income[match(long$id, d$id)]
s3 <- summary(aov_ez(id = "id", dv = "qol", data = long, within = "time", between = "income", type = 3))
print(s3$univariate.tests[-1, c("F value", "Pr(>F)")], digits = 6); print(s3$pval.adjustments[, 1:2], digits = 6)
fm <- lm(m ~ income, data = d) # subject means, error pooled over the 3 groups (df = N - 3)
print(summary(emmeans(fm, revpairwise ~ income, adjust = "bonferroni")$contrasts, infer = TRUE), digits = 7)
pre <- d$qolscore1; lv <- levels(d$income) # between groups at Pre: 3 time points x 3 pairs = 9 comparisons
print(sapply(list(c(2, 1), c(3, 1), c(3, 2)), function(ab) {
tt <- t.test(pre[d$income == lv[ab[1]]], pre[d$income == lv[ab[2]]], var.equal = TRUE, conf.level = 1 - 0.05 / 9)
c(diff = unname(diff(rev(tt$estimate))), low = tt$conf.int[1], high = tt$conf.int[2], p_bonf = min(1, 9 * tt$p.value)) }), digits = 7)
## A. One group (n = 1,300)
Sum Sq num Df Error SS den Df F value Pr(>F)
39141.21782 2.00000 186.94885 2598.00000 271969.80883 0.00000
Test statistic p-value
time 0.591249 7.57207e-149
[1] 682.1214
GG eps Pr(>F[GG]) HF eps Pr(>F[HF])
time 0.709849 0 0.710402 0
df1 df2
1.419698 1844.187385
eta2p low high
0.9952464 0.9949241 0.9955389
Pre Mid Post
mean 68.3638462 73.8619231 75.8553846
SE 0.4949421 0.4949556 0.4949806
low 67.3928728 72.8909232 74.8843357
high 69.3348195 74.8329229 76.8264336
# post hoc: paired t, 95% CI at the Bonferroni level, Holm p (printed as 0: too small to show)
diff low high p_raw dz p_holm
Mid-Pre 5.4980769 5.4716824 5.5244715 0 13.8486848 0
Post-Pre 7.4915385 7.4606496 7.5224273 0 16.1243131 0
Post-Mid 1.9934615 1.9774129 2.0095102 0 8.2581068 0
[,1] [,2]
sidak 5.471751 5.524402
no_adjustment 5.476475 5.519678
## B. Two groups (CAPD, APD)
Sum Sq num Df Error SS den Df F value Pr(>F)
group 3.7018543e+03 1 1237228.87515 1298 3.8836847e+00 0.048969656
time 3.9138173e+04 2 186.92011 2596 2.7178108e+05 0.000000000
group:time 2.8740930e-02 2 186.92011 2596 1.9958114e-01 0.819086328
Test statistic p-value
time 0.590991 7.4152e-149
[1] 682.1633
GG eps Pr(>F[GG]) HF eps Pr(>F[HF])
time 0.709719 0.000000 0.710272 0.000000
group:time 0.709719 0.741123 0.710272 0.741309
eta2p low high
group 0.0029831272 0.0000000 0.011769469
time 0.9952467981 0.9949243 0.995539405
time_x_group 0.0001537369 0.0000000 0.002743447
diff low high t
1.948614162 0.008813429 3.888414895 1.970706648
Pre Mid Post
diff 1.9468830 1.9430011 1.9559584
low -0.4234339 -0.4273948 -0.4145106
high 4.3172000 4.3133970 4.3264273
p_bonf 0.1475411 0.1489235 0.1444461
g 0.1091549 0.1089336 0.1096566
CAPD APD
sd_mid_pre 0.0000000 0.564282
sd_post_mid 0.3398245 0.000000
diff low high dz
CAPD_post_pre 7.4870427 7.4551978 7.5188876 22.0320847
CAPD_post_mid 1.9870427 1.9551978 2.0188876 5.8472610
APD_mid_pre 5.4961180 5.4427462 5.5494898 9.7400206
APD_post_pre 7.4961180 7.4427462 7.5494898 13.2843479
## C. Three groups (Personal Income)
F value Pr(>F)
income 6.22550e+00 0.00203796
time 1.48450e+05 0.00000000
income:time 3.53813e+00 0.00692334
GG eps Pr(>F[GG])
time 0.710957 0.0000000
income:time 0.710957 0.0158691
contrast estimate SE df lower.CL upper.CL t.ratio
< 10,000 - No income -3.455709 1.914200 1297 -8.044217 1.132799 -1.805
>= 10,000 - No income -5.209392 1.506354 1297 -8.820258 -1.598526 -3.458
>= 10,000 - < 10,000 -1.753683 1.434330 1297 -5.191900 1.684534 -1.223
p.value
0.2138
0.0017
0.6651
# between groups at Pre (columns: 2-1, 3-1, 3-2), Bonferroni over 9
diff -3.5169466 -5.275134725 -1.758188
low -8.8026090 -9.456974888 -5.758080
high 1.7687158 -1.093294562 2.241704
p_bonf 0.5778105 0.004277449 1.000000
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| A · Time F(2, 2598) · partial η² (95% CI) | 271969.81 · 0.995 (0.995 to 0.996) | 271969.81 · 0.995 (0.995 to 0.996) | < 0.01 | ✓ PASS |
| A · Mauchly W · χ²(2) · p | 0.591249 · 682.121 · 7.57e−149 | 0.591249 · 682.121 · 7.57e−149 | < 1e−6 | ✓ PASS |
| A · ε GG · ε HF · GG-corrected df | 0.709849 · 0.710402 · 1.42, 1844.19 | 0.709849 · 0.710402 · 1.42, 1844.19 | < 1e−6 | ✓ PASS |
| A · Mean Pre / Mid / Post · SE · 95% CI (Pre) | 68.3638 / 73.8619 / 75.8554 · 0.4949 · 67.3929 to 69.3348 | 68.3638 / 73.8619 / 75.8554 · 0.4949 · 67.3929 to 69.3348 | < 1e−7 | ✓ PASS |
| A · Mid − Pre · 95% CI (Bonferroni level) · dz | 5.4981 · 5.4717 to 5.5245 · 13.849 | 5.4981 · 5.4717 to 5.5245 · 13.849 | < 1e−7 | ✓ PASS |
| A · Post − Pre · 95% CI · dz | 7.4915 · 7.4606 to 7.5224 · 16.124 | 7.4915 · 7.4606 to 7.5224 · 16.124 | < 1e−7 | ✓ PASS |
| A · Post − Mid · 95% CI · dz | 1.9935 · 1.9774 to 2.0095 · 8.258 | 1.9935 · 1.9774 to 2.0095 · 8.258 | < 1e−7 | ✓ PASS |
| A · Holm-adjusted p, all three pairs | 0 (too small to print) | < 0.001 | — | ✓ PASS |
| A · Mid − Pre 95% CI with Šidák / with no adjustment | 5.471751 to 5.524402 / 5.476475 to 5.519678 | 5.471751 to 5.524402 / 5.476475 to 5.519678 | < 1e−6 | ✓ PASS |
| B · Group F(1, 1298) · p · partial η² (95% CI) | 3.8837 · 0.04897 · 0.003 (0.000 to 0.012) | 3.8837 · 0.04897 · 0.003 (0.000 to 0.012) | < 1e−7 | ✓ PASS |
| B · Time F(2, 2596) · GG df · partial η² (95% CI) | 271781.08 · 1.42, 1842.43 · 0.995 (0.995 to 0.996) | 271781.08 · 1.42, 1842.43 · 0.995 (0.995 to 0.996) | < 0.01 | ✓ PASS |
| B · Time × Group F(2, 2596) · p · p (GG) · p (HF) | 0.1996 · 0.8191 · 0.7411 · 0.7413 | 0.1996 · 0.8191 · 0.7411 · 0.7413 | < 1e−6 | ✓ PASS |
| B · Mauchly W · χ²(2) · ε GG · ε HF | 0.590991 · 682.163 · 0.709719 · 0.710272 | 0.590991 · 682.163 · 0.709719 · 0.710272 | < 1e−6 | ✓ PASS |
| B · APD − CAPD averaged over time (95% CI) · t | 1.9486 (0.0088 to 3.8884) · 1.9707 | 1.9486 (0.0088 to 3.8884) · 1.9707 | < 1e−9 | ✓ PASS |
| B · APD − CAPD at Pre / Mid / Post · p (Bonferroni, 3 time points) | 1.9469 / 1.9430 / 1.9560 · 0.1475 / 0.1489 / 0.1444 | 1.9469 / 1.9430 / 1.9560 · 0.1475 / 0.1489 / 0.1444 | < 1e−7 | ✓ PASS |
| B · 95% CI at Pre (Bonferroni level) · Hedges' g Pre / Mid / Post | −0.4234 to 4.3172 · 0.1092 / 0.1089 / 0.1097 | −0.4234 to 4.3172 · 0.1092 / 0.1089 / 0.1097 | < 1e−7 | ✓ PASS |
| B · within CAPD Post − Pre (CI, dz) · within APD Mid − Pre (CI, dz) | 7.4870 (7.4552 to 7.5189), 22.032 · 5.4961 (5.4427 to 5.5495), 9.740 | 7.4870 (7.4552 to 7.5189), 22.032 · 5.4961 (5.4427 to 5.5495), 9.740 | < 1e−7 | ✓ PASS |
| C · Income F · Time × Income F · p (GG) | 6.2255 · 3.5381 · 0.0159 | 6.2255 · 3.5381 · 0.0159 | < 1e−4 | ✓ PASS |
| C · averaged over time, 3 pairs (Bonferroni): differences (95% CI) · p | −3.4557 (−8.0442 to 1.1328) · −5.2094 (−8.8203 to −1.5985) · −1.7537 (−5.1919 to 1.6845) · 0.2138 / 0.0017 / 0.6651 | −3.4557 (−8.0442 to 1.1328) · −5.2094 (−8.8203 to −1.5985) · −1.7537 (−5.1919 to 1.6845) · 0.2138 / 0.0017 / 0.6651 | < 1e−6 | ✓ PASS |
| C · at Pre, 3 pairs (Bonferroni over 9): differences · p | −3.5169 / −5.2751 / −1.7582 · 0.5778 / 0.0043 / 1.0000 | −3.5169 / −5.2751 / −1.7582 · 0.5778 / 0.0043 / 1.0000 | < 1e−7 | ✓ PASS |
ทุกค่าตรงกับ R 4.3.3 · คู่ภายในกลุ่มอีกสองคู่ไม่อยู่ในตาราง เพราะทุกคนในกลุ่ม CAPD มีผลต่างระหว่างช่วงกลางกับก่อนการรักษาเท่ากันพอดี (5.5) และทุกคนในกลุ่ม APD มีผลต่างระหว่างหลังกับช่วงกลางเท่ากันพอดี (2.0) ส่วนเบี่ยงเบนมาตรฐานของผลต่างเป็น 0 (ผล R ข้างบน) จึงคำนวณ paired t-test ไม่ได้ (t.test ของ R หยุดทำงาน) DAPH แสดงช่วงเชื่อมั่นเป็นค่าเดียว (5.50 ถึง 5.50 และ 2.00 ถึง 2.00) เว้น dz ว่าง แต่พิมพ์ p < 0.001 ให้อ่านสองแถวนี้เป็นค่าบรรยายเท่านั้น ไม่ใช่ผลการทดสอบ · ตาราง Pairwise Comparisons ของ DAPH แสดงคู่เป็นช่วงหลังลบช่วงก่อน และ t.test(x, y, paired = TRUE) ใน R ต้องให้ x และ y เป็นคนเดียวกันในลำดับเดียวกัน ซึ่งเป็นจริงเมื่อใช้คอลัมน์ของข้อมูลแบบ Wide
Every value agrees with R 4.3.3. Two within-group pairs are not in the table: every CAPD patient has exactly the same Mid − Pre difference (5.5) and every APD patient exactly the same Post − Mid difference (2.0), so the SD of the differences is 0 (R output above) and no paired t-test exists (R's t.test stops). DAPH shows their CI as a single value (5.50 to 5.50 and 2.00 to 2.00) and leaves dz blank, but prints p < 0.001; read these two rows as descriptive only, not as test results. The DAPH Pairwise Comparisons tables list each pair as later minus earlier; in R, t.test(x, y, paired = TRUE) needs x and y to hold the same people in the same order, which the columns of wide data do.
4การแปลผลและตัวอย่างInterpretation and Example
DAPH เลือกแถวที่รายงานให้อัตโนมัติ: ตาราง omnibus แสดงทั้งแถวที่ไม่แก้ และแถวที่แก้ด้วย Greenhouse-Geisser กับ Huynh-Feldt · การแปลผลใช้แถวเดียวตามผลของ Mauchly — ถ้า Mauchly p ≥ 0.05 (หรือมีเพียง 2 ช่วงเวลา ซึ่ง sphericity เป็นจริงเสมอ) ใช้แถวที่ไม่แก้ · ถ้า Mauchly p < 0.05 ใช้ Greenhouse-Geisser เมื่อ ε < 0.75 ไม่อย่างนั้นใช้ Huynh-Feldt (Girden, 1992) · ผลของกลุ่ม (Group) เป็นผลระหว่างผู้ถูกวัด ไม่ต้องแก้ · Mauchly's test มีกำลังต่ำเมื่อคนน้อยและไวมากเมื่อคนมาก จึงควรดู ε ประกอบ ถ้าการละเมิดรุนแรง (ε ใกล้ 1/(T − 1)) ควรพิจารณา GEE (หัวข้อ 1.6) ร่วมด้วย · ถ้าปฏิสัมพันธ์เวลา × กลุ่มมีนัยสำคัญ การเปลี่ยนแปลงตามเวลาต่างกันระหว่างกลุ่ม ผลหลักของเวลาและของกลุ่ม (ซึ่งเฉลี่ยข้ามอีกปัจจัยหนึ่ง) จึงอธิบายผลได้ไม่ครบ ให้ดูการเปรียบเทียบภายในกลุ่มและระหว่างกลุ่ม ณ แต่ละช่วงเวลา · การเปรียบเทียบระหว่างกลุ่ม ณ แต่ละช่วงเวลาปรับค่า p แบบ Bonferroni และช่วงเชื่อมั่นใช้ระดับเดียวกัน จึงสอดคล้องกัน: ช่วงไม่คร่อม 0 เมื่อ p ที่ปรับแล้วต่ำกว่า 0.05
DAPH chooses the row to report: the omnibus table lists the uncorrected row and the Greenhouse-Geisser and Huynh-Feldt rows. The interpretation uses one of them according to Mauchly's test: if Mauchly p ≥ 0.05 (or there are only 2 time points, where sphericity always holds) the uncorrected row; if Mauchly p < 0.05, Greenhouse-Geisser when ε < 0.75 and Huynh-Feldt otherwise (Girden, 1992). The Group effect is between subjects and needs no correction. Mauchly's test has little power with few people and flags trivial departures with many, so look at ε as well; with a severe violation (ε near 1/(T − 1)) consider GEE (section 1.6) too. A significant time × group interaction means the change over time differed between groups, so the main effects of Time and Group, which average over the other factor, do not describe the result on their own; read the within-group comparisons and the between-group comparisons at each time point. Between-group comparisons at each time point are Bonferroni-adjusted and their confidence interval is at the same level, so the two agree: the interval excludes 0 exactly when the adjusted p is below 0.05.
การอ่านผล post hoc: ชื่อตาราง "Pairwise Comparisons" บอกวิธีที่ใช้จริง เช่น "paired t-tests with Holm adjustment" · แต่ละแถวคือคู่ของช่วงเวลา (ช่วงหลังลบช่วงก่อน) พร้อมผลต่างเฉลี่ย ช่วงเชื่อมั่น 95% ที่ปรับตามวิธีที่ใช้ ค่า p ที่ปรับแล้ว และ dz · คู่ที่ค่า p ที่ปรับแล้วต่ำกว่า 0.05 คือคู่ที่ต่างกันอย่างมีนัยสำคัญ ไม่ต้องหารด้วยจำนวนคู่อีก · อ่านคู่เมื่อการทดสอบรวมของเวลามีนัยสำคัญ (หลังพิจารณา sphericity ตามข้างต้น) DAPH แสดงตารางคู่ทุกครั้งที่ติ๊ก Post Hoc เพื่อให้ตรวจดูได้ แต่ถ้าการทดสอบรวมไม่มีนัยสำคัญ ไม่ควรสรุปจากคู่ใดคู่หนึ่ง · ผลที่ไม่มีนัยสำคัญไม่ได้พิสูจน์ว่าไม่ต่างกัน · ประโยคในรายงาน Word: "เปรียบเทียบรายคู่ระหว่างช่วงเวลาด้วย paired t-test ซึ่งไม่อาศัยข้อสมมติ sphericity (Maxwell, 1980) และปรับค่า p ด้วย Holm (Holm, 1979) ขั้นตอน เกณฑ์การเลือกวิธี post hoc และเกณฑ์การแปลผลอธิบายไว้ใน DAPH Guide หัวข้อ 1.5 (Sornlorm, 2026b)"
Reading the post hoc table: the "Pairwise Comparisons" title names the method actually used, for example "paired t-tests with Holm adjustment". Each row is a pair of time points (later minus earlier) with the mean difference, a 95% CI adjusted for the method used, the adjusted p-value and dz. A pair whose adjusted p is below 0.05 differs significantly, with no further division by the number of pairs. Read pairs when the overall time effect is significant (after the sphericity check above): DAPH shows the pairwise table whenever Post Hoc is ticked so it can be inspected, but if the overall test is not significant, do not draw conclusions from any single pair. A non-significant result does not prove that there is no difference. The Word report sentence: "Pairwise comparisons between time points used paired t-tests, which do not rely on sphericity (Maxwell, 1980), with Holm's adjustment (Holm, 1979). The procedure, the rule for choosing the post hoc method and the interpretation criteria are documented in DAPH Guide, section 1.5 (Sornlorm, 2026b)."
📖 References
- Dunn, O. J. (1961). Multiple comparisons among means. Journal of the American Statistical Association, 56(293), 52–64. doi:10.1080/01621459.1961.10482090
- Girden, E. R. (1992). ANOVA: Repeated measures. Sage.
- Greenhouse, S. W., & Geisser, S. (1959). On methods in the analysis of profile data. Psychometrika, 24(2), 95–112. doi:10.1007/BF02289823
- Hedges, L. V. (1981). Distribution theory for Glass's estimator of effect size and related estimators. Journal of Educational Statistics, 6(2), 107–128. doi:10.3102/10769986006002107
- Holm, S. (1979). A simple sequentially rejective multiple test procedure. Scandinavian Journal of Statistics, 6(2), 65–70.
- Huynh, H., & Feldt, L. S. (1976). Estimation of the Box correction for degrees of freedom from sample data in randomized block and split-plot designs. Journal of Educational Statistics, 1(1), 69–82. doi:10.3102/10769986001001069
- Lecoutre, B. (1991). A correction for the ε̃ approximate test in repeated measures designs with two or more independent groups. Journal of Educational Statistics, 16(4), 371–372. doi:10.3102/10769986016004371
- Mauchly, J. W. (1940). Significance test for sphericity of a normal n-variate distribution. The Annals of Mathematical Statistics, 11(2), 204–209. doi:10.1214/aoms/1177731915
- Maxwell, S. E. (1980). Pairwise multiple comparisons in repeated measures designs. Journal of Educational Statistics, 5(3), 269–287. doi:10.3102/10769986005003269
- Šidák, Z. (1967). Rectangular confidence regions for the means of multivariate normal distributions. Journal of the American Statistical Association, 62(318), 626–633. doi:10.1080/01621459.1967.10482935
- Steiger, J. H. (2004). Beyond the F test: Effect size confidence intervals and tests of close fit in the analysis of variance and contrast analysis. Psychological Methods, 9(2), 164–182. doi:10.1037/1082-989X.9.2.164
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
1.6GEE — Generalized Estimating Equations (Linear)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
GEE (generalized estimating equations, สมการประมาณค่าทั่วไป; Liang & Zeger, 1986; Zeger & Liang, 1986) วิเคราะห์ข้อมูลที่ค่าภายในกลุ่มเดียวกันสัมพันธ์กัน เช่น วัดซ้ำในคนเดียวกัน โดยประมาณผลเฉลี่ยในประชากร (population-averaged effect) และใช้ความคลาดเคลื่อนมาตรฐานแบบ robust (sandwich) ซึ่งยังใช้ได้แม้โครงสร้างสหสัมพันธ์ที่สมมติ (working correlation) ไม่ตรงกับความจริง · ใน DAPH สถิติ "GEE (Repeated Measures)" ตอบคำถามว่า ค่าเฉลี่ยของผลลัพธ์ต่อเนื่องที่วัดซ้ำต่างกันระหว่างกลุ่มเท่าไร เมื่อเฉลี่ยทุกช่วงเวลาและปรับช่วงเวลา (และตัวแปรร่วม) · ต่างจาก RM-ANOVA (หัวข้อ 1.5) ตรงที่ใช้ทุกค่าที่วัดได้ ไม่ต้องมีครบทุกช่วงเวลา และปรับตัวแปรร่วมได้ · ไม่เหมาะเมื่อคำถามคือ "การเปลี่ยนแปลงตามเวลาต่างกันระหว่างกลุ่มหรือไม่" (แบบจำลองของ DAPH ไม่มีปฏิสัมพันธ์เวลา × กลุ่ม ใช้หัวข้อ 1.5) เมื่อมีจำนวนคนน้อย (sandwich SE ต้องการกลุ่มจำนวนมาก) หรือเมื่อค่าที่ขาดหายเกี่ยวข้องกับผลลัพธ์
GEE (generalized estimating equations; Liang & Zeger, 1986; Zeger & Liang, 1986) analyses data whose values are correlated within clusters, such as repeated measurements on the same person, by estimating a population-averaged effect with robust (sandwich) standard errors that remain valid even when the assumed (working) correlation structure is wrong. In DAPH the statistic "GEE (Repeated Measures)" answers how much the mean of a repeatedly measured continuous outcome differs between groups, averaged over the time points and adjusted for time (and covariates). Unlike RM-ANOVA (section 1.5) it uses every available measurement, not only people measured at every time point, and it can adjust for covariates. It is not the tool when the question is whether the change over time differs between groups (DAPH's model has no time × group interaction; use section 1.5), when there are few people (the sandwich SE needs many clusters), or when missing measurements are related to the outcome.
qolscore1) ระหว่าง (qolscore2) และหลังการรักษา (qolscore3) · คำถาม: เมื่อเฉลี่ยทั้งสามช่วงเวลา คุณภาพชีวิตของกลุ่ม APD (Automated PD) ต่างจาก CAPD (Continuous Ambulatory PD) เท่าไร (ตัวแปรกลุ่ม Treatment Group) และเมื่อปรับอายุ (age) และเพศ (gender) แล้วต่างกันเท่าไรqolscore1), during (qolscore2) and after treatment (qolscore3). Question: averaged over the three time points, how much does the quality of life of APD (Automated PD) patients differ from that of CAPD (Continuous Ambulatory PD) patients (grouping variable Treatment Group), and how much after adjusting for age (age) and sex (gender)?2หลักการและสูตรLogic and Formula
- τ_g
- ผลต่างของค่าเฉลี่ยระหว่างกลุ่ม g กับกลุ่มอ้างอิง (รหัสต่ำสุด) เฉลี่ยทุกช่วงเวลา ปรับช่วงเวลาและตัวแปรร่วม = "Adj. Mean diff." ในรายงานmean difference between group g and the reference group (lowest code), averaged over the time points and adjusted for time and covariates = "Adj. Mean diff." in the report
- K, n_i, N, p
- จำนวนคน (กลุ่มของการวัดซ้ำ) จำนวนครั้งที่วัดของคนที่ i จำนวนค่าทั้งหมด และจำนวนสัมประสิทธิ์number of people (clusters), number of measurements of person i, total number of measurements, and number of coefficients
- α, φ
- สหสัมพันธ์ระหว่างสองค่าของคนเดียวกัน (เท่ากันทุกคู่ของช่วงเวลา) และความแปรปรวนของส่วนเหลือ ประมาณด้วยวิธีโมเมนต์correlation between two measurements of the same person (the same for every pair of time points) and the residual variance, both estimated by the method of moments
- A, B
- "ขนมปัง" (ความแปรปรวนตามแบบจำลอง) และ "ไส้" (ความแปรปรวนจากส่วนเหลือจริงของแต่ละคน) ของตัวประมาณ sandwich ไม่มีการแก้สำหรับตัวอย่างเล็กthe "bread" (model-based) and the "meat" (each person's actual residuals) of the sandwich estimator, with no small-sample correction
ขั้นตอนของ DAPH: ข้อมูลแบบ Wide (หนึ่งแถวต่อคน คอลัมน์ละช่วงเวลา) ถูกแปลงเป็นแบบ Long ให้อัตโนมัติ ตัวแปรกลุ่มและตัวแปรร่วมถือว่าคงที่ตลอดเวลา · ต้องเลือกทั้ง Subject ID และตัวแปรกลุ่ม (ถ้าไม่เลือกตัวแปรกลุ่ม DAPH แจ้งให้เลือก) · ช่วงเวลาเข้าแบบจำลองเป็นหมวดหมู่ (ช่วงแรกเป็นค่าอ้างอิง) ผลต่างของกลุ่มจึงปรับช่วงเวลาแล้ว · ไม่มีพจน์ปฏิสัมพันธ์ ผลต่างของกลุ่มจึงเป็นผลต่างเฉลี่ยรวมทุกช่วงเวลา · working correlation เป็นแบบ exchangeable เสมอ (เลือกแบบอื่นไม่ได้ และไม่คำนวณ QIC; Pan, 2001) · ตัดเฉพาะแถว (คน × ช่วงเวลา) ที่มีค่าว่าง คนที่มีค่าไม่ครบทุกช่วงเวลายังใช้ค่าที่มีอยู่ · ตัวแปรร่วมที่กำหนดชนิดเป็นตัวแปรกลุ่ม (nominal, binominal, ordinal) เข้าแบบจำลองเป็นหมวดหมู่ (ตัวแปรหุ่น ระดับอ้างอิง = รหัสต่ำสุด) ตัวแปรร่วมที่เป็นตัวเลขเข้าเป็นเส้นตรง · รายงานแสดง n และ Mean (SD) ของแต่ละกลุ่มในแต่ละช่วงเวลา และ Adj. Mean diff. พร้อม 95% CI และค่า p ของแต่ละกลุ่มเทียบกลุ่มอ้างอิง หมายเหตุใต้ตารางและย่อหน้าแรกของการแปลผลใน Word บอกแบบจำลอง (มีช่วงเวลาในแบบจำลอง, Gaussian family, working correlation แบบ exchangeable พร้อมค่า α ที่ประมาณได้, robust SE) และตัวแปรที่ปรับ ส่วนสัมประสิทธิ์ของช่วงเวลาและของตัวแปรร่วมไม่แสดง (ตารางข้างล่างดึงจาก engine)
What DAPH does: wide data (one row per person, one column per time point) are reshaped to long automatically, and the group and covariates are treated as constant over time. Both a Subject ID and a Group Variable must be chosen (without a Group Variable DAPH asks for one). Time enters as categories (the first time point is the reference), so the group difference is adjusted for time. There is no interaction term, so the group difference is the overall difference averaged over the time points. The working correlation is always exchangeable (no other structure can be chosen and no QIC is computed; Pan, 2001). Only rows (person × time point) with a missing value are dropped, so a person with some time points missing still contributes the others. A covariate whose DAPH type is categorical (nominal, binominal, ordinal) enters as categories (dummy variables, reference = lowest code), and a numeric covariate as a straight line. The report gives n and Mean (SD) of each group at each time point and the Adj. Mean diff. with 95% CI and p for each group against the reference; the table note and the first interpretation paragraph of the Word report state the model (time point in the model, Gaussian family, exchangeable working correlation with the estimated α, robust SEs) and the covariates adjusted for, while the coefficients of time and of the covariates are not shown (the table below reads them from the engine).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
geepack (geeglm; Halekoh et al., 2006) บนข้อมูลตัวอย่าง DAPH ในรูปแบบ Long เรียงตามคนแล้วตามช่วงเวลาpackage geepack (geeglm; Halekoh et al., 2006) on the DAPH example data in long format, ordered by person and then time point# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(geepack)
d$group <- factor(d$group, 1:2, c("CAPD", "APD")) # reference = CAPD (lowest code), as in DAPH
qol <- c(Pre = "qolscore1", Mid = "qolscore2", Post = "qolscore3")
d$gender <- factor(d$gender, 1:2, c("Male", "Female")) # categorical covariates enter as factors, as in DAPH
d$bmi_group <- factor(d$bmi_group)
long <- reshape(d[, c("id", "group", "age", "gender", "bmi_group", qol)], direction = "long", varying = unname(qol),
v.names = "qol", timevar = "time", times = names(qol), idvar = "id")
long$time <- factor(long$time, levels = names(qol)) # time enters as categories, Pre = reference
long <- long[order(long$id, long$time), ] # geeglm needs each person's rows together
# descriptive table of the DAPH report: n, mean (SD) by group at each time point
aggregate(cbind(qolscore1, qolscore2, qolscore3) ~ group, data = d, FUN = function(y) c(n = length(y), mean = mean(y), sd = sd(y)))
# GEE: Gaussian, identity link, exchangeable working correlation, robust (sandwich) SE
g <- geeglm(qol ~ group + time, id = id, data = long, family = gaussian, corstr = "exchangeable")
print(coef(summary(g)), digits = 8) # estimate, robust SE, Wald chi-square, p
est <- coef(g)["groupAPD"]; se <- sqrt(diag(vcov(g)))["groupAPD"]
c(adj_mean_diff = unname(est), low = unname(est - qnorm(0.975) * se), high = unname(est + qnorm(0.975) * se),
z = unname(est / se), p = unname(2 * pnorm(-abs(est / se))))
c(alpha = unname(g$geese$alpha)) # estimated working correlation
gee_ci <- function(fit) { e <- coef(fit)["groupAPD"]; s <- sqrt(diag(vcov(fit)))["groupAPD"]
c(adj_mean_diff = unname(e), low = unname(e - qnorm(0.975) * s), high = unname(e + qnorm(0.975) * s)) }
# with covariates age (numeric) and gender (categorical)
g2 <- geeglm(qol ~ group + time + age + gender, id = id, data = long, family = gaussian, corstr = "exchangeable")
print(coef(summary(g2)), digits = 8)
gee_ci(g2)
# with a categorical covariate of 4 levels: BMI group (dummy variables, reference = level 1)
g3 <- geeglm(qol ~ group + time + bmi_group, id = id, data = long, family = gaussian, corstr = "exchangeable")
print(coef(summary(g3))["groupAPD", ], digits = 8)
gee_ci(g3)
# n, mean and SD by group at Pre, Mid and Post (the DAPH descriptive columns)
group qolscore1.n qolscore1.mean qolscore1.sd qolscore2.n qolscore2.mean
1 CAPD 656.00000 67.39939 17.37267 656.00000 72.89939
2 APD 644.00000 69.34627 18.27557 644.00000 74.84239
qolscore2.sd qolscore3.n qolscore3.mean qolscore3.sd
1 17.37267 656.00000 74.88643 17.37379
2 18.27674 644.00000 76.84239 18.27674
# GEE: group + time
Estimate Std.err Wald Pr(>|W|)
(Intercept) 67.3985327 0.677800717 9.8877354e+03 0.000000000
groupAPD 1.9486142 0.988489956 3.8860393e+00 0.048689119
timeMid 5.4980769 0.011006862 2.4951383e+05 0.000000000
timePost 7.4915385 0.012881043 3.3825171e+05 0.000000000
adj_mean_diff low high z p
1.94861416 0.01120945 3.88601888 1.97130396 0.04868912
alpha
0.9997734
# GEE with age and gender
Estimate Std.err Wald Pr(>|W|)
(Intercept) 89.16849536 4.925532794 3.2773019e+02 0.0000000e+00
groupAPD 1.78935098 0.979857845 3.3347626e+00 6.7830195e-02
timeMid 5.49807692 0.011006862 2.4951383e+05 0.0000000e+00
timePost 7.49153846 0.012881043 3.3825171e+05 0.0000000e+00
age -0.31051960 0.068976195 2.0266538e+01 6.7368596e-06
genderFemale -0.16374143 1.064851083 2.3645005e-02 8.7779162e-01
adj_mean_diff low high
1.7893510 -0.1311351 3.7098371
# GEE with BMI group (4 levels)
Estimate Std.err Wald Pr(>|W|)
groupAPD 1.9257738 0.98679504 3.8085236 0.050992381
adj_mean_diff low high
1.925773822 -0.008308908 3.859856552
| ค่าที่ตรวจQuantity | R (geepack) | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Pre: Mean (SD) CAPD · APD | 67.40 (17.37) · 69.35 (18.28) | 67.40 (17.37) · 69.35 (18.28) | < 0.005 | ✓ PASS |
| Adj. Mean diff. APD − CAPD · robust SE | 1.9486142 · 0.9884900 | 1.9486142 · 0.9884900 | < 1e−9 | ✓ PASS |
| 95% CI · p | 0.0112094 to 3.8860189 · 0.0486891 | 0.0112094 to 3.8860189 · 0.0486891 | < 1e−9 | ✓ PASS |
| Time: Mid − Pre (robust SE) · Post − Pre (robust SE) | 5.4980769 (0.0110069) · 7.4915385 (0.0128810) | 5.4980769 (0.0110069) · 7.4915385 (0.0128810) | < 1e−9 | ✓ PASS |
| Working correlation α | 0.9997734 | 0.9997734 | < 1e−9 | ✓ PASS |
| With age and gender: Adj. Mean diff. (95% CI) · p | 1.7893510 (−0.1311351 to 3.7098371) · 0.0678302 | 1.7893510 (−0.1311351 to 3.7098371) · 0.0678302 | < 1e−9 | ✓ PASS |
| With age and gender: age · Female vs Male (robust SE) | −0.3105196 (0.0689762) · −0.1637414 (1.0648511) | −0.3105196 (0.0689762) · −0.1637414 (1.0648511) | < 1e−9 | ✓ PASS |
| With BMI group (4 levels, as categories): Adj. Mean diff. (95% CI) · p | 1.9257738 (−0.0083089 to 3.8598566) · 0.0509924 | 1.9257738 (−0.0083089 to 3.8598566) · 0.0509924 | < 1e−9 | ✓ PASS |
ทุกค่าตรงกับ geepack (R 4.3.3) ความต่างไม่เกิน 1e−9 · ค่าความแปรปรวนของส่วนเหลือ φ ต่างกันเล็กน้อยเพราะ geepack หารด้วย N ส่วน DAPH หารด้วย N − p แต่ไม่มีผลต่อค่าประมาณ ค่า SE แบบ robust และค่า α
Every value agrees with geepack (R 4.3.3) to within 1e−9. The residual variance φ differs slightly because geepack divides by N and DAPH by N − p, which changes neither the estimates, the robust SEs nor α.
4การแปลผลและตัวอย่างInterpretation and Example
Adj. Mean diff. ของ GEE คือผลต่างเฉลี่ยในประชากรระหว่างกลุ่ม เฉลี่ยทุกช่วงเวลา (หน่วยเดียวกับผลลัพธ์) · สำหรับผลลัพธ์ต่อเนื่องที่ใช้ identity link ผลเฉลี่ยในประชากรและผลภายในคน (ค่าคงที่ของ mixed model หัวข้อ 1.7) ประมาณปริมาณเดียวกัน ความต่างของสองแนวคิดมีความหมายเมื่อใช้ link ที่ไม่ใช่เส้นตรง เช่น logistic (หัวข้อ 2.3) · รายงานผลต่างพร้อม 95% CI (robust) ค่า p โครงสร้าง working correlation และจำนวนคนที่ใช้ · ค่า p ทดสอบแบบสองทาง ด้วยการแจกแจงปกติ · ค่าที่ไม่มีนัยสำคัญไม่ได้แปลว่าไม่ต่างกัน · GEE ที่ใช้ทุกค่าที่มีอยู่ให้ผลไม่เอนเอียงเมื่อการขาดหายของข้อมูลไม่เกี่ยวกับผลลัพธ์ (missing completely at random; Liang & Zeger, 1986) · ถ้าต้องการเทียบ working correlation หลายแบบ ใช้ QIC (Pan, 2001) ใน R ด้วย geepack::QIC()
GEE's Adj. Mean diff. is the population-averaged difference between groups, averaged over the time points, in the units of the outcome. For a continuous outcome with the identity link, the population-averaged effect and the within-person effect (the fixed effect of a mixed model, section 1.7) estimate the same quantity; the distinction matters for non-linear links such as the logistic (section 2.3). Report the difference with its robust 95% CI, the p-value, the working correlation structure and the number of people analysed. The p-value is two-sided, from the normal distribution. A non-significant result does not mean no difference. GEE using every available measurement is unbiased when missingness is unrelated to the outcome (missing completely at random; Liang & Zeger, 1986). To compare working correlation structures, use QIC (Pan, 2001) in R with geepack::QIC().
📖 References
- Halekoh, U., Højsgaard, S., & Yan, J. (2006). The R package geepack for generalized estimating equations. Journal of Statistical Software, 15(2). doi:10.18637/jss.v015.i02
- Liang, K.-Y., & Zeger, S. L. (1986). Longitudinal data analysis using generalized linear models. Biometrika, 73(1), 13–22. doi:10.1093/biomet/73.1.13
- Pan, W. (2001). Akaike's information criterion in generalized estimating equations. Biometrics, 57(1), 120–125. doi:10.1111/j.0006-341X.2001.00120.x
- Zeger, S. L., & Liang, K.-Y. (1986). Longitudinal data analysis for discrete and continuous outcomes. Biometrics, 42(1), 121–130. doi:10.2307/2531248
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
1.7Mixed-Effect Linear Regression (LMM)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Mixed-Effect Linear Regression (linear mixed model, LMM, แบบจำลองเชิงเส้นผสม; Laird & Ware, 1982) คือการถดถอยเชิงเส้นที่เพิ่มผลสุ่ม (random effect) ให้ข้อมูลที่ซ้อนกันเป็นกลุ่ม (cluster) เช่น ผู้ป่วยในอำเภอหรือโรงพยาบาลเดียวกัน ซึ่งมีค่าใกล้กันมากกว่าผู้ป่วยต่างกลุ่ม · ถ้าไม่คำนึงถึงกลุ่ม ความคลาดเคลื่อนมาตรฐานจะผิด และผลของตัวแปรที่ต่างกันระหว่างกลุ่มอาจปนกับผลของกลุ่ม · DAPH ใส่ค่าคงที่สุ่ม (random intercept) หนึ่งตัวต่อกลุ่ม: แต่ละกลุ่มมีระดับพื้นฐานของผลลัพธ์ของตัวเอง ส่วนผลของตัวแปรอิสระ (fixed effects) เท่ากันทุกกลุ่ม · ใช้เมื่อผลลัพธ์เป็นตัวเลขต่อเนื่องและมีกลุ่มจำนวนพอสมควร · ไม่เหมาะเมื่อมีกลุ่มน้อยมาก (การประมาณความแปรปรวนระหว่างกลุ่มไม่แม่น) เมื่อต้องการให้ความชันต่างกันระหว่างกลุ่ม (random slope ซึ่ง DAPH ไม่มี) หรือเมื่อข้อมูลวัดซ้ำอยู่ในรูปแบบ Wide (ใช้หัวข้อ 1.5 หรือ 1.6)
Mixed-Effect Linear Regression (a linear mixed model, LMM; Laird & Ware, 1982) is linear regression with a random effect for data nested in clusters, such as patients in the same district or hospital, who resemble each other more than patients in different clusters. Ignoring the clusters gives wrong standard errors, and the effect of a variable that differs between clusters can be mixed up with the cluster effect. DAPH fits one random intercept per cluster: each cluster has its own baseline level of the outcome, while the effects of the independent variables (fixed effects) are the same in every cluster. Use it for a continuous outcome with a reasonable number of clusters. It is not suitable with very few clusters (the between-cluster variance is then estimated poorly), when the slopes should vary between clusters (random slopes, which DAPH does not fit), or for repeated measures stored in wide format (use section 1.5 or 1.6).
qolscore3) ของผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย สัมพันธ์กับกลุ่มรักษา (Treatment Group: CAPD, APD) อายุ (age) และเพศ (gender) อย่างไร เมื่อผู้ป่วยซ้อนอยู่ใน 10 อำเภอ (District, amp; 55 ถึง 264 รายต่ออำเภอ) · ใช้อำเภอเป็นค่าคงที่สุ่ม เพราะผู้ป่วยในอำเภอเดียวกันได้รับบริการและสภาพแวดล้อมคล้ายกันqolscore3) of 1,300 peritoneal-dialysis patients associated with treatment group (Treatment Group: CAPD, APD), age (age) and sex (gender), when the patients are nested in 10 districts (District, amp; 55 to 264 patients per district)? The district is the random intercept because patients in the same district share services and surroundings.2หลักการและสูตรLogic and Formula
- x_ij, β
- ตัวแปรอิสระของผู้ป่วย (ตัวแปรกลุ่มเป็นตัวแปรหุ่น ระดับอ้างอิง = รหัสต่ำสุด) และสัมประสิทธิ์ fixed effects ("Adjusted Mean Diff." ในตาราง DAPH)the patient's independent variables (categorical ones as dummies, reference = lowest code) and the fixed-effect coefficients ("Adjusted Mean Diff." in the DAPH table)
- u_j, τ²
- ค่าคงที่สุ่มของกลุ่ม j และความแปรปรวนระหว่างกลุ่มrandom intercept of cluster j and the between-cluster variance
- σ², J_n
- ความแปรปรวนภายในกลุ่ม (ของส่วนเหลือ) และเมทริกซ์ที่มีค่า 1 ทุกช่องwithin-cluster (residual) variance, and the matrix of ones
- β_L, ℓ_ML
- สัมประสิทธิ์ของทุกระดับ (ยกเว้นระดับอ้างอิง) ของตัวแปรกลุ่มหนึ่งตัว และ log-likelihood แบบ ML ของแบบจำลองเดียวกันthe coefficients of all non-reference levels of one categorical variable, and the ML log-likelihood of the same model
ขั้นตอนของ DAPH: (1) ตัดแถวที่มีค่าว่างในตัวแปรที่ใช้ (2) ประมาณด้วย REML โดยลองตัวหาค่าเหมาะที่สุดหลายวิธี (L-BFGS, Powell, Nelder-Mead, conjugate gradient, BFGS) แล้วเก็บผลที่ REML log-likelihood สูงสุดและเป็นค่าจำกัด จึงหาค่าที่ถูกต้องได้แม้ความแปรปรวนระหว่างกลุ่มอยู่ที่ขอบ (0) (3) รายงานแต่ละตัวแปร: n และ Mean (SD) ดิบของตัวแปรตามในแต่ละระดับ ค่าสัมประสิทธิ์ (Adjusted Mean Diff.) 95% CI และค่า p จากการทดสอบ Wald แบบ z (ไม่ใช้ df แบบ Satterthwaite หรือ Kenward-Roger) ตัวแปรกลุ่มมีค่า p รวมของตัวแปร (Wald χ²; ตัวแปรสองระดับเท่ากับค่า p ของระดับนั้น) (4) รายงาน τ² และ σ² (พร้อม SD) ICC และ AIC, BIC จากการประมาณซ้ำแบบ ML ของแบบจำลองเดียวกัน (ค่า log-likelihood แบบ REML เทียบข้ามแบบจำลองที่ fixed effects ต่างกันไม่ได้) ทั้งในบรรทัด "Random intercept" ใต้ตาราง Word และในการแปลผล ส่วน Tab 3 แสดง ICC พร้อมคำบรรยายระดับ และ design effect = 1 + (m − 1) × ICC (m = ขนาดกลุ่มเฉลี่ย) · ค่าคงที่สุ่มมีหนึ่งตัวต่อกลุ่ม ไม่มี random slope · คำบรรยายระดับ ICC เป็นเกณฑ์ของ DAPH (ต่ำกว่า 0.05 ต่ำมาก, 0.05 ถึงต่ำกว่า 0.10 ต่ำ, 0.10 ถึงต่ำกว่า 0.25 ปานกลาง, 0.25 ถึงต่ำกว่า 0.50 สูง, ตั้งแต่ 0.50 สูงมาก) ไม่ใช่เกณฑ์มาตรฐาน ให้ดู design effect ประกอบ
What DAPH does: (1) rows with a missing value in any variable used are dropped; (2) the model is fitted by REML with several optimisers (L-BFGS, Powell, Nelder-Mead, conjugate gradient, BFGS), keeping the fit with the highest finite REML log-likelihood, so the right optimum is found even when the between-cluster variance sits on its boundary (0); (3) for each variable it reports n and the raw Mean (SD) of the outcome at each level, the coefficient (Adjusted Mean Diff.), its 95% CI and the p-value of a Wald z test (no Satterthwaite or Kenward-Roger df), and a categorical variable gets one overall p-value (Wald χ²; for a two-level variable this equals the p of its level); (4) it reports τ² and σ² (with their SDs), the ICC, and AIC and BIC from an ML refit of the same model (REML log-likelihoods cannot be compared across models with different fixed effects), in the "Random intercept" line under the Word table and in the interpretation; Tab 3 shows the ICC with a verbal rating and the design effect 1 + (m − 1) × ICC (m = average cluster size). There is one random intercept per cluster and no random slope. The verbal rating is DAPH's own scale (below 0.05 very low, 0.05 to below 0.10 low, 0.10 to below 0.25 moderate, 0.25 to below 0.50 high, 0.50 and above very high), not a standard benchmark; read it together with the design effect.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
lme4 (REML, Bates et al., 2015) และ lmerTest (เพื่อเปรียบเทียบ df แบบ Satterthwaite เท่านั้น) บนข้อมูลตัวอย่าง DAPHpackages lme4 (REML; Bates et al., 2015) and lmerTest (only to compare Satterthwaite df) on the DAPH example data# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
suppressPackageStartupMessages({library(lme4); library(lmerTest)})
d$group <- factor(d$group, 1:2, c("CAPD", "APD")) # reference = lowest code, as in DAPH
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$amp <- factor(d$amp) # District: the cluster (random intercept)
range(table(d$amp)) # 10 districts, 55 to 264 patients each
range(prop.table(table(d$amp, d$group), 1)[, "APD"]) # share of APD patients by district
# Random-intercept linear mixed model by REML (DAPH: the REML fit with the highest finite log-likelihood)
fit <- lme4::lmer(qolscore3 ~ group + age + gender + (1 | amp), data = d, REML = TRUE)
logLik(fit)
cf <- coef(summary(fit)) # estimate, SE and the Wald statistic
w <- cbind(cf[, 1:3], p_z = 2 * pnorm(-abs(cf[, 3])), confint(fit, method = "Wald")[rownames(cf), ])
print(w, digits = 7) # DAPH reports Wald z p-values and z-based 95% CIs
vc <- as.data.frame(VarCorr(fit))[, c("grp", "vcov", "sdcor")]; print(vc, digits = 8)
icc <- vc$vcov[1] / sum(vc$vcov) # share of variance between districts
c(ICC = icc, design_effect = 1 + (nrow(d) / nlevels(d$amp) - 1) * icc) # average cluster size m = 130
fit_ml <- update(fit, REML = FALSE) # AIC and BIC come from an ML refit
c(AIC = AIC(fit_ml), BIC = BIC(fit_ml))
aggregate(qolscore3 ~ group, data = d, FUN = function(y) c(n = length(y), mean = mean(y), sd = sd(y)))
aggregate(qolscore3 ~ gender, data = d, FUN = function(y) c(n = length(y), mean = mean(y), sd = sd(y)))
# For comparison only (not what DAPH reports): t-tests with Satterthwaite degrees of freedom
print(coef(summary(lmerTest::lmer(qolscore3 ~ group + age + gender + (1 | amp), data = d)))[, c("df", "Pr(>|t|)")], digits = 5)
# cluster sizes; share of APD patients by district (min, max)
[1] 55 264
[1] 0 1
'log Lik.' -5562.948 (df=6)
# fixed effects: estimate, SE, Wald statistic, p (z), Wald 95% CI
Estimate Std. Error t value p_z 2.5 %
(Intercept) 96.9027380 5.1882817 18.6772315 7.585248e-78 86.7338928
groupAPD -0.5676434 2.5920212 -0.2189964 8.266528e-01 -5.6479116
age -0.3001880 0.0691437 -4.3415100 1.415068e-05 -0.4357072
genderFemale -0.2578132 1.0206890 -0.2525875 8.005870e-01 -2.2583270
97.5 %
(Intercept) 107.0715832
groupAPD 4.5126248
age -0.1646689
genderFemale 1.7427005
grp vcov sdcor
1 amp 20.147032 4.4885446
2 Residual 302.134422 17.3820143
ICC design_effect
0.06251378 9.06427780
# AIC, BIC from the ML refit
AIC BIC
11142.51 11173.53
# raw n, mean, SD of the outcome by category (the DAPH Mean (SD) column)
group qolscore3.n qolscore3.mean qolscore3.sd
1 CAPD 656.00000 74.88643 17.37379
2 APD 644.00000 76.84239 18.27674
gender qolscore3.n qolscore3.mean qolscore3.sd
1 Male 446.00000 76.11435 18.95623
2 Female 854.00000 75.72014 17.24896
# comparison only: Satterthwaite df and p (lmerTest)
df Pr(>|t|)
(Intercept) 417.617 4.9692e-57
groupAPD 17.252 8.2922e-01
age 1295.591 1.5253e-05
genderFemale 1290.125 8.0063e-01
| ค่าที่ตรวจQuantity | R (lme4) | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| REML log-likelihood (engine value) | −5562.948 | −5562.948 | < 0.001 | ✓ PASS |
| Between-district variance τ² (SD) · residual variance σ² (SD) | 20.1470 (4.4885) · 302.1344 (17.3820) | 20.1466 (4.4885) · 302.1345 (17.3820) | < 1e−4 relative | ✓ PASS |
| ICC · design effect (Tab 3) | 0.0625 · 9.06 | 0.0625 · 9.06 | < 1e−4 | ✓ PASS |
| APD vs CAPD: estimate | −0.5676 | −0.5676 | < 1e−4 | ✓ PASS |
| APD vs CAPD: SE · 95% CI · p | 2.5920 · −5.648 to 4.513 · 0.827 | 2.5920 · −5.648 to 4.513 · 0.827 | < 1e−4 | ✓ PASS |
| Age: estimate · 95% CI · p | −0.300 · −0.436 to −0.165 · < 0.001 | −0.300 · −0.436 to −0.165 · < 0.001 | < 5e−4 | ✓ PASS |
| Female vs Male: estimate · 95% CI · p | −0.258 · −2.258 to 1.743 · 0.801 | −0.258 · −2.258 to 1.743 · 0.801 | < 5e−4 | ✓ PASS |
| AIC · BIC (ML refit) | 11142.51 · 11173.53 | 11142.51 · 11173.53 | < 0.01 | ✓ PASS |
| Mean (SD): CAPD · APD · Male · Female | 74.89 (17.37) · 76.84 (18.28) · 76.11 (18.96) · 75.72 (17.25) | 74.89 (17.37) · 76.84 (18.28) · 76.11 (18.96) · 75.72 (17.25) | < 0.005 | ✓ PASS |
ทุกค่าตรงกับ R ค่าประมาณ ความแปรปรวน และ SE ต่างกันไม่เกิน 1e−4 (สัมพัทธ์) ตามความคลาดเคลื่อนของการหาค่าเหมาะที่สุด · SE ของ fixed effects คำนวณจาก (ΣXᵀV̂⁻¹X)⁻¹ เหมือน R
Every value agrees with R: estimates, variances and SEs within 1e−4 (relative), the optimiser tolerance; the fixed-effect SEs are (ΣXᵀV̂⁻¹X)⁻¹, as in R.
4การแปลผลและตัวอย่างInterpretation and Example
รายงาน fixed effects (สัมประสิทธิ์ 95% CI และค่า p) ความแปรปรวนระหว่างกลุ่ม τ² และภายในกลุ่ม σ² (หรือ SD) ICC จำนวนกลุ่มและขนาดกลุ่ม และวิธีประมาณ (REML, การทดสอบ Wald แบบ z) · สัมประสิทธิ์ของ LMM ที่ใช้ identity link มีความหมายเหมือนการถดถอยเชิงเส้น: ผลต่างของค่าเฉลี่ยเมื่อเทียบผู้ป่วยในกลุ่มเดียวกัน ปรับตัวแปรอื่นแล้ว และในแบบจำลองเชิงเส้นมีความหมายเดียวกับผลเฉลี่ยในประชากรของ GEE (หัวข้อ 1.6) · ICC บอกสัดส่วนความแปรปรวนที่อยู่ระหว่างกลุ่ม ไม่ได้บอกว่าตัวแปรใดสำคัญ · เมื่อกลุ่มมีน้อยและตัวแปรต่างกันส่วนใหญ่ระหว่างกลุ่ม การทดสอบแบบ z อาจให้ค่า p และช่วงเชื่อมั่นแคบเกินจริง ให้ตรวจด้วย df แบบ Satterthwaite ใน R (lmerTest) · การเปรียบเทียบแบบจำลองที่ fixed effects ต่างกันด้วย likelihood-ratio test ต้องประมาณแบบ ML ทั้งสองแบบจำลอง (DAPH ไม่ทำการทดสอบนี้ ทำได้ใน R ด้วย anova())
Report the fixed effects (coefficient, 95% CI and p-value), the between-cluster variance τ² and within-cluster variance σ² (or their SDs), the ICC, the number and sizes of the clusters, and the estimation method (REML, Wald z tests). An LMM coefficient with the identity link reads like a linear-regression coefficient: the mean difference when patients in the same cluster are compared, adjusted for the other variables; in a linear model it has the same meaning as GEE's population-averaged effect (section 1.6). The ICC gives the share of variance that lies between clusters; it does not say which variable matters. With few clusters and a variable that differs mainly between clusters, z tests can give p-values and intervals that are too small; check with Satterthwaite df in R (lmerTest). Comparing models with different fixed effects by a likelihood-ratio test needs ML fits of both models (DAPH does not run this test; in R use anova()).
📖 References
- Bates, D., Mächler, M., Bolker, B., & Walker, S. (2015). Fitting linear mixed-effects models using lme4. Journal of Statistical Software, 67(1), 1–48. doi:10.18637/jss.v067.i01
- Laird, N. M., & Ware, J. H. (1982). Random-effects models for longitudinal data. Biometrics, 38(4), 963–974. doi:10.2307/2529876
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
1.8Pearson & Spearman Correlation
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
สัมประสิทธิ์สหสัมพันธ์ (correlation coefficient) บอกทิศทางและความแรงของความสัมพันธ์ระหว่างตัวแปรตัวเลข 2 ตัวที่วัดในคนเดียวกัน มีค่าตั้งแต่ −1 ถึง 1 (0 = ไม่สัมพันธ์กัน) · Pearson's r (Pearson, 1895) วัดความสัมพันธ์แบบเส้นตรง · Spearman's ρ (อ่านว่า rho; Spearman, 1904) คือ Pearson's r ที่คำนวณจากอันดับของข้อมูลแทนค่าจริง จึงวัดความสัมพันธ์แบบทิศทางเดียว (monotonic คือเมื่อค่าหนึ่งเพิ่ม อีกค่ามีแนวโน้มเพิ่มตลอดหรือลดตลอด ไม่จำเป็นต้องเป็นเส้นตรง) และได้รับผลจากค่าผิดปกติ (outlier) และการแจกแจงที่เบ้น้อยกว่า Pearson
A correlation coefficient describes the direction and strength of the association between two numeric variables measured on the same people; it runs from −1 to 1 (0 = no association). Pearson's r (Pearson, 1895) measures a straight-line association. Spearman's ρ (rho; Spearman, 1904) is Pearson's r computed on the ranks of the data instead of the values, so it measures a monotonic association (as one variable rises the other tends to rise, or to fall, throughout, not necessarily along a straight line) and is less affected by outliers and skewed distributions than Pearson's r.
ใช้เมื่อ ต้องการบรรยายว่าตัวแปรตัวเลข 2 ตัวขึ้นลงไปด้วยกันมากน้อยเพียงใด เช่น อายุกับคะแนนคุณภาพชีวิต · ไม่ควรใช้ เมื่อตัวแปรหนึ่งเป็นตัวแปรกลุ่ม (ใช้ t-test, ANOVA หรือการทดสอบแบบอันดับในหัวข้อ 1.1–1.10) เมื่อความสัมพันธ์เป็นรูปโค้งขึ้นแล้วลง (ค่าสหสัมพันธ์อาจใกล้ 0 ทั้งที่สัมพันธ์กันชัดเจน) เมื่อคนเดียวกันมีหลายแถวในข้อมูล (ข้อมูลไม่เป็นอิสระต่อกัน) หรือเมื่อต้องควบคุมตัวแปรกวน (ใช้ Linear Regression หัวข้อ 1.12) · สหสัมพันธ์ไม่ได้บอกว่าตัวแปรหนึ่งเป็นสาเหตุของอีกตัวหนึ่ง
Use it to describe how closely two numeric variables move together, such as age and a quality-of-life score. Do not use it when one variable is categorical (use a t-test, ANOVA or the rank tests in sections 1.1–1.10), when the relationship rises and then falls (the coefficient can be near 0 even though the variables are clearly related), when the same person contributes several rows (the observations are not independent), or when confounders must be controlled (use linear regression, section 1.12). A correlation does not show that one variable causes the other.
ใน DAPH: Tab 2 → ตัวแปรตามแบบต่อเนื่อง (Continuous) → สถิติ Correlation coefficient → ใส่ตัวแปรตัวเลขอย่างน้อย 1 ตัวในช่องตัวแปรอิสระ · ตารางผลมีหนึ่งแถวต่อตัวแปรอิสระ (ตัวแปรที่ไม่ใช่ตัวเลขจะถูกข้าม) · DAPH เลือกใช้ Pearson หรือ Spearman เองตามกฎในส่วนที่ 2
In DAPH: Tab 2 → a continuous dependent variable → statistic Correlation coefficient → put one or more numeric variables in the independent-variable box. The results table has one row per independent variable (non-numeric variables are skipped). DAPH chooses Pearson or Spearman itself, by the rule in part 2.
qolscore3) ต่ำกว่าหรือไม่ และดัชนีมวลกาย (Body Mass Index, BMI) สัมพันธ์กับคะแนนนี้หรือไม่ · คะแนนคุณภาพชีวิตไม่ผ่านการตรวจการแจกแจงปกติ (Shapiro-Wilk p < 0.001) DAPH จึงใช้ Spearman: อายุ ρ = −0.1204 (95% CI −0.1737 ถึง −0.0665, p < 0.001) และ BMI ρ = 0.0479 (95% CI −0.0065 ถึง 0.1020, p = 0.084) · เมื่อกรองเฉพาะผู้ป่วยของ Pak Chong Nana Hospital 94 คน คะแนนผ่านการตรวจ (Shapiro-Wilk p = 0.200) DAPH จึงใช้ Pearson: อายุ r = −0.1721 (95% CI −0.3621 ถึง 0.0317, p = 0.097)qolscore3), and is body mass index (BMI) related to it? The quality-of-life score fails the normality check (Shapiro-Wilk p < 0.001), so DAPH uses Spearman: age ρ = −0.1204 (95% CI −0.1737 to −0.0665, p < 0.001) and BMI ρ = 0.0479 (95% CI −0.0065 to 0.1020, p = 0.084). Filtered to the 94 patients of Pak Chong Nana Hospital, the score passes the check (Shapiro-Wilk p = 0.200), so DAPH uses Pearson: age r = −0.1721 (95% CI −0.3621 to 0.0317, p = 0.097).2หลักการและสูตรLogic and Formula
- x_i, y_i
- ค่าของตัวแปรอิสระและตัวแปรตามของคนที่ ivalues of the independent and the dependent variable for person i
- x̄, ȳ
- ค่าเฉลี่ยของแต่ละตัวแปรmeans of the two variables
- n
- จำนวนคนที่มีค่าครบทั้ง 2 ตัวแปร (นับแยกทีละแถวของตาราง)number of people with both values (counted separately for each row of the table)
- R(x_i)
- อันดับของ x_i เมื่อเรียงจากน้อยไปมาก ค่าที่ซ้ำกันได้อันดับเฉลี่ยrank of x_i from smallest to largest; tied values get the average rank
- T_{n−2}
- การแจกแจง t ที่มีองศาอิสระ n − 2t distribution with n − 2 degrees of freedom
กฎเลือกวิธีของ DAPH: ทดสอบการแจกแจงปกติของตัวแปรตามด้วย Shapiro-Wilk (Shapiro & Wilk, 1965) จากค่าที่ไม่สูญหายทั้งหมด ถ้า p > 0.05 ใช้ Pearson ถ้า p ≤ 0.05 ใช้ Spearman และใช้วิธีเดียวกันทุกแถวของตาราง (ไม่ได้ตรวจตัวแปรอิสระ) · หมายเหตุใต้ตารางบอกวิธีที่ใช้และค่า p ของ Shapiro-Wilk · ข้อมูลสูญหายตัดทีละคู่ตัวแปร แต่ละแถวจึงมี n ของตัวเอง
DAPH's choice rule: the dependent variable is tested for normality with Shapiro-Wilk (Shapiro & Wilk, 1965) on all its non-missing values; p > 0.05 gives Pearson, p ≤ 0.05 gives Spearman, and the same method is used for every row of the table (the independent variables are not tested). The note under the table states the method and the Shapiro-Wilk p. Missing values are removed pair by pair, so each row has its own n.
สิ่งที่ DAPH คำนวณ: ρ ของ Spearman คำนวณเป็น Pearson's r บนอันดับเฉลี่ย ซึ่งถูกต้องเมื่อมีค่าซ้ำ (สูตรลัด 6Σd² ใช้ได้เฉพาะเมื่อไม่มีค่าซ้ำ: ในข้อมูลตัวอย่างได้ −0.1187 แทน −0.1204) · ค่า p ของทั้งสองวิธีมาจากสถิติ t ข้างบน (สำหรับ Spearman เป็นการประมาณสำหรับตัวอย่างขนาดใหญ่ ใน R ต้องใส่ exact = FALSE จึงจะได้ค่าเดียวกัน) · ช่วงเชื่อมั่นใช้ Fisher's z กับทั้ง r และ ρ ด้วยค่า 1.96 · สำหรับ ρ ช่วงนี้เป็นค่าประมาณ Bonett & Wright (2000) เสนอค่าคลาดเคลื่อนมาตรฐานที่กว้างกว่าเล็กน้อย √[(1 + ρ²/2)/(n − 3)] ซึ่งในข้อมูลขนาดใหญ่ต่างกันเพียงทศนิยมตำแหน่งที่ 4
What DAPH computes: Spearman's ρ is Pearson's r on mid-ranks, which is correct when there are ties (the 6Σd² shortcut holds only without ties: in the example data it gives −0.1187 instead of −0.1204). The p-value of both methods comes from the t statistic above (for Spearman this is the large-sample approximation; in R use exact = FALSE to get the same value). The confidence interval uses Fisher's z with 1.96 for both r and ρ. For ρ this interval is an approximation; Bonett & Wright (2000) proposed a slightly larger standard error, √[(1 + ρ²/2)/(n − 3)], which in large samples changes only the fourth decimal.
คอลัมน์ในตาราง DAPH: n · Mean (SD) ของตัวแปรอิสระในแถวนั้น · Correlation Coefficient (r หรือ ρ ทศนิยม 4 ตำแหน่ง) · R² · 95% CI · p-value (แสดง <0.001 เมื่อ p < 0.001) · Strength ระดับความแรงตามค่าสัมบูรณ์: < 0.1 Negligible, 0.1 ถึง < 0.3 Weak, 0.3 ถึง < 0.5 Moderate, 0.5 ถึง < 0.7 Strong, ≥ 0.7 Very strong พร้อมทิศทาง positive/negative (จุดตัด 0.1, 0.3, 0.5 ตรงกับขนาดผลเล็ก กลาง ใหญ่ของ Cohen, 1988) · หน้าผลลัพธ์และรายงาน Word ใช้ระดับความแรงชุดเดียวกันนี้ หน้าผลลัพธ์บอกวิธีที่ใช้และข้อสมมติของวิธีนั้น และใช้สัญลักษณ์ ρ เมื่อเป็น Spearman
Columns of the DAPH table: n · Mean (SD) of the row's independent variable · Correlation Coefficient (r or ρ, 4 decimals) · R² · 95% CI · p-value (shown as <0.001 when p < 0.001) · Strength, by absolute value: < 0.1 Negligible, 0.1 to < 0.3 Weak, 0.3 to < 0.5 Moderate, 0.5 to < 0.7 Strong, ≥ 0.7 Very strong, with the direction (positive/negative). The cut-offs 0.1, 0.3 and 0.5 are Cohen's (1988) small, medium and large effects. The results page and the Word report use the same strength bands; the results page names the method used and its assumptions, and writes ρ for Spearman.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
# DAPH's rule: Shapiro-Wilk on the dependent variable; p > 0.05 -> Pearson, otherwise Spearman
shapiro.test(d$qolscore3)
# One row per independent variable, as in the DAPH table
corr_row <- function(y, x, method) {
ok <- complete.cases(x, y)
ct <- cor.test(x[ok], y[ok], method = method, exact = FALSE)
r <- unname(ct$estimate); n <- sum(ok)
ci <- tanh(atanh(r) + c(-1, 1) * 1.96 / sqrt(n - 3)) # Fisher z, 1.96 as in DAPH
data.frame(n = n, r = round(r, 4), R2 = round(r^2, 4), lower = round(ci[1], 4),
upper = round(ci[2], 4), p = signif(ct$p.value, 4))
}
rbind(age = corr_row(d$qolscore3, d$age, "spearman"),
bmi = corr_row(d$qolscore3, d$bmi, "spearman"))
# Spearman's rho is Pearson's r computed on mid-ranks (ties get the average rank)
cor(rank(d$age), rank(d$qolscore3))
n <- nrow(d)
1 - 6 * sum((rank(d$age) - rank(d$qolscore3))^2) / (n * (n^2 - 1)) # no-ties shortcut: not exact here
# Pearson branch: patients of one hospital (DAPH: Data Tools > Filter Data, hos = 4)
h4 <- subset(d, hos == 4)
nrow(h4)
shapiro.test(h4$qolscore3)
rbind(age = corr_row(h4$qolscore3, h4$age, "pearson"),
bmi = corr_row(h4$qolscore3, h4$bmi, "pearson"))
cor.test(h4$age, h4$qolscore3)
W = 0.97559, p-value = 5.012e-14
n r R2 lower upper p
age 1300 -0.1204 0.0145 -0.1737 -0.0665 1.338e-05
bmi 1300 0.0479 0.0023 -0.0065 0.1020 8.447e-02
[1] -0.1204274
[1] -0.1187354
[1] 94
W = 0.98133, p-value = 0.1996
n r R2 lower upper p
age 94 -0.1721 0.0296 -0.3621 0.0317 0.09727
bmi 94 0.0456 0.0021 -0.1585 0.2459 0.66280
t = -1.6753, df = 92, p-value = 0.09727
95 percent confidence interval:
-0.36205384 0.03166196
cor
-0.1720588
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Shapiro-Wilk of Quality of Life Score (Post): W / p → method | 0.97559 / 5.012e−14 → Spearman | 0.97559 / p < 0.001 → Spearman | < 1e−9 | ✓ PASS |
| Age: Spearman ρ / R² | −0.1204 / 0.0145 | −0.1204 / 0.0145 | < 1e−12 | ✓ PASS |
| Age: 95% CI | −0.1737 to −0.0665 | −0.1737 to −0.0665 | < 1e−12 | ✓ PASS |
| Age: p | 1.338e−05 | 1.338e−05 (table <0.001) | < 1e−15 | ✓ PASS |
| BMI: Spearman ρ / R² / 95% CI | 0.0479 / 0.0023 / −0.0065 to 0.1020 | 0.0479 / 0.0023 / −0.0065 to 0.1020 | < 1e−12 | ✓ PASS |
| BMI: p | 0.08447 | 0.084 | < 1e−12 | ✓ PASS |
| hos = 4 (n = 94): Shapiro-Wilk p → method | 0.1996 → Pearson | 0.1996 → Pearson | < 1e−9 | ✓ PASS |
| hos = 4: age Pearson r / 95% CI / p | −0.1721 / −0.3621 to 0.0317 / 0.09727 | −0.1721 / −0.3621 to 0.0317 / 0.097 | < 1e−12 | ✓ PASS |
| hos = 4: BMI Pearson r / 95% CI / p | 0.0456 / −0.1585 to 0.2459 / 0.66280 | 0.0456 / −0.1585 to 0.2459 / 0.663 | < 1e−12 | ✓ PASS |
ความต่างคำนวณจากค่าเต็มของ R และค่าที่ engine ของ DAPH คำนวณได้จริงก่อนปัดเศษ · ช่วงเชื่อมั่นของ cor.test ใช้ 1.959964 แทน 1.96 ได้ค่าเดียวกันที่ทศนิยม 4 ตำแหน่ง
Differences are computed from R's full-precision values and the values DAPH's engine computed before rounding. cor.test uses 1.959964 instead of 1.96 for its interval; the result is the same to 4 decimals.
4การแปลผลและตัวอย่างInterpretation and Example
อายุ: ρ = −0.1204 เป็นความสัมพันธ์ทางลบระดับอ่อน (Weak negative) ผู้ป่วยที่อายุมากกว่ามีแนวโน้มได้คะแนนคุณภาพชีวิตหลังการรักษาต่ำกว่าเล็กน้อย · ρ² = 0.0145 คืออันดับอายุอธิบายความผันแปรของอันดับคะแนนได้ประมาณร้อยละ 1.4 · p < 0.001 เพราะตัวอย่างมีขนาดใหญ่ ความสัมพันธ์ที่อ่อนจึงมีนัยสำคัญทางสถิติได้ ควรอ่านขนาดจาก ρ และ 95% CI (−0.1737 ถึง −0.0665) ไม่ใช่จาก p
Age: ρ = −0.1204 is a weak negative association (Weak negative): older patients tend to have a slightly lower post-treatment quality-of-life score. ρ² = 0.0145, so the ranks of age account for about 1.4% of the variation in the ranks of the score. The p-value is below 0.001 because the sample is large, so even a weak association is statistically significant; judge the size from ρ and its 95% CI (−0.1737 to −0.0665), not from p.
BMI: ρ = 0.0479 (Negligible positive) p = 0.084 ไม่มีนัยสำคัญทางสถิติ แต่ไม่ได้แปลว่าไม่มีความสัมพันธ์: 95% CI −0.0065 ถึง 0.1020 ครอบคลุมทั้งค่า 0 และความสัมพันธ์ทางบวกระดับอ่อนเล็กน้อย · กลุ่มย่อย 94 คน: Pearson r ของอายุ = −0.1721 ทิศทางเดียวกับทั้งกลุ่ม แต่ CI กว้าง (−0.3621 ถึง 0.0317) และ p = 0.097 เพราะตัวอย่างเล็ก
BMI: ρ = 0.0479 (Negligible positive), p = 0.084, not statistically significant, which does not mean there is no association: the 95% CI of −0.0065 to 0.1020 covers both 0 and a small positive association. The subgroup of 94: Pearson's r for age is −0.1721, the same direction as in the whole cohort, but the CI is wide (−0.3621 to 0.0317) and p = 0.097 because the sample is small.
ข้อสมมติที่ DAPH ตรวจและข้อจำกัด: DAPH ตรวจเพียงการแจกแจงของตัวแปรตามเพื่อเลือกวิธี ไม่ได้ตรวจความเป็นเส้นตรงหรือค่าผิดปกติ จึงควรดูแผนภาพการกระจาย (Scatter Plot) ทุกครั้ง · Shapiro-Wilk ไวมากเมื่อข้อมูลมาก (ทุกตัวแปรตัวเลขในข้อมูลตัวอย่าง 1,300 คนไม่ผ่าน) DAPH จึงมักใช้ Spearman กับข้อมูลขนาดใหญ่ · ค่าสหสัมพันธ์ไม่ได้ปรับตัวแปรกวน และไม่ใช่ความเป็นเหตุเป็นผล
Checks DAPH makes, and limitations: DAPH checks only the distribution of the dependent variable, to choose the method; it does not check linearity or outliers, so always look at the Scatter Plot. Shapiro-Wilk is very sensitive in large samples (every numeric variable of the 1,300-patient example data fails it), so with large data DAPH will usually use Spearman. A correlation is not adjusted for confounders and does not show causation.
📖 References
- Bonett, D. G., & Wright, T. A. (2000). Sample size requirements for estimating Pearson, Kendall and Spearman correlations. Psychometrika, 65(1), 23–28. doi:10.1007/BF02294183
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
- Pearson, K. (1895). Note on regression and inheritance in the case of two parents. Proceedings of the Royal Society of London, 58, 240–242. doi:10.1098/rspl.1895.0041
- Shapiro, S. S., & Wilk, M. B. (1965). An analysis of variance test for normality (complete samples). Biometrika, 52(3–4), 591–611. doi:10.1093/biomet/52.3-4.591
- Spearman, C. (1904). The proof and measurement of association between two things. American Journal of Psychology, 15(1), 72–101. doi:10.2307/1412159
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
1.9Mann-Whitney U test
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Mann-Whitney U test (Mann & Whitney, 1947; อีกชื่อคือ Wilcoxon rank-sum test) เปรียบเทียบตัวแปรตัวเลขหรือตัวแปรอันดับระหว่างสองกลุ่มอิสระ โดยใช้อันดับของข้อมูลแทนค่าจริง จึงไม่ต้องอาศัยการแจกแจงปกติและได้รับผลจากค่าผิดปกติน้อย · สมมติฐานว่าง (H₀) คือการแจกแจงของสองกลุ่มเหมือนกัน กล่าวคือค่าที่สุ่มจากกลุ่มหนึ่งมีโอกาสมากกว่าค่าจากอีกกลุ่มเท่ากับโอกาสที่น้อยกว่า: P(X > Y) + ½P(X = Y) = ½ · การทดสอบนี้ไม่ได้เปรียบเทียบมัธยฐานโดยตรง ยกเว้นเมื่อรูปร่างการแจกแจงของสองกลุ่มเหมือนกัน
The Mann-Whitney U test (Mann & Whitney, 1947; also called the Wilcoxon rank-sum test) compares a numeric or ordinal variable between two independent groups using the ranks of the data instead of the values, so it does not rely on a normal distribution and is little affected by outliers. The null hypothesis (H₀) is that the two groups have the same distribution: a value drawn from one group is as likely to be larger as to be smaller than a value from the other, P(X > Y) + ½P(X = Y) = ½. It is not a test of medians as such, unless the two distributions have the same shape.
ใช้เมื่อ ตัวแปรตามเบ้มาก มีค่าผิดปกติ หรือเป็นคะแนนแบบอันดับ และกลุ่มเป็นอิสระต่อกัน · ไม่ใช้ กับข้อมูลจับคู่หรือวัดซ้ำในคนเดียวกัน (ใช้ Wilcoxon Signed-Rank หัวข้อ 1.11) กับกลุ่มตั้งแต่ 3 กลุ่ม (ใช้ Kruskal-Wallis หัวข้อ 1.10) หรือเมื่อต้องการผลต่างค่าเฉลี่ยพร้อมควบคุมตัวแปรกวน (ใช้ t-test หัวข้อ 1.1 หรือ Linear Regression หัวข้อ 1.12)
Use it when the outcome is strongly skewed, has outliers or is an ordinal score, and the groups are independent. Do not use it for paired or repeated measurements on the same people (use the Wilcoxon signed-rank test, section 1.11), for three or more groups (Kruskal-Wallis, section 1.10), or when you need a mean difference adjusted for confounders (t-test, section 1.1, or linear regression, section 1.12).
qolscore3) ของผู้ป่วยกลุ่ม APD (Automated PD) ต่างจากกลุ่ม CAPD (Continuous Ambulatory PD) หรือไม่ (ตัวแปร Treatment Group, group) · คะแนนไม่แจกแจงปกติในทั้งสองกลุ่ม (Shapiro-Wilk p < 0.001) · ผล: มัธยฐาน APD 78.50 (IQR 63.50–90.50) CAPD 76.50 (IQR 64.50–86.50), U = 197052.5, Z = −2.0955, p = 0.036, r = 0.0581qolscore3) differ between APD (Automated PD) and CAPD (Continuous Ambulatory PD) patients (Treatment Group, group)? The score is not normally distributed in either group (Shapiro-Wilk p < 0.001). Result: median APD 78.50 (IQR 63.50–90.50), CAPD 76.50 (IQR 64.50–86.50), U = 197052.5, Z = −2.0955, p = 0.036, r = 0.0581.2หลักการและสูตรLogic and Formula
รวมข้อมูลสองกลุ่มแล้วจัดอันดับจากน้อยไปมาก (ค่าที่ซ้ำกันได้อันดับเฉลี่ย) ถ้ากลุ่มหนึ่งมีแนวโน้มค่าสูงกว่า ผลรวมอันดับของกลุ่มนั้นจะสูงกว่าที่คาดไว้เมื่อไม่มีความต่าง
Pool the two groups and rank all values from smallest to largest (tied values get the average rank). If one group tends to have larger values, its rank sum is larger than expected under no difference.
- R_1
- ผลรวมอันดับของกลุ่มแรก (รหัสต่ำสุด) จากการจัดอันดับรวมสองกลุ่มrank sum of the first group (lowest code) in the joint ranking
- n_1, n_2
- จำนวนคนในกลุ่มแรกและกลุ่มที่สองsizes of the first and second groups
- t_j
- จำนวนค่าที่ซ้ำกันในชุดค่าซ้ำที่ jnumber of values in the j-th set of tied values
- Z_0
- ตัวแปรสุ่มปกติมาตรฐานa standard normal variable
สิ่งที่ DAPH คำนวณ: ค่า p แบบแม่นตรง (exact distribution ของ U) เมื่อกลุ่มที่เล็กกว่ามีไม่เกิน 8 ค่าและไม่มีค่าซ้ำ นอกนั้นใช้การประมาณด้วยการแจกแจงปกติที่ปรับค่าซ้ำและปรับความต่อเนื่อง (continuity correction) ตามสูตรข้างบน และหมายเหตุผลบอกว่าใช้วิธีใด · กฎของ R ต่างออกไป (wilcox.test ใช้ค่าแม่นตรงเมื่อทั้งสองกลุ่มมีน้อยกว่า 50 ค่าและไม่มีค่าซ้ำ) จึงต้องกำหนด exact = FALSE เพื่อให้ได้ค่าเดียวกับ DAPH เมื่อ DAPH ใช้การประมาณ · Z ในตารางไม่ปรับความต่อเนื่อง จึงอาจต่างจาก Z ที่ใช้คำนวณ p เล็กน้อย · ขนาดผล r ใช้ Z ที่ปรับค่าซ้ำแล้ว โดย DAPH ระบุระดับ: < 0.1 น้อยมาก (negligible), < 0.3 น้อย (small), < 0.5 ปานกลาง (medium), ตั้งแต่ 0.5 มาก (large) ตามเกณฑ์ 0.1, 0.3, 0.5 ของ Cohen (1988)
What DAPH computes: an exact p-value (the exact distribution of U) when the smaller group has at most 8 values and there are no ties; otherwise the normal approximation with the tie correction and the continuity correction shown above, and the results state which was used. R's rule differs (wilcox.test is exact when both groups have fewer than 50 values and there are no ties), so set exact = FALSE to reproduce DAPH whenever DAPH uses the approximation. Z in the table has no continuity correction, so it can differ slightly from the Z behind p. The effect size r uses the tie-corrected Z, and DAPH labels it < 0.1 negligible, < 0.3 small, < 0.5 medium, 0.5 or more large, after Cohen's (1988) 0.1, 0.3, 0.5.
ตาราง DAPH: แถวละกลุ่ม: n · Median (IQR) (ควอร์ไทล์แบบประมาณค่าในช่วงเชิงเส้น เท่ากับค่าเริ่มต้นของ quantile() ใน R) · Mean Rank (อันดับเฉลี่ยจากการจัดอันดับรวมสองกลุ่ม) · แถว Test Results: U statistic (= U₁) · Z · p-value (มี * เมื่อ p < 0.05) · Effect Size (r) · ตัดแถวที่ตัวแปรตามหรือตัวแปรกลุ่มสูญหาย · ตัวแปรกลุ่มต้องมี 2 กลุ่มพอดีและแต่ละกลุ่มมีอย่างน้อย 3 ค่า · ใส่ตัวแปรกลุ่มหลายตัวได้ DAPH ทดสอบแยกทีละตัว
DAPH table: one row per group with n · Median (IQR) (quartiles by linear interpolation, R's default quantile()) · Mean Rank (average rank in the joint ranking); a Test Results row with U statistic (= U₁) · Z · p-value (* when p < 0.05) · Effect Size (r). Rows with a missing outcome or group are removed. The grouping variable must have exactly 2 groups with at least 3 values each; several grouping variables are tested one at a time.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
tapply(d$qolscore3, d$group, function(x) shapiro.test(x)$p.value) # normality in each group
# Median (IQR) per group and mean rank (ranks of both groups together, ties = average rank)
aggregate(qolscore3 ~ group, data = d, FUN = quantile, probs = c(0.25, 0.50, 0.75))
d$rank <- rank(d$qolscore3)
tapply(d$rank, d$group, mean)
# U of the first group (CAPD): rank sum minus its minimum possible value
n1 <- sum(d$group == "CAPD"); n2 <- sum(d$group == "APD"); N <- n1 + n2
U1 <- sum(d$rank[d$group == "CAPD"]) - n1 * (n1 + 1) / 2
U1
# p-value: normal approximation with tie and continuity corrections (DAPH, because of ties)
wt <- wilcox.test(qolscore3 ~ group, data = d, exact = FALSE, correct = TRUE)
wt
unname(wt$statistic) # R's W = U of the first group
# Z (tie-corrected variance, no continuity correction) and effect size r = |Z| / sqrt(N)
tt <- table(d$qolscore3)
sigma <- sqrt(n1 * n2 / 12 * ((N + 1) - sum(tt^3 - tt) / (N * (N - 1))))
Z <- (U1 - n1 * n2 / 2) / sigma
c(Z = Z, r = abs(Z) / sqrt(N))
CAPD APD
3.304726e-09 7.579096e-10
group qolscore3.25% qolscore3.50% qolscore3.75%
1 CAPD 64.5 76.5 86.5
2 APD 63.5 78.5 90.5
CAPD APD
628.8849 672.5179
[1] 197052.5
Wilcoxon rank sum test with continuity correction
W = 197052, p-value = 0.03613
[1] 197052.5
Z r
-2.09552068 0.05811929
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| n: CAPD / APD | 656 / 644 | 656 / 644 | 0 | ✓ PASS |
| Median (IQR): CAPD | 76.5 (64.5–86.5) | 76.50 (64.50-86.50) | 0 | ✓ PASS |
| Median (IQR): APD | 78.5 (63.5–90.5) | 78.50 (63.50-90.50) | 0 | ✓ PASS |
| Mean rank: CAPD / APD | 628.8849 / 672.5179 | 628.88 / 672.52 | < 1e−9 | ✓ PASS |
| U (= R's W) | 197052.5 | 197052.5 | 0 | ✓ PASS |
| Z (tie-corrected) | −2.09552068 | −2.0955 | < 1e−12 | ✓ PASS |
| p (normal approximation, tie and continuity corrections) | 0.03613 | 0.036 | < 1e−15 | ✓ PASS |
| Effect size r | 0.05811929 | 0.0581 | < 1e−12 | ✓ PASS |
ความต่างคำนวณจากค่าเต็มของ R และค่าที่ engine ของ DAPH คำนวณก่อนปัดเศษ (เช่น p ของ DAPH = 0.036131294…) · DAPH แสดง U = 197052.5 เท่ากับ W ของ R ทุกตำแหน่ง (R พิมพ์ W ด้วยเลขนัยสำคัญ 5 หลักจึงเห็นเป็น 197052)
Differences are computed from R's full-precision values and the values DAPH's engine computed before rounding (for example DAPH's p = 0.036131294…). DAPH's U = 197052.5 equals R's W exactly (R prints W with 5 significant digits, hence 197052).
4การแปลผลและตัวอย่างInterpretation and Example
ทิศทาง: อ่านจากมัธยฐานและอันดับเฉลี่ย ไม่ใช่จากเครื่องหมายของ Z · กลุ่ม APD มีอันดับเฉลี่ยสูงกว่า (672.52 เทียบกับ 628.88) และมัธยฐานสูงกว่า (78.50 เทียบกับ 76.50) Z ติดลบเพราะคำนวณจาก U ของกลุ่มแรก (CAPD) ซึ่งต่ำกว่าค่าที่คาดไว้ n₁n₂/2 · นัยสำคัญ: p = 0.036 การแจกแจงของคะแนนต่างกันอย่างมีนัยสำคัญทางสถิติ · ขนาด: r = 0.0581 น้อยมาก (negligible) ความต่างนี้แทบไม่มีความหมายทางคลินิก · ผู้ป่วยไม่ได้ถูกสุ่มเข้ากลุ่มการรักษา จึงบอกได้เพียงความแตกต่าง ไม่ใช่ผลของวิธีล้างไต
Direction: read it from the medians and mean ranks, not from the sign of Z. APD patients have the higher mean rank (672.52 vs 628.88) and median (78.50 vs 76.50); Z is negative because it is computed from the U of the first group (CAPD), which lies below its expected value n₁n₂/2. Significance: p = 0.036, the score distributions differ significantly. Size: r = 0.0581, negligible, so the difference has little clinical meaning. Patients were not randomised to the treatment groups, so this is a difference between groups, not an effect of the dialysis method.
สิ่งที่ DAPH ตรวจ: ตัวแปรกลุ่มต้องเป็นตัวแปรกลุ่มที่มี 2 กลุ่ม และแต่ละกลุ่มมีอย่างน้อย 3 ค่า (ถ้าไม่ครบ DAPH ข้ามตัวแปรนั้นพร้อมบอกเหตุผล) · การทดสอบไม่ต้องการการแจกแจงปกติ แต่ถือว่าข้อมูลแต่ละคนเป็นอิสระต่อกัน · หน้าผลลัพธ์บอกว่า p มาจากการแจกแจงแม่นตรงหรือการประมาณ · ประโยคแปลผลใน Word ของ DAPH บอกว่ากลุ่มใดมีอันดับสูงกว่า พร้อม n มัธยฐาน (IQR) และอันดับเฉลี่ยของแต่ละกลุ่ม และค่า U, Z, p, r
What DAPH checks: the grouping variable must be categorical with 2 groups of at least 3 values each (otherwise DAPH skips it and says why). The test needs no normal distribution but assumes independent observations. The results state whether p is exact or approximate. DAPH's Word interpretation states which group had the higher ranks, with each group's n, median (IQR) and mean rank, and U, Z, p and r.
📖 References
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
- Mann, H. B., & Whitney, D. R. (1947). On a test of whether one of two random variables is stochastically larger than the other. Annals of Mathematical Statistics, 18(1), 50–60. doi:10.1214/aoms/1177730491
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
1.10Kruskal-Wallis H test
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Kruskal-Wallis H test (Kruskal & Wallis, 1952) เปรียบเทียบตัวแปรตัวเลขหรือตัวแปรอันดับระหว่างกลุ่มอิสระตั้งแต่ 3 กลุ่มขึ้นไป โดยใช้อันดับของข้อมูลทุกกลุ่มรวมกัน เป็นทางเลือกของ One-way ANOVA (หัวข้อ 1.2) เมื่อตัวแปรตามเบ้มาก มีค่าผิดปกติ หรือเป็นคะแนนแบบอันดับ · สมมติฐานว่าง (H₀) คือการแจกแจงของทุกกลุ่มเหมือนกัน ถ้า H มีนัยสำคัญ แปลว่ามีอย่างน้อยหนึ่งกลุ่มที่มีแนวโน้มค่าสูงหรือต่ำกว่ากลุ่มอื่น จากนั้นใช้ Dunn's test (post hoc) หาว่าคู่ใดต่างกัน
The Kruskal-Wallis H test (Kruskal & Wallis, 1952) compares a numeric or ordinal variable across three or more independent groups using the ranks of all groups together. It is the alternative to one-way ANOVA (section 1.2) when the outcome is strongly skewed, has outliers or is an ordinal score. The null hypothesis (H₀) is that all groups have the same distribution; a significant H means at least one group tends to have higher or lower values than the others, and Dunn's test (post hoc) then shows which pairs differ.
ไม่ใช้ กับ 2 กลุ่ม (ใช้ Mann-Whitney หัวข้อ 1.9) กับการวัดซ้ำในคนเดียวกัน หรือเมื่อต้องควบคุมตัวแปรกวน (ใช้ Linear Regression หัวข้อ 1.12)
Do not use it for 2 groups (use Mann-Whitney, section 1.9), for repeated measurements on the same people, or when confounders must be controlled (use linear regression, section 1.12).
qolscore3) ต่างกันตามรายได้ครัวเรือน (Household Income, fam_income: < 10,000 · 10,000–30,000 · > 30,000 บาท/เดือน) หรือไม่ · ผล: H(2) = 27.24, p < 0.001, η²H = 0.019 · มัธยฐาน 81.50, 77.50 และ 74.50 ตามลำดับ · Dunn's test ปรับค่า p ด้วย Holm พบความแตกต่าง 2 จาก 3 คู่ (กลุ่ม < 10,000 กับอีกสองกลุ่ม)qolscore3) differ by household income (Household Income, fam_income: < 10,000 · 10,000–30,000 · > 30,000 Baht/month)? Result: H(2) = 27.24, p < 0.001, η²H = 0.019; medians 81.50, 77.50 and 74.50. Dunn's test with Holm's adjustment found 2 of 3 pairs different (the < 10,000 group versus each of the other two).2หลักการและสูตรLogic and Formula
- K, N
- จำนวนกลุ่ม และจำนวนข้อมูลทั้งหมดที่ใช้ทดสอบnumber of groups and number of observations in the test
- R_k, n_k
- ผลรวมอันดับ และจำนวนข้อมูลของกลุ่ม krank sum and size of group k
- t_j
- จำนวนค่าที่ซ้ำกันในชุดค่าซ้ำที่ jnumber of values in the j-th set of tied values
- p_(s)
- ค่า p ที่ยังไม่ปรับ เรียงจากน้อยไปมาก (ลำดับที่ s)unadjusted p-values sorted from smallest (s-th smallest)
- Z_0
- ตัวแปรสุ่มปกติมาตรฐานa standard normal variable
สิ่งที่ DAPH คำนวณ: H ที่ปรับค่าซ้ำแล้ว ค่า p จากการแจกแจงไคสแควร์ df = K − 1 (เท่ากับ kruskal.test ของ R) และ η²H · ตัดแถวที่ตัวแปรตามหรือตัวแปรกลุ่มสูญหาย · ตัวแปรกลุ่มต้องเป็นตัวแปรกลุ่มที่มีมากกว่า 2 กลุ่ม และทุกกลุ่มมีอย่างน้อย 2 ค่า (ถ้ามี 2 กลุ่ม DAPH แนะนำ Mann-Whitney) · ใส่ตัวแปรกลุ่มหลายตัวได้ DAPH ทดสอบแยกทีละตัว
What DAPH computes: the tie-corrected H, its p-value from the chi-square distribution with K − 1 df (the same as R's kruskal.test), and η²H. Rows with a missing outcome or group are removed. The grouping variable must be categorical with more than 2 groups and at least 2 values in every group (with 2 groups DAPH points to Mann-Whitney). Several grouping variables are tested one at a time.
ขั้นตอนและกฎการเลือก post hoc (ช่อง "Post Hoc ⓘ" ใน Tab 2 ติ๊กไว้เป็นค่าเริ่มต้น และตัวเลือกเริ่มต้นคือ "อัตโนมัติ (แนะนำ)"): (1) DAPH ทำ post hoc เมื่อติ๊กช่องนี้ และ H มีนัยสำคัญ (p < 0.05) ถ้า H ไม่มีนัยสำคัญ จะไม่ทำ และเขียนว่า "ไม่ได้เปรียบเทียบรายคู่ เพราะการทดสอบรวมไม่มีนัยสำคัญ" (2) อัตโนมัติ = Dunn's test (Dunn, 1964) บนอันดับชุดเดียวกับที่ใช้คำนวณ H พร้อมแก้สูตรสำหรับค่าซ้ำ แล้วปรับค่า p ด้วย Holm (Holm, 1979) ซึ่งควบคุมโอกาสสรุปผิดได้เท่า Bonferroni แต่พบความต่างที่มีจริงได้มากกว่าหรือเท่ากันเสมอ · การทำ Mann-Whitney ทีละคู่ไม่เหมาะเพราะจัดอันดับใหม่ทุกคู่ ผลรายคู่จึงอาจขัดกับการทดสอบรวม (3) เลือกเองได้: Dunn + Holm, Dunn + Bonferroni (Dunn, 1961) ซึ่งคูณค่า p ทุกคู่ด้วยจำนวนคู่ และ Dunn + Šidák (Šidák, 1967) ซึ่งหลวมกว่า Bonferroni เล็กน้อย เมื่อเลือกเอง หน้าผลลัพธ์เขียนว่าผู้ใช้เลือกวิธีนั้นแทนวิธีที่ระบบแนะนำ · ไม่ติ๊กช่อง = ไม่ทำ post hoc
Procedure and the rule for choosing the post hoc method (the "Post Hoc ⓘ" box in Tab 2 is ticked by default and its default choice is "Automatic (recommended)"): (1) DAPH runs post hoc comparisons when the box is ticked and H is significant (p < 0.05); when H is not significant it does not, and says "Pairwise comparisons were not run because the overall test was not significant". (2) Automatic = Dunn's test (Dunn, 1964) on the same ranks used for H, corrected for ties, with p-values adjusted by Holm (Holm, 1979), which controls the chance of a false conclusion as Bonferroni does but always finds at least as many real differences. Pairwise Mann-Whitney tests are not used because they re-rank every pair, so their results need not agree with the overall test. (3) You can choose Dunn + Holm, Dunn + Bonferroni (Dunn, 1961), which multiplies every p-value by the number of pairs, or Dunn + Šidák (Šidák, 1967), slightly less strict than Bonferroni; the results page then says that you chose that method instead of the recommended one. Unticking the box means no post hoc tests.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
d$fam_income <- factor(d$fam_income, 1:3, c("<10,000", "10,000-30,000", ">30,000"))
# Median (IQR) and mean rank per group (all groups ranked together, ties = average rank)
aggregate(qolscore3 ~ fam_income, data = d, FUN = quantile, probs = c(0.25, 0.50, 0.75))
d$rank <- rank(d$qolscore3)
mr <- tapply(d$rank, d$fam_income, mean); mr
# Kruskal-Wallis H (tie-corrected) and eta-squared based on H
kw <- kruskal.test(qolscore3 ~ fam_income, data = d)
kw
H <- unname(kw$statistic); k <- nlevels(d$fam_income); N <- nrow(d)
c(H = H, eta2_H = (H - k + 1) / (N - k))
# Dunn's test on the joint ranks with the tie correction, every option in the dropdown
ng <- table(d$fam_income); tt <- table(d$qolscore3)
s2 <- N * (N + 1) / 12 - sum(tt^3 - tt) / (12 * (N - 1))
pr <- combn(levels(d$fam_income), 2)
z <- apply(pr, 2, function(p) (mr[[p[1]]] - mr[[p[2]]]) / sqrt(s2 * (1 / ng[[p[1]]] + 1 / ng[[p[2]]])))
p <- 2 * pnorm(-abs(z)); m <- length(p)
data.frame(pair = paste(pr[1, ], "vs", pr[2, ]), z = round(z, 4), p = signif(p, 4),
holm = signif(p.adjust(p, "holm"), 4), bonferroni = signif(p.adjust(p, "bonferroni"), 4),
sidak = signif(1 - (1 - p)^m, 4), r = round(abs(z) / sqrt(N), 4))
# the same z and Holm p from a package (rstatix reports z as second group minus first)
library(rstatix)
dunn_test(d, qolscore3 ~ fam_income, p.adjust.method = "holm")[, c("group1", "group2", "statistic", "p", "p.adj")]
fam_income qolscore3.25% qolscore3.50% qolscore3.75%
1 <10,000 69.375 81.500 93.500
2 10,000-30,000 63.500 77.500 88.250
3 >30,000 61.500 74.500 86.500
<10,000 10,000-30,000 >30,000
730.3618 645.3121 601.3694
Kruskal-Wallis chi-squared = 27.237, df = 2, p-value = 1.218e-06
H eta2_H
27.2371588 0.0194581
pair z p holm bonferroni sidak
1 <10,000 vs 10,000-30,000 3.0305 2.441e-03 4.883e-03 7.324e-03 7.306e-03
2 <10,000 vs >30,000 5.2106 1.883e-07 5.648e-07 5.648e-07 5.648e-07
3 10,000-30,000 vs >30,000 1.7119 8.692e-02 8.692e-02 2.608e-01 2.388e-01
r
1 0.0841
2 0.1445
3 0.0475
group1 group2 statistic p p.adj
1 <10,000 10,000-30,000 -3.03 0.00244 0.00488
2 <10,000 >30,000 -5.21 0.000000188 0.000000565
3 10,000-30,000 >30,000 -1.71 0.0869 0.0869
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| n per group | 380 / 338 / 582 | 380 / 338 / 582 | 0 | ✓ PASS |
| Median (IQR) per group | 81.5 (69.375–93.5) / 77.5 (63.5–88.25) / 74.5 (61.5–86.5) | 81.50 (69.38-93.50) / 77.50 (63.50-88.25) / 74.50 (61.50-86.50) | 0 | ✓ PASS |
| Mean Rank per group | 730.3618 / 645.3121 / 601.3694 | 730.36 / 645.31 / 601.37 | < 1e−9 | ✓ PASS |
| H, df, p | 27.2371588, 2, 1.218e−06 | H(2) = 27.24, p <0.001 (engine 27.2371588, 1.218e−06) | < 1e−12 | ✓ PASS |
| η²H | 0.0194581 | 0.019 | < 1e−12 | ✓ PASS |
| Automatic choice | Dunn's test + Holm | Dunn's test with Holm adjustment | — | ✓ PASS |
| Dunn's z (first − second) | 3.0305 / 5.2106 / 1.7119 | 3.031 / 5.211 / 1.712 | < 1e−12 | ✓ PASS |
| p unadjusted | 2.441e−03 / 1.883e−07 / 8.692e−02 | 0.002 / <0.001 / 0.087 | < 1e−15 | ✓ PASS |
| Holm (automatic), adjusted p | 4.883e−03 / 5.648e−07 / 8.692e−02 | 0.005 / <0.001 / 0.087 | < 1e−15 | ✓ PASS |
| Bonferroni, adjusted p | 7.324e−03 / 5.648e−07 / 2.608e−01 | 0.007 / <0.001 / 0.261 | < 1e−15 | ✓ PASS |
| Šidák, adjusted p | 7.306e−03 / 5.648e−07 / 2.388e−01 | 0.007 / <0.001 / 0.239 | < 1e−15 | ✓ PASS |
| r = |z| ÷ √N | 0.0841 / 0.1445 / 0.0475 | 0.084 / 0.145 / 0.047 | < 1e−12 | ✓ PASS |
ความต่างคำนวณจากค่าเต็มของ R และค่าที่ engine ของ DAPH คำนวณก่อนปัดเศษ · ในตาราง DAPH คอลัมน์ Mean Rank คืออันดับเฉลี่ยจากการจัดอันดับรวมทุกกลุ่ม (ชุดเดียวกับที่ใช้คำนวณ H) ไม่ใช่ค่าเฉลี่ยของข้อมูล · dunn_test ของ rstatix รายงาน z เป็นกลุ่มหลังลบกลุ่มแรก DAPH รายงานกลุ่มแรกลบกลุ่มหลัง เครื่องหมายจึงกลับกัน
Differences are computed from R's full-precision values and the values DAPH's engine computed before rounding. In DAPH's table the Mean Rank column is each group's average rank in the joint ranking (the ranks used for H), not the mean of the data. rstatix's dunn_test reports z as the second group minus the first, DAPH as the first minus the second, so the signs are opposite.
4การแปลผลและตัวอย่างInterpretation and Example
การทดสอบรวม: H(2) = 27.24, p < 0.001 การแจกแจงของคะแนนคุณภาพชีวิตหลังการรักษาต่างกันตามรายได้ครัวเรือน · η²H = 0.019 คือรายได้ครัวเรือนอธิบายความผันแปรของอันดับคะแนนได้ประมาณร้อยละ 2 (เกณฑ์ทั่วไป 0.01 น้อย, 0.06 ปานกลาง, 0.14 มาก; Cohen, 1988) · รายงานมัธยฐาน (IQR) ของแต่ละกลุ่มคู่กับ H, df และ p
Overall test: H(2) = 27.24, p < 0.001: the distribution of the post-treatment quality-of-life score differs by household income. η²H = 0.019, so household income accounts for about 2% of the variation in the ranks of the score (common benchmarks: 0.01 small, 0.06 medium, 0.14 large; Cohen, 1988). Report each group's median (IQR) with H, df and p.
เกณฑ์การอ่านตาราง post hoc: แต่ละแถวคือหนึ่งคู่ z บอกทิศทาง (อันดับเฉลี่ยกลุ่มแรกลบกลุ่มหลัง ค่าบวกแปลว่ากลุ่มแรกมีแนวโน้มค่าสูงกว่า) คู่ที่ ค่า p ที่ปรับแล้ว ต่ำกว่า 0.05 คือคู่ที่ต่างกันอย่างมีนัยสำคัญ ไม่ต้องหารด้วยจำนวนคู่อีก · r = |z| ÷ √N บอกขนาด (0.1 น้อย, 0.3 ปานกลาง, 0.5 มาก; Cohen, 1988) โดย N คือจำนวนข้อมูลทั้งหมดในการทดสอบ · Dunn's test เปรียบเทียบอันดับ จึงรายงานคู่กับมัธยฐาน (IQR) ไม่ใช่ผลต่างค่าเฉลี่ย · อ่านรายคู่เฉพาะเมื่อ H มีนัยสำคัญ
Criteria for reading the post hoc table: each row is one pair; z gives the direction (mean rank of the first group minus the second, so a positive z means the first group tends to be higher), and a pair whose adjusted p is below 0.05 differs significantly, with no further division by the number of pairs. r = |z| ÷ √N gives the size (0.1 small, 0.3 medium, 0.5 large; Cohen, 1988), with N the number of observations in the whole test. Dunn's test compares ranks, so report the pairs with the medians (IQR), not with mean differences. Read the pairs only when H is significant.
ผลรายคู่ของตัวอย่าง (Dunn + Holm): < 10,000 กับ 10,000–30,000 z = 3.031, p ที่ปรับแล้ว = 0.005 · < 10,000 กับ > 30,000 z = 5.211, p < 0.001 · 10,000–30,000 กับ > 30,000 z = 1.712, p = 0.087 ไม่มีนัยสำคัญ · ผู้ป่วยจากครัวเรือนรายได้ต่ำกว่า 10,000 บาท/เดือน มีแนวโน้มได้คะแนนสูงกว่าอีกสองกลุ่ม แต่ขนาดผลน้อย (r = 0.084 และ 0.145) · Holm คูณค่า p ที่เล็กที่สุดด้วย 3 ค่าถัดไปด้วย 2 (0.002441 → 0.004883) และค่าสุดท้ายด้วย 1 (0.087) ขณะที่ Bonferroni คูณทุกค่าด้วย 3 (0.007 และ 0.261) · เป็นการเปรียบเทียบที่ยังไม่ปรับตัวแปรอื่น จึงไม่ควรสรุปว่ารายได้เป็นสาเหตุ
The example's pairs (Dunn + Holm): < 10,000 vs 10,000–30,000 z = 3.031, adjusted p = 0.005; < 10,000 vs > 30,000 z = 5.211, p < 0.001; 10,000–30,000 vs > 30,000 z = 1.712, p = 0.087, not significant. Patients from households earning under 10,000 Baht/month tend to score higher than the other two groups, with small effects (r = 0.084 and 0.145). Holm multiplies the smallest p by 3, the next by 2 (0.002441 → 0.004883) and the last by 1 (0.087), whereas Bonferroni multiplies every p by 3 (0.007 and 0.261). The comparison is not adjusted for other variables, so income should not be read as a cause.
ในรายงาน Word ของ DAPH: ตาราง Dunn's test แยกจากตารางสถิติเชิงพรรณนา (คอลัมน์ คู่เปรียบเทียบ · อันดับเฉลี่ยของสองกลุ่ม · ผลต่างอันดับเฉลี่ย · z · p (ไม่ปรับ) · p (ปรับแล้ว) · r) และประโยควิธีการ: "เปรียบเทียบรายคู่ด้วย Dunn's test บนอันดับรวมของทุกกลุ่ม (Dunn, 1964) และปรับค่า p ด้วย Holm (Holm, 1979) ขั้นตอน เกณฑ์การเลือกวิธี post hoc และเกณฑ์การแปลผลอธิบายไว้ใน DAPH Guide หัวข้อ 1.10 (Sornlorm, 2026b)" ตามด้วย "พบความแตกต่างอย่างมีนัยสำคัญ 2 จาก 3 คู่ ..." พร้อม z และค่า p ที่ปรับแล้วของแต่ละคู่
In DAPH's Word report: the Dunn's test table is separate from the descriptive table (columns Comparison · the two Mean ranks · Mean rank difference · z · p (unadjusted) · Adjusted p · r), with the methods sentence "Pairwise comparisons used Dunn's test on the joint ranks (Dunn, 1964) with Holm's adjustment (Holm, 1979). The procedure, the rule for choosing the post hoc method and the interpretation criteria are documented in DAPH Guide, section 1.10 (Sornlorm, 2026b)." followed by "2 of 3 pairs differed significantly: ..." with each pair's z and adjusted p.
📖 References
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
- Dunn, O. J. (1961). Multiple comparisons among means. Journal of the American Statistical Association, 56(293), 52–64. doi:10.1080/01621459.1961.10482090
- Dunn, O. J. (1964). Multiple comparisons using rank sums. Technometrics, 6(3), 241–252. doi:10.1080/00401706.1964.10490181
- Holm, S. (1979). A simple sequentially rejective multiple test procedure. Scandinavian Journal of Statistics, 6(2), 65–70.
- Kruskal, W. H., & Wallis, W. A. (1952). Use of ranks in one-criterion variance analysis. Journal of the American Statistical Association, 47(260), 583–621. doi:10.1080/01621459.1952.10483441
- Šidák, Z. (1967). Rectangular confidence regions for the means of multivariate normal distributions. Journal of the American Statistical Association, 62(318), 626–633. doi:10.1080/01621459.1967.10482935
- Tomczak, M., & Tomczak, E. (2014). The need to report effect size estimates revisited. An overview of some recommended measures of effect size. Trends in Sport Sciences, 21(1), 19–25.
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
1.11Wilcoxon Signed-Rank test
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Wilcoxon Signed-Rank test (Wilcoxon, 1945) เปรียบเทียบการวัด 2 ครั้งในคนเดียวกัน เช่น ก่อนและหลังการรักษา โดยใช้อันดับของผลต่างรายคน เป็นทางเลือกของ paired t-test (หัวข้อ 1.1) เมื่อผลต่างเบ้มาก มีค่าผิดปกติ หรือเป็นคะแนนแบบอันดับ · สมมติฐานว่าง (H₀) คือผลต่างกระจายสมมาตรรอบ 0 (มัธยฐานของผลต่างเท่ากับ 0) · ไม่ใช้ กับสองกลุ่มอิสระ (ใช้ Mann-Whitney หัวข้อ 1.9) หรือการวัดตั้งแต่ 3 ครั้ง (ใช้ Repeated Measures ANOVA หัวข้อ 1.5)
The Wilcoxon signed-rank test (Wilcoxon, 1945) compares two measurements on the same people, such as before and after treatment, using the ranks of each person's difference. It is the alternative to the paired t-test (section 1.1) when the differences are strongly skewed, have outliers or are ordinal scores. The null hypothesis (H₀) is that the differences are distributed symmetrically around 0 (median difference 0). Do not use it for two independent groups (use Mann-Whitney, section 1.9) or for three or more measurements (Repeated Measures ANOVA, section 1.5).
ใน DAPH: Tab 2 → ตัวแปรตามแบบต่อเนื่อง → ติ๊ก "Intervention/Interested Factor?" → สถิติ Wilcoxon Signed-Rank test → Dependent Variable = ค่าหลัง (Post-test) และ Matching Variable = ค่าก่อน (Pre-test) · DAPH คำนวณผลต่างเป็น ค่าหลัง − ค่าก่อน (Dependent − Matching)
In DAPH: Tab 2 → a continuous dependent variable → tick "Intervention/Interested Factor?" → statistic Wilcoxon Signed-Rank test → Dependent Variable = the post-test value and Matching Variable = the pre-test value. DAPH computes each difference as post − pre (Dependent − Matching).
qolscore1) และหลังการรักษา (Quality of Life Score (Post), qolscore3) · ผล: มัธยฐาน 70.00 → 77.50 มัธยฐานของผลต่าง 7.50 คะแนนเพิ่มขึ้น 1,299 คน ลดลง 1 คน ไม่เปลี่ยน 0 คน · W = 3.0, Z = −35.9186, p < 0.001, r = 0.9962qolscore1) and after treatment (Quality of Life Score (Post), qolscore3)? Result: median 70.00 → 77.50, median difference 7.50; the score rose in 1,299 patients, fell in 1 and was unchanged in 0; W = 3.0, Z = −35.9186, p < 0.001, r = 0.9962.2หลักการและสูตรLogic and Formula
คำนวณผลต่างของแต่ละคน ตัดคนที่ผลต่างเป็น 0 ออก จัดอันดับค่าสัมบูรณ์ของผลต่างที่เหลือ (ค่าที่ซ้ำกันได้อันดับเฉลี่ย) แล้วรวมอันดับแยกตามเครื่องหมาย ถ้าไม่มีการเปลี่ยนแปลง ผลรวมอันดับของผลต่างบวกและลบควรใกล้กัน
Compute each person's difference, drop the zero differences, rank the absolute values of the rest (tied values get the average rank) and add the ranks separately by sign. With no change, the rank sums of the positive and negative differences should be similar.
- n
- จำนวนคู่ที่มีค่าครบทั้งสองครั้ง (รวมคู่ที่ผลต่างเป็น 0)number of complete pairs (including zero differences)
- n′
- จำนวนคู่ที่ผลต่างไม่เป็น 0number of non-zero differences
- t_j
- จำนวนค่าที่ซ้ำกันในชุดค่าซ้ำที่ j ของ |d|number of values in the j-th set of tied |d|
- Z_0
- ตัวแปรสุ่มปกติมาตรฐานa standard normal variable
สิ่งที่ DAPH คำนวณ: W คือผลรวมอันดับที่น้อยกว่า ดังนั้น Z ที่คำนวณจาก W ไม่เป็นบวกเสมอ เครื่องหมายของ Z จึงไม่ได้บอกทิศทาง · ค่า p เลือกวิธีตามข้อมูล: (1) ไม่มีผลต่างเป็น 0 ไม่มีค่าซ้ำ และ n ≤ 50 ใช้การแจกแจงแม่นตรงของ W (2) มีผลต่างเป็น 0 หรือค่าซ้ำ และ n ≤ 13 ใช้การแจกแจงแม่นตรงจากการสลับเครื่องหมายของผลต่างที่ไม่เป็น 0 ทุกแบบ (3) นอกนั้นใช้การประมาณปกติตามสูตรข้างบน ปรับค่าซ้ำ ไม่ปรับความต่อเนื่อง · หน้าผลลัพธ์บอกว่าใช้วิธีใด · ใน R ค่าเริ่มต้นของ wilcox.test(paired = TRUE) ปรับความต่อเนื่อง จึงต้องใส่ correct = FALSE (และ exact = FALSE เมื่อ DAPH ใช้การประมาณ) · ขนาดผล r ใช้ n ทุกคู่ และ DAPH ระบุระดับ < 0.1 น้อยมาก, < 0.3 น้อย, < 0.5 ปานกลาง, ตั้งแต่ 0.5 มาก (Cohen, 1988) · ตัดคู่ที่มีค่าสูญหายค่าใดค่าหนึ่ง ต้องมีอย่างน้อย 6 คู่ และถ้าผลต่างเป็น 0 ทุกคู่ DAPH จะไม่ทดสอบ
What DAPH computes: W is the smaller rank sum, so the Z computed from it is never positive and its sign does not show the direction. The p-value method depends on the data: (1) no zero differences, no ties and n ≤ 50: the exact distribution of W; (2) zero differences or ties and n ≤ 13: the exact distribution from every sign flip of the non-zero differences; (3) otherwise the normal approximation above, with the tie correction and no continuity correction. The results state which was used. R's wilcox.test(paired = TRUE) applies a continuity correction by default, so use correct = FALSE (and exact = FALSE when DAPH uses the approximation). The effect size r uses all n pairs, and DAPH labels it < 0.1 negligible, < 0.3 small, < 0.5 medium, 0.5 or more large (Cohen, 1988). Pairs with either value missing are removed; at least 6 pairs are needed, and DAPH does not test when every difference is 0.
ตาราง DAPH: แถวค่าก่อนและค่าหลัง (n, Median) · Positive ranks (Post > Pre) · Negative ranks (Post < Pre) · Ties (จำนวนคู่ที่ผลต่างเป็น 0) · แถว Test Results: จำนวนคู่ · Median Diff · W statistic · Z · p-value · Effect Size (r)
DAPH table: rows for the pre and post values (n, Median) · Positive ranks (Post > Pre) · Negative ranks (Post < Pre) · Ties (pairs with a zero difference) · a Test Results row with the number of pairs · Median Diff · W statistic · Z · p-value · Effect Size (r).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
# DAPH: Dependent = Post-test (qolscore3), Matching = Pre-test (qolscore1); difference = Post - Pre
dif <- d$qolscore3 - d$qolscore1
c(median_pre = median(d$qolscore1), median_post = median(d$qolscore3), median_diff = median(dif))
table(sign(dif)) # -1 = Post < Pre, 0 = no change, 1 = Post > Pre
summary(dif)
# Signed ranks of the non-zero differences (tied |d| get the average rank)
nz <- dif[dif != 0]; n <- length(nz)
rk <- rank(abs(nz))
c(R_plus = sum(rk[nz > 0]), R_minus = sum(rk[nz < 0]))
# Normal approximation with the tie correction and no continuity correction (as DAPH here)
wt <- wilcox.test(d$qolscore3, d$qolscore1, paired = TRUE, exact = FALSE, correct = FALSE)
wt # R's V = R_plus
wt$p.value
# DAPH's W = the smaller rank sum; Z from W; effect size r = |Z| / sqrt(number of pairs)
W <- min(sum(rk[nz > 0]), sum(rk[nz < 0]))
tt <- table(abs(nz))
Z <- (W - n * (n + 1) / 4) / sqrt(n * (n + 1) * (2 * n + 1) / 24 - sum(tt^3 - tt) / 48)
c(W = W, Z = Z, r = abs(Z) / sqrt(nrow(d)))
median_pre median_post median_diff
70.0 77.5 7.5
-1 1
1 1299
Min. 1st Qu. Median Mean 3rd Qu. Max.
-4.000 7.500 7.500 7.492 7.500 16.000
R_plus R_minus
845647 3
Wilcoxon signed rank test
V = 845647, p-value < 2.2e-16
[1] 1.563402e-282
W Z r
3.0000000 -35.9186389 0.9962038
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Median Pre / Post / Median Diff (Post − Pre) | 70.0 / 77.5 / 7.5 | 70.00 / 77.50 / 7.50 | 0 | ✓ PASS |
| Positive ranks (Post > Pre) / Negative ranks / Ties | 1299 / 1 / 0 | 1299 / 1 / 0 | 0 | ✓ PASS |
| W = min(R⁺, R⁻) | 3 (R's V = R⁺ = 845647) | 3.0 | 0 | ✓ PASS |
| Z (tie-corrected) | −35.9186389 | −35.9186 | < 1e−12 | ✓ PASS |
| p (normal approximation, no continuity correction) | 1.563402e−282 | <0.001 (engine 1.563402e−282) | < 1e−290 | ✓ PASS |
| Effect size r | 0.9962038 | 0.9962 | < 1e−12 | ✓ PASS |
ความต่างคำนวณจากค่าเต็มของ R และค่าที่ engine ของ DAPH คำนวณก่อนปัดเศษ · |Z| และ p ของ R (คำนวณจาก V = R⁺) เท่ากับของ DAPH (คำนวณจาก W = R⁻) เพราะ R⁺ และ R⁻ อยู่ห่างจากค่าคาดหมาย n′(n′ + 1)/4 เท่ากันคนละด้าน
Differences are computed from R's full-precision values and the values DAPH's engine computed before rounding. R's |Z| and p (from V = R⁺) equal DAPH's (from W = R⁻) because R⁺ and R⁻ lie the same distance from their expected value n′(n′ + 1)/4, on opposite sides.
4การแปลผลและตัวอย่างInterpretation and Example
ทิศทาง: อ่านจากแถว Positive/Negative ranks และ Median Diff ไม่ใช่จากเครื่องหมายของ Z · คะแนนเพิ่มขึ้นใน 1,299 จาก 1,300 คน และมัธยฐานของผลต่าง (หลัง − ก่อน) = 7.50 คะแนน · นัยสำคัญ: p < 0.001 · ขนาด: r = 0.9962 มาก · ในข้อมูลตัวอย่างนี้คะแนนหลังสูงกว่าคะแนนก่อนประมาณ 7.5 คะแนนเกือบทุกคน ผลจึงชัดเจนมากผิดปกติ ข้อมูลจริงมักแปรผันมากกว่านี้
Direction: read it from the Positive/Negative ranks rows and the Median Diff, not from the sign of Z. The score rose in 1,299 of the 1,300 patients and the median difference (post − pre) is 7.50 points. Significance: p < 0.001. Size: r = 0.9962, large. In this example dataset the post score is about 7.5 points above the pre score for almost everyone, so the result is unusually clear-cut; real data usually vary more.
ข้อจำกัด: การออกแบบก่อน-หลังที่ไม่มีกลุ่มเปรียบเทียบบอกได้ว่าคะแนนเปลี่ยน แต่ไม่ได้พิสูจน์ว่าการรักษาเป็นสาเหตุ (เวลาที่ผ่านไปหรือการถดถอยเข้าหาค่าเฉลี่ยอาจมีส่วน) · การทดสอบถือว่าผลต่างของแต่ละคนเป็นอิสระต่อกัน · DAPH ไม่ได้รายงานช่วงเชื่อมั่นของการเปลี่ยนแปลง ถ้าต้องการ ใช้ wilcox.test(..., conf.int = TRUE) ใน R ซึ่งให้ค่าประมาณ Hodges-Lehmann (Hodges & Lehmann, 1963) และช่วงเชื่อมั่น · ประโยคแปลผลใน Word ของ DAPH บอกมัธยฐานของสองครั้ง มัธยฐานของผลต่าง จำนวน Positive/Negative ranks และ Ties ค่า W, Z, p, r และว่าการวัดครั้งใดสูงกว่า
Limitations: a before–after design without a comparison group shows that the score changed, not that the treatment caused it (time or regression to the mean may contribute). The test assumes the people's differences are independent. DAPH does not report a confidence interval for the change; if you need one, R's wilcox.test(..., conf.int = TRUE) gives the Hodges-Lehmann estimate (Hodges & Lehmann, 1963) with its interval. DAPH's Word interpretation gives the two medians, the median difference, the numbers of positive and negative ranks and ties, W, Z, p and r, and states which measurement was higher.
📖 References
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
- Hodges, J. L., & Lehmann, E. L. (1963). Estimates of location based on rank tests. Annals of Mathematical Statistics, 34(2), 598–611. doi:10.1214/aoms/1177704172
- Wilcoxon, F. (1945). Individual comparisons by ranking methods. Biometrics Bulletin, 1(6), 80–83. doi:10.2307/3001968
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
1.12Linear Regression (Enter, Backward, Stepwise, Forward, Bivariate)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Linear Regression (การถดถอยเชิงเส้น ประมาณค่าด้วยวิธีกำลังสองน้อยที่สุด, ordinary least squares หรือ OLS) อธิบายค่าเฉลี่ยของตัวแปรตามแบบต่อเนื่องด้วยตัวแปรอิสระหลายตัวพร้อมกัน ค่าสัมประสิทธิ์ (B) ของแต่ละตัวแปรคือผลต่างของค่าเฉลี่ยตัวแปรตามที่สัมพันธ์กับตัวแปรนั้น เมื่อตัวแปรอื่นในแบบจำลองคงที่ จึงใช้ควบคุมตัวแปรกวนได้ เป็นสถิติที่ใช้บ่อยที่สุดสำหรับผลลัพธ์ต่อเนื่อง เช่น คะแนนคุณภาพชีวิต ความดันโลหิต หรือระดับน้ำตาล
Linear regression (fitted by ordinary least squares, OLS) models the mean of a continuous outcome from several independent variables at once. Each coefficient (B) is the difference in the mean outcome associated with that variable with the other variables in the model held constant, so it can control for confounders. It is the most used statistic for continuous outcomes such as a quality-of-life score, blood pressure or blood glucose.
ใช้เมื่อ ตัวแปรตามเป็นตัวเลขต่อเนื่อง ข้อมูลแต่ละแถวเป็นอิสระต่อกัน และความสัมพันธ์กับตัวแปรอิสระที่เป็นตัวเลขเป็นเส้นตรงโดยประมาณ · ไม่ใช้ กับตัวแปรตามแบบ 2 กลุ่ม (ใช้ Logistic หรือ Log-binomial หัวข้อ 2.1, 2.7) ตัวแปรนับ (Poisson หัวข้อ 4.1) เวลาจนเกิดเหตุการณ์ (Cox หัวข้อ 5.2) หรือการวัดซ้ำในคนเดียวกัน (Mixed-Effect Linear หรือ GEE หัวข้อ 1.6, 1.7)
Use it when the outcome is a continuous number, the rows are independent, and the relationship with each numeric predictor is roughly a straight line. Do not use it for a two-category outcome (logistic or log-binomial regression, sections 2.1 and 2.7), counts (Poisson, section 4.1), time to an event (Cox, section 5.2) or repeated measurements on the same people (mixed-effect linear regression or GEE, sections 1.6 and 1.7).
ใน DAPH: Tab 2 → ตัวแปรตามแบบต่อเนื่อง → สถิติ Linear regression (ค่าเริ่มต้นของผลลัพธ์ต่อเนื่อง) → ใส่ตัวแปรอิสระ → เลือกวิธีนำตัวแปรเข้า: Enter (ค่าเริ่มต้น) · Backward Elimination · Stepwise Regression · Forward Selection · Bivariate Analysis (รายละเอียดแต่ละวิธีในส่วนที่ 2)
In DAPH: Tab 2 → a continuous outcome → statistic Linear regression (the default for continuous outcomes) → choose the independent variables → choose how they enter: Enter (default) · Backward Elimination · Stepwise Regression · Forward Selection · Bivariate Analysis (each is described in part 2).
qolscore3) ของผู้ป่วยล้างไตทางช่องท้อง 1,300 คน เมื่อพิจารณาอายุ (Age), เพศ (Gender), กลุ่มการรักษา (Treatment Group: CAPD/APD), ดัชนีมวลกาย (BMI), โรคเรื้อรัง (Chronic Disease) และรายได้ครัวเรือน (Household Income) พร้อมกัน · ผลวิธี Enter: อายุเพิ่ม 1 ปี คะแนนเฉลี่ยลดลง 0.288 (95% CI −0.429 ถึง −0.146, p < 0.001) · รายได้ครัวเรือน 10,000–30,000 และ > 30,000 บาท/เดือน มีคะแนนต่ำกว่ากลุ่ม < 10,000 บาท/เดือน 3.848 และ 5.443 คะแนน (p ของตัวแปร < 0.001) · ตัวแปรอื่นไม่มีนัยสำคัญ · R² = 0.0367 · ทั้ง Backward, Stepwise และ Forward ได้แบบจำลองสุดท้ายเป็นอายุกับรายได้ครัวเรือนqolscore3) of the 1,300 peritoneal-dialysis patients, considering age, gender, treatment group (CAPD/APD), body mass index (BMI), chronic disease and household income together? Enter results: each additional year of age goes with a 0.288-point lower mean score (95% CI −0.429 to −0.146, p < 0.001); households earning 10,000–30,000 and > 30,000 Baht/month score 3.848 and 5.443 points lower than those earning < 10,000 (variable p < 0.001); the other variables are not significant; R² = 0.0367. Backward, Stepwise and Forward all end with age and household income.2หลักการและสูตรLogic and Formula
- X_{ji}
- ค่าของตัวแปรตัวเลข หรือตัวแปรหุ่น (dummy) 0/1 ของระดับหนึ่งของตัวแปรกลุ่มa numeric predictor, or a 0/1 dummy for one level of a categorical predictor
- p
- จำนวนสัมประสิทธิ์ไม่รวมค่าคงที่ (ตัวแปรกลุ่ม L ระดับใช้ L − 1 ตัว)number of coefficients excluding the intercept (a categorical variable with L levels uses L − 1)
- e_i
- ส่วนเหลือ (residual) = ค่าจริง − ค่าทำนายresidual = observed − predicted
- SS_res, SS_tot
- ผลรวมกำลังสองของส่วนเหลือ และของค่าเบี่ยงเบนจากค่าเฉลี่ยresidual sum of squares and total sum of squares about the mean
- L
- ค่า likelihood ของแบบจำลองthe model's likelihood
การเข้ารหัสตัวแปร: ตัวแปรชนิด integer/real เป็นตัวแปรต่อเนื่อง (B = การเปลี่ยนแปลงของค่าเฉลี่ยต่อ 1 หน่วย) · ตัวแปรชนิด nominal, binominal, ordinal และข้อความเป็นตัวแปรกลุ่ม แปลงเป็นตัวแปรหุ่น โดยระดับที่มีรหัสต่ำสุดเป็นกลุ่มอ้างอิง (เช่น Male, CAPD, ไม่มีโรคเรื้อรัง, < 10,000 บาท/เดือน) · ตัวแปรอันดับ (ordinal) ใช้ตัวแปรหุ่นเช่นกัน ไม่ใช่แนวโน้มเส้นตรง · ค่าสูญหาย: ทุกวิธีใช้เฉพาะแถวที่มีค่าครบทั้งตัวแปรตามและทุกตัวแปรที่ใส่ (complete cases) ทุกแบบจำลอง ทุก F test ทุกขั้นของการคัดเลือก และค่า crude ของ Bivariate จึงมาจากผู้ป่วยชุดเดียวกัน · DAPH ไม่รายงานสัมประสิทธิ์มาตรฐาน (standardized β) · การแทนค่าแบบพหุ (multiple imputation) ใช้ได้กับ Enter เท่านั้น
Coding: integer/real variables are continuous (B = change in the mean per 1 unit); nominal, binominal, ordinal and text variables are categorical and become dummies with the lowest code as the reference level (for example Male, CAPD, no chronic disease, < 10,000 Baht/month). Ordinal variables also become dummies, not a linear trend. Missing values: every method uses the rows complete on the outcome and on every variable entered (complete cases), so every model, every F test, every selection step and the crude (Bivariate) estimates come from the same patients. DAPH does not report standardized coefficients (β). Multiple imputation works with Enter only.
วิธีนำตัวแปรเข้า (เกณฑ์ p = 0.05 ทั้งนำเข้าและคัดออก ค่า p ของตัวแปรคือ partial F test ข้างบน ตัวแปรกลุ่มทดสอบตัวแปรหุ่นทุกตัวพร้อมกัน):
How variables enter (p = 0.05 to enter and to remove; a variable's p is the partial F test above, with all dummies of a categorical variable tested together):
- Enter: ใส่ทุกตัวแปรพร้อมกันในแบบจำลองเดียวEnter: all variables together in one model.
- Backward Elimination: เริ่มจากทุกตัวแปร แต่ละรอบตัดตัวแปรที่ค่า p สูงสุดออกถ้า p > 0.05 ทำซ้ำจนทุกตัวแปรที่เหลือมี p ≤ 0.05Backward Elimination: start with all variables; at each step remove the variable with the largest p if p > 0.05; repeat until every remaining variable has p ≤ 0.05.
- Stepwise Regression: เริ่มจากแบบจำลองว่าง แต่ละรอบเพิ่มตัวแปรที่ค่า p น้อยที่สุดถ้า p < 0.05 หลังเพิ่มทุกครั้งตรวจย้อน: ตัวแปรในแบบจำลองที่ p ≥ 0.05 ถูกตัดออก (ทีละตัว ค่า p สูงสุดก่อน) และไม่ถูกนำกลับเข้ามาอีก หยุดเมื่อไม่มีตัวแปรใดมี p < 0.05 · ก่อนเริ่ม ถ้ามีตัวแปรเกิน 25 ตัว หรือ EPV = n ÷ องศาอิสระรวมของตัวแปร (ตัวเลข = 1, ตัวแปรกลุ่ม = จำนวนระดับ − 1) น้อยกว่า 10 DAPH คัดกรองก่อนด้วยการวิเคราะห์ทีละตัวแปรที่ p < 0.25Stepwise Regression: start from the empty model; at each step add the variable with the smallest p if p < 0.05; after every addition check backwards: a variable in the model with p ≥ 0.05 is removed (one at a time, largest p first) and cannot re-enter; stop when no variable has p < 0.05. Before starting, when there are more than 25 variables or EPV = n ÷ total degrees of freedom of the variables (numeric = 1, categorical = levels − 1) is below 10, DAPH first screens each variable alone at p < 0.25.
- Forward Selection: เหมือน Stepwise แต่ไม่ตรวจย้อน ตัวแปรที่เข้าแล้วอยู่ตลอดForward Selection: as Stepwise without the backward check; a variable that enters stays.
- Bivariate Analysis: วิเคราะห์ทีละตัวแปร (ค่าที่ยังไม่ปรับ, crude) ค่า p ของตัวแปรกลุ่มคือ F test ของแบบจำลองตัวแปรเดียว ไม่มี R², F หรือ AIC รวม เพราะไม่มีแบบจำลองเดียวBivariate Analysis: one variable at a time (unadjusted, crude estimates); a categorical variable's p is the F test of its one-variable model; no overall R², F or AIC, because there is no single model.
ถ้าไม่มีตัวแปรใดผ่านการคัดเลือก DAPH แสดงแบบจำลอง Enter ของทุกตัวแปรพร้อมหมายเหตุเตือน · หน้าผลลัพธ์แสดงทุกขั้นตอนการคัดเลือก เช่น "p < 0.0001 < 0.0500, adding Household Income"
When no variable is selected, DAPH shows the Enter model of all variables with a warning note. The results page lists every selection step, for example "p < 0.0001 < 0.0500, adding Household Income".
ตาราง DAPH: Variable · n · Mean (SD) · Adjusted Mean Diff. (เมื่อวิเคราะห์หลายตัวแปร) หรือ Mean Diff. (Bivariate) = B · 95% CI · p-value · เมื่อวิเคราะห์หลายตัวแปร ตัวแปรต่อเนื่องอยู่บนสุด (ส่วน Bivariate เรียงตามลำดับที่เลือก) (n = จำนวนแถวที่ใช้วิเคราะห์, Mean (SD) = NA, p = t test) ตามด้วยตัวแปรกลุ่ม: แถวหัวมี p ของตัวแปร (partial F test) แถวย่อยแต่ละระดับมี n และ Mean (SD) ของตัวแปรตามในระดับนั้นจากแถวที่ใช้วิเคราะห์ (ค่าที่ยังไม่ปรับ) กลุ่มอ้างอิงเขียน Ref. ระดับอื่นมี B และ 95% CI (ไม่แสดง p รายระดับ) · ใต้ตาราง: R² และ Adjusted R² · หน้าผลลัพธ์ (Tab 3) เพิ่ม F, df, p ของแบบจำลอง, AIC, BIC, การตรวจข้อสมมติ (หัวข้อ 12.3) และสมการทำนายสำหรับหน้าทำนาย
DAPH table: Variable · n · Mean (SD) · Adjusted Mean Diff. (multivariable) or Mean Diff. (Bivariate) = B · 95% CI · p-value. In a multivariable run continuous variables come first (Bivariate keeps the order in which they were chosen) (n = number of rows analysed, Mean (SD) = NA, p = t test), then categorical ones: a header row with the variable's p (partial F test) and one row per level with n and the outcome's Mean (SD) in that level among the rows analysed (unadjusted); the reference level reads Ref. and the other levels show B and its 95% CI (no per-level p). Below the table: R² and Adjusted R². The results page (Tab 3) adds the model's F, df and p, AIC, BIC, the assumption checks (section 12.3) and a prediction equation for the prediction page.
AIC/BIC (Akaike, 1974; Schwarz, 1978): DAPH นับพารามิเตอร์เฉพาะสัมประสิทธิ์ (k = p + 1) ส่วน AIC() และ BIC() ของ R นับความแปรปรวน σ² ด้วย ค่าของ R จึงมากกว่าของ DAPH 2 และ ln n ตามลำดับเสมอ ใช้เปรียบเทียบแบบจำลองได้เหมือนกันถ้าใช้โปรแกรมเดียวกันตลอด
AIC/BIC (Akaike, 1974; Schwarz, 1978): DAPH counts only the coefficients (k = p + 1), while R's AIC() and BIC() also count the variance σ², so R's values are always larger by 2 and by ln n. Either works for comparing models, as long as all values come from the same program.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
d$gender <- factor(d$gender, 1:2, c("Male", "Female")) # first level = reference
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
d$fam_income <- factor(d$fam_income, 1:3, c("<10,000", "10,000-30,000", ">30,000"))
vars <- c("age", "gender", "group", "bmi", "chronic", "fam_income")
# n and Mean (SD) of the outcome in each level (descriptive columns of the DAPH table)
for (v in vars[sapply(d[vars], is.factor)])
print(aggregate(d$qolscore3, d[v], function(x) round(c(n = length(x), mean = mean(x), sd = sd(x)), 2)))
# Enter: all predictors together (complete cases), B with t-based 95% CI
fit <- lm(qolscore3 ~ age + gender + group + bmi + chronic + fam_income, data = d)
round(cbind(B = coef(fit), confint(fit)), 3)
summary(fit)$coefficients[, "Pr(>|t|)"]
drop1(fit, test = "F") # one p per variable: partial F test
s <- summary(fit)
c(n = nobs(fit), R2 = s$r.squared, adjR2 = s$adj.r.squared, s$fstatistic,
p = pf(s$fstatistic[1], s$fstatistic[2], s$fstatistic[3], lower.tail = FALSE))
c(AIC = AIC(fit), BIC = BIC(fit), AIC_DAPH = AIC(fit) - 2, BIC_DAPH = BIC(fit) - log(nobs(fit)))
# Bivariate Analysis: one model per variable (crude B; p = F test of that variable)
for (v in vars) {
m <- lm(reformulate(v, "qolscore3"), data = d)
print(cbind(round(cbind(B = coef(m)[-1], confint(m)[-1, , drop = FALSE]), 4), p = signif(anova(m)[1, "Pr(>F)"], 4)))
}
# Backward Elimination: drop the variable with the largest partial-F p while that p > 0.05
bw <- vars
repeat {
pv <- drop1(lm(reformulate(bw, "qolscore3"), data = d), test = "F")[-1, "Pr(>F)"]
if (max(pv) <= 0.05) break
cat(sprintf("remove %-10s p = %.4f\n", bw[which.max(pv)], max(pv)))
bw <- bw[-which.max(pv)]
}
bw
# Stepwise (backward = TRUE) and Forward Selection (backward = FALSE), p = 0.05 to enter and to stay
step_daph <- function(cands, backward = TRUE) {
sel <- character(0); out <- character(0)
repeat {
left <- setdiff(cands, c(sel, out)); if (!length(left)) break
cur <- lm(reformulate(c("1", sel), "qolscore3"), data = d)
p_in <- sapply(left, function(v) anova(cur, update(cur, paste(". ~ . +", v)))[2, "Pr(>F)"])
if (min(p_in) >= 0.05) break
cat(sprintf("add %-10s p = %.3g\n", left[which.min(p_in)], min(p_in)))
sel <- c(sel, left[which.min(p_in)])
while (backward && length(sel)) {
p_out <- drop1(lm(reformulate(sel, "qolscore3"), data = d), test = "F")[-1, "Pr(>F)"]
if (max(p_out) < 0.05) break
out <- c(out, sel[which.max(p_out)]); sel <- sel[-which.max(p_out)]
}
}
sel
}
step_daph(vars)
step_daph(vars, backward = FALSE)
# The final model of all three selection methods
final <- lm(qolscore3 ~ age + fam_income, data = d)
round(cbind(B = coef(final), confint(final)), 3)
round(c(R2 = summary(final)$r.squared, adjR2 = summary(final)$adj.r.squared, summary(final)$fstatistic), 4)
# Missing values: hos has 3 missing, so the model uses 1297 complete cases;
# the F test for a variable must compare two models fitted to those same 1297 rows
d$hos <- factor(d$hos)
fh <- lm(qolscore3 ~ age + gender + hos, data = d)
nobs(fh)
drop1(fh, test = "F")
gender x.n x.mean x.sd
1 Male 446.00 76.11 18.96
2 Female 854.00 75.72 17.25
fam_income x.n x.mean x.sd
1 <10,000 380.00 79.37 17.61
2 10,000-30,000 338.00 75.69 17.61
3 >30,000 582.00 73.66 17.80
B 2.5 % 97.5 %
(Intercept) 99.671 86.764 112.577
age -0.288 -0.429 -0.146
genderFemale 0.165 -1.868 2.197
groupAPD 1.503 -0.415 3.420
bmi -0.014 -0.285 0.258
chronicYes -1.846 -3.796 0.103
fam_income10,000-30,000 -3.848 -6.429 -1.267
fam_income>30,000 -5.443 -7.723 -3.162
Df Sum of Sq RSS AIC F value Pr(>F)
age 1 4916.2 403462 7473.0 15.9373 6.916e-05 ***
gender 1 7.8 398554 7457.1 0.0253 0.87360
group 1 729.2 399276 7459.5 2.3640 0.12440
bmi 1 3.0 398549 7457.1 0.0097 0.92138
chronic 1 1064.7 399611 7460.6 3.4515 0.06342 .
fam_income 2 6842.2 405388 7477.2 11.0904 1.676e-05 ***
n R2 adjR2 value numdf dendf
1.300000e+03 3.672598e-02 3.150700e-02 7.037007e+00 7.000000e+00 1.292000e+03
p.value
2.925291e-08
AIC BIC AIC_DAPH BIC_DAPH
11150.34 11196.87 11148.34 11189.70
B 2.5 % 97.5 % p
age -0.3152 -0.4522 -0.1781 7.009e-06
genderFemale -0.3942 -2.4403 1.6519 0.7055
groupAPD 1.956 0.0159 3.896 0.04815
bmi 0.0988 -0.1655 0.3632 0.4634
chronicYes -2.1249 -4.0643 -0.1854 0.03179
fam_income10,000-30,000 -3.6746 -6.2705 -1.0788 6.875e-06
fam_income>30,000 -5.7129 -8.0027 -3.4231 6.875e-06
remove bmi p = 0.9214
remove gender p = 0.8795
remove group p = 0.1248
remove chronic p = 0.0514
[1] "age" "fam_income"
add fam_income p = 6.88e-06
add age p = 1.67e-05
[1] "fam_income" "age"
B 2.5 % 97.5 %
(Intercept) 100.145 90.548 109.741
age -0.300 -0.437 -0.164
fam_income10,000-30,000 -3.749 -6.327 -1.170
fam_income>30,000 -5.463 -7.741 -3.186
R2 adjR2 value numdf dendf
0.0321 0.0299 14.3321 3.0000 1296.0000
[1] 1297
Df Sum of Sq RSS AIC F value Pr(>F)
age 1 6196.3 411550 7486.6 19.6886 9.893e-06 ***
gender 1 25.1 405378 7467.0 0.0797 0.7777
hos 6 1612.9 406966 7462.0 0.8542 0.5282
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Enter: n / reference levels | 1300 / Male, CAPD, No, <10,000 | 1300 / Male, CAPD, No chronic disease, < 10,000 | 0 | ✓ PASS |
| Enter: n and Mean (SD) per level (e.g. Male / Female) | 446, 76.11 (18.96) / 854, 75.72 (17.25) | 446, 76.11 (18.96) / 854, 75.72 (17.25) | 0 | ✓ PASS |
| Enter: B (95% CI) age | −0.288 (−0.429 to −0.146) | −0.288 (−0.429 to −0.146) | < 1e−10 | ✓ PASS |
| Enter: B (95% CI) Female / APD / BMI / chronic | 0.165 / 1.503 / −0.014 / −1.846 | 0.165 / 1.503 / −0.014 / −1.846 (CIs identical) | < 1e−10 | ✓ PASS |
| Enter: B (95% CI) household income 10,000–30,000 / > 30,000 | −3.848 (−6.429 to −1.267) / −5.443 (−7.723 to −3.162) | −3.848 (−6.429 to −1.267) / −5.443 (−7.723 to −3.162) | < 1e−10 | ✓ PASS |
| Enter: p per variable (age, BMI: t; others: partial F) | 6.916e−05 / 0.92138 / 0.87360 / 0.12440 / 0.06342 / 1.676e−05 | <0.001 / 0.921 / 0.874 / 0.124 / 0.063 / <0.001 | < 1e−12 | ✓ PASS |
| Enter: R² / Adjusted R² / F(7, 1292) / p | 0.036726 / 0.031507 / 7.037007 / 2.925291e−08 | 0.0367 / 0.0315 / 7.04 / <0.001 (engine 2.925291e−08) | < 1e−12 | ✓ PASS |
| Enter: AIC / BIC (DAPH convention: R value − 2 / − ln n) | 11148.34 / 11189.70 | 11148.3 / 11189.7 | < 1e−8 | ✓ PASS |
| Bivariate: crude B and p (age; Female; APD; BMI; chronic; income 2, 3) | −0.3152; −0.3942, 0.7055; 1.956, 0.04815; 0.0988, 0.4634; −2.1249, 0.03179; −3.6746, −5.7129 | −0.315; −0.394, 0.706; 1.956, 0.048; 0.099, 0.463; −2.125, 0.032; −3.675, −5.713 | < 0.0005 (display) | ✓ PASS |
| Backward: variables removed (p) in order | BMI 0.9214, gender 0.8795, group 0.1248, chronic 0.0514 | BMI 0.9214, Gender 0.8795, Treatment Group 0.1248, Chronic Disease 0.0514 | 0 (4 dp) | ✓ PASS |
| Stepwise / Forward: variables added in order | fam_income, age | Household Income, Age (years) | — | ✓ PASS |
| Final model (all three methods): B age / income 2 / income 3 | −0.300 / −3.749 / −5.463 | −0.300 / −3.749 / −5.463 | < 0.0005 (display) | ✓ PASS |
| Final model: R² / Adjusted R² / F(3, 1296) | 0.0321 / 0.0299 / 14.3321 | 0.0321 / 0.0299 / 14.33 | < 0.005 (display) | ✓ PASS |
| Missing values (age + gender + hos, n = 1297): p of Hospital | 0.5282 (F(6, 1288) = 0.8542) | 0.528 (engine F(6, 1288) = 0.854184, p = 0.5281540; both models on the 1297 rows) | < 1e−12 | ✓ PASS |
ความต่างคำนวณจากค่าเต็มของ R และค่าที่ engine ของ DAPH คำนวณก่อนปัดเศษ เว้นแถวที่เขียนว่า display ซึ่งเทียบที่ทศนิยมที่ DAPH แสดง · ค่าสูญหาย: hos มีค่าสูญหาย 3 ค่า DAPH จึงวิเคราะห์ 1,297 แถวที่มีค่าครบ และทดสอบ Hospital โดยเปรียบเทียบสองแบบจำลองบนแถวชุดเดียวกันนี้ ได้ค่าเดียวกับ R
Differences are computed from R's full-precision values and the values DAPH's engine computed before rounding, except rows marked display, which are compared at the decimals DAPH shows. Missing values: hos has 3 missing values, so DAPH analyses the 1,297 complete rows and tests Hospital by comparing two models fitted to those same rows, giving R's value.
4การแปลผลและตัวอย่างInterpretation and Example
อ่านค่าสัมประสิทธิ์: ตัวแปรต่อเนื่อง B = ค่าเฉลี่ยของตัวแปรตามเปลี่ยนไปเท่าใดต่อ 1 หน่วย เมื่อตัวแปรอื่นคงที่ (อายุ −0.288 คะแนนต่อปี: อายุต่างกัน 10 ปี คะแนนเฉลี่ยต่างกันประมาณ 2.9 คะแนน) · ตัวแปรกลุ่ม B = ผลต่างของค่าเฉลี่ยจากกลุ่มอ้างอิงหลังปรับตัวแปรอื่น (รายได้ > 30,000 บาท/เดือน ต่ำกว่ากลุ่ม < 10,000 บาท/เดือน 5.443 คะแนน) · ค่า Mean (SD) ในตารางเป็นค่าที่ยังไม่ปรับ จึงอาจต่างจาก B ได้ (Female: ค่าเฉลี่ยดิบต่ำกว่า Male 0.39 แต่ B หลังปรับ = 0.165 ทั้งสองค่าไม่มีนัยสำคัญ) · ใช้ค่า p ของตัวแปร (แถวหัว) ตัดสินว่าตัวแปรกลุ่มสัมพันธ์กับผลลัพธ์หรือไม่
Reading the coefficients: for a continuous variable, B is how much the mean outcome changes per 1 unit with the other variables held constant (age −0.288 points per year: a 10-year difference in age goes with about a 2.9-point difference in the mean score). For a categorical variable, B is the difference in the mean from the reference level after adjustment (> 30,000 Baht/month is 5.443 points below < 10,000 Baht/month). The table's Mean (SD) values are unadjusted, so they can disagree with B (Female: the raw mean is 0.39 below Male, but the adjusted B is 0.165; neither is significant). Use the variable's p (the header row) to judge whether a categorical variable is associated with the outcome.
ความเหมาะสมของแบบจำลอง: R² = 0.0367 ตัวแปรทั้งหกอธิบายความผันแปรของคะแนนได้เพียงร้อยละ 3.7 (Adjusted R² = 0.0315 ปรับตามจำนวนตัวแปร) แม้ F(7, 1292) = 7.04, p < 0.001 ซึ่งบอกเพียงว่ามีตัวแปรอย่างน้อยหนึ่งตัวสัมพันธ์กับผลลัพธ์ ไม่ได้บอกว่าแบบจำลองเหมาะสมหรือทำนายได้ดี · ตัวแปรที่ไม่มีนัยสำคัญ (เช่น กลุ่มการรักษา p = 0.124, 95% CI ของ APD −0.415 ถึง 3.420) ไม่ได้แปลว่าไม่มีความต่าง ช่วงเชื่อมั่นยังครอบคลุมความต่างขนาดเล็กได้ทั้งสองทิศ
Fit: R² = 0.0367, so the six variables explain only 3.7% of the variation in the score (Adjusted R² = 0.0315 allows for the number of variables). F(7, 1292) = 7.04, p < 0.001 only says that at least one variable is associated with the outcome, not that the model is adequate or predicts well. A non-significant variable (for example treatment group, p = 0.124, APD 95% CI −0.415 to 3.420) does not mean no difference; the interval still covers small differences in either direction.
การคัดเลือกตัวแปร: Backward, Stepwise และ Forward ได้ อายุ + รายได้ครัวเรือน (R² = 0.0321) ค่า p และช่วงเชื่อมั่นของแบบจำลองที่ผ่านการคัดเลือกมักแคบเกินจริงเพราะใช้ข้อมูลชุดเดียวกันทั้งเลือกและประมาณค่า ถ้าต้องการควบคุมตัวแปรกวนตามกรอบแนวคิด ให้ใช้ Enter กับตัวแปรที่กำหนดไว้ล่วงหน้า · การตรวจข้อสมมติ (ความเป็นปกติของส่วนเหลือ ความแปรปรวนคงที่ multicollinearity ค่าอิทธิพลสูง) อธิบายไว้ในหัวข้อ 12.3 ด้วยแบบจำลอง Enter เดียวกันนี้ · ข้อมูลเป็นการสังเกต จึงรายงานเป็นความสัมพันธ์ ไม่ใช่ผลเชิงเหตุ
Variable selection: Backward, Stepwise and Forward all keep age + household income (R² = 0.0321). p-values and confidence intervals after selection tend to be too narrow, because the same data chose and estimated the model; to control confounders according to a conceptual framework, use Enter with variables chosen in advance. The assumption checks (normal residuals, constant variance, multicollinearity, influential points) are described in section 12.3 with this same Enter model. The data are observational, so report associations, not causal effects.
📖 References
- Akaike, H. (1974). A new look at the statistical model identification. IEEE Transactions on Automatic Control, 19(6), 716–723. doi:10.1109/TAC.1974.1100705
- Schwarz, G. (1978). Estimating the dimension of a model. The Annals of Statistics, 6(2), 461–464. doi:10.1214/aos/1176344136
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 2 — ตัวแปรเลือก 2 ทาง (Binary)Chapter 2 — Binary Outcomes ✓ Verified
สถิติสำหรับตัวแปรตามที่มี 2 ค่า เช่น ป่วย/ไม่ป่วย เสียชีวิต/รอดชีวิต · เลือกตามรูปแบบของข้อมูลและคำถาม: odds ratio จากข้อมูลที่แต่ละคนเป็นอิสระต่อกัน (2.1) ข้อมูลที่จับคู่หรือแบ่งเป็นชั้น (2.2) ข้อมูลที่รวมกลุ่มกันในโรงพยาบาลหรือพื้นที่ (2.3) ความสัมพันธ์ของตัวแปรกลุ่มสองตัว (2.4) ผลลัพธ์ 2 ค่าที่วัดซ้ำในคนเดิมหรือในคู่ที่จับคู่ (2.5) ความแม่นของการทดสอบวินิจฉัย (2.6) และ risk ratio เมื่อผลลัพธ์พบบ่อย (2.7) · ทุกหัวข้อทวนสอบผลของ DAPH กับ R บนข้อมูลตัวอย่างของ DAPH และระบุค่าที่ไม่ตรงกันไว้ในตารางทวนสอบ (✗ FAIL) แทนการบอกว่าตรงกันทั้งหมด Methods for outcomes with two values, such as ill/not ill or died/survived. Choose by the structure of the data and the question: odds ratios from independent observations (2.1), matched or stratified data (2.2), data clustered in hospitals or areas (2.3), the association of two categorical variables (2.4), a two-value outcome measured twice on the same person or in matched pairs (2.5), the accuracy of a diagnostic test (2.6), and the risk ratio when the outcome is common (2.7). Every section checks DAPH against R on the DAPH example data and marks any disagreement in its verification table (✗ FAIL) instead of claiming that everything matches.
2.1Logistic Regression (Unconditional)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Logistic Regression ใช้ตอบคำถามว่าปัจจัยใดสัมพันธ์กับผลลัพธ์ที่มี 2 ค่า (ตาย/รอด ป่วย/ไม่ป่วย) โดยรายงานเป็น odds ratio (OR, อัตราส่วนออดส์) ของแต่ละปัจจัยที่ปรับด้วยตัวแปรอื่นในแบบจำลองแล้ว (Cox, 1958) · ใช้เมื่อตัวแปรตามมี 2 ระดับและแต่ละคนเป็นข้อมูลอิสระต่อกัน · ไม่เหมาะเมื่อข้อมูลเป็นชุดจับคู่ (ใช้ 2.2) เมื่อผู้ป่วยรวมกลุ่มกันในโรงพยาบาลหรืออำเภอและต้องคำนึงถึงกลุ่ม (2.3) เมื่อตัวแปรตามมี 3 ระดับขึ้นไป (3.1, 3.2) เมื่อผลลัพธ์พบบ่อยและต้องการ risk ratio (2.7) หรือเมื่อคำถามคือระยะเวลาจนเกิดเหตุการณ์และแต่ละคนถูกติดตามนานไม่เท่ากัน (5.2)
Logistic regression asks which factors are associated with a two-level outcome (died/survived, ill/not ill) and reports each factor as an odds ratio (OR) adjusted for the other variables in the model (Cox, 1958). Use it when the dependent variable has two levels and every person is an independent observation. It is not the right tool for matched sets (use 2.2), for patients grouped in hospitals or districts when the grouping matters (2.3), for outcomes with three or more levels (3.1, 3.2), when the outcome is common and a risk ratio is wanted (2.7), or when the question is time to an event and follow-up differs between people (5.2).
สองชื่อ หนึ่งแบบจำลองใน DAPH: Logistic Regression อยู่ในรายการสถิติเมื่อไม่ได้ติ๊ก Intervention/Interested Factor? ส่วน Unconditional Logistic Regression ปรากฏเมื่อติ๊กช่องนี้ เลือกตัวแปร intervention (ต้องอยู่ในกล่อง Independent Variables) และไม่ได้เลือก Matching Variable · ทั้งสองส่งไปคำนวณที่ส่วนประมวลผลเดียวกัน ได้ OR ช่วงเชื่อมั่น ค่า p ของแต่ละตัวแปร และค่าความเหมาะสมของแบบจำลองเท่ากันทุกค่า ต่างกันที่รูปแบบตาราง: Logistic Regression แสดงจำนวนและร้อยละของผู้เกิดเหตุการณ์ในแต่ละระดับ คู่กับ Crude OR และ Adjusted OR · Unconditional Logistic Regression แสดงสองระดับของตัวแปรตามเป็นคอลัมน์ (จำนวนและร้อยละตามคอลัมน์ คือการกระจายของแต่ละปัจจัยในกลุ่มที่เสียชีวิตและกลุ่มที่ไม่เสียชีวิต) ตามด้วย Adjusted OR, 95% CI และค่า p หนึ่งค่าต่อตัวแปร โดยไม่มี Crude OR · คำว่า "unconditional" หมายถึงไม่ได้วิเคราะห์ภายในชุดจับคู่ ต่างจาก conditional logistic regression ในหัวข้อ 2.2
Two names, one model in DAPH: Logistic Regression is listed when Intervention/Interested Factor? is not ticked; Unconditional Logistic Regression appears when the box is ticked, an intervention variable is chosen (it must be one of the Independent Variables) and no Matching Variable is set. Both are sent to the same engine and give identical ORs, confidence intervals, variable p values and model-fit statistics; only the table differs. Logistic Regression shows the number and percentage with the event at each level, with crude and adjusted ORs. Unconditional Logistic Regression shows the two outcome levels as columns (numbers and column percentages: how each factor is distributed among those who died and those who did not), then the adjusted OR, 95% CI and one p per variable, without crude ORs. "Unconditional" means the analysis is not conditioned on matched sets, unlike conditional logistic regression in 2.2.
2หลักการและสูตรLogic and Formula
- pi, Yi
- ความน่าจะเป็นที่คนที่ i เกิดเหตุการณ์ (Y = 1) · DAPH ใช้รหัสที่สูงกว่าของตัวแปรตามเป็นเหตุการณ์ (status 1 = Died/Event)probability that person i has the event (Y = 1); DAPH takes the higher code of the outcome as the event (status 1 = Died/Event)
- xji, βj
- ตัวทำนายที่ j และสัมประสิทธิ์ (log-odds ที่เปลี่ยนต่อ 1 หน่วยของ xj) · ตัวแปรกลุ่มแปลงเป็นตัวแปรหุ่นเทียบกับรหัสต่ำสุด (กลุ่มอ้างอิง)predictor j and its coefficient (change in log-odds per unit of xj); a categorical predictor becomes dummy variables against its lowest code (the reference group)
- SEj
- ความคลาดเคลื่อนมาตรฐาน จากรากที่สองของแนวทแยงของอินเวอร์สเมทริกซ์สารสนเทศstandard error, the square root of a diagonal element of the inverse information matrix
- ℓ0, ℓ(β̂(−v))
- log-likelihood ของแบบจำลองที่มีแต่ค่าคงที่ และของแบบจำลองที่ตัดตัวแปร v ออก ทั้งสองต้องประมาณบนแถวชุดเดียวกับแบบจำลองเต็มlog-likelihood of the intercept-only model and of the model without variable v, both fitted on the same rows as the full model
- dv, k, q, n
- จำนวนสัมประสิทธิ์ของตัวแปร v (1 สำหรับตัวแปรต่อเนื่องหรือ 2 ระดับ, จำนวนระดับ − 1 สำหรับตัวแปรกลุ่ม) · k = จำนวนสัมประสิทธิ์ไม่นับค่าคงที่ · q = k + 1 · n = จำนวนคนที่ใช้วิเคราะห์number of coefficients of variable v (1 for a continuous or two-level variable, levels − 1 for a categorical one); k = coefficients excluding the intercept; q = k + 1; n = number of people analysed
- O1g, O0g, ng
- จำนวนที่เกิดและไม่เกิดเหตุการณ์ที่สังเกตได้ และจำนวนคนในกลุ่ม gobserved numbers with and without the event, and the number of people, in group g
สิ่งที่ DAPH คำนวณ: ประมาณค่าด้วยวิธีภาวะน่าจะเป็นสูงสุด (maximum likelihood) แบบ Newton-Raphson ซึ่งสำหรับ logit link คือขั้นตอนเดียวกับ IRLS/Fisher scoring ของ R glm จึงได้ค่าประมาณเท่ากัน · ช่วงเชื่อมั่นเป็นแบบ Wald (ข้างบน) ไม่ใช่ profile likelihood ใน R ต้องใช้ confint.default() เพราะ confint() ของ glm ให้ช่วงแบบ profile ซึ่งต่างเล็กน้อย · ใช้เฉพาะคนที่มีข้อมูลครบทุกตัวแปรในแบบจำลอง ทั้งในแบบจำลองที่ปรับแล้ว แบบจำลองที่ใช้ทดสอบ LR และทุกขั้นของการคัดเลือกตัวแปร (Tab 3 ยังรายงานจำนวนทั้งหมดและจำนวนที่ข้อมูลขาด) · Crude OR ประมาณจากแบบจำลองทีละตัวแปรบนแถวชุดเดียวกับแบบจำลองที่ปรับแล้ว
What DAPH computes: maximum likelihood by Newton-Raphson, which for the logit link is the same iteration as the IRLS/Fisher scoring of R glm, so the estimates are identical. Intervals are Wald intervals (above), not profile-likelihood intervals; in R use confint.default(), because confint() on a glm gives profile intervals that differ slightly. Only people with complete data on every model variable are used, for the adjusted model, the models behind the LR tests and every selection step (Tab 3 still reports the total and the number missing). The crude OR comes from a one-predictor model fitted on the same rows as the adjusted model.
ค่า p ในตาราง (หนึ่งค่าต่อตัวแปร): ตัวแปรกลุ่ม = LR test Gv แสดงที่แถวชื่อตัวแปร (แถวระดับย่อยไม่มีค่า p) · ตัวแปรต่อเนื่อง = Wald z · หมายเหตุใต้ตารางแสดง Events/N, LR χ²(k), Pseudo R² (McFadden), Nagelkerke R² (Nagelkerke, 1991), Hosmer-Lemeshow (Hosmer & Lemeshow, 1980), AUC (พื้นที่ใต้โค้ง ROC คำนวณบนข้อมูลชุดเดียวกับที่ใช้สร้างแบบจำลอง จึงมองโลกในแง่ดีเล็กน้อย), AIC, BIC และ log-likelihood
p values in the table (one per variable): a categorical variable gets the LR test Gv on its name row (its level rows carry no p); a continuous variable gets the Wald z test. The note under the table gives Events/N, LR χ²(k), pseudo R² (McFadden), Nagelkerke R² (Nagelkerke, 1991), Hosmer-Lemeshow (Hosmer & Lemeshow, 1980), AUC (area under the ROC curve, computed on the same data that built the model and therefore slightly optimistic), AIC, BIC and the log-likelihood.
Hosmer-Lemeshow กับความเสี่ยงที่ทำนายได้ซ้ำกัน: DAPH แบ่ง 10 กลุ่มตามความเสี่ยงที่ทำนายได้ (deciles of risk) โดยตัดที่ควอนไทล์ของความเสี่ยง คนที่มีความเสี่ยงที่ทำนายได้เท่ากันจึงอยู่กลุ่มเดียวกันเสมอ (Hosmer et al., 2013) เป็นกฎเดียวกับ R ResourceSelection::hoslem.test และ df = G − 2 = 8 · ข้อมูลนี้มีความเสี่ยงที่ทำนายได้ต่างกันเพียง 548 ค่าในผู้ป่วย 1,300 คน ถ้าแบ่งรายการที่เรียงแล้วเป็นกลุ่มเท่ากันพอดีโดยไม่สนใจค่าซ้ำ ค่าสถิติจะเปลี่ยนตามลำดับแถวของข้อมูล
Hosmer-Lemeshow and tied predicted risks: DAPH forms the ten groups of predicted risk (deciles of risk) by cutting at quantiles of the predicted risk, so people with the same predicted risk always fall in the same group (Hosmer et al., 2013); this is the rule of R ResourceSelection::hoslem.test, with df = G − 2 = 8. These data have only 548 distinct predicted risks among 1,300 patients; cutting the sorted list into exactly equal groups regardless of ties would make the statistic depend on the order of the rows.
วิธีนำตัวแปรเข้า (Analysis Method): Enter ใส่ทุกตัวแปร · Backward Elimination เริ่มจากทุกตัวแปร ตัดตัวแปรที่ค่า p ของ LR test มากที่สุดออกทีละตัวเมื่อค่านั้นเกิน 0.05 แล้วประมาณค่าใหม่ · Forward Selection เริ่มจากไม่มีตัวแปร เพิ่มตัวแปรที่ค่า p น้อยที่สุดทีละตัวเมื่อค่านั้นน้อยกว่า 0.05 (Wald p สำหรับตัวแปรต่อเนื่อง, LR p สำหรับตัวแปรกลุ่ม) · Stepwise Regression ทำแบบ Forward และหลังเพิ่มตัวแปรแต่ละครั้งตัดตัวแปรที่ LR p ≥ 0.05 ออก ตัวแปรที่ถูกตัดแล้วไม่นำกลับเข้ามาอีก · สำหรับ Forward และ Stepwise ถ้ามีตัวแปรมากกว่า 25 ตัว หรือจำนวนเหตุการณ์ (หรือไม่เกิดเหตุการณ์ ถ้าน้อยกว่า) ต่อองศาอิสระของตัวแปรทั้งหมด (EPV, events per variable) น้อยกว่า 10 จะคัดกรองทีละตัวแปรด้วย p < 0.25 ก่อน · Bivariate Analysis วิเคราะห์ทีละตัวแปร ให้ OR แบบ crude พร้อม 95% CI และค่า p (LR test สำหรับตัวแปรกลุ่ม) ไม่มีค่าความเหมาะสมของแบบจำลอง
How variables enter (Analysis Method): Enter keeps every variable. Backward Elimination starts with all of them and removes, one at a time, the variable with the largest LR-test p while that p is above 0.05, refitting after each removal. Forward Selection starts empty and adds, one at a time, the variable with the smallest p while that p is below 0.05 (Wald p for a continuous variable, LR p for a categorical one). Stepwise Regression works as Forward and, after each addition, removes any variable whose LR p is 0.05 or more; a removed variable is not offered again. For Forward and Stepwise, when there are more than 25 candidates or fewer than 10 events (or non-events, if fewer) per candidate degree of freedom (EPV, events per variable), each candidate is first screened on its own with p < 0.25. Bivariate Analysis fits each variable on its own and reports its crude OR, 95% CI and p (LR test for a categorical variable), without model-fit statistics.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
glm), pROC, ResourceSelectionR 4.3.3 · packages stats (glm), pROC, ResourceSelection# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
d$bmi_group <- factor(d$bmi_group, 1:4, c("Underweight", "Normal", "Overweight", "Obese"))
table(d$status) # 0 = alive/censored, 1 = died (the event)
round(100 * tapply(d$status, d$group, mean), 2) # % died by treatment group
# 1) Enter: adjusted OR with Wald 95% CI and Wald p
fit <- glm(status ~ group + age + gender + chronic + bmi_group, data = d, family = binomial)
round(cbind(OR = exp(coef(fit)), exp(confint.default(fit)), p = coef(summary(fit))[, 4]), 4)
exp(10 * coef(fit)["age"]) # OR per 10 years of age
# 2) one p per variable: likelihood-ratio test of dropping the variable
drop1(fit, test = "LRT")
# both models must use the same rows; Hospital Type (type) has 3 missing values
drop1(glm(status ~ group + age + type, data = d, family = binomial), test = "LRT")["type", ]
# 3) crude OR (one predictor at a time) and the bivariate LR p
vars <- c("group", "age", "gender", "chronic", "bmi_group")
crude <- lapply(vars, function(v) glm(reformulate(v, "status"), data = d, family = binomial))
round(do.call(rbind, lapply(crude, function(m)
cbind(OR = exp(coef(m)), exp(confint.default(m)))[-1, , drop = FALSE])), 4)
setNames(sapply(crude, function(m) anova(m, test = "LRT")[2, "Pr(>Chi)"]), vars)
# 4) model fit, as in the note under the DAPH table
null <- glm(status ~ 1, data = d, family = binomial)
ll1 <- as.numeric(logLik(fit)); ll0 <- as.numeric(logLik(null)); n <- nobs(fit)
LR <- 2 * (ll1 - ll0)
round(c(LR = LR, df = length(coef(fit)) - 1, p = pchisq(LR, length(coef(fit)) - 1, lower.tail = FALSE),
McFadden = 1 - ll1 / ll0, Nagelkerke = (1 - exp(-LR / n)) / (1 - exp(2 * ll0 / n)),
AIC = AIC(fit), BIC = BIC(fit), logLik = ll1), 4)
library(pROC)
auc(roc(d$status, fitted(fit), quiet = TRUE))
library(ResourceSelection)
hoslem.test(d$status, fitted(fit), g = 10) # tied predicted risks stay in one group
length(unique(fitted(fit))) # distinct predicted risks among 1,300 patients
# 5) Backward Elimination as DAPH does it: drop the variable with the largest
# LR-test p while that p is above 0.05, refit, repeat
m <- fit
repeat {
t <- drop1(m, test = "LRT")[-1, ]
if (max(t[, "Pr(>Chi)"]) <= 0.05) break
out <- rownames(t)[which.max(t[, "Pr(>Chi)"])]
cat("removed:", out, " LR p =", round(max(t[, "Pr(>Chi)"]), 4), "\n")
m <- update(m, as.formula(paste(". ~ . -", out)))
}
round(cbind(OR = exp(coef(m)), exp(confint.default(m))), 4)
round(c(LR = 2 * (as.numeric(logLik(m)) - ll0), AIC = AIC(m)), 3)
# alive (0) / died (1); % died by treatment group
0 1
1071 229
CAPD APD
13.11 22.20
# 1) Enter: adjusted OR, Wald 95% CI, Wald p
OR 2.5 % 97.5 % p
(Intercept) 0.0067 0.0013 0.0337 0.0000
groupAPD 2.0261 1.5026 2.7320 0.0000
age 1.0419 1.0209 1.0634 0.0001
genderFemale 1.1729 0.8547 1.6095 0.3233
chronicYes 1.6030 1.1874 2.1640 0.0021
bmi_groupNormal 0.8592 0.5246 1.4073 0.5466
bmi_groupOverweight 0.8077 0.4642 1.4054 0.4497
bmi_groupObese 0.8200 0.4772 1.4091 0.4726
# OR per 10 years of age
age
1.50752
# 2) LR test of each variable (DAPH: p on the variable row)
Df Deviance AIC LRT Pr(>Chi)
<none> 1159.6 1175.6
group 1 1181.8 1195.8 22.142 2.533e-06 ***
age 1 1174.9 1188.9 15.289 9.226e-05 ***
gender 1 1160.6 1174.6 0.987 0.320477
chronic 1 1169.3 1183.3 9.643 0.001901 **
bmi_group 3 1160.3 1170.3 0.639 0.887457
# Hospital Type (3 missing values): LR test on the same 1,297 rows
Df Deviance AIC LRT Pr(>Chi)
type 1 1169.8 1175.8 0.18979 0.6631
# 3) crude OR, then the bivariate LR p
OR 2.5 % 97.5 %
groupAPD 1.8918 1.4111 2.5362
age 1.0440 1.0241 1.0643
genderFemale 1.2289 0.9032 1.6719
chronicYes 1.6017 1.1984 2.1408
bmi_groupNormal 0.7612 0.4739 1.2227
bmi_groupOverweight 0.6598 0.3903 1.1154
bmi_groupObese 0.7173 0.4324 1.1900
group age gender chronic bmi_group
1.549431e-05 1.457141e-05 1.857566e-01 1.335074e-03 4.801957e-01
# 4) model fit
LR df p McFadden Nagelkerke AIC BIC
50.6984 7.0000 0.0000 0.0419 0.0631 1175.6301 1216.9911
logLik
-579.8151
Area under the curve: 0.6412
X-squared = 6.1585, df = 8, p-value = 0.6295
[1] 548
# 5) Backward Elimination
removed: bmi_group LR p = 0.8875
removed: gender LR p = 0.3178
OR 2.5 % 97.5 %
(Intercept) 0.0053 0.0013 0.0220
groupAPD 2.0218 1.5000 2.7251
age 1.0445 1.0243 1.0652
chronicYes 1.6014 1.1912 2.1528
LR AIC
49.061 1169.267
| Quantity | R 4.3.3 | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Adjusted OR, APD vs CAPD (95% CI) | 2.0261 (1.5026 to 2.7320) | 2.026 (1.503 to 2.732) | < 0.0005 | ✓ PASS |
| Adjusted OR, age per year (95% CI) | 1.0419 (1.0209 to 1.0634) | 1.042 (1.021 to 1.063) | < 0.0005 | ✓ PASS |
| Adjusted OR, chronic disease (95% CI) | 1.6030 (1.1874 to 2.1640) | 1.603 (1.187 to 2.164) | < 0.0005 | ✓ PASS |
| Adjusted OR, female (95% CI) | 1.1729 (0.8547 to 1.6095) | 1.173 (0.855 to 1.610) | < 0.0005 | ✓ PASS |
| LR-test p: gender / chronic disease / BMI group | 0.320477 / 0.001901 / 0.887457 | 0.320 / 0.002 / 0.887 | < 0.0005 | ✓ PASS |
| LR-test p of a variable with missing values: Hospital Type (3 missing) in status ~ group + age + type | 0.6631 | 0.663 | < 0.0005 | ✓ PASS |
| Crude OR, APD vs CAPD (95% CI) | 1.8918 (1.4111 to 2.5362) | 1.892 (1.411 to 2.536) | < 0.0005 | ✓ PASS |
| Bivariate LR p: gender / BMI group | 0.1858 / 0.4802 | 0.186 / 0.480 | < 0.0005 | ✓ PASS |
| Model LR χ²(7) | 50.6984 | 50.698 | < 0.0005 | ✓ PASS |
| McFadden R² / Nagelkerke R² | 0.0419 / 0.0631 | 0.0419 / 0.0631 | < 0.00005 | ✓ PASS |
| AIC / BIC / log-likelihood | 1175.6301 / 1216.9911 / −579.8151 | 1175.6 / 1217.0 / −579.815 | < 0.05 | ✓ PASS |
| AUC | 0.6412 | 0.6412 | < 0.00005 | ✓ PASS |
| Hosmer-Lemeshow χ²(8), p | 6.1585, p = 0.6295 | 6.158, p = 0.6295 | < 0.0005 | ✓ PASS |
| Backward Elimination: removed, then APD OR (95% CI) and LR χ²(3) | bmi_group, gender · 2.0218 (1.5000 to 2.7251) · 49.061 | BMI Group, Gender · 2.022 (1.500 to 2.725) · 49.061 | < 0.0005 | ✓ PASS |
แถว Hospital Type ตรวจกรณีตัวแปรมีค่าว่าง: Hospital Type ขาด 3 ราย แบบจำลองเต็มและแบบจำลองที่ตัด Hospital Type ออกจึงประมาณบนผู้ป่วย 1,297 คนชุดเดียวกัน ค่า p ตรงกับ R drop1 · ใน DAPH วิธี Stepwise Regression และ Forward Selection ได้แบบจำลองสุดท้ายชุดเดียวกับ Backward Elimination (Treatment Group, Age (years), Chronic Disease)
The Hospital Type row checks a variable with missing values: Hospital Type is missing for 3 patients, so the full model and the model without Hospital Type are both fitted on the same 1,297 patients, and the p equals that of R drop1. In DAPH, Stepwise Regression and Forward Selection reach the same final model as Backward Elimination (Treatment Group, Age (years), Chronic Disease).
4การแปลผลและตัวอย่างInterpretation and Example
ผลหลัก: ผู้ป่วยกลุ่ม APD มี odds ของการเสียชีวิตระหว่างติดตามเป็น 2.03 เท่าของกลุ่ม CAPD ที่มีอายุ เพศ โรคเรื้อรัง และกลุ่ม BMI เดียวกัน (Adjusted OR 2.03, 95% CI 1.50 to 2.73, p < 0.001) ใกล้เคียงกับ Crude OR 1.89 การปรับด้วยตัวแปรอื่นจึงเปลี่ยนค่าประมาณเพียงเล็กน้อย · อายุ: OR 1.04 ต่อ 1 ปี (95% CI 1.02 to 1.06, p < 0.001) หรือประมาณ 1.51 เท่าต่อ 10 ปี · มีโรคเรื้อรัง: OR 1.60 (95% CI 1.19 to 2.16, p = 0.002) · เพศหญิง: OR 1.17 (95% CI 0.85 to 1.61, p = 0.320) ไม่มีนัยสำคัญ ซึ่งไม่ได้แปลว่าไม่ต่างกัน เพราะช่วงเชื่อมั่นยังครอบคลุมทั้งผลลดลงและเพิ่มขึ้นระดับปานกลาง · BMI Group: p = 0.887
Main result: patients on APD had 2.03 times the odds of dying during follow-up of CAPD patients of the same age, gender, chronic-disease status and BMI group (adjusted OR 2.03, 95% CI 1.50 to 2.73, p < 0.001), close to the crude OR of 1.89, so adjustment changed the estimate little. Age: OR 1.04 per year (95% CI 1.02 to 1.06, p < 0.001), about 1.51 per 10 years. Chronic disease: OR 1.60 (95% CI 1.19 to 2.16, p = 0.002). Female gender: OR 1.17 (95% CI 0.85 to 1.61, p = 0.320), not significant, which does not mean no difference: the interval still includes moderate decreases and increases. BMI Group: p = 0.887.
ความเหมาะสมของแบบจำลอง: LR χ²(7) = 50.70, p < 0.001 · McFadden R² 0.042 และ Nagelkerke R² 0.063 คือปัจจัยเหล่านี้อธิบายความแปรผันของการเสียชีวิตได้น้อย ซึ่งพบบ่อยในข้อมูลระดับบุคคล · AUC 0.641 จำแนกผู้เสียชีวิตกับผู้รอดได้ปานกลางค่อนข้างต่ำ · Hosmer-Lemeshow (χ²(8) = 6.16, p = 0.629) ไม่พบหลักฐานว่าการปรับเทียบไม่ดี ซึ่งไม่ได้พิสูจน์ว่าการปรับเทียบดี · Backward Elimination ตัด BMI Group และ Gender ออก แบบจำลองสุดท้ายให้ OR ของ APD 2.02 (95% CI 1.50 to 2.73)
Model fit: LR χ²(7) = 50.70, p < 0.001. McFadden R² 0.042 and Nagelkerke R² 0.063: these factors explain little of the variation in death, which is common for individual-level data. AUC 0.641: modest discrimination between those who died and those who survived. Hosmer-Lemeshow (χ²(8) = 6.16, p = 0.629) shows no evidence of poor calibration, which is not proof of good calibration. Backward Elimination removes BMI Group and Gender; the final model gives APD an OR of 2.02 (95% CI 1.50 to 2.73).
สิ่งที่ DAPH ตรวจให้ (Tab 3): ตัวแปรตามมี 2 ระดับ · EPV ≥ 10 · ขนาดตัวอย่าง · VIF ≤ 5 (ไม่มี multicollinearity) · LR test ของแบบจำลอง · ความเป็นเส้นตรงของตัวแปรต่อเนื่องบนสเกล logit ถูกระบุเป็นข้อตกลงแต่ไม่ได้ทดสอบ ควรตรวจเอง เช่น แบ่งอายุเป็นช่วงแล้วดู OR ของแต่ละช่วง · ตาราง Word แสดง OR ทศนิยม 2 ตำแหน่ง ตารางใน Tab 3 แสดง 3 ตำแหน่ง
What DAPH checks (Tab 3): a two-level outcome, EPV ≥ 10, sample size, VIF ≤ 5 (no multicollinearity) and the model LR test. Linearity of a continuous predictor on the logit scale is listed as an assumption but not tested; check it yourself, for example by grouping age and looking at the OR of each group. The Word table shows ORs to 2 decimals; the Tab 3 table shows 3.
ข้อจำกัด: เป็นข้อมูลเชิงสังเกต OR บอกความสัมพันธ์ ไม่ใช่ผลเชิงเหตุของการรักษาแบบ APD (ผู้ป่วยไม่ได้ถูกสุ่มเลือกวิธีรักษา อาจมีตัวกวนที่ไม่ได้วัด) · ระยะติดตามของแต่ละคนไม่เท่ากัน logistic regression ไม่ใช้เวลาที่เสี่ยง คำถามเรื่องเวลาจนเสียชีวิตควรใช้ Cox regression (5.2) · การเสียชีวิตพบร้อยละ 17.6 ซึ่งไม่ใช่เหตุการณ์ที่พบน้อย OR จึงห่างจาก 1 มากกว่า risk ratio ถ้าต้องการ "เสี่ยงเป็นกี่เท่า" ให้ใช้ 2.7
Limitations: the data are observational, so the OR describes an association, not a causal effect of APD (treatment was not randomised and unmeasured confounding is possible). Follow-up differs between patients and logistic regression ignores time at risk; for time to death use Cox regression (5.2). Death occurred in 17.6%, not a rare outcome, so the OR is further from 1 than the risk ratio; for "how many times the risk" use 2.7.
ตัวอย่างการเขียนรายงาน: "การวิเคราะห์ multiple logistic regression (n = 1,300; เสียชีวิต 229 ราย) พบว่าผู้ป่วยที่ล้างไตทางช่องท้องด้วยเครื่องอัตโนมัติ (APD) มี odds ของการเสียชีวิตสูงกว่าผู้ป่วย CAPD (Adjusted OR 2.03, 95% CI 1.50 to 2.73, p < 0.001) เมื่อควบคุมอายุ (OR 1.04 ต่อปี, 95% CI 1.02 to 1.06) โรคเรื้อรัง (OR 1.60, 95% CI 1.19 to 2.16) เพศ และกลุ่ม BMI"
Model results sentence: "In multiple logistic regression (n = 1,300; 229 deaths), patients on automated peritoneal dialysis (APD) had higher odds of death than those on CAPD (adjusted OR 2.03, 95% CI 1.50 to 2.73, p < 0.001), adjusting for age (OR 1.04 per year, 95% CI 1.02 to 1.06), chronic disease (OR 1.60, 95% CI 1.19 to 2.16), gender and BMI group."
📖 References
- Cox, D. R. (1958). The regression analysis of binary sequences. Journal of the Royal Statistical Society: Series B (Methodological), 20(2), 215–232. doi:10.1111/j.2517-6161.1958.tb00292.x
- Hosmer, D. W., & Lemeshow, S. (1980). Goodness of fit tests for the multiple logistic regression model. Communications in Statistics - Theory and Methods, 9(10), 1043–1069. doi:10.1080/03610928008827941
- Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied logistic regression (3rd ed.). Wiley. ISBN 978-0-470-58247-3.
- Nagelkerke, N. J. D. (1991). A note on a general definition of the coefficient of determination. Biometrika, 78(3), 691–692. doi:10.1093/biomet/78.3.691
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
2.2Conditional Logistic Regression
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Conditional Logistic Regression ประมาณ odds ratio (OR) ภายในชุดจับคู่ (matched set หรือ stratum) โดยวิเคราะห์แบบมีเงื่อนไขว่าแต่ละชุดมีจำนวนผู้ป่วย (case) เท่าที่สังเกตได้ ค่า odds พื้นฐานของแต่ละชุดจึงถูกตัดออกโดยไม่ต้องประมาณ ทุกอย่างที่เหมือนกันภายในชุด (ปัจจัยที่ใช้จับคู่และสิ่งอื่นที่ชุดนั้นมีร่วมกัน) ถูกควบคุมไปด้วย (Breslow et al., 1978; Breslow & Day, 1980) · ใช้กับการศึกษา case-control แบบจับคู่ (1:1 หรือ 1:M) และกับข้อมูลที่แบ่งเป็นชั้นจำนวนมากเมื่อต้องการเปรียบเทียบภายในชั้น · ไม่เหมาะกับข้อมูลที่ไม่ได้จับคู่ (ใช้ 2.1) ประมาณผลของตัวแปรที่คงที่ภายในทุกชุดไม่ได้ และไม่ให้ OR ระดับประชากรหรือความแปรปรวนระหว่างกลุ่ม (ดู 2.3)
Conditional logistic regression estimates odds ratios (OR) within matched sets (strata). By conditioning on the number of cases observed in each set, the baseline odds of every set drop out without being estimated, so everything shared within a set (the matching factors and anything else common to the set) is controlled (Breslow et al., 1978; Breslow & Day, 1980). Use it for matched case-control studies (1:1 or 1:M) and for data split into many strata when the comparison should be made within strata. It is not for unmatched data (use 2.1), it cannot estimate the effect of a variable that is constant within every set, and it gives neither a population-averaged OR nor a between-cluster variance (see 2.3).
ใน DAPH: Tab 2 → Outcome type: Categorical → ติ๊ก Intervention/Interested Factor? → เลือกตัวแปร intervention จากตัวแปรในกล่อง Independent Variables (DAPH ใช้ตรวจเพียงว่ามีอย่างน้อย 2 กลุ่ม ไม่ได้เปลี่ยนแบบจำลอง) → เลือก Matching Variable ซึ่งต้องเป็นตัวแปรกลุ่ม (nominal หรือ binominal) ที่บอกว่าแต่ละคนอยู่ชุดจับคู่ใด → Statistic: Conditional Logistic Regression (ถ้าตัวแปรจับคู่มี 2 ค่า จะมี McNemar test ให้เลือกด้วย) → Analysis Method: Enter หรือ Backward Elimination (ตัดตัวแปรที่ค่า p ในตารางมากที่สุดออกทีละตัวเมื่อค่านั้นตั้งแต่ 0.05 ขึ้นไป แล้วประมาณค่าใหม่ ตัวแปร intervention ไม่ถูกตัด · Tab 3 แสดงแต่ละขั้นและตัวแปรที่เหลือ รายงาน Word ระบุตัวแปรที่ถูกตัด)
In DAPH: Tab 2 → Outcome type: Categorical → tick Intervention/Interested Factor? → choose the intervention variable among the Independent Variables (DAPH only checks that it has at least 2 groups; it does not change the model) → choose the Matching Variable, a categorical (nominal or binominal) variable that says which matched set each person belongs to → Statistic: Conditional Logistic Regression (McNemar test is also offered when the matching variable has 2 values) → Analysis Method: Enter or Backward Elimination (removes, one at a time, the variable with the largest p in the table while that p is 0.05 or more, and refits; the intervention variable is never removed; Tab 3 lists each step and the retained variables, and the Word report names the removed variables).
2หลักการและสูตรLogic and Formula
- S, Ds, R
- จำนวนชุดจับคู่ที่ใช้ได้ · กลุ่ม case ในชุด s · ทุกกลุ่มย่อยขนาด ms ที่เลือกได้จากชุด snumber of usable matched sets; the cases in set s; every subset of size ms that can be drawn from set s
- xi, β
- ตัวทำนายของคนที่ i (ไม่มีค่าคงที่ เพราะค่าคงที่ของแต่ละชุดถูกตัดออก) และสัมประสิทธิ์ log-ORpredictors of person i (no intercept: each set's intercept cancels) and the log-OR coefficients
- Bi(k)
- ผลรวมของ exp(Σ x⊤β) ทุกวิธีเลือก k คนจาก i คนแรกของชุดsum of exp(Σ x⊤β) over every way of choosing k people among the first i of the set
- SEj, V̂v
- ความคลาดเคลื่อนมาตรฐานจาก observed information (อินเวอร์สของเมทริกซ์อนุพันธ์อันดับสองของ log ของ Lc) และเมทริกซ์ความแปรปรวนของสัมประสิทธิ์ของตัวแปร vstandard error from the observed information (inverse of the matrix of second derivatives of log Lc) and the covariance matrix of the coefficients of variable v
- dv, k, ℓc(0)
- จำนวนสัมประสิทธิ์ของตัวแปร v · จำนวนสัมประสิทธิ์ทั้งหมด · log ของ Lc เมื่อ β = 0number of coefficients of variable v; total number of coefficients; log Lc at β = 0
สิ่งที่ DAPH คำนวณ: likelihood แบบมีเงื่อนไขที่แม่นตรง (exact) ข้างบน คำนวณตัวหารด้วยการเวียนเกิดในสเกล log จึงใช้ได้กับชุดขนาดใหญ่ (โรงพยาบาลที่มีผู้ป่วยหลายร้อยคน) · หาค่าสูงสุดด้วย Newton-Raphson พร้อมลดขนาดก้าว · เป็น likelihood เดียวกับที่ R survival::clogit(method = "exact") ใช้ (ค่าเริ่มต้นของ clogit คือ "exact") · ใช้เฉพาะคนที่มีข้อมูลครบทั้งตัวแปรตาม ตัวแปรจับคู่ และตัวทำนาย · ชุดจับคู่จะถูกใช้เมื่อมีทั้ง case และ control อย่างน้อยอย่างละ 1 คน (ตัวแปรตามแปรผันในชุด) ชุดที่ทุกคนมีผลลัพธ์เหมือนกันไม่มีข้อมูลต่อ likelihood · รหัสที่สูงกว่าของตัวแปรตามเป็น case รหัสที่ต่ำกว่าเป็น control (ใช้ได้ทั้งรหัส 0/1 และ 1/2) · ถ้าการประมาณค่าล้มเหลวหรือไม่ลู่เข้า DAPH แจ้งข้อผิดพลาดพร้อมเหตุผล ไม่เปลี่ยนไปใช้ logistic regression แบบไม่มีเงื่อนไขแทน
What DAPH computes: the exact conditional likelihood above, with the denominator built by the recursion on the log scale, so large sets (hospitals with hundreds of patients) work. It is maximised by Newton-Raphson with step halving. This is the likelihood that R survival::clogit(method = "exact") maximises ("exact" is clogit's default). Only people with complete data on the outcome, the matching variable and the predictors are used. A matched set is used when it contains at least one case and one control (the outcome varies within the set); a set in which everyone has the same outcome carries no information. The higher code of the outcome is the case and the lower code the control (0/1 and 1/2 coding both work). If the fit fails or does not converge, DAPH reports an error with the reason; it never substitutes an unconditional logistic regression.
ตารางและค่า p: คอลัมน์ Control n (%) และ Case n (%) ของแต่ละระดับ (ตัวแปรต่อเนื่องแสดงค่าเฉลี่ย ± SD) · Crude OR = OR แบบมีเงื่อนไขของตัวแปรนั้นตัวเดียว บนแถวและชุดเดียวกัน (แสดงเมื่อมีตัวทำนายมากกว่า 1 ตัว ไม่แสดงช่วงเชื่อมั่น) · Adjusted OR และ 95% CI แบบ Wald ทศนิยม 2 ตำแหน่ง · ค่า p หนึ่งค่าต่อตัวแปร: ตัวแปรต่อเนื่องหรือตัวแปร 2 ระดับ = Wald z · ตัวแปรกลุ่มหลายระดับ = Wald χ² ร่วม Wv · หมายเหตุใต้ตารางระบุตัวแปรจับคู่ จำนวนชุดจับคู่ Events/N และ LR χ²(k) · สรุปผลใน Tab 3 แสดงจำนวนคน จำนวนชุดจับคู่ที่ใช้ได้ จำนวนเหตุการณ์ และ LR χ²
Table and p values: Control n (%) and Case n (%) for each level (mean ± SD for a continuous variable); crude OR = the conditional OR of that variable alone, on the same rows and sets (shown when there is more than one predictor, without an interval); adjusted OR and Wald 95% CI to 2 decimals. One p per variable: Wald z for a continuous or two-level variable, the joint Wald χ² Wv for a categorical variable with more levels. The note under the table names the matching variable and the number of matched sets and gives Events/N and the LR χ²(k); the Tab 3 summary gives the number of people, usable matched sets, events and the LR χ².
ตัวแปรที่คงที่ภายในทุกชุด (เช่น ปัจจัยที่ใช้จับคู่เอง หรือ Hospital Type เมื่อใช้โรงพยาบาลเป็นชั้น เพราะแต่ละโรงพยาบาลเป็นรัฐหรือเอกชนแบบเดียว) ไม่มีข้อมูลใน likelihood แบบมีเงื่อนไข จึงประมาณค่าไม่ได้ · DAPH แสดงตัวแปรนั้นเป็น NA (not estimable) พร้อมหมายเหตุ และไม่นับในองศาอิสระของ LR test เช่นเดียวกับที่ R รายงานเป็น NA
Variables constant within every set (for example the matching factors themselves, or Hospital Type when hospitals are the strata, since each hospital is either public or private) carry no information in the conditional likelihood and cannot be estimated. DAPH shows such a variable as NA (not estimable) with a note and leaves it out of the LR degrees of freedom, as R reports NA.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
clogit), statsR 4.3.3 · packages survival (clogit), stats# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(survival)
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
d$bmi_group <- factor(d$bmi_group, 1:4, c("Underweight", "Normal", "Overweight", "Obese"))
table(d$hos, d$status) # strata = 7 hospitals; each has deaths and survivors (3 rows lack a hospital)
# 1) conditional logistic regression, strata = hospital, exact conditional likelihood
fit <- clogit(status ~ group + age + gender + chronic + bmi_group + strata(hos),
data = d, method = "exact")
round(cbind(OR = exp(coef(fit)), exp(confint(fit)), p = summary(fit)$coefficients[, 5]), 4)
cat(sprintf("n = %d, events = %d, LR chi-square = %.3f, df = %d\n",
fit$n, fit$nevent, 2 * diff(fit$loglik), length(coef(fit))))
# 2) one p for BMI group: joint Wald chi-square of its 3 coefficients (as DAPH)
k <- grep("bmi_group", names(coef(fit)))
W <- drop(coef(fit)[k] %*% solve(vcov(fit)[k, k], coef(fit)[k]))
c(Wald = round(W, 4), p = round(pchisq(W, length(k), lower.tail = FALSE), 4))
# 3) crude conditional OR: one predictor at a time, same 1,297 rows and hospitals
dd <- na.omit(d[, c("status", "group", "age", "gender", "chronic", "bmi_group", "hos")])
crude <- lapply(c("group", "age", "gender", "chronic", "bmi_group"), function(v)
exp(coef(clogit(as.formula(paste("status ~", v, "+ strata(hos)")), data = dd, method = "exact"))))
round(unlist(crude), 4)
# 4) large strata: ordinary logistic regression with hospital dummies gives almost the same OR
round(exp(coef(glm(status ~ group + age + gender + chronic + bmi_group + factor(hos),
data = d, family = binomial)))["groupAPD"], 4)
# 5) check of the matched-set rule: strata = district (treatment varies in only 2 of 10 districts)
table(d$amp, d$group)
fd <- clogit(status ~ group + age + gender + chronic + bmi_group + strata(amp), data = d, method = "exact")
round(cbind(OR = exp(coef(fd)), exp(confint(fd)), p = summary(fd)$coefficients[, 5])[1:4, ], 4)
cat(sprintf("matched sets = %d, LR chi-square = %.3f\n", length(unique(d$amp)), 2 * diff(fd$loglik)))
# 6) Backward Elimination as DAPH: drop the variable with the largest p (joint Wald for
# BMI group) while that p is 0.05 or more; Treatment Group (the intervention) stays
wald_p <- function(m, v) { k <- grep(paste0("^", v), names(coef(m)))
pchisq(drop(coef(m)[k] %*% solve(vcov(m)[k, k], coef(m)[k])), length(k), lower.tail = FALSE) }
keep <- c("age", "gender", "chronic", "bmi_group")
repeat {
m <- clogit(reformulate(c("group", keep, "strata(hos)"), "status"), data = d, method = "exact")
p <- sapply(keep, wald_p, m = m)
if (max(p) < 0.05) break
cat("removed:", names(which.max(p)), " p =", round(max(p), 4), "\n")
keep <- keep[-which.max(p)]
}
round(cbind(OR = exp(coef(m)), exp(confint(m))), 4)
cat(sprintf("LR chi-square = %.3f, df = %d\n", 2 * diff(m$loglik), length(coef(m))))
# 7) Hospital Type is constant within every hospital: not estimable (NA)
coef(clogit(status ~ group + age + chronic + factor(type) + strata(hos), data = d, method = "exact"))
# deaths (1) and survivors (0) in each hospital
0 1
1 75 21
2 42 8
3 266 56
4 77 17
5 31 5
6 86 18
7 491 104
# 1) conditional OR (strata = hospital), Wald 95% CI, Wald p
OR 2.5 % 97.5 % p
groupAPD 2.0495 1.5197 2.7641 0.0000
age 1.0422 1.0211 1.0637 0.0001
genderFemale 1.1662 0.8498 1.6005 0.3410
chronicYes 1.6122 1.1944 2.1762 0.0018
bmi_groupNormal 0.8738 0.5334 1.4312 0.5920
bmi_groupOverweight 0.8085 0.4645 1.4073 0.4523
bmi_groupObese 0.8348 0.4858 1.4344 0.5132
# model note
n = 1297, events = 229, LR chi-square = 51.500, df = 7
# 2) BMI group: joint Wald chi-square(3)
Wald p
0.6145 0.8931
# 3) crude conditional OR
groupAPD age genderFemale chronicYes
1.9058 1.0440 1.2223 1.6062
bmi_groupNormal bmi_groupOverweight bmi_groupObese
0.7700 0.6626 0.7252
# 4) ordinary logistic regression with hospital dummies: OR of APD
groupAPD
2.0585
# 5) district as strata: treatment varies only in districts 1 and 9
CAPD APD
1 144 16
2 0 85
3 0 75
4 0 62
5 220 0
6 0 264
7 55 0
8 0 79
9 1 63
10 236 0
OR 2.5 % 97.5 % p
groupAPD 1.8532 0.5638 6.0913 0.3096
age 1.0425 1.0211 1.0644 0.0001
genderFemale 1.1724 0.8531 1.6112 0.3269
chronicYes 1.7034 1.2534 2.3151 0.0007
matched sets = 10, LR chi-square = 37.097
# 6) Backward Elimination (Treatment Group always kept)
removed: bmi_group p = 0.8931
removed: gender p = 0.3355
OR 2.5 % 97.5 %
groupAPD 2.0441 1.5163 2.7556
age 1.0447 1.0245 1.0654
chronicYes 1.6115 1.1987 2.1666
LR chi-square = 49.955, df = 3
# 7) Hospital Type: constant within every hospital, NA
groupAPD age chronicYes factor(type)2
0.71493818 0.04376762 0.47719230 NA
| Quantity | R 4.3.3 | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| OR, APD vs CAPD (95% CI) | 2.0495 (1.5197 to 2.7641) | 2.05 (1.52 to 2.76) | < 0.005 | ✓ PASS |
| OR, age per year (95% CI) | 1.0422 (1.0211 to 1.0637) | 1.04 (1.02 to 1.06) | < 0.005 | ✓ PASS |
| OR, chronic disease (95% CI), p | 1.6122 (1.1944 to 2.1762), 0.0018 | 1.61 (1.19 to 2.18), 0.002 | < 0.005 | ✓ PASS |
| OR, female (95% CI), p | 1.1662 (0.8498 to 1.6005), 0.3410 | 1.17 (0.85 to 1.60), 0.341 | < 0.005 | ✓ PASS |
| BMI group, joint Wald χ²(3) p | 0.8931 | 0.893 | < 0.0005 | ✓ PASS |
| n, events, LR χ²(7) | 1297, 229, 51.500 | 1,297, 229, 51.500 | < 0.0005 | ✓ PASS |
| Crude conditional OR, APD / chronic disease | 1.9058 / 1.6062 | 1.91 / 1.61 | < 0.005 | ✓ PASS |
| District as strata: sets used, OR APD (95% CI), LR χ²(7) | 10, 1.8532 (0.5638 to 6.0913), 37.097 | 10, 1.85 (0.56 to 6.09), 37.097 | < 0.005 | ✓ PASS |
| Backward Elimination: removed (p), then OR APD (95% CI) and LR χ²(3) | bmi_group 0.8931, gender 0.3355 · 2.0441 (1.5163 to 2.7556) · 49.955 | BMI Group 0.8931, Gender 0.3355 · 2.04 (1.52 to 2.76) · 49.955 | < 0.005 | ✓ PASS |
| Hospital Type (constant within every hospital) added to group + age + chronic disease | NA | NA (not estimable), LR χ²(3) = 49.955 | 0 | ✓ PASS |
แถว District ตรวจกฎการเลือกชุดจับคู่: ใน 10 อำเภอ มีเพียงอำเภอ 1 และ 9 ที่มีผู้ป่วยทั้ง CAPD และ APD แต่ทุกอำเภอมีทั้งผู้เสียชีวิตและผู้รอดชีวิต DAPH จึงใช้ทั้ง 10 ชุดเหมือน R (ชุดที่การรักษาไม่แปรผันยังให้ข้อมูลเรื่องอายุ โรคเรื้อรัง และตัวแปรอื่น) · OR ของ APD ภายในอำเภอมีช่วงเชื่อมั่นกว้างมาก (0.56 to 6.09) เพราะข้อมูลเปรียบเทียบการรักษามาจาก 2 อำเภอเท่านั้น
The District row checks the matched-set rule: of the 10 districts, only districts 1 and 9 have both CAPD and APD patients, but every district has deaths and survivors, so DAPH uses all 10 sets, as R does (sets in which treatment does not vary still inform the age, chronic-disease and other coefficients). The within-district OR for APD has a very wide interval (0.56 to 6.09) because the treatment comparison comes from 2 districts only.
4การแปลผลและตัวอย่างInterpretation and Example
ผลหลัก: เมื่อเทียบภายในโรงพยาบาลเดียวกัน ผู้ป่วย APD มี odds ของการเสียชีวิตเป็น 2.05 เท่าของผู้ป่วย CAPD ที่มีอายุ เพศ โรคเรื้อรัง และกลุ่ม BMI เดียวกัน (OR 2.05, 95% CI 1.52 to 2.76, p < 0.001) · อายุ OR 1.04 ต่อปี (95% CI 1.02 to 1.06, p < 0.001) · โรคเรื้อรัง OR 1.61 (95% CI 1.19 to 2.18, p = 0.002) · เพศหญิง OR 1.17 (95% CI 0.85 to 1.60, p = 0.341) และ BMI Group (p = 0.893) ไม่มีนัยสำคัญ ซึ่งไม่ได้แปลว่าไม่มีความต่าง · OR เหล่านี้ใกล้กับ logistic regression ปกติ (2.1) แปลว่าความต่างระหว่างโรงพยาบาลไม่ได้กวนความสัมพันธ์นี้มาก
Main result: comparing patients within the same hospital, those on APD had 2.05 times the odds of death of CAPD patients of the same age, gender, chronic-disease status and BMI group (OR 2.05, 95% CI 1.52 to 2.76, p < 0.001). Age: OR 1.04 per year (95% CI 1.02 to 1.06, p < 0.001); chronic disease: OR 1.61 (95% CI 1.19 to 2.18, p = 0.002). Female gender (OR 1.17, 95% CI 0.85 to 1.60, p = 0.341) and BMI Group (p = 0.893) were not significant, which does not show that there is no difference. These ORs are close to ordinary logistic regression (2.1), so differences between hospitals did not confound the association much.
ชุดใหญ่หรือชุดเล็ก: เมื่อแต่ละชุดใหญ่ (ที่นี่หลายสิบถึงหลายร้อยคน) logistic regression ปกติที่ใส่โรงพยาบาลเป็นตัวแปรกลุ่มให้ผลเกือบเท่ากัน (OR ของ APD 2.0585) แต่เมื่อชุดเล็ก เช่น คู่ 1:1 หรือ 1:M วิธีนั้นมีอคติชัดเจน (ใน 1:1 OR ที่ได้ใกล้เคียงกำลังสองของค่าจริง) จึงต้องใช้ conditional logistic regression (Breslow & Day, 1980)
Large or small sets: when sets are large (here tens to hundreds of patients), ordinary logistic regression with hospital entered as a categorical variable gives almost the same answer (APD OR 2.0585). With small sets, such as 1:1 or 1:M matching, that approach is clearly biased (with 1:1 pairs its OR approaches the square of the true OR), so conditional logistic regression is required (Breslow & Day, 1980).
ข้อจำกัด: ตัวอย่างนี้เป็นการวิเคราะห์แบบแบ่งชั้นในข้อมูล cohort ไม่ใช่การศึกษา case-control แบบจับคู่ จึงเป็นความสัมพันธ์ ไม่ใช่ผลเชิงเหตุของการรักษา · ไม่ได้ใช้เวลาติดตาม (ดู 5.2) · ผลของปัจจัยที่ใช้จับคู่ (และตัวแปรที่คงที่ภายในชุด) ประมาณไม่ได้ แต่ถ้าต้องการรู้ว่า OR ของการรักษาต่างกันตามปัจจัยที่ใช้จับคู่หรือไม่ ทำได้ด้วยพจน์ปฏิสัมพันธ์ใน R ซึ่ง DAPH ยังไม่มี
Limitations: this example is a stratified analysis of cohort data, not a matched case-control study, so it shows an association, not a causal effect of treatment. Follow-up time is not used (see 5.2). The effect of the matching factors (and of anything constant within sets) cannot be estimated; whether the treatment OR differs across levels of a matching factor can be tested with an interaction term in R, which DAPH does not offer.
ตัวอย่างการเขียนรายงาน: "Conditional logistic regression โดยใช้โรงพยาบาลเป็นชั้น (7 โรงพยาบาล ผู้ป่วย 1,297 คน เสียชีวิต 229 คน) พบว่าเมื่อเปรียบเทียบภายในโรงพยาบาลเดียวกัน APD สัมพันธ์กับ odds ของการเสียชีวิตที่สูงกว่า CAPD (OR 2.05, 95% CI 1.52 to 2.76, p < 0.001) เมื่อควบคุมอายุ เพศ โรคเรื้อรัง และกลุ่ม BMI"
Model results sentence: "In conditional logistic regression with hospital as the stratum (7 hospitals; 1,297 patients; 229 deaths), APD was associated with higher odds of death than CAPD among patients of the same hospital (OR 2.05, 95% CI 1.52 to 2.76, p < 0.001), adjusting for age, gender, chronic disease and BMI group."
📖 References
- Breslow, N. E., & Day, N. E. (1980). Statistical methods in cancer research: Vol. 1. The analysis of case-control studies (IARC Scientific Publications No. 32). International Agency for Research on Cancer. ISBN 978-92-832-0132-8.
- Breslow, N. E., Day, N. E., Halvorsen, K. T., Prentice, R. L., & Sabai, C. (1978). Estimation of multiple relative risk functions in matched case-control studies. American Journal of Epidemiology, 108(4), 299–307. doi:10.1093/oxfordjournals.aje.a112623
- Gail, M. H., Lubin, J. H., & Rubinstein, L. V. (1981). Likelihood calculations for matched case-control studies and survival studies with tied death times. Biometrika, 68(3), 703–707. doi:10.1093/biomet/68.3.703
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
2.3Mixed-Effect / GEE Logistic Regression
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
เมื่อผลลัพธ์ 2 ค่ามาจากข้อมูลที่รวมกลุ่มกัน (cluster) เช่น ผู้ป่วยในโรงพยาบาลหรืออำเภอเดียวกัน หรือการวัดซ้ำในคนเดิม ข้อมูลในกลุ่มเดียวกันไม่เป็นอิสระต่อกัน ถ้าละเลยจะได้ช่วงเชื่อมั่นแคบเกินจริง โดยเฉพาะของตัวแปรที่แตกต่างกันระหว่างกลุ่ม · มีสองแนวทาง: GLMM logistic (generalized linear mixed model) ใส่ค่าคงที่สุ่ม (random intercept) ของแต่ละกลุ่ม ให้ OR แบบเฉพาะกลุ่ม (cluster-specific) คือเปรียบเทียบสองคนในกลุ่มเดียวกัน (Breslow & Clayton, 1993) และ GEE logistic (generalized estimating equations) ให้ OR เฉลี่ยระดับประชากร (population-averaged) พร้อม SE แบบ robust (Liang & Zeger, 1986; Zeger et al., 1988)
When a two-level outcome comes from clustered data, such as patients in the same hospital or district, or repeated measurements on the same person, observations in a cluster are not independent; ignoring this gives intervals that are too narrow, especially for variables that differ between clusters. There are two approaches: GLMM logistic (generalized linear mixed model) adds a random intercept for each cluster and gives a cluster-specific OR, comparing two people in the same cluster (Breslow & Clayton, 1993); GEE logistic (generalized estimating equations) gives a population-averaged OR with a robust standard error (Liang & Zeger, 1986; Zeger et al., 1988).
DAPH มีเฉพาะ GLMM: สถิติ Mixed Effect Logistic Regression คือ random-intercept logistic model ที่ประมาณค่าด้วยวิธีภาวะน่าจะเป็นสูงสุด (maximum likelihood) แบบประมาณ Laplace มีค่าคงที่สุ่ม 1 ระดับ ไม่มี random slope · DAPH ไม่มี GEE สำหรับผลลัพธ์ 2 ค่า (GEE ใน 1.6 ใช้กับผลลัพธ์ต่อเนื่องเท่านั้น) สคริปต์ R ด้านล่างแสดง GEE ด้วย geepack สำหรับผู้ที่ต้องการ OR ระดับประชากร · วิธีเลือก: Tab 2 → Outcome type: Categorical → เลือก Dependent Variable และ Independent Variables → Statistic: Logistic Regression (ไม่ติ๊ก Intervention/Interested Factor?) → Type of Model: ติ๊ก Mixed Effects Model แล้ว DAPH เปลี่ยนสถิติเป็น Mixed Effect Logistic Regression ให้ → เลือก Random Effect Variable (ตัวแปรกลุ่มแบบ nominal หรือ binominal ที่บอกว่าแต่ละคนอยู่กลุ่มใด) → Analysis Method มีเฉพาะ Enter
DAPH offers the GLMM only: Mixed Effect Logistic Regression is a random-intercept logistic model fitted by maximum likelihood with the Laplace approximation, with one level of random intercept and no random slopes. DAPH has no GEE for two-level outcomes (the GEE of 1.6 is for continuous outcomes only); the R script below shows GEE with geepack for readers who need a population-averaged OR. To run it: Tab 2 → Outcome type: Categorical → choose the Dependent Variable and Independent Variables → Statistic: Logistic Regression (Intervention/Interested Factor? not ticked) → Type of Model: tick Mixed Effects Model, and DAPH switches the statistic to Mixed Effect Logistic Regression → choose the Random Effect Variable (a nominal or binominal variable naming each person's cluster) → Analysis Method: Enter is the only choice.
2หลักการและสูตรLogic and Formula
- Yij, xij
- ผลลัพธ์ (1 = รหัสที่สูงกว่าของตัวแปรตาม) และตัวทำนายของคนที่ i ในกลุ่ม j · ตัวแปรกลุ่มเทียบกับรหัสต่ำสุดoutcome (1 = the higher code of the dependent variable) and predictors of person i in cluster j; a categorical predictor is compared with its lowest code
- bj, σ²
- ค่าคงที่สุ่มของกลุ่ม j และความแปรปรวนระหว่างกลุ่มบนสเกล log-oddsrandom intercept of cluster j and the between-cluster variance on the log-odds scale
- ûj, Dj
- ค่า u ที่ทำให้ hj สูงสุด (mode) และความโค้งของ hj ที่จุดนั้น · p̂ij คำนวณที่ u = ûjthe value of u that maximises hj (the mode) and the curvature of hj there; p̂ij is evaluated at u = ûj
- SEk
- จากอินเวอร์สของ Hessian ของ log-likelihood ส่วนขอบ (marginal) เทียบกับ (β, σ) · ค่า p แบบ Wald zfrom the inverse Hessian of the marginal log-likelihood in (β, σ); p values are Wald z tests
- π²/3
- ความแปรปรวนของการแจกแจงโลจิสติกมาตรฐาน ใช้เป็นความแปรปรวนระดับบุคคลบนสเกลแฝง (latent scale)variance of the standard logistic distribution, used as the individual-level variance on the latent scale
- DE, m̄
- design effect และขนาดกลุ่มเฉลี่ยdesign effect and the mean cluster size
- q, n
- จำนวนสัมประสิทธิ์ fixed effect รวมค่าคงที่ (บวก 1 สำหรับ σ) · จำนวนคนที่ใช้วิเคราะห์number of fixed-effect coefficients including the intercept (plus 1 for σ); number of people analysed
- βPA
- สัมประสิทธิ์ระดับประชากร ซึ่งใกล้ 0 กว่าค่าเฉพาะกลุ่มเมื่อ σ² > 0 (ค่าประมาณของ Zeger et al., 1988)population-averaged coefficient, closer to 0 than the cluster-specific one when σ² > 0 (approximation of Zeger et al., 1988)
สิ่งที่ DAPH คำนวณ: เริ่มจากค่าประมาณของ logistic regression ปกติและ σ = 1 หาค่าสูงสุดด้วย L-BFGS-B ภายใต้เงื่อนไข σ ≥ 0 แล้วขัดเกลาด้วย Newton · ใช้การประมาณ Laplace (เท่ากับ nAGQ = 1 ของ R lme4::glmer) หน้าจอไม่มีตัวเลือก quadrature · ใช้เฉพาะคนที่มีข้อมูลครบทั้งตัวแปรตาม ตัวทำนาย และตัวแปรกลุ่ม · ค่า p หนึ่งค่าต่อตัวแปร: ตัวแปรต่อเนื่องหรือ 2 ระดับ = Wald z · ตัวแปรกลุ่มหลายระดับ = Wald χ² ร่วม · ICC บนสเกลแฝง · LR test ของ σ² = 0 เทียบกับ logistic regression ปกติบนข้อมูลชุดเดียวกัน ใช้ครึ่งหนึ่งของความน่าจะเป็นส่วนหางเพราะ σ² = 0 อยู่ที่ขอบของช่วงค่าที่เป็นไปได้ (Self & Liang, 1987) · ถ้า σ² ประมาณได้ 0 DAPH แจ้งว่าเป็นค่าที่ขอบ และ fixed effects เท่ากับ logistic regression ปกติ · ตาราง Tab 3 แสดง Adjusted OR, 95% CI, ค่า p, จำนวนและร้อยละของผู้เกิดเหตุการณ์ในแต่ละระดับ (ไม่มี Crude OR) · สรุปผลใน Tab 3 และหมายเหตุใต้ตาราง Word แสดง σ², SD, ICC, จำนวนและขนาดกลุ่ม, วิธีประมาณค่า และ LR test (Tab 3 แสดง design effect เพิ่ม)
What DAPH computes: starting from the ordinary logistic estimates and σ = 1, the likelihood is maximised by L-BFGS-B under σ ≥ 0 and polished by Newton steps. It uses the Laplace approximation (R lme4::glmer with nAGQ = 1); the screen has no quadrature option. Only people with complete data on the outcome, the predictors and the cluster variable are used. One p per variable: Wald z for a continuous or two-level variable, the joint Wald χ² for a categorical variable with more levels. The ICC is on the latent scale. The LR test of σ² = 0 compares with ordinary logistic regression on the same rows and halves the tail probability because σ² = 0 lies on the boundary of its range (Self & Liang, 1987). When σ² is estimated at 0, DAPH says it is a boundary estimate and the fixed effects equal ordinary logistic regression. The Tab 3 table shows the adjusted OR, 95% CI, p and the number and percentage with the event at each level (no crude OR); the Tab 3 summary and the note under the Word table give σ², SD, ICC, the number and size of clusters, the estimation method and the LR test (Tab 3 adds the design effect).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
glmer), glmmTMB, geepack, statsR 4.3.3 · packages lme4 (glmer), glmmTMB, geepack, stats# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(lme4)
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
d$bmi_group <- factor(d$bmi_group, 1:4, c("Underweight", "Normal", "Overweight", "Obese"))
# Model A: death, random intercept for hospital; Laplace approximation (nAGQ = 1) as DAPH
dA <- d[!is.na(d$hos), ] # the 1,297 patients with a hospital code
mA <- glmer(status ~ group + age + gender + chronic + bmi_group + (1 | hos),
data = dA, family = binomial, nAGQ = 1)
print(VarCorr(mA), comp = "Variance") # hospital variance estimated at 0 (boundary)
c(logLik = as.numeric(logLik(mA)), AIC = AIC(mA), BIC = BIC(mA))
round(cbind(OR = exp(fixef(mA)), exp(confint(mA, parm = "beta_", method = "Wald")),
p = coef(summary(mA))[, 4]), 4)
k <- grep("bmi_group", names(fixef(mA))) # one p for BMI group: joint Wald chi-square
W <- drop(fixef(mA)[k] %*% solve(as.matrix(vcov(mA))[k, k], fixef(mA)[k]))
round(pchisq(W, length(k), lower.tail = FALSE), 4)
gA <- glm(status ~ group + age + gender + chronic + bmi_group, data = dA, family = binomial)
as.numeric(logLik(gA)) # equals the GLMM log-likelihood: sigma^2 = 0
# Model B: high quality of life after treatment, random intercept for district.
# glmmTMB: Laplace approximation with exact derivatives, so its SEs match DAPH's.
library(glmmTMB)
mB <- glmmTMB(qol_g3 ~ group + age + gender + (1 | amp), data = d, family = binomial)
s2 <- VarCorr(mB)$cond$amp[1]
round(c(sigma2 = s2, SD = sqrt(s2), ICC = s2 / (s2 + pi^2 / 3)), 4)
round(1 + (nrow(d) / 10 - 1) * s2 / (s2 + pi^2 / 3), 4) # design effect, 130 patients per district on average
c(logLik = as.numeric(logLik(mB)), AIC = AIC(mB), BIC = BIC(mB))
round(cbind(OR = exp(fixef(mB)$cond), exp(confint(mB, parm = "beta_", method = "Wald"))[, 1:2],
p = summary(mB)$coefficients$cond[, 4]), 4)
gB <- glm(qol_g3 ~ group + age + gender, data = d, family = binomial)
LR <- 2 * (as.numeric(logLik(mB)) - as.numeric(logLik(gB)))
round(c(LR = LR, p = 0.5 * pchisq(LR, 1, lower.tail = FALSE)), 5) # H0: sigma^2 = 0 (half the tail: boundary)
# lme4 gives the same estimates; its SEs come from a finite-difference Hessian
mB2 <- glmer(qol_g3 ~ group + age + gender + (1 | amp), data = d, family = binomial, nAGQ = 1)
round(rbind(glmmTMB = sqrt(diag(vcov(mB)$cond)), lme4 = sqrt(diag(as.matrix(vcov(mB2))))), 4)
# GEE logistic (population-averaged) for comparison: not available in DAPH
library(geepack)
dB <- d[order(d$amp), ] # geeglm needs each cluster's rows together
gee <- geeglm(qol_g3 ~ group + age + gender, id = amp, data = dB,
family = binomial, corstr = "exchangeable")
cf <- coef(summary(gee))
round(cbind(OR = exp(setNames(cf[, 1], rownames(cf))), lower = exp(cf[, 1] - qnorm(0.975) * cf[, 2]),
upper = exp(cf[, 1] + qnorm(0.975) * cf[, 2]), p = cf[, 4]), 4)
# Model A (death, hospital): variance, fit, OR with Wald 95% CI
boundary (singular) fit: see help('isSingular')
Groups Name Variance
hos (Intercept) 0
logLik AIC BIC
-579.1006 1176.2012 1222.7114
OR 2.5 % 97.5 % p
(Intercept) 0.0067 0.0013 0.0341 0.0000
groupAPD 2.0379 1.5112 2.7481 0.0000
age 1.0417 1.0207 1.0632 0.0001
genderFemale 1.1670 0.8503 1.6016 0.3389
chronicYes 1.6074 1.1906 2.1702 0.0019
bmi_groupNormal 0.8629 0.5268 1.4134 0.5581
bmi_groupOverweight 0.8063 0.4634 1.4031 0.4463
bmi_groupObese 0.8231 0.4790 1.4145 0.4810
# BMI group joint Wald p; then the ordinary logistic log-likelihood
[1] 0.8851
[1] -579.1006
# Model B (high QoL, district): variance, SD, latent ICC, fit, OR
sigma2 SD ICC
0.1973 0.4442 0.0566
# design effect = 1 + (130 - 1) x ICC
[1] 8.2993
logLik AIC BIC
-613.5077 1237.0154 1262.8660
OR 2.5 % 97.5 % p
(Intercept) 0.0107 0.0026 0.0450 0.0000
groupAPD 1.3069 0.7159 2.3856 0.3834
age 1.0435 1.0237 1.0637 0.0000
genderFemale 0.8175 0.6080 1.0991 0.1821
# LR test of sigma^2 = 0
LR p
11.85955 0.00029
# standard errors: glmmTMB (as DAPH) and lme4
(Intercept) groupAPD age genderFemale
glmmTMB 0.7312 0.3071 0.0098 0.1510
lme4 0.7294 0.3066 0.0098 0.1506
# GEE (population-averaged), not in DAPH
OR lower upper p
(Intercept) 0.0123 0.0016 0.0960 0.0000
groupAPD 1.2185 0.7325 2.0268 0.4466
age 1.0429 1.0139 1.0728 0.0035
genderFemale 0.8239 0.7301 0.9298 0.0017
| Quantity | R 4.3.3 | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| A: σ² (hospital) | 0 (boundary, singular fit) | 0.0000 (boundary) | 0 | ✓ PASS |
| A: log-likelihood / AIC / BIC | −579.1006 / 1176.2012 / 1222.7114 | −579.1006 / 1176.2 / 1222.71 | < 0.05 | ✓ PASS |
| A: OR, APD vs CAPD (95% CI) | 2.0379 (1.5112 to 2.7481) | 2.038 (1.511 to 2.748) | < 0.0005 | ✓ PASS |
| A: OR, age per year / chronic disease (95% CI) | 1.0417 (1.0207 to 1.0632) / 1.6074 (1.1906 to 2.1702) | 1.042 (1.021 to 1.063) / 1.607 (1.191 to 2.170) | < 0.0005 | ✓ PASS |
| A: p, gender / BMI group (joint Wald) | 0.3389 / 0.8851 | 0.339 / 0.885 | < 0.0005 | ✓ PASS |
| A: ordinary logistic log-likelihood (LR test of σ² = 0) | −579.1006 (χ² = 0) | χ² = 0.000, p = 1.000 | 0 | ✓ PASS |
| B: σ², SD, ICC (district) | 0.1973, 0.4442, 0.0566 | 0.1973, 0.4442, 0.0566 | < 0.00005 | ✓ PASS |
| B: design effect (mean 130 per district) | 8.2993 | 8.30 | < 0.005 | ✓ PASS |
| B: log-likelihood / AIC / BIC | −613.5077 / 1237.0154 / 1262.8660 | −613.5077 / 1237.02 / 1262.87 | < 0.005 | ✓ PASS |
| B: OR, APD vs CAPD (95% CI), p | 1.3069 (0.7159 to 2.3856), 0.3834 | 1.307 (0.716 to 2.386), 0.383 | < 0.0005 | ✓ PASS |
| B: OR, age per year / female (95% CI) | 1.0435 (1.0237 to 1.0637) / 0.8175 (0.6080 to 1.0991) | 1.044 (1.024 to 1.064) / 0.817 (0.608 to 1.099) | < 0.0005 | ✓ PASS |
| B: LR test of σ² = 0 | χ² = 11.85955, p = 0.00029 | χ² = 11.860, p < 0.001 | < 0.0005 | ✓ PASS |
แบบจำลอง B ทวนสอบกับ glmmTMB ซึ่งใช้การประมาณ Laplace เหมือนกันแต่คำนวณอนุพันธ์แบบแม่นตรง · lme4::glmer ให้ค่าประมาณเท่ากันแต่ SE มาจาก Hessian แบบผลต่างจำกัด (finite difference) จึงต่างประมาณร้อยละ 0.2 (SE ของ APD 0.3066 เทียบกับ 0.3071 ใน DAPH และ glmmTMB) ทำให้ขอบบนของช่วงเชื่อมั่นต่างที่ทศนิยมตำแหน่งที่ 3
Model B is checked against glmmTMB, which uses the same Laplace approximation but exact derivatives. lme4::glmer gives the same estimates, but its SEs come from a finite-difference Hessian and differ by about 0.2% (APD SE 0.3066 against 0.3071 in DAPH and glmmTMB), which moves the upper confidence limit in the third decimal.
4การแปลผลและตัวอย่างInterpretation and Example
แบบจำลอง A: ความแปรปรวนระหว่างโรงพยาบาลประมาณได้ 0 (LR test p = 1.000) ไม่พบหลักฐานว่าความเสี่ยงการเสียชีวิตต่างกันระหว่างโรงพยาบาลเกินกว่าที่อธิบายได้ด้วยลักษณะของผู้ป่วย แบบจำลองจึงเท่ากับ logistic regression ปกติบนผู้ป่วย 1,297 คน: APD มี odds ของการเสียชีวิตเป็น 2.04 เท่าของ CAPD (OR 2.04, 95% CI 1.51 to 2.75, p < 0.001) · ค่า 0 ไม่ได้พิสูจน์ว่าโรงพยาบาลไม่ต่างกันเลย ด้วยกลุ่มเพียง 7 กลุ่ม ความแปรปรวนระหว่างกลุ่มประมาณได้ไม่แม่นยำ
Model A: the between-hospital variance is estimated at 0 (LR test p = 1.000): there is no evidence that the risk of death differs between hospitals beyond what the patients' characteristics explain, so the model equals ordinary logistic regression on the 1,297 patients: APD had 2.04 times the odds of death of CAPD (OR 2.04, 95% CI 1.51 to 2.75, p < 0.001). An estimate of 0 does not prove that hospitals do not differ at all; with only 7 clusters the between-cluster variance is estimated imprecisely.
แบบจำลอง B: ความแปรปรวนระหว่างอำเภอ σ² = 0.197 (SD 0.444) ICC บนสเกลแฝง 0.057 คือราวร้อยละ 5.7 ของความแปรผันของแนวโน้มที่จะมีคุณภาพชีวิตสูงอยู่ที่ระดับอำเภอ และ LR test ของ σ² = 0 มีนัยสำคัญ (χ² = 11.86, p < 0.001) จึงควรมีค่าคงที่สุ่มของอำเภอ · APD เทียบกับ CAPD ในอำเภอเดียวกัน: OR 1.31 (95% CI 0.72 to 2.39, p = 0.383) ไม่มีนัยสำคัญ ช่วงเชื่อมั่นกว้างเพราะวิธีรักษาแทบถูกกำหนดโดยอำเภอ (8 ใน 10 อำเภอมีวิธีรักษาเดียว ดู 2.2) · อายุ OR 1.04 ต่อปี (95% CI 1.02 to 1.06) · GEE ใน R ให้ OR ระดับประชากรของ APD 1.22 (95% CI 0.73 to 2.03) ใกล้ 1 กว่า OR เฉพาะกลุ่มตามที่คาด แต่เมื่อมีเพียง 10 กลุ่ม SE แบบ robust ของ GEE ไม่น่าเชื่อถือและมักต่ำกว่าความจริง (Mancl & DeRouen, 2001) สังเกตว่าช่วงเชื่อมั่นของเพศแคบกว่าของ GLMM มาก จึงควรอ่านผล GEE นี้อย่างระมัดระวัง
Model B: between-district variance σ² = 0.197 (SD 0.444) and latent-scale ICC 0.057: about 5.7% of the variation in the propensity to a high quality of life lies at district level, and the LR test of σ² = 0 is significant (χ² = 11.86, p < 0.001), so the district random intercept is needed. APD versus CAPD within the same district: OR 1.31 (95% CI 0.72 to 2.39, p = 0.383), not significant; the interval is wide because treatment is almost fixed by district (8 of 10 districts use one treatment only, see 2.2). Age: OR 1.04 per year (95% CI 1.02 to 1.06). GEE in R gives a population-averaged OR for APD of 1.22 (95% CI 0.73 to 2.03), closer to 1 than the cluster-specific OR, as expected; with only 10 clusters, however, the GEE robust SE is unreliable and tends to be too small (Mancl & DeRouen, 2001); note how much narrower its interval for gender is than the GLMM's, and read these GEE results with caution.
สิ่งที่ต้องรายงาน: OR + 95% CI ของ fixed effects, σ² (หรือ SD), ICC, จำนวนกลุ่มและขนาดกลุ่ม, วิธีประมาณค่า (ML, Laplace) และ LR test ของ σ² = 0 · DAPH แสดงครบทั้งใน Tab 3 และหมายเหตุใต้ตาราง Word (ตัวแปรกลุ่ม จำนวนและขนาดกลุ่ม σ² และ SD, ICC บนสเกลแฝง, LR test ของ σ² = 0 แบบปรับที่ขอบ และวิธีประมาณค่า) · Tab 3 จัดระดับ ICC (ต่ำกว่า 0.05 ต่ำมาก, 0.05 ถึงต่ำกว่า 0.10 ต่ำ, 0.10 ถึงต่ำกว่า 0.25 ปานกลาง, 0.25 ถึงต่ำกว่า 0.50 สูง, ตั้งแต่ 0.50 สูงมาก) และแสดง design effect = 1 + (m̄ − 1) × ICC เมื่อ m̄ คือขนาดกลุ่มเฉลี่ย (แบบจำลอง B: 8.30 จากเฉลี่ย 130 คนต่ออำเภอ) แต่การมีค่าคงที่สุ่มควรขึ้นกับรูปแบบการเก็บข้อมูลที่เป็นกลุ่ม ไม่ใช่ ICC อย่างเดียว · ข้อจำกัด: ค่าคงที่สุ่มสมมุติว่าผลของกลุ่มไม่สัมพันธ์กับตัวทำนาย ในแบบจำลอง B การรักษาแทบทั้งหมดต่างกันระหว่างอำเภอ ผลของการรักษาจึงปนกับลักษณะของอำเภอ · ทั้งหมดเป็นความสัมพันธ์ในข้อมูลเชิงสังเกต ไม่ใช่ผลเชิงเหตุ
What to report: the fixed-effect ORs with 95% CI, σ² (or SD), the ICC, the number and size of clusters, the estimation method (ML, Laplace) and the LR test of σ² = 0. DAPH gives all of them in Tab 3 and in the note under the Word table (cluster variable, number and size of clusters, σ² and SD, latent-scale ICC, the boundary-corrected LR test of σ² = 0 and the estimation method). Tab 3 grades the ICC (below 0.05 very low, 0.05 to below 0.10 low, 0.10 to below 0.25 moderate, 0.25 to below 0.50 high, 0.50 or more very high) and adds the design effect 1 + (m̄ − 1) × ICC, where m̄ is the mean cluster size (Model B: 8.30 with 130 patients per district on average); whether to keep a random intercept should still follow the clustered design, not the ICC alone. Limitations: a random intercept assumes that cluster effects are unrelated to the predictors; in Model B treatment differs almost entirely between districts, so the treatment effect is mixed with district characteristics. All results are associations in observational data, not causal effects.
ตัวอย่างการเขียนรายงาน: "Random-intercept logistic regression (maximum likelihood, Laplace approximation) โดยมีอำเภอเป็นกลุ่ม (10 อำเภอ ผู้ป่วย 1,300 คน) พบความแปรปรวนระหว่างอำเภอ 0.197 (ICC 0.057; LR test p < 0.001) และไม่พบความสัมพันธ์อย่างมีนัยสำคัญระหว่าง APD กับคุณภาพชีวิตสูงหลังการรักษา (OR 1.31, 95% CI 0.72 to 2.39, p = 0.383) เมื่อควบคุมอายุและเพศ"
Model results sentence: "In random-intercept logistic regression (maximum likelihood, Laplace approximation) with district as the cluster (10 districts; 1,300 patients), the between-district variance was 0.197 (ICC 0.057; LR test p < 0.001), and APD was not significantly associated with a high quality of life after treatment (OR 1.31, 95% CI 0.72 to 2.39, p = 0.383), adjusting for age and gender."
📖 References
- Breslow, N. E., & Clayton, D. G. (1993). Approximate inference in generalized linear mixed models. Journal of the American Statistical Association, 88(421), 9–25. doi:10.1080/01621459.1993.10594284
- Liang, K.-Y., & Zeger, S. L. (1986). Longitudinal data analysis using generalized linear models. Biometrika, 73(1), 13–22. doi:10.1093/biomet/73.1.13
- Mancl, L. A., & DeRouen, T. A. (2001). A covariance estimator for GEE with improved small-sample properties. Biometrics, 57(1), 126–134. doi:10.1111/j.0006-341X.2001.00126.x
- Self, S. G., & Liang, K.-Y. (1987). Asymptotic properties of maximum likelihood estimators and likelihood ratio tests under nonstandard conditions. Journal of the American Statistical Association, 82(398), 605–610. doi:10.1080/01621459.1987.10478472
- Zeger, S. L., Liang, K.-Y., & Albert, P. S. (1988). Models for longitudinal data: A generalized estimating equation approach. Biometrics, 44(4), 1049–1060. doi:10.2307/2531734
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
2.4Pearson Chi-square test
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Pearson chi-square (χ²) test ทดสอบว่าตัวแปรกลุ่ม 2 ตัวสัมพันธ์กันหรือไม่ เช่น กลุ่มการรักษากับการเสียชีวิต โดยเทียบจำนวนที่พบจริงในตารางไขว้ (contingency table) ขนาด r×c กับจำนวนที่คาดว่าจะพบถ้าตัวแปรทั้งสองไม่สัมพันธ์กัน (Pearson, 1900) · ใช้เมื่อแต่ละคนถูกนับเพียงครั้งเดียวและเป็นอิสระต่อกัน · ไม่ใช้กับข้อมูลจับคู่หรือวัดซ้ำในคนเดียวกัน (ใช้ McNemar test ส่วน 2.5) · เมื่อจำนวนที่คาดหวังน้อย (มีเซลล์ที่ค่าคาดหวังน้อยกว่า 5 เกินร้อยละ 20 ของเซลล์) ค่า p จาก χ² ไม่น่าเชื่อถือ ให้ใช้ Fisher's exact test (Cochran, 1954) · χ² บอกเพียงว่ามีความสัมพันธ์หรือไม่ จึงต้องรายงานสัดส่วนในแต่ละกลุ่มและขนาดความสัมพันธ์ (Cramér's V) ด้วย · ในการศึกษาแบบ cohort ที่ระยะติดตามไม่เท่ากัน χ² เปรียบเทียบเพียงสัดส่วนที่เกิดเหตุการณ์จนสิ้นสุดการศึกษา โดยไม่คำนึงถึงเวลา ถ้าเวลาสำคัญให้ใช้ Kaplan-Meier และ log-rank test (5.1) หรือ Cox regression (5.2)
The Pearson chi-square (χ²) test asks whether two categorical variables are associated, for example treatment group and death, by comparing the counts observed in an r×c contingency table with the counts expected if the two variables were unrelated (Pearson, 1900). Use it when each person is counted once and people are independent of one another. Do not use it for paired or repeated measurements on the same people (use the McNemar test, 2.5). When expected counts are small (more than 20% of cells with an expected count below 5) the χ² p-value is unreliable and Fisher's exact test should be used (Cochran, 1954). χ² only says whether there is an association, so also report the proportion in each group and the strength of the association (Cramér's V). In a cohort with unequal follow-up, χ² compares only the proportion with the event by the end of the study and ignores time; when time matters use Kaplan-Meier with the log-rank test (5.1) or Cox regression (5.2).
2หลักการและสูตรLogic and Formula
- O_ij, E_ij
- จำนวนที่พบจริง และจำนวนที่คาดหวังเมื่อไม่มีความสัมพันธ์ ของเซลล์แถว i คอลัมน์ jobserved count and count expected under no association, in row i and column j
- R_i, C_j, N
- ผลรวมแถว i ผลรวมคอลัมน์ j และจำนวนทั้งหมดtotal of row i, total of column j, grand total
- r, c
- จำนวนแถว (ระดับของตัวแปรอิสระ) และจำนวนคอลัมน์ (ระดับของตัวแปรตาม)number of rows (levels of the independent variable) and of columns (levels of the dependent variable)
- a
- จำนวนในเซลล์แถวที่ 1 คอลัมน์ที่ 2 ของตาราง 2×2 (เมื่อผลรวมแถวและคอลัมน์คงที่ เซลล์เดียวกำหนดทั้งตาราง) · ค่า p รวมความน่าจะเป็นของทุกตารางที่น่าจะเกิดน้อยกว่าหรือเท่ากับตารางที่พบ (สองทาง)count in row 1, column 2 of the 2×2 table (with fixed row and column totals one cell fixes the whole table); the two-sided p adds the probabilities of every table no more likely than the one observed
- OR
- odds ratio จากตัวอย่าง (cross-product) = odds ของระดับที่ 2 ของตัวแปรตามในแถวที่ 2 เทียบกับแถวที่ 1sample (cross-product) odds ratio = odds of the dependent variable's second level in row 2 relative to row 1
สิ่งที่ DAPH คำนวณ: ตัวแปรอิสระแต่ละตัวทดสอบกับตัวแปรตามทีละตัว (ตารางแยกต่อตัวแปร) ตัดแถวที่ขาดค่าในคู่ตัวแปรนั้น · ตาราง 2×2 ใช้ Yates' correction เสมอ (ไม่มีตัวเลือกปิด) ส่วนตารางที่ใหญ่กว่าไม่ปรับ · ตาราง 2×2 แสดงแถว Fisher's Exact Test (OR และค่า p สองทาง) ทุกครั้ง และในรายงาน Word ถ้าเซลล์ที่ค่าคาดหวังน้อยกว่า 5 มีมากกว่าร้อยละ 20 ประโยคแปลผลจะใช้ค่า p ของ Fisher แทน χ² · ตารางที่ใหญ่กว่า 2×2 ไม่มี Fisher's exact test ใน DAPH ถ้าค่าคาดหวังน้อย หน้าผลลัพธ์ (Tab 3) จะแนะนำให้รวมกลุ่มย่อย · Cramér's V คำนวณจาก Pearson χ² ที่ไม่ปรับเสมอ (ตาราง 2×2 จึงได้ V = φ) แม้แถวผลทดสอบจะรายงาน χ² ที่ปรับด้วย Yates · หน้าผลลัพธ์ (Tab 3) และรายงาน Word ระบุว่า χ² ของตาราง 2×2 ปรับด้วย Yates' continuity correction · DAPH ไม่คำนวณ likelihood-ratio χ² ค่า residual รายเซลล์ หรือช่วงเชื่อมั่นของสัดส่วน
What DAPH computes: each independent variable is tested against the dependent variable on its own (one table block per variable), dropping rows with a missing value in that pair. A 2×2 table always gets Yates' correction (there is no option to switch it off); larger tables are not corrected. Every 2×2 table also gets a Fisher's Exact Test row (the OR and the two-sided p), and in the Word report the interpretation sentence uses Fisher's p instead of the χ² p when more than 20% of cells have an expected count below 5. DAPH has no Fisher's exact test for tables larger than 2×2; when their expected counts are small the results page (Tab 3) recommends merging categories. Cramér's V is always computed from the uncorrected Pearson χ² (so for a 2×2 table V = φ), even though the test row reports the Yates-corrected χ²; the results page (Tab 3) and the Word report state that a 2×2 χ² carries Yates' continuity correction. DAPH does not compute the likelihood-ratio χ², cell residuals or confidence intervals for the proportions.
เกณฑ์ขนาดความสัมพันธ์ที่ DAPH ใช้: V < 0.1 น้อยมาก, 0.1 ถึง < 0.3 น้อย, 0.3 ถึง < 0.5 ปานกลาง, ≥ 0.5 มาก · ตัวเลข 0.1, 0.3, 0.5 คือเกณฑ์ของ Cohen (1988) สำหรับ w ซึ่งเท่ากับ V เมื่อตัวแปรตัวใดตัวหนึ่งมี 2 ระดับ (ทั้งสองตารางในตัวอย่างนี้)
Size labels DAPH uses: V < 0.1 negligible, 0.1 to < 0.3 small, 0.3 to < 0.5 medium, ≥ 0.5 large. The cut-offs 0.1, 0.3 and 0.5 are Cohen's (1988) for w, which equals V when one of the two variables has two levels (as in both tables of this example).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
chisq.test, fisher.test) บนข้อมูลตัวอย่าง DAPHbase R (stats: chisq.test, fisher.test) on the DAPH example data# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$bmi_group <- factor(d$bmi_group, 1:4, c("Underweight", "Normal", "Overweight", "Obese"))
d$status <- factor(d$status, 0:1, c("Alive", "Died"))
# 1) Treatment group x death (2 x 2 table)
tab <- table(Group = d$group, Status = d$status)
tab
round(100 * prop.table(tab, 1), 1) # row %, as in the DAPH table
round(chisq.test(tab)$expected, 1) # expected counts (all >= 5)
yates <- chisq.test(tab) # 2 x 2: Yates' correction (R default = DAPH)
yates
pearson <- chisq.test(tab, correct = FALSE) # Pearson chi-square without correction
pearson
n <- sum(tab)
round(sqrt(unname(pearson$statistic) / n), 4) # Cramér's V = phi, from the uncorrected chi-square (as DAPH)
fisher.test(tab)$p.value # Fisher's exact test, two-sided
(tab[1, 1] * tab[2, 2]) / (tab[1, 2] * tab[2, 1]) # sample odds ratio (APD vs CAPD), as DAPH prints
# 2) BMI group x death (4 x 2 table): no continuity correction
tab2 <- table(BMI = d$bmi_group, Status = d$status)
round(100 * prop.table(tab2, 1), 1)
round(min(chisq.test(tab2)$expected), 1)
bmi <- chisq.test(tab2)
bmi
round(sqrt(unname(bmi$statistic) / (sum(tab2) * (min(dim(tab2)) - 1))), 4) # Cramér's V
Status
Group Alive Died
CAPD 86.9 13.1
APD 77.8 22.2
# expected counts: CAPD 540.4 / 115.6, APD 530.6 / 113.4
Pearson's Chi-squared test with Yates' continuity correction
X-squared = 17.903, df = 1, p-value = 2.325e-05
Pearson's Chi-squared test
X-squared = 18.524, df = 1, p-value = 1.678e-05
[1] 0.1194 # Cramér's V = phi
[1] 1.669228e-05 # Fisher's exact p
[1] 1.891798 # odds ratio
BMI Alive Died
Underweight 77.8 22.2
Normal 82.1 17.9
Overweight 84.1 15.9
Obese 83.0 17.0
[1] 22.2 # smallest expected count
X-squared = 2.5665, df = 3, p-value = 0.4634
[1] 0.0444 # Cramér's V
| Quantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Died: CAPD / APD (row %) | 13.1 / 22.2 | 13.1% / 22.2% | 0 | ✓ PASS |
| Smallest expected count (group × status) | 113.4 | 113.4 | 0 | ✓ PASS |
| χ²(1) with Yates' correction | 17.903 | 17.90254 (table: 17.90) | < 0.0005 | ✓ PASS |
| p (χ², Yates) | 2.325e−05 | 2.3251e−05 (table: <0.001) | < 1e−8 | ✓ PASS |
| Fisher's exact p (two-sided) | 1.669228e−05 | 1.669228e−05 | < 1e−11 | ✓ PASS |
| Odds ratio in the Fisher row (APD vs CAPD) | 1.891798 | 1.891798 (table: 1.892) | < 1e−6 | ✓ PASS |
| Cramér's V = φ, 2×2 (from the uncorrected χ² 18.524) | 0.1194 | 0.11937 (table: 0.119) | < 0.00005 | ✓ PASS |
| BMI group: χ²(3) | 2.5665 | 2.56646 (table: 2.57) | < 0.00005 | ✓ PASS |
| BMI group: p | 0.4634 | 0.46340 (table: 0.463) | < 0.00005 | ✓ PASS |
| BMI group: Cramér's V; smallest expected count | 0.0444; 22.2 | 0.0444 (table: 0.044); 22.2 | < 0.00005 | ✓ PASS |
4การแปลผลและตัวอย่างInterpretation and Example
กลุ่มการรักษา: ผู้ป่วย APD เสียชีวิตระหว่างติดตามร้อยละ 22.2 สูงกว่ากลุ่ม CAPD ร้อยละ 13.1 (ต่างกัน 9.1 จุดร้อยละ) χ²(1) = 17.90 (ปรับด้วย Yates) p < 0.001 และ Fisher's exact test ให้ข้อสรุปเดียวกัน (p < 0.001) · odds ของการเสียชีวิตในกลุ่ม APD เป็น 1.89 เท่าของกลุ่ม CAPD · ขนาดความสัมพันธ์น้อย (Cramér's V = φ = 0.119) · ทุกเซลล์มีค่าคาดหวังอย่างน้อย 113.4 จึงใช้ค่า p ของ χ² ได้ · นี่เป็นข้อมูลเชิงสังเกต ผู้ป่วยไม่ได้ถูกสุ่มเข้ากลุ่มการรักษา ความต่างนี้อาจมาจากอายุ โรคร่วม หรือระยะติดตามที่ต่างกัน จึงยังสรุปไม่ได้ว่า APD ทำให้เสียชีวิตมากขึ้น ควรวิเคราะห์ต่อด้วยแบบจำลองที่ปรับปัจจัยเหล่านี้ (เช่น Cox regression 5.2)
Treatment group: 22.2% of APD patients died during follow-up against 13.1% of CAPD patients (a difference of 9.1 percentage points), χ²(1) = 17.90 with Yates' correction, p < 0.001, and Fisher's exact test agrees (p < 0.001). The odds of death with APD were 1.89 times those with CAPD. The association is small (Cramér's V = φ = 0.119). Every expected count is at least 113.4, so the χ² p-value can be used. These are observational data and patients were not randomised to treatment, so the difference may reflect age, comorbidity or follow-up time rather than the treatment itself; it does not show that APD causes more deaths. Follow it with a model that adjusts for these factors (for example Cox regression, 5.2).
กลุ่ม BMI: สัดส่วนผู้เสียชีวิตอยู่ระหว่างร้อยละ 15.9 ถึง 22.2 χ²(3) = 2.57, p = 0.463, V = 0.044 · ไม่พบหลักฐานว่ากลุ่ม BMI สัมพันธ์กับการเสียชีวิต แต่ "ไม่มีนัยสำคัญ" ไม่ได้แปลว่า "ไม่มีความแตกต่าง" กลุ่ม Underweight มีเพียง 126 ราย ความต่างขนาดนี้อาจตรวจไม่พบด้วยขนาดตัวอย่างนี้
BMI group: the proportion who died ranged from 15.9% to 22.2%, χ²(3) = 2.57, p = 0.463, V = 0.044. There is no evidence that BMI group is associated with death, but "not significant" does not mean "no difference": the Underweight group has only 126 patients, and a difference of this size may go undetected at this sample size.
ประโยครายงานผลแบบวารสาร: "ผู้ป่วยที่ได้รับ APD เสียชีวิตระหว่างการติดตามมากกว่าผู้ป่วย CAPD (ร้อยละ 22.2 และ 13.1; χ²(1) = 17.90 ปรับด้วย Yates, p < 0.001; Cramér's V = 0.119) ขณะที่สัดส่วนการเสียชีวิตไม่แตกต่างกันอย่างมีนัยสำคัญระหว่างกลุ่ม BMI (χ²(3) = 2.57, p = 0.463)"
Journal-style sentence: "Death during follow-up was more frequent among patients on APD than on CAPD (22.2% vs 13.1%; χ²(1) = 17.90 with Yates' correction, p < 0.001; Cramér's V = 0.119), whereas the proportion who died did not differ significantly across BMI groups (χ²(3) = 2.57, p = 0.463)."
ในรายงาน Word: ตารางที่ 1 แสดง n (ร้อยละตามแถว) ของแต่ละกลุ่ม แถวผลทดสอบ χ²(df) กับ Cramér's V และค่า p และแถว Fisher's Exact Test ของตาราง 2×2 · หมายเหตุใต้ตารางบอกว่า χ² ของตาราง 2×2 ปรับด้วย Yates และ Cramér's V คำนวณจาก χ² ที่ไม่ปรับ · การแปลผลเขียนประโยคต่อตัวแปร มี χ²(df) (ตาราง 2×2 ระบุว่าปรับแก้ความต่อเนื่องของ Yates), Cramér's V และค่า p (หรือระบุว่าใช้ Fisher's exact test ตามกฎค่าคาดหวังข้างต้น) และบอกร้อยละของระดับสุดท้ายของตัวแปรตามในทุกกลุ่ม (ตัวอย่างนี้คือร้อยละที่เสียชีวิต: 13.1 ในกลุ่ม CAPD และ 22.2 ในกลุ่ม APD) · ตรวจสอบเพิ่มได้ในหน้าผลลัพธ์ (Tab 3) ซึ่งรายงานค่าคาดหวังต่ำสุดและขนาดตัวอย่าง · การทดสอบ χ² แบบ homogeneity (เปรียบเทียบสัดส่วนหลายกลุ่ม) กับแบบ independence ใช้สูตรเดียวกัน ต่างกันที่การออกแบบการเก็บข้อมูล
In the Word report: Table 1 shows n (row %) for each group, the test row with χ²(df), Cramér's V and p, and for a 2×2 table the Fisher's Exact Test row. A note under the table says that a 2×2 χ² uses Yates' correction and that Cramér's V is computed from the uncorrected χ². The interpretation has one sentence per variable with χ²(df) (for a 2×2 table marked "with Yates' continuity correction"), Cramér's V and p (or names Fisher's exact test under the expected-count rule above) and gives the proportion in the outcome's last level for every group (here the percentage who died: 13.1 with CAPD and 22.2 with APD). The results page (Tab 3) also reports the smallest expected count and the sample size. The χ² test of homogeneity (comparing proportions across groups) and the test of independence use the same formula; they differ only in how the data were sampled.
📖 References
- Cochran, W. G. (1954). Some methods for strengthening the common χ² tests. Biometrics, 10(4), 417–451. doi:10.2307/3001616
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
- Cramér, H. (1946). Mathematical methods of statistics. Princeton University Press.
- Fisher, R. A. (1922). On the interpretation of χ² from contingency tables, and the calculation of P. Journal of the Royal Statistical Society, 85(1), 87–94. doi:10.2307/2340521
- Pearson, K. (1900). On the criterion that a given system of deviations from the probable in the case of a correlated system of variables is such that it can be reasonably supposed to have arisen from random sampling. The London, Edinburgh, and Dublin Philosophical Magazine and Journal of Science, Series 5, 50(302), 157–175. doi:10.1080/14786440009463897
- Yates, F. (1934). Contingency tables involving small numbers and the χ² test. Supplement to the Journal of the Royal Statistical Society, 1(2), 217–235. doi:10.2307/2983604
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
2.5McNemar test
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
McNemar test (McNemar, 1947) ใช้กับตัวแปร 2 กลุ่มที่วัดซ้ำในคนเดียวกัน (ก่อน-หลัง) หรือในคู่ที่จับคู่กัน เช่น สัดส่วนผู้มีคุณภาพชีวิตต่ำตอนเริ่มกับตอนกลางการศึกษาในผู้ป่วยกลุ่มเดียวกัน · ทดสอบว่าสัดส่วนของกลุ่มหนึ่งเปลี่ยนไประหว่างการวัดสองครั้งหรือไม่ (marginal homogeneity) · ค่าสถิติใช้เฉพาะคู่ที่เปลี่ยนกลุ่ม (b และ c) เพราะคนที่อยู่กลุ่มเดิมทั้งสองครั้งไม่ได้บอกทิศทางการเปลี่ยนแปลง · ถ้าสองกลุ่มเป็นคนละคนกัน (เป็นอิสระ) ให้ใช้ Chi-square test (2.4) · DAPH รายงานผลต่างของสัดส่วนแบบจับคู่พร้อม 95% CI ด้วย จึงบอกขนาดของการเปลี่ยนแปลงได้ ไม่ใช่เพียงค่า p
The McNemar test (McNemar, 1947) is for a two-category variable measured twice on the same people (before and after) or on matched pairs, for example the proportion of patients with low quality of life at baseline and at mid-study in the same cohort. It tests whether the proportion in a category changed between the two measurements (marginal homogeneity). The statistic uses only the pairs that changed category (b and c), because people who stayed in the same category say nothing about the direction of change. If the two groups are different people (independent), use the chi-square test (2.4). DAPH also reports the paired difference in proportions with a 95% CI, so the size of the change is shown, not only a p-value.
2หลักการและสูตรLogic and Formula
- 0, 1
- ระดับรหัสต่ำ (ระดับ 0) และรหัสสูง (ระดับ 1) ของตัวแปร เช่น 0 = Low quality of life, 1 = High quality of lifethe lower code (level 0) and the higher code (level 1), e.g. 0 = Low quality of life, 1 = High quality of life
- a, d
- คู่ที่อยู่ระดับเดิมทั้งสองครั้งpairs in the same level both times
- b
- คู่ที่ครั้งแรกอยู่ระดับ 1 และครั้งที่สองอยู่ระดับ 0pairs at level 1 the first time and level 0 the second time
- c
- คู่ที่ครั้งแรกอยู่ระดับ 0 และครั้งที่สองอยู่ระดับ 1pairs at level 0 the first time and level 1 the second time
- p̂_first, p̂_second
- สัดส่วนระดับ 0 ในการวัดครั้งแรก (a + c)/n และครั้งที่สอง (a + b)/nproportion at level 0 at the first measurement, (a + c)/n, and at the second, (a + b)/n
สิ่งที่ DAPH คำนวณ: ตัวแปรตาม (Dependent Variable) คือการวัดครั้งที่สอง (หลัง) และตัวแปรจับคู่ (Matching Variable) คือการวัดครั้งแรก (ก่อน) ทั้งสองตัวต้องมี 2 ค่า แถวที่ขาดค่าในตัวใดตัวหนึ่งไม่ถูกนับ · เมื่อคู่ที่เปลี่ยนกลุ่ม b + c ≥ 25 ใช้ χ² ที่ปรับความต่อเนื่องแบบ Edwards (1948) ซึ่งเท่ากับ mcnemar.test() ของ R ยกเว้นกรณี b = c ที่ DAPH ไม่ให้ค่าติดลบ (|b − c| − 1 ถูกตั้งเป็น 0 จึงได้ χ² = 0 และ p = 1 ส่วน R ให้ 1/(b + c)) · เมื่อ b + c < 25 ใช้ exact binomial test แบบสองทาง (ไม่ใช่ mid-P) · ไม่มีคู่ที่เปลี่ยนกลุ่มเลยให้ p = 1 · ช่วงเชื่อมั่นของผลต่างเป็นแบบ Wald ข้างต้น (ไม่ใช่ Wilson) · แถว OR = b/c แสดงเฉพาะเมื่อ b และ c มากกว่า 0
What DAPH computes: the Dependent Variable is the second (after) measurement and the Matching Variable the first (before); both must have exactly 2 values, and a row missing either is not counted. With b + c ≥ 25 discordant pairs the test is χ² with Edwards' (1948) continuity correction, the same as R's mcnemar.test() except when b = c: DAPH does not let the correction go negative (|b − c| − 1 is set to 0, giving χ² = 0 and p = 1, where R gives 1/(b + c)). With b + c < 25 the two-sided exact binomial test is used (not the mid-P). With no discordant pair p = 1. The interval for the difference is the Wald interval above (not Wilson). The OR = b/c row appears only when both b and c are above 0.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
mcnemar.test, binom.test) บนข้อมูลตัวอย่าง DAPHbase R (stats: mcnemar.test, binom.test) on the DAPH example data# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
lev <- c("Low", "High") # 0 = Low quality of life, 1 = High quality of life
d$pre <- factor(d$qol_g1, 0:1, lev) # QoL Group (Pre) = first measurement (DAPH: Matching Variable)
d$mid <- factor(d$qol_g2, 0:1, lev) # QoL Group (Mid) = second measurement (DAPH: Dependent Variable)
paired <- function(tab) { # tab = table(first, second)
n <- sum(tab)
b <- tab["High", "Low"] # High -> Low
c <- tab["Low", "High"] # Low -> High
diff <- (b - c) / n # change in the proportion Low (second minus first)
se <- sqrt((b + c) - (b - c)^2 / n) / n # Wald SE for paired proportions
print(c(n = n, b = b, c = c))
print(round(100 * c(first_low = sum(tab["Low", ]) / n, second_low = sum(tab[, "Low"]) / n,
diff = diff, lower = diff - 1.96 * se, upper = diff + 1.96 * se), 2))
stat <- max(abs(b - c) - 1, 0)^2 / (b + c) # Edwards' continuity correction, floored at 0
print(c(chi2_cc = stat, p = pchisq(stat, 1, lower.tail = FALSE)))
print(c(exact_binomial_p = binom.test(b, b + c, 0.5)$p.value)) # DAPH uses this when b + c < 25
}
# 1) All 1,300 patients: b + c >= 25, so the continuity-corrected chi-square is used
tab <- table(Pre = d$pre, Mid = d$mid)
tab
mcnemar.test(tab) # same statistic (R prints p < 2.2e-16)
paired(tab)
# 2) Bangkok Hospital only (DAPH: Data Tools > Filter, hos = 1): b + c < 25, so the exact binomial test
h1 <- d[which(d$hos == 1), ]
tab1 <- table(Pre = h1$pre, Mid = h1$mid)
tab1
paired(tab1)
Mid
Pre Low High
Low 287 116
High 0 897
McNemar's chi-squared = 114.01, df = 1, p-value < 2.2e-16
n b c
1300 0 116
first_low second_low diff lower upper
31.00 22.08 -8.92 -10.47 -7.37
chi2_cc p
1.140086e+02 1.297432e-26
Mid # Bangkok Hospital
Pre Low High
Low 26 7
High 0 63
first_low second_low diff lower upper
34.38 27.08 -7.29 -12.49 -2.09
chi2_cc p
5.1428571 0.0233422 # not used: b + c = 7 < 25
exact_binomial_p
0.015625
| Quantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Low QoL: Pre / Mid (% of 1,300 pairs) | 31.00 / 22.08 | 31.0 / 22.077 (table: 31.0% / 22.1%) | < 0.005 | ✓ PASS |
| Discordant pairs b (High→Low) / c (Low→High) | 0 / 116 | 0 / 116 | 0 | ✓ PASS |
| McNemar χ²(1), Edwards' correction | 114.0086 | 114.00862 (note and Tab 3: χ²(1) = 114.01, continuity-corrected) | < 0.00005 | ✓ PASS |
| p | 1.297432e−26 | 1.297432e−26 (table: <0.001) | < 1e−31 | ✓ PASS |
| Change in % Low (Mid − Pre), Wald 95% CI | −8.92 (−10.47 to −7.37) | −8.92 (−10.47 to −7.37) (table: −8.9 (−10.5 to −7.4)) | < 0.005 | ✓ PASS |
| Ratio b/c and its CI | not estimable (b = 0) | row not shown | — | ✓ PASS |
| Bangkok Hospital (n = 96): b / c | 0 / 7 | 0 / 7 | 0 | ✓ PASS |
| Bangkok Hospital: test used and p | exact binomial, 0.015625 | exact binomial, 0.015625 (table: 0.016; Tab 3: “Exact binomial test (b = 0, c = 7), p = 0.016”) | 0 | ✓ PASS |
| Bangkok Hospital: change in % Low, Wald 95% CI | −7.29 (−12.49 to −2.09) | −7.29 (−12.49 to −2.09) (table: −7.3 (−12.5 to −2.1)) | < 0.005 | ✓ PASS |
4การแปลผลและตัวอย่างInterpretation and Example
ผลทั้ง 1,300 ราย: ผู้มีคุณภาพชีวิตต่ำลดจากร้อยละ 31.0 ตอนเริ่ม เหลือร้อยละ 22.1 ตอนกลางการศึกษา ลดลง 8.9 จุดร้อยละ (95% CI 7.4 ถึง 10.5 จุดร้อยละ) McNemar χ²(1) = 114.01, p < 0.001 · ทั้ง 116 รายที่เปลี่ยนกลุ่มเปลี่ยนจากต่ำเป็นสูง ไม่มีผู้ใดเปลี่ยนจากสูงเป็นต่ำ (b = 0) อัตราส่วน b/c จึงเป็น 0 และคำนวณช่วงเชื่อมั่นไม่ได้ DAPH จึงไม่แสดงแถวนี้ · นี่เป็นการเปรียบเทียบก่อน-หลังโดยไม่มีกลุ่มควบคุม การเปลี่ยนแปลงอาจมาจากเวลาที่ผ่านไป การถดถอยเข้าหาค่าเฉลี่ยของผู้ที่มีคะแนนใกล้จุดตัด หรือปัจจัยอื่น จึงยังไม่ใช่หลักฐานว่าการรักษาทำให้คุณภาพชีวิตดีขึ้น
All 1,300 patients: low quality of life fell from 31.0% at baseline to 22.1% at mid-study, a fall of 8.9 percentage points (95% CI 7.4 to 10.5 points), McNemar χ²(1) = 114.01, p < 0.001. All 116 patients who changed group moved from Low to High and none from High to Low (b = 0), so the ratio b/c is 0 with no computable interval and DAPH leaves that row out. This is a before-after comparison without a control group: the change may come from the passage of time, regression to the mean among patients scored near the cut-off, or other factors, so it is not evidence that treatment improved quality of life.
Bangkok Hospital: มีคู่ที่เปลี่ยนกลุ่มเพียง 7 คู่ DAPH จึงใช้ exact binomial test (p = 0.016) แทน χ² (ซึ่งจะให้ p = 0.023) · ผลต่าง −7.3 จุดร้อยละ (95% CI −12.5 ถึง −2.1) · เมื่อคู่ที่เปลี่ยนกลุ่มน้อย ช่วงเชื่อมั่นแบบ Wald เป็นเพียงค่าประมาณ ควรรายงานจำนวนคู่ที่เปลี่ยนกลุ่ม (b และ c) กำกับไว้เสมอ
Bangkok Hospital: only 7 pairs changed group, so DAPH used the exact binomial test (p = 0.016) instead of χ² (which would give p = 0.023). The change was −7.3 percentage points (95% CI −12.5 to −2.1). With few discordant pairs the Wald interval is only approximate; always report the numbers of discordant pairs (b and c) with it.
ประโยครายงานผลแบบวารสาร: "สัดส่วนผู้ป่วยที่มีคุณภาพชีวิตต่ำลดลงจากร้อยละ 31.0 ตอนเริ่มการศึกษาเป็นร้อยละ 22.1 ตอนกลางการศึกษา (ผลต่าง −8.9 จุดร้อยละ, 95% CI −10.5 ถึง −7.4; McNemar χ²(1) = 114.01, p < 0.001; ผู้ป่วยเปลี่ยนจากต่ำเป็นสูง 116 ราย และจากสูงเป็นต่ำ 0 ราย)"
Journal-style sentence: "The proportion of patients with low quality of life fell from 31.0% at baseline to 22.1% at mid-study (difference −8.9 percentage points, 95% CI −10.5 to −7.4; McNemar χ²(1) = 114.01, p < 0.001; 116 patients moved from low to high and none from high to low)."
ในรายงาน Word: ตารางแสดง n (ร้อยละของทุกคู่) ของแต่ละระดับในการวัดครั้งแรกและครั้งที่สอง ค่า p หนึ่งค่า ผลต่างของร้อยละพร้อม 95% CI และแถวอัตราส่วนคู่ที่เปลี่ยนกลุ่มเมื่อคำนวณได้ · การแปลผลบอกทิศทางและขนาดของการเปลี่ยนแปลง ระบุว่าใช้ McNemar test ที่ปรับความต่อเนื่อง (McNemar, 1947; Edwards, 1948) หรือ exact binomial test และอ้างอิงทั้งสองบทความ
In the Word report: the table gives n (% of all pairs) for each level at the first and second measurement, one p-value, the difference in percentage with its 95% CI, and the discordant-pair ratio row when it can be computed. The interpretation states the direction and size of the change and whether the continuity-corrected McNemar test (McNemar, 1947; Edwards, 1948) or the exact binomial test was used, with both papers in the reference list.
📖 References
- Agresti, A. (2013). Categorical data analysis (3rd ed.). Wiley. ISBN 978-0-470-46363-5.
- Edwards, A. L. (1948). Note on the "correction for continuity" in testing the significance of the difference between correlated proportions. Psychometrika, 13(3), 185–187. doi:10.1007/BF02289261
- McNemar, Q. (1947). Note on the sampling error of the difference between correlated proportions or percentages. Psychometrika, 12(2), 153–157. doi:10.1007/BF02295996
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
2.6Diagnostic Test Accuracy — ROC, AUC, Sensitivity, Specificity
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
ความแม่นของการตรวจ (diagnostic or prognostic accuracy) ตอบว่าการตรวจหรือตัวบ่งชี้แยกคนที่มีภาวะ (หรือจะเกิดเหตุการณ์) ออกจากคนที่ไม่มีได้ดีเพียงใด เมื่อเทียบกับมาตรฐานอ้างอิง (reference standard) ที่รู้ผลของทุกคน · DAPH มีเครื่องมือ 2 ตัวในเมนู วิเคราะห์เพิ่มเติม (Additional Analysis): (1) ROC Curve Analysis สำหรับคะแนนต่อเนื่อง ให้ ROC curve (receiver operating characteristic: ความไวเทียบกับ 1 − ความจำเพาะ ทุกจุดตัด) พื้นที่ใต้โค้ง AUC (area under the curve) พร้อม 95% CI และจุดตัดที่ดีที่สุดตาม Youden's index (2) Diagnostic Test Accuracy สำหรับผลตรวจ 2 ค่า (บวก/ลบ) ให้ sensitivity (ความไว), specificity (ความจำเพาะ), PPV และ NPV (ค่าทำนายผลบวก/ผลลบ), accuracy, likelihood ratio (LR) และ diagnostic odds ratio (DOR) · ไม่เหมาะเมื่อไม่มีมาตรฐานอ้างอิง หรือเมื่อต้องการดูความสอดคล้องของผู้ประเมิน 2 คน · AUC ของแบบจำลองทั้งชุดดูใน Logistic Regression (2.1) และการเปรียบเทียบ AUC ระหว่างแบบจำลองดูใน 7.1
Diagnostic (or prognostic) accuracy asks how well a test or marker separates people who have a condition (or will have an event) from those who do not, judged against a reference standard known for everyone. DAPH has two tools in the Additional Analysis menu: (1) ROC Curve Analysis for a continuous score, giving the ROC curve (receiver operating characteristic: sensitivity against 1 − specificity at every cut-off), the area under it (AUC) with a 95% CI, and the best cut-off by Youden's index; (2) Diagnostic Test Accuracy for a positive/negative test, giving sensitivity, specificity, the positive and negative predictive values (PPV, NPV), accuracy, likelihood ratios (LR) and the diagnostic odds ratio (DOR). These tools do not fit when there is no reference standard or when the question is agreement between two raters. A whole model's AUC is reported by logistic regression (2.1); comparing the AUCs of models is in 7.1.
2หลักการและสูตรLogic and Formula
- TP, FP, FN, TN
- ผลบวกจริง ผลบวกลวง ผลลบลวง ผลลบจริง (เทียบกับมาตรฐานอ้างอิง) · N = ทั้งหมดtrue positives, false positives, false negatives, true negatives against the reference standard; N = total
- X, t
- คะแนนของตัวบ่งชี้ และจุดตัด (DAPH ใช้ค่าที่พบจริงในข้อมูลเป็นจุดตัด คะแนน ≥ t ถือเป็นผลบวก)the marker's score and a cut-off (DAPH uses observed values as cut-offs; a score ≥ t is positive)
- D⁺, D⁻
- กลุ่มที่มีภาวะ (ค่า Positive Label) และกลุ่มที่ไม่มีthose with the condition (the Positive Label value) and those without
- AUC*
- AUC ของแต่ละชุดสุ่มซ้ำ (bootstrap resample)the AUC of each bootstrap resample
สิ่งที่ DAPH คำนวณ (ROC Curve Analysis): เลือก Score Variable (ตัวแปรตัวเลข) Outcome Variable และค่า Positive Label (ค่าเริ่มต้น 1) · ตัดแถวที่ขาดค่า · DAPH ถือว่าคะแนนสูงชี้ไปทางผลบวกเสมอ และไม่มีตัวเลือกทิศทาง ถ้าคะแนนต่ำคือความเสี่ยง (เช่น คุณภาพชีวิต) AUC จะต่ำกว่า 0.5 และจุดตัดใช้ไม่ได้ ผลลัพธ์จะขึ้นคำเตือน "⚠ AUC < 0.5" ว่าคะแนนทำงานกลับทิศ และบอกวิธีแก้ ให้กลับทิศคะแนนก่อนด้วย Data Tools > Compute (คะแนนติดลบ) หรือใส่ Positive Label เป็นอีกระดับหนึ่ง (กรณีหลังค่า sensitivity กับ specificity ที่แสดงจะสลับความหมายกัน) · AUC คำนวณแบบสี่เหลี่ยมคางหมูใต้โค้ง ซึ่งเท่ากับความน่าจะเป็นข้างต้น · 95% CI ของ AUC เป็น percentile bootstrap 1,000 รอบ สุ่มซ้ำจากผู้ป่วยทั้งหมดโดยไม่แยกตามผลลัพธ์ ใช้ seed คงที่ (ผลลัพธ์เขียนว่า "95% CI (bootstrap percentile, 1,000 resamples)" ไม่ใช่วิธี DeLong) · จุดตัดคือค่าที่พบจริงที่ทำให้ J สูงสุด ถ้ามีหลายค่าเท่ากันเลือกค่าสูงสุด · ระดับ AUC ที่แสดง: ≥ 0.9 Excellent, ≥ 0.8 Good, ≥ 0.7 Fair, ≥ 0.6 Poor, ต่ำกว่านั้น Fail · ผลแสดงเป็นข้อความในหน้าต่างเครื่องมือ ไม่มี SE ค่า p หรือการเปรียบเทียบ AUC สองค่า
What DAPH computes (ROC Curve Analysis): choose the Score Variable (numeric), the Outcome Variable and the Positive Label value (1 unless changed); rows with a missing value are dropped. DAPH always treats a higher score as pointing to the positive outcome; there is no direction option. When a low score signals risk (quality of life, for example) the AUC falls below 0.5 and the cut-off cannot be used; the output then shows a "⚠ AUC < 0.5" warning that the score works in the opposite direction and how to fix it. Reverse the score first with Data Tools > Compute (the negative of the score), or enter the other outcome level as the Positive Label (then the sensitivity and specificity shown swap meanings). The AUC is the trapezoidal area under the curve, which equals the probability above. Its 95% CI is a percentile bootstrap of 1,000 resamples of all patients, not stratified by outcome, with a fixed seed (the output labels it "95% CI (bootstrap percentile, 1,000 resamples)"; it is not DeLong's). The cut-off is the observed value with the largest J; when several tie, the highest is taken. The AUC labels shown are ≥ 0.9 Excellent, ≥ 0.8 Good, ≥ 0.7 Fair, ≥ 0.6 Poor and Fail below that. Results appear as text in the tool window, with no SE, no p-value and no comparison of two AUCs.
สิ่งที่ DAPH คำนวณ (Diagnostic Test Accuracy): เลือก Test Variable และ Gold Standard พร้อมค่าที่ถือเป็นผลบวกของแต่ละตัว (Positive Test Value, Positive Gold Value) · ให้ตาราง 2×2, prevalence, Se, Sp, PPV, NPV และ accuracy พร้อม Wilson 95% CI, LR⁺ และ LR⁻ (ไม่มี CI), DOR พร้อม CI แบบ log (ไม่คำนวณ DOR เมื่อ FP หรือ FN เป็น 0) · PPV และ NPV เป็นค่าที่ความชุกของข้อมูลชุดนี้เท่านั้น ถ้าจะใช้ในพื้นที่ที่ความชุกต่างไปให้คำนวณจากสูตร Bayes ข้างต้น · ข้อความแปลผล: Se และ Sp ≥ 0.9 ดีเยี่ยม, ≥ 0.8 ดี, ≥ 0.7 พอใช้, ต่ำกว่านั้นต่ำ · LR⁺ ≥ 10, ≥ 5, ≥ 2 และ LR⁻ ≤ 0.1, ≤ 0.2, ≤ 0.5 คือหลักฐานระดับสูงมาก ปานกลาง และเล็กน้อย
What DAPH computes (Diagnostic Test Accuracy): choose the Test Variable and the Gold Standard with the value that counts as positive for each (Positive Test Value, Positive Gold Value). The output is the 2×2 table, prevalence, Se, Sp, PPV, NPV and accuracy with Wilson 95% CIs, LR⁺ and LR⁻ (no CI), and the DOR with its log-scale CI (no DOR when FP or FN is 0). PPV and NPV hold only at the prevalence of these data; for a setting with a different prevalence use the Bayes formulas above. Interpretation text: Se and Sp both ≥ 0.9 excellent, ≥ 0.8 good, ≥ 0.7 fair, otherwise poor; LR⁺ ≥ 10, ≥ 5, ≥ 2 and LR⁻ ≤ 0.1, ≤ 0.2, ≤ 0.5 are called very strong, moderate and small evidence.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
pROC และ epiR บนข้อมูลตัวอย่าง DAPHpackages pROC and epiR on the DAPH example data# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
suppressMessages({library(pROC); library(epiR)})
# 1) ROC: baseline QoL score (qolscore1) as a marker of death during follow-up (status = 1).
# A LOW score points to death; DAPH counts high values as positive, so the score is reversed
# (DAPH: Data Tools > Compute, qol_neg = -qolscore1).
d$qol_neg <- -d$qolscore1
r <- roc(d$status, d$qol_neg, levels = c(0, 1), direction = "<", quiet = TRUE)
auc(r)
ci.auc(r, method = "delong") # DeLong CI, for comparison
set.seed(2026)
ci.auc(r, method = "bootstrap", boot.n = 2000, boot.stratified = FALSE) # percentile bootstrap, as DAPH
# Youden cut-off as DAPH reports it: an observed value t, positive when score >= t
t <- sort(unique(d$qol_neg), decreasing = TRUE)
se <- sapply(t, function(x) mean(d$qol_neg[d$status == 1] >= x))
sp <- sapply(t, function(x) mean(d$qol_neg[d$status == 0] < x))
k <- which.max(se + sp - 1)
round(c(cutoff = t[k], sensitivity = se[k], specificity = sp[k], youden_J = se[k] + sp[k] - 1), 4)
coords(r, "best", best.method = "youden") # pROC: midpoint between two observed values
# without reversing, high scores are taken as positive: AUC = 1 - 0.6169
auc(roc(d$status, d$qolscore1, levels = c(0, 1), direction = "<", quiet = TRUE))
# 2) Diagnostic accuracy: QoL Group (Pre) = Low quality of life (qol_g1 = 0, score 60 or less)
# as a positive test for death (status = 1)
test <- factor(d$qol_g1 == 0, c(TRUE, FALSE), c("Low QoL", "High QoL"))
death <- factor(d$status == 1, c(TRUE, FALSE), c("Died", "Alive"))
tab <- table(Test = test, Death = death)
tab
TP <- tab[1, 1]; FP <- tab[1, 2]; FN <- tab[2, 1]; TN <- tab[2, 2]; n <- sum(tab)
wilson <- function(x, m) prop.test(x, m, correct = FALSE)$conf.int[1:2] # Wilson score interval
est <- rbind(Sensitivity = c(TP / (TP + FN), wilson(TP, TP + FN)),
Specificity = c(TN / (TN + FP), wilson(TN, TN + FP)),
PPV = c(TP / (TP + FP), wilson(TP, TP + FP)),
NPV = c(TN / (TN + FN), wilson(TN, TN + FN)),
Accuracy = c((TP + TN) / n, wilson(TP + TN, n)))
colnames(est) <- c("estimate", "lower", "upper")
round(est, 4)
Se <- TP / (TP + FN); Sp <- TN / (TN + FP)
dor <- (TP * TN) / (FP * FN); s <- sqrt(1 / TP + 1 / FP + 1 / FN + 1 / TN)
round(c(prevalence = (TP + FN) / n, LR_pos = Se / (1 - Sp), LR_neg = (1 - Se) / Sp,
DOR = dor, DOR_lower = exp(log(dor) - 1.96 * s), DOR_upper = exp(log(dor) + 1.96 * s)), 4)
epi.tests(tab, method = "wilson", digits = 4) # same estimates and Wilson CIs from epiR
Area under the curve: 0.6169
95% CI: 0.5762-0.6577 (DeLong)
95% CI: 0.5773-0.6575 (2000 non-stratified bootstrap replicates)
cutoff sensitivity specificity youden_J
-63.0000 0.5633 0.6881 0.2515
threshold specificity sensitivity
1 -63.5 0.6881419 0.5633188
Area under the curve: 0.3831
Death
Test Died Alive
Low QoL 112 291
High QoL 117 780
estimate lower upper
Sensitivity 0.4891 0.4251 0.5535
Specificity 0.7283 0.7009 0.7541
PPV 0.2779 0.2364 0.3236
NPV 0.8696 0.8459 0.8900
Accuracy 0.6862 0.6604 0.7108
prevalence LR_pos LR_neg DOR DOR_lower DOR_upper
0.1762 1.8000 0.7015 2.5659 1.9161 3.4359
Positive likelihood ratio 1.8000 (1.5266, 2.1224) # CI from epiR only; DAPH shows no LR CI
Negative likelihood ratio 0.7015 (0.6148, 0.8004)
| Quantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| AUC (score reversed) | 0.6169 | 0.6169 | < 0.00005 | ✓ PASS |
| AUC 95% CI, percentile bootstrap (simulation: tolerance ± 0.005) | 0.5773 to 0.6575 (2,000 resamples) | 0.5751 to 0.6582 (“bootstrap percentile, 1,000 resamples”) | 0.0022 / 0.0007 | ✓ PASS |
| Youden cut-off (qol_neg ≥ −63, i.e. qolscore1 ≤ 63) and J | −63; 0.2515 | −63.0000; 0.2515 | 0 | ✓ PASS |
| Sensitivity / specificity at the cut-off | 0.5633 / 0.6881 | 0.5633 / 0.6881 | < 0.00005 | ✓ PASS |
| AUC if the score is not reversed (higher = positive) | 0.3831 | 0.3831 (with the “⚠ AUC < 0.5” warning) | < 0.00005 | ✓ PASS |
| TP / FP / FN / TN (qol_g1 = Low vs death) | 112 / 291 / 117 / 780 | 112 / 291 / 117 / 780 | 0 | ✓ PASS |
| Sensitivity (Wilson 95% CI) | 0.4891 (0.4251 to 0.5535) | 0.4891 (0.4251 to 0.5535) | < 0.00005 | ✓ PASS |
| Specificity (Wilson 95% CI) | 0.7283 (0.7009 to 0.7541) | 0.7283 (0.7009 to 0.7541) | < 0.00005 | ✓ PASS |
| PPV / NPV (Wilson 95% CI) | 0.2779 (0.2364 to 0.3236) / 0.8696 (0.8459 to 0.8900) | 0.2779 (0.2364 to 0.3236) / 0.8696 (0.8459 to 0.8900) | < 0.00005 | ✓ PASS |
| Accuracy (Wilson 95% CI); prevalence | 0.6862 (0.6604 to 0.7108); 0.1762 | 0.6862 (0.6604 to 0.7108); 0.1762 | < 0.00005 | ✓ PASS |
| LR⁺ / LR⁻ | 1.8000 / 0.7015 | 1.8000 / 0.7015 | < 0.00005 | ✓ PASS |
| DOR (log-scale 95% CI) | 2.5659 (1.9161 to 3.4359) | 2.5659 (1.9161 to 3.4359) | < 0.00005 | ✓ PASS |
ช่วงเชื่อมั่นแบบ bootstrap ขึ้นกับการสุ่ม ค่าจาก R กับ DAPH จึงต่างกันได้ในหลักที่สามตามความคลาดเคลื่อนของการจำลอง (ประมาณ 0.002 สำหรับ 1,000 รอบ) · ช่วงเชื่อมั่นแบบ DeLong ของ R (0.5762 ถึง 0.6577) ใกล้เคียงกัน แต่ DAPH ไม่ได้คำนวณ
A bootstrap interval depends on the random resamples, so R and DAPH can differ in the third decimal by Monte-Carlo error (about 0.002 for 1,000 resamples). R's DeLong interval (0.5762 to 0.6577) is close, but DAPH does not compute it.
4การแปลผลและตัวอย่างInterpretation and Example
ROC: AUC = 0.617 (95% CI 0.575 ถึง 0.658) แปลว่าถ้าสุ่มผู้ป่วยที่เสียชีวิต 1 รายกับผู้ที่รอดชีวิต 1 ราย ผู้ที่เสียชีวิตมีคะแนนคุณภาพชีวิตตอนเริ่มต่ำกว่าร้อยละ 61.7 ของโอกาส · ช่วงเชื่อมั่นไม่ครอบคลุม 0.5 จึงดีกว่าการเดา แต่แยกได้น้อย (DAPH ให้ระดับ Poor) · จุดตัดตาม Youden คือคะแนน 63 ลงมา ได้ sensitivity ร้อยละ 56.3 และ specificity ร้อยละ 68.8 · จุดตัดที่หาจากข้อมูลชุดเดียวกันมักดูดีเกินจริง ควรยืนยันในข้อมูลชุดอื่น และควรเลือกจุดตัดตามผลเสียของการพลาดผู้ป่วยกับการเตือนผิด ไม่ใช่ J อย่างเดียว · ถ้าไม่กลับทิศคะแนน DAPH จะให้ AUC = 0.383 พร้อมคำเตือนว่าคะแนนทำงานกลับทิศ และจุดตัดที่ได้ (คะแนน 22, J = 0.010) ใช้ไม่ได้
ROC: AUC = 0.617 (95% CI 0.575 to 0.658): for a randomly chosen patient who died and one who survived, the one who died had the lower baseline quality-of-life score 61.7% of the time. The interval excludes 0.5, so the score does better than chance, but its discrimination is weak (DAPH labels it Poor). The Youden cut-off is a score of 63 or less, with sensitivity 56.3% and specificity 68.8%. A cut-off chosen on the same data tends to look better than it will elsewhere and should be confirmed in other data, and in practice it should weigh the harm of missed deaths against false alarms, not J alone. Without reversing the score DAPH gives AUC = 0.383 with a warning that the score works in the opposite direction and that its cut-off (a score of 22, J = 0.010) cannot be used.
ผลตรวจ 2 ค่า (คุณภาพชีวิตต่ำตอนเริ่ม): ตรวจพบผู้ที่เสียชีวิตได้ร้อยละ 48.9 (95% CI 42.5 ถึง 55.3) และให้ผลลบในผู้รอดชีวิตร้อยละ 72.8 (95% CI 70.1 ถึง 75.4) · ในผู้ที่คุณภาพชีวิตต่ำ เสียชีวิตร้อยละ 27.8 (PPV) และในผู้ที่คุณภาพชีวิตสูง รอดชีวิตร้อยละ 87.0 (NPV) ซึ่งเป็นค่าที่ความชุกของการเสียชีวิตร้อยละ 17.6 ในข้อมูลนี้ · LR⁺ = 1.80 และ LR⁻ = 0.70 เปลี่ยน odds ของการเสียชีวิตได้เพียงเล็กน้อย DOR = 2.57 (95% CI 1.92 ถึง 3.44) · การเสียชีวิตในที่นี้นับจนสิ้นสุดการติดตามซึ่งยาวไม่เท่ากัน จึงเป็นความแม่นในการพยากรณ์อย่างหยาบ และเป็นความสัมพันธ์เชิงสังเกต ไม่ได้บอกว่าคุณภาพชีวิตต่ำเป็นสาเหตุของการเสียชีวิต · AUC บอกความสามารถในการแยกกลุ่ม ไม่ได้บอกว่าความเสี่ยงที่ทำนายตรงกับความเป็นจริง (calibration) ซึ่งตรวจในแบบจำลอง (2.1)
Binary test (low quality of life at baseline): it picked up 48.9% of the patients who died (95% CI 42.5 to 55.3) and was negative in 72.8% of survivors (95% CI 70.1 to 75.4). Of the patients with low quality of life 27.8% died (PPV), and of those with high quality of life 87.0% survived (NPV), at the 17.6% death proportion of these data. LR⁺ = 1.80 and LR⁻ = 0.70 shift the odds of death only a little; DOR = 2.57 (95% CI 1.92 to 3.44). Death here is counted to the end of follow-up, whose length varies, so this is a rough measure of prognostic accuracy, and the association is observational: it does not show that low quality of life causes death. The AUC measures discrimination, not whether predicted risks match observed ones (calibration), which is checked for models (2.1).
ระดับของ AUC: ป้ายที่ DAPH แสดง (Excellent ถึง Fail ในส่วนที่ 2) ต่างจากเกณฑ์ของ Hosmer et al. (2013) ที่ถือว่า AUC 0.7 ถึง 0.8 ยอมรับได้ 0.8 ถึง 0.9 ดีเยี่ยม และ 0.9 ขึ้นไปดีเลิศ จึงควรรายงานค่า AUC พร้อม 95% CI มากกว่าป้ายระดับ
AUC labels: the labels DAPH shows (Excellent to Fail, part 2) differ from the scale of Hosmer et al. (2013), where an AUC of 0.7 to 0.8 is acceptable, 0.8 to 0.9 excellent and 0.9 or more outstanding, so report the AUC with its 95% CI rather than a label.
ประโยครายงานผลแบบวารสาร: "คะแนนคุณภาพชีวิตตอนเริ่มการศึกษาแยกผู้ป่วยที่เสียชีวิตระหว่างการติดตามได้น้อย (AUC 0.617, 95% CI 0.575 ถึง 0.658 แบบ bootstrap) จุดตัดตาม Youden (คะแนน 63 ลงมา) ให้ sensitivity ร้อยละ 56.3 และ specificity ร้อยละ 68.8 ส่วนกลุ่มคุณภาพชีวิตต่ำ (คะแนน 60 ลงมา) ให้ sensitivity ร้อยละ 48.9 (95% CI 42.5 ถึง 55.3) และ specificity ร้อยละ 72.8 (95% CI 70.1 ถึง 75.4)"
Journal-style sentence: "The baseline quality-of-life score discriminated poorly between patients who died during follow-up and survivors (AUC 0.617, bootstrap 95% CI 0.575 to 0.658); the Youden cut-off (a score of 63 or less) gave a sensitivity of 56.3% and a specificity of 68.8%, and the low quality-of-life group (a score of 60 or less) a sensitivity of 48.9% (95% CI 42.5 to 55.3) and a specificity of 72.8% (95% CI 70.1 to 75.4)."
📖 References
- Altman, D. G., & Bland, J. M. (1994). Statistics notes: Diagnostic tests 2: Predictive values. BMJ, 309(6947), 102. doi:10.1136/bmj.309.6947.102
- DeLong, E. R., DeLong, D. M., & Clarke-Pearson, D. L. (1988). Comparing the areas under two or more correlated receiver operating characteristic curves: A nonparametric approach. Biometrics, 44(3), 837–845. doi:10.2307/2531595
- Efron, B. (1979). Bootstrap methods: Another look at the jackknife. The Annals of Statistics, 7(1), 1–26. doi:10.1214/aos/1176344552
- Hanley, J. A., & McNeil, B. J. (1982). The meaning and use of the area under a receiver operating characteristic (ROC) curve. Radiology, 143(1), 29–36. doi:10.1148/radiology.143.1.7063747
- Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied logistic regression (3rd ed.). Wiley. doi:10.1002/9781118548387
- Wilson, E. B. (1927). Probable inference, the law of succession, and statistical inference. Journal of the American Statistical Association, 22(158), 209–212. doi:10.1080/01621459.1927.10502953
- Woolf, B. (1955). On estimating the relation between blood group and disease. Annals of Human Genetics, 19(4), 251–253. doi:10.1111/j.1469-1809.1955.tb01348.x
- Youden, W. J. (1950). Index for rating diagnostic tests. Cancer, 3(1), 32–35. doi:10.1002/1097-0142(1950)3:1<32::AID-CNCR2820030106>3.0.CO;2-3
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
2.7Log-binomial Regression — Risk Ratio (RR), modified Poisson when log-binomial cannot be fitted
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
งานวิจัยแบบ cohort, cross-sectional และการทดลองมักต้องการ risk ratio (RR) หรือ prevalence ratio ซึ่งอ่านตรงกว่า odds ratio (OR): RR = 1.5 แปลว่าความเสี่ยงเป็น 1.5 เท่า · OR อยู่ห่างจาก 1 มากกว่า RR เสมอ และห่างมากขึ้นเมื่อผลลัพธ์พบบ่อย (เกินประมาณร้อยละ 10) จึงไม่ควรอ่าน OR เป็น RR (McNutt et al., 2003) · DAPH ประมาณค่า RR ด้วย Log-binomial regression ก่อน และเปลี่ยนเป็น Modified Poisson regression (Zou, 2004) ให้อัตโนมัติเมื่อ log-binomial ประมาณค่าไม่ได้ · ใช้กับตัวแปรตาม 2 ระดับ ถ้าตัวแปรตามเป็นจำนวนนับหรืออัตราต่อเวลาให้ใช้ Poisson regression (4.1) ถ้าสนใจเวลาจนเกิดเหตุการณ์ให้ใช้ Cox regression (5.2)
Cohort, cross-sectional and trial studies often need the risk ratio (RR) or prevalence ratio, which reads more directly than an odds ratio (OR): RR = 1.5 means 1.5 times the risk. The OR is always further from 1 than the RR, and the gap grows when the outcome is common (above roughly 10%), so an OR should not be read as an RR (McNutt et al., 2003). DAPH estimates the RR by log-binomial regression first and switches automatically to modified Poisson regression (Zou, 2004) when log-binomial cannot be fitted. It needs a two-level outcome; for counts or rates per unit time use Poisson regression (4.1), and for time to an event use Cox regression (5.2).
2หลักการและสูตรLogic and Formula
- p_i, μ_i
- ความเสี่ยงของคนที่ i (ระดับสูงสุดของตัวแปรตามคือเหตุการณ์)risk of person i (the outcome's highest level is the event)
- X_i
- แถวของ design matrix (1, ตัวแปรต่อเนื่อง, dummy ของตัวแปรกลุ่มเทียบระดับรหัสต่ำสุด)row of the design matrix (1, continuous variables, dummies of categorical variables against the lowest code)
- b̂, V̂_b
- สัมประสิทธิ์ของตัวแปรนั้นและเมทริกซ์ความแปรปรวนแบบ robust ของมันthat variable's coefficients and their robust covariance matrix
กฎการเลือกวิธี: เริ่ม log-binomial ด้วยค่าเริ่มต้น β₀ = log(ความชุก) และ β อื่น = 0 ประมาณค่าแบบ IRLS พร้อมลดขนาดก้าว (step-halving) เมื่อก้าวใดทำให้ความเสี่ยงที่ทำนายได้ ≥ 1 (วิธีเดียวกับ R glm) หยุดเมื่อ deviance เปลี่ยนน้อยกว่า 10⁻¹² (สัดส่วน) ภายใน 200 รอบ · ถ้าไม่ลู่เข้า เมทริกซ์สารสนเทศเป็นเอกฐาน ไม่มีก้าวใดที่ทำให้ความเสี่ยงทุกค่าต่ำกว่า 1 ความเสี่ยงที่ทำนายได้บางค่าถึง 1 (มากกว่า 1 − 10⁻⁶ คือค่าประมาณอยู่ที่ขอบ) หรือคำนวณ SE ไม่ได้ → ใช้ modified Poisson กับแบบจำลองเดียวกัน · การคัดเลือกตัวแปร (Backward / Forward / Stepwise) ถ้า log-binomial ใช้ไม่ได้ในขั้นใดจะใช้ modified Poisson ทั้งกระบวนการ ค่า p ทุกค่าจึงมาจากวิธีเดียวกัน · Bivariate ประมาณค่าแยกทีละตัวแปร และรายงานว่าตัวแปรใดใช้วิธีใด · หน้าจอ Tab 2 เริ่มจาก log-binomial เสมอ ไม่มีตัวเลือกให้ใช้ modified Poisson ตั้งแต่แรก (มีเฉพาะในคำขอ API: rr_settings = {"method": "modified_poisson"})
Choice of method: log-binomial starts at β₀ = log(prevalence) and every other β = 0, and is fitted by IRLS with step-halving whenever a step would make a predicted risk ≥ 1 (the algorithm of R glm), stopping when the relative change in deviance is below 10⁻¹² within 200 iterations. If it does not converge, the information matrix is singular, no step keeps every risk below 1, a predicted risk reaches 1 (above 1 − 10⁻⁶, a boundary estimate), or the SE cannot be computed, the same model is fitted by modified Poisson. For variable selection (Backward / Forward / Stepwise) the whole procedure switches when log-binomial fails at any step, so every p comes from one method; Bivariate fits each variable separately and reports which method each used. The Tab 2 screen always starts with log-binomial; choosing modified Poisson from the start exists only as an API request option (rr_settings = {"method": "modified_poisson"}).
ค่า p (หนึ่งตัวแปรหนึ่งค่า): ตัวแปรต่อเนื่อง = Wald z · ตัวแปรกลุ่ม = likelihood-ratio test เทียบกับแบบจำลองที่ตัดตัวแปรนั้นออกบนแถวเดียวกัน ประมาณจากค่าเริ่มต้นเดิม (log-binomial; ถ้าแบบจำลองที่ตัดออกประมาณค่าไม่ได้จะใช้ Wald χ² แทน) หรือ robust Wald χ² (modified Poisson — likelihood ของ Poisson ไม่ใช่ likelihood ของแบบจำลองจริง จึงไม่ใช้ LR) · เหตุการณ์คือระดับรหัสสูงสุดของตัวแปรตาม กลุ่มอ้างอิงคือระดับรหัสต่ำสุด ใช้เฉพาะแถวที่ครบทุกตัวแปร · ตารางมี Crude RR (ทีละตัวแปรบนแถวเดียวกับแบบจำลองปรับ ด้วยวิธีเดียวกัน) คู่กับ Adjusted RR · หมายเหตุตารางรายงาน LR χ² และ AIC ของแบบจำลอง (log-binomial) หรือ robust Wald χ² ของทุกตัวแปรรวมกัน (modified Poisson)
p values (one per variable): continuous = Wald z; categorical = likelihood-ratio test against the model without that variable on the same rows, refitted from the same start (log-binomial; if the reduced model cannot be fitted a Wald χ² is used instead) or robust Wald χ² (modified Poisson — the Poisson likelihood is not the model's likelihood, so no LR test). The event is the outcome's highest code, the reference group the lowest code, and only rows complete on every variable are used. The table shows the crude RR (one predictor at a time, on the rows of the adjusted model, by the same method) beside the adjusted RR. The table note gives the model LR χ² and AIC (log-binomial) or the robust Wald χ² of all variables together (modified Poisson).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
glm พร้อมแพ็กเกจ sandwich และ lmtest บนข้อมูลตัวอย่าง DAPHstats glm with packages sandwich and lmtest on the DAPH example data# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
suppressMessages({library(sandwich); library(lmtest)})
for (v in c("gender", "bmi_group", "group", "income")) d[[v]] <- factor(d[[v]]) # reference = lowest code
d$chronic_f <- factor(d$chronic, 0:1, c("No", "Yes"))
round(mean(d$chronic), 4) # risk of chronic disease (event = highest code, 1)
# Log-binomial, started where DAPH starts: log(prevalence) for the intercept, 0 for every slope
fit_lb <- function(f) {
y <- model.response(model.frame(f, d)); k <- ncol(model.matrix(f, d))
glm(f, data = d, family = binomial(link = "log"), start = c(log(mean(y)), rep(0, k - 1)),
control = glm.control(epsilon = 1e-12, maxit = 200))
}
# one p per variable, as DAPH: Wald z for a number, likelihood-ratio test (same start) for a factor
var_p <- function(f) {
full <- fit_lb(f)
sapply(attr(terms(f), "term.labels"), function(t) {
if (is.numeric(d[[t]])) return(summary(full)$coefficients[t, 4])
red <- fit_lb(update(f, paste(". ~ . -", t)))
pchisq(2 * as.numeric(logLik(full) - logLik(red)), length(coef(full)) - length(coef(red)), lower.tail = FALSE)
})
}
f <- chronic ~ age + gender + bmi_group + group + income
lb <- fit_lb(f)
round(cbind(RR = exp(coef(lb)), exp(confint.default(lb)), SE = sqrt(diag(vcov(lb))),
p = summary(lb)$coefficients[, 4]), 5)
round(var_p(f), 5)
null <- glm(chronic ~ 1, data = d, family = binomial(link = "log"))
round(c(LR = 2 * as.numeric(logLik(lb) - logLik(null)), AIC = AIC(lb)), 3)
round(exp(coef(glm(f, data = d, family = binomial)))["gender2"], 3) # odds ratio of the same model
# Backward elimination (remove the largest p while it is above 0.05)
round(var_p(f), 5) # income 0.17172 -> removed
f2 <- update(f, . ~ . - income); round(var_p(f2), 5) # group 0.10053 -> removed
f3 <- update(f2, . ~ . - group); round(var_p(f3), 5) # all below 0.05 -> stop
round(2 * as.numeric(logLik(fit_lb(f3)) - logLik(null)), 3) # LR chi-square, 5 df
round(exp(coef(fit_lb(f3))), 3)
# Modified Poisson (Zou, 2004): Poisson fit + sandwich (HC0) variance
mp <- glm(f, data = d, family = poisson, control = glm.control(epsilon = 1e-12))
V <- sandwich(mp)
round(cbind(RR = exp(coef(mp)), exp(coefci(mp, vcov = V)), SE = sqrt(diag(V)), p = coeftest(mp, vcov = V)[, 4]), 5)
i <- grep("^bmi_group", names(coef(mp)))
w <- as.numeric(t(coef(mp)[i]) %*% solve(V[i, i]) %*% coef(mp)[i])
round(c(robust_Wald_BMI = w, p = pchisq(w, length(i), lower.tail = FALSE)), 5)
# Death: log-binomial reaches the boundary (a fitted risk of 1), so DAPH switches to modified Poisson
fd <- status ~ age + group + n_peritonitis + n_infection + chronic_f
lbd <- suppressWarnings(fit_lb(fd))
max(fitted(lbd)) # 1 = boundary: no usable log-binomial estimate
mpd <- glm(fd, data = d, family = poisson, control = glm.control(epsilon = 1e-12))
Vd <- sandwich(mpd)
round(cbind(RR = exp(coef(mpd)), exp(coefci(mpd, vcov = Vd)), p = coeftest(mpd, vcov = Vd)[, 4]), 5)
[1] 0.5023
RR 2.5 % 97.5 % SE p
age 1.01236 1.00511 1.01966 0.00367 0.00081
gender2 1.18993 1.05357 1.34393 0.06210 0.00510
bmi_group4 1.54149 1.23083 1.93055 0.11483 0.00016
group2 0.91251 0.82139 1.01374 0.05368 0.08806
age gender bmi_group group income
0.00081 0.00413 0.00001 0.08383 0.17172
LR AIC
52.643 1767.512
gender2
1.426
age gender bmi_group group # after removing income
0.00034 0.00277 0.00001 0.10053
age gender bmi_group # after removing group
0.00026 0.00301 0.00001
[1] 46.422
(Intercept) age gender2 bmi_group2 bmi_group3 bmi_group4
0.136 1.013 1.196 1.185 1.283 1.554
RR 2.5 % 97.5 % SE p # modified Poisson
bmi_group4 1.59829 1.27300 2.00671 0.11610 0.00005
robust_Wald_BMI p
29.21702 0.00000
[1] 1
RR 2.5 % 97.5 % p # death, modified Poisson
age 1.04285 1.02895 1.05694 0.00000
group2 1.49778 1.18790 1.88850 0.00064
n_peritonitis 0.63457 0.53613 0.75110 0.00000
n_infection 0.56169 0.47689 0.66157 0.00000
chronic_fYes 1.63432 1.30663 2.04419 0.00002
| Quantity | R 4.3.3 | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Log-binomial RR gender (Female), 95% CI, SE | 1.18993 (1.05357 to 1.34393), SE 0.06210 | 1.18993 (1.05357 to 1.34393), SE 0.06210 (table: 1.190, 1.054 to 1.344) | < 0.000005 | ✓ PASS |
| Log-binomial RR BMI group (Obese), SE | 1.54149, SE 0.11483 | 1.54149, SE 0.11483 | < 0.000005 | ✓ PASS |
| Log-binomial RR age (per year), p | 1.01236, p 0.00081 | 1.01236, p 0.000808 (table: <0.001) | < 0.000005 | ✓ PASS |
| p per variable: gender / BMI group / treatment group / income (LR, same start) | 0.00413 / 0.00001 / 0.08383 / 0.17172 | 0.00413 / 0.0000143 / 0.08383 / 0.17172 (table: 0.004 / <0.001 / 0.084 / 0.172) | < 0.000005 | ✓ PASS |
| Model LR χ²(8); AIC | 52.643; 1767.512 | 52.643; 1767.51 | < 0.005 | ✓ PASS |
| Adjusted OR gender (Female), logistic regression, same variables | 1.426 | 1.426 | < 0.0005 | ✓ PASS |
| Backward: removed (p), then final LR χ²(5) | income (0.17172), group (0.10053) · 46.422 | income (0.17172), group (0.10053) · 46.422 | < 0.000005 | ✓ PASS |
| Modified Poisson RR BMI group (Obese), sandwich SE | 1.59829, SE 0.11610 | 1.59829, SE 0.11610 (table: 1.598) | < 0.000005 | ✓ PASS |
| Robust Wald χ² BMI group (3 df) | 29.21702 | 29.21702 | < 0.000005 | ✓ PASS |
| Death model: method | log-binomial stops at a fitted risk of 1 | log-binomial "did not converge" → Modified Poisson | — | ✓ PASS |
| Death model (modified Poisson): RR treatment group (APD); chronic disease | 1.49778 (1.18790 to 1.88850); 1.63432 (1.30663 to 2.04419) | 1.49778 (1.18790 to 1.88850); 1.63432 (1.30663 to 2.04419) (table: 1.498; 1.634) | < 0.000005 | ✓ PASS |
หมายเหตุ: drop1() ของ R ประมาณค่าแบบจำลองที่ตัดตัวแปรออกโดยไม่มีค่าเริ่มต้น จึงล้มกับแบบจำลองโรคเรื้อรังนี้ ("no valid set of coefficients has been found") — ต้องประมาณแบบจำลองย่อยเองด้วยค่าเริ่มต้นเดียวกัน ดังฟังก์ชัน var_p ในสคริปต์ · R รายงานว่าแบบจำลองการเสียชีวิตหยุดที่ขอบ (ความเสี่ยงที่ทำนายได้ = 1) ส่วน DAPH รายงานว่าไม่ลู่เข้า ทั้งสองแปลว่า log-binomial ใช้ไม่ได้ และ DAPH เขียนวิธีที่ใช้พร้อมเหตุผลในหมายเหตุตารางของ Word
Note: R's drop1() refits the reduced model without starting values and fails for this chronic-disease model ("no valid set of coefficients has been found"); refit the reduced model with the same start, as the function var_p in the script does. For the death model R reports that the fit stopped at the boundary (a fitted risk of 1) while DAPH reports no convergence; both mean log-binomial cannot be used, and DAPH writes the method used and the reason in the Word table note.
4การแปลผลและการใช้งานใน DAPHInterpretation and Use in DAPH
รายงาน RR + 95% CI และค่า p หนึ่งค่าต่อตัวแปร พร้อมระบุว่าใช้วิธีใดและเพราะเหตุใด (DAPH เขียนให้ใน Word) · RR ของระดับหนึ่งเทียบกับกลุ่มอ้างอิง (ระดับรหัสต่ำสุด) · ตัวแปรต่อเนื่องเป็น RR ต่อ 1 หน่วย และต้องเป็นเส้นตรงบนสเกล log ของความเสี่ยง · ความเสี่ยงที่นับคือระดับสูงสุดของตัวแปรตาม (Word เขียนชื่อระดับนั้นกำกับ)
Report the RR + 95% CI and one p per variable, and state which method was used and why (DAPH writes this in the Word report). A level's RR is against the reference group (the lowest code); a continuous predictor's RR is per one unit and assumes linearity on the log-risk scale. The risk counted is that of the outcome's highest level (the Word report names that level).
ตัวอย่างโรคเรื้อรัง: เมื่อปรับปัจจัยอื่นแล้ว ผู้หญิงมีความเสี่ยงของการมีโรคเรื้อรังเป็น 1.19 เท่าของผู้ชาย (95% CI 1.05 ถึง 1.34; p = 0.004) กลุ่ม Obese เป็น 1.54 เท่าของกลุ่ม Underweight (95% CI 1.23 ถึง 1.93; กลุ่ม BMI p < 0.001) และความเสี่ยงเพิ่มร้อยละ 1.2 ต่ออายุ 1 ปี (RR 1.012, 95% CI 1.005 ถึง 1.020) · กลุ่มการรักษา (p = 0.084) และรายได้ (p = 0.172) ไม่มีนัยสำคัญ ซึ่งไม่ได้แปลว่าไม่มีความแตกต่าง · Backward Elimination ตัดรายได้แล้วตัดกลุ่มการรักษาออก RR ที่เหลือเปลี่ยนเล็กน้อย (ผู้หญิง 1.196, Obese 1.554) · เป็นข้อมูลเชิงสังเกตแบบภาคตัดขวาง RR นี้คือ prevalence ratio และบอกความสัมพันธ์ ไม่ใช่เหตุและผล
Chronic-disease example: after adjustment, women had 1.19 times the risk of a chronic disease of men (95% CI 1.05 to 1.34; p = 0.004), the Obese group 1.54 times that of the Underweight group (95% CI 1.23 to 1.93; BMI group p < 0.001), and the risk rose by 1.2% per year of age (RR 1.012, 95% CI 1.005 to 1.020). Treatment group (p = 0.084) and income (p = 0.172) were not significant, which does not mean there is no difference. Backward elimination removed income and then treatment group, and the remaining RRs changed little (women 1.196, Obese 1.554). These are cross-sectional observational data: the RR here is a prevalence ratio and describes an association, not cause and effect.
ตัวอย่างการเสียชีวิต (DAPH เปลี่ยนเป็น modified Poisson): ความเสี่ยงของการเสียชีวิตในกลุ่ม APD เป็น 1.50 เท่าของ CAPD (95% CI 1.19 ถึง 1.89) และในผู้มีโรคเรื้อรังเป็น 1.63 เท่า (95% CI 1.31 ถึง 2.04) · RR ของจำนวนครั้งเยื่อบุช่องท้องอักเสบ (0.63) และการติดเชื้อ (0.56) ต่ำกว่า 1 ไม่ได้แปลว่าการติดเชื้อช่วยป้องกัน: จำนวนเหล่านี้สะสมระหว่างติดตาม ผู้ที่เสียชีวิตเร็วจึงมีเวลาสะสมน้อยกว่า ตัวอย่างนี้ใช้แสดงการเปลี่ยนวิธีเท่านั้น งานจริงควรใช้ตัวแปรที่วัดก่อนเริ่มติดตาม และใช้ Cox regression (5.2) เมื่อระยะติดตามต่างกัน
Death example (DAPH switched to modified Poisson): the risk of death with APD was 1.50 times that with CAPD (95% CI 1.19 to 1.89), and 1.63 times higher with a chronic disease (95% CI 1.31 to 2.04). The RRs below 1 for the numbers of peritonitis episodes (0.63) and infections (0.56) do not mean that infections protect: these counts accumulate during follow-up, so patients who died early had less time to accumulate them. The example only shows the switch; real analyses should use variables measured before follow-up starts, and Cox regression (5.2) when follow-up lengths differ.
ใน DAPH: Tab 2 → ตัวแปรตามแบบกลุ่ม 2 ระดับ → สถิติ Log-binomial Regression → เลือกวิธีนำตัวแปรเข้า (Enter · Backward Elimination · Stepwise Regression · Forward Selection · Bivariate Analysis) เช่นเดียวกับ Logistic Regression · เกณฑ์ p = 0.05 ทั้งการนำเข้าและการตัดออก
In DAPH: Tab 2 → a 2-level categorical outcome → statistic Log-binomial Regression → choose how variables enter (Enter · Backward Elimination · Stepwise Regression · Forward Selection · Bivariate Analysis), as for logistic regression; p = 0.05 to enter and to remove.
ตารางผล: เมื่อวิเคราะห์แบบหลายตัวแปร ตารางแสดงจำนวน ร้อยละของเหตุการณ์ Crude RR · Adjusted RR · 95% CI ของ Adjusted RR · ค่า p (ช่วงเชื่อมั่นของ Crude RR ไม่แสดง เพราะค่าที่นำไปตีความคือค่าที่ปรับแล้ว) ส่วนวิธี Bivariate แสดง RR ของแต่ละตัวแปรพร้อมช่วงเชื่อมั่นของตัวเอง · หมายเหตุตารางใน Word บอกวิธีที่ใช้ (และเหตุผลถ้าเปลี่ยนวิธี) จำนวนเหตุการณ์ต่อจำนวนทั้งหมด จำนวนเหตุการณ์ต่อพารามิเตอร์ และ LR χ² กับ AIC หรือ robust Wald χ²
Results table: a multivariable run reports the count, the percentage with the event, Crude RR, Adjusted RR, the 95% CI of the adjusted RR and the p-value; the crude estimate's own interval is not shown, since the adjusted estimate is the one being interpreted. A bivariate run reports each variable's RR with its own interval. The Word table note gives the method used (and the reason when it switched), events out of the total, events per parameter, and the LR χ² with AIC or the robust Wald χ².
ส่งออกเพื่อทำนาย: แบบจำลองที่ได้จากวิธี Enter/Backward/Stepwise/Forward ส่งออกเป็นแพ็กเกจสำหรับหน้าทำนายได้ (ปุ่ม “ส่งออกสำหรับเว็บ”) · สมการให้ log ของความเสี่ยง และหน้าเว็บคืนค่าเป็น ความเสี่ยง = e^(ค่าที่ได้) ไม่ใช่ odds และไม่ใช่จำนวนนับ · ค่าที่คำนวณได้เกิน 1 หมายถึงโปรไฟล์นั้นอยู่นอกช่วงข้อมูลที่ใช้สร้างแบบจำลอง หน้าเว็บจะแจ้งว่าไม่ควรใช้ผลนั้น · วิธี Bivariate ส่งออกไม่ได้เพราะไม่มีสมการเดียว
Export for prediction: a model from Enter / Backward / Stepwise / Forward can be exported as a package for the prediction page (“Export for Web”). The equation returns a log risk and the page reports a risk = e^(value), not an odds and not a count. A value above 1 means the profile lies outside the data the model was fitted on; the page says the result should not be used. A bivariate run has no single equation and is refused.
📖 References
- McNutt, L.-A., Wu, C., Xue, X., & Hafner, J. P. (2003). Estimating the relative risk in cohort studies and clinical trials of common outcomes. American Journal of Epidemiology, 157(10), 940–943. doi:10.1093/aje/kwg074
- Zou, G. (2004). A modified Poisson regression approach to prospective studies with binary data. American Journal of Epidemiology, 159(7), 702–706. doi:10.1093/aje/kwh090
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 3 — ตัวแปรหลายระดับ (Multiclass)Chapter 3 — Multiclass Outcomes ✓ Verified
ตัวแปรตามแบบกลุ่มที่มีตั้งแต่ 3 ระดับ · ถ้าระดับมีลำดับ ใช้ Ordered Logistic Regression (หัวข้อ 3.1) ซึ่งรายงาน odds ratio (OR) ค่าเดียวต่อตัวแปรภายใต้ข้อตกลง proportional odds · ถ้าระดับไม่มีลำดับหรือไม่ต้องการบังคับลำดับ ใช้ Multinomial Logistic Regression (หัวข้อ 3.2) ซึ่งรายงาน relative risk ratio (RRR) = exp(β) ของแต่ละระดับเทียบกับกลุ่มอ้างอิง (RRR มีค่าเท่ากับ odds ratio ของระดับนั้นเทียบกับกลุ่มอ้างอิง ไม่ใช่อัตราส่วนความเสี่ยง) · ตัวอย่างใช้ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย) และตรวจกับ R Categorical outcomes with three or more levels. Ordered levels: Ordered Logistic Regression (section 3.1), one odds ratio (OR) per variable under the proportional-odds assumption. Unordered levels, or when no order should be imposed: Multinomial Logistic Regression (section 3.2), which reports the relative risk ratio (RRR) = exp(β) of each level against the reference (the RRR equals the odds ratio of that level versus the reference; it is not a risk ratio). The examples use the DAPH example data (1,300 peritoneal-dialysis patients) and are checked against R.
3.1Ordered Logistic Regression (Proportional Odds)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Ordered Logistic Regression หรือ proportional odds model ใช้เมื่อตัวแปรตามเป็นกลุ่มที่มีลำดับตั้งแต่ 3 ระดับขึ้นไป เช่น ความถี่ของพฤติกรรม (ไม่เคย ถึง ทุกวัน) ระดับความรุนแรงของโรค หรือระดับรายได้ แบบจำลองดู odds สะสม (cumulative odds) ของการอยู่ในระดับที่สูงกว่าจุดตัดแต่ละจุด และกำหนดให้ผลของตัวแปรอิสระแต่ละตัวเท่ากันที่ทุกจุดตัด (proportional odds: PO) ผลของตัวแปรหนึ่งตัวจึงสรุปได้ด้วย odds ratio (OR) ค่าเดียว (McCullagh, 1980)
Ordered Logistic Regression, the proportional odds model, is used when the outcome has three or more ordered categories, such as how often a behaviour occurs (never to every day), disease severity or income band. It models the cumulative odds of being above each cut-point between categories and assumes that each predictor has the same effect at every cut-point (proportional odds, PO), so the effect of a predictor is summarised by a single odds ratio (OR) (McCullagh, 1980).
ไม่ควรใช้เมื่อ: ระดับของตัวแปรตามไม่มีลำดับ (ใช้ Multinomial Logistic Regression หัวข้อ 3.2) · ตัวแปรตามมี 2 ระดับ (ใช้ Logistic Regression หัวข้อ 2.1) · ผลของตัวแปรต่างกันชัดเจนระหว่างจุดตัด (PO ไม่เป็นจริง)
Do not use it when the categories have no order (use Multinomial Logistic Regression, section 3.2), when the outcome has two categories (use Logistic Regression, section 2.1), or when a predictor's effect clearly differs between cut-points (the PO assumption fails).
2หลักการและสูตรLogic and Formula
- J
- จำนวนระดับของตัวแปรตาม (ตัวอย่างนี้ J = 5 จึงมีจุดตัด 4 จุด)number of outcome levels (here J = 5, so there are 4 cut-points)
- θ_j
- จุดตัด (cut-point หรือ threshold) ระหว่างระดับ j กับ j + 1cut-point (threshold) between level j and level j + 1
- β, x
- สัมประสิทธิ์และค่าของตัวแปรอิสระ (ตัวแปรกลุ่มแตกเป็นตัวแปรหุ่น 0/1 เทียบกลุ่มอ้างอิง)slopes and predictor values (a categorical variable becomes 0/1 dummy columns against its reference level)
- SE_m
- ความคลาดเคลื่อนมาตรฐาน (standard error) จากเมทริกซ์ความแปรปรวนร่วม V = อินเวอร์สของ Hessian ของ −ℓstandard error from the covariance matrix V = inverse Hessian of −ℓ
- q, k, n
- จำนวนคอลัมน์ตัวแปรหุ่นของตัวแปรกลุ่มหนึ่งตัว · จำนวนสัมประสิทธิ์ β ทั้งหมด · จำนวนผู้ป่วยdummy columns of one categorical variable · number of slopes β · number of patients
- ℓ, ℓ_0
- log-likelihood ของแบบจำลอง และของแบบจำลองที่มีแต่จุดตัด (ไม่มีตัวแปรอิสระ)log-likelihood of the model and of the thresholds-only model (no predictors)
สิ่งที่ DAPH คำนวณ: ประมาณค่าด้วย maximum likelihood โดยอัลกอริทึม quasi-Newton (BFGS) แล้วใช้ Newton-Raphson จนลู่เข้าเต็มที่ · SE ของจุดตัดคำนวณด้วย delta method · ℓ_0 คำนวณจากสัดส่วนของแต่ละระดับ ℓ_0 = Σ n_j ln(n_j / n) · OR > 1 หมายถึงตัวแปรสัมพันธ์กับระดับที่สูงขึ้น (สมการใช้ θ_j − x′β แบบเดียวกับ R MASS::polr และ ordinal::clm) · ตัวแปรชนิด integer/real เข้าเป็นตัวแปรต่อเนื่อง ส่วนชนิด nominal/binominal/ordinal แตกเป็นตัวแปรหุ่นโดยใช้รหัสต่ำสุดเป็นกลุ่มอ้างอิง (ตัวแปร ordinal เช่น รายได้ครัวเรือน จึงไม่ได้เข้าเป็นแนวโน้มเส้นตรง) · ตัดแถวที่มีค่าว่างในตัวแปรใดตัวหนึ่งออกทั้งแถว · 95% CI แบบ Wald · ค่า p ของตัวแปรต่อเนื่อง = Wald z ส่วนตัวแปรกลุ่มมีค่า p เดียวจาก joint Wald χ² ที่แถวชื่อตัวแปร · วิธี Bivariate Analysis ประมาณค่าทีละตัวแปร (crude OR)
What DAPH computes: maximum likelihood with the quasi-Newton BFGS algorithm followed by Newton-Raphson steps to full convergence. Cut-point SEs come from the delta method, and ℓ_0 is computed from the level proportions, ℓ_0 = Σ n_j ln(n_j / n). OR > 1 means the predictor goes with higher levels (the model uses θ_j − x′β, as R MASS::polr and ordinal::clm do). Integer/real variables enter as continuous; nominal/binominal/ordinal variables become dummies with the lowest code as reference (so an ordinal predictor such as Household Income is not entered as a linear trend). Rows with a missing value in any analysed variable are dropped. 95% CIs are Wald intervals. A continuous predictor's p is the Wald z test; a categorical predictor gets one p, the joint Wald χ² on its header row. The Bivariate Analysis method fits one predictor at a time (crude OR).
ข้อตกลง PO: DAPH ระบุไว้ในรายการข้อตกลงแต่ยังไม่ได้ทดสอบ จึงควรตรวจเองด้วย likelihood-ratio test ข้างต้น (ให้ตัวแปรหนึ่งตัวมีความชันแยกกันในแต่ละจุดตัด แล้วเทียบกับแบบจำลอง PO) ซึ่งทำใน R ได้ตามสคริปต์ด้านล่าง หรือใช้ Brant test (Brant, 1990) ถ้า PO ไม่เป็นจริงสำหรับตัวแปรใด ให้พิจารณา partial proportional odds model (Peterson & Harrell, 1990) หรือ Multinomial Logistic Regression (หัวข้อ 3.2)
The PO assumption: DAPH lists it among the assumptions but does not test it. Check it with the likelihood-ratio test above (give one variable separate slopes at each cut-point and compare with the PO model), as the R script below does, or with the Brant test (Brant, 1990). If PO fails for a variable, consider a partial proportional odds model (Peterson & Harrell, 1990) or Multinomial Logistic Regression (section 3.2).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
ordinal (clm, nominal_test)package ordinal (clm, nominal_test)# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(ordinal) # clm(): cumulative-logit (proportional odds) model
d$salt <- factor(d$saltyfoodfreq, levels = 0:4, ordered = TRUE,
labels = c("Never (0)", "A few days (1-4)", "About half the days (5-9)",
"Most days (10-13)", "All day (14)"))
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$bmi_group <- factor(d$bmi_group, 1:4, c("Underweight", "Normal", "Overweight", "Obese"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
d$fam_income <- factor(d$fam_income, 1:3, c("<10,000", "10,000-30,000", ">30,000"))
table(d$salt) # outcome: 5 ordered levels
fit <- clm(salt ~ age + gender + bmi_group + chronic + fam_income, data = d)
summary(fit) # logit P(Y <= j) = theta_j - x'beta
b <- fit$beta # slopes; the cut-points are fit$alpha
V <- vcov(fit)[names(b), names(b)]
se <- sqrt(diag(V))
round(cbind(OR = exp(b), lower = exp(b - qnorm(0.975) * se),
upper = exp(b + qnorm(0.975) * se), p = 2 * pnorm(-abs(b / se))), 4)
wald <- function(term) { # joint Wald test: one p per categorical variable
i <- grep(paste0("^", term), names(b))
X2 <- drop(t(b[i]) %*% solve(V[i, i]) %*% b[i])
c(chisq = X2, df = length(i), p = pchisq(X2, length(i), lower.tail = FALSE))
}
round(sapply(c("gender", "bmi_group", "chronic", "fam_income"), wald), 4)
fit0 <- clm(salt ~ 1, data = d) # thresholds only
LR <- 2 * (as.numeric(logLik(fit)) - as.numeric(logLik(fit0)))
round(c(logLik = as.numeric(logLik(fit)), logLik0 = as.numeric(logLik(fit0)),
AIC = AIC(fit), BIC = BIC(fit), LR_chisq = LR, df = length(b),
p = pchisq(LR, length(b), lower.tail = FALSE),
McFadden_R2 = 1 - as.numeric(logLik(fit)) / as.numeric(logLik(fit0))), 4)
# Proportional-odds check (DAPH does not compute it): LR test of each variable's
# slopes being equal at all 4 cut-points. Age is centred at 70 years so that the
# thresholds of the larger model are checked inside the data range.
d$age70 <- d$age - 70
fit_c <- clm(salt ~ age70 + gender + bmi_group + chronic + fam_income, data = d)
nominal_test(fit_c)
Never (0) A few days (1-4) About half the days (5-9)
269 674 124
Most days (10-13) All day (14)
53 180
Coefficients:
Estimate Std. Error z value Pr(>|z|)
age -0.006265 0.007631 -0.821 0.41169
genderFemale 0.033831 0.110840 0.305 0.76020
bmi_groupNormal -0.482129 0.188769 -2.554 0.01065 *
bmi_groupOverweight -0.270635 0.205595 -1.316 0.18806
bmi_groupObese -0.537660 0.203572 -2.641 0.00826 **
chronicYes 0.227409 0.106636 2.133 0.03296 *
fam_income10,000-30,000 -0.235724 0.143314 -1.645 0.10001
fam_income>30,000 0.136273 0.124317 1.096 0.27300
Threshold coefficients:
Estimate Std. Error z value
Never (0)|A few days (1-4) -2.0623 0.5909 -3.490
A few days (1-4)|About half the days (5-9) 0.2866 0.5880 0.487
About half the days (5-9)|Most days (10-13) 0.8430 0.5883 1.433
Most days (10-13)|All day (14) 1.1516 0.5890 1.955
OR lower upper p
age 0.9938 0.9790 1.0087 0.4117
genderFemale 1.0344 0.8324 1.2854 0.7602
bmi_groupNormal 0.6175 0.4265 0.8939 0.0106
bmi_groupOverweight 0.7629 0.5099 1.1415 0.1881
bmi_groupObese 0.5841 0.3919 0.8705 0.0083
chronicYes 1.2553 1.0186 1.5471 0.0330
fam_income10,000-30,000 0.7900 0.5965 1.0462 0.1000
fam_income>30,000 1.1460 0.8982 1.4622 0.2730
gender bmi_group chronic fam_income
chisq 0.0932 9.5272 4.5479 8.0955
df 1.0000 3.0000 1.0000 2.0000
p 0.7602 0.0230 0.0330 0.0175
logLik logLik0 AIC BIC LR_chisq df
-1671.9397 -1683.3883 3367.8795 3429.9209 22.8972 8.0000
p McFadden_R2
0.0035 0.0068
Tests of nominal effects
formula: salt ~ age70 + gender + bmi_group + chronic + fam_income
Df logLik AIC LRT Pr(>Chi)
<none> -1671.9 3367.9
age70 3 -1669.7 3369.3 4.5360 0.2091
gender 3 -1671.2 3372.4 1.4636 0.6907
bmi_group 9 -1666.1 3374.2 11.7055 0.2304
chronic 3 -1670.2 3370.3 3.5483 0.3146
fam_income 6 -1668.0 3371.9 7.9384 0.2427
| Quantity | R 4.3.3 | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| Age (per year): OR (95% CI), p | 0.994 (0.979 to 1.009), 0.412 | 0.994 (0.979 to 1.009), 0.412 | <1e−6 | ✓ PASS |
| Gender, Female vs Male: OR (95% CI), p | 1.034 (0.832 to 1.285), 0.760 | 1.034 (0.832 to 1.285), 0.760 | <1e−6 | ✓ PASS |
| BMI group, Normal vs Underweight: OR (95% CI) | 0.617 (0.427 to 0.894) | 0.617 (0.427 to 0.894) | <1e−6 | ✓ PASS |
| BMI group, Overweight vs Underweight: OR (95% CI) | 0.763 (0.510 to 1.141) | 0.763 (0.510 to 1.141) | <1e−6 | ✓ PASS |
| BMI group, Obese vs Underweight: OR (95% CI) | 0.584 (0.392 to 0.871) | 0.584 (0.392 to 0.871) | <1e−6 | ✓ PASS |
| BMI group: joint Wald p (3 df) | 0.023 | 0.023 | <1e−6 | ✓ PASS |
| Chronic disease, Yes vs No: OR (95% CI), p | 1.255 (1.019 to 1.547), 0.033 | 1.255 (1.019 to 1.547), 0.033 | <1e−6 | ✓ PASS |
| Household income 10,000-30,000 vs <10,000: OR (95% CI) | 0.790 (0.597 to 1.046) | 0.790 (0.597 to 1.046) | <1e−6 | ✓ PASS |
| Household income >30,000 vs <10,000: OR (95% CI) | 1.146 (0.898 to 1.462) | 1.146 (0.898 to 1.462) | <1e−6 | ✓ PASS |
| Household income: joint Wald p (2 df) | 0.017 | 0.017 | <1e−6 | ✓ PASS |
| Log-likelihood / AIC / BIC | −1671.940 / 3367.88 / 3429.92 | −1671.940 / 3367.88 / 3429.92 | <1e−6 | ✓ PASS |
| Cut-points θ1 / θ2 / θ3 / θ4 (Tab 3 summary) | −2.0623 / 0.2866 / 0.8430 / 1.1516 | −2.0623 / 0.2866 / 0.8430 / 1.1516 | 3e−9 | ✓ PASS |
| SE of θ1 / θ2 / θ3 / θ4 (Tab 3 summary) | 0.5909 / 0.5880 / 0.5883 / 0.5890 | 0.5909 / 0.5880 / 0.5883 / 0.5890 | <5e−5 (4 decimals shown) | ✓ PASS |
| LR χ² against the thresholds-only model (8 df), p | 22.897, 0.0035 | 22.897, 0.003 | <5e−4 (3 decimals shown) | ✓ PASS |
| McFadden R² | 0.0068 | 0.0068 | <5e−5 (4 decimals shown) | ✓ PASS |
ค่าความต่างคำนวณจากค่าที่ไม่ปัดเศษ (DAPH จากการรันเอนจินจริง) ยกเว้นค่าที่ DAPH ไม่ได้ส่งออกแบบไม่ปัดเศษ (SE ของจุดตัด LR χ² และ McFadden R²) ซึ่งเทียบที่ทศนิยมที่แสดง · ทุกค่าตรงกับ R
Differences use unrounded values (DAPH from a run of the engine itself), except where DAPH outputs only rounded values (cut-point SEs, LR χ², McFadden R²), which are compared at the decimals shown. Every value agrees with R.
4การแปลผลและตัวอย่างInterpretation and Example
อ่าน OR อย่างไร: OR ของตัวแปรหนึ่งคืออัตราส่วนของ odds ที่จะอยู่ในระดับที่สูงกว่า (เทียบกับระดับนั้นหรือต่ำกว่า) ซึ่งมีค่าเดียวกันที่ทุกจุดตัด · Word ของ DAPH เขียนว่า “times the odds of a higher category of Salty food frequency”
Reading the OR: a predictor's OR is the ratio of the odds of being in a higher level (versus that level or lower), the same at every cut-point. The Word report words it as “times the odds of a higher category of Salty food frequency”.
ผลในข้อมูลตัวอย่าง: ผู้มีโรคเรื้อรังมี odds ของการกินเค็มบ่อยกว่าสูงกว่าผู้ไม่มีโรคเรื้อรัง (OR 1.255, 95% CI 1.019 to 1.547, p = 0.033) · กลุ่ม BMI สัมพันธ์กับความถี่การกินเค็ม (joint p = 0.023) โดยกลุ่มน้ำหนักปกติ (OR 0.617, 95% CI 0.427 to 0.894) และกลุ่มอ้วน (OR 0.584, 95% CI 0.392 to 0.871) มี odds ต่ำกว่ากลุ่มน้ำหนักน้อย ส่วนกลุ่มน้ำหนักเกินไม่ต่างอย่างมีนัยสำคัญ (OR 0.763, 95% CI 0.510 to 1.141) · รายได้ครัวเรือนโดยรวมสัมพันธ์กับความถี่การกินเค็ม (joint p = 0.017) แม้ว่าแต่ละระดับเมื่อเทียบกับกลุ่มรายได้ต่ำกว่า 10,000 บาทจะไม่มีนัยสำคัญ (OR 0.790, 95% CI 0.597 to 1.046 และ OR 1.146, 95% CI 0.898 to 1.462) ซึ่งชี้ไปคนละทิศ · อายุ (OR 0.994 ต่อปี, 95% CI 0.979 to 1.009, p = 0.412) และเพศ (OR 1.034, 95% CI 0.832 to 1.285, p = 0.760) ไม่มีนัยสำคัญ ซึ่งไม่ได้แปลว่าไม่มีความสัมพันธ์ ช่วงเชื่อมั่นยังครอบคลุมผลขนาดเล็กได้ทั้งสองทิศ
Results in the example data: patients with a chronic disease had higher odds of eating salty food more often (OR 1.255, 95% CI 1.019 to 1.547, p = 0.033). BMI group was associated with salty food frequency (joint p = 0.023): normal-weight (OR 0.617, 95% CI 0.427 to 0.894) and obese patients (OR 0.584, 95% CI 0.392 to 0.871) had lower odds than underweight patients, while overweight patients did not differ significantly (OR 0.763, 95% CI 0.510 to 1.141). Household income as a whole was associated (joint p = 0.017), although neither higher-income group differed significantly from the under-10,000-Baht group on its own (OR 0.790, 95% CI 0.597 to 1.046, and OR 1.146, 95% CI 0.898 to 1.462), and the two point in opposite directions. Age (OR 0.994 per year, 95% CI 0.979 to 1.009, p = 0.412) and gender (OR 1.034, 95% CI 0.832 to 1.285, p = 0.760) were not significant; this is not evidence of no association, as the intervals still allow small effects either way.
ความเหมาะสมของแบบจำลอง: แบบจำลองดีกว่าแบบจำลองที่ไม่มีตัวแปรอิสระ (LR χ²(8) = 22.90, p = 0.0035) แต่ McFadden R² = 0.0068 แปลว่าตัวแปรชุดนี้อธิบายความต่างของพฤติกรรมได้น้อยมาก จึงใช้ดูความสัมพันธ์ ไม่ใช่การทำนายรายบุคคล · การทดสอบ PO ให้ p = 0.21 ถึง 0.69 ทุกตัวแปร จึงไม่พบหลักฐานว่าข้อตกลง PO ผิด (แต่ไม่ได้พิสูจน์ว่าเป็นจริง) · ข้อมูลเป็นการสังเกต ความสัมพันธ์จึงไม่ใช่เหตุและผล
Model adequacy: the model fits better than the thresholds-only model (LR χ²(8) = 22.90, p = 0.0035), but McFadden R² = 0.0068 means these predictors explain very little of the behaviour, so the model describes associations rather than predicting individuals. The PO tests give p = 0.21 to 0.69 for every variable, so there is no evidence against proportional odds (which does not prove it holds). The data are observational, so the associations are not causal.
ตัวอย่างการเขียนผล: จาก ordinal logistic regression (proportional odds) ที่ปรับอายุ เพศ กลุ่ม BMI และรายได้ครัวเรือน ผู้ป่วยที่มีโรคเรื้อรังมี odds ของการกินอาหารเค็มในระดับที่บ่อยกว่าเป็น 1.255 เท่าของผู้ไม่มีโรคเรื้อรัง (adjusted OR 1.255, 95% CI 1.019 to 1.547, p = 0.033)
Model results sentence: In an ordinal logistic (proportional odds) model adjusted for age, gender, BMI group and household income, patients with a chronic disease had higher odds of reporting more frequent salty food intake than those without (adjusted OR 1.255, 95% CI 1.019 to 1.547, p = 0.033).
📖 References
- Brant, R. (1990). Assessing proportionality in the proportional odds model for ordinal logistic regression. Biometrics, 46(4), 1171–1178. doi:10.2307/2532457
- McCullagh, P. (1980). Regression models for ordinal data. Journal of the Royal Statistical Society: Series B (Methodological), 42(2), 109–127. doi:10.1111/j.2517-6161.1980.tb01109.x
- Peterson, B., & Harrell, F. E., Jr. (1990). Partial proportional odds models for ordinal response variables. Applied Statistics, 39(2), 205–217. doi:10.2307/2347760
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
3.2Multinomial Logistic Regression (RRR reporting)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Multinomial Logistic Regression ใช้เมื่อตัวแปรตามเป็นกลุ่มตั้งแต่ 3 ระดับ และไม่ต้องการให้แบบจำลองบังคับลำดับของระดับ เช่น ชนิดเชื้อก่อโรค วิธีรักษาที่ผู้ป่วยเลือก หรือหมวดภาวะโภชนาการ แบบจำลองเลือกระดับหนึ่งเป็นกลุ่มอ้างอิง แล้วสร้างสมการ logit แยกสำหรับแต่ละระดับที่เหลือเมื่อเทียบกับกลุ่มอ้างอิง (J − 1 สมการ) และรายงานผลเป็น relative risk ratio (RRR) = exp(β) (Agresti, 2013; Hosmer et al., 2013)
Multinomial Logistic Regression is used when the outcome has three or more categories and no order should be imposed on them, for example the type of pathogen, the treatment a patient chooses, or a nutritional-status category. One category is the reference, and a separate logit equation compares each other category with it (J − 1 equations); effects are reported as relative risk ratios (RRR) = exp(β) (Agresti, 2013; Hosmer et al., 2013).
ไม่ควรใช้เมื่อ: ตัวแปรตามมี 2 ระดับ (ใช้ Logistic Regression หัวข้อ 2.1) · ตัวแปรตามมีลำดับและข้อตกลง proportional odds เป็นจริง (Ordered Logistic Regression หัวข้อ 3.1 ใช้ค่าเดียวต่อตัวแปรแทน J − 1 ค่า) · บางระดับมีจำนวนน้อยมาก (ค่าประมาณไม่เสถียร ช่วงเชื่อมั่นกว้าง)
Do not use it when the outcome has two categories (use Logistic Regression, section 2.1), when the categories are ordered and proportional odds holds (Ordered Logistic Regression, section 3.1, needs one estimate per variable instead of J − 1), or when some categories are very small (unstable estimates, wide intervals).
2หลักการและสูตรLogic and Formula
- J, r
- จำนวนระดับของตัวแปรตาม และกลุ่มอ้างอิง (DAPH ใช้ระดับรหัสต่ำสุด ตัวอย่างนี้คือ Underweight)number of outcome categories and the reference category (DAPH uses the lowest code; here Underweight)
- β_jm
- สัมประสิทธิ์ของตัวแปร m ในสมการของระดับ j เทียบกับกลุ่มอ้างอิงcoefficient of predictor m in the equation for category j versus the reference
- W_jG
- joint Wald test ของตัวแปรกลุ่ม G (q ตัวแปรหุ่น) ภายในการเปรียบเทียบ j เทียบกับกลุ่มอ้างอิงเท่านั้นjoint Wald test of categorical variable G (q dummies) within the comparison of j with the reference only
- LR_G
- likelihood-ratio test ของการตัดตัวแปร G ออกจากทุกสมการ (ℓ_−G คือ log-likelihood เมื่อไม่มีตัวแปรนั้น)likelihood-ratio test of dropping variable G from every equation (ℓ_−G is the log-likelihood without it)
- k, n, ℓ_0
- จำนวนคอลัมน์ตัวแปรอิสระ (ไม่รวมค่าคงที่) · จำนวนผู้ป่วย · log-likelihood ของแบบจำลองที่มีแต่ค่าคงที่number of predictor columns (excluding intercepts) · number of patients · log-likelihood of the intercept-only model
ความหมายของ RRR: RRR คืออัตราส่วนของ “ความเสี่ยงสัมพัทธ์ของระดับ j เทียบกับกลุ่มอ้างอิง” เมื่อตัวแปรเพิ่ม 1 หน่วย ซึ่งมีค่าเท่ากับ odds ratio ของระดับ j เทียบกับกลุ่มอ้างอิงในกลุ่มผู้ที่อยู่ในสองระดับนี้ ไม่ใช่อัตราส่วนความเสี่ยง P(Y = j | x + 1) / P(Y = j | x) และเปลี่ยนไปเมื่อเปลี่ยนกลุ่มอ้างอิง
What an RRR is: the factor by which the relative risk of category j versus the reference changes for a one-unit increase in the predictor. It equals the odds ratio of j versus the reference among people in those two categories; it is not the risk ratio P(Y = j | x + 1) / P(Y = j | x), and it changes when the reference category changes.
สิ่งที่ DAPH คำนวณ: maximum likelihood ด้วย Newton-Raphson (ไม่เกิน 100 รอบ) · กลุ่มอ้างอิงของตัวแปรตามและของตัวแปรอิสระแบบกลุ่มคือรหัสต่ำสุด (ถ้าต้องการกลุ่มอ้างอิงอื่น ให้ใช้ Recode ตัวแปร ใน Tab 1 ให้กลุ่มนั้นมีรหัสต่ำสุด) · ตัดแถวที่มีค่าว่าง · ในตาราง แต่ละการเปรียบเทียบมีคอลัมน์ % (ร้อยละของผู้ป่วยในแถวนั้นที่อยู่ในระดับนั้น) RRR (95% CI แบบ Wald) และ p · ตัวแปรต่อเนื่องได้ Wald z ต่อการเปรียบเทียบ · ตัวแปรกลุ่มได้ joint Wald p ต่อการเปรียบเทียบที่แถวชื่อตัวแปร · คอลัมน์ Overall p (LR) คือ LR_G ซึ่งตอบว่าตัวแปรนั้นสัมพันธ์กับตัวแปรตามหรือไม่โดยรวม · Word ใช้ LR_G เป็นเกณฑ์สรุป · DAPH ระบุข้อตกลง IIA (RRR ของสองระดับไม่ควรเปลี่ยนเมื่อตัดระดับอื่นออก) แต่ไม่ได้ทดสอบ ถ้าเรื่องนี้สำคัญ เช่น ระดับเป็นทางเลือกที่ผู้ป่วยเลือก ใช้ Hausman–McFadden test (Hausman & McFadden, 1984)
What DAPH computes: maximum likelihood by Newton-Raphson (at most 100 iterations). The reference of the outcome and of each categorical predictor is the lowest code (for another reference, use Recode Variable in Tab 1 to give that category the lowest code). Rows with missing values are dropped. For each comparison the table shows % (the share of the row's patients in that category), the RRR with its Wald 95% CI, and p: a continuous predictor gets its Wald z test per comparison; a categorical predictor gets one joint Wald p per comparison on its header row. The Overall p (LR) column is LR_G, which answers whether the variable is associated with the outcome as a whole; the Word report uses it for its conclusions. DAPH lists the IIA assumption (the RRR of two categories should not change when another category is removed) but does not test it; where it matters, for example when the categories are alternatives patients choose between, use the Hausman–McFadden test (Hausman & McFadden, 1984).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
nnet (multinom) และ car (Anova)packages nnet (multinom) and car (Anova)# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(nnet) # multinom(): multinomial logistic regression
library(car) # Anova(): likelihood-ratio test of each variable
d$bmi_group <- factor(d$bmi_group, 1:4, c("Underweight", "Normal", "Overweight", "Obese"))
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$income <- factor(d$income, 1:3, c("No income", "<10,000", ">=10,000"))
table(d$bmi_group) # reference outcome = Underweight (lowest code), as in DAPH
fit <- multinom(bmi_group ~ age + gender + chronic + group + income, data = d,
trace = FALSE, maxit = 1000, reltol = 1e-12) # run to full convergence
b <- coef(fit) # one row of coefficients per non-reference outcome
se <- summary(fit)$standard.errors
z <- qnorm(0.975)
rrr <- data.frame(outcome = rep(rownames(b), ncol(b)), term = rep(colnames(b), each = nrow(b)),
RRR = c(exp(b)), lower = c(exp(b - z * se)), upper = c(exp(b + z * se)),
p = c(2 * pnorm(-abs(b / se))))
rrr <- rrr[rrr$term != "(Intercept)", ]
rrr[, 3:6] <- round(rrr[, 3:6], 4)
rrr
V <- vcov(fit)
cf <- setNames(c(t(b)), rownames(V)) # coefficients in the order of vcov()
wald <- function(outcome, term) { # joint Wald test of one variable, one comparison
i <- grep(paste0("^", outcome, ":", term), names(cf))
X2 <- drop(t(cf[i]) %*% solve(V[i, i]) %*% cf[i])
round(c(chisq = X2, df = length(i), p = pchisq(X2, length(i), lower.tail = FALSE)), 4)
}
sapply(c("Normal", "Overweight", "Obese"), wald, term = "income")
Anova(fit) # overall p: LR test of dropping each variable
fit0 <- multinom(bmi_group ~ 1, data = d, trace = FALSE)
LR <- 2 * (as.numeric(logLik(fit)) - as.numeric(logLik(fit0)))
round(c(logLik = as.numeric(logLik(fit)), AIC = AIC(fit), BIC = BIC(fit),
LR_chisq = LR, df = 18, p = pchisq(LR, 18, lower.tail = FALSE),
McFadden_R2 = 1 - as.numeric(logLik(fit)) / as.numeric(logLik(fit0))), 4)
round(100 * prop.table(table(d$chronic, d$bmi_group), 1), 2) # the % columns of the DAPH table
Underweight Normal Overweight Obese
126 543 290 341
outcome term RRR lower upper p
4 Normal age 0.9528 0.9287 0.9776 0.0002
5 Overweight age 0.9083 0.8815 0.9360 0.0000
6 Obese age 0.8940 0.8677 0.9210 0.0000
7 Normal genderFemale 0.9368 0.6169 1.4224 0.7592
8 Overweight genderFemale 0.7821 0.4976 1.2293 0.2868
9 Obese genderFemale 1.3909 0.8803 2.1976 0.1574
10 Normal chronicYes 1.3907 0.9301 2.0794 0.1081
11 Overweight chronicYes 1.5717 1.0130 2.4383 0.0436
12 Obese chronicYes 2.6120 1.6924 4.0313 0.0000
13 Normal groupAPD 0.9624 0.6486 1.4281 0.8490
14 Overweight groupAPD 0.9540 0.6199 1.4681 0.8303
15 Obese groupAPD 1.1143 0.7284 1.7046 0.6179
16 Normal income<10,000 0.5815 0.2223 1.5210 0.2691
17 Overweight income<10,000 0.3511 0.1274 0.9675 0.0430
18 Obese income<10,000 0.7640 0.2804 2.0821 0.5988
19 Normal income>=10,000 0.4797 0.2118 1.0864 0.0782
20 Overweight income>=10,000 0.4079 0.1759 0.9458 0.0366
21 Obese income>=10,000 0.5584 0.2383 1.3085 0.1799
Normal Overweight Obese
chisq 3.2835 4.8370 2.4514
df 2.0000 2.0000 2.0000
p 0.1936 0.0891 0.2936
Analysis of Deviance Table (Type II tests)
Response: bmi_group
LR Chisq Df Pr(>Chisq)
age 75.304 3 3.119e-16 ***
gender 11.889 3 0.007775 **
chronic 27.202 3 5.341e-06 ***
group 1.287 3 0.732287
income 10.797 6 0.094847 .
logLik AIC BIC LR_chisq df p
-1596.0875 3234.1750 3342.7475 126.8572 18.0000 0.0000
McFadden_R2
0.0382
Underweight Normal Overweight Obese
No 11.44 44.51 23.34 20.71
Yes 7.96 39.05 21.29 31.70
| Quantity (Normal / Overweight / Obese, each vs Underweight) | R 4.3.3 | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| Age, per year: RRR (95% CI) | 0.95 (0.93-0.98) / 0.91 (0.88-0.94) / 0.89 (0.87-0.92) | 0.95 (0.93-0.98) / 0.91 (0.88-0.94) / 0.89 (0.87-0.92) | 1e−6 | ✓ PASS |
| Female vs Male: RRR (95% CI) | 0.94 (0.62-1.42) / 0.78 (0.50-1.23) / 1.39 (0.88-2.20) | 0.94 (0.62-1.42) / 0.78 (0.50-1.23) / 1.39 (0.88-2.20) | 1.8e−5 | ✓ PASS |
| Chronic disease, Yes vs No: RRR (95% CI) | 1.39 (0.93-2.08) / 1.57 (1.01-2.44) / 2.61 (1.69-4.03) | 1.39 (0.93-2.08) / 1.57 (1.01-2.44) / 2.61 (1.69-4.03) | 3.1e−5 | ✓ PASS |
| APD vs CAPD: RRR (95% CI) | 0.96 (0.65-1.43) / 0.95 (0.62-1.47) / 1.11 (0.73-1.70) | 0.96 (0.65-1.43) / 0.95 (0.62-1.47) / 1.11 (0.73-1.70) | 1.3e−5 | ✓ PASS |
| Personal income <10,000 vs No income: RRR (95% CI) | 0.58 (0.22-1.52) / 0.35 (0.13-0.97) / 0.76 (0.28-2.08) | 0.58 (0.22-1.52) / 0.35 (0.13-0.97) / 0.76 (0.28-2.08) | 3.9e−5 | ✓ PASS |
| Personal income ≥10,000 vs No income: RRR (95% CI) | 0.48 (0.21-1.09) / 0.41 (0.18-0.95) / 0.56 (0.24-1.31) | 0.48 (0.21-1.09) / 0.41 (0.18-0.95) / 0.56 (0.24-1.31) | 2.1e−5 | ✓ PASS |
| Personal income: joint Wald p per comparison (2 df) | 0.194 / 0.089 / 0.294 | 0.194 / 0.089 / 0.294 | 3e−10 | ✓ PASS |
| Chronic disease: Wald p per comparison | 0.108 / 0.044 / <0.001 | 0.108 / 0.044 / <0.001 | <1e−6 | ✓ PASS |
| Overall p (LR): age / gender / chronic / group / income | <0.001 / 0.008 / <0.001 / 0.732 / 0.095 | <0.001 / 0.008 / <0.001 / 0.732 / 0.095 | 1e−8 | ✓ PASS |
| LR χ² of gender (3 df) / income (6 df) in the Word text | 11.89 / 10.80 | 11.89 / 10.80 | 1e−8 | ✓ PASS |
| Chronic disease = Yes: % Normal / Overweight / Obese | 39.05 / 21.29 / 31.70 | 39.05 / 21.29 / 31.70 | 0 | ✓ PASS |
| Log-likelihood / AIC / BIC | −1596.088 / 3234.18 / 3342.75 | −1596.088 / 3234.18 / 3342.75 | 1e−6 | ✓ PASS |
| LR χ²(18) against the intercept-only model, p · McFadden R² | 126.857, <0.001 · 0.0382 | 126.857, <0.001 · 0.0382 | 1e−6 | ✓ PASS |
ค่าความต่างคำนวณจากค่าที่ไม่ปัดเศษ (DAPH จากการรันเอนจินจริง) · ความต่างของช่วงเชื่อมั่นมาจาก DAPH ใช้ 1.96 ส่วน R ใช้ qnorm(0.975) = 1.959964
Differences use unrounded values (DAPH from a run of the engine itself). The small CI differences come from DAPH using 1.96 where R uses qnorm(0.975) = 1.959964.
4การแปลผลและตัวอย่างInterpretation and Example
อ่านจากภาพรวมก่อน: ใช้ Overall p (LR) ตัดสินว่าตัวแปรสัมพันธ์กับกลุ่ม BMI หรือไม่ แล้วจึงดู RRR ว่าการเปรียบเทียบใดเป็นแหล่งของความสัมพันธ์ · อายุ (LR χ²(3) = 75.30, p < 0.001): อายุมากขึ้นทุก 1 ปี โอกาสอยู่ในกลุ่มปกติ (RRR 0.95, 95% CI 0.93 to 0.98) กลุ่มน้ำหนักเกิน (RRR 0.91, 95% CI 0.88 to 0.94) และกลุ่มอ้วน (RRR 0.89, 95% CI 0.87 to 0.92) เมื่อเทียบกับกลุ่มน้ำหนักน้อยลดลง คือผู้ป่วยสูงอายุมีแนวโน้มอยู่ในกลุ่มน้ำหนักน้อยมากกว่า · โรคเรื้อรัง (LR χ²(3) = 27.20, p < 0.001): RRR ของกลุ่มอ้วน 2.61 (95% CI 1.69 to 4.03) และกลุ่มน้ำหนักเกิน 1.57 (95% CI 1.01 to 2.44) ส่วนกลุ่มปกติไม่มีนัยสำคัญ (RRR 1.39, 95% CI 0.93 to 2.08)
Read the whole variable first: use Overall p (LR) to decide whether a variable is associated with BMI group, then use the RRRs to see which comparisons carry the association. Age (LR χ²(3) = 75.30, p < 0.001): each additional year lowers the relative risk of being normal (RRR 0.95, 95% CI 0.93 to 0.98), overweight (RRR 0.91, 95% CI 0.88 to 0.94) or obese (RRR 0.89, 95% CI 0.87 to 0.92) rather than underweight, so older patients were more often underweight. Chronic disease (LR χ²(3) = 27.20, p < 0.001): RRR 2.61 for obese (95% CI 1.69 to 4.03) and 1.57 for overweight (95% CI 1.01 to 2.44), while the normal-weight comparison was not significant (RRR 1.39, 95% CI 0.93 to 2.08).
เพศสัมพันธ์กับกลุ่ม BMI โดยรวม (LR χ²(3) = 11.89, p = 0.008) แม้ไม่มีการเปรียบเทียบใดกับกลุ่มน้ำหนักน้อยที่มีนัยสำคัญ เพราะความต่างอยู่ระหว่างกลุ่มที่ไม่ใช่กลุ่มอ้างอิง (RRR ของผู้หญิงในกลุ่มอ้วน 1.39 และกลุ่มน้ำหนักเกิน 0.78 ชี้คนละทิศ) · กลุ่มการรักษา APD เทียบ CAPD ไม่สัมพันธ์กับกลุ่ม BMI (p = 0.732) · รายได้ส่วนบุคคลไม่มีนัยสำคัญโดยรวม (LR χ²(6) = 10.80, p = 0.095) และช่วงเชื่อมั่นกว้างมาก (เช่น RRR 0.35, 95% CI 0.13 to 0.97) เพราะกลุ่มอ้างอิงของทั้งตัวแปรตาม (Underweight 126 ราย) และตัวแปรอิสระ (No income) มีจำนวนน้อย จึงไม่ควรตีความการเปรียบเทียบรายคู่ที่ p < 0.05 เมื่อการทดสอบโดยรวมไม่มีนัยสำคัญ
Gender was associated with BMI group as a whole (LR χ²(3) = 11.89, p = 0.008) although no comparison with underweight was significant: the difference lies between the non-reference groups (women's RRR 1.39 for obese and 0.78 for overweight point in opposite directions). Treatment group (APD vs CAPD) was not associated with BMI group (p = 0.732). Personal income was not significant overall (LR χ²(6) = 10.80, p = 0.095), and its intervals are very wide (for example RRR 0.35, 95% CI 0.13 to 0.97) because the reference groups of both the outcome (126 underweight patients) and the predictor (No income) are small; a single comparison with p < 0.05 should not be read as a finding when the variable's overall test is not significant.
ความเหมาะสมของแบบจำลอง: LR χ²(18) = 126.86, p < 0.001 แต่ McFadden R² = 0.0382 (McFadden, 1974) ต่ำ ตัวแปรชุดนี้อธิบายกลุ่ม BMI ได้น้อย · แบบจำลองมี 21 สัมประสิทธิ์ (3 สมการ × 7) จึงต้องมีจำนวนผู้ป่วยในทุกระดับเพียงพอ · ข้อมูลเป็นการสังเกต ความสัมพันธ์ไม่ใช่เหตุและผล
Model adequacy: LR χ²(18) = 126.86, p < 0.001, but McFadden R² = 0.0382 (McFadden, 1974) is low: these predictors explain little of BMI group. The model has 21 coefficients (3 equations × 7), so every category needs enough patients. The data are observational, so the associations are not causal.
ตัวอย่างการเขียนผล: จาก multinomial logistic regression ที่ใช้กลุ่มน้ำหนักน้อยเป็นกลุ่มอ้างอิง โรคเรื้อรังสัมพันธ์กับกลุ่ม BMI (LR χ²(3) = 27.20, p < 0.001) ผู้มีโรคเรื้อรังมีโอกาสอยู่ในกลุ่มอ้วนเมื่อเทียบกับกลุ่มน้ำหนักน้อยสูงกว่าผู้ไม่มีโรคเรื้อรัง (RRR 2.61, 95% CI 1.69 to 4.03)
Model results sentence: In a multinomial logistic regression with underweight as the reference category, chronic disease was associated with BMI group (LR χ²(3) = 27.20, p < 0.001); patients with a chronic disease had a higher relative risk of being obese rather than underweight (RRR 2.61, 95% CI 1.69 to 4.03).
📖 References
- Agresti, A. (2013). Categorical data analysis (3rd ed.). Wiley. ISBN 978-0-470-46363-5.
- Hausman, J., & McFadden, D. (1984). Specification tests for the multinomial logit model. Econometrica, 52(5), 1219–1240. doi:10.2307/1910997
- Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied logistic regression (3rd ed.). Wiley. doi:10.1002/9781118548387
- McFadden, D. (1974). Conditional logit analysis of qualitative choice behavior. In P. Zarembka (Ed.), Frontiers in econometrics (pp. 105–142). Academic Press. ISBN 978-0-12-776150-3.
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 4 — ตัวแปรนับ (Count)Chapter 4 — Count Outcomes ✓ Verified
ตัวแปรตามเป็นจำนวนครั้งของเหตุการณ์ต่อคน (หรือต่อพื้นที่หรือช่วงเวลา) เช่น จำนวนครั้งที่ติดเชื้อในช่องท้อง · ใส่ระยะเวลาติดตาม (person-time) เป็น offset เพื่อวิเคราะห์อัตรา และรายงาน incidence rate ratio (IRR) · หัวข้อ 4.1 Poisson ซึ่ง DAPH เปลี่ยนเป็น negative binomial อัตโนมัติเมื่อ Pearson χ²/df หรือ deviance/df เกิน 1.5 (ตรงกับ R glm และ MASS::glm.nb) · หัวข้อ 4.2 Poisson mixed model ที่มี random intercept สำหรับข้อมูลเป็นกลุ่ม เช่น ผู้ป่วยในโรงพยาบาลเดียวกัน (ตรงกับ R lme4::glmer)
Outcomes that count events per person (or per area or period), such as peritonitis episodes. Follow-up time (person-time) enters as an offset so that rates are analysed and incidence rate ratios (IRR) reported. Section 4.1: Poisson regression, which DAPH switches to negative binomial when the Pearson χ²/df or deviance/df exceeds 1.5 (matching R glm and MASS::glm.nb). Section 4.2: a random-intercept Poisson mixed model for clustered data such as patients within hospitals (matching R lme4::glmer).
4.1Poisson & Negative Binomial Regression
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Poisson regression ใช้กับตัวแปรตามที่เป็นจำนวนครั้ง (0, 1, 2, …) เช่น จำนวนครั้งที่ติดเชื้อหรือจำนวนครั้งที่นอนโรงพยาบาล เมื่อแต่ละคนถูกติดตามนานไม่เท่ากัน ให้ใส่ระยะเวลาติดตามเป็น offset แบบจำลองจึงเป็นแบบจำลองของอัตรา (จำนวนครั้งต่อคน-ปี) และ exp(β) คือ incidence rate ratio (IRR) · Poisson กำหนดให้ความแปรปรวนเท่ากับค่าเฉลี่ย ถ้าข้อมูลกระจายมากกว่านั้น (overdispersion) ความคลาดเคลื่อนมาตรฐาน (SE) จะต่ำเกินจริงและค่า p เล็กเกินจริง จึงใช้ negative binomial (NB) regression ซึ่งมีพารามิเตอร์การกระจาย α เพิ่ม (Nelder & Wedderburn, 1972; Cameron & Trivedi, 2013)
Poisson regression models a count outcome (0, 1, 2, …) such as the number of infections or hospital admissions. When people are followed for different lengths of time, the follow-up time enters as an offset, so the model describes a rate (events per person-year) and exp(β) is the incidence rate ratio (IRR). Poisson assumes the variance equals the mean; when the data vary more (overdispersion) the standard errors (SE) are too small and the p values too small, so negative binomial (NB) regression, which adds a dispersion parameter α, is used instead (Nelder & Wedderburn, 1972; Cameron & Trivedi, 2013).
ไม่ควรใช้เมื่อ: ตัวแปรตามเป็นค่าต่อเนื่อง หรือเป็นสัดส่วนที่มีตัวหารชัดเจน (ใช้แบบจำลอง binomial) · มีการนับซ้ำในคนเดียวกันหรือข้อมูลเป็นกลุ่ม เช่น ผู้ป่วยในโรงพยาบาลเดียวกัน (ใช้หัวข้อ 4.2) · มีค่าศูนย์มากเกินกว่าที่ NB อธิบายได้ (ต้องใช้ zero-inflated model ซึ่ง DAPH ยังไม่มี)
Do not use it when the outcome is continuous or a proportion with a known denominator (use a binomial model), when counts are repeated within people or clustered, for example patients within hospitals (use section 4.2), or when there are more zeros than NB can describe (a zero-inflated model is needed; DAPH does not offer one).
2หลักการและสูตรLogic and Formula
- μ_i, t_i
- จำนวนครั้งที่คาดไว้ของคนที่ i และระยะเวลาติดตาม (offset = ln t_i)expected count of person i and follow-up time (offset = ln t_i)
- α, θ
- พารามิเตอร์การกระจายของ NB (α = 1/θ; R รายงาน θ)NB dispersion parameter (α = 1/θ; R reports θ)
- n, p
- จำนวนผู้ป่วย และจำนวนสัมประสิทธิ์รวมค่าคงที่ (n − p = degrees of freedom ของ residual)number of patients and number of coefficients including the intercept (n − p = residual degrees of freedom)
- X², D
- Pearson χ² และ deviance ของแบบจำลอง PoissonPearson χ² and deviance of the Poisson fit
- ℓ, ℓ_−G, q
- log-likelihood ของแบบจำลอง และเมื่อตัดตัวแปร G (q ตัวแปรหุ่น) ออกlog-likelihood of the model, and without variable G (q dummy columns)
- IR_g
- อัตราการเกิดดิบของกลุ่ม g ต่อ 100 คน-ปีcrude incidence rate of group g per 100 person-years
สิ่งที่ DAPH คำนวณ: (1) ประมาณ Poisson ด้วย IRLS พร้อม offset = ln(ตัวแปร person-time ที่เลือก ซึ่งต้องมากกว่า 0) (2) ถ้า X²/(n − p) หรือ D/(n − p) ของ Poisson มากกว่า 1.5 จะเปลี่ยนเป็น NB และประมาณ α ด้วย maximum likelihood (หาค่า α ที่ทำให้ likelihood สูงสุด โดยประมาณ β ด้วย IRLS ที่แต่ละค่า α) ถ้า α ที่ดีที่สุดคือ 0 จะใช้ Poisson ต่อ (3) 95% CI แบบ Wald (4) ตัวแปรต่อเนื่องใช้ Wald z ส่วนตัวแปรกลุ่มใช้ LR_G โดยประมาณ α ใหม่ในแบบจำลองที่ตัดตัวแปรออก (5) AIC นับ α เป็นพารามิเตอร์ด้วย (6) ตารางมี Crude IRR (ทีละตัวแปร ด้วยตระกูลเดียวกัน) คู่กับ Adjusted IRR และอัตราดิบต่อ 100 คน-ปีของแต่ละกลุ่ม ซึ่ง DAPH แปลงหน่วยเป็นปีเมื่อรู้หน่วยของ offset (จากหน่วยเวลาที่เลือกเมื่อให้ DAPH คำนวณ person-time จากวันที่ หรือจากชื่อตัวแปร เช่น person_years, follow_up_days) (7) Word บอกชื่อแบบจำลองที่ใช้จริง เหตุผลที่เปลี่ยนเป็น NB และค่า α (SE) ไว้ใต้ตาราง ส่วนสรุปใน Tab 3 ไม่แสดง α · DAPH ไม่ได้ทดสอบ α = 0 ด้วย LR (สูตรสุดท้ายข้างบน) เกณฑ์ 1.5 เป็นเกณฑ์ตัดสินเชิงปฏิบัติ
What DAPH computes: (1) Poisson by IRLS with offset = ln(the chosen person-time variable, which must be above 0); (2) if the Poisson X²/(n − p) or D/(n − p) exceeds 1.5 it switches to NB and estimates α by maximum likelihood (the α that maximises the likelihood, with β fitted by IRLS at each α); if the best α is 0 it keeps Poisson; (3) 95% CIs are Wald intervals; (4) a continuous predictor's p is the Wald z test and a categorical predictor's p is LR_G with α re-estimated in the reduced model; (5) the AIC counts α as a parameter; (6) the table shows the crude IRR (one variable at a time, same family) beside the adjusted IRR, and each group's crude rate per 100 person-years, converted to years when the offset's unit is known (the time unit chosen when DAPH calculates person-time from dates, or the variable name such as person_years or follow_up_days). (7) The Word report names the model actually fitted, explains the switch to NB and gives α (SE) under the table; the Tab 3 summary does not show α. DAPH does not run the LR test of α = 0 (the last formula above); the 1.5 cut-off is a practical decision rule.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
glm (Poisson) และแพ็กเกจ MASS (glm.nb)R glm (Poisson) and package MASS (glm.nb)# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(MASS) # glm.nb(): negative binomial with theta by maximum likelihood
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
c(events = sum(d$n_peritonitis), person_years = sum(d$person_years))
round(100 * tapply(d$n_peritonitis, d$group, sum) / tapply(d$person_years, d$group, sum), 2) # IR per 100 person-years
f <- n_peritonitis ~ group + age + gender + chronic + offset(log(person_years))
pois <- glm(f, family = poisson, data = d)
round(c(deviance_df = deviance(pois) / df.residual(pois),
pearson_df = sum(residuals(pois, type = "pearson")^2) / df.residual(pois)), 4)
nb <- glm.nb(f, data = d) # chosen because Pearson chi-square/df > 1.5
round(c(theta = nb$theta, alpha = 1 / nb$theta, SE_alpha = nb$SE.theta / nb$theta^2,
logLik = as.numeric(logLik(nb)), AIC = AIC(nb),
deviance_df = deviance(nb) / df.residual(nb)), 4)
round(cbind(IRR = exp(coef(nb)), exp(confint.default(nb)),
p = coef(summary(nb))[, 4]), 4)
round(exp(10 * coef(nb)["age"]), 4) # IRR for 10 years of age
drop_lr <- function(term) { # LR test of one variable, theta re-estimated
nb_red <- glm.nb(update(f, paste(". ~ . -", term)), data = d)
a <- anova(nb_red, nb)
round(c(LR = a[2, "LR stat."], df = a[2, " df"], p = a[2, "Pr(Chi)"]), 4)
}
sapply(c("group", "gender", "chronic"), drop_lr)
nb0 <- glm.nb(n_peritonitis ~ 1 + offset(log(person_years)), data = d)
LR <- 2 * (as.numeric(logLik(nb)) - as.numeric(logLik(nb0)))
round(c(LR_chisq = LR, df = 4, p = pchisq(LR, 4, lower.tail = FALSE)), 4)
crude <- sapply(c("group", "age", "gender", "chronic"), function(v)
exp(coef(glm.nb(reformulate(c(v, "offset(log(person_years))"), "n_peritonitis"), data = d))[2]))
round(crude, 4) # crude IRR: one variable at a time, same family
# Extra check (not computed by DAPH): LR test of alpha = 0 (Poisson inside NB);
# alpha cannot be negative, so the p value is half the chi-square(1) tail
LR_a <- 2 * (as.numeric(logLik(nb)) - as.numeric(logLik(pois)))
round(c(LR = LR_a, p = 0.5 * pchisq(LR_a, 1, lower.tail = FALSE)), 4)
events person_years
1648.00 2389.42
CAPD APD
94.06 41.34
deviance_df pearson_df
1.6834 1.7840
theta alpha SE_alpha logLik AIC deviance_df
1.5778 0.6338 0.0649 -1845.8877 3703.7753 0.9858
IRR 2.5 % 97.5 % p
(Intercept) 0.1856 0.0936 0.3680 0.0000
groupAPD 0.4514 0.3916 0.5202 0.0000
age 1.0219 1.0120 1.0318 0.0000
genderFemale 0.9421 0.8152 1.0889 0.4197
chronicYes 1.3163 1.1460 1.5118 0.0001
age
1.2415
group gender chronic
LR 115.9794 0.6465 14.8513
df 1.0000 1.0000 1.0000
p 0.0000 0.4214 0.0001
LR_chisq df p
153.7148 4.0000 0.0000
group.groupAPD age.age gender.genderFemale chronic.chronicYes
0.4452 1.0247 1.0222 1.3933
LR p
284.6967 0.0000
| Quantity | R 4.3.3 | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| Events / person-years; IR per 100 person-years CAPD / APD | 1648 / 2389.42; 94.06 / 41.34 | 1,648 / 2,389.4; 94.06 / 41.34 | 0 | ✓ PASS |
| Poisson fit: Pearson χ²/df / deviance/df | 1.784 / 1.683 | 1.784 / 1.683 | <5e−5 | ✓ PASS |
| Model used | NB (Pearson χ²/df > 1.5) | Negative binomial | — | ✓ PASS |
| α (θ) by maximum likelihood · SE(α) | 0.634 (θ 1.5778) · 0.065 | 0.634 · 0.065 (Word note); θ 1.5778 (response data) | 4e−8 · 9.9e−6 | ✓ PASS |
| NB log-likelihood / AIC (α counted) | −1845.888 / 3703.78 | −1845.888 / 3703.78 | 3e−7 | ✓ PASS |
| APD vs CAPD: adjusted IRR (95% CI), LR p | 0.45 (0.39 to 0.52), <0.001 | 0.45 (0.39 to 0.52), <0.001 | 1e−8 | ✓ PASS |
| Age per year: adjusted IRR (95% CI), Wald p | 1.02 (1.01 to 1.03), <0.001 | 1.02 (1.01 to 1.03), <0.001 | 1e−8 | ✓ PASS |
| Female vs Male: adjusted IRR (95% CI), LR p | 0.94 (0.82 to 1.09), 0.421 | 0.94 (0.82 to 1.09), 0.421 | 1e−8 | ✓ PASS |
| Chronic disease Yes vs No: adjusted IRR (95% CI), LR p | 1.32 (1.15 to 1.51), <0.001 | 1.32 (1.15 to 1.51), <0.001 | 1e−8 | ✓ PASS |
| Crude IRR: group / age / gender / chronic | 0.45 / 1.02 / 1.02 / 1.39 | 0.45 / 1.02 / 1.02 / 1.39 | <5e−3 | ✓ PASS |
| LR χ²(4) against the intercept-only NB model · NB deviance/df | 153.715 · 0.986 | 153.715 · 0.986 | 2e−4 | ✓ PASS |
ค่าความต่างคำนวณจากค่าที่ไม่ปัดเศษ (DAPH จากการรันเอนจินจริง) · Crude IRR ของ DAPH แสดง 2 ตำแหน่ง จึงเทียบได้ที่ความละเอียดนั้น · SE(α) ต่างกันเล็กน้อยเพราะ R กับ DAPH หยุดการวนซ้ำที่จุดต่างกันเล็กน้อย (เกณฑ์ยอมรับ 1×10⁻⁴)
Differences use unrounded values (DAPH from a run of the engine itself). DAPH prints the crude IRRs to 2 decimals, so they are compared at that precision. SE(α) differs slightly because R and DAPH stop their iterations at slightly different points (tolerance 1×10⁻⁴).
4การแปลผลและตัวอย่างInterpretation and Example
การเลือกแบบจำลอง: แบบจำลอง Poisson มี Pearson χ²/df = 1.78 (มากกว่า 1.5) DAPH จึงใช้ NB ซึ่งได้ α = 0.634 การทดสอบ α = 0 ใน R ยืนยันว่ามี overdispersion (LR = 284.70, p < 0.001) และหลังใช้ NB แล้ว deviance/df = 0.986 ใกล้ 1
Choice of model: the Poisson fit had Pearson χ²/df = 1.78 (above 1.5), so DAPH used NB, with α = 0.634. The R test of α = 0 confirms the overdispersion (LR = 284.70, p < 0.001), and after the NB fit the deviance/df is 0.986, close to 1.
ผล: APD มีอัตราการติดเชื้อในช่องท้องต่ำกว่า CAPD (adjusted IRR 0.45, 95% CI 0.39 to 0.52, p < 0.001) คืออัตราต่ำกว่าประมาณร้อยละ 55 เมื่อปรับอายุ เพศ และโรคเรื้อรัง (อัตราดิบ 41.34 เทียบกับ 94.06 ครั้งต่อ 100 คน-ปี) · อายุมากขึ้นทุก 1 ปี อัตราเพิ่มขึ้น 1.02 เท่า (95% CI 1.01 to 1.03, p < 0.001) หรือ 1.24 เท่าเมื่ออายุต่างกัน 10 ปี · ผู้มีโรคเรื้อรังมีอัตราสูงกว่า 1.32 เท่า (95% CI 1.15 to 1.51, p < 0.001) · เพศไม่มีนัยสำคัญ (IRR 0.94, 95% CI 0.82 to 1.09, p = 0.421) ซึ่งไม่ได้แปลว่าอัตราเท่ากัน
Results: APD had a lower peritonitis rate than CAPD (adjusted IRR 0.45, 95% CI 0.39 to 0.52, p < 0.001), about 55% lower after adjusting for age, gender and chronic disease (crude rates 41.34 versus 94.06 episodes per 100 person-years). Each additional year of age multiplied the rate by 1.02 (95% CI 1.01 to 1.03, p < 0.001), that is 1.24 for a 10-year difference. Patients with a chronic disease had a 1.32 times higher rate (95% CI 1.15 to 1.51, p < 0.001). Gender was not significant (IRR 0.94, 95% CI 0.82 to 1.09, p = 0.421), which does not mean the rates are equal.
ข้อจำกัด: ข้อมูลเป็นการสังเกต ผู้ป่วยไม่ได้ถูกสุ่มเข้า APD หรือ CAPD ความต่างอาจมาจากปัจจัยที่ไม่ได้วัด (confounding by indication) จึงสรุปเป็นความสัมพันธ์ ไม่ใช่ผลของการรักษา · ถ้าผู้ป่วยจากโรงพยาบาลเดียวกันคล้ายกัน ให้ดูหัวข้อ 4.2
Limitations: the data are observational; patients were not randomised to APD or CAPD, so the difference may reflect unmeasured factors (confounding by indication) and is an association, not a treatment effect. If patients from the same hospital resemble each other, see section 4.2.
ตัวอย่างการเขียนผล: จาก negative binomial regression ที่ใช้ log ของระยะเวลาติดตาม (ปี) เป็น offset และปรับอายุ เพศ และโรคเรื้อรัง ผู้ป่วย APD มีอัตราการติดเชื้อในช่องท้องเป็น 0.45 เท่าของผู้ป่วย CAPD (adjusted IRR 0.45, 95% CI 0.39 to 0.52, p < 0.001) · ใช้ NB เพราะแบบจำลอง Poisson มี overdispersion (Pearson χ²/df = 1.78)
Model results sentence: In a negative binomial regression with log follow-up time (years) as the offset, adjusted for age, gender and chronic disease, patients on APD had 0.45 times the peritonitis rate of patients on CAPD (adjusted IRR 0.45, 95% CI 0.39 to 0.52, p < 0.001); the negative binomial model was used because the Poisson model was overdispersed (Pearson χ²/df = 1.78).
📖 References
- Cameron, A. C., & Trivedi, P. K. (2013). Regression analysis of count data (2nd ed.). Cambridge University Press. doi:10.1017/CBO9781139013567
- Nelder, J. A., & Wedderburn, R. W. M. (1972). Generalized linear models. Journal of the Royal Statistical Society: Series A (General), 135(3), 370–384. doi:10.2307/2344614
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
4.2Mixed-Effect / GEE Poisson Regression
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
เมื่อข้อมูลนับมาจากผู้ป่วยที่อยู่เป็นกลุ่ม (cluster) เช่น ผู้ป่วยในโรงพยาบาลเดียวกัน ข้อมูลในกลุ่มเดียวกันมักคล้ายกัน Poisson regression ธรรมดา (หัวข้อ 4.1) จึงให้ความคลาดเคลื่อนมาตรฐาน (SE) ต่ำเกินจริง DAPH ใช้ Poisson mixed model (generalized linear mixed model, GLMM) ที่มี random intercept หนึ่งค่าต่อกลุ่ม (Breslow & Clayton, 1993) ค่า exp(β) คือ incidence rate ratio (IRR) ของผู้ป่วยที่อยู่ในกลุ่มเดียวกัน (cluster-specific) · อีกแนวทางคือ GEE (generalized estimating equations) ซึ่งให้ IRR เฉลี่ยของประชากร (population-averaged) (Liang & Zeger, 1986; Zeger et al., 1988) DAPH ยังไม่มี GEE สำหรับตัวแปรนับ จึงแสดงไว้เป็นสคริปต์ R เพื่อเปรียบเทียบเท่านั้น
When counts come from patients grouped in clusters, for example patients of the same hospital, patients within a cluster tend to resemble each other, and ordinary Poisson regression (section 4.1) gives standard errors (SE) that are too small. DAPH fits a Poisson mixed model (generalized linear mixed model, GLMM) with one random intercept per cluster (Breslow & Clayton, 1993); exp(β) is the incidence rate ratio (IRR) for patients within the same cluster (cluster-specific). The alternative, GEE (generalized estimating equations), gives a population-averaged IRR (Liang & Zeger, 1986; Zeger et al., 1988); DAPH does not offer GEE for counts, so it appears here only as an R script for comparison.
ข้อควรระวัง: ถ้ามีกลุ่มน้อย (DAPH เตือนเมื่อน้อยกว่า 5 กลุ่ม) ความแปรปรวนระหว่างกลุ่มจะประมาณได้ไม่แม่น · ถ้ายังมี overdispersion หลังใส่ random intercept ควรใช้ negative binomial mixed model ซึ่ง DAPH ยังไม่มี
Cautions: with few clusters (DAPH warns below 5) the between-cluster variance is poorly estimated; if overdispersion remains after the random intercept, a negative binomial mixed model is needed, which DAPH does not yet offer.
2หลักการและสูตรLogic and Formula
- b_j, σ²
- random intercept ของกลุ่ม j และความแปรปรวนระหว่างกลุ่มบนสเกล log ของอัตราrandom intercept of cluster j and the between-cluster variance on the log-rate scale
- t_ij
- person-time ของผู้ป่วย i ในกลุ่ม j (offset = ln t)person-time of patient i in cluster j (offset = ln t)
- λ
- จำนวนครั้งที่คาดไว้ “โดยทั่วไป” — DAPH ใช้ค่าเฉลี่ยของ ln t + x′β̂ ทุกแถวบวก σ²/2the “typical” expected count: DAPH uses the mean of ln t + x′β̂ over all rows plus σ²/2
- φ, μ̂_ij
- อัตราส่วน Pearson χ²/df ที่ค่าคาดหมายแบบมีเงื่อนไข (รวม b_j ที่ทำนายได้) · ค่าใกล้ 1 แปลว่าไม่มี overdispersion เหลือPearson χ²/df at the conditional means (including the predicted b_j); a value near 1 means no overdispersion is left
- p, n, J, m̄
- จำนวนสัมประสิทธิ์คงที่รวมค่าคงที่ · จำนวนผู้ป่วย · จำนวนกลุ่ม · ขนาดกลุ่มเฉลี่ย · Deff = design effectnumber of fixed coefficients including the intercept · patients · clusters · average cluster size · Deff = design effect
สิ่งที่ DAPH คำนวณ: maximum likelihood โดยประมาณอินทิกรัลด้วย Laplace approximation (adaptive Gauss–Hermite 1 จุด = nAGQ 1 แบบเดียวกับค่าเริ่มต้นของ R lme4::glmer) หาค่าสูงสุดด้วย L-BFGS-B แล้วตามด้วย Newton · SE จาก observed information (Hessian เชิงตัวเลข) · 95% CI แบบ Wald · ค่า p ของตัวแปรต่อเนื่องและตัวแปรกลุ่ม 2 ระดับ = Wald z ตัวแปรกลุ่มตั้งแต่ 3 ระดับ = joint Wald χ² · ตัดแถวที่มีค่าว่างในตัวแปรใดก็ได้รวมทั้งตัวแปรกลุ่ม · offset = ln(person-time) · รายงานความแปรปรวนและ SD ระหว่างกลุ่ม การทดสอบ σ² = 0 (p เป็นครึ่งหนึ่งของ χ²₁ เพราะ σ² อยู่ที่ขอบของช่วงค่า) ICC พร้อม design effect และ φ พร้อมคำเตือนเมื่อ φ สูงกว่าเกณฑ์ปกติ ทั้งใน Tab 3 และในหมายเหตุใต้ตารางของ Word
What DAPH computes: maximum likelihood with the integral approximated by the Laplace approximation (adaptive Gauss–Hermite with one node, nAGQ = 1, the default of R lme4::glmer), maximised by L-BFGS-B followed by Newton steps. SEs come from the observed information (numerical Hessian); 95% CIs are Wald intervals. A continuous or two-level categorical predictor's p is the Wald z test; a categorical predictor with three or more levels gets a joint Wald χ². Rows with a missing value in any used variable, including the cluster variable, are dropped; the offset is ln(person-time). DAPH reports the between-cluster variance and SD, the test of σ² = 0 (p is half the χ²₁ tail because σ² lies on the boundary of its range), the ICC with the design effect, and φ with a warning when it is above the usual limit, both in Tab 3 and in the note under the Word table.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
lme4 (glmer)package lme4 (glmer)# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(lme4) # glmer(): generalized linear mixed model
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
d <- d[!is.na(d$hos), ] # DAPH drops the 3 patients without a hospital code
d$hos <- factor(d$hos)
d$age70 <- d$age - 70 # age centred at 70: same IRR per year, no scaling warning
c(n = nrow(d), hospitals = nlevels(d$hos), events = sum(d$n_peritonitis),
person_years = sum(d$person_years))
fit <- glmer(n_peritonitis ~ group + age70 + gender + chronic + offset(log(person_years)) +
(1 | hos), family = poisson, data = d, nAGQ = 1) # Laplace, as DAPH
b <- fixef(fit); se <- sqrt(diag(vcov(fit)))
round(cbind(IRR = exp(b), lower = exp(b - qnorm(0.975) * se),
upper = exp(b + qnorm(0.975) * se), p = 2 * pnorm(-abs(b / se))), 4)
s2 <- VarCorr(fit)$hos[1] # between-hospital variance of the log rate
pois <- glm(n_peritonitis ~ group + age70 + gender + chronic + offset(log(person_years)),
family = poisson, data = d)
LR <- 2 * (as.numeric(logLik(fit)) - as.numeric(logLik(pois)))
eta <- drop(model.matrix(fit) %*% b) + log(d$person_years)
v1 <- log(1 + 1 / exp(mean(eta) + s2 / 2)) # count-scale level-1 variance (as DAPH)
round(c(var_between = s2, SD = sqrt(s2), logLik = as.numeric(logLik(fit)),
AIC = AIC(fit), BIC = BIC(fit), LR = LR, p_LR = 0.5 * pchisq(LR, 1, lower.tail = FALSE),
ICC = s2 / (s2 + v1),
dispersion = sum(residuals(fit, type = "pearson")^2) / (nrow(d) - length(b) - 1)), 4)
m_bar <- nrow(d) / nlevels(d$hos) # average patients per hospital
deff <- 1 + (m_bar - 1) * s2 / (s2 + v1) # design effect, as DAPH
round(c(m_bar = m_bar, design_effect = deff, sqrt_deff = sqrt(deff)), 2)
geepack ต่อจากสคริปต์ข้างบนGEE Poisson for comparison (not in DAPH), package geepack, continuing the script above# Population-averaged alternative (not offered by DAPH): GEE Poisson, exchangeable
# working correlation within hospital, robust (sandwich) SE
library(geepack)
d <- d[order(d$hos), ] # geeglm needs the rows of a cluster together
gee <- geeglm(n_peritonitis ~ group + age70 + gender + chronic + offset(log(person_years)),
id = hos, family = poisson, corstr = "exchangeable", data = d)
bg <- coef(gee); sg <- sqrt(diag(vcov(gee)))
round(cbind(IRR = exp(bg), lower = exp(bg - qnorm(0.975) * sg),
upper = exp(bg + qnorm(0.975) * sg)), 4)
n hospitals events person_years
1297.00 7.00 1644.00 2383.73
IRR lower upper p
(Intercept) 0.8486 0.7503 0.9596 0.0089
groupAPD 0.4492 0.4034 0.5002 0.0000
age70 1.0191 1.0123 1.0260 0.0000
genderFemale 0.9645 0.8703 1.0689 0.4906
chronicYes 1.3448 1.2182 1.4846 0.0000
var_between SD logLik AIC BIC LR
0.0062 0.0788 -1981.9019 3975.8037 4006.8106 3.2242
p_LR ICC dispersion
0.0363 0.0087 1.7727
m_bar design_effect sqrt_deff
185.29 2.61 1.62
IRR lower upper
(Intercept) 0.8284 0.6912 0.9929
groupAPD 0.4486 0.3925 0.5126
age70 1.0189 1.0114 1.0265
genderFemale 0.9612 0.9017 1.0245
chronicYes 1.3385 1.1237 1.5943
| Quantity | R 4.3.3 | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| Patients / hospitals / events / person-years | 1297 / 7 / 1644 / 2383.73 | 1,297 / 7 / 1,644 / 2,383.7 | 0 | ✓ PASS |
| APD vs CAPD: IRR (95% CI), p | 0.449 (0.403 to 0.500), <0.001 | 0.449 (0.403 to 0.500), <0.001 | 1.6e−5 | ✓ PASS |
| Age per year: IRR (95% CI), p | 1.019 (1.012 to 1.026), <0.001 | 1.019 (1.012 to 1.026), <0.001 | 2e−6 | ✓ PASS |
| Female vs Male: IRR (95% CI), p | 0.965 (0.870 to 1.069), 0.491 | 0.965 (0.870 to 1.069), 0.491 | 1.3e−4 | ✓ PASS |
| Chronic disease Yes vs No: IRR (95% CI), p | 1.345 (1.218 to 1.485), <0.001 | 1.345 (1.218 to 1.485), <0.001 | 4.7e−5 | ✓ PASS |
| Between-hospital variance / SD | 0.0062 / 0.0788 | 0.0062 / 0.0788 | 7e−7 | ✓ PASS |
| LR test of σ² = 0: χ², p (half χ²₁) | 3.224, 0.036 | 3.224, 0.036 | 3e−7 | ✓ PASS |
| ICC (count scale) | 0.0087 | 0.0087 | 9e−7 | ✓ PASS |
| Design effect (average patients per hospital) | 2.61 (185.29) | 2.61 (185.3) | <5e−3 (2 decimals shown) | ✓ PASS |
| Dispersion φ (Pearson χ²/df, conditional) | 1.77 | 1.77 | <5e−5 | ✓ PASS |
| Log-likelihood / AIC / BIC | −1981.902 / 3975.8 / 4006.8 | −1981.902 / 3975.8 / 4006.8 | 1e−7 | ✓ PASS |
ค่าความต่างคำนวณจากค่าที่ไม่ปัดเศษ (DAPH จากการรันเอนจินจริง) · ทั้งสองโปรแกรมหาค่าสูงสุดแบบวนซ้ำและ SE มาจาก Hessian เชิงตัวเลข ความต่างระดับ 10⁻⁵ ถึง 10⁻⁴ จึงอยู่ในเกณฑ์ (ทุกค่าตรงกันที่ทศนิยมที่ DAPH แสดง)
Differences use unrounded values (DAPH from a run of the engine itself). Both programs maximise iteratively and take SEs from a numerical Hessian, so differences of 10⁻⁵ to 10⁻⁴ are within tolerance; every value agrees at the decimals DAPH displays.
4การแปลผลและตัวอย่างInterpretation and Example
ผล: เมื่อเทียบผู้ป่วยในโรงพยาบาลเดียวกัน APD มีอัตราการติดเชื้อในช่องท้องเป็น 0.449 เท่าของ CAPD (IRR 0.449, 95% CI 0.403 to 0.500, p < 0.001) · อายุมากขึ้น 1 ปี อัตราเพิ่ม 1.019 เท่า (95% CI 1.012 to 1.026) · ผู้มีโรคเรื้อรัง IRR 1.345 (95% CI 1.218 to 1.485) · เพศไม่มีนัยสำคัญ (IRR 0.965, 95% CI 0.870 to 1.069, p = 0.491)
Results: comparing patients within the same hospital, APD had 0.449 times the peritonitis rate of CAPD (IRR 0.449, 95% CI 0.403 to 0.500, p < 0.001). Each additional year of age multiplied the rate by 1.019 (95% CI 1.012 to 1.026); chronic disease IRR 1.345 (95% CI 1.218 to 1.485); gender was not significant (IRR 0.965, 95% CI 0.870 to 1.069, p = 0.491).
ผลของการจัดกลุ่ม: ความแปรปรวนระหว่างโรงพยาบาลเล็ก (σ² = 0.0062, SD 0.0788) แต่ต่างจากศูนย์อย่างมีนัยสำคัญ (LR = 3.224, p = 0.036) ICC = 0.0087 ซึ่ง DAPH ระบุว่าต่ำมาก และรายงาน design effect = 1 + (185.29 − 1) × ICC = 2.61 เพื่อเตือนว่าเมื่อกลุ่มใหญ่ ICC เล็กก็ยังมีผลได้ การละเลยการจัดกลุ่มอาจทำให้ SE ของผลที่ต่างกันระหว่างโรงพยาบาลต่ำเกินจริงได้ถึงราว √2.61 = 1.62 เท่า · มีเพียง 7 โรงพยาบาล ค่า σ² จึงประมาณได้ไม่แม่น
Clustering: the between-hospital variance is small (σ² = 0.0062, SD 0.0788) but differs significantly from zero (LR = 3.224, p = 0.036), and the ICC is 0.0087, which DAPH labels very low; it also reports the design effect, 1 + (185.29 − 1) × ICC = 2.61, a reminder that with large clusters even a small ICC matters: ignoring the clustering could understate the SE of an effect that varies between hospitals by up to about √2.61 = 1.62 times. With only 7 hospitals, σ² is estimated imprecisely.
ข้อจำกัดที่สำคัญ: φ = 1.77 แปลว่ายังมี overdispersion หลังใส่ random intercept SE ของ GLMM Poisson จึงน่าจะต่ำเกินจริง (ช่วงเชื่อมั่นของ APD 0.403 to 0.500 แคบกว่าของ negative binomial ในหัวข้อ 4.1 ซึ่งคือ 0.39 to 0.52) DAPH เตือนเรื่องนี้ในผลลัพธ์ ควรรายงานผลจาก negative binomial (หัวข้อ 4.1) เป็นหลัก หรือใช้ negative binomial mixed model นอก DAPH · GEE ในสคริปต์ให้ IRR ใกล้เคียงกัน (APD 0.4486) แต่ robust SE เชื่อถือได้เมื่อมีกลุ่มจำนวนมาก ไม่ใช่ 7 กลุ่ม · ข้อมูลเป็นการสังเกต ความสัมพันธ์ไม่ใช่เหตุและผล
Key limitation: φ = 1.77 shows overdispersion left after the random intercept, so the GLMM Poisson SEs are probably too small (the APD interval 0.403 to 0.500 is narrower than the negative binomial interval of section 4.1, 0.39 to 0.52). DAPH warns about this in its output; report the negative binomial results (section 4.1) as the main analysis, or fit a negative binomial mixed model outside DAPH. The GEE in the script gives a similar IRR (APD 0.4486), but robust SEs are reliable only with many clusters, not 7. The data are observational, so the associations are not causal.
ตัวอย่างการเขียนผล: จาก Poisson mixed model ที่มี random intercept ของโรงพยาบาล (7 แห่ง) และใช้ log ของระยะเวลาติดตามเป็น offset ผู้ป่วย APD มีอัตราการติดเชื้อในช่องท้องต่ำกว่า CAPD (IRR 0.449, 95% CI 0.403 to 0.500, p < 0.001) ความแปรปรวนระหว่างโรงพยาบาลมีค่าน้อย (σ² = 0.0062, ICC = 0.0087) แต่ยังมี overdispersion (Pearson χ²/df = 1.77)
Model results sentence: In a Poisson mixed model with a random intercept for hospital (7 hospitals) and log follow-up time as the offset, patients on APD had a lower peritonitis rate than those on CAPD (IRR 0.449, 95% CI 0.403 to 0.500, p < 0.001); the between-hospital variance was small (σ² = 0.0062, ICC = 0.0087), but overdispersion remained (Pearson χ²/df = 1.77).
📖 References
- Breslow, N. E., & Clayton, D. G. (1993). Approximate inference in generalized linear mixed models. Journal of the American Statistical Association, 88(421), 9–25. doi:10.1080/01621459.1993.10594284
- Liang, K.-Y., & Zeger, S. L. (1986). Longitudinal data analysis using generalized linear models. Biometrika, 73(1), 13–22. doi:10.1093/biomet/73.1.13
- Nakagawa, S., Johnson, P. C. D., & Schielzeth, H. (2017). The coefficient of determination R² and intra-class correlation coefficient from generalized linear mixed-effects models revisited and expanded. Journal of the Royal Society Interface, 14(134), 20170213. doi:10.1098/rsif.2017.0213
- Zeger, S. L., Liang, K.-Y., & Albert, P. S. (1988). Models for longitudinal data: A generalized estimating equation approach. Biometrics, 44(4), 1049–1060. doi:10.2307/2531734
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 5 — เวลาเกิดเหตุการณ์ (Survival)Chapter 5 — Time-to-event / Survival ✓ Verified
วิเคราะห์เวลาจากจุดเริ่มต้นถึงเหตุการณ์ (เช่น เวลาจนเสียชีวิต) เมื่อผู้ป่วยบางรายยังไม่เกิดเหตุการณ์เมื่อสิ้นสุดการติดตาม (censoring) · หัวข้อ 5.1 Kaplan-Meier และ log-rank test บรรยายการรอดชีพและเปรียบเทียบกลุ่มโดยไม่ปรับตัวแปรอื่น · หัวข้อ 5.2 Cox regression ให้ hazard ratio ที่ปรับแล้วพร้อมการทดสอบข้อตกลง proportional hazards · ทั้งสองหัวข้อตรวจกับ R package survival
Time from a starting point to an event (for example, death) when some patients are still event-free at the end of follow-up (censoring). Section 5.1: Kaplan-Meier curves and the log-rank test describe survival and compare groups without adjustment. Section 5.2: Cox regression gives adjusted hazard ratios with a test of the proportional-hazards assumption. Both are checked against the R package survival.
5.1Kaplan-Meier Curves + Log-rank Test
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Kaplan-Meier (KM) estimator ประมาณสัดส่วนผู้ที่ยังไม่เกิดเหตุการณ์ (เช่น ยังมีชีวิต) ตามเวลา S(t) โดยใช้ข้อมูลของผู้ที่ถูก censor (ยังไม่เกิดเหตุการณ์เมื่อสิ้นสุดการติดตาม) จนถึงเวลาที่ถูก censor (Kaplan & Meier, 1958) · Log-rank test เปรียบเทียบเส้นโค้งทั้งเส้นระหว่างกลุ่ม โดยเทียบจำนวนเหตุการณ์ที่พบจริงกับที่คาดไว้ ณ ทุกเวลาที่เกิดเหตุการณ์ (Mantel, 1966; Peto & Peto, 1972)
The Kaplan-Meier (KM) estimator estimates the proportion still free of the event (for example, still alive) over time, S(t), using censored patients (event-free when follow-up ended) up to the time they were censored (Kaplan & Meier, 1958). The log-rank test compares whole curves between groups by comparing observed with expected events at every event time (Mantel, 1966; Peto & Peto, 1972).
ข้อจำกัด: KM และ log-rank ไม่ปรับตัวแปรอื่น (ใช้ Cox regression หัวข้อ 5.2) · สมมติว่าการ censor ไม่เกี่ยวกับโอกาสเกิดเหตุการณ์ · ถ้ามีเหตุการณ์แข่งขัน (competing risk) เช่น ย้ายไปฟอกเลือดหรือปลูกถ่ายไต 1 − S(t) จะสูงกว่าความเสี่ยงสะสมจริง
Limitations: KM and the log-rank test do not adjust for other variables (use Cox regression, section 5.2); censoring is assumed to be unrelated to the chance of the event; with competing events, such as transfer to haemodialysis or transplantation, 1 − S(t) overstates the cumulative risk.
2หลักการและสูตรLogic and Formula
- t_i, d_i, n_i
- เวลาที่เกิดเหตุการณ์ จำนวนเหตุการณ์ ณ เวลานั้น และจำนวนผู้ที่ยังอยู่ในการติดตาม (at risk: เวลา ≥ t_i)event time, number of events at that time, and number still followed (at risk: time ≥ t_i)
- n_1j, n_2j, d_1j
- จำนวน at risk ในกลุ่ม 1 และ 2 และจำนวนเหตุการณ์ในกลุ่ม 1 ณ เวลาเหตุการณ์ที่ jnumber at risk in groups 1 and 2, and events in group 1, at event time j
- t̂_0.5
- เวลาแรกที่ Ŝ(t) ลดลงถึง 0.5 หรือต่ำกว่า · ขอบล่างและขอบบนของ 95% CI คือเวลาแรกที่ขอบบนและขอบล่างของแถบความเชื่อมั่นลดลงถึง 0.5 (Brookmeyer & Crowley, 1982)first time Ŝ(t) falls to 0.5 or below; the 95% CI runs from the first time the upper band reaches 0.5 to the first time the lower band does (Brookmeyer & Crowley, 1982)
สิ่งที่ DAPH คำนวณ: เหตุการณ์คือแถวที่ตัวแปรเหตุการณ์มีค่าเท่ากับ “ค่าที่หมายถึง Event” (ตัวอย่างนี้ status = 1) · เวลาใช้ตัวแปรที่มีอยู่หรือคำนวณจากวันที่เริ่มและวันที่สิ้นสุด · ต่อกลุ่มรายงาน n เหตุการณ์ มัธยฐาน (95% CI แบบ log−log ตรงกับ R survfit(..., conf.type = "log-log"); แสดง NR เมื่อยังไม่ถึง) person-time และ IR ต่อ 100 คน-ปี และอัตรารอดชีพที่ 1, 2, 3 และ 5 ปีเฉพาะเวลาที่อยู่ในช่วงติดตาม (95% CI แบบ log ซึ่งเป็นค่าเริ่มต้นของ R) · log-rank test ใช้แบบสองกลุ่ม และใช้ log-rank หลายกลุ่ม (df = จำนวนกลุ่ม − 1) เมื่อมีตั้งแต่ 3 กลุ่ม · กราฟมี 4 แบบ คือเส้นโค้งที่มีและไม่มี 95% CI และสองแบบเดียวกันที่มีแถบ “Number at risk” ใต้แกนเวลา (จำนวนผู้ที่มีเวลา ≥ t นิยามเดียวกับ n.risk ของ R) · หมายเหตุใต้ตารางใน Word อธิบายวิธีคำนวณช่วงเชื่อมั่นทั้งสองแบบ
What DAPH computes: an event is a row whose event variable equals the “Event Value” (here status = 1); time is an existing variable or is calculated from start and end dates. Per group it reports n, events, the median (95% CI on the log−log scale, as R survfit(..., conf.type = "log-log"); NR when not reached), person-time and the IR per 100 person-years, and survival at 1, 2, 3 and 5 years for times within follow-up (95% CI on the log scale, the R default). The log-rank test is the two-group test, or the k-group log-rank test (df = groups − 1) with three or more groups. The chart menu offers four figures: the curve with and without its 95% CI, and the same two with a “Number at risk” strip under the time axis (patients with time ≥ t, the definition of R's n.risk). The note under the Word table explains both CI scales.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
survival (survfit, survdiff)package survival (survfit, survdiff)# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(survival) # survfit(), survdiff()
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
# status: 1 = died (event), 0 = alive / censored; follow_up_days = time in days
c(patients = nrow(d), deaths = sum(d$status), max_days = max(d$follow_up_days))
km <- survfit(Surv(follow_up_days, status) ~ group, data = d,
conf.type = "log-log") # the CI DAPH uses for the median
km # n, events, median (NA = not reached)
km_log <- survfit(Surv(follow_up_days, status) ~ group, data = d) # R default: log scale, as DAPH
s12 <- summary(km_log, times = c(1, 2) * 365.25) # survival at 1 and 2 years
data.frame(group = s12$strata, years = s12$time / 365.25, n.risk = s12$n.risk,
surv = round(100 * s12$surv, 1), lower = round(100 * s12$lower, 1),
upper = round(100 * s12$upper, 1))
lr <- survdiff(Surv(follow_up_days, status) ~ group, data = d) # log-rank test
lr
round(c(chisq = lr$chisq, df = 1, p = pchisq(lr$chisq, 1, lower.tail = FALSE)), 6)
py <- tapply(d$follow_up_days, d$group, sum) / 365.25 # person-years
round(cbind(person_years = py, IR_per_100 = 100 * tapply(d$status, d$group, sum) / py), 2)
patients deaths max_days
1300 229 1095
Call: survfit(formula = Surv(follow_up_days, status) ~ group, data = d,
conf.type = "log-log")
n events median 0.95LCL 0.95UCL
group=CAPD 656 86 NA NA NA
group=APD 644 143 NA NA NA
group years n.risk surv lower upper
1 group=CAPD 1 562 90.7 88.5 93.0
2 group=CAPD 2 326 86.1 83.4 88.9
3 group=APD 1 508 84.6 81.8 87.4
4 group=APD 2 294 77.8 74.5 81.2
Call:
survdiff(formula = Surv(follow_up_days, status) ~ group, data = d)
N Observed Expected (O-E)^2/E (O-E)^2/V
group=CAPD 656 86 119 9.19 19.2
group=APD 644 143 110 9.95 19.2
Chisq= 19.2 on 1 degrees of freedom, p= 1e-05
chisq df p
19.181842 1.000000 0.000012
person_years IR_per_100
CAPD 1252.50 6.87
APD 1137.01 12.58
| Quantity (CAPD / APD) | R 4.3.3 | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| n / events | 656 / 86 · 644 / 143 | 656 / 86 · 644 / 143 | 0 | ✓ PASS |
| Median survival (95% CI) | not reached (NA) | NR | — | ✓ PASS |
| Person-years · deaths per 100 person-years | 1252.50 / 1137.01 · 6.87 / 12.58 | 1252.5 / 1137.0 · 6.87 / 12.58 | 0 | ✓ PASS |
| Survival at 1 year, % (95% CI) | 90.7 (88.5 to 93.0) / 84.6 (81.8 to 87.4) | 90.7 (88.5 to 93.0) / 84.6 (81.8 to 87.4) | <1e−8 | ✓ PASS |
| Survival at 2 years, % (95% CI) | 86.1 (83.4 to 88.9) / 77.8 (74.5 to 81.2) | 86.1 (83.4 to 88.9) / 77.8 (74.5 to 81.2) | <1e−8 | ✓ PASS |
| Log-rank χ² (df), p | 19.18 (1), <0.001 | 19.18 (1), <0.001 | <5e−7 | ✓ PASS |
| Tab 3 summary: events per group · log-rank line | 86 / 143 · χ²(1) = 19.18 | 86 / 143 · χ²(1) = 19.18 | 0 | ✓ PASS |
ค่าความต่างคำนวณจากค่าที่ไม่ปัดเศษ (DAPH จากการรันเอนจินจริง) · วิธีหาช่วงเชื่อมั่นของมัธยฐานตรวจกับ R บนข้อมูลที่มัธยฐานถึงแล้ว (log−log ตรงกับ R ทุกค่า)
Differences use unrounded values (DAPH from a run of the engine itself). The median CI rule was checked against R on data where the median is reached (log−log: every limit matched).
4การแปลผลและตัวอย่างInterpretation and Example
ผล: ผู้ป่วย APD มีอัตรารอดชีพต่ำกว่า CAPD ทั้งที่ 1 ปี (84.6% เทียบกับ 90.7%) และ 2 ปี (77.8% เทียบกับ 86.1%) อัตราการเสียชีวิต 12.58 เทียบกับ 6.87 ต่อ 100 คน-ปี และเส้นโค้งต่างกันอย่างมีนัยสำคัญ (log-rank χ²(1) = 19.18, p < 0.001) · ทั้งสองกลุ่มรอดชีพเกินครึ่งจนสิ้นสุดการติดตาม มัธยฐานจึง “not reached” ซึ่งไม่ใช่ข้อมูลขาดหาย ให้รายงานอัตรารอดชีพ ณ เวลาที่กำหนดแทน
Results: APD patients had lower survival than CAPD patients at 1 year (84.6% versus 90.7%) and at 2 years (77.8% versus 86.1%), with death rates of 12.58 versus 6.87 per 100 person-years, and the curves differed significantly (log-rank χ²(1) = 19.18, p < 0.001). More than half of each group was still alive at the end of follow-up, so the median is “not reached”; this is not missing data, and survival at fixed times is reported instead.
ข้อควรระวัง: log-rank บอกว่าเส้นโค้งต่างกัน แต่ไม่บอกขนาดของความต่าง และมีอำนาจสูงสุดเมื่อ hazard ของสองกลุ่มเป็นสัดส่วนคงที่ · ผลนี้ยังไม่ได้ปรับอายุหรือโรคร่วม ถ้ากลุ่ม APD และ CAPD มีลักษณะต่างกัน ความต่างอาจมาจากปัจจัยเหล่านั้น จึงควรวิเคราะห์ต่อด้วย Cox regression (หัวข้อ 5.2) · ข้อมูลเป็นการสังเกต ความสัมพันธ์ไม่ใช่ผลของการรักษา
Cautions: the log-rank test says the curves differ but not by how much, and it is most powerful when the two hazards are proportional. These results are not adjusted for age or comorbidity; if APD and CAPD patients differ in such factors, they may explain part of the difference, so continue with Cox regression (section 5.2). The data are observational, so this is an association, not a treatment effect.
ตัวอย่างการเขียนผล: อัตรารอดชีพ 2 ปีตามวิธี Kaplan-Meier ของผู้ป่วย APD เท่ากับ 77.8% (95% CI 74.5 to 81.2) และของผู้ป่วย CAPD เท่ากับ 86.1% (95% CI 83.4 to 88.9) เส้นโค้งการรอดชีพต่างกันอย่างมีนัยสำคัญ (log-rank χ²(1) = 19.18, p < 0.001) และมัธยฐานของเวลารอดชีพยังไม่ถึงในทั้งสองกลุ่ม
Model results sentence: Kaplan-Meier 2-year survival was 77.8% (95% CI 74.5 to 81.2) among APD patients and 86.1% (95% CI 83.4 to 88.9) among CAPD patients; the survival curves differed significantly (log-rank χ²(1) = 19.18, p < 0.001), and median survival was not reached in either group.
📖 References
- Brookmeyer, R., & Crowley, J. (1982). A confidence interval for the median survival time. Biometrics, 38(1), 29–41. doi:10.2307/2530286
- Kaplan, E. L., & Meier, P. (1958). Nonparametric estimation from incomplete observations. Journal of the American Statistical Association, 53(282), 457–481. doi:10.1080/01621459.1958.10501452
- Mantel, N. (1966). Evaluation of survival data and two new rank order statistics arising in its consideration. Cancer Chemotherapy Reports, 50(3), 163–170. PMID 5910392
- Peto, R., & Peto, J. (1972). Asymptotically efficient rank invariant test procedures. Journal of the Royal Statistical Society: Series A (General), 135(2), 185–207. doi:10.2307/2344317
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
5.2Cox Proportional Hazards Regression
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Cox Proportional Hazards Regression วิเคราะห์เวลาจนเกิดเหตุการณ์โดยปรับหลายตัวแปรพร้อมกัน แบบจำลองคือ h(t | x) = h₀(t) · exp(x′β) โดยไม่ต้องกำหนดรูปร่างของ baseline hazard h₀(t) (Cox, 1972) · exp(β) = hazard ratio (HR) คืออัตราส่วนของอัตราการเกิดเหตุการณ์ ณ ขณะใดขณะหนึ่งระหว่างสองกลุ่ม ภายใต้ข้อตกลงว่า HR คงที่ตลอดการติดตาม (proportional hazards: PH)
Cox Proportional Hazards Regression analyses time to an event while adjusting for several variables. The model is h(t | x) = h₀(t) · exp(x′β), with no assumed shape for the baseline hazard h₀(t) (Cox, 1972). exp(β) is the hazard ratio (HR): the ratio of the instantaneous event rates of two groups, assumed constant over follow-up (proportional hazards, PH).
ไม่ควรใช้ตามปกติเมื่อ: PH ไม่เป็นจริงชัดเจน (ใช้ Cox แบบแบ่งชั้น หรือให้ผลเปลี่ยนตามเวลา) · มีเหตุการณ์แข่งขัน (competing risk) ที่ต้องการประมาณความเสี่ยงสะสม · จำนวนเหตุการณ์น้อยเมื่อเทียบกับจำนวนสัมประสิทธิ์
Do not use it as it stands when PH clearly fails (use a stratified Cox model or a time-varying effect), when competing events matter and cumulative risk is wanted, or when there are few events per coefficient.
2หลักการและสูตรLogic and Formula
- R_j, D_j, d_j
- ชุดผู้ที่ยังอยู่ในการติดตาม (risk set) ณ เวลาเหตุการณ์ที่ j · ชุดผู้ที่เกิดเหตุการณ์ ณ เวลานั้น · จำนวนของผู้นั้นrisk set at event time j · set of patients with the event at that time · their number
- ℓ, ℓ_−G, ℓ_0
- log partial likelihood ของแบบจำลอง เมื่อตัดตัวแปร G (q คอลัมน์) ออก และเมื่อไม่มีตัวแปรอิสระlog partial likelihood of the model, without variable G (q columns), and with no predictors
- U_γ, 𝓘
- score ของ γ (ผลรวมของ g(t) × Schoenfeld residual ณ ทุกเวลาเหตุการณ์) และ information ของ (β, γ) ที่ค่า β ที่ประมาณได้score for γ (the sum over event times of g(t) times the Schoenfeld residual) and the information of (β, γ) at the fitted β
- comparable pair
- คู่ที่รู้ว่าใครเกิดเหตุการณ์ก่อน (คนที่เวลาสั้นกว่าเกิดเหตุการณ์) · concordant คือคนที่เกิดก่อนมีค่า η̂ สูงกว่าa pair where it is known who had the event first (the shorter time is an event); concordant when that patient has the higher η̂
สิ่งที่ DAPH คำนวณ: maximum partial likelihood แบบ Efron สำหรับเวลาที่เท่ากัน (Efron, 1977; ค่าเริ่มต้นของ R coxph) วนซ้ำจนเปลี่ยนแปลงไม่เกิน 10⁻¹² · 95% CI แบบ Wald · ค่า p ของตัวแปรต่อเนื่อง = Wald z ส่วนตัวแปรกลุ่ม (รวมตัวแปร 2 ระดับ) = LR_G จากการตัดตัวแปรนั้นออกแล้วประมาณใหม่ (R drop1) · การทดสอบ PH ต่อตัวแปรและ GLOBAL แบบเดียวกับ R cox.zph(fit, transform = "km") (survival 3.x) และเตือนเมื่อ p < 0.05 · concordance แบบ Harrell (Harrell et al., 1982) พร้อมคำบรรยาย (ตามเกณฑ์ AUC ของ Hosmer et al. (2013): < 0.7 poor, 0.7 ถึง < 0.8 acceptable, 0.8 ถึง < 0.9 excellent, ≥ 0.9 outstanding) · ตารางมี Crude HR (ทีละตัวแปร) median อัตราการเกิดต่อ 100 คน-ปีของแต่ละกลุ่ม และ log-rank test ของตัวแปรกลุ่มตัวแรก
What DAPH computes: maximum partial likelihood with Efron's method for tied times (Efron, 1977; the R coxph default), iterated until changes are below 10⁻¹². 95% CIs are Wald intervals. A continuous predictor's p is the Wald z test; a categorical predictor (including a two-level one) gets LR_G from refitting without it (R drop1). The PH test per variable and GLOBAL is that of R cox.zph(fit, transform = "km") (survival 3.x), with a warning when p < 0.05. Harrell's concordance (Harrell et al., 1982) comes with a label (the AUC bands of Hosmer et al. (2013): < 0.7 poor, 0.7 to < 0.8 acceptable, 0.8 to < 0.9 excellent, ≥ 0.9 outstanding). The table adds the crude HR (one variable at a time), each group's median and rate per 100 person-years, and the log-rank test of the first categorical variable.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
survival (coxph, cox.zph)package survival (coxph, cox.zph)# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(survival) # coxph(), cox.zph()
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
d$bmi_group <- factor(d$bmi_group, 1:4, c("Underweight", "Normal", "Overweight", "Obese"))
fit <- coxph(Surv(follow_up_days, status) ~ group + age + gender + chronic + bmi_group,
data = d, ties = "efron") # Efron ties, as DAPH (R default)
s <- summary(fit)
round(cbind(HR = s$conf.int[, 1], lower = s$conf.int[, 3], upper = s$conf.int[, 4],
p = s$coefficients[, 5]), 4)
round(c(concordance = unname(s$concordance[1]), LR = unname(s$logtest[1]),
df = unname(s$logtest[2]), p = unname(s$logtest[3])), 4)
drop1(fit, test = "Chisq") # LR test of each variable: the p on DAPH's header rows
cox.zph(fit, transform = "km") # proportional-hazards test (score test, KM time scale)
crude <- sapply(c("group", "age", "gender", "chronic"), function(v)
exp(coef(coxph(reformulate(v, "Surv(follow_up_days, status)"), data = d)))[1])
round(crude, 4) # crude HR, one variable at a time (first level for factors)
HR lower upper p
groupAPD 1.8926 1.4471 2.4753 0.0000
age 1.0384 1.0200 1.0571 0.0000
genderFemale 1.1597 0.8733 1.5399 0.3059
chronicYes 1.5436 1.1806 2.0182 0.0015
bmi_groupNormal 0.8767 0.5732 1.3408 0.5437
bmi_groupOverweight 0.8435 0.5202 1.3677 0.4900
bmi_groupObese 0.8369 0.5230 1.3392 0.4579
concordance LR df p
0.6349 53.0365 7.0000 0.0000
Single term deletions
Model:
Surv(follow_up_days, status) ~ group + age + gender + chronic +
bmi_group
Df AIC LRT Pr(>Chi)
<none> 3162.1
group 1 3182.6 22.5107 2.090e-06 ***
age 1 3176.5 16.3436 5.283e-05 ***
gender 1 3161.2 1.0671 0.30161
chronic 1 3170.4 10.2727 0.00135 **
bmi_group 3 3156.7 0.6033 0.89568
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
chisq df p
group 0.233 1 0.629
age 1.325 1 0.250
gender 1.747 1 0.186
chronic 4.892 1 0.027
bmi_group 2.032 3 0.566
GLOBAL 11.062 7 0.136
group.groupAPD age.age gender.genderFemale chronic.chronicYes
1.8026 1.0406 1.2038 1.5692
| Quantity | R 4.3.3 | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| APD vs CAPD: adjusted HR (95% CI), LR p | 1.89 (1.45 to 2.48), <0.001 | 1.89 (1.45 to 2.48), <0.001 | <1e−8 | ✓ PASS |
| Age per year: adjusted HR (95% CI), Wald p | 1.04 (1.02 to 1.06), <0.001 | 1.04 (1.02 to 1.06), <0.001 | <1e−8 | ✓ PASS |
| Female vs Male: adjusted HR (95% CI), LR p | 1.16 (0.87 to 1.54), 0.302 | 1.16 (0.87 to 1.54), 0.302 | <1e−8 | ✓ PASS |
| Chronic disease Yes vs No: adjusted HR (95% CI), LR p | 1.54 (1.18 to 2.02), 0.001 | 1.54 (1.18 to 2.02), 0.001 | <1e−8 | ✓ PASS |
| BMI group Normal / Overweight / Obese vs Underweight: HR; LR p (3 df) | 0.88 / 0.84 / 0.84; 0.896 | 0.88 / 0.84 / 0.84; 0.896 | <1e−8 | ✓ PASS |
| Crude HR: group / age / gender / chronic | 1.80 / 1.04 / 1.20 / 1.57 | 1.80 / 1.04 / 1.20 / 1.57 | <5e−3 | ✓ PASS |
| Concordance C · model LR χ²(7) | 0.6349 · 53.04 | 0.6349 · 53.04 | <5e−5 | ✓ PASS |
| PH test χ² (p): group / age / gender / chronic / BMI group | 0.233 (0.629) / 1.325 (0.250) / 1.747 (0.186) / 4.892 (0.027) / 2.032 (0.566) | 0.233 (0.629) / 1.325 (0.250) / 1.747 (0.186) / 4.892 (0.027) / 2.032 (0.566) | <5e−4 | ✓ PASS |
| PH test GLOBAL χ²(7), p | 11.062, 0.136 | 11.062, 0.136 | <5e−4 | ✓ PASS |
ค่าความต่างคำนวณจากค่าที่ไม่ปัดเศษเมื่อมี (DAPH จากการรันเอนจินจริง) ส่วนค่าที่ R พิมพ์ทศนิยมจำกัด (การทดสอบ PH, C) เทียบที่ความละเอียดที่พิมพ์ · การทดสอบ PH ตรงกับ cox.zph
Differences use unrounded values where available (DAPH from a run of the engine itself); where R prints limited decimals (PH test, C) the comparison is at the printed precision. The PH test matches cox.zph.
4การแปลผลและตัวอย่างInterpretation and Example
ผล: เมื่อปรับอายุ เพศ โรคเรื้อรัง และกลุ่ม BMI แล้ว ผู้ป่วย APD มี hazard ของการเสียชีวิตเป็น 1.89 เท่าของ CAPD (95% CI 1.45 to 2.48, p < 0.001) ใกล้เคียงกับ crude HR 1.80 · อายุมากขึ้นทุก 1 ปี hazard เพิ่ม 1.04 เท่า (95% CI 1.02 to 1.06, p < 0.001) · ผู้มีโรคเรื้อรัง HR 1.54 (95% CI 1.18 to 2.02, p = 0.001) · เพศ (p = 0.302) และกลุ่ม BMI (p = 0.896) ไม่มีนัยสำคัญ ซึ่งไม่ได้แปลว่าไม่มีความสัมพันธ์
Results: after adjusting for age, gender, chronic disease and BMI group, APD patients had 1.89 times the hazard of death of CAPD patients (95% CI 1.45 to 2.48, p < 0.001), close to the crude HR of 1.80. Each additional year of age multiplied the hazard by 1.04 (95% CI 1.02 to 1.06, p < 0.001), and chronic disease by 1.54 (95% CI 1.18 to 2.02, p = 0.001). Gender (p = 0.302) and BMI group (p = 0.896) were not significant, which is not evidence of no association.
ข้อตกลง PH: การทดสอบรวม (GLOBAL) ไม่มีนัยสำคัญ (χ²(7) = 11.062, p = 0.136) แต่ตัวแปรโรคเรื้อรังมี p = 0.027 แปลว่า HR ของโรคเรื้อรังอาจเปลี่ยนตามเวลา HR 1.54 จึงเป็นค่าเฉลี่ยตลอดการติดตาม ควรดูกราฟ Schoenfeld residual ใน R (plot(cox.zph(fit))) และพิจารณา Cox แบบแบ่งชั้นตามโรคเรื้อรัง (strata(chronic); Therneau & Grambsch, 2000) ถ้าตัวแปรนี้เป็นเพียงตัวแปรปรับ หรือให้ผลเปลี่ยนตามช่วงเวลา ถ้าต้องการรายงาน HR ของมันเอง · ตัวแปรหลักคือกลุ่มการรักษาเป็นไปตามข้อตกลง (p = 0.629)
The PH assumption: the GLOBAL test is not significant (χ²(7) = 11.062, p = 0.136), but chronic disease has p = 0.027, so its HR may change over time and 1.54 is an average over follow-up. Look at the Schoenfeld residual plot in R (plot(cox.zph(fit))) and consider a Cox model stratified by chronic disease (strata(chronic); Therneau & Grambsch, 2000) if it is only an adjustment variable, or a time-varying effect if its own HR is to be reported. The main exposure, treatment group, meets the assumption (p = 0.629).
ความสามารถในการจำแนก: C = 0.6349 ซึ่ง DAPH ระบุว่าจำแนกได้ไม่ดี (poor discrimination, C < 0.7; Hosmer et al., 2013) แบบจำลองนี้จึงเหมาะกับการดูความสัมพันธ์มากกว่าการทำนายรายบุคคล · ข้อมูลเป็นการสังเกต ผู้ป่วยไม่ได้ถูกสุ่มเข้ากลุ่มการรักษา ความสัมพันธ์ไม่ใช่ผลของการรักษา
Discrimination: C = 0.6349, which DAPH labels poor discrimination (C < 0.7; Hosmer et al., 2013); the model suits describing associations better than predicting individuals. The data are observational and treatment was not randomised, so the associations are not treatment effects.
ตัวอย่างการเขียนผล: จาก Cox proportional hazards regression (Efron ties) ที่ปรับอายุ เพศ โรคเรื้อรัง และกลุ่ม BMI ผู้ป่วย APD มี hazard ของการเสียชีวิตสูงกว่า CAPD (adjusted HR 1.89, 95% CI 1.45 to 2.48, p < 0.001) การทดสอบ proportional hazards ด้วย Schoenfeld residuals ไม่มีนัยสำคัญโดยรวม (χ²(7) = 11.062, p = 0.136)
Model results sentence: In a Cox proportional hazards model (Efron ties) adjusted for age, gender, chronic disease and BMI group, APD was associated with a higher hazard of death than CAPD (adjusted HR 1.89, 95% CI 1.45 to 2.48, p < 0.001); the global Schoenfeld-residual test of proportional hazards was not significant (χ²(7) = 11.062, p = 0.136).
📖 References
- Cox, D. R. (1972). Regression models and life-tables. Journal of the Royal Statistical Society: Series B (Methodological), 34(2), 187–202. doi:10.1111/j.2517-6161.1972.tb00899.x
- Efron, B. (1977). The efficiency of Cox's likelihood function for censored data. Journal of the American Statistical Association, 72(359), 557–565. doi:10.1080/01621459.1977.10480613
- Grambsch, P. M., & Therneau, T. M. (1994). Proportional hazards tests and diagnostics based on weighted residuals. Biometrika, 81(3), 515–526. doi:10.1093/biomet/81.3.515
- Harrell, F. E., Jr., Califf, R. M., Pryor, D. B., Lee, K. L., & Rosati, R. A. (1982). Evaluating the yield of medical tests. JAMA, 247(18), 2543–2546. doi:10.1001/jama.1982.03320430047030
- Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied logistic regression (3rd ed.). Wiley. doi:10.1002/9781118548387
- Therneau, T. M., & Grambsch, P. M. (2000). Modeling survival data: Extending the Cox model. Springer. doi:10.1007/978-1-4757-3294-8
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 6 — สถิติเชิงพื้นที่ (Spatial)Chapter 6 — Spatial Statistics ✓ Verified
สถิติที่ใช้ตำแหน่งที่ตั้งหรือแผนที่ของพื้นที่ (shapefile หรือไฟล์ spatial weights) — แบบจำลองถดถอยที่คำนึงถึงความสัมพันธ์ระหว่างพื้นที่ข้างเคียง ทั้งข้อมูลปีเดียวและข้อมูลหลายช่วงเวลา (6.1–6.3), การหากลุ่มก้อนและพื้นที่ร้อนของค่าสูงหรือต่ำ (LISA, Bivariate LISA, Getis-Ord; 6.4–6.6), การเลือก spatial weights (6.7), แผนที่การกระจาย (6.8) และการทำแผนที่โรคแบบ Bayesian BYM2 รวมถึงสองผลลัพธ์ (6.9–6.10). ข้อมูลตัวอย่างผู้ป่วยของ DAPH ไม่มีแผนที่ หัวข้อในบทนี้จึงใช้ข้อมูลสาธารณะที่มีแผนที่และมากับ R package (เช่น ข้อมูล Columbus ใน spData) ซึ่งผู้อ่านเปิดได้ทั้งใน R และใน DAPH
Methods that use the locations or map of areas (a shapefile or a spatial-weights file) — regression models that account for dependence between neighbouring areas, for one period and for panels of several periods (6.1–6.3), detection of clusters and hot spots of high or low values (LISA, bivariate LISA, Getis-Ord; 6.4–6.6), the choice of spatial weights (6.7), distribution maps (6.8) and Bayesian BYM2 disease mapping, including two outcomes (6.9–6.10). The DAPH patient example has no map, so the sections in this chapter use public data with maps that ship with R packages (for example the Columbus data in spData), which readers can open both in R and in DAPH.
6.1 Spatial Regression (OLS · SLM · SEM)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Spatial regression ใช้เมื่อหน่วยวิเคราะห์เป็น พื้นที่ (อำเภอ ตำบล ย่าน) และค่าของพื้นที่ที่อยู่ติดกันมักคล้ายกัน เรียกว่า spatial autocorrelation (ความสัมพันธ์ระหว่างค่าของพื้นที่ข้างเคียง). เมื่อมีลักษณะนี้ สมมติฐานว่าค่าคลาดเคลื่อนเป็นอิสระต่อกันของ OLS (Ordinary Least Squares — การถดถอยเชิงเส้นแบบกำลังสองน้อยที่สุด) จะไม่เป็นจริง: ค่าความคลาดเคลื่อนมาตรฐาน (SE) และ p-value ของ OLS เชื่อถือไม่ได้ และถ้าผลลัพธ์ของพื้นที่ข้างเคียงสัมพันธ์กันโดยตรง ค่าสัมประสิทธิ์ของ OLS ก็ลำเอียงด้วย. DAPH ประมาณค่าแบบจำลองที่ผู้ใช้ติ๊กเลือกจากข้อมูลชุดเดียวกัน: OLS (แบบจำลองพื้นฐาน พร้อมการตรวจความสัมพันธ์เชิงพื้นที่ของส่วนเหลือ), Spatial Lag Model (SLM) ซึ่งใส่ค่าเฉลี่ยถ่วงน้ำหนักของผลลัพธ์ในพื้นที่ข้างเคียง (ρWy) เป็นตัวแปรอธิบาย และ Spatial Error Model (SEM) ซึ่งให้ส่วนคลาดเคลื่อนมีโครงสร้างเชิงพื้นที่ (u = λWu + ε). แบบจำลอง Spatial Durbin (SDM) อธิบายในหัวข้อ 6.2.
Spatial regression is used when the unit of analysis is an area (district, sub-district, neighbourhood) and adjacent areas tend to have similar values — spatial autocorrelation. The independence assumption of OLS (ordinary least squares regression) then fails: its standard errors (SE) and p-values cannot be trusted, and when the outcomes of neighbouring areas depend on each other directly, its coefficients are biased as well. DAPH fits the models the user ticks, on the same data: OLS (the baseline, with spatial diagnostics on its residuals), the Spatial Lag Model (SLM), which adds the weighted average of the outcome in neighbouring areas (ρWy) as an explanatory term, and the Spatial Error Model (SEM), which lets the error term carry the spatial structure (u = λWu + ε). The Spatial Durbin Model (SDM) is described in 6.2.
ใช้เมื่อ: ผลลัพธ์เป็นตัวแปรต่อเนื่องที่วัดรายพื้นที่ (อัตรา ร้อยละ ค่าเฉลี่ย) และมีแผนที่ของพื้นที่ (shapefile) หรือไฟล์ spatial weights. ไม่ใช้เมื่อ: ข้อมูลเป็นรายบุคคลที่ไม่มีตำแหน่งที่ตั้ง · มีพื้นที่ที่ข้อมูลครบน้อยกว่า 30 พื้นที่ (DAPH หยุดและแจ้งเตือน) · ผลลัพธ์เป็นจำนวนผู้ป่วยในพื้นที่ที่มีผู้ป่วยน้อย (ใช้ Bayesian BYM2 ในหัวข้อ 6.9) · มีข้อมูลหลายช่วงเวลาของพื้นที่ชุดเดียวกัน (ใช้ Spatial Panel Regression ในหัวข้อ 6.3).
Use it when the outcome is a continuous area-level measure (a rate, a percentage, a mean) and a map of the areas (shapefile) or a spatial-weights file is available. Do not use it for individual records without locations · with fewer than 30 complete areas (DAPH stops with a message) · for small disease counts per area (use Bayesian BYM2, 6.9) · for repeated periods of the same areas (use Spatial Panel Regression, 6.3).
spData ซึ่งเปิดได้ทั้งใน R และใน DAPH (สคริปต์ในข้อ 3 สร้างไฟล์ columbus.zip ให้): 49 ย่านของเมือง Columbus รัฐโอไฮโอ ปี 1980 · ผลลัพธ์ CRIME = จำนวนการลักทรัพย์ในบ้านและการขโมยรถต่อ 1,000 ครัวเรือน · INC = รายได้ครัวเรือน (พันดอลลาร์สหรัฐ) · HOVAL = มูลค่าบ้าน (พันดอลลาร์สหรัฐ). คำถามวิจัย: ในระดับย่าน รายได้และมูลค่าบ้านสัมพันธ์กับอัตราอาชญากรรมอย่างไร และอัตราของย่านข้างเคียงยังสัมพันธ์กันหลังคุมสองตัวแปรนี้แล้วหรือไม่ — เป็นคำถามระดับพื้นที่ (ecological) แบบเดียวกับการศึกษาอัตราป่วยรายอำเภอ.
spData, which open in both R and DAPH (the script in step 3 writes columbus.zip): 49 neighbourhoods of Columbus, Ohio, in 1980 · outcome CRIME = residential burglaries and vehicle thefts per 1,000 households · INC = household income (USD 1,000) · HOVAL = housing value (USD 1,000). Research question: at neighbourhood level, how are income and housing value associated with the crime rate, and do neighbouring rates remain associated once both are controlled? It is the same kind of area-level (ecological) question as a study of district disease rates.
2หลักการและสูตรLogic and Formula
กำหนดให้ y = เวกเตอร์ผลลัพธ์ (n×1), X = เมทริกซ์ตัวแปรอธิบายรวมค่าคงที่ (n×k) และ W = spatial weights matrix ที่ปรับให้ผลรวมของแต่ละแถวเท่ากับ 1 (row-standardised). สำหรับ Queen contiguity (พื้นที่ที่มีขอบหรือจุดมุมร่วมกันเป็นเพื่อนบ้าน):
Let y = outcome vector (n×1), X = design matrix including the constant (n×k) and W = the spatial weights matrix, row-standardised so that every row sums to 1. For Queen contiguity (areas sharing an edge or a corner are neighbours):
- ρ, λ
- ค่าที่ทำให้ log-likelihood สูงสุด โดยค้นในช่วง (−1, 1)the values that maximise the log-likelihood, searched within (−1, 1)
- β̂(ρ), β̂(λ)
- SLM: OLS ของ (I − ρW)y บน X · SEM: generalised least squares บนข้อมูลที่กรองแล้ว (I − λW)y และ (I − λW)XSLM: OLS of (I − ρW)y on X · SEM: generalised least squares on the filtered data (I − λW)y and (I − λW)X
- ln|I − ρW|
- log-determinant (Jacobian) คำนวณแบบตรงจากเมทริกซ์ขนาด n×n ทั้งเมทริกซ์ — ให้ค่าเท่ากับ Σ ln(1 − ρωi) จาก eigenvalue ωi ของ W ที่ R ใช้ (
method = "eigen")log-determinant (Jacobian), computed exactly from the full n×n matrix — equal to Σ ln(1 − ρωi) over the eigenvalues ωi of W that R uses (method = "eigen") - σ̂²
- ความแปรปรวนของส่วนเหลือแบบ maximum likelihood (หารด้วย n)maximum-likelihood residual variance (divided by n)
- SE
- จาก inverse ของ information matrix เชิงวิเคราะห์ (asymptotic) · p-value จาก z-testfrom the inverse of the analytical (asymptotic) information matrix · p-values from z-tests
แบบจำลอง ตัวประมาณค่าแบบ maximum likelihood และ SE แบบ asymptotic เป็นไปตาม Anselin (1988); คำสั่ง lagsarlm และ errorsarlm ของ R package spatialreg ใช้ตัวประมาณค่าเดียวกัน (Bivand & Piras, 2015).
The models, the maximum-likelihood estimators and their asymptotic SEs follow Anselin (1988); lagsarlm and errorsarlm in the R package spatialreg implement the same estimators (Bivand & Piras, 2015).
ตัวประมาณค่าขึ้นกับรูปแบบ weights: Queen contiguity, Distance band และไฟล์ weights ที่นำเข้า (เมื่อความเป็นเพื่อนบ้านสมมาตร) ใช้ maximum likelihood (ML) ตามสูตรข้างบน. เมื่อเลือก KNN (k nearest neighbours) ความเป็นเพื่อนบ้านไม่สมมาตร DAPH จึงใช้ GMM (generalized method of moments) แทน: SLM ประมาณด้วย spatial two-stage least squares (ใช้ WX และ W²X เป็นตัวแปรเครื่องมือ) และ SEM ด้วย GMM ของ Kelejian & Prucha (2010) ที่รองรับความแปรปรวนไม่คงที่ — แบบจำลอง GMM ไม่มี log-likelihood จึงไม่มี AIC, BIC และ likelihood-ratio test. สำหรับ Distance band และ KNN แบบจำลองใช้ weights แบบ 0/1 ส่วนการวินิจฉัยบนส่วนเหลือของ OLS (Moran's I และ LM) ใช้ weights แบบผกผันกับระยะทาง 1/dp บนชุดเพื่อนบ้านเดียวกัน (ทั้งสองแบบปรับผลรวมแถวเป็น 1). หน้าจอ Tab 2 ตั้งค่าเริ่มต้นไว้ที่ Distance band.
The estimator follows the weights: Queen contiguity, Distance band and an imported weights file (when its neighbour structure is symmetric) use maximum likelihood (ML) as above. With KNN (k nearest neighbours) the neighbour structure is asymmetric, so DAPH switches to GMM (generalized method of moments): the SLM by spatial two-stage least squares (WX and W²X as instruments) and the SEM by the heteroskedasticity-robust GMM of Kelejian & Prucha (2010). GMM models have no log-likelihood, hence no AIC, BIC or likelihood-ratio test. For Distance band and KNN the models use 0/1 weights while the OLS residual diagnostics (Moran's I and LM) use inverse-distance weights 1/dp on the same neighbour set (both row-standardised). The Tab 2 screen starts at Distance band.
- e
- ส่วนเหลือของ OLSOLS residuals
- S₀
- ผลรวมของทุกค่าใน W (เท่ากับ n เมื่อปรับผลรวมแถวเป็น 1 และไม่มีพื้นที่ไร้เพื่อนบ้าน)sum of all weights (equals n for a row-standardised W without isolated areas)
- p-value
- Moran's I ใช้ z สองทาง · LM, RLM แจกแจงแบบ χ²(1) · SARMA แบบ χ²(2)Moran's I: two-sided z · LM and RLM: χ²(1) · SARMA: χ²(2)
- R²pseudo
- σ̂² เป็นค่าแบบ maximum likelihood และความแปรปรวนของ y หารด้วย n · ข้อความใน Tab 3 พิมพ์ค่าเสริมอีกสองค่า: SLM = corr(y, (I − ρ̂W)⁻¹Xβ̂)² และ SEM = corr(y, Xβ̂)²σ̂² is the maximum-likelihood value and the variance of y is divided by n · the Tab 3 text also prints two supplementary values: SLM = corr(y, (I − ρ̂W)⁻¹Xβ̂)² and SEM = corr(y, Xβ̂)²
กฎเลือกแบบจำลองของ DAPH (Anselin LM cascade, ระดับนัยสำคัญ 0.05): (1) LM-lag และ LM-error ไม่มีนัยสำคัญทั้งคู่ → คง OLS (ไม่ใช้รูปแบบ robust เพราะเป็นการทดสอบแบบมีเงื่อนไข) · (2) มีนัยสำคัญเฉพาะ LM-lag → SLM; เฉพาะ LM-error → SEM · (3) มีนัยสำคัญทั้งคู่ → ดูรูปแบบ robust: เฉพาะ robust LM-lag → SLM; เฉพาะ robust LM-error → SEM; ทั้งคู่ → ตัวที่ค่าสถิติสูงกว่า พร้อมคำเตือนให้ตรวจชุดตัวแปรและ W · (4) LM มาตรฐานมีนัยสำคัญทั้งคู่แต่รูปแบบ robust ไม่มีนัยสำคัญเลย → สรุปไม่ได้ (inconclusive) ซึ่งไม่ได้แปลว่าควรใช้ OLS.
DAPH's model-choice rule (Anselin LM cascade, significance level 0.05): (1) neither LM-lag nor LM-error significant → keep OLS (the robust forms are conditional tests and are not used here) · (2) only LM-lag significant → SLM; only LM-error → SEM · (3) both significant → look at the robust forms: only robust LM-lag → SLM; only robust LM-error → SEM; both → the larger statistic, with a warning to check the predictors and W · (4) both standard tests significant but neither robust form → inconclusive, which is not a verdict for OLS.
เมื่อการทดสอบ LM ไม่ชี้ขาด หรือแบบจำลองที่การทดสอบแนะนำไม่ได้ถูกติ๊กไว้ การเลือกแบบจำลองจะพิจารณาจากความเหมาะสมของแบบจำลอง (fit) แทน: รายงาน Word ของ DAPH แปลผลแบบจำลองเชิงพื้นที่ที่ติ๊กไว้ซึ่งมี AIC (Akaike information criterion) ต่ำสุด และเมื่อ LM cascade สรุปไม่ได้ จะพิมพ์ AIC, BIC (Bayesian information criterion) และ likelihood-ratio (LR) test เทียบกับ OLS ของแบบจำลองนั้นด้วย. เกณฑ์สารสนเทศเปรียบเทียบแบบจำลองที่ประมาณจาก ข้อมูลแถวเดียวกันและตัวแปรตามตัวเดียวกัน ว่าแบบใดได้ log-likelihood เพิ่มขึ้นคุ้มกับจำนวนพารามิเตอร์ที่เพิ่ม; Burnham & Anderson (2002) อ่านผลต่าง ΔAIC ว่า < 2 = มีหลักฐานสนับสนุนพอ ๆ กัน · 4–7 = ด้อยกว่าชัดเจน · > 10 = แทบไม่มีหลักฐานสนับสนุน. LR test ทดสอบพารามิเตอร์เชิงพื้นที่โดยตรง (H0: ρ = 0 หรือ λ = 0).
When the LM tests do not discriminate, or the recommended model was not ticked, the choice is made on fit instead: DAPH's Word report interprets the ticked spatial model with the lowest AIC (Akaike information criterion) and, when the LM cascade is inconclusive, also prints that model's AIC, BIC (Bayesian information criterion) and likelihood-ratio (LR) test against OLS. Information criteria rank models fitted to the same rows and the same outcome by how much log-likelihood each buys per parameter; Burnham & Anderson (2002) read ΔAIC < 2 as both models having substantial support · 4–7 as considerably less support · > 10 as essentially none. The LR test tests the spatial parameter itself (H0: ρ = 0 or λ = 0).
- k (DAPH)
- OLS = จำนวนสัมประสิทธิ์รวมค่าคงที่ · SLM = สัมประสิทธิ์ + ρ · SEM = สัมประสิทธิ์ + λ · DAPH ไม่นับ σ² ในทุกแบบจำลอง ขณะที่
AIC()ของ R นับ σ² ด้วย ค่า AIC ของ R จึงมากกว่าของ DAPH 2 หน่วย (BIC มากกว่า ln n) โดยลำดับของแบบจำลองไม่เปลี่ยนOLS = number of coefficients including the constant · SLM = coefficients + ρ · SEM = coefficients + λ · DAPH leaves σ² out of k in every model, while R'sAIC()counts it, so R's AIC is 2 units higher than DAPH's (BIC higher by ln n) and the ranking of models is unchanged - LR
- ใช้ได้เฉพาะแบบจำลองที่ประมาณด้วย ML · df = 1 สำหรับ SLM และ SEMvalid only for ML fits · df = 1 for SLM and SEM
- Direct
- ผลต่อผลลัพธ์ของพื้นที่เดียวกันเมื่อ x ของพื้นที่นั้นเพิ่ม 1 หน่วย (รวมผลย้อนกลับผ่านเพื่อนบ้าน) เฉลี่ยทุกพื้นที่effect on an area's own outcome of a one-unit increase in its own x (including feedback through neighbours), averaged over areas
- Indirect
- DAPH เรียกว่า spillover: ผลรวมต่อพื้นที่อื่นทั้งหมดเมื่อ x ของพื้นที่หนึ่งเพิ่ม 1 หน่วย (เท่ากับผลต่อพื้นที่หนึ่งเมื่อ x ของพื้นที่อื่นทุกพื้นที่เพิ่ม 1 หน่วย) เฉลี่ยทุกพื้นที่labelled "spillover" in DAPH: the summed effect on all other areas of a one-unit increase in one area's x (equivalently, the effect on one area of a one-unit increase in every other area's x), averaged over areas
- 95% CI
- สุ่ม 10,000 ชุด (ผู้ใช้ตั้งได้ 100–100,000) ของ (ค่าคงที่, β, ρ) จากการแจกแจงปกติพหุตัวแปร N(θ̂, V̂) ด้วย seed คงที่ (รันซ้ำได้ค่าเดิม) จำกัด ρ ไว้ที่ ±0.99 แล้วใช้เปอร์เซ็นไทล์ที่ 2.5 และ 97.510,000 draws (user-settable, 100–100,000) of (constant, β, ρ) from the multivariate normal N(θ̂, V̂) with a fixed seed (a re-run reproduces the table), ρ capped at ±0.99, then the 2.5th and 97.5th percentiles
ใน SLM ค่าสัมประสิทธิ์ β ไม่ใช่ผลส่วนเพิ่ม (marginal effect) เพราะการเปลี่ยนแปลงของพื้นที่หนึ่งส่งต่อไปยังเพื่อนบ้านแล้วย้อนกลับผ่าน (I − ρW)⁻¹; ผลที่นำไปอ้างคือ Direct · Indirect · Total. ใน SEM ค่า β คือผลส่วนเพิ่มโดยตรงเพราะความสัมพันธ์เชิงพื้นที่อยู่ในส่วนคลาดเคลื่อนเท่านั้น.
In the SLM a coefficient β is not a marginal effect, because a change in one area passes to its neighbours and back through (I − ρW)⁻¹; the quantities to quote are Direct · Indirect · Total. In the SEM, β is the marginal effect, because the spatial dependence sits only in the errors.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
สคริปต์ส่วนแรกอ่านแผนที่ Columbus จาก spData, สร้างไฟล์ columbus.zip สำหรับเปิดใน DAPH, สร้าง Queen contiguity แบบปรับผลรวมแถวเป็น 1 แล้วฟิต OLS พร้อมการวินิจฉัยเชิงพื้นที่ (คำสั่ง utils::zip ต้องมีโปรแกรม zip ในเครื่อง ถ้าไม่มีให้บีบอัดไฟล์ columbus.shp, .shx, .dbf ด้วยมือเป็น zip เดียว):
The first part reads the Columbus map from spData, writes columbus.zip for DAPH, builds row-standardised Queen contiguity and fits OLS with its spatial diagnostics (utils::zip needs a zip program on the computer; otherwise compress columbus.shp, .shx and .dbf into one zip by hand):
# Data: the DAPH example dataset (PD cohort) has no map, so this section uses the
# Columbus (Ohio) neighbourhood data that ships with the R package spData.
library(sf); library(spdep)
shp <- system.file("shapes/columbus.shp", package = "spData")
col <- st_read(shp, quiet = TRUE) # 49 neighbourhoods, 1980
# The same polygons for DAPH: zip .shp + .shx + .dbf, then File > Open > columbus.zip
f <- paste0(sub("\\.shp$", "", shp), c(".shp", ".shx", ".dbf"))
invisible(file.copy(f, ".", overwrite = TRUE))
utils::zip("columbus.zip", basename(f), flags = "-9Xq")
# Queen contiguity, row-standardised (DAPH: Weights = Queen contiguity, order 1)
nb <- poly2nb(col, queen = TRUE)
lw <- nb2listw(nb, style = "W")
summary(card(nb)) # neighbours per area
# 1. OLS and the diagnostics DAPH computes on its residuals
ols <- lm(CRIME ~ INC + HOVAL, data = col)
summary(ols)$coefficients
cat(sprintf("OLS R2 = %.4f logLik = %.4f\n", summary(ols)$r.squared, logLik(ols)))
lm.morantest(ols, lw, alternative = "two.sided") # Moran's I of residuals
summary(lm.LMtests(ols, lw, test = "all")) # LM, robust LM, SARMA
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.000 3.000 4.000 4.816 6.000 10.000
Estimate Std. Error t value Pr(>|t|)
(Intercept) 68.6189611 4.7354861 14.490373 9.21089e-19
INC -1.5973108 0.3341308 -4.780496 1.82896e-05
HOVAL -0.2739315 0.1031987 -2.654409 1.08745e-02
OLS R2 = 0.5524 logLik = -187.3772
Global Moran I for regression residuals
Moran I statistic standard deviate = 2.8393, p-value = 0.004521
alternative hypothesis: two.sided
Observed Moran I Expectation Variance
0.222109407 -0.033418335 0.008099305
Lagrange multiplier diagnostics for spatial dependence
statistic parameter p.value
LMerr 5.206214 1 0.022506 *
LMlag 8.897999 1 0.002855 **
RLMerr 0.043906 1 0.834029
RLMlag 3.735691 1 0.053262 .
SARMA 8.941905 2 0.011436 *
library(spatialreg)
# 2. Spatial lag (SLM) and spatial error (SEM) models, maximum likelihood
slm <- lagsarlm(CRIME ~ INC + HOVAL, data = col, listw = lw)
sem <- errorsarlm(CRIME ~ INC + HOVAL, data = col, listw = lw)
summary(slm)$Coef; summary(sem)$Coef
cat(sprintf("rho = %.6f (SE %.4f) lambda = %.6f (SE %.4f)\n",
slm$rho, slm$rho.se, sem$lambda, sem$lambda.se))
# Fit: pseudo-R2 = 1 - sigma2 / Var(y) with Var(y) divided by n
y <- col$CRIME; vy <- mean((y - mean(y))^2)
fit <- data.frame(model = c("OLS", "SLM", "SEM"),
logLik = c(logLik(ols), logLik(slm), logLik(sem)),
k_R = c(attr(logLik(ols), "df"), attr(logLik(slm), "df"), attr(logLik(sem), "df")),
AIC_R = c(AIC(ols), AIC(slm), AIC(sem)),
pseudoR2 = c(summary(ols)$r.squared, 1 - slm$s2 / vy, 1 - sem$s2 / vy))
fit$BIC_R <- c(BIC(ols), BIC(slm), BIC(sem))
# DAPH's convention leaves sigma2 out of k, so its AIC is R's AIC - 2 and BIC is R's BIC - log(n)
fit$AIC_no_sigma2 <- fit$AIC_R - 2
fit$BIC_no_sigma2 <- fit$BIC_R - log(nrow(col))
print(fit, digits = 7)
cat(sprintf("LR vs OLS: SLM = %.4f (p = %.4f), SEM = %.4f (p = %.4f)\n",
2 * (logLik(slm) - logLik(ols)), pchisq(2 * (logLik(slm) - logLik(ols)), 1, lower.tail = FALSE),
2 * (logLik(sem) - logLik(ols)), pchisq(2 * (logLik(sem) - logLik(ols)), 1, lower.tail = FALSE)))
# 3. LeSage-Pace effects of the SLM: point values and 100,000 simulation draws
set.seed(2026)
imp <- impacts(slm, listw = lw, R = 100000)
print(imp)
cat("draws kept:", nrow(imp$sres$direct), "\n")
# 95% limits from all 100,000 draws; the spread of the same limit over 10 batches
# of 10,000 draws is the Monte-Carlo SE of a 10,000-draw limit such as DAPH's
lim <- do.call(rbind, lapply(c("direct", "indirect", "total"), function(e) {
s <- imp$sres[[e]]
do.call(rbind, lapply(colnames(s), function(v) {
x <- s[, v]; q <- quantile(x, c(0.025, 0.975))
bq <- sapply(split(x, cut(seq_along(x), 10, labels = FALSE)), quantile, c(0.025, 0.975))
data.frame(effect = e, variable = v, lower = q[1], upper = q[2],
mcse_lower = sd(bq[1, ]), mcse_upper = sd(bq[2, ]))
}))
}))
rownames(lim) <- NULL; lim[3:6] <- round(lim[3:6], 4)
print(lim)
# SLM
Estimate Std. Error z value Pr(>|z|)
(Intercept) 45.6032484 7.25740386 6.283686 3.306377e-10
INC -1.0487282 0.30740592 -3.411542 6.459658e-04
HOVAL -0.2663348 0.08909629 -2.989292 2.796250e-03
# SEM
Estimate Std. Error z value Pr(>|z|)
(Intercept) 60.2794695 5.36559384 11.234445 0.0000000000
INC -0.9573053 0.33423075 -2.864205 0.0041805763
HOVAL -0.3045593 0.09204732 -3.308725 0.0009372183
rho = 0.423325 (SE 0.1195) lambda = 0.546753 (SE 0.1381)
model logLik k_R AIC_R pseudoR2 BIC_R AIC_no_sigma2 BIC_no_sigma2
1 OLS -187.3772 4 382.7545 0.5524040 390.3218 380.7545 386.4299
2 SLM -182.6740 5 375.3479 0.6468281 384.8070 373.3479 380.9152
3 SEM -183.7494 5 377.4989 0.6438488 386.9580 375.4989 383.0661
LR vs OLS: SLM = 9.4065 (p = 0.0022), SEM = 7.2556 (p = 0.0071)
Impact measures (lag, exact):
Direct Indirect Total
INC -1.1008954 -0.7176834 -1.8185788
HOVAL -0.2795832 -0.1822627 -0.4618459
effect variable lower upper mcse_lower mcse_upper
1 direct INC -1.7143 -0.4843 0.0101 0.0106
2 direct HOVAL -0.4677 -0.0981 0.0027 0.0026
3 indirect INC -1.7118 -0.2237 0.0250 0.0062
4 indirect HOVAL -0.5122 -0.0416 0.0107 0.0012
5 total INC -3.1524 -0.8371 0.0295 0.0188
6 total HOVAL -0.9255 -0.1589 0.0139 0.0036
columbus.zip → Tab 2: ชนิดผลลัพธ์ Spatial · สถิติ Spatial Regression · Dependent = CRIME · Independent = INC, HOVAL · Spatial weights = Queen contiguity, order 1 · Models = OLS, SLM, SEM · Variable selection = Enter · Monte-Carlo draws = 10,000File > Open: columbus.zip → Tab 2: outcome type Spatial · statistic Spatial Regression · Dependent = CRIME · Independent = INC, HOVAL · Spatial weights = Queen contiguity, order 1 · Models = OLS, SLM, SEM · Variable selection = Enter · Monte-Carlo draws = 10,000| ค่าที่วัดQuantity | โมเดลModel | R | DAPH | ความต่างDifference | สถานะStatus |
|---|---|---|---|---|---|
| β INC (SE) | OLS | −1.597311 (0.334131) | −1.597311 (0.334131) | < 1e−6 | ✓ PASS |
| β HOVAL (SE) | OLS | −0.273931 (0.103199) | −0.273931 (0.103199) | < 1e−6 | ✓ PASS |
| R² | OLS | 0.552404 | 0.552404 | < 1e−6 | ✓ PASS |
| Moran's I ของส่วนเหลือ (z; p)Moran's I of residuals (z; p) | OLS | 0.222109 (2.8393; 0.004521) | 0.222109 (2.8393; 0.004521) | < 1e−6 | ✓ PASS |
| LM-lag (p) | OLS | 8.897999 (0.002855) | 8.897999 (0.002855) | < 1e−6 | ✓ PASS |
| LM-error (p) | OLS | 5.206214 (0.022506) | 5.206214 (0.022506) | < 1e−6 | ✓ PASS |
| Robust LM-lag (p) | OLS | 3.735691 (0.053262) | 3.735691 (0.053262) | < 1e−6 | ✓ PASS |
| Robust LM-error (p) | OLS | 0.043906 (0.834029) | 0.043906 (0.834029) | < 1e−6 | ✓ PASS |
| SARMA (p) | OLS | 8.941905 (0.011436) | 8.941905 (0.011436) | < 1e−6 | ✓ PASS |
| ρ | SLM | 0.423325 | 0.423325 | < 1e−6 | ✓ PASS |
| β INC (SE) | SLM | −1.048728 (0.307406) | −1.048728 (0.307406) | < 1e−6 | ✓ PASS |
| β HOVAL (SE) | SLM | −0.266335 (0.089096) | −0.266335 (0.089096) | < 1e−6 | ✓ PASS |
| λ | SEM | 0.546753 | 0.546753 | < 1e−6 | ✓ PASS |
| β INC (SE) | SEM | −0.957305 (0.334231) | −0.957305 (0.334231) | < 1e−6 | ✓ PASS |
| β HOVAL (SE) | SEM | −0.304559 (0.092047) | −0.304559 (0.092047) | < 1e−6 | ✓ PASS |
| Log-likelihood | OLS · SLM · SEM | −187.3772 · −182.6740 · −183.7494 | −187.3772 · −182.6740 · −183.7494 | < 0.0001 | ✓ PASS |
| Pseudo-R² = 1 − σ̂²/Var(y) | SLM · SEM | 0.646828 · 0.643849 | 0.646828 · 0.643849 | < 1e−6 | ✓ PASS |
| AIC (ไม่นับ σ²)AIC (σ² not counted) | OLS · SLM · SEM | 380.7545 · 373.3479 · 375.4989 | 380.7545 · 373.3479 · 375.4989 | < 0.0001 | ✓ PASS |
| BIC (ไม่นับ σ²)BIC (σ² not counted) | OLS · SLM · SEM | 386.4299 · 380.9152 · 383.0661 | 386.4299 · 380.9152 · 383.0661 | < 0.0001 | ✓ PASS |
| LR เทียบกับ OLS (p)LR vs OLS (p) | SLM | 9.4065 (0.0022) | 9.41 (p = 0.002, รายงาน Word)9.41 (p = 0.002, Word report) | 0.0035 (DAPH แสดง 2 ตำแหน่ง)0.0035 (DAPH prints 2 dp) | ✓ PASS |
| Direct INC (95% CI) | SLM | −1.1009 (−1.7143 to −0.4843) | −1.1009 (−1.7158 to −0.4922) | 0 · ขอบ 0.0015 / 0.0079 (เกณฑ์ 0.033)0 · limits 0.0015 / 0.0079 (tolerance 0.033) | ✓ PASS |
| Indirect INC (95% CI) | SLM | −0.7177 (−1.7118 to −0.2237) | −0.7177 (−1.7167 to −0.2299) | 0 · ขอบ 0.0049 / 0.0062 (เกณฑ์ 0.079)0 · limits 0.0049 / 0.0062 (tolerance 0.079) | ✓ PASS |
| Total INC (95% CI) | SLM | −1.8186 (−3.1524 to −0.8371) | −1.8186 (−3.1728 to −0.8636) | 0 · ขอบ 0.0204 / 0.0265 (เกณฑ์ 0.093)0 · limits 0.0204 / 0.0265 (tolerance 0.093) | ✓ PASS |
| Direct HOVAL (95% CI) | SLM | −0.2796 (−0.4677 to −0.0981) | −0.2796 (−0.4644 to −0.0988) | 0 · ขอบ 0.0033 / 0.0007 (เกณฑ์ 0.0085)0 · limits 0.0033 / 0.0007 (tolerance 0.0085) | ✓ PASS |
| Indirect HOVAL (95% CI) | SLM | −0.1823 (−0.5122 to −0.0416) | −0.1823 (−0.5243 to −0.0425) | 0 · ขอบ 0.0121 / 0.0009 (เกณฑ์ 0.034)0 · limits 0.0121 / 0.0009 (tolerance 0.034) | ✓ PASS |
| Total HOVAL (95% CI) | SLM | −0.4618 (−0.9255 to −0.1589) | −0.4618 (−0.9385 to −0.1598) | 0 · ขอบ 0.0130 / 0.0009 (เกณฑ์ 0.044)0 · limits 0.0130 / 0.0009 (tolerance 0.044) | ✓ PASS |
ค่า DAPH อ่านจากผลของ DAPH เอง (ตารางผลและ JSON ของการรัน) ไม่ได้คัดลอกจาก R. ค่าประมาณที่ได้จากการหาค่าเหมาะที่สุดตรงกันภายใน 1e−6. ช่วงเชื่อมั่นของผลกระทบได้จากการสุ่มคนละชุด: DAPH สุ่ม 10,000 ครั้ง ส่วน R สุ่ม 100,000 ครั้ง และพิมพ์ Monte-Carlo SE (s) ของขอบเขตที่ได้จากการสุ่ม 10,000 ครั้ง (ส่วนเบี่ยงเบนมาตรฐานของขอบเขตเดียวกันใน 10 ชุดย่อย ชุดละ 10,000 ครั้ง) เกณฑ์ยอมรับจึงเท่ากับ 3 × s × √(1 + 1/10) = 3.146 × s.DAPH values are read from DAPH's own output (results table and run JSON), never copied from R. Optimiser-based estimates agree within 1e−6. Effect intervals come from different simulations: DAPH draws 10,000 times and R 100,000 times, and R prints the Monte-Carlo SE (s) of a 10,000-draw limit (the standard deviation of the same limit over 10 batches of 10,000 draws), so the tolerance is 3 × s × √(1 + 1/10) = 3.146 × s.
4การแปลผลและตัวอย่างInterpretation and Example
ขั้นที่ 1 — มีความสัมพันธ์เชิงพื้นที่เหลืออยู่หรือไม่: Moran's I ของส่วนเหลือ OLS = 0.222 (p = 0.005) แสดงว่าส่วนเหลือของย่านที่อยู่ติดกันยังคล้ายกัน SE และ p-value ของ OLS จึงใช้ไม่ได้. การทดสอบ LM: LM-lag = 8.90 (p = 0.003), LM-error = 5.21 (p = 0.023) มีนัยสำคัญทั้งคู่ แต่ robust LM-lag = 3.74 (p = 0.053) และ robust LM-error = 0.04 (p = 0.834) ไม่มีนัยสำคัญทั้งคู่ → กฎข้อ (4): สรุปไม่ได้ว่าเป็นแบบ lag หรือ error.
Step 1 — Is spatial dependence left over? Moran's I of the OLS residuals = 0.222 (p = 0.005): residuals of adjacent neighbourhoods are still alike, so the OLS SEs and p-values are not valid. LM tests: LM-lag = 8.90 (p = 0.003) and LM-error = 5.21 (p = 0.023) are both significant, but robust LM-lag = 3.74 (p = 0.053) and robust LM-error = 0.04 (p = 0.834) are both not → rule (4): the tests cannot tell lag from error dependence.
ขั้นที่ 2 — เลือกด้วยความเหมาะสมของแบบจำลอง: AIC ของ DAPH: SLM = 373.35, SEM = 375.50, OLS = 380.75 → DAPH แปลผล SLM (AIC ต่ำสุด) และ LR เทียบกับ OLS = 9.41, df = 1, p = 0.002 แสดงว่า ρ ต่างจาก 0. ผลต่าง AIC ระหว่าง SLM กับ SEM มีเพียง 2.15 จึงควรรายงาน SEM ประกอบเป็นการวิเคราะห์ความไว.
Step 2 — Choose on fit: DAPH's AIC: SLM = 373.35, SEM = 375.50, OLS = 380.75 → DAPH interprets the SLM (lowest AIC), and the LR test against OLS = 9.41, df = 1, p = 0.002 shows that ρ differs from 0. The AIC gap between SLM and SEM is only 2.15, so the SEM should be reported alongside as a sensitivity analysis.
ขั้นที่ 3 — อ่าน ρ และผลกระทบ: ρ̂ = 0.423: อัตราอาชญากรรมของย่านหนึ่งสัมพันธ์ทางบวกกับค่าเฉลี่ยของอัตราในย่านข้างเคียง หลังคุมรายได้และมูลค่าบ้านแล้ว (ρ ไม่ใช่สัดส่วนที่อธิบายได้). สัมประสิทธิ์ดิบของ SLM (INC = −1.05) ไม่ใช่ผลส่วนเพิ่ม ให้อ่านจากตารางผลกระทบ: รายได้ครัวเรือนที่สูงขึ้น 1,000 ดอลลาร์ สัมพันธ์กับการลักทรัพย์และขโมยรถที่น้อยลง 1.10 ครั้งต่อ 1,000 ครัวเรือนในย่านเดียวกัน (Direct, 95% CI −1.72 to −0.49) และ 0.72 ครั้งผ่านย่านอื่น (Indirect, 95% CI −1.72 to −0.23) รวม 1.82 (Total, 95% CI −3.17 to −0.86). มูลค่าบ้านที่สูงขึ้น 1,000 ดอลลาร์: Direct −0.28 (95% CI −0.46 to −0.10), Total −0.46 (95% CI −0.94 to −0.16).
Step 3 — Read ρ and the effects: ρ̂ = 0.423: a neighbourhood's crime rate is positively associated with the average rate of its neighbours after income and housing value are controlled (ρ is not an attributable fraction). The raw SLM coefficient (INC = −1.05) is not a marginal effect; read the effects table: USD 1,000 more household income is associated with 1.10 fewer burglaries and vehicle thefts per 1,000 households in the same neighbourhood (Direct, 95% CI −1.72 to −0.49) and 0.72 fewer through the other neighbourhoods (Indirect, 95% CI −1.72 to −0.23), 1.82 in total (Total, 95% CI −3.17 to −0.86). USD 1,000 more housing value: Direct −0.28 (95% CI −0.46 to −0.10), Total −0.46 (95% CI −0.94 to −0.16).
ข้อตกลงที่ DAPH ตรวจและข้อจำกัด: DAPH ตรวจส่วนเหลือของ OLS: Jarque–Bera p = 0.399 (ไม่พบหลักฐานว่าไม่ปกติ), Breusch–Pagan p = 0.019 (ใช้กำลังสองของตัวแปรอธิบาย — พบความแปรปรวนไม่คงที่ ซึ่ง SE แบบ ML สมมติว่าไม่มี) และ condition number = 6.5 (ไม่มีปัญหา collinearity). ผลเป็นความสัมพันธ์ระดับพื้นที่ในข้อมูลภาคตัดขวาง ไม่ใช่ความเป็นเหตุเป็นผลและไม่ใช่ข้อสรุปรายบุคคล และผลขึ้นกับการเลือก W — ควรทำซ้ำด้วย weights แบบอื่นเป็นการวิเคราะห์ความไว.
Checks DAPH performs and limitations: DAPH tests the OLS residuals: Jarque–Bera p = 0.399 (no evidence against normality), Breusch–Pagan p = 0.019 (on the squared predictors — heteroskedasticity is present, which the ML standard errors assume away) and condition number = 6.5 (no collinearity problem). The results are cross-sectional area-level associations, not causal effects and not statements about individuals, and they depend on the choice of W — repeat the analysis with another weights matrix as a sensitivity analysis.
📖 References
- Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
- Anselin, L., Bera, A. K., Florax, R., & Yoon, M. J. (1996). Simple diagnostic tests for spatial dependence. Regional Science and Urban Economics, 26(1), 77–104. doi:10.1016/0166-0462(95)02111-6
- Bivand, R., & Piras, G. (2015). Comparing implementations of estimation methods for spatial econometrics. Journal of Statistical Software, 63(18). doi:10.18637/jss.v063.i18
- Burnham, K. P., & Anderson, D. R. (2002). Model selection and multimodel inference: A practical information-theoretic approach (2nd ed.). Springer. ISBN 978-0-387-95364-9. doi:10.1007/b97636
- Kelejian, H. H., & Prucha, I. R. (2010). Specification and estimation of spatial autoregressive models with autoregressive and heteroskedastic disturbances. Journal of Econometrics, 157(1), 53–67. doi:10.1016/j.jeconom.2009.10.025
- LeSage, J., & Pace, R. K. (2009). Introduction to spatial econometrics. Chapman & Hall/CRC. doi:10.1201/9781420064254
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
6.2 Spatial Durbin Model (SDM)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Spatial Durbin Model (SDM) ขยาย Spatial Lag Model (SLM, หัวข้อ 6.1) โดยเพิ่ม ค่าเฉลี่ยถ่วงน้ำหนักของตัวแปรอธิบายในพื้นที่ข้างเคียง (W·X) เข้าไปในสมการ ผลลัพธ์ของพื้นที่หนึ่งจึงขึ้นกับทั้งผลลัพธ์ของเพื่อนบ้าน (ρWy) และลักษณะของเพื่อนบ้าน (WXθ). ใช้เมื่อมีเหตุผลว่าลักษณะของพื้นที่ข้างเคียงสัมพันธ์กับผลลัพธ์ของพื้นที่เรา (เช่น บริการสุขภาพของอำเภอข้างเคียง) หรือเมื่อสงสัยว่ามีตัวแปรที่ไม่ได้วัดซึ่งเกาะกลุ่มเชิงพื้นที่และสัมพันธ์กับตัวแปรอธิบาย — LeSage & Pace (2009) แสดงว่าในกรณีนั้น SLM และ SEM ให้ค่าประมาณที่ลำเอียง แต่ SDM ไม่ลำเอียง. SLM (θ = 0) และ SEM (θ = −ρβ) เป็นกรณีพิเศษของ SDM จึงทดสอบได้ว่ารูปแบบที่ง่ายกว่าเพียงพอหรือไม่.
The Spatial Durbin Model (SDM) extends the Spatial Lag Model (SLM, 6.1) by adding the weighted average of the explanatory variables in neighbouring areas (W·X): an area's outcome depends both on its neighbours' outcome (ρWy) and on its neighbours' characteristics (WXθ). Use it when neighbouring areas' characteristics can plausibly relate to the local outcome (for example, health services in adjacent districts), or when omitted variables are suspected to be spatially clustered and correlated with the predictors — LeSage & Pace (2009) show that the SLM and the SEM are then biased while the SDM is not. The SLM (θ = 0) and the SEM (θ = −ρβ) are special cases of the SDM, so whether a simpler form suffices can be tested.
ใน DAPH, SDM เป็นช่องติ๊กในตัวเลือกแบบจำลองของ Spatial Regression (OLS / SLM / SEM / SDM) และประมาณค่าเฉพาะเมื่อติ๊กเลือก รายงานแสดงบล็อกสัมประสิทธิ์ W×X, การทดสอบ Wald สองข้อ และตารางผลกระทบ direct / spillover / total. ข้อกำหนดเรื่องข้อมูลเหมือน 6.1 (ผลลัพธ์ต่อเนื่องรายพื้นที่ ข้อมูลครบอย่างน้อย 30 พื้นที่); SDM มีพารามิเตอร์มากกว่า SLM อีก k ตัว (หนึ่ง θ ต่อหนึ่งตัวแปรอธิบาย) จึงไม่เหมาะกับพื้นที่จำนวนน้อยและตัวแปรจำนวนมาก.
In DAPH the SDM is a tickbox in the Spatial Regression model picker (OLS / SLM / SEM / SDM) and is fitted only when ticked; the report shows the W×X coefficient block, two Wald tests and the direct / spillover / total effects table. The data requirements are those of 6.1 (a continuous area-level outcome, at least 30 complete areas); the SDM has k more parameters than the SLM (one θ per predictor), so it suits neither few areas nor many predictors.
spData; ข้อมูลตัวอย่างผู้ป่วยของ DAPH ไม่มีแผนที่จึงใช้ไม่ได้). คำถามวิจัย: รายได้ครัวเรือน (INC) และมูลค่าบ้าน (HOVAL) ของ ย่านข้างเคียง สัมพันธ์กับอัตราการลักทรัพย์และขโมยรถ (CRIME) ของย่านหนึ่ง นอกเหนือจากรายได้และมูลค่าบ้านของย่านนั้นเองหรือไม่ และ SDM จำเป็นกว่า SLM หรือ SEM หรือไม่.
spData; the DAPH patient example has no map). Research question: are the household income (INC) and housing value (HOVAL) of neighbouring neighbourhoods associated with a neighbourhood's burglary and vehicle-theft rate (CRIME) beyond its own income and housing value, and is the SDM needed rather than the SLM or the SEM?
2หลักการและสูตรLogic and Formula
- W
- spatial weights ที่ปรับผลรวมแถวเป็น 1 (เหมือน 6.1)row-standardised spatial weights (as in 6.1)
- WX
- ค่าเฉลี่ยถ่วงน้ำหนักของตัวแปรอธิบายแต่ละตัวในพื้นที่ข้างเคียง (ไม่รวมค่าคงที่) — DAPH แสดงเป็นแถว "W × ชื่อตัวแปร"the neighbours' weighted average of each predictor (constant excluded) — shown by DAPH as rows "W × variable"
- θ
- สัมประสิทธิ์ของ WX (หนึ่งค่าต่อหนึ่งตัวแปรอธิบาย, รวม k ค่า)coefficients of WX (one per predictor, k in total)
- ρ
- สัมประสิทธิ์ของผลลัพธ์ในพื้นที่ข้างเคียง ค้นในช่วง (−1, 1)coefficient of the neighbours' outcome, searched within (−1, 1)
การประมาณค่า: DAPH ประมาณ SDM เป็น SLM บนเมทริกซ์ตัวแปรที่ขยายแล้ว [X, WX] ด้วย maximum likelihood แบบเดียวกับ 6.1 (concentrated log-likelihood, log-determinant ln|I − ρW| แบบตรงจากเมทริกซ์เต็ม, SE จาก inverse ของ information matrix เชิงวิเคราะห์, z-test) — ตรงกับ lagsarlm(..., Durbin = TRUE) ของ R. เมื่อเลือก weights แบบ KNN จะใช้ spatial two-stage least squares (GMM) แทน และไม่มี log-likelihood. ค่า R² ในตารางคือ 1 − σ̂²/Var(y) (หารด้วย n) และ AIC = −2ℓ + 2k โดย k = ค่าคงที่ + β + θ + ρ (DAPH ไม่นับ σ² ส่วน R นับ ค่า AIC ของ R จึงมากกว่า 2 หน่วย).
Estimation: DAPH fits the SDM as an SLM on the extended design [X, WX] by maximum likelihood exactly as in 6.1 (concentrated log-likelihood, log-determinant ln|I − ρW| computed exactly from the full matrix, SEs from the inverse of the analytical information matrix, z-tests) — the same as R's lagsarlm(..., Durbin = TRUE). With KNN weights it uses spatial two-stage least squares (GMM) instead, which has no log-likelihood. The R² in the table is 1 − σ̂²/Var(y) (divided by n), and AIC = −2ℓ + 2k with k = constant + β + θ + ρ (DAPH leaves σ² out while R counts it, so R's AIC is 2 units higher).
- V̂
- เมทริกซ์ความแปรปรวนร่วมของ (β, θ, ρ) จาก information matrix · V̂θθ คือส่วนของ θcovariance matrix of (β, θ, ρ) from the information matrix · V̂θθ is its θ block
- G
- อนุพันธ์ของ g เทียบกับ (β, θ, ρ) — Wald แบบ delta method (common-factor test)derivative of g with respect to (β, θ, ρ) — the delta-method Wald (common-factor test)
- ค่าติดลบnegative value
- Wald เป็นรูปกำลังสองจึงติดลบไม่ได้ ถ้าคำนวณได้ค่าติดลบ (V̂ ไม่ positive definite) DAPH รายงานว่าทดสอบไม่ได้ ไม่แปลเป็น p = 1a Wald statistic is a quadratic form and cannot be negative; if one comes out negative (V̂ not positive definite) DAPH reports the test as unavailable instead of reading it as p = 1
R มีการทดสอบแบบ likelihood-ratio (LR) ของสองข้อนี้ด้วย (LR.Sarlm: SDM เทียบ SLM และ SDM เทียบ SEM) ซึ่งให้ข้อสรุปใกล้เคียงกันในตัวอย่างนี้ แต่ DAPH ใช้ Wald.
R also offers likelihood-ratio (LR) versions of both tests (LR.Sarlm: SDM against SLM and SDM against SEM); they lead to the same conclusions here, but DAPH uses the Wald forms.
กฎเลือกแบบจำลองของ DAPH เมื่อติ๊ก SDM (ยุทธศาสตร์ของ Elhorst, 2010 ร่วมกับ LM cascade ของ 6.1, ระดับนัยสำคัญ 0.05):
DAPH's model choice when the SDM is ticked (Elhorst's 2010 strategy combined with the LM cascade of 6.1, significance level 0.05):
| ผลการทดสอบTest results | แบบจำลองที่ DAPH แปลผลModel DAPH interprets |
|---|---|
| LM cascade ไม่พบความสัมพันธ์เชิงพื้นที่ และไม่ปฏิเสธ θ = 0LM cascade finds no spatial dependence and θ = 0 is not rejected | OLS |
| LM cascade ไม่พบความสัมพันธ์ แต่ปฏิเสธ θ = 0 (LM ตรวจ W×X ไม่ได้)LM cascade finds none, but θ = 0 is rejected (the LM tests cannot detect W×X) | SDM |
| ปฏิเสธ θ = 0 และปฏิเสธ common factorθ = 0 rejected and common factor rejected | SDM — แปลผลผ่านตารางผลกระทบ ไม่ใช่สัมประสิทธิ์ดิบ— interpret through the effects table, not the raw coefficients |
| ไม่ปฏิเสธ θ = 0 แต่ปฏิเสธ common factorθ = 0 not rejected, common factor rejected | SLM |
| ปฏิเสธ θ = 0 แต่ไม่ปฏิเสธ common factorθ = 0 rejected, common factor not rejected | SEM |
| ไม่ปฏิเสธทั้งสองข้อneither rejected | ตามผล LM cascade (SLM หรือ SEM); ถ้า LM cascade สรุปไม่ได้ → เลือกแบบจำลองเชิงพื้นที่ที่ติ๊กไว้ซึ่งมี AIC ต่ำสุด (เกณฑ์สารสนเทศและ LR test ตาม 6.1; Burnham & Anderson, 2002)follow the LM cascade (SLM or SEM); if the cascade is inconclusive → the ticked spatial model with the lowest AIC (information criteria and LR test as in 6.1; Burnham & Anderson, 2002) |
| คำนวณ Wald ไม่ได้Wald tests unavailable | ตามผล LM cascade; ถ้าสรุปไม่ได้ → AIC ต่ำสุดfollow the LM cascade; if inconclusive → lowest AIC |
ถ้าแบบจำลองที่กฎเลือกไม่ได้ถูกติ๊กไว้ รายงานจะแปลผลแบบจำลองที่ติ๊กไว้ซึ่งมี AIC ต่ำสุดและบอกเหตุผลไว้. เมื่อ SDM ไม่ใช่แบบจำลองที่เลือก ตารางผลกระทบของ SDM ยังแสดงเป็น "ตารางเสริม" เพื่อเปรียบเทียบ ไม่ใช่ค่าที่ใช้อ้างในผลการวิจัย.
If the model the rule picks was not ticked, the report interprets the ticked model with the lowest AIC and says so. When the SDM is not the retained model, its effects table is still printed as a "supplementary table" for comparison, not as a result to quote.
- S_r(W)
- เมทริกซ์ผลกระทบของตัวแปร r คำนวณจาก (I − ρW)⁻¹ ทั้งเมทริกซ์ (ถูกต้องแม้มีพื้นที่ที่ไม่มีเพื่อนบ้าน)impact matrix of predictor r, computed from the full (I − ρW)⁻¹ (exact even when some areas have no neighbours)
- Direct
- ผลต่อผลลัพธ์ของพื้นที่เดียวกันเมื่อ x ของพื้นที่นั้นเพิ่ม 1 หน่วย (รวมผลย้อนกลับผ่านเพื่อนบ้าน)effect on an area's own outcome of a one-unit increase in its own x (including feedback through neighbours)
- Spillover
- ผลทางอ้อม (indirect effect): ผลรวมต่อพื้นที่อื่นเมื่อ x ของพื้นที่หนึ่งเพิ่ม 1 หน่วย เฉลี่ยทุกพื้นที่the indirect effect: summed effect on the other areas of a one-unit increase in one area's x, averaged over areas
- 95% CI
- สุ่ม 10,000 ชุด (ตั้งได้ 100–100,000) ของ (ค่าคงที่, β, θ, ρ) จาก N(θ̂, V̂) ด้วย seed คงที่ จำกัด ρ ไว้ที่ ±0.99 แล้วใช้เปอร์เซ็นไทล์ที่ 2.5 และ 97.5 · "*" = CI ไม่คร่อม 010,000 draws (settable, 100–100,000) of (constant, β, θ, ρ) from N(θ̂, V̂) with a fixed seed, ρ capped at ±0.99, then the 2.5th and 97.5th percentiles · "*" = CI excludes 0
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
ใช้แผนที่และ Queen contiguity ชุดเดียวกับ 6.1 (สคริปต์สร้าง columbus.zip ซ้ำเพื่อให้หัวข้อนี้รันได้ด้วยตัวเอง):
The same map and Queen contiguity as in 6.1 (the script writes columbus.zip again so this section runs on its own):
# Data: Columbus (Ohio) neighbourhoods from the R package spData, as in 6.1
# (the DAPH example dataset has no map). columbus.zip is the file to open in DAPH.
library(sf); library(spdep); library(spatialreg)
shp <- system.file("shapes/columbus.shp", package = "spData")
col <- st_read(shp, quiet = TRUE)
f <- paste0(sub("\\.shp$", "", shp), c(".shp", ".shx", ".dbf"))
invisible(file.copy(f, ".", overwrite = TRUE))
utils::zip("columbus.zip", basename(f), flags = "-9Xq")
lw <- nb2listw(poly2nb(col, queen = TRUE), style = "W")
# Spatial Durbin model: y = rho*Wy + X*beta + WX*theta + e (maximum likelihood)
sdm <- lagsarlm(CRIME ~ INC + HOVAL, data = col, listw = lw, Durbin = TRUE)
summary(sdm)$Coef # lag.INC, lag.HOVAL = theta
cat(sprintf("rho = %.6f (SE %.6f, z-test p = %.6f)\n", sdm$rho, sdm$rho.se,
2 * pnorm(-abs(sdm$rho / sdm$rho.se))))
y <- col$CRIME
cat(sprintf("logLik = %.4f AIC (R, counts sigma2) = %.4f AIC without sigma2 = %.4f pseudo-R2 = %.6f\n",
logLik(sdm), AIC(sdm), AIC(sdm) - 2, 1 - sdm$s2 / mean((y - mean(y))^2)))
Estimate Std. Error z value Pr(>|z|)
(Intercept) 44.3200029 13.0454739 3.397347 0.000680426
INC -0.9199061 0.3347419 -2.748106 0.005994070
HOVAL -0.2971294 0.0904159 -3.286251 0.001015304
lag.INC -0.5839133 0.5742245 -1.016873 0.309213954
lag.HOVAL 0.2576843 0.1872349 1.376262 0.168740384
rho = 0.403463 (SE 0.161334, z-test p = 0.012392)
logLik = -181.6393 AIC (R, counts sigma2) = 377.2785 AIC without sigma2 = 375.2785 pseudo-R2 = 0.659900
# Wald tests of the two restrictions (DAPH uses these Wald forms)
b <- coef(sdm); V <- vcov(sdm) # includes rho
th <- b[c("lag.INC", "lag.HOVAL")]; be <- b[c("INC", "HOVAL")]; rho <- b["rho"]
w_theta <- drop(t(th) %*% solve(V[names(th), names(th)]) %*% th)
g <- th + rho * be # common factor: theta = -rho * beta
J <- matrix(0, 2, length(b), dimnames = list(NULL, names(b)))
J[1, c("INC", "lag.INC")] <- c(rho, 1); J[2, c("HOVAL", "lag.HOVAL")] <- c(rho, 1)
J[, "rho"] <- be
w_cf <- drop(t(g) %*% solve(J %*% V %*% t(J)) %*% g)
cat(sprintf("Wald theta = 0: chi2(2) = %.4f, p = %.4f\n", w_theta, pchisq(w_theta, 2, lower.tail = FALSE)))
cat(sprintf("Wald common factor: chi2(2) = %.4f, p = %.4f\n", w_cf, pchisq(w_cf, 2, lower.tail = FALSE)))
# Likelihood-ratio versions of the same two tests (for comparison)
slm <- lagsarlm(CRIME ~ INC + HOVAL, data = col, listw = lw)
sem <- errorsarlm(CRIME ~ INC + HOVAL, data = col, listw = lw)
LR.Sarlm(sdm, slm); LR.Sarlm(sdm, sem)
# LeSage-Pace effects of the SDM: point values and 100,000 simulation draws
set.seed(2026)
imp <- impacts(sdm, listw = lw, R = 100000)
print(imp)
cat("draws kept:", nrow(imp$sres$direct), "\n")
# 95% limits from all 100,000 draws; the spread of the same limit over 10 batches
# of 10,000 draws is the Monte-Carlo SE of a 10,000-draw limit such as DAPH's
lim <- do.call(rbind, lapply(c("direct", "indirect", "total"), function(e) {
s <- imp$sres[[e]]
do.call(rbind, lapply(colnames(s), function(v) {
x <- s[, v]; q <- quantile(x, c(0.025, 0.975))
bq <- sapply(split(x, cut(seq_along(x), 10, labels = FALSE)), quantile, c(0.025, 0.975))
data.frame(effect = e, variable = v, lower = q[1], upper = q[2],
mcse_lower = sd(bq[1, ]), mcse_upper = sd(bq[2, ]))
}))
}))
rownames(lim) <- NULL; lim[3:6] <- round(lim[3:6], 4)
print(lim)
Wald theta = 0: chi2(2) = 2.1330, p = 0.3442
Wald common factor: chi2(2) = 4.4737, p = 0.1068
Likelihood ratio for spatial linear models
Likelihood ratio = 2.0694, df = 2, p-value = 0.3553
Likelihood ratio for spatial linear models
Likelihood ratio = 4.2203, df = 2, p-value = 0.1212
Impact measures (mixed, exact):
Direct Indirect Total
INC -1.0249878 -1.495926 -2.52091388
HOVAL -0.2819673 0.215844 -0.06612334
draws kept: 99991
effect variable lower upper mcse_lower mcse_upper
1 direct INC -1.6635 -0.3848 0.0079 0.0090
2 direct HOVAL -0.4648 -0.0999 0.0024 0.0021
3 indirect INC -3.2472 -0.0458 0.0305 0.0192
4 indirect HOVAL -0.4009 0.8923 0.0097 0.0093
5 total INC -4.4001 -0.9710 0.0303 0.0440
6 total HOVAL -0.7518 0.6792 0.0076 0.0138
columbus.zip → Tab 2: ชนิดผลลัพธ์ Spatial · สถิติ Spatial Regression · Dependent = CRIME · Independent = INC, HOVAL · Spatial weights = Queen contiguity, order 1 · Models = OLS, SLM, SEM, SDM · Variable selection = Enter · Monte-Carlo draws = 10,000 (และรันซ้ำด้วย 100,000)File > Open: columbus.zip → Tab 2: outcome type Spatial · statistic Spatial Regression · Dependent = CRIME · Independent = INC, HOVAL · Spatial weights = Queen contiguity, order 1 · Models = OLS, SLM, SEM, SDM · Variable selection = Enter · Monte-Carlo draws = 10,000 (and a second run with 100,000)| ค่าที่วัดQuantity | R | DAPH | ความต่างDifference | สถานะStatus |
|---|---|---|---|---|
| ρ (SE; p) | 0.403463 (0.161334; 0.012392) | 0.403463 (0.161334; 0.012392) | < 1e−6 | ✓ PASS |
| β INC (SE) | −0.919906 (0.334742) | −0.919906 (0.334742) | < 1e−6 | ✓ PASS |
| β HOVAL (SE) | −0.297129 (0.090416) | −0.297129 (0.090416) | < 1e−6 | ✓ PASS |
| θ W×INC (SE; p) | −0.583913 (0.574224; 0.309214) | −0.583913 (0.574224; 0.309214) | < 1e−6 | ✓ PASS |
| θ W×HOVAL (SE; p) | 0.257684 (0.187235; 0.168740) | 0.257684 (0.187235; 0.168740) | < 1e−6 | ✓ PASS |
| ค่าคงที่ (SE)Constant (SE) | 44.320003 (13.045474) | 44.320003 (13.045474) | < 1e−6 | ✓ PASS |
| Log-likelihood | −181.6393 | −181.6393 | < 0.0001 | ✓ PASS |
| AIC (ไม่นับ σ²)AIC (σ² not counted) | 375.2785 | 375.2785 | < 0.0001 | ✓ PASS |
| Pseudo-R² = 1 − σ̂²/Var(y) | 0.659900 | 0.659900 | < 1e−6 | ✓ PASS |
| Wald θ = 0: χ²(2) (p) | 2.1330 (0.3442) | 2.1330 (0.3442) | < 0.0001 | ✓ PASS |
| Wald common factor: χ²(2) (p) | 4.4737 (0.1068) | 4.4737 (0.1068) | < 0.0001 | ✓ PASS |
| Direct INC (95% CI) · DAPH 10,000 ครั้งDirect INC (95% CI) · DAPH 10,000 draws | −1.0250 (−1.6635 to −0.3848) | −1.0250 (−1.6513 to −0.3853) | 0 · ขอบ 0.0122 / 0.0005 (เกณฑ์ 0.028)0 · limits 0.0122 / 0.0005 (tolerance 0.028) | ✓ PASS |
| Spillover INC (95% CI) · DAPH 10,000 ครั้งSpillover INC (95% CI) · DAPH 10,000 draws | −1.4959 (−3.2472 to −0.0458) | −1.4959 (−3.3347 to −0.0977) | 0 · ขอบ 0.0875 / 0.0519 (เกณฑ์ 0.096)0 · limits 0.0875 / 0.0519 (tolerance 0.096) | ✓ PASS |
| Total INC (95% CI) · DAPH 10,000 ครั้งTotal INC (95% CI) · DAPH 10,000 draws | −2.5209 (−4.4001 to −0.9710) | −2.5209 (−4.4483 to −1.0247) | 0 · ขอบ 0.0482 / 0.0537 (เกณฑ์ 0.138)0 · limits 0.0482 / 0.0537 (tolerance 0.138) | ✓ PASS |
| Direct HOVAL (95% CI) · DAPH 10,000 ครั้งDirect HOVAL (95% CI) · DAPH 10,000 draws | −0.2820 (−0.4648 to −0.0999) | −0.2820 (−0.4623 to −0.0947) | 0 · ขอบ 0.0025 / 0.0052 (เกณฑ์ 0.0076)0 · limits 0.0025 / 0.0052 (tolerance 0.0076) | ✓ PASS |
| Spillover HOVAL (95% CI) · DAPH 10,000 ครั้งSpillover HOVAL (95% CI) · DAPH 10,000 draws | 0.2158 (−0.4009 to 0.8923) | 0.2158 (−0.3664 to 0.9383) | 0 · ขอบ 0.0345 / 0.0460 (เกณฑ์ 0.031)0 · limits 0.0345 / 0.0460 (tolerance 0.031) | ✗ FAIL |
| Total HOVAL (95% CI) · DAPH 10,000 ครั้งTotal HOVAL (95% CI) · DAPH 10,000 draws | −0.0661 (−0.7518 to 0.6792) | −0.0661 (−0.7249 to 0.7236) | 0 · ขอบ 0.0269 / 0.0444 (เกณฑ์ 0.043)0 · limits 0.0269 / 0.0444 (tolerance 0.043) | ✗ FAIL |
| Spillover HOVAL (95% CI) · DAPH 100,000 ครั้งSpillover HOVAL (95% CI) · DAPH 100,000 draws | 0.2158 (−0.4009 to 0.8923) | 0.2158 (−0.3919 to 0.9003) | 0 · ขอบ 0.0090 / 0.0080 (เกณฑ์ 0.013)0 · limits 0.0090 / 0.0080 (tolerance 0.013) | ✓ PASS |
| Total HOVAL (95% CI) · DAPH 100,000 ครั้งTotal HOVAL (95% CI) · DAPH 100,000 draws | −0.0661 (−0.7518 to 0.6792) | −0.0661 (−0.7432 to 0.6860) | 0 · ขอบ 0.0086 / 0.0068 (เกณฑ์ 0.019)0 · limits 0.0086 / 0.0068 (tolerance 0.019) | ✓ PASS |
ค่า DAPH อ่านจากผลการรันของ DAPH เอง. ค่าประมาณจากการหาค่าเหมาะที่สุดตรงกันภายใน 1e−6. ช่วงเชื่อมั่นของผลกระทบได้จากการสุ่มคนละชุด: R สุ่ม 100,000 ครั้ง (ตัด 9 ชุดที่ ρ ≥ 1 ทิ้ง ส่วน DAPH จำกัด ρ ไว้ที่ 0.99) และพิมพ์ Monte-Carlo SE (s) ของขอบเขตที่ได้จากการสุ่ม 10,000 ครั้ง; เกณฑ์ยอมรับ = 3.146 × s เมื่อ DAPH สุ่ม 10,000 ครั้ง และ 1.342 × s เมื่อ DAPH สุ่ม 100,000 ครั้ง. แถวที่ ✗ FAIL: ด้วยค่าเริ่มต้น 10,000 ครั้งและ seed คงที่ ขอบเขตของผลกระทบ HOVAL ของ DAPH ห่างจากค่าระยะยาวเกิน 3 Monte-Carlo SE (ไม่ใช่สูตรผิด — เมื่อสุ่ม 100,000 ครั้งค่าตรงกับ R) จึงควรตั้งจำนวนการสุ่มเป็น 100,000 เมื่อจะตีพิมพ์.DAPH values are read from DAPH's own run. Optimiser-based estimates agree within 1e−6. Effect intervals come from different simulations: R draws 100,000 times (dropping the 9 draws with ρ ≥ 1, where DAPH caps ρ at 0.99) and prints the Monte-Carlo SE (s) of a 10,000-draw limit; the tolerance is 3.146 × s when DAPH draws 10,000 times and 1.342 × s when DAPH draws 100,000 times. ✗ FAIL rows: with the default 10,000 draws and its fixed seed, DAPH's limits for the HOVAL effects lie more than 3 Monte-Carlo SE from the long-run value (not a formula error — with 100,000 draws they match R), so set the draws to 100,000 for publication.
4การแปลผลและตัวอย่างInterpretation and Example
ขั้นที่ 1 — SDM จำเป็นหรือไม่: Wald θ = 0: χ²(2) = 2.13, p = 0.344 (ไม่ปฏิเสธ — ไม่มีหลักฐานว่ารายได้และมูลค่าบ้านของย่านข้างเคียงสัมพันธ์กับอาชญากรรมของย่านหนึ่งเพิ่มเติม) และ common factor: χ²(2) = 4.47, p = 0.107 (ไม่ปฏิเสธ). ไม่ปฏิเสธทั้งสองข้อและ LM cascade ของ 6.1 สรุปไม่ได้ DAPH จึงเลือกด้วย AIC: SLM = 373.35, SDM = 375.28, SEM = 375.50 → แปลผล SLM (ตามที่อธิบายใน 6.1). การไม่ปฏิเสธ θ = 0 ไม่ได้พิสูจน์ว่า θ = 0 — ข้อมูล 49 ย่านอาจมีกำลังทดสอบไม่พอ.
Step 1 — Is the SDM needed? Wald θ = 0: χ²(2) = 2.13, p = 0.344 (not rejected — no evidence that neighbours' income and housing value are associated with a neighbourhood's crime beyond the lag) and common factor: χ²(2) = 4.47, p = 0.107 (not rejected). With neither restriction rejected and the 6.1 LM cascade inconclusive, DAPH chooses by AIC: SLM = 373.35, SDM = 375.28, SEM = 375.50 → the SLM is interpreted (as described in 6.1). Not rejecting θ = 0 does not prove θ = 0 — 49 neighbourhoods may give the tests little power.
ขั้นที่ 2 — ถ้า SDM เป็นแบบจำลองที่เลือก ให้อ่านตารางผลกระทบ ไม่ใช่ β หรือ θ ดิบ: ใน SDM ผลของตัวแปรหนึ่งไหลผ่าน (I − ρW)⁻¹ ทั้งระบบ. ในตัวอย่างนี้ (ตารางเสริมของ DAPH) รายได้ที่สูงขึ้น 1,000 ดอลลาร์: direct −1.02 (95% CI −1.65 to −0.39), spillover −1.50 (95% CI −3.33 to −0.10), total −2.52 (95% CI −4.45 to −1.02); มูลค่าบ้าน: direct −0.28 (95% CI −0.46 to −0.09) แต่ spillover 0.22 (95% CI −0.37 to 0.94) และ total −0.07 (95% CI −0.72 to 0.72) คร่อม 0 จึงสรุปทิศทางไม่ได้ (ไม่ได้แปลว่าไม่มีผล). เนื่องจากการทดสอบไม่สนับสนุน SDM ค่าชุดนี้ใช้เปรียบเทียบเท่านั้น.
Step 2 — If the SDM is the retained model, read the effects table, not the raw β or θ: in the SDM a predictor's effect passes through the whole (I − ρW)⁻¹. In this example (DAPH's supplementary table) USD 1,000 more income: direct −1.02 (95% CI −1.65 to −0.39), spillover −1.50 (95% CI −3.33 to −0.10), total −2.52 (95% CI −4.45 to −1.02); housing value: direct −0.28 (95% CI −0.46 to −0.09), but spillover 0.22 (95% CI −0.37 to 0.94) and total −0.07 (95% CI −0.72 to 0.72) span 0, so no direction can be concluded (which is not the same as no effect). Because the tests do not support the SDM, these values are for comparison only.
ข้อจำกัด: เป็นความสัมพันธ์ระดับพื้นที่ในข้อมูลภาคตัดขวาง ไม่ใช่ความเป็นเหตุเป็นผล · ช่วงเชื่อมั่นของผลกระทบได้จากการสุ่ม ทศนิยมตำแหน่งที่สองอาจต่างกันได้เมื่อเปลี่ยนจำนวนการสุ่ม (ดูตารางทวนสอบ) — ถ้าจะตีพิมพ์ ให้ตั้งจำนวนการสุ่มเป็น 100,000.
Limitations: cross-sectional area-level associations, not causal effects · effect intervals are simulated and the second decimal can move with the number of draws (see the verification table) — for publication, set the draws to 100,000.
📖 References
- Burnham, K. P., & Anderson, D. R. (2002). Model selection and multimodel inference: A practical information-theoretic approach (2nd ed.). Springer. ISBN 978-0-387-95364-9. doi:10.1007/b97636
- Elhorst, J. P. (2010). Applied spatial econometrics: Raising the bar. Spatial Economic Analysis, 5(1), 9–28. doi:10.1080/17421770903541772
- LeSage, J., & Pace, R. K. (2009). Introduction to spatial econometrics. Chapman & Hall/CRC. doi:10.1201/9781420064254
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
6.3 Spatial Panel Regression (FE/RE × Lag/Error)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Spatial Panel Regression วิเคราะห์ข้อมูล พื้นที่ × ช่วงเวลา เช่น อัตราป่วยรายอำเภอหลายปี. เมื่อเทียบกับการวิเคราะห์ปีเดียว (6.1) panel แยก "ความแตกต่างถาวรระหว่างพื้นที่" ออกจาก "การเปลี่ยนแปลงภายในพื้นที่เดียวกันตามเวลา" ได้ และยังจับความสัมพันธ์ระหว่างพื้นที่ข้างเคียงในช่วงเวลาเดียวกันได้. Fixed effects (FE) ใส่ผลประจำพื้นที่ μi ซึ่งดูดซับทุกลักษณะของพื้นที่ที่ไม่เปลี่ยนตามเวลา (ใช้เฉพาะการเปลี่ยนแปลงภายในพื้นที่ — ตัวแปรที่คงที่ตามเวลาจึงประมาณค่าไม่ได้) ส่วน random effects (RE) ถือว่า μi เป็นตัวแปรสุ่มที่ไม่สัมพันธ์กับตัวแปรอธิบาย จึงใช้ทั้งความแปรผันภายในและระหว่างพื้นที่. Time fixed effects (dummy รายช่วงเวลา) ดูดซับเหตุการณ์ที่กระทบทุกพื้นที่พร้อมกันในช่วงเดียว (เช่น ปีที่มีการระบาด) ซึ่งถ้าไม่คุมจะถูกอ่านเป็นความสัมพันธ์เชิงพื้นที่.
Spatial Panel Regression analyses areas × periods data, such as district disease rates over several years. Compared with a single year (6.1), a panel separates permanent between-area differences from within-area change over time, while still modelling dependence between neighbouring areas in the same period. Fixed effects (FE) add an area effect μi that absorbs every time-invariant characteristic of the area (only within-area variation is used, so time-invariant predictors cannot be estimated); random effects (RE) treat μi as a random draw uncorrelated with the predictors and use both within- and between-area variation. Time fixed effects (period dummies) absorb events that hit every area at once (an epidemic year, for example), which a model without them would read as spatial dependence.
ข้อมูลที่ DAPH รับ: หน้าจอ Tab 2 รับข้อมูลแบบ wide เท่านั้น — 1 แถวต่อ 1 พื้นที่ มีคอลัมน์รหัสพื้นที่ (ห้ามซ้ำ) และแต่ละตัวแปรมีคอลัมน์แยกตามช่วงเวลา ตั้งชื่อเป็น "ชื่อชุด + ช่วงเวลา" เช่น TB_2557 … TB_2566 หรือ lgsp_1970 … lgsp_1986 (ปี ค.ศ. 19xx/20xx หรือ พ.ศ. 25xx ไว้ท้ายหรือหน้าชื่อ หรือเลข 1–3 หลักท้ายชื่อ). ผู้ใช้เลือก "ชุด" ของผลลัพธ์และของตัวแปรทำนาย (ตัวแปรที่คงที่ตามเวลาเลือกเป็นคอลัมน์เดี่ยวได้) แล้ว DAPH แปลงเป็นแบบ long ให้เอง. ต้องเป็น balanced panel (ทุกพื้นที่มีครบทุกช่วงเวลา ถ้าไม่ครบ DAPH หยุดและบอกรหัสพื้นที่ที่มีปัญหา) อย่างน้อย 10 พื้นที่และ 2 ช่วงเวลา (Time FE ต้องมีอย่างน้อย 3 ช่วง) และต้องมี shapefile หรือไฟล์ weights. ไม่ใช้เมื่อ: มีช่วงเวลาเดียว (ใช้ 6.1) · ข้อมูลรายบุคคล · panel ไม่สมดุล.
Data DAPH accepts: the Tab 2 screen takes wide data only — one row per area with a unique area-ID column, and each variable spread over one column per period named "set + period", e.g. TB_2557 … TB_2566 or lgsp_1970 … lgsp_1986 (a 19xx/20xx Gregorian or 25xx Buddhist year at the end or the start of the name, or a trailing 1–3-digit number). The user picks the outcome "set" and the predictor sets (time-invariant predictors can be picked as single columns) and DAPH reshapes the table to long form itself. The panel must be balanced (every area in every period; otherwise DAPH stops and names the offending areas), with at least 10 areas and 2 periods (Time FE needs at least 3), plus a shapefile or a weights file. Do not use it with a single period (use 6.1) · for individual records · for an unbalanced panel.
แบบจำลองที่ติ๊กไว้เป็นค่าเริ่มต้น: Pooled OLS · FE (non-spatial) · FE-Lag (SAR) · RE-Lag (SAR) · FE-Error (SEM) · FE-SDM (Durbin) และ Time FE เปิดอยู่ (ใส่ dummy รายช่วงเวลาในทุกแบบจำลอง); RE-Error (SEM) เลือกเพิ่มได้.
Models ticked by default: Pooled OLS · FE (non-spatial) · FE-Lag (SAR) · RE-Lag (SAR) · FE-Error (SEM) · FE-SDM (Durbin), with Time FE on (period dummies in every model); RE-Error (SEM) can be added.
plm (ตัวอย่างมาตรฐานของ package splm; Millo & Piras, 2012) คือ 48 รัฐของสหรัฐอเมริกา × 17 ปี (1970–1986) เชื่อมกับแผนที่รัฐจาก spData::us_states (ตัด District of Columbia ออก) — สคริปต์ในข้อ 3 สร้างไฟล์ produc48.zip แบบ wide สำหรับเปิดใน DAPH. ตัวแปร (ใช้ log ธรรมชาติ): lgsp = ln ผลิตภัณฑ์มวลรวมของรัฐ · lpcap = ln ทุนภาครัฐ · lpc = ln ทุนภาคเอกชน · lemp = ln การจ้างงานนอกภาคเกษตร · unemp = อัตราการว่างงาน (%). คำถาม: ภายในรัฐเดียวกันตามเวลา ผลผลิตสัมพันธ์กับทุนและแรงงานอย่างไร และรัฐข้างเคียงสัมพันธ์กันในปีเดียวกันหรือไม่ — โครงสร้างเดียวกับการศึกษาอัตราป่วยรายอำเภอ × ปี กับปัจจัยด้านบริการและเศรษฐกิจ.
plm (the standard example of the splm package; Millo & Piras, 2012): 48 US states × 17 years (1970–1986), joined to state polygons from spData::us_states (District of Columbia dropped) — the script in step 3 writes the wide file produc48.zip for DAPH. Variables (natural logs): lgsp = ln gross state product · lpcap = ln public capital · lpc = ln private capital · lemp = ln non-agricultural employment · unemp = unemployment rate (%). Question: within the same state over time, how is output associated with capital and labour, and are neighbouring states related in the same year? It has the structure of a district × year disease-rate study with service and economic factors.
2หลักการและสูตรLogic and Formula
สำหรับพื้นที่ i = 1…n และช่วงเวลา t = 1…T (W คือ weights ระหว่าง n พื้นที่ ปรับผลรวมแถวเป็น 1 และใช้เมทริกซ์เดียวกันทุกช่วงเวลา; αt คือผลประจำช่วงเวลาเมื่อเปิด Time FE):
For area i = 1…n and period t = 1…T (W = row-standardised weights between the n areas, the same matrix in every period; αt = period effects when Time FE is on):
- μi
- ผลประจำพื้นที่ (FE: พารามิเตอร์คงที่ที่ถูกขจัดด้วยการหักค่าเฉลี่ยของแต่ละพื้นที่ · RE: ตัวแปรสุ่ม)area effect (FE: a fixed parameter removed by subtracting each area's mean over time · RE: a random draw)
- αt
- T − 1 dummy รายช่วงเวลา ใส่ทุกแบบจำลองเมื่อ Time FE เปิด (ไม่แสดงในตาราง) และไม่ถูกคูณด้วย WT − 1 period dummies, in every model when Time FE is on (not tabulated), never multiplied by W
- ρ, λ, θ
- เหมือน 6.1–6.2as in 6.1–6.2
- φ
- น้ำหนักการแปลงของ RE ที่ DAPH รายงาน — ไม่ใช่สัดส่วนความแปรปรวนระดับพื้นที่ ซึ่งคือ ICC (DAPH พิมพ์ทั้งสองค่าในข้อความแปลผล)the RE transformation weight DAPH reports — not the area-level variance share, which is the ICC (DAPH prints both in the narrative)
การประมาณค่า: แบบจำลอง FE ทั้งหมดหักค่าเฉลี่ยตามเวลาของแต่ละพื้นที่ออกจาก y, X, WX และ dummy รายช่วงเวลา แล้วประมาณด้วย maximum likelihood โดยใช้ log-likelihood แบบ concentrated ที่มี Jacobian T·ln|I − ρW| (หรือ λ) และ σ̂² = SSE/(nT) (Elhorst, 2014) — เท่ากับฟิต spml(model = "within", effect = "individual") ของ R ที่ใส่ factor(year) ในสูตร (ไม่ใช่ effect = "twoways" ซึ่งหักค่าเฉลี่ยของ Wy ต่างไปเล็กน้อย). FE (non-spatial) ใช้ OLS บนข้อมูลที่หักค่าเฉลี่ยแล้ว พร้อม SE แบบ cluster-robust ตามพื้นที่ (CR1, Arellano, 1987) และ t-test ที่ df = nT − n − k; R² ของคอลัมน์นี้เป็น R² ของแบบจำลองที่มี dummy พื้นที่และช่วงเวลา. RE ใช้ maximum likelihood แบบ random effects. การประมาณค่าใช้ weights แบบสมมาตรเท่านั้น (Queen, Distance band) — KNN ใช้ไม่ได้.
Estimation: every FE model subtracts each area's mean over time from y, X, WX and the period dummies and is then fitted by maximum likelihood on the concentrated log-likelihood with Jacobian T·ln|I − ρW| (or λ) and σ̂² = SSE/(nT) (Elhorst, 2014) — the same as R's spml(model = "within", effect = "individual") with factor(year) in the formula (not effect = "twoways", which demeans Wy slightly differently). FE (non-spatial) is OLS on the demeaned data with standard errors cluster-robust by area (CR1, Arellano, 1987) and t-tests on nT − n − k df; its R² is that of the model with area and period dummies. RE models are fitted by random-effects maximum likelihood. The estimators need symmetric weights (Queen, Distance band); KNN cannot be used.
log-likelihood และ AIC: DAPH คำนวณ log-likelihood แบบเต็มบนสเกลเดียวกันทุกคอลัมน์ และ AIC = −2ℓ + 2k โดย k = สัมประสิทธิ์ (รวม dummy รายช่วงเวลา) + ρ หรือ λ + σ² และบวก intercept รายพื้นที่ n ตัวสำหรับแบบจำลอง FE หรือบวก σ²μ สำหรับ RE (Pooled OLS: ค่าคงที่ + สัมประสิทธิ์ + σ²); พิมพ์ AICc ไว้ด้วย.
Log-likelihood and AIC: DAPH computes the full log-likelihood of every column on one scale, and AIC = −2ℓ + 2k with k = coefficients (period dummies included) + ρ or λ + σ², plus the n area intercepts for FE models or σ²μ for RE (Pooled OLS: constant + coefficients + σ²); AICc is printed as well.
- F, LMBP
- มีผลประจำพื้นที่หรือไม่ (Baltagi, 2021; Breusch & Pagan, 1980); e = ส่วนเหลือของ Pooled OLSare there area effects at all? (Baltagi, 2021; Breusch & Pagan, 1980); e = Pooled OLS residuals
- H
- Hausman-type test (Hausman, 1978) ด้วย pseudo-inverse "+" · เมื่อติ๊ก FE-SDM ใช้สเปค Durbin: FE-SDM เทียบกับ RE-SDM ที่ DAPH ฟิตภายใน บนสัมประสิทธิ์ β และ θ (q = 2kx) และพิมพ์คู่ FE-Lag/RE-Lag (q = kx) ไว้อ้างอิง · ถ้าไม่มี SDM ใช้คู่ Lag แล้วจึงคู่ Error · ค่าติดลบ = ไม่มีหลักฐานคัดค้าน RE · ตัวแปรที่ FE ดูดซับไม่ถูกนำมาคำนวณHausman-type test (Hausman, 1978) with the pseudo-inverse "+" · with FE-SDM ticked it uses the Durbin specification: FE-SDM against an RE-SDM fitted internally, on β and θ (q = 2kx), and prints the FE-Lag/RE-Lag pair (q = kx) for reference · without SDM the Lag pair, then the Error pair · a negative value = no evidence against RE · predictors absorbed by FE are excluded
- Common factor
- Wald แบบ delta method ของ θ + ρβ = 0 บน FE-SDM ใช้ความแปรปรวนร่วมเต็มของ (β, θ, ρ) เหมือน 6.2delta-method Wald test of θ + ρβ = 0 on FE-SDM with the full covariance of (β, θ, ρ), as in 6.2
- LM, Moran's I
- สูตรเดียวกับ 6.1 บนส่วนเหลือของ OLS หลังหักค่าเฉลี่ยทั้งรายพื้นที่และรายช่วงเวลา (two-way within) ด้วย WnT = IT ⊗ W (Moran's I ใช้ค่าคาดหวัง −1/(nT − 1) และความแปรปรวนใต้สมมติฐานการแจกแจงปกติ)the 6.1 formulas on the OLS residuals after removing both area and period means (two-way within), with WnT = IT ⊗ W (Moran's I with expectation −1/(nT − 1) and the variance under normality)
แบบจำลองที่ DAPH ติดดาว ★ และนำมาแปลผล (ระดับนัยสำคัญ 0.05): (1) ถ้าทั้ง F และ LMBP ไม่มีนัยสำคัญ → Pooled OLS (ไม่มีหลักฐานว่าต้องมีผลประจำพื้นที่) · (2) เลือกตระกูล FE หรือ RE: Hausman ปฏิเสธ → FE · คำนวณ Hausman ไม่ได้ → FE (FE consistent ไม่ว่า RE จะถูกหรือไม่) · Hausman ไม่ปฏิเสธ → RE ยกเว้นเมื่อ AIC ที่ดีที่สุดของตระกูล FE ต่ำกว่าของ RE ตั้งแต่ 10 หน่วยขึ้นไป (Δ ≥ 10 = แทบไม่มีหลักฐานสนับสนุนแบบจำลองที่ด้อยกว่า; Burnham & Anderson, 2002) จึงใช้ FE · (3) ในตระกูลที่เลือก ใช้แบบจำลองที่มี AIC ต่ำสุด โดยไม่นับคอลัมน์ RE ที่ค่าประมาณ ρ/λ เปลี่ยนเกิน 0.001 เมื่อฟิตซ้ำด้วยเกณฑ์ลู่เข้าที่เข้มขึ้น (ทำเครื่องหมาย ⚠). การไม่ปฏิเสธ Hausman ไม่ใช่หลักฐานยืนยัน RE.
The model DAPH stars ★ and interprets (significance level 0.05): (1) if neither F nor LMBP is significant → Pooled OLS (no evidence that area effects are needed) · (2) FE or RE family: Hausman rejects → FE · no usable Hausman → FE (FE is consistent whether or not RE holds) · Hausman does not reject → RE, unless the best FE AIC is at least 10 below the best RE AIC (Δ ≥ 10 = essentially no support for the weaker model; Burnham & Anderson, 2002), then FE · (3) within the chosen family, the lowest AIC, ignoring RE columns whose ρ/λ moves by more than 0.001 when refitted with a tighter convergence tolerance (flagged ⚠). Not rejecting Hausman is not evidence for RE.
ตารางผลกระทบ: DAPH แยกผล direct / spillover / total ตาม LeSage & Pace (2009) ของแบบจำลองแบบ lag (FE-Lag, RE-Lag หรือ FE-SDM) ที่มี AIC ต่ำสุดในตระกูลที่ Hausman เลือก ด้วยสูตรของ 6.2 บน W ขนาด n×n (ผลภายในช่วงเวลาเดียวกัน) และสุ่ม 10,000 ชุดด้วย seed คงที่; ถ้า FE-SDM ไม่ใช่แบบจำลองนั้น ผลของ FE-SDM แสดงเป็นตารางเสริม. ในแบบจำลองที่มี ρ ให้อ่านผลจากตารางนี้ ไม่ใช่จากสัมประสิทธิ์.
Effects table: DAPH decomposes direct / spillover / total effects (LeSage & Pace, 2009) for the lag-type model (FE-Lag, RE-Lag or FE-SDM) with the lowest AIC in the Hausman-preferred family, with the 6.2 formulas on the n×n W (effects within a period) and 10,000 draws with a fixed seed; when that model is not FE-SDM, FE-SDM's effects are printed as a supplementary table. In a model with ρ, read the effects, not the coefficients.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: the DAPH example dataset (PD cohort) has no map, so this section uses a public
# panel: Produc (R package plm; 48 US states x 17 years, 1970-1986) joined to the state
# polygons of spData::us_states (District of Columbia dropped).
library(sf); library(spdep); library(plm); library(splm)
data(us_states, package = "spData"); data(Produc, package = "plm")
us <- us_states[us_states$NAME != "District of Columbia", "NAME"]
us <- us[order(us$NAME, method = "radix"), ] # DAPH orders the areas the same way
Produc$state <- as.character(Produc$state)
Produc$state[Produc$state == "TENNESSE"] <- "TENNESSEE" # spelling used in plm
key <- setNames(us$NAME, toupper(gsub(" ", "_", us$NAME)))
P <- transform(Produc, NAME = key[state], lgsp = log(gsp), lpcap = log(pcap),
lpc = log(pc), lemp = log(emp))
P <- P[order(P$year, P$NAME, method = "radix"),
c("NAME", "year", "lgsp", "lpcap", "lpc", "lemp", "unemp")]
# Wide file for DAPH: one row per state, one column per variable and year (lgsp_1970 ...)
wide <- reshape(P, idvar = "NAME", timevar = "year", direction = "wide", sep = "_")
st_write(merge(us, wide, by = "NAME"), "produc48.shp", quiet = TRUE,
delete_dsn = file.exists("produc48.shp"))
utils::zip("produc48.zip", paste0("produc48", c(".shp", ".shx", ".dbf", ".prj")), flags = "-9Xq")
# Queen contiguity between the 48 states, row-standardised
lw <- nb2listw(poly2nb(us, queen = TRUE), style = "W"); W <- listw2mat(lw)
summary(card(lw$neighbours))
xs <- c("lpcap", "lpc", "lemp", "unemp")
for (v in xs) # W*x within each year (Durbin terms)
P[[paste0("W_", v)]] <- unlist(lapply(split(P[[v]], P$year), function(x) drop(W %*% x)))
P$year <- factor(P$year) # period dummies = Time FE
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.000 3.000 4.000 4.458 6.000 8.000
fl <- lgsp ~ lpcap + lpc + lemp + unemp + year
fd <- update(fl, . ~ . + W_lpcap + W_lpc + W_lemp + W_unemp)
ix <- c("NAME", "year")
pooled <- lm(fl, data = P) # Pooled OLS
lsdv <- lm(update(fl, . ~ . + NAME), data = P) # FE (non-spatial)
fe_lag <- spml(fl, data = P, index = ix, listw = lw, model = "within",
effect = "individual", lag = TRUE, spatial.error = "none")
fe_err <- spml(fl, data = P, index = ix, listw = lw, model = "within",
effect = "individual", lag = FALSE, spatial.error = "b")
fe_sdm <- spml(fd, data = P, index = ix, listw = lw, model = "within",
effect = "individual", lag = TRUE, spatial.error = "none")
re_lag <- spml(fl, data = P, index = ix, listw = lw, model = "random",
lag = TRUE, spatial.error = "none")
# splm names the spatial-lag coefficient "lambda" and the spatial-error one "rho"
V_ <- function(m) { V <- as.matrix(vcov(m)); dimnames(V) <- list(names(coef(m)), names(coef(m))); V }
est <- function(m, nm) sprintf("%.6f (%.6f)", coef(m)[nm], sqrt(diag(V_(m)))[nm])
library(sandwich)
cr1 <- sqrt(diag(vcovCL(lsdv, cluster = ~NAME, type = "HC1"))) # cluster-robust by area
tab <- rbind(
"Pooled OLS" = c(sprintf("%.6f (%.6f)", coef(pooled)[xs], sqrt(diag(vcov(pooled)))[xs]), "-"),
"FE (non-spatial)" = c(sprintf("%.6f (%.6f)", coef(lsdv)[xs], cr1[xs]), "-"),
"FE-Lag rho" = c(est(fe_lag, xs), est(fe_lag, "lambda")),
"FE-Error lambda" = c(est(fe_err, xs), est(fe_err, "rho")),
"FE-SDM rho" = c(est(fe_sdm, xs), est(fe_sdm, "lambda")),
"RE-Lag rho" = c(sprintf("%.6f", coef(re_lag)[xs]), sprintf("%.6f", re_lag$arcoef[["lambda"]])))
colnames(tab) <- c(xs, "spatial")
print(noquote(tab))
print(noquote(est(fe_sdm, paste0("W_", xs))))
cat(sprintf("RE-Lag: SE(rho) = %.6f; phi = sigma2_mu/sigma2_e = %.4f -> DAPH phi = %.6f\n",
sqrt(re_lag$vcov.arcoef[1, 1]), re_lag$errcomp[["phi"]],
1 / sqrt(1 + 17 * re_lag$errcomp[["phi"]])))
cat(sprintf("R2: pooled %.4f, FE (non-spatial) %.4f\n", summary(pooled)$r.squared, summary(lsdv)$r.squared))
# log-likelihood and AIC on DAPH's scale: k = coefficients + rho + sigma2 (+ 48 area
# intercepts for FE; RE: + sigma2_mu)
ll <- c(pooled = logLik(pooled), fe_ols = logLik(lsdv), fe_lag = fe_lag$logLik,
fe_sdm = fe_sdm$logLik, re_lag = re_lag$logLik)
k <- c(pooled = 22, fe_ols = 69, fe_lag = length(coef(fe_lag)) + 1 + 48,
fe_sdm = length(coef(fe_sdm)) + 1 + 48, re_lag = length(coef(re_lag)) + 3)
print(round(rbind(logLik = ll, k = k, AIC = -2 * ll + 2 * k), 4))
lpcap lpc lemp
Pooled OLS 0.164780 (0.017491) 0.303596 (0.010443) 0.588811 (0.013776)
FE (non-spatial) -0.030176 (0.060042) 0.168828 (0.088331) 0.769306 (0.087700)
FE-Lag rho -0.034868 (0.024777) 0.159114 (0.025449) 0.687827 (0.028522)
FE-Error lambda -0.013540 (0.024724) 0.155711 (0.025460) 0.758985 (0.027782)
FE-SDM rho -0.009637 (0.025262) 0.159428 (0.025611) 0.750650 (0.028828)
RE-Lag rho 0.023512 0.220508 0.725794
unemp spatial
Pooled OLS -0.006057 (0.001770) -
FE (non-spatial) -0.004221 (0.003294) -
FE-Lag rho -0.003472 (0.001049) 0.196914 (0.026956)
FE-Error lambda -0.003009 (0.001152) 0.394685 (0.039757)
FE-SDM rho -0.001463 (0.001233) 0.370168 (0.040481)
RE-Lag rho -0.004000 0.087218
[1] -0.061801 (0.046307) 0.017277 (0.045847) -0.280510 (0.051884)
[4] -0.003156 (0.001872)
RE-Lag: SE(rho) = 0.025715; phi = sigma2_mu/sigma2_e = 12.7482 -> DAPH phi = 0.067772
R2: pooled 0.9929, FE (non-spatial) 0.9990
pooled fe_ols fe_lag fe_sdm re_lag
logLik 842.2573 1629.963 1659.487 1680.623 1486.447
k 22.0000 69.000 70.000 74.000 24.000
AIC -1640.5146 -3121.926 -3178.974 -3213.246 -2924.894
# Are there area effects at all? (F test and Breusch-Pagan LM, design with period dummies)
anova(pooled, lsdv)
plmtest(plm(fl, data = P, index = ix, model = "pooling"), effect = "individual", type = "bp")
# Hausman-type test FE vs RE on the Durbin specification (beta + theta), and on the lag pair
re_sdm <- spml(fd, data = P, index = ix, listw = lw, model = "random",
lag = TRUE, spatial.error = "none")
hausman <- function(fe, re, cn) { d <- coef(fe)[cn] - coef(re)[cn]
drop(t(d) %*% MASS::ginv(V_(fe)[cn, cn] - V_(re)[cn, cn]) %*% d) }
cn <- c(xs, paste0("W_", xs))
H8 <- hausman(fe_sdm, re_sdm, cn); H4 <- hausman(fe_lag, re_lag, xs)
cat(sprintf("Hausman Durbin: chi2(8) = %.4f, p = %.2e; lag pair: chi2(4) = %.4f, p = %.2e\n",
H8, pchisq(H8, 8, lower.tail = FALSE), H4, pchisq(H4, 4, lower.tail = FALSE)))
# theta = 0: LR test FE-SDM vs FE-Lag; common factor theta = -rho*beta: Wald (delta method)
LR <- 2 * (fe_sdm$logLik - fe_lag$logLik)
b <- coef(fe_sdm); V <- V_(fe_sdm); rho <- b[["lambda"]]
g <- b[paste0("W_", xs)] + rho * b[xs]
G <- matrix(0, 4, length(b), dimnames = list(NULL, names(b)))
for (j in 1:4) G[j, c(xs[j], paste0("W_", xs[j]))] <- c(rho, 1)
G[, "lambda"] <- b[xs]
Wcf <- drop(t(g) %*% solve(G %*% V %*% t(G)) %*% g)
cat(sprintf("LR theta = 0: chi2(4) = %.4f, p = %.2e\n", LR, pchisq(LR, 4, lower.tail = FALSE)))
cat(sprintf("Wald common factor with splm's vcov (Cov(rho, beta) stored as 0): chi2(4) = %.4f -- see part 4\n", Wcf))
# LR test of the period effects in FE-SDM (16 dummies)
fe_sdm0 <- spml(update(fd, . ~ . - year), data = P, index = ix, listw = lw, model = "within",
effect = "individual", lag = TRUE, spatial.error = "none")
LRt <- 2 * (fe_sdm$logLik - fe_sdm0$logLik)
cat(sprintf("LR period effects (FE-SDM): chi2(16) = %.4f, p = %.2e\n", LRt, pchisq(LRt, 16, lower.tail = FALSE)))
# LM tests and Moran's I on the two-way within residuals, W for the stacked panel = I_T (x) W
tw <- function(v) { m <- matrix(v, 17, 48, byrow = TRUE)
m <- sweep(m, 2, colMeans(m)); m <- sweep(m, 1, rowMeans(m)); as.vector(t(m)) }
D2 <- data.frame(y = tw(P$lgsp), sapply(xs, function(v) tw(P[[v]])))
w2 <- lm(y ~ . - 1, data = D2)
lwNT <- mat2listw(kronecker(diag(17), W), style = "W")
summary(lm.LMtests(w2, lwNT, test = c("LMerr", "LMlag", "RLMerr", "RLMlag")))
moran.test(residuals(w2), lwNT, randomisation = FALSE, alternative = "two.sided")
Res.Df RSS Df Sum of Sq F Pr(>F)
1 795 6.0629
2 748 0.8794 47 5.1834 93.802 < 2.2e-16 ***
Lagrange Multiplier Test - (Breusch-Pagan)
chisq = 4458.5, df = 1, p-value < 2.2e-16
Hausman Durbin: chi2(8) = 49.2915, p = 5.59e-08; lag pair: chi2(4) = 67.8762, p = 6.37e-14
LR theta = 0: chi2(4) = 42.2719, p = 1.47e-08
Wald common factor with splm's vcov (Cov(rho, beta) stored as 0): chi2(4) = 12.8132 -- see part 4
LR period effects (FE-SDM): chi2(16) = 51.2077, p = 1.47e-05
statistic parameter p.value
LMerr 98.7246 1 < 2.2e-16 ***
LMlag 69.1663 1 < 2.2e-16 ***
RLMerr 39.2758 1 3.68e-10 ***
RLMlag 9.7175 1 0.001825 **
Moran I statistic standard deviate = 10.012, p-value < 2.2e-16
Moran I statistic Expectation Variance
0.245672028 -0.001226994 0.000608170
# The full maximum-likelihood covariance of (rho, beta, theta): fit the same FE models by
# spatialreg on the area-demeaned panel stacked year by year, with W_NT = I_T (x) W.
# (splm's vcov sets Cov(rho, beta) to 0, which the common-factor test and the effect
# intervals need.) Same estimates, SEs and log-likelihood as above.
library(spatialreg)
wi <- function(v) { m <- matrix(v, 17, 48, byrow = TRUE); as.vector(t(sweep(m, 2, colMeans(m)))) }
S <- data.frame(y = wi(P$lgsp), apply(model.matrix(fd, P)[, -1], 2, wi))
st <- lagsarlm(y ~ . - 1, data = S, listw = lwNT, method = "eigen") # FE-SDM
ste <- errorsarlm(y ~ . - 1, data = S[, !grepl("^W_", names(S))], listw = lwNT,
method = "eigen") # FE-Error
cat(sprintf("FE-SDM rho = %.6f (SE %.6f), logLik = %.4f; FE-Error lambda = %.6f, logLik = %.4f, AIC (k = 70) = %.4f\n",
st$rho, st$rho.se, logLik(st), ste$lambda, logLik(ste), -2 * logLik(ste) + 2 * 70))
b <- c(rho = unname(st$rho), coef(st)[-1]); V <- vcov(st); wn <- paste0("W_", xs)
g <- b[wn] + b[["rho"]] * b[xs]
G <- matrix(0, 4, ncol(V), dimnames = list(NULL, rownames(V)))
for (j in 1:4) G[j, c(xs[j], wn[j])] <- c(b[["rho"]], 1)
G[, "rho"] <- b[xs]
Wcf <- drop(t(g) %*% solve(G %*% V %*% t(G)) %*% g)
cat(sprintf("Wald common factor (full ML covariance): chi2(4) = %.4f, p = %.4f\n",
Wcf, pchisq(Wcf, 4, lower.tail = FALSE)))
# LeSage-Pace effects of FE-SDM with the 48 x 48 W (eigenvalues w of W):
# direct = [beta * sum(1/(1 - rho*w)) + theta * sum(w/(1 - rho*w))] / 48, total = (beta + theta)/(1 - rho)
ev <- Re(eigen(W, only.values = TRUE)$values)
eff <- function(r, be, th) { a <- sum(1 / (1 - r * ev)) / 48; c <- sum(ev / (1 - r * ev)) / 48
d <- be * a + th * c; t <- (be + th) / (1 - r); cbind(direct = d, spillover = t - d, total = t) }
print(round(`rownames<-`(eff(b[["rho"]], b[xs], b[wn]), xs), 4))
set.seed(2026)
sel <- c("rho", xs, wn)
D <- MASS::mvrnorm(100000, b[sel], V[sel, sel]); D <- D[abs(D[, "rho"]) < 1, ]
sims <- lapply(seq_along(xs), function(j) t(sapply(seq_len(nrow(D)), function(i)
eff(D[i, "rho"], D[i, xs[j]], D[i, wn[j]]))))
lim <- do.call(rbind, lapply(seq_along(xs), function(j) do.call(rbind, lapply(1:3, function(e) {
x <- sims[[j]][, e]; q <- quantile(x, c(0.025, 0.975))
bq <- sapply(split(x, cut(seq_along(x), 10, labels = FALSE)), quantile, c(0.025, 0.975))
data.frame(variable = xs[j], effect = c("direct", "spillover", "total")[e], lower = q[1],
upper = q[2], mcse_lower = sd(bq[1, ]), mcse_upper = sd(bq[2, ])) }))))
rownames(lim) <- NULL; lim[3:6] <- round(lim[3:6], 5)
print(lim)
FE-SDM rho = 0.370168 (SE 0.040481), logLik = 1680.6229; FE-Error lambda = 0.394685, logLik = 1672.8237, AIC (k = 70) = -3205.6475
Wald common factor (full ML covariance): chi2(4) = 15.6587, p = 0.0035
direct spillover total
lpcap -0.0164 -0.0970 -0.1134
lpc 0.1673 0.1132 0.2806
lemp 0.7504 -0.0039 0.7465
unemp -0.0018 -0.0055 -0.0073
variable effect lower upper mcse_lower mcse_upper
1 lpcap direct -0.06641 0.03368 0.00060 0.00078
2 lpcap spillover -0.22832 0.03536 0.00113 0.00117
3 lpcap total -0.26169 0.03619 0.00178 0.00210
4 lpc direct 0.11632 0.21799 0.00085 0.00066
5 lpc spillover -0.01329 0.24247 0.00226 0.00166
6 lpc total 0.13671 0.42547 0.00222 0.00166
7 lemp direct 0.69463 0.80561 0.00063 0.00043
8 lemp spillover -0.11667 0.10744 0.00176 0.00124
9 lemp total 0.62478 0.86682 0.00158 0.00119
10 unemp direct -0.00419 0.00048 0.00002 0.00003
11 unemp spillover -0.01037 -0.00065 0.00007 0.00006
12 unemp total -0.01237 -0.00238 0.00008 0.00005
produc48.zip → Tab 2: ชนิดผลลัพธ์ Spatial · สถิติ Spatial Panel Regression · รหัสพื้นที่ = NAME · ชุดผลลัพธ์ = lgsp · ชุดตัวแปรทำนาย = lpcap, lpc, lemp, unemp · Spatial weights = Queen contiguity, order 1 (หน้าจอเริ่มที่ Distance band) · แบบจำลอง = ค่าเริ่มต้น (Pooled OLS, FE (non-spatial), FE-Lag, RE-Lag, FE-Error, FE-SDM) · Time FE = เปิด · Monte-Carlo draws = 10,000 · Variable selection = EnterFile > Open: produc48.zip → Tab 2: outcome type Spatial · statistic Spatial Panel Regression · area ID = NAME · outcome set = lgsp · predictor sets = lpcap, lpc, lemp, unemp · Spatial weights = Queen contiguity, order 1 (the screen starts at Distance band) · models = default (Pooled OLS, FE (non-spatial), FE-Lag, RE-Lag, FE-Error, FE-SDM) · Time FE = on · Monte-Carlo draws = 10,000 · Variable selection = Enter| ค่าที่วัดQuantity | โมเดลModel | R | DAPH | ความต่างDifference | สถานะStatus |
|---|---|---|---|---|---|
| β (SE) | Pooled OLS | 0.164780 (0.017491) · 0.303596 (0.010443) · 0.588811 (0.013776) · −0.006057 (0.001770) | 0.164780 (0.017491) · 0.303596 (0.010443) · 0.588811 (0.013776) · −0.006057 (0.001770) | < 1e−6 | ✓ PASS |
| β (SE แบบ cluster-robust CR1)β (cluster-robust CR1 SE) | FE (non-spatial) | −0.030176 (0.060042) · 0.168828 (0.088331) · 0.769306 (0.087700) · −0.004221 (0.003294) | −0.030176 (0.060042) · 0.168828 (0.088331) · 0.769306 (0.087700) · −0.004221 (0.003294) | < 1e−6 | ✓ PASS |
| β (SE) · ρ (SE) | FE-Lag | −0.034868 (0.024777) · 0.159114 (0.025449) · 0.687827 (0.028522) · −0.003472 (0.001049) · ρ 0.196914 (0.026956) | −0.034868 (0.024777) · 0.159114 (0.025449) · 0.687827 (0.028522) · −0.003472 (0.001049) · ρ 0.196914 (0.026956) | < 1e−6 | ✓ PASS |
| β (SE) · λ (SE) | FE-Error | −0.013540 (0.024724) · 0.155711 (0.025460) · 0.758985 (0.027782) · −0.003009 (0.001152) · λ 0.394685 (0.039757) | −0.013540 (0.024724) · 0.155711 (0.025460) · 0.758985 (0.027782) · −0.003009 (0.001152) · λ 0.394685 (0.039757) | < 1e−6 | ✓ PASS |
| β (SE) · ρ (SE) | FE-SDM | −0.009637 (0.025262) · 0.159428 (0.025611) · 0.750650 (0.028828) · −0.001463 (0.001233) · ρ 0.370168 (0.040481) | −0.009637 (0.025262) · 0.159428 (0.025611) · 0.750650 (0.028828) · −0.001463 (0.001233) · ρ 0.370168 (0.040481) | < 1e−6 | ✓ PASS |
| θ = W·x (SE) | FE-SDM | −0.061801 (0.046307) · 0.017277 (0.045847) · −0.280510 (0.051884) · −0.003156 (0.001872) | −0.061801 (0.046307) · 0.017277 (0.045847) · −0.280510 (0.051884) · −0.003156 (0.001872) | < 1e−6 | ✓ PASS |
| β · ρ · φ | RE-Lag | 0.023512 · 0.220508 · 0.725794 · −0.004000 · ρ 0.087218 · φ 0.067772 | 0.023512 · 0.220507 · 0.725794 · −0.004000 · ρ 0.087219 · φ 0.067772 | < 1e−5 | ✓ PASS |
| SE(ρ) | RE-Lag | 0.025715 (numerical Hessian ของ splm)0.025715 (splm numerical Hessian) | 0.019954 | 0.005761 | ✗ FAIL |
| R² | Pooled OLS · FE (non-spatial) | 0.9929 · 0.9990 | 0.992866 · 0.998965 | < 0.00005 | ✓ PASS |
| Log-likelihood | Pooled · FE · FE-Lag · FE-Error · FE-SDM · RE-Lag | 842.2573 · 1629.963 · 1659.487 · 1672.8237 · 1680.623 · 1486.447 | 842.2573 · 1629.9629 · 1659.4869 · 1672.8237 · 1680.6229 · 1486.4468 | < 0.0005 | ✓ PASS |
| AIC (k ตามนิยามของ DAPHas defined by DAPH) | Pooled · FE · FE-Lag · FE-Error · FE-SDM · RE-Lag | −1640.5146 · −3121.926 · −3178.974 · −3205.6475 · −3213.246 · −2924.894 | −1640.5146 · −3121.9259 · −3178.9738 · −3205.6475 · −3213.2457 · −2924.8936 | < 0.0005 | ✓ PASS |
| F test (47, 748) | Pooled vs FE | 93.802 | 93.8023 | < 0.0005 | ✓ PASS |
| Breusch–Pagan LM | Pooled | 4458.5 | 4458.536 | < 0.05 | ✓ PASS |
| Hausman χ²(8) (Durbin) | FE-SDM vs RE-SDM | 49.2915 | 49.3170 | 0.0255 | ✗ FAIL |
| Hausman χ²(4) (คู่ Lag, อ้างอิง)Hausman χ²(4) (Lag pair, reference) | FE-Lag vs RE-Lag | 67.8762 | 55.1350 | 12.7412 | ✗ FAIL |
| LR θ = 0: χ²(4) | FE-SDM vs FE-Lag | 42.2719 | 42.2719 | < 0.0001 | ✓ PASS |
| Wald common factor: χ²(4) (p) | FE-SDM | 15.6587 (0.0035) | 15.6587 (0.0035) | < 0.0001 | ✓ PASS |
| LR ผลรายช่วงเวลา: χ²(16)LR period effects: χ²(16) | FE-SDM | 51.2077 | 51.2077 | < 0.0001 | ✓ PASS |
| LM-lag · LM-error · robust LM-lag · robust LM-error | ส่วนเหลือ two-way withintwo-way within residuals | 69.1663 · 98.7246 · 9.7175 · 39.2758 | 69.1663 · 98.7246 · 9.7175 · 39.2758 | < 0.0001 | ✓ PASS |
| Moran's I (z) | ส่วนเหลือ two-way withintwo-way within residuals | 0.245672 (10.012) | 0.245672 (10.0117) | < 1e−6 | ✓ PASS |
| lpcap: direct · spillover · total (95% CI) | FE-SDM | −0.0164 (−0.06641 to 0.03368) · −0.0970 (−0.22832 to 0.03536) · −0.1134 (−0.26169 to 0.03619) | −0.0164 (−0.06661 to 0.03364) · −0.0970 (−0.22689 to 0.03558) · −0.1134 (−0.25994 to 0.03736) | 0 · ขอบสูงสุด 0.00020 / 0.00143 / 0.00175 (เกณฑ์ 0.0025 / 0.0037 / 0.0066)0 · largest limit gap 0.00020 / 0.00143 / 0.00175 (tolerance 0.0025 / 0.0037 / 0.0066) | ✓ PASS |
| lpc: direct · spillover · total (95% CI) | FE-SDM | 0.1673 (0.11632 to 0.21799) · 0.1132 (−0.01329 to 0.24247) · 0.2806 (0.13671 to 0.42547) | 0.1673 (0.11635 to 0.21925) · 0.1132 (−0.01300 to 0.24422) · 0.2806 (0.13749 to 0.42578) | 0 · ขอบสูงสุด 0.00126 / 0.00175 / 0.00078 (เกณฑ์ 0.0027 / 0.0071 / 0.0070)0 · largest limit gap 0.00126 / 0.00175 / 0.00078 (tolerance 0.0027 / 0.0071 / 0.0070) | ✓ PASS |
| lemp: direct · spillover · total (95% CI) | FE-SDM | 0.7504 (0.69463 to 0.80561) · −0.0039 (−0.11667 to 0.10744) · 0.7465 (0.62478 to 0.86682) | 0.7504 (0.69431 to 0.80501) · −0.0039 (−0.11640 to 0.10667) · 0.7465 (0.62339 to 0.86467) | 0 · ขอบสูงสุด 0.00060 / 0.00077 / 0.00215 (เกณฑ์ 0.0020 / 0.0055 / 0.0050)0 · largest limit gap 0.00060 / 0.00077 / 0.00215 (tolerance 0.0020 / 0.0055 / 0.0050) | ✓ PASS |
| unemp: direct · spillover · total (95% CI) | FE-SDM | −0.0018 (−0.00419 to 0.00048) · −0.0055 (−0.01037 to −0.00065) · −0.0073 (−0.01237 to −0.00238) | −0.0018 (−0.00413 to 0.00042) · −0.0055 (−0.01048 to −0.00079) · −0.0073 (−0.01244 to −0.00244) | 0 · ขอบสูงสุด 0.00006 / 0.00014 / 0.00007 (เกณฑ์ 0.00009 / 0.00022 / 0.00025)0 · largest limit gap 0.00006 / 0.00014 / 0.00007 (tolerance 0.00009 / 0.00022 / 0.00025) | ✓ PASS |
ค่า DAPH อ่านจากผลการรันของ DAPH เอง. ค่าประมาณจากการหาค่าเหมาะที่สุดตรงกันภายใน 1e−5. ช่วงเชื่อมั่นของผลกระทบ: DAPH สุ่ม 10,000 ครั้ง R สุ่ม 100,000 ครั้ง เกณฑ์ยอมรับ = 3.146 × Monte-Carlo SE ที่ R พิมพ์ (เหมือน 6.1). แถว ✗ FAIL ทั้งสามมาจากเมทริกซ์ความแปรปรวนของแบบจำลอง RE: SE ของ ρ ใน RE-Lag ของ DAPH (0.019954) ต่ำกว่าค่าจาก numerical Hessian ของ likelihood เต็มรูป (0.025715 ใน splm) และ Hausman ซึ่งใช้ความแปรปรวนของ RE จึงต่างจาก R; ข้อสรุป (ปฏิเสธ RE, p < 0.001) เหมือนกันทั้งสองโปรแกรม แต่ SE และ p-value ของ RE-Lag ใน DAPH ควรอ่านด้วยความระมัดระวัง. splm เก็บ Cov(ρ, β) ของแบบจำลอง within เป็น 0 ทำให้ Wald common factor จาก vcov(fe_sdm) ของ splm ได้ 12.81 ส่วนความแปรปรวนร่วมเต็มจาก spatialreg (ส่วนที่ 4) ได้ 15.6587 เท่ากับ DAPH.DAPH values are read from DAPH's own run. Optimiser-based estimates agree within 1e−5. Effect intervals: DAPH draws 10,000 times and R 100,000 times; tolerance = 3.146 × the Monte-Carlo SE printed by R (as in 6.1). All three ✗ FAIL rows come from the covariance matrix of the RE models: DAPH's SE of ρ in RE-Lag (0.019954) is below the numerical-Hessian value of the full likelihood (0.025715 in splm), and the Hausman statistics, which use the RE covariance, therefore differ from R; the conclusion (reject RE, p < 0.001) is the same in both programs, but DAPH's RE-Lag SEs and p-values should be read with caution. splm stores Cov(ρ, β) = 0 for within models, so a Wald common-factor test built on splm's vcov(fe_sdm) gives 12.81, whereas the full covariance from spatialreg (part 4) gives 15.6587, equal to DAPH.
4การแปลผลและตัวอย่างInterpretation and Example
ขั้นที่ 1 — ต้องมีผลประจำพื้นที่หรือไม่ และ FE หรือ RE: F(47, 748) = 93.80, p < 0.001 และ LMBP = 4458.54, p < 0.001 → Pooled OLS ไม่พอ. Hausman (สเปค Durbin) χ²(8) = 49.32, p < 0.001 → ปฏิเสธสมมติฐานของ RE จึงใช้ตระกูล FE. LR ของผลรายช่วงเวลา χ²(16) = 51.21, p < 0.001 สนับสนุนการคง Time FE.
Step 1 — Are area effects needed, and FE or RE? F(47, 748) = 93.80, p < 0.001 and LMBP = 4458.54, p < 0.001 → Pooled OLS is not adequate. Hausman (Durbin specification) χ²(8) = 49.32, p < 0.001 → the RE assumption is rejected, so the FE family is used. The LR test of the period effects, χ²(16) = 51.21, p < 0.001, supports keeping Time FE.
ขั้นที่ 2 — Lag, Error หรือ Durbin: LR θ = 0: χ²(4) = 42.27, p < 0.001 (คงพจน์ W·x) และ Wald common factor: χ²(4) = 15.66, p = 0.004 (FE-SDM ยุบเป็น FE-Error ไม่ได้). AIC ในตระกูล FE: FE-SDM −3213.2 · FE-Error −3205.6 · FE-Lag −3179.0 · FE (non-spatial) −3121.9 → DAPH ติดดาว ★ ที่ FE-SDM. ส่วนเหลือหลังหักผลประจำพื้นที่และช่วงเวลายังมีความสัมพันธ์เชิงพื้นที่ (Moran's I = 0.246, p < 0.001; LM-lag = 69.17, LM-error = 98.72).
Step 2 — Lag, Error or Durbin: LR θ = 0: χ²(4) = 42.27, p < 0.001 (keep the W·x terms) and Wald common factor: χ²(4) = 15.66, p = 0.004 (FE-SDM does not reduce to FE-Error). AIC within the FE family: FE-SDM −3213.2 · FE-Error −3205.6 · FE-Lag −3179.0 · FE (non-spatial) −3121.9 → DAPH stars ★ FE-SDM. Residuals after removing area and period effects are still spatially dependent (Moran's I = 0.246, p < 0.001; LM-lag = 69.17, LM-error = 98.72).
ขั้นที่ 3 — อ่านผลของ FE-SDM: ρ = 0.370 (SE 0.040, p < 0.001): ผลผลิตของรัฐหนึ่งสัมพันธ์ทางบวกกับค่าเฉลี่ยของรัฐข้างเคียงในปีเดียวกัน (ไม่ใช่สัดส่วนที่อธิบายได้). ตัวแปรเป็น log จึงอ่านผลกระทบเป็น elasticity: การจ้างงานที่สูงขึ้น 1% ภายในรัฐเดียวกัน สัมพันธ์กับผลผลิตของรัฐนั้นที่สูงขึ้น 0.750% (direct, 95% CI 0.694 to 0.805) โดยไม่พบหลักฐานของผลต่อรัฐข้างเคียง (spillover −0.004, 95% CI −0.116 to 0.107); ทุนภาคเอกชน 1%: direct 0.167% (95% CI 0.116 to 0.219), total 0.281% (95% CI 0.137 to 0.426); ทุนภาครัฐ: direct −0.016 (95% CI −0.067 to 0.034) ไม่มีนัยสำคัญ (ไม่ได้แปลว่าไม่มีผล); อัตราว่างงานสูงขึ้น 1 จุดร้อยละ สัมพันธ์กับผลผลิตรวมที่ต่ำลงประมาณ 0.73% (total −0.0073, 95% CI −0.0124 to −0.0024). สัมประสิทธิ์ W·lemp = −0.281 คือสัมประสิทธิ์ของการจ้างงานเฉลี่ยของรัฐข้างเคียง ไม่ใช่ผลในรัฐเดียวกัน.
Step 3 — Read FE-SDM: ρ = 0.370 (SE 0.040, p < 0.001): a state's output is positively associated with the average output of its neighbours in the same year (ρ is not an attributable fraction). The variables are logs, so the effects read as elasticities: 1% higher employment within a state is associated with 0.750% higher output in that state (direct, 95% CI 0.694 to 0.805), with no evidence of an effect on neighbouring states (spillover −0.004, 95% CI −0.116 to 0.107); private capital 1%: direct 0.167% (95% CI 0.116 to 0.219), total 0.281% (95% CI 0.137 to 0.426); public capital: direct −0.016 (95% CI −0.067 to 0.034), not significant (which is not the same as no effect); one percentage point more unemployment is associated with about 0.73% lower output in total (total −0.0073, 95% CI −0.0124 to −0.0024). The coefficient W·lemp = −0.281 belongs to the neighbours' average employment, not to an effect within the same state.
ข้อจำกัด: เป็นความสัมพันธ์ภายในพื้นที่ตามเวลา ไม่ใช่ความเป็นเหตุเป็นผล · SE ของคอลัมน์เชิงพื้นที่สมมติว่าส่วนคลาดเคลื่อนเป็นอิสระตามเวลา (มีเพียงคอลัมน์ FE (non-spatial) ที่ใช้ SE แบบ cluster-robust) · ผลขึ้นกับ W — ควรทำซ้ำด้วย weights แบบอื่น.
Limitations: within-area associations over time, not causal effects · the spatial columns' SEs assume errors independent over time (only the FE (non-spatial) column uses cluster-robust SEs) · results depend on W — repeat with another weights matrix.
📖 References
- Anselin, L., Le Gallo, J., & Jayet, H. (2008). Spatial panel econometrics. In L. Mátyás & P. Sevestre (Eds.), The econometrics of panel data (3rd ed., pp. 625–660). Springer. doi:10.1007/978-3-540-75892-1_19
- Arellano, M. (1987). Computing robust standard errors for within-groups estimators. Oxford Bulletin of Economics and Statistics, 49(4), 431–434. doi:10.1111/j.1468-0084.1987.mp49004006.x
- Baltagi, B. H. (2021). Econometric analysis of panel data (6th ed.). Springer. doi:10.1007/978-3-030-53953-5
- Breusch, T. S., & Pagan, A. R. (1980). The Lagrange multiplier test and its applications to model specification in econometrics. The Review of Economic Studies, 47(1), 239–253. doi:10.2307/2297111
- Burnham, K. P., & Anderson, D. R. (2002). Model selection and multimodel inference: A practical information-theoretic approach (2nd ed.). Springer. ISBN 978-0-387-95364-9. doi:10.1007/b97636
- Elhorst, J. P. (2014). Spatial econometrics: From cross-sectional data to spatial panels. Springer. doi:10.1007/978-3-642-40340-8
- Hausman, J. A. (1978). Specification tests in econometrics. Econometrica, 46(6), 1251–1271. doi:10.2307/1913827
- LeSage, J., & Pace, R. K. (2009). Introduction to spatial econometrics. Chapman & Hall/CRC. doi:10.1201/9781420064254
- Millo, G., & Piras, G. (2012). splm: Spatial panel data models in R. Journal of Statistical Software, 47(1), 1–38. doi:10.18637/jss.v047.i01
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
6.4 LISA Univariate — Local Moran's I
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Local Moran's I เป็นสถิติในกลุ่ม LISA (Local Indicators of Spatial Association, ตัวชี้วัดความสัมพันธ์เชิงพื้นที่ระดับท้องถิ่น; Anselin, 1995) ตอบคำถามว่า "พื้นที่ใดบ้างที่มีค่าคล้ายกับพื้นที่ข้างเคียงมากกว่าที่ควรเกิดโดยบังเอิญ" Global Moran's I (Moran, 1950) ให้ตัวเลขเดียวว่าทั้งแผนที่มีการเกาะกลุ่มหรือไม่ แต่ไม่บอกว่าอยู่ที่ไหน ส่วน Local Moran's I ให้ค่า Ii แยกรายพื้นที่ พร้อม pseudo-p จากการสุ่มเรียงค่าใหม่ (permutation) แล้วจัดพื้นที่ที่มีนัยสำคัญเป็น 4 กลุ่ม: High-High (ค่าสูง รอบข้างสูง), Low-Low (ค่าต่ำ รอบข้างต่ำ), High-Low (ค่าสูง รอบข้างต่ำ) และ Low-High (ค่าต่ำ รอบข้างสูง) ที่เหลือเป็น Not significant
Local Moran's I belongs to the LISA family (Local Indicators of Spatial Association; Anselin, 1995). It answers "which areas resemble their neighbours more than chance would allow?" The global Moran's I (Moran, 1950) gives one number for the whole map — clustering or not — but not where. Local Moran's I gives each area its own Ii, a pseudo-p from a permutation test, and places each significant area in one of four groups: High-High (high value, high neighbours), Low-Low (low, low), High-Low (high value, low neighbours) and Low-High (low value, high neighbours); the rest are Not significant.
ใช้เมื่อ: มีค่าตัวเลขหนึ่งค่าต่อพื้นที่ (อัตราป่วย อัตราการเกิดเหตุ ฯลฯ) และมีแผนที่ขอบเขตพื้นที่หรือพิกัด ต้องการหาตำแหน่งของกลุ่มค่าสูง/ค่าต่ำและพื้นที่ที่แตกต่างจากรอบข้าง · ไม่ควรใช้เมื่อ: ข้อมูลเป็นรายบุคคลที่ไม่มีตำแหน่ง, จำนวนพื้นที่น้อยกว่า 10 (DAPH ไม่รัน), หรือเป็นอัตราจากประชากรน้อยมากจนค่าแกว่ง (ควรใช้อัตราที่ปรับให้นิ่งก่อน เช่น Bayesian disease mapping ในหัวข้อ 6.9)
Use it when there is one numeric value per area (a disease rate, an incident rate…) and a boundary map or coordinates, and you want to locate clusters of high or low values and areas that differ from their surroundings. Do not use it for individual records without locations, for fewer than 10 areas (DAPH refuses), or for rates from very small populations whose values jump around (smooth them first, e.g. Bayesian disease mapping in section 6.9).
spData (Anselin, 1988): 49 ย่านที่พักอาศัย ตัวแปร CRIME = จำนวนการลักทรัพย์ในบ้านและการขโมยรถต่อ 1,000 ครัวเรือน · คำถาม: "ย่านที่มีอัตราเหตุสูงอยู่ติดกันเป็นกลุ่มหรือไม่ และกลุ่มนั้นอยู่ที่ใด" — โครงสร้างเดียวกับคำถามด้านสาธารณสุข เช่น อัตราป่วยรายตำบล
spData (Anselin, 1988): 49 residential neighbourhoods; CRIME = residential burglaries and vehicle thefts per 1,000 households. Question: "do neighbourhoods with high rates sit next to each other, and where?" — the same structure as a public-health question such as disease rates by sub-district.
2หลักการและสูตรLogic and Formula
ให้ xi เป็นค่าของพื้นที่ i จาก n พื้นที่ และ wij เป็นน้ำหนักเชิงพื้นที่แบบ row-standardised (พื้นที่ i มีเพื่อนบ้าน ki แห่ง แต่ละแห่งได้น้ำหนัก 1/ki; การสร้างเพื่อนบ้านดูหัวข้อ 6.7) DAPH คำนวณดังนี้:
Let xi be the value of area i (n areas) and wij the row-standardised spatial weight (area i has ki neighbours, each weighted 1/ki; how neighbours are built: section 6.7). DAPH computes:
- zi
- ค่ามาตรฐานของ xi (หารด้วยส่วนเบี่ยงเบนมาตรฐานตัวอย่าง s ซึ่งใช้ตัวหาร n − 1)standardised xi (divided by the sample standard deviation s, divisor n − 1)
- Σj wij zj
- spatial lag = ค่าเฉลี่ยของ z ในพื้นที่ข้างเคียงของ ispatial lag = mean of z over the neighbours of i
- Ii
- บวก = พื้นที่ i คล้ายรอบข้าง (สูง-สูง หรือ ต่ำ-ต่ำ) · ลบ = ต่างจากรอบข้างpositive = area i resembles its neighbours (high-high or low-low) · negative = it differs
- S0
- ผลรวมน้ำหนักทั้งหมดsum of all weights
- R, I(r)
- จำนวนรอบการสุ่ม (ค่าเริ่มต้น 999) และค่าสถิติในรอบที่ rnumber of permutations (default 999) and the statistic in permutation r
การทดสอบรายพื้นที่ (conditional permutation): สำหรับพื้นที่ i ค่า xi คงอยู่ที่เดิม แล้วสุ่มเลือกค่า ki ค่าแบบไม่ซ้ำจากอีก n − 1 พื้นที่มาเป็น "เพื่อนบ้าน" ทำ R = 999 รอบ นับ k = จำนวนรอบที่ Ii จากการสุ่ม ≥ Ii จริง แล้วใช้หางที่เล็กกว่า (สูตรข้างบน) pseudo-p จึงอยู่ระหว่าง 0.001 ถึง 0.5 · การทดสอบรวม: สุ่มเรียงค่าทั้งชุดใหม่ 999 รอบ, pseudo-p ใช้สูตรเดียวกัน และ z = (I − ค่าเฉลี่ยของ I จากการสุ่ม) / SD ของ I จากการสุ่ม (เป็น z จากการสุ่ม ไม่ใช่ z จากสูตรวิเคราะห์)
Local test (conditional permutation): for area i the value xi stays in place; ki values are drawn without repeats from the other n − 1 areas to act as its neighbours, R = 999 times; k = number of draws with Ii ≥ the observed Ii, and the smaller tail is used (formula above), so the pseudo-p lies between 0.001 and 0.5. Global test: all values are reshuffled over the areas 999 times; the pseudo-p uses the same formula, and z = (I − mean of the permuted I) / SD of the permuted I — a permutation z, not the analytic z.
การจัดกลุ่ม: High-High เมื่อ zi > 0 และ spatial lag > 0 · Low-Low เมื่อทั้งคู่ < 0 · High-Low เมื่อ zi > 0 แต่ lag < 0 · Low-High เมื่อ zi < 0 แต่ lag > 0 — แสดงกลุ่มเฉพาะพื้นที่ที่ pseudo-p < α (α ค่าเริ่มต้น 0.05, ใช้เครื่องหมายน้อยกว่าแบบเคร่งครัด) ดาว * ** *** = pseudo-p < 0.05, 0.01, 0.001
Groups: High-High when zi > 0 and the spatial lag > 0 · Low-Low when both < 0 · High-Low when zi > 0 but the lag < 0 · Low-High when zi < 0 but the lag > 0 — shown only for areas with pseudo-p < α (default α = 0.05, strict inequality). Stars * ** *** = pseudo-p < 0.05, 0.01, 0.001.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
สคริปต์สร้างไฟล์ columbus.zip (shp + shx + dbf) สำหรับนำเข้า DAPH แล้วคำนวณด้วย polygon ชุดเดียวกัน ถ้าเครื่อง Windows ไม่มีโปรแกรม zip ให้เลือกสามไฟล์ใน File Explorer แล้วสั่งบีบอัดเป็น ZIP แทน
The script writes columbus.zip (shp + shx + dbf) for import into DAPH and then computes on the same polygons. On Windows without a zip program, select the three files in File Explorer and compress them to a ZIP instead.
sf · spdep · spData# Data: the DAPH example dataset (PD cohort) has no map, so this section uses the public
# Columbus, Ohio (1980) neighbourhood map shipped with the R package spData (49 areas).
library(sf); library(spdep)
shp <- system.file("shapes", package = "spData")
utils::zip("columbus.zip", flags = "-j9X",
files = file.path(shp, paste0("columbus.", c("shp", "shx", "dbf"))))
# -> upload columbus.zip in DAPH Tab 1 (the same polygons and attribute table)
col <- st_read(file.path(shp, "columbus.shp"), quiet = TRUE)
x <- col$CRIME # burglaries and vehicle thefts per 1,000 households
# Queen contiguity built from the polygons, row-standardised (as DAPH)
nb <- poly2nb(col, queen = TRUE)
lw <- nb2listw(nb, style = "W")
summary(card(nb)) # neighbours per area
# Global Moran's I: analytic moments under randomisation, and a permutation test
moran.test(x, lw, randomisation = TRUE)
set.seed(12345)
moran.mc(x, lw, nsim = 999)
# Local Moran's I: variance divisor n - 1 (mlvar = FALSE) and conditional
# permutation without repeats (no_repeat_in_row = TRUE), as DAPH
set.seed(12345)
lm <- localmoran_perm(x, lw, nsim = 999, mlvar = FALSE, no_repeat_in_row = TRUE)
p <- lm[, "Pr(folded) Sim"] # (min(k, 999 - k) + 1) / 1000
q <- as.character(attr(lm, "quadr")$pysal)
cl <- ifelse(p < 0.05, q, "Not significant")
table(cl)
split(paste0("#", seq_along(x)), cl) # compare with the lists in DAPH Tab 3
round(cbind(CRIME = x, Ii = lm[, "Ii"], p = p)[c(7, 16, 17, 32), ], 4)
sum(lm[, "Ii"]) / (length(x) - 1) # = global Moran's I
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.000 3.000 4.000 4.816 6.000 10.000
Moran I statistic standard deviate = 5.5894, p-value = 1.139e-08
Moran I statistic Expectation Variance
0.500188557 -0.020833333 0.008689289
statistic = 0.50019, observed rank = 1000, p-value = 0.001
cl
High-High High-Low Low-High Low-Low Not significant
11 1 1 7 29
$`High-High`
[1] "#11" "#15" "#16" "#18" "#24" "#25" "#26" "#28" "#29" "#30" "#37"
$`High-Low`
[1] "#17"
$`Low-High`
[1] "#7"
$`Low-Low`
[1] "#23" "#31" "#32" "#36" "#39" "#40" "#46"
CRIME Ii p
7 0.1783 -1.8226 0.035
16 54.8387 1.2135 0.001
17 36.8688 -0.1059 0.043
32 19.1456 1.2146 0.004
[1] 0.5001886
| ค่าที่เทียบQuantity | R | DAPH | ความต่างDifference | สถานะStatus |
|---|---|---|---|---|
| จำนวนเพื่อนบ้าน ต่ำสุด / เฉลี่ย / สูงสุดNeighbours min / mean / max | 2 / 4.816 / 10 | 2 / 4.816 / 10 | 0 | ✓ PASS |
| Global Moran's I | 0.500189 | 0.500189 | < 1e−6 | ✓ PASS |
| E[I] = −1/(n − 1) | −0.020833 | −0.020833 | < 1e−6 | ✓ PASS |
| z ของ I (R: สูตรวิเคราะห์ · DAPH: การสุ่ม) ²z of I (R: analytic · DAPH: permutation) ² | 5.589 | 5.705 | 0.116 (≤ 0.387) | ✓ PASS |
| pseudo-p ของ Global Ipseudo-p of global I | 0.001 | 0.001 | 0 | ✓ PASS |
| Ii ทั้ง 49 พื้นที่ (ความต่างสูงสุด)Ii, all 49 areas (largest difference) | 49 ค่าvalues | 49 ค่าvalues | 7e−16 | ✓ PASS |
| Ii #7 / #16 / #17 / #32 | −1.8226 / 1.2135 / −0.1059 / 1.2146 | −1.8226 / 1.2135 / −0.1059 / 1.2146 | < 1e−4 | ✓ PASS |
| pseudo-p #7 / #16 / #17 / #32 ³pseudo-p #7 / #16 / #17 / #32 ³ | 0.035 / 0.001 / 0.043 / 0.004 | 0.038 / 0.001 / 0.030 / 0.003 | ≤ 0.013 | ✓ PASS |
| pseudo-p ทั้ง 49 พื้นที่ ³pseudo-p, all 49 areas ³ | 49 ค่าvalues | 49 ค่าvalues | สูงสุด 0.050 · อยู่ในเกณฑ์ 49/49max 0.050 · 49/49 within rule | ✓ PASS |
| กลุ่ม HH / HL / LH / LL / ไม่มีนัยสำคัญ ⁴Groups HH / HL / LH / LL / not significant ⁴ | 11 / 1 / 1 / 7 / 29 | 11 / 1 / 1 / 9 / 27 | ตรงกัน 45/49 พื้นที่45/49 areas agree | ✓ PASS |
² z ของ DAPH มาจากการสุ่ม จึงคลาดจาก z เชิงวิเคราะห์ได้ตามความคลาดเคลื่อนของการสุ่ม เกณฑ์ที่ใช้: |ต่าง| ≤ 3√((1 + z²/2)/999) = 0.387 · ³ pseudo-p ของทั้งสองโปรแกรมเป็นค่าประมาณจากการสุ่มคนละชุด เกณฑ์: |ต่าง| ≤ 3√(2p̄(1 − p̄)/999) โดย p̄ = ค่าเฉลี่ยของสองโปรแกรม · ⁴ สี่พื้นที่ที่ป้ายต่างกัน (#31, #34, #41, #47) มี pseudo-p ระหว่าง 0.040 ถึง 0.070 ในทั้งสองโปรแกรม คือใกล้เส้น 0.05 ผลต่างจึงมาจากการสุ่ม ไม่ใช่วิธีคำนวณ ค่า Ii ตรงกันทุกพื้นที่² DAPH's z comes from the permutations, so it differs from the analytic z by Monte Carlo error; rule used: |difference| ≤ 3√((1 + z²/2)/999) = 0.387 · ³ both programs' pseudo-p are estimates from different random draws; rule: |difference| ≤ 3√(2p̄(1 − p̄)/999), p̄ = mean of the two · ⁴ the four areas whose label differs (#31, #34, #41, #47) have pseudo-p between 0.040 and 0.070 in both programs — close to the 0.05 line, so the difference is random draw, not method; Ii agrees at every area.
4การแปลผลและตัวอย่างInterpretation and Example
① ภาพรวม: Global Moran's I = 0.500 (pseudo-p = 0.001, z จากการสุ่ม = 5.70) — ย่านที่มีอัตราการลักทรัพย์และขโมยรถสูงมักอยู่ติดกับย่านที่อัตราสูง (ความสัมพันธ์เชิงพื้นที่เป็นบวก) pseudo-p = 0.001 คือค่าต่ำสุดที่เป็นไปได้เมื่อสุ่ม 999 รอบ หมายความว่าไม่มีรอบใดได้ I สูงเท่าค่าจริง
② High-High 11 ย่าน (#11, #15, #16, #18, #24, #25, #26, #28, #29, #30, #37) และ Low-Low 9 ย่าน (#23, #32, #34, #36, #39, #40, #41, #46, #47) ที่ pseudo-p < 0.05 — พื้นที่ที่ระบุคือ "แกน" ของกลุ่ม เพื่อนบ้านของแกนเป็นส่วนหนึ่งของกลุ่มด้วยแม้ตัวเองจะไม่มีนัยสำคัญ
③ High-Low #17 (อัตรา 36.9 ซึ่งสูงกว่าค่าเฉลี่ย 35.1 เล็กน้อย แต่รอบข้างต่ำ) และ Low-High #7 (อัตรา 0.18 ต่ำที่สุดในข้อมูล แต่รอบข้างสูง) เป็นพื้นที่ที่ต่างจากรอบข้าง ควรตรวจสอบสาเหตุหรือความถูกต้องของข้อมูล
④ ข้อจำกัด: ทดสอบ 49 พื้นที่ที่ α = 0.05 ถ้าไม่มีรูปแบบเชิงพื้นที่เลยก็คาดว่าจะมีพื้นที่ "มีนัยสำคัญ" โดยบังเอิญราว 2–3 แห่ง และ DAPH ไม่ปรับการทดสอบหลายครั้ง ถ้าต้องการเข้มขึ้นให้ใส่ p threshold เล็กลง เช่น 0.01 (เหลือพื้นที่ที่มี ** หรือ ***) หรือปรับ pseudo-p ใน R ด้วย p.adjust(p, "BH") · ป้ายของพื้นที่ที่ pseudo-p ใกล้ 0.05 อาจเปลี่ยนเมื่อ seed หรือจำนวนรอบเปลี่ยน · ผลขึ้นกับการเลือกเพื่อนบ้าน (หัวข้อ 6.7) · เป็นการบรรยายรูปแบบ ไม่ได้บอกสาเหตุ
① Whole map: global Moran's I = 0.500 (pseudo-p = 0.001, permutation z = 5.70) — neighbourhoods with high burglary and vehicle-theft rates tend to border other high-rate neighbourhoods (positive spatial autocorrelation). A pseudo-p of 0.001 is the smallest possible with 999 permutations: no permutation reached the observed I.
② 11 High-High (#11, #15, #16, #18, #24, #25, #26, #28, #29, #30, #37) and 9 Low-Low (#23, #32, #34, #36, #39, #40, #41, #46, #47) neighbourhoods at pseudo-p < 0.05 — the flagged areas are the "cores" of the clusters; the neighbours of a core belong to the cluster even when not significant themselves.
③ High-Low #17 (rate 36.9, just above the mean of 35.1, with low-rate neighbours) and Low-High #7 (rate 0.18, the lowest in the data, with high-rate neighbours) differ from their surroundings; check the reason, or the data.
④ Limitations: 49 tests at α = 0.05 would flag about 2–3 areas by chance even with no spatial pattern, and DAPH does not adjust for multiple testing. For a stricter reading set a smaller p threshold, e.g. 0.01 (areas with ** or ***), or adjust the pseudo-p in R with p.adjust(p, "BH"). Labels of areas with pseudo-p near 0.05 can change with the seed or the number of permutations. Results depend on the neighbour definition (section 6.7). The analysis describes a pattern; it does not explain its cause.
📖 References
- Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
- Anselin, L. (1995). Local indicators of spatial association—LISA. Geographical Analysis, 27(2), 93–115. doi:10.1111/j.1538-4632.1995.tb00338.x
- Bivand, R. S., & Wong, D. W. S. (2018). Comparing implementations of global and local indicators of spatial association. TEST, 27(3), 716–748. doi:10.1007/s11749-018-0599-x
- Moran, P. A. P. (1950). Notes on continuous stochastic phenomena. Biometrika, 37(1–2), 17–23. doi:10.1093/biomet/37.1-2.17
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
6.5 LISA Bivariate — Local Moran's I_xy
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Bivariate Local Moran's I (Anselin et al., 2002) นำค่าของตัวแปร X ที่พื้นที่ i ไปเทียบกับ ค่าเฉลี่ยของตัวแปร Y ในพื้นที่ข้างเคียงของ i ตอบคำถามว่า "พื้นที่ที่มี X สูง (หรือต่ำ) ถูกล้อมรอบด้วยพื้นที่ที่มี Y สูง (หรือต่ำ) มากกว่าที่ควรเกิดโดยบังเอิญหรือไม่ และอยู่ที่ใด" ผลแบ่งเป็น 4 กลุ่มเหมือน Local Moran's I แบบตัวแปรเดียว (หัวข้อ 6.4) แต่ตัวอักษรแรกหมายถึง X ที่พื้นที่นั้น ตัวอักษรที่สองหมายถึง Y รอบข้าง
Bivariate Local Moran's I (Anselin et al., 2002) relates the value of variable X at area i to the average of variable Y over the neighbours of i. It asks: "are areas with high (or low) X surrounded by areas with high (or low) Y more often than chance would allow, and where?" The four groups are as in the univariate Local Moran's I (section 6.4), but the first letter refers to X at the area and the second to Y around it.
ใช้เมื่อ: ต้องการสำรวจว่าลักษณะของพื้นที่หนึ่ง (เช่น รายได้) สัมพันธ์กับผลลัพธ์ของพื้นที่รอบข้าง (เช่น อัตราป่วย) อย่างไรบนแผนที่ · ข้อควรระวัง: ค่านี้รวมความสัมพันธ์ของ X กับ Y ในพื้นที่เดียวกันเข้ากับความเกาะกลุ่มของ Y เอง ถ้า X และ Y สัมพันธ์กันในพื้นที่เดียวกันและ Y เกาะกลุ่ม ผลจะออกมามีนัยสำคัญได้ แม้ไม่มีอะไร "ส่งผลข้ามพื้นที่" เลย จึงใช้เป็นการบรรยายรูปแบบ ไม่ใช่หลักฐานเชิงสาเหตุ และการสลับ X กับ Y ให้ผลต่างกัน
Use it to explore on a map how a characteristic of an area (e.g. income) relates to an outcome in the surrounding areas (e.g. a disease rate). Caution: the statistic mixes the same-area correlation of X and Y with the clustering of Y itself. If X and Y are correlated within areas and Y is clustered, the result can be significant although nothing "spills over" between areas, so it describes a pattern and is not evidence of cause; swapping X and Y gives a different result.
spData (Anselin, 1988) ชุดเดียวกับหัวข้อ 6.4: X = INC รายได้ครัวเรือน (พันดอลลาร์สหรัฐ) ของย่าน i และ Y = CRIME อัตราการลักทรัพย์ในบ้านและการขโมยรถต่อ 1,000 ครัวเรือนของย่านรอบข้าง · คำถาม: "ย่านรายได้ต่ำถูกล้อมด้วยย่านที่อัตราเหตุสูงหรือไม่ และอยู่ที่ใด"
spData (Anselin, 1988), as in section 6.4: X = INC, household income (1,000 USD) of neighbourhood i, and Y = CRIME, residential burglaries and vehicle thefts per 1,000 households in the surrounding neighbourhoods. Question: "are low-income neighbourhoods surrounded by high-crime neighbourhoods, and where?"
2หลักการและสูตรLogic and Formula
ให้ xi, yi เป็นค่าของพื้นที่ i จาก n พื้นที่ และ wij เป็นน้ำหนักแบบ row-standardised (หัวข้อ 6.7) DAPH คำนวณ:
Let xi, yi be the values of area i (n areas) and wij the row-standardised weights (section 6.7). DAPH computes:
- zxi, zyj
- ค่ามาตรฐานของ X และ Y (หารด้วยส่วนเบี่ยงเบนมาตรฐานตัวอย่าง ตัวหาร n − 1)standardised X and Y (sample standard deviations, divisor n − 1)
- Σj wij zyj
- spatial lag ของ Y = ค่าเฉลี่ยของ Y มาตรฐานในพื้นที่ข้างเคียงของ ispatial lag of Y = mean standardised Y over the neighbours of i
- Ixyi
- บวก = X ที่ i และ Y รอบข้างไปทางเดียวกัน · ลบ = ไปคนละทางpositive = X at i and Y around it go the same way · negative = opposite ways
การทดสอบ: รายพื้นที่ใช้ conditional permutation — ค่า X ของพื้นที่ i คงที่ แล้วสุ่มค่า Y แบบไม่ซ้ำ ki ค่าจากอีก n − 1 พื้นที่มาเป็นเพื่อนบ้าน 999 รอบ pseudo-p = (min(k, R − k) + 1)/(R + 1) เมื่อ k = จำนวนรอบที่ค่าจากการสุ่ม ≥ ค่าจริง (สูตรเดียวกับหัวข้อ 6.4) · ภาพรวมสุ่มเรียงค่า Y ทั้งชุดใหม่ (X อยู่ที่เดิม) 999 รอบ ได้ pseudo-p และ z จากการสุ่ม · กลุ่ม: High-High = zxi > 0 และ lag ของ Y > 0, Low-Low = ทั้งคู่ < 0, High-Low = X สูงแต่ Y รอบข้างต่ำ, Low-High = X ต่ำแต่ Y รอบข้างสูง แสดงเฉพาะ pseudo-p < α
Tests: locally, conditional permutation — X of area i stays fixed while ki values of Y are drawn without repeats from the other n − 1 areas as its neighbours, 999 times; pseudo-p = (min(k, R − k) + 1)/(R + 1), k = number of draws ≥ the observed value (same rule as section 6.4). Globally, all Y values are reshuffled over the areas (X stays) 999 times, giving a pseudo-p and a permutation z. Groups: High-High = zxi > 0 and the lag of Y > 0, Low-Low = both < 0, High-Low = high X but low Y around, Low-High = low X but high Y around; shown only when pseudo-p < α.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
R package spdep มีฟังก์ชัน localmoran_bv() สำหรับสถิตินี้โดยตรง สคริปต์สร้าง columbus.zip สำหรับนำเข้า DAPH (Windows ที่ไม่มีโปรแกรม zip ให้บีบอัดสามไฟล์ด้วย File Explorer)
The R package spdep provides localmoran_bv() for this statistic. The script writes columbus.zip for import into DAPH (on Windows without a zip program, compress the three files with File Explorer).
sf · spdep · spData# Data: the DAPH example dataset (PD cohort) has no map, so this section uses the public
# Columbus, Ohio (1980) neighbourhood map shipped with the R package spData (49 areas).
library(sf); library(spdep)
shp <- system.file("shapes", package = "spData")
utils::zip("columbus.zip", flags = "-j9X",
files = file.path(shp, paste0("columbus.", c("shp", "shx", "dbf"))))
# -> upload columbus.zip in DAPH Tab 1
col <- st_read(file.path(shp, "columbus.shp"), quiet = TRUE)
nb <- poly2nb(col, queen = TRUE)
lw <- nb2listw(nb, style = "W")
x <- col$INC # X, focal at area i: household income (1,000 USD)
y <- col$CRIME # Y, lagged over the neighbours: burglaries + thefts per 1,000 households
n <- length(x)
cor(x, y) # same-area (in-place) correlation of X and Y
# Global bivariate Moran's I and a permutation test (X fixed, Y reshuffled)
zx <- as.numeric(scale(x)); zy <- as.numeric(scale(y)) # sample SD, divisor n - 1
lag_zy <- lag.listw(lw, zy)
Ibv <- sum(zx * lag_zy) / (n - 1)
Ibv
set.seed(12345)
sims <- replicate(999, sum(zx * lag.listw(lw, sample(zy))) / (n - 1))
(Ibv - mean(sims)) / sd(sims) # permutation z
(min(sum(sims >= Ibv), 999 - sum(sims >= Ibv)) + 1) / 1000 # folded pseudo-p
# Local bivariate Moran's I with conditional permutation (as DAPH)
set.seed(12345)
bv <- localmoran_bv(x, y, lw, nsim = 999, no_repeat_in_row = TRUE)
p <- bv[, "Pr(folded) Sim"]
q <- ifelse(zx > 0, ifelse(lag_zy > 0, "High-High", "High-Low"),
ifelse(lag_zy > 0, "Low-High", "Low-Low"))
cl <- ifelse(p < 0.05, q, "Not significant")
table(cl)
split(paste0("#", seq_len(n)), cl) # compare with the lists in DAPH Tab 3
data.frame(area = paste0("#", seq_len(n)), INC = x, CRIME = y,
Ibv = round(bv[, "Ibvi"], 4), p = p)[c(7, 16, 32, 37), ]
[1] -0.6955898
[1] -0.4516227
[1] -4.545099
[1] 0.001
cl
High-High High-Low Low-High Low-Low Not significant
1 7 11 1 29
$`High-High`
[1] "#37"
$`High-Low`
[1] "#23" "#31" "#32" "#34" "#36" "#39" "#40"
$`Low-High`
[1] "#7" "#11" "#15" "#16" "#18" "#24" "#25" "#26" "#28" "#29" "#30"
$`Low-Low`
[1] "#17"
area INC CRIME Ibv p
7 #7 8.438 0.178269 -0.9083 0.032
16 #16 7.625 54.838711 -1.2192 0.001
32 #32 18.942 19.145592 -1.0181 0.002
37 #37 17.017 42.445076 0.4392 0.008
| ค่าที่เทียบQuantity | R | DAPH | ความต่างDifference | สถานะStatus |
|---|---|---|---|---|
| Global bivariate Moran's I | −0.451623 | −0.451623 | < 1e−6 | ✓ PASS |
| z จากการสุ่ม (ทั้งสองโปรแกรม) ²permutation z (both programs) ² | −4.545 | −4.329 | 0.216 (≤ 0.442) | ✓ PASS |
| pseudo-p ภาพรวมglobal pseudo-p | 0.001 | 0.001 | 0 | ✓ PASS |
| Ixyi ทั้ง 49 พื้นที่ (ความต่างสูงสุด)Ixyi, all 49 areas (largest difference) | 49 ค่าvalues | 49 ค่าvalues | 2e−16 | ✓ PASS |
| Ixyi #7 / #16 / #32 / #37 | −0.9083 / −1.2192 / −1.0181 / 0.4392 | −0.9083 / −1.2192 / −1.0181 / 0.4392 | < 1e−4 | ✓ PASS |
| pseudo-p #7 / #16 / #32 / #37 ³pseudo-p #7 / #16 / #32 / #37 ³ | 0.032 / 0.001 / 0.002 / 0.008 | 0.038 / 0.001 / 0.003 / 0.008 | ≤ 0.006 | ✓ PASS |
| pseudo-p ทั้ง 49 พื้นที่ ³pseudo-p, all 49 areas ³ | 49 ค่าvalues | 49 ค่าvalues | สูงสุด 0.042 · อยู่ในเกณฑ์ 49/49max 0.042 · 49/49 within rule | ✓ PASS |
| กลุ่ม HH / HL / LH / LL / ไม่มีนัยสำคัญ ⁴Groups HH / HL / LH / LL / not significant ⁴ | 1 / 7 / 11 / 1 / 29 | 1 / 9 / 11 / 1 / 27 | ตรงกัน 45/49 พื้นที่45/49 areas agree | ✓ PASS |
² ทั้งสองค่าเป็นค่าประมาณจากการสุ่มคนละชุด เกณฑ์: |ต่าง| ≤ 3√(2(1 + z̄²/2)/999) = 0.442 เมื่อ z̄ = ค่าเฉลี่ยของสองโปรแกรม · ³ เกณฑ์: |ต่าง| ≤ 3√(2p̄(1 − p̄)/999) · ⁴ พื้นที่ที่ป้ายต่างกัน (#31, #41, #46, #47) มี pseudo-p ระหว่าง 0.035 ถึง 0.076 คือใกล้เส้น 0.05 ส่วนค่า Ixyi ตรงกันทุกพื้นที่² both values are permutation estimates from different draws; rule: |difference| ≤ 3√(2(1 + z̄²/2)/999) = 0.442, z̄ = mean of the two · ³ rule: |difference| ≤ 3√(2p̄(1 − p̄)/999) · ⁴ the areas whose label differs (#31, #41, #46, #47) have pseudo-p between 0.035 and 0.076, close to the 0.05 line; Ixyi agrees at every area.
4การแปลผลและตัวอย่างInterpretation and Example
① ภาพรวม: Global bivariate Moran's I = −0.452 (pseudo-p = 0.001, z จากการสุ่ม = −4.33) — ย่านที่รายได้สูงมักถูกล้อมด้วยย่านที่อัตราเหตุต่ำ และย่านรายได้ต่ำมักถูกล้อมด้วยย่านที่อัตราเหตุสูง ทั้งนี้รายได้กับอัตราเหตุในย่านเดียวกันก็สัมพันธ์กันอยู่แล้ว (r = −0.70) ค่านี้จึงสะท้อนทั้งสองอย่างรวมกัน
② Low-High 11 ย่าน (#7, #11, #15, #16, #18, #24, #25, #26, #28, #29, #30): รายได้ต่ำ รอบข้างอัตราเหตุสูง · High-Low 9 ย่าน (#23, #32, #34, #36, #39, #40, #41, #46, #47): รายได้สูง รอบข้างอัตราเหตุต่ำ — สองกลุ่มนี้ไปตามความสัมพันธ์เชิงลบของภาพรวม
③ High-High #37 (รายได้ 17.0 แต่รอบข้างอัตราเหตุสูง) และ Low-Low #17 (รายได้ต่ำ รอบข้างอัตราเหตุต่ำ) เป็นพื้นที่ที่ไม่เป็นไปตามรูปแบบหลัก ควรดูรายละเอียดเพิ่ม
④ ข้อจำกัด: เป็นความสัมพันธ์เชิงพื้นที่ ไม่ได้บอกว่ารายได้ทำให้เกิดเหตุในย่านข้างเคียง · ไม่ได้ปรับการทดสอบหลายครั้ง · ป้ายของพื้นที่ที่ pseudo-p ใกล้ 0.05 อาจเปลี่ยนเมื่อสุ่มใหม่ · ถ้าต้องการแยกผลของตัวแปรหลายตัวพร้อมกัน ให้ใช้ Spatial Regression
① Whole map: global bivariate Moran's I = −0.452 (pseudo-p = 0.001, permutation z = −4.33) — higher-income neighbourhoods tend to be surrounded by lower crime rates, and lower-income neighbourhoods by higher crime rates. Income and crime are already correlated within the same neighbourhood (r = −0.70), so the value reflects both together.
② 11 Low-High neighbourhoods (#7, #11, #15, #16, #18, #24, #25, #26, #28, #29, #30): low income, high crime around · 9 High-Low (#23, #32, #34, #36, #39, #40, #41, #46, #47): high income, low crime around — both follow the overall negative association.
③ High-High #37 (income 17.0 with high crime around) and Low-Low #17 (low income, low crime around) do not follow the main pattern and deserve a closer look.
④ Limitations: a spatial association, not evidence that income causes crime next door · no multiple-testing adjustment · labels of areas with pseudo-p near 0.05 can change with new random draws · to separate several variables at once, use Spatial Regression.
📖 References
- Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
- Anselin, L., Syabri, I., & Smirnov, O. (2002). Visualizing multivariate spatial correlation with dynamically linked windows. In L. Anselin & S. Rey (Eds.), New tools for spatial data analysis: Proceedings of the specialist meeting. Center for Spatially Integrated Social Science (CSISS), University of California, Santa Barbara.
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
6.6 Getis-Ord — Global G, Local G_i, G*_i (Hotspot trio)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
สถิติ Getis-Ord (Getis & Ord, 1992; Ord & Getis, 1995) วัดว่า ค่าสูง หรือ ค่าต่ำ กระจุกอยู่ด้วยกันหรือไม่ จึงแยก "จุดร้อน" (hot spot) ออกจาก "จุดเย็น" (cold spot) ได้ ต่างจาก Moran's I (หัวข้อ 6.4) ที่วัดว่าพื้นที่ติดกัน "คล้ายกัน" ทั้งสูง-สูงและต่ำ-ต่ำ DAPH มี 3 ตัว: Global G (ทั้งแผนที่, ตัวเลขเดียว), Getis-Ord Gi (รายพื้นที่ ใช้เฉพาะค่าของพื้นที่ข้างเคียง ไม่นับตัวเอง) และ Getis-Ord Gi* (รายพื้นที่ นับตัวเองรวมกับข้างเคียง)
The Getis-Ord statistics (Getis & Ord, 1992; Ord & Getis, 1995) measure whether high or low values are concentrated together, so they separate hot spots from cold spots, whereas Moran's I (section 6.4) measures whether neighbouring areas are similar, high-high and low-low alike. DAPH offers three: Global G (whole map, one number), Getis-Ord Gi (per area, neighbours only, the area itself excluded) and Getis-Ord Gi* (per area, the area together with its neighbours).
ใช้เมื่อ: ตัวแปรเป็นค่าที่ไม่ติดลบ เช่น อัตราป่วย จำนวนผู้ป่วย และต้องการหาว่าจุดร้อน/จุดเย็นอยู่ที่ใด · ไม่ควรใช้เมื่อ: ตัวแปรมีค่าลบหรือเป็นคะแนนที่ศูนย์ไม่มีความหมาย (สูตรแบ่งด้วยผลรวมของค่า), จำนวนพื้นที่น้อยกว่า 10, หรืออัตรามาจากประชากรน้อยมาก
Use it for non-negative variables such as disease rates or case counts when you want to locate hot and cold spots. Do not use it for variables with negative values or scores whose zero has no meaning (the formulas divide by sums of the values), for fewer than 10 areas, or for rates from very small populations.
spData (Anselin, 1988) ชุดเดียวกับหัวข้อ 6.4: 49 ย่าน, CRIME = การลักทรัพย์ในบ้านและการขโมยรถต่อ 1,000 ครัวเรือน (ไม่มีค่าลบ) · คำถาม: "อัตราเหตุสูงกระจุกตัวหรือไม่ และย่านใดเป็นจุดร้อน/จุดเย็น"
spData (Anselin, 1988), as in section 6.4: 49 neighbourhoods, CRIME = residential burglaries and vehicle thefts per 1,000 households (no negative values). Question: "are high rates concentrated, and which neighbourhoods are hot or cold spots?"
2หลักการและสูตรLogic and Formula
ให้ xi ≥ 0 เป็นค่าของพื้นที่ i จาก n พื้นที่ และ N(i) เป็นเพื่อนบ้านของ i (ki แห่ง, หัวข้อ 6.7)
Let xi ≥ 0 be the value of area i (n areas) and N(i) its ki neighbours (section 6.7).
- x̄, s
- ค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานของ x ทั้ง n พื้นที่ (ตัวหาร n)mean and standard deviation of x over all n areas (divisor n)
- x̄(i), s(i)
- ค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานของอีก n − 1 พื้นที่ที่ไม่ใช่ i (ตัวหาร n − 1)mean and standard deviation of the n − 1 areas other than i (divisor n − 1)
- S0
- จำนวนคู่เพื่อนบ้าน (นับสองทิศ)number of neighbour links (both directions)
- z
- บวก = ค่ารวมรอบพื้นที่สูงกว่าที่คาด · ลบ = ต่ำกว่าที่คาด · ค่า z ไม่ขึ้นกับว่าน้ำหนักเป็นแบบ 0/1 หรือ row-standardisedpositive = the local sum is higher than expected · negative = lower · z is the same for binary and row-standardised weights
การทดสอบ: Global G — สุ่มเรียงค่า x ใหม่ทั้งชุด 999 รอบ แล้ว z = (G − ค่าเฉลี่ยของ G จากการสุ่ม)/SD ของ G จากการสุ่ม และ pseudo-p สองด้าน = 2 × (min(k, R − k) + 1)/(R + 1) เมื่อ k = จำนวนรอบที่ G จากการสุ่ม ≥ G จริง · Gi และ Gi* — conditional permutation: ค่า xi ของพื้นที่ i คงที่ แล้วสุ่มค่า ki ค่าแบบไม่ซ้ำจากอีก n − 1 พื้นที่มาเป็นเพื่อนบ้าน 999 รอบ pseudo-p = (min(k, R − k) + 1)/(R + 1) (หางที่เล็กกว่า) · เพราะค่าของตัวเองคงที่ การสุ่มของ Gi* จึงเปลี่ยนเฉพาะเพื่อนบ้าน DAPH จึงให้ pseudo-p ของ Gi กับ Gi* เท่ากันทุกพื้นที่ ต่างกันเฉพาะค่า G และ z
Tests: Global G — all x values are reshuffled over the areas 999 times; z = (G − mean of the permuted G)/SD of the permuted G, and the two-sided pseudo-p = 2 × (min(k, R − k) + 1)/(R + 1), k = number of permutations with G ≥ the observed G. Gi and Gi* — conditional permutation: xi stays fixed and ki values are drawn without repeats from the other n − 1 areas as its neighbours, 999 times; pseudo-p = (min(k, R − k) + 1)/(R + 1) (the smaller tail). Because the area's own value is fixed, the Gi* permutations change only the neighbours, so DAPH gives Gi and Gi* the same pseudo-p at every area; only G and z differ.
การจัดกลุ่มของ DAPH: ทิศทาง Hot/Cold ตามเครื่องหมายของ z · ระดับตาม pseudo-p: Hot/Cold 99% เมื่อ pseudo-p < 0.01, 95% เมื่อ pseudo-p < 0.05, 90% เมื่อ pseudo-p < α ที่ตั้งไว้มากกว่า 0.05 (ที่ α = 0.05 กลุ่ม 90% ว่างเสมอ) ส่วนที่เหลือเป็น Not Significant — ระดับจึงมาจาก pseudo-p ไม่ใช่ จากเกณฑ์ |z| > 1.65/1.96/2.58
DAPH's grouping: Hot/Cold direction from the sign of z · level from the pseudo-p: Hot/Cold 99% when pseudo-p < 0.01, 95% when pseudo-p < 0.05, 90% when pseudo-p < an α set above 0.05 (with α = 0.05 the 90% groups are always empty); the rest are Not Significant. The levels therefore come from the pseudo-p, not from |z| > 1.65/1.96/2.58.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
Global G ใช้น้ำหนัก 0/1 (style = "B") เหมือน DAPH ส่วน Gi/Gi* ใช้ style = "W" เพื่อให้ค่า G เท่ากับที่ DAPH พิมพ์ (z เท่ากันทั้งสองแบบ) สคริปต์สร้าง columbus.zip สำหรับนำเข้า DAPH
Global G uses 0/1 weights (style = "B") as DAPH does; Gi/Gi* use style = "W" so that the G values equal the ones DAPH prints (z is identical either way). The script writes columbus.zip for import into DAPH.
sf · spdep · spData# Data: the DAPH example dataset (PD cohort) has no map, so this section uses the public
# Columbus, Ohio (1980) neighbourhood map shipped with the R package spData (49 areas).
library(sf); library(spdep)
shp <- system.file("shapes", package = "spData")
utils::zip("columbus.zip", flags = "-j9X",
files = file.path(shp, paste0("columbus.", c("shp", "shx", "dbf"))))
# -> upload columbus.zip in DAPH Tab 1
col <- st_read(file.path(shp, "columbus.shp"), quiet = TRUE)
x <- col$CRIME # burglaries and vehicle thefts per 1,000 households
nb <- poly2nb(col, queen = TRUE)
# Global G: binary weights (w_ij = 1 for each queen neighbour), analytic moments
lwB <- nb2listw(nb, style = "B")
globalG.test(x, lwB, alternative = "two.sided")
# DAPH's z for G comes from 999 permutations of x over the areas
G <- function(v) sum(v * lag.listw(lwB, v)) / (sum(v)^2 - sum(v^2))
set.seed(123456789)
sims <- replicate(999, G(sample(x)))
(G(x) - mean(sims)) / sd(sims) # permutation z
k <- sum(sims >= G(x)); 2 * (min(k, 999 - k) + 1) / 1000 # two-sided pseudo-p
# Local Gi (self excluded) and Gi* (self included), conditional permutation.
# Row-standardised weights give the G values DAPH prints; z is the same either way.
band <- function(z, p) ifelse(p >= 0.05, "Not significant",
paste(ifelse(z > 0, "Hot", "Cold"), ifelse(p < 0.01, "99%", "95%")))
set.seed(123456789)
gi <- localG_perm(x, nb2listw(nb, style = "W"), nsim = 999, no_repeat_in_row = TRUE)
set.seed(123456789)
gis <- localG_perm(x, nb2listw(include.self(nb), style = "W"), nsim = 999,
no_repeat_in_row = TRUE)
p_gi <- attr(gi, "internals")[, "Pr(folded) Sim"]
p_gis <- attr(gis, "internals")[, "Pr(folded) Sim"]
table(Gi = band(as.numeric(gi), p_gi))
table(Gi_star = band(as.numeric(gis), p_gis))
data.frame(area = paste0("#", c(7, 16, 17, 32)), CRIME = x[c(7, 16, 17, 32)],
Gi = round(attr(gi, "internals")[c(7, 16, 17, 32), "Gi"], 4),
z_Gi = round(as.numeric(gi)[c(7, 16, 17, 32)], 3), p_Gi = p_gi[c(7, 16, 17, 32)],
Gi_star = round(attr(gis, "internals")[c(7, 16, 17, 32), "Gi"], 4),
z_Gi_star = round(as.numeric(gis)[c(7, 16, 17, 32)], 3),
p_Gi_star = p_gis[c(7, 16, 17, 32)])
standard deviate = 4.6382, p-value = 3.515e-06
Global G statistic Expectation Variance
1.278075e-01 1.003401e-01 3.507057e-05
[1] 4.718786
[1] 0.002
Gi
Cold 95% Cold 99% Hot 95% Hot 99% Not significant
7 2 3 8 29
Gi_star
Cold 95% Cold 99% Hot 95% Hot 99% Not significant
7 1 6 6 29
area CRIME Gi z_Gi p_Gi Gi_star z_Gi_star p_Gi_star
1 #7 0.178269 0.0289 1.799 0.050 0.0231 0.661 0.032
2 #16 54.838711 0.0314 3.282 0.001 0.0306 3.475 0.001
3 #17 36.868774 0.0107 -1.799 0.027 0.0132 -1.540 0.037
4 #32 19.145592 0.0081 -2.696 0.003 0.0087 -2.851 0.005
| ค่าที่เทียบQuantity | R | DAPH | ความต่างDifference | สถานะStatus |
|---|---|---|---|---|
| Global G | 0.127807 | 0.127807 | < 1e−6 | ✓ PASS |
| E[G] | 0.100340 | 0.100340 | < 1e−6 | ✓ PASS |
| z ของ G (R: สูตรวิเคราะห์ · DAPH: การสุ่ม) ²z of G (R: analytic · DAPH: permutation) ² | 4.638 | 4.462 | 0.176 (≤ 0.325) | ✓ PASS |
| pseudo-p สองด้านของ Gtwo-sided pseudo-p of G | 0.002 | 0.002 | 0 | ✓ PASS |
| Gi และ G*i ทั้ง 49 พื้นที่ (ความต่างสูงสุด)Gi and G*i, all 49 areas (largest difference) | 98 ค่าvalues | 98 ค่าvalues | 1e−17 | ✓ PASS |
| z ของ Gi และ G*i ทั้ง 49 พื้นที่z of Gi and G*i, all 49 areas | 98 ค่าvalues | 98 ค่าvalues | 3e−15 | ✓ PASS |
| Gi #7 / #16 / #17 / #32: G · z | 0.0289 · 1.799 / 0.0314 · 3.282 / 0.0107 · −1.799 / 0.0081 · −2.696 | 0.0289 · 1.799 / 0.0314 · 3.282 / 0.0107 · −1.799 / 0.0081 · −2.696 | < 0.001 | ✓ PASS |
| Gi* #7 / #16 / #17 / #32: G · z | 0.0231 · 0.661 / 0.0306 · 3.475 / 0.0132 · −1.540 / 0.0087 · −2.851 | 0.0231 · 0.661 / 0.0306 · 3.475 / 0.0132 · −1.540 / 0.0087 · −2.851 | < 0.001 | ✓ PASS |
| pseudo-p Gi #7 / #16 / #17 / #32 ³pseudo-p Gi #7 / #16 / #17 / #32 ³ | 0.050 / 0.001 / 0.027 / 0.003 | 0.032 / 0.001 / 0.027 / 0.003 | ≤ 0.018 | ✓ PASS |
| pseudo-p Gi* #7 / #16 / #17 / #32 ³pseudo-p Gi* #7 / #16 / #17 / #32 ³ | 0.032 / 0.001 / 0.037 / 0.005 | 0.032 / 0.001 / 0.027 / 0.003 | ≤ 0.010 | ✓ PASS |
| pseudo-p ทั้ง 49 พื้นที่ (Gi · Gi*) ³pseudo-p, all 49 areas (Gi · Gi*) ³ | 98 ค่าvalues | 98 ค่าvalues | สูงสุด 0.044 · 0.040 · อยู่ในเกณฑ์ 49/49 ทั้งคู่max 0.044 · 0.040 · 49/49 within rule for both | ✓ PASS |
| Gi: Hot 99 / Hot 95 / Cold 95 / Cold 99 / ไม่มีนัยสำคัญ ⁴Gi: Hot 99 / Hot 95 / Cold 95 / Cold 99 / not significant ⁴ | 8 / 3 / 7 / 2 / 29 | 5 / 7 / 6 / 2 / 29 | ทิศทางตรงกัน 47/49 · ระดับตรงกัน 44/49direction 47/49 · level 44/49 agree | ✓ PASS |
| Gi*: Hot 99 / Hot 95 / Cold 95 / Cold 99 / ไม่มีนัยสำคัญ ⁴Gi*: Hot 99 / Hot 95 / Cold 95 / Cold 99 / not significant ⁴ | 6 / 6 / 7 / 1 / 29 | 5 / 7 / 6 / 2 / 29 | ทิศทางตรงกัน 47/49 · ระดับตรงกัน 45/49direction 47/49 · level 45/49 agree | ✓ PASS |
² z ของ DAPH มาจากการสุ่ม เกณฑ์: |ต่าง| ≤ 3√((1 + z²/2)/999) = 0.325 (R เองสุ่มได้ 4.719 ซึ่งก็อยู่ในช่วงเดียวกัน) · ³ pseudo-p เป็นค่าประมาณจากการสุ่มคนละชุด เกณฑ์: |ต่าง| ≤ 3√(2p̄(1 − p̄)/999) · ⁴ พื้นที่ที่ทิศทางต่างกัน (Gi: #7, #23 · Gi*: #23, #46) มี pseudo-p 0.032 ถึง 0.053 คือใกล้เส้น 0.05 และพื้นที่ที่ต่างเฉพาะระดับมี pseudo-p ใกล้ 0.01 ส่วนค่า G และ z ตรงกันทุกพื้นที่² DAPH's z comes from permutations; rule: |difference| ≤ 3√((1 + z²/2)/999) = 0.325 (R's own permutation gave 4.719, within the same range) · ³ pseudo-p are estimates from different random draws; rule: |difference| ≤ 3√(2p̄(1 − p̄)/999) · ⁴ areas whose direction differs (Gi: #7, #23 · Gi*: #23, #46) have pseudo-p from 0.032 to 0.053, close to the 0.05 line, and those differing only in level have pseudo-p near 0.01; G and z agree at every area.
4การแปลผลและตัวอย่างInterpretation and Example
① Global G = 0.128 สูงกว่าค่าคาดหมาย E[G] = 0.100 (z จากการสุ่ม = 4.46, pseudo-p สองด้าน = 0.002) — อัตราเหตุสูงกระจุกอยู่ใกล้กันมากกว่าที่ควรเกิดโดยบังเอิญ (ถ้า G ต่ำกว่า E[G] จะหมายถึงค่าต่ำกระจุกตัว) Global G บอกเพียงว่ามีการกระจุก ไม่บอกตำแหน่ง
② Gi* (α = 0.05): จุดร้อน 12 ย่าน — Hot 99%: #16, #24, #25, #28, #29 · Hot 95%: #7, #11, #15, #18, #26, #30, #37 — และจุดเย็น 8 ย่าน — Cold 99%: #32, #36 · Cold 95%: #17, #31, #34, #39, #40, #46 · Gi ให้ป้ายชุดเดียวกัน (pseudo-p เท่ากัน) ต่างกันที่ค่า z
③ อ่านป้ายคู่กับ z เสมอ: #7 มีอัตราต่ำที่สุดในข้อมูล (0.18) แต่ได้ป้าย Hot 95% เพราะการสุ่มคงค่าของตัวเองไว้ pseudo-p จึงวัดว่า "เพื่อนบ้านสูงผิดปกติ" ขณะที่ z ของ Gi* = 0.66 บอกว่าผลรวมของตัวเองกับเพื่อนบ้านไม่ได้สูงผิดปกติ ทำนองเดียวกัน #17 (อัตรา 36.9 สูงกว่าค่าเฉลี่ย) ได้ Cold 95% จากเพื่อนบ้านที่ต่ำ (z = −1.54) ป้ายที่ |z| < 1.96 จึงควรอ่านว่า "อยู่ติดกับกลุ่ม" มากกว่า "เป็นส่วนของกลุ่ม"
④ ข้อจำกัด: ทดสอบ 49 พื้นที่โดยไม่ปรับการทดสอบหลายครั้ง และพื้นที่ติดกันใช้เพื่อนบ้านร่วมกันจึงไม่เป็นอิสระต่อกัน · ป้ายที่ pseudo-p ใกล้ 0.01 หรือ 0.05 อาจเปลี่ยนเมื่อสุ่มใหม่ · ผลขึ้นกับการเลือกเพื่อนบ้าน (หัวข้อ 6.7) · เป็นการบรรยายรูปแบบ ไม่ได้บอกสาเหตุ
① Global G = 0.128, above its expectation E[G] = 0.100 (permutation z = 4.46, two-sided pseudo-p = 0.002) — high rates are concentrated near each other more than chance would allow (G below E[G] would mean low values are concentrated). Global G says that clustering exists, not where.
② Gi* (α = 0.05): 12 hot spots — Hot 99%: #16, #24, #25, #28, #29 · Hot 95%: #7, #11, #15, #18, #26, #30, #37 — and 8 cold spots — Cold 99%: #32, #36 · Cold 95%: #17, #31, #34, #39, #40, #46. Gi gives the same labels (same pseudo-p); only z differs.
③ Always read the label with z: #7 has the lowest rate in the data (0.18) yet is labelled Hot 95%, because the permutation keeps its own value fixed, so the pseudo-p measures whether its neighbours are unusually high, while the Gi* z = 0.66 says the area plus its neighbours is not unusually high. Likewise #17 (rate 36.9, above the mean) is Cold 95% because of low neighbours (z = −1.54). Read a label with |z| < 1.96 as "next to a cluster" rather than "part of it".
④ Limitations: 49 tests without multiple-testing adjustment, and neighbouring areas share neighbours, so the tests are not independent · labels with pseudo-p near 0.01 or 0.05 can change with new random draws · results depend on the neighbour definition (section 6.7) · the analysis describes a pattern, not its cause.
📖 References
- Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
- Getis, A., & Ord, J. K. (1992). The analysis of spatial association by use of distance statistics. Geographical Analysis, 24(3), 189–206. doi:10.1111/j.1538-4632.1992.tb00261.x
- Ord, J. K., & Getis, A. (1995). Local spatial autocorrelation statistics: Distributional issues and an application. Geographical Analysis, 27(4), 286–306. doi:10.1111/j.1538-4632.1995.tb00912.x
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
6.7การเลือก Spatial Weights (Queen · Queen ปรับ · Distance band · KNN)GUIDE
1ทำไมการเลือก weights ถึงสำคัญที่สุดWhy the weights choice matters most
ทุกสถิติในบทนี้เริ่มจากเมทริกซ์น้ำหนักเชิงพื้นที่ W ที่กำหนดว่า "พื้นที่ใดเป็นเพื่อนบ้านของพื้นที่ใด" (Anselin, 1988) เมื่อเปลี่ยน W ค่า Moran's I, กลุ่ม LISA, จุดร้อน และค่า ρ, λ ของ Spatial Regression ก็เปลี่ยน จึง ต้องรายงานชนิดของ weights ที่ใช้เสมอ — DAPH พิมพ์บรรทัด "Spatial weights" ไว้ใน Tab 3 และในไฟล์ Word ให้อัตโนมัติ
Every statistic in this chapter starts from a spatial weights matrix W that declares which areas are neighbours (Anselin, 1988). Change W and Moran's I, the LISA groups, the hot spots and the ρ, λ of Spatial Regression change with it, so the weights specification must always be reported — DAPH prints a "Spatial weights" line in Tab 3 and in the Word file automatically.
spData (Anselin, 1988) กับตัวแปร CRIME (หัวข้อ 6.4) ข้อมูลชุดเดียวกันได้ Global Moran's I = 0.500 เมื่อใช้ Queen order 1, 0.552 เมื่อใช้ distance band และ 0.583 เมื่อใช้ 4 เพื่อนบ้านใกล้สุด (ตารางในส่วนที่ 3) — ข้อสรุปตรงกัน แต่ขนาดต่างกัน ส่วนเรื่องเกาะใช้แผนที่ 77 จังหวัดของประเทศไทย (ส่วนที่ 4)
spData (Anselin, 1988) with the variable CRIME (section 6.4). The same data give global Moran's I = 0.500 with Queen order 1, 0.552 with the distance band and 0.583 with the 4 nearest neighbours (table in part 3) — the same conclusion, a different size. Islands are illustrated with a 77-province map of Thailand (part 4).
2ตัวเลือกที่มีให้ และควรใช้เมื่อไรThe options, and when to use each
- dij
- ระยะระหว่างจุดศูนย์กลาง (centroid) ของ polygon i และ j ตามตัวเลือก Distance Metricdistance between the polygon centroids of i and j, in the chosen Distance Metric
- d*
- รัศมีอัตโนมัติ = ระยะเล็กที่สุดที่ทำให้ทุกพื้นที่มีเพื่อนบ้านอย่างน้อย 1 แห่ง (คูณ 1.001)automatic radius = the smallest distance that gives every area at least one neighbour (times 1.001)
- λ, φ, R
- ลองจิจูด ละติจูด และรัศมีโลก — ลำดับ (ลองจิจูด, ละติจูด) ต้องถูก ถ้าสลับกันจะได้ระยะผิดโดยไม่มีข้อความเตือนlongitude, latitude and the Earth's radius — the (longitude, latitude) order matters; swapping them gives wrong distances without any warning
| ตัวเลือกใน Tab 2Option in Tab 2 | นิยามเพื่อนบ้านและน้ำหนักที่ DAPH ใช้จริงNeighbours and the weights DAPH really uses | เหมาะกับUse when |
|---|---|---|
| Queen Contiguity | polygon ที่มีจุดบนขอบร่วมกันอย่างน้อยหนึ่งจุด (ขอบหรือมุม) · Order 1 = เพื่อนบ้านโดยตรง · Order 2 = เพื่อนบ้านโดยตรงรวมกับเพื่อนบ้านของเพื่อนบ้าน (สะสม) — เหมือนกันในทุกสถิติของบทนี้polygons sharing at least one boundary point (edge or corner) · Order 1 = direct neighbours · Order 2 = direct neighbours plus neighbours of neighbours (cumulative) — the same in every statistic of this chapter | พื้นที่ปกครองที่ต่อกันเป็นผืนเดียวadministrative areas forming one contiguous landmass |
| Queen Contiguity (ปรับ — เชื่อมเกาะmodified — link islands) | Queen แล้วเชื่อมพื้นที่ที่ไม่มีเพื่อนบ้านเลย (เกาะ) กับพื้นที่ใกล้สุด k แห่ง (ช่อง "เกาะเชื่อมกี่พื้นที่" ค่าเริ่มต้น 1) โดยวัดจากขอบถึงขอบเป็น กม. หรือ ไมล์ และเชื่อมเฉพาะเมื่อไม่เกิน "ระยะเชื่อมเกาะสูงสุด" (เว้นว่าง = ระยะเล็กสุดที่ทุกพื้นที่มีเพื่อนบ้าน วัดระหว่างจุดศูนย์กลาง คูณ 1.001) เกาะที่ไกลกว่าไม่ถูกเชื่อมและถูกระบุชื่อในบรรทัด weights · เชื่อมเฉพาะพื้นที่ที่มีเพื่อนบ้านเป็นศูนย์ กลุ่มหลายพื้นที่ที่แยกจากแผ่นดินใหญ่ไม่ถูกเชื่อมQueen, then every area with no neighbour (an island) is linked to its k nearest areas (box "Islands link to k nearest", default 1), measured border to border in km or miles, and only within the "Max linking distance" (blank = the smallest distance at which every area has a neighbour, measured between centroids, times 1.001). Islands beyond it stay unlinked and are named in the weights line · only areas with zero neighbours are linked; a group of several areas cut off from the mainland is not joined | แผนที่ที่มีเกาะ เช่น จังหวัดภูเก็ตmaps with islands, e.g. Phuket province |
| Inverse Distance Weight (distance band)(distance band) | พื้นที่ที่จุดศูนย์กลางห่างไม่เกินรัศมี d* ซึ่ง DAPH ตั้งให้อัตโนมัติ (ไม่มีช่องให้กำหนดรัศมี) · Spatial Regression ใช้น้ำหนักเท่ากันสำหรับแบบจำลอง และใช้ 1/dpower เฉพาะการทดสอบเชิงพื้นที่ของ OLS · Local Moran และ Getis-Ord ใช้น้ำหนักเท่ากัน ช่อง Power ไม่มีผลareas whose centroids lie within the radius d*, which DAPH sets automatically (there is no box for the radius) · Spatial Regression uses equal weights for the model and 1/dpower only for the OLS spatial diagnostics · Local Moran and Getis-Ord use equal weights; the Power box has no effect | เมื่อระยะทางจริงเป็นตัวกำหนดความใกล้ ไม่ใช่รูปร่างเขตปกครอง (พื้นที่ห่างไกลจะมีเพื่อนบ้านน้อย พื้นที่หนาแน่นมีมาก)when real distance, not administrative shape, defines nearness (remote areas get few neighbours, dense areas many) |
| K-Nearest Neighbors | จุดศูนย์กลางที่ใกล้ที่สุด k แห่ง (ช่อง k ค่าเริ่มต้น 1) ทุกพื้นที่มีเพื่อนบ้านเท่ากัน · W ไม่สมมาตร (j อาจเป็นเพื่อนบ้านของ i แต่ i ไม่เป็นของ j) · k = 1 ให้เพื่อนบ้านเพียงแห่งเดียวและมักแยกแผนที่เป็นกลุ่มเล็ก ๆ จึงควรกำหนด k เองthe k nearest centroids (box k, default 1); every area has the same number of neighbours · W is not symmetric (j can be a neighbour of i without the reverse) · k = 1 gives a single neighbour and often splits the map into small groups, so set k yourself | เมื่อต้องการให้ทุกพื้นที่มีเพื่อนบ้านจำนวนเท่ากันwhen every area should have the same number of neighbours |
| นำเข้าไฟล์เวทImport weights file (.gal/.gwt/.kwt/.swm/.mat) | เพื่อนบ้านและน้ำหนักจากไฟล์ จับคู่กับแถวด้วยคอลัมน์รหัสพื้นที่ แล้วปรับเป็น row-standardisedneighbours and weights from the file, matched to rows through an area-ID column, then row-standardised | ต้องการใช้ W ชุดเดียวกับงานอื่นหรือที่แก้ไขเองto reuse a W from other work or a hand-corrected one |
Distance Metric (ใช้กับ distance band, KNN และระยะเชื่อมเกาะ): Arc Distance (km) เป็นค่าเริ่มต้น และ Arc (mi) คำนวณระยะตามส่วนโค้งโลกโดยถือว่าพิกัดเป็นองศาลองจิจูด/ละติจูด · Euclidean คือระยะเส้นตรงในหน่วยของพิกัดเอง · shapefile ที่มีไฟล์ .prj ถูกแปลงเป็นลองจิจูด/ละติจูดตอนนำเข้า แต่ไฟล์ที่ไม่มี .prj ใช้พิกัดตามเดิม DAPH ห้ามใช้ Arc เฉพาะเมื่อพิกัดเกิน ±90/±180 ดังนั้นแผนที่ที่ใช้หน่วยระนาบเล็ก ๆ (เช่น Columbus ที่พิกัดอยู่ช่วง 5.9–11.3 และ 10.8–14.7) จะถูกอ่านเป็นองศาโดยไม่มีคำเตือน — แผนที่แบบนี้ให้เลือก Euclidean (DAPH จะพิมพ์หน่วยของรัศมีว่า "degrees" แม้หน่วยจริงไม่ใช่องศา) · row-standardised: ทุกสถิติในบทนี้ใช้ wij ตามสูตรข้างบน ยกเว้น Global G ที่ใช้ cij แบบ 0/1 (หัวข้อ 6.6) · Rook (ขอบร่วมเท่านั้น) มีให้เลือกเฉพาะใน Bayesian disease mapping (หัวข้อ 6.9–6.10)
Distance Metric (for the distance band, KNN and the island links): Arc Distance (km), the default, and Arc (mi) compute great-circle distances treating the coordinates as longitude/latitude degrees · Euclidean is the straight-line distance in the coordinates' own unit · a shapefile with a .prj file is converted to longitude/latitude on import; one without .prj keeps its coordinates. DAPH refuses Arc only when coordinates exceed ±90/±180, so a map in small planar units (such as Columbus, coordinates 5.9–11.3 and 10.8–14.7) is read as degrees without a warning — choose Euclidean for such maps (DAPH then prints the radius unit as "degrees" even though it is not) · row-standardised: every statistic in this chapter uses wij as above, except Global G, which uses the 0/1 cij (section 6.6) · Rook (shared edge only) is offered only in Bayesian disease mapping (sections 6.9–6.10).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
สคริปต์สร้าง W แต่ละแบบจากแผนที่ Columbus ชุดเดียวกับที่นำเข้า DAPH แล้วพิมพ์จำนวนเพื่อนบ้านและ Global Moran's I ของ CRIME ภายใต้ W นั้น เพื่อเทียบกับบรรทัด weights และค่า Moran's I ที่ DAPH พิมพ์ใน Local Moran (Univariate)
The script builds each W from the same Columbus map that is imported into DAPH and prints the neighbour counts and the global Moran's I of CRIME under that W, for comparison with the weights line and the Moran's I that DAPH prints in Local Moran (Univariate).
sf · spdep · spData# Data: the DAPH example dataset (PD cohort) has no map, so this section uses the public
# Columbus, Ohio (1980) neighbourhood map shipped with the R package spData (49 areas).
library(sf); library(spdep)
shp <- system.file("shapes", package = "spData")
utils::zip("columbus.zip", flags = "-j9X",
files = file.path(shp, paste0("columbus.", c("shp", "shx", "dbf"))))
# -> upload columbus.zip in DAPH Tab 1
col <- st_read(file.path(shp, "columbus.shp"), quiet = TRUE)
x <- col$CRIME
xy <- st_coordinates(st_centroid(st_geometry(col))) # polygon centroids, as DAPH
moranI <- function(nb) unname(moran.test(x, nb2listw(nb, style = "W"))$estimate[1])
nbinfo <- function(nb) c(min = min(card(nb)), mean = mean(card(nb)),
max = max(card(nb)), moran_I = moranI(nb))
q1 <- poly2nb(col, queen = TRUE) # Queen contiguity, order 1
l2 <- nblag(q1, maxlag = 2)
q2 <- nblag_cumul(l2) # order 2 = 1st + 2nd order neighbours
d1 <- max(unlist(nbdists(knn2nb(knearneigh(xy, k = 1)), xy)))
db <- dnearneigh(xy, 0, d1 * 1.001) # distance band, automatic radius (Euclidean)
k4 <- knn2nb(knearneigh(xy, k = 4)) # 4 nearest neighbours (Euclidean)
round(rbind(queen_order1 = nbinfo(q1), queen_order2 = nbinfo(q2),
distance_band = nbinfo(db), knn_4 = nbinfo(k4)), 6)
d1 * 1.001 # automatic radius, in coordinate units
n.comp.nb(q1)$nc # 1 = one connected map, no isolated group
# Inverse-distance weights 1/d^power on the same band (what the menu name promises)
idw <- function(power) unname(moran.test(x, nb2listw(db, style = "W",
glist = lapply(nbdists(db, xy), function(d) d^-power)))$estimate[1])
round(c(power_1 = idw(1), power_2 = idw(2)), 6)
# "Arc Distance (km)" would read these planar units as longitude/latitude degrees:
pts <- st_as_sf(data.frame(lon = xy[, 1], lat = xy[, 2]), coords = c("lon", "lat"), crs = 4326)
D <- units::drop_units(st_distance(pts)) / 1000; diag(D) <- NA
max(apply(D, 1, min, na.rm = TRUE)) * 1.001 # automatic radius in "km" on a sphere
min mean max moran_I
queen_order1 2 4.816327 10 0.500189
queen_order2 4 13.306122 24 0.300780
distance_band 1 5.142857 11 0.551826
knn_4 4 4.000000 4 0.582552
[1] 0.619483
[1] 1
power_1 power_2
0.570812 0.590197
[1] 67.55015
| W และค่าที่เทียบW and quantity | R | DAPH | ความต่างDifference | สถานะStatus |
|---|---|---|---|---|
| Queen order 1: เพื่อนบ้าน ต่ำสุด/เฉลี่ย/สูงสุด · Moran's IQueen order 1: neighbours min/mean/max · Moran's I | 2 / 4.816 / 10 · 0.500189 | 2 / 4.816 / 10 · 0.500189 | < 1e−6 | ✓ PASS |
| Queen order 2 ใน Spatial Regression: เพื่อนบ้าน ต่ำสุด/เฉลี่ย/สูงสุดQueen order 2 in Spatial Regression: neighbours min/mean/max | 4 / 13.306 / 24 | 4 / 13.306 / 24 | 0 | ✓ PASS |
| Queen order 2 ใน Local Moran: เพื่อนบ้าน ต่ำสุด/เฉลี่ย/สูงสุด · Moran's IQueen order 2 in Local Moran: neighbours min/mean/max · Moran's I | 4 / 13.306 / 24 · 0.300780 | 4 / 13.306 / 24 · 0.300780 | < 1e−6 | ✓ PASS |
| Distance band (Euclidean): รัศมี d* · เพื่อนบ้าน · Moran's IDistance band (Euclidean): radius d* · neighbours · Moran's I | 0.619483 · 1 / 5.143 / 11 · 0.551826 | 0.619483 · 1 / 5.143 / 11 · 0.551826 | < 1e−6 | ✓ PASS |
| Inverse Distance Weight, Power 1 · Power 2: Moran's I ²Inverse Distance Weight, Power 1 · Power 2: Moran's I ² | 0.570812 · 0.590197 | 0.551826 · 0.551826 | 0.018986 · 0.038371 | ✗ FAIL |
| KNN k = 4 (Euclidean): เพื่อนบ้าน · Moran's IKNN k = 4 (Euclidean): neighbours · Moran's I | 4 / 4 / 4 · 0.582552 | 4 / 4 / 4 · 0.582552 | < 1e−6 | ✓ PASS |
| Distance band, Arc Distance (km): รัศมี d* เมื่อพิกัดถูกอ่านเป็นองศาDistance band, Arc Distance (km): radius d* with the coordinates read as degrees | 67.550 km | 67.550 km | 0.0001 | ✓ PASS |
| Queen order 1: จำนวนกลุ่มที่แยกกันQueen order 1: number of separate groups | 1 | 1 (ไม่มีคำเตือน)1 (no warning) | 0 | ✓ PASS |
² เมนูชื่อ Inverse Distance Weight และช่อง Power ระบุน้ำหนัก 1/dpower แต่ Local Moran และ Getis-Ord ใช้น้ำหนักเท่ากันทุกเพื่อนบ้านภายในรัศมีเดียวกัน ค่า Moran's I จึงเท่ากับแถว distance band (0.551826) ทุก Power ขณะที่น้ำหนัก 1/d และ 1/d² ใน R ให้ 0.570812 และ 0.590197² The menu name Inverse Distance Weight and the Power box promise weights 1/dpower, but Local Moran and Getis-Ord give every neighbour within the same radius an equal weight, so Moran's I equals the distance-band row (0.551826) for every Power, whereas weights 1/d and 1/d² in R give 0.570812 and 0.590197.
4คำเตือน "เชื่อมกันไม่ครบ" และการเลือกใช้The "not fully connected" warning, and choosing
Spatial Regression, Spatial Panel และ Spatial ML ตรวจว่า W เชื่อมทุกพื้นที่เป็นกลุ่มเดียวหรือไม่ ถ้าแผนที่แตกเป็นหลายกลุ่มที่ไม่มีเพื่อนบ้านร่วมกัน หรือมีพื้นที่ที่ไม่มีเพื่อนบ้านเลย DAPH ต่อท้ายบรรทัด Spatial weights ว่า "⚠ เชื่อมกันไม่ครบ: แยกเป็น N กลุ่ม…" · ใน W แบบ row-standardised แต่ละกลุ่มที่มีตั้งแต่ 2 พื้นที่ขึ้นไปจะให้ eigenvalue เท่ากับ 1 หนึ่งค่า และพื้นที่ที่ไม่มีเพื่อนบ้านจะมีแถวเป็นศูนย์ทั้งแถว (spatial lag = 0 เสมอ) ค่าพารามิเตอร์เชิงพื้นที่ (ρ, λ) จึงขึ้นกับว่าแต่ละโปรแกรมจัดการส่วนนี้อย่างไร และอาจต่างกันระหว่างโปรแกรม · Local Moran และ Getis-Ord ไม่พิมพ์คำเตือนนี้ จึงควรตรวจเองว่าไม่มีเกาะ · ทางแก้: ใช้ Queen ปรับ (ถ้าสาเหตุคือเกาะ), distance band (ทุกพื้นที่มีเพื่อนบ้านอย่างน้อย 1 แห่ง แต่ยังแยกกลุ่มได้), KNN ที่ k มากพอ หรือนำเข้าไฟล์เวทที่แก้แล้ว แล้วดูบรรทัด weights อีกครั้ง
Spatial Regression, Spatial Panel and Spatial ML check whether W links every area into one group. If the map splits into groups with no shared neighbour, or an area has no neighbour at all, DAPH appends "⚠ not fully connected: N separate groups…" to the Spatial weights line. In a row-standardised W every group of two or more areas contributes one eigenvalue equal to 1, and an area without neighbours has a row of zeros (its spatial lag is always 0), so the spatial parameter (ρ, λ) depends on how each program handles these parts and can differ between programs. Local Moran and Getis-Ord do not print this warning, so check for islands yourself. Fix: the modified Queen (if islands are the cause), the distance band (every area gets at least one neighbour, but groups can still be separate), KNN with a large enough k, or an imported, corrected weights file — then read the weights line again.
หลักการเลือก: เลือก W ตามสิ่งที่ทำให้พื้นที่ "เกี่ยวข้องกัน" ในเรื่องที่ศึกษา (การเดินทาง การติดต่อ ระยะทาง) ก่อนดูผล และรายงานผลจาก W อีกแบบหนึ่งเพื่อดูความคงที่ของข้อสรุป มีวิธีสร้าง W จากข้อมูลเองด้วย (Getis & Aldstadt, 2004) · ถ้าเกาะอยู่ไกลเกินกว่าจะถือเป็นเพื่อนบ้านจริง ให้ใส่ระยะสูงสุดที่ยอมรับได้ในช่อง "ระยะเชื่อมเกาะสูงสุด" เกาะที่ไกลกว่านั้นจะไม่ถูกเชื่อมและมีชื่อพร้อมระยะในรายงาน
How to choose: pick W from what makes areas "related" for the question (travel, contact, distance) before looking at the results, and report the result under a second W to show how stable the conclusion is; ways to build W from the data have also been proposed (Getis & Aldstadt, 2004). If an island is genuinely too far to count as a neighbour, enter the largest acceptable distance in "Max linking distance" — islands beyond it stay unlinked and the report names them with their distance.
📖 References
- Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
- Getis, A., & Aldstadt, J. (2004). Constructing the spatial weights matrix using a local statistic. Geographical Analysis, 36(2), 90–104. doi:10.1111/j.1538-4632.2004.tb01127.x
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
6.8 Distribution Map — Choropleth + KDE Heatmap
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Distribution Map ของ DAPH เป็นแผนที่บรรยายข้อมูล ไม่ใช่การทดสอบทางสถิติ มี 2 แบบ: Choropleth ระบายสี polygon ตามช่วงค่า (class) ของตัวแปร และ Heat Map (KDE) (Kernel Density Estimation) ที่เกลี่ยจุดให้เป็นพื้นผิวความเข้ม วิธีแบ่งช่วงมี 4 แบบ: Quantile, Equal Interval (กำหนดจุดแบ่งเองได้), Natural Breaks (Jenks) และ Standard Deviation ภาพที่ได้ขึ้นกับวิธีแบ่งช่วงมาก จึงต้องระบุวิธีและจำนวนช่วงทุกครั้งที่รายงาน
DAPH's Distribution Map is a descriptive map, not a statistical test. It has two modes: Choropleth, which colours polygons by class of a variable, and Heat Map (KDE) (kernel density estimation), which smooths points into an intensity surface. There are four ways to form classes: Quantile, Equal Interval (with optional manual breaks), Natural Breaks (Jenks) and Standard Deviation. The picture depends strongly on the classification, so always report the method and the number of classes.
spData (Anselin, 1988): 49 ย่าน, CRIME = การลักทรัพย์ในบ้านและการขโมยรถต่อ 1,000 ครัวเรือน · คำถาม: "ควรแบ่ง 5 ช่วงสีอย่างไรให้ผู้อ่านเห็นการกระจายของอัตรานี้ และ heat map ของ DAPH เกลี่ยค่ากว้างเท่าใด"
spData (Anselin, 1988): 49 neighbourhoods, CRIME = residential burglaries and vehicle thefts per 1,000 households. Question: "how should five colour classes be cut so that readers see the distribution of this rate, and how widely does DAPH's heat map smooth the values?"
2หลักการและสูตรLogic and Formula
ให้ x(1) ≤ … ≤ x(n) เป็นค่าที่เรียงแล้ว และ K เป็นจำนวนช่วง (ช่อง Classes 2–10, ค่าเริ่มต้นใน Tab 2 คือ Quantile 4 ช่วง) DAPH รายงาน "ขอบบน" ของแต่ละช่วง c1 < … < cK = ค่าสูงสุด ช่วงที่ k คือ (ck−1, ck] และช่วงแรกเริ่มที่ค่าต่ำสุด
Let x(1) ≤ … ≤ x(n) be the sorted values and K the number of classes (Classes box 2–10; Tab 2 starts with Quantile, 4 classes). DAPH reports the upper bound of each class, c1 < … < cK = the maximum; class k is (ck−1, ck] and the first class starts at the minimum.
- K, ck
- จำนวนช่วง และขอบบนของช่วงที่ knumber of classes and the upper bound of class k
- x̄k, SDCM
- ค่าเฉลี่ยของช่วง k และผลรวมกำลังสองของความเบี่ยงเบนจากค่าเฉลี่ยของช่วง (Sum of squared Deviations from Class Means)mean of class k and the Sum of squared Deviations from Class Means
- x̄, s
- ค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานตัวอย่าง (ตัวหาร n − 1) · K = 2 แบ่งที่ค่าเฉลี่ย · K = 8–10 ใช้พหุคูณจำนวนเต็มต่อออกไป · ถ้าขอบบนสุดต่ำกว่าค่าสูงสุดจะเพิ่มค่าสูงสุดเป็นขอบสุดท้าย จำนวนช่วงจริงจึงอาจไม่เท่ากับ K และอาจมีช่วงว่างsample mean and standard deviation (divisor n − 1) · K = 2 splits at the mean · K = 8–10 continue with whole multiples · if the top cut is below the maximum, the maximum is added as the last bound, so the number of classes can differ from K and a class can be empty
Natural Breaks ใน DAPH: หาช่วงด้วยการจัดกลุ่ม k-means ในหนึ่งมิติ เริ่มสุ่ม 10 ครั้งแล้วเลือกผลที่ SDCM ต่ำสุด ซึ่งมักได้ผลเดียวกับวิธีแน่นอนของ Fisher (1958) แต่ไม่รับประกัน จึงควรเทียบกับ classInt style "fisher" ใน R (ด้านล่างได้ผลตรงกัน) · Equal Interval แบบกำหนดเอง: ติ๊ก Manual แล้วใส่ขอบบนเอง ค่าที่ต่ำกว่าค่าต่ำสุดหรือไม่ต่ำกว่าค่าสูงสุดถูกตัดทิ้ง และค่าสูงสุดถูกเพิ่มเป็นขอบสุดท้าย
Natural Breaks in DAPH: the classes come from one-dimensional k-means clustering with 10 random starts, keeping the lowest SDCM; this usually equals Fisher's (1958) exact optimum but is not guaranteed, so compare with classInt style "fisher" in R (below they agree) · Equal Interval with manual breaks: tick Manual and type your own upper bounds; values below the minimum or not below the maximum are dropped and the maximum is added as the last bound.
- pi, s
- จุดที่ i (ลองจิจูด, ละติจูด) และตำแหน่งบนตารางที่ประเมินค่า (ตาราง 500 × 500 เมื่อ n < 500, 400 × 400 เมื่อ n < 5,000 และ 300 × 300 เมื่อมากกว่านั้น ขยายเกินขอบจุด 5% และตัดส่วนที่อยู่นอก polygon ออก)point i (longitude, latitude) and the grid location evaluated (a 500 × 500 grid when n < 500, 400 × 400 when n < 5,000, 300 × 300 above; extended 5% beyond the points and clipped to the polygons)
- S, Sw
- เมทริกซ์ความแปรปรวนร่วมตัวอย่างของพิกัด และแบบถ่วงน้ำหนักด้วย wisample covariance matrix of the coordinates, and its wi-weighted version
- L, sλ, sφ
- 1.1 × ด้านที่ยาวกว่าของกรอบที่ครอบจุดศูนย์กลางทั้งหมด และส่วนเบี่ยงเบนมาตรฐาน (ไม่ถ่วงน้ำหนัก) ของลองจิจูดและละติจูด — kernel จึงกว้างราว 3% ของความกว้างแผนที่ · เมื่อมีตั้งแต่ 1,000 จุดขึ้นไปใช้ factor ของ Scott แทน1.1 × the longer side of the box around all centroids, and the unweighted standard deviations of longitude and latitude — so the kernel spreads over about 3% of the map width · with 1,000 points or more, Scott's factor is used instead
โหมด Polygon centroid ถ่วงน้ำหนักด้วย "ค่า − ค่าต่ำสุด" พื้นที่ที่มีค่าต่ำสุดจึงแทบไม่มีน้ำหนัก และพื้นผิวแสดงเป็นร้อยละของจุดที่เข้มที่สุด (0–100%) ไม่ใช่จำนวนผู้ป่วยต่อตารางกิโลเมตร โหมด Lat/Lon ไม่ใช้ตัวแปร ทุกจุดมีน้ำหนักเท่ากัน จึงแสดงความหนาแน่นของจุด · ปุ่มแก้ไขกราฟปรับความกว้างของ kernel ได้ (คูณ 0.1–10 เท่า)
The polygon-centroid mode weights each point by "value − minimum", so the area with the lowest value has almost no weight, and the surface is shown as a percentage of its peak (0–100%), not as cases per square kilometre. The Lat/Lon mode uses no variable; every point has the same weight, so it shows the density of points · the chart editor can scale the kernel width (0.1–10 times).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
ค่าจุดแบ่งตรวจด้วย R package classInt และเมทริกซ์ H ของ KDE ตรวจด้วย ks::Hns() (Duong, 2007) ซึ่งเป็นกฎ normal-scale ที่เท่ากับกฎของ Scott (1992) ในสองมิติ ส่วนโหมด polygon centroid คำนวณตามสูตรข้างบนโดยตรง
The class breaks are checked with the R package classInt, and the KDE matrix H with ks::Hns() (Duong, 2007), the normal-scale rule that equals Scott's (1992) rule in two dimensions; the polygon-centroid mode is computed from the formula above.
sf · classInt · ks · spData# Data: the DAPH example dataset (PD cohort) has no map, so this section uses the public
# Columbus, Ohio (1980) neighbourhood map shipped with the R package spData (49 areas).
library(sf); library(classInt); library(ks)
shp <- system.file("shapes", package = "spData")
utils::zip("columbus.zip", flags = "-j9X",
files = file.path(shp, paste0("columbus.", c("shp", "shx", "dbf"))))
# -> upload columbus.zip in DAPH Tab 1
col <- st_read(file.path(shp, "columbus.shp"), quiet = TRUE)
x <- col$CRIME # burglaries and vehicle thefts per 1,000 households
# Choropleth class breaks, 5 classes (first value = minimum, then the upper bound of each class)
classIntervals(x, n = 5, style = "quantile")$brks # sample quantiles, type 7
classIntervals(x, n = 5, style = "equal")$brks
jk <- classIntervals(x, n = 5, style = "jenks") # natural breaks
fi <- classIntervals(x, n = 5, style = "fisher") # Fisher's exact optimum
jk$brks
rbind(jenks = table(findCols(jk)), fisher = table(findCols(fi))) # same classes
sdcm <- function(cl) sum(tapply(x, cl, function(v) sum((v - mean(v))^2)))
c(jenks = sdcm(findCols(jk)), fisher = sdcm(findCols(fi)))
c(mean(x) + c(-2, -1, 1, 2) * sd(x), max(x)) # Standard Deviation, 5 classes
# Heat map (KDE): kernel covariance matrix H
# (a) Lat/Lon point mode, X and Y columns as longitude/latitude: Scott's rule
xy <- cbind(lon = col$X, lat = col$Y)
Hns(xy) # normal-scale H = n^(-1/3) * cov(xy)
nrow(xy)^(-1/6) # Scott factor for 2 dimensions
# (b) Polygon-centroid mode weighted by CRIME (fewer than 1,000 areas)
ce <- st_coordinates(st_centroid(st_geometry(col)))
w <- (x - min(x) + 1e-9) / sum(x - min(x) + 1e-9)
L <- 1.1 * max(diff(range(ce[, 1])), diff(range(ce[, 2])))
f <- 0.03 * L / mean(apply(ce, 2, sd))
c(factor = f, n_eff = 1 / sum(w^2))
f^2 * cov.wt(ce, wt = w, method = "unbiased")$cov
[1] 0.178269 19.022576 29.325974 39.025214 53.161033 68.892044
[1] 0.178269 13.921024 27.663779 41.406534 55.149289 68.892044
[1] 0.178269 0.223797 22.541491 34.000835 48.585487 68.892044
1 2 3 4 5
jenks 2 12 11 12 12
fisher 2 12 11 12 12
jenks fisher
601.1551 601.1551
[1] 1.66464 18.39673 51.86092 68.59301 68.89204
lon lat
lon 11.32665721 0.01321579
lat 0.01321579 6.46908429
[1] 0.522758
factor n_eff
0.1583405 40.0159758
X Y
X 0.020334228 -0.001397784
Y -0.001397784 0.013887633
| ค่าที่เทียบQuantity | R | DAPH | ความต่างDifference | สถานะStatus |
|---|---|---|---|---|
| Quantile: ขอบบน 5 ช่วงQuantile: 5 upper bounds | 19.0226 / 29.3260 / 39.0252 / 53.1610 / 68.8920 | 19.0226 / 29.3260 / 39.0252 / 53.1610 / 68.8920 | < 1e−6 | ✓ PASS |
| Equal Interval: ขอบบน 5 ช่วงEqual Interval: 5 upper bounds | 13.9210 / 27.6638 / 41.4065 / 55.1493 / 68.8920 | 13.9210 / 27.6638 / 41.4065 / 55.1493 / 68.8920 | < 1e−6 | ✓ PASS |
| Natural Breaks: ขอบบน 5 ช่วง (R: jenks)Natural Breaks: 5 upper bounds (R: jenks) | 0.2238 / 22.5415 / 34.0008 / 48.5855 / 68.8920 | 0.2238 / 22.5415 / 34.0008 / 48.5855 / 68.8920 | < 1e−6 | ✓ PASS |
| Natural Breaks: จำนวนพื้นที่ต่อช่วง และ SDCM (R: fisher = ค่าที่ดีที่สุด)Natural Breaks: areas per class and SDCM (R: fisher = exact optimum) | 2 / 12 / 11 / 12 / 12 · 601.155 | 2 / 12 / 11 / 12 / 12 · 601.155 | 0 | ✓ PASS |
| Standard Deviation (5 ช่วง): ขอบบนStandard Deviation (5 classes): upper bounds | 1.6646 / 18.3967 / 51.8609 / 68.5930 / 68.8920 | 1.6646 / 18.3967 / 51.8609 / 68.5930 / 68.8920 | < 1e−6 | ✓ PASS |
| KDE โหมด Lat/Lon: factor · H11 / H12 / H22KDE Lat/Lon mode: factor · H11 / H12 / H22 | 0.522758 · 11.326657 / 0.013216 / 6.469084 | 0.522758 · 11.326657 / 0.013216 / 6.469084 | < 1e−6 | ✓ PASS |
| KDE โหมด Polygon centroid: factor · neffKDE polygon-centroid mode: factor · neff | 0.158340 · 40.0160 | 0.158340 · 40.0160 | < 1e−6 | ✓ PASS |
| KDE โหมด Polygon centroid: H11 / H12 / H22KDE polygon-centroid mode: H11 / H12 / H22 | 0.020334 / −0.001398 / 0.013888 | 0.020334 / −0.001398 / 0.013888 | < 1e−6 | ✓ PASS |
4การแปลผลและตัวอย่างInterpretation and Example
ข้อมูลเดียวกัน 5 ช่วง แต่ภาพต่างกัน:
— Quantile ได้ 10 / 10 / 9 / 10 / 10 ย่านต่อช่วง เหมาะกับการเปรียบเทียบลำดับ เช่น "20% ของย่านที่อัตราสูงสุด" แต่ค่าที่ต่างกันน้อยอาจตกคนละสี
— Equal Interval ความกว้างช่วงละ 13.74 เท่ากัน อ่านง่ายและเทียบระหว่างแผนที่ได้เมื่อใช้ช่วงเดียวกัน แต่ถ้าค่ากระจุกตัว สีส่วนใหญ่จะอยู่ไม่กี่ช่วง
— Natural Breaks แยกสองย่านที่อัตราเกือบศูนย์ (0.18 และ 0.22) ออกเป็นช่วงของตัวเอง เพราะลดความแปรปรวนภายในช่วงได้มากที่สุด เหมาะเมื่อข้อมูลมีกลุ่มตามธรรมชาติ แต่จุดแบ่งเปลี่ยนตามข้อมูลแต่ละชุด เทียบข้ามแผนที่ยาก
— Standard Deviation (ค่าเฉลี่ย 35.13 ± 1 และ 2 SD, SD = 16.73) ช่วงล่างสุดมี 2 ย่านที่ต่ำกว่าค่าเฉลี่ย − 2 SD และช่วงบนสุดมีเพียงย่านที่ค่าสูงสุด (68.89) ช่วงกลาง 18.4–51.9 กว้างมาก เหมาะเมื่อข้อมูลใกล้เคียงการแจกแจงปกติและต้องการชี้ค่าที่ห่างจากค่าเฉลี่ย
— Heat map: โหมด polygon centroid ของ Columbus ใช้ kernel ที่มีส่วนเบี่ยงเบนมาตรฐานราว 0.14 และ 0.12 หน่วยพิกัด (√0.020334 และ √0.013888) คือประมาณ 3% ของความกว้างแผนที่ จึงเห็นเป็นหย่อมรอบย่านที่อัตราสูง ส่วนโหมด Lat/Lon ใช้กฎของ Scott ซึ่งกว้างกว่ามาก (≈ 3.4 และ 2.5 หน่วยของคอลัมน์ X, Y) — ทั้งสองแบบเป็นภาพบรรยาย ไม่มีการทดสอบนัยสำคัญ หากต้องการบอกว่าจุดร้อนมีนัยสำคัญให้ใช้หัวข้อ 6.4–6.6
Same data, five classes, different pictures:
— Quantile gives 10 / 10 / 9 / 10 / 10 neighbourhoods per class; good for ranking ("the top 20% of neighbourhoods"), but nearly equal values can fall into different colours.
— Equal Interval gives equal widths of 13.74; easy to read and comparable between maps that share the classes, but with skewed data most areas fall into a few colours.
— Natural Breaks puts the two neighbourhoods with rates near zero (0.18 and 0.22) in a class of their own, because that most reduces the within-class variation; good when the data have natural groups, but the cuts change with every dataset, so maps are hard to compare.
— Standard Deviation (mean 35.13 ± 1 and 2 SD, SD = 16.73): the lowest class holds the 2 neighbourhoods below the mean − 2 SD and the top class only the maximum (68.89), while the middle class 18.4–51.9 is very wide; suits roughly normal data when values far from the mean are of interest.
— Heat map: for Columbus the polygon-centroid mode uses a kernel with standard deviations of about 0.14 and 0.12 coordinate units (√0.020334 and √0.013888), about 3% of the map width, so patches appear around high-rate neighbourhoods; the Lat/Lon mode uses Scott's rule, which is much wider (≈ 3.4 and 2.5 units of the X, Y columns). Both are descriptive pictures without a significance test; to say that a hot spot is significant, use sections 6.4–6.6.
📖 References
- Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
- Duong, T. (2007). ks: Kernel density estimation and kernel discriminant analysis for multivariate data in R. Journal of Statistical Software, 21(7), 1–16. doi:10.18637/jss.v021.i07
- Fisher, W. D. (1958). On grouping for maximum homogeneity. Journal of the American Statistical Association, 53(284), 789–798. doi:10.1080/01621459.1958.10501479
- Scott, D. W. (1992). Multivariate density estimation: Theory, practice, and visualization. Wiley. doi:10.1002/9780470316849
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
6.9 Bayesian Disease Mapping (BYM2) — แผนที่ความเสี่ยงโรคแบบเบย์smoothed relative risk and exceedance probability R
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
อัตรารายพื้นที่ที่คำนวณตรง ๆ คือ SIR (standardised incidence ratio) = จำนวนที่พบ (O) ÷ จำนวนที่คาดหวัง (E) ค่านี้แกว่งมากในพื้นที่ที่จำนวนคาดหวังน้อย ในข้อมูลของหัวข้อนี้ เคาน์ตี Anson พบทารกเสียชีวิต 15 รายจากที่คาด 3.17 ราย (SIR 4.726) ส่วนหนึ่งของความต่างระดับนี้เป็นความบังเอิญของจำนวนน้อย แผนที่ความเสี่ยงโรคแบบเบย์ (BYM2) ให้แต่ละพื้นที่ "ยืมข้อมูล" จากพื้นที่ข้างเคียงและจากภาพรวม ได้ความเสี่ยงสัมพัทธ์ (relative risk, RR) ที่นิ่งขึ้น พร้อมช่วงความเชื่อถือ 95% (95% credible interval, 95% CrI) และความน่าจะเป็นภายหลังที่ RR ของพื้นที่เกินเกณฑ์ เช่น P(RR > 1) ซึ่งใช้จัดลำดับพื้นที่ที่ควรให้ความสำคัญ
The plain area rate is the SIR (standardised incidence ratio) = observed (O) ÷ expected (E), and it swings widely where expected counts are small: in this section's data, Anson County had 15 infant deaths where 3.17 were expected (SIR 4.726), and part of such a gap is the chance of small numbers. Bayesian disease mapping (BYM2) lets each area borrow strength from its neighbours and from the whole map, giving a steadier relative risk (RR) with a 95% credible interval (95% CrI) and the posterior probability that the area's RR exceeds a threshold, such as P(RR > 1), which is what priority lists are built on.
ใช้เมื่อ ข้อมูลเป็นจำนวนนับรายพื้นที่ของเหตุการณ์ที่ไม่บ่อย (ผู้ป่วยใหม่ ผู้เสียชีวิต) มีตัวหารของแต่ละพื้นที่ (ประชากร จำนวนเกิดมีชีพ หรือจำนวนที่ตรวจ) และมีแผนที่รูปหลายเหลี่ยม (shapefile) ที่พื้นที่เชื่อมกันเป็นกราฟเพื่อนบ้านเดียว ไม่ใช้เมื่อ เป็นข้อมูลรายบุคคล (ใช้การถดถอยระดับบุคคล) มีแต่อัตราที่ไม่มีจำนวนนับ เป็นข้อมูลจุดพิกัด หรือต้องการสรุปเชิงสาเหตุ (ความสัมพันธ์ระดับพื้นที่ไม่ใช่ความสัมพันธ์ระดับบุคคล)
Use it for counts of a relatively rare event per area (new cases, deaths) with a denominator per area (population, live births or number tested) and a polygon map (shapefile) whose areas form one connected neighbour graph. Do not use it for individual-level data (use an individual-level regression), for rates without their counts, for point coordinates, or to draw causal conclusions (an area-level association is not an individual-level one).
2หลักการและสูตรLogic and Formula
- yi = Oi, ni
- จำนวนที่พบ (SID74) และตัวหาร (BIR74) ของพื้นที่ iobserved count (SID74) and denominator (BIR74) of area i
- Ei
- จำนวนที่คาดหวังจากการปรับมาตรฐานทางอ้อมบนแถวที่วิเคราะห์ (ΣE = Σy)expected count by indirect standardisation on the analysed rows (ΣE = Σy)
- θi, α
- ความเสี่ยงสัมพัทธ์ทั้งหมดของพื้นที่ i และระดับรวมบนสเกล log (ที่ค่าเฉลี่ยของตัวแปรร่วม)total relative risk of area i, and the overall level on the log scale (at the covariate means)
- zi, βk
- ตัวแปรร่วมที่ปรับมาตรฐาน (ค่าเฉลี่ย 0, SD 1 โดย SD หารด้วย n − 1) และ log RR ต่อ 1 SDcovariates standardised to mean 0 and SD 1 (SD with n − 1), and the log RR per 1 SD
- bi, v, u
- ผลรายพื้นที่บนสเกล log ส่วนที่ไม่มีโครงสร้าง และส่วน ICAR (intrinsic conditional autoregressive) ที่เกาะกลุ่มตามเพื่อนบ้าน; i ∼ j คือ i กับ j เป็นเพื่อนบ้านกันarea effect on the log scale, its unstructured part, and its ICAR (intrinsic conditional autoregressive) part that follows the neighbours; i ∼ j means i and j are neighbours
- W, D, Q+
- เมทริกซ์เพื่อนบ้าน 0/1, เมทริกซ์ทแยงของจำนวนเพื่อนบ้าน, generalised (Moore–Penrose) inverse ของ Q0/1 neighbour matrix, diagonal matrix of neighbour counts, generalised (Moore–Penrose) inverse of Q
- s
- scaling factor: ค่าเฉลี่ยเรขาคณิตของแนวทแยงของ Q+ (ขึ้นกับกราฟเพื่อนบ้านเท่านั้น)scaling factor: geometric mean of the diagonal of Q+ (depends on the neighbour graph only)
- φ, σ
- สัดส่วนความแปรปรวนของผลรายพื้นที่ที่เกาะกลุ่มตามเพื่อนบ้าน และขนาดความต่างระหว่างพื้นที่ (SD บนสเกล log)share of the area-effect variance that is spatially structured, and the between-area SD on the log scale
- γt
- ผลของช่วงเวลา t (log อัตราเทียบช่วงแรก) ใช้เมื่อเลือกหลายช่วงเวลาeffect of period t (log rate ratio against the first period), used when several periods are chosen
- c, S, ESSi
- เกณฑ์ RR (ค่าเริ่มต้น 1.0 และ 1.5 ค่าแรกใช้ติดธง), จำนวนค่าสุ่มที่ใช้ (1,000 ค่าที่เก็บไว้ เลือกห่างเท่า ๆ กันจากค่าสุ่มทั้งหมด), ขนาดตัวอย่างประสิทธิผลของ bi (ไม่เกิน S)RR threshold (defaults 1.0 and 1.5; the first sets the flag), number of draws used (the 1,000 kept, evenly spaced over all draws), effective sample size of bi (at most S)
φ คือสัดส่วนของความแปรปรวนของผลรายพื้นที่ที่เกาะกลุ่มตามเพื่อนบ้าน (0 = ไม่เกาะกลุ่ม, 1 = เกาะกลุ่มทั้งหมด) การหารส่วน ICAR ด้วย √s ทำให้ความแปรปรวนของส่วนนี้มีค่าเฉลี่ยเรขาคณิตเท่ากับ 1 φ และ σ จึงตีความได้แบบเดียวกันทุกแผนที่ (Riebler et al., 2016) s นิยามได้เฉพาะกราฟที่เชื่อมถึงกันทั้งหมด ถ้ามีหลายช่วงเวลา (แผง BYM2 > ข้อมูล > ช่วงเวลา) DAPH เพิ่ม γt ใน log θ คำนวณ E จากทุกแถวพื้นที่ × ช่วงเวลา ใช้ตัวแปรร่วมค่าเดียวกันทุกช่วง และใช้ bi ตัวเดียวกันทุกช่วง (ไม่มีผลร่วมพื้นที่ × ช่วงเวลา)
φ is the share of the area-effect variance that is spatially structured (0 = none, 1 = all). Dividing the ICAR part by √s gives it variances whose geometric mean is 1, so φ and σ read the same way on every map (Riebler et al., 2016); s exists only for a connected graph. With several periods (BYM2 settings > Data > Periods), DAPH adds γt to log θ, computes E over all area × period rows, uses the same covariate values in every period and the same bi in every period (no area × period interaction).
เพื่อนบ้าน: DAPH สร้าง W แบบ 0/1 สมมาตรจากรูปหลายเหลี่ยม ด้วยแผงเพื่อนบ้านเดียวกับ Spatial Regression และ LISA แต่เลือกได้เฉพาะนิยามแบบพื้นที่ติดกัน: Queen (เชื่อมเกาะกับพื้นที่ใกล้สุด) ซึ่ง DAPH ตั้งให้เมื่อเข้าสถิตินี้ถ้ายังไม่ได้เลือกนิยามแบบติดกันไว้, Queen, Rook, Queen (ยอมช่องว่างขอบ) หรือไฟล์เวทที่นำเข้า ถ้ากราฟไม่เชื่อมถึงกันทั้งหมด DAPH ล็อกปุ่ม Run และบอกชื่อพื้นที่ที่แยกออกจากกลุ่มใหญ่ North Carolina ไม่มีเกาะ กราฟจึงเท่ากับ Queen ธรรมดา (245 เส้นเชื่อม)
Neighbours: DAPH builds a 0/1 symmetric W from the polygons with the same neighbour panel as Spatial Regression and LISA, restricted to contiguity rules: Queen (islands linked to nearest areas), which DAPH sets on entry unless a contiguity rule is already chosen, Queen, Rook, Queen (edge-gap tolerance) or an imported weights file. If the graph is not connected, DAPH locks Run and names the areas cut off from the main part. North Carolina has no islands, so the graph equals plain Queen (245 edges).
RR ของพื้นที่ ใน DAPH คือ ebi คือความเสี่ยงของพื้นที่นั้นเทียบกับระดับที่แบบจำลองคาดจากอัตรารวม (α) และตัวแปรร่วมของพื้นที่นั้น ไม่ใช่ θi และไม่ใช่ O/E เมื่อมีตัวแปรร่วม RR จึงเป็นความเสี่ยงที่เหลือหลังปรับตัวแปรร่วมแล้ว รายงานเป็นมัธยฐานภายหลังกับช่วงแบบหางเท่ากัน (ควอนไทล์ 2.5% และ 97.5% ของค่าสุ่มทั้งหมด) ส่วน P(RR > c) คำนวณจากค่าสุ่ม 1,000 ค่าที่เก็บไว้ และหมายเหตุใต้ตารางที่ 2 บอกช่วงของ MCSE ของ P
The area RR in DAPH is ebi: the area's risk relative to the level the model expects from the overall rate (α) and the area's covariates. It is not θi and not O/E; with covariates it is the risk left after them. It is reported as the posterior median with an equal-tailed interval (2.5% and 97.5% quantiles of all draws); P(RR > c) uses the 1,000 draws kept, and the note under Table 2 gives the range of its MCSE.
การลู่เข้า: ใช้ผลได้เมื่อ R-hat สูงสุด < 1.01 และ ESS bulk และ tail ต่ำสุด > 400 คิดบน α, β, γ, σ, φ และ b ทุกพื้นที่ (Vehtari et al., 2021) ไม่มี divergent transitions และ E-BFMI ของทุกโซ่ > 0.2 (ค่าที่ DAPH กำหนด) ถ้าไม่ผ่าน DAPH ไม่รายงานค่าประมาณใด ๆ: Tab 3 และ Word มีเฉพาะตารางวินิจฉัย (R-hat และ ESS ไม่มีค่าเฉลี่ย) กราฟมีเฉพาะ trace/rank plot และกราฟเพื่อนบ้าน และ Word แนะนำให้เพิ่ม tune และ draws หรือเพิ่ม target accept เป็น 0.99 แล้วรันใหม่ จำนวนครั้งที่ชนความลึกสูงสุดของต้นไม้ (tree depth) รายงานไว้แต่ไม่ใช้ตัดสิน เพราะเป็นเรื่องประสิทธิภาพของการสุ่ม ไม่ใช่ความถูกต้องของค่าสุ่ม
Convergence: results are used only when the maximum R-hat < 1.01 and the minimum bulk and tail ESS > 400 over α, β, γ, σ, φ and every bi (Vehtari et al., 2021), there are no divergent transitions, and E-BFMI > 0.2 in every chain (a DAPH setting). Otherwise DAPH reports no estimate at all: Tab 3 and Word show only the diagnostics table (R-hat and ESS, no means), the charts are limited to the trace/rank plots and the neighbour graph, and Word advises more tuning and draws, or target accept 0.99, before running again. Maximum tree-depth hits are reported but do not decide, because they concern sampling efficiency, not the validity of the draws.
การเปรียบเทียบแบบจำลอง (ตัวเลือก ขั้นสูง > เปรียบเทียบแบบจำลอง ใช้เวลาราว 4 เท่า): DAPH ประมาณ 4 แบบจำลองบนแถว E และ prior ชุดเดียวกัน คือ ไม่มีผลรายพื้นที่, ผลอิสระ (IID: b = σv), เฉพาะ ICAR (b = σu/√s) และ BYM2 แล้วรายงาน elpd (expected log predictive density) จาก PSIS-LOO (Vehtari et al., 2017), SE, ผลต่างจากแบบจำลองที่ elpd สูงสุด, dSE (= √n × SD ของผลต่างรายพื้นที่), p_loo และร้อยละของพื้นที่ที่ Pareto k > 0.7 (ค่า elpd ของพื้นที่เหล่านี้เป็นค่าประมาณคร่าว ๆ) ประโยคสรุปใช้กฎ 2 × dSE: BYM2 ดีกว่าแบบไม่มีผลรายพื้นที่ "ชัดเจน" เมื่อผลต่าง > 2 dSE และถ้า |ICAR − IID| < 2 dSE แปลว่าการเกาะกลุ่มตามเพื่อนบ้านไม่ทำให้ทำนายต่างกัน DAPH ไม่ประกาศแบบจำลองที่ "ดีที่สุด" ให้อ่านคู่กับ φ เสมอ
Model comparison (optional, Advanced > Compare models; about four times the run time): DAPH fits four models on the same rows, E and priors: no area effect, independent effects (IID: b = σv), ICAR only (b = σu/√s) and BYM2, and reports the elpd (expected log predictive density) from PSIS-LOO (Vehtari et al., 2017), its SE, the difference from the model with the highest elpd, dSE (= √n × SD of the pointwise differences), p_loo and the percentage of areas with Pareto k > 0.7 (their elpd is only approximate). The sentence applies a 2 × dSE rule: BYM2 is "clearly" better than no area effect when the difference exceeds 2 dSE, and |ICAR − IID| < 2 dSE means the neighbour structure does not change prediction. DAPH declares no "best" model; read it together with φ.
วิธีสุ่มตัวอย่าง: DAPH สุ่มค่าจากการแจกแจงภายหลังด้วย No-U-Turn sampler (NUTS; Hoffman & Gelman, 2014) เมื่อจำนวนผู้ป่วยต่อพื้นที่สูง (หลักร้อยถึงหลักหมื่น) การเขียนแบบจำลองแบบ non-centred (b = σ × สนามมาตรฐาน) ทำให้ NUTS เดินช้ามาก DAPH จึงสุ่มผลรายพื้นที่ในฐาน eigen ของ Q แบบ centred โดยแต่ละ mode เลือกระดับ centring จากปริมาณข้อมูลของ mode นั้นเอง (Papaspiliopoulos et al., 2003) ข้อมูลน้อยจะกลับไปใกล้แบบ non-centred โดยอัตโนมัติ แบบจำลองและการแจกแจงภายหลังไม่เปลี่ยน เปลี่ยนเพียงพิกัดที่ตัวสุ่มเดิน การทดสอบภายในของ DAPH (ไม่ใช้ MCMC) ตรวจว่า covariance ของ prior ในพิกัดใหม่ตรงกับสูตรเชิงวิเคราะห์ทุกแบบจำลอง และค่าคงที่ของความหนาแน่นไม่ขึ้นกับ σ และ φ (Jacobian ถูกต้อง) แผนที่ที่มีมากกว่า 2,500 พื้นที่ใช้แบบ non-centred เดิม เพราะฐาน eigen ใช้หน่วยความจำตามจำนวนพื้นที่ยกกำลังสอง หมายเหตุใต้ตารางวินิจฉัยบอกว่าใช้พิกัดใด บนข้อมูลของหัวข้อนี้ ผลของ DAPH ตรงกับ brms ของ R ซึ่งเขียนแบบจำลองแบบ non-centred (ตารางผลการตรวจสอบด้านล่าง)
Sampling method: DAPH draws from the posterior with the No-U-Turn sampler (NUTS; Hoffman & Gelman, 2014). With large counts per area (hundreds to tens of thousands) the non-centred form (b = σ × a standard field) makes NUTS crawl, so DAPH samples the area effects in the eigenbasis of Q, centred, each mode choosing its degree of centring from the information it carries (Papaspiliopoulos et al., 2003); weak data fall back towards the non-centred form automatically. The model and the posterior are unchanged; only the coordinates the sampler moves in change. DAPH's internal test (no MCMC) checks that the prior covariance in these coordinates equals the analytic one for every model and that the normalising constant does not depend on σ and φ (the Jacobian is right). Maps with more than 2,500 areas keep the original non-centred form, because the eigenbasis needs memory that grows with the square of the number of areas; the note under the diagnostics table says which coordinates were used. On this section's data DAPH agrees with R's brms, which uses the non-centred form (verification table below).
| ช่องField | BYM2 | สองโรคTwo outcomes | ที่มาSource |
|---|---|---|---|
| draws | 1500 | 5000 | ข้อกำหนดการออกแบบของ DAPH; เกณฑ์ ESS bulk และ tail > 400 (Vehtari et al., 2021); บนข้อมูล North Carolina ในหัวข้อ 6.9 และ 6.10 ได้ ESS ต่ำสุด 2,312 และ 8,846DAPH module specification; rule ESS bulk and tail > 400 (Vehtari et al., 2021); on the North Carolina data of 6.9 and 6.10 the minimum ESS was 2,312 and 8,846 |
| tune | 1500 | 4000 | ข้อกำหนดการออกแบบของ DAPH (สองโรคมีสองสนามกับ ρ จึงปรับนานกว่า)DAPH module specification (two fields and ρ, so longer tuning) |
| chains | 4 | 4 | Vehtari et al. (2021): อย่างน้อย 4 โซ่at least four chains |
| target accept | 0.95 | 0.97 | ข้อกำหนดการออกแบบของ DAPH สูงกว่าค่าทั่วไป 0.8 เพราะผลรายพื้นที่เป็นแบบหลายระดับDAPH module specification; above the usual 0.8 because the area effects are multilevel |
| seed | 12345 | 12345 | เลขเดียวกับสถิติอื่นของ DAPHthe same seed as the other DAPH statistics |
| เกณฑ์ RRRR thresholds | 1.0, 1.5 | 1.0, 1.5 | ข้อกำหนดการออกแบบของ DAPH; 1.0 คือเกณฑ์ของกฎตัดสินใจ (Richardson et al., 2004); สองโรคคำนวณแยกแต่ละโรคDAPH module specification; 1.0 is the threshold of the decision rule (Richardson et al., 2004); computed per outcome in the two-outcome model |
| ติดธงเมื่อความน่าจะเป็น ≥Flag when probability ≥ | 0.80 | 0.80 | Richardson et al. (2004): เกณฑ์ P(RR > 1) ระหว่าง 0.70 ถึง 0.80 จำเพาะสูงและไวพอสมควรเมื่อจำนวนคาดหวังราว 20 และ RR จริงราว 1.5 ถึง 2; สองโรคใช้แบ่ง P(RR1 > RR2) ด้วย (≥ 0.80 และ ≤ 0.20)a P(RR > 1) cut-off between 0.70 and 0.80 is specific, with reasonable sensitivity at expected counts of about 20 and true RRs of about 1.5 to 2; the two-outcome model also splits P(RR1 > RR2) at ≥ 0.80 and ≤ 0.20 |
| นิยามเพื่อนบ้านNeighbour rule | Queen* | Queen* | * Queen (เชื่อมเกาะกับพื้นที่ใกล้สุด, 1 พื้นที่) ตั้งให้เมื่อเข้าสถิตินี้ ถ้าแผงเพื่อนบ้านยังไม่ใช่นิยามแบบติดกัน* Queen (islands linked to the 1 nearest area), set on entering the statistic when the neighbour panel holds no contiguity rule |
| เปรียบเทียบแบบจำลองCompare models | ปิดoff | – | เปิดเองได้ (ใช้เวลาราว 4 เท่า)tick to switch on (about four times the run time) |
3สคริปต์ R และผลการตรวจสอบR Script and Verification
สคริปต์นี้รันได้ทันทีใน R 4.3.3 ในโฟลเดอร์ว่าง (ข้อมูลมากับแพ็กเกจ sf) brms คอมไพล์แบบจำลอง Stan ครั้งแรกราว 1 ถึง 2 นาที ใช้หน่วยความจำราว 2 GB brms เขียน ICAR ด้วยรูปผลต่างรายคู่ของ Morris et al. (2019) และเรียงผลรายพื้นที่ rcar[k] ตามชื่อเคาน์ตีที่เรียงตัวอักษร (levels ของ gr) ไม่ใช่ตามลำดับแถว สคริปต์จึงจับคู่ด้วยชื่อ (Bürkner, 2017) ค่าที่ได้บนคอมพิวเตอร์อื่นอาจต่างจากด้านล่างเล็กน้อยตามความคลาดเคลื่อนจากการสุ่ม
The script runs as is in R 4.3.3 in an empty folder (the data ship with sf). brms compiles a Stan model the first time (1 to 2 minutes, about 2 GB of memory). brms writes the ICAR prior in the pairwise-difference form of Morris et al. (2019) and orders the area effects rcar[k] by the alphabetical county names (levels of gr), not by row, so the script matches them by name (Bürkner, 2017). On another computer the numbers may differ slightly, within Monte Carlo error.
# Data: North Carolina SIDS, shipped with the R package sf (100 counties; live births BIR74,
# sudden infant deaths SID74 and non-white live births NWBIR74 in 1974-78)
library(sf); library(spdep); library(MASS); library(brms); library(posterior)
nc <- st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
nc$PNW74 <- round(100 * nc$NWBIR74 / nc$BIR74, 2) # % non-white births, 1974-78
# The same polygons for DAPH: write nc_sids.shp, zip its four parts, then open nc_sids.zip in DAPH
st_write(nc, "nc_sids.shp", delete_layer = TRUE, quiet = TRUE)
zip::zip("nc_sids.zip", paste0("nc_sids.", c("shp", "shx", "dbf", "prj")))
# 1) Queen neighbours (binary W), graph facts and the BYM2 scaling factor s
nb <- poly2nb(nc, queen = TRUE)
W <- nb2mat(nb, style = "B")
dimnames(W) <- list(nc$NAME, nc$NAME)
Q <- diag(rowSums(W)) - W # ICAR precision Q = D - W
s <- exp(mean(log(diag(ginv(Q))))) # geometric mean of diag(Q+)
print(c(areas = nrow(W), edges = sum(W) / 2, mean_neighbours = mean(rowSums(W)),
components = n.comp.nb(nb)$nc))
print(c(scaling_factor = s), digits = 7)
# the same formula on small graphs with known values (path of 3 areas = (50/729)^(1/3), K4 = 3/16, C4 = 5/16)
sfac <- function(A) { Q <- diag(rowSums(A)) - A; exp(mean(log(diag(ginv(Q))))) }
ring <- function(n) { A <- matrix(0, n, n); A[cbind(1:n, c(2:n, 1))] <- 1; A + t(A) }
grid <- function(k, type) nb2mat(cell2nb(k, k, type = type), style = "B")
print(round(c(path3 = sfac(matrix(c(0, 1, 0, 1, 0, 1, 0, 1, 0), 3)), K4 = sfac(1 - diag(4)),
C4 = sfac(ring(4)), rook3x3 = sfac(grid(3, "rook")), queen3x3 = sfac(grid(3, "queen")),
queen4x4 = sfac(grid(4, "queen"))), 6))
# 2) Expected counts by indirect standardisation; covariate standardised (z = per 1 SD)
d <- data.frame(county = nc$NAME, y = nc$SID74,
E = nc$BIR74 * sum(nc$SID74) / sum(nc$BIR74),
z = as.numeric(scale(nc$PNW74)))
print(c(deaths = sum(d$y), births = sum(nc$BIR74), counties_E_below_20 = sum(d$E < 20)))
print(c(sum_E = sum(d$E), mean_PNW74 = mean(nc$PNW74), sd_PNW74 = sd(nc$PNW74)))
# 3) BYM2 with the priors DAPH uses (rhocar = phi, sdcar = sigma)
pri <- c(prior(normal(0, 5), class = Intercept), prior(normal(0, 1), class = b),
prior(normal(0, 1), class = sdcar), prior(beta(1, 1), class = rhocar))
fit <- brm(y ~ offset(log(E)) + z + car(W, gr = county, type = "bym2"),
data = d, data2 = list(W = W), family = poisson(), prior = pri,
chains = 4, cores = 1, iter = 4000, warmup = 2000, seed = 12345,
control = list(adapt_delta = 0.95), refresh = 0)
print(c(car_scale_brms = standata(fit)$car_scale), digits = 7)
# 4) Posterior medians, 95% equal-tailed CrI and their Monte Carlo SEs (MCSE)
dr <- as_draws_array(fit)
m <- function(v) extract_variable_matrix(dr, v)
summ <- function(x) c(median = median(x), lo = quantile(x, 0.025, names = FALSE),
hi = quantile(x, 0.975, names = FALSE), mcse_med = unname(mcse_median(x)),
mcse_lo = unname(mcse_quantile(x, 0.025)), mcse_hi = unname(mcse_quantile(x, 0.975)))
par <- rbind(phi = summ(m("rhocar")), sigma = summ(m("sdcar")),
RR_per_SD = summ(exp(m("b_z"))), alpha = summ(m("b_Intercept")))
write.csv(par, "r_bym2_params.csv")
print(round(par, 4))
print(c(P_phi_gt_0.5 = mean(m("rhocar") > 0.5)), digits = 3)
# 5) County RR = exp(b_i), P(RR > 1) and the flag P(RR > 1) >= 0.80
# brms numbers the CAR effects rcar[k] in the sorted order of the county names (levels of gr)
lev <- levels(factor(d$county))
rr <- t(sapply(d$county, function(cn) {
b <- m(sprintf("rcar[%d]", match(cn, lev)))
c(summ(exp(b)), P = mean(b > 0), mcse_P = unname(mcse_mean(b > 0)))
}))
res <- data.frame(county = d$county, O = d$y, E = round(d$E, 2), SIR = round(d$y / d$E, 3),
PNW74 = nc$PNW74, round(rr, 4))
res <- res[order(-res$P, -res$median), ]
write.csv(res, "r_bym2_counties.csv", row.names = FALSE)
print(head(res[, c("county", "O", "E", "SIR", "PNW74", "median", "lo", "hi", "P")], 10), row.names = FALSE)
print(c(flagged = sum(res$P >= 0.80)))
# 6) Convergence over the parameters DAPH checks (alpha, beta, sigma, phi, every b_i)
cv <- summarise_draws(subset_draws(dr, c("b_Intercept", "b_z", "sdcar", "rhocar", "rcar"), regex = TRUE),
"rhat", "ess_bulk", "ess_tail")
np <- nuts_params(fit)
print(c(max_rhat = max(cv$rhat), min_ess_bulk = min(cv$ess_bulk), min_ess_tail = min(cv$ess_tail),
divergent = sum(np$Value[np$Parameter == "divergent__"])), digits = 4)
areas edges mean_neighbours components
100.0 245.0 4.9 1.0
scaling_factor
0.5859796
path3 K4 C4 rook3x3 queen3x3 queen4x4
0.409337 0.187500 0.312500 0.409709 0.210748 0.224433
deaths births counties_E_below_20
667 329962 94
sum_E mean_PNW74 sd_PNW74
667.00000 31.24950 20.86048
car_scale_brms
0.5859791
median lo hi mcse_med mcse_lo mcse_hi
phi 0.4361 0.0254 0.9435 0.0116 0.0020 0.0044
sigma 0.2738 0.1369 0.4239 0.0014 0.0041 0.0029
RR_per_SD 1.5068 1.3233 1.7363 0.0026 0.0040 0.0050
alpha -0.0654 -0.1745 0.0356 0.0009 0.0018 0.0015
P_phi_gt_0.5
0.431
county O E SIR PNW74 median lo hi P
Onslow 29 22.56 1.286 19.87 1.3876 0.9947 1.9744 0.9732
Rutherford 12 6.05 1.984 16.54 1.4562 0.9488 2.4808 0.9540
Anson 15 3.17 4.726 60.64 1.4344 0.9362 2.4168 0.9442
Columbus 15 6.77 2.215 42.72 1.3229 0.9072 2.0487 0.9220
Rockingham 16 8.99 1.779 27.94 1.2528 0.8610 1.9689 0.8632
Lincoln 8 4.48 1.786 13.63 1.2231 0.8160 2.1031 0.8174
Henderson 5 5.20 0.961 6.14 1.2227 0.7631 2.0370 0.8049
McDowell 5 3.93 1.271 6.89 1.2087 0.7820 2.0722 0.7992
Transylvania 3 2.37 1.265 7.84 1.2184 0.7505 2.1487 0.7798
Bladen 8 3.60 2.221 45.90 1.1729 0.7764 1.8757 0.7779
flagged
7
max_rhat min_ess_bulk min_ess_tail divergent
1.002 1471.353 2768.335 0.000
# Model comparison by PSIS-LOO (DAPH: tick "Compare models"): no area effect, independent (IID),
# ICAR only and BYM2 - same rows, same E, priors on the DAPH scale (ICAR: sdcar = sigma / sqrt(s))
pri0 <- c(prior(normal(0, 5), class = Intercept), prior(normal(0, 1), class = b))
opt <- list(chains = 4, cores = 1, iter = 4000, warmup = 2000, seed = 12345, refresh = 0)
f_none <- do.call(brm, c(list(y ~ offset(log(E)) + z, data = d, family = poisson(), prior = pri0), opt))
f_iid <- do.call(brm, c(list(y ~ offset(log(E)) + z + (1 | county), data = d, family = poisson(),
prior = c(pri0, prior(normal(0, 1), class = sd)),
control = list(adapt_delta = 0.95)), opt))
f_icar <- do.call(brm, c(list(y ~ offset(log(E)) + z + car(W, gr = county, type = "icar"), data = d,
data2 = list(W = W), family = poisson(),
prior = c(pri0, set_prior(sprintf("normal(0, %f)", 1 / sqrt(s)), class = "sdcar")),
control = list(adapt_delta = 0.95)), opt))
loos <- list(none = loo(f_none), iid = loo(f_iid), icar = loo(f_icar), bym2 = loo(fit))
print(round(t(sapply(loos, function(l) c(l$estimates["elpd_loo", ], p_loo = l$estimates["p_loo", 1],
k_gt_0.7_pct = 100 * mean(l$diagnostics$pareto_k > 0.7)))), 2))
# the two differences in DAPH's sentence, with dSE from the pointwise differences
dd <- function(a, b) { x <- loos[[a]]$pointwise[, "elpd_loo"] - loos[[b]]$pointwise[, "elpd_loo"]
c(diff = sum(x), dSE = sqrt(length(x)) * sd(x)) }
print(round(rbind(bym2_vs_none = dd("bym2", "none"), icar_vs_iid = dd("icar", "iid")), 2))
Estimate SE p_loo k_gt_0.7_pct
none -221.28 14.08 2.95 0
iid -216.84 11.03 24.77 6
icar -218.44 12.19 23.04 5
bym2 -216.83 11.28 24.67 5
diff dSE
bym2_vs_none 4.44 4.03
icar_vs_iid -1.60 2.41
ไฟล์ > นำเข้า > Shapefile (.zip) แล้วเลือก nc_sids.zip ที่สคริปต์สร้าง; Tab 2 > Outcome type: Spatial > Bayesian Disease Mapping (BYM2); ตัวแปรตาม = SID74; ตัวแปรอิสระ = PNW74; ตั้งค่า BYM2 > ข้อมูล > ตัวหาร = BIR74; เพื่อนบ้าน = Queen (เชื่อมเกาะกับพื้นที่ใกล้สุด) ตามที่ตั้งไว้ (บรรทัดตรวจกราฟแสดง 100 พื้นที่ · 245 เส้น · เฉลี่ย 4.90 เพื่อนบ้าน · scaling factor 0.5860); ค่าอื่นเป็นค่าเริ่มต้น; สำหรับแถวการเปรียบเทียบแบบจำลอง ติ๊ก ขั้นสูง > เปรียบเทียบแบบจำลอง การรันเป็นงานเบื้องหลัง ผลขึ้นที่ Tab 3 เมื่อเสร็จ
File > Import > Shapefile (.zip) and choose the nc_sids.zip the script wrote; Tab 2 > Outcome type: Spatial > Bayesian Disease Mapping (BYM2); Dependent = SID74; Independent = PNW74; BYM2 settings > Data > Offset = BIR74; Neighbours = Queen (islands linked to nearest areas) as set (the graph line shows 100 areas · 245 edges · mean 4.90 neighbours · scaling factor 0.5860); everything else at its default; for the model-comparison rows tick Advanced > Compare models. The run is a background job; the result appears in Tab 3 when it finishes.
| รายการItem | R | DAPH | ความต่าง / เกณฑ์Difference / rule | สถานะStatus |
|---|---|---|---|---|
| กราฟ Queen: จำนวนพื้นที่ / เส้นเชื่อม / เพื่อนบ้านเฉลี่ยQueen graph: areas / edges / mean neighbours | 100 / 245 / 4.9 | 100 / 245 / 4.90 | 0 | ✓ PASS |
| scaling factor s ของกราฟ North Carolinascaling factor s, North Carolina graph | 0.5859796 | 0.5859796 | < 1e−7 | ✓ PASS |
| scaling factor ที่ brms คำนวณเอง (เติมค่าเล็กมากบนแนวทแยงของ Q)scaling factor computed by brms itself (adds a tiny value to the diagonal of Q) | 0.5859791 | 0.5859796 | 5.4e−7 < 1e−6 | ✓ PASS |
| scaling factor, เส้นทาง 3 พื้นที่ = (50/729)1/3scaling factor, path of 3 areas = (50/729)1/3 | 0.409337 | 0.409337 | < 1e−6 | ✓ PASS |
| scaling factor, กราฟสมบูรณ์ K4 = 3/16scaling factor, complete graph K4 = 3/16 | 0.187500 | 0.187500 | < 1e−6 | ✓ PASS |
| scaling factor, วงรอบ C4 = 5/16scaling factor, cycle C4 = 5/16 | 0.312500 | 0.312500 | < 1e−6 | ✓ PASS |
| scaling factor, ตาราง 3 × 3 rookscaling factor, 3 × 3 rook grid | 0.409709 | 0.409709 | < 1e−6 | ✓ PASS |
| scaling factor, ตาราง 3 × 3 queenscaling factor, 3 × 3 queen grid | 0.210748 | 0.210748 | < 1e−6 | ✓ PASS |
| scaling factor, ตาราง 4 × 4 queenscaling factor, 4 × 4 queen grid | 0.224433 | 0.224433 | < 1e−6 | ✓ PASS |
| ΣE = ΣO (การปรับมาตรฐานทางอ้อม)ΣE = ΣO (indirect standardisation) | 667 | 667 | 0 | ✓ PASS |
| SD ของ PNW74 (หน่วยของ 1 SD)SD of PNW74 (the unit of 1 SD) | 20.86048 | 20.86048 | < 1e−5 | ✓ PASS |
| φ มัธยฐานภายหลังφ posterior median | 0.4361 | 0.4328 | 0.0033 ≤ 0.0396 | ✓ PASS |
| φ ขอบล่าง 95% CrIφ lower 95% CrI limit | 0.0254 | 0.0208 | 0.0046 ≤ 0.0089 | ✓ PASS |
| φ ขอบบน 95% CrIφ upper 95% CrI limit | 0.9435 | 0.9519 | 0.0084 ≤ 0.0169 | ✓ PASS |
| σ มัธยฐานภายหลังσ posterior median | 0.2738 | 0.2745 | 0.0007 ≤ 0.0058 | ✓ PASS |
| σ ขอบล่าง 95% CrIσ lower 95% CrI limit | 0.1369 | 0.1348 | 0.0021 ≤ 0.0168 | ✓ PASS |
| σ ขอบบน 95% CrIσ upper 95% CrI limit | 0.4239 | 0.4278 | 0.0040 ≤ 0.0129 | ✓ PASS |
| RR ต่อ 1 SD ของ PNW74 มัธยฐานRR per 1 SD of PNW74, median | 1.5068 | 1.5062 | 0.0006 ≤ 0.0097 | ✓ PASS |
| RR ต่อ 1 SD ขอบล่าง 95% CrIRR per 1 SD, lower 95% CrI limit | 1.3233 | 1.3248 | 0.0015 ≤ 0.0170 | ✓ PASS |
| RR ต่อ 1 SD ขอบบน 95% CrIRR per 1 SD, upper 95% CrI limit | 1.7363 | 1.7302 | 0.0061 ≤ 0.0227 | ✓ PASS |
| α มัธยฐานα median | −0.0654 | −0.0669 | 0.0014 ≤ 0.0033 | ✓ PASS |
| Onslow: RR มัธยฐานOnslow: RR median | 1.3876 | 1.3903 | 0.0027 ≤ 0.0140 | ✓ PASS |
| Onslow: P(RR > 1)Onslow: P(RR > 1) | 0.9732 | 0.9830 | 0.0098 ≤ 0.0138 | ✓ PASS |
| Rutherford: RR มัธยฐานRutherford: RR median | 1.4562 | 1.4529 | 0.0033 ≤ 0.0302 | ✓ PASS |
| Rutherford: P(RR > 1)Rutherford: P(RR > 1) | 0.9540 | 0.9540 | 0.0000 ≤ 0.0218 | ✓ PASS |
| Anson: RR มัธยฐานAnson: RR median | 1.4344 | 1.4353 | 0.0009 ≤ 0.0295 | ✓ PASS |
| Anson: P(RR > 1)Anson: P(RR > 1) | 0.9442 | 0.9520 | 0.0078 ≤ 0.0227 | ✓ PASS |
| ทุกเคาน์ตี: RR มัธยฐาน ขอบล่าง ขอบบน และ P(RR > 1) (400 ค่า)every county: RR median, lower and upper limits and P(RR > 1) (400 values) | – | – | อยู่ในเกณฑ์ 399 จาก 400 ค่า; มากสุด 1.01 เท่าของเกณฑ์ (Currituck, P); คาดว่าเกินเกณฑ์โดยบังเอิญราว 1.1 ค่า399 of 400 within the rule; largest 1.01 × the limit (Currituck, P); about 1.1 expected outside by chance | ✓ PASS |
| จำนวนเคาน์ตีที่เข้าเกณฑ์ P(RR > 1) ≥ 0.80counties flagged, P(RR > 1) ≥ 0.80 | 7 | 8 | Transylvania: P 0.7798 vs 0.8080, 0.0282 ≤ 0.0417 | ✓ PASS |
| การลู่เข้า: R-hat สูงสุด / ESS bulk และ tail ต่ำสุด / divergentconvergence: max R-hat / min bulk and tail ESS / divergent | 1.002 / 1471, 2768 / 0 | 1.003 / 2312, 2934 / 0 | ผ่านเกณฑ์ทั้งคู่ (< 1.01, > 400, 0)both meet the rule (< 1.01, > 400, 0) | ✓ PASS |
| elpd_loo (SE), ไม่มีผลรายพื้นที่elpd_loo (SE), no area effect | −221.28 (14.08) | −221.37 (14.01) | 0.09 < 1 | ✓ PASS |
| elpd_loo (SE), IIDelpd_loo (SE), IID | −216.84 (11.03) | −216.72 (10.91) | 0.12 < 1 | ✓ PASS |
| elpd_loo (SE), ICARelpd_loo (SE), ICAR | −218.44 (12.19) | −217.86 (11.91) | 0.58 < 1 | ✓ PASS |
| elpd_loo (SE), BYM2elpd_loo (SE), BYM2 | −216.83 (11.28) | −216.52 (11.19) | 0.31 < 1 | ✓ PASS |
| BYM2 − ไม่มีผลรายพื้นที่ (dSE)BYM2 − no area effect (dSE) | 4.44 (4.03) | 4.85 (4.11) | 0.41 < 1; ข้อสรุปเดียวกันsame conclusion | ✓ PASS |
| ICAR − IID (dSE)ICAR − IID (dSE) | −1.60 (2.41) | −1.14 (2.23) | 0.46 < 1; ข้อสรุปเดียวกันsame conclusion | ✓ PASS |
ค่าที่ไม่ใช้การสุ่ม (กราฟ, scaling factor, E) ต้องตรงกันถึงหลักที่แสดง ค่าจากการสุ่มของสองโปรแกรมไม่มีทางตรงกันทุกหลัก จึงใช้เกณฑ์ |R − DAPH| ≤ 3 × √(MCSER² + MCSEDAPH²) โดย MCSE ของมัธยฐานและควอนไทล์คำนวณตาม Vehtari et al. (2021) (R: แพ็กเกจ posterior; DAPH: จากค่าสุ่มของงานเดียวกัน) และ MCSE ของ P(RR > 1) ของ DAPH คือค่าที่ DAPH รายงาน (1,000 ค่าสุ่มที่เก็บไว้) การเทียบ 400 ค่าที่เกณฑ์นี้คาดว่าจะเกินเกณฑ์โดยบังเอิญราว 1 ค่า PSIS-LOO มีความคลาดเคลื่อนของตัวเองและพื้นที่ที่ Pareto k > 0.7 ทำให้ค่าไม่แน่นอน จึงใช้เกณฑ์ |ผลต่าง| < 1 หน่วย elpd และต้องได้ข้อสรุปเดียวกันตามกฎ 2 × dSEValues that do not depend on sampling (graph, scaling factor, E) must agree to the digits shown. Sampling-based estimates from two programs never agree to every digit, so the rule is |R − DAPH| ≤ 3 × √(MCSER² + MCSEDAPH²), with the MCSE of medians and quantiles as in Vehtari et al. (2021) (R: package posterior; DAPH: from the draws of the same run) and, for P(RR > 1), the MCSE DAPH reports (1,000 draws kept). Over 400 comparisons this rule is expected to be exceeded about once by chance. PSIS-LOO has its own error, and areas with Pareto k > 0.7 make it uncertain, so the rule there is |difference| < 1 elpd unit with the same conclusion under the 2 × dSE rule.
4การแปลผลและตัวอย่างInterpretation and Example
— PNW74: RR ต่อ 1 SD = 1.506 (95% CrI 1.325 ถึง 1.730; P(RR > 1) = 1.000) คือเคาน์ตีที่ร้อยละการเกิดมีชีพที่ไม่ใช่คนผิวขาวสูงกว่า 20.86 จุดร้อยละ (1 SD)
มีความเสี่ยง SIDS สูงกว่า 1.506 เท่า เป็นความสัมพันธ์ระดับเคาน์ตี (ecological) ไม่ใช่ผลเชิงสาเหตุ และไม่ใช่ความเสี่ยงของทารกแต่ละคน
— φ = 0.433 (95% CrI 0.021 ถึง 0.952; P(φ > 0.5) = 0.424): ช่วงกว้างเกือบตลอด 0 ถึง 1 ข้อมูลชุดนี้จึงบอกไม่ได้ว่าความต่างระหว่างเคาน์ตีที่เหลือหลังปรับ PNW74
เกาะกลุ่มตามเพื่อนบ้านหรือเป็นรายเคาน์ตี σ = 0.274 (95% CrI 0.135 ถึง 0.428) คือขนาดของความต่างที่เหลือนั้นบนสเกล log
— เข้าเกณฑ์ 8 จาก 100 เคาน์ตี (P(RR > 1) ≥ 0.80) เช่น Onslow RR 1.390 (95% CrI 1.001 ถึง 1.974; P(RR > 1) = 0.983), Rutherford 1.453 (0.956 ถึง 2.450; 0.954)
และ Anson 1.435 (0.942 ถึง 2.378; 0.952) ช่วง 95% CrI ของบางเคาน์ตีครอบ 1 แต่ยังเข้าเกณฑ์ได้ เพราะกฎใช้ความน่าจะเป็น 0.80 ไม่ใช่ 0.975 การเข้าเกณฑ์เป็นกฎตัดสินใจ ไม่ใช่การทดสอบนัยสำคัญ และไม่มีค่า p
— RR หลังปรับตัวแปรร่วมต่างจาก SIR: Anson มี SIR 4.726 แต่ RR 1.435 เพราะ PNW74 สูง (60.64) อธิบายส่วนเกินได้มาก และจำนวนน้อยถูกดึงเข้าหาค่าเพื่อนบ้าน
ส่วน Henderson มี SIR 0.961 แต่เข้าเกณฑ์ (RR 1.218; P(RR > 1) = 0.815) เพราะ PNW74 ต่ำ (6.14) แบบจำลองจึงคาดความเสี่ยงต่ำกว่าอัตรารวม การพบเท่ากับอัตรารวมจึงสูงกว่าที่คาดสำหรับเคาน์ตีนี้
— ธงที่อยู่ใกล้ 0.80 อาจพลิกได้ตามความคลาดเคลื่อนจากการสุ่ม: Transylvania ได้ P(RR > 1) = 0.808 ใน DAPH และ 0.780 ใน R (ต่างกันไม่เกินเกณฑ์ MCSE)
พื้นที่ที่ P ห่างจาก 0.80 ไม่ถึงราว 2 MCSE (ดูหมายเหตุใต้ตารางที่ 2) ควรรายงานว่าอยู่ที่ขอบเกณฑ์
— ความไว: 94 จาก 100 เคาน์ตีมีจำนวนคาดหวังต่ำกว่า 20 ซึ่ง Richardson et al. (2004) พบว่ากฎนี้จำเพาะสูงแต่ไวต่ำเมื่อ RR จริงน้อยกว่า 2 เท่า
การไม่เข้าเกณฑ์จึงไม่ได้แปลว่าเคาน์ตีนั้นไม่มีความเสี่ยงเกิน
— การเปรียบเทียบแบบจำลอง (ตารางที่ 4): BYM2 เทียบกับไม่มีผลรายพื้นที่ ผลต่าง elpd 4.8 (dSE 4.1) น้อยกว่า 2 dSE ผลรายพื้นที่จึงไม่ได้ทำให้ทำนายดีขึ้นอย่างชัดเจน
และแบบ IID กับ ICAR ทำนายได้ใกล้เคียงกัน (ต่ำกว่า BYM2 0.2 และ 1.3, dSE 1.1 และ 1.2) สอดคล้องกับ φ ที่ไม่แน่นอน
— การรายงานแบบเบย์ควรบอก prior ค่าตั้งของตัวสุ่ม ผลวินิจฉัยการลู่เข้า และสรุปการแจกแจงภายหลัง (Kruschke, 2021) ซึ่ง Word ของ DAPH ใส่ไว้ครบ
— PNW74: RR per 1 SD = 1.506 (95% CrI 1.325 to 1.730; P(RR > 1) = 1.000): counties whose share of non-white births was 20.86 percentage points (1 SD) higher
had a 1.506 times higher SIDS risk. This is a county-level (ecological) association, not a causal effect and not the risk of an individual infant.
— φ = 0.433 (95% CrI 0.021 to 0.952; P(φ > 0.5) = 0.424): the interval covers almost all of 0 to 1, so these data cannot tell whether the differences left after PNW74
cluster by neighbourhood or are county-specific. σ = 0.274 (95% CrI 0.135 to 0.428) is the size of those remaining differences on the log scale.
— 8 of 100 counties are flagged (P(RR > 1) ≥ 0.80), for example Onslow RR 1.390 (95% CrI 1.001 to 1.974; P(RR > 1) = 0.983), Rutherford 1.453 (0.956 to 2.450; 0.954)
and Anson 1.435 (0.942 to 2.378; 0.952). Some flagged counties have a 95% CrI that includes 1, because the rule uses a probability of 0.80, not 0.975. Flagging is a decision rule,
not a significance test, and there is no p-value.
— The adjusted RR is not the SIR: Anson has SIR 4.726 but RR 1.435, because its high PNW74 (60.64) explains much of the excess and small numbers are pulled
towards the neighbours; Henderson has SIR 0.961 yet is flagged (RR 1.218; P(RR > 1) = 0.815), because its low PNW74 (6.14) makes the model expect less than the state rate,
so a count at the state rate is above what is expected for this county.
— Flags near 0.80 can flip with Monte Carlo error: Transylvania has P(RR > 1) = 0.808 in DAPH and 0.780 in R (a difference within the MCSE rule).
Report areas whose P is within about 2 MCSE of 0.80 (see the note under Table 2) as borderline.
— Sensitivity: 94 of 100 counties have an expected count below 20; Richardson et al. (2004) found the rule specific but of low sensitivity there when the true RR is
below 2, so an unflagged county is not shown to be free of excess risk.
— Model comparison (Table 4): BYM2 versus no area effect differs by 4.8 elpd (dSE 4.1), less than 2 dSE, so the area effects do not clearly improve prediction,
and the IID and ICAR forms predict about equally (0.2 and 1.3 below BYM2, dSE 1.1 and 1.2), in line with the uncertain φ.
— A Bayesian report should give the priors, the sampler settings, the convergence diagnostics and the posterior summaries (Kruschke, 2021); DAPH's Word report includes all four.
ตัวอย่างการเขียนผล: แบบจำลอง BYM2 ของการเสียชีวิตด้วย SIDS ใน 100 เคาน์ตีของรัฐ North Carolina ปี 1974–78 (667 ราย จากเกิดมีชีพ 329,962 ราย) พบว่าร้อยละการเกิดมีชีพที่ไม่ใช่คนผิวขาว ที่สูงขึ้น 1 SD (20.86 จุดร้อยละ) สัมพันธ์กับความเสี่ยงที่สูงขึ้น (RR 1.506, 95% CrI 1.325 ถึง 1.730) สัดส่วนของความต่างที่เหลือที่เกาะกลุ่มตามเพื่อนบ้านยังไม่แน่นอน (φ 0.433, 95% CrI 0.021 ถึง 0.952) 8 เคาน์ตีมีความน่าจะเป็นภายหลังอย่างน้อย 0.80 ที่ความเสี่ยงสัมพัทธ์หลังปรับเกิน 1 (สูงสุดคือ Onslow, RR 1.390, 95% CrI 1.001 ถึง 1.974) การสุ่มลู่เข้า (R-hat สูงสุด 1.003, ESS ต่ำสุด 2,312, ไม่มี divergent transitions)
Example write-up: In a BYM2 model of SIDS deaths in the 100 counties of North Carolina in 1974–78 (667 deaths among 329,962 live births), a 1 SD (20.86 percentage points) higher share of non-white births was associated with a higher risk (RR 1.506, 95% CrI 1.325 to 1.730). The share of the remaining variation that clusters by neighbourhood was uncertain (φ 0.433, 95% CrI 0.021 to 0.952). Eight counties had a posterior probability of at least 0.80 that their adjusted relative risk exceeded 1 (highest: Onslow, RR 1.390, 95% CrI 1.001 to 1.974). The sampler converged (maximum R-hat 1.003, minimum ESS 2,312, no divergent transitions).
กราฟที่ DAPH ให้: แผนที่ RR (ขอบหนา = เข้าเกณฑ์) · แผนที่ P(RR > c) หนึ่งแผนที่ต่อเกณฑ์ · SIR เทียบ RR · RR และ 95% CrI ของทุกพื้นที่ · การแจกแจงภายหลังของ φ และ σ · RR ของตัวแปรร่วม (เมื่อมี) · อัตราเทียบของช่วงเวลา (เมื่อมีหลายช่วง) · trace และ rank plot · posterior predictive check · การเปรียบเทียบ PSIS-LOO (เมื่อเปิด) · กราฟเพื่อนบ้าน
Charts DAPH draws: RR map (bold outline = flagged) · P(RR > c) map, one per threshold · SIR vs RR · RR with 95% CrI for every area · posteriors of φ and σ · covariate RRs (when present) · period rate ratios (with several periods) · trace and rank plots · posterior predictive check · PSIS-LOO comparison (when switched on) · neighbour graph
📖 References
- Besag, J., York, J., & Mollié, A. (1991). Bayesian image restoration, with two applications in spatial statistics. Annals of the Institute of Statistical Mathematics, 43(1), 1–20. doi:10.1007/BF00116466
- Bürkner, P.-C. (2017). brms: An R package for Bayesian multilevel models using Stan. Journal of Statistical Software, 80(1), 1–28. doi:10.18637/jss.v080.i01
- Cressie, N., & Chan, N. H. (1989). Spatial modeling of regional variables. Journal of the American Statistical Association, 84(406), 393–401. doi:10.1080/01621459.1989.10478783
- Hoffman, M. D., & Gelman, A. (2014). The No-U-Turn sampler: Adaptively setting path lengths in Hamiltonian Monte Carlo. Journal of Machine Learning Research, 15(47), 1593–1623. https://jmlr.org/papers/v15/hoffman14a.html
- Kruschke, J. K. (2021). Bayesian analysis reporting guidelines. Nature Human Behaviour, 5(10), 1282–1291. doi:10.1038/s41562-021-01177-7
- Morris, M., Wheeler-Martin, K., Simpson, D., Mooney, S. J., Gelman, A., & DiMaggio, C. (2019). Bayesian hierarchical spatial models: Implementing the Besag York Mollié model in stan. Spatial and Spatio-temporal Epidemiology, 31, 100301. doi:10.1016/j.sste.2019.100301
- Papaspiliopoulos, O., Roberts, G. O., & Sköld, M. (2003). Non-centered parameterizations for hierarchical models and data augmentation. In J. M. Bernardo et al. (Eds.), Bayesian Statistics 7 (pp. 307–326). Oxford University Press. doi:10.1093/oso/9780198526155.003.0017
- Richardson, S., Thomson, A., Best, N., & Elliott, P. (2004). Interpreting posterior relative risk estimates in disease-mapping studies. Environmental Health Perspectives, 112(9), 1016–1025. doi:10.1289/ehp.6740
- Riebler, A., Sørbye, S. H., Simpson, D., & Rue, H. (2016). An intuitive Bayesian spatial model for disease mapping that accounts for scaling. Statistical Methods in Medical Research, 25(4), 1145–1165. doi:10.1177/0962280216660421
- Vehtari, A., Gelman, A., & Gabry, J. (2017). Practical Bayesian model evaluation using leave-one-out cross-validation and WAIC. Statistics and Computing, 27(5), 1413–1432. doi:10.1007/s11222-016-9696-4
- Vehtari, A., Gelman, A., Simpson, D., Carpenter, B., & Bürkner, P.-C. (2021). Rank-normalization, folding, and localization: An improved R-hat for assessing convergence of MCMC. Bayesian Analysis, 16(2), 667–718. doi:10.1214/20-BA1221
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
6.10 Bayesian Joint Disease Mapping — แผนที่ความเสี่ยงสองโรคร่วมกันtwo outcomes R
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
ใช้ตอบคำถามว่า "พื้นที่ที่โรคหนึ่งสูง อีกโรคสูงตามไปด้วยหรือไม่" เช่น วัณโรคกับเอชไอวี หรือไข้เลือดออกกับชิคุนกุนยา และในแต่ละพื้นที่โรคใดสูงกว่ากันเชิงสัมพัทธ์ แบบจำลองประมาณความเสี่ยงสัมพัทธ์ (RR) ของทั้งสองโรครายพื้นที่พร้อมกัน สหสัมพันธ์ของรูปแบบเชิงพื้นที่ของสองโรค ρ และความน่าจะเป็นภายหลังที่ RR ของโรคที่ 1 สูงกว่าโรคที่ 2 ในแต่ละพื้นที่ การประมาณร่วมกันทำให้แต่ละโรคยืมข้อมูลจากอีกโรคในพื้นที่เดียวกันได้มากหรือน้อยตามขนาดของ ρ
Answers "where one disease is high, is the other high too?", for example tuberculosis and HIV, or dengue and chikungunya, and which of the two is relatively higher in each area. The model estimates both outcomes' area relative risks (RR) together, the correlation ρ of their spatial patterns, and the posterior probability that outcome 1's RR exceeds outcome 2's in each area; fitting them jointly lets each outcome borrow strength from the other in the same area, as much as ρ allows.
ใช้เมื่อ มีจำนวนนับสองชุดบนพื้นที่ชุดเดียวกัน แต่ละชุดมีตัวหารของตัวเอง และแผนที่เชื่อมเป็นกราฟเพื่อนบ้านเดียว ไม่ใช้เมื่อ ต้องปรับตัวแปรร่วมหรือแยกช่วงเวลา (แบบจำลองสองโรคของ DAPH ไม่มีทั้งสองอย่าง ให้ใช้ 6.9 ทีละโรค) หรือคนกลุ่มเดียวกันถูกนับในทั้งสองโรค (ดูข้อควรระวัง)
Use it for two counts on the same areas, each with its own denominator, on a map that forms one connected neighbour graph. Do not use it when covariates or separate periods are needed (DAPH's two-outcome model has neither; use 6.9 for each outcome) or when the same people are counted under both outcomes (see the caution below).
2หลักการและสูตรLogic and Formula
- yki, nki, Eki
- จำนวนที่พบ ตัวหาร และจำนวนที่คาดหวังของโรค k ในพื้นที่ i (E ของแต่ละโรคคำนวณจากอัตรารวมของโรคนั้นเอง)observed count, denominator and expected count of outcome k in area i (each outcome's E uses its own overall rate)
- αk, bki
- ระดับรวมบนสเกล log และผลรายพื้นที่ของโรค koverall level on the log scale and area effect of outcome k
- u, w, W, Q+, s
- สนาม ICAR อิสระสองชุดบนกราฟเพื่อนบ้าน W; Q+ และ scaling factor s เหมือนหัวข้อ 6.9two independent ICAR fields on the neighbour graph W; Q+ and the scaling factor s as in section 6.9
- σ1, σ2, ρ
- ขนาดความต่างระหว่างพื้นที่ของแต่ละโรค (SD บนสเกล log) และสหสัมพันธ์ของผลรายพื้นที่ของสองโรคbetween-area SD of each outcome on the log scale, and the correlation of the two outcomes' area effects
- S, c1
- P(RR1 > RR2), σ1/σ2 และ ρ ใช้ค่าสุ่มทั้งหมด ส่วน P(RRk > c) ใช้ 1,000 ค่าที่เก็บไว้; c1 คือเกณฑ์ RR ค่าแรก (ค่าเริ่มต้น 1.0)P(RR1 > RR2), σ1/σ2 and ρ use all draws, P(RRk > c) the 1,000 draws kept; c1 is the first RR threshold (default 1.0)
เป็นแบบจำลอง CAR หลายตัวแปรที่มีโครงสร้างร่วม (co-regionalised; Gelfand & Vounatsou, 2003; Jin et al., 2007) สนามทั้งสองปรับสเกลแบบ Riebler et al. (2016) จึงทำให้ σ1, σ2 อ่านได้แบบเดียวกับ σ ของหัวข้อ 6.9 และ ρ เป็นสหสัมพันธ์ของผลรายพื้นที่ของสองโรค ต่างจาก BYM2 ตรงที่ผลรายพื้นที่ของแต่ละโรคเกาะกลุ่มตามเพื่อนบ้านทั้งหมด (ไม่มีส่วนอิสระ) ไม่มีตัวแปรร่วมและไม่มีหลายช่วงเวลา กราฟเพื่อนบ้าน เกณฑ์การลู่เข้า (คิดบน ρ, σ1, σ2, α1, α2 และ b ทุกพื้นที่ของทั้งสองโรค) การไม่รายงานค่าประมาณเมื่อไม่ลู่เข้า และวิธีสุ่มแบบ eigen-centred เหมือนหัวข้อ 6.9 ค่าเริ่มต้นการสุ่มคือ 4 โซ่ × 5000 ค่าหลังปรับ 4000 รอบ target accept 0.97 seed 12345 (ตารางค่าเริ่มต้นในหัวข้อ 6.9)
A co-regionalised multivariate CAR model (Gelfand & Vounatsou, 2003; Jin et al., 2007); both fields are scaled as in Riebler et al. (2016), so σ1 and σ2 read like the σ of section 6.9 and ρ is the correlation of the two outcomes' area effects. Unlike BYM2, each outcome's area effect is entirely spatially structured (no independent part), and there are no covariates and no periods. The neighbour graph, the convergence rule (over ρ, σ1, σ2, α1, α2 and every area effect of both outcomes), the refusal to report estimates from a run that did not converge, and the eigen-centred sampler are those of section 6.9. Sampler defaults are 4 chains × 5000 draws after 4000 tuning iterations, target accept 0.97, seed 12345 (defaults table in section 6.9).
กฎตัดสินใจ: แต่ละโรคติดธงแยกกันเมื่อ P(RR ของโรคนั้น > เกณฑ์แรก) ≥ ค่าติดธง (ค่าเริ่มต้น 1.0 และ 0.80; Richardson et al., 2004) และค่าติดธงเดียวกันแบ่งพื้นที่ตาม P(RR1 > RR2): ≥ 0.80 = โรคที่ 1 สูงกว่าเชิงสัมพัทธ์ ≤ 0.20 = โรคที่ 2 สูงกว่าเชิงสัมพัทธ์ ระหว่างนั้นยังบอกไม่ได้ เป็นกฎตัดสินใจ ไม่ใช่การทดสอบนัยสำคัญ เพราะ E ของแต่ละโรคคำนวณจากอัตรารวมของโรคนั้น RR1/RR2 จึงเทียบตำแหน่งของพื้นที่เมื่อเทียบกับภาพรวมของแต่ละโรค ไม่ได้เทียบอัตราป่วยตรง ๆ
Decision rules: each outcome is flagged separately when P(RR of that outcome > the first threshold) ≥ the flag value (defaults 1.0 and 0.80; Richardson et al., 2004), and the same flag value splits the areas by P(RR1 > RR2): ≥ 0.80 = outcome 1 relatively higher, ≤ 0.20 = outcome 2 relatively higher, in between = undecided. These are decision rules, not significance tests. Because each outcome's E comes from its own overall rate, RR1/RR2 compares the area's position relative to each outcome's overall level, not the raw rates.
ข้อควรระวัง: ถ้าคนเดียวกันถูกนับในทั้งสองโรค (เช่น ผู้ติดเชื้อร่วม หรือผู้ป่วยกับผู้เสียชีวิตของโรคเดียวกัน) ρ จะสูงเกินจริง ควรแยกกรณีที่นับซ้ำก่อนวิเคราะห์ และเมื่อพื้นที่น้อย ช่วงของ ρ จะกว้าง (ในตัวอย่างนี้ 100 เคาน์ตี ช่วงยังกว้างตั้งแต่ 0.125 ถึง 0.893)
Caution: when the same people are counted under both outcomes (co-infection, or the cases and deaths of one disease), ρ is inflated; separate the double-counted cases first. With few areas the interval for ρ is wide (even with this example's 100 counties it runs from 0.125 to 0.893).
3สคริปต์ R และผลการตรวจสอบR Script and Verification
ไม่มีแพ็กเกจ R สำเร็จรูปที่เขียนแบบจำลองนี้ด้วย prior ชุดเดียวกัน สคริปต์จึงเขียนแบบจำลองของ DAPH เป็นโปรแกรม Stan และรันด้วยแพ็กเกจ rstan (คอมไพล์ราว 1 ถึง 2 นาที) ICAR เขียนด้วยรูปผลต่างรายคู่ (Morris et al., 2019) และแบบ non-centred ซึ่งต่างจากพิกัดการสุ่มของ DAPH แต่เป็นแบบจำลองเดียวกัน ค่าที่ได้บนคอมพิวเตอร์อื่นอาจต่างจากด้านล่างเล็กน้อยตามความคลาดเคลื่อนจากการสุ่ม
No ready-made R package fits this model with these priors, so the script writes DAPH's model as a Stan program and runs it with rstan (compiling takes 1 to 2 minutes). The ICAR prior is written in the pairwise-difference form (Morris et al., 2019) and non-centred, which differs from DAPH's sampler coordinates but is the same model. On another computer the numbers may differ slightly, within Monte Carlo error.
# Data: North Carolina SIDS, shipped with the R package sf (100 counties): SIDS deaths and live births
# in 1974-78 (SID74, BIR74) and in 1979-84 (SID79, BIR79)
library(sf); library(spdep); library(MASS); library(rstan); library(posterior)
nc <- st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
# The same polygons for DAPH: zip the four shapefile parts, then open nc.zip in DAPH
zip::zip("nc.zip", system.file("shape", paste0("nc.", c("shp", "shx", "dbf", "prj")), package = "sf"),
mode = "cherry-pick")
# 1) Queen neighbours, edge list, scaling factor s; expected counts per outcome (indirect standardisation)
W <- nb2mat(poly2nb(nc, queen = TRUE), style = "B")
s <- exp(mean(log(diag(ginv(diag(rowSums(W)) - W)))))
ed <- which(upper.tri(W) & W == 1, arr.ind = TRUE)
E1 <- nc$BIR74 * sum(nc$SID74) / sum(nc$BIR74)
E2 <- nc$BIR79 * sum(nc$SID79) / sum(nc$BIR79)
print(c(areas = nrow(W), edges = nrow(ed), scaling_factor = round(s, 7),
events = sum(nc$SID74) + sum(nc$SID79)))
print(c(sum_O1 = sum(nc$SID74), sum_E1 = sum(E1), sum_O2 = sum(nc$SID79), sum_E2 = sum(E2)))
# 2) The DAPH two-outcome model written in Stan
code <- "
data {
int<lower=1> N; int<lower=1> K;
array[K] int<lower=1, upper=N> node1; array[K] int<lower=1, upper=N> node2;
array[N] int<lower=0> y1; array[N] int<lower=0> y2;
vector<lower=0>[N] E1; vector<lower=0>[N] E2; real<lower=0> s;
}
parameters {
real alpha1; real alpha2; real<lower=0> sigma1; real<lower=0> sigma2;
real<lower=0, upper=1> B; vector[N] u; vector[N] w;
}
transformed parameters {
real rho = 2 * B - 1;
vector[N] b1 = sigma1 * u / sqrt(s);
vector[N] b2 = sigma2 * (rho * u + sqrt(1 - square(rho)) * w) / sqrt(s);
}
model {
y1 ~ poisson_log(log(E1) + alpha1 + b1);
y2 ~ poisson_log(log(E2) + alpha2 + b2);
target += -0.5 * dot_self(u[node1] - u[node2]); // u ~ ICAR(W)
target += -0.5 * dot_self(w[node1] - w[node2]); // w ~ ICAR(W)
sum(u) ~ normal(0, 0.001 * N); // sum-to-zero
sum(w) ~ normal(0, 0.001 * N);
alpha1 ~ normal(0, 5); alpha2 ~ normal(0, 5);
sigma1 ~ normal(0, 0.5); sigma2 ~ normal(0, 0.5); // half-normal (sigma > 0)
B ~ beta(2, 2);
}"
fit <- stan(model_code = code, seed = 12345, chains = 4, cores = 1, iter = 4000, warmup = 2000,
control = list(adapt_delta = 0.97), refresh = 0,
data = list(N = nrow(W), K = nrow(ed), node1 = ed[, 1], node2 = ed[, 2],
y1 = nc$SID74, y2 = nc$SID79, E1 = E1, E2 = E2, s = s))
# 3) Posterior medians, 95% equal-tailed CrI and their Monte Carlo SEs (MCSE)
dr <- as_draws_array(fit)
m <- function(v) extract_variable_matrix(dr, v)
summ <- function(x) c(median = median(x), lo = quantile(x, 0.025, names = FALSE),
hi = quantile(x, 0.975, names = FALSE), mcse_med = unname(mcse_median(x)),
mcse_lo = unname(mcse_quantile(x, 0.025)), mcse_hi = unname(mcse_quantile(x, 0.975)))
par <- rbind(rho = summ(m("rho")), sigma1 = summ(m("sigma1")), sigma2 = summ(m("sigma2")),
ratio = summ(m("sigma1") / m("sigma2")))
write.csv(par, "r_joint_params.csv")
print(round(par, 4))
print(round(c(P_rho_gt_0 = mean(m("rho") > 0), P_rho_gt_0.5 = mean(m("rho") > 0.5)), 3))
# 4) Per county: RR1, RR2, RR1/RR2 = exp(b1 - b2), P(RR1 > RR2), P(RRk > 1) and the 0.80 rules
mc <- function(x) c(unname(median(x)), unname(mcse_median(x)))
cty <- t(sapply(seq_len(nrow(W)), function(i) {
b1 <- m(sprintf("b1[%d]", i)); b2 <- m(sprintf("b2[%d]", i))
c(RR1 = mc(exp(b1)), RR2 = mc(exp(b2)), ratio = mc(exp(b1 - b2)),
P12 = mean(b1 > b2), mcse_P12 = unname(mcse_mean(b1 > b2)),
P1 = mean(b1 > 0), mcse_P1 = unname(mcse_mean(b1 > 0)),
P2 = mean(b2 > 0), mcse_P2 = unname(mcse_mean(b2 > 0)))
}))
colnames(cty)[1:6] <- c("RR1", "mcse_RR1", "RR2", "mcse_RR2", "ratio", "mcse_ratio")
res <- data.frame(county = nc$NAME, O1 = nc$SID74, E1 = round(E1, 2), O2 = nc$SID79, E2 = round(E2, 2),
round(cty, 4))
write.csv(res, "r_joint_counties.csv", row.names = FALSE)
res <- res[order(-res$P12, -res$ratio), ]
show <- c("county", "O1", "E1", "O2", "E2", "RR1", "RR2", "ratio", "P12")
print(head(res[, show], 5), row.names = FALSE)
print(tail(res[, show], 5), row.names = FALSE)
print(c(P12_ge_0.80 = sum(res$P12 >= 0.80), P12_le_0.20 = sum(res$P12 <= 0.20),
flag_SID74 = sum(res$P1 >= 0.80), flag_SID79 = sum(res$P2 >= 0.80),
flag_both = sum(res$P1 >= 0.80 & res$P2 >= 0.80)))
# 5) Convergence over rho, sigma1, sigma2, alpha1, alpha2 and every b1_i, b2_i
cv <- summarise_draws(subset_draws(dr, c("rho", "sigma1", "sigma2", "alpha1", "alpha2", "b1", "b2"), regex = TRUE),
"rhat", "ess_bulk", "ess_tail")
print(c(max_rhat = max(cv$rhat), min_ess_bulk = min(cv$ess_bulk), min_ess_tail = min(cv$ess_tail),
divergent = get_num_divergent(fit)), digits = 4)
areas edges scaling_factor events
100.0000000 245.0000000 0.5859796 1503.0000000
sum_O1 sum_E1 sum_O2 sum_E2
667 667 836 836
median lo hi mcse_med mcse_lo mcse_hi
rho 0.5828 0.1117 0.8854 0.0074 0.0082 0.0075
sigma1 0.5041 0.3461 0.6834 0.0024 0.0028 0.0040
sigma2 0.3687 0.2318 0.5272 0.0015 0.0030 0.0033
ratio 1.3663 0.8332 2.3009 0.0079 0.0080 0.0377
P_rho_gt_0 P_rho_gt_0.5
0.992 0.645
county O1 E1 O2 E2 RR1 RR2 ratio P12
Northampton 9 2.87 3 3.18 2.3399 1.2746 1.8249 0.9845
Halifax 18 7.29 17 8.83 2.0712 1.3512 1.5270 0.9738
Bertie 6 2.68 5 3.20 1.9711 1.2085 1.6219 0.9661
Onslow 29 22.56 23 29.01 1.2788 0.9199 1.3820 0.9481
Washington 5 2.00 0 2.26 1.3922 0.8799 1.5804 0.9414
county O1 E1 O2 E2 RR1 RR2 ratio P12
Caldwell 6 7.30 9 8.41 0.7223 0.9893 0.7348 0.0889
Gaston 11 18.22 26 22.67 0.7849 1.0730 0.7357 0.0885
Alexander 0 2.69 2 3.33 0.5601 0.8413 0.6719 0.0814
Burke 5 7.22 15 8.54 0.9161 1.2621 0.7281 0.0681
Catawba 5 11.63 21 13.62 0.7454 1.1688 0.6384 0.0192
P12_ge_0.80 P12_le_0.20 flag_SID74 flag_SID79 flag_both
22 22 26 21 16
max_rhat min_ess_bulk min_ess_tail divergent
1.003 911.758 1548.227 0.000
ไฟล์ > นำเข้า > Shapefile (.zip) แล้วเลือก nc.zip ที่สคริปต์สร้าง; Tab 2 > Outcome type: Spatial > Bayesian Joint Disease Mapping (Two Outcomes); ตั้งค่าแผนที่สองโรค > ข้อมูล: โรคที่ 1 จำนวนผู้ป่วย = SID74 ตัวหาร = BIR74; โรคที่ 2 จำนวนผู้ป่วย = SID79 ตัวหาร = BIR79; เพื่อนบ้าน = Queen (เชื่อมเกาะกับพื้นที่ใกล้สุด) ตามที่ตั้งไว้ (100 พื้นที่ · 245 เส้น); ค่าอื่นเป็นค่าเริ่มต้น การรันเป็นงานเบื้องหลัง ผลขึ้นที่ Tab 3 เมื่อเสร็จ
File > Import > Shapefile (.zip) and choose the nc.zip the script wrote; Tab 2 > Outcome type: Spatial > Bayesian Joint Disease Mapping (Two Outcomes); Two-outcome settings > Data: Disease 1 Count = SID74, Offset = BIR74; Disease 2 Count = SID79, Offset = BIR79; Neighbours = Queen (islands linked to nearest areas) as set (100 areas · 245 edges); everything else at its default. The run is a background job; the result appears in Tab 3 when it finishes.
| รายการItem | R | DAPH | ความต่าง / เกณฑ์Difference / rule | สถานะStatus |
|---|---|---|---|---|
| กราฟ Queen: พื้นที่ / เส้นเชื่อมQueen graph: areas / edges | 100 / 245 | 100 / 245 | 0 | ✓ PASS |
| scaling factor sscaling factor s | 0.5859796 | 0.5859796 | < 1e−7 | ✓ PASS |
| ΣE1 = ΣO1 และ ΣE2 = ΣO2 (เหตุการณ์รวม)ΣE1 = ΣO1 and ΣE2 = ΣO2 (total events) | 667, 836 (1503) | 667, 836 (1503) | 0 | ✓ PASS |
| ρ มัธยฐานภายหลังρ posterior median | 0.5828 | 0.5958 | 0.0131 ≤ 0.0237 | ✓ PASS |
| ρ ขอบล่าง 95% CrIρ lower 95% CrI limit | 0.1117 | 0.1252 | 0.0135 ≤ 0.0295 | ✓ PASS |
| ρ ขอบบน 95% CrIρ upper 95% CrI limit | 0.8854 | 0.8928 | 0.0074 ≤ 0.0232 | ✓ PASS |
| σ1 มัธยฐานภายหลังσ1 posterior median | 0.5041 | 0.5028 | 0.0013 ≤ 0.0079 | ✓ PASS |
| σ1 ขอบล่าง 95% CrIσ1 lower 95% CrI limit | 0.3461 | 0.3510 | 0.0049 ≤ 0.0097 | ✓ PASS |
| σ1 ขอบบน 95% CrIσ1 upper 95% CrI limit | 0.6834 | 0.6834 | 0.0000 ≤ 0.0144 | ✓ PASS |
| σ2 มัธยฐานภายหลังσ2 posterior median | 0.3687 | 0.3703 | 0.0017 ≤ 0.0052 | ✓ PASS |
| σ2 ขอบล่าง 95% CrIσ2 lower 95% CrI limit | 0.2318 | 0.2339 | 0.0021 ≤ 0.0098 | ✓ PASS |
| σ2 ขอบบน 95% CrIσ2 upper 95% CrI limit | 0.5272 | 0.5288 | 0.0016 ≤ 0.0112 | ✓ PASS |
| σ1/σ2 มัธยฐานภายหลังσ1/σ2 posterior median | 1.3663 | 1.3603 | 0.0061 ≤ 0.0253 | ✓ PASS |
| σ1/σ2 ขอบล่าง 95% CrIσ1/σ2 lower 95% CrI limit | 0.8332 | 0.8371 | 0.0038 ≤ 0.0264 | ✓ PASS |
| σ1/σ2 ขอบบน 95% CrIσ1/σ2 upper 95% CrI limit | 2.3009 | 2.3094 | 0.0084 ≤ 0.1223 | ✓ PASS |
| Northampton: RR1/RR2 มัธยฐานNorthampton: RR1/RR2 median | 1.8249 | 1.8022 | 0.0227 ≤ 0.0325 | ✓ PASS |
| Northampton: P(RR1 > RR2)Northampton: P(RR1 > RR2) | 0.9845 | 0.9819 | 0.0026 ≤ 0.0057 | ✓ PASS |
| Catawba: RR1/RR2 มัธยฐานCatawba: RR1/RR2 median | 0.6384 | 0.6443 | 0.0059 ≤ 0.0099 | ✓ PASS |
| Catawba: P(RR1 > RR2)Catawba: P(RR1 > RR2) | 0.0192 | 0.0191 | 0.0001 ≤ 0.0060 | ✓ PASS |
| ทุกเคาน์ตี: RR1, RR2, RR1/RR2, P(RR1 > RR2), P(RR1 > 1), P(RR2 > 1) (600 ค่า)every county: RR1, RR2, RR1/RR2, P(RR1 > RR2), P(RR1 > 1), P(RR2 > 1) (600 values) | – | – | อยู่ในเกณฑ์ 597 จาก 600 ค่า; มากสุด 1.33 เท่าของเกณฑ์ (Forsyth, P(RR1>1)); คาดว่าเกินเกณฑ์โดยบังเอิญราว 1.6 ค่า597 of 600 within the rule; largest 1.33 × the limit (Forsyth, P(RR1>1)); about 1.6 expected outside by chance | ✓ PASS |
| P(RR1 > RR2) ≥ 0.80 (SID74 สูงกว่าเชิงสัมพัทธ์)P(RR1 > RR2) ≥ 0.80 (SID74 relatively higher) | 22 | 22 | เคาน์ตีเดียวกันsame counties | ✓ PASS |
| P(RR1 > RR2) ≤ 0.20 (SID79 สูงกว่าเชิงสัมพัทธ์)P(RR1 > RR2) ≤ 0.20 (SID79 relatively higher) | 22 | 23 | ต่างกันเฉพาะเคาน์ตีที่อยู่ใกล้เกณฑ์: differ only near the cut-off: McDowell 0.201 vs 0.195 (0.006 ≤ 0.020) | ✓ PASS |
| เข้าเกณฑ์ SID74: P(RR1 > 1) ≥ 0.80flagged for SID74: P(RR1 > 1) ≥ 0.80 | 26 | 25 | ต่างกันเฉพาะเคาน์ตีที่อยู่ใกล้เกณฑ์: differ only near the cut-off: Richmond 0.801 vs 0.798 (0.003 ≤ 0.041) | ✓ PASS |
| เข้าเกณฑ์ SID79: P(RR2 > 1) ≥ 0.80flagged for SID79: P(RR2 > 1) ≥ 0.80 | 21 | 23 | ต่างกันเฉพาะเคาน์ตีที่อยู่ใกล้เกณฑ์: differ only near the cut-off: Haywood 0.798 vs 0.803 (0.005 ≤ 0.041); Transylvania 0.793 vs 0.813 (0.020 ≤ 0.040) | ✓ PASS |
| การลู่เข้า: R-hat สูงสุด / ESS bulk และ tail ต่ำสุด / divergentconvergence: max R-hat / min bulk and tail ESS / divergent | 1.003 / 912, 1548 / 0 | 1.001 / 8846, 12075 / 0 | ผ่านเกณฑ์ทั้งคู่ (< 1.01, > 400, 0)both meet the rule (< 1.01, > 400, 0) | ✓ PASS |
ค่าที่ไม่ใช้การสุ่มต้องตรงกันถึงหลักที่แสดง ค่าจากการสุ่มใช้เกณฑ์ |R − DAPH| ≤ 3 × √(MCSER² + MCSEDAPH²) เหมือนหัวข้อ 6.9 (MCSE ของมัธยฐานและควอนไทล์ตาม Vehtari et al., 2021; MCSE ของ DAPH จากค่าสุ่มของงานเดียวกัน และสำหรับ P(RRk > 1) ใช้ค่าที่ DAPH รายงานจาก 1,000 ค่าสุ่มที่เก็บไว้) การเทียบหลายร้อยค่าที่เกณฑ์นี้คาดว่าจะเกินโดยบังเอิญราว 0.27% ของจำนวนค่าValues that do not depend on sampling must agree to the digits shown. Sampling-based values use the rule of section 6.9, |R − DAPH| ≤ 3 × √(MCSER² + MCSEDAPH²) (MCSE of medians and quantiles as in Vehtari et al., 2021; DAPH's MCSE from the draws of the same run, and for P(RRk > 1) the value DAPH reports from the 1,000 draws kept). Over several hundred comparisons the rule is expected to be exceeded by chance in about 0.27% of them.
4การแปลผลInterpretation
— ρ = 0.596 (95% CrI 0.125 ถึง 0.893; P(ρ > 0) = 0.993; P(ρ > 0.5) = 0.676): เคาน์ตีที่ความเสี่ยง SIDS เมื่อเทียบกับทั้งรัฐสูงในปี 1974–78 มักสูงในปี 1979–84 ด้วย
ความน่าจะเป็นที่รูปแบบทั้งสองไปทางเดียวกันสูงมาก แต่ความแรงของความสัมพันธ์ยังไม่แน่นอน (ช่วงกว้าง)
— σ1 = 0.503 (95% CrI 0.351 ถึง 0.683), σ2 = 0.370 (95% CrI 0.234 ถึง 0.529), σ1/σ2 = 1.360 (95% CrI 0.837 ถึง 2.309):
ความต่างระหว่างเคาน์ตีในช่วงแรกมากกว่าเล็กน้อย แต่ช่วงของอัตราส่วนครอบ 1 จึงยังสรุปไม่ได้ว่าต่างกัน σ ในหัวข้อนี้ไม่ได้ปรับตัวแปรร่วม จึงใหญ่กว่า σ = 0.274 ของหัวข้อ 6.9 ซึ่งปรับ PNW74 แล้ว
— พื้นที่ที่ควรให้ความสำคัญ (ตารางที่ 3; P(RR > 1) ≥ 0.80): SID74 เข้าเกณฑ์ 25 จาก 100 เคาน์ตี SID79 เข้าเกณฑ์ 23 และเข้าเกณฑ์ทั้งสองช่วง 15 เคาน์ตี
เช่น Robeson และ Columbus เป็นกฎตัดสินใจ ไม่ใช่การทดสอบนัยสำคัญ
— P(RR1 > RR2) ≥ 0.80 ใน 22 เคาน์ตี เช่น Northampton (RR1 2.334, RR2 1.282, RR1/RR2 1.802, 95% CrI 1.043 ถึง 3.439; P = 0.982) คือตำแหน่งเทียบกับทั้งรัฐลดลงจากช่วงแรกสู่ช่วงหลัง
และ ≤ 0.20 ใน 23 เคาน์ตี เช่น Catawba (RR1 0.748, RR2 1.166, RR1/RR2 0.644, 95% CrI 0.377 ถึง 0.980; P = 0.019) คือตำแหน่งสูงขึ้น อีก 55 เคาน์ตียังบอกไม่ได้
เพราะ E ของแต่ละช่วงคำนวณจากอัตราของทั้งรัฐในช่วงนั้น ข้อนี้จึงไม่ได้บอกว่าอัตราตายของเคาน์ตีลดลงหรือเพิ่มขึ้นจริง
— จำนวนเคาน์ตีที่เข้าเกณฑ์ใน R ต่างจาก DAPH ไม่กี่เคาน์ตี ทุกเคาน์ตีที่ต่างมีความน่าจะเป็นอยู่ใกล้เกณฑ์และต่างกันไม่เกินความคลาดเคลื่อนจากการสุ่ม (ตารางผลการตรวจสอบ)
ควรรายงานเคาน์ตีที่อยู่ใกล้ 0.80 หรือ 0.20 ว่าอยู่ที่ขอบเกณฑ์
— ρ = 0.596 (95% CrI 0.125 to 0.893; P(ρ > 0) = 0.993; P(ρ > 0.5) = 0.676): counties with a high SIDS risk relative to the state in 1974–78 tended to be high in 1979–84 too;
that the two patterns move together is very probable, but how strongly is uncertain (wide interval).
— σ1 = 0.503 (95% CrI 0.351 to 0.683), σ2 = 0.370 (95% CrI 0.234 to 0.529), σ1/σ2 = 1.360 (95% CrI 0.837 to 2.309):
counties differed somewhat more in the first period, but the ratio's interval includes 1, so the difference is not established. These σ are not adjusted for a covariate, which is why they are
larger than the σ = 0.274 of section 6.9, where PNW74 is in the model.
— Priority areas (Table 3; P(RR > 1) ≥ 0.80): 25 of 100 counties are flagged for SID74, 23 for SID79 and 15 for both, for example Robeson and Columbus.
These are decision rules, not significance tests.
— P(RR1 > RR2) ≥ 0.80 in 22 counties, for example Northampton (RR1 2.334, RR2 1.282, RR1/RR2 1.802, 95% CrI 1.043 to 3.439; P = 0.982): its position relative to the state fell
from the first period to the second; ≤ 0.20 in 23 counties, for example Catawba (RR1 0.748, RR2 1.166, RR1/RR2 0.644, 95% CrI 0.377 to 0.980; P = 0.019): its position rose;
the other 55 counties are undecided. Because each period's E uses that period's state rate, this does not say whether a county's death rate itself fell or rose.
— R and DAPH flag a few different counties; every such county has a probability close to the cut-off and the two values differ by less than the Monte Carlo rule allows
(verification table). Report counties near 0.80 or 0.20 as borderline.
ตัวอย่างการเขียนผล: แบบจำลองแผนที่ความเสี่ยงสองช่วงเวลาร่วมกันของการเสียชีวิตด้วย SIDS ใน 100 เคาน์ตีของรัฐ North Carolina (1974–78 และ 1979–84) พบว่ารูปแบบเชิงพื้นที่ของสองช่วงมีสหสัมพันธ์ทางบวก (ρ 0.596, 95% CrI 0.125 ถึง 0.893; P(ρ > 0) = 0.993) 15 เคาน์ตีมีความน่าจะเป็นภายหลังอย่างน้อย 0.80 ที่ความเสี่ยงสัมพัทธ์เกิน 1 ในทั้งสองช่วง และตำแหน่งเทียบกับทั้งรัฐลดลงใน 22 เคาน์ตี และสูงขึ้นใน 23 เคาน์ตี (P(RR1 > RR2) ≥ 0.80 และ ≤ 0.20) การสุ่มลู่เข้า (R-hat สูงสุด 1.001, ESS ต่ำสุด 8,846, ไม่มี divergent transitions)
Example write-up: In a joint disease-mapping model of SIDS deaths in the 100 counties of North Carolina in 1974–78 and 1979–84, the spatial patterns of the two periods were positively correlated (ρ 0.596, 95% CrI 0.125 to 0.893; P(ρ > 0) = 0.993). Fifteen counties had a posterior probability of at least 0.80 that their relative risk exceeded 1 in both periods; the position relative to the state fell in 22 counties and rose in 23 (P(RR1 > RR2) ≥ 0.80 and ≤ 0.20). The sampler converged (maximum R-hat 1.001, minimum ESS 8,846, no divergent transitions).
ตารางและกราฟที่ DAPH ให้: ตารางที่ 1 สรุป ρ, σ1, σ2 และ σ1/σ2 · ตารางที่ 2 RR ของสองโรคและ P(RR1 > RR2) รายพื้นที่ · ตารางที่ 3 พื้นที่ที่ควรให้ความสำคัญของแต่ละโรค · ตารางที่ 4 การวินิจฉัยการลู่เข้า · แผนที่ RR คู่ · แผนที่ความน่าจะเป็นที่เกินเกณฑ์คู่ · การแจกแจงภายหลังของ ρ · ผลรายพื้นที่โรคที่ 1 เทียบโรคที่ 2 · แผนที่ P(RR1 > RR2) · trace และ rank plot · กราฟเพื่อนบ้าน
Tables and charts DAPH gives: Table 1 summary of ρ, σ1, σ2 and σ1/σ2 · Table 2 both RRs and P(RR1 > RR2) by area · Table 3 priority areas of each outcome · Table 4 convergence diagnostics · paired RR maps · paired exceedance maps · posterior of ρ · area effects of outcome 1 against outcome 2 · map of P(RR1 > RR2) · trace and rank plots · neighbour graph
📖 References
- Cressie, N., & Chan, N. H. (1989). Spatial modeling of regional variables. Journal of the American Statistical Association, 84(406), 393–401. doi:10.1080/01621459.1989.10478783
- Gelfand, A. E., & Vounatsou, P. (2003). Proper multivariate conditional autoregressive models for spatial data analysis. Biostatistics, 4(1), 11–25. doi:10.1093/biostatistics/4.1.11
- Jin, X., Banerjee, S., & Carlin, B. P. (2007). Order-free co-regionalized areal data models with application to multiple-disease mapping. Journal of the Royal Statistical Society: Series B (Statistical Methodology), 69(5), 817–838. doi:10.1111/j.1467-9868.2007.00612.x
- Morris, M., Wheeler-Martin, K., Simpson, D., Mooney, S. J., Gelman, A., & DiMaggio, C. (2019). Bayesian hierarchical spatial models: Implementing the Besag York Mollié model in stan. Spatial and Spatio-temporal Epidemiology, 31, 100301. doi:10.1016/j.sste.2019.100301
- Richardson, S., Thomson, A., Best, N., & Elliott, P. (2004). Interpreting posterior relative risk estimates in disease-mapping studies. Environmental Health Perspectives, 112(9), 1016–1025. doi:10.1289/ehp.6740
- Riebler, A., Sørbye, S. H., Simpson, D., & Rue, H. (2016). An intuitive Bayesian spatial model for disease mapping that accounts for scaling. Statistical Methods in Medical Research, 25(4), 1145–1165. doi:10.1177/0962280216660421
- Vehtari, A., Gelman, A., Simpson, D., Carpenter, B., & Bürkner, P.-C. (2021). Rank-normalization, folding, and localization: An improved R-hat for assessing convergence of MCMC. Bayesian Analysis, 16(2), 667–718. doi:10.1214/20-BA1221
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 7 — Machine Learning ComparisonChapter 7 — Machine Learning Comparison ✓ Verified
บทนี้รวมการเปรียบเทียบแบบจำลองทำนายด้วย Machine Learning ของ DAPH · Machine Learning Comparison (7.1 ถึง 7.3) เป็นสถิติเดียวที่เลือกชนิดของผลลัพธ์ให้เอง: ผลลัพธ์ที่มีค่าต่างกัน 2 ค่าเป็น binary (7.1) ตัวแปรที่พจนานุกรมข้อมูลกำหนดเป็นตัวแปรกลุ่ม (nominal หรือ ordinal) ตั้งแต่ 3 ระดับเป็น multiclass (7.2) และตัวแปรที่กำหนดเป็นตัวเลข (integer หรือ real) เป็น regression (7.3) ถ้าไม่ได้กำหนดชนิด รหัส 3 ถึง 15 ค่าที่เป็นจำนวนเต็มหรือข้อความเป็น multiclass นอกนั้นเป็น regression ทุกแบบฟิตหลายแบบจำลองบนชุดฝึกเดียวกัน ประเมินบนชุดทดสอบที่แบ่งแบบสุ่มหรือตามเวลา (และ cross-validation ถ้าเลือก) พร้อมช่วงเชื่อมั่นแบบ bootstrap · Spatial Machine Learning (7.4) เพิ่มตัวแปรเชิงพื้นที่และ Spatial Block CV · External Validation และ Save Model (7.5) นำแบบจำลองที่บันทึกเป็นไฟล์ .daphmodel ไปประเมินกับข้อมูลชุดใหม่ และอธิบายการแบ่งตามเวลา · Spatio-Temporal Machine Learning (7.6) ใช้ข้อมูลรายพื้นที่หลายช่วงเวลาและทดสอบกับช่วงเวลาล่าสุด · การคัดตัวแปรอธิบายในหัวข้อ 13.3 · รายงาน Word เขียนตามแนวทาง TRIPOD+AI (Collins et al. 2024) This chapter covers DAPH's machine-learning comparison of prediction models. Machine Learning Comparison (7.1 to 7.3) is one statistic that chooses the outcome type itself: an outcome with two distinct values gives binary classification (7.1), one declared in the data dictionary as a group variable (nominal or ordinal) with three or more categories gives multiclass classification (7.2), and one declared as a number (integer or real) gives regression (7.3); without a declared type, 3 to 15 whole-number or text codes give multiclass and anything else regression. Each fits several models on the same training set and evaluates them on a test set split at random or by time (plus cross-validation if chosen), with bootstrap confidence intervals. Spatial Machine Learning (7.4) adds spatial features and Spatial Block CV. External Validation and Save Model (7.5) applies a model saved as a .daphmodel file to new data and explains the temporal split. Spatio-Temporal Machine Learning (7.6) uses area data over several periods and tests on the latest periods. Variable selection is explained in 13.3. The Word reports follow the TRIPOD+AI guideline (Collins et al. 2024).
7.1Binary Classification (event / non-event)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Machine Learning Comparison สำหรับผลลัพธ์ 2 กลุ่ม (เกิดเหตุการณ์ / ไม่เกิด เช่น เสียชีวิต / ไม่เสียชีวิต) สร้างแบบจำลองทำนายหลายแบบจากข้อมูลชุดฝึก (training set) ชุดเดียวกัน แล้ววัดว่าแต่ละแบบทำนายผลของผู้ป่วยที่ไม่ได้ใช้สร้างแบบจำลอง (ชุดทดสอบ test set) ได้ดีเพียงใด ตัวแปรผลลัพธ์ที่มีค่าต่างกัน 2 ค่าจะวิเคราะห์แบบ binary เสมอ (กติกาเลือกชนิดของผลลัพธ์อยู่ในบทนำของบทที่ 7) · แบบจำลองที่เลือกไว้เป็นค่าเริ่มต้นมี 5 แบบ ได้แก่ Logistic Regression (มีบทลงโทษแบบ ridge ค่า C = 1), Elastic Net (Logistic) (Zou & Hastie 2005), Random Forest (Breiman 2001), XGBoost (Chen & Guestrin 2016) และ LightGBM ส่วนที่เลือกเพิ่มได้ ได้แก่ SVM แบบ RBF kernel (Cortes & Vapnik 1995), MLP (ชั้นซ่อน 1 ชั้น 64 หน่วย), Decision Tree, KNN และ Gaussian Naive Bayes · Logistic Regression เป็นแบบจำลองอ้างอิง (baseline) ที่ทุกแบบจำลองถูกนำมาเทียบค่า AUC ด้วย DeLong test (DeLong et al. 1988)
Machine Learning Comparison with a two-category outcome (event / no event, e.g. died / did not die) fits several prediction models on the same training set and measures how well each one predicts the outcome of patients who were not used to build it (the test set). An outcome with exactly two distinct values is always analysed as binary (the rule for the outcome type is in the chapter introduction). Five models are ticked by default: Logistic Regression (with a ridge penalty, C = 1), Elastic Net (Logistic) (Zou & Hastie 2005), Random Forest (Breiman 2001), XGBoost (Chen & Guestrin 2016) and LightGBM; SVM with an RBF kernel (Cortes & Vapnik 1995), MLP (one hidden layer of 64 units), Decision Tree, KNN and Gaussian Naive Bayes can be added. Logistic Regression is the baseline: every other model's AUC is compared with it by the DeLong test (DeLong et al. 1988).
สิ่งที่ DAPH รายงาน · บนชุดทดสอบ: AUC, Brier score และ sensitivity, specificity, PPV, NPV, F1 ที่จุดตัด (cut-off) ที่เลือก รวมทั้ง net benefit ของ Decision Curve Analysis (Vickers & Elkin 2006) ที่ threshold 0.2 ทุกค่ามีช่วงเชื่อมั่น 95% จาก bootstrap · หน้าผล (Tab 3) แสดง log-loss, accuracy, balanced accuracy และ Matthews correlation coefficient (MCC) เพิ่ม (ไม่มีช่วงเชื่อมั่น) · รายงาน Word มีกราฟ ROC ของทุกแบบจำลอง, decision curve, calibration plot (แบ่งผู้ป่วยเป็น 10 กลุ่มเท่า ๆ กันตามความเสี่ยงที่ทำนาย), confusion matrix และค่า SHAP (Lundberg & Lee 2017) ของแบบจำลองที่ดีที่สุด และขนาดตัวอย่างขั้นต่ำตามเกณฑ์ของ Riley et al. (2020)
What DAPH reports. On the test set: AUC, Brier score, and sensitivity, specificity, PPV, NPV and F1 at the chosen cut-off, plus the Decision Curve Analysis net benefit (Vickers & Elkin 2006) at threshold 0.2, each with a bootstrap 95% CI. The results page (Tab 3) adds log-loss, accuracy, balanced accuracy and the Matthews correlation coefficient (MCC), without CIs. The Word report adds ROC curves of all models, decision curves, a calibration plot (patients split into 10 equal-sized groups by predicted risk), a confusion matrix and SHAP values (Lundberg & Lee 2017) for the best model, and the minimum sample size by the criteria of Riley et al. (2020).
ใช้เมื่อ เป้าหมายคือทำนายความเสี่ยงของผู้ป่วยแต่ละราย และต้องการเทียบแบบจำลองที่ยืดหยุ่นกับ logistic regression ภายใต้การตรวจสอบแบบเดียวกัน แล้วรายงานตามแนวทาง TRIPOD+AI (Collins et al. 2024) · ไม่ควรใช้ เมื่อต้องการประมาณขนาดความสัมพันธ์ของปัจจัย (ใช้ Logistic Regression หัวข้อ 2.1 ซึ่งให้ odds ratio พร้อมช่วงเชื่อมั่น) หรือเมื่อผลลัพธ์คือเวลาจนเกิดเหตุการณ์และผู้ป่วยถูกติดตามนานไม่เท่ากัน (ใช้ Cox regression หัวข้อ 5.2) · ถ้าจำนวนผู้ป่วยในชุดฝึกน้อยกว่าเกณฑ์ของ Riley ค่าทุกค่าจะไม่เสถียร
Use it when the aim is to predict each patient's risk and you want to compare flexible models with logistic regression under one validation design, reported following TRIPOD+AI (Collins et al. 2024). Do not use it to estimate how strongly a factor is associated with the outcome (use Logistic Regression, 2.1, which gives odds ratios with CIs), or when the outcome is time to an event and patients were followed for different lengths of time (use Cox regression, 5.2). If the training set is smaller than Riley's minimum, every figure is unstable.
2หลักการและสูตรLogic and Formula
- ỹ_i, x_i
- ỹ_i = +1 ถ้าเกิดเหตุการณ์ และ −1 ถ้าไม่เกิด · x_i คือตัวทำนายหลังเตรียมข้อมูล: ตัวแปรต่อเนื่องปรับเป็นคะแนนมาตรฐานด้วยค่าเฉลี่ยและ SD ประชากร (หาร n) ของชุดฝึก ส่วนตัวแปรกลุ่มแยกเป็นคอลัมน์ 0/1 ครบทุกระดับỹ_i = +1 for an event and −1 otherwise; x_i are the predictors after preprocessing: continuous ones standardised with the training mean and population SD (divided by n), categorical ones split into one 0/1 column for every level
- C, ρ
- C = 1 คือส่วนกลับของความแรงของบทลงโทษ (ไม่ลงโทษค่าคงที่ β₀) · ρ = 0.5 คือสัดส่วน L1 ของ Elastic Net (ค่าเริ่มต้น เมื่อไม่ได้ปรับ hyperparameter)C = 1 is the inverse penalty strength (the intercept β₀ is not penalised); ρ = 0.5 is the Elastic Net L1 share (the defaults when hyperparameters are not tuned)
- p̂_i, n₁, n₀
- ความเสี่ยงที่ทำนายของผู้ป่วย i · จำนวนผู้ที่เกิดและไม่เกิดเหตุการณ์ในข้อมูลที่ประเมินpredicted risk of patient i; numbers with and without the event in the evaluated data
- t*, p_t, π
- จุดตัดที่ทำให้ J สูงสุด (ถ้าเสมอกันใช้ค่าที่สูงที่สุด) · threshold probability ของ decision curve · สัดส่วนผู้เกิดเหตุการณ์ในข้อมูลที่ประเมินthe cut-off that maximises J (the highest one when tied); the decision-curve threshold probability; the event proportion in the evaluated data
- θ̂*_b, Q
- ค่าตัวชี้วัดจากการสุ่มซ้ำผู้ป่วยชุดทดสอบแบบใส่คืนครั้งที่ b (ใช้ค่าทำนายเดิม ไม่สร้างแบบจำลองใหม่) · Q คือเปอร์เซ็นไทล์แบบ linear interpolation (R type 7)the metric in bootstrap resample b of the test patients (same predictions, the model is not refitted); Q is the linear-interpolation percentile (R type 7)
- P, φ, S
- จำนวนพารามิเตอร์ของตัวทำนาย (ตัวแปรต่อเนื่องนับ 1 ตัวแปรกลุ่มนับจำนวนระดับ − 1) · สัดส่วนผู้เกิดเหตุการณ์ในชุดฝึก · shrinkage เป้าหมายnumber of predictor parameters (1 per continuous predictor, levels − 1 per categorical one); event proportion in the training set; target shrinkage
- F, f(S)
- เซตของตัวทำนายทั้งหมด · ค่าที่แบบจำลองทำนายเมื่อรู้เฉพาะตัวทำนายในเซต Sset of all predictors; the model's prediction when only the predictors in S are known
ขั้นตอนที่ DAPH ทำ · (1) แบ่งข้อมูล: ค่าเริ่มต้นสุ่มแบบ stratified 70/30 หรือเลือก Temporal ซึ่งเรียงแถวตามตัวแปรเวลา (ถ้าเวลาเท่ากันคงลำดับในไฟล์) แล้วให้ round(0.7 × n) แถวแรกเป็นชุดฝึก (ดูหัวข้อ 7.5) · (2) เตรียมข้อมูลจากชุดฝึกเท่านั้น: เติมค่าที่ขาดด้วยมัธยฐาน (ตัวแปรต่อเนื่อง) หรือค่าที่พบบ่อยที่สุด (ตัวแปรกลุ่ม) ปรับมาตรฐานตัวแปรต่อเนื่องสำหรับ Logistic, Elastic Net, SVM, MLP และ KNN แล้วแยกตัวแปรกลุ่มเป็นคอลัมน์ 0/1 ครบทุกระดับ · (3) ความไม่สมดุลของกลุ่ม: ค่าเริ่มต้น Auto-SMOTE จะสร้างผู้ป่วยสังเคราะห์ของกลุ่มน้อยด้วย SMOTE เมื่ออัตราส่วนกลุ่มน้อยต่อกลุ่มใหญ่ในชุดฝึกต่ำกว่า 0.25 และใช้น้ำหนัก class_weight = balanced เมื่อต่ำกว่า 0.5 · (4) hyperparameter: ค่าเริ่มต้นใช้ค่าตั้งต้นของแต่ละอัลกอริทึม (ไม่ปรับ) หรือเลือก Optuna 20/50 รอบ ซึ่งให้คะแนนแต่ละชุดค่าด้วย AUC จาก k-fold cross-validation ภายในชุดฝึก · (5) ประเมินบนชุดทดสอบ และถ้าเปิด Cross-Validation จะได้ค่าจาก out-of-fold เพิ่มอีกชุด · (6) แบบจำลองที่ดีที่สุดเลือกด้วย AUC ของ cross-validation เมื่อเปิดไว้ ถ้าไม่เปิด ชุดทดสอบจะทั้งเลือกและรายงาน (รายงานจะเขียนกำกับว่าค่าดีเกินจริง)
What DAPH does. (1) Split: a stratified random 70/30 split by default, or Temporal, which sorts the rows by a time variable (ties keep the file order) and makes the first round(0.7 × n) rows the training set (see 7.5). (2) Preprocessing learnt from the training set only: median imputation for continuous and most-frequent imputation for categorical predictors, standardisation of continuous predictors for Logistic, Elastic Net, SVM, MLP and KNN, and one 0/1 column for every level of a categorical predictor. (3) Class imbalance: the default Auto-SMOTE adds synthetic minority patients by SMOTE when the minority-to-majority ratio in the training set is below 0.25, and uses class_weight = balanced when it is below 0.5. (4) Hyperparameters: by default each algorithm's own defaults (no tuning), or Optuna with 20/50 trials, each scored by the k-fold cross-validated AUC inside the training set. (5) Evaluation on the test set, plus an out-of-fold estimate when Cross-Validation is on. (6) The best model is chosen by the cross-validated AUC when CV is on; without CV the test set both chooses and reports, and the report says the figures are therefore optimistic.
จุดที่ต้องรู้ · จุดตัด t* (Youden ซึ่งเป็นค่าเริ่มต้น หรือ F1-optimal) ถูกเลือกจากข้อมูลชุดเดียวกับที่รายงาน คือชุดทดสอบ (ตาราง cross-validation ใช้ค่า out-of-fold) ค่า sensitivity และ specificity ที่จุดตัดนี้จึงดีเกินจริง ถ้าต้องการจุดตัดที่ไม่ลำเอียงให้เลือก Fixed 0.5 หรือกำหนดจากข้อมูลพัฒนาแล้วนำไปใช้ซ้ำ (หัวข้อ 7.5) · Bootstrap สุ่มซ้ำเฉพาะผู้ป่วยในชุดทดสอบโดยไม่สร้างแบบจำลองใหม่ ช่วงเชื่อมั่นจึงสะท้อนความไม่แน่นอนจากขนาดชุดทดสอบเท่านั้น · DAPH ไม่แนะนำแบบจำลองเมื่อ AUC ของแบบจำลองที่ดีที่สุดต่ำกว่า 0.70 หรือช่วงเชื่อมั่นคร่อม 0.5 หรือมีตัวทำนายที่สัมพันธ์กับผลลัพธ์จน |r| ≥ 0.95 · DAPH ไม่คำนวณ calibration intercept และ slope ในหัวข้อนี้ (มีเพียง Brier score และ calibration plot) ดูวิธีคำนวณใน R ในหัวข้อ 7.5
Points to know. The cut-off t* (Youden, the default, or F1-optimal) is chosen on the same data that are reported, i.e. the test set (the cross-validation table uses the out-of-fold predictions), so sensitivity and specificity at that cut-off are optimistic; for an unbiased cut-off choose Fixed 0.5 or fix it on development data and reuse it (7.5). The bootstrap resamples only the test patients and does not refit the model, so the CI reflects the size of the test set only. DAPH does not recommend a model when the best AUC is below 0.70, when its CI includes 0.5, or when a predictor correlates with the outcome at |r| ≥ 0.95. DAPH does not compute a calibration intercept or slope here (only the Brier score and the calibration plot); 7.5 shows how to compute them in R.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
ออกแบบการทวนสอบ · การสุ่มแบ่งข้อมูล Random Forest และ XGBoost ใช้ตัวสร้างเลขสุ่มของภาษา Python ซึ่ง R สร้างซ้ำให้ตรงทุกหลักไม่ได้ การทวนสอบจึงใช้การแบ่งตามเวลา (ไม่มีการสุ่ม) และแบบจำลองที่ไม่มีการสุ่ม คือ Logistic Regression และ Elastic Net (Logistic) ซึ่ง R ประมาณได้ด้วยสมการเดียวกัน (glmnet: lambda = 1/(C·n)) ค่าจาก Random Forest และ XGBoost รายงานตามที่ DAPH คำนวณโดยไม่ได้เทียบ ส่วนช่วงเชื่อมั่นแบบ bootstrap เทียบได้ภายในความคลาดเคลื่อนจากการสุ่ม เพราะ R และ DAPH สุ่มผู้ป่วยต่างชุดกัน
Verification design. A random split, Random Forest and XGBoost depend on Python's random-number streams, which R cannot reproduce digit for digit. The check therefore uses the temporal split (no randomness) and the two deterministic models, Logistic Regression and Elastic Net (Logistic), which R fits with the same objective (glmnet with lambda = 1/(C·n)). Random Forest and XGBoost figures are reported as DAPH computes them and are not compared. Bootstrap CIs are compared within Monte-Carlo error, because R and DAPH draw different resamples.
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(glmnet); library(pROC)
# 1) Temporal split as DAPH does it: sort by enrolment date (ties keep the file order),
# the first round(0.7 * n) patients = training set, the rest = test set
d$enroll <- as.Date(substr(d$enroll_date, 1, 10))
d <- d[order(d$enroll, seq_len(nrow(d))), ]
n_tr <- round(0.7 * nrow(d)); tr <- d[1:n_tr, ]; te <- d[(n_tr + 1):nrow(d), ]
cat("train", nrow(tr), format(range(tr$enroll)), "| test", nrow(te), format(range(te$enroll)), "\n")
cat("deaths: train", sum(tr$status), "test", sum(te$status), "| follow-up ends", max(substr(d$end_date, 1, 10)), "\n")
# 2) DAPH preprocessing: numeric predictors standardised with the TRAINING mean and population SD;
# every level of a categorical predictor becomes its own 0/1 column (one-hot, all levels)
num <- c("age", "bmi", "qolscore1"); cat_v <- c("gender", "chronic", "group")
mu <- sapply(tr[num], mean); s <- sapply(tr[num], function(x) sqrt(mean((x - mean(x))^2)))
design <- function(D) {
Z <- sweep(sweep(as.matrix(D[num]), 2, mu), 2, s, "/")
for (v in cat_v) for (l in sort(unique(tr[[v]]))) {
Z <- cbind(Z, as.numeric(D[[v]] == l)); colnames(Z)[ncol(Z)] <- paste0(v, "_", l) }
Z
}
Xtr <- design(tr); Xte <- design(te); ytr <- tr$status; yte <- te$status
# 3) DAPH "Logistic Regression" = ridge (L2) penalty with C = 1 -> glmnet alpha = 0, lambda = 1/(C n)
# DAPH "Elastic Net (Logistic)" = l1_ratio 0.5 with C = 1 -> glmnet alpha = 0.5, lambda = 1/(C n)
fit_lr <- glmnet(Xtr, ytr, family = "binomial", alpha = 0, lambda = 1 / n_tr, standardize = FALSE, thresh = 1e-14)
fit_en <- glmnet(Xtr, ytr, family = "binomial", alpha = 0.5, lambda = 1 / n_tr, standardize = FALSE, thresh = 1e-14)
p_lr <- as.vector(predict(fit_lr, Xte, type = "response"))
p_en <- as.vector(predict(fit_en, Xte, type = "response"))
print(round(coef(fit_lr)[, 1], 4))
# 4) Test-set metrics, defined as in DAPH
youden <- function(y, p) { # Youden's J on these data; the highest cut-off among ties
t <- sort(unique(p), decreasing = TRUE)
t[which.max(sapply(t, function(c) mean(p[y == 1] >= c) - mean(p[y == 0] >= c)))]
}
auc_mw <- function(y, p) { r <- rank(p); n1 <- sum(y); n0 <- length(y) - n1
(sum(r[y == 1]) - n1 * (n1 + 1) / 2) / (n1 * n0) }
metrics <- function(y, p, thr) {
pos <- p >= thr; TP <- sum(pos & y == 1); FP <- sum(pos & y == 0)
FN <- sum(!pos & y == 1); TN <- sum(!pos & y == 0)
nb <- function(pt) mean(y == 1 & p >= pt) - mean(y == 0 & p >= pt) * pt / (1 - pt)
c(AUC = auc_mw(y, p), Brier = mean((y - p)^2), Sens = TP / (TP + FN), Spec = TN / (TN + FP),
PPV = TP / (TP + FP), NPV = TN / (TN + FN), F1 = 2 * TP / (2 * TP + FP + FN),
NB_0.2 = nb(0.2), NB_0.5 = nb(0.5),
MCC = (TP * TN - FP * FN) / sqrt((TP + FP) * (TP + FN) * (TN + FP) * (TN + FN)),
LogLoss = -mean(y * log(p) + (1 - y) * log(1 - p)), Accuracy = mean(pos == (y == 1)),
BalAcc = (TP / (TP + FN) + TN / (TN + FP)) / 2)
}
thr_lr <- youden(yte, p_lr); thr_en <- youden(yte, p_en)
cat("Youden cut-off chosen on the test set: Logistic", round(thr_lr, 4), "| Elastic Net", round(thr_en, 4), "\n")
print(round(rbind(Logistic = metrics(yte, p_lr, thr_lr), ElasticNet = metrics(yte, p_en, thr_en)), 4))
cat("test death rate", round(mean(yte), 4), "| Brier of predicting that rate for everyone",
round(mean(yte) * (1 - mean(yte)), 4), "\n")
g <- glm(status ~ age + bmi + qolscore1 + factor(gender) + factor(chronic) + factor(group), binomial, tr)
cat("unpenalised glm for comparison: AUC", round(auc_mw(yte, predict(g, te, type = "response")), 4), "\n")
# 5) DeLong test (paired, same 390 test patients): Elastic Net vs Logistic
cat("DeLong p =", roc.test(roc(yte, p_lr, direction = "<", quiet = TRUE),
roc(yte, p_en, direction = "<", quiet = TRUE), method = "delong")$p.value, "\n")
# 6) Bootstrap 95% CI: 1,000 resamples of the test patients, predictions fixed, 2.5th/97.5th percentiles
set.seed(12345)
B <- t(replicate(1000, { i <- sample.int(length(yte), replace = TRUE)
c(AUC = auc_mw(yte[i], p_lr[i]), Brier = mean((yte[i] - p_lr[i])^2)) }))
print(round(apply(B, 2, quantile, c(0.025, 0.975)), 4))
# 7) Minimum sample size: Riley et al. (2020) criteria 1-3, computed by DAPH on the training set
phi <- mean(ytr); P <- 6 # 3 numeric predictors + 3 two-level predictors (levels - 1 each)
maxR2 <- 1 - exp(2 * (phi * log(phi) + (1 - phi) * log(1 - phi)))
R2cs <- round(0.15 * maxR2, 3) # anticipated Nagelkerke R2 0.15, rounded as pmsampsize does
S2 <- R2cs / (R2cs + 0.05 * maxR2)
n_crit <- ceiling(c(P / ((0.9 - 1) * log(1 - R2cs / 0.9)), P / ((S2 - 1) * log(1 - R2cs / S2)),
(1.96 / 0.05)^2 * phi * (1 - phi)))
cat("prevalence", round(phi, 4), "| R2cs", R2cs, "| criteria", n_crit, "| minimum n", max(n_crit), "\n")
train 910 2022-01-01 2023-01-23 | test 390 2023-01-25 2023-06-29
deaths: train 169 test 60 | follow-up ends 2024-12-31
(Intercept) age bmi qolscore1 gender_1 gender_2
-1.6574 0.2673 -0.1001 -0.2925 -0.1261 0.1261
chronic_0 chronic_1 group_1 group_2
-0.2472 0.2472 -0.3864 0.3864
Youden cut-off chosen on the test set: Logistic 0.1306 | Elastic Net 0.1533
AUC Brier Sens Spec PPV NPV F1 NB_0.2 NB_0.5
Logistic 0.6337 0.1249 0.8167 0.3818 0.1937 0.9197 0.3131 0 0.0026
ElasticNet 0.6341 0.1248 0.7167 0.4818 0.2009 0.9034 0.3139 0 0.0051
MCC LogLoss Accuracy BalAcc
Logistic 0.1500 0.4129 0.4487 0.5992
ElasticNet 0.1439 0.4127 0.5179 0.5992
test death rate 0.1538 | Brier of predicting that rate for everyone 0.1302
unpenalised glm for comparison: AUC 0.6344
DeLong p = 0.636603
AUC Brier
2.5% 0.5558 0.1062
97.5% 0.7134 0.1463
prevalence 0.1857 | R2cs 0.093 | criteria 551 183 233 | minimum n 551
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| ชุดฝึก: n · ช่วงวันที่เข้าโครงการ · จำนวนเสียชีวิตTraining set: n · enrolment dates · deaths | 910 · 2022-01-01 to 2023-01-23 · 169 | 910 · 2022-01-01 to 2023-01-23 · 169 | 0 | ✓ PASS |
| ชุดทดสอบ: n · ช่วงวันที่ · สัดส่วนเสียชีวิตTest set: n · dates · death rate | 390 · 2023-01-25 to 2023-06-29 · 0.1538 | 390 · 2023-01-25 to 2023-06-29 · 0.1538 | 0 | ✓ PASS |
| Logistic: AUC / BrierLogistic: AUC / Brier | 0.6337 / 0.1249 | 0.6337 / 0.1249 | < 0.000001 | ✓ PASS |
| Logistic: จุดตัด Youden บนชุดทดสอบLogistic: Youden cut-off on the test set | 0.1306 | 0.1306 | < 0.00001 | ✓ PASS |
| Logistic: Sens / Spec ที่จุดตัดLogistic: Sens / Spec at the cut-off | 0.8167 / 0.3818 | 0.8167 / 0.3818 | 0 | ✓ PASS |
| Logistic: PPV / NPV / F1Logistic: PPV / NPV / F1 | 0.1937 / 0.9197 / 0.3131 | 0.1937 / 0.9197 / 0.3131 | 0 | ✓ PASS |
| Logistic: MCC / accuracy / balanced accuracy (Tab 3)Logistic: MCC / accuracy / balanced accuracy (Tab 3) | 0.1500 / 0.4487 / 0.5992 | 0.150 / 0.449 / 0.599 | < 0.0005 | ✓ PASS |
| Logistic: log-loss / NB(0.2) / NB(0.5)Logistic: log-loss / NB(0.2) / NB(0.5) | 0.4129 / 0 / 0.0026 | 0.413 / 0.000 / 0.0026 | < 0.0005 | ✓ PASS |
| Elastic Net: AUC / BrierElastic Net: AUC / Brier | 0.6341 / 0.1248 | 0.6341 / 0.1248 | < 0.000001 | ✓ PASS |
| Elastic Net: จุดตัด / Sens / SpecElastic Net: cut-off / Sens / Spec | 0.1533 / 0.7167 / 0.4818 | 0.1533 / 0.7167 / 0.4818 | < 0.00001 / 0 / 0 | ✓ PASS |
| Elastic Net: PPV / NPV / F1 / MCCElastic Net: PPV / NPV / F1 / MCC | 0.2009 / 0.9034 / 0.3139 / 0.1439 | 0.2009 / 0.9034 / 0.3139 / 0.144 | < 0.0005 | ✓ PASS |
| Elastic Net: log-loss / accuracy / balanced accuracy / NB(0.5)Elastic Net: log-loss / accuracy / balanced accuracy / NB(0.5) | 0.4127 / 0.5179 / 0.5992 / 0.0051 | 0.413 / 0.518 / 0.599 / 0.0051 | < 0.0005 | ✓ PASS |
| DeLong p: Elastic Net เทียบกับ LogisticDeLong p: Elastic Net vs Logistic | 0.6366 | 0.6366 | < 0.000001 | ✓ PASS |
| Logistic: 95% CI ของ AUC (bootstrap)*Logistic: AUC 95% CI (bootstrap)* | 0.5558 to 0.7134 | 0.5521 to 0.7100 | 0.0037 (≤ 0.015) | ✓ PASS |
| Logistic: 95% CI ของ Brier (bootstrap)*Logistic: Brier 95% CI (bootstrap)* | 0.1062 to 0.1463 | 0.1035 to 0.1472 | 0.0027 (≤ 0.005) | ✓ PASS |
| ขนาดตัวอย่างขั้นต่ำ (Riley): สัดส่วนเสียชีวิตในชุดฝึก · R²CS · เกณฑ์ 1/2/3 · n ขั้นต่ำMinimum sample size (Riley): training death rate · R²CS · criteria 1/2/3 · minimum n | 0.1857 · 0.093 · 551/183/233 · 551 | 0.1857 · 0.093 · 551/183/233 · 551 | 0 | ✓ PASS |
| Random Forest / XGBoost: AUC (95% CI) · Brier · DeLong p เทียบกับ LogisticRandom Forest / XGBoost: AUC (95% CI) · Brier · DeLong p vs Logistic | — | 0.637 (0.555 to 0.711) · 0.136 · 0.926 / 0.597 (0.517 to 0.670) · 0.159 · 0.345 | — | ไม่ได้เทียบ (เลขสุ่มของ Python)not compared (Python random numbers) |
ผลการทวนสอบ · ทุกค่าของ Logistic Regression และ Elastic Net (Logistic) ตรงกับ R รวมทั้งจุดตัด Youden ค่าที่จุดตัด และ DeLong p เพราะ DAPH ฟิตทั้งสองแบบจำลองจนถึงค่าที่ดีที่สุดของสมการในส่วนที่ 2 · * R และ DAPH สุ่มผู้ป่วยต่างชุดกัน จึงยอมรับความต่างจากการสุ่ม (0.015 สำหรับ AUC และ 0.005 สำหรับ Brier) และเมื่อนำดัชนีการสุ่มชุดเดียวกับของ DAPH มาคำนวณใน R จะได้ช่วงเชื่อมั่นตรงกันทุกหลัก
Verification result. Every Logistic Regression and Elastic Net (Logistic) value agrees with R, including the Youden cut-offs, the values at them and the DeLong p, because DAPH fits both models to the optimum of the objective in part 2. * R and DAPH draw different resamples, so a Monte-Carlo tolerance applies (0.015 for AUC, 0.005 for Brier); recomputed in R with DAPH's own resample indices, the CIs agree to every digit.
4การแปลผลและตัวอย่างInterpretation and Example
การจำแนก (discrimination) · AUC ของ Logistic Regression บนผู้ป่วยชุดหลัง 390 ราย เท่ากับ 0.634 (95% CI 0.552 ถึง 0.710) แปลว่าถ้าสุ่มผู้เสียชีวิต 1 รายกับผู้รอดชีวิต 1 ราย แบบจำลองจะให้ความเสี่ยงแก่ผู้เสียชีวิตสูงกว่าประมาณ 63% ของคู่ ช่วงเชื่อมั่นไม่คร่อม 0.5 จึงดีกว่าการสุ่ม แต่ต่ำกว่า 0.70 จึงไม่พอสำหรับการทำนายรายบุคคล · Random Forest ได้ 0.637 ซึ่งไม่ต่างจาก Logistic (DeLong p = 0.926) และ XGBoost ได้ต่ำกว่า (0.597) ป้าย “ดีที่สุด” ของ Random Forest ในรอบนี้มาจากชุดทดสอบที่ทั้งเลือกและรายงานเพราะปิด cross-validation ไว้ ความต่างระดับ 0.003 จึงไม่มีความหมาย
Discrimination. On the 390 later patients the Logistic Regression AUC is 0.634 (95% CI 0.552 to 0.710): for a random pair of one patient who died and one who survived, the model gives the higher risk to the one who died in about 63% of pairs. The CI excludes 0.5, so the model is better than chance, but it is below 0.70 and too weak for individual prediction. Random Forest reaches 0.637, not different from Logistic (DeLong p = 0.926), and XGBoost is lower (0.597). Random Forest is labelled "best" only because the test set both chose and reported the winner (cross-validation was off), so a 0.003 difference means nothing.
ความเสี่ยงที่ทำนายและจุดตัด · Brier score ของ Logistic เท่ากับ 0.125 เทียบกับ 0.130 ถ้าทำนายความเสี่ยงเท่ากับสัดส่วนเสียชีวิตของชุดทดสอบ (15.4%) ให้ทุกคน จึงดีขึ้นเพียงเล็กน้อย ส่วน Random Forest (0.136) แย่กว่าการทำนายด้วยสัดส่วนเฉย ๆ · ที่จุดตัด Youden 0.131 (ค่าที่ถูกต้องจาก R) แบบจำลองจับผู้เสียชีวิตได้ 81.7% แต่ระบุผู้รอดชีวิตว่าเสี่ยงต่ำได้เพียง 38.2% และในผู้ที่ถูกจัดว่าเสี่ยงสูง เสียชีวิตจริงเพียง 19.4% (PPV) จุดตัดนี้เลือกจากชุดทดสอบเอง ค่าจึงดีเกินจริงอยู่แล้ว · net benefit ที่ threshold 0.2 เท่ากับ 0 คือไม่ดีกว่าการไม่รักษาใครเลย
Predicted risks and the cut-off. The Logistic Brier score is 0.125 against 0.130 for giving everyone the test-set death rate (15.4%), only slightly better; Random Forest (0.136) is worse than the rate alone. At the Youden cut-off of 0.131 (the correct value, from R) the model flags 81.7% of the patients who died but classes only 38.2% of survivors as low risk, and only 19.4% of those flagged actually died (PPV). The cut-off was chosen on the test set itself, so these values are already optimistic. The net benefit at threshold 0.2 is 0: no better than treating no one.
ข้อจำกัดของตัวอย่างนี้ · Study Status คือการเสียชีวิตก่อนสิ้นสุดการติดตาม (2024-12-31) ผู้ที่เข้าโครงการทีหลังจึงมีเวลาเสี่ยงสั้นกว่า สัดส่วนเสียชีวิตในชุดทดสอบ (15.4%) จึงต่ำกว่าชุดฝึก (169/910 = 18.6%) แบบจำลองจำแนกที่ไม่คิดเวลาติดตามผสมความเสี่ยงกับความยาวของการติดตามเข้าด้วยกัน สำหรับคำถามนี้ Cox regression (หัวข้อ 5.2) เหมาะกว่า · ตัวอย่างตั้งค่าความไม่สมดุลกลุ่มเป็น “ไม่ปรับ” เพราะค่าเริ่มต้น Auto-SMOTE จะทำงาน (อัตราส่วนในชุดฝึก 169 : 741 = 0.23) ซึ่งทำให้ความเสี่ยงที่ทำนายสูงเกินจริงโดย AUC ไม่ดีขึ้น (van den Goorbergh et al. 2022) และเพิ่มการสุ่มที่ทำซ้ำใน R ไม่ได้
Limitations of this example. Study Status means death before the end of follow-up (2024-12-31), so patients enrolled later had less time at risk; the test-set death rate (15.4%) is lower than in the training set (169/910 = 18.6%). A classifier that ignores follow-up time mixes risk with length of follow-up; for this question Cox regression (5.2) is the better tool. Class imbalance was set to None because the default Auto-SMOTE would have run (training ratio 169 : 741 = 0.23): it inflates the predicted risks without improving the AUC (van den Goorbergh et al. 2022) and adds randomness that R cannot reproduce.
ตัวอย่างการเขียนรายงาน · “ในการตรวจสอบตามเวลา (ผู้ป่วย 390 ราย เสียชีวิต 60 ราย) แบบจำลอง logistic regression แบบ ridge มี AUC 0.634 (95% CI 0.552 ถึง 0.710) และ Brier score 0.125 ส่วน random forest (AUC 0.637, 95% CI 0.555 ถึง 0.711; DeLong p = 0.926) และ XGBoost (AUC 0.597) ไม่ได้จำแนกดีกว่า แบบจำลองทั้งหมดจำแนกได้ต่ำและไม่ควรนำไปใช้ทำนายรายบุคคล”
Model results sentence. "In temporal validation (390 patients, 60 deaths), the ridge logistic regression model had an AUC of 0.634 (95% CI 0.552 to 0.710) and a Brier score of 0.125; random forest (AUC 0.637, 95% CI 0.555 to 0.711; DeLong p = 0.926) and XGBoost (AUC 0.597) did not discriminate better. All models discriminated poorly and should not be used for individual prediction."
📖 References
- Breiman, L. (2001). Random forests. Machine Learning, 45(1), 5–32. doi:10.1023/A:1010933404324
- Chen, T., & Guestrin, C. (2016). XGBoost: A scalable tree boosting system. Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD '16), 785–794. doi:10.1145/2939672.2939785
- Collins, G. S., Moons, K. G. M., Dhiman, P., Riley, R. D., Beam, A. L., Van Calster, B., et al. (2024). TRIPOD+AI statement: Updated guidance for reporting clinical prediction models that use regression or machine learning methods. BMJ, 385, e078378. doi:10.1136/bmj-2023-078378
- Cortes, C., & Vapnik, V. (1995). Support-vector networks. Machine Learning, 20(3), 273–297. doi:10.1007/BF00994018
- DeLong, E. R., DeLong, D. M., & Clarke-Pearson, D. L. (1988). Comparing the areas under two or more correlated receiver operating characteristic curves: A nonparametric approach. Biometrics, 44(3), 837–845. doi:10.2307/2531595
- Lundberg, S. M., & Lee, S.-I. (2017). A unified approach to interpreting model predictions. Advances in Neural Information Processing Systems (NeurIPS), 30, 4765–4774.
- Riley, R. D., Ensor, J., Snell, K. I. E., Harrell, F. E., Jr., Martin, G. P., Reitsma, J. B., et al. (2020). Calculating the sample size required for developing a clinical prediction model. BMJ, 368, m441. doi:10.1136/bmj.m441
- van den Goorbergh, R., van Smeden, M., Timmerman, D., & Van Calster, B. (2022). The harm of class imbalance corrections for risk prediction models: Illustration and simulation using logistic regression. Journal of the American Medical Informatics Association, 29(9), 1525–1534. doi:10.1093/jamia/ocac093
- Vickers, A. J., & Elkin, E. B. (2006). Decision curve analysis: A novel method for evaluating prediction models. Medical Decision Making, 26(6), 565–574. doi:10.1177/0272989X06295361
- Youden, W. J. (1950). Index for rating diagnostic tests. Cancer, 3(1), 32–35. doi:10.1002/1097-0142(1950)3:1<32::AID-CNCR2820030106>3.0.CO;2-3
- Zou, H., & Hastie, T. (2005). Regularization and variable selection via the elastic net. Journal of the Royal Statistical Society: Series B, 67(2), 301–320. doi:10.1111/j.1467-9868.2005.00503.x
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
7.2Multiclass Classification (≥3 unordered categories)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Multiclass คือ Machine Learning Comparison เมื่อผลลัพธ์มีตั้งแต่ 3 กลุ่มขึ้นไปที่ไม่มีลำดับ (เช่น โรงพยาบาลที่รักษา ชนิดเชื้อก่อโรค) DAPH วิเคราะห์แบบ multiclass เมื่อพจนานุกรมข้อมูลกำหนดตัวแปรผลลัพธ์เป็นตัวแปรกลุ่ม (nominal หรือ ordinal) ที่มีตั้งแต่ 3 ระดับ หรือเมื่อไม่ได้กำหนดชนิดแต่มีรหัส 3 ถึง 15 ค่าที่เป็นจำนวนเต็มหรือข้อความ (ตัวแปรที่กำหนดเป็นตัวเลข integer หรือ real จะวิเคราะห์แบบ regression) แต่ละแบบจำลองประมาณความน่าจะเป็นของทุกกลุ่มสำหรับผู้ป่วยแต่ละราย แล้วทำนายว่าอยู่กลุ่มที่มีความน่าจะเป็นสูงสุด · แบบจำลองที่ใช้ได้เหมือนหัวข้อ 7.1 ยกเว้น Naive Bayes (ใช้ได้เฉพาะผลลัพธ์ 2 กลุ่ม) · Logistic Regression ในกรณีนี้คือ multinomial (softmax) logistic regression ที่มีบทลงโทษแบบ ridge ค่า C = 1 และ Elastic Net (Logistic) คือแบบ multinomial ที่ใช้บทลงโทษ elastic net
Multiclass is Machine Learning Comparison when the outcome has three or more unordered categories (e.g. treating hospital, pathogen type). DAPH uses multiclass when the data dictionary declares the outcome a group variable (nominal or ordinal) with three or more categories, or, without a declared type, when it has 3 to 15 whole-number or text codes (an outcome declared as a number, integer or real, is analysed by regression). Each model estimates the probability of every category for each patient and predicts the category with the highest probability. The models are those of 7.1 except Naive Bayes (binary outcomes only); Logistic Regression here is a multinomial (softmax) logistic regression with a ridge penalty, C = 1, and Elastic Net (Logistic) is its elastic-net-penalised version.
สิ่งที่ DAPH รายงาน · บนชุดทดสอบ: macro-AUC แบบ one-vs-rest, macro-F1 และ accuracy พร้อมช่วงเชื่อมั่น 95% จาก bootstrap · Tab 3 แสดง Cohen's κ (Cohen 1960), balanced accuracy และ log-loss เพิ่ม (ไม่มีช่วงเชื่อมั่น) · รายงาน Word มีกราฟเปรียบเทียบ macro-AUC, confusion matrix ของแบบจำลองที่ดีที่สุด และกราฟ SHAP ซึ่งในกรณี multiclass อธิบายความน่าจะเป็นของกลุ่มแรก (รหัสต่ำสุด) เท่านั้น · ไม่มี DeLong test ไม่มีจุดตัด และไม่มี decision curve สำหรับผลลัพธ์หลายกลุ่ม
What DAPH reports. On the test set: one-vs-rest macro-AUC, macro-F1 and accuracy with bootstrap 95% CIs. Tab 3 adds Cohen's κ (Cohen 1960), balanced accuracy and log-loss (no CIs). The Word report shows a macro-AUC comparison chart, the confusion matrix of the best model and a SHAP chart, which for a multiclass outcome explains the probability of the first category (the lowest code) only. There is no DeLong test, no cut-off and no decision curve for a multi-category outcome.
ใช้เมื่อ ต้องการทำนายว่าผู้ป่วยอยู่กลุ่มใดในหลายกลุ่มที่ไม่มีลำดับ · ไม่ควรใช้ เมื่อกลุ่มมีลำดับ (ใช้ Ordered Logistic Regression หัวข้อ 3.1) หรือเมื่อต้องการประมาณขนาดความสัมพันธ์ของปัจจัยกับแต่ละกลุ่ม (ใช้ Multinomial Logistic Regression หัวข้อ 3.2 ซึ่งรายงาน relative risk ratio)
Use it when you want to predict which of several unordered categories a patient belongs to. Do not use it when the categories are ordered (use Ordered Logistic Regression, 3.1) or when you want to estimate how a factor relates to each category (use Multinomial Logistic Regression, 3.2, which reports relative risk ratios).
2หลักการและสูตรLogic and Formula
Elastic Net (Logistic) ใช้บทลงโทษ ρ Σ|β| + (1 − ρ)/2 Σβ² กับทุกสัมประสิทธิ์ (ρ = 0.5) แทน ½Σβ²
Elastic Net (Logistic) replaces ½Σβ² by ρ Σ|β| + (1 − ρ)/2 Σβ² over all coefficients (ρ = 0.5).
- K, p̂_ik
- จำนวนกลุ่ม · ความน่าจะเป็นที่แบบจำลองให้ผู้ป่วย i อยู่กลุ่ม knumber of categories; the model's probability that patient i belongs to category k
- TP_k, FP_k, FN_k
- ทายเป็นกลุ่ม k และใช่ · ทายเป็นกลุ่ม k แต่ไม่ใช่ · เป็นกลุ่ม k แต่ทายเป็นกลุ่มอื่น (ถ้าไม่เคยทายกลุ่ม k เลย F1,k = 0)predicted k and truly k; predicted k but not k; truly k but predicted otherwise (a category never predicted gets F1,k = 0)
- n_kk, n_k+, n_+k
- จำนวนในเซลล์ทแยงของ confusion matrix · ผลรวมแถว k (กลุ่มจริง) · ผลรวมคอลัมน์ k (กลุ่มที่ทาย)diagonal cell of the confusion matrix; row k total (true category); column k total (predicted category)
จุดที่ต้องรู้ · macro-AUC ของ DAPH เป็นค่าเฉลี่ยแบบไม่ถ่วงน้ำหนักของ AUC แบบหนึ่งกลุ่มเทียบกับกลุ่มที่เหลือ (one-vs-rest; Fawcett 2006) ไม่ใช่ค่าเฉลี่ยของทุกคู่กลุ่ม (one-vs-one) ของ Hand & Till (2001) เมื่อขนาดกลุ่มต่างกันมากสองค่านี้ไม่เท่ากัน · การเฉลี่ยแบบ macro ให้ทุกกลุ่มมีน้ำหนักเท่ากัน กลุ่มเล็กที่ทายไม่ถูกเลยจึงดึงค่าลง (Sokolova & Lapalme 2009) ส่วน accuracy ถูกกลุ่มใหญ่ครอบงำ จึงต้องเทียบกับสัดส่วนของกลุ่มใหญ่ที่สุดเสมอ · การแบ่งข้อมูล การเตรียมข้อมูล การจัดการความไม่สมดุล การเลือกแบบจำลองที่ดีที่สุด และ bootstrap 1,000 รอบบนชุดทดสอบ เหมือนหัวข้อ 7.1 (macro-AUC แทน AUC)
Points to know. DAPH's macro-AUC is the unweighted mean of one-vs-rest AUCs (Fawcett 2006), not the mean over all pairs of categories (one-vs-one) of Hand & Till (2001); with unequal category sizes the two differ. Macro averaging gives every category the same weight, so small categories that are never predicted pull it down (Sokolova & Lapalme 2009), whereas accuracy is dominated by the largest category and must always be compared with that category's share. The split, preprocessing, imbalance handling, choice of the best model and the 1,000-resample bootstrap on the test set are as in 7.1 (with macro-AUC in place of AUC).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
ออกแบบการทวนสอบ · ใช้การแบ่งตามเวลาและแบบจำลองที่ไม่มีการสุ่ม (multinomial Logistic Regression และ Elastic Net ด้วย glmnet ซึ่งใช้สมการเดียวกัน lambda = 1/(C·n)) ส่วน Random Forest ไม่ได้เทียบเพราะใช้เลขสุ่มของ Python ค่า DAPH มาจาก Tab 3 รายงาน Word และค่าภายในที่ทศนิยมเต็ม
Verification design. The temporal split and the deterministic models (multinomial Logistic Regression and Elastic Net, fitted in R by glmnet with the same objective, lambda = 1/(C·n)) are compared; Random Forest is not, because it uses Python's random numbers. DAPH values come from Tab 3, the Word report and the engine's full-precision values.
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(glmnet)
d <- d[!is.na(d$hos), ] # outcome must be present (3 rows dropped)
d$enroll <- as.Date(substr(d$enroll_date, 1, 10))
d <- d[order(d$enroll, seq_len(nrow(d))), ]
n_tr <- round(0.7 * nrow(d)); tr <- d[1:n_tr, ]; te <- d[(n_tr + 1):nrow(d), ]
cat("n =", nrow(d), "| train", n_tr, "| test", nrow(te), "\n"); print(table(test_hospital = te$hos))
num <- c("age", "bmi", "qolscore1")
cat_v <- c("gender", "chronic", "group", "income", "fam_income", "occupation", "amp")
mu <- sapply(tr[num], mean); s <- sapply(tr[num], function(x) sqrt(mean((x - mean(x))^2)))
design <- function(D) {
Z <- sweep(sweep(as.matrix(D[num]), 2, mu), 2, s, "/")
for (v in cat_v) for (l in sort(unique(tr[[v]]))) Z <- cbind(Z, as.numeric(D[[v]] == l))
Z
}
Xtr <- design(tr); Xte <- design(te); ytr <- factor(tr$hos); yte <- factor(te$hos, levels(ytr))
cat("encoded predictor columns:", ncol(Xtr), "\n")
# DAPH "Logistic Regression" for K classes = multinomial (softmax) model, L2 penalty C = 1
fit_lr <- glmnet(Xtr, ytr, family = "multinomial", alpha = 0, lambda = 1 / n_tr,
standardize = FALSE, thresh = 1e-14)
fit_en <- glmnet(Xtr, ytr, family = "multinomial", alpha = 0.5, lambda = 1 / n_tr,
standardize = FALSE, thresh = 1e-14, type.multinomial = "ungrouped")
P_lr <- predict(fit_lr, Xte, type = "response")[, , 1]
P_en <- predict(fit_en, Xte, type = "response")[, , 1]
auc_mw <- function(y, p) { r <- rank(p); n1 <- sum(y); n0 <- length(y) - n1
(sum(r[y == 1]) - n1 * (n1 + 1) / 2) / (n1 * n0) }
mc_metrics <- function(y, P) {
K <- levels(y); pred <- factor(K[max.col(P, ties.method = "first")], K)
cm <- table(y, pred); tp <- diag(cm); fp <- colSums(cm) - tp; fn <- rowSums(cm) - tp
po <- sum(tp) / sum(cm); pe <- sum(rowSums(cm) * colSums(cm)) / sum(cm)^2
c(macroAUC = mean(sapply(seq_along(K), function(k) auc_mw(as.numeric(y == K[k]), P[, k]))),
macroF1 = mean(2 * tp / (2 * tp + fp + fn)), Accuracy = po,
Kappa = (po - pe) / (1 - pe), BalAcc = mean(tp / rowSums(cm)),
LogLoss = -mean(log(P[cbind(seq_along(y), as.integer(y))])))
}
print(round(rbind(Logistic = mc_metrics(yte, P_lr), ElasticNet = mc_metrics(yte, P_en)), 4))
p0 <- prop.table(table(ytr)) # reference: no information about the patient
cat("largest hospital's share of the test set", round(max(prop.table(table(yte))), 4),
"| log-loss of predicting the training shares for everyone", round(-mean(log(p0[as.integer(yte)])), 4), "\n")
print(table(observed = yte, predicted = factor(levels(ytr)[max.col(P_lr, "first")], levels(ytr))))
set.seed(12345)
B <- t(replicate(1000, { i <- sample.int(length(yte), replace = TRUE); mc_metrics(yte[i], P_lr[i, ])[1:3] }))
print(round(apply(B, 2, quantile, c(0.025, 0.975)), 4))
n = 1297 | train 908 | test 389
test_hospital
1 2 3 4 5 6 7
42 16 89 23 10 27 182
encoded predictor columns: 27
macroAUC macroF1 Accuracy Kappa BalAcc LogLoss
Logistic 0.4792 0.0988 0.4473 -0.0118 0.1399 1.5778
ElasticNet 0.4760 0.0970 0.4499 -0.0116 0.1398 1.5683
largest hospital's share of the test set 0.4679 | log-loss of predicting the training shares for everyone 1.5329
predicted
observed 1 2 3 4 5 6 7
1 0 0 0 0 0 0 42
2 0 0 0 0 0 0 16
3 0 0 4 0 0 0 85
4 0 0 2 0 0 0 21
5 0 0 2 0 0 0 8
6 0 0 3 0 0 0 24
7 0 0 12 0 0 0 170
macroAUC macroF1 Accuracy
2.5% 0.4323 0.0875 0.4010
97.5% 0.5292 0.1110 0.4936
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| ชนิดของผลลัพธ์ (Hospital, 7 กลุ่ม)Outcome type (Hospital, 7 categories) | multiclass | multiclass | — | ✓ PASS |
| n ที่ใช้ · ชุดฝึก · ชุดทดสอบn used · training · test | 1297 · 908 · 389 | 1297 · 908 · 389 | 0 | ✓ PASS |
| Logistic: macro-AUC / macro-F1 / accuracyLogistic: macro-AUC / macro-F1 / accuracy | 0.4792 / 0.0988 / 0.4473 | 0.4792 / 0.0988 / 0.4473 | < 0.000001 | ✓ PASS |
| Logistic: κ / balanced accuracy / log-loss (Tab 3)Logistic: κ / balanced accuracy / log-loss (Tab 3) | −0.0118 / 0.1399 / 1.5778 | −0.012 / 0.140 / 1.578 | < 0.0005 | ✓ PASS |
| Logistic: 95% CI ของ macro-AUC (bootstrap)*Logistic: macro-AUC 95% CI (bootstrap)* | 0.4323 to 0.5292 | 0.4339 to 0.5267 | 0.0025 (≤ 0.015) | ✓ PASS |
| Elastic Net: macro-AUC / macro-F1 / accuracyElastic Net: macro-AUC / macro-F1 / accuracy | 0.4760 / 0.0970 / 0.4499 | 0.4760 / 0.0970 / 0.4499 | < 0.000001 | ✓ PASS |
| Elastic Net: κ / balanced accuracy / log-loss (Tab 3)Elastic Net: κ / balanced accuracy / log-loss (Tab 3) | −0.0116 / 0.1398 / 1.5683 | −0.012 / 0.140 / 1.568 | < 0.0005 | ✓ PASS |
| Random Forest: macro-AUC (95% CI) · macro-F1 · accuracyRandom Forest: macro-AUC (95% CI) · macro-F1 · accuracy | — | 0.486 (0.445 to 0.533) · 0.110 · 0.391 | — | ไม่ได้เทียบ (เลขสุ่มของ Python)not compared (Python random numbers) |
ผลการทวนสอบ · ทุกตัวชี้วัดของ multinomial Logistic Regression และ Elastic Net ตรงกับ R ทุกหลักที่แสดง · * R และ DAPH สุ่มผู้ป่วยต่างชุดกัน จึงยอมรับความต่างจากการสุ่ม · รายงาน Word ของ DAPH ระบุ Random Forest เป็นแบบจำลองที่ดีที่สุด (macro-AUC 0.486, 95% CI 0.445 ถึง 0.533) และสรุปว่าไม่ควรนำไปใช้ เพราะช่วงเชื่อมั่นคร่อม 0.5
Verification result. Every multinomial Logistic Regression and Elastic Net metric agrees with R to the displayed digits. * R and DAPH draw different resamples, so a Monte-Carlo tolerance applies. DAPH's Word report names Random Forest the best model (macro-AUC 0.486, 95% CI 0.445 to 0.533) and concludes that it should not be used because the interval includes 0.5.
4การแปลผลและตัวอย่างInterpretation and Example
การจำแนก · macro-AUC 0.479 (95% CI 0.434 ถึง 0.527) คร่อม 0.5 แบบจำลองจึงแยกโรงพยาบาลไม่ได้ดีกว่าการสุ่ม ข้อมูลไม่แสดงหลักฐานว่าลักษณะผู้ป่วยที่วัดได้ต่างกันระหว่างโรงพยาบาล (ไม่ได้พิสูจน์ว่าไม่ต่างเลย เพราะตัวแปรที่ไม่ได้วัดอาจต่างกัน)
Discrimination. The macro-AUC of 0.479 (95% CI 0.434 to 0.527) includes 0.5, so the model separates the hospitals no better than chance. The data give no evidence that the measured patient characteristics differ between hospitals (this does not prove they are identical: unmeasured characteristics may differ).
ทำไม accuracy หลอกได้ · accuracy 0.447 ดูเหมือนพอใช้ แต่การทายว่าทุกคนรักษาที่โรงพยาบาลใหญ่ที่สุด (Srinakarin Hospital 182 จาก 389 ราย) ได้ 0.468 ซึ่งดีกว่า confusion matrix แสดงว่าแบบจำลองทายเกือบทุกคนเป็นโรงพยาบาลรหัส 7 และไม่เคยทาย 5 โรงพยาบาลที่เล็กกว่าเลย macro-F1 จึงเหลือ 0.099 และ balanced accuracy 0.140 ซึ่งเท่ากับระดับการสุ่ม (1/7 = 0.143) · κ = −0.012 คือไม่เห็นด้วยกับความจริงมากกว่าที่เกิดจากความบังเอิญ · log-loss ของแบบจำลอง (1.578) สูงกว่าการให้ทุกคนมีความน่าจะเป็นเท่ากับสัดส่วนของแต่ละโรงพยาบาลในชุดฝึก (1.533) แปลว่าตัวทำนายเพิ่มแต่สัญญาณรบกวน
Why accuracy misleads. An accuracy of 0.447 looks acceptable, but guessing the largest hospital (Srinakarin Hospital, 182 of 389 patients) for everyone scores 0.468, which is better. The confusion matrix shows that the model predicts code 7 for almost everyone and never predicts five smaller hospitals, so macro-F1 is only 0.099 and balanced accuracy 0.140, the chance level (1/7 = 0.143). κ = −0.012 means no agreement with the truth beyond chance. The model's log-loss (1.578) is higher than that of giving everyone the hospitals' training-set shares (1.533): the predictors add only noise.
ตัวอย่างการเขียนรายงาน · “ในการตรวจสอบตามเวลา (ผู้ป่วย 389 ราย) แบบจำลอง multinomial logistic regression ที่ใช้ลักษณะผู้ป่วย 10 ตัวแยกโรงพยาบาลทั้ง 7 แห่งไม่ได้ดีกว่าการสุ่ม (macro-AUC 0.479, 95% CI 0.434 ถึง 0.527; macro-F1 0.099; κ −0.012) ไม่พบหลักฐานว่าลักษณะผู้ป่วยที่วัดได้ต่างกันระหว่างโรงพยาบาล”
Model results sentence. "In temporal validation (389 patients), a multinomial logistic regression model using ten patient characteristics did not separate the seven hospitals better than chance (macro-AUC 0.479, 95% CI 0.434 to 0.527; macro-F1 0.099; κ −0.012), giving no evidence that measured patient characteristics differ between hospitals."
📖 References
- Cohen, J. (1960). A coefficient of agreement for nominal scales. Educational and Psychological Measurement, 20(1), 37–46. doi:10.1177/001316446002000104
- Fawcett, T. (2006). An introduction to ROC analysis. Pattern Recognition Letters, 27(8), 861–874. doi:10.1016/j.patrec.2005.10.010
- Hand, D. J., & Till, R. J. (2001). A simple generalisation of the area under the ROC curve for multiple class classification problems. Machine Learning, 45(2), 171–186. doi:10.1023/A:1010920819831
- Sokolova, M., & Lapalme, G. (2009). A systematic analysis of performance measures for classification tasks. Information Processing & Management, 45(4), 427–437. doi:10.1016/j.ipm.2009.03.002
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
7.3Continuous Regression (numeric outcome)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Regression คือ Machine Learning Comparison เมื่อผลลัพธ์เป็นตัวเลขต่อเนื่อง (DAPH ใช้แบบนี้เมื่อพจนานุกรมข้อมูลกำหนดผลลัพธ์เป็นตัวเลข integer หรือ real ที่มีมากกว่า 2 ค่า หรือเมื่อไม่ได้กำหนดชนิดและผลลัพธ์ไม่ใช่รหัส 3 ถึง 15 ค่า) เช่น คะแนนคุณภาพชีวิต ระดับน้ำตาลในเลือด ค่าใช้จ่าย · แบบจำลองที่เลือกไว้เป็นค่าเริ่มต้นมี 5 แบบ ได้แก่ Linear Regression (กำลังสองน้อยที่สุด ไม่มีบทลงโทษ เป็น baseline), Elastic Net (Zou & Hastie 2005; ส่วน L1 คือ lasso ของ Tibshirani 1996 และส่วน L2 คือ ridge ของ Hoerl & Kennard 1970), Random Forest (Breiman 2001), XGBoost (Chen & Guestrin 2016) และ LightGBM ส่วนที่เลือกเพิ่มได้ ได้แก่ SVR แบบ RBF kernel, MLP, Decision Tree และ KNN · DAPH ไม่มีแบบจำลอง Ridge หรือ Lasso แยกต่างหาก
Regression is Machine Learning Comparison when the outcome is a continuous number (DAPH uses it when the data dictionary declares the outcome a number, integer or real, with more than two values, or, without a declared type, when the outcome is not 3 to 15 codes), such as a quality-of-life score, blood glucose or cost. Five models are ticked by default: Linear Regression (ordinary least squares, no penalty, the baseline), Elastic Net (Zou & Hastie 2005; its L1 part is the lasso of Tibshirani 1996 and its L2 part the ridge of Hoerl & Kennard 1970), Random Forest (Breiman 2001), XGBoost (Chen & Guestrin 2016) and LightGBM; SVR with an RBF kernel, MLP, Decision Tree and KNN can be added. DAPH has no separate Ridge or Lasso model.
สิ่งที่ DAPH รายงาน · บนชุดทดสอบ: R², RMSE และ MAE พร้อมช่วงเชื่อมั่น 95% จาก bootstrap · Tab 3 แสดง adjusted R² และ MAPE เพิ่ม (ไม่มีช่วงเชื่อมั่น) · รายงาน Word มีกราฟเปรียบเทียบ R², กราฟ residual และค่า SHAP ของแบบจำลองที่ดีที่สุด · แบบจำลองที่ดีที่สุดเลือกด้วย R² (ของ cross-validation เมื่อเปิดไว้) และรายงาน Word จะไม่แนะนำแบบจำลองใดเมื่อ R² ของแบบจำลองที่ดีที่สุดต่ำกว่า 0.10 หรือช่วงเชื่อมั่นคร่อม 0 · ไม่มี DeLong test และไม่มีการปรับความไม่สมดุลกลุ่มสำหรับผลลัพธ์ต่อเนื่อง
What DAPH reports. On the test set: R², RMSE and MAE with bootstrap 95% CIs. Tab 3 adds adjusted R² and MAPE (no CIs). The Word report shows an R² comparison chart, a residual plot and SHAP values for the best model. The best model is chosen by R² (the cross-validated R² when CV is on), and the Word report recommends no model when the best R² is below 0.10 or its CI includes 0. There is no DeLong test and no class-imbalance handling for a continuous outcome.
ใช้เมื่อ ต้องการทำนายค่าตัวเลขของผู้ป่วยแต่ละราย · ไม่ควรใช้ เมื่อต้องการประมาณผลของปัจจัยพร้อมช่วงเชื่อมั่น (ใช้ Linear Regression หัวข้อ 1.12)
Use it when you want to predict each patient's numeric value. Do not use it to estimate the effect of a factor with a CI (use Linear Regression, 1.12).
qolscore3) ได้ดีเพียงใด · ไม่ใส่คะแนนคุณภาพชีวิตก่อนหรือระหว่างรักษาเป็นตัวทำนาย เพราะในข้อมูลนี้คะแนนหลังรักษาเท่ากับคะแนนก่อนรักษาบวกค่าเกือบคงที่ (r = 0.9997) แบบจำลองจะเพียงลอกคะแนนเดิม และรายงานของ DAPH จะไม่แนะนำแบบจำลองที่มีตัวทำนายสัมพันธ์กับผลลัพธ์จน |r| ≥ 0.95 · แบ่งตามเวลา: ชุดฝึก 910 รายแรก ชุดทดสอบ 390 รายหลัง · ผล: Linear Regression ได้ R² 0.042 (95% CI −0.004 ถึง 0.076) และ RMSE 17.12 คะแนน เทียบกับ 17.52 เมื่อทายค่าเฉลี่ยของชุดฝึกให้ทุกคน ส่วน Random Forest (R² −0.174) และ XGBoost (R² −0.431) แย่กว่าการทายค่าเฉลี่ยqolscore3)? The pre- and mid-treatment QoL scores are not used as predictors: in these data the post score equals the pre score plus an almost constant amount (r = 0.9997), so a model would simply copy it, and DAPH's report does not recommend a model with a predictor correlated with the outcome at |r| ≥ 0.95. Temporal split: the first 910 patients for training, the later 390 for testing. Result: Linear Regression gives R² 0.042 (95% CI −0.004 to 0.076) and RMSE 17.12 points against 17.52 for giving everyone the training mean; Random Forest (R² −0.174) and XGBoost (R² −0.431) do worse than the mean.2หลักการและสูตรLogic and Formula
ส่วน L1 (ρ‖β‖₁) ทำให้สัมประสิทธิ์บางตัวเป็นศูนย์พอดี ส่วน L2 หดสัมประสิทธิ์ที่เหลือ · α = 1 และ ρ = 0.5 เป็นค่าคงที่เมื่อไม่ได้ปรับ hyperparameter ถ้าเลือก Optuna จะค้นหา α ใน 0.001 ถึง 10 และ ρ ใน 0.05 ถึง 0.95 ด้วย R² จาก cross-validation ในชุดฝึก
The L1 part (ρ‖β‖₁) sets some coefficients exactly to zero and the L2 part shrinks the rest. α = 1 and ρ = 0.5 are fixed when hyperparameters are not tuned; with Optuna, α is searched in 0.001 to 10 and ρ in 0.05 to 0.95 by the cross-validated R² in the training set.
- x_i
- ตัวทำนายหลังเตรียมข้อมูล: ตัวแปรต่อเนื่องปรับเป็นคะแนนมาตรฐานด้วยค่าเฉลี่ยและ SD ประชากรของชุดฝึก (สำหรับ Linear, Elastic Net, SVR, MLP, KNN) ตัวแปรกลุ่มแยกเป็นคอลัมน์ 0/1 ครบทุกระดับthe predictors after preprocessing: continuous ones standardised with the training mean and population SD (for Linear, Elastic Net, SVR, MLP, KNN), categorical ones as one 0/1 column per level
- ȳ, n
- ค่าเฉลี่ยและจำนวนผู้ป่วยของชุดทดสอบ (ไม่ใช่ชุดฝึก) R² บนชุดทดสอบจึงติดลบได้ เมื่อแบบจำลองทำนายแย่กว่าค่าเฉลี่ยของชุดทดสอบเองmean and number of the test patients (not the training set), so a test-set R² can be negative when the model predicts worse than the test mean itself
- p
- จำนวนคอลัมน์ตัวทำนายหลังแยกระดับ (ทุกระดับของตัวแปรกลุ่มนับเป็น 1 คอลัมน์) · DAPH รายงาน MAPE เฉพาะเมื่อไม่มีผลลัพธ์เป็นศูนย์number of predictor columns after encoding (every level of a categorical predictor counts as one); DAPH reports MAPE only when no outcome value is zero
ขั้นตอนที่ DAPH ทำ · เหมือนหัวข้อ 7.1 ยกเว้น (1) การแบ่งแบบสุ่มเป็น simple random เพราะไม่มีกลุ่มให้ stratify (2) ไม่มีการจัดการความไม่สมดุลกลุ่ม (3) Optuna ให้คะแนนด้วย R² · Bootstrap สุ่มซ้ำผู้ป่วยในชุดทดสอบ 1,000 รอบโดยใช้ค่าทำนายเดิม แล้วใช้เปอร์เซ็นไทล์ที่ 2.5 และ 97.5
What DAPH does. As in 7.1, except that (1) a random split is a simple random split, since there are no classes to stratify on; (2) there is no class-imbalance handling; (3) Optuna scores by R². The bootstrap resamples the test patients 1,000 times with the predictions held fixed and takes the 2.5th and 97.5th percentiles.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
ออกแบบการทวนสอบ · ใช้การแบ่งตามเวลาและแบบจำลองที่ไม่มีการสุ่ม: Linear Regression (lm) และ Elastic Net ซึ่งเขียนเป็น coordinate descent ตามสมการในส่วนที่ 2 โดยตรง (glmnet ปรับมาตราส่วนของ y ภายในสำหรับผลลัพธ์ต่อเนื่อง จึงไม่ได้สมการเดียวกันถ้าไม่แปลงค่า) ส่วน Random Forest และ XGBoost ไม่ได้เทียบ
Verification design. The temporal split and the deterministic models are compared: Linear Regression (lm) and Elastic Net, written as coordinate descent directly from the objective in part 2 (glmnet rescales y internally for a continuous outcome, so it does not solve the same objective without a transformation). Random Forest and XGBoost are not compared.
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
# Temporal split as DAPH: sort by enrolment date (ties keep file order), first 70% = training
d$enroll <- as.Date(substr(d$enroll_date, 1, 10))
d <- d[order(d$enroll, seq_len(nrow(d))), ]
n_tr <- round(0.7 * nrow(d)); tr <- d[1:n_tr, ]; te <- d[(n_tr + 1):nrow(d), ]
cat("r(QoL pre, QoL post) =", round(cor(d$qolscore1, d$qolscore3), 4), "\n") # why QoL scores are not predictors
cat("train", n_tr, "| test", nrow(te), "| mean QoL (post): train", round(mean(tr$qolscore3), 2),
"test", round(mean(te$qolscore3), 2), "\n")
# DAPH preprocessing: numeric predictors standardised with the training mean and population SD,
# categorical predictors one-hot coded with all levels
num <- c("age", "bmi"); cat_v <- c("gender", "chronic", "group", "income", "fam_income", "occupation")
mu <- sapply(tr[num], mean); s <- sapply(tr[num], function(x) sqrt(mean((x - mean(x))^2)))
design <- function(D) {
Z <- sweep(sweep(as.matrix(D[num]), 2, mu), 2, s, "/")
for (v in cat_v) for (l in sort(unique(tr[[v]]))) Z <- cbind(Z, as.numeric(D[[v]] == l))
Z
}
Xtr <- design(tr); Xte <- design(te); ytr <- tr$qolscore3; yte <- te$qolscore3
# Linear Regression = ordinary least squares (lm drops the redundant dummy columns; same predictions)
ols <- lm(ytr ~ Xtr); b <- coef(ols); b[is.na(b)] <- 0
yhat_ols <- as.vector(cbind(1, Xte) %*% b)
# Elastic Net (DAPH defaults alpha = 1, l1_ratio = 0.5): minimise
# (1/2n) sum (y - b0 - Xb)^2 + alpha * l1_ratio * sum|b| + alpha * (1 - l1_ratio) / 2 * sum b^2
enet <- function(X, y, alpha = 1, l1_ratio = 0.5) {
xm <- colMeans(X); Xc <- sweep(X, 2, xm); yc <- y - mean(y); n <- nrow(X)
w <- rep(0, ncol(X)); z <- colSums(Xc^2) / n
repeat { # coordinate descent until the coefficients stop moving
w_old <- w
for (j in seq_along(w)) {
g <- sum(Xc[, j] * (yc - Xc[, -j, drop = FALSE] %*% w[-j])) / n
w[j] <- sign(g) * max(abs(g) - alpha * l1_ratio, 0) / (z[j] + alpha * (1 - l1_ratio))
}
if (max(abs(w - w_old)) < 1e-10) break
}
c(mean(y) - sum(xm * w), w)
}
be <- enet(Xtr, ytr); yhat_en <- as.vector(cbind(1, Xte) %*% be)
cat("Elastic net: coefficients shrunk to exactly 0:", sum(be[-1] == 0), "of", length(be) - 1, "\n")
reg_metrics <- function(y, f, p = 16) {
r2 <- 1 - sum((y - f)^2) / sum((y - mean(y))^2) # mean of the TEST outcomes
c(R2 = r2, RMSE = sqrt(mean((y - f)^2)), MAE = mean(abs(y - f)),
MAPE = 100 * mean(abs((y - f) / y)), AdjR2 = 1 - (1 - r2) * (length(y) - 1) / (length(y) - p - 1))
}
print(round(rbind(Linear = reg_metrics(yte, yhat_ols), ElasticNet = reg_metrics(yte, yhat_en)), 4))
cat("baseline: predict the training mean for everyone -> RMSE",
round(sqrt(mean((yte - mean(ytr))^2)), 4), "\n")
# Bootstrap 95% CI: 1,000 resamples of the test patients, percentiles (R random numbers)
set.seed(12345)
B <- t(replicate(1000, { i <- sample.int(length(yte), replace = TRUE); reg_metrics(yte[i], yhat_ols[i])[1:3] }))
print(round(apply(B, 2, quantile, c(0.025, 0.975)), 4))
r(QoL pre, QoL post) = 0.9997
train 910 | test 390 | mean QoL (post): train 76.18 test 75.11
Elastic net: coefficients shrunk to exactly 0: 9 of 16
R2 RMSE MAE MAPE AdjR2
Linear 0.0415 17.1242 13.7111 22.6569 0.0004
ElasticNet 0.0206 17.3100 13.9595 22.9679 -0.0214
baseline: predict the training mean for everyone -> RMSE 17.5242
R2 RMSE MAE
2.5% -0.0059 15.9373 12.7135
97.5% 0.0779 18.3528 14.7271
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| ชุดฝึก / ชุดทดสอบ (n)Training / test set (n) | 910 / 390 | 910 / 390 | 0 | ✓ PASS |
| Linear: R² / RMSE / MAELinear: R² / RMSE / MAE | 0.0415 / 17.1242 / 13.7111 | 0.04155 / 17.12419 / 13.71107 | < 0.00005 | ✓ PASS |
| Linear: MAPE / adjusted R² (Tab 3)Linear: MAPE / adjusted R² (Tab 3) | 22.6569% / 0.0004 | 22.7% / 0.000 | < 0.05 / < 0.0005 | ✓ PASS |
| Elastic Net: R² / RMSE / MAEElastic Net: R² / RMSE / MAE | 0.0206 / 17.3100 / 13.9595 | 0.02064 / 17.30998 / 13.95945 | < 0.00005 | ✓ PASS |
| Elastic Net: MAPE / adjusted R² (Tab 3)Elastic Net: MAPE / adjusted R² (Tab 3) | 22.9679% / −0.0214 | 23.0% / −0.021 | < 0.05 / < 0.0005 | ✓ PASS |
| Linear: 95% CI ของ R² (bootstrap)*Linear: R² 95% CI (bootstrap)* | −0.0059 to 0.0779 | −0.0044 to 0.0762 | 0.0017 (≤ 0.015) | ✓ PASS |
| Linear: 95% CI ของ RMSE / MAE (bootstrap)*Linear: RMSE / MAE 95% CI (bootstrap)* | 15.9373 to 18.3528 / 12.7135 to 14.7271 | 15.9676 to 18.3644 / 12.7642 to 14.7803 | 0.0303 / 0.0532 (≤ 0.25) | ✓ PASS |
| Random Forest / XGBoost: R² (95% CI) · RMSERandom Forest / XGBoost: R² (95% CI) · RMSE | — | −0.174 (−0.271 to −0.092) · 18.952 / −0.431 (−0.619 to −0.266) · 20.921 | — | ไม่ได้เทียบ (เลขสุ่มของ Python)not compared (Python random numbers) |
| ข้อสรุปในรายงาน WordConclusion of the Word report | R² 0.042 ช่วงเชื่อมั่นคร่อม 0: ไม่มีแบบจำลองที่ใช้ทำนายได้R² 0.042, CI includes 0: no usable model | “… (R² 0.042, 95% CI −0.004 to 0.076; the interval includes 0) … no model is recommended for use”"… (R² 0.042, 95% CI −0.004 to 0.076; the interval includes 0) … no model is recommended for use" | — | ✓ PASS |
ผลการทวนสอบ · ทุกตัวชี้วัดของ Linear Regression และ Elastic Net ตรงกันทุกหลักที่แสดง · * R และ DAPH สุ่มผู้ป่วยต่างชุดกัน จึงยอมรับความต่างจากการสุ่ม · รายงาน Word สรุปตรงกับการอ่านค่าของ R ว่าไม่มีแบบจำลองที่ควรนำไปใช้
Verification result. Every Linear Regression and Elastic Net metric agrees to all displayed digits. * R and DAPH draw different resamples, so a Monte-Carlo tolerance applies. The Word report reaches the same conclusion as the R reading: no model should be used.
4การแปลผลและตัวอย่างInterpretation and Example
ขนาดของความแม่นยำ · Linear Regression อธิบายความผันแปรของคะแนนคุณภาพชีวิตหลังรักษาของผู้ป่วยชุดหลังได้ประมาณ 4% (R² 0.042, 95% CI −0.004 ถึง 0.076 ซึ่งคร่อม 0) ความคลาดเคลื่อนเฉลี่ยกำลังสอง 17.12 คะแนน ลดลงจาก 17.52 คะแนนของการทายค่าเฉลี่ยของชุดฝึกให้ทุกคนเพียง 0.40 คะแนน และความคลาดเคลื่อนสัมบูรณ์เฉลี่ย (MAE) 13.71 คะแนน · Elastic Net หดสัมประสิทธิ์ 9 จาก 16 คอลัมน์ให้เป็นศูนย์และได้ R² ต่ำกว่า (0.021) · Random Forest และ XGBoost ที่ใช้ค่าตั้งต้นได้ R² ติดลบ คือทำนายแย่กว่าค่าเฉลี่ยของชุดทดสอบ เพราะไปเรียนรู้สัญญาณรบกวนของชุดฝึก
Size of the accuracy. Linear Regression explains about 4% of the variation in post-treatment QoL among the later patients (R² 0.042, 95% CI −0.004 to 0.076, which includes 0). Its root mean squared error of 17.12 points is only 0.40 points below the 17.52 of giving everyone the training mean, and its mean absolute error is 13.71 points. Elastic Net sets 9 of the 16 coefficients to zero and reaches a lower R² (0.021). Random Forest and XGBoost with default settings have negative R²: they predict worse than the test-set mean because they learnt noise in the training set.
อ่าน MAPE และ adjusted R² อย่างระวัง · MAPE 22.7% หมายถึงความคลาดเคลื่อนเฉลี่ยประมาณหนึ่งในห้าของคะแนนจริง แต่ MAPE ขึ้นกับระดับของคะแนนและใช้ไม่ได้เมื่อมีค่าใกล้ศูนย์ MAE ในหน่วยคะแนนอ่านง่ายกว่า · adjusted R² ของ DAPH (0.000) คำนวณจากชุดทดสอบโดยนับทุกระดับของตัวแปรกลุ่มเป็นตัวทำนาย (p = 16) จึงเป็นเพียงการปรับคร่าว ๆ
Read MAPE and adjusted R² with care. A MAPE of 22.7% means an average error of about one fifth of the observed score, but MAPE depends on the level of the score and fails for values near zero; MAE in points is easier to read. DAPH's adjusted R² (0.000) is computed on the test set counting every level of a categorical predictor as a predictor (p = 16), so it is only a rough correction.
ตัวอย่างการเขียนรายงาน · “ในการตรวจสอบตามเวลา (ผู้ป่วย 390 ราย) ลักษณะพื้นฐาน 8 ตัวทำนายคะแนนคุณภาพชีวิตหลังรักษาได้น้อยมาก: linear regression มี R² 0.042 (95% CI −0.004 ถึง 0.076), RMSE 17.12 และ MAE 13.71 คะแนน ส่วน random forest และ XGBoost ทำนายแย่กว่าค่าเฉลี่ย (R² −0.174 และ −0.431) ไม่มีแบบจำลองใดเหมาะสำหรับการทำนายรายบุคคล”
Model results sentence. "In temporal validation (390 patients), eight baseline characteristics predicted post-treatment quality of life very poorly: linear regression had R² 0.042 (95% CI −0.004 to 0.076), RMSE 17.12 and MAE 13.71 points, while random forest and XGBoost predicted worse than the mean (R² −0.174 and −0.431). No model is suitable for individual prediction."
📖 References
- Breiman, L. (2001). Random forests. Machine Learning, 45(1), 5–32. doi:10.1023/A:1010933404324
- Chen, T., & Guestrin, C. (2016). XGBoost: A scalable tree boosting system. Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining (KDD '16), 785–794. doi:10.1145/2939672.2939785
- Hoerl, A. E., & Kennard, R. W. (1970). Ridge regression: Biased estimation for nonorthogonal problems. Technometrics, 12(1), 55–67. doi:10.1080/00401706.1970.10488634
- Tibshirani, R. (1996). Regression shrinkage and selection via the lasso. Journal of the Royal Statistical Society: Series B, 58(1), 267–288. doi:10.1111/j.2517-6161.1996.tb02080.x
- Zou, H., & Hastie, T. (2005). Regularization and variable selection via the elastic net. Journal of the Royal Statistical Society: Series B, 67(2), 301–320. doi:10.1111/j.1467-9868.2005.00503.x
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
7.4Spatial Machine Learning
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Spatial Machine Learning ใช้ทำนายค่าผลลัพธ์ของพื้นที่ (ข้อมูล 1 แถวต่อ 1 พื้นที่ เช่น อัตราป่วยรายอำเภอ) จากตัวแปรทำนายของพื้นที่นั้น ด้วยแบบจำลอง machine learning (ML) ชุดเดียวกับ Machine Learning Comparison (หัวข้อ 7.1–7.3) แล้วเพิ่มสี่ส่วนที่เกี่ยวกับพื้นที่: (1) ตัวแปรเชิงพื้นที่ คือพิกัดจุดศูนย์กลาง (centroid) ของแต่ละพื้นที่ (coord_x, coord_y) และค่าเฉลี่ยของพื้นที่เพื่อนบ้าน W_ชื่อตัวแปร (spatial lag, W·x) ของตัวแปรทำนายที่เป็นตัวเลข; (2) Spatial Block Cross-Validation (CV) คือแบ่งพื้นที่เป็นบล็อกด้วย k-means บนพิกัดจุดศูนย์กลาง แล้วใช้บล็อกเป็น fold ของ CV พื้นที่ทั้งบล็อกจึงถูกกันออกไปทดสอบพร้อมกัน; (3) Moran's I ของ residual (Moran, 1950) ของแบบจำลองที่ดีที่สุด (residual แบบ out-of-fold คือค่าที่ทำนายโดยแบบจำลองที่ไม่เคยเห็นพื้นที่นั้น) ทดสอบด้วยการสลับค่า (permutation) 999 ครั้ง; (4) แผนที่ค่าที่ทำนายและ residual.
Spatial Machine Learning predicts an area-level outcome (one row per area, e.g. a district disease rate) from that area's predictors, with the same machine-learning (ML) models as Machine Learning Comparison (sections 7.1–7.3), plus four spatial parts: (1) spatial features: each area's centroid coordinates (coord_x, coord_y) and the neighbour average W_name (spatial lag, W·x) of every numeric predictor; (2) Spatial Block Cross-Validation (CV): k-means groups the centroids into blocks and each block is one CV fold, so a whole block of areas is held out together; (3) Moran's I of the residuals (Moran, 1950) of the best model (out-of-fold residuals, i.e. each area is predicted by a model that never saw it), tested with 999 random permutations; (4) maps of the predicted values and the residuals.
ใช้เมื่อใด: เมื่อคำถามคือ "แบบจำลองทำนายพื้นที่ที่ไม่เคยเห็นได้แม่นเพียงใด" เช่น ทำนายอัตราป่วยของอำเภอที่ยังไม่มีข้อมูลเฝ้าระวัง. พื้นที่ที่อยู่ติดกันมักมีค่าใกล้กัน ถ้าแบ่งข้อมูลทดสอบแบบสุ่ม พื้นที่เพื่อนบ้านของพื้นที่ทดสอบจะอยู่ในชุดฝึก ค่าที่ได้จึงมักดีเกินจริง การกันพื้นที่ออกเป็นบล็อกช่วยลดปัญหานี้ (Roberts et al., 2017). ไม่ควรใช้เมื่อ: ต้องการขนาดผลและค่า p ของตัวแปรทำนาย (ใช้ Spatial Regression บทที่ 6); มีหลายช่วงเวลาต่อพื้นที่ (ใช้ Spatio-Temporal Machine Learning หัวข้อ 7.6); มีพื้นที่ที่ข้อมูลครบน้อยกว่า 30 พื้นที่ (DAPH ไม่รัน) หรือไม่มีไฟล์แผนที่ polygon (.zip). ถ้าผลลัพธ์เป็นกลุ่มมากกว่าสองกลุ่ม (multiclass) DAPH จะไม่คำนวณ Moran's I และแผนที่ residual เพราะ residual ไม่มีความหมาย.
When to use: when the question is "how well does the model predict areas it has never seen", e.g. disease rates for districts that have no surveillance data yet. Neighbouring areas tend to have similar values; with a random hold-out, the neighbours of a test area sit in the training data and the estimate tends to be over-optimistic. Holding out whole blocks of areas reduces this (Roberts et al., 2017). Do not use it to estimate effect sizes and p values of predictors (use Spatial Regression, Chapter 6), for several periods per area (use Spatio-Temporal Machine Learning, section 7.6), with fewer than 30 complete areas (DAPH refuses to run) or without a polygon map (.zip). For an outcome with more than two classes (multiclass) DAPH computes no Moran's I and no residual map, because a residual has no meaning there.
ข้อมูลที่ใช้ในหัวข้อนี้: ข้อมูลตัวอย่างผู้ป่วยของ DAPH ไม่มีแผนที่ จึงใช้ข้อมูลสาธารณะ Columbus ที่มากับ R (package spData; Anselin, 1988) ซึ่งทุกคนเปิดได้ทั้งใน R และใน DAPH จากไฟล์ชุดเดียวกัน: 49 ย่านของเมือง Columbus รัฐ Ohio ปี 1980 — CRIME = จำนวนการลักทรัพย์ในบ้านและการขโมยรถ ต่อ 1,000 ครัวเรือน, HOVAL = มูลค่าบ้าน (พันดอลลาร์), INC = รายได้ครัวเรือน (พันดอลลาร์). สคริปต์ในข้อ 3 สร้างไฟล์ columbus.zip (shp + shx + dbf) สำหรับเปิดใน DAPH. ในงานสาธารณสุขให้แทน CRIME ด้วยอัตราป่วยรายพื้นที่ และแทน HOVAL, INC ด้วยปัจจัยของพื้นที่.
Data used in this section: the DAPH patient example has no map, so this section uses the public Columbus data shipped with R (package spData; Anselin, 1988), which anyone can open in both R and DAPH from the same files: 49 neighbourhoods of Columbus, Ohio, in 1980 — CRIME = residential burglaries and vehicle thefts per 1,000 households, HOVAL = housing value (USD 1,000), INC = household income (USD 1,000). The script in step 3 writes columbus.zip (shp + shx + dbf) to open in DAPH. In public-health work, CRIME would be a disease rate per area and HOVAL, INC area characteristics.
CRIME, ตัวแปรทำนาย = HOVAL, INC, Weights = Queen contiguity, ใส่พิกัดจุดศูนย์กลางและ W·x, 5 บล็อก, ค่าอื่นเป็นค่าเริ่มต้น. ผล Spatial Block CV (49 ย่าน): Random Forest R² = 0.523 (95% CI 0.259 ถึง 0.731), Linear Regression R² = 0.397 (95% CI 0.090 ถึง 0.638); Moran's I ของ residual ของ Random Forest = 0.1320 (p = 0.040).CRIME, predictors = HOVAL, INC, Weights = Queen contiguity, centroid coordinates and W·x on, 5 blocks, everything else at its default. Spatial Block CV result (49 neighbourhoods): Random Forest R² = 0.523 (95% CI 0.259 to 0.731), Linear Regression R² = 0.397 (95% CI 0.090 to 0.638); Moran's I of the Random Forest residuals = 0.1320 (p = 0.040).2หลักการและสูตรLogic and Formula
- cij
- 1 เมื่อ j เป็นเพื่อนบ้านของ i (Queen = มีขอบหรือมุมร่วมกัน; KNN = k จุดศูนย์กลางที่ใกล้ที่สุด; Distance band = จุดศูนย์กลางอยู่ในระยะตัด ซึ่ง DAPH ตั้งให้อัตโนมัติเป็นระยะถึงเพื่อนบ้านที่ใกล้ที่สุดที่ไกลที่สุด × 1.001 เพื่อให้ทุกพื้นที่มีเพื่อนบ้าน) มิฉะนั้น 0; ไฟล์เวทที่นำเข้า (.gal/.gwt) ใช้ค่าในไฟล์. ช่อง Power ไม่มีผลต่อสถิตินี้ เพราะ W·x และ Moran's I ใช้ค่า 0/1 เสมอ1 when j is a neighbour of i (Queen = shares an edge or a corner; KNN = one of the k nearest centroids; Distance band = centroid within the cut-off distance, which DAPH sets automatically to the largest nearest-neighbour distance × 1.001 so that every area has a neighbour), otherwise 0; an imported weights file (.gal/.gwt) uses the file's values. The Power box has no effect on this statistic: W·x and Moran's I always use the 0/1 neighbour set
- mi, N(i)
- จำนวนและชุดของเพื่อนบ้านของพื้นที่ i; ดังนั้น (Wx)i คือค่าเฉลี่ยของ x ในพื้นที่เพื่อนบ้าน ซึ่ง DAPH เพิ่มเป็นคอลัมน์
W_ชื่อตัวแปรให้ทุกตัวแปรทำนายที่เก็บเป็นตัวเลข (ตัวแปรที่เก็บเป็นข้อความถูกข้าม แต่ตัวแปรกลุ่มที่เก็บเป็นรหัสตัวเลข เช่น ภาค 1–9 จะถูกเฉลี่ยรหัสไปด้วย จึงควรเก็บเป็นข้อความหรือไม่ใส่). W·x ใช้เฉพาะค่าตัวแปรทำนาย ไม่ใช้ค่าผลลัพธ์number and set of neighbours of area i, so (Wx)i is the mean of x over the neighbours; DAPH adds it as the columnW_namefor every predictor stored as a number (predictors stored as text are skipped, but a category stored as number codes, e.g. region 1–9, has its codes averaged, so store such a variable as text or leave it out). W·x uses predictor values only, never the outcome - (cxi, cyi)
- จุดศูนย์กลางพื้นที่ของ polygon Pi (พื้นที่ Ai) คำนวณบนระนาบของพิกัดแผนที่ =
coord_x,coord_y. ถ้าไฟล์มี .prj DAPH แปลงแผนที่เป็นลองจิจูด/ละติจูด (WGS84) ก่อน แล้วหาจุดศูนย์กลางบนระนาบองศา; ถ้าไม่มี .prj (เช่น Columbus) ใช้หน่วยของไฟล์เองarea centroid of polygon Pi (area Ai) on the plane of the map coordinates =coord_x,coord_y. When the file has a .prj, DAPH first converts the map to longitude/latitude (WGS84) and takes the centroid on the plane of the degrees; without a .prj (as in Columbus) the file's own units are used - B, K, n
- จำนวนบล็อกที่ตั้งในช่อง "จำนวนบล็อกพื้นที่" (2–10, เริ่มต้น 5), จำนวนบล็อกที่ใช้จริง, จำนวนพื้นที่blocks requested in the "Spatial blocks" box (2–10, default 5), blocks actually used, number of areas
- Gk, ci
- บล็อกที่ k และพิกัดจุดศูนย์กลาง (cyi, cxi); DAPH หาบล็อกด้วย k-means (จุดเริ่มแบบ k-means++, เริ่ม 10 ครั้ง, ใช้ค่า Random seed ในการตั้งค่าขั้นสูง ค่าเริ่มต้น 12345) ซึ่งให้คำตอบเฉพาะที่ (local solution) จึงอาจไม่ใช่การแบ่งที่ผลรวมกำลังสองต่ำที่สุด. fold ของ CV = บล็อก (ช่อง k-fold ถูกล็อก)block k and centroid (cyi, cxi); DAPH finds the blocks with k-means (k-means++ starting points, 10 starts, the Random seed of the advanced settings, 12345 by default), which returns a local solution, not necessarily the split with the smallest sum of squares. CV folds = blocks (the k-fold box is locked)
- f̂−k
- แบบจำลองที่ฝึกบนทุกบล็อกยกเว้นบล็อก k (การเตรียมข้อมูล เช่น การปรับมาตรฐานตัวแปร ก็ fit ใหม่ในแต่ละ fold); ค่าวัดคำนวณจากค่าทำนายของทุกพื้นที่รวมกัน (ไม่ใช่ค่าเฉลี่ยของแต่ละ fold) และ ȳ คือค่าเฉลี่ยของ y ในแถวที่ประเมินthe model trained on every block except block k (preprocessing such as standardisation is refitted inside each fold); the metrics pool the predictions of all areas (they are not averages over folds) and ȳ is the mean of y over the evaluated rows
- ei, wij
- residual แบบ out-of-fold ของแบบจำลองที่ดีที่สุด (ผลลัพธ์สองกลุ่ม: ค่า 0/1 ลบความน่าจะเป็นที่ทำนาย) และน้ำหนักแบบ row-standardised (ผลรวมแต่ละแถว = 1 จึงได้ S0 = n เมื่อทุกพื้นที่มีเพื่อนบ้าน)out-of-fold residual of the best model (binary outcome: the 0/1 outcome minus the predicted probability), and the row-standardised weights (each row sums to 1, so S0 = n when every area has a neighbour)
- m, Īperm, sperm
- จำนวนค่า I จากการสลับ residual แบบสุ่ม 999 ครั้งที่ ≥ ค่า I จริง และค่าเฉลี่ยกับส่วนเบี่ยงเบนมาตรฐานของค่า I ที่สลับ; p คือหางด้านเดียวในทิศของ I ที่สังเกตได้ (ค่าต่ำสุด 0.001). DAPH ตรึง seed ของการสลับไว้ที่ 12345 รันซ้ำจึงได้ p และ z เท่าเดิม แต่โปรแกรมอื่นหรือ seed อื่นจะได้ p ต่างไปเล็กน้อย (ความคลาดเคลื่อนจากการสุ่มประมาณ √(p(1−p)/999) เช่น ±0.006 เมื่อ p ≈ 0.04)the number of the 999 permuted I values that are ≥ the observed I, and the mean and SD of the permuted values; p is the one-sided tail in the direction of the observed I (smallest possible 0.001). DAPH fixes the seed of the permutations at 12345, so a rerun gives the same p and z, but another program or seed gives a slightly different p (Monte-Carlo error about √(p(1−p)/999), e.g. ±0.006 at p ≈ 0.04)
การตรวจสอบที่ DAPH ทำ (ค่าเริ่มต้น): (ก) แบ่ง Train/Test แบบสุ่ม 70/30 ซึ่งไม่ได้แบ่งตามพื้นที่ พื้นที่ทดสอบจึงมีเพื่อนบ้านอยู่ในชุดฝึก และ DAPH คำนวณ 95% CI แบบ bootstrap (1,000 รอบ, percentile) เฉพาะเมื่อแถวที่ประเมินมีอย่างน้อย 20 แถว; (ข) Spatial Block CV บนทุกพื้นที่ รวมพื้นที่ในชุดทดสอบด้วย. เมื่อเปิดทั้งสองแบบ แบบจำลองที่ดีที่สุดคือแบบที่มี R² ของ Spatial Block CV สูงสุด (ผลลัพธ์ตัวเลข; ผลลัพธ์กลุ่มใช้ AUC) ดังนั้นชุดทดสอบไม่ได้แยกขาดจากการเลือกแบบจำลองโดยสมบูรณ์. แบบจำลองใช้ค่า hyperparameter เริ่มต้นของแต่ละอัลกอริทึม (เช่น Elastic Net ของ Zou & Hastie, 2005: alpha = 1, l1_ratio = 0.5) เว้นแต่เลือก Optuna 20 หรือ 50 รอบ ซึ่งปรับค่าด้วย fold แบบบล็อกบนชุดฝึก.
What DAPH validates (defaults): (a) a random 70/30 Train/Test split, which is not split by area, so test areas have neighbours in the training data, and DAPH gives a bootstrap 95% CI (1,000 resamples, percentile) only when at least 20 rows are evaluated; (b) Spatial Block CV over all areas, including the areas in the test set. With both on, the best model is the one with the highest Spatial Block CV R² (numeric outcome; AUC for a categorical outcome), so the test set is not fully separate from model selection. Hyperparameters are each algorithm's defaults (e.g. Elastic Net, Zou & Hastie, 2005: alpha = 1, l1_ratio = 0.5) unless Optuna with 20 or 50 trials is chosen, which tunes on block folds of the training rows.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
สคริปต์สร้างตัวแปรเชิงพื้นที่แบบเดียวกับ DAPH แล้วคำนวณซ้ำทุกอย่างที่คำนวณแบบกำหนดแน่นอนได้ (deterministic): Linear Regression (OLS) และ Elastic Net ด้วยค่าเริ่มต้นของ DAPH ทั้งบน Spatial Block CV และบนชุดทดสอบแบบสุ่ม และ Moran's I ของ residual. DAPH ไม่แสดงว่าแต่ละพื้นที่อยู่บล็อกใด และไม่แสดงว่าพื้นที่ใดตกอยู่ในชุดทดสอบ สองรายการนี้จึงอ่านจากโปรแกรมคำนวณของ DAPH และพิมพ์ไว้ในสคริปต์.
The script builds the spatial features as DAPH does and recomputes everything that is deterministic: Linear Regression (OLS) and Elastic Net with DAPH's defaults, on Spatial Block CV and on the random test set, and Moran's I of the residuals. DAPH does not show which block each area is in or which areas fell into the test set, so these two lists were read from DAPH's engine and are typed into the script.
# Data: the DAPH example dataset (PD cohort) has no map, so this section uses the public
# Columbus data shipped with R (package spData): 49 neighbourhoods of Columbus, Ohio, 1980.
library(sf); library(spdep); library(glmnet)
shp <- system.file("shapes", c("columbus.shp", "columbus.shx", "columbus.dbf"), package = "spData")
utils::zip("columbus.zip", shp, flags = "-j9Xq") # open columbus.zip in DAPH (File > Open)
# (Windows without a zip program: zip::zip("columbus.zip", shp, mode = "cherry-pick"))
col <- st_read(shp[1], quiet = TRUE)
# 1) Spatial features: Queen contiguity W (row-standardised), centroids, W*x
lw <- nb2listw(poly2nb(col, queen = TRUE), style = "W")
xy <- st_coordinates(st_centroid(st_geometry(col))) # no CRS: planar centroid
d <- data.frame(CRIME = col$CRIME, HOVAL = col$HOVAL, INC = col$INC,
coord_x = xy[, 1], coord_y = xy[, 2],
W_HOVAL = lag.listw(lw, col$HOVAL), W_INC = lag.listw(lw, col$INC))
c(links = sum(card(lw$neighbours)), r_HOVAL_INC = round(cor(d$HOVAL, d$INC), 2),
mean_CRIME = round(mean(d$CRIME), 1))
round(d[1:3, ], 4)
# 2) Spatial blocks. DAPH: k-means with 5 blocks on the centroids (seed 12345). DAPH does not
# print which block each area is in; the labels below (POLYID order) were read from its engine
blk <- as.integer(strsplit("2222225224555555455453455533351431313314413331433", "")[[1]])
table(blk) # DAPH prints sizes 6, 8, 13, 8, 14
ctr <- apply(xy, 2, function(v) tapply(v, blk, mean)) # block centres
near <- apply(xy, 1, function(p) which.min(colSums((t(ctr) - p)^2)))
all(near == blk) # TRUE: every area is nearest its own centre
set.seed(12345); km <- kmeans(xy, centers = 5, nstart = 25) # R's own k-means
sort(km$size)
round(c(withinSS_R = km$tot.withinss, withinSS_DAPH = sum((xy - ctr[blk, ])^2)), 3)
# 3) Models as DAPH fits them with library defaults: Linear Regression (OLS) and
# Elastic Net (alpha = 1, l1_ratio = 0.5, predictors standardised on the fitting rows)
enet <- function(tr, te, a = 1, r = 0.5) {
X <- as.matrix(tr[, -1]); m <- colMeans(X); s <- sqrt(colMeans(sweep(X, 2, m)^2))
cy <- sqrt(mean((tr$CRIME - mean(tr$CRIME))^2)) # glmnet needs y with SD 1
lam <- a * (1 - r) + a * r / cy
f <- glmnet(scale(X, m, s), tr$CRIME / cy, alpha = a * r / cy / lam, lambda = lam,
standardize = FALSE, thresh = 1e-14)
cy * drop(predict(f, scale(as.matrix(te[, -1]), m, s)))
}
ols <- function(tr, te) predict(lm(CRIME ~ ., data = tr), newdata = te)
perf <- function(y, p) c(R2 = 1 - sum((y - p)^2) / sum((y - mean(y))^2),
RMSE = sqrt(mean((y - p)^2)), MAE = mean(abs(y - p)))
# 4) Spatial Block CV: each block is predicted by a model fitted on the other four
oof <- sapply(c(ols = ols, enet = enet), function(fit) {
p <- numeric(nrow(d))
for (b in 1:5) p[blk == b] <- fit(d[blk != b, ], d[blk == b, ])
p })
print(round(apply(oof, 2, function(p) perf(d$CRIME, p)), 6), digits = 8)
# 5) DAPH's random 70/30 split (seed 12345): the 15 test areas (POLYID), read from the engine
test <- c(3, 9, 13, 21, 22, 23, 31, 32, 33, 34, 36, 39, 41, 43, 45)
print(round(sapply(c(ols = ols, enet = enet),
function(fit) perf(d$CRIME[test], fit(d[-test, ], d[test, ]))), 6), digits = 8)
# 6) Moran's I of the out-of-fold residuals (Linear Regression)
e <- d$CRIME - oof[, "ols"]
round(moran(e, lw, n = 49, S0 = Szero(lw))$I, 6)
set.seed(12345); moran.mc(e, lw, nsim = 999)
links r_HOVAL_INC mean_CRIME
236.0 0.5 35.1
CRIME HOVAL INC coord_x coord_y W_HOVAL W_INC
1 15.7260 80.467 19.531 8.8272 14.3691 35.4585 18.5940
2 18.8018 44.567 21.232 8.3327 14.0316 46.6723 13.3213
3 30.6268 26.350 15.956 9.0123 13.8197 45.3648 14.1230
blk
1 2 3 4 5
6 8 13 8 14
[1] TRUE
[1] 6 8 8 12 15
withinSS_R withinSS_DAPH
14.962 15.150
# Spatial Block CV (out-of-fold, all 49 areas)
ols enet
R2 0.396546 0.372290
RMSE 12.864555 13.120562
MAE 10.054037 10.943499
# random test set (15 areas)
ols enet
R2 0.095520 0.002692
RMSE 9.274555 9.738863
MAE 8.320525 8.594261
[1] 0.227149
Monte-Carlo simulation of Moran I
statistic = 0.22715, observed rank = 991, p-value = 0.009
alternative hypothesis: greater
columbus.zip → Tab 2: ชนิดผลลัพธ์ Spatial · สถิติ Spatial Machine Learning · ผลลัพธ์ = CRIME · ตัวแปรทำนาย = HOVAL, INC · Weights = Queen contiguity, order 1 (หน้าจอเริ่มที่ Distance band) · ใส่พิกัดจุดศูนย์กลางและ W·x · จำนวนบล็อกพื้นที่ = 5 · ค่าอื่นเป็นค่าเริ่มต้น (5 แบบจำลอง, แบ่ง Train/Test 70/30, Library defaults, seed 12345). รอบที่ 2: เหมือนเดิมแต่เลือกเฉพาะ Linear Regression และ Elastic Net (เพื่อให้ Moran's I มาจาก residual ของ Linear Regression)File > Open: columbus.zip → Tab 2: outcome type Spatial · statistic Spatial Machine Learning · outcome = CRIME · predictors = HOVAL, INC · Weights = Queen contiguity, order 1 (the screen starts at Distance band) · centroid coordinates and W·x on · Spatial blocks = 5 · everything else at its default (5 models, Train/Test 70/30, Library defaults, seed 12345). Run 2: the same with only Linear Regression and Elastic Net ticked (so Moran's I comes from the Linear Regression residuals)| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | สถานะStatus |
|---|---|---|---|---|
| จำนวนคู่เพื่อนบ้าน Queen (49 ย่าน)Queen neighbour links (49 areas) | 236 | 236 | 0 | ✓ PASS |
| coord_x · coord_y ของย่านที่ 1 (ตรวจครบ 49 ย่าน)coord_x · coord_y of area 1 (all 49 areas checked) | 8.8272 · 14.3691 | 8.8272 · 14.3691 | 0 | ✓ PASS |
| W_HOVAL · W_INC ของย่านที่ 1 (ตรวจครบ 49 ย่าน)W_HOVAL · W_INC of area 1 (all 49 areas checked) | 35.4585 · 18.5940 | 35.4585 · 18.5940 | 0 | ✓ PASS |
| บล็อกของ DAPH เป็นคำตอบของ k-means (ทุกย่านอยู่ใกล้จุดศูนย์กลางบล็อกของตนที่สุด)DAPH's blocks are a k-means solution (every area is nearest its own block centre) | TRUE | ขนาด 6, 8, 13, 8, 14sizes 6, 8, 13, 8, 14 | — | ✓ PASS |
| Linear Regression, Spatial Block CV: R² · RMSE · MAE | 0.396546 · 12.864555 · 10.054037 | 0.396546 · 12.864555 · 10.054037 | < 0.000001 | ✓ PASS |
| Elastic Net, Spatial Block CV: R² · RMSE · MAE (เกณฑ์ 0.0001)Elastic Net, Spatial Block CV: R² · RMSE · MAE (tolerance 0.0001) | 0.372290 · 13.120562 · 10.943499 | 0.372293 · 13.120523 · 10.943487 | 0.000004 · 0.000039 · 0.000012 | ✓ PASS |
| Linear Regression, ชุดทดสอบ 15 ย่าน: R² · RMSE · MAELinear Regression, test set of 15 areas: R² · RMSE · MAE | 0.095520 · 9.274555 · 8.320525 | 0.095520 · 9.274555 · 8.320525 | < 0.000001 | ✓ PASS |
| Elastic Net, ชุดทดสอบ 15 ย่าน: R² · RMSE · MAE (เกณฑ์ 0.0001)Elastic Net, test set of 15 areas: R² · RMSE · MAE (tolerance 0.0001) | 0.002692 · 9.738863 · 8.594261 | 0.002683 · 9.738907 · 8.594298 | 0.000009 · 0.000043 · 0.000036 | ✓ PASS |
| Moran's I ของ residual แบบ out-of-fold ของ Linear Regression (รอบที่ 2)Moran's I of the Linear Regression out-of-fold residuals (run 2) | 0.227149 | 0.227149 | < 0.000001 | ✓ PASS |
| |r| สูงสุดระหว่างตัวแปรทำนาย (HOVAL, INC)Largest |r| between predictors (HOVAL, INC) | 0.5 | 0.50 | 0 | ✓ PASS |
ค่า DAPH ในตารางมาจากผลของ DAPH (response และ Word) หรือจากโปรแกรมคำนวณของ DAPH โดยตรงเมื่อหน้าจอไม่แสดง (พิกัด, W·x, บล็อก). ความต่างของ Elastic Net (ไม่เกิน 0.00005) มาจาก DAPH หยุดการคำนวณแบบวนซ้ำ (coordinate descent) ที่ค่าความคลาดเคลื่อน 0.0001; เมื่อให้วิธีเดียวกันของ DAPH คำนวณจนละเอียดถึง 10−12 ได้ค่าตรงกับ R ทั้ง 6 ตำแหน่ง.
The DAPH values come from DAPH's output (response and Word) or, where the screen does not show them (coordinates, W·x, blocks), directly from DAPH's engine. The Elastic Net differences (at most 0.00005) come from DAPH stopping its iterative fit (coordinate descent) at tolerance 0.0001; run with DAPH's own method to a tolerance of 10−12, the values equal R's to 6 decimals.
ค่าที่เทียบกับ R ไม่ได้ตรงตัว (จึงไม่ใส่ PASS): (1) Random Forest, XGBoost และ LightGBM — R ไม่มีโปรแกรมที่สุ่มตัวอย่างและหาจุดแบ่งแบบเดียวกันทุกขั้น ค่าจึงต่างกันได้แม้ข้อมูลเดียวกัน; ใน DAPH ค่าเหล่านี้ซ้ำได้ทุกครั้งเพราะตรึง seed 12345 (รอบภาษาไทยและอังกฤษได้ค่าเท่ากันทุกตำแหน่ง). (2) 95% CI แบบ bootstrap — ใช้ตัวเลขสุ่มของ DAPH เอง. (3) ค่า p และ z ของ Moran's I — มาจากการสลับแบบสุ่มด้วยตัวเลขสุ่มของ DAPH (seed 12345 ซ้ำได้ทุกครั้ง) ซึ่งต่างจากตัวเลขสุ่มของ R: residual ของ Linear Regression ได้ p = 0.004 ใน DAPH และ 0.009 ใน R (moran.mc, seed 12345). (4) k-means ของ R (kmeans()) ได้บล็อกอีกชุดหนึ่ง (ขนาด 6, 8, 8, 12, 15; ผลรวมกำลังสองภายในบล็อก 14.962 เทียบกับ 15.150 ของ DAPH) สคริปต์จึงใช้บล็อกของ DAPH; ถ้าใช้บล็อกของ R ค่า CV จะต่างไปบ้าง.
What cannot be matched exactly in R (so no PASS is claimed): (1) Random Forest, XGBoost and LightGBM — R has no implementation that draws the same samples and searches the same splits at every step, so values differ even on the same data; in DAPH they are repeatable because the seed is fixed at 12345 (the Thai and English runs agree to every digit). (2) Bootstrap 95% CIs — they use DAPH's own random numbers. (3) Moran's I p and z — they come from random permutations drawn with DAPH's own random numbers (seed 12345, repeatable), which differ from R's: the Linear Regression residuals give p = 0.004 in DAPH and 0.009 in R (moran.mc, seed 12345). (4) R's kmeans() finds a different set of blocks (sizes 6, 8, 8, 12, 15; within-block sum of squares 14.962 against DAPH's 15.150), so the script uses DAPH's blocks; with R's blocks the CV values would differ somewhat.
4การแปลผลและตัวอย่างInterpretation and Example
ผลของ DAPH (รอบที่ 1, 5 แบบจำลอง): Spatial Block CV บน 49 ย่าน — Random Forest R² = 0.523 (95% CI 0.259 ถึง 0.731), RMSE = 11.436, MAE = 7.942; Linear Regression R² = 0.397 (95% CI 0.090 ถึง 0.638), RMSE = 12.865; Elastic Net 0.372 (95% CI 0.173 ถึง 0.523); XGBoost 0.340 (95% CI 0.077 ถึง 0.545); LightGBM 0.009 (95% CI −0.323 ถึง 0.183). ชุดทดสอบแบบสุ่ม 15 ย่าน (ไม่มี CI เพราะน้อยกว่า 20 แถว) — Random Forest R² = 0.479, Linear Regression 0.096, XGBoost 0.004, Elastic Net 0.003, LightGBM −1.060. DAPH เลือก Random Forest (Breiman, 2001) เพราะ R² ของ Spatial Block CV สูงสุด.
DAPH result (run 1, 5 models): Spatial Block CV over 49 neighbourhoods — Random Forest R² = 0.523 (95% CI 0.259 to 0.731), RMSE = 11.436, MAE = 7.942; Linear Regression R² = 0.397 (95% CI 0.090 to 0.638), RMSE = 12.865; Elastic Net 0.372 (95% CI 0.173 to 0.523); XGBoost 0.340 (95% CI 0.077 to 0.545); LightGBM 0.009 (95% CI −0.323 to 0.183). Random test set of 15 areas (no CI, fewer than 20 rows) — Random Forest R² = 0.479, Linear Regression 0.096, XGBoost 0.004, Elastic Net 0.003, LightGBM −1.060. DAPH retains Random Forest (Breiman, 2001) because it has the highest Spatial Block CV R².
อ่านอย่างไร: (1) รายงานค่า Spatial Block CV เป็นค่าหลัก เพราะทุกย่านถูกทำนายโดยแบบจำลองที่ไม่เคยเห็นย่านนั้นและย่านในบล็อกเดียวกัน. Random Forest อธิบายความแปรปรวนของอัตราอาชญากรรมในย่านที่ไม่เคยเห็นได้ราวครึ่งหนึ่ง และทำนายคลาดเฉลี่ย 7.9 ครั้งต่อ 1,000 ครัวเรือน (MAE) เทียบกับค่าเฉลี่ย 35.1. (2) CI ของ Random Forest กับ Linear Regression ซ้อนกันมาก ด้วยข้อมูล 49 ย่าน จึงยังสรุปไม่ได้ว่าแบบใดดีกว่าอย่างชัดเจน "R² สูงสุด" ไม่ได้แปลว่าดีกว่าอย่างมีนัยสำคัญ. (3) ค่าบนชุดทดสอบสุ่ม 15 ย่านแกว่งมาก (−1.060 ถึง 0.479) และไม่ได้กันเพื่อนบ้านออก จึงใช้เป็นค่าประกอบเท่านั้น; Spatial Block CV ที่ใช้เลือกแบบจำลองก็รวม 15 ย่านนี้ไว้ด้วย. ข้อมูลพื้นที่น้อยเช่นนี้อาจปิดการแบ่ง Train/Test แล้วอ่าน Spatial Block CV อย่างเดียว. (4) ขอบของบล็อกยังมีย่านที่เป็นเพื่อนบ้านกันอยู่คนละ fold ค่าจึงอาจยังดีเกินจริงเล็กน้อย และขึ้นกับการแบ่งบล็อก.
How to read it: (1) Report Spatial Block CV as the main estimate: every neighbourhood is predicted by a model that saw neither it nor the rest of its block. Random Forest explains about half of the variation in crime rates of unseen neighbourhoods, with a mean absolute error of 7.9 per 1,000 households against a mean of 35.1. (2) The CIs of Random Forest and Linear Regression overlap widely; with 49 areas the data cannot show that one is clearly better — "highest R²" does not mean significantly better. (3) The random 15-area test values swing widely (−1.060 to 0.479) and do not keep neighbours apart, so treat them as supporting information only; the Spatial Block CV that chose the model also included these 15 areas. With this few areas, consider switching the Train/Test split off and reading Spatial Block CV alone. (4) At block borders, neighbouring areas still sit in different folds, so the estimate can remain slightly optimistic, and it depends on how the blocks fall.
Moran's I ของ residual: residual ของ Random Forest มี I = 0.1320, z = 1.791, p = 0.040 DAPH จึงรายงานว่า "ยังเหลือโครงสร้างเชิงพื้นที่ใน residuals" แต่ค่า p อยู่ใกล้ 0.05 และ I มีขนาดเล็ก จึงเป็นหลักฐานระดับอ่อนว่า residual ยังจับกลุ่มตามพื้นที่. residual ของ Linear Regression มี I = 0.2271, z = 2.863, p = 0.004 แปลว่าแบบจำลองเชิงเส้นยังทิ้งรูปแบบเชิงพื้นที่ไว้ชัดกว่า แม้มีพิกัดและ W·x แล้ว ควรพิจารณา Spatial Regression (บทที่ 6) หรือเพิ่มตัวแปรของพื้นที่. ดูแผนที่ residual ประกอบเพื่อหาย่านที่ทำนายพลาดเป็นกลุ่ม; ในประโยคบรรยายแผนที่ DAPH เรียกพื้นที่ด้วยลำดับแถวที่เริ่มจาก 0 (แถว 0 = พื้นที่แรกในไฟล์) ไม่ใช่รหัสพื้นที่.
Moran's I of the residuals: the Random Forest residuals have I = 0.1320, z = 1.791, p = 0.040, so DAPH reports that residual spatial structure remains; with p close to 0.05 and a small I, this is weak evidence that the residuals still cluster in space. The Linear Regression residuals have I = 0.2271, z = 2.863, p = 0.004: the linear model leaves clearer spatial pattern unexplained even with the coordinates and W·x, so consider Spatial Regression (Chapter 6) or more area-level predictors. Use the residual map to find neighbourhoods that are mispredicted together; in the sentences under the maps DAPH names areas by their row number counted from 0 (row 0 = the first area in the file), not by an area ID.
ข้อจำกัด: ผลนี้เป็นความสัมพันธ์เพื่อการทำนาย ไม่ใช่ผลเชิงเหตุ (มูลค่าบ้านหรือรายได้ไม่ได้ "ทำให้" อาชญากรรมลดลงตามผลนี้); 49 ย่านถือว่าน้อยสำหรับ ML ค่า CI จึงกว้าง. ตัวอย่างประโยครายงาน: "ใน Spatial Block CV (k-means 5 บล็อก, 49 ย่าน) Random Forest ทำนายย่านที่ไม่เคยเห็นได้ดีที่สุด (R² = 0.52, 95% CI 0.26 ถึง 0.73; MAE = 7.9 ต่อ 1,000 ครัวเรือน) เทียบกับ Linear Regression (R² = 0.40, 95% CI 0.09 ถึง 0.64); Moran's I ของ residual = 0.13 (permutation p = 0.040)".
Limitations: these are predictive associations, not causal effects (housing value or income do not "cause" lower crime on this evidence); 49 areas are few for ML, hence the wide CIs. Example of a results sentence: "In spatial block cross-validation (5 k-means blocks, 49 neighbourhoods), Random Forest predicted unseen neighbourhoods best (R² = 0.52, 95% CI 0.26 to 0.73; MAE = 7.9 per 1,000 households), against R² = 0.40 (95% CI 0.09 to 0.64) for linear regression; Moran's I of its residuals was 0.13 (permutation p = 0.040)."
📖 References
- Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic Publishers. doi:10.1007/978-94-015-7799-1
- Breiman, L. (2001). Random forests. Machine Learning, 45(1), 5–32. doi:10.1023/A:1010933404324
- Moran, P. A. P. (1950). Notes on continuous stochastic phenomena. Biometrika, 37(1–2), 17–23. doi:10.1093/biomet/37.1-2.17
- Roberts, D. R., Bahn, V., Ciuti, S., Boyce, M. S., Elith, J., Guillera-Arroita, G., Hauenstein, S., Lahoz-Monfort, J. J., Schröder, B., Thuiller, W., Warton, D. I., Wintle, B. A., Hartig, F., & Dormann, C. F. (2017). Cross-validation strategies for data with temporal, spatial, hierarchical, or phylogenetic structure. Ecography, 40(8), 913–929. doi:10.1111/ecog.02881
- Zou, H., & Hastie, T. (2005). Regularization and variable selection via the elastic net. Journal of the Royal Statistical Society: Series B (Statistical Methodology), 67(2), 301–320. doi:10.1111/j.1467-9868.2005.00503.x
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
7.5External Validation & Save Model (.daphmodel) + Temporal Split
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
แบบจำลองทำนายที่ดีในข้อมูลที่ใช้สร้าง อาจทำงานแย่ลงเมื่อใช้กับผู้ป่วยในเวลาอื่นหรือสถานที่อื่น หัวข้อนี้อธิบายเครื่องมือ 3 อย่างของ DAPH สำหรับตรวจเรื่องนี้ · Temporal split แบ่งข้อมูลชุดเดียวตามเวลาใน Machine Learning Comparison · Save Model บันทึกแบบจำลองเป็นไฟล์ .daphmodel · External Validation นำไฟล์นั้นไปให้คะแนนข้อมูลชุดใหม่โดยไม่สร้างแบบจำลองใหม่
A prediction model that performs well in the data used to build it may perform worse for patients from another time or place. This topic covers DAPH's three tools for checking this: Temporal split splits one dataset by time inside Machine Learning Comparison; Save Model stores the model as a .daphmodel file; External Validation applies that file to a new dataset without fitting any model.
สิ่งที่บันทึกในไฟล์ .daphmodel · จาก Machine Learning Comparison (และ Spatial ML) ไฟล์เก็บแบบจำลองที่ดีที่สุดเพียงตัวเดียว ได้แก่ ขั้นตอนเตรียมข้อมูลที่เรียนจากชุดฝึก (ค่าที่ใช้เติมค่าขาด ค่าเฉลี่ยและ SD ที่ใช้ปรับมาตรฐาน ระดับของตัวแปรกลุ่ม) ตัวแบบจำลองที่ฟิตแล้ว จุดตัดที่ใช้กับตัวชี้วัดของชุดทดสอบ (Youden บนชุดทดสอบ หรือบนค่า out-of-fold เมื่อไม่ได้แบ่งชุดทดสอบ) ชื่อผลลัพธ์และตัวทำนาย ระดับของผลลัพธ์ คอลัมน์ที่ตัวคัดตัวแปรเลือกไว้ (ถ้าใช้) ขนาดข้อมูลพัฒนา และตัวชี้วัดตอนพัฒนาพร้อมช่วงเชื่อมั่น · จาก Linear, Logistic และ Mixed-Effect Linear Regression ไฟล์เก็บแบบจำลองที่ฟิตกับข้อมูลทั้งชุด สำหรับ logistic จุดตัด Youden คำนวณจากความน่าจะเป็นที่ทำนายในข้อมูลเดียวกับที่ใช้ฟิต ตัวชี้วัดตอนพัฒนาของกลุ่มนี้จึงเป็นค่าในตัวอย่าง (apparent) ซึ่งดีเกินจริง · ไฟล์เป็น Python pickle (joblib) ควรเปิดเฉพาะไฟล์ที่สร้างเอง
What a .daphmodel file holds. From Machine Learning Comparison (and Spatial ML) the file keeps only the best model: the preprocessing learnt from the training set (imputation values, the means and SDs used for standardisation, the levels of categorical predictors), the fitted model, the cut-off used for its test-set metrics (Youden on the test set, or on the out-of-fold predictions when there is no test split), the outcome and predictor names, the outcome categories, the columns kept by the variable-selection screen (if one was used), the development sample size and the development metrics with their CIs. From Linear, Logistic and Mixed-Effect Linear Regression the file keeps the model fitted on the whole dataset; for logistic models the Youden cut-off is computed on the predicted probabilities of the same data used for fitting, so their development metrics are apparent (in-sample) values and are optimistic. The file is a Python pickle (joblib): open only files you created yourself.
External Validation ใน DAPH · นำเข้าข้อมูลชุดใหม่ แนบไฟล์ใน Tab 2 > External Validation (โมเดลที่บันทึกไว้) แล้วกด Run · DAPH ให้คะแนนผู้ป่วยทุกรายที่ข้อมูลครบ (แถวที่มีค่าว่างในตัวทำนายหรือผลลัพธ์ถูกตัดออก ไม่มีการเติมค่า) ด้วยการเตรียมข้อมูลและแบบจำลองเดิมทุกอย่าง และใช้จุดตัดเดิมที่ล็อกไว้ ไม่หาจุดตัดใหม่จากข้อมูลชุดใหม่ · รายงานตาราง “ตอนพัฒนา เทียบกับข้อมูลภายนอก” ของ AUC, Brier, sensitivity, specificity, PPV, NPV, F1 (ผลลัพธ์ 2 กลุ่ม) หรือ R², RMSE, MAE (ผลลัพธ์ต่อเนื่อง) พร้อมช่วงเชื่อมั่น 95% จาก bootstrap 1,000 รอบ ค่า Δ = ตอนพัฒนา − ภายนอก และคำวินิจฉัยตามเกณฑ์ของ DAPH เอง (Δ ของ AUC หรือ R² ≤ 0.05 ใช้ต่อได้ · 0.05 ถึง 0.10 ควรพิจารณา recalibration · > 0.10 ควรปรับปรุงหรือสร้างใหม่) ซึ่งไม่ใช่เกณฑ์มาตรฐานสากล · DAPH ไม่คำนวณ calibration-in-the-large หรือ calibration slope และไม่มีคำสั่ง recalibration ให้ · แบบจำลอง Spatial ML ยังทำ external validation ไม่ได้
External Validation in DAPH. Load the new data, attach the file in Tab 2 > External Validation (saved model) and Run. DAPH scores every patient with complete data (rows with a missing predictor or outcome are dropped, nothing is imputed) using the saved preprocessing and model unchanged, at the locked cut-off: the cut-off is never re-chosen on the new data. It reports a development-versus-external table of AUC, Brier, sensitivity, specificity, PPV, NPV and F1 (binary outcomes) or R², RMSE and MAE (continuous outcomes) with 1,000-resample bootstrap 95% CIs, the difference Δ = development − external, and a verdict by DAPH's own rule (Δ of AUC or R² ≤ 0.05 keep using; 0.05 to 0.10 consider recalibration; > 0.10 update or rebuild), which is not an international standard. DAPH does not compute calibration-in-the-large or the calibration slope and offers no recalibration. Spatial ML models cannot yet be externally validated.
ภาษาของ TRIPOD · TRIPOD (Collins et al. 2015) แบ่งการตรวจสอบเป็น การแบ่งข้อมูลชุดเดียวแบบสุ่ม (type 2a) การแบ่งข้อมูลชุดเดียวแบบไม่สุ่ม เช่น ตามเวลาหรือสถานที่ (type 2b) และการตรวจกับข้อมูลที่เก็บแยกต่างหาก (type 3 เมื่อพัฒนาและตรวจในงานเดียวกัน type 4 เมื่อตรวจแบบจำลองที่มีอยู่แล้ว) · Temporal split ของ DAPH จึงเป็น type 2b ส่วน External Validation จะนับเป็น external แท้หรือไม่ขึ้นกับที่มาของข้อมูลชุดใหม่ ซึ่ง DAPH ไม่สามารถรู้ได้
TRIPOD terms. TRIPOD (Collins et al. 2015) distinguishes a random split of one dataset (type 2a), a non-random split of one dataset, e.g. by time or place (type 2b), and evaluation in separately collected data (type 3 when the model is developed and validated in the same report, type 4 when an existing model is validated). DAPH's temporal split is therefore type 2b; whether an External Validation run is truly external depends on where the new data come from, which DAPH cannot know.
2หลักการและสูตรLogic and Formula
- t_(k), r
- ค่าของตัวแปรเวลาหลังเรียงจากน้อยไปมาก · สัดส่วนชุดฝึก (ค่าเริ่มต้น 0.7) ถ้าค่าเวลาซ้ำกันตรงจุดตัด แถวที่มีเวลาเดียวกันจะอยู่ได้ทั้งสองฝั่ง และ Tab 3 จะแจ้งไว้time values sorted ascending; training share (default 0.7). If tied times fall at the cut, rows with the same time can end up on both sides, and Tab 3 says so
- J_dev, t*
- Youden's J บนชุดทดสอบของรอบพัฒนา · จุดตัดที่ล็อกไว้ในไฟล์Youden's J on the development run's test set; the cut-off locked in the file
- M, a, b
- ตัวชี้วัดใด ๆ · a = 0 แปลว่าความเสี่ยงที่ทำนายโดยเฉลี่ยเท่ากับที่เกิดจริง · b < 1 แปลว่าความเสี่ยงที่ทำนายกระจายมากเกินไป (Van Calster et al. 2019)any metric; a = 0 means the average predicted risk equals the observed rate; b < 1 means the predicted risks are too spread out (Van Calster et al. 2019)
เหตุผลที่ต้องล็อกจุดตัด · ถ้าเลือกจุดตัดใหม่จากข้อมูลชุดใหม่ ค่า sensitivity และ specificity ที่รายงานจะดีเกินจริงเพราะข้อมูลที่ใช้ประเมินถูกใช้เลือกค่าเอง (Steyerberg 2019) · ข้อควรรู้: ใน Machine Learning Comparison จุดตัดที่ล็อกเป็นจุดที่ดีที่สุดบนชุดทดสอบของรอบพัฒนา ค่า sensitivity และ specificity ตอนพัฒนาจึงดีเกินจริงอยู่แล้ว ส่วนค่าในข้อมูลภายนอกไม่ลำเอียง · DAPH จะแนะนำในรายงานหลักให้ทำ external validation เมื่อเปิดทั้งชุดทดสอบและ cross-validation และ AUC (หรือ R²) ที่ดีที่สุดของสองวิธีต่างกันตั้งแต่ 0.07
Why the cut-off is locked. Re-choosing the cut-off on the new data would make the reported sensitivity and specificity optimistic, because the evaluation data would have chosen it (Steyerberg 2019). Note that in Machine Learning Comparison the locked cut-off is the best one on the development run's test set, so the development sensitivity and specificity are already optimistic, while the external values are not. The main report recommends external validation when both a test split and cross-validation are on and the best AUC (or R²) of the two differ by 0.07 or more.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(glmnet); library(pROC)
d$enroll <- as.Date(substr(d$enroll_date, 1, 10))
dev <- subset(d, type == 1) # development data: public hospitals
ext <- subset(d, type == 2) # new data: private hospitals
cat("development n =", nrow(dev), "| external n =", nrow(ext), "\n")
# Development run as in 7.1: temporal split 70/30 by enrolment date, Logistic Regression (L2, C = 1)
dev <- dev[order(dev$enroll, seq_len(nrow(dev))), ]
n_tr <- round(0.7 * nrow(dev)); tr <- dev[1:n_tr, ]; te <- dev[(n_tr + 1):nrow(dev), ]
cat("train", n_tr, format(range(tr$enroll)), "| test", nrow(te), format(range(te$enroll)), "\n")
num <- c("age", "bmi", "qolscore1"); cat_v <- c("gender", "chronic", "group")
mu <- sapply(tr[num], mean); s <- sapply(tr[num], function(x) sqrt(mean((x - mean(x))^2)))
design <- function(D) { # the SAVED preprocessing: training mean/SD + one-hot
Z <- sweep(sweep(as.matrix(D[num]), 2, mu), 2, s, "/")
for (v in cat_v) for (l in sort(unique(tr[[v]]))) Z <- cbind(Z, as.numeric(D[[v]] == l))
Z
}
fit <- glmnet(design(tr), tr$status, family = "binomial", alpha = 0, lambda = 1 / n_tr,
standardize = FALSE, thresh = 1e-14)
risk <- function(D) as.vector(predict(fit, design(D), type = "response"))
youden <- function(y, p) { t <- sort(unique(p), decreasing = TRUE)
t[which.max(sapply(t, function(c) mean(p[y == 1] >= c) - mean(p[y == 0] >= c)))] }
auc_mw <- function(y, p) { r <- rank(p); n1 <- sum(y); n0 <- length(y) - n1
(sum(r[y == 1]) - n1 * (n1 + 1) / 2) / (n1 * n0) }
metrics <- function(y, p, thr) { pos <- p >= thr
TP <- sum(pos & y == 1); FP <- sum(pos & y == 0); FN <- sum(!pos & y == 1); TN <- sum(!pos & y == 0)
c(AUC = auc_mw(y, p), Brier = mean((y - p)^2), Sens = TP / (TP + FN), Spec = TN / (TN + FP),
PPV = TP / (TP + FP), NPV = TN / (TN + FN), F1 = 2 * TP / (2 * TP + FP + FN)) }
p_dev <- risk(te); thr <- youden(te$status, p_dev) # cut-off fixed at development
cat("locked threshold", round(thr, 4), "\n")
p_ext <- risk(ext) # external: score every patient, no refitting
tab <- rbind(development = metrics(te$status, p_dev, thr), external = metrics(ext$status, p_ext, thr))
tab <- rbind(tab, delta = tab[1, ] - tab[2, ]); print(round(tab, 5))
# The Brier score depends on the event rate: compare each with "predict the rate for everyone"
r_dev <- mean(te$status); r_ext <- mean(ext$status)
cat("death rate: development test", round(r_dev, 4), "| external", round(r_ext, 4), "\n")
cat("Brier of predicting that rate for everyone:", round(r_dev * (1 - r_dev), 4), "|", round(r_ext * (1 - r_ext), 4), "\n")
cat("Brier improvement over that reference (1 - Brier/reference):", round(1 - tab[1, "Brier"] / (r_dev * (1 - r_dev)), 3),
"|", round(1 - tab[2, "Brier"] / (r_ext * (1 - r_ext)), 3), "\n")
# Calibration in the new data (DAPH does not report these): mean predicted risk,
# calibration-in-the-large (intercept with the linear predictor as offset) and calibration slope
lp <- qlogis(p_ext)
cat("external: mean predicted risk", round(mean(p_ext), 4), "\n")
print(round(c(CITL = unname(coef(glm(status ~ offset(lp), family = binomial, data = ext))),
slope = unname(coef(glm(status ~ lp, family = binomial, data = ext))[2])), 3))
# Bootstrap 95% CI of the external AUC (1,000 resamples of the new patients; R's random numbers)
set.seed(12345)
B <- replicate(1000, { i <- sample.int(nrow(ext), replace = TRUE); auc_mw(ext$status[i], p_ext[i]) })
print(round(quantile(B, c(0.025, 0.975)), 4))
development n = 1061 | external n = 236
train 743 2022-01-01 2023-01-17 | test 318 2023-01-17 2023-06-28
locked threshold 0.2271
AUC Brier Sens Spec PPV NPV F1
development 0.65633 0.12202 0.45833 0.81481 0.30556 0.89431 0.36667
external 0.66323 0.14438 0.47727 0.73438 0.29167 0.85976 0.36207
delta -0.00691 -0.02236 -0.01894 0.08044 0.01389 0.03455 0.00460
death rate: development test 0.1509 | external 0.1864
Brier of predicting that rate for everyone: 0.1282 | 0.1517
Brier improvement over that reference (1 - Brier/reference): 0.048 | 0.048
external: mean predicted risk 0.1853
CITL slope
0.008 0.888
2.5% 97.5%
0.5710 0.7469
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| ข้อมูลพัฒนา (Hospital Type = 1): n · ชุดฝึก · ชุดทดสอบDevelopment data (Hospital Type = 1): n · training · test | 1061 · 743 · 318 | 1061 · 743 · 318 | 0 | ✓ PASS |
| จุดตัดที่ล็อกไว้Locked cut-off | 0.2271 | 0.2271 | < 0.000001 | ✓ PASS |
| ตอนพัฒนา: AUC / BrierDevelopment: AUC / Brier | 0.65633 / 0.12202 | 0.65633 / 0.12202 | < 0.000005 | ✓ PASS |
| ตอนพัฒนา: Sens / Spec / PPV / NPV / F1Development: Sens / Spec / PPV / NPV / F1 | 0.45833 / 0.81481 / 0.30556 / 0.89431 / 0.36667 | 0.45833 / 0.81481 / 0.30556 / 0.89431 / 0.36667 | 0 | ✓ PASS |
| ข้อมูลภายนอก (Hospital Type = 2): nExternal data (Hospital Type = 2): n | 236 | 236 | 0 | ✓ PASS |
| ภายนอก: AUC / BrierExternal: AUC / Brier | 0.66323 / 0.14438 | 0.66323 / 0.14438 | < 0.000001 | ✓ PASS |
| ภายนอก: Sens / Spec / PPV / NPV / F1 ที่จุดตัดเดิมExternal: Sens / Spec / PPV / NPV / F1 at the locked cut-off | 0.47727 / 0.73438 / 0.29167 / 0.85976 / 0.36207 | 0.47727 / 0.73438 / 0.29167 / 0.85976 / 0.36207 | 0 | ✓ PASS |
| Δ AUC / Δ Brier / Δ SpecΔ AUC / Δ Brier / Δ Spec | −0.00691 / −0.02236 / 0.08044 | −0.00691 / −0.02236 / 0.08044 | < 0.000001 | ✓ PASS |
| ภายนอก: 95% CI ของ AUC (bootstrap)*External: AUC 95% CI (bootstrap)* | 0.5710 to 0.7469 | 0.5715 to 0.7500 | 0.0031 (≤ 0.015) | ✓ PASS |
| ข้อความคำวินิจฉัยVerdict text | AUC เพิ่มขึ้น 0.007: ใช้ต่อได้AUC rose by 0.007: keep using | "AUC rose by 0.007 — the model transports well to this dataset" | — | ✓ PASS |
| ข้อความของ temporal split ในรอบพัฒนา (Tab 3)Temporal-split statement in the development run (Tab 3) | 2023-01-17 อยู่ทั้งในชุดฝึกและชุดทดสอบ2023-01-17 is in both the training and the test set | "the cut falls inside 2023-01-17: rows with that same time are on both sides" | — | ✓ PASS |
| ข้อความของ temporal split ในรอบพัฒนา (Word ส่วนวิธีการ)Temporal-split statement in the development run (Word Methods) | 2023-01-17 อยู่ทั้งในชุดฝึกและชุดทดสอบ2023-01-17 is in both the training and the test set | "the cut falls inside 2023-01-17, so observations with that same time are in both sets" | — | ✓ PASS |
| บันทึกและตรวจแบบจำลองที่ฟิตด้วยวิธีเลือกตัวแปร (elastic net / importance)Saving and validating a model fitted with variable selection (elastic net / importance) | ต้องใช้คอลัมน์ชุดเดิมmust reuse the kept columns | ทำงานได้ (AUC ภายนอก 0.655 / 0.653)runs (external AUC 0.655 / 0.653) | — | ✓ PASS |
| calibration-in-the-large / slope ในข้อมูลภายนอกCalibration-in-the-large / slope in the external data | 0.008 / 0.888 | — | — | DAPH ไม่รายงานnot reported by DAPH |
ผลการทวนสอบ · การกรองข้อมูล การแบ่งตามเวลา จุดตัดที่ล็อก และตัวชี้วัดทุกตัวทั้งตอนพัฒนาและในข้อมูลภายนอกตรงกับ R ทุกหลักที่แสดง คำวินิจฉัยบอกทิศทางถูกต้อง (AUC เพิ่มขึ้น) Tab 3 และรายงาน Word แจ้งว่าผู้ป่วยวันที่ 2023-01-17 อยู่ทั้งสองฝั่งของจุดตัด และแบบจำลองที่ฟิตด้วยวิธีเลือกตัวแปรนำไปตรวจกับข้อมูลใหม่ได้ เพราะไฟล์เก็บคอลัมน์ที่ตัวคัดเลือกไว้ · * R และ DAPH สุ่มผู้ป่วยต่างชุดกัน
Verification result. The filtering, the temporal split, the locked cut-off and every development and external metric agree with R to the displayed digits; the verdict states the direction correctly (the AUC rose); Tab 3 and the Word report both say that patients enrolled on 2023-01-17 are on both sides of the cut; and a model fitted with variable selection can be validated on new data because the file stores the columns the screen kept. * R and DAPH draw different resamples.
4การแปลผลและตัวอย่างInterpretation and Example
การจำแนก · AUC ในผู้ป่วยโรงพยาบาลเอกชน (0.663, 95% CI 0.571 ถึง 0.750 จาก DAPH) ใกล้เคียงกับตอนพัฒนา (0.656) จึงไม่มีหลักฐานว่าความสามารถในการจำแนกลดลง แต่ทั้งสองค่าต่ำกว่า 0.70 แบบจำลองจึงจำแนกได้ต่ำทั้งสองที่ คำวินิจฉัย “ใช้ต่อได้” ของ DAPH ดูเฉพาะการเปลี่ยนแปลงของ AUC ไม่ได้บอกว่าแบบจำลองดีพอใช้งาน
Discrimination. The AUC in private-hospital patients (0.663, 95% CI 0.571 to 0.750 from DAPH) is close to development (0.656), so there is no evidence that discrimination fell, but both are below 0.70: the model discriminates poorly in both settings. DAPH's "transports well" looks only at the change in AUC; it does not say the model is good enough to use.
Brier score เพิ่มขึ้นไม่ได้แปลว่าความแม่นยำแย่ลงเสมอ · Brier เพิ่มจาก 0.122 เป็น 0.144 เพราะสัดส่วนเสียชีวิตสูงขึ้น (0.151 เป็น 0.186) ซึ่งทำให้ Brier ของการทายสัดส่วนให้ทุกคนสูงขึ้นด้วย (0.128 เป็น 0.152) เมื่อเทียบกับค่าอ้างอิงนี้ แบบจำลองดีขึ้นประมาณ 5% (0.048) เท่ากันทั้งสองที่ · การเทียบ calibration ใน R: ความเสี่ยงที่ทำนายเฉลี่ย 0.185 ตรงกับอัตราเสียชีวิตจริง 0.186 (calibration-in-the-large 0.008) และ slope 0.888 ซึ่งน้อยกว่า 1 เล็กน้อย คือความเสี่ยงที่ทำนายกระจายมากเกินไปเล็กน้อย (Van Calster et al. 2019) · specificity ลดลง 0.080 ที่จุดตัดเดิม คือผู้รอดชีวิตในโรงพยาบาลเอกชนมีความเสี่ยงที่ทำนายเกิน 0.227 ในสัดส่วนที่มากกว่า
A higher Brier score does not always mean worse accuracy. Brier rose from 0.122 to 0.144 because the death rate rose (0.151 to 0.186), which also raises the Brier score of predicting that rate for everyone (0.128 to 0.152); against that reference the model is about 5% (0.048) better in both settings. The calibration check in R: the mean predicted risk of 0.185 matches the observed death rate of 0.186 (calibration-in-the-large 0.008), and the slope of 0.888, slightly below 1, means the predicted risks are slightly too spread out (Van Calster et al. 2019). Specificity fell by 0.080 at the locked cut-off: a larger share of the surviving private-hospital patients had predicted risks above 0.227.
ตัวอย่างการเขียนรายงาน · “แบบจำลอง logistic regression ที่พัฒนาในผู้ป่วยโรงพยาบาลรัฐ (ชุดทดสอบตามเวลา AUC 0.656) เมื่อนำไปใช้กับผู้ป่วยโรงพยาบาลเอกชน 236 รายโดยไม่ปรับใด ๆ ได้ AUC 0.663 (95% CI 0.571 ถึง 0.750) calibration-in-the-large 0.008 และ calibration slope 0.888 ที่จุดตัด 0.227 ได้ sensitivity 0.477 และ specificity 0.734 ความสามารถในการจำแนกยังคงต่ำ”
Model results sentence. "The logistic regression model developed in public-hospital patients (temporal test AUC 0.656) was applied without modification to 236 private-hospital patients: AUC 0.663 (95% CI 0.571 to 0.750), calibration-in-the-large 0.008 and calibration slope 0.888; at the cut-off of 0.227, sensitivity was 0.477 and specificity 0.734. Discrimination remained poor."
📖 References
- Collins, G. S., Reitsma, J. B., Altman, D. G., & Moons, K. G. M. (2015). Transparent Reporting of a multivariable prediction model for Individual Prognosis Or Diagnosis (TRIPOD): the TRIPOD statement. Annals of Internal Medicine, 162(1), 55–63. doi:10.7326/M14-0697
- Steyerberg, E. W. (2019). Clinical Prediction Models: A Practical Approach to Development, Validation, and Updating (2nd ed.). Cham: Springer. ISBN 978-3-030-16398-3.
- Van Calster, B., McLernon, D. J., van Smeden, M., Wynants, L., Steyerberg, E. W., & Topic Group 'Evaluating diagnostic tests and prediction models' of the STRATOS initiative. (2019). Calibration: The Achilles heel of predictive analytics. BMC Medicine, 17, 230. doi:10.1186/s12916-019-1466-7
- Youden, W. J. (1950). Index for rating diagnostic tests. Cancer, 3(1), 32–35. doi:10.1002/1097-0142(1950)3:1<32::AID-CNCR2820030106>3.0.CO;2-3
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
7.6Spatio-Temporal Machine Learning
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Spatio-Temporal Machine Learning (ML เชิงพื้นที่และเวลา) ใช้กับข้อมูลพื้นที่ที่วัดซ้ำหลายช่วงเวลา (panel: พื้นที่ × ช่วงเวลา เช่น อัตราป่วยไข้เลือดออกรายอำเภอรายปี) เพื่อตอบว่า "แบบจำลองที่เรียนจากช่วงเวลาก่อนหน้า ทำนายช่วงเวลาหลังได้แม่นเพียงใด". DAPH รับไฟล์แผนที่แบบ wide (1 แถวต่อ 1 พื้นที่ และ 1 คอลัมน์ต่อตัวแปรต่อช่วงเวลา เช่น lgsp_1970 … lgsp_1986) แล้วแปลงเป็น 1 แถวต่อพื้นที่ต่อช่วงเวลาให้เอง จากนั้นใช้แบบจำลองและตัวแปรเชิงพื้นที่ชุดเดียวกับ Spatial Machine Learning (หัวข้อ 7.4: พิกัดจุดศูนย์กลาง, W·x, Spatial Block CV, Moran's I ของ residual; Moran, 1950) โดยมีสามส่วนที่ต่างออกไป: (1) ชุดทดสอบคือช่วงเวลาท้าย ๆ (เช่น 30% สุดท้ายของช่วงเวลา) ไม่ใช่แถวที่สุ่ม — แบบจำลองถูกวัดกับปีที่ไม่เคยเห็น; (2) W·x คำนวณภายในช่วงเวลาเดียวกัน และแต่ละพื้นที่อยู่บล็อกเดิมทุกช่วงเวลา; (3) เลือกเพิ่มตัวแปรเชิงเวลาได้สองตัว คือ ค่าผลลัพธ์ของพื้นที่เดียวกันในช่วงก่อนหน้า (lag 1 ช่วง) และลำดับของช่วงเวลา (period index).
Spatio-Temporal Machine Learning works on area data measured over several periods (a panel: areas × periods, e.g. yearly dengue rates by district) and answers "how well does a model trained on earlier periods predict later periods". DAPH takes a wide map file (one row per area and one column per variable and period, e.g. lgsp_1970 … lgsp_1986), reshapes it to one row per area and period itself, and then uses the same models and spatial features as Spatial Machine Learning (section 7.4: centroid coordinates, W·x, Spatial Block CV, Moran's I of the residuals; Moran, 1950), with three differences: (1) the test set is the last periods (e.g. the last 30% of the periods), not random rows, so the models are scored on years they never saw; (2) W·x is computed within each period, and every area keeps the same block in all periods; (3) two optional time features: the same area's outcome in the previous period (a 1-period lag) and the position of the period (period index).
ใช้เมื่อใด: เมื่อต้องการทดสอบความสามารถพยากรณ์ไปข้างหน้าของแบบจำลองระดับพื้นที่ เช่น ใช้ข้อมูล 2557–2563 ทำนายอัตราป่วยรายอำเภอปี 2564–2566 (การตรวจสอบตามเวลา หรือ temporal validation; Roberts et al., 2017; Meyer et al., 2018). ไม่ควรใช้เมื่อ: ต้องการขนาดผลของตัวแปรทำนาย (ใช้ Spatial Panel Regression หัวข้อ 6.3); ข้อมูลเป็นแบบ long (หน้าจอนี้รับเฉพาะแบบ wide); มีพื้นที่ใดขาดข้อมูลในช่วงเวลาใด (DAPH ต้องการค่าครบทุกพื้นที่ทุกช่วงเวลา และอย่างน้อย 30 แถว); มีพื้นที่ช่วงเวลาเดียว (ใช้หัวข้อ 7.4).
When to use: to test how well an area-level model forecasts forward, e.g. use 2014–2020 to predict district rates for 2021–2023 (temporal validation; Roberts et al., 2017; Meyer et al., 2018). Do not use it to estimate effect sizes of predictors (use Spatial Panel Regression, section 6.3), with long-format data (this screen accepts wide files only), when any area misses any period (DAPH needs every area in every period and at least 30 rows), or with a single period per area (use section 7.4).
ข้อมูลที่ใช้ในหัวข้อนี้: ข้อมูลตัวอย่างผู้ป่วยของ DAPH ไม่มีแผนที่และไม่มีพื้นที่ที่วัดซ้ำ จึงใช้ข้อมูลสาธารณะ Produc ที่มากับ R package plm (Croissant & Millo, 2008): 48 รัฐของสหรัฐอเมริกา × 17 ปี (1970–1986) เชื่อมกับแผนที่รัฐจาก spData::us_states (ตัด District of Columbia) — ไฟล์เดียวกับหัวข้อ 6.3. ตัวแปร (ลอการิทึมธรรมชาติ): lgsp = ผลิตภัณฑ์มวลรวมของรัฐ, lpcap = ทุนภาครัฐ, lpc = ทุนภาคเอกชน, lemp = การจ้างงานนอกภาคเกษตร; และ unemp = อัตราการว่างงาน (%). สคริปต์ในข้อ 3 สร้าง produc48.zip สำหรับเปิดใน DAPH. ในงานสาธารณสุขให้แทน lgsp ด้วยอัตราป่วยรายพื้นที่รายปี.
Data used in this section: the DAPH patient example has no map and no repeated areas, so this section uses the public Produc panel shipped with the R package plm (Croissant & Millo, 2008): 48 US states × 17 years (1970–1986), joined to state polygons from spData::us_states (District of Columbia dropped) — the same file as section 6.3. Variables (natural logs): lgsp = gross state product, lpcap = public capital, lpc = private capital, lemp = non-agricultural employment; and unemp = unemployment rate (%). The script in step 3 writes produc48.zip to open in DAPH. In public-health work, lgsp would be a yearly disease rate per area.
lgsp ของแต่ละรัฐในปี 1982–1986 ได้แม่นเพียงใด? ใน DAPH: Spatio-Temporal Machine Learning, รหัสพื้นที่ = NAME, ชุดผลลัพธ์ = lgsp, ชุดตัวแปรทำนาย = lpcap, lpc, lemp, unemp, Weights = Queen contiguity, ค่าอื่นเป็นค่าเริ่มต้น. ผลบนปีทดสอบ (240 แถว): Random Forest R² = 0.994 (95% CI 0.992 ถึง 0.995), Linear Regression R² = 0.992 (95% CI 0.989 ถึง 0.994), Elastic Net R² = 0.650. เมื่อเพิ่ม lag 1 ปีและ period index: Linear Regression R² = 0.998 แต่ residual จับกลุ่มเชิงพื้นที่ชัดเจน (Moran's I = 0.7843).lgsp in 1982–1986? In DAPH: Spatio-Temporal Machine Learning, area ID = NAME, outcome set = lgsp, predictor sets = lpcap, lpc, lemp, unemp, Weights = Queen contiguity, everything else at its default. Result on the test years (240 rows): Random Forest R² = 0.994 (95% CI 0.992 to 0.995), Linear Regression R² = 0.992 (95% CI 0.989 to 0.994), Elastic Net R² = 0.650. With the 1-year lag and the period index added: Linear Regression R² = 0.998, but the residuals cluster strongly in space (Moran's I = 0.7843).2หลักการและสูตรLogic and Formula
- yit, xit, zi
- ผลลัพธ์และตัวแปรทำนายรายช่วงเวลาของพื้นที่ i ในช่วง t และตัวแปรที่คงที่ตามเวลา. DAPH จับชุดคอลัมน์จากชื่อ: ชื่อตัวแปร + (ขีด _ . - หรือไม่มี) + ปี 4 หลัก (19xx, 20xx หรือ 25xx) หรือเลขลำดับ 1–3 หลัก เช่น
TB_2557,wave2; ใช้เฉพาะช่วงเวลาที่ทุกชุดที่เลือกมีร่วมกัน. ตัวแปรคงที่ตามเวลาที่มีค่าไม่ซ้ำกันตั้งแต่ 90% ของจำนวนพื้นที่ขึ้นไป (เป็นเหมือนรหัสพื้นที่) ถูกตัดออกพร้อมหมายเหตุoutcome and per-period predictors of area i in period t, and time-invariant predictors. DAPH finds the column sets by name: variable name + (_ . - or nothing) + a 4-digit year (19xx, 20xx or 25xx) or a 1–3 digit number, e.g.TB_2557,wave2; only the periods shared by every chosen set are used. A time-invariant predictor with distinct values in 90% or more of the areas (it acts like an area ID) is dropped with a note - ρ, Ttrain
- สัดส่วน Train ที่เลือก (เริ่มต้น 0.7) และจำนวนช่วงเวลาที่ใช้ฝึก ซึ่งปัดเป็นจำนวนช่วงเวลาเต็ม (ปัดครึ่งไปหาเลขคู่ เช่น round(3.5) = 4 เหมือน R) ทำให้ไม่มีปีใดอยู่ทั้งสองฝั่ง. DAPH ใช้การกันช่วงเวลาท้ายเสมอแม้จะไม่ได้ติ๊กช่อง Train/Test Split และบรรทัด Validation แสดงสัดส่วนแถวจริงปัดเป็นจำนวนเต็มร้อยละ (เช่น 12 จาก 17 ปี = 576 จาก 816 แถว แสดงเป็น 71/29)the chosen Train share (default 0.7) and the number of training periods, rounded to whole periods (halves round to even, round(3.5) = 4, as in R), so no year falls on both sides. DAPH always holds out the later periods, even when the Train/Test Split box is unticked, and its Validation line shows the actual row shares rounded to whole percent (e.g. 12 of 17 years = 576 of 816 rows shows as 71/29)
- wij, block(i)
- น้ำหนักแบบ row-standardised ชุดเดียวกับหัวข้อ 7.4 สร้างครั้งเดียวจาก N พื้นที่ แล้วใช้คำนวณ W·x แยกทีละช่วงเวลา (ไม่ผสมปีต่างกัน); บล็อก k-means คำนวณจากจุดศูนย์กลางของพื้นที่ ครั้งเดียว แล้วใช้บล็อกเดิมทุกช่วงเวลา. จำนวนบล็อก K = max(2, min(B, ⌊N/5⌋)). DAPH รายงานขนาดบล็อกเป็นจำนวนแถว (= จำนวนพื้นที่ × จำนวนช่วงเวลา)the row-standardised weights of section 7.4, built once from the N areas and applied to each period separately (years are never mixed); the k-means blocks are computed once from the area centroids and kept in every period. Number of blocks K = max(2, min(B, ⌊N/5⌋)). DAPH reports block sizes in rows (= areas × periods)
- ylag, τt
- "เพิ่มตัวแปรหน่วงเวลา 1 ช่วง" = ค่าผลลัพธ์ของพื้นที่เดียวกันในช่วงก่อนหน้า (ต้องมีอย่างน้อย 3 ช่วงเวลา; ช่วงแรกถูกตัดเพราะไม่มีค่าก่อนหน้า) และถ้าเปิด W·x จะได้ค่าเฉลี่ยของเพื่อนบ้านในช่วงก่อนหน้าด้วย (
W_ชื่อ_lag1); ใช้เฉพาะข้อมูลในอดีต. "เพิ่มตัวแปรลำดับช่วงเวลา" = 0, 1, 2, … นับจากช่วงแรกที่เหลือ. ตัวแปรนี้เข้าแบบจำลองเป็นตัวเลขเสมอ แบบจำลองเชิงเส้นจึงต่อแนวโน้มไปยังช่วงเวลาทดสอบได้ แต่แบบจำลองกลุ่มต้นไม้ทำนายเกินช่วงค่าที่ใช้ฝึกไม่ได้"Add 1-period lag of the outcome" = the same area's outcome in the previous period (needs at least 3 periods; the first period is dropped because it has no previous value), plus, with W·x on, the neighbours' previous-period average (W_name_lag1); past information only. "Add period index" = 0, 1, 2, … from the first remaining period. It always enters the models as a number, so a linear model can carry the trend into the test periods, whereas tree-based models cannot predict beyond the range seen in training - eit, Ī
- residual แบบ out-of-fold ของแบบจำลองที่ดีที่สุดในแต่ละช่วงเวลา. DAPH คำนวณ Moran's I และการสลับ 999 ครั้งแยกทีละช่วงเวลา แล้วรายงานค่าเฉลี่ยของ It, ค่าเฉลี่ยของ z และมัธยฐานของค่า p รายช่วงเวลา (มัธยฐานของค่า p เป็นตัวสรุป ไม่ใช่การทดสอบรวมแบบเป็นทางการ); ช่วงเวลาที่ใช้รวมช่วงทดสอบด้วย. รายงาน Word ให้อีกค่าหนึ่งด้วย คือ Moran's I ของ residual เฉลี่ยตลอดทุกช่วงเวลาของแต่ละพื้นที่ (ēi) พร้อมค่า p จากการสลับ 999 ครั้ง ซึ่งบอกว่าส่วนที่แบบจำลองพลาดซ้ำ ๆ จับกลุ่มตามพื้นที่หรือไม่. การสลับใช้ seed 12345 รันซ้ำจึงได้ค่าเดิมthe best model's out-of-fold residuals in each period. DAPH computes Moran's I and 999 permutations period by period and reports the mean of the It, the mean z and the median of the per-period p values (a median p is a summary, not a formal combined test); the periods include the test periods. The Word report adds Moran's I of each area's residual averaged over all periods (ēi), with its own 999-permutation p, which shows whether what the model persistently misses clusters in space. The permutations use seed 12345, so a rerun gives the same values
สองคำถามที่ต่างกัน: ชุดทดสอบตามเวลาวัดว่าแบบจำลองทำนายอนาคตของพื้นที่ที่เคยเห็นได้ดีเพียงใด ส่วน Spatial Block CV วัดการทำนายพื้นที่ที่ไม่เคยเห็น. ใน DAPH, Spatial Block CV ใช้ทุกแถวทุกช่วงเวลา รวมช่วงทดสอบ (แบบจำลองของแต่ละ fold ฝึกด้วยพื้นที่ในบล็อกอื่นทุกปี) และ R² ของ CV นี้เป็นตัวเลือกแบบจำลองที่ดีที่สุด ช่วงทดสอบจึงไม่ได้แยกขาดจากการเลือกแบบจำลองโดยสมบูรณ์ ตามที่รายงานของ DAPH ระบุไว้. ค่า R², RMSE, MAE และ 95% CI แบบ bootstrap คำนวณแบบเดียวกับหัวข้อ 7.4. Hyperparameter เป็นค่าเริ่มต้นของแต่ละอัลกอริทึม (Elastic Net ของ Zou & Hastie, 2005: alpha = 1, l1_ratio = 0.5) เว้นแต่เลือก Optuna ซึ่งปรับค่าบนชุดฝึกด้วย fold แบบบล็อก.
Two different questions: the temporal test set measures how well the model predicts the future of areas it has seen; Spatial Block CV measures prediction for areas it has not seen. In DAPH, Spatial Block CV uses every row of every period, test periods included (each fold's model is trained on the other blocks' areas in all years), and its R² chooses the best model, so the test periods are not fully separate from model selection as DAPH's report states. R², RMSE, MAE and the bootstrap 95% CIs are computed as in section 7.4. Hyperparameters are each algorithm's defaults (Elastic Net, Zou & Hastie, 2005: alpha = 1, l1_ratio = 0.5) unless Optuna is chosen, which tunes on block folds of the training rows.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
สคริปต์สร้างไฟล์ wide สำหรับ DAPH, จัดข้อมูลแบบเดียวกับที่ DAPH แปลง (เรียงทีละปี), สร้างตัวแปรเชิงพื้นที่และเชิงเวลา, แบ่งช่วงทดสอบ แล้วคำนวณซ้ำทุกค่าที่กำหนดแน่นอนได้ (Linear Regression และ Elastic Net) ในสองการวิเคราะห์: A = ค่าเริ่มต้นของ Tab 2 และ B = เพิ่ม lag 1 ปีและ period index โดยเลือกเฉพาะ Linear Regression กับ Elastic Net (เพื่อให้ Moran's I มาจาก residual ของ Linear Regression). DAPH ไม่แสดงว่าแต่ละรัฐอยู่บล็อกใด จึงอ่านจากโปรแกรมคำนวณของ DAPH และพิมพ์ไว้ในสคริปต์.
The script writes the wide file for DAPH, arranges the data as DAPH reshapes it (year by year), builds the spatial and time features, splits off the test years and recomputes every deterministic value (Linear Regression and Elastic Net) in two analyses: A = the Tab 2 defaults, and B = with the 1-year lag and the period index and only Linear Regression and Elastic Net ticked (so Moran's I comes from the Linear Regression residuals). DAPH does not show which block each state is in, so the list was read from DAPH's engine and is typed into the script.
# Data: the DAPH example dataset (PD cohort) has no map and no repeated areas, so this section
# uses a public panel: Produc (R package plm; 48 US states x 17 years, 1970-1986) joined to the
# state polygons of spData::us_states (District of Columbia dropped), the same file as section 6.3.
library(sf); library(spdep); library(plm); library(glmnet)
data(us_states, package = "spData"); data(Produc, package = "plm")
us <- us_states[us_states$NAME != "District of Columbia", "NAME"]
us <- us[order(us$NAME, method = "radix"), ] # one row per state, as in the DAPH file
Produc$state <- as.character(Produc$state)
Produc$state[Produc$state == "TENNESSE"] <- "TENNESSEE" # spelling used in plm
key <- setNames(us$NAME, toupper(gsub(" ", "_", us$NAME)))
P <- transform(Produc, NAME = key[state], lgsp = log(gsp), lpcap = log(pcap),
lpc = log(pc), lemp = log(emp))
P <- P[order(P$year, P$NAME, method = "radix"), # long table, year by year (as DAPH)
c("NAME", "year", "lgsp", "lpcap", "lpc", "lemp", "unemp")]
# Wide file for DAPH: one row per state, one column per variable and year (lgsp_1970 ...)
wide <- reshape(P, idvar = "NAME", timevar = "year", direction = "wide", sep = "_")
st_write(merge(us, wide, by = "NAME"), "produc48.shp", quiet = TRUE,
delete_dsn = file.exists("produc48.shp"))
utils::zip("produc48.zip", paste0("produc48", c(".shp", ".shx", ".dbf", ".prj")), flags = "-9Xq")
# 1) Spatial features: centroid in longitude/latitude degrees (planar, as DAPH), Queen W,
# and W*x computed within each year
sf_use_s2(FALSE)
xy <- st_coordinates(st_centroid(st_geometry(st_transform(us, 4326))))
lw <- nb2listw(poly2nb(us, queen = TRUE), style = "W")
i <- match(P$NAME, us$NAME)
P$coord_x <- xy[i, "X"]; P$coord_y <- xy[i, "Y"]
xs <- c("lpcap", "lpc", "lemp", "unemp")
for (v in xs) P[[paste0("W_", v)]] <- ave(P[[v]], P$year, FUN = function(x) lag.listw(lw, x))
c(links = sum(card(lw$neighbours)), rows = nrow(P), sd_lgsp = round(sd(P$lgsp), 2))
round(P[P$NAME == "Ohio" & P$year == 1970, -1], 6)
# 2) Spatial blocks: DAPH's k-means block of each state (alphabetical order). DAPH does not print
# this list (it was read from the DAPH engine); R's kmeans() reaches a different local solution.
blk <- as.integer(strsplit("525231155244435511144542321131134321153532112143", "")[[1]])
P$blk <- blk[i]
table(blk) # states per block (DAPH prints rows = states x years)
ctr <- apply(xy, 2, function(v) tapply(v, blk, mean)) # block centres
all(apply(xy, 1, function(p) which.min(colSums((t(ctr) - p)^2))) == blk) # k-means condition
# 3) Models as DAPH fits them with library defaults: OLS and Elastic Net
# (alpha = 1, l1_ratio = 0.5, predictors standardised on the fitting rows)
ols <- function(f, tr, te) predict(lm(f, data = tr), newdata = te)
enet <- function(f, tr, te, a = 1, r = 0.5) {
X <- model.matrix(f, tr)[, -1]; y <- model.response(model.frame(f, tr))
m <- colMeans(X); s <- sqrt(colMeans(sweep(X, 2, m)^2)); cy <- sqrt(mean((y - mean(y))^2))
lam <- a * (1 - r) + a * r / cy # glmnet form of the same penalty
g <- glmnet(scale(X, m, s), y / cy, alpha = a * r / cy / lam, lambda = lam,
standardize = FALSE, thresh = 1e-14)
cy * drop(predict(g, scale(model.matrix(f, te)[, -1], m, s)))
}
perf <- function(y, p) c(R2 = 1 - sum((y - p)^2) / sum((y - mean(y))^2),
RMSE = sqrt(mean((y - p)^2)), MAE = mean(abs(y - p)))
run <- function(D, f, train) { # later-period hold-out + Spatial Block CV on all rows
y <- D[[all.vars(f)[1]]]
fits <- c(ols = ols, enet = enet)
test <- sapply(fits, function(fit) perf(y[!train], fit(f, D[train, ], D[!train, ])))
oof <- sapply(fits, function(fit) {
p <- numeric(nrow(D))
for (b in 1:5) p[D$blk == b] <- fit(f, D[D$blk != b, ], D[D$blk == b, ])
p })
list(test = test, cv = apply(oof, 2, function(p) perf(y, p)), oof = oof)
}
# 4) Analysis A (Tab 2 defaults): train on the first round(0.7 x 17) = 12 years, test on 5
fA <- lgsp ~ lpcap + lpc + lemp + unemp + coord_x + coord_y + W_lpcap + W_lpc + W_lemp + W_unemp
ntr <- round(17 * 0.7)
trainA <- P$year <= 1969 + ntr
c(n_train = sum(trainA), n_test = sum(!trainA), last_train_year = 1969 + ntr)
round(c(max_lgsp_train = max(P$lgsp[trainA]), max_lgsp_test = max(P$lgsp[!trainA])), 2)
A <- run(P, fA, trainA)
print(round(A$test, 6), digits = 8) # test years 1982-1986
print(round(A$cv, 6), digits = 8) # Spatial Block CV, all 816 rows
# 5) Analysis B: + 1-year lag of the outcome and a period index (1970 has no lag and is dropped)
Q <- P
Q$lgsp_lag1 <- ave(Q$lgsp, Q$NAME, FUN = function(v) c(NA, head(v, -1)))
Q <- Q[Q$year > 1970, ]
Q$period_idx <- Q$year - 1971
Q$W_lgsp_lag1 <- ave(Q$lgsp_lag1, Q$year, FUN = function(x) lag.listw(lw, x))
fB <- update(fA, . ~ . + lgsp_lag1 + period_idx + W_lgsp_lag1)
trainB <- Q$year <= 1970 + round(16 * 0.7)
c(n_train = sum(trainB), n_test = sum(!trainB), last_train_year = 1970 + round(16 * 0.7))
round(Q[Q$NAME == "Ohio" & Q$year == 1971, c("lgsp_lag1", "period_idx", "W_lgsp_lag1")], 6)
B <- run(Q, fB, trainB)
print(round(B$test, 6), digits = 8)
print(round(B$cv, 6), digits = 8)
# 6) Moran's I of the OLS out-of-fold residuals: year by year (Tab 3 reports their mean) and of
# each state's residual averaged over the years (the Word report's time-averaged value)
E <- matrix(Q$lgsp - B$oof[, "ols"], nrow = 48) # 48 states x 16 years
Ik <- apply(E, 2, function(e) moran(e, lw, n = 48, S0 = Szero(lw))$I)
round(c(mean_I = mean(Ik), min_I = min(Ik), max_I = max(Ik),
time_averaged_I = moran(rowMeans(E), lw, n = 48, S0 = Szero(lw))$I), 4)
links rows sd_lgsp
214.00 816.00 1.02
year lgsp lpcap lpc lemp unemp coord_x coord_y W_lpcap W_lpc W_lemp W_unemp
545 1970 11.70596 10.78555 11.57492 8.263771 5.4 -82.79116 40.29223 9.987703 10.88047 7.393473 5.46
blk
1 2 3 4 5
14 8 9 8 9
[1] TRUE
# Analysis A
n_train n_test last_train_year
576 240 1981
max_lgsp_train max_lgsp_test
12.85 13.05
ols enet
R2 0.991610 0.650277
RMSE 0.091482 0.590633
MAE 0.071916 0.490233
ols enet
R2 0.975086 0.629125
RMSE 0.161079 0.621483
MAE 0.122544 0.514771
# Analysis B (lag + period index)
n_train n_test last_train_year
528 240 1981
lgsp_lag1 period_idx W_lgsp_lag1
546 11.70596 0 10.8874
ols enet
R2 0.998318 0.674365
RMSE 0.040965 0.569929
MAE 0.034303 0.473242
ols enet
R2 0.996797 0.652014
RMSE 0.057573 0.600086
MAE 0.043536 0.495823
mean_I min_I max_I time_averaged_I
0.7843 0.6885 0.8699 0.8967
produc48.zip → Tab 2: ชนิดผลลัพธ์ Spatial · สถิติ Spatio-Temporal Machine Learning · รหัสพื้นที่ (ID) = NAME · ชุดตัวแปรผลลัพธ์ = lgsp · ตัวแปรทำนาย (ชุดรายช่วงเวลา) = lpcap, lpc, lemp, unemp · Weights = Queen contiguity, order 1 (หน้าจอเริ่มที่ Distance band) · ใส่พิกัดจุดศูนย์กลางและ W·x · จำนวนบล็อกพื้นที่ = 5 · ค่าอื่นเป็นค่าเริ่มต้น (5 แบบจำลอง, Train/Test 70/30, Library defaults, seed 12345) = การวิเคราะห์ A. การวิเคราะห์ B: ติ๊กเพิ่ม "เพิ่มตัวแปรหน่วงเวลา 1 ช่วง" และ "เพิ่มตัวแปรลำดับช่วงเวลา" และเลือกเฉพาะ Linear Regression กับ Elastic NetFile > Open: produc48.zip → Tab 2: outcome type Spatial · statistic Spatio-Temporal Machine Learning · Area ID = NAME · Outcome variable set = lgsp · Predictors (per-period sets) = lpcap, lpc, lemp, unemp · Weights = Queen contiguity, order 1 (the screen starts at Distance band) · centroid coordinates and W·x on · Spatial blocks = 5 · everything else at its default (5 models, Train/Test 70/30, Library defaults, seed 12345) = analysis A. Analysis B: also tick "Add 1-period lag of the outcome" and "Add period index (trend)", with only Linear Regression and Elastic Net ticked| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | สถานะStatus |
|---|---|---|---|---|
| คู่เพื่อนบ้าน Queen (48 รัฐ) · จำนวนแถวหลังแปลงQueen neighbour links (48 states) · rows after reshaping | 214 · 816 | 214 · 816 | 0 | ✓ PASS |
| Ohio ปี 1970: coord_x · coord_y (ตรวจครบ 816 แถว)Ohio 1970: coord_x · coord_y (all 816 rows checked) | −82.79116 · 40.29223 | −82.79116 · 40.29223 | 0 | ✓ PASS |
| Ohio ปี 1970: W_lpcap · W_lpc · W_lemp · W_unemp (ตรวจครบ 816 แถว)Ohio 1970: W_lpcap · W_lpc · W_lemp · W_unemp (all 816 rows checked) | 9.987703 · 10.88047 · 7.393473 · 5.46 | 9.987703 · 10.88047 · 7.393473 · 5.46 | < 10−14 | ✓ PASS |
| บล็อกของ DAPH เป็นคำตอบของ k-means (ทุกรัฐอยู่ใกล้จุดศูนย์กลางบล็อกของตนที่สุด)DAPH's blocks are a k-means solution (every state is nearest its own block centre) | TRUE · 14, 8, 9, 8, 9 รัฐTRUE · 14, 8, 9, 8, 9 states | 238, 136, 153, 136, 153 แถว (= รัฐ × 17)238, 136, 153, 136, 153 rows (= states × 17) | — | ✓ PASS |
| A: ช่วงฝึก · ช่วงทดสอบ (แถว)A: training · test periods (rows) | 1970–1981 (576) · 1982–1986 (240) | 1970–1981 (576) · 1982–1986 (240) | 0 | ✓ PASS |
| A: Linear Regression, ปีทดสอบ: R² · RMSE · MAEA: Linear Regression, test years: R² · RMSE · MAE | 0.991610 · 0.091482 · 0.071916 | 0.991610 · 0.091482 · 0.071916 | < 0.000001 | ✓ PASS |
| A: Elastic Net, ปีทดสอบ (เกณฑ์ 0.0001)A: Elastic Net, test years (tolerance 0.0001) | 0.650277 · 0.590633 · 0.490233 | 0.650274 · 0.590636 · 0.490235 | 0.000003 · 0.000003 · 0.000002 | ✓ PASS |
| A: Linear Regression, Spatial Block CV (816 แถว)A: Linear Regression, Spatial Block CV (816 rows) | 0.975086 · 0.161079 · 0.122544 | 0.975086 · 0.161079 · 0.122544 | < 0.000001 | ✓ PASS |
| A: Elastic Net, Spatial Block CV (เกณฑ์ 0.0001)A: Elastic Net, Spatial Block CV (tolerance 0.0001) | 0.629125 · 0.621483 · 0.514771 | 0.629120 · 0.621487 · 0.514774 | 0.000005 · 0.000004 · 0.000003 | ✓ PASS |
| B: ช่วงฝึก · ช่วงทดสอบ (ตัดปี 1970)B: training · test periods (1970 dropped) | 1971–1981 (528) · 1982–1986 (240) | 1971–1981 (528) · 1982–1986 (240) | 0 | ✓ PASS |
| B: Ohio ปี 1971: lgsp_lag1 · period_idx · W_lgsp_lag1 (ตรวจครบ 768 แถว)B: Ohio 1971: lgsp_lag1 · period_idx · W_lgsp_lag1 (all 768 rows checked) | 11.70596 · 0 · 10.8874 | 11.70596 · 0 · 10.8874 | 0 | ✓ PASS |
| B: Linear Regression, ปีทดสอบB: Linear Regression, test years | 0.998318 · 0.040965 · 0.034303 | 0.998318 · 0.040965 · 0.034303 | < 0.000001 | ✓ PASS |
| B: Elastic Net, ปีทดสอบ (เกณฑ์ 0.0001)B: Elastic Net, test years (tolerance 0.0001) | 0.674365 · 0.569929 · 0.473242 | 0.674370 · 0.569925 · 0.473239 | 0.000005 · 0.000004 · 0.000003 | ✓ PASS |
| B: Linear Regression, Spatial Block CV (768 แถว)B: Linear Regression, Spatial Block CV (768 rows) | 0.996797 · 0.057573 · 0.043536 | 0.996797 · 0.057573 · 0.043536 | < 0.000001 | ✓ PASS |
| B: Elastic Net, Spatial Block CV (เกณฑ์ 0.0001)B: Elastic Net, Spatial Block CV (tolerance 0.0001) | 0.652014 · 0.600086 · 0.495823 | 0.652020 · 0.600080 · 0.495819 | 0.000006 · 0.000005 · 0.000004 | ✓ PASS |
| B: Moran's I เฉลี่ยรายปีของ residual ของ Linear Regression (16 ปี)B: mean of the yearly Moran's I of the Linear Regression residuals (16 years) | 0.7843 | 0.7843 | < 10−12 | ✓ PASS |
| B: Moran's I ของ residual เฉลี่ยตลอด 16 ปีของแต่ละรัฐ (รายงาน Word)B: Moran's I of each state's residual averaged over the 16 years (Word report) | 0.8967 | 0.897 (0.8967) | < 10−12 | ✓ PASS |
ค่า DAPH ในตารางมาจากผลของ DAPH (response และ Word) หรือจากโปรแกรมคำนวณของ DAPH โดยตรงเมื่อหน้าจอไม่แสดง (พิกัด, W·x, lag, บล็อก, ค่าทศนิยมเพิ่ม). ความต่างของ Elastic Net (ไม่เกิน 0.00001) มาจาก DAPH หยุดการคำนวณแบบวนซ้ำที่ค่าความคลาดเคลื่อน 0.0001; เมื่อให้วิธีเดียวกันของ DAPH คำนวณจนละเอียดถึง 10−12 ได้ค่าตรงกับ R ทั้ง 6 ตำแหน่ง.
The DAPH values come from DAPH's output (response and Word) or, where the screen does not show them (coordinates, W·x, lags, blocks, extra decimals), directly from DAPH's engine. The Elastic Net differences (at most 0.00001) come from DAPH stopping its iterative fit at tolerance 0.0001; run with DAPH's own method to a tolerance of 10−12, the values equal R's to 6 decimals.
ค่าที่เทียบกับ R ไม่ได้ตรงตัว (จึงไม่ใส่ PASS): ค่าของ Random Forest, XGBoost และ LightGBM, 95% CI แบบ bootstrap และค่า p กับ z ของ Moran's I — เหตุผลเดียวกับหัวข้อ 7.4 (โปรแกรมต่างกันและตัวเลขสุ่มต่างกัน; การสลับของ Moran's I ใน DAPH ใช้ seed 12345 จึงซ้ำได้ใน DAPH แต่ไม่ตรงกับตัวเลขสุ่มของ R). k-means ของ R ได้บล็อกอีกชุดหนึ่ง (8, 8, 9, 11, 12 รัฐ) สคริปต์จึงใช้บล็อกของ DAPH.
What cannot be matched exactly in R (so no PASS is claimed): the Random Forest, XGBoost and LightGBM values, the bootstrap 95% CIs, and the p and z of Moran's I — for the reasons given in section 7.4 (different implementations and random numbers; DAPH's Moran permutations use seed 12345, so they repeat within DAPH but not with R's random numbers). R's k-means finds different blocks (8, 8, 9, 11, 12 states), so the script uses DAPH's blocks.
4การแปลผลและตัวอย่างInterpretation and Example
การวิเคราะห์ A (ค่าเริ่มต้น): บนปีทดสอบ 1982–1986 (240 แถว) — Random Forest R² = 0.994 (95% CI 0.992 ถึง 0.995), RMSE = 0.080; LightGBM 0.993 (95% CI 0.991 ถึง 0.995); XGBoost 0.992 (95% CI 0.991 ถึง 0.994); Linear Regression 0.992 (95% CI 0.989 ถึง 0.994), RMSE = 0.091; Elastic Net 0.650 (95% CI 0.623 ถึง 0.665). Spatial Block CV — Random Forest R² = 0.978 (95% CI 0.975 ถึง 0.980), Linear Regression 0.975 (95% CI 0.972 ถึง 0.978). DAPH เลือก Random Forest (Breiman, 2001). Moran's I ของ residual: Ī = 0.0761, z = 1.016, p = 0.107 (ไม่พบการจับกลุ่มชัดเจน; Moran's I ของ residual เฉลี่ยตลอดช่วงเวลาในรายงาน Word = 0.091, p = 0.133).
Analysis A (defaults): on the test years 1982–1986 (240 rows) — Random Forest R² = 0.994 (95% CI 0.992 to 0.995), RMSE = 0.080; LightGBM 0.993 (95% CI 0.991 to 0.995); XGBoost 0.992 (95% CI 0.991 to 0.994); Linear Regression 0.992 (95% CI 0.989 to 0.994), RMSE = 0.091; Elastic Net 0.650 (95% CI 0.623 to 0.665). Spatial Block CV — Random Forest R² = 0.978 (95% CI 0.975 to 0.980), Linear Regression 0.975 (95% CI 0.972 to 0.978). DAPH retains Random Forest (Breiman, 2001). Moran's I of the residuals: Ī = 0.0761, z = 1.016, p = 0.107 (no clear clustering; the Word report's Moran's I of the residuals averaged over the periods = 0.091, p = 0.133).
อ่านอย่างไร: (1) R² ใกล้ 1 เกือบทุกแบบจำลอง เพราะความต่างของ lgsp ส่วนใหญ่เป็นความต่างระหว่างรัฐใหญ่กับรัฐเล็ก ซึ่งแทบไม่เปลี่ยนในเวลา 17 ปี; R² สูงจึงไม่ได้แปลว่าทำนาย "การเปลี่ยนแปลง" รายปีได้ดี ให้ดู RMSE (หน่วยลอการิทึม) ประกอบ. (2) Random Forest, LightGBM, XGBoost และ Linear Regression ต่างกันน้อยมาก CI ซ้อนกัน ข้อมูลนี้จึงไม่ได้แสดงว่าแบบใดดีกว่าอย่างชัดเจน. (3) Elastic Net ต่ำมาก (0.650) เพราะค่าเริ่มต้น alpha = 1 ลงโทษสัมประสิทธิ์แรงเกินไปสำหรับผลลัพธ์ที่ส่วนเบี่ยงเบนมาตรฐานเพียง 1.02 หน่วยลอการิทึม — ถ้าจะเทียบ Elastic Net อย่างเป็นธรรมให้เลือก Optuna. (4) ค่าบนปีทดสอบ (อนาคตของรัฐที่เคยเห็น) สูงกว่า Spatial Block CV (รัฐที่ไม่เคยเห็น) เพราะตอบคนละคำถาม และ CV ที่ใช้เลือกแบบจำลองรวมปีทดสอบไว้ด้วย. (5) แบบจำลองกลุ่มต้นไม้ทำนายค่านอกช่วงที่เคยเห็นตอนฝึกไม่ได้ ที่นี่ค่า lgsp สูงสุดในปีทดสอบ (13.05) สูงกว่าทุกค่าในช่วงฝึก (สูงสุด 12.85) รัฐที่ใหญ่ที่สุดในปีหลัง ๆ จึงถูกทำนายต่ำกว่าจริงได้.
How to read it: (1) R² is close to 1 for almost every model because most of the variation in lgsp is between large and small states, which barely changes over 17 years; a high R² therefore does not mean that year-to-year change is predicted well — read RMSE (log units) as well. (2) Random Forest, LightGBM, XGBoost and Linear Regression differ very little and their CIs overlap, so these data do not show that one is clearly better. (3) Elastic Net is far lower (0.650) because its default alpha = 1 shrinks the coefficients too hard for an outcome whose SD is only 1.02 log units — to compare Elastic Net fairly, choose Optuna. (4) The test-year values (the future of states already seen) are higher than Spatial Block CV (states never seen) because they answer different questions, and the CV that chose the model also contains the test years. (5) Tree-based models cannot predict outside the range seen in training; here the largest test-year lgsp (13.05) is above every training value (maximum 12.85), so the largest state in the later years can be under-predicted.
การวิเคราะห์ B (เพิ่ม lag 1 ปีและ period index): Linear Regression บนปีทดสอบ R² = 0.998 (95% CI 0.998 ถึง 0.999), RMSE = 0.041 เพราะค่าของปีก่อนหน้าบอกระดับของรัฐได้เกือบหมด. แต่ residual ที่เหลือ (การเปลี่ยนแปลงรายปีที่แบบจำลองจับไม่ได้) จับกลุ่มเชิงพื้นที่ชัดเจน: Ī = 0.7843, z = 8.298, p = 0.001 (มัธยฐานของค่า p รายปี) และค่า I รายปีอยู่ระหว่าง 0.6885 ถึง 0.8699 ทุกปี — รัฐที่อยู่ใกล้กันพลาดไปในทิศเดียวกัน เช่น จากภาวะเศรษฐกิจของภูมิภาค. ควรเพิ่มตัวแปรระดับภูมิภาคหรือใช้ Spatial Panel Regression (หัวข้อ 6.3). ผลนี้เป็นความสัมพันธ์เพื่อการพยากรณ์ ไม่ใช่ผลเชิงเหตุ.
Analysis B (with the 1-year lag and the period index): Linear Regression on the test years has R² = 0.998 (95% CI 0.998 to 0.999), RMSE = 0.041, because the previous year's value carries almost all of a state's level. But what is left (the year-to-year change the model misses) clusters strongly in space: Ī = 0.7843, z = 8.298, p = 0.001 (median of the yearly p values), and every yearly I lies between 0.6885 and 0.8699 — neighbouring states miss in the same direction, e.g. through regional economic conditions. Add regional predictors or use Spatial Panel Regression (section 6.3). These are predictive associations, not causal effects.
ตัวอย่างประโยครายงาน: "แบบจำลองที่ฝึกด้วยข้อมูลปี 1970–1981 ของ 48 รัฐ ทำนาย log ผลิตภัณฑ์มวลรวมของรัฐปี 1982–1986 ได้ใกล้เคียงกันระหว่าง Random Forest (R² = 0.994, 95% CI 0.992 ถึง 0.995) และ Linear Regression (R² = 0.992, 95% CI 0.989 ถึง 0.994); เมื่อเพิ่มค่าของปีก่อนหน้า Linear Regression ได้ R² = 0.998 แต่ residual ยังจับกลุ่มเชิงพื้นที่ (Moran's I เฉลี่ยรายปี = 0.78, permutation p = 0.001)".
Example of a results sentence: "Models trained on 1970–1981 data for 48 states predicted log gross state product in 1982–1986 about equally well with Random Forest (R² = 0.994, 95% CI 0.992 to 0.995) and linear regression (R² = 0.992, 95% CI 0.989 to 0.994); adding the previous year's value raised linear regression to R² = 0.998, but its residuals remained spatially clustered (mean yearly Moran's I = 0.78, permutation p = 0.001)."
📖 References
- Breiman, L. (2001). Random forests. Machine Learning, 45(1), 5–32. doi:10.1023/A:1010933404324
- Croissant, Y., & Millo, G. (2008). Panel data econometrics in R: The plm package. Journal of Statistical Software, 27(2), 1–43. doi:10.18637/jss.v027.i02
- Meyer, H., Reudenbach, C., Hengl, T., Katurji, M., & Nauss, T. (2018). Improving performance of spatio-temporal machine learning models using forward feature selection and target-oriented validation. Environmental Modelling & Software, 101, 1–9. doi:10.1016/j.envsoft.2017.12.001
- Moran, P. A. P. (1950). Notes on continuous stochastic phenomena. Biometrika, 37(1–2), 17–23. doi:10.1093/biomet/37.1-2.17
- Roberts, D. R., Bahn, V., Ciuti, S., Boyce, M. S., Elith, J., Guillera-Arroita, G., Hauenstein, S., Lahoz-Monfort, J. J., Schröder, B., Thuiller, W., Warton, D. I., Wintle, B. A., Hartig, F., & Dormann, C. F. (2017). Cross-validation strategies for data with temporal, spatial, hierarchical, or phylogenetic structure. Ecography, 40(8), 913–929. doi:10.1111/ecog.02881
- Zou, H., & Hastie, T. (2005). Regularization and variable selection via the elastic net. Journal of the Royal Statistical Society: Series B (Statistical Methodology), 67(2), 301–320. doi:10.1111/j.1467-9868.2005.00503.x
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 8 — การวิเคราะห์เส้นทาง (Path Analysis: SEM / GSEM)Chapter 8 — Path Analysis (SEM / GSEM) ✓ Verified
การวิเคราะห์เส้นทาง (Path Analysis) แยกความสัมพันธ์ระหว่างตัวแปรต้นกับตัวแปรตามออกเป็น อิทธิพลทางตรง (direct), อิทธิพลทางอ้อม (indirect) ที่ผ่านตัวแปรส่งผ่าน (mediator) และ อิทธิพลรวม (total) โดยใช้ตัวแปรที่วัดได้โดยตรงเท่านั้น (ถ้ามีตัวแปรแฝง ใช้บทที่ 10) · DAPH ประมาณแต่ละสมการแยกกัน และเลือกโมเดลของสมการตัวแปรตามจากชนิดของตัวแปรตามที่กำหนดไว้ในข้อมูล: SEM แบบเชิงเส้น (OLS) เมื่อ Y ต่อเนื่อง (8.1) · GSEM แบบ binary logit เมื่อ Y มีสองกลุ่ม (8.2) · ordered logit (proportional odds) เมื่อ Y เป็นอันดับ และ multinomial logit เมื่อ Y เป็นหลายกลุ่มไม่มีลำดับ (8.3) · ในกรณีเชิงเส้น อิทธิพลทางอ้อมคือผลคูณสัมประสิทธิ์ a × b พร้อมช่วงเชื่อมั่นแบบ percentile bootstrap (1,000 ชุด) · เมื่อสมการ Y ไม่เชิงเส้น ผลคูณสัมประสิทธิ์ใช้ไม่ได้ DAPH จึงรายงานอิทธิพลทางตรงและทางอ้อมตามธรรมชาติ (NDE/NIE) จาก g-formula บนสเกลอัตราส่วน (OR หรือ RRR) พร้อมช่วงเชื่อมั่นแบบ quasi-Bayesian Monte Carlo · การอ่านผลเป็น "ผลของ" ต้องอาศัยข้อสมมติว่าไม่มีตัวแปรกวนที่ไม่ได้วัด Path analysis splits the association between predictors and an outcome into direct, indirect (through mediators) and total effects, using directly measured variables only (with latent variables use Chapter 10). DAPH fits each equation separately and chooses the outcome equation from the outcome's declared variable type: linear SEM (OLS) for a continuous Y (8.1), GSEM binary logit for a two-level Y (8.2), ordered logit (proportional odds) for an ordinal Y and multinomial logit for an unordered (nominal) Y (8.3). In the linear case the indirect effect is the product of coefficients a × b with a percentile bootstrap interval (1,000 resamples). When the outcome equation is non-linear the product of coefficients is not valid, so DAPH reports the natural direct and indirect effects (NDE/NIE) from the g-formula on a ratio scale (OR or RRR), with quasi-Bayesian Monte Carlo intervals. Reading the results as "effects of" rests on the assumption of no unmeasured confounding.
8.1SEM Path Analysis — Continuous Outcome (direct, indirect, total + model fit)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Path analysis แบบ SEM (structural equation modeling) สำหรับตัวแปรตามต่อเนื่อง แยกความสัมพันธ์ระหว่างตัวแปรต้น (X) กับตัวแปรตาม (Y) ออกเป็น อิทธิพลทางตรง และ อิทธิพลทางอ้อม ที่ผ่านตัวแปรส่งผ่าน (mediator, M) ซึ่งการถดถอยสมการเดียวแยกไม่ได้ ใช้เมื่อทฤษฎีกำหนดลำดับ X → M → Y ไว้ล่วงหน้า ตัวแปรทุกตัววัดได้โดยตรง และตัวแปรตามเป็นตัวแปรต่อเนื่อง · ถ้าตัวแปรตามเป็นสองกลุ่ม อันดับ หรือหลายกลุ่ม ใช้หัวข้อ 8.2–8.3 · ถ้าต้องสร้างตัวแปรแฝงจากหลายข้อคำถาม ใช้ SEM ในบทที่ 10 · ไม่ควรใช้เมื่อลำดับเวลาของ X, M, Y ไม่ชัด หรือเมื่อมีตัวแปรกวนระหว่าง M กับ Y ที่ไม่ได้วัด เพราะอิทธิพลทางอ้อมจะลำเอียง
SEM path analysis (structural equation modeling) with a continuous outcome splits the association between a predictor (X) and an outcome (Y) into a direct effect and an indirect effect through a mediator (M), which a single regression cannot do. Use it when theory fixes the order X → M → Y in advance, every variable is measured directly, and the outcome is continuous. For a binary, ordinal or nominal outcome use 8.2–8.3; when constructs must be built from several items, use the SEM of Chapter 10. Do not use it when the time order of X, M and Y is unclear or when the mediator–outcome relation has unmeasured confounders, because the indirect effect would be biased.
2หลักการและสูตรLogic and Formula
เมื่อตัวแปรต้นทุกตัวที่มีเส้นทางไป Y มีเส้นทางไปตัวแปรส่งผ่านทุกตัวด้วย (ค่าเริ่มต้นของ DAPH) อิทธิพลรวมจาก OLS เท่ากับความชันของ Y บนตัวแปรต้นเพียงอย่างเดียวพอดี (reduced form)
When every predictor with a path to Y also has a path to every mediator (DAPH's default paths), the OLS total effect equals exactly the slope of Y on the predictors alone (the reduced form).
- a_kj, b_j, c'_k
- สัมประสิทธิ์ของเส้นทาง X→M, M→Y และ X→Y (ทางตรง) ไม่มาตรฐาน (B)unstandardized coefficients (B) of the X→M, M→Y and direct X→Y paths
- N, k, RSS
- จำนวนผู้ป่วยที่วิเคราะห์ / จำนวนตัวทำนายในสมการ / ผลรวมกำลังสองของส่วนเหลือpatients analysed / predictors in the equation / residual sum of squares
- A, Ψ
- เมทริกซ์สัมประสิทธิ์ของเส้นทาง / เมทริกซ์ที่มีความแปรปรวน-ความแปรปรวนร่วมของตัวแปรต้น และความแปรปรวนของส่วนเหลือ (RSS/(N−1)) ของแต่ละสมการmatrix of path coefficients / matrix holding the variances and covariances of the predictors and the residual variance (RSS/(N−1)) of each equation
- S, Σ̂, p, q
- เมทริกซ์ความแปรปรวนร่วมที่สังเกตได้ (หารด้วย N−1) / ที่โมเดลกำหนด / จำนวนตัวแปร / จำนวนพารามิเตอร์อิสระ (เส้นทาง + ความแปรปรวนของส่วนเหลือ + ความแปรปรวนและความแปรปรวนร่วมของตัวแปรต้น)observed covariance matrix (divisor N−1) / model-implied matrix / number of variables / free parameters (paths + residual variances + variances and covariances of the predictors)
- χ²₀, df₀
- ของโมเดลฐานที่ให้ตัวแปรทุกตัวไม่สัมพันธ์กัน (independence model) ใช้คำนวณ CFI และ TLIof the baseline model in which all variables are uncorrelated (independence model), used for CFI and TLI
- r_ij, r̂_ij
- สหสัมพันธ์ที่สังเกตได้ / ที่โมเดลกำหนดobserved / model-implied correlations
- ab*, B
- ค่าอิทธิพลทางอ้อมที่คำนวณซ้ำในตัวอย่าง bootstrap แต่ละชุด / จำนวนชุด bootstrapindirect effect recomputed in each bootstrap resample / number of resamples
DAPH คำนวณอย่างไร: DAPH ประมาณสมการแต่ละสมการแยกกันด้วย OLS · เมื่อโมเดลเป็นแบบ recursive และส่วนเหลือของแต่ละสมการไม่สัมพันธ์กัน ค่าสัมประสิทธิ์จาก OLS เท่ากับค่าประมาณแบบ maximum likelihood (ML) ของ SEM ทุกตำแหน่ง แต่ค่าคลาดเคลื่อนมาตรฐาน (SE) ของ DAPH ใช้ RSS/(N−k−1) และค่า p จากการแจกแจง t ของแต่ละสมการ จึงใหญ่กว่า SE แบบ ML ของ lavaan เล็กน้อย (คูณ √(N/(N−k−1)) ซึ่งที่ N = 1,300 ต่างกันไม่ถึง 0.2%) · ช่วงเชื่อมั่นของอิทธิพลทางตรงคือ B ± 1.96 SE · อิทธิพลทางอ้อมคือผลคูณ a × b ตามหลักการลากเส้นทางของ Wright (1934) และทดสอบด้วย percentile bootstrap: สุ่มผู้ป่วยซ้ำแบบใส่คืน 1,000 ชุดด้วย seed คงที่ (12345) ประมาณทั้งสองสมการใหม่ทุกชุด (MacKinnon และคณะ, 2004; Preacher & Hayes, 2008) เพราะการแจกแจงของผลคูณเบ้ การใช้ SE แบบปกติ (Sobel test) จึงไม่เหมาะ · ดัชนีความกลมกลืนคำนวณจาก Σ̂ ตามสูตรข้างบน (Bollen, 1989; Kline, 2016) โดย χ² = (N − 1)FML ตรงกับ lavaan เมื่อตั้ง likelihood = "wishart" (ค่าเริ่มต้นของ lavaan ใช้ N × FML ซึ่งใหญ่กว่า 0.08% ที่ N = 1,300) ส่วน log-likelihood, AIC และ BIC เป็นแบบการแจกแจงปกติเหมือนค่าเริ่มต้นของ lavaan · ข้อควรรู้: เมื่อมีทุกเส้นทาง (ค่าเริ่มต้น) โมเดลเป็น just-identified (df = 0) จึงได้ χ² = 0, CFI = 1, RMSEA = 0, SRMR = 0 เสมอ ดัชนีเหล่านี้ไม่ได้บอกอะไร · จะทดสอบความกลมกลืนได้ต้องตัดเส้นทางที่ทฤษฎีบอกว่าไม่มีออกก่อน เช่น โมเดล 2 ในตัวอย่าง
How DAPH computes it: DAPH fits each equation separately by OLS. For a recursive model whose equations have uncorrelated residuals, the OLS coefficients are exactly the maximum-likelihood (ML) SEM estimates. DAPH's standard errors, however, use RSS/(N−k−1) with t-test p values for each equation, so they are slightly larger than lavaan's ML standard errors (by √(N/(N−k−1)), less than 0.2% at N = 1,300). The 95% CI of a direct effect is B ± 1.96 SE. The indirect effect is the product a × b, following Wright's (1934) path-tracing rules, and is tested with a percentile bootstrap: 1,000 resamples of patients drawn with replacement at a fixed seed (12345), both equations refitted each time (MacKinnon et al., 2004; Preacher & Hayes, 2008); the product has a skewed distribution, so a normal-theory standard error (the Sobel test) is not appropriate. Fit indices come from Σ̂ with the formulas above (Bollen, 1989; Kline, 2016); χ² = (N − 1)FML, which is lavaan with likelihood = "wishart" (lavaan's default N × FML is 0.08% larger at N = 1,300), while the log-likelihood, AIC and BIC are the normal-theory values of lavaan's default. Note: with all paths drawn (the default) the model is just-identified (df = 0), so χ² = 0, CFI = 1, RMSEA = 0 and SRMR = 0 by construction and carry no information. Fit can be tested only after removing a path that theory says is absent, as in model 2 of the example.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(lavaan)
d$apd <- as.integer(d$group == 2) # Treatment group: 1 = CAPD (reference) -> 0, 2 = APD -> 1
# 1) Model 1 (all three paths). DAPH fits each equation by ordinary least squares.
m_eq <- lm(n_peritonitis ~ apd, data = d) # a : APD -> peritonitis episodes
y_eq <- lm(qolscore3 ~ apd + n_peritonitis, data = d) # c' : APD -> QoL (post); b : episodes -> QoL
path <- function(fit, v) {
s <- coef(summary(fit))[v, ]
c(B = s[[1]], SE = s[[2]], lower = s[[1]] - qnorm(0.975) * s[[2]],
upper = s[[1]] + qnorm(0.975) * s[[2]], p = s[[4]])
}
round(rbind(a_apd_to_episodes = path(m_eq, "apd"),
b_episodes_to_qol = path(y_eq, "n_peritonitis"),
direct_apd_to_qol = path(y_eq, "apd")), 4)
a <- coef(m_eq)[["apd"]]; b <- coef(y_eq)[["n_peritonitis"]]; cp <- coef(y_eq)[["apd"]]
round(c(indirect = a * b, total = cp + a * b,
R2_episodes = summary(m_eq)$r.squared, R2_qol = summary(y_eq)$r.squared), 4)
# the total effect equals the slope of QoL (post) on APD alone (reduced form)
round(path(lm(qolscore3 ~ apd, data = d), "apd"), 4)
# 2) Percentile bootstrap: B = 1,000 resamples of patients, both equations refitted each time
set.seed(12345)
boot <- t(replicate(1000, {
i <- sample.int(nrow(d), replace = TRUE)
ai <- coef(lm(n_peritonitis ~ apd, data = d[i, ]))[["apd"]]
fi <- coef(lm(qolscore3 ~ apd + n_peritonitis, data = d[i, ]))
c(indirect = ai * fi[["n_peritonitis"]], total = fi[["apd"]] + ai * fi[["n_peritonitis"]])
}))
p_boot <- function(x) min(1, 2 * min(mean(x <= 0), mean(x >= 0)))
round(rbind(lower = apply(boot, 2, quantile, 0.025), upper = apply(boot, 2, quantile, 0.975),
p = apply(boot, 2, p_boot)), 4)
# 3) Log-likelihood, AIC, BIC of model 1 (normal-theory likelihood, as DAPH reports them)
model1 <- sem('n_peritonitis ~ apd
qolscore3 ~ apd + n_peritonitis', data = d)
round(unclass(fitMeasures(model1, c("npar", "logl", "aic", "bic"))), 3)
# 4) Model 2 (full mediation: direct path removed, df = 1) and its fit indices.
# DAPH uses chi-square = (N - 1) x F_ML, which is lavaan's likelihood = "wishart".
model2 <- sem('n_peritonitis ~ apd
qolscore3 ~ n_peritonitis', data = d, likelihood = "wishart")
round(unclass(fitMeasures(model2, c("chisq", "df", "pvalue", "cfi", "tli", "rmsea", "srmr"))), 4)
y_eq2 <- lm(qolscore3 ~ n_peritonitis, data = d)
round(c(path(y_eq2, "n_peritonitis"), indirect = a * coef(y_eq2)[["n_peritonitis"]]), 4)
# 5) Monte Carlo check: the same bootstrap with 50 other seeds shows how far the limits move
X1 <- cbind(1, d$apd); X2 <- cbind(1, d$apd, d$n_peritonitis)
mc <- t(sapply(1:50, function(s) {
set.seed(s)
r <- replicate(1000, {
i <- sample.int(nrow(d), replace = TRUE)
ai <- lm.fit(X1[i, ], d$n_peritonitis[i])$coefficients[[2]]
fi <- lm.fit(X2[i, ], d$qolscore3[i])$coefficients
c(ai * fi[[3]], fi[[2]] + ai * fi[[3]])
})
c(ind_lower = quantile(r[1, ], 0.025, names = FALSE), ind_upper = quantile(r[1, ], 0.975, names = FALSE),
ind_p = p_boot(r[1, ]), tot_lower = quantile(r[2, ], 0.025, names = FALSE),
tot_upper = quantile(r[2, ], 0.975, names = FALSE), tot_p = p_boot(r[2, ]))
}))
round(rbind(SD = apply(mc, 2, sd), min = apply(mc, 2, min), max = apply(mc, 2, max)), 3)
c(share_of_seeds_total_p_significant = mean(mc[, "tot_p"] < 0.05))
# 1) paths of model 1: B, SE, 95% CI (B +/- z SE), t-test p
B SE lower upper p
a_apd_to_episodes -1.0659 0.0974 -1.2569 -0.8750 0.0000
b_episodes_to_qol -0.8358 0.2809 -1.3863 -0.2852 0.0030
direct_apd_to_qol 1.0651 1.0304 -0.9544 3.0846 0.3015
indirect total R2_episodes R2_qol
0.8909 1.9560 0.0844 0.0098
# reduced form: slope of QoL (post) on APD alone = the total effect
B SE lower upper p
1.9560 0.9889 0.0178 3.8942 0.0481
# 2) percentile bootstrap (R random numbers; DAPH uses its own)
indirect total
lower 0.2907 0.0968
upper 1.5171 3.8745
p 0.0080 0.0420
# 3) model 1: log-likelihood, AIC, BIC
npar logl aic bic
5.000 -8159.874 16329.748 16355.598
# 4) model 2 (no direct path): fit, then its b path and indirect effect
chisq df pvalue cfi tli rmsea srmr
1.0697 1.0000 0.3010 0.9994 0.9983 0.0073 0.0112
B SE lower upper p indirect
-0.9202 0.2688 -1.4469 -0.3934 0.0006 0.9808
# 5) the same bootstrap with 50 other seeds
ind_lower ind_upper ind_p tot_lower tot_upper tot_p
SD 0.025 0.027 0.003 0.094 0.091 0.011
min 0.237 1.453 0.000 -0.201 3.673 0.026
max 0.352 1.579 0.012 0.197 4.116 0.070
share_of_seeds_total_p_significant
0.56
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| เส้นทาง a (APD → จำนวนครั้งที่อักเสบ): B / SEPath a (APD → episodes): B / SE | −1.0659 / 0.0974 | −1.0659 / 0.0974 | < 5e−5 | ✓ PASS |
| เส้นทาง b (จำนวนครั้งที่อักเสบ → QoL): B / 95% CI / pPath b (episodes → QoL): B / 95% CI / p | −0.8358 / −1.386 to −0.285 / 0.003 | −0.836 / −1.386 to −0.285 / 0.003 | < 5e−4 | ✓ PASS |
| อิทธิพลทางตรง c′ (APD → QoL): B / 95% CI / pDirect effect c′ (APD → QoL): B / 95% CI / p | 1.0651 / −0.954 to 3.085 / 0.3015 | 1.065 / −0.954 to 3.085 / 0.301 | < 5e−4 | ✓ PASS |
| อิทธิพลทางอ้อม a × b / อิทธิพลรวมIndirect a × b / total effect | 0.8909 / 1.9560 | 0.8909 / 1.956 | < 5e−5 | ✓ PASS |
| R² ของสมการ M / สมการ YR² of the M equation / Y equation | 0.0844 / 0.0098 | 0.0844 / 0.0098 | < 5e−5 | ✓ PASS |
| Bootstrap 95% CI ของอิทธิพลทางอ้อม (เกณฑ์ ±0.11)*Bootstrap 95% CI of the indirect effect (tolerance ±0.11)* | 0.291 to 1.517 | 0.331 to 1.480 | 0.040 / 0.037 | ✓ PASS |
| Bootstrap p ของอิทธิพลทางอ้อม (เกณฑ์ ±0.013)*Bootstrap p of the indirect effect (tolerance ±0.013)* | 0.008 | 0.002 | 0.006 | ✓ PASS |
| Bootstrap 95% CI ของอิทธิพลรวม (เกณฑ์ ±0.40)*Bootstrap 95% CI of the total effect (tolerance ±0.40)* | 0.097 to 3.875 | −0.165 to 3.856 | 0.262 / 0.019 | ✓ PASS |
| Bootstrap p ของอิทธิพลรวม (เกณฑ์ ±0.047)*Bootstrap p of the total effect (tolerance ±0.047)* | 0.042 | 0.072 | 0.030 | ✓ PASS |
| โมเดล 1: log-likelihood / AIC / BICModel 1: log-likelihood / AIC / BIC | −8159.874 / 16329.748 / 16355.598 | −8159.874 / 16329.748 / 16355.598 | < 5e−4 | ✓ PASS |
| โมเดล 2: χ² / df / pModel 2: χ² / df / p | 1.0697 / 1 / 0.3010 | 1.0697 / 1 / 0.3010 | < 5e−5 | ✓ PASS |
| โมเดล 2: CFI / TLI / RMSEA / SRMRModel 2: CFI / TLI / RMSEA / SRMR | 0.9994 / 0.9983 / 0.0073 / 0.0112 | 0.9994 / 0.9983 / 0.0073 / 0.0112 | < 5e−5 | ✓ PASS |
| โมเดล 2: เส้นทาง b (95% CI) / อิทธิพลทางอ้อมModel 2: path b (95% CI) / indirect effect | −0.9202 (−1.447 to −0.393) / 0.9808 | −0.920 (−1.447 to −0.393) / 0.981 | < 5e−4 | ✓ PASS |
* R และ DAPH ใช้ตัวสร้างเลขสุ่มต่างกัน ค่าจาก bootstrap จึงต่างกันได้ด้วยความคลาดเคลื่อนจากการสุ่ม (Monte Carlo) เพียงอย่างเดียว · เกณฑ์ = 3 เท่าของส่วนเบี่ยงเบนมาตรฐานของผลต่าง R − DAPH โดย SD ระหว่าง seed วัดจากส่วนที่ 5 ของสคริปต์ (50 seed: ขอบ CI ทางอ้อม 0.025–0.027, ทางรวม 0.091–0.094; ค่า p ทางอ้อม 0.003, ทางรวม 0.011) และ SD ของผลต่าง = √2 × SD · ค่าอื่นทุกค่าในตารางเป็นค่าแน่นอน (ไม่มีการสุ่ม) และตรงกันตามจำนวนตำแหน่งทศนิยมที่แสดง · ทวนสอบ 2 ต.ค. 2026: R 4.3.3, lavaan 0.6-21 บนไฟล์ example_en.csv
* R and DAPH use different random-number generators, so bootstrap results differ by Monte Carlo error alone. Tolerance = 3 × the standard deviation of the R − DAPH difference, with the between-seed SD taken from part 5 of the script (50 seeds: indirect CI limits 0.025–0.027, total CI limits 0.091–0.094; p value indirect 0.003, total 0.011) and the SD of a difference = √2 × SD. Every other quantity in the table is exact (no random numbers) and agrees to the decimals shown. Verified 2 Oct 2026: R 4.3.3, lavaan 0.6-21 on example_en.csv.
4การแปลผลและตัวอย่างInterpretation and Example
สัญลักษณ์: ตารางและรายงานของ DAPH ใช้ B = สัมประสิทธิ์ไม่มาตรฐาน (การเปลี่ยนของตัวแปรตามต่อการเปลี่ยนตัวแปรต้น 1 หน่วย) ไม่ใช่ค่ามาตรฐาน β · ตัวแปรต้นแบบสองกลุ่มถูกเปลี่ยนเป็น 0/1 โดยรหัสต่ำสุดเป็นกลุ่มอ้างอิง (ที่นี่ CAPD = 0, APD = 1) ตัวแปรกลุ่มที่มีตั้งแต่ 3 ระดับถูกแยกเป็นตัวแปรหุ่น (dummy) และมีการทดสอบ Wald ร่วม (ดู 8.3) · ตัวอย่าง: กลุ่ม APD มีเยื่อบุช่องท้องอักเสบน้อยกว่า 1.066 ครั้ง (95% CI −1.257 ถึง −0.875) และการอักเสบแต่ละครั้งสัมพันธ์กับคะแนนคุณภาพชีวิตหลังติดตามต่ำลง 0.836 คะแนน (95% CI −1.386 ถึง −0.285) อิทธิพลทางอ้อม B = 0.891 (95% CI แบบ bootstrap 0.331 ถึง 1.480, p = 0.002) คือส่วนต่างของคะแนนคุณภาพชีวิตระหว่าง APD กับ CAPD ที่ไปด้วยกันกับจำนวนครั้งที่อักเสบที่น้อยกว่า · อิทธิพลทางตรง B = 1.065 (95% CI −0.954 ถึง 3.085, p = 0.301) ไม่มีนัยสำคัญ ซึ่งไม่ได้แปลว่าไม่มีอิทธิพลทางตรง ช่วงเชื่อมั่นยังครอบคลุมค่าได้ถึง 3 คะแนน · อิทธิพลรวม B = 1.956 อยู่ใกล้เส้นแบ่งนัยสำคัญ: DAPH ได้ 95% CI −0.165 ถึง 3.856 (p = 0.072) แต่ bootstrap ของ R ได้ 0.097 ถึง 3.875 (p = 0.042) และการถดถอย Y บน X อย่างเดียวได้ p = 0.048 · ที่ B = 1,000 ค่า p ของอิทธิพลรวมเปลี่ยนตาม seed ระหว่าง 0.026 ถึง 0.070 (มีนัยสำคัญใน 56% ของ 50 seed) จึงควรรายงานว่าก้ำกึ่ง ไม่ควรสรุปว่า "ไม่มีผลรวม" · ประโยคสำหรับวารสาร: "In a path model of 1,300 patients, APD was associated with fewer peritonitis episodes (B = −1.066, 95% CI −1.257 to −0.875), and each episode with a lower post-treatment QoL score (B = −0.836, 95% CI −1.386 to −0.285); the indirect association of APD with QoL through peritonitis was B = 0.891 (bootstrap 95% CI 0.331 to 1.480), whereas the direct association was not statistically significant (B = 1.065, 95% CI −0.954 to 3.085)."
Notation: DAPH's table and report use B = the unstandardized coefficient (change in the outcome per one-unit change in the predictor), not the standardized β. A two-level predictor is recoded 0/1 with the lowest code as reference (here CAPD = 0, APD = 1); a categorical predictor with three or more levels is split into dummy variables with a joint Wald test (see 8.3). Example: APD patients had 1.066 fewer peritonitis episodes (95% CI −1.257 to −0.875), and each episode was associated with a 0.836-point lower QoL score at the end of follow-up (95% CI −1.386 to −0.285). The indirect effect B = 0.891 (bootstrap 95% CI 0.331 to 1.480, p = 0.002) is the part of the APD–CAPD difference in QoL that goes together with the smaller number of episodes. The direct effect B = 1.065 (95% CI −0.954 to 3.085, p = 0.301) is not statistically significant, which does not mean there is no direct effect: the interval still includes values up to 3 points. The total effect B = 1.956 is borderline: DAPH gives 95% CI −0.165 to 3.856 (p = 0.072), R's bootstrap gives 0.097 to 3.875 (p = 0.042), and regressing Y on X alone gives p = 0.048. With B = 1,000 the total-effect p moved between 0.026 and 0.070 across 50 seeds (significant in 56% of them), so it should be reported as borderline, not as "no total effect". Journal-style sentence: "In a path model of 1,300 patients, APD was associated with fewer peritonitis episodes (B = −1.066, 95% CI −1.257 to −0.875), and each episode with a lower post-treatment QoL score (B = −0.836, 95% CI −1.386 to −0.285); the indirect association of APD with QoL through peritonitis was B = 0.891 (bootstrap 95% CI 0.331 to 1.480), whereas the direct association was not statistically significant (B = 1.065, 95% CI −0.954 to 3.085)."
เกณฑ์ความกลมกลืน (ใช้ได้เฉพาะโมเดลที่ df > 0): Hu & Bentler (1999) เสนอ CFI และ TLI ประมาณ 0.95 ขึ้นไป, RMSEA ไม่เกินประมาณ 0.06 และ SRMR ไม่เกินประมาณ 0.08 · Browne & Cudeck (1992) ถือ RMSEA ≤ 0.05 ว่ากลมกลืนใกล้เคียง และ ≤ 0.08 ว่าพอใช้ · χ² ที่ไม่มีนัยสำคัญหมายถึงข้อมูลไม่ขัดกับโมเดล แต่เมื่อ N ใหญ่ χ² มักมีนัยสำคัญแม้ความคลาดเคลื่อนเล็กน้อย · โมเดล 2 ในตัวอย่าง: χ²(1) = 1.070, p = 0.301, CFI = 0.999, TLI = 0.998, RMSEA = 0.007, SRMR = 0.011 ข้อมูลจึงไม่ขัดกับโมเดลที่ไม่มีเส้นทางตรง (χ² ของโมเดลนี้คือการทดสอบ likelihood-ratio ว่าเส้นทางตรงเป็นศูนย์ และสอดคล้องกับการทดสอบ c′ ในโมเดล 1 คือ p = 0.301 ทั้งคู่) · การส่งผ่าน: ตัดสินจาก CI ของอิทธิพลทางอ้อม (ไม่คร่อม 0 = มีนัยสำคัญ) ไม่ใช่ขั้นตอนของ Baron & Kenny (1986) · การเรียกว่า "full" หรือ "partial" mediation ขึ้นกับว่ามีอำนาจการทดสอบพอจะพบอิทธิพลทางตรงหรือไม่ จึงควรรายงานขนาดและ CI ของทั้งอิทธิพลทางตรงและทางอ้อมแทนการติดป้าย (Zhao และคณะ, 2010) · ข้อจำกัด: เป็นข้อมูลเชิงสังเกต ใช้ภาษาความสัมพันธ์ ("สัมพันธ์กับ") ไม่ใช่ "ทำให้" · การตีความเชิงเหตุผลต้องไม่มีตัวแปรกวนระหว่าง X–Y, X–M และ M–Y ที่ไม่ได้วัด · จำนวนครั้งของการอักเสบเป็นข้อมูลนับ แต่สมการ M ใช้ OLS (อิทธิพลยังอ่านเป็นจำนวนครั้งเฉลี่ยได้ แต่ SE อาศัยสมมติฐานความแปรปรวนคงที่) · ในข้อมูลตัวอย่างนี้ คะแนนคุณภาพชีวิตหลังติดตามเท่ากับคะแนนก่อนเริ่มบวกประมาณ 7.5 คะแนนในผู้ป่วยเกือบทุกคน การวิเคราะห์นี้จึงแยกการเปลี่ยนแปลงระหว่างรักษาออกจากความต่างที่มีอยู่ก่อนเริ่มไม่ได้ งานวิจัยจริงควรปรับด้วยคะแนนก่อนเริ่ม
Fit criteria (meaningful only for models with df > 0): Hu & Bentler (1999) proposed CFI and TLI close to 0.95 or above, RMSEA close to 0.06 or below and SRMR close to 0.08 or below; Browne & Cudeck (1992) regard RMSEA ≤ 0.05 as close fit and ≤ 0.08 as reasonable fit. A non-significant χ² means the data do not contradict the model, but with a large N the χ² is often significant for trivial misfit. Model 2 of the example: χ²(1) = 1.070, p = 0.301, CFI = 0.999, TLI = 0.998, RMSEA = 0.007, SRMR = 0.011, so the data do not contradict the model without a direct path (this χ² is the likelihood-ratio test of a zero direct path and agrees with the test of c′ in model 1: p = 0.301 in both). Mediation: judge it from the CI of the indirect effect (significant if it excludes 0), not from the causal steps of Baron & Kenny (1986). Calling mediation "full" or "partial" depends on whether there was power to detect the direct effect, so report the size and CI of both the direct and the indirect effect instead of the label (Zhao et al., 2010). Limitations: the data are observational, so use associational wording ("associated with"), not "causes". A causal reading requires no unmeasured X–Y, X–M or M–Y confounding. The number of episodes is a count, but its equation is fitted by OLS (the effect still reads as a mean number of episodes, but the SE relies on constant variance). In this example dataset the post-treatment QoL score equals the baseline score plus about 7.5 points for almost every patient, so the analysis cannot separate change during treatment from differences that existed at baseline; a real study would adjust for the baseline score.
📖 References
- Wright, S. (1934). The method of path coefficients. The Annals of Mathematical Statistics, 5(3), 161–215. doi:10.1214/aoms/1177732676
- Bollen, K. A. (1989). Structural Equations with Latent Variables. New York: Wiley. ISBN 978-0-471-01171-2.
- Baron, R. M., & Kenny, D. A. (1986). The moderator–mediator variable distinction in social psychological research: Conceptual, strategic, and statistical considerations. Journal of Personality and Social Psychology, 51(6), 1173–1182. doi:10.1037/0022-3514.51.6.1173
- MacKinnon, D. P., Lockwood, C. M., & Williams, J. (2004). Confidence limits for the indirect effect: distribution of the product and resampling methods. Multivariate Behavioral Research, 39(1), 99–128. doi:10.1207/s15327906mbr3901_4
- Preacher, K. J., & Hayes, A. F. (2008). Asymptotic and resampling strategies for assessing and comparing indirect effects in multiple mediator models. Behavior Research Methods, 40(3), 879–891. doi:10.3758/BRM.40.3.879
- Zhao, X., Lynch, J. G., & Chen, Q. (2010). Reconsidering Baron and Kenny: Myths and truths about mediation analysis. Journal of Consumer Research, 37(2), 197–206. doi:10.1086/651257
- Hu, L., & Bentler, P. M. (1999). Cutoff criteria for fit indexes in covariance structure analysis: Conventional criteria versus new alternatives. Structural Equation Modeling, 6(1), 1–55. doi:10.1080/10705519909540118
- Browne, M. W., & Cudeck, R. (1992). Alternative ways of assessing model fit. Sociological Methods & Research, 21(2), 230–258. doi:10.1177/0049124192021002005
- Kline, R. B. (2016). Principles and Practice of Structural Equation Modeling (4th ed.). New York: Guilford Press. ISBN 978-1-4625-2334-4.
- Rosseel, Y. (2012). lavaan: an R package for structural equation modeling. Journal of Statistical Software, 48(2), 1–36. doi:10.18637/jss.v048.i02
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
8.2GSEM & Causal Mediation — Binary Outcome (NDE / NIE, odds-ratio scale)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
เมื่อตัวแปรตามเป็น สองกลุ่ม (เช่น คุณภาพชีวิตสูง/ต่ำ) สมการของ Y เป็น logit ผลคูณสัมประสิทธิ์ a × b จึง ไม่ใช่ อิทธิพลทางอ้อมที่ถูกต้องบนสเกล odds ratio (OR) เว้นแต่ผลลัพธ์จะเกิดน้อย เพราะ OR เป็นค่าที่ไม่ collapsible: การใส่หรือไม่ใส่ตัวแปรส่งผ่านในโมเดลเปลี่ยนค่า OR ได้แม้ไม่มีตัวแปรกวน · DAPH จึงรายงานอิทธิพลทางตรง ทางอ้อม และรวมด้วย causal mediation แบบ counterfactual: natural direct effect (NDE) และ natural indirect effect (NIE) บนสเกล OR ที่ประมาณด้วย g-formula (mediation formula; VanderWeele, 2015) · ใช้เมื่อ Y เป็นสองกลุ่ม ลำดับ X → M → Y ชัดเจน และเก็บตัวแปรกวนได้ครบ · ถ้าคาดว่าอิทธิพลของ M ต่อ Y ต่างกันระหว่างกลุ่มของ X (exposure–mediator interaction) DAPH ยังใส่พจน์ปฏิสัมพันธ์นี้ไม่ได้
When the outcome is binary (for example high/low quality of life), the Y equation is a logit, and the product a × b is not a valid indirect effect on the odds-ratio (OR) scale unless the outcome is rare, because the OR is non-collapsible: adding or removing the mediator changes the OR even without confounding. DAPH therefore reports the direct, indirect and total effects by counterfactual causal mediation: the natural direct effect (NDE) and natural indirect effect (NIE) on the OR scale, estimated by the g-formula (the mediation formula; VanderWeele, 2015). Use it when Y is binary, the order X → M → Y is clear and the confounders are measured. If the effect of M on Y is expected to differ between levels of X (exposure–mediator interaction), note that DAPH cannot yet include that interaction term.
2หลักการและสูตรLogic and Formula
- x, x*
- ค่าของตัวแปรต้นที่เทียบกัน: DAPH ใช้ x = 1 และ x* = 0 บนสเกลที่ลงรหัสแล้ว (ตัวแปรสองกลุ่มถูกเปลี่ยนเป็น 0/1 โดยรหัสต่ำสุด = 0)contrasted predictor values: DAPH uses x = 1 and x* = 0 on the coded scale (a two-level predictor is recoded 0/1, lowest code = 0)
- p₁₀, p₀₀, p₁₁
- ความน่าจะเป็นเฉลี่ยทั้งประชากรของ Y = 1 ในสามสถานการณ์ counterfactualpopulation-averaged probabilities of Y = 1 in the three counterfactual scenarios
- μ_i(x*), σ_M
- ค่าเฉลี่ยของตัวแปรส่งผ่านของคนที่ i เมื่อ X = x* / ส่วนเบี่ยงเบนมาตรฐานของส่วนเหลือในโมเดลตัวแปรส่งผ่าน (√(RSS/(N−k−1)))mediator mean of person i under X = x* / residual SD of the mediator model (√(RSS/(N−k−1)))
- z_q, w_q
- จุดและน้ำหนักของ Gauss–Hermite สำหรับการแจกแจงปกติมาตรฐาน (24 จุด, Σw = 1)Gauss–Hermite nodes and weights for the standard normal (24 nodes, Σw = 1)
- Σ_ε, b
- เมทริกซ์ความแปรปรวนร่วมของส่วนเหลือของตัวแปรส่งผ่านต่อเนื่อง (หารด้วย N−k−1) / เวกเตอร์สัมประสิทธิ์ M→Yresidual covariance matrix of the continuous mediators (divisor N−k−1) / vector of M→Y coefficients
- θ̂, V̂
- สัมประสิทธิ์ของทั้งสองโมเดลและเมทริกซ์ความแปรปรวนร่วมตามปกติของแต่ละโมเดล (σ_M คงที่)coefficients of both models and each model's usual covariance matrix (σ_M held fixed)
DAPH คำนวณอย่างไร: DAPH เลือกเส้นทางนี้อัตโนมัติเมื่อตัวแปรตามมี 2 ระดับ (หรือประกาศชนิดเป็น binominal) และเปลี่ยนรหัสเป็น 0/1 โดยรหัสต่ำสุดเป็นกลุ่มอ้างอิง · สมการ Y ประมาณด้วย maximum likelihood (logit) · แถว "Direct" ของตัวแปรส่งผ่านในตารางเป็น OR แบบมีเงื่อนไข exp(βM) พร้อม Wald 95% CI · สำหรับตัวแปรต้นที่มีเส้นทางผ่านตัวแปรส่งผ่าน แถว Direct / Indirect / Total คือ NDE / NIE / Total จาก g-formula ซึ่งมีโมเดลตัวแปรส่งผ่านเป็นการถดถอยเชิงเส้นแบบปกติ (ตัวแปรส่งผ่าน 0/1 ใช้ logit และตัวแปรกลุ่มตั้งแต่ 3 ระดับใช้ multinomial logit) · ในการคำนวณ g-formula โมเดลของ Y และของตัวแปรส่งผ่านใส่ตัวแปรต้นทุกตัวเป็นตัวแปรร่วมเสมอ (Y ใส่ตัวแปรส่งผ่านทุกตัวด้วย) แม้ผู้ใช้จะเอาเครื่องหมายบางเส้นทางออก · ตัวแปรต้นที่ไม่มีเส้นทางผ่านตัวแปรส่งผ่านแสดงเป็น OR แบบมีเงื่อนไข · ช่วงเชื่อมั่นและค่า p มาจากการสุ่มพารามิเตอร์ 10,000 ชุดด้วย seed คงที่ (12345) แบบ quasi-Bayesian (Imai และคณะ, 2010; Tingley และคณะ, 2014) · ตัวแปรต้นต่อเนื่อง: DAPH เทียบค่า 0 กับ 1 ของตัวแปรนั้นในทุกคน ถ้า 0 อยู่นอกช่วงข้อมูล (เช่น อายุ) ผลเป็นการคาดการณ์นอกข้อมูล ควรปรับสเกลให้ 0 และ 1 มีความหมายก่อน · สัดส่วนการส่งผ่าน (PM) แสดงในหมายเหตุใต้ตารางเฉพาะเมื่อ CI ของ NIE ไม่คร่อม 1 และ 0 ≤ PM ≤ 1
How DAPH computes it: DAPH takes this route automatically when the outcome has two levels (or is declared binominal) and recodes it 0/1 with the lowest code as reference. The Y equation is fitted by maximum likelihood (logit). The "Direct" row of a mediator in the table is the conditional OR exp(βM) with a Wald 95% CI. For a predictor with a path through a mediator, the Direct / Indirect / Total rows are the NDE / NIE / Total from the g-formula, whose mediator model is a normal linear regression (a 0/1 mediator uses a logit and a categorical mediator with three or more levels a multinomial logit). In the g-formula the Y model and the mediator models always contain every predictor as a covariate (and the Y model every mediator), even when some paths are unticked. A predictor without a mediated path is shown as a conditional OR. Intervals and p values come from 10,000 quasi-Bayesian parameter draws at a fixed seed (12345) (Imai et al., 2010; Tingley et al., 2014). Continuous predictor: DAPH contrasts the values 0 and 1 of that predictor for everybody; if 0 is outside the data (age, for example) the effect is an extrapolation, so rescale the predictor first so that 0 and 1 are meaningful. The proportion mediated (PM) is printed in the table note only when the NIE interval excludes 1 and 0 ≤ PM ≤ 1.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(MASS) # mvrnorm(): quasi-Bayesian parameter draws
library(mediation) # independent cross-check on the risk-difference scale
d$apd <- as.integer(d$group == 2) # Treatment group: CAPD (reference) = 0, APD = 1
# qol_g2: QoL group at mid-point, 0 = low, 1 = high (score 60.5 or more)
# 1) The two models DAPH fits: mediator (normal linear) and outcome (logit)
m_eq <- lm(n_peritonitis ~ apd, data = d)
y_eq <- glm(qol_g2 ~ apd + n_peritonitis, family = binomial, data = d)
s <- coef(summary(y_eq))["n_peritonitis", ] # mediator -> outcome: conditional OR, Wald 95% CI
round(exp(c(OR = s[[1]], lower = s[[1]] - qnorm(0.975) * s[[2]], upper = s[[1]] + qnorm(0.975) * s[[2]])), 4)
round(s[[4]], 4)
round(c(logLik = as.numeric(logLik(m_eq) + logLik(y_eq)), # sum over the two equations
McFadden_R2 = 1 - y_eq$deviance / y_eq$null.deviance), 4) # outcome equation
# 2) g-formula: E[Y(x, M(x*))] integrates the logit over the normal mediator (24-node Gauss-Hermite)
gh <- function(n) { # nodes/weights for E[f(Z)], Z ~ N(0, 1) (Golub-Welsch)
J <- matrix(0, n, n); i <- seq_len(n - 1); J[cbind(i, i + 1)] <- J[cbind(i + 1, i)] <- sqrt(i)
e <- eigen(J, symmetric = TRUE); list(z = e$values, w = e$vectors[1, ]^2)
}
q <- gh(24)
sigma_m <- summary(m_eq)$sigma # residual SD of the mediator model (held fixed)
p_cf <- function(by, bm, x, xs) { # by = outcome coefficients, bm = mediator coefficients
mu <- bm[[1]] + bm[[2]] * xs # mediator mean when APD = xs
lin <- by[[1]] + by[[2]] * x + by[[3]] * mu # outcome linear predictor when APD = x
sum(q$w * plogis(lin + by[[3]] * sigma_m * q$z)) # no other covariates: same for every patient
}
effects <- function(by, bm) {
p10 <- p_cf(by, bm, 1, 0); p00 <- p_cf(by, bm, 0, 0); p11 <- p_cf(by, bm, 1, 1)
odds <- function(p) p / (1 - p)
c(NDE = odds(p10) / odds(p00), NIE = odds(p11) / odds(p10), Total = odds(p11) / odds(p00),
NDE_rd = p10 - p00, NIE_rd = p11 - p10)
}
est <- effects(coef(y_eq), coef(m_eq))
round(est, 6)
round(c(PM = est[["NDE"]] * (est[["NIE"]] - 1) / (est[["NDE"]] * est[["NIE"]] - 1)), 3)
# 3) Quasi-Bayesian Monte Carlo CI: 10,000 draws of each coefficient vector from N(estimate, vcov)
set.seed(12345)
dy <- mvrnorm(10000, coef(y_eq), vcov(y_eq))
dm <- mvrnorm(10000, coef(m_eq), vcov(m_eq))
sims <- t(sapply(1:10000, function(k) effects(dy[k, ], dm[k, ])[1:3]))
p_mc <- function(x) min(1, 2 * min(mean(x <= 1), mean(x >= 1)))
round(rbind(lower = apply(sims, 2, quantile, 0.025), upper = apply(sims, 2, quantile, 0.975),
p = apply(sims, 2, p_mc)), 4)
# 4) Cross-check with mediation::mediate (risk-difference scale):
# ADE (control) = NDE_rd and ACME (treated) = NIE_rd
set.seed(12345)
med <- mediate(m_eq, y_eq, treat = "apd", mediator = "n_peritonitis", sims = 1000)
round(c(ADE_control = med$z0, ACME_treated = med$d1, total = med$tau.coef), 4)
# 5) Monte Carlo check: the same 10,000-draw intervals with 20 other seeds
mc <- t(sapply(1:20, function(seed) {
set.seed(seed)
dy <- mvrnorm(10000, coef(y_eq), vcov(y_eq)); dm <- mvrnorm(10000, coef(m_eq), vcov(m_eq))
x <- t(sapply(1:10000, function(k) effects(dy[k, ], dm[k, ])[1:3]))
c(lower = apply(x, 2, quantile, 0.025), upper = apply(x, 2, quantile, 0.975), p = apply(x, 2, p_mc))
}))
round(apply(mc, 2, sd), 4)
# 1) mediator -> outcome: conditional OR and Wald 95% CI, its p, log-likelihood and McFadden R2
OR lower upper
0.9151 0.8536 0.9810
[1] 0.0124
logLik McFadden_R2
-3258.9700 0.0044
# 2) g-formula point estimates (odds-ratio and risk-difference scale) and PM
NDE NIE Total NDE_rd NIE_rd
0.874121 1.098759 0.960448 -0.023754 0.016811
PM
-2.183
# 3) quasi-Bayesian Monte Carlo 95% CI and p (R random numbers)
NDE NIE Total
lower 0.6660 1.0207 0.7394
upper 1.1496 1.1878 1.2429
p 0.3324 0.0112 0.7534
# 4) mediation::mediate, risk-difference scale
ADE_control ACME_treated total
-0.0239 0.0167 -0.0072
# 5) SD of the interval limits and p across 20 other seeds
lower.NDE lower.NIE lower.Total upper.NDE upper.NIE upper.Total
0.0031 0.0010 0.0022 0.0040 0.0011 0.0044
p.NDE p.NIE p.Total
0.0062 0.0016 0.0095
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| จำนวนครั้งที่อักเสบ → Y: OR แบบมีเงื่อนไข (Wald 95% CI) / pEpisodes → Y: conditional OR (Wald 95% CI) / p | 0.9151 (0.8536 to 0.9810) / 0.0124 | 0.915 (0.854 to 0.981) / 0.012 | < 5e−4 | ✓ PASS |
| log-likelihood (สองสมการรวมกัน) / McFadden R² ของสมการ YLog-likelihood (both equations) / McFadden R² of the Y equation | −3258.9700 / 0.0044 | −3258.9700 / 0.0044 | < 5e−5 | ✓ PASS |
| NDE OR / NIE OR / Total OR | 0.874121 / 1.098759 / 0.960448 | 0.874121 / 1.098759 / 0.960448 | < 5e−7 | ✓ PASS |
| NDE / NIE บนสเกลผลต่างความน่าจะเป็นNDE / NIE on the risk-difference scale | −0.023754 / 0.016811 | −0.023754 / 0.016811 | < 5e−7 | ✓ PASS |
| PM บนสเกล OR (DAPH ไม่แสดงเพราะอยู่นอก 0–1)PM on the OR scale (not shown by DAPH: outside 0–1) | −2.183 | −2.183 | < 5e−4 | ✓ PASS |
| NDE: 95% CI / p (เกณฑ์ ±0.017 / ±0.026)*NDE: 95% CI / p (tolerance ±0.017 / ±0.026)* | 0.6660 to 1.1496 / 0.3324 | 0.6644 to 1.1546 / 0.3392 | 0.0016 / 0.0050 / 0.0068 | ✓ PASS |
| NIE: 95% CI / p (เกณฑ์ ±0.005 / ±0.007)*NIE: 95% CI / p (tolerance ±0.005 / ±0.007)* | 1.0207 to 1.1878 / 0.0112 | 1.0223 to 1.1879 / 0.0112 | 0.0016 / 0.0001 / 0.0000 | ✓ PASS |
| Total: 95% CI / p (เกณฑ์ ±0.019 / ±0.040)*Total: 95% CI / p (tolerance ±0.019 / ±0.040)* | 0.7394 to 1.2429 / 0.7534 | 0.7382 to 1.2521 / 0.7772 | 0.0012 / 0.0092 / 0.0238 | ✓ PASS |
| mediation::mediate: ADE (control) / ACME (treated) / total เทียบ NDE / NIE / total ของ DAPH บนสเกลผลต่าง (เกณฑ์ ±0.001)**mediation::mediate: ADE (control) / ACME (treated) / total vs DAPH's NDE / NIE / total on the difference scale (tolerance ±0.001)** | −0.0239 / 0.0167 / −0.0072 | −0.0238 / 0.0168 / −0.0069 | 0.0001 / 0.0001 / 0.0003 | ✓ PASS |
* R และ DAPH ใช้ตัวสร้างเลขสุ่มต่างกัน · เกณฑ์ = 3 × √2 × SD ระหว่าง seed จากส่วนที่ 5 ของสคริปต์ · ** mediate ใช้การจำลองค่าตัวแปรส่งผ่านแทนการอินทิเกรต และค่าประมาณเป็นค่าเฉลี่ยของ 1,000 รอบจำลอง จึงต่างจากค่า plug-in ของ DAPH ได้เล็กน้อย · ค่าที่ไม่มีการสุ่มตรงกันตามทศนิยมที่แสดง · ทวนสอบ 2 ต.ค. 2026: R 4.3.3 บนไฟล์ example_en.csv
* R and DAPH use different random-number generators; tolerance = 3 × √2 × the between-seed SD from part 5 of the script. ** mediate simulates mediator values instead of integrating and averages 1,000 simulations, so it can differ slightly from DAPH's plug-in values. Quantities without random numbers agree to the decimals shown. Verified 2 Oct 2026: R 4.3.3 on example_en.csv.
4การแปลผลและตัวอย่างInterpretation and Example
ความหมาย: NDE = อิทธิพลของ X ต่อ Y เมื่อให้ตัวแปรส่งผ่านมีค่าเท่าที่จะเป็นตามธรรมชาติเมื่อ X = 0 · NIE = ส่วนที่ทำงานผ่านการเปลี่ยนของตัวแปรส่งผ่านจาก M(0) เป็น M(1) โดย X = 1 · Total = NDE × NIE บนสเกล OR · ตัวอย่าง: ถ้าให้ผู้ป่วยทุกคนเป็น APD แต่จำนวนครั้งที่อักเสบเท่ากับเมื่อเป็น CAPD odds ของคุณภาพชีวิตสูงเป็น 0.874 เท่า (95% CI 0.664 ถึง 1.155, p = 0.339: ไม่มีนัยสำคัญ ซึ่งไม่ได้แปลว่าไม่มีอิทธิพลทางตรง) · การลดลงของการอักเสบที่ไปกับ APD สัมพันธ์กับ odds ของคุณภาพชีวิตสูงที่เพิ่มขึ้น 1.099 เท่า (95% CI 1.022 ถึง 1.188, p = 0.011) · ผลรวม OR = 0.960 (95% CI 0.738 ถึง 1.252) · ตรวจการแยกแบบคูณ: 0.874121 × 1.098759 = 0.960448 · เพราะทางตรงและทางอ้อมมีทิศตรงข้าม (inconsistent mediation) PM = −2.183 ไม่มีความหมายเป็นสัดส่วน DAPH จึงไม่รายงาน · ประโยคสำหรับวารสาร: "The natural indirect effect of APD versus CAPD on high mid-point QoL through peritonitis episodes was OR 1.099 (95% CI 1.022 to 1.188), the natural direct effect OR 0.874 (95% CI 0.664 to 1.155) and the total effect OR 0.960 (95% CI 0.738 to 1.252)."
Meaning: the NDE is the effect of X on Y with the mediator held at the value it would naturally take when X = 0; the NIE is the part that works through the change of the mediator from M(0) to M(1) with X = 1; Total = NDE × NIE on the OR scale. Example: if every patient were on APD but had the number of episodes they would have on CAPD, the odds of high QoL would be 0.874 times as large (95% CI 0.664 to 1.155, p = 0.339: not significant, which does not mean there is no direct effect). The reduction in episodes that goes with APD is associated with 1.099 times higher odds of high QoL (95% CI 1.022 to 1.188, p = 0.011). The total OR is 0.960 (95% CI 0.738 to 1.252). Check of the multiplicative decomposition: 0.874121 × 1.098759 = 0.960448. Because the direct and indirect effects point in opposite directions (inconsistent mediation), PM = −2.183 has no meaning as a proportion, so DAPH does not report it. Journal-style sentence: "The natural indirect effect of APD versus CAPD on high mid-point QoL through peritonitis episodes was OR 1.099 (95% CI 1.022 to 1.188), the natural direct effect OR 0.874 (95% CI 0.664 to 1.155) and the total effect OR 0.960 (95% CI 0.738 to 1.252)."
สเกลของผลถูกกำหนดโดยตัวแปรตาม: สมการ Y เป็น logit ผลทุกแถว (ทางตรงของตัวแปรส่งผ่าน, NDE, NIE, Total) จึงเป็น OR ไม่ว่าตัวแปรส่งผ่านหรือตัวแปรต้นจะเป็นชนิดใด และการแยกผลเป็นแบบ คูณ ไม่ใช่บวกเหมือน 8.1 · หลายตัวแปรส่งผ่าน: เมื่อตัวแปรต้นมีตัวแปรส่งผ่านตั้งแต่ 2 ตัว DAPH รายงานทั้ง NIE รายตัว (interventional: เปลี่ยนตัวแปรส่งผ่านทีละตัว ตัวอื่นคงค่าที่สังเกตได้) และ NIE รวมของทั้งชุด ผลรายตัวไม่จำเป็นต้องคูณกันได้เท่าผลรวมพอดี (VanderWeele และคณะ, 2014; Vansteelandt & Daniel, 2017) · ตัวแปรส่งผ่านแบบกลุ่ม (เช่น กลุ่ม BMI) นับเป็นตัวแปรส่งผ่านตัวเดียว · ข้อสมมติเชิงเหตุผล: การอ่านเป็น "ผลของ" ต้องไม่มีตัวแปรกวนที่ไม่ได้วัดระหว่าง X–Y, M–Y และ X–M และไม่มีตัวแปรกวนของ M–Y ที่ถูก X กระทบ (VanderWeele, 2015) DAPH เขียนข้อสมมตินี้ในหมายเหตุของผลทุกครั้ง · ข้อมูลตัวอย่างเป็นข้อมูลเชิงสังเกต ควรใช้คำว่า "สัมพันธ์กับ" · จำนวนครั้งที่อักเสบนับตลอดการติดตาม ส่วนหนึ่งจึงอาจเกิดหลังการวัดคุณภาพชีวิตช่วงกลาง และคะแนนคุณภาพชีวิตช่วงกลางในข้อมูลตัวอย่างเท่ากับคะแนนก่อนเริ่มบวก 5.5 คะแนนในผู้ป่วยเกือบทุกคน ตัวอย่างนี้จึงใช้สาธิตการคำนวณ ไม่ใช่ข้อสรุปทางคลินิก · โมเดลตัวแปรส่งผ่านแบบปกติใช้กับข้อมูลนับได้โดยประมาณเท่านั้น
The scale is set by the outcome: the Y equation is a logit, so every row (a mediator's direct effect, NDE, NIE, Total) is an OR whatever the type of the mediator or predictor, and the decomposition is multiplicative, not additive as in 8.1. Several mediators: when a predictor has two or more mediators, DAPH reports both the mediator-specific (interventional) NIE, changing one mediator at a time with the others at their observed values, and the joint NIE through the whole set; the mediator-specific effects need not multiply exactly to the joint one (VanderWeele et al., 2014; Vansteelandt & Daniel, 2017). A categorical mediator (for example BMI group) counts as one mediator. Causal assumptions: reading the effects as "effects of" requires no unmeasured X–Y, M–Y or X–M confounding and no M–Y confounder affected by X (VanderWeele, 2015); DAPH states this in the note of every result. The example data are observational, so use "associated with". The peritonitis episodes are counted over the whole follow-up, so some may occur after the mid-point QoL assessment, and in the example data the mid-point QoL score equals the baseline score plus 5.5 points for almost every patient; this example therefore demonstrates the computation, not a clinical conclusion. A normal mediator model is only an approximation for a count.
📖 References
- Robins, J. M., & Greenland, S. (1992). Identifiability and exchangeability for direct and indirect effects. Epidemiology, 3(2), 143–155. doi:10.1097/00001648-199203000-00013
- Pearl, J. (2001). Direct and indirect effects. Proceedings of the 17th Conference on Uncertainty in Artificial Intelligence (UAI), 411–420.
- Imai, K., Keele, L., & Tingley, D. (2010). A general approach to causal mediation analysis. Psychological Methods, 15(4), 309–334. doi:10.1037/a0020761
- Tingley, D., Yamamoto, T., Hirose, K., Keele, L., & Imai, K. (2014). mediation: R package for causal mediation analysis. Journal of Statistical Software, 59(5), 1–38. doi:10.18637/jss.v059.i05
- VanderWeele, T. J. (2015). Explanation in Causal Inference: Methods for Mediation and Interaction. New York: Oxford University Press. ISBN 978-0-19-932587-0.
- VanderWeele, T. J., Vansteelandt, S., & Robins, J. M. (2014). Effect decomposition in the presence of an exposure-induced mediator-outcome confounder. Epidemiology, 25(2), 300–306. doi:10.1097/EDE.0000000000000034
- Vansteelandt, S., & Daniel, R. M. (2017). Interventional effects for mediation analysis with multiple mediators. Epidemiology, 28(2), 258–265. doi:10.1097/EDE.0000000000000596
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
8.3Ordinal & Nominal Outcomes + Categorical Predictors (PO-OR / RRR, g-formula mediation)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
ผลลัพธ์ทางสุขภาพจำนวนมากมีมากกว่าสองระดับ: อันดับ (ordinal) เช่น ความถี่ของพฤติกรรม (ไม่เคย … ทุกวัน) หรือระยะของโรค และ นามบัญญัติ (nominal) ซึ่งไม่มีลำดับ เช่น ชนิดของการรักษา · การยุบให้เหลือสองกลุ่มทำให้เสียข้อมูล · DAPH ใช้ ordered logit (proportional odds) เมื่อตัวแปรตามประกาศชนิดเป็น ordinal และ multinomial logit เมื่อเป็น nominal แล้วแยกอิทธิพลทางตรงและทางอ้อมด้วย g-formula: เป็น OR สะสม (cumulative OR) สำหรับ ordinal และเป็น relative-risk ratio (RRR) ของแต่ละกลุ่มเทียบกลุ่มอ้างอิงสำหรับ nominal · ตัวแปรต้นแบบกลุ่มที่มีตั้งแต่ 3 ระดับ (nominal หรือ ordinal) ถูกแยกเป็นตัวแปรหุ่น (dummy) เทียบกับรหัสต่ำสุด และทดสอบผลรวมของทั้งตัวแปรด้วยการทดสอบร่วม · ไม่ควรใช้ ordered logit เมื่อข้อสมมติ proportional odds ไม่สมเหตุสมผล (DAPH ไม่ได้ทดสอบข้อนี้ให้) และไม่ควรใช้ multinomial logit เมื่อบางกลุ่มมีจำนวนน้อยมาก
Many health outcomes have more than two levels: ordinal, such as the frequency of a behaviour (never … every day) or a disease stage, and nominal (unordered), such as the type of treatment. Collapsing them to two groups discards information. DAPH uses an ordered logit (proportional odds) model when the outcome is declared ordinal and a multinomial logit model when it is nominal, and splits direct and indirect effects with the g-formula: a cumulative odds ratio for an ordinal outcome and a relative-risk ratio (RRR) of each category against the reference category for a nominal outcome. A categorical predictor with three or more levels (nominal or ordinal) is split into dummy variables against its lowest code, and the variable as a whole is tested jointly. Do not use the ordered logit when the proportional-odds assumption is implausible (DAPH does not test it), and avoid the multinomial logit when some categories are very small.
2หลักการและสูตรLogic and Formula
- τ_c, K
- จุดตัด (cut-point) ของระดับ c / จำนวนระดับของตัวแปรตาม · proportional odds หมายถึง β เท่ากันทุกจุดตัดcut-point of level c / number of outcome levels; proportional odds means one common β for all cut-points
- R, ℓ
- เมทริกซ์ที่เลือกสัมประสิทธิ์ของตัวแปรหุ่นทั้ง k − 1 ตัว / log-likelihood ของโมเดลที่มีและไม่มีตัวแปรนั้นmatrix selecting the k − 1 dummy coefficients / log-likelihood of the model with and without the variable
- p_k(x, x*)
- ความน่าจะเป็นเฉลี่ยทั้งประชากรของกลุ่ม k เมื่อ X = x และตัวแปรส่งผ่านมีการแจกแจงเหมือนเมื่อ X = x* (ตัวแปรส่งผ่านต่อเนื่องอินทิเกรตด้วย Gauss–Hermite)population-averaged probability of category k with X = x and the mediator distributed as under X = x* (a continuous mediator is integrated by Gauss–Hermite quadrature)
- D_j
- ตัวแปรหุ่นของระดับ j ของตัวแปรต้นแบบกลุ่มdummy variable of level j of a categorical predictor
DAPH คำนวณอย่างไร: สมการตัวแปรส่งผ่านเป็น OLS (การถดถอยเชิงเส้นแบบปกติใน g-formula) · สมการตัวแปรตามเป็น ordered logit หรือ multinomial logit ประมาณด้วย maximum likelihood · ตารางแสดง OR หรือ RRR แบบมีเงื่อนไขพร้อม Wald 95% CI สำหรับเส้นทางจากตัวแปรส่งผ่านไปยัง Y และสำหรับตัวแปรต้นที่ไม่มีเส้นทางผ่านตัวแปรส่งผ่าน · ตัวแปรต้นที่มีเส้นทางผ่านตัวแปรส่งผ่านแสดง NDE / NIE / Total จาก g-formula: ordinal อินทิเกรตด้วย Gauss–Hermite 16 จุด ส่วน nominal ใช้ตารางจุด Gauss–Hermite หลายมิติ 6 จุดต่อมิติ (สคริปต์ R ด้านล่างใช้ 24 จุดซึ่งให้ผลเท่ากันถึงทศนิยมที่แสดง) · ช่วงเชื่อมั่นและค่า p มาจากการสุ่มพารามิเตอร์แบบ quasi-Bayesian 5,000 ชุด seed คงที่ 12345 (Imai และคณะ, 2010) · การทดสอบร่วมของตัวแปรต้นแบบกลุ่มใช้ Wald χ² ในสมการ Y (F-test เมื่อ Y ต่อเนื่องใน 8.1 และ likelihood-ratio test เมื่อ Y เป็น nominal) · NDE / NIE แบบ ordinal เป็นค่าสรุปของ DAPH ที่เฉลี่ย logit สะสมทุกจุดตัด และ Total = NDE × NIE พอดี (Valeri & VanderWeele, 2013; VanderWeele, 2015) · ตัวแปรต้นแบบกลุ่มที่มีตั้งแต่ 3 ระดับ: แต่ละระดับเทียบกับกลุ่มอ้างอิงโดยตั้งตัวแปรหุ่นทุกตัวของตัวแปรนั้นพร้อมกัน (ตัวแปรหุ่นของระดับนั้น = 1 ตัวอื่น = 0) ตามสูตรสุดท้ายข้างบน
How DAPH computes it: the mediator equation is OLS (a normal linear model in the g-formula); the outcome equation is an ordered or multinomial logit fitted by maximum likelihood. The table gives conditional ORs or RRRs with Wald 95% CIs for the mediator-to-Y path and for predictors without a mediated path. A predictor with a mediated path shows the NDE / NIE / Total from the g-formula: the ordinal case integrates with 16-node Gauss–Hermite quadrature, the nominal case with a multidimensional Gauss–Hermite grid of 6 nodes per dimension (the R script below uses 24 nodes, which gives the same values to the decimals shown). Intervals and p values come from 5,000 quasi-Bayesian parameter draws at a fixed seed (12345) (Imai et al., 2010). The joint test of a categorical predictor is a Wald χ² in the Y equation (an F test for a continuous Y in 8.1 and a likelihood-ratio test for a nominal Y). The ordinal NDE / NIE is DAPH's summary averaging the cumulative logits over all cut-points, and Total = NDE × NIE exactly (Valeri & VanderWeele, 2013; VanderWeele, 2015). For a categorical predictor with three or more levels, each level is compared with the reference by setting all of the variable's dummies together (that level's dummy = 1, the others = 0), as in the last formula above.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(MASS) # polr(): proportional-odds model; mvrnorm(): quasi-Bayesian draws
library(nnet) # multinom(): multinomial logit
d$apd <- as.integer(d$group == 2) # Treatment group: CAPD (reference) = 0, APD = 1
d$inc2 <- as.integer(d$fam_income == 2) # Household income 10,000-30,000 vs < 10,000 Baht/month (reference)
d$inc3 <- as.integer(d$fam_income == 3) # Household income > 30,000 vs < 10,000 Baht/month
gh <- function(n) { # Gauss-Hermite nodes/weights for E[f(Z)], Z ~ N(0, 1)
J <- matrix(0, n, n); i <- seq_len(n - 1); J[cbind(i, i + 1)] <- J[cbind(i + 1, i)] <- sqrt(i)
e <- eigen(J, symmetric = TRUE); list(z = e$values, w = e$vectors[1, ]^2)
}
p_mc <- function(x) min(1, 2 * min(mean(x <= 1), mean(x >= 1)))
ci_mc <- function(s) round(rbind(lower = apply(s, 2, quantile, 0.025),
upper = apply(s, 2, quantile, 0.975), p = apply(s, 2, p_mc)), 4)
## A. Ordinal outcome: Hobbies activities frequency (0 = never ... 4 = all 14 days)
m_ord <- lm(n_peritonitis ~ apd + inc2 + inc3, data = d)
y_ord <- polr(factor(hobbiesactivities) ~ apd + inc2 + inc3 + n_peritonitis, data = d,
Hess = TRUE, control = list(reltol = 1e-12))
round(c(coef(y_ord), y_ord$zeta), 4) # slopes and cut-points
s <- coef(summary(y_ord))["n_peritonitis", ] # mediator -> outcome: PO-OR, Wald CI
round(exp(c(OR = s[[1]], lower = s[[1]] - qnorm(0.975) * s[[2]], upper = s[[1]] + qnorm(0.975) * s[[2]])), 4)
round(2 * pnorm(-abs(s[[3]])), 4)
b <- coef(y_ord)[c("inc2", "inc3")] # joint Wald test of household income (df = 2)
W <- drop(t(b) %*% solve(vcov(y_ord)[names(b), names(b)]) %*% b)
round(c(chi2 = W, p = pchisq(W, 2, lower.tail = FALSE)), 4)
# g-formula: patients with the same covariate pattern share their probabilities, so the average
# over the 6 patterns (weighted by their counts) equals the average over all 1,300 patients
pat <- aggregate(list(n = rep(1, nrow(d))), d[c("apd", "inc2", "inc3")], length)
q16 <- gh(16); s_ord <- summary(m_ord)$sigma
pvec_ord <- function(beta, zeta, am, setY, setM) {
XY <- pat; XY[names(setY)] <- as.list(setY) # predictor values for the outcome
XM <- pat; XM[names(setM)] <- as.list(setM) # predictor values for the mediator
mu <- am[1] + am[2] * XM$apd + am[3] * XM$inc2 + am[4] * XM$inc3
eta <- beta[1] * XY$apd + beta[2] * XY$inc2 + beta[3] * XY$inc3 + beta[4] * mu
P <- 0
for (k in seq_along(q16$z)) {
cum <- plogis(outer(eta + beta[4] * s_ord * q16$z[k], zeta, function(e, z) z - e)) # P(Y <= c)
P <- P + q16$w[k] * (cbind(cum, 1) - cbind(0, cum))
}
colSums(P * pat$n) / sum(pat$n)
}
cumlogit <- function(p) mean(qlogis(rev(cumsum(rev(p)))[-1])) # mean of logit P(Y >= c), c = 1..4
ord_eff <- function(beta, zeta, am, x1, x0) {
p10 <- pvec_ord(beta, zeta, am, x1, x0); p00 <- pvec_ord(beta, zeta, am, x0, x0)
p11 <- pvec_ord(beta, zeta, am, x1, x1)
c(NDE = exp(cumlogit(p10) - cumlogit(p00)), NIE = exp(cumlogit(p11) - cumlogit(p10)),
Total = exp(cumlogit(p11) - cumlogit(p00)))
}
# each contrast sets ALL dummies of a categorical predictor (level vs reference)
con <- list(APD = list(x1 = c(apd = 1), x0 = c(apd = 0)),
inc_10_30k = list(x1 = c(inc2 = 1, inc3 = 0), x0 = c(inc2 = 0, inc3 = 0)),
inc_gt_30k = list(x1 = c(inc2 = 0, inc3 = 1), x0 = c(inc2 = 0, inc3 = 0)))
est_ord <- sapply(con, function(k) ord_eff(coef(y_ord), y_ord$zeta, coef(m_ord), k$x1, k$x0))
round(est_ord, 4)
set.seed(12345) # 5,000 quasi-Bayesian draws
th <- mvrnorm(5000, c(coef(y_ord), y_ord$zeta), vcov(y_ord))
am <- mvrnorm(5000, coef(m_ord), vcov(m_ord))
for (k in names(con)) {
sims <- t(sapply(1:5000, function(r) ord_eff(th[r, 1:4], th[r, 5:8], am[r, ], con[[k]]$x1, con[[k]]$x0)))
cat(k, "\n"); print(ci_mc(sims))
}
## B. Nominal outcome: BMI group (1 = underweight [reference], 2 = normal, 3 = overweight, 4 = obese)
m_nom <- lm(n_peritonitis ~ apd, data = d)
y_nom <- multinom(factor(bmi_group) ~ apd + n_peritonitis, data = d, trace = FALSE,
reltol = 1e-12, maxit = 1000)
B <- coef(y_nom); S <- sqrt(diag(vcov(y_nom)))[paste0(2:4, ":n_peritonitis")]
round(cbind(RRR_episodes = exp(B[, "n_peritonitis"]), # mediator -> outcome, per category
lower = exp(B[, "n_peritonitis"] - qnorm(0.975) * S),
upper = exp(B[, "n_peritonitis"] + qnorm(0.975) * S),
p = 2 * pnorm(-abs(B[, "n_peritonitis"] / S))), 4)
q24 <- gh(24); s_nom <- summary(m_nom)$sigma
pvec_nom <- function(Bk, am, x, xs) { # Bk: 3 x 3 matrix (categories 2-4 by intercept, apd, episodes)
mu <- am[1] + am[2] * xs # no other covariates: the same for every patient
P <- 0
for (k in seq_along(q24$z)) {
e <- c(0, Bk[, 1] + Bk[, 2] * x + Bk[, 3] * (mu + s_nom * q24$z[k]))
P <- P + q24$w[k] * exp(e) / sum(exp(e))
}
P
}
nom_eff <- function(Bk, am) { # relative-risk ratio of each category vs the reference
rr <- function(p) p[-1] / p[1]
p10 <- pvec_nom(Bk, am, 1, 0); p00 <- pvec_nom(Bk, am, 0, 0); p11 <- pvec_nom(Bk, am, 1, 1)
setNames(c(rr(p10) / rr(p00), rr(p11) / rr(p10), rr(p11) / rr(p00)),
paste(rep(c("NDE", "NIE", "Total"), each = 3), c("normal", "overweight", "obese"), sep = "_"))
}
round(nom_eff(B, coef(m_nom)), 4) # NDE2..4, NIE2..4, Total2..4
set.seed(12345)
tb <- mvrnorm(5000, as.vector(t(B)), vcov(y_nom)) # category-major, as vcov(y_nom)
am <- mvrnorm(5000, coef(m_nom), vcov(m_nom))
sims <- t(sapply(1:5000, function(r) nom_eff(matrix(tb[r, ], 3, 3, byrow = TRUE), am[r, ])))
ci_mc(sims)
## C. Monte Carlo check: SD of the APD interval limits and p across 10 other seeds
mc_ord <- t(sapply(1:10, function(seed) {
set.seed(seed)
th <- mvrnorm(5000, c(coef(y_ord), y_ord$zeta), vcov(y_ord)); am <- mvrnorm(5000, coef(m_ord), vcov(m_ord))
s <- t(sapply(1:5000, function(r) ord_eff(th[r, 1:4], th[r, 5:8], am[r, ], con$APD$x1, con$APD$x0)))
c(lower = apply(s, 2, quantile, 0.025), upper = apply(s, 2, quantile, 0.975), p = apply(s, 2, p_mc))
}))
round(apply(mc_ord, 2, sd), 4)
mc_nom <- t(sapply(1:10, function(seed) {
set.seed(seed)
tb <- mvrnorm(5000, as.vector(t(B)), vcov(y_nom)); am <- mvrnorm(5000, coef(m_nom), vcov(m_nom))
s <- t(sapply(1:5000, function(r) nom_eff(matrix(tb[r, ], 3, 3, byrow = TRUE), am[r, ])))
c(lower = apply(s, 2, quantile, 0.025), upper = apply(s, 2, quantile, 0.975), p = apply(s, 2, p_mc))
}))
round(max(apply(mc_nom[, 1:18], 2, sd)), 4); round(max(apply(mc_nom[, 19:27], 2, sd)), 4)
# A) ordinal outcome: slopes and cut-points
apd inc2 inc3 n_peritonitis 0|1
0.1075 -0.2747 -0.1440 0.0298 -1.2362
1|2 2|3 3|4
-0.8961 -0.5570 0.2339
# mediator -> outcome: proportional-odds OR, Wald 95% CI, p
OR lower upper
1.0302 0.9736 1.0902
[1] 0.3021
# joint Wald test of household income (two dummies)
chi2 p
3.9916 0.1359
# g-formula NDE / NIE / Total (cumulative OR)
APD inc_10_30k inc_gt_30k
NDE 1.1131 0.7600 0.8660
NIE 0.9687 1.0004 0.9975
Total 1.0783 0.7603 0.8638
# quasi-Bayesian 95% CI and p (R random numbers)
APD
NDE NIE Total
lower 0.9052 0.9125 0.8867
upper 1.3661 1.0274 1.3136
p 0.3136 0.2924 0.4464
inc_10_30k
NDE NIE Total
lower 0.5769 0.9891 0.5777
upper 1.0008 1.0133 1.0007
p 0.0516 0.9440 0.0512
inc_gt_30k
NDE NIE Total
lower 0.6842 0.9843 0.6821
upper 1.0938 1.0065 1.0914
p 0.2332 0.6148 0.2248
# B) nominal outcome: mediator -> outcome RRR per category (2 normal, 3 overweight, 4 obese)
RRR_episodes lower upper p
2 0.9792 0.8847 1.0837 0.6842
3 0.9272 0.8267 1.0398 0.1961
4 0.9137 0.8160 1.0232 0.1180
# g-formula per category (RRR)
NDE_normal NDE_overweight NDE_obese NIE_normal
0.9453 0.9241 0.9994 1.0226
NIE_overweight NIE_obese Total_normal Total_overweight
1.0836 1.1006 0.9667 1.0014
Total_obese
1.1000
# quasi-Bayesian 95% CI and p
NDE_normal NDE_overweight NDE_obese NIE_normal NIE_overweight NIE_obese
lower 0.6409 0.5946 0.6665 0.9176 0.9570 0.9755
upper 1.4149 1.4418 1.5311 1.1402 1.2258 1.2431
p 0.7884 0.7276 1.0000 0.6820 0.1956 0.1272
Total_normal Total_overweight Total_obese
lower 0.6663 0.6593 0.7448
upper 1.4310 1.5255 1.6522
p 0.8652 0.9956 0.6528
# C) SD across 10 other seeds: ordinal APD limits and p, then the largest nominal SD (limits, p)
lower.NDE lower.NIE lower.Total upper.NDE upper.NIE upper.Total
0.0040 0.0012 0.0046 0.0073 0.0011 0.0064
p.NDE p.NIE p.Total
0.0101 0.0089 0.0116
[1] 0.0171
[1] 0.0179
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| A: slopes (APD / รายได้ 10,000–30,000 / > 30,000 / จำนวนครั้งที่อักเสบ)A: slopes (APD / income 10,000–30,000 / > 30,000 / episodes) | 0.1075 / −0.2747 / −0.1440 / 0.0298 | 0.1075 / −0.2747 / −0.1440 / 0.0298 | < 2e−5 | ✓ PASS |
| A: cut-pointsA: cut-points | −1.2362 / −0.8961 / −0.5570 / 0.2339 | −1.2362 / −0.8961 / −0.5570 / 0.2339 | < 4e−5 | ✓ PASS |
| A: จำนวนครั้งที่อักเสบ → Y: OR (Wald 95% CI) / pA: episodes → Y: OR (Wald 95% CI) / p | 1.0302 (0.9736 to 1.0902) / 0.3021 | 1.030 (0.974 to 1.090) / 0.302 | < 5e−4 | ✓ PASS |
| A: Household Income การทดสอบร่วม χ²(2) / pA: Household Income joint test χ²(2) / p | 3.9916 / 0.1359 | 3.9919 / 0.1359 | 0.0003 | ✓ PASS |
| A: APD NDE / NIE / Total (OR สะสม)A: APD NDE / NIE / Total (cumulative OR) | 1.1131 / 0.9687 / 1.0783 | 1.1132 / 0.9687 / 1.0783 | < 5e−5 | ✓ PASS |
| A: APD NDE 95% CI / p (เกณฑ์ ±0.017, ±0.031 / ±0.043)*A: APD NDE 95% CI / p (tolerance ±0.017, ±0.031 / ±0.043)* | 0.9052 to 1.3661 / 0.3136 | 0.9023 to 1.3587 / 0.3028 | 0.0029 / 0.0074 / 0.0108 | ✓ PASS |
| A: APD NIE 95% CI / p (เกณฑ์ ±0.005 / ±0.038)*A: APD NIE 95% CI / p (tolerance ±0.005 / ±0.038)* | 0.9125 to 1.0274 / 0.2924 | 0.9098 to 1.0293 / 0.3048 | 0.0027 / 0.0019 / 0.0124 | ✓ PASS |
| A: APD Total 95% CI / p (เกณฑ์ ±0.020, ±0.027 / ±0.049)*A: APD Total 95% CI / p (tolerance ±0.020, ±0.027 / ±0.049)* | 0.8867 to 1.3136 / 0.4464 | 0.8832 to 1.3073 / 0.4428 | 0.0035 / 0.0063 / 0.0036 | ✓ PASS |
| A: รายได้ 10,000–30,000 เทียบ < 10,000: NDE / NIE / Total A: income 10,000–30,000 vs < 10,000: NDE / NIE / Total | 0.7600 / 1.0004 / 0.7603 | 0.7600 / 1.0004 / 0.7603 | 4e−6 | ✓ PASS |
| A: รายได้ > 30,000 เทียบ < 10,000: NDE / NIE / Total A: income > 30,000 vs < 10,000: NDE / NIE / Total | 0.8660 / 0.9975 / 0.8638 | 0.8660 / 0.9975 / 0.8638 | 6e−6 | ✓ PASS |
| B: จำนวนครั้งที่อักเสบ → Y: RRR ปกติ / น้ำหนักเกิน / อ้วน (เทียบน้ำหนักต่ำ)B: episodes → Y: RRR normal / overweight / obese (vs underweight) | 0.9792 / 0.9272 / 0.9137 | 0.979 / 0.927 / 0.914 | < 5e−4 | ✓ PASS |
| B: Wald 95% CI ของ RRR ข้างบนB: Wald 95% CIs of these RRRs | 0.8847–1.0837 / 0.8267–1.0398 / 0.8160–1.0232 | 0.885–1.084 / 0.827–1.040 / 0.816–1.023 | < 5e−4 | ✓ PASS |
| B: APD NDE ปกติ / น้ำหนักเกิน / อ้วนB: APD NDE normal / overweight / obese | 0.9453 / 0.9241 / 0.9994 | 0.945 / 0.924 / 0.999 | < 5e−4 | ✓ PASS |
| B: APD NIE ปกติ / น้ำหนักเกิน / อ้วนB: APD NIE normal / overweight / obese | 1.0226 / 1.0836 / 1.1006 | 1.023 / 1.084 / 1.101 | < 5e−4 | ✓ PASS |
| B: APD Total ปกติ / น้ำหนักเกิน / อ้วนB: APD Total normal / overweight / obese | 0.9667 / 1.0014 / 1.1000 | 0.967 / 1.001 / 1.100 | < 5e−4 | ✓ PASS |
| B: 95% CI และ p ของ NDE / NIE / Total ทั้ง 9 ค่า (เกณฑ์ขอบ CI ±0.073, p ±0.076)*B: 95% CIs and p of all 9 NDE / NIE / Total (tolerance limits ±0.073, p ±0.076)* | obese NIE: 0.9755 to 1.2431 / 0.1272 | obese NIE: 0.977 to 1.241 / 0.110 | ≤ 0.035 / ≤ 0.041 | ✓ PASS |
* ค่าจากการสุ่ม: เกณฑ์ = 3 × √2 × SD ระหว่าง seed จากส่วน C ของสคริปต์ · ค่าประมาณจุดของ proportional-odds ใน DAPH หยุดก่อนถึงค่าสูงสุดเล็กน้อย (ต่างจาก R ไม่เกิน 4e−5) · ทวนสอบ 2 ต.ค. 2026: R 4.3.3 บนไฟล์ example_en.csv
* Simulation quantities: tolerance = 3 × √2 × the between-seed SD from part C of the script. DAPH's proportional-odds optimiser stops slightly short of the maximum (differences from R up to 4e−5). Verified 2 Oct 2026: R 4.3.3 on example_en.csv.
4การแปลผลและตัวอย่างInterpretation and Example
Ordinal: OR สะสม > 1 หมายถึงมีแนวโน้มอยู่ในระดับที่สูงกว่าของตัวแปรตาม · ตัวอย่าง A: ความถี่ของกิจกรรมงานอดิเรกไม่ต่างกันอย่างมีนัยสำคัญระหว่าง APD กับ CAPD (Total OR = 1.078, 95% CI 0.883 ถึง 1.307) และไม่มีหลักฐานของเส้นทางผ่านเยื่อบุช่องท้องอักเสบ (NIE OR = 0.969, 95% CI 0.910 ถึง 1.029) · ไม่มีนัยสำคัญไม่ได้แปลว่าไม่มีผล ช่วงเชื่อมั่นยังกว้าง · ตัวแปรต้นแบบกลุ่ม: อ่านการทดสอบร่วมก่อน (Household Income: χ²(2) = 3.99, p = 0.136 รายได้โดยรวมไม่สัมพันธ์กับความถี่ของงานอดิเรกอย่างมีนัยสำคัญ) แล้วจึงดูรายระดับ: รายได้ 10,000–30,000 บาทเทียบ < 10,000 บาท มี NDE OR ประมาณ 0.76 ซึ่งค่า p อยู่ที่เส้นแบ่ง (DAPH 0.047, R 0.052 ต่างกันด้วยการสุ่มเท่านั้น) จึงไม่ควรสรุปจากระดับเดียวเมื่อการทดสอบร่วมไม่มีนัยสำคัญ · Nominal: RRR ของแต่ละกลุ่มเทียบกลุ่มอ้างอิง (รหัสต่ำสุด) และ NDE / NIE / Total รายงานแยกตามกลุ่ม · ตัวอย่าง B: ไม่มีกลุ่ม BMI ใดที่มี NDE, NIE หรือ Total ต่างจาก 1 อย่างมีนัยสำคัญ · ข้อจำกัด: DAPH ไม่ได้ทดสอบข้อสมมติ proportional odds ควรตรวจเพิ่ม เช่น เทียบกับ logit แยกตามจุดตัด · การตีความเชิงเหตุผลต้องไม่มีตัวแปรกวนที่ไม่ได้วัด เหมือน 8.2 · ข้อมูลตัวอย่างเป็นข้อมูลเชิงสังเกต และกิจกรรมงานอดิเรกกับกลุ่ม BMI ไม่ได้ระบุเวลาที่วัดเทียบกับการอักเสบ ตัวอย่างนี้จึงใช้สาธิตการคำนวณ
Ordinal: a cumulative OR > 1 means a tendency towards higher outcome levels. Example A: the frequency of hobby activities did not differ significantly between APD and CAPD (Total OR = 1.078, 95% CI 0.883 to 1.307), and there is no evidence of a pathway through peritonitis (NIE OR = 0.969, 95% CI 0.910 to 1.029); not significant does not mean no effect, as the intervals are still wide. Categorical predictor: read the joint test first (Household Income: χ²(2) = 3.99, p = 0.136, income as a whole is not significantly associated with hobby frequency) and only then the levels: income 10,000–30,000 versus < 10,000 Baht has an NDE OR of about 0.76 with a p value at the boundary (DAPH 0.047, R 0.052, which differ by Monte Carlo error only), so no conclusion should rest on one level when the joint test is not significant. Nominal: each RRR compares a category with the reference (lowest code), and NDE / NIE / Total are reported per category. Example B: no BMI category has an NDE, NIE or Total that differs significantly from 1. Limitations: DAPH does not test the proportional-odds assumption, so check it separately, for example against separate logits at each cut-point. A causal reading needs no unmeasured confounding, as in 8.2. The example data are observational, and the timing of the hobby and BMI measurements relative to the peritonitis episodes is not recorded, so this example demonstrates the computation.
📖 References
- McCullagh, P. (1980). Regression models for ordinal data. Journal of the Royal Statistical Society: Series B, 42(2), 109–142. doi:10.1111/j.2517-6161.1980.tb01109.x
- Agresti, A. (2013). Categorical Data Analysis (3rd ed.). Hoboken: Wiley. ISBN 978-0-470-46363-5.
- Valeri, L., & VanderWeele, T. J. (2013). Mediation analysis allowing for exposure–mediator interactions and causal interpretation: Theoretical assumptions and implementation with SAS and SPSS macros. Psychological Methods, 18(2), 137–150. doi:10.1037/a0031034
- VanderWeele, T. J. (2015). Explanation in Causal Inference: Methods for Mediation and Interaction. New York: Oxford University Press. ISBN 978-0-19-932587-0.
- Imai, K., Keele, L., & Tingley, D. (2010). A general approach to causal mediation analysis. Psychological Methods, 15(4), 309–334. doi:10.1037/a0020761
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 9 — การวิเคราะห์องค์ประกอบ (Factor Analysis: EFA / CFA)Chapter 9 — Factor Analysis (EFA / CFA) ✓ Verified
การวิเคราะห์องค์ประกอบ (Factor Analysis) สรุปตัวชี้วัดที่สังเกตได้หลายข้อให้เหลือ ตัวแปรแฝง (factor) ไม่กี่ตัวที่อธิบายสหสัมพันธ์ระหว่างข้อ เป็นขั้นตอนหลักของการพัฒนาและตรวจสอบเครื่องมือวัด (แบบสอบถาม มาตรวัด) ในงานสาธารณสุข · DAPH มีสองโหมด: EFA (9.1) สำรวจว่าข้อคำถามจับกลุ่มเป็นกี่องค์ประกอบเมื่อยังไม่มีโครงสร้างที่ชัดเจน พร้อม KMO, Bartlett's test, parallel analysis, ค่าน้ำหนัก, communality และความเชื่อมั่นรายองค์ประกอบ (Cronbach's α / McDonald's ω) · CFA (9.2) ทดสอบโครงสร้างที่กำหนดไว้ล่วงหน้า พร้อมดัชนีความกลมกลืน ความเชื่อมั่นรวม (CR) ความแปรปรวนเฉลี่ยที่สกัดได้ (AVE) และความตรงเชิงจำแนก (Fornell–Larcker, HTMT2) · ทั้งสองโหมดใช้สหสัมพันธ์ Pearson เป็นค่าเริ่มต้น และใช้สหสัมพันธ์ polychoric/tetrachoric เมื่อเลือกตัวเลือกข้อมูลอันดับ Factor analysis summarises many observed indicators by a few latent variables (factors) that explain the correlations among the items; it is the core of developing and validating measurement instruments (questionnaires, scales) in public-health research. DAPH has two modes: EFA (9.1) explores how many factors the items form when no structure is fixed yet, with KMO, Bartlett's test, parallel analysis, loadings, communalities and per-factor reliability (Cronbach's α / McDonald's ω); CFA (9.2) tests a structure specified in advance, with fit indices, composite reliability (CR), average variance extracted (AVE) and discriminant validity (Fornell–Larcker, HTMT2). Both modes use Pearson correlations by default and polychoric/tetrachoric correlations when the ordinal option is ticked.
9.1Exploratory Factor Analysis (EFA) — KMO / Bartlett, loadings, communalities, parallel analysis, α / ω
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
EFA ใช้เมื่อยังไม่รู้ว่าข้อคำถามจับกลุ่มเป็นกี่องค์ประกอบและข้อใดสะท้อนองค์ประกอบใด เช่น ชุดคำถามพฤติกรรมสุขภาพที่ยังไม่เคยตรวจโครงสร้าง เป็นขั้นแรกของการสร้างหรือปรับมาตรวัด ก่อนยืนยันโครงสร้างด้วย CFA (9.2) ในกลุ่มตัวอย่างอิสระ · เหมาะกับข้อคำถามแบบสะท้อน (reflective: องค์ประกอบเป็นสาเหตุของคำตอบ) ที่มีสหสัมพันธ์กันพอสมควรและกลุ่มตัวอย่างพอ · ไม่ควรใช้เมื่อทฤษฎีกำหนดโครงสร้างไว้แล้ว (ใช้ CFA) หรือเมื่อข้อคำถามเป็นดัชนีที่ประกอบกันขึ้น (formative) ซึ่งไม่จำเป็นต้องสัมพันธ์กัน
EFA is used when it is not yet known how many factors the items form and which item reflects which factor, for example a set of health-behaviour questions whose structure has never been checked. It is the first step in building or adapting a scale, before the structure is confirmed with CFA (9.2) in an independent sample. It suits reflective items (the factor causes the answers) that correlate reasonably and a sufficient sample. Do not use it when theory already fixes the structure (use CFA) or for formative indices whose components need not correlate.
2หลักการและสูตรLogic and Formula
- Λ (λ_ij), Φ, Ψ
- เมทริกซ์ค่าน้ำหนักแบบ pattern / สหสัมพันธ์ระหว่างองค์ประกอบ / ความแปรปรวนเฉพาะ (uniqueness)pattern loading matrix / interfactor correlations / unique variances
- S (s_ij)
- เมทริกซ์ structure = สหสัมพันธ์ระหว่างข้อกับองค์ประกอบstructure matrix = item–factor correlations
- r_ij, q_ij
- สหสัมพันธ์ / สหสัมพันธ์บางส่วน (anti-image) ของข้อ i กับ jzero-order / partial (anti-image) correlation of items i and j
- N, p
- จำนวนผู้ตอบ / จำนวนข้อrespondents / items
- k, σ_i², σ_T²
- จำนวนข้อที่เด่นในองค์ประกอบ / ความแปรปรวนของแต่ละข้อ / ของผลรวมคะแนนnumber of salient items of the factor / item variances / variance of the sum score
DAPH คำนวณอย่างไร: ค่าเริ่มต้นคือสหสัมพันธ์ Pearson, สกัดแบบ MINRES (เลือก ML, principal axis หรือ PCA ได้) และหมุนแกนแบบ promax (เลือก oblimin, varimax หรือไม่หมุนได้) · ถ้าเลือก "ข้อมูลอันดับ (polychoric)" จะใช้สหสัมพันธ์ polychoric/tetrachoric และคำนวณ KMO กับ Bartlett จากเมทริกซ์นั้น · จำนวนองค์ประกอบ "อัตโนมัติ" ใช้ parallel analysis แบบดั้งเดิมของ Horn: เทียบ eigenvalue ของเมทริกซ์สหสัมพันธ์ (แบบ principal components) กับเปอร์เซ็นไทล์ที่ 95 ของ eigenvalue จากข้อมูลสุ่มแจกแจงปกติขนาดเดียวกัน 100 ชุด (seed คงที่) และนับทุกลำดับที่สูงกว่า ซึ่งแม่นกว่าเกณฑ์ Kaiser eigenvalue > 1 (Fabrigar และคณะ, 1999) · ค่าน้ำหนักที่ |λ| ≥ 0.32 ถือว่าเด่น (พิมพ์ตัวหนา) · องค์ประกอบเรียงตามผลรวมกำลังสองของค่าน้ำหนัก pattern · α และ ω คำนวณจากข้อที่มีค่าน้ำหนักสูงสุดในองค์ประกอบนั้นและ |λ| ≥ 0.32 (ต้องมีอย่างน้อย 2 ข้อ) · ω ใช้ uniqueness จากโมเดลทุกองค์ประกอบ จึงไม่ใช่ค่าเดียวกับ omega total ของ psych::omega() · ข้อควรระวัง: ร้อยละความแปรปรวนที่ DAPH รายงานเป็นผลรวมกำลังสองของค่าน้ำหนัก pattern ซึ่งสำหรับการหมุนแกนเฉียงไม่เท่ากับความแปรปรวนร่วมที่องค์ประกอบอธิบายได้จริง (Σh²/p)
How DAPH computes it: the defaults are Pearson correlations, MINRES extraction (ML, principal axis or PCA can be chosen) and promax rotation (oblimin, varimax or none can be chosen). With "Ordinal items (polychoric)" ticked, polychoric/tetrachoric correlations are used and KMO and Bartlett's test are computed from that matrix. The "Auto" number of factors is Horn's original parallel analysis: the eigenvalues of the correlation matrix (principal components) are compared with the 95th percentile of the eigenvalues from 100 random normal data sets of the same size (fixed seed), and every eigenvalue above its threshold is counted; this is more accurate than the Kaiser eigenvalue > 1 rule (Fabrigar et al., 1999). Loadings with |λ| ≥ 0.32 are salient (bold). Factors are ordered by their sum of squared pattern loadings. α and ω use the items whose largest loading is on that factor with |λ| ≥ 0.32 (at least 2 items); ω uses the uniquenesses of the full model, so it is not the omega total of psych::omega(). Caution: the percentage of variance DAPH reports is the sum of squared pattern loadings, which after an oblique rotation is not the common variance actually explained by the factors (Σh²/p).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(psych) # KMO(), cortest.bartlett(), fa(), alpha()
library(GPArotation) # rotations used by fa()
items <- c("alcoholfreq", "cigarettefreq", "betelfreq", # substance use
"sugaryfoodfreq", "fattyfoodfreq", "saltyfoodfreq", # diet
"vigorousphysicalactivities", "moderatephysicalactivities", # activity
"hobbiesactivities")
X <- d[items] # nine lifestyle items, 0 = never ... 4 = all 14 days; no missing values
round(mean(X$alcoholfreq == 0) * 100, 1) # % who never drink alcohol
# 1) Sampling adequacy (KMO, overall and per item) and Bartlett's test of sphericity
k <- KMO(X)
round(k$MSA, 3); round(k$MSAi, 3)
b <- cortest.bartlett(cor(X), n = nrow(X))
round(c(chi2 = b$chisq, df = b$df), 3); signif(b$p.value, 3)
# 2) Parallel analysis as DAPH runs it: eigenvalues of the correlation matrix versus the
# 95th percentile of eigenvalues from 100 random normal data sets of the same size
ev <- eigen(cor(X))$values
set.seed(20260701)
sim <- replicate(100, eigen(cor(matrix(rnorm(nrow(X) * ncol(X)), nrow(X))))$values)
q95 <- apply(sim, 1, quantile, 0.95)
round(rbind(observed = ev, random_95th = q95), 4)
sum(ev > q95) # number of factors retained
# Monte Carlo check: SD of the random 95th percentiles over 20 other seeds
round(apply(sapply(1:20, function(s) {
set.seed(s)
apply(replicate(100, eigen(cor(matrix(rnorm(nrow(X) * ncol(X)), nrow(X))))$values), 1, quantile, 0.95)
}), 1, sd), 4)
# 3) MINRES extraction with promax rotation (DAPH's defaults), 3 factors
f <- fa(X, nfactors = 3, fm = "minres", rotate = "promax")
o <- order(-colSums(unclass(f$loadings)^2)) # DAPH orders factors by sum of squared loadings
L <- unclass(f$loadings)[, o]; colnames(L) <- c("F1", "F2", "F3") # pattern matrix
Phi <- f$Phi[o, o]; dimnames(Phi) <- list(colnames(L), colnames(L))
round(cbind(L, h2 = f$communality), 3)
round(Phi, 3) # factor correlations
round(colSums(L^2), 4); round(colSums(L^2) / ncol(X), 4) # SS of pattern loadings, proportion
round(sum(colSums(L^2)) / ncol(X), 4); round(sum(f$communality) / ncol(X), 4)
# 4) Reliability per factor: items whose largest |loading| is on that factor and is >= 0.32
dom <- apply(abs(L), 1, which.max)
for (j in 1:3) {
m <- which(dom == j & abs(L[cbind(seq_along(dom), j)]) >= 0.32)
if (length(m) < 2) { cat(colnames(L)[j], ": fewer than two salient items\n"); next }
lam <- abs(L[m, j]); theta <- 1 - f$communality[m]
cat(colnames(L)[j], ":", items[m], "\n")
print(round(c(alpha = alpha(X[m], check.keys = FALSE)$total$raw_alpha,
omega = sum(lam)^2 / (sum(lam)^2 + sum(theta))), 3))
}
# share who never drink alcohol (%), then KMO overall and per item
[1] 92.2
[1] 0.623
alcoholfreq cigarettefreq
0.638 0.619
betelfreq sugaryfoodfreq
0.703 0.650
fattyfoodfreq saltyfoodfreq
0.620 0.665
vigorousphysicalactivities moderatephysicalactivities
0.507 0.539
hobbiesactivities
0.526
# Bartlett's test: chi-square, df, p
chi2 df
813.777 36.000
[1] 1.32e-147
# parallel analysis: observed eigenvalues vs random 95th percentiles, factors retained, seed SD
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
observed 1.9394 1.3211 1.0949 0.9910 0.8952 0.8236 0.7402 0.6689 0.5257
random_95th 1.1626 1.1099 1.0759 1.0452 1.0167 0.9886 0.9676 0.9398 0.9065
[1] 3
[1] 0.0035 0.0039 0.0022 0.0030 0.0022 0.0023 0.0026 0.0022 0.0030
# pattern loadings (DAPH order) and communalities, factor correlations
F1 F2 F3 h2
alcoholfreq 0.034 0.031 0.344 0.132
cigarettefreq -0.035 -0.006 0.587 0.332
betelfreq 0.191 -0.131 0.203 0.112
sugaryfoodfreq 0.472 -0.008 0.034 0.235
fattyfoodfreq 0.773 0.287 -0.083 0.559
saltyfoodfreq 0.547 0.090 0.059 0.315
vigorousphysicalactivities -0.023 -0.247 -0.126 0.094
moderatephysicalactivities -0.241 0.172 0.111 0.109
hobbiesactivities 0.145 0.625 -0.122 0.344
F1 F2 F3
F1 1.000 -0.172 0.294
F2 -0.172 1.000 0.268
F3 0.294 0.268 1.000
# sum of squared pattern loadings, proportion, their total, and common variance (sum h2 / 9)
F1 F2 F3
1.2373 0.5895 0.5588
F1 F2 F3
0.1375 0.0655 0.0621
[1] 0.2651
[1] 0.2481
# reliability per factor (salient items)
F1 : sugaryfoodfreq fattyfoodfreq saltyfoodfreq
alpha omega
0.574 0.629
F2 : fewer than two salient items
F3 : alcoholfreq cigarettefreq
alpha omega
0.212 0.361
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| KMO รวม / MSA รายข้อ (ต่ำสุด–สูงสุด)Overall KMO / per-item MSA (min–max) | 0.623 / 0.507–0.703 | 0.623 / 0.507–0.703 (all 9 equal) | < 5e−4 | ✓ PASS |
| Bartlett χ² / df / pBartlett χ² / df / p | 813.777 / 36 / 1.32e−147 | 813.777 / 36 / < 0.001 | < 5e−4 | ✓ PASS |
| Eigenvalue ที่สังเกตได้ (9 ค่า)Observed eigenvalues (9) | 1.9394 / 1.3211 / 1.0949 / … / 0.5257 | 1.9394 / 1.3211 / 1.0949 / … / 0.5257 | < 5e−5 | ✓ PASS |
| Parallel analysis: เปอร์เซ็นไทล์ที่ 95 ของข้อมูลสุ่ม (เกณฑ์ ±0.017)*Parallel analysis: random 95th percentiles (tolerance ±0.017)* | 1.1626 / 1.1099 / 1.0759 / … | 1.1679 / 1.1147 / 1.0739 / … | ≤ 0.0053 (9 values) | ✓ PASS |
| จำนวนองค์ประกอบที่คงไว้ / จำนวน eigenvalue > 1Factors retained / eigenvalues > 1 | 3 / 3 | 3 / 3 | 0 | ✓ PASS |
| ค่าน้ำหนัก pattern (27 ค่า) เช่น อาหารมัน F1Pattern loadings (27 values), e.g. fatty food on F1 | 0.773 (all 27 to 3 decimals) | 0.7727 (all 27) | < 5e−4 | ✓ PASS |
| Communality h² (9 ค่า) เช่น อาหารมัน / กิจกรรมหนักCommunalities h² (9), e.g. fatty food / vigorous activity | 0.559 / 0.094 | 0.5594 / 0.0938 | < 5e−4 | ✓ PASS |
| สหสัมพันธ์ระหว่างองค์ประกอบ F1–F2 / F1–F3 / F2–F3Factor correlations F1–F2 / F1–F3 / F2–F3 | −0.172 / 0.294 / 0.268 | −0.172 / 0.294 / 0.268 | < 5e−4 | ✓ PASS |
| ผลรวมกำลังสองของค่าน้ำหนัก pattern F1 / F2 / F3 และผลรวมสัดส่วนSum of squared pattern loadings F1 / F2 / F3 and total proportion | 1.2373 / 0.5895 / 0.5588; 0.2651 | 1.2373 / 0.5895 / 0.5588; 0.2651 | < 5e−5 | ✓ PASS |
| ความแปรปรวนร่วมที่ 3 องค์ประกอบอธิบาย (Σh²/9) เทียบกับค่าที่ DAPH รายงานว่า "variance explained"Common variance explained by the 3 factors (Σh²/9) vs the "variance explained" DAPH reports | 0.2481 | 0.2651 | 0.0170 | ✗ FAIL |
| α / ω: F1 (อาหาร 3 ข้อ) / F3 (สารเสพติด 2 ข้อ); F2 มีข้อเด่นข้อเดียวα / ω: F1 (diet, 3 items) / F3 (substance, 2 items); F2 has one salient item | 0.574 / 0.629; 0.212 / 0.361 | 0.574 / 0.629; 0.212 / 0.361 | < 5e−4 | ✓ PASS |
* ข้อมูลสุ่มของ parallel analysis ใช้ตัวสร้างเลขสุ่มต่างกัน เกณฑ์ = 3 × √2 × SD ระหว่าง seed (สูงสุด 0.0039 จากสคริปต์) · DAPH เรียกผลรวมกำลังสองของค่าน้ำหนัก pattern ว่า "eigenvalue" และรายงานผลรวมของมันว่าเป็นความแปรปรวนที่อธิบายได้ (26.5%) แต่หลังการหมุนแกนเฉียงความแปรปรวนร่วมที่อธิบายได้จริงคือ Σh²/p = 24.8% จึงเป็น FAIL · ทวนสอบ 2 ต.ค. 2026: R 4.3.3, psych 2.4.1 บนไฟล์ example_en.csv
* The parallel-analysis random data use different random-number generators; tolerance = 3 × √2 × the between-seed SD (at most 0.0039, from the script). DAPH calls the sums of squared pattern loadings "eigenvalues" and reports their total as the variance explained (26.5%), but after an oblique rotation the common variance actually explained is Σh²/p = 24.8%, hence FAIL. Verified 2 Oct 2026: R 4.3.3, psych 2.4.1 on example_en.csv.
4การแปลผลและตัวอย่างInterpretation and Example
ความเพียงพอของข้อมูล: Kaiser (1974) ให้ KMO ระดับ 0.90 ขึ้นไป = ดีเยี่ยม, 0.80 = ดีมาก, 0.70 = ปานกลาง, 0.60 = พอใช้, 0.50 = ต่ำ และต่ำกว่า 0.50 = ใช้ไม่ได้ · Bartlett's test ต้องมีนัยสำคัญ (แต่เมื่อ N ใหญ่มักมีนัยสำคัญเสมอ จึงบอกได้เพียงว่าสหสัมพันธ์ไม่เป็นศูนย์ทั้งหมด) · ค่าน้ำหนัก: |λ| ≥ 0.32 ถือว่าเด่น ข้อที่เด่นในหลายองค์ประกอบ (cross-loading) และองค์ประกอบที่มีข้อเด่นน้อยกว่า 3 ข้อควรทบทวน communality ต่ำกว่าประมาณ 0.40 แสดงว่าข้อนั้นสัมพันธ์กับองค์ประกอบน้อย (Costello & Osborne, 2005) · ความเชื่อมั่น: α และ ω ≥ 0.70 ยอมรับได้ และนิยม ω มากกว่าเพราะไม่ต้องสมมติ tau-equivalence (Hayes & Coutts, 2020) · ตัวอย่าง: KMO = 0.623 อยู่ระดับพอใช้ · โครงสร้างที่ได้มีองค์ประกอบอาหารไม่เหมาะสมชัดเจนแต่ความเชื่อมั่นยังต่ำกว่า 0.70 (α = 0.574, ω = 0.629) · องค์ประกอบการใช้สารเสพติดมีข้อเด่นเพียง 2 ข้อและความเชื่อมั่นต่ำมาก (α = 0.212, ω = 0.361) · องค์ประกอบที่สามมีข้อเด่นข้อเดียว ข้อกิจกรรมทางกายไม่รวมเป็นองค์ประกอบ · องค์ประกอบทั้งสามอธิบายความแปรปรวนร่วมของข้อได้เพียง 24.8% (DAPH พิมพ์ 26.5% จากผลรวมกำลังสองของค่าน้ำหนัก pattern) · ข้อสรุป: ชุดคำถามนี้ไม่ใช่มาตรวัดหลายมิติที่ดี ใช้ได้อย่างมากเป็นองค์ประกอบอาหารและการใช้สารเสพติดที่ต้องยืนยันด้วย CFA (9.2) ในกลุ่มตัวอย่างอื่น · ข้อมีความเบ้มาก (เช่น 92% ไม่เคยดื่มสุรา) การใช้สหสัมพันธ์ polychoric เป็นการวิเคราะห์ความไวที่ควรทำ · ผลเป็นเชิงสำรวจเสมอ
Sampling adequacy: Kaiser (1974) labels KMO in the .90s marvelous, .80s meritorious, .70s middling, .60s mediocre, .50s miserable and below .50 unacceptable. Bartlett's test should be significant, but with a large N it nearly always is, so it only shows that not all correlations are zero. Loadings: |λ| ≥ 0.32 is salient; items salient on several factors (cross-loadings) and factors with fewer than three salient items should be reconsidered, and a communality below about 0.40 shows an item that relates weakly to the factors (Costello & Osborne, 2005). Reliability: α and ω ≥ 0.70 are acceptable, and ω is preferred because it does not assume tau-equivalence (Hayes & Coutts, 2020). Example: KMO = 0.623 is mediocre. The solution has a clear unhealthy-diet factor whose reliability is still below 0.70 (α = 0.574, ω = 0.629); the substance-use factor has only two salient items and very low reliability (α = 0.212, ω = 0.361); the third factor has a single salient item, and the physical-activity items do not form a factor. The three factors explain only 24.8% of the item variance (DAPH prints 26.5%, the sum of squared pattern loadings). Conclusion: this item set is not a good multidimensional scale; at most it suggests diet and substance-use factors to be confirmed with CFA (9.2) in another sample. The items are very skewed (92% never drink alcohol), so a polychoric analysis is a sensible sensitivity check. The result is always exploratory.
📖 References
- Fabrigar, L. R., Wegener, D. T., MacCallum, R. C., & Strahan, E. J. (1999). Evaluating the use of exploratory factor analysis in psychological research. Psychological Methods, 4(3), 272–299. doi:10.1037/1082-989X.4.3.272
- Costello, A. B., & Osborne, J. W. (2005). Best practices in exploratory factor analysis: four recommendations for getting the most from your analysis. Practical Assessment, Research & Evaluation, 10(7), 1–9.
- Horn, J. L. (1965). A rationale and test for the number of factors in factor analysis. Psychometrika, 30(2), 179–185. doi:10.1007/BF02289447
- Kaiser, H. F. (1974). An index of factorial simplicity. Psychometrika, 39(1), 31–36. doi:10.1007/BF02291575
- Bartlett, M. S. (1950). Tests of significance in factor analysis. British Journal of Statistical Psychology, 3(2), 77–85. doi:10.1111/j.2044-8317.1950.tb00285.x
- Hayes, A. F., & Coutts, J. J. (2020). Use omega rather than Cronbach's alpha for estimating reliability. But… Communication Methods and Measures, 14(1), 1–24. doi:10.1080/19312458.2020.1718629
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
9.2Confirmatory Factor Analysis (CFA) — fit indices, CR / AVE, Fornell–Larcker, HTMT
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
CFA ทดสอบ โครงสร้างการวัดที่กำหนดไว้ล่วงหน้า: ผู้วิจัยระบุว่าข้อใดวัดองค์ประกอบใด แล้วดูว่าข้อมูลกลมกลืนกับโครงสร้างนั้นเพียงใด (Brown, 2015) และแต่ละองค์ประกอบวัดได้เชื่อถือได้และแยกจากกันหรือไม่ เป็นขั้นตอนมาตรฐานก่อนนำมาตรวัดไปใช้ใน SEM (บทที่ 10) หรือรายงานความตรงเชิงโครงสร้าง (construct validity) ในวารสาร · ใช้เมื่อมีทฤษฎีหรือผล EFA จากกลุ่มตัวอย่างอื่นกำหนดโครงสร้างไว้ · ไม่ควรใช้เพื่อค้นหาโครงสร้างใหม่ด้วยการปรับโมเดลตามดัชนีไปเรื่อย ๆ (ใช้ EFA, 9.1)
CFA tests a measurement structure specified in advance: the researcher states which items measure which factor, then checks how well the data fit that structure (Brown, 2015) and whether each factor is measured reliably and is distinct from the others. It is the standard step before a scale is used in SEM (Chapter 10) or its construct validity is reported in a journal. Use it when theory, or an EFA in another sample, fixes the structure; do not use it to search for a new structure by repeatedly modifying the model (use EFA, 9.1).
2หลักการและสูตรLogic and Formula
- Λ, Φ (φ_ij), Θ_δ
- ค่าน้ำหนัก / ความแปรปรวนและสหสัมพันธ์ระหว่างองค์ประกอบ / ความแปรปรวน-ร่วมของความคลาดเคลื่อนของข้อloadings / factor variances and correlations / indicator error (co)variances
- S, N, p, df
- เมทริกซ์ความแปรปรวนร่วมที่สังเกตได้ (หารด้วย N) / จำนวนผู้ตอบ / จำนวนข้อ / p(p+1)/2 − จำนวนพารามิเตอร์อิสระobserved covariance matrix (divisor N) / respondents / items / p(p+1)/2 − free parameters
- χ²₀, df₀
- ของโมเดลฐานที่ทุกข้อไม่สัมพันธ์กัน: χ²₀ = −N ln|R|, df₀ = p(p−1)/2of the baseline model with all items uncorrelated: χ²₀ = −N ln|R|, df₀ = p(p−1)/2
- r_ij, r̂_ij
- สหสัมพันธ์ที่สังเกตได้ / ที่โมเดลกำหนด (แต่ละเมทริกซ์ปรับมาตรฐานด้วยแนวทแยงของตัวเอง)observed / model-implied correlations (each matrix standardized by its own diagonal)
- λ_i, k
- ค่าน้ำหนักมาตรฐานของข้อ i / จำนวนข้อขององค์ประกอบstandardized loading of item i / number of items of the factor
- HTMT2, GM
- อัตราส่วน heterotrait–monotrait ที่ใช้ค่าเฉลี่ยเรขาคณิต (GM) ของ |r| · องค์ประกอบที่มีสหสัมพันธ์ระหว่างข้อเป็นลบแปลผลไม่ได้และแสดงเป็น —heterotrait–monotrait ratio using geometric means (GM) of |r|; a factor with a negative inter-item correlation is not interpretable and is shown as —
- V̂(θ̂), J
- เมทริกซ์ความแปรปรวนร่วมของพารามิเตอร์ / อนุพันธ์ของค่าน้ำหนักมาตรฐานต่อพารามิเตอร์parameter covariance matrix / derivatives of the standardized loading with respect to the parameters
DAPH คำนวณอย่างไร: ค่าเริ่มต้นคือ maximum likelihood (ML) บนเมทริกซ์ความแปรปรวนร่วมของข้อมูลดิบ ตรึงค่าน้ำหนักของข้อแรกในแต่ละองค์ประกอบไว้ที่ 1 · χ², log-likelihood, AIC และ BIC เท่ากับค่าเริ่มต้นของ lavaan (Rosseel, 2012) ส่วน RMSEA และช่วงเชื่อมั่น 90% หารด้วย df × (N − 1) (lavaan หารด้วย N) และ SRMR ใช้ผลต่างของสหสัมพันธ์ (Kline, 2016) · SE มาจาก expected information · ตัวเลือกอื่น: "Robust ML (MLR)" ให้ SE แบบ sandwich แต่ χ² และดัชนีความกลมกลืนยังเป็นของ ML (ไม่มีการปรับ χ² แบบ Yuan–Bentler) · เมื่อติ๊ก "Ordinal indicators (ULS, polychoric)" DAPH ประมาณด้วย unweighted least squares บนสหสัมพันธ์ polychoric/tetrachoric ไม่ว่าจะเลือก estimator ใด (ไม่ใช่ WLSMV) พร้อม SE แบบ sandwich จากความแปรปรวนร่วมเชิงเส้นกำกับของสหสัมพันธ์ polychoric (Muthén, 1984) แต่ χ² ของเส้นทางนี้คือ N × FML ที่คำนวณจากผล ULS เทียบกับเมทริกซ์ polychoric ไม่ใช่การทดสอบแบบ mean- and variance-adjusted จึงควรอ่านค่า p, CFI, TLI และ RMSEA ของเส้นทางนี้เป็นค่าโดยประมาณ · estimator "Weighted least squares (WLS)" โดยไม่ติ๊กช่องนี้ จะได้ weighted least squares บนเมทริกซ์ความแปรปรวนร่วมของข้อมูลดิบ · CR และ AVE ใช้ค่าน้ำหนักมาตรฐาน (CR เท่ากับ McDonald's ω เมื่อไม่มี error covariance) · α เป็น Cronbach's α แบบดิบ · HTMT2 ใช้สหสัมพันธ์ที่สังเกตได้ · modification index คำนวณจากการ fit โมเดลใหม่ทีละคู่ (ไม่ใช่ score test) · ตรวจ Heywood case (ค่าน้ำหนักมาตรฐานเกิน 1 หรือความแปรปรวนคงเหลือติดลบ) อัตโนมัติ
How DAPH computes it: the default is maximum likelihood (ML) on the raw-data covariance matrix with the first loading of each factor fixed to 1. χ², the log-likelihood, AIC and BIC equal lavaan's defaults (Rosseel, 2012); RMSEA and its 90% CI divide by df × (N − 1) (lavaan divides by N), and SRMR uses correlation residuals (Kline, 2016). Standard errors come from the expected information. Other options: "Robust ML (MLR)" gives sandwich standard errors, but χ² and the fit indices stay those of ML (no Yuan–Bentler scaling of χ²). With "Ordinal indicators (ULS, polychoric)" ticked, DAPH fits unweighted least squares to the polychoric/tetrachoric correlations whatever estimator is chosen (not WLSMV), with sandwich standard errors from the asymptotic covariance of the polychoric correlations (Muthén, 1984); the χ² on this route is N × FML evaluated at the ULS solution against the polychoric matrix, not a mean- and variance-adjusted test, so read its p value, CFI, TLI and RMSEA as approximations. The estimator "Weighted least squares (WLS)" with the box unticked fits weighted least squares to the raw-data covariance matrix. CR and AVE use the standardized loadings (CR equals McDonald's ω when there are no error covariances); α is the raw Cronbach's α; HTMT2 uses the observed correlations; a modification index is obtained by refitting the model with one pair freed at a time (not a score test); Heywood cases (standardized loading above 1 or a negative residual variance) are flagged automatically.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(lavaan) # cfa(), fitMeasures(), standardizedSolution(), modindices()
library(semTools) # htmt()
library(psych) # alpha()
model <- '
Subst =~ alcoholfreq + cigarettefreq + betelfreq # Substance use
Diet =~ sugaryfoodfreq + fattyfoodfreq + saltyfoodfreq # Unhealthy diet
'
round(mean(d$alcoholfreq == 0) * 100, 1) # % who never drink alcohol
fit <- cfa(model, data = d, estimator = "ML") # first loading of each factor fixed to 1
# 1) Fit indices (chi-square = N x F_ML, as DAPH)
round(unclass(fitMeasures(fit, c("chisq", "df", "pvalue", "cfi", "tli", "rmsea",
"rmsea.ci.lower", "rmsea.ci.upper", "srmr"))), 4)
round(unclass(fitMeasures(fit, c("npar", "logl", "aic", "bic"))), 3)
# DAPH's RMSEA and 90% CI divide by df x (N - 1); DAPH's SRMR uses the correlation residuals
rmsea_ci <- function(chi2, df, n) {
f <- function(lam, prob) pchisq(chi2, df, ncp = lam) - prob
bound <- function(prob) if (f(0, prob) < 0) 0 else uniroot(f, c(0, max(4 * chi2, 20)), prob = prob)$root
sqrt(c(rmsea = max(chi2 - df, 0), lower = bound(0.95), upper = bound(0.05)) / (df * (n - 1)))
}
round(rmsea_ci(fitMeasures(fit, "chisq"), fitMeasures(fit, "df"), nobs(fit)), 4)
r <- residuals(fit, type = "cor")$cov
round(c(SRMR = sqrt(mean(r[lower.tri(r, diag = TRUE)]^2))), 4)
# 2) Loadings: unstandardized (SE, 95% CI) and standardized with their delta-method 95% CI
pe <- parameterEstimates(fit); ss <- standardizedSolution(fit)
L <- pe$op == "=~"
out <- data.frame(item = pe$rhs[L], B = pe$est[L], SE = pe$se[L], lower = pe$ci.lower[L],
upper = pe$ci.upper[L], p = pe$pvalue[L], std = ss$est.std[L],
std_lower = ss$ci.lower[L], std_upper = ss$ci.upper[L], R2 = ss$est.std[L]^2)
print(cbind(out[1], round(out[-1], 4)), row.names = FALSE)
# 3) Reliability and convergent validity from the standardized loadings
lam <- split(ss$est.std[L], ss$lhs[L])
CR <- sapply(lam, function(l) sum(l)^2 / (sum(l)^2 + sum(1 - l^2)))
AVE <- sapply(lam, function(l) mean(l^2))
a <- c(Diet = alpha(d[c("sugaryfoodfreq", "fattyfoodfreq", "saltyfoodfreq")])$total$raw_alpha,
Subst = alpha(d[c("alcoholfreq", "cigarettefreq", "betelfreq")])$total$raw_alpha)
round(rbind(CR = CR, AVE = AVE, sqrt_AVE = sqrt(AVE), alpha = a[names(CR)]), 3)
# 4) Discriminant validity: factor correlation (Fornell-Larcker) and HTMT2 (geometric means)
round(ss$est.std[ss$op == "~~" & ss$lhs == "Subst" & ss$rhs == "Diet"], 3)
round(htmt(model, data = d, htmt2 = TRUE, absolute = TRUE), 3)
# 5) Modification index as DAPH computes it: the exact chi-square drop after freeing one error
# covariance, and the freed covariance divided by the model-implied SDs of the two items
fit_mi <- cfa(paste(model, "alcoholfreq ~~ cigarettefreq"), data = d)
pe2 <- parameterEstimates(fit_mi); S2 <- fitted(fit_mi)$cov
e <- pe2$est[pe2$lhs == "alcoholfreq" & pe2$op == "~~" & pe2$rhs == "cigarettefreq"]
round(c(MI = unname(fitMeasures(fit, "chisq") - fitMeasures(fit_mi, "chisq")),
EPC = e / sqrt(S2["alcoholfreq", "alcoholfreq"] * S2["cigarettefreq", "cigarettefreq"])), 3)
mi <- modindices(fit, op = "~~") # lavaan's score-test version, for comparison
head(mi[order(-mi$mi), c("lhs", "op", "rhs", "mi", "sepc.all")], 3)
# share who never drink alcohol (%)
[1] 92.2
# 1) fit indices (lavaan: RMSEA with N), log-likelihood, AIC, BIC
chisq df pvalue cfi tli rmsea rmsea.ci.lower rmsea.ci.upper
42.2211 8.0000 0.0000 0.9418 0.8909 0.0574 0.0410 0.0750
srmr
0.0363
npar logl aic bic
13.00 -11543.09 23112.18 23179.39
# RMSEA and its 90% CI with N - 1, and SRMR from correlation residuals (DAPH's formulas)
rmsea lower upper
0.0574 0.0411 0.0750
SRMR
0.0363
# 2) loadings: B, SE, 95% CI, p; standardized loading and its 95% CI; R2
item B SE lower upper p std std_lower std_upper R2
alcoholfreq 1.0000 0.0000 1.0000 1.0000 NA 0.3666 0.2753 0.4580 0.1344
cigarettefreq 3.6172 0.6919 2.2611 4.9733 0 0.4206 0.3244 0.5168 0.1769
betelfreq 3.2140 0.6439 1.9520 4.4760 0 0.3244 0.2354 0.4133 0.1052
sugaryfoodfreq 1.0000 0.0000 1.0000 1.0000 NA 0.4956 0.4354 0.5557 0.2456
fattyfoodfreq 0.9845 0.0922 0.8037 1.1652 0 0.7159 0.6502 0.7815 0.5125
saltyfoodfreq 1.0627 0.0938 0.8789 1.2464 0 0.5489 0.4881 0.6097 0.3013
# 3) CR, AVE, square root of AVE, Cronbach's alpha
Diet Subst
CR 0.615 0.324
AVE 0.353 0.139
sqrt_AVE 0.594 0.373
alpha 0.574 0.225
# 4) factor correlation, then HTMT2
[1] 0.491
Subst Diet
Subst 1.000
Diet 0.551 1.000
# 5) modification index (exact chi-square drop) and EPC as DAPH defines them; lavaan's score test
MI EPC
18.357 0.145
lhs op rhs mi sepc.all
22 alcoholfreq ~~ cigarettefreq 18.907 0.236
35 sugaryfoodfreq ~~ saltyfoodfreq 13.011 -0.221
34 sugaryfoodfreq ~~ fattyfoodfreq 11.904 0.364
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| χ² / df / p | 42.2211 / 8 / < 0.001 | 42.221 / 8 / < 0.001 | < 5e−4 | ✓ PASS |
| CFI / TLI | 0.9418 / 0.8909 | 0.9418 / 0.8909 | < 5e−5 | ✓ PASS |
| RMSEA (90% CI) หารด้วย N − 1RMSEA (90% CI), divisor N − 1 | 0.0574 (0.0411 to 0.0750) | 0.0574 (0.0411 to 0.0750) | < 5e−5 | ✓ PASS |
| SRMR (เกณฑ์ ±0.001)*SRMR (tolerance ±0.001)* | 0.0363 | 0.0364 | 0.0001 | ✓ PASS |
| log-likelihood / AIC / BIC | −11543.09 / 23112.18 / 23179.39 | −11543.089 / 23112.178 / 23179.390 | < 5e−3 | ✓ PASS |
| ค่าน้ำหนักไม่มาตรฐาน: บุหรี่ / หมาก / อาหารมัน / อาหารเค็ม (เกณฑ์ ±0.001)*Unstandardized loadings: cigarettes / betel / fatty / salty food (tolerance ±0.001)* | 3.6172 / 3.2140 / 0.9845 / 1.0627 | 3.6170 / 3.2111 / 0.9848 / 1.0626 | 0.0029 (betel) | ✗ FAIL |
| SE ของค่าน้ำหนักข้างบนSEs of these loadings | 0.6919 / 0.6439 / 0.0922 / 0.0938 | 0.6918 / 0.6433 / 0.0923 / 0.0938 | ≤ 0.0006 | ✓ PASS |
| ค่าน้ำหนักมาตรฐาน 6 ข้อ (เกณฑ์ ±0.001)*Six standardized loadings (tolerance ±0.001)* | 0.3666 / 0.4206 / 0.3244 / 0.4956 / 0.7159 / 0.5489 | 0.3668 / 0.4207 / 0.3242 / 0.4955 / 0.7160 / 0.5487 | ≤ 0.0002 | ✓ PASS |
| Std. 95% CI เช่น บุหรี่ / อาหารมันStd. 95% CI, e.g. cigarettes / fatty food | 0.3244 to 0.5168 / 0.6502 to 0.7815 | 0.324 to 0.517 / 0.650 to 0.782 | < 5e−4 | ✓ PASS |
| CR / AVE / α: สารเสพติด; อาหารCR / AVE / α: substance use; diet | 0.324 / 0.139 / 0.225; 0.615 / 0.353 / 0.574 | 0.324 / 0.139 / 0.225; 0.615 / 0.353 / 0.574 | < 5e−4 | ✓ PASS |
| สหสัมพันธ์ระหว่างองค์ประกอบ / √AVE / HTMT2Factor correlation / √AVE / HTMT2 | 0.491 / 0.373, 0.594 / 0.551 | 0.491 / 0.373, 0.594 / 0.551 | < 5e−4 | ✓ PASS |
| MI สูงสุด (สุรา–บุหรี่) / EPCLargest MI (alcohol–cigarettes) / EPC | 18.357 / 0.145 | 18.36 / 0.145 | < 5e−3 | ✓ PASS |
* ค่าที่ขึ้นกับการหาค่าที่ดีที่สุดแบบวนซ้ำ: เกณฑ์ ±0.001 · χ² ของ DAPH และ lavaan เท่ากัน แต่ DAPH หยุดการหาค่าเร็วกว่าเล็กน้อย ค่าน้ำหนักของหมากต่างกัน 0.0029 (เกินเกณฑ์) · ทวนสอบ 2 ต.ค. 2026: R 4.3.3, lavaan 0.6-21 บนไฟล์ example_en.csv
* Quantities that depend on the iterative optimisation: tolerance ±0.001. DAPH's χ² equals lavaan's, but DAPH stops its optimiser slightly earlier; the betel loading differs by 0.0029 (beyond the tolerance). Verified 2 Oct 2026: R 4.3.3, lavaan 0.6-21 on example_en.csv.
4การแปลผลและตัวอย่างInterpretation and Example
ความกลมกลืน: Hu & Bentler (1999) เสนอ CFI และ TLI ประมาณ 0.95 ขึ้นไป, RMSEA ไม่เกินประมาณ 0.06 และ SRMR ไม่เกินประมาณ 0.08 · Browne & Cudeck (1992) ถือ RMSEA ≤ 0.05 ว่ากลมกลืนใกล้เคียง และ ≤ 0.08 ว่าพอใช้ · ความตรงเชิงลู่เข้า: ค่าน้ำหนักมาตรฐานควรมีนัยสำคัญและไม่ต่ำกว่า 0.50, CR ≥ 0.70 และ AVE ≥ 0.50 (Fornell & Larcker, 1981) · ความตรงเชิงจำแนก: √AVE ของแต่ละองค์ประกอบควรมากกว่าสหสัมพันธ์กับองค์ประกอบอื่น และ HTMT ควรต่ำกว่า 0.85 (เข้ม) หรือ 0.90 (หลวม) (Henseler และคณะ, 2015) · ตัวอย่าง: RMSEA = 0.057 และ SRMR = 0.036 อยู่ในเกณฑ์ แต่ CFI = 0.942 และ TLI = 0.891 ต่ำกว่าเกณฑ์ และ χ²(8) = 42.221 มีนัยสำคัญ จึงกลมกลืนพอใช้เท่านั้น · ข้อของการใช้สารเสพติดมีค่าน้ำหนัก 0.32–0.42, CR = 0.324 และ AVE = 0.139 จึงเป็นองค์ประกอบที่วัดได้ไม่ดี องค์ประกอบอาหาร (CR = 0.615, AVE = 0.353) ก็ยังต่ำกว่าเกณฑ์ · Fornell–Larcker ไม่ผ่านสำหรับการใช้สารเสพติด (√AVE 0.373 < 0.491) ขณะที่ HTMT2 = 0.551 ผ่าน เพราะ AVE ที่ต่ำทำให้เกณฑ์ Fornell–Larcker ผ่านยาก · MI สูงสุดคือความคลาดเคลื่อนของสุรากับบุหรี่ (MI = 18.36) ซึ่งอธิบายได้ด้วยการใช้ร่วมกัน แต่ควรปลดเฉพาะเมื่อมีเหตุผลเชิงทฤษฎีและตรวจซ้ำในกลุ่มตัวอย่างอื่น (Sörbom, 1989; MacCallum และคณะ, 1992) · ข้อมีความเบ้มาก (เช่น 92% ไม่เคยดื่มสุรา) การใช้ ML บนสหสัมพันธ์ Pearson จึงลดทอนค่าน้ำหนัก ควรทำการวิเคราะห์ความไวด้วยตัวเลือกตัวชี้วัดอันดับ · ข้อสรุป: โครงสร้างสององค์ประกอบได้รับการสนับสนุนเพียงบางส่วน ยังไม่ควรใช้เป็นมาตรวัดที่เชื่อถือได้ · Heywood case: ไม่พบ
Fit: Hu & Bentler (1999) proposed CFI and TLI close to 0.95 or above, RMSEA close to 0.06 or below and SRMR close to 0.08 or below; Browne & Cudeck (1992) regard RMSEA ≤ 0.05 as close and ≤ 0.08 as reasonable fit. Convergent validity: standardized loadings significant and preferably 0.50 or more, CR ≥ 0.70 and AVE ≥ 0.50 (Fornell & Larcker, 1981). Discriminant validity: each factor's √AVE should exceed its correlations with the other factors, and HTMT should be below 0.85 (strict) or 0.90 (liberal) (Henseler et al., 2015). Example: RMSEA = 0.057 and SRMR = 0.036 meet the criteria, but CFI = 0.942 and TLI = 0.891 do not, and χ²(8) = 42.221 is significant, so the fit is only fair. The substance-use items load 0.32–0.42 with CR = 0.324 and AVE = 0.139, a poorly measured factor; the diet factor (CR = 0.615, AVE = 0.353) also falls short. Fornell–Larcker fails for substance use (√AVE 0.373 < 0.491) while HTMT2 = 0.551 passes, because a low AVE makes the Fornell–Larcker criterion hard to meet. The largest MI is the error covariance of alcohol and cigarettes (MI = 18.36), plausible as co-use, but free it only with a theoretical reason and cross-validate in another sample (Sörbom, 1989; MacCallum et al., 1992). The items are very skewed (92% never drink alcohol), so ML on Pearson correlations attenuates the loadings; a sensitivity analysis with the ordinal option is advisable. Conclusion: the two-factor structure is only partly supported and is not yet a reliable scale. No Heywood case was found.
📖 References
- Brown, T. A. (2015). Confirmatory Factor Analysis for Applied Research (2nd ed.). New York: Guilford Press. ISBN 978-1-4625-1779-4.
- Hu, L., & Bentler, P. M. (1999). Cutoff criteria for fit indexes in covariance structure analysis: Conventional criteria versus new alternatives. Structural Equation Modeling, 6(1), 1–55. doi:10.1080/10705519909540118
- Browne, M. W., & Cudeck, R. (1992). Alternative ways of assessing model fit. Sociological Methods & Research, 21(2), 230–258. doi:10.1177/0049124192021002005
- Fornell, C., & Larcker, D. F. (1981). Evaluating structural equation models with unobservable variables and measurement error. Journal of Marketing Research, 18(1), 39–50. doi:10.1177/002224378101800104
- Henseler, J., Ringle, C. M., & Sarstedt, M. (2015). A new criterion for assessing discriminant validity in variance-based structural equation modeling. Journal of the Academy of Marketing Science, 43(1), 115–135. doi:10.1007/s11747-014-0403-8
- Roemer, E., Schuberth, F., & Henseler, J. (2021). HTMT2–an improved criterion for assessing discriminant validity in structural equation modeling. Industrial Management & Data Systems, 121(12), 2637–2650. doi:10.1108/IMDS-02-2021-0082
- Muthén, B. (1984). A general structural equation model with dichotomous, ordered categorical, and continuous latent variable indicators. Psychometrika, 49(1), 115–132. doi:10.1007/BF02294210
- Sörbom, D. (1989). Model modification. Psychometrika, 54(3), 371–384. doi:10.1007/BF02294623
- MacCallum, R. C., Roznowski, M., & Necowitz, L. B. (1992). Model modifications in covariance structure analysis: The problem of capitalization on chance. Psychological Bulletin, 111(3), 490–504. doi:10.1037/0033-2909.111.3.490
- Kline, R. B. (2016). Principles and Practice of Structural Equation Modeling (4th ed.). New York: Guilford Press. ISBN 978-1-4625-2334-4.
- Rosseel, Y. (2012). lavaan: an R package for structural equation modeling. Journal of Statistical Software, 48(2), 1–36. doi:10.18637/jss.v048.i02
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 10 — โมเดลสมการโครงสร้าง (SEM & GSEM — ตัวแปรแฝง)Chapter 10 — Structural Equation Modeling (SEM & GSEM — latent variables) ✓ Verified
โมเดลสมการโครงสร้าง (SEM) ต่อยอดการวิเคราะห์เส้นทางของบทที่ 8 โดยเพิ่ม โมเดลการวัด (CFA) สร้าง ตัวแปรแฝง จากตัวชี้วัดหลายข้อ แล้วประมาณ โมเดลการวัดและโมเดลเชิงโครงสร้างพร้อมกัน ด้วย maximum likelihood (10.1) ความคลาดเคลื่อนของการวัดจึงถูกแยกออกจากความสัมพันธ์เชิงโครงสร้าง และสัมประสิทธิ์ไม่ถูกลดทอน · GSEM (10.2) ใช้เมื่อตัวแปรตามเป็นสองกลุ่ม อันดับ หรือหลายกลุ่ม: DAPH ประมาณแบบสองขั้น คือ CFA ให้คะแนนองค์ประกอบ แล้วใช้คะแนนนั้นในโมเดล logit / ordered logit / multinomial logit · วิธีนี้ไม่ใช่การประมาณพร้อมกันทั้งโมเดล คะแนนองค์ประกอบยังมีความคลาดเคลื่อนของการวัด สัมประสิทธิ์เชิงโครงสร้างจึงถูกลดทอนได้ · เหมาะกับงานวิจัยที่มีแนวคิดซึ่งวัดตรงไม่ได้ เช่น พฤติกรรมการกิน หรือพฤติกรรมเสี่ยง และควรตรวจโมเดลการวัดด้วย CFA (9.2) ก่อน Structural equation modeling (SEM) extends the path analysis of Chapter 8 with a measurement model (CFA): it builds latent variables from several indicators and estimates the measurement and structural models jointly by maximum likelihood (10.1), so measurement error is separated from the structural relations and the coefficients are not attenuated. GSEM (10.2) is for a binary, ordinal or nominal outcome: DAPH estimates it in two stages, CFA factor scores first and then a logit / ordered-logit / multinomial-logit model on those scores. This is not a joint estimation of the whole model; the factor scores still contain measurement error, so the structural coefficients can be attenuated. These methods suit research on constructs that cannot be measured directly, such as dietary or risk behaviour, and the measurement model should first be checked with CFA (9.2).
10.1Structural Equation Modeling — CFA measurement + structural model (loadings, CR/AVE, discriminant validity, direct/indirect/total, model fit)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
SEM ใช้เมื่อตัวแปรสำคัญ เช่น "พฤติกรรมการกิน" หรือ "การใช้สารเสพติด" วัดตรงไม่ได้ แต่สะท้อนผ่านข้อคำถามหลายข้อ · SEM สร้างตัวแปรแฝงจากข้อคำถาม (โมเดลการวัด แบบ CFA ใน 9.2) และประมาณเส้นทางระหว่างตัวแปรแฝงกับตัวแปรสังเกตได้ไปพร้อมกัน (Bollen, 1989; Kline, 2016) ความคลาดเคลื่อนของการวัดจึงไม่ลดทอนสัมประสิทธิ์เชิงโครงสร้าง และได้การทดสอบความกลมกลืนของทั้งโมเดล · DAPH ใช้ SEM เมื่อตัวแปรตามเป็นตัวแปรต่อเนื่อง (ตัวแปรตามแบบกลุ่มใช้ GSEM, 10.2) · ไม่ควรใช้เมื่อโมเดลการวัดยังไม่ผ่าน CFA หรือเมื่อกลุ่มตัวอย่างเล็กเมื่อเทียบกับจำนวนพารามิเตอร์
SEM is used when key variables such as "dietary behaviour" or "substance use" cannot be measured directly but are reflected by several items. SEM builds latent variables from the items (the measurement model, a CFA as in 9.2) and estimates the paths among latent and observed variables at the same time (Bollen, 1989; Kline, 2016), so measurement error does not attenuate the structural coefficients, and the whole model gets a test of fit. DAPH uses SEM when the outcome is continuous (a categorical outcome uses GSEM, 10.2). Do not use it before the measurement model has passed a CFA, or with a sample that is small relative to the number of parameters.
2หลักการและสูตรLogic and Formula
- λ, ξ, η
- ค่าน้ำหนัก / ตัวแปรแฝงต้นทาง (exogenous) / ตัวแปรปลายทาง (endogenous)loading / exogenous latent variable / endogenous variable
- B, Γ, ζ
- เส้นทางระหว่างตัวแปรปลายทาง / จากตัวแปรต้นทางไปปลายทาง / ส่วนเหลือของสมการpaths among endogenous variables / from exogenous to endogenous / equation residuals
- B, SE(B), β
- (ในสูตรเส้นทาง) สัมประสิทธิ์ไม่มาตรฐานและ SE จาก ML / สัมประสิทธิ์มาตรฐาน (std.all) ใช้ SD ที่โมเดลกำหนด(in the path formulas) unstandardized coefficient and its ML SE / standardized coefficient (std.all) using model-implied SDs
- χ²₀
- χ² ของโมเดลฐานที่ทุกตัวแปรไม่สัมพันธ์กันχ² of the baseline model with all variables uncorrelated
DAPH คำนวณอย่างไร: DAPH ประมาณโมเดลการวัดและโมเดลเชิงโครงสร้างพร้อมกันด้วย maximum likelihood ลองตัวหาค่าที่ดีที่สุดหลายวิธีแล้วเก็บค่าที่ FML ต่ำสุด · χ², CFI, TLI, NFI, GFI, AGFI, SRMR, log-likelihood, AIC และ BIC ตรงกับค่าเริ่มต้นของ lavaan (Rosseel, 2012) · RMSEA และช่วงเชื่อมั่น 90% หารด้วย df × (N − 1) · ตัวแปรกลุ่มที่มีตั้งแต่ 3 ระดับที่ใช้เป็นตัวแปรสังเกตได้ในโมเดลเชิงโครงสร้างถูกแยกเป็นตัวแปรหุ่น · ตารางผลแสดงสัมประสิทธิ์มาตรฐาน (β) · ข้อจำกัดที่พบ: (1) SE ของ β ได้จากการคูณ SE ของ B ด้วย |β/B| ไม่ใช่ delta method ในตัวอย่างนี้ CI ของเส้นทางการใช้สารเสพติด → อาหาร กว้างกว่า delta method ของ lavaan ประมาณ 67% (0.295 ถึง 0.684 เทียบ 0.373 ถึง 0.606) และ Monte Carlo ของอิทธิพลทางอ้อมสุ่ม β แต่ละตัวแยกกันจาก SE นี้ (Preacher & Selig, 2012) · (2) ตัวเลือก "Robust ML (MLR)" ใช้ค่าประมาณของ ML แล้วคำนวณ SE แบบ sandwich จาก expected information ส่วน χ² และดัชนีความกลมกลืนไม่ได้ปรับ (รายงานระบุไว้) ค่า SE เท่ากับ MLR ของ lavaan เมื่อตั้ง information = "expected" · (3) เมื่อองค์ประกอบสองตัวเชื่อมกันด้วยเส้นทางเชิงโครงสร้าง ตาราง Fornell–Larcker ของ DAPH เว้นช่องสหสัมพันธ์ไว้ว่าง ทั้งที่สหสัมพันธ์ที่โมเดลกำหนดคือ 0.490 ซึ่งมากกว่า √AVE ของการใช้สารเสพติด (0.373) · แผนภาพวาดตามหลักมาตรฐาน (วงรี = ตัวแปรแฝง, สี่เหลี่ยม = ตัวแปรสังเกตได้, ลูกศรเดี่ยว = เส้นทาง, ลูกศรโค้งสองหัว = ความแปรปรวนร่วม)
How DAPH computes it: DAPH fits the measurement and structural models jointly by maximum likelihood, trying several optimisers and keeping the lowest FML. χ², CFI, TLI, NFI, GFI, AGFI, SRMR, the log-likelihood, AIC and BIC equal lavaan's defaults (Rosseel, 2012); RMSEA and its 90% CI divide by df × (N − 1). Categorical observed structural variables with three or more levels are split into dummies. The results table shows standardized coefficients (β). Limitations found: (1) the SE of β is the SE of B multiplied by |β/B|, not the delta method; in this example the CI of the path substance use → diet is about 67% wider than lavaan's delta-method interval (0.295 to 0.684 versus 0.373 to 0.606), and the Monte Carlo interval of the indirect effect draws each β independently from this SE (Preacher & Selig, 2012). (2) The "Robust ML (MLR)" option keeps the ML estimates and computes sandwich standard errors from the expected information, leaving χ² and the fit indices unscaled (the report says so); the SEs equal lavaan's MLR with information = "expected". (3) When two factors are linked by a structural path, DAPH's Fornell–Larcker table leaves the correlation cell empty, although the model-implied correlation is 0.490, which exceeds √AVE of substance use (0.373). The diagram follows standard conventions (ellipse = latent, rectangle = observed, single arrow = path, curved double arrow = covariance).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(lavaan) # sem(), fitMeasures(), parameterEstimates()
library(semTools) # htmt()
library(psych) # alpha()
model <- '
# measurement model (the first loading of each factor is fixed to 1)
Subst =~ alcoholfreq + cigarettefreq + betelfreq # Substance use
Diet =~ sugaryfoodfreq + fattyfoodfreq + saltyfoodfreq # Unhealthy diet
# structural model
Diet ~ a * Subst
bmi ~ b * Diet + c * Subst
'
fit <- sem(model, data = d) # maximum likelihood; chi-square = N x F_ML
# 1) Fit indices, log-likelihood, AIC, BIC
round(unclass(fitMeasures(fit, c("chisq", "df", "pvalue", "cfi", "tli", "rmsea", "rmsea.ci.lower",
"rmsea.ci.upper", "srmr", "gfi", "agfi", "nfi"))), 4)
round(unclass(fitMeasures(fit, c("npar", "logl", "aic", "bic"))), 3)
rmsea_ci <- function(chi2, df, n) { # DAPH divides by df x (N - 1); lavaan by df x N
f <- function(lam, prob) pchisq(chi2, df, ncp = lam) - prob
bound <- function(prob) if (f(0, prob) < 0) 0 else uniroot(f, c(0, max(4 * chi2, 20)), prob = prob)$root
sqrt(c(rmsea = max(chi2 - df, 0), lower = bound(0.95), upper = bound(0.05)) / (df * (n - 1)))
}
round(rmsea_ci(fitMeasures(fit, "chisq"), fitMeasures(fit, "df"), nobs(fit)), 4)
# 2) Loadings and structural paths: B, SE, p and the standardized value (std.all).
# DAPH gives a standardized path the SE of B rescaled by |beta / B| and a 95% CI beta +/- 1.96 SE
pe <- parameterEstimates(fit, standardized = TRUE)
k <- pe$op %in% c("=~", "~")
tab <- data.frame(path = paste(pe$lhs, pe$op, pe$rhs)[k], B = pe$est[k], SE = pe$se[k], p = pe$pvalue[k],
beta = pe$std.all[k], se_beta = pe$se[k] * abs(pe$std.all[k] / pe$est[k]))
tab$lower <- tab$beta - 1.96 * tab$se_beta; tab$upper <- tab$beta + 1.96 * tab$se_beta
print(cbind(tab[1], round(tab[-1], 4)), row.names = FALSE)
round(inspect(fit, "r2")[c("Diet", "bmi")], 4) # R2 of the endogenous variables
# 3) Measurement quality: CR, AVE, Cronbach's alpha, Fornell-Larcker, HTMT2
lam <- split(pe$std.all[pe$op == "=~"], pe$lhs[pe$op == "=~"])
CR <- sapply(lam, function(l) sum(abs(l))^2 / (sum(abs(l))^2 + sum(1 - l^2)))
AVE <- sapply(lam, function(l) mean(l^2))
alp <- c(Diet = alpha(d[c("sugaryfoodfreq", "fattyfoodfreq", "saltyfoodfreq")])$total$raw_alpha,
Subst = alpha(d[c("alcoholfreq", "cigarettefreq", "betelfreq")])$total$raw_alpha)
round(rbind(CR = CR, AVE = AVE, sqrt_AVE = sqrt(AVE), alpha = alp[names(CR)]), 3)
round(htmt(model, data = d, htmt2 = TRUE), 3)
round(unclass(lavInspect(fit, "cor.lv")), 4) # model-implied factor correlation (Fornell-Larcker)
# 4) Indirect (a x b) and total (c + a x b) effects on the standardized scale with DAPH's
# Monte Carlo interval: 20,000 independent normal draws of each standardized path
s <- split(tab[c("beta", "se_beta")], tab$path) # one row per path, picked by name
pa <- s[["Diet ~ Subst"]]; pb <- s[["bmi ~ Diet"]]; pc <- s[["bmi ~ Subst"]]
set.seed(12345)
da <- rnorm(20000, pa$beta, pa$se_beta); db <- rnorm(20000, pb$beta, pb$se_beta)
dc <- rnorm(20000, pc$beta, pc$se_beta)
mc <- cbind(indirect = da * db, total = dc + da * db)
p_mc <- function(x) min(1, 2 * min(mean(x <= 0), mean(x >= 0)))
round(rbind(estimate = c(pa$beta * pb$beta, pc$beta + pa$beta * pb$beta),
lower = apply(mc, 2, quantile, 0.025), upper = apply(mc, 2, quantile, 0.975),
p = apply(mc, 2, p_mc)), 4)
# 5) For comparison: lavaan's delta-method interval of the same standardized effects
std <- standardizedSolution(fit)
round(as.data.frame(subset(std, op == "~", select = c(lhs, rhs, est.std, se, ci.lower, ci.upper))[, -(1:2)]), 4)
# 6) Monte Carlo check: SD of the interval limits and p of part 4 across 10 other seeds
round(apply(sapply(1:10, function(seed) {
set.seed(seed)
a1 <- rnorm(20000, pa$beta, pa$se_beta); b1 <- rnorm(20000, pb$beta, pb$se_beta)
c1 <- rnorm(20000, pc$beta, pc$se_beta); x <- cbind(a1 * b1, c1 + a1 * b1)
c(apply(x, 2, quantile, 0.025), apply(x, 2, quantile, 0.975), apply(x, 2, p_mc))
}), 1, sd), 4)
# 7) DAPH's MLR option: the ML estimates with sandwich SEs from the expected information;
# chi-square and fit indices stay unscaled in DAPH (lavaan's scaled chi-square shown for comparison)
fit_mlr <- sem(model, data = d, estimator = "MLR", information = "expected")
pm <- parameterEstimates(fit_mlr); k <- pm$op %in% c("=~", "~") & pm$se > 0
print(setNames(round(pm$se[k], 4), paste(pm$lhs, pm$op, pm$rhs)[k]))
round(unclass(fitMeasures(fit_mlr, c("chisq", "chisq.scaled"))), 4)
# 1) fit indices (lavaan: RMSEA with N), log-likelihood, AIC, BIC; RMSEA and 90% CI with N - 1 (DAPH)
chisq df pvalue cfi tli rmsea rmsea.ci.lower rmsea.ci.upper
45.5487 12.0000 0.0000 0.9430 0.9002 0.0464 0.0325 0.0610
srmr gfi agfi nfi
0.0326 0.9903 0.9773 0.9252
npar logl aic bic
16.00 -15077.89 30187.77 30270.50
rmsea lower upper
0.0464 0.0326 0.0611
# 2) paths: B, SE, p, standardized beta, DAPH's rescaled SE and 95% CI; R2 of Diet and BMI
path B SE p beta se_beta lower upper
Subst =~ alcoholfreq 1.0000 0.0000 NA 0.3636 0.0000 0.3636 0.3636
Subst =~ cigarettefreq 3.7073 0.7048 0.0000 0.4275 0.0813 0.2682 0.5868
Subst =~ betelfreq 3.2125 0.6426 0.0000 0.3215 0.0643 0.1955 0.4476
Diet =~ sugaryfoodfreq 1.0000 0.0000 NA 0.4961 0.0000 0.4961 0.4961
Diet =~ fattyfoodfreq 0.9824 0.0919 0.0000 0.7151 0.0669 0.5839 0.8463
Diet =~ saltyfoodfreq 1.0620 0.0937 0.0000 0.5491 0.0484 0.4542 0.6441
Diet ~ Subst 1.8278 0.3697 0.0000 0.4895 0.0990 0.2954 0.6835
bmi ~ Diet 0.0464 0.2803 0.8686 0.0082 0.0493 -0.0885 0.1049
bmi ~ Subst -1.6649 1.3535 0.2187 -0.0785 0.0638 -0.2035 0.0466
Diet bmi
0.2396 0.0056
# 3) CR, AVE, sqrt(AVE), alpha; HTMT2; model-implied factor correlation
Diet Subst
CR 0.615 0.324
AVE 0.353 0.139
sqrt_AVE 0.594 0.373
alpha 0.574 0.225
Subst Diet
Subst 1.000
Diet 0.551 1.000
Subst Diet
Subst 1.0000 0.4895
Diet 0.4895 1.0000
# 4) indirect and total effect (standardized) with DAPH's Monte Carlo interval
indirect total
estimate 0.0040 -0.0745
lower -0.0441 -0.2101
upper 0.0534 0.0586
p 0.8573 0.2730
# 5) lavaan's delta-method intervals of the standardized paths
est.std se ci.lower ci.upper
7 0.4895 0.0594 0.3731 0.6058
8 0.0082 0.0493 -0.0885 0.1048
9 -0.0785 0.0626 -0.2011 0.0442
# 6) SD across 10 other seeds: lower ind, lower tot, upper ind, upper tot, p ind, p tot
[1] 0.0005 0.0015 0.0005 0.0012 0.0049 0.0067
# 7) MLR (expected information): sandwich SEs of the free loadings and paths; chi-square unscaled and scaled
Subst =~ cigarettefreq Subst =~ betelfreq Diet =~ fattyfoodfreq Diet =~ saltyfoodfreq Diet ~ Subst
0.8178 0.8223 0.1166 0.1185 0.4021
bmi ~ Diet bmi ~ Subst
0.2794 1.4058
chisq chisq.scaled
45.5487 34.6346
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| χ² / df / p | 45.5487 / 12 / < 0.001 | 45.549 / 12 / < 0.001 | < 5e−4 | ✓ PASS |
| CFI / TLI / NFI | 0.9430 / 0.9002 / 0.9252 | 0.943 / 0.9002 / 0.9252 | < 5e−5 | ✓ PASS |
| RMSEA (90% CI) หารด้วย N − 1RMSEA (90% CI), divisor N − 1 | 0.0464 (0.0326 to 0.0611) | 0.0464 (0.0326 to 0.0611) | < 5e−5 | ✓ PASS |
| SRMR / GFI / AGFI | 0.0326 / 0.9903 / 0.9773 | 0.0326 / 0.9903 / 0.9773 | < 5e−5 | ✓ PASS |
| log-likelihood / AIC / BIC | −15077.89 / 30187.77 / 30270.50 | −15077.887 / 30187.774 / 30270.496 | < 5e−3 | ✓ PASS |
| ค่าน้ำหนัก B (4 ค่าอิสระ) / ค่าน้ำหนักมาตรฐาน (6)Loadings B (4 free) / standardized loadings (6) | 3.7073, 3.2125, 0.9824, 1.0620 / 0.3636 … 0.7151 | 3.7073, 3.2126, 0.9824, 1.0620 / 0.3636 … 0.7151 | ≤ 1e−4 | ✓ PASS |
| เส้นทาง B (SE): สารเสพติด → อาหาร / อาหาร → BMI / สารเสพติด → BMIPaths B (SE): substance → diet / diet → BMI / substance → BMI | 1.8278 (0.3697) / 0.0464 (0.2803) / −1.6649 (1.3535) | 1.8278 (0.3697) / 0.0464 (0.2803) / −1.6649 (1.3535) | < 5e−5 | ✓ PASS |
| β และ p ของสามเส้นทางβ and p of the three paths | 0.4895, 0.0082, −0.0785 / < 0.001, 0.8686, 0.2187 | 0.489, 0.008, −0.078 / < 0.001, 0.869, 0.219 | < 5e−4 | ✓ PASS |
| 95% CI ของ β ตามวิธีของ DAPH (SE ของ B × |β/B|)95% CI of β by DAPH's method (SE of B × |β/B|) | 0.2954 to 0.6835 / −0.0885 to 0.1049 / −0.2035 to 0.0466 | 0.295 to 0.684 / −0.089 to 0.105 / −0.203 to 0.047 | < 5e−4 | ✓ PASS |
| CI เดียวกันเทียบ delta method ของ lavaanThe same CIs versus lavaan's delta method | 0.3731 to 0.6058 / −0.0885 to 0.1048 / −0.2011 to 0.0442 | 0.295 to 0.684 / −0.089 to 0.105 / −0.203 to 0.047 | 0.078 (substance → diet) | ✗ FAIL |
| R² ของอาหาร / BMIR² of diet / BMI | 0.2396 / 0.0056 | 0.2396 / 0.0056 | < 5e−5 | ✓ PASS |
| CR / AVE / α: สารเสพติด; อาหาร · HTMT2CR / AVE / α: substance; diet · HTMT2 | 0.324 / 0.139 / 0.225; 0.615 / 0.353 / 0.574 · 0.551 | 0.324 / 0.139 / 0.225; 0.615 / 0.353 / 0.574 · 0.551 | < 5e−4 | ✓ PASS |
| Fornell–Larcker: สหสัมพันธ์ระหว่างองค์ประกอบFornell–Larcker: factor correlation | 0.4895 | — (blank) | missing | ✗ FAIL |
| อิทธิพลทางอ้อม β / 95% CI / p (เกณฑ์ ±0.002 / ±0.021)*Indirect β / 95% CI / p (tolerance ±0.002 / ±0.021)* | 0.0040 / −0.0441 to 0.0534 / 0.8573 | 0.004 / −0.044 to 0.054 / 0.8667 | 0.0001 / 0.0006 / 0.0094 | ✓ PASS |
| อิทธิพลรวม β / 95% CI / p (เกณฑ์ ±0.006 / ±0.028)*Total β / 95% CI / p (tolerance ±0.006 / ±0.028)* | −0.0745 / −0.2101 to 0.0586 / 0.2730 | −0.074 / −0.210 to 0.060 / 0.2777 | 0.0001 / 0.0014 / 0.0047 | ✓ PASS |
| ตัวเลือก MLR: SE แบบ sandwich ของเส้นทางสารเสพติด → อาหาร / ค่าน้ำหนักอาหารเค็ม / ค่าน้ำหนักบุหรี่MLR option: sandwich SE of substance → diet / salty-food loading / cigarette loading | 0.4021 / 0.1185 / 0.8178 | 0.4021 / 0.1185 / 0.8178 | < 5e−5 | ✓ PASS |
* Monte Carlo: เกณฑ์ = 3 × √2 × SD ระหว่าง seed จากส่วนที่ 6 ของสคริปต์ · แถว FAIL: DAPH ใช้ SE แบบปรับสเกลแทน delta method และเว้นสหสัมพันธ์ของ Fornell–Larcker ไว้ว่าง · ทวนสอบ 2 ต.ค. 2026: R 4.3.3, lavaan 0.6-21 บนไฟล์ example_en.csv
* Monte Carlo: tolerance = 3 × √2 × the between-seed SD from part 6 of the script. FAIL rows: DAPH uses a rescaled SE instead of the delta method and leaves the Fornell–Larcker correlation blank. Verified 2 Oct 2026: R 4.3.3, lavaan 0.6-21 on example_en.csv.
4การแปลผลและตัวอย่างInterpretation and Example
โมเดลการวัด: ค่าน้ำหนักมาตรฐานควรไม่ต่ำกว่า 0.50, CR ≥ 0.70 และ AVE ≥ 0.50 (ความตรงเชิงลู่เข้า) · √AVE มากกว่าสหสัมพันธ์ระหว่างองค์ประกอบ (Fornell & Larcker, 1981) และ HTMT2 < 0.85 (ความตรงเชิงจำแนก; Henseler และคณะ, 2015; Roemer และคณะ, 2021) · ความกลมกลืน: CFI/TLI ประมาณ 0.95 ขึ้นไป, RMSEA ไม่เกินประมาณ 0.06, SRMR ไม่เกินประมาณ 0.08 (Hu & Bentler, 1999) และ RMSEA ≤ 0.08 ถือว่าพอใช้ (Browne & Cudeck, 1992) · GFI/AGFI ไวต่อขนาดตัวอย่าง จึงไม่ควรใช้ตัดสินเพียงลำพัง · การส่งผ่าน: ตัดสินจาก CI ของอิทธิพลทางอ้อม (ไม่คร่อม 0 = มีนัยสำคัญ) · ตัวอย่าง: RMSEA = 0.046 และ SRMR = 0.033 อยู่ในเกณฑ์ แต่ CFI = 0.943 และ TLI = 0.900 ต่ำกว่า 0.95 ความกลมกลืนจึงพอใช้ · ผู้ที่ใช้สารเสพติดบ่อยมีแนวโน้มกินอาหารไม่เหมาะสมมากกว่า (β = 0.489) แต่ไม่พบความสัมพันธ์ระหว่างอาหารไม่เหมาะสมกับ BMI (β = 0.008, 95% CI −0.089 ถึง 0.105) และไม่พบอิทธิพลทางอ้อม (β = 0.004, 95% CI −0.044 ถึง 0.054) ซึ่งไม่ได้แปลว่าไม่มีผล แต่ข้อมูลนี้ไม่สนับสนุน · โมเดลการวัดอ่อน (CR และ AVE ต่ำ, Fornell–Larcker ไม่ผ่านสำหรับการใช้สารเสพติด) ผลเชิงโครงสร้างจึงควรตีความอย่างระมัดระวัง · ข้อมูลเป็นภาคตัดขวางเชิงสังเกต ใช้คำว่า "สัมพันธ์กับ" · ประโยคสำหรับวารสาร: "In an SEM of 1,300 patients (χ²(12) = 45.55, CFI = 0.943, RMSEA = 0.046, SRMR = 0.033), substance use was associated with an unhealthy diet (β = 0.49, p < 0.001), but neither the diet factor (β = 0.01, p = 0.869) nor substance use (β = −0.08, p = 0.219) was associated with BMI."
Measurement model: standardized loadings preferably 0.50 or more, CR ≥ 0.70 and AVE ≥ 0.50 (convergent validity); √AVE above the factor correlations (Fornell & Larcker, 1981) and HTMT2 < 0.85 (discriminant validity; Henseler et al., 2015; Roemer et al., 2021). Fit: CFI/TLI close to 0.95 or above, RMSEA close to 0.06 or below, SRMR close to 0.08 or below (Hu & Bentler, 1999), and RMSEA ≤ 0.08 as reasonable (Browne & Cudeck, 1992); GFI/AGFI depend on sample size and should not be used alone. Mediation: judge it from the CI of the indirect effect (significant if it excludes 0). Example: RMSEA = 0.046 and SRMR = 0.033 meet the criteria, but CFI = 0.943 and TLI = 0.900 are below 0.95, so the fit is fair. Patients with more substance use tend to report a less healthy diet (β = 0.489), but the diet factor is not associated with BMI (β = 0.008, 95% CI −0.089 to 0.105) and there is no indirect effect (β = 0.004, 95% CI −0.044 to 0.054); this does not prove the absence of an effect, but these data do not support one. The measurement model is weak (low CR and AVE, Fornell–Larcker failing for substance use), so the structural results should be read with caution. The data are cross-sectional and observational: use "associated with". Journal-style sentence: "In an SEM of 1,300 patients (χ²(12) = 45.55, CFI = 0.943, RMSEA = 0.046, SRMR = 0.033), substance use was associated with an unhealthy diet (β = 0.49, p < 0.001), but neither the diet factor (β = 0.01, p = 0.869) nor substance use (β = −0.08, p = 0.219) was associated with BMI."
📖 References
- Bollen, K. A. (1989). Structural Equations with Latent Variables. New York: Wiley. ISBN 978-0-471-01171-2.
- Kline, R. B. (2016). Principles and Practice of Structural Equation Modeling (4th ed.). New York: Guilford Press. ISBN 978-1-4625-2334-4.
- Hu, L., & Bentler, P. M. (1999). Cutoff criteria for fit indexes in covariance structure analysis: Conventional criteria versus new alternatives. Structural Equation Modeling, 6(1), 1–55. doi:10.1080/10705519909540118
- Browne, M. W., & Cudeck, R. (1992). Alternative ways of assessing model fit. Sociological Methods & Research, 21(2), 230–258. doi:10.1177/0049124192021002005
- Fornell, C., & Larcker, D. F. (1981). Evaluating structural equation models with unobservable variables and measurement error. Journal of Marketing Research, 18(1), 39–50. doi:10.1177/002224378101800104
- Henseler, J., Ringle, C. M., & Sarstedt, M. (2015). A new criterion for assessing discriminant validity in variance-based structural equation modeling. Journal of the Academy of Marketing Science, 43(1), 115–135. doi:10.1007/s11747-014-0403-8
- Roemer, E., Schuberth, F., & Henseler, J. (2021). HTMT2–an improved criterion for assessing discriminant validity in structural equation modeling. Industrial Management & Data Systems, 121(12), 2637–2650. doi:10.1108/IMDS-02-2021-0082
- Preacher, K. J., & Selig, J. P. (2012). Advantages of Monte Carlo confidence intervals for indirect effects. Communication Methods and Measures, 6(2), 77–98. doi:10.1080/19312458.2012.679848
- Rosseel, Y. (2012). lavaan: an R package for structural equation modeling. Journal of Statistical Software, 48(2), 1–36. doi:10.18637/jss.v048.i02
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
10.2Generalized SEM — categorical outcome (logit / ordered / multinomial; OR / RRR; g-formula mediation)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
GSEM ใน DAPH ใช้เมื่อตัวแปรตามเป็น สองกลุ่ม อันดับ หรือหลายกลุ่ม (เช่น มี/ไม่มีโรคเรื้อรัง) และมีตัวแปรแฝงที่วัดด้วยหลายข้อคำถาม · DAPH ประมาณแบบ สองขั้น: ขั้นที่ 1 ประมาณโมเดลการวัด (CFA) แล้วคำนวณคะแนนองค์ประกอบ · ขั้นที่ 2 ใช้คะแนนนั้นเหมือนตัวแปรที่วัดได้ในโมเดล logit / ordered logit / multinomial logit และแยกอิทธิพลทางตรงและทางอ้อมด้วย g-formula บนสเกล OR หรือ RRR (เหมือน 8.2–8.3) เพราะผลคูณสัมประสิทธิ์ใช้ไม่ได้บนสเกล odds · กติกาของ DAPH: GSEM รับเฉพาะตัวแปรตามเชิงกลุ่ม ตัวแปรตามต่อเนื่องใช้ SEM (10.1) · ตัวแปรส่งผ่านเป็นได้ทุกชนิด (ตัวแปรกลุ่มถูกแยกเป็นตัวแปรหุ่นและใช้สมการ logit) · ไม่ควรใช้เมื่อโมเดลการวัดอ่อน เพราะคะแนนองค์ประกอบยิ่งมีความคลาดเคลื่อนมาก สัมประสิทธิ์ขั้นที่ 2 ยิ่งถูกลดทอน
GSEM in DAPH is for a binary, ordinal or nominal outcome (for example chronic disease yes/no) together with latent variables measured by several items. DAPH estimates it in two stages: stage 1 fits the measurement model (CFA) and computes factor scores; stage 2 uses those scores as if they were measured variables in a logit / ordered-logit / multinomial-logit model and splits direct and indirect effects with the g-formula on the OR or RRR scale (as in 8.2–8.3), because products of coefficients are not valid on the odds scale. DAPH rule: GSEM takes a categorical outcome only; a continuous outcome uses SEM (10.1). Mediators may be of any type (a categorical mediator is split into dummies with logit equations). Do not use it when the measurement model is weak: the more error the factor scores carry, the more the stage-2 coefficients are attenuated.
2หลักการและสูตรLogic and Formula
- Λ̂, Φ̂, Σ̂
- ค่าน้ำหนัก / ความแปรปรวนร่วมขององค์ประกอบ / เมทริกซ์ที่โมเดลกำหนด จาก CFA ขั้นที่ 1loadings / factor covariance matrix / model-implied matrix from the stage-1 CFA
- η̂, M, Z
- คะแนนองค์ประกอบมาตรฐาน / ตัวแปรส่งผ่าน / ตัวแปรสังเกตได้อื่นstandardized factor score / mediator / other observed variables
- p₁₀, p₀₀, p₁₁
- ความน่าจะเป็นเฉลี่ยทั้งประชากรของ Y = 1 ในสามสถานการณ์ counterfactual (คะแนนตัวแปรต้น 1 SD หรือ 0, ตัวแปรส่งผ่านตามระดับนั้น)population-averaged probabilities of Y = 1 in the three counterfactual scenarios (predictor score 1 SD or 0, mediator as under that level)
- ℓ, k, N
- log-likelihood ของสมการตัวแปรตาม / จำนวนสัมประสิทธิ์ของสมการนั้น / ขนาดตัวอย่างlog-likelihood of the outcome equation / number of its coefficients / sample size
DAPH คำนวณอย่างไร: ขั้นที่ 1 เป็น CFA แบบ ML (ค่าเท่ากับ 9.2 รวมทั้ง CR, AVE, α, HTMT2 และ modification index ของโมเดลการวัด) และคะแนนองค์ประกอบแบบ regression ปรับให้เฉลี่ย 0 และ SD 1 (หารด้วย N) · ขั้นที่ 2 ใช้ logit, ordered logit หรือ multinomial logit แบบ maximum likelihood · ตัวแปรสองกลุ่มที่ไม่ได้ลงรหัส 0/1 ถูกเปลี่ยนเป็น 0/1 อัตโนมัติ · สมการตัวแปรส่งผ่านแบบต่อเนื่องใช้ OLS และรายงาน β · อิทธิพลทางตรง ทางอ้อม และรวมของตัวแปรต้นที่มีเส้นทางผ่านตัวแปรส่งผ่านมาจาก g-formula ทั้งหมด (Valeri & VanderWeele, 2013; VanderWeele, 2015) ด้วยการสุ่มพารามิเตอร์ 10,000 ชุด (ordinal/nominal 5,000 ชุด) seed 12345 · ดัชนี χ², CFI, TLI, RMSEA และ SRMR ของโมเดลทั้งหมดไม่ได้นิยามสำหรับโมเดลสองขั้นนี้ DAPH จึงไม่รายงาน (ความกลมกลืนของโมเดลการวัดดูได้จาก CFA ใน 9.2) · ข้อจำกัด: คะแนนองค์ประกอบถูกใช้เหมือนค่าที่วัดได้โดยไม่แก้ความลำเอียงตามวิธีของ Croon (2002) สัมประสิทธิ์ขั้นที่ 2 จึงถูกลดทอนจากความคลาดเคลื่อนของการวัด และช่วงเชื่อมั่นไม่รวมความไม่แน่นอนของคะแนน (Devlieger และคณะ, 2016) · สหสัมพันธ์ของคะแนนองค์ประกอบทั้งสองคือ 0.716 สูงกว่าสหสัมพันธ์ขององค์ประกอบแฝงใน CFA ขั้นที่ 1 (0.491) ตัวอย่างนี้จึงไม่ใช่ตัวประมาณแบบ full-information · ตัวแปรส่งผ่านแบบกลุ่มที่มีตั้งแต่ 3 ระดับ: g-formula ของ GSEM ถือตัวแปรหุ่นแต่ละตัวเป็นตัวแปรส่งผ่านสองกลุ่มที่เป็นอิสระต่อกัน (ต่างจาก Path Analysis ที่จำลองทุกระดับร่วมกันด้วย multinomial logit) จึงให้น้ำหนักกับสถานะที่เป็นไปไม่ได้ (อยู่สองระดับพร้อมกัน) ควรหลีกเลี่ยงหรือใช้ Path Analysis (8.2) แทน
How DAPH computes it: stage 1 is an ML CFA (the same values as 9.2, including CR, AVE, α, HTMT2 and the measurement model's modification indices), with regression-method factor scores rescaled to mean 0 and SD 1 (divisor N). Stage 2 is a logit, ordered logit or multinomial logit fitted by maximum likelihood; a two-level variable not coded 0/1 is recoded to 0/1 automatically; a continuous mediator equation is OLS and reported as β. For a predictor with a mediated path, the direct, indirect and total effects all come from the g-formula (Valeri & VanderWeele, 2013; VanderWeele, 2015), with 10,000 parameter draws (5,000 for ordinal/nominal outcomes) at seed 12345. χ², CFI, TLI, RMSEA and SRMR of the whole model are not defined for this two-stage model, so DAPH does not report them (the measurement model's fit is the CFA of 9.2). Limitations: the factor scores are used as if measured, without the bias correction of Croon (2002), so the stage-2 coefficients are attenuated by measurement error and their intervals omit the uncertainty of the scores (Devlieger et al., 2016). The correlation of the two factor scores is 0.716, higher than the latent correlation in the stage-1 CFA (0.491); this is not a full-information estimator. Categorical mediators with three or more levels: GSEM's g-formula treats each dummy as an independent binary mediator (unlike Path Analysis, which models all levels jointly with a multinomial logit), so it gives weight to impossible states (two levels at once); avoid this, or use Path Analysis (8.2) instead.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(lavaan) # stage 1: cfa(), lavPredict()
library(MASS) # mvrnorm(): quasi-Bayesian draws
# Stage 1: measurement model (ML CFA, as in 9.2) and regression-method factor scores,
# standardized to mean 0 and SD 1 (population SD, divisor N)
cf <- cfa('Subst =~ alcoholfreq + cigarettefreq + betelfreq # Substance use
Diet =~ sugaryfoodfreq + fattyfoodfreq + saltyfoodfreq', data = d)
round(standardizedSolution(cf)[1:6, "est.std"], 4) # standardized loadings
round(lavInspect(cf, "cor.lv")[1, 2], 4) # latent correlation
fs <- lavPredict(cf, method = "regression")
z <- function(v) (v - mean(v)) / sqrt(mean((v - mean(v))^2))
d$Subst <- z(fs[, "Subst"]); d$Diet <- z(fs[, "Diet"])
# Stage 2: outcome model (logit) and mediator model (linear) on the factor scores
# chronic: Chronic Disease, 0 = no (reference), 1 = has chronic disease
y_eq <- glm(chronic ~ Subst + Diet, family = binomial, data = d)
m_eq <- lm(Diet ~ Subst, data = d)
s <- coef(summary(y_eq))
round(cbind(OR = exp(s[-1, 1]), lower = exp(s[-1, 1] - qnorm(0.975) * s[-1, 2]),
upper = exp(s[-1, 1] + qnorm(0.975) * s[-1, 2]), p = s[-1, 4]), 4) # conditional ORs per 1 SD
round(c(coef(summary(m_eq))["Subst", 1:2], R2 = summary(m_eq)$r.squared), 4) # mediator equation
ll <- as.numeric(logLik(y_eq)); ll0 <- as.numeric(logLik(update(y_eq, . ~ 1))); n <- nrow(d)
round(c(logLik = ll, AIC = AIC(y_eq), BIC = BIC(y_eq), McFadden = 1 - ll / ll0,
Nagelkerke = (1 - exp(2 * (ll0 - ll) / n)) / (1 - exp(2 * ll0 / n))), 4)
# g-formula: Substance use 1 SD above the mean (x = 1) versus the mean (x* = 0), 24-node Gauss-Hermite
gh <- function(k) {
J <- matrix(0, k, k); i <- seq_len(k - 1); J[cbind(i, i + 1)] <- J[cbind(i + 1, i)] <- sqrt(i)
e <- eigen(J, symmetric = TRUE); list(z = e$values, w = e$vectors[1, ]^2)
}
q <- gh(24); sig <- summary(m_eq)$sigma
p_cf <- function(by, bm, x, xs) {
lin <- by[[1]] + by[[2]] * x + by[[3]] * (bm[[1]] + bm[[2]] * xs)
sum(q$w * plogis(lin + by[[3]] * sig * q$z))
}
eff <- function(by, bm) {
odds <- function(p) p / (1 - p)
p10 <- p_cf(by, bm, 1, 0); p00 <- p_cf(by, bm, 0, 0); p11 <- p_cf(by, bm, 1, 1)
c(NDE = odds(p10) / odds(p00), NIE = odds(p11) / odds(p10), Total = odds(p11) / odds(p00))
}
round(eff(coef(y_eq), coef(m_eq)), 4)
set.seed(12345)
dy <- mvrnorm(10000, coef(y_eq), vcov(y_eq)); dm <- mvrnorm(10000, coef(m_eq), vcov(m_eq))
sims <- t(sapply(1:10000, function(k) eff(dy[k, ], dm[k, ])))
p_mc <- function(x) min(1, 2 * min(mean(x <= 1), mean(x >= 1)))
round(rbind(lower = apply(sims, 2, quantile, 0.025), upper = apply(sims, 2, quantile, 0.975),
p = apply(sims, 2, p_mc)), 4)
# Monte Carlo check: SD of the interval limits and p across 10 other seeds
round(apply(sapply(1:10, function(seed) {
set.seed(seed)
dy <- mvrnorm(10000, coef(y_eq), vcov(y_eq)); dm <- mvrnorm(10000, coef(m_eq), vcov(m_eq))
x <- t(sapply(1:10000, function(k) eff(dy[k, ], dm[k, ])))
c(apply(x, 2, quantile, 0.025), apply(x, 2, quantile, 0.975), apply(x, 2, p_mc))
}), 1, sd), 4)
# stage 1: standardized loadings, latent correlation
[1] 0.3666 0.4206 0.3244 0.4956 0.7159 0.5489
[1] 0.4913
# stage 2: conditional ORs per 1 SD (Wald 95% CI), mediator equation, model quality
OR lower upper p
Subst 0.9686 0.8286 1.1323 0.6888
Diet 1.1297 0.9660 1.3212 0.1267
Estimate Std. Error R2
0.7164 0.0194 0.5132
logLik AIC BIC McFadden Nagelkerke
-899.4098 1804.8197 1820.3300 0.0019 0.0034
# g-formula: NDE, NIE, Total OR for substance use (1 SD vs mean), then 95% CI and p
NDE NIE Total
0.9687 1.0911 1.0569
NDE NIE Total
lower 0.8288 0.9745 0.9473
upper 1.1339 1.2183 1.1812
p 0.7018 0.1258 0.3228
# SD across 10 other seeds: lower limits, upper limits, p (NDE, NIE, Total)
NDE NIE Total NDE NIE Total NDE NIE Total
0.0024 0.0015 0.0016 0.0022 0.0015 0.0016 0.0067 0.0036 0.0068
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| ขั้นที่ 1: ค่าน้ำหนักมาตรฐาน 6 ข้อ (เกณฑ์ ±0.001)*Stage 1: six standardized loadings (tolerance ±0.001)* | 0.3666 / 0.4206 / 0.3244 / 0.4956 / 0.7159 / 0.5489 | 0.3668 / 0.4207 / 0.3242 / 0.4955 / 0.7160 / 0.5487 | ≤ 0.0002 | ✓ PASS |
| อาหารไม่เหมาะสม → โรคเรื้อรัง: OR (Wald 95% CI) / p (เกณฑ์ ±0.001)*Diet → chronic disease: OR (Wald 95% CI) / p (tolerance ±0.001)* | 1.1297 (0.9660 to 1.3212) / 0.1267 | 1.130 (0.966 to 1.321) / 0.1269 | ≤ 0.0003 | ✓ PASS |
| สมการตัวแปรส่งผ่าน: β (SE) ของสารเสพติด → อาหาร / R²Mediator equation: β (SE) of substance → diet / R² | 0.7164 (0.0194) / 0.5132 | 0.716 (0.678 to 0.754) / 0.513 | < 5e−4 | ✓ PASS |
| log-likelihood / AIC / BIC | −899.4098 / 1804.8197 / 1820.3300 | −899.410 / 1804.821 / 1820.331 | ≤ 0.0013 | ✓ PASS |
| McFadden R² / Nagelkerke R² | 0.0019 / 0.0034 | 0.0019 / 0.0034 | < 5e−5 | ✓ PASS |
| NDE / NIE / Total OR | 0.9687 / 1.0911 / 1.0569 | 0.969 / 1.091 / 1.057 | < 5e−4 | ✓ PASS |
| NDE: 95% CI / p (เกณฑ์ ±0.010 / ±0.029)**NDE: 95% CI / p (tolerance ±0.010 / ±0.029)** | 0.8288 to 1.1339 / 0.7018 | 0.832 to 1.134 / 0.709 | 0.0032 / 0.0001 / 0.0072 | ✓ PASS |
| NIE: 95% CI / pNIE: 95% CI / p | 0.9745 to 1.2183 / 0.1258 | 0.975 to 1.217 / 0.132 | 0.0005 / 0.0013 / 0.0062 | ✓ PASS |
| Total: 95% CI / pTotal: 95% CI / p | 0.9473 to 1.1812 / 0.3228 | 0.948 to 1.177 / 0.301 | 0.0007 / 0.0042 / 0.0218 | ✓ PASS |
* ขั้นที่ 1 ของ DAPH หยุดการหาค่าที่ดีที่สุดเร็วกว่า lavaan เล็กน้อย (ดู 9.2) ค่าที่ตามมาจึงต่างกันในทศนิยมตำแหน่งที่ 4 · ** Monte Carlo: เกณฑ์ = 3 × √2 × SD ระหว่าง seed (สูงสุด 0.0024 สำหรับขอบ CI และ 0.0068 สำหรับ p) · ทวนสอบ 2 ต.ค. 2026: R 4.3.3, lavaan 0.6-21 บนไฟล์ example_en.csv
* DAPH's stage 1 stops its optimiser slightly earlier than lavaan (see 9.2), so the quantities that follow differ in the 4th decimal. ** Monte Carlo: tolerance = 3 × √2 × the between-seed SD (at most 0.0024 for CI limits and 0.0068 for p). Verified 2 Oct 2026: R 4.3.3, lavaan 0.6-21 on example_en.csv.
4การแปลผลและตัวอย่างInterpretation and Example
ค่าอิทธิพล: OR หรือ RRR > 1 หมายถึง odds (หรืออัตราส่วนความเสี่ยงเทียบกลุ่มอ้างอิง) สูงขึ้นต่อคะแนนองค์ประกอบที่เพิ่ม 1 SD, < 1 หมายถึงต่ำลง และมีนัยสำคัญเมื่อ 95% CI ไม่คร่อม 1 · คุณภาพของโมเดล: pseudo-R² ของ logit มักต่ำและเทียบกับ R² ของการถดถอยเชิงเส้นไม่ได้ ใช้ AIC/BIC เทียบโมเดลที่มีตัวแปรตามชุดเดียวกัน (ต่ำกว่า = ดีกว่า) · ไม่ควรรายงาน χ², CFI, TLI, RMSEA หรือ SRMR ของโมเดลสองขั้นนี้ · การส่งผ่าน: โมเดลเชิงโครงสร้างต้องไม่มีวงจร (เส้นทางสองทิศถูกเตือนและตัดออก) · ตัวอย่าง: ไม่มีหลักฐานว่าคะแนนการใช้สารเสพติดหรืออาหารไม่เหมาะสมสัมพันธ์กับโรคเรื้อรัง (อาหาร OR = 1.130, 95% CI 0.966 ถึง 1.321; Total ของสารเสพติด OR = 1.057, 95% CI 0.948 ถึง 1.177) และ McFadden R² = 0.002 · ไม่มีนัยสำคัญไม่ได้แปลว่าไม่มีความสัมพันธ์ ยิ่งโมเดลการวัดอ่อน (CR 0.324 และ 0.615) ผลยิ่งถูกลดทอนเข้าหา 1 · ข้อมูลเป็นภาคตัดขวางเชิงสังเกต และโรคเรื้อรังอาจเกิดก่อนพฤติกรรมที่รายงาน จึงอ่านเป็นความสัมพันธ์เท่านั้น · ประโยคสำหรับวารสาร: "In a two-stage generalized SEM (factor scores per SD), substance use was not associated with chronic disease directly (NDE OR 0.969, 95% CI 0.832 to 1.134) or through an unhealthy diet (NIE OR 1.091, 95% CI 0.975 to 1.217)."
Effects: an OR or RRR > 1 means higher odds (or a higher risk ratio versus the reference category) per 1-SD higher factor score, < 1 lower; it is significant when the 95% CI excludes 1. Model quality: logit pseudo-R² values are usually low and are not comparable with a linear R²; use AIC/BIC to compare models with the same outcome (lower is better). Do not report χ², CFI, TLI, RMSEA or SRMR for this two-stage model. Mediation: the structural model must be acyclic (bidirectional paths are warned about and removed). Example: there is no evidence that the substance-use or diet scores are associated with chronic disease (diet OR = 1.130, 95% CI 0.966 to 1.321; substance-use total OR = 1.057, 95% CI 0.948 to 1.177), and McFadden R² = 0.002. Not significant does not mean no association, and the weaker the measurement model (CR 0.324 and 0.615), the more the effects are attenuated towards 1. The data are cross-sectional and observational, and chronic disease may precede the reported behaviour, so read the results as associations only. Journal-style sentence: "In a two-stage generalized SEM (factor scores per SD), substance use was not associated with chronic disease directly (NDE OR 0.969, 95% CI 0.832 to 1.134) or through an unhealthy diet (NIE OR 1.091, 95% CI 0.975 to 1.217)."
📖 References
- Valeri, L., & VanderWeele, T. J. (2013). Mediation analysis allowing for exposure–mediator interactions and causal interpretation: Theoretical assumptions and implementation with SAS and SPSS macros. Psychological Methods, 18(2), 137–150. doi:10.1037/a0031034
- VanderWeele, T. J. (2015). Explanation in Causal Inference: Methods for Mediation and Interaction. New York: Oxford University Press. ISBN 978-0-19-932587-0.
- Croon, M. (2002). Using predicted latent scores in general latent structure models. In G. A. Marcoulides & I. Moustaki (Eds.), Latent Variable and Latent Structure Models (pp. 195–223). Mahwah, NJ: Erlbaum. ISBN 978-0-8058-4046-7.
- Devlieger, I., Mayer, A., & Rosseel, Y. (2016). Hypothesis testing using factor score regression. Educational and Psychological Measurement, 76(5), 741–770. doi:10.1177/0013164415607618
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 11 — อนุกรมเวลา (Time-Series)Chapter 11 — Time-Series Analysis ✓ Verified
สถิติสำหรับข้อมูลที่เรียงตามเวลา เช่น จำนวนผู้ป่วยรายสัปดาห์/รายเดือน อัตราตายรายปี ค่าเฝ้าระวังสิ่งแวดล้อม · ครอบคลุมสิ่งที่นักระบาดวิทยาใช้ในงานวิจัย: ดูแนวโน้ม (11.1) แยกฤดูกาล (11.2) ตรวจการพึ่งพาในตัวเองและความคงที่ (11.3) พยากรณ์ (11.4) หา lag ของปัจจัย (11.5) ประเมินผลของเหตุการณ์ที่รู้วันที่ (11.6) และการถดถอยอนุกรมเวลาที่มีผลล่าช้า (11.7) ส่วน 11.8 อธิบายการเตรียมข้อมูลและหน้าจอ · ข้อมูลรายบุคคลใช้ได้ เพราะ DAPH รวมแถวตามคอลัมน์วันที่เป็นค่ารายช่วงให้ (เช่น จำนวนผู้เสียชีวิตต่อเดือนของผู้ป่วยในข้อมูลตัวอย่าง DAPH) ข้อมูลที่ไม่มีคอลัมน์วันที่ก็ใช้ได้ด้วยการ "กำหนดช่วงเวลาเอง" จากลำดับแถว · ทุกตัวอย่างในบทนี้มาจากข้อมูลตัวอย่าง DAPH (EN) และตรวจเทียบกับ R 4.3.3 Methods for data ordered in time, such as weekly or monthly case counts, annual mortality and environmental surveillance. They cover what epidemiologists use in research: trend (11.1), seasonality (11.2), autocorrelation and stationarity (11.3), forecasting (11.4), lagged drivers (11.5), the effect of a dated event (11.6) and time-series regression with delayed effects (11.7); 11.8 explains data preparation and the screens. Patient-level data can be used, because DAPH combines the rows by a date column into one value per period (for example deaths per month among the patients of the DAPH example data); data without a date column can be analysed by defining the periods from row order. Every example in this chapter uses the DAPH example data (EN) and is checked against R 4.3.3.
11.1Time Plot & Trend (Mann-Kendall · Sen's slope)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
ก่อนสร้างแบบจำลองใด ๆ ต้อง ดูอนุกรมก่อน: แนวโน้ม ฤดูกาล จุดสูงสุด/ต่ำสุด และค่าผิดปกติ สถิตินี้ตอบคำถามว่า "โดยรวมอนุกรมเพิ่มขึ้นหรือลดลงทิศทางเดียวตลอดช่วงหรือไม่ และเปลี่ยนเท่าไรต่อหนึ่งช่วงเวลา" ด้วยการทดสอบแนวโน้มแบบไม่ใช้พารามิเตอร์ Mann-Kendall (MK) คู่กับความชันของ Sen (Sen's slope) ซึ่งไม่สมมติการแจกแจงและทนต่อค่าผิดปกติ จึงเป็นคู่มาตรฐานในงานเฝ้าระวังโรคและอนามัยสิ่งแวดล้อม · ใช้เมื่อมีหนึ่งค่าต่อหนึ่งช่วงเวลาอย่างน้อย 8–10 ช่วง · ไม่ควรใช้เมื่อรูปแบบเป็นเส้นโค้ง (ขึ้นแล้วลง) เพราะการทดสอบนี้ดูเฉพาะแนวโน้มทิศทางเดียว เมื่อรู้วันที่ที่มีเหตุการณ์เปลี่ยนแปลงให้ใช้ Interrupted Time Series (11.6) และเมื่อต้องการผลของปัจจัยให้ใช้ 11.7
Look before you model: trend, seasonality, peaks, troughs and outliers. This statistic answers "did the series rise or fall in one direction over the whole period, and by how much per period?" with the non-parametric Mann-Kendall (MK) trend test and Sen's slope, which assume no distribution and resist outliers — the standard pair in disease surveillance and environmental health. Use it with one value per period and at least 8–10 periods. Do not use it for a curved pattern (rise then fall), because it looks only for a monotonic trend; when the date of a change is known use Interrupted Time Series (11.6), and to estimate the effect of a factor use 11.7.
2หลักการและสูตรLogic and Formula
- n, tg
- จำนวนช่วงที่มีข้อมูล และขนาดของกลุ่มค่าซ้ำกลุ่มที่ gnumber of periods with data, and the size of tie group g
- m, nk, Sk
- จำนวนฤดูต่อรอบ (12 สำหรับรายเดือน) จำนวนค่าในฤดู k และสถิติ S ที่คำนวณภายในฤดู kseasons per cycle (12 for monthly data), observations in season k, and S computed within season k
- ρi
- สหสัมพันธ์ในตัวเองที่ lag i ของอันดับของอนุกรมหลังหักแนวโน้มด้วย Sen's slope (xt − β̂t)lag-i autocorrelation of the ranks of the series after removing the Sen trend (xt − β̂t)
- N, β̂(r)
- จำนวนความชันทุกคู่ และความชันลำดับที่ r เมื่อเรียงจากน้อยไปมาก (M1 และ M2 + 1 ปัดเป็นจำนวนเต็ม) · ในแบบฤดูกาลใช้เฉพาะคู่ในฤดูเดียวกัน หารด้วย m เพื่อให้เป็นต่อช่วง และใช้ Var(S′)number of pairwise slopes, and the r-th smallest slope (M1 and M2 + 1 rounded to integers); in seasonal mode only within-season pairs are used, divided by m to give a slope per period, with Var(S′)
DAPH เลือกรูปแบบของการทดสอบให้อัตโนมัติ: ถ้าอนุกรมมีฤดูกาล (รายวัน/สัปดาห์/เดือน/ไตรมาส) และยาวอย่างน้อย 2 รอบ (2m ช่วง) ใช้ Seasonal Kendall ซึ่งไม่ให้ฤดูกาลถูกอ่านเป็นแนวโน้ม และไม่มีการแก้สหสัมพันธ์ในตัวเอง · ถ้าไม่ครบ 2 รอบหรือเป็นข้อมูลรายปี ใช้ Mann-Kendall และเมื่อมีอย่างน้อย 10 ช่วง จะตรวจสหสัมพันธ์ของอันดับหลังหักแนวโน้ม ถ้ามี lag ใดเกินขอบเขต ±1.96/√n จะขยาย Var(S) ตาม Hamed & Rao (1998) (ตารางเขียนว่า "Mann-Kendall แก้ความแปรปรวนจากสหสัมพันธ์ในตัวเอง") · ค่า p เป็นแบบสองทาง จากการแจกแจงปกติ · ตัดสินว่า "เพิ่มขึ้น" เมื่อ p < 0.05 และ S > 0 "ลดลง" เมื่อ p < 0.05 และ S < 0 ไม่เช่นนั้น "ไม่พบแนวโน้มทิศทางเดียวที่มีนัยสำคัญ" · Sen's slope มีหน่วยต่อหนึ่งช่วงเวลาและแสดงเป็นร้อยละของค่ามัธยฐานด้วย · ตารางรายงานสหสัมพันธ์ในตัวเองที่ lag 1 ของค่าดิบด้วย
DAPH picks the test form automatically: when the series has a season (daily, weekly, monthly, quarterly) and spans at least two cycles (2m periods) it uses the Seasonal Kendall test, so seasonality cannot masquerade as a trend; this form has no autocorrelation correction. With fewer than two cycles, or yearly data, it uses Mann-Kendall and, with at least 10 periods, checks the rank autocorrelation of the detrended series; if any lag exceeds ±1.96/√n, Var(S) is inflated following Hamed & Rao (1998) (the table then reads "Mann-Kendall, variance corrected for autocorrelation"). p is two-sided from the normal distribution. The verdict is "increasing" when p < 0.05 and S > 0, "decreasing" when p < 0.05 and S < 0, otherwise "no significant monotonic trend". Sen's slope is per period and is also shown as a percentage of the series median; the table also gives the lag-1 autocorrelation of the raw values.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(trend); library(modifiedmk)
# Series 1: deaths per month = rows with status = 1 (Died/Event), counted by the month of end_date
m_end <- format(seq(as.Date("2022-02-01"), as.Date("2024-12-01"), by = "month"), "%Y-%m")
deaths <- as.numeric(table(factor(substr(d$end_date[d$status == 1], 1, 7), levels = m_end)))
y <- ts(deaths, frequency = 12, start = c(2022, 2))
round(c(n = length(y), mean = mean(y), sd = sd(y), lag1 = acf(y, plot = FALSE)$acf[2]), 4)
round(tapply(y, cycle(y), mean), 2) # mean deaths by calendar month (1 = Jan)
sum(d$status == 1 & substr(d$end_date, 1, 10) == "2024-12-31") # deaths dated on the closing day
sk <- smk.test(y) # Seasonal Kendall (Hirsch et al. 1982)
S <- sk$estimates[["S"]]; varS <- sk$estimates[["varS"]]
round(c(S = S, varS = varS, z = sk$statistic[[1]], p = sk$p.value,
tau = S / sum(choose(table(cycle(y)), 2))), 4) # tau = S / within-season pairs
pair_slopes <- function(v) unlist(lapply(1:(length(v) - 1), function(i)
(v[(i + 1):length(v)] - v[i]) / ((i + 1):length(v) - i)))
sl <- sort(unlist(lapply(1:12, function(k) pair_slopes(as.numeric(y[cycle(y) == k]))))) / 12
N <- length(sl); C <- qnorm(0.975) * sqrt(varS) # Gilbert (1987): ranks M1 and M2 + 1
round(c(N = N, sen = median(sl), lower = sl[round((N - C) / 2)], upper = sl[round((N + C) / 2) + 1],
pct_of_median = 100 * median(sl) / median(y)), 4)
# Series 2: new patients per month = rows counted by the month of enroll_date
m_enr <- format(seq(as.Date("2022-01-01"), as.Date("2023-06-01"), by = "month"), "%Y-%m")
enrol <- as.numeric(table(factor(substr(d$enroll_date, 1, 7), levels = m_enr)))
enrol; round(c(mean = mean(enrol), sd = sd(enrol)), 2)
mk <- mk.test(enrol); ss <- sens.slope(enrol)
round(c(S = mk$estimates[["S"]], varS = mk$estimates[["varS"]], z = mk$statistic[[1]], p = mk$p.value,
tau = mk$estimates[["S"]] / choose(length(enrol), 2), sen = ss$estimates[[1]],
lower = ss$conf.int[1], upper = ss$conf.int[2], lag1 = acf(enrol, plot = FALSE)$acf[2]), 4)
round(mmkh(enrol)[c("Corrected Zc", "new P-value", "N/N*")], 4) # Hamed-Rao: N/N* = 1, no correction
n mean sd lag1
35.0000 6.5429 4.1469 0.3609
1 2 3 4 5 6 7 8 9 10 11 12
6.50 6.33 5.00 6.33 7.00 7.00 9.00 6.00 4.67 5.33 5.33 10.00
[1] 10
S varS z p tau
-10.0000 39.3333 -1.4350 0.1513 -0.2941
N sen lower upper pct_of_median
34.0000 -0.0833 -0.2917 0.0833 -1.3889
[1] 81 67 73 68 80 58 70 70 75 73 72 73 72 70 84 79 62 73
mean sd
72.22 6.41
S varS z p tau sen lower upper
11.0000 683.6667 0.3825 0.7021 0.0719 0.1429 -0.7273 0.6000
lag1
-0.2685
Corrected Zc new P-value N/N*
0.3825 0.7021 1.0000
| Quantity | R (trend, modifiedmk) | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| Deaths: periods n / Seasonal Kendall S | 35 / −10 | 35 / −10 | 0 | ✓ PASS |
| Deaths: z / p | −1.4350 / 0.1513 | −1.435 / 0.151277 | < 0.0001 | ✓ PASS |
| Deaths: Kendall's tau (S / within-season pairs) | −0.2941 | −0.2941 | 0 | ✓ PASS |
| Deaths: seasonal Sen's slope per month (% of median) | −0.0833 (−1.3889) | −0.083333 (−1.39) | < 0.0001 | ✓ PASS |
| Deaths: Sen's slope 95% CI lower bound | −0.2917 | −0.291667 | < 0.0001 | ✓ PASS |
| Deaths: Sen's slope 95% CI upper bound | 0.0833 | 0.083333 | < 0.0001 | ✓ PASS |
| Deaths: lag-1 autocorrelation | 0.3609 | 0.3609 | 0 | ✓ PASS |
| Deaths: month with the highest / lowest seasonal mean | Dec (10.00) / Sep (4.67) | Dec / Sep | 0 | ✓ PASS |
| New patients: Mann-Kendall S / z / p | 11 / 0.3825 / 0.7021 | 11 / 0.3825 / 0.702126 | < 0.0001 | ✓ PASS |
| New patients: tau / Hamed-Rao factor N/N* | 0.0719 / 1 (no correction) | 0.0719 / test "Mann-Kendall" (no lag corrected) | 0 | ✓ PASS |
| New patients: Sen's slope per month | 0.1429 | 0.142857 | < 0.0001 | ✓ PASS |
| New patients: Sen's slope 95% CI (lower / upper) | −0.7273 / 0.6000 | −0.727273 / 0.6 | < 0.0001 | ✓ PASS |
ทุกค่าตรงกับ R: S, z, p, tau, Sen's slope และ 95% CI ตามลำดับที่ของ Gilbert (1987) · ชื่อเดือนในหมายเหตุ "ค่าเฉลี่ยตามฤดูกาลสูงสุดใน…" นับตามปฏิทินจากป้ายช่วงเวลา (สูงสุดเดือนธันวาคม ต่ำสุดเดือนกันยายน) แม้อนุกรมจะเริ่มเดือนกุมภาพันธ์ · ประโยคสรุปของ DAPH ระบุชื่อการทดสอบที่ใช้จริง (Seasonal Kendall)
Every value agrees with R: S, z, p, tau, Sen's slope and its 95% CI by Gilbert's (1987) ranks. The month names in the note "Seasonal means peak in …" follow the calendar from the period labels (peak December, trough September) although this series starts in February, and DAPH's summary sentence names the test actually used (Seasonal Kendall).
4การแปลผลและตัวอย่างInterpretation and Example
เกณฑ์อ่านผล: p < 0.05 กับ S บวก = แนวโน้มเพิ่ม · S ลบ = แนวโน้มลด · p ≥ 0.05 = ไม่พบหลักฐานของแนวโน้มทิศทางเดียว ซึ่งไม่ได้แปลว่าอนุกรมคงที่ · Sen's slope คือขนาดของการเปลี่ยนแปลงต่อหนึ่งช่วงเวลา รายงานคู่กับ 95% CI เสมอ และร้อยละของค่ามัธยฐานช่วยเทียบขนาดข้ามโรคหรือข้ามพื้นที่ · สหสัมพันธ์ในตัวเองที่ lag 1 สูง (|r| > 0.3) ในทาง Mann-Kendall ที่ไม่ได้แก้ค่า ทำให้ต้องอ่าน p อย่างระมัดระวัง
Reading criteria: p < 0.05 with positive S = increasing trend; negative S = decreasing trend; p ≥ 0.05 = no evidence of a monotonic trend, which does not mean the series is constant. Sen's slope is the size of change per period; always report it with its 95% CI, and use the percentage of the median to compare sizes across diseases or areas. A high lag-1 autocorrelation (|r| > 0.3) on the uncorrected Mann-Kendall path means p should be read with caution.
ตัวอย่างนี้: การเสียชีวิตต่อเดือนไม่มีแนวโน้มทิศทางเดียวที่มีนัยสำคัญ (p = 0.151) แต่กราฟแสดงว่าเพิ่มขึ้นในช่วงรับผู้ป่วยถึงสูงสุด 19 รายในเดือน 2023-07 แล้วลดลงหลังปิดรับผู้ป่วยใหม่ (มิ.ย. 2566) ซึ่งสอดคล้องกับจำนวนผู้ป่วยที่อยู่ในการติดตามที่เพิ่มแล้วคงตัว ผลรวมของขาขึ้นและขาลงจึงหักล้างกัน — เมื่อรู้จุดเปลี่ยนเช่นนี้ควรใช้ 11.6 · ก่อนวิเคราะห์ต่อ ให้สังเกตเดือน 2024-12 ที่มีผู้เสียชีวิต 13 ราย ในจำนวนนี้ 10 รายลงวันที่ 31 ธ.ค. 2567 ซึ่งเป็นวันปิดการศึกษา ควรตรวจว่าเป็นการเสียชีวิตในเดือนนั้นจริงหรือเป็นการบันทึกตอนปิดโครงการ · ผู้ป่วยใหม่ต่อเดือนคงที่ (p = 0.702; Sen's slope 0.14 รายต่อเดือน 95% CI −0.73 ถึง 0.60) ช่วงเชื่อมั่นครอบศูนย์ แต่ช่วงนี้สั้นเพียง 18 เดือน จึงตัดแนวโน้มขนาดเล็กออกไม่ได้
This example: deaths per month show no significant monotonic trend (p = 0.151), but the plot shows a rise during recruitment to a peak of 19 deaths in 2023-07 and a fall after recruitment closed (June 2023), in line with the number of patients under follow-up growing and then levelling off; the rising and falling halves cancel out — when the change point is known, use 11.6. Before going further, note 2024-12: 13 deaths, 10 of them dated 31 Dec 2024, the study's closing date; check whether these are true December deaths or deaths recorded at closure. New patients per month were stable (p = 0.702; Sen's slope 0.14 per month, 95% CI −0.73 to 0.60); the interval covers zero, but with only 18 months a small trend cannot be ruled out.
ตัวอย่างประโยครายงาน: "จำนวนผู้เสียชีวิตต่อเดือนระหว่าง ก.พ. 2565 ถึง ธ.ค. 2567 (35 เดือน) ไม่มีแนวโน้มทิศทางเดียวที่มีนัยสำคัญทางสถิติ (Seasonal Kendall S = −10, z = −1.435, p = 0.151; Sen's slope −0.083 รายต่อเดือน, 95% CI −0.292 ถึง 0.083)"
Example results sentence: "Monthly deaths between February 2022 and December 2024 (35 months) showed no statistically significant monotonic trend (Seasonal Kendall S = −10, z = −1.435, p = 0.151; Sen's slope −0.083 deaths per month, 95% CI −0.292 to 0.083)."
เมื่อใดควรใช้และข้อจำกัด: ใช้ทดสอบแนวโน้มทิศทางเดียวโดยไม่ต้องสมมติการแจกแจง และยอมรับช่วงที่ไม่มีข้อมูล · ต้องมีอย่างน้อย 8–10 ช่วง (แบบฤดูกาลต้องครบ 2 รอบ และควรมีหลายปีเพราะคู่ที่เทียบมีเฉพาะเดือนเดียวกันข้ามปี: ตัวอย่างนี้มีเพียง 34 คู่ อำนาจการทดสอบจึงต่ำ) · ตรวจไม่เจอแนวโน้มรูปโค้ง · Seasonal Kendall ไม่แก้สหสัมพันธ์ในตัวเอง ส่วน Mann-Kendall แก้แบบ Hamed-Rao ให้เองเมื่อพบ · อนุกรมนับจากข้อมูลรายบุคคลเป็นจำนวนนับ ไม่ใช่อัตรา ถ้าจำนวนผู้ที่อยู่ในความเสี่ยงเปลี่ยนตามเวลา แนวโน้มของจำนวนสะท้อนทั้งความเสี่ยงและขนาดประชากร
When to use and limits: tests a monotonic trend without distributional assumptions and tolerates gaps. Needs at least 8–10 periods (the seasonal form needs two full cycles, and preferably several years, because only the same month across years is compared: this example has just 34 such pairs, so power is low). It cannot detect a curved trend. The Seasonal Kendall form has no autocorrelation correction; the Mann-Kendall form applies Hamed-Rao automatically when needed. A series counted from patient records is a count, not a rate: if the number of people at risk changes over time, a trend in counts reflects both risk and population size.
รายการตรวจสอบก่อนตีพิมพ์: ระบุการทดสอบที่ใช้จริง (Seasonal Kendall / Mann-Kendall / แก้ Hamed-Rao) · จำนวนช่วง ความถี่ ช่วงเวลา และวิธีสร้างอนุกรมจากข้อมูลรายบุคคล · S และ z พร้อม p · Sen's slope ต่อช่วงพร้อม 95% CI และร้อยละของค่ามัธยฐาน · กราฟอนุกรมพร้อมเส้น Sen · แนวทางการรายงาน STROBE (von Elm et al., 2007) หรือ RECORD สำหรับข้อมูลที่เก็บเป็นประจำ (Benchimol et al., 2015)
Pre-submission checklist: the test actually used (Seasonal Kendall / Mann-Kendall / Hamed-Rao corrected); number of periods, frequency, date range and how the series was built from patient records; S and z with p; Sen's slope per period with 95% CI and as a percentage of the median; the time plot with the Sen line; reporting guideline STROBE (von Elm et al., 2007) or RECORD for routinely collected data (Benchimol et al., 2015).
📖 References
- Mann, H. B. (1945). Nonparametric tests against trend. Econometrica, 13(3), 245–259. doi:10.2307/1907187
- Sen, P. K. (1968). Estimates of the regression coefficient based on Kendall's tau. Journal of the American Statistical Association, 63(324), 1379–1389. doi:10.1080/01621459.1968.10480934
- Hirsch, R. M., Slack, J. R., & Smith, R. A. (1982). Techniques of trend analysis for monthly water quality data. Water Resources Research, 18(1), 107–121. doi:10.1029/WR018i001p00107
- Hamed, K. H., & Rao, A. R. (1998). A modified Mann-Kendall trend test for autocorrelated data. Journal of Hydrology, 204(1–4), 182–196. doi:10.1016/S0022-1694(97)00125-X
- Gilbert, R. O. (1987). Statistical methods for environmental pollution monitoring. Van Nostrand Reinhold. ISBN 978-0-471-28878-7.
- von Elm, E., Altman, D. G., Egger, M., Pocock, S. J., Gøtzsche, P. C., & Vandenbroucke, J. P. (2007). The Strengthening the Reporting of Observational Studies in Epidemiology (STROBE) statement: Guidelines for reporting observational studies. The Lancet, 370(9596), 1453–1457. doi:10.1016/S0140-6736(07)61602-X
- Benchimol, E. I., Smeeth, L., Guttmann, A., Harron, K., Moher, D., Petersen, I., Sørensen, H. T., von Elm, E., & Langan, S. M. (2015). The REporting of studies Conducted using Observational Routinely-collected health Data (RECORD) statement. PLoS Medicine, 12(10), e1001885. doi:10.1371/journal.pmed.1001885
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
11.2Seasonal Decomposition (STL)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
โรคติดเชื้อหลายโรคมีฤดูกาล การแยกอนุกรมเป็น แนวโน้ม + ฤดูกาล + ส่วนเหลือ ทำให้เห็นว่าการขึ้นลงมาจากฤดูกาลหรือจากแนวโน้มระยะยาว ให้ดัชนีฤดูกาลสำหรับวางแผนทรัพยากร และแยกเดือนที่ผิดปกติออกมาในส่วนเหลือ · เป็นการบรรยาย ไม่ใช่การทดสอบนัยสำคัญ · ใช้กับข้อมูลที่มีฤดูกาล (รายวัน สัปดาห์ เดือน ไตรมาส) ที่ครบอย่างน้อย 2 รอบ (แนะนำ 3 รอบขึ้นไป) · ไม่ใช้กับข้อมูลรายปี
Many infectious diseases are seasonal. Splitting a series into trend + seasonal + remainder shows whether movement comes from the season or from the long-term trend, gives seasonal indices for resource planning, and isolates unusual months in the remainder. It is descriptive, not a significance test. Use it for seasonal data (daily, weekly, monthly, quarterly) covering at least two full cycles (three or more recommended); not for yearly data.
2หลักการและสูตรLogic and Formula
- m
- จำนวนช่วงต่อรอบฤดูกาล (12 รายเดือน · 4 รายไตรมาส · 52 รายสัปดาห์ · 7 รายวัน)periods per seasonal cycle (12 monthly · 4 quarterly · 52 weekly · 7 daily)
- T, S, R
- แนวโน้ม ฤดูกาล ส่วนเหลือ (แบบคูณ: คำนวณบนลอการิทึมแล้วแปลงกลับ)trend, seasonal, remainder (multiplicative: computed on the log scale and transformed back)
- ninner, nouter
- รอบ loess ภายใน และรอบถ่วงน้ำหนักแบบ robust (bisquare) ที่ลดน้ำหนักค่าผิดปกติinner loess passes and robustness (bisquare) iterations that down-weight outliers
- FT, FS
- 0–1 · คำที่ DAPH ใช้: ≥ 0.64 สูง · 0.30–0.64 ปานกลาง · ต่ำกว่า 0.30 ต่ำ0–1 · DAPH wording: ≥ 0.64 strong · 0.30–0.64 moderate · below 0.30 weak
STL ใช้ loess วนซ้ำแยกฤดูกาลและแนวโน้ม · DAPH ตั้ง s.window = 7 และ s.degree = 0 เหมือนที่นิยมใช้ใน R ส่วน t.window, l.window และ jump คำนวณตามสูตรค่าเริ่มต้นของ R stl() (รายเดือน: t.window = 23, l.window = 13) · ข้อมูลรายวัน (m = 7) R ใช้ l.window = 7 แต่ตัวคำนวณของ DAPH ต้องการ l.window มากกว่า m จึงใช้ 9 · แบบ robust ของ DAPH ใช้ loess ภายใน 2 รอบต่อการถ่วงน้ำหนักหนึ่งครั้ง (15 ครั้ง) ขณะที่ stl(robust = TRUE) ของ R ใช้ 1 รอบ จึงต้องใส่ inner = 2 ใน R เพื่อให้ได้ค่าเดียวกัน (ถ้าใช้ค่าเริ่มต้นของ R ข้อมูลชุดนี้ต่างได้ถึง 0.03 ในแนวโน้มและ 0.06 ในฤดูกาล) · ดัชนีฤดูกาล = ค่าเฉลี่ยขององค์ประกอบฤดูกาลในแต่ละตำแหน่งของรอบ (ตารางเรียงตามเดือนในปฏิทิน) และแอมพลิจูด = ดัชนีสูงสุดลบต่ำสุด · แบบคูณต้องการค่ามากกว่าศูนย์ทุกช่วง · ช่วงที่ไม่มีข้อมูลถูกเติมเชิงเส้นก่อนแยกองค์ประกอบ
STL iterates loess smoothers to separate the seasonal and trend components. DAPH sets s.window = 7 and s.degree = 0, as is common in R, and computes t.window, l.window and the jumps with the formulas of R's stl() defaults (monthly: t.window = 23, l.window = 13). For daily data (m = 7) R uses l.window = 7, but DAPH's solver needs l.window greater than m, so it uses 9. DAPH's robust fit runs 2 inner loess passes per robustness iteration (15 iterations), whereas R's stl(robust = TRUE) runs 1, so R needs inner = 2 to reproduce DAPH (with R's default the components of these data differ by up to 0.03 in the trend and 0.06 in the seasonal part). The seasonal index is the mean of the seasonal component at each position of the cycle (listed in calendar order), and the amplitude is the highest minus the lowest index. The multiplicative form needs values above zero in every period. Missing periods are linearly interpolated before decomposition.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
# deaths per month = rows with status = 1 (Died/Event), counted by the month of end_date
m_end <- format(seq(as.Date("2022-02-01"), as.Date("2024-12-01"), by = "month"), "%Y-%m")
y <- ts(as.numeric(table(factor(substr(d$end_date[d$status == 1], 1, 7), levels = m_end))),
frequency = 12, start = c(2022, 2))
# STL as DAPH runs it: s.window 7, s.degree 0, robust, t.window/l.window/jumps = R defaults,
# 2 inner iterations (R's default with robust = TRUE is 1) and 15 robustness iterations
st <- stl(y, s.window = 7, s.degree = 0, robust = TRUE, inner = 2, outer = 15)
tr <- st$time.series[, "trend"]; se <- st$time.series[, "seasonal"]; re <- st$time.series[, "remainder"]
c(t.window = st$win[["t"]], l.window = st$win[["l"]])
round(c(mean = mean(y), trend_first = tr[1], trend_max = max(tr), trend_last = tr[35]), 4)
round(c(F_T = max(0, 1 - var(re) / var(tr + re)), F_S = max(0, 1 - var(re) / var(se + re))), 4)
idx <- tapply(se, cycle(se), mean); round(idx, 4) # seasonal index, 1 = Jan ... 12 = Dec
round(c(amplitude = max(idx) - min(idx)), 4)
round(cbind(y, trend = tr, seasonal = se, remainder = re)[c(18, 34, 35), ], 4) # 2023-07, 2024-11, 2024-12
# Classical decomposition (centred 2 x 12 moving average), not robust to single spikes
dc <- decompose(y); ok <- !is.na(dc$random)
round(dc$figure, 4) # seasonal index, 1 = Feb (first month of the series)
round(c(F_T = max(0, 1 - var(dc$random[ok]) / var(dc$trend[ok] + dc$random[ok])),
F_S = max(0, 1 - var(dc$random[ok]) / var(dc$seasonal[ok] + dc$random[ok]))), 4)
t.window l.window
23 13
mean trend_first trend_max trend_last
6.5429 5.1022 6.9065 -0.2991
F_T F_S
0.2756 0.0262
1 2 3 4 5 6 7 8 9 10
0.2434 -1.8728 -3.6383 0.6651 -0.7376 1.6350 -0.3265 0.9049 -0.1142 0.6829
11 12
0.6919 1.7164
amplitude
5.3547
y trend seasonal remainder
[1,] 19 6.8715 -0.3284 12.4569
[2,] 1 0.2765 0.8179 -0.0944
[3,] 13 -0.2991 1.4770 11.8221
[1] 0.4271 -1.4062 -1.7187 0.5104 -0.4479 8.5521 -0.4687 -2.5104 -0.4688
[10] -0.9063 0.1771 -1.7396
F_T F_S
0.5881 0.5654
| Quantity | R (stats) | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| STL strength of trend FT / of season FS | 0.2756 / 0.0262 | 0.2756 / 0.0262 | 0 | ✓ PASS |
| STL 2023-07: trend / seasonal / remainder | 6.8715 / −0.3284 / 12.4569 | 6.8715 / −0.3284 / 12.4569 | 0 | ✓ PASS |
| STL 2024-12: trend / seasonal / remainder | −0.2991 / 1.4770 / 11.8221 | −0.2991 / 1.477 / 11.8221 | 0 | ✓ PASS |
| STL trend and seasonal, all 35 months (R inner = 2) | 35 + 35 values | 35 + 35 values | max 5.0e−05 (4-decimal rounding) | ✓ PASS |
| STL seasonal index (12 values) and amplitude | Mar −3.6383 … Dec 1.7164; 5.3547 | same 12 values; 5.3547 | 0 | ✓ PASS |
| Season names in the index table and summary (STL) | peak Dec, trough Mar | Dec / Mar (table rows Jan … Dec in calendar order) | 0 | ✓ PASS |
| Classical seasonal figure (12 values) | Jul 8.5521 … Sep −2.5104 | 8.5521 … −2.5104 | ≤ 0.0001 | ✓ PASS |
| Classical FT / FS | 0.5881 / 0.5654 | 0.5881 / 0.5654 | 0 | ✓ PASS |
| Season names (classical) | peak Jul, trough Sep | Jul / Sep | 0 | ✓ PASS |
ค่าทุกตัวของ DAPH ตรงกับ stl(..., inner = 2, outer = 15) และ decompose() ใน R · ตารางดัชนีฤดูกาลเรียงเดือนตามปฏิทิน (มกราคมก่อน) ไม่ว่าอนุกรมจะเริ่มเดือนใด และประโยคสรุประบุเดือนสูงสุด (ธันวาคม) และต่ำสุด (มีนาคม) ถูกต้อง
Every DAPH value agrees with R's stl(..., inner = 2, outer = 15) and decompose(). The seasonal-index table lists the months in calendar order (January first) whatever month the series starts in, and the summary names the peak (December) and trough (March) months correctly.
4การแปลผลและตัวอย่างInterpretation and Example
เกณฑ์อ่านผล: ดัชนีฤดูกาลบวก = ช่วงที่สูงกว่าระดับแนวโน้ม · ความแรง ≥ 0.64 = สูง, 0.30–0.64 = ปานกลาง, ต่ำกว่านั้น = ต่ำ · ดูแอมพลิจูดเทียบกับขนาดของอนุกรม · ส่วนเหลือที่มีรูปแบบ หรือค่าที่ใหญ่มากบางช่วง = โครงสร้างที่แยกไม่ได้ หรือเหตุการณ์เฉพาะช่วงที่ควรตรวจข้อมูล
Reading criteria: a positive seasonal index = a period above the trend level. Strength ≥ 0.64 strong, 0.30–0.64 moderate, below that weak. Judge the amplitude against the size of the series. A patterned remainder, or a few very large remainders, means structure the decomposition did not capture or one-off events whose data should be checked.
ตัวอย่างนี้: ฤดูกาลอ่อนมาก (FS = 0.03) จึงไม่ควรสรุปว่าการเสียชีวิตมีฤดูกาล และไม่ควรใช้ดัชนีฤดูกาลวางแผน · แนวโน้มก็อ่อน (FT = 0.28) เพราะความผันผวนระหว่างเดือนของจำนวนที่น้อย (เฉลี่ย 6.5 รายต่อเดือน) ใหญ่กว่าการเปลี่ยนระดับ · ส่วนเหลือที่ใหญ่สองค่า (2023-07 และ 2024-12) ชี้ให้ตรวจข้อมูล: ใน 13 รายของ 2024-12 มี 10 รายที่ลงวันที่ปิดการศึกษา (ดู 11.1) · ข้อมูลมีเพียง 2.9 รอบ DAPH จึงเตือนว่าดัชนีฤดูกาลยังไม่นิ่ง · เมื่อวิธีคลาสสิกกับ STL ให้ผลต่างกันมาก (FS 0.57 เทียบ 0.03) ให้เชื่อ STL แบบ robust และรายงานว่าความต่างมาจากค่าผิดปกติเดือนเดียว
This example: the season is very weak (FS = 0.03), so do not conclude that deaths are seasonal and do not plan with these seasonal indices. The trend strength is also weak (FT = 0.28) because the month-to-month variation of small counts (6.5 deaths a month on average) is larger than the change in level. The two large remainders (2023-07 and 2024-12) call for a data check: 10 of the 13 deaths in 2024-12 are dated on the study's closing day (see 11.1). With only 2.9 cycles DAPH warns that the seasonal indices are unstable. When the classical method and STL disagree this much (FS 0.57 vs 0.03), trust robust STL and report that the difference comes from a single outlying month.
ตัวอย่างประโยครายงาน: "การแยกองค์ประกอบด้วย STL (seasonal window 7, robust) ของจำนวนผู้เสียชีวิตรายเดือน 35 เดือน พบฤดูกาลอ่อน (ความแรง 0.03) และแนวโน้มอ่อน (ความแรง 0.28) โดยเดือน 2023-07 และ 2024-12 มีส่วนเหลือสูงผิดปกติ"
Example results sentence: "STL decomposition (seasonal window 7, robust) of 35 months of deaths showed weak seasonality (strength 0.03) and a weak trend (strength 0.28), with unusually large remainders in 2023-07 and 2024-12."
เมื่อใดควรใช้และข้อจำกัด: ใช้บรรยายว่าการขึ้นลงมาจากฤดูกาลหรือแนวโน้ม และหาดัชนีฤดูกาลสำหรับวางแผน · ต้องครบอย่างน้อย 2 รอบ (แนะนำ ≥ 3 เพื่อดัชนีที่นิ่ง) · แบบบวกเมื่อแอมพลิจูดฤดูกาลคงที่ แบบคูณเมื่อแอมพลิจูดโตตามระดับ (ทุกช่วงต้องมากกว่าศูนย์) · STL ทนค่าผิดปกติและยอมให้ฤดูกาลค่อย ๆ เปลี่ยน ส่วนวิธีคลาสสิกให้ฤดูกาลคงที่ ไม่มีค่าแนวโน้มที่ปลายอนุกรมข้างละ m/2 ช่วง และไวต่อค่าผิดปกติ · จำนวนนับที่น้อยมีความผันผวนสูง ความแรงจึงมักต่ำ
When to use and limits: describes whether movement comes from season or trend and yields seasonal indices for planning. Needs at least two full cycles (three or more for stable indices). Use the additive form when the seasonal amplitude is constant and the multiplicative form when it grows with the level (all values must be above zero). STL resists outliers and lets the season change slowly; the classical method fixes the season, leaves the trend undefined for m/2 periods at each end and is sensitive to outliers. Small counts vary a lot, so strengths tend to be low.
รายการตรวจสอบก่อนตีพิมพ์: วิธี (STL หรือคลาสสิก) และค่าตั้ง (seasonal window 7, degree 0, robust) · แบบบวก/คูณ · จำนวนรอบ · ตารางดัชนีฤดูกาลพร้อมเดือนสูงสุด/ต่ำสุดและแอมพลิจูด · ความแรงของแนวโน้ม FT และฤดูกาล FS · กราฟ 4 แผง (ข้อมูล แนวโน้ม ฤดูกาล ส่วนเหลือ)
Pre-submission checklist: method (STL or classical) and settings (seasonal window 7, degree 0, robust); additive or multiplicative; number of cycles; the seasonal-index table with the peak and trough months and the amplitude; strength of trend FT and season FS; the four-panel figure (data, trend, seasonal, remainder).
📖 References
- Cleveland, R. B., Cleveland, W. S., McRae, J. E., & Terpenning, I. (1990). STL: A seasonal-trend decomposition procedure based on loess. Journal of Official Statistics, 6(1), 3–73.
- Hyndman, R. J., & Athanasopoulos, G. (2021). Forecasting: Principles and practice (3rd ed.). OTexts. https://otexts.com/fpp3/
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
11.3Autocorrelation (ACF · PACF · Ljung-Box · ADF · KPSS)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
ค่าในอนุกรมเวลาไม่เป็นอิสระต่อกัน ค่าเดือนนี้มักสัมพันธ์กับเดือนก่อน การถดถอยธรรมดาบนข้อมูลแบบนี้ให้ค่า p เล็กเกินจริง · ฟังก์ชันสหสัมพันธ์ในตัวเอง (ACF) และสหสัมพันธ์ในตัวเองบางส่วน (PACF) บอกโครงสร้างการพึ่งพา การทดสอบ Ljung-Box บอกว่าอนุกรมต่างจากสัญญาณรบกวนขาว (white noise) หรือไม่ และการทดสอบความคงที่ (stationarity) สองแบบ ADF (Augmented Dickey-Fuller) กับ KPSS (Kwiatkowski-Phillips-Schmidt-Shin) บอกว่าควรหาผลต่างก่อนสร้างแบบจำลอง ARIMA หรือไม่ · ใช้ก่อนสร้างแบบจำลองพยากรณ์ (11.4) หรือก่อนถดถอยบนอนุกรม (11.6, 11.7) · ต้องมีอย่างน้อย 10 ช่วง
Time-series values are not independent: this month usually depends on last month, and ordinary regression on such data gives p-values that are too small. The autocorrelation function (ACF) and partial autocorrelation function (PACF) reveal the dependence structure, the Ljung-Box test asks whether the series differs from white noise, and two stationarity tests, ADF (augmented Dickey-Fuller) and KPSS (Kwiatkowski-Phillips-Schmidt-Shin), tell whether the series should be differenced before an ARIMA model. Use them before forecasting (11.4) or regressing on the series (11.6, 11.7). At least 10 periods are needed.
2หลักการและสูตรLogic and Formula
- h
- lag ที่ทดสอบ = min(lag สูงสุด, 20) · lag สูงสุดของ DAPH = min(max(2m, 12), n/2 − 1) เมื่อมีฤดูกาล (ไม่มีฤดูกาล: min(24, n/2 − 1))lag tested = min(maximum lag, 20); DAPH's maximum lag = min(max(2m, 12), n/2 − 1) for seasonal data (non-seasonal: min(24, n/2 − 1))
- p
- จำนวน lag ของผลต่างใน ADF เลือกด้วย AIC บนตัวอย่างเดียวกันทุก p (ไม่เกิน n/2 − 2) แล้วประมาณใหม่ด้วยข้อมูลทั้งหมดที่ใช้ได้number of lagged differences in ADF, chosen by AIC on a common sample (capped at n/2 − 2), then refitted on all usable observations
- ℓ, σ̂²LR
- bandwidth และความแปรปรวนระยะยาว (Bartlett kernel) · DAPH เลือก ℓ อัตโนมัติตาม Hobijn et al. (2004)bandwidth and long-run variance (Bartlett kernel); DAPH chooses ℓ automatically following Hobijn et al. (2004)
PACF คำนวณจาก ACF ด้วยสมการ Yule-Walker (Durbin-Levinson) แบบเดียวกับ pacf() ของ R · ค่า p ของ ADF ใช้การประมาณของ MacKinnon (1994) และรายงานค่าวิกฤต 5% แบบปรับตามขนาดตัวอย่าง · ค่า p ของ KPSS ได้จากการเทียบตารางค่าวิกฤต (0.347, 0.463, 0.574, 0.739 ที่ 10%, 5%, 2.5%, 1%) จึงรายงานได้เพียง "> 0.10" หรือ "< 0.01" ที่ปลายตาราง · การอ่านคู่กัน: ADF ปฏิเสธและ KPSS ไม่ปฏิเสธ = คงที่ · ADF ไม่ปฏิเสธและ KPSS ปฏิเสธ = ไม่คงที่ ให้หาผลต่าง · ทั้งคู่ไม่ปฏิเสธ หรือทั้งคู่ปฏิเสธ = ไม่ชัดเจน ให้ตัดสินจากกราฟร่วมด้วย
The PACF is computed from the ACF by the Yule-Walker (Durbin-Levinson) equations, as R's pacf() does. The ADF p-value uses MacKinnon's (1994) approximation, and the 5% critical value is adjusted for sample size. The KPSS p-value is read from its table of critical values (0.347, 0.463, 0.574, 0.739 at 10%, 5%, 2.5%, 1%), so at the ends of the table it can only be reported as "> 0.10" or "< 0.01". Read them together: ADF rejects and KPSS does not = stationary; ADF does not reject and KPSS rejects = non-stationary, difference first; neither rejects, or both reject = inconclusive, also judge from the plot.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(urca)
m_end <- format(seq(as.Date("2022-02-01"), as.Date("2024-12-01"), by = "month"), "%Y-%m")
y <- ts(as.numeric(table(factor(substr(d$end_date[d$status == 1], 1, 7), levels = m_end))),
frequency = 12, start = c(2022, 2))
n <- length(y); K <- min(2 * 12, n %/% 2 - 1) # DAPH: max lag = min(2m, n/2 - 1) = 16
r <- acf(y, lag.max = K, plot = FALSE)$acf[-1]; p <- pacf(y, lag.max = K, plot = FALSE)$acf
round(rbind(lag = 1:K, acf = r, pacf = p), 4)
round(c(bound = 1.96 / sqrt(n)), 4)
Box.test(y, lag = min(K, 20), type = "Ljung-Box") # white-noise test of the raw series
# ADF with a constant; lag chosen by AIC over 0..10 on a common sample (as DAPH does), then refitted
dy <- diff(y); kmax <- ceiling(12 * (n / 100)^(1 / 4))
t <- (kmax + 2):n # common sample: 24 differences
aic <- sapply(0:kmax, function(k) {
X <- matrix(y[t - 1]); for (j in seq_len(k)) X <- cbind(X, dy[t - 1 - j])
AIC(lm(dy[t - 1] ~ X)) })
k <- which.min(aic) - 1; c(kmax = kmax, chosen_lag = k)
adf <- ur.df(y, type = "drift", lags = k); round(adf@teststat[1], 4) # tau2 statistic (constant, k lags)
signif(punitroot(adf@teststat[1], N = Inf, trend = "c", statistic = "t"), 6) # approximate p (MacKinnon)
kp <- ur.kpss(y, type = "mu", use.lag = 3); round(kp@teststat, 4) # KPSS at DAPH's bandwidth 3
kp@cval
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
lag 1.0000 2.0000 3.0000 4.0000 5.0000 6.0000 7.0000 8.0000 9.0000 10.0000
acf 0.3609 0.4495 0.2477 0.3007 0.2290 0.1102 0.1072 -0.0912 -0.1045 -0.3089
pacf 0.3609 0.3671 0.0167 0.1014 0.0643 -0.1252 -0.0178 -0.2018 -0.1518 -0.2557
[,11] [,12] [,13] [,14] [,15] [,16]
lag 11.0000 12.0000 13.0000 14.0000 15.0000 16.0000
acf -0.1723 -0.4267 -0.2472 -0.3051 -0.3490 -0.3429
pacf 0.0189 -0.2614 0.0412 0.0807 -0.1475 -0.0803
bound
0.3313
Box-Ljung test
data: y
X-squared = 65.474, df = 16, p-value = 6.105e-08
kmax chosen_lag
10 1
[1] -2.174
[1] 0.216012
[1] 0.2433
10pct 5pct 2.5pct 1pct
critical values 0.347 0.463 0.574 0.739
| Quantity | R (stats, urca) | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| ACF lag 1 / 2 / 12 | 0.3609 / 0.4495 / −0.4267 | 0.3609 / 0.4495 / −0.4267 | 0 | ✓ PASS |
| ACF and PACF, all 16 lags | 32 values | 32 values | 0 (4 dp) | ✓ PASS |
| 95% bound ±1.96/√n | 0.3313 | 0.3313 | 0 | ✓ PASS |
| Ljung-Box Q(16) / p | 65.474 / 6.1e−08 | 65.4737 / < 0.000001 | < 0.001 | ✓ PASS |
| ADF lag chosen by AIC / τ statistic | 1 / −2.174 | 1 / −2.174 | 0 | ✓ PASS |
| ADF p (R: MacKinnon 1996; DAPH: MacKinnon 1994; tolerance 0.001) | 0.216012 | 0.215799 | 0.0002 | ✓ PASS |
| KPSS statistic (level, bandwidth 3) / 5% critical value | 0.2433 / 0.463 | 0.2433 / 0.463 | 0 | ✓ PASS |
ทุกค่าตรงกับ R · ค่า p ของ ADF ต่างกัน 0.0002 เพราะ R (urca) ใช้ตารางของ MacKinnon (1996) ส่วน DAPH ใช้สูตรประมาณของ MacKinnon (1994) ซึ่งเป็นการประมาณการแจกแจงเดียวกันคนละฉบับ · bandwidth ของ KPSS (3) เป็นค่าที่ DAPH เลือกอัตโนมัติ สคริปต์ R จึงกำหนด use.lag = 3 ให้ตรงกัน · ข้อความสรุปของ DAPH อธิบาย ACF ที่ lag 12 = −0.43 ว่าเป็นสหสัมพันธ์ลบระหว่างค่าที่ห่างกันหนึ่งรอบ ไม่ใช่รูปแบบฤดูกาลที่ซ้ำ และแนะนำให้ตรวจด้วยการแยกองค์ประกอบ (11.2)
Every value agrees with R. The ADF p-values differ by 0.0002 because R (urca) uses MacKinnon's (1996) tables and DAPH MacKinnon's (1994) approximation — two approximations of the same distribution. The KPSS bandwidth (3) is DAPH's automatic choice, so the R script sets use.lag = 3. DAPH's summary describes the lag-12 ACF of −0.43 as a negative correlation one cycle apart, not a repeating seasonal pattern, and points to the seasonal decomposition (11.2).
4การแปลผลและตัวอย่างInterpretation and Example
เกณฑ์อ่านผล: แท่งที่เกินเส้นประ ±1.96/√n = lag ที่มีนัยสำคัญ (เมื่อดูหลาย lag อาจเกินโดยบังเอิญราว 1 ใน 20) · ACF ค่อย ๆ ลดกับ PACF ตัดหลัง lag p → รูปแบบ AR(p) · ACF ตัดหลัง lag q กับ PACF ค่อย ๆ ลด → MA(q) · ACF บวกที่ lag m (12 สำหรับรายเดือน) → ฤดูกาล · Ljung-Box มีนัยสำคัญ = ยังมีโครงสร้างที่ต้องจำลอง · ADF ที่ไม่มีนัยสำคัญไม่ใช่หลักฐานว่าไม่คงที่ และ KPSS ที่ไม่มีนัยสำคัญไม่ใช่หลักฐานว่าคงที่ (ไม่ปฏิเสธ ≠ ยืนยัน)
Reading criteria: bars beyond the dashed ±1.96/√n lines are significant lags (with many lags, about 1 in 20 crosses by chance). ACF decaying with the PACF cutting off after lag p → an AR(p) pattern; ACF cutting off after lag q with the PACF decaying → MA(q); a positive ACF at lag m (12 for monthly data) → seasonality. A significant Ljung-Box test = structure remains to be modelled. A non-significant ADF is not evidence of non-stationarity, and a non-significant KPSS is not evidence of stationarity (failing to reject ≠ confirming).
ตัวอย่างนี้: การเสียชีวิตเดือนนี้สัมพันธ์กับสองเดือนก่อนหน้า (PACF ตัดหลัง lag 2 คล้าย AR(2)) และอนุกรมไม่ใช่สัญญาณรบกวนขาว · ความคงที่ไม่ชัดเจน (ADF และ KPSS ต่างไม่ปฏิเสธ) กราฟใน 11.1 ชี้ว่าระดับเปลี่ยนตามช่วงรับผู้ป่วย จึงควรจำลองการเปลี่ยนระดับนั้นโดยตรง (11.6) แทนการหาผลต่างโดยอัตโนมัติ · ACF ลบที่ lag 12 ไม่ใช่ฤดูกาล · ผลนี้ใช้ต่อใน 11.4: DAPH ใช้ ADF บนชุดฝึกตัดสินว่าจะหาผลต่าง (d) หรือไม่
This example: deaths this month are related to the previous two months (the PACF cuts off after lag 2, AR(2)-like), and the series is not white noise. Stationarity is unclear (neither ADF nor KPSS rejects); the plot in 11.1 shows a level that changes with recruitment, so that change is better modelled directly (11.6) than removed by automatic differencing. The negative ACF at lag 12 is not seasonality. This feeds 11.4, where DAPH uses ADF on the training data to decide whether to difference (d).
ตัวอย่างประโยครายงาน: "จำนวนผู้เสียชีวิตรายเดือนมีสหสัมพันธ์ในตัวเองที่ lag 1 และ 2 (r = 0.36 และ 0.45; Ljung-Box Q(16) = 65.47, p < 0.001) ส่วนการทดสอบความคงที่ให้ผลไม่ชัดเจน (ADF τ = −2.174, p = 0.216; KPSS = 0.2433, p > 0.10)"
Example results sentence: "Monthly deaths were autocorrelated at lags 1 and 2 (r = 0.36 and 0.45; Ljung-Box Q(16) = 65.47, p < 0.001), while stationarity tests were inconclusive (ADF τ = −2.174, p = 0.216; KPSS = 0.2433, p > 0.10)."
เมื่อใดควรใช้และข้อจำกัด: ทำก่อนสร้าง ARIMA หรือก่อนถดถอยบนอนุกรม · ต้องมีอย่างน้อย 10 ช่วง และ lag สูงสุดไม่เกินครึ่งของจำนวนช่วง · ADF มีอำนาจต่ำเมื่ออนุกรมสั้น ส่วน KPSS ปฏิเสธได้ง่ายเมื่อมีการเปลี่ยนระดับ จึงต้องอ่านคู่กันและดูกราฟ · ช่วงที่ไม่มีข้อมูลถูกเติมเชิงเส้นก่อนคำนวณ (DAPH แจ้งจำนวนในหมายเหตุ)
When to use and limits: run before building an ARIMA model or regressing on the series. Needs at least 10 periods, with a maximum lag below half the series length. ADF has low power in short series and KPSS rejects easily when the level shifts, so read them together and with the plot. Missing periods are linearly interpolated first (DAPH states how many in the notes).
รายการตรวจสอบก่อนตีพิมพ์: กราฟ ACF/PACF ถึง lag ที่ครอบคลุม 1–2 รอบฤดูกาล พร้อมขอบเขต ±1.96/√n · Ljung-Box (lag, Q, df, p) · ADF พร้อมสเปก (ค่าคงที่, จำนวน lag และวิธีเลือก) · KPSS พร้อม bandwidth และค่าวิกฤต · ข้อสรุปเรื่องการหาผลต่าง
Pre-submission checklist: ACF/PACF figure up to a lag covering one to two seasonal cycles, with the ±1.96/√n bounds; Ljung-Box (lag, Q, df, p); ADF with its specification (constant, number of lags and how it was chosen); KPSS with bandwidth and critical value; the conclusion about differencing.
📖 References
- Box, G. E. P., Jenkins, G. M., Reinsel, G. C., & Ljung, G. M. (2015). Time series analysis: Forecasting and control (5th ed.). Wiley. ISBN 978-1-118-67502-1.
- Ljung, G. M., & Box, G. E. P. (1978). On a measure of lack of fit in time series models. Biometrika, 65(2), 297–303. doi:10.1093/biomet/65.2.297
- Dickey, D. A., & Fuller, W. A. (1979). Distribution of the estimators for autoregressive time series with a unit root. Journal of the American Statistical Association, 74(366), 427–431. doi:10.2307/2286348
- Kwiatkowski, D., Phillips, P. C. B., Schmidt, P., & Shin, Y. (1992). Testing the null hypothesis of stationarity against the alternative of a unit root. Journal of Econometrics, 54(1–3), 159–178. doi:10.1016/0304-4076(92)90104-Y
- MacKinnon, J. G. (1994). Approximate asymptotic distribution functions for unit-root and cointegration tests. Journal of Business & Economic Statistics, 12(2), 167–176. doi:10.1080/07350015.1994.10510005
- MacKinnon, J. G. (1996). Numerical distribution functions for unit root and cointegration tests. Journal of Applied Econometrics, 11(6), 601–618. doi:10.1002/(SICI)1099-1255(199611)11:6<601::AID-JAE417>3.0.CO;2-T
- Hobijn, B., Franses, P. H., & Ooms, M. (2004). Generalizations of the KPSS-test for stationarity. Statistica Neerlandica, 58(4), 483–502. doi:10.1111/j.1467-9574.2004.00272.x
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
11.4Time-Series Forecast (SARIMA · Holt-Winters)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
การพยากรณ์ค่าในอนาคตพร้อมช่วงความไม่แน่นอนใช้วางแผนเวชภัณฑ์ เตียง และกำลังคน · DAPH ประมาณสองตระกูลที่ใช้มากที่สุด คือ SARIMA (seasonal autoregressive integrated moving average: ทำนายจากค่าในอดีต ความคลาดเคลื่อนในอดีต และรอบฤดูกาล) และ Holt-Winters (การปรับเรียบเอ็กซ์โพเนนเชียลของระดับ แนวโน้ม และฤดูกาล) แล้วเลือกด้วยความแม่นบนช่วงท้ายที่กันไว้ ซึ่งแบบจำลองไม่เคยเห็น · ไม่เทียบ AICc (เกณฑ์สารสนเทศของ Akaike แก้สำหรับตัวอย่างเล็ก) ข้ามตระกูล เพราะ likelihood ของสองตระกูลอยู่คนละสเกล AICc ใช้เฉพาะเลือกลำดับภายในกริด SARIMA · ใส่ตัวทำนายได้ (regression with ARIMA errors) · ใช้เมื่อต้องการค่าคาดการณ์ ไม่ใช่การอธิบายสาเหตุ · ควรมีอย่างน้อย 3 รอบฤดูกาล (รายเดือน ≥ 36 เดือน)
Forecasting future values with an uncertainty range drives planning for supplies, beds and staff. DAPH fits the two most used families, SARIMA (seasonal autoregressive integrated moving average: predicts from past values, past errors and the seasonal cycle) and Holt-Winters (exponential smoothing of level, trend and season), and selects by accuracy on the most recent periods held back from fitting. AICc (Akaike's information criterion corrected for small samples) is not compared across families, because their likelihoods are on different scales; it only orders the SARIMA grid. Predictors can be added (regression with ARIMA errors). Use it to anticipate values, not to explain causes; three or more seasonal cycles are advisable (monthly: 36 months or more).
2หลักการและสูตรLogic and Formula
- B, m
- ตัวดำเนินการถอยหลัง (Byt = yt−1) และคาบฤดูกาลbackshift operator (Byt = yt−1) and seasonal period
- kj
- lag ของตัวทำนาย j — อัตโนมัติ หรือผู้ใช้กำหนดlag of predictor j — automatic or set by the user
- ℓ, b, s, φ
- ระดับ แนวโน้ม ฤดูกาล และตัวลดทอนแนวโน้ม (0.8 ≤ φ ≤ 0.995)level, trend, season and damping (0.8 ≤ φ ≤ 0.995)
- k (AICc), et, H, T
- จำนวนพารามิเตอร์รวม σ² · ความคลาดเคลื่อนบนช่วงที่กันไว้ H ช่วง · จำนวนช่วงของชุดฝึก (ตัวหารของ MASE ใช้ชุดฝึกเท่านั้น)number of parameters including σ²; errors on the H held-back periods; number of training periods (the MASE denominator uses the training data only)
ขั้นตอนของ DAPH (1) กันช่วงท้าย H = min(m, max(4, ⌊n/5⌋)) ช่วง (ไม่มีฤดูกาล: ใช้ 6 แทน m) ไม่เกิน ⌊n/3⌋ · (2) ตระกูล SARIMA: d = 0 ถ้า ADF (มีค่าคงที่, lag เลือกด้วย AIC) บนชุดฝึกให้ p < 0.05 ไม่เช่นนั้น d = 1 · D = 1 เมื่อชุดฝึกมีอย่างน้อย 3 รอบ · ค้นกริด p, q ∈ {0, 1, 2} และ P, Q ∈ {0, 1} (เมื่อข้อมูลมีคาบฤดูกาล) เลือกด้วย AICc · ใส่ค่าคงที่เฉพาะเมื่อไม่หาผลต่าง · ประมาณด้วย exact maximum likelihood ผ่านตัวกรอง Kalman โดยบังคับ stationarity/invertibility และ SE จาก Hessian · (3) Holt-Winters: แนวโน้มแบบบวกลดทอนเสมอ ใส่ฤดูกาลแบบบวกเมื่อชุดฝึกมีอย่างน้อย 2 รอบ พารามิเตอร์และค่าเริ่มต้น (ℓ0, b0, s) ได้จากการทำให้ผลรวมกำลังสองของความคลาดเคลื่อนหนึ่งขั้นต่ำสุด โดย α, β, γ ∈ [0, 1] และ φ ∈ [0.8, 0.995] · (4) เลือกตระกูลที่ RMSE บนช่วงที่กันไว้ต่ำกว่า แล้วประมาณใหม่ด้วยข้อมูลทั้งหมดก่อนพยากรณ์ (ระยะพยากรณ์อัตโนมัติ: รายเดือน 12, รายไตรมาส 8, รายสัปดาห์ 12, รายวัน 14, รายปี 3) · (5) ช่วงพยากรณ์ของ SARIMA คำนวณตรงจากแบบจำลอง ส่วนของ Holt-Winters ได้จากการจำลอง 1,000 เส้นทาง (ค่า seed คงที่) ด้วยความคลาดเคลื่อนแบบปกติที่ σ = √(SSE/(n − จำนวนพารามิเตอร์)) · อนุกรมที่ไม่เคยติดลบจะถูกตัดค่าพยากรณ์และช่วงที่ศูนย์
DAPH's procedure: (1) hold back the last H = min(m, max(4, ⌊n/5⌋)) periods (non-seasonal: 6 instead of m), at most ⌊n/3⌋. (2) SARIMA family: d = 0 if ADF (constant, lag by AIC) on the training data gives p < 0.05, otherwise d = 1; D = 1 when the training data span at least three cycles; grid p, q ∈ {0, 1, 2} and P, Q ∈ {0, 1} (when the data have a seasonal period), chosen by AICc; a constant only when there is no differencing; exact maximum likelihood through the Kalman filter with stationarity/invertibility enforced and Hessian-based SE. (3) Holt-Winters: always an additive damped trend, plus an additive season when the training data span at least two cycles; parameters and initial states (ℓ0, b0, s) minimise the sum of squared one-step errors with α, β, γ ∈ [0, 1] and φ ∈ [0.8, 0.995]. (4) The family with the lower held-back RMSE is chosen and refitted on all data before forecasting (automatic horizon: monthly 12, quarterly 8, weekly 12, daily 14, yearly 3). (5) SARIMA intervals are computed from the model; Holt-Winters intervals come from 1,000 simulated paths (fixed seed) with normal errors of σ = √(SSE/(n − number of parameters)). A series that is never negative has forecasts and limits floored at zero.
ตัวทำนาย: เมื่อเลือกตัวแปรอิสระ DAPH ใช้ regression with ARIMA errors เท่านั้น (Holt-Winters ไม่มีที่ให้ตัวทำนาย จึงไม่ถูกเทียบ) · lag ของตัวทำนายเลือกสองขั้น: สหสัมพันธ์ไขว้หลัง prewhiten (11.5) ใช้คัดกรองผู้สมัคร (lag 0 เสมอ และ lag ≥ 0 ที่มีนัยสำคัญได้สูงสุด 3 ตัว ค้นถึง min(max(m, 12), n/4)) แล้วเทียบผู้สมัครด้วย AICc บนตัวอย่างเดียวกัน หรือผู้ใช้กำหนด lag เอง · ค่าของตัวทำนายในอนาคตที่เกิน lag มาจากการพยากรณ์อนุกรมของตัวทำนายเอง ช่วงพยากรณ์จึงเป็น "แบบมีเงื่อนไข" ที่ไม่รวมความไม่แน่นอนของตัวทำนาย (Hyndman & Athanasopoulos 2021)
Predictors: with independent variables DAPH fits only regression with ARIMA errors (Holt-Winters has no place for predictors, so it is not compared). A predictor's lag is chosen in two steps: the prewhitened cross-correlation (11.5) screens candidates (lag 0 always, plus up to three significant lags ≥ 0, searched up to min(max(m, 12), n/4)), then the candidates are compared by AICc on the same sample; users can also set the lags. Beyond its lag a predictor's future values are forecast from its own series, so the interval is "conditional" and excludes the predictors' own uncertainty (Hyndman & Athanasopoulos 2021).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
suppressMessages({library(forecast); library(urca)})
# new patients per month = rows counted by the month of enroll_date (2022-01 to 2023-06)
m_enr <- format(seq(as.Date("2022-01-01"), as.Date("2023-06-01"), by = "month"), "%Y-%m")
y <- ts(as.numeric(table(factor(substr(d$enroll_date, 1, 7), levels = m_enr))), frequency = 12, start = c(2022, 1))
tr <- window(y, end = c(2023, 2)); te <- window(y, start = c(2023, 3)) # DAPH holds out the last 4 months
# 1. d for the ARIMA grid: ADF (constant, lag by AIC) on the 14 training months; d = 0 when p < 0.05
n <- length(tr); kmax <- min(ceiling(12 * (n / 100)^(1 / 4)), n %/% 2 - 2); dy <- diff(tr); t <- (kmax + 2):n
aic <- sapply(0:kmax, function(k) { X <- matrix(tr[t - 1]); for (j in seq_len(k)) X <- cbind(X, dy[t - 1 - j]); AIC(lm(dy[t - 1] ~ X)) })
k <- which.min(aic) - 1; adf <- ur.df(tr, type = "drift", lags = k)
round(c(lag = k, tau = adf@teststat[1], p = punitroot(adf@teststat[1], N = Inf, trend = "c", statistic = "t")), 4)
# 2. SARIMA grid (p, q = 0-2; P, Q = 0-1, period 12; d = 0, D = 0) by AICc on the training months
g <- expand.grid(p = 0:2, q = 0:2, P = 0:1, Q = 0:1)
fits <- apply(g, 1, function(v) tryCatch(Arima(tr, order = c(v[1], 0, v[2]),
seasonal = list(order = c(v[3], 0, v[4]), period = 12), method = "ML"), error = function(e) NULL))
ok <- function(f) !is.null(f) && f$sigma2 > 1e-3 && all(abs(coef(f)[grepl("ar", names(coef(f)))]) < 0.999)
g$aicc <- sapply(fits, function(f) if (ok(f)) f$aicc else NA) # DAPH keeps AR terms strictly stationary
head(g[order(g$aicc), ], 3)
fa <- Arima(tr, order = c(0, 0, 1), method = "ML"); fa
fca <- forecast(fa, h = 4, level = 95)
round(accuracy(fca, te)["Test set", c("RMSE", "MAE", "MAPE", "MASE")], 4)
mean(te >= fca$lower & te <= fca$upper) # 95% interval coverage on the held-out months
# 3. Holt's damped trend (no season: fewer than 24 months), SSE minimised with
# alpha, beta in [0, 1], phi in [0.8, 0.995], initial level and trend estimated (as DAPH)
holt <- function(par, x) { a <- par[1]; b <- par[2]; ph <- par[3]; l <- par[4]; bb <- par[5]; e <- x
for (i in seq_along(x)) { f <- l + ph * bb; e[i] <- x[i] - f; ln <- a * x[i] + (1 - a) * f
bb <- b * (ln - l) + (1 - b) * ph * bb; l <- ln }
list(sse = sum(e^2), l = l, b = bb, e = e) }
fit_holt <- function(x) { best <- NULL # several starting values, keep the smallest SSE
for (st in list(c(0.5, 0.1, 0.9), c(0.1, 0.01, 0.95))) { o <- optim(c(st, mean(x), 0), function(p) holt(p, x)$sse,
method = "L-BFGS-B", lower = c(0, 0, 0.8, -Inf, -Inf), upper = c(1, 1, 0.995, Inf, Inf))
if (is.null(best) || o$value < best$value) best <- o }
best }
o <- fit_holt(as.numeric(tr)); h <- holt(o$par, as.numeric(tr)); round(o$par, 4)
e <- as.numeric(te) - (h$l + cumsum(o$par[3]^(1:4)) * h$b)
round(c(RMSE = sqrt(mean(e^2)), MAE = mean(abs(e)), MAPE = 100 * mean(abs(e / te)),
MASE = mean(abs(e)) / mean(abs(diff(tr, lag = 12)))), 4) # MASE scale: seasonal naive on training data
# 4. Holt-Winters wins on held-out RMSE, so it is refitted on all 18 months and forecast 12 months ahead
o2 <- fit_holt(as.numeric(y)); h2 <- holt(o2$par, as.numeric(y)); round(o2$par, 4)
fc <- h2$l + cumsum(o2$par[3]^(1:12)) * h2$b; s <- sqrt(h2$sse / (18 - 5))
round(rbind(mean = fc, lo95 = fc - 1.96 * s, hi95 = fc + 1.96 * s)[, c(1, 2, 12)], 4) # alpha = beta = 0: mean +/- 1.96 s
y1 <- y[-1]; e1 <- h2$e[-1] # DAPH treats Holt as d = 1: first period left out
aic5 <- 18 * log(h2$sse / 18) + 2 * 5 # 5 estimated values: alpha, beta, phi, level, trend
round(c(R2 = 1 - sum(e1^2) / sum((y1 - mean(y1))^2), AIC = aic5, AICc = aic5 + 2 * 5 * 6 / (18 - 5 - 1),
NBIC = log(sum(e1^2) / 17) + 5 * log(17) / 17), 4) # normalized BIC on the 17 months used
Box.test(h2$e, lag = 4, type = "Ljung-Box", fitdf = 3) # residuals; df = 4 - 3 smoothing parameters
lag tau p
5.0000 -3.9809 0.0015
p q P Q aicc
4 0 1 0 0 91.24416
2 1 0 0 0 91.57438
1 0 0 0 0 91.87438
Series: tr
ARIMA(0,0,1) with non-zero mean
Coefficients:
ma1 mean
-0.9999 71.0993
s.e. 0.3077 0.2530
sigma^2 = 20.91: log likelihood = -41.42
AIC=88.84 AICc=91.24 BIC=90.76
RMSE MAE MAPE MASE
9.5663 8.4098 11.2067 1.4016
[1] 0.75
[1] 0.0000 0.0000 0.8000 74.7582 -1.0961
RMSE MAE MAPE MASE
9.1113 8.2486 10.9889 1.3748
[1] 0.0000 0.0000 0.9950 71.5394 0.0743
[,1] [,2] [,3]
mean 72.8826 72.9498 73.6037
lo95 58.5342 58.6014 59.2553
hi95 87.2310 87.2982 87.9522
R2 AIC AICc NBIC
0.0145 75.8074 80.8074 4.4112
Box-Ljung test
data: h2$e
X-squared = 3.6815, df = 1, p-value = 0.05502
| Quantity | R (forecast, urca, optim) | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| Held-back months / training months | 4 / 14 | 4 / 14 | 0 | ✓ PASS |
| SARIMA grid choice (d = 0) and its AICc / AIC / BIC | ARIMA(0,0,1)+mean; 91.24416 / 88.84 / 90.76 | ARIMA(0,0,1)+const; 91.2442 / 88.8442 / 90.7613 | < 0.001 | ✓ PASS |
| ARIMA held-back RMSE / MAE / MASE (tolerance 0.01: MA(1) at the invertibility limit, flat likelihood) | 9.5663 / 8.4098 / 1.4016 | 9.5643 / 8.4084 / 1.4014 | 0.0020 | ✓ PASS |
| ARIMA 95% PI coverage on held-back months | 0.75 | 75.0% | 0 | ✓ PASS |
| Holt-Winters training fit α / β / φ | 0 / 0 / 0.8 | 0 / 0 / 0.8 | 0 | ✓ PASS |
| Holt-Winters held-back RMSE / MAE / MAPE / MASE | 9.1113 / 8.2486 / 10.9889 / 1.3748 | 9.1113 / 8.2486 / 10.99 / 1.3748 | < 0.0001 | ✓ PASS |
| Selected model (lower held-back RMSE) | Holt-Winters | Holt-Winters (damped trend) | — | ✓ PASS |
| Refit on 18 months: φ / initial level / initial trend | 0.995 / 71.5394 / 0.0743 | 0.995 (shown) / 71.5394 / 0.0743 (engine internals) | < 0.0001 | ✓ PASS |
| Smoothing parameters printed in the DAPH coefficient table | α 0, β 0, φ 0.995 (refit) | α 0, β 0, φ 0.995 | 0 | ✓ PASS |
| Forecast 2023-07 / 2023-08 / 2024-06 | 72.8826 / 72.9498 / 73.6037 | 72.8826 / 72.9498 / 73.6037 | 0 | ✓ PASS |
| 95% PI, 12 months (R: exact normal limits; DAPH: 1,000 simulated paths; tolerance 2) | 2023-07: 58.5342 to 87.2310 | 2023-07: 58.4781 to 86.9951 | max 1.59 over 24 limits | ✓ PASS |
| R² (first month excluded) / AIC of the final model | 0.0145 / 75.8074 | 0.0145 / 75.8074 | 0 | ✓ PASS |
| AICc of the final model (k = 5 estimated values) | 80.8074 | 80.8074 | 0 | ✓ PASS |
| Normalized BIC of the final model (k = 5, 17 months) | 4.4112 | 4.411 | < 0.001 | ✓ PASS |
| Residual Ljung-Box Q(4), df = 1 / p | 3.6815 / 0.05502 | 3.6815 / 0.055021 | 0 | ✓ PASS |
ทุกขั้นตอนของ DAPH ทำซ้ำได้ใน R: การกันช่วงตรวจ การเลือก d ด้วย ADF การเลือกลำดับด้วย AICc ความแม่นบนช่วงที่กันไว้ การเลือกตระกูล การประมาณใหม่ และค่าพยากรณ์ · กริด SARIMA ใน R ต้องตัดแบบจำลองที่ AR อยู่บนขอบไม่คงที่ออก (R ยอมให้ AR = −1 ซึ่งให้ likelihood เสื่อม) เพราะตัวประมาณของ DAPH บังคับ stationarity · ตารางพารามิเตอร์ของ Holt-Winters แสดงค่าของแบบจำลองที่ประมาณใหม่ซึ่งใช้พยากรณ์จริง (φ = 0.995) และ AICc กับ Normalized BIC ของแบบจำลองสุดท้ายนับพารามิเตอร์ที่ประมาณ 5 ค่า · ช่วงพยากรณ์ของ Holt-Winters ต่างจากสูตรตรงได้ถึง 1.59 เพราะมาจากการจำลอง 1,000 เส้นทาง
Every DAPH step can be repeated in R: the hold-back, the choice of d by ADF, the AICc order search, the held-back accuracy, the family choice, the refit and the forecasts. In R the SARIMA grid must drop fits with an AR coefficient on the non-stationary boundary (R allows AR = −1, a degenerate likelihood), because DAPH's estimator enforces stationarity. The Holt-Winters parameter table shows the refitted model that produces the forecasts (φ = 0.995), and the final-model AICc and Normalized BIC count the 5 estimated values. The Holt-Winters intervals differ from the exact formula by up to 1.59 because they come from 1,000 simulated paths.
4การแปลผลและตัวอย่างInterpretation and Example
หลักการเลือกแบบจำลองที่ DAPH ใช้และรายงานใน Word (ประโยค "เลือก … เพราะ …"): (1) แบบจำลองต่างตระกูล (SARIMA กับ Holt-Winters) เทียบกันด้วย RMSE บนช่วงที่กันไว้เท่านั้น เพราะ AICc ของสองตระกูลอยู่คนละสเกล likelihood · (2) ภายในตระกูลเดียวกัน (กริดลำดับของ SARIMA) เลือกด้วย AICc บนชุดฝึก · (3) เมื่อมีตัวทำนาย ใช้ regression with ARIMA errors อย่างเดียว (Hyndman & Athanasopoulos, 2021) · AICc ของชุดฝึก (ตารางแบบจำลองที่เปรียบเทียบ) กับ AICc ของแบบจำลองสุดท้าย (ทุกช่วง) มาจากคนละตัวอย่าง ห้ามนำมาเทียบกัน
The model-selection principle DAPH applies and reports in Word (the "selected because …" sentence): (1) models of different families (SARIMA versus Holt-Winters) are compared only on held-back RMSE, because their AICc values sit on different likelihood scales; (2) within a family (the SARIMA order grid) the order is chosen by AICc on the training data; (3) with predictors only regression with ARIMA errors is fitted (Hyndman & Athanasopoulos, 2021). The training-sample AICc (candidate table) and the final-model AICc (all periods) come from different samples and must not be compared.
เกณฑ์อ่านความแม่น: MASE ต่ำกว่า 1 = แม่นกว่าการพยากรณ์แบบไร้เดียงสาตามฤดูกาลบนชุดฝึก (Hyndman & Koehler, 2006) · ความครอบคลุมของช่วงพยากรณ์ 95% บนช่วงที่กันไว้ควรใกล้ 95% (ต่ำกว่ามาก = ช่วงแคบเกินจริง; เมื่อมีเพียงไม่กี่เดือนตัวเลขนี้หยาบมาก) · MAPE ไม่รายงานเมื่อช่วงที่กันไว้มีค่าศูนย์ · Ljung-Box ของส่วนเหลือหักองศาอิสระตามจำนวนพารามิเตอร์ (ARIMA: p + q + P + Q; Holt-Winters: α, β, φ และ γ) ถ้ามีนัยสำคัญ ช่วงพยากรณ์อาจแคบเกินจริง · R² บนสเกลเดิม และ stationary R² (Harvey 1989) ซึ่งเทียบกับค่าเฉลี่ยของอนุกรมที่หาผลต่างแล้ว (Holt-Winters ถือเป็น d = 1) · ตัดสินใจจากช่วงพยากรณ์ ไม่ใช่ค่าจุดเดียว
Accuracy criteria: MASE below 1 = more accurate than the seasonal naive forecast on the training data (Hyndman & Koehler, 2006); the 95% interval coverage on the held-back periods should be near 95% (much lower = intervals too narrow; with only a few months it is very coarse); MAPE is withheld when a held-back value is zero; the residual Ljung-Box test removes degrees of freedom for the parameters (ARIMA: p + q + P + Q; Holt-Winters: α, β, φ and γ) — if significant, the intervals may be too narrow; R² on the original scale and the stationary R² (Harvey 1989), which compares with the mean of the differenced series (Holt-Winters counts as d = 1). Plan from the interval, not the point forecast.
ตัวอย่างนี้: แผนงานควรเตรียมรับผู้ป่วยใหม่ราว 73 รายต่อเดือน โดยเผื่อได้ระหว่างราว 58 ถึง 88 ราย (95% PI) · α = β = 0 หมายความว่าแบบจำลองไม่ปรับระดับตามข้อมูลใหม่เลย ค่าพยากรณ์จึงเป็นเส้นที่ประมาณได้จากข้อมูลทั้งหมด (R² = 0.0145: ความผันผวนรายเดือนเป็นความสุ่มรอบค่าเฉลี่ย) · MASE 1.37 มากกว่า 1 คือบนช่วงที่กันไว้ แบบจำลองแม่นน้อยกว่าการใช้ค่าเดือนเดียวกันของปีก่อน แต่ตัวหารของ MASE มาจากผลต่างข้ามปีเพียง 2 คู่ (ชุดฝึกมี 14 เดือน) จึงไม่นิ่ง · ความครอบคลุม 75% มาจาก 4 เดือนเท่านั้น · ข้อมูลเพียง 18 เดือนน้อยกว่าที่แนะนำ (36 เดือน) และการรับผู้ป่วยหยุดจริงในเดือนถัดไป — ตัวอย่างที่ดีว่าค่าพยากรณ์ใช้ได้เฉพาะเมื่อกระบวนการเดิมดำเนินต่อ
This example: the programme should prepare for about 73 new patients a month, allowing for roughly 58 to 88 (95% PI). α = β = 0 means the model never updates its level with new data, so the forecast is the line estimated from all the data (R² = 0.0145: the month-to-month variation is noise around the mean). A MASE of 1.37 (above 1) means that on the held-back months the model was less accurate than repeating last year's value for the same month, but the MASE denominator rests on only two year-on-year differences (14 training months) and is unstable. The 75% coverage comes from just 4 months. With only 18 months the series is shorter than advised (36), and recruitment really did stop the following month — a reminder that forecasts hold only while the process continues unchanged.
ตัวอย่างประโยครายงาน: "จากผู้ป่วยใหม่รายเดือน 18 เดือน (ม.ค. 2565 – มิ.ย. 2566) แบบจำลอง Holt-Winters แนวโน้มลดทอนถูกเลือกด้วยความแม่นบน 4 เดือนล่าสุดที่กันไว้ (RMSE 9.11 เทียบ 9.57 ของ ARIMA(0,0,1); MASE 1.37) และพยากรณ์ผู้ป่วยใหม่ 72.88 รายในเดือนแรก (95% PI 58.48 ถึง 87.00)"
Example results sentence: "Using 18 months of new-patient counts (January 2022 to June 2023), a damped-trend Holt-Winters model was selected on accuracy over the 4 most recent held-back months (RMSE 9.11 vs 9.57 for ARIMA(0,0,1); MASE 1.37) and forecast 72.88 new patients in the first month (95% PI 58.48 to 87.00)."
เมื่อใดควรใช้และข้อจำกัด: ใช้เมื่อต้องการค่าคาดการณ์พร้อมช่วงความไม่แน่นอน · ควรมีอย่างน้อย 3 รอบฤดูกาล และพยากรณ์ไม่เกิน 1 รอบ · สมมติว่ารูปแบบเดิมดำเนินต่อ การเปลี่ยนโครงสร้าง (การระบาดใหญ่ มาตรการใหม่ การปิดรับผู้ป่วย) ทำให้แบบจำลองจากอดีตใช้ไม่ได้ ควรตัดช่วงนั้นหรือใช้ 11.6 · กริด SARIMA ของ DAPH ลองพจน์ฤดูกาล (P, Q) แม้ชุดฝึกจะสั้นกว่า 2 รอบ ควรระวังแบบจำลองฤดูกาลที่ได้จากข้อมูลสั้น · ค่าพยากรณ์ไม่ใช่การประมาณเชิงสาเหตุ
When to use and limits: when you need expected values with an uncertainty range. Have at least three seasonal cycles and forecast no further than one cycle. The method assumes the observed pattern continues; a structural break (a large outbreak, a new policy, the end of recruitment) invalidates a model fitted to the past — trim that period or use 11.6. DAPH's SARIMA grid tries seasonal terms (P, Q) even when the training data are shorter than two cycles, so be wary of seasonal models fitted to short series. Forecasts are not causal estimates.
รายการตรวจสอบก่อนตีพิมพ์ (EPIFORGE 2020; Pollett et al., 2021): แหล่งข้อมูล ช่วงเวลา ความถี่ · การเตรียมข้อมูล (การรวม อัตรา ค่าที่หาย) · แบบจำลองที่เทียบและเกณฑ์เลือก (ความแม่นบนช่วงที่กันไว้) · RMSE/MAE/MASE และความครอบคลุมของช่วงพยากรณ์ · แบบจำลองสุดท้าย (ลำดับหรือพารามิเตอร์ ตัวทำนายและ lag) · การตรวจส่วนเหลือ (Ljung-Box พร้อม df) · ค่าพยากรณ์พร้อม 80/95% PI ในตารางและกราฟ · ข้อสมมติและข้อจำกัด
Pre-submission checklist (EPIFORGE 2020; Pollett et al., 2021): data source, period and frequency; data preparation (aggregation, rates, missing values); models compared and the selection rule (held-back accuracy); RMSE/MAE/MASE and interval coverage; the final model (order or parameters, predictors and lags); residual checks (Ljung-Box with df); forecasts with 80/95% PI in a table and figure; assumptions and limitations.
📖 References
- Box, G. E. P., Jenkins, G. M., Reinsel, G. C., & Ljung, G. M. (2015). Time series analysis: Forecasting and control (5th ed.). Wiley. ISBN 978-1-118-67502-1.
- Hyndman, R. J., & Athanasopoulos, G. (2021). Forecasting: Principles and practice (3rd ed.). OTexts. https://otexts.com/fpp3/
- Hyndman, R. J., & Koehler, A. B. (2006). Another look at measures of forecast accuracy. International Journal of Forecasting, 22(4), 679–688. doi:10.1016/j.ijforecast.2006.03.001
- Harvey, A. C. (1989). Forecasting, structural time series models and the Kalman filter. Cambridge University Press. ISBN 978-0-521-40573-7.
- Holt, C. C. (2004). Forecasting seasonals and trends by exponentially weighted moving averages. International Journal of Forecasting, 20(1), 5–10. doi:10.1016/j.ijforecast.2003.09.015
- Winters, P. R. (1960). Forecasting sales by exponentially weighted moving averages. Management Science, 6(3), 324–342. doi:10.1287/mnsc.6.3.324
- Pollett, S., Johansson, M. A., Reich, N. G., Brett-Major, D., Del Valle, S. Y., Venkatramanan, S., Lowe, R., Porco, T., Berry, I. M., Deshpande, A., Kraemer, M. U. G., Blazes, D. L., Pan-ngum, W., Vespigiani, A., Mate, S. E., Silal, S. P., Kandula, S., Sippy, R., Quandelacy, T. M., … Rivers, C. (2021). Recommended reporting items for epidemic forecasting and prediction research: The EPIFORGE 2020 guidelines. PLOS Medicine, 18(10), e1003793. doi:10.1371/journal.pmed.1003793
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
11.5Cross-Correlation (prewhitened CCF)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
ปัจจัยหลายอย่าง (ฝน อุณหภูมิ ฝุ่น การเริ่มรักษา) ส่งผลต่อผลลัพธ์ทางสุขภาพแบบล่าช้า ฟังก์ชันสหสัมพันธ์ไขว้ (cross-correlation function, CCF) บอกว่าอนุกรมอธิบาย x นำหน้าอนุกรมผลลัพธ์ y กี่ช่วง · แต่ถ้าทั้งสองอนุกรมมีแนวโน้มหรือฤดูกาลร่วมกัน CCF ดิบจะสูงที่หลาย lag โดยไม่มีความหมาย จึงต้อง prewhiten ก่อน: ประมาณ ARIMA ให้ x แล้วกรองทั้ง x และ y ด้วยตัวกรองเดียวกัน · ใช้คัดกรอง lag ก่อนประมาณขนาดผลใน 11.7 หรือใส่เป็นตัวทำนายใน 11.4 · ไม่ใช่การประมาณขนาดผลและไม่ใช่เหตุ-ผล
Many factors (rain, temperature, particulate matter, starting a treatment) affect health outcomes with a delay. The cross-correlation function (CCF) shows by how many periods an explanatory series x leads an outcome series y. When both series share a trend or a season, the raw CCF is high at many lags for no meaningful reason, so the series are prewhitened first: an ARIMA model is fitted to x and the same filter is applied to x and y. Use it to screen lags before estimating the effect in 11.7 or entering a predictor in 11.4; it does not estimate an effect size and does not show causation.
2หลักการและสูตรLogic and Formula
- n, n′
- จำนวนช่วง และจำนวนช่วงหลังตัดส่วนเหลือช่วงเริ่มต้น d + D·m ของตัวกรอง (ไม่ prewhiten: n′ = n)number of periods, and periods left after dropping the filter's d + D·m start-up residuals (no prewhitening: n′ = n)
- at, bt
- อนุกรมที่ prewhiten แล้ว = ส่วนเหลือมาตรฐาน (innovation หารด้วยส่วนเบี่ยงเบนมาตรฐานของการพยากรณ์หนึ่งขั้น คูณ σ) ซึ่งเป็นสัญญาณรบกวนขาวถ้าแบบจำลองถูกprewhitened series = standardised residuals (innovation divided by its one-step forecast standard deviation, times σ), white noise if the model is right
- max lag
- ค่าเริ่มต้นของ DAPH = min(max(m, 12), n/3)DAPH default = min(max(m, 12), n/3)
DAPH เลือกตัวกรองด้วยกฎเดียวกับ 11.4 (d จาก ADF, D = 1 เมื่อมีอย่างน้อย 3 รอบ, กริด p, q ≤ 2 และ P, Q ≤ 1 เลือกด้วย AICc ที่ใช้ n เต็ม) ประมาณจาก x แล้วใช้พารามิเตอร์ชุดเดียวกันกรอง y ตัดส่วนเหลือ d + D·m ค่าแรกของทั้งสองอนุกรม แล้วคำนวณ CCF ตั้งแต่ −max lag ถึง +max lag · lag ที่มีนัยสำคัญ = |r| เกิน ±1.96/√n′ · "lag นำที่ดีที่สุด" ในรายงานคือ lag ≥ 0 ที่ |r| สูงสุด ไม่ว่าจะมีนัยสำคัญหรือไม่ · ถ้าประมาณตัวกรองไม่ได้ DAPH รายงาน CCF ดิบและบอกว่า prewhiten ไม่สำเร็จ · DAPH และ R ใช้ส่วนเหลือแบบมาตรฐาน (innovation หารด้วยส่วนเบี่ยงเบนมาตรฐานของการพยากรณ์หนึ่งขั้น) ทุกช่วงจึงมีความแปรปรวนเท่ากัน รวมทั้งรอบฤดูกาลแรกหลังช่วงเริ่มต้น ซึ่ง innovation ดิบจะแปรปรวนสูงกว่าช่วงอื่นมาก (ในตัวอย่างนี้ราว 3.7 เท่าของส่วนเบี่ยงเบนมาตรฐาน เพราะ Φ = −0.96)
DAPH chooses the filter with the rules of 11.4 (d from ADF, D = 1 with at least three cycles, grid p, q ≤ 2 and P, Q ≤ 1 by AICc computed with the full n), fits it to x, filters y with the same parameters, drops the first d + D·m residuals of both series and computes the CCF from −max lag to +max lag. A lag is significant when |r| exceeds ±1.96/√n′. The "best lead" in the report is the lag ≥ 0 with the largest |r|, significant or not. If the filter cannot be estimated, DAPH reports the raw CCF and says prewhitening failed. DAPH, like R, uses standardised residuals (innovations divided by their one-step forecast standard deviation), so every period has the same variance, including the first seasonal cycle after the start-up, where raw innovations would be far more variable (here about 3.7 times the standard deviation, because Φ = −0.96).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
suppressMessages({library(forecast); library(urca)})
# One row per month, 2022-01 to 2024-12: new patients (by enroll_date) and deaths (status = 1, by end_date)
months <- format(seq(as.Date("2022-01-01"), as.Date("2024-12-01"), by = "month"), "%Y-%m")
pd <- data.frame(month = paste0(months, "-01"),
new_patients = as.numeric(table(factor(substr(d$enroll_date, 1, 7), levels = months))),
deaths = as.numeric(table(factor(substr(d$end_date[d$status == 1], 1, 7), levels = months))))
write.csv(pd, "pd_monthly.csv", row.names = FALSE) # open this file in DAPH (File > Open)
# Months from enrolment to death (0 = same calendar month): early deaths motivate a lag of 1-3 months
dd <- d[d$status == 1, ]
gap <- (as.numeric(substr(dd$end_date, 1, 4)) - as.numeric(substr(dd$enroll_date, 1, 4))) * 12 +
as.numeric(substr(dd$end_date, 6, 7)) - as.numeric(substr(dd$enroll_date, 6, 7))
table(factor(pmin(gap, 7), 0:7, c(0:6, "7+")))
x <- ts(pd$new_patients, frequency = 12, start = c(2022, 1)); y <- ts(pd$deaths, frequency = 12, start = c(2022, 1))
# 1. Raw cross-correlation. DAPH lag +k = new patients k months BEFORE deaths (= lag -k of R's ccf(x, y))
raw <- ccf(as.numeric(x), as.numeric(y), lag.max = 12, plot = FALSE)
round(setNames(rev(raw$acf[, 1, 1]), -12:12), 4); round(1.96 / sqrt(36), 4)
# 2. Prewhitening filter chosen as DAPH does: d by ADF (constant, lag by AIC), D = 1 (36 months = 3 cycles),
# grid p, q = 0-2 and P, Q = 0-1 by AICc = AIC + 2k(k + 1)/(n - k - 1) with n = 36 and k counting sigma^2
n <- 36; kmax <- min(ceiling(12 * (n / 100)^(1 / 4)), n %/% 2 - 2); dx <- diff(x); t <- (kmax + 2):n
aic <- sapply(0:kmax, function(k) { X <- matrix(x[t - 1]); for (j in seq_len(k)) X <- cbind(X, dx[t - 1 - j]); AIC(lm(dx[t - 1] ~ X)) })
adf <- ur.df(x, type = "drift", lags = which.min(aic) - 1)
round(punitroot(adf@teststat[1], N = Inf, trend = "c", statistic = "t"), 4) # p > 0.05, so d = 1
g <- expand.grid(p = 0:2, q = 0:2, P = 0:1, Q = 0:1)
g$aicc <- apply(g, 1, function(v) { f <- tryCatch(Arima(x, order = c(v[1], 1, v[2]),
seasonal = list(order = c(v[3], 1, v[4]), period = 12), method = "ML"), error = function(e) NULL)
if (is.null(f)) NA else { k <- length(coef(f)) + 1; f$aic + 2 * k * (k + 1) / (n - k - 1) } })
g[which.min(g$aicc), ]
fx <- Arima(x, order = c(1, 1, 0), seasonal = list(order = c(1, 1, 0), period = 12), method = "ML"); coef(fx)
ax <- as.numeric(residuals(fx))[-(1:13)] # drop the d + D*m = 13 start-up residuals
ay <- as.numeric(residuals(Arima(y, model = fx)))[-(1:13)] # the same filter applied to deaths
pw <- ccf(ax, ay, lag.max = 12, plot = FALSE)
round(setNames(rev(pw$acf[, 1, 1]), -12:12), 4); round(1.96 / sqrt(length(ax)), 4)
0 1 2 3 4 5 6 7+
0 34 24 19 12 13 12 115
-12 -11 -10 -9 -8 -7 -6 -5 -4 -3
-0.4050 -0.4107 -0.3792 -0.3797 -0.3645 -0.3608 -0.2891 -0.2337 -0.1386 -0.0262
-2 -1 0 1 2 3 4 5 6 7
-0.0091 0.1552 0.0984 0.3266 0.3530 0.4538 0.4692 0.5171 0.4814 0.5085
8 9 10 11 12
0.4529 0.4018 0.4060 0.3347 0.3059
[1] 0.3267
[1] 0.6546
p q P Q aicc
11 1 0 1 0 192.0672
ar1 sar1
-0.5843891 -0.9623219
-12 -11 -10 -9 -8 -7 -6 -5 -4 -3
0.0680 0.0917 -0.1941 0.0671 0.0522 0.0893 -0.1082 0.0098 0.0120 -0.1113
-2 -1 0 1 2 3 4 5 6 7
-0.1322 -0.0450 -0.1266 -0.0262 -0.2030 -0.0124 -0.1858 0.2344 0.2379 0.1428
8 9 10 11 12
0.2250 0.0968 0.3131 -0.0366 0.0524
[1] 0.4087
| Quantity | R (stats, forecast, urca) | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| Raw CCF, lags −12 to +12 (e.g. lag +5) | 25 values (0.5171) | 25 values (0.5171) | 0 (4 dp) | ✓ PASS |
| Raw: bound / number of significant lags | 0.3267 / 16 | 0.3267 / 16 | 0 | ✓ PASS |
| Filter: ADF p for new patients (so d = 1) / chosen order | 0.6546 / (1,1,0)(1,1,0)[12] | d = 1 / (1,1,0)(1,1,0)[12] | 0 | ✓ PASS |
| Filter AICc (n = 36) (tolerance 0.05, iterative ML) | 192.0672 | 192.058 | 0.009 | ✓ PASS |
| Filter ar1 / sar1 (tolerance 0.005) | −0.5844 / −0.9623 | −0.5849 / −0.9624 | 0.0005 | ✓ PASS |
| Start-up residuals dropped / bound ±1.96/√n′ | 13 / 0.4087 | 13 / 0.4087 | 0 | ✓ PASS |
| Prewhitened CCF (lag 0 / +1 / +5 / +10) (tolerance 0.001: filter coefficients from iterative ML) | −0.1266 / −0.0262 / 0.2344 / 0.3131 | −0.1265 / −0.0264 / 0.2341 / 0.313 | max 0.0003 over 25 lags | ✓ PASS |
| Prewhitened: number of significant lags | 0 | 0 | 0 | ✓ PASS |
ทุกค่าตรงกับ R · CCF หลัง prewhiten ต่างกันไม่เกิน 0.0003 เพราะสัมประสิทธิ์ของตัวกรองที่ประมาณแบบวนซ้ำต่างกันที่ทศนิยมตำแหน่งที่สี่ · "lag นำที่ดีที่สุด" ที่ DAPH รายงานคือ lag +10 (r = 0.313) ซึ่งไม่มีนัยสำคัญ
Every value agrees with R; the prewhitened CCF differs by at most 0.0003 because the iteratively estimated filter coefficients differ in the fourth decimal. The "best lead" DAPH reports is lag +10 (r = 0.313), which is not significant.
4การแปลผลและตัวอย่างInterpretation and Example
เกณฑ์อ่านผล: lag บวก = อนุกรมอธิบายนำหน้าผลลัพธ์ · lag ที่มีนัยสำคัญคือ |r| เกิน ±1.96/√n′ (Box et al., 2015) · เมื่อดู 25 lag พร้อมกัน โอกาสเจอ lag ที่ "มีนัยสำคัญ" โดยบังเอิญราว 1 ใน 20 จึงควรสนใจ lag ที่มีเหตุผลทางชีววิทยาหรือระบาดวิทยารองรับ · lag ลบที่มีนัยสำคัญ (ผลลัพธ์นำหน้า) มักเป็นแนวโน้มหรือฤดูกาลที่กรองไม่หมด · CCF ใช้คัดกรองเท่านั้น ขนาดผลต้องประมาณด้วยการถดถอยที่มี lag (11.7) หรือตัวทำนายใน 11.4 (Dean & Dunsmuir, 2016) · รายงาน Word บอกเสมอว่า prewhiten สำเร็จหรือไม่
Reading criteria: a positive lag = the explanatory series leads the outcome; a lag is significant when |r| exceeds ±1.96/√n′ (Box et al., 2015). With 25 lags examined, about 1 in 20 crosses the bound by chance, so focus on lags with biological or epidemiological support. A significant negative lag (outcome leading) usually signals trend or season left after filtering. The CCF only screens; estimate the effect with a lagged regression (11.7) or as a predictor in 11.4 (Dean & Dunsmuir, 2016). The Word report always states whether prewhitening succeeded.
ตัวอย่างนี้: CCF ดิบดูเหมือนผู้ป่วยใหม่นำหน้าการเสียชีวิต 2–11 เดือน (r สูงสุด 0.52 ที่ lag +5) แต่รูปกว้างแบบนี้และค่าลบที่ lag −12 ถึง −7 เป็นลักษณะของแนวโน้มร่วม ไม่ใช่ lag จริง · หลัง prewhiten ไม่มี lag ใดเกิน ±0.41 จึงไม่มีหลักฐานจาก CCF ว่าผู้ป่วยใหม่นำหน้าการเสียชีวิตกี่เดือน ซึ่งไม่ได้แปลว่าไม่มีความสัมพันธ์: ข้อมูลรายบุคคลบอกชัดว่าการเสียชีวิตกระจุกใน 1–3 เดือนแรก แต่ในอนุกรมรายเดือนสัญญาณนี้ซ่อนอยู่ในขั้นบันไดของการรับผู้ป่วย ซึ่งตัวกรองตัดทิ้งไป · ขั้นต่อไปที่เหมาะคือ distributed-lag regression ที่ lag 0–3 (11.7)
This example: the raw CCF suggests that new patients lead deaths by 2–11 months (largest r 0.52 at lag +5), but such a broad pattern, with negative values at lags −12 to −7, is the signature of a shared trend, not of a real lag. After prewhitening no lag exceeds ±0.41, so the CCF gives no evidence of how many months new patients lead deaths — which does not mean there is no relation: the patient records show deaths clustered in the first 1–3 months, but in the monthly series this signal sits inside the recruitment step, which the filter removes. The appropriate next step is a distributed-lag regression at lags 0–3 (11.7).
เมื่อใดควรใช้และข้อจำกัด: ใช้คัดกรองว่าปัจจัยนำหน้าผลลัพธ์กี่ช่วงก่อนนำ lag ไปใส่ในแบบจำลอง · ทั้งสองอนุกรมต้องความถี่เดียวกัน ช่วงเวลาตรงกัน อย่างน้อย 12 ช่วง (แนะนำ ≥ 3 รอบฤดูกาล) · ต้อง prewhiten เมื่อมีแนวโน้มหรือฤดูกาลร่วม · ตัวกรองที่มีผลต่างตามฤดูกาลกินข้อมูล d + D·m ช่วง อนุกรมสั้นจึงเหลือน้อยและขอบเขตกว้าง · อนุกรมอธิบายที่เป็นขั้นบันไดหรือแทบไม่ผันผวน prewhiten ได้ไม่ดี · ไม่ใช่เหตุ-ผล · ใน DAPH ตัวแปรอธิบายต้องอยู่ในแถวเดียวกับเวลา (คอลัมน์เวลาเดียว) ถ้าสองอนุกรมนับจากวันที่คนละคอลัมน์ ให้สร้างตารางรายเดือนก่อนแบบสคริปต์ข้างต้น
When to use and limits: screens how many periods a factor leads the outcome before the lag enters a model. Both series need the same frequency, the same dates and at least 12 periods (three or more seasonal cycles advised). Prewhiten whenever they share a trend or season. A filter with seasonal differencing uses up d + D·m periods, so short series keep few values and the bound is wide. A step-like or nearly constant explanatory series cannot be prewhitened well. Not causation. In DAPH both series share one time column; when they are dated by different columns, build a monthly table first, as in the script above.
รายการตรวจสอบก่อนตีพิมพ์: ตัวกรอง prewhitening (ลำดับ ARIMA ของอนุกรมอธิบาย) และจำนวนช่วงที่ตัด · lag สูงสุด · ขอบเขต 95% · ตาราง CCF ทุก lag และกราฟแท่ง · lag ที่เลือกพร้อมเหตุผลทางวิชาการ · แบบจำลองขั้นต่อไปที่ใช้ lag นั้น
Pre-submission checklist: the prewhitening filter (ARIMA order of the explanatory series) and the periods dropped; maximum lag; 95% bound; the CCF table for every lag and the bar figure; the lag chosen and its subject-matter rationale; the follow-up model that uses it.
📖 References
- Box, G. E. P., Jenkins, G. M., Reinsel, G. C., & Ljung, G. M. (2015). Time series analysis: Forecasting and control (5th ed.). Wiley. ISBN 978-1-118-67502-1.
- Dean, R. T., & Dunsmuir, W. T. M. (2016). Dangers and uses of cross-correlation in analyzing time series in perception, performance, movement, and neuroscience: The importance of constructing transfer function autoregressive models. Behavior Research Methods, 48(2), 783–802. doi:10.3758/s13428-015-0611-2
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
11.6Interrupted Time Series (segmented regression)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
วิธีมาตรฐานสำหรับประเมินผลของนโยบายหรือมาตรการที่มีวันเริ่มชัดเจนเมื่อไม่มีกลุ่มควบคุม เช่น ก่อน-หลังขึ้นภาษี ก่อน-หลังเริ่มฉีดวัคซีน · segmented regression ประมาณสองสิ่งเทียบกับแนวโน้มสมมติหากไม่มีมาตรการ (counterfactual = แนวโน้มก่อนมาตรการที่ลากต่อ): ระดับเปลี่ยนไปเท่าไร และความชันเปลี่ยนไปเท่าไร · ใช้เมื่อมีอย่างน้อย 3 ช่วง (แนะนำ 8 ขึ้นไป) ทั้งก่อนและหลัง · ไม่ใช้เมื่อไม่รู้วันที่ของการเปลี่ยนแปลง (ใช้ 11.1) หรือเมื่อมีเหตุการณ์อื่นเกิดพร้อมกันที่แยกไม่ออก
The standard design for evaluating a policy or intervention with a clear start date when there is no control group — before and after a tax, before and after a vaccination programme. Segmented regression estimates, against the counterfactual (the pre-intervention trend continued), how much the level changed and how much the slope changed. Use it with at least 3 periods (8 or more advised) before and after; not when the date of change is unknown (use 11.1) or when another event at the same time cannot be separated.
2หลักการและสูตรLogic and Formula
- t, t0, Dt
- ลำดับช่วง 1…n · ช่วงแรกที่มาตรการมีผล (เลื่อนได้ด้วยช่อง "ผลล่าช้า") · ตัวบ่งชี้หลังแทรกแซง (0/1) · พจน์ความชัน = 1, 2, 3 … ตั้งแต่ t0period index 1…n; the first period the intervention applies (shiftable with "Delayed effect"); post-interruption indicator (0/1); the slope term is 1, 2, 3 … from t0
- β2
- ระยะห่างระหว่างเส้นหลังมาตรการกับเส้นก่อนมาตรการที่ลากต่อ อ่านที่จุดที่พจน์ความชันเท่ากับ 0 (ก่อน t0 หนึ่งช่วง) · ผล ณ ช่วงแรกหลังมาตรการ = β2 + β3gap between the post-interruption line and the extended pre-interruption line where the slope term equals 0 (one period before t0); the effect in the first post period is β2 + β3
- m, K
- คาบฤดูกาลและจำนวนคู่ Fourier: ค่าเริ่มต้น 2 คู่ (m > 4) หรือ 1 คู่ (m ≤ 4) เมื่อมีอย่างน้อย 2 รอบ ไม่เช่นนั้น 0 · ผู้ใช้กำหนดได้ · t นับจากช่วงแรกของอนุกรมseasonal period and number of Fourier pairs: default 2 pairs (m > 4) or 1 pair (m ≤ 4) with at least two cycles, otherwise 0; user-settable; t counts from the first period of the series
- c, V̂
- เวกเตอร์คอนทราสต์ของผลรวมพจน์ และเมทริกซ์ความแปรปรวนร่วม (Newey-West หรือ Prais-Winsten) · CI = ค่าประมาณ ± 1.96 SEcontrast vector for a combination of terms, and the covariance matrix (Newey-West or Prais-Winsten); CI = estimate ± 1.96 SE
DAPH ประมาณด้วย OLS และใช้ค่าคลาดเคลื่อนมาตรฐานแบบ Newey-West (ไม่ปรับ df) ที่ bandwidth L = round(4(n/100)2/9) โดย n คือจำนวนช่วงทั้งหมด (35 ช่วงได้ L = 3; ผู้ใช้กำหนดเองได้ในช่อง "แบนด์วิดท์ HAC") · ค่า p และ 95% CI ใช้การแจกแจงปกติ · รายงานผลเฉลี่ยหลังแทรกแซงเป็นร้อยละ = ค่าเฉลี่ยของ (ค่าที่ fit − เส้นสมมติ) ÷ ค่าเฉลี่ยของเส้นสมมติ ในช่วงหลัง · ตรวจส่วนเหลือด้วย Durbin-Watson และ Ljung-Box ที่ lag = min(12, n/4) · ทดสอบร่วมแต่ละคู่ sin/cos ด้วย Wald (χ² df 2 และรูป F) บนเมทริกซ์ความแปรปรวนร่วมเดียวกัน · ตารางเตือนเมื่อด้านใดมีน้อยกว่า 8 ช่วง
DAPH fits OLS with Newey-West standard errors (no df adjustment) at bandwidth L = round(4(n/100)2/9), n being all periods (35 periods give L = 3; users can set it in "HAC bandwidth"). p-values and 95% CIs use the normal distribution. The mean post-interruption effect as a percentage = mean(fitted − counterfactual) ÷ mean(counterfactual) over the post periods. Residuals are checked with Durbin-Watson and Ljung-Box at lag min(12, n/4). Each sin/cos pair is tested jointly by Wald (χ² with 2 df and an F form) on the same covariance matrix. A warning appears when either side has fewer than 8 periods.
Prais-Winsten (ช่อง "ค่าคลาดเคลื่อนมาตรฐาน"): ประมาณสัมประสิทธิ์ใหม่ภายใต้ส่วนเหลือ AR(1) โดยวนประมาณ ρ จนนิ่ง มีประสิทธิภาพกว่าเมื่อ AR(1) เป็นจริง ส่วน Newey-West คงสัมประสิทธิ์ OLS และแก้เฉพาะ SE จึงทนทานกว่า · DAPH รายงาน ρ และ Durbin-Watson กับ Ljung-Box ของส่วนเหลือหลังแปลง (ut) ซึ่งควรเป็นสัญญาณรบกวนขาวถ้า AR(1) เพียงพอ
Prais-Winsten ("Standard errors" field): re-estimates the coefficients under AR(1) errors, iterating ρ to convergence; more efficient when AR(1) holds, whereas Newey-West keeps the OLS coefficients and corrects only the SE, so it is more robust. DAPH reports ρ and the Durbin-Watson and Ljung-Box statistics of the transformed residuals (ut), which should look like white noise if AR(1) is adequate.
ลักษณะมาตรการ (ช่อง "ลักษณะมาตรการ" ตาม Bernal et al. 2017): จุดเดียว (ค่าเริ่มต้น) คือสมการข้างต้น · ค่อย ๆ เริ่ม: ช่วง t0 ถึงช่อง "ถึง" เป็นช่วงเปลี่ยนผ่าน ถูกตัดออกจากการประมาณค่า และ Dt กับพจน์ความชันนับจากช่วงแรกหลังช่วงเปลี่ยนผ่าน (t1) ส่วนพจน์เวลาและฤดูกาลยังใช้ตำแหน่งเดิม · ชั่วคราว: มาตรการมีผลตั้งแต่ t0 ถึง "ถึง" แล้วสิ้นสุด เพิ่มจุดเปลี่ยนที่สอง t1: yt = β0 + β1t + β2Dt + β3(t − t0 + 1)Dt + β4Et + β5(t − t1 + 1)Et + ฤดูกาล + εt โดย Et = 1 ตั้งแต่ t1 · ความชันระหว่างมีมาตรการ = β1 + β3 · ความชันหลังสิ้นสุด = β1 + β3 + β5 · การเปลี่ยนความชันสุทธิ = β3 + β5 · ระดับ ณ ช่วงแรกหลังสิ้นสุดเทียบแนวโน้มเดิม = β2 + β3(t1 − t0 + 1) + β4 + β5 · ทุกส่วนต้องมีอย่างน้อย 3 ช่วง · วันที่เต็ม (เช่น 2023-07-15) หมายถึงช่วงที่ครอบวันนั้น
Intervention type ("Intervention type" field, after Bernal et al. 2017): single point (default) is the equation above. Gradual start: the periods from t0 to the "to" period are a transition, excluded from the fit; Dt and the slope term count from the first period after the transition (t1), while the time and seasonal terms keep their positions. Temporary: the intervention applies from t0 to "to" and then stops, adding a second change point t1: yt = β0 + β1t + β2Dt + β3(t − t0 + 1)Dt + β4Et + β5(t − t1 + 1)Et + seasonal terms + εt, with Et = 1 from t1; slope during the intervention = β1 + β3; slope after it ended = β1 + β3 + β5; net slope change = β3 + β5; level in the first period after the end versus the old trend = β2 + β3(t1 − t0 + 1) + β4 + β5. Every segment needs at least 3 periods; a full date (e.g. 2023-07-15) means the period containing it.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
suppressMessages({library(sandwich); library(lmtest); library(prais)})
# deaths per month (status = 1, by the month of end_date), 2022-02 to 2024-12
m_end <- format(seq(as.Date("2022-02-01"), as.Date("2024-12-01"), by = "month"), "%Y-%m")
its <- data.frame(y = as.numeric(table(factor(substr(d$end_date[d$status == 1], 1, 7), levels = m_end))))
n <- nrow(its); its$time <- 1:n
pos <- which(m_end == "2023-07") - 1 # 17 months before recruitment closed
its$level <- as.numeric(its$time > pos) # D_t: 1 from 2023-07
its$slope <- ifelse(its$level == 1, its$time - pos, 0) # months since the interruption: 1, 2, ...
for (k in 1:2) { its[[paste0("sin", k)]] <- sin(2 * pi * k * its$time / 12) # 2 Fourier pairs (n >= 24)
its[[paste0("cos", k)]] <- cos(2 * pi * k * its$time / 12) }
m <- lm(y ~ time + level + slope + sin1 + cos1 + sin2 + cos2, data = its)
L <- round(4 * (n / 100)^(2 / 9)); L # Newey-West bandwidth (rounded) = 3
V <- NeweyWest(m, lag = L, prewhite = FALSE, adjust = FALSE)
coeftest(m, vcov. = V, df = Inf) # z tests, as DAPH reports
round(coefci(m, vcov. = V, df = Inf), 4)
ctr <- function(cv) { e <- sum(cv * coef(m)); s <- sqrt(drop(t(cv) %*% V %*% cv)); round(c(est = e, lo = e - 1.96 * s, hi = e + 1.96 * s), 4) }
ctr(c(0, 1, 0, 1, 0, 0, 0, 0)) # slope after the interruption: b1 + b3
ctr(c(0, 0, 1, n - pos, 0, 0, 0, 0)) # effect at 2024-12: b2 + b3 * 18
ctr(c(0, 0, 1, 1, 0, 0, 0, 0)) # change in the first post period (2023-07): b2 + b3
cf <- predict(m, transform(its, level = 0, slope = 0)); post <- its$time > pos
round(c(mean_deaths = mean(its$y), mean_effect_pct = 100 * mean(fitted(m)[post] - cf[post]) / mean(cf[post]), R2 = summary(m)$r.squared,
adjR2 = summary(m)$adj.r.squared, DW = dwtest(m)$statistic[[1]]), 4)
Box.test(resid(m), lag = min(12, n %/% 4), type = "Ljung-Box")
w <- function(i) { b <- coef(m)[i]; drop(t(b) %*% solve(V[i, i]) %*% b) } # joint Wald test of a sin/cos pair
round(c(pair1_chi2 = w(5:6), p1 = pchisq(w(5:6), 2, lower.tail = FALSE), pair2_chi2 = w(7:8), p2 = pchisq(w(7:8), 2, lower.tail = FALSE)), 4)
# Option: Prais-Winsten (AR(1) errors, iterated to convergence)
pw <- prais_winsten(y ~ time + level + slope + sin1 + cos1 + sin2 + cos2, data = its, index = "time")
round(tail(pw$rho, 1), 4); round(summary(pw)$coefficients[c("level", "slope"), 1:2], 4)
X <- model.matrix(m); e_orig <- its$y - drop(X %*% coef(pw)) # residuals on the original scale
r <- as.numeric(tail(pw$rho, 1)); e_tr <- c(sqrt(1 - r^2) * e_orig[1], e_orig[-1] - r * e_orig[-n]) # transformed residuals
dw <- function(e) sum(diff(e)^2) / sum(e^2)
round(c(DW_original = dw(e_orig), DW_transformed = dw(e_tr)), 4)
Box.test(e_tr, lag = min(12, n %/% 4), type = "Ljung-Box") # Ljung-Box of the transformed residuals
[1] 3
z test of coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 3.350640 0.695490 4.8177 1.452e-06 ***
time 0.441848 0.092952 4.7535 1.999e-06 ***
level -0.092184 2.532801 -0.0364 0.9710
slope -0.957423 0.195578 -4.8954 9.812e-07 ***
sin1 -0.122077 0.453189 -0.2694 0.7876
cos1 0.150125 0.793287 0.1892 0.8499
sin2 -1.122324 0.556711 -2.0160 0.0438 *
cos2 1.108072 0.725786 1.5267 0.1268
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
2.5 % 97.5 %
(Intercept) 1.9875 4.7138
time 0.2597 0.6240
level -5.0564 4.8720
slope -1.3407 -0.5741
sin1 -1.0103 0.7662
cos1 -1.4047 1.7049
sin2 -2.2135 -0.0312
cos2 -0.3144 2.5306
est lo hi
-0.5156 -0.8953 -0.1359
est lo hi
-17.3258 -23.4219 -11.2297
est lo hi
-1.0496 -5.8289 3.7297
mean_deaths mean_effect_pct R2 adjR2 DW
6.5429 -60.9402 0.4697 0.3322 2.1422
Box-Ljung test
data: resid(m)
X-squared = 4.8691, df = 8, p-value = 0.7715
pair1_chi2 p1 pair2_chi2 p2
0.1227 0.9405 4.7564 0.0927
Iteration 0: rho = 0
Iteration 1: rho = -0.3317
Iteration 2: rho = -0.4009
Iteration 3: rho = -0.4088
Iteration 4: rho = -0.4097
Iteration 5: rho = -0.4098
Iteration 6: rho = -0.4098
Iteration 7: rho = -0.4098
rho
7 -0.4098
Estimate Std. Error
level -0.8683 1.6953
slope -1.0148 0.1586
DW_original DW_transformed
2.1767 1.6165
Box-Ljung test
data: e_tr
X-squared = 1.3141, df = 8, p-value = 0.9954
| Quantity | R (sandwich, lmtest, prais) | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| Interruption position / periods before / after / NW bandwidth / Fourier pairs | 18 / 17 / 18 / 3 / 2 | 18 / 17 / 18 / 3 / 2 | 0 | ✓ PASS |
| Pre-interruption slope β1 (SE) | 0.4418 (0.0930) | 0.4418 (0.093) | 0 | ✓ PASS |
| Level change β2 (SE) [95% CI] p | −0.0922 (2.5328) [−5.0564, 4.8720] 0.9710 | −0.0922 (2.5328) [−5.0564, 4.872] 0.970967 | 0 | ✓ PASS |
| Slope change β3 (SE) [95% CI] | −0.9574 (0.1956) [−1.3407, −0.5741] | −0.9574 (0.1956) [−1.3407, −0.5741] | 0 | ✓ PASS |
| Post slope β1 + β3 [95% CI] | −0.5156 [−0.8953, −0.1359] | −0.5156 [−0.8953, −0.1359] | 0 | ✓ PASS |
| Change in the first post period β2 + β3 | −1.0496 | −1.050 (summary sentence) | < 0.001 | ✓ PASS |
| Effect at 2024-12 [95% CI] / mean effect % | −17.3258 [−23.4219, −11.2297] / −60.9402 | −17.3258 [−23.4219, −11.2297] / −60.94 | 0 | ✓ PASS |
| R² / adjusted R² / Durbin-Watson | 0.4697 / 0.3322 / 2.1422 | 0.4697 / 0.3322 / 2.1422 | 0 | ✓ PASS |
| Ljung-Box Q(8) / p | 4.8691 / 0.7715 | 4.8691 / 0.771471 | 0 | ✓ PASS |
| Fourier pair 1 / pair 2: Wald χ² (p) | 0.1227 (0.9405) / 4.7564 (0.0927) | 0.1227 (0.940496) / 4.7564 (0.092719) | 0 | ✓ PASS |
| Prais-Winsten ρ / level change (SE) / slope change (SE) | −0.4098 / −0.8683 (1.6953) / −1.0148 (0.1586) | −0.410 / −0.8683 (1.6953) / −1.0148 (0.1586) | < 0.0005 | ✓ PASS |
| Prais-Winsten: Durbin-Watson / Ljung-Box Q(8) of the transformed residuals | 1.6165 / 1.3141 | 1.6165 / 1.3141 | 0 | ✓ PASS |
ทุกค่าของ Newey-West และ Prais-Winsten ตรงกับ R ถึงทศนิยมที่แสดง (R ต้องใช้ df = Inf ใน coeftest/coefci เพราะ DAPH ใช้การแจกแจงปกติ) · ในโหมด Prais-Winsten ค่า Durbin-Watson (1.6165) และ Ljung-Box (p = 0.9954) มาจากส่วนเหลือหลังแปลง · ลักษณะมาตรการแบบค่อย ๆ เริ่มและชั่วคราวใช้สมการและเวกเตอร์คอนทราสต์ตามหัวข้อ 2 แต่ข้อมูลตัวอย่างไม่มีมาตรการที่เป็นช่วงจริง จึงไม่ได้ยกตัวอย่างเชิงตัวเลข
Every Newey-West and Prais-Winsten value agrees with R to the printed decimals (R needs df = Inf in coeftest/coefci because DAPH uses the normal distribution). In the Prais-Winsten mode the Durbin-Watson (1.6165) and Ljung-Box (p = 0.9954) come from the transformed residuals. The gradual-start and temporary types use the equations and contrast vectors of section 2, but the example data contain no genuine time-limited intervention, so no numerical example is given for them.
4การแปลผลและตัวอย่างInterpretation and Example
เกณฑ์อ่านผล: รายงานทั้งการเปลี่ยนระดับและการเปลี่ยนความชันพร้อม 95% CI · ความชันหลังแทรกแซง (β1 + β3) บอกว่าหลังมาตรการอนุกรมยังเพิ่มหรือลด · ผลปลายอนุกรมและผลเฉลี่ยเป็นร้อยละเทียบเส้นสมมติ ตอบว่า "ถึงวันนี้ต่างจากที่ควรจะเป็นเท่าใด" แต่ขึ้นกับการลากแนวโน้มเดิมต่อ ยิ่งไกลยิ่งไม่แน่นอน · Durbin-Watson ใกล้ 2 และ Ljung-Box ไม่มีนัยสำคัญ = ไม่เหลือสหสัมพันธ์ในส่วนเหลือ · แถว sin/cos เป็นพจน์ฤดูกาลที่ระบบใส่เอง อ่านเป็นคู่ (ขนาด = √(a² + b²)) ไม่ตีความทีละตัว · "ไม่มีนัยสำคัญ" ไม่ได้แปลว่า "ไม่มีผล"
Reading criteria: report both the level change and the slope change with 95% CI; the post slope (β1 + β3) says whether the series still rises or falls after the interruption; the end-of-series effect and the mean percentage versus the counterfactual answer "how different is it now from what it would have been", but depend on extending the old trend and grow less certain with distance. Durbin-Watson near 2 and a non-significant Ljung-Box = no residual autocorrelation left. The sin/cos rows are seasonal terms the model adds; read each pair together (size = √(a² + b²)), not one by one. "Not significant" does not mean "no effect".
ตัวอย่างนี้: พจน์การเปลี่ยนระดับใกล้ศูนย์ (−0.09 ราย, CI กว้าง −5.06 ถึง 4.87) และการเปลี่ยนที่แบบจำลองให้ในเดือนแรกหลังปิดรับ β2 + β3 = −1.05 ราย (95% CI −5.83 ถึง 3.73) มาจากความชันเป็นหลัก ส่วนความชันเปลี่ยนชัดเจน จากเพิ่มเดือนละ 0.44 ราย เป็นลดเดือนละ 0.52 ราย · กลไกคือขนาดกลุ่มที่ติดตามหยุดโต และผู้ป่วยที่เหลือผ่านช่วงเสี่ยงสูงในเดือนแรก ๆ ไปแล้ว ไม่ใช่ผลของมาตรการใด ๆ · "ต่ำกว่าเส้นสมมติ 60.9%" เทียบกับเส้นที่สมมติว่าการเสียชีวิตยังเพิ่มเดือนละ 0.44 รายไปอีก 18 เดือน ซึ่งเป็นไปไม่ได้เมื่อไม่มีผู้ป่วยใหม่ — ตัวอย่างที่ดีว่าต้องถามเสมอว่าเส้นสมมติสมเหตุสมผลหรือไม่ · คู่ฤดูกาลไม่มีนัยสำคัญ (p = 0.9405 และ 0.0927) สอดคล้องกับ 11.2 · จำนวนนับน้อย (เฉลี่ย 6.5 ต่อเดือน) และเดือน 2024-12 ที่มีการบันทึกเสียชีวิต ณ วันปิดการศึกษา ทำให้ควรวิเคราะห์ความไว เช่น ตัดเดือนสุดท้าย หรือเลื่อนจุดแทรกแซง ±1–2 เดือน · Prais-Winsten ให้ข้อสรุปเดียวกัน (การเปลี่ยนความชัน −1.01)
This example: the level-change term was close to zero (−0.09 deaths; CI −5.06 to 4.87), and the modelled change in the first month after closure, β2 + β3 = −1.05 deaths (95% CI −5.83 to 3.73), comes mostly from the slope; the slope changed clearly, from rising by 0.44 a month to falling by 0.52 a month. The mechanism is that the cohort stopped growing and the remaining patients had passed their high-risk first months; it is not the effect of any intervention. "60.9% below the counterfactual" compares with a line in which deaths keep rising by 0.44 a month for another 18 months, which cannot happen without new patients — a reminder always to ask whether the counterfactual is plausible. The seasonal pairs are not significant (p = 0.9405 and 0.0927), in line with 11.2. Small counts (6.5 a month on average) and the deaths recorded on the closing date in 2024-12 call for sensitivity analyses, for example dropping the last month or moving the interruption by ±1–2 months. Prais-Winsten gives the same conclusion (slope change −1.01).
ตัวอย่างประโยครายงาน: "หลังปิดรับผู้ป่วยใหม่ (ก.ค. 2566) พจน์การเปลี่ยนระดับของจำนวนผู้เสียชีวิตต่อเดือนเท่ากับ −0.09 ราย (95% CI −5.06 ถึง 4.87) และความชันลดลง 0.96 รายต่อเดือน (95% CI −1.34 ถึง −0.57, p < 0.001) จากแนวโน้มเพิ่ม 0.44 รายต่อเดือนก่อนปิดรับ เป็นลดลง 0.52 รายต่อเดือน (segmented regression, Newey-West SE)"
Example results sentence: "After recruitment closed (July 2023), the level-change term for monthly deaths was −0.09 (95% CI −5.06 to 4.87) and the slope fell by 0.96 deaths per month (95% CI −1.34 to −0.57, p < 0.001), from a rise of 0.44 to a fall of 0.52 deaths per month (segmented regression with Newey-West SE)."
เมื่อใดควรใช้และข้อจำกัด: ใช้ประเมินมาตรการที่มีวันเริ่มชัดเจนเมื่อไม่มีกลุ่มควบคุม · ข้อสมมติ: แนวโน้มก่อนมาตรการ (หลังปรับฤดูกาล) เป็นเส้นตรงและจะดำเนินต่อหากไม่มีมาตรการ ไม่มีเหตุการณ์อื่นเกิดพร้อมกัน · อย่างน้อย 3 ช่วงต่อด้าน (เกณฑ์ขั้นต่ำของ Cochrane EPOC ตามที่ Jandoc et al. 2015 สรุปไว้) และ DAPH เตือนเมื่อต่ำกว่า 8 · ผลลัพธ์เป็นจำนวนนับน้อยหรือมีศูนย์มากควรใช้แบบจำลอง Poisson/negative binomial (ยังไม่มีใน DAPH) · Newey-West แก้สหสัมพันธ์แต่ไม่แก้ความไม่เป็นเชิงเส้น · ควรวิเคราะห์ความไวโดยเลื่อนจุดแทรกแซง ±1–2 ช่วง
When to use and limits: evaluates an intervention with a clear start date when no control group exists. Assumptions: the pre-intervention trend (after seasonal adjustment) is linear and would have continued without the intervention, and no other event coincides with it. At least 3 periods per side (the Cochrane EPOC minimum as summarised by Jandoc et al. 2015); DAPH warns below 8. Low counts or many zeros call for a Poisson/negative binomial model (not yet in DAPH). Newey-West corrects autocorrelation, not non-linearity. Run a sensitivity analysis shifting the interruption by ±1–2 periods.
รายการตรวจสอบก่อนตีพิมพ์ (Jandoc et al. 2015): วันที่แทรกแซงและเหตุผล · จำนวนช่วงก่อน/หลัง · สมการ (เวลา ระดับ ความชันนับจากจุดแทรกแซง พจน์ฤดูกาล) · วิธี SE (Newey-West bandwidth หรือ Prais-Winsten ρ) · ตาราง: การเปลี่ยนระดับ การเปลี่ยนความชัน ความชันหลังแทรกแซง ผล ณ ปลายอนุกรม พร้อม 95% CI · Durbin-Watson และ Ljung-Box · กราฟก่อน/หลังพร้อมเส้นสมมติและแถบ CI (Turner et al. 2021) · เหตุการณ์อื่นใกล้จุดแทรกแซง · การวิเคราะห์ความไว · แนวทาง STROBE (von Elm et al. 2007) หรือ RECORD (Benchimol et al. 2015)
Pre-submission checklist (Jandoc et al. 2015): interruption date and rationale; periods before and after; the equation (time, level, slope since the interruption, seasonal terms); SE method (Newey-West bandwidth or Prais-Winsten ρ); a table of level change, slope change, post slope and end-of-series effect with 95% CI; Durbin-Watson and Ljung-Box; the figure with the counterfactual line and CI bands (Turner et al. 2021); co-occurring events; sensitivity analyses; STROBE (von Elm et al. 2007) or RECORD (Benchimol et al. 2015).
📖 References
- Bernal, J. L., Cummins, S., & Gasparrini, A. (2017). Interrupted time series regression for the evaluation of public health interventions: A tutorial. International Journal of Epidemiology, 46(1), 348–355. doi:10.1093/ije/dyw098
- Xiao, H., Augusto, O., & Wagenaar, B. H. (2021). Reflection on modern methods: A common error in the segmented regression parameterization of interrupted time-series analyses. International Journal of Epidemiology, 50(3), 1011–1015. doi:10.1093/ije/dyaa148
- Newey, W. K., & West, K. D. (1987). A simple, positive semi-definite, heteroskedasticity and autocorrelation consistent covariance matrix. Econometrica, 55(3), 703–708. doi:10.2307/1913610
- Newey, W. K., & West, K. D. (1994). Automatic lag selection in covariance matrix estimation. Review of Economic Studies, 61(4), 631–653. doi:10.2307/2297912
- Turner, S. L., Karahalios, A., Forbes, A. B., Taljaard, M., Grimshaw, J. M., Korevaar, E., Cheng, A. C., Bero, L., & McKenzie, J. E. (2021). Creating effective interrupted time series graphs: Review and recommendations. Research Synthesis Methods, 12(1), 106–117. doi:10.1002/jrsm.1435
- Jandoc, R., Burden, A. M., Mamdani, M., Lévesque, L. E., & Cadarette, S. M. (2015). Interrupted time series analysis in drug utilization research is increasing: Systematic review and recommendations. Journal of Clinical Epidemiology, 68(8), 950–956. doi:10.1016/j.jclinepi.2014.12.018
- von Elm, E., Altman, D. G., Egger, M., Pocock, S. J., Gøtzsche, P. C., & Vandenbroucke, J. P. (2007). The Strengthening the Reporting of Observational Studies in Epidemiology (STROBE) statement: Guidelines for reporting observational studies. The Lancet, 370(9596), 1453–1457. doi:10.1016/S0140-6736(07)61602-X
- Benchimol, E. I., Smeeth, L., Guttmann, A., Harron, K., Moher, D., Petersen, I., Sørensen, H. T., von Elm, E., & Langan, S. M. (2015). The REporting of studies Conducted using Observational Routinely-collected health Data (RECORD) statement. PLoS Medicine, 12(10), e1001885. doi:10.1371/journal.pmed.1001885
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
11.7Time-Series Regression (Distributed lags · AR terms · Newey-West / Prais-Winsten / ARIMA errors)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
คำถามที่พบบ่อยในระบาดวิทยาสิ่งแวดล้อมและการเฝ้าระวังคือ "ปัจจัย X ส่งผลต่อผลลัพธ์ Y ตามเวลาอย่างไร" เช่น PM2.5 วันนี้กับผู้ป่วยหอบหืดในอีก 1–7 วัน · การถดถอยธรรมดาบนอนุกรมเวลาให้ค่า p เล็กเกินจริงเพราะส่วนเหลือมีสหสัมพันธ์ในตัวเอง และมองไม่เห็นผลที่ล่าช้า · Time-Series Regression ของ DAPH รวมแบบแผนที่วรรณกรรมใช้ไว้ในสถิติเดียว: distributed lag model (ตัวทำนายที่ lag 0..L พร้อมผลสะสม), พจน์ AR (ค่าอดีตของผลลัพธ์เป็นพจน์ — dynamic regression), และสามวิธีจัดการส่วนเหลือ: Newey-West (heteroskedasticity and autocorrelation consistent, HAC), Prais-Winsten (feasible generalized least squares, FGLS, สำหรับ AR(1)) และ regression with ARIMA errors · ใช้เมื่อมีตัวทำนายที่เป็นอนุกรมความถี่เดียวกันอย่างน้อย 1 ตัว · การพยากรณ์อยู่ใน 11.4 และการประเมินมาตรการอยู่ใน 11.6
A common question in environmental epidemiology and surveillance is "how does factor X move outcome Y over time", such as PM2.5 today and asthma visits over the next 1–7 days. Ordinary regression on a time series gives p-values that are too small, because the residuals are autocorrelated, and cannot see delayed effects. DAPH's Time-Series Regression brings the designs the literature uses into one statistic: a distributed lag model (predictors at lags 0..L with a cumulative effect), AR terms (past values of the outcome as terms — dynamic regression), and three ways to handle the residuals: Newey-West (heteroskedasticity and autocorrelation consistent, HAC), Prais-Winsten (feasible generalized least squares, FGLS, for AR(1)) and regression with ARIMA errors. Use it with at least one predictor series of the same frequency. Forecasting lives in 11.4 and intervention evaluation in 11.6.
2หลักการและสูตรLogic and Formula
- Lj, p
- lag สูงสุดของตัวทำนาย j และจำนวนพจน์ AR ของผลลัพธ์ (ไม่เกิน n/4) · ตัด max(L, p) ช่วงแรกออกmaximum lag of predictor j and number of AR terms of the outcome (at most n/4); the first max(L, p) periods are dropped
- K, m
- จำนวนคู่ Fourier (อัตโนมัติด้วย AICc เมื่อมีอย่างน้อย 2 รอบ หรือผู้ใช้กำหนด) และคาบฤดูกาล · t นับจากช่วงแรกของอนุกรมnumber of Fourier pairs (automatic by AICc with at least two cycles, or user-set) and seasonal period; t counts from the first period of the series
- c, V̂
- เวกเตอร์ที่เป็น 1 ที่สัมประสิทธิ์ lag ของตัวทำนาย j และเมทริกซ์ความแปรปรวนร่วมของวิธีที่เลือก · p และ CI ใช้การแจกแจงปกติvector with 1 at predictor j's lag coefficients, and the covariance matrix of the chosen method; p-values and CIs use the normal distribution
สามวิธีจัดการส่วนเหลือตอบคำถามต่างกัน: Newey-West คงสัมประสิทธิ์ OLS แล้วแก้เฉพาะ SE จึงทนทานที่สุด · Prais-Winsten ประมาณสัมประสิทธิ์ใหม่ภายใต้ AR(1) มีประสิทธิภาพกว่าเมื่อ AR(1) เป็นจริง (Durbin-Watson และ Ljung-Box คำนวณจากส่วนเหลือหลังแปลง) · ARIMA errors ทั่วไปที่สุดเมื่อโครงสร้างส่วนเหลือซับซ้อนกว่า AR(1) (เมื่อ d = 1 ไม่มีค่าคงที่ และสัมประสิทธิ์ของแนวโน้มทำหน้าที่เป็น drift) · Ljung-Box ใช้ lag = max(df + 1, min(12, nused/4)) โดยหัก df เท่ากับจำนวนพจน์ AR (และ p + q ของ ARIMA errors) และเพิ่ม lag ตามฤดูกาลเมื่อมีอย่างน้อย 4 รอบ · DAPH ตรวจความคงที่ของผลลัพธ์และตัวทำนายทุกตัวด้วย ADF (ค่าคงที่ + แนวโน้ม, lag = ⌊(n−1)1/3⌋) และ KPSS (รอบแนวโน้ม) เมื่อมีพจน์แนวโน้ม (ไม่มีพจน์แนวโน้ม: สเปครอบระดับ) แล้วเตือนเรื่องการถดถอยลวง (spurious regression) เมื่อพบสัญญาณ unit root — ไม่หาผลต่างให้อัตโนมัติ
The three ways of handling the residuals answer different questions: Newey-West keeps the OLS coefficients and corrects only the SE, so it is the most robust; Prais-Winsten re-estimates the coefficients under AR(1) and is more efficient when AR(1) holds (its Durbin-Watson and Ljung-Box use the transformed residuals); ARIMA errors is the most general when the residual structure is richer than AR(1) (with d = 1 there is no constant and the trend coefficient acts as a drift). Ljung-Box uses lag = max(df + 1, min(12, nused/4)), removing df equal to the number of AR terms (plus p + q of the ARIMA errors), and adds the seasonal lag with at least four cycles. DAPH checks the stationarity of the outcome and every predictor with ADF (constant + trend, lag = ⌊(n−1)1/3⌋) and KPSS (around a trend) when the model has a trend (around a level when it has none), and warns about spurious regression when a unit root is signalled — it never differences a series automatically.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
suppressMessages({library(sandwich); library(lmtest); library(prais); library(forecast); library(urca)})
# Monthly table as in 11.5 (open pd_monthly.csv in DAPH)
months <- format(seq(as.Date("2022-01-01"), as.Date("2024-12-01"), by = "month"), "%Y-%m")
pd <- data.frame(month = paste0(months, "-01"),
new_patients = as.numeric(table(factor(substr(d$enroll_date, 1, 7), levels = months))),
deaths = as.numeric(table(factor(substr(d$end_date[d$status == 1], 1, 7), levels = months))))
write.csv(pd, "pd_monthly.csv", row.names = FALSE)
# Check from the patient records: share of all 1,300 patients who died 0-3 calendar months after enrolment
dd <- d[d$status == 1, ]
gap <- (as.numeric(substr(dd$end_date, 1, 4)) - as.numeric(substr(dd$enroll_date, 1, 4))) * 12 +
as.numeric(substr(dd$end_date, 6, 7)) - as.numeric(substr(dd$enroll_date, 6, 7))
round(sum(gap <= 3) / nrow(d), 4)
# Distributed lags 0-3 of new patients + linear trend; the first 3 months are dropped (no lag 3 yet)
n <- 36; lagx <- function(l) c(rep(NA, l), pd$new_patients[1:(n - l)])
dl <- data.frame(y = pd$deaths, trend = 1:n, x0 = lagx(0), x1 = lagx(1), x2 = lagx(2), x3 = lagx(3))
for (k in 1:3) { dl[[paste0("s", k)]] <- sin(2 * pi * k * (1:n) / 12); dl[[paste0("c", k)]] <- cos(2 * pi * k * (1:n) / 12) }
dl <- dl[-(1:3), ]; nu <- nrow(dl); nu
# Number of Fourier pairs K = 0-3 chosen by AICc on the same sample (sigma^2 counted as a parameter)
base <- "y ~ trend + x0 + x1 + x2 + x3"
aicc <- sapply(0:3, function(K) { f <- if (K == 0) base else paste(base, "+", paste0(c("s", "c"), rep(1:K, each = 2), collapse = " + "))
m <- lm(as.formula(f), data = dl); p <- length(coef(m)) + 1; AIC(m) + 2 * p * (p + 1) / (nu - p - 1) })
round(setNames(aicc, paste0("K", 0:3)), 4) # K = 0 has the smallest AICc
m <- lm(as.formula(base), data = dl)
L <- round(4 * (nu / 100)^(2 / 9)); V <- NeweyWest(m, lag = L, prewhite = FALSE, adjust = FALSE); L
coeftest(m, vcov. = V, df = Inf) # Newey-West, z tests as in DAPH
cum <- function(b, V, i = 3:6) { e <- sum(b[i]); s <- sqrt(sum(V[i, i])); round(c(cum = e, se = s, lo = e - 1.96 * s, hi = e + 1.96 * s, p = 2 * pnorm(-abs(e / s))), 4) }
cum(coef(m), V) # cumulative effect over lags 0-3
round(c(R2 = summary(m)$r.squared, adjR2 = summary(m)$adj.r.squared, DW = dwtest(m)$statistic[[1]]), 4)
Box.test(resid(m), lag = 8, type = "Ljung-Box")
# Stationarity table (36 months; trend specification because the model has a trend):
# ADF with constant + trend and floor((n - 1)^(1/3)) = 3 lags; KPSS around a trend, bandwidth 3
st <- sapply(pd[, c("deaths", "new_patients")], function(v) c(
ADF = suppressWarnings(tseries::adf.test(v, k = 3))$statistic[[1]], KPSS = urca::ur.kpss(v, type = "tau", use.lag = 3)@teststat))
round(st, 4)
# Option 1: Prais-Winsten AR(1) FGLS
pw <- prais_winsten(as.formula(base), data = transform(dl, t = trend), index = "t")
r <- as.numeric(tail(pw$rho, 1)); bp <- coef(pw); round(c(rho = r, bp), 4)
X <- model.matrix(m); e <- dl$y - drop(X %*% bp); u <- c(sqrt(1 - r^2) * e[1], e[-1] - r * e[-nu])
Xs <- rbind(sqrt(1 - r^2) * X[1, ], X[-1, ] - r * X[-nu, ]) # transformed design matrix
Vp <- sum(u^2) / (nu - ncol(X)) * solve(crossprod(Xs)); cum(bp, Vp) # OLS covariance on transformed data
round(c(R2 = 1 - sum(e^2) / sum((dl$y - mean(dl$y))^2), DW_transformed = sum(diff(u)^2) / sum(u^2)), 4)
# Option 2: regression with ARIMA errors; d from ADF on the outcome, (p, q) by AICc with n = 33
kmax <- min(ceiling(12 * (nu / 100)^(1 / 4)), nu %/% 2 - 2); dy <- diff(dl$y); tt <- (kmax + 2):nu
aic <- sapply(0:kmax, function(k) { Z <- matrix(dl$y[tt - 1]); for (j in seq_len(k)) Z <- cbind(Z, dy[tt - 1 - j]); AIC(lm(dy[tt - 1] ~ Z)) })
adf <- ur.df(dl$y, type = "drift", lags = which.min(aic) - 1)
round(punitroot(adf@teststat[1], N = Inf, trend = "c", statistic = "t"), 4) # p > 0.05, so d = 1
xr <- as.matrix(dl[, c("trend", "x0", "x1", "x2", "x3")])
g <- expand.grid(p = 0:2, q = 0:2)
g$aicc <- apply(g, 1, function(v) { f <- tryCatch(Arima(dl$y, order = c(v[1], 1, v[2]), xreg = xr, method = "ML"), error = function(e) NULL)
if (is.null(f)) NA else { k <- length(coef(f)) + 1; f$aic + 2 * k * (k + 1) / (nu - k - 1) } })
g[which.min(g$aicc), ]
fa <- Arima(dl$y, order = c(0, 1, 1), xreg = xr, method = "ML"); round(coef(fa), 4)
cum(coef(fa), vcov(fa), 3:6)
ea <- residuals(fa)[-1]; round(c(DW = sum(diff(ea)^2) / sum(ea^2)), 4)
Box.test(ea, lag = 8, type = "Ljung-Box", fitdf = 1)
# Option 3: one AR term of the outcome (deaths in the previous month), Newey-West
dl$ylag1 <- c(NA, pd$deaths[1:(n - 1)])[-(1:3)]
ma <- lm(y ~ trend + x0 + x1 + x2 + x3 + ylag1, data = dl)
Va <- NeweyWest(ma, lag = L, prewhite = FALSE, adjust = FALSE); round(coef(ma)["ylag1"], 4); cum(coef(ma), Va)
round(sum(coef(ma)[3:6]) / (1 - coef(ma)[["ylag1"]]), 4) # long-run cumulative effect = sum(b) / (1 - phi)
[1] 0.0592
[1] 33
K0 K1 K2 K3
184.8480 186.4712 193.4626 203.9758
[1] 3
z test of coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 2.361238 5.141156 0.4593 0.64603
trend 0.079498 0.169693 0.4685 0.63944
x0 -0.121715 0.031152 -3.9071 9.341e-05 ***
x1 0.107616 0.026736 4.0251 5.695e-05 ***
x2 0.018979 0.015111 1.2560 0.20912
x3 0.060641 0.029823 2.0334 0.04202 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
cum se lo hi p
0.0655 0.0476 -0.0278 0.1588 0.1687
R2 adjR2 DW
0.4474 0.3451 1.4775
Box-Ljung test
data: resid(m)
X-squared = 1.9172, df = 8, p-value = 0.9834
deaths new_patients
ADF -1.8746 -2.2996
KPSS 0.2029 0.1042
Iteration 0: rho = 0
Iteration 1: rho = 0.1964
Iteration 2: rho = 0.2164
Iteration 3: rho = 0.2189
Iteration 4: rho = 0.2193
Iteration 5: rho = 0.2193
Iteration 6: rho = 0.2193
Iteration 7: rho = 0.2193
rho (Intercept) trend x0 x1 x2
0.2193 2.0414 0.0977 -0.1208 0.1137 0.0236
x3
0.0504
cum se lo hi p
0.0669 0.0445 -0.0203 0.1540 0.1326
R2 DW_transformed
0.4446 1.7800
[1] 0.3539
p q aicc
4 0 1 183.1705
ma1 trend x0 x1 x2 x3
-0.7290 0.0864 -0.1069 0.1152 0.0087 0.0353
cum se lo hi p
0.0523 0.0441 -0.0342 0.1388 0.2359
DW
1.6828
Box-Ljung test
data: ea
X-squared = 1.2941, df = 7, p-value = 0.9886
ylag1
0.2591
cum se lo hi p
0.0567 0.0410 -0.0238 0.1371 0.1673
[1] 0.0765
| Quantity | R | DAPH | |R − DAPH| | Status |
|---|---|---|---|---|
| Periods used / Newey-West bandwidth | 33 / 3 | 33 / 3 | 0 | ✓ PASS |
| AICc for K = 0 / 1 / 2 / 3 (K = 0 chosen) | 184.8480 / 186.4712 / 193.4626 / 203.9758 | 184.848 / 186.4712 / 193.4626 / 203.9758 | 0 | ✓ PASS |
| β lag 0 / 1 / 2 / 3 | −0.1217 / 0.1076 / 0.0190 / 0.0606 | −0.1217 / 0.1076 / 0.019 / 0.0606 | 0 | ✓ PASS |
| Newey-West SE lag 0 / 1 / 2 / 3 | 0.0312 / 0.0267 / 0.0151 / 0.0298 | 0.0312 / 0.0267 / 0.0151 / 0.0298 | 0 | ✓ PASS |
| Cumulative effect (SE) [95% CI] p | 0.0655 (0.0476) [−0.0278, 0.1588] 0.1687 | 0.0655 (0.0476) [−0.0278, 0.1588] 0.168694 | 0 | ✓ PASS |
| R² / adjusted R² / Durbin-Watson / Ljung-Box Q(8), p | 0.4474 / 0.3451 / 1.4775 / 1.9172, 0.9834 | 0.4474 / 0.3451 / 1.4775 / 1.9172, 0.983445 | 0 | ✓ PASS |
| Stationarity: ADF (trend, 3 lags) / KPSS (trend), deaths and new_patients | −1.8746, −2.2996 / 0.2029, 0.1042 | −1.8746, −2.2996 / 0.2029, 0.1042 | 0 | ✓ PASS |
| Prais-Winsten ρ / cumulative (SE) / R² / DW of transformed residuals | 0.2193 / 0.0669 (0.0445) / 0.4446 / 1.7800 | 0.2193 / 0.0669 (0.0445) / 0.4446 / 1.78 | 0 | ✓ PASS |
| ARIMA errors: ADF p (so d = 1) / order / AICc | 0.3539 / (0,1,1) / 183.1705 | d = 1 / (0,1,1) / 183.1705 | 0 | ✓ PASS |
| ARIMA errors: cumulative / SE (tolerance 0.001: numerical Hessian) | 0.0523 / 0.0441 | 0.0523 / 0.0435 | 0 / 0.0006 | ✓ PASS |
| ARIMA errors: Durbin-Watson / Ljung-Box Q(8), df 7 (tolerance 0.01: start-up residuals) | 1.6828 / 1.2941 | 1.6856 / 1.2949 | 0.0028 / 0.0008 | ✓ PASS |
| AR term φ (deaths lag 1) / cumulative (SE) [95% CI] | 0.2591 / 0.0567 (0.0410) [−0.0238, 0.1371] | 0.2591 / 0.0567 (0.041) [−0.0238, 0.1371] | 0 | ✓ PASS |
ทุกค่าตรงกับ R · ส่วนต่างเล็กน้อยของ ARIMA errors มาจากการประมาณ Hessian เชิงตัวเลขและการจัดการส่วนเหลือช่วงเริ่มต้นของสองโปรแกรม · ผลระยะยาวเมื่อมีพจน์ AR (0.0567 / (1 − 0.2591) = 0.0765) DAPH ไม่ได้คำนวณให้ ต้องคำนวณเอง · ความคงที่: DAPH จัดทั้งสองอนุกรมเป็น "ไม่คงที่" เพราะ ADF ไม่ปฏิเสธ (p > 0.10) แม้ KPSS ของ new_patients ไม่ปฏิเสธความคงที่ ตามหลักใน 11.3 กรณีนี้ควรเป็น "ไม่ชัดเจน" จึงควรอ่านคำเตือนนี้อย่างระมัดระวัง
Every value agrees with R. The small ARIMA-errors differences come from the numerical Hessian and the handling of start-up residuals in the two programs. The long-run effect with an AR term (0.0567 / (1 − 0.2591) = 0.0765) is not computed by DAPH; work it out yourself. Stationarity: DAPH labels both series "non-stationary" because ADF does not reject (p > 0.10), although KPSS does not reject stationarity for new_patients; by the rule in 11.3 this case is "inconclusive", so read the warning with that in mind.
4การแปลผลและตัวอย่างInterpretation and Example
เกณฑ์อ่านผล: สัมประสิทธิ์ที่ lag l = การเปลี่ยนของผลลัพธ์ต่อหนึ่งหน่วยของตัวทำนายเมื่อ l ช่วงก่อน โดยคุม lag อื่นและพจน์อื่นคงที่ · ผลสะสมคือคำตอบหลักของ distributed lag model เพราะ lag ที่ติดกันสัมพันธ์กันสูง อย่าอ่านทีละ lag · เมื่อมีพจน์ AR สัมประสิทธิ์ตัวทำนายเป็นผลระยะสั้น ผลระยะยาว = ผลสะสม/(1 − Σφ) · Durbin-Watson ห่างจาก 2 หรือ Ljung-Box มีนัยสำคัญ = ยังมีสหสัมพันธ์ในส่วนเหลือ ให้ลอง Prais-Winsten หรือ ARIMA errors · ตั้ง L จากความรู้ทางชีววิทยา/ระบาดวิทยา (ระยะฟักตัว ช่วงสัมผัส) หรือจาก 11.5 ไม่ใช่ลองจนได้นัยสำคัญ · แถว sin/cos เป็นพจน์ฤดูกาลที่ระบบใส่เอง อ่านเป็นคู่ (ขนาด √(a² + b²)) · การทดสอบร่วมของแต่ละคู่รายงานทั้ง χ² (df 2) และรูป F
Reading criteria: the coefficient at lag l is the change in the outcome per unit of the predictor l periods earlier, holding the other lags and terms constant. The cumulative effect is the main answer of a distributed lag model, because adjacent lags are highly correlated; do not read lags one by one. With AR terms the predictor coefficients are short-run effects; the long-run effect = cumulative/(1 − Σφ). Durbin-Watson far from 2 or a significant Ljung-Box = residual autocorrelation remains; try Prais-Winsten or ARIMA errors. Choose L from biology or epidemiology (incubation, exposure window) or from 11.5, never by searching until something is significant. The sin/cos rows are seasonal terms the model adds; read each pair together (size √(a² + b²)); the joint test of each pair is reported as χ² (2 df) and as an F form.
ตัวอย่างนี้: ผู้ป่วยใหม่ 100 รายสัมพันธ์กับการเสียชีวิตเพิ่มราว 6.6 รายในเดือนที่รับเข้าและ 3 เดือนถัดไป (95% CI −2.8 ถึง 15.9 ราย) ใกล้กับ 5.92% ที่นับได้จากข้อมูลรายบุคคล แต่ข้อมูลรายเดือนเพียง 33 เดือนให้ความแม่นยำต่ำ ผลจึงยังไม่มีนัยสำคัญ ("ไม่มีนัยสำคัญ" ≠ "ไม่มีผล") · สัมประสิทธิ์ lag 0 ที่ติดลบอย่างมีนัยสำคัญเป็นผลของความสัมพันธ์กันระหว่าง lag และกับพจน์แนวโน้ม (ไม่มีผู้ป่วยรายใดเสียชีวิตในเดือนที่รับเข้า) จึงไม่ควรตีความ · ส่วนเหลือไม่เหลือสหสัมพันธ์ (Ljung-Box p = 0.983) และทุกวิธีให้ผลสะสมใกล้กัน (0.0523 ถึง 0.0669) ข้อสรุปจึงไม่ขึ้นกับวิธี · DAPH เตือนว่าอนุกรมอาจไม่คงที่ ในตัวอย่างนี้ผลต่อแนวโน้มส่วนใหญ่มาจากขั้นบันไดของการรับผู้ป่วย การมีพจน์แนวโน้มและการได้ผลใกล้เคียงกับ ARIMA(0,1,1) errors (ซึ่งหาผลต่างแล้ว) ช่วยยืนยันว่าไม่ใช่การถดถอยลวง · ผลลัพธ์เป็นจำนวนนับน้อย แบบจำลอง Poisson ที่มี lag จะเหมาะกว่า (ยังไม่มีใน DAPH) · เป็นความสัมพันธ์ ไม่ใช่ผลเชิงสาเหตุ
This example: 100 new patients go with about 6.6 extra deaths in the month of enrolment and the next 3 months (95% CI −2.8 to 15.9), close to the 5.92% counted from the patient records, but 33 monthly values give low precision, so the result is not significant ("not significant" ≠ "no effect"). The significantly negative lag-0 coefficient reflects the correlation between lags and with the trend term (no patient died in the month of enrolment) and should not be interpreted. No residual autocorrelation remains (Ljung-Box p = 0.983), and every method gives a similar cumulative effect (0.0523 to 0.0669), so the conclusion does not depend on the method. DAPH warns that the series may be non-stationary; here most of the trend comes from the recruitment step, and the trend term plus the similar result under ARIMA(0,1,1) errors (which differences the data) argue against a spurious regression. The outcome is a small count, so a lagged Poisson model would suit it better (not yet in DAPH). These are associations, not causal effects.
ตัวอย่างประโยครายงาน: "ใน distributed lag model ที่ lag 0–3 เดือนพร้อมพจน์แนวโน้ม (Newey-West SE, 33 เดือน) ผู้ป่วยใหม่หนึ่งรายสัมพันธ์กับผู้เสียชีวิตสะสมเพิ่ม 0.0655 ราย (95% CI −0.0278 ถึง 0.1588, p = 0.169)"
Example results sentence: "In a distributed lag model with lags 0–3 months and a linear trend (Newey-West SE, 33 months), each new patient was associated with a cumulative 0.0655 additional deaths (95% CI −0.0278 to 0.1588, p = 0.169)."
ตัวทำนายที่เป็นตัวแปรกลุ่ม (เช่น เพศ ผลตรวจ): ในโหมดคอลัมน์วันที่ เลือกเข้ากล่องตัวทำนายได้ DAPH รวมต่อช่วงเป็นสัดส่วนของระดับ (ค่าเริ่มต้น ระดับแรกของตัวแปร เปลี่ยนได้) หรือจำนวนที่เป็นระดับ หรือจำนวนแถว (แถว "ตัวแปรกลุ่มเป็นตัวทำนาย" ในแผงตั้งค่า) ป้ายระบุสิ่งที่นับ เช่น "Gender (proportion of Female per period)" · สัมประสิทธิ์ของสัดส่วนคือการเปลี่ยนของผลลัพธ์เมื่อสัดส่วนเพิ่มจาก 0 เป็น 1 จึงมักรายงานต่อ 0.1 · ตัวทำนายตัวเลขที่มีหลายแถวต่อช่วงใช้ค่าเฉลี่ยต่อช่วงเป็นค่าเริ่มต้น (เปลี่ยนเป็นผลรวมได้) · ใช้แบบเดียวกันกับอนุกรมอธิบายของ 11.5 และตัวทำนายของ 11.4 · โหมดกำหนดช่วงเวลาเองมีหนึ่งแถวต่อช่วง จึงใช้ตัวแปรกลุ่มเป็นตัวทำนายไม่ได้ (ระบบบล็อกตั้งแต่เลือก)
Categorical predictors (sex, test result): in date-column mode they can go into the predictor box; DAPH aggregates them per period as the proportion of a level (default: the variable's first level, changeable), the count of that level, or the number of rows (row "Categorical predictors" of the settings panel), and the label says what was counted, e.g. "Gender (proportion of Female per period)". The coefficient of a proportion is the change in the outcome when the proportion rises from 0 to 1, so it is usually reported per 0.1. Numeric predictors with several rows per period use the period mean by default (sum is an option). The same applies to the explanatory series of 11.5 and the predictors of 11.4. Define-dates mode has one row per period, so a categorical predictor cannot be used there (blocked at selection).
เมื่อใดควรใช้และข้อจำกัด: ต้องมีตัวทำนายอย่างน้อย 1 ตัวเป็นอนุกรมความถี่เดียวกัน · ช่วงที่ใช้ได้ต้องมากกว่าจำนวนพารามิเตอร์อย่างน้อย 8 (L และ p ที่มากกินข้อมูล) · ผลลัพธ์จำลองบนสเกลเชิงเส้น — จำนวนนับต่ำหรือมีศูนย์มากควรใช้ Poisson/negative binomial ที่มี lag · lag ยาวที่ไม่จำกัดรูปมี SE กว้าง (ทางเลือกในวรรณกรรม: polynomial หรือ distributed lag non-linear models; Bhaskaran et al., 2013) · ค่า p และ CI ใช้การแจกแจงปกติ ซึ่งให้ค่า p ต่ำกว่าการใช้ t(n − k) เล็กน้อยในตัวอย่างเล็ก · สัมประสิทธิ์เป็นความสัมพันธ์ ไม่ใช่ผลเชิงสาเหตุ
When to use and limits: at least one predictor series of the same frequency; usable periods must exceed the number of parameters by at least 8 (large L and p consume data). The outcome is modelled on the linear scale — low or zero-heavy counts call for a lagged Poisson/negative binomial model. Long unconstrained lags have wide SEs (the literature's alternatives are polynomial and distributed lag non-linear models; Bhaskaran et al., 2013). p-values and CIs use the normal distribution, which gives slightly smaller p-values than t(n − k) in small samples. Coefficients are associations, not causal effects.
รายการตรวจสอบก่อนตีพิมพ์: สมการเต็ม (L, p, แนวโน้ม, K) · วิธีจัดการสหสัมพันธ์และเหตุผล (bandwidth / ρ / ลำดับ ARIMA) · จำนวนช่วงที่ใช้และที่ตัด · ตารางสัมประสิทธิ์ทุก lag และผลสะสมพร้อม 95% CI · Durbin-Watson และ Ljung-Box ของส่วนเหลือ · ผลการตรวจความคงที่ · กราฟ lag-response · แนวทาง STROBE หรือ RECORD
Pre-submission checklist: the full equation (L, p, trend, K); how autocorrelation was handled and why (bandwidth / ρ / ARIMA order); periods used and dropped; the coefficient table for every lag and the cumulative effect with 95% CI; Durbin-Watson and Ljung-Box of the residuals; the stationarity checks; the lag-response figure; STROBE or RECORD.
📖 References
- Newey, W. K., & West, K. D. (1987). A simple, positive semi-definite, heteroskedasticity and autocorrelation consistent covariance matrix. Econometrica, 55(3), 703–708. doi:10.2307/1913610
- Newey, W. K., & West, K. D. (1994). Automatic lag selection in covariance matrix estimation. Review of Economic Studies, 61(4), 631–653. doi:10.2307/2297912
- Prais, S. J., & Winsten, C. B. (1954). Trend estimators and serial correlation (Cowles Commission Discussion Paper No. 383). Cowles Commission for Research in Economics.
- Bhaskaran, K., Gasparrini, A., Hajat, S., Smeeth, L., & Armstrong, B. (2013). Time series regression studies in environmental epidemiology. International Journal of Epidemiology, 42(4), 1187–1195. doi:10.1093/ije/dyt092
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
11.8การเตรียมข้อมูล การเลือกวิธี หน้าจอ DAPH และการตรวจสอบกับ R ทั้งบท (Data preparation · method choice · DAPH screens · chapter-level validation)
1จะใช้สถิติตัวไหนWhich statistic answers which question
ตัวแปรตามชนิด Time-Series วิเคราะห์หนึ่งค่าต่อหนึ่งช่วงเวลา (วัน สัปดาห์ เดือน ไตรมาส ปี) · ข้อมูลรายบุคคลใช้ได้ เพราะ DAPH รวมแถวตามคอลัมน์เวลาให้เป็นค่ารายช่วงก่อน (เช่น จำนวนผู้เสียชีวิตต่อเดือน) · คำถาม → สถิติ: โดยรวมเพิ่มหรือลด? → 11.1 Time Plot & Trend · มีฤดูกาลไหม เดือนไหนสูงสุด? → 11.2 Seasonal Decomposition · ค่าปัจจุบันขึ้นกับอดีตกี่ช่วง ต้องหาผลต่างไหม? → 11.3 Autocorrelation · อีก 6–12 ช่วงข้างหน้าจะเป็นเท่าไร? → 11.4 Forecast · ปัจจัย X นำหน้าผลลัพธ์กี่ช่วง? → 11.5 Cross-Correlation · เหตุการณ์ที่รู้วันที่เปลี่ยนระดับหรือแนวโน้มหรือไม่? → 11.6 Interrupted Time Series · ปัจจัย X สัมพันธ์กับ Y ตามเวลาอย่างไร (รวมผลล่าช้า)? → 11.7 Time-Series Regression · ลำดับที่แนะนำ: 11.1 → 11.2 → 11.3 แล้วจึง 11.4–11.7 ตามคำถามวิจัย · ในข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย) บทนี้ใช้จำนวนผู้เสียชีวิตต่อเดือน (end_date) และผู้ป่วยใหม่ต่อเดือน (enroll_date) ซึ่ง DAPH รวมให้เอง (11.1–11.4, 11.6) และตารางรายเดือน pd_monthly.csv ที่สร้างด้วย R เมื่อสองอนุกรมนับจากคนละคอลัมน์วันที่ (11.5, 11.7) · ข้อมูลชุดนี้สั้น (18–36 เดือน) และไม่มีฤดูกาล ผลแต่ละหัวข้อจึงอธิบายข้อจำกัดนี้ไว้ด้วย
The Time-Series outcome type analyses one value per period (day, week, month, quarter, year). Patient-level data can be used, because DAPH first combines the rows by the time column into one value per period (for example deaths per month). Question → statistic: is there an overall rise or fall? → 11.1 Time Plot & Trend · is there a season, which month peaks? → 11.2 Seasonal Decomposition · how far back does the present depend on the past, must we difference? → 11.3 Autocorrelation · what will the next 6–12 periods be? → 11.4 Forecast · by how many periods does factor X lead the outcome? → 11.5 Cross-Correlation · did a dated event change the level or the trend? → 11.6 Interrupted Time Series · how is factor X related to Y over time (including delayed effects)? → 11.7 Time-Series Regression. Suggested order: 11.1 → 11.2 → 11.3, then 11.4–11.7 as the research question requires. In the DAPH example data (1,300 peritoneal-dialysis patients) this chapter uses deaths per month (end_date) and new patients per month (enroll_date), which DAPH aggregates itself (11.1–11.4, 11.6), and a monthly table pd_monthly.csv built in R when two series are dated by different columns (11.5, 11.7). These series are short (18–36 months) and have no seasonality, and each section says what that limits.
2การเตรียมข้อมูลใน Tab 2 (แผง "ตั้งค่าอนุกรมเวลา")Preparing the series in Tab 2 (the "Time-Series settings" panel)
แผงเดียวมีสองโหมด · "ข้อมูลมีคอลัมน์วันที่หรือช่วงเวลา": เลือกตัวแปรเวลา แล้ว DAPH เดาความถี่จากระยะห่างของวันที่ที่ไม่ซ้ำกัน (รายวัน / รายสัปดาห์แบบสัปดาห์ระบาด MMWR เริ่มวันอาทิตย์ / รายเดือน / รายไตรมาส / รายปี; เดาไม่ได้ = รายเดือน) และเปลี่ยนเองได้ — วันที่รายบุคคลมักถูกอ่านเป็นรายวัน (เช่น enroll_date) จึงควรเลือกความถี่เองเสมอ · หลายแถวในช่วงเดียวกันถูกรวม: อนุกรมตัวเลขใช้ "รวมแถวต่อช่วง" (ผลรวม = ค่าเริ่มต้น หรือค่าเฉลี่ย) · ตัวแปรกลุ่มในกล่องอนุกรมถูกนับต่อช่วงที่แถว "ตัวแปรกลุ่มเป็นอนุกรม": นับจำนวนที่เป็นระดับ (ค่าเริ่มต้น โดยเลือกระดับแรกไว้ก่อน เช่น status = Alive/Censored ต้องเปลี่ยนเป็น Died/Event เพื่อนับผู้เสียชีวิต) สัดส่วนของระดับ หรือนับจำนวนแถวทั้งหมด (เช่น group = จำนวนผู้ป่วยใหม่ต่อเดือน) · ป้ายบอกสิ่งที่นับเสมอ เช่น "Study Status (count of Died/Event per period)" · คอลัมน์ประชากรแปลงเป็นอัตราต่อ 100,000 (อนุกรมแบบนับใช้ค่าเฉลี่ยของประชากรในช่วง ส่วนอนุกรมแบบสัดส่วนไม่ใช้ประชากรและแจ้งในหมายเหตุ) · แถวที่ไม่มีวันที่ถูกตัดออก · รหัสเวลาที่เป็นตัวเลข: ปี 4 หลัก → รายปี, ปีเดือน 6 หลัก (202001 หรือ 256601) → รายเดือน, ปีเดือนวัน 8 หลัก → รายวัน, ตัวเลขอื่น = ลำดับ · "กำหนดช่วงเวลาเอง (แถวเรียงตามเวลาแล้ว)": หนึ่งแถว = หนึ่งช่วง เลือกความถี่และช่วงของแถวแรก (ปี / ไตรมาส / เดือน / สัปดาห์ระบาด / วันที่)
One panel, two modes. "Data has a date / period column": pick the time variable and DAPH guesses the frequency from the spacing of the distinct dates (daily / weekly as MMWR epidemiological weeks starting Sunday / monthly / quarterly / yearly; unrecognised = monthly), which you can override — patient-level dates are often read as daily (enroll_date, for example), so always set the frequency yourself. Several rows in one period are combined: a numeric series uses "Combine rows per period" (Sum = default, or Mean); a categorical variable in the series box is counted per period in the row "Categorical series": Count rows equal to level (default, with the first level preselected — status = Alive/Censored must be changed to Died/Event to count deaths), Proportion of level, or Count all rows (group, for example, gives new patients per month). The label always says what was counted, e.g. "Study Status (count of Died/Event per period)". A population column converts the series into a rate per 100,000 (count series use the period mean of the population; proportion series ignore it, with a note). Rows without a date are left out. Numeric time codes: 4-digit year → yearly, 6-digit year-month (202001 or 256601) → monthly, 8-digit year-month-day → daily, other integers = sequence. "Define dates from row order": one row = one period; choose the frequency and the period of the first row (year / quarter / month / epi week / date).
ช่วงว่าง: ช่วงที่ไม่มีแถวเลยเป็น "ไม่มีข้อมูล" ไม่ถูกตัดทิ้ง (ไม่งั้น lag และฤดูกาลจะเลื่อน) — แม้ในอนุกรมแบบนับ ช่วงที่ไม่มีแถวก็เป็นช่วงว่าง ไม่ใช่ศูนย์ จึงควรเลือกความถี่ที่ทุกช่วงมีข้อมูล หรือสร้างตารางรายช่วงเองแบบ 11.5 · ช่วงว่างถูกเติมเชิงเส้นในขั้นที่ต้องใช้อนุกรมต่อเนื่อง (STL, ACF/PACF, ARIMA/Holt-Winters, CCF) และแจ้งจำนวนในหมายเหตุ ส่วน Mann-Kendall ข้ามค่าที่หาย และ ITS/การถดถอยใช้เฉพาะช่วงที่มีค่า · ตัวแปรในกล่อง: สถิติเชิงเดี่ยว (11.1–11.3) รับได้หลายอนุกรมและวิเคราะห์ทีละอนุกรม · สถิติที่มีตัวทำนาย (11.4, 11.5, 11.7) ใช้อนุกรมผลลัพธ์ตัวเดียว ตัวแปรอิสระคืออนุกรมอธิบาย (11.5) หรือตัวทำนาย (11.4, 11.7) · ทุกอนุกรมใช้คอลัมน์เวลาเดียวกัน ถ้าสองอนุกรมนับจากวันที่คนละคอลัมน์ (เช่น วันรับเข้ากับวันเสียชีวิต) ต้องสร้างตารางรายช่วงก่อน · ตัวทำนายตัวเลขรวมต่อช่วงด้วยค่าเฉลี่ย (ค่าเริ่มต้น) หรือผลรวม · ตัวทำนายที่เป็นตัวแปรกลุ่มรวมเป็นสัดส่วนของระดับ (ค่าเริ่มต้น) จำนวนของระดับ หรือจำนวนแถว และถูกบล็อกตั้งแต่กด >> เฉพาะในโหมดกำหนดช่วงเวลาเอง · ITS มีช่อง ลักษณะมาตรการ (จุดเดียว / ค่อย ๆ เริ่ม / ชั่วคราว) จุดแทรกแซง (พิมพ์หรือเลือกจากปฏิทิน) ถึง ผลล่าช้า ปรับฤดูกาล ค่าคลาดเคลื่อนมาตรฐาน (Newey-West / Prais-Winsten) แบนด์วิดท์ HAC และคู่ฤดูกาล (K) · Time-Series Regression มีช่อง lag สูงสุด L พจน์ AR วิธีจัดการส่วนเหลือ (Newey-West / Prais-Winsten / ARIMA errors) แนวโน้มเชิงเส้น ปรับฤดูกาล แบนด์วิดท์ HAC และคู่ฤดูกาล (K) · ตัวเลือก "อัตโนมัติ (AICc)" ของ K เลือกด้วย AICc จริงเฉพาะใน 11.7 ส่วน ITS ใช้ค่าเริ่มต้นคงที่ (2 คู่สำหรับรายเดือน) · ทุกช่องมี ⓘ ให้อ่านคำอธิบาย
Gaps: a period with no rows is "no data" and is kept rather than dropped (otherwise lags and seasons would shift) — even in a count series a period without rows is a gap, not a zero, so choose a frequency at which every period has data, or build the per-period table yourself as in 11.5. Gaps are linearly interpolated in the steps that need a continuous series (STL, ACF/PACF, ARIMA/Holt-Winters, CCF), with the number stated in the notes; Mann-Kendall skips missing values and ITS/regression use only the periods with data. Variables in the boxes: the univariate statistics (11.1–11.3) take several series and analyse each separately; the statistics with predictors (11.4, 11.5, 11.7) model one outcome series, and the independent variables are the explanatory series (11.5) or predictors (11.4, 11.7). All series share one time column; when two series are dated by different columns (enrolment and death dates, for example), build a per-period table first. Numeric predictors are combined per period by the mean (default) or the sum; categorical predictors by the proportion of a level (default), the count of a level or the row count, and they are blocked at >> only in define-dates mode. ITS has the fields Intervention type (single point / gradual start / temporary), Interruption at (typed or picked from a calendar), To, Delayed effect, Adjust for seasonality, Standard errors (Newey-West / Prais-Winsten), HAC bandwidth and Seasonal pairs (K). Time-Series Regression has Max lag L, AR terms, Residual autocorrelation (Newey-West / Prais-Winsten / ARIMA errors), Linear trend, Adjust for seasonality, HAC bandwidth and Seasonal pairs (K). The K option "Automatic (AICc)" really chooses K by AICc only in 11.7; ITS uses a fixed default (2 pairs for monthly data). Every field has an ⓘ tooltip.
3การอ่านผลใน Tab 3 กราฟ และ WordReading Tab 3, the figures and the Word report
แผงขวา = ตารางผล ที่ใช้แปลผล (ตารางหลักของสถิติ และตารางสัมประสิทธิ์พร้อม 95% CI) · แผงซ้าย = คำอธิบายผลเป็นประโยค ตามด้วยการประเมินแบบจำลองและหมายเหตุ · กราฟใช้ชุดสี Okabe-Ito ที่คนตาบอดสีแยกได้ (Wong, 2011): ค่าสังเกต = น้ำเงิน, ค่า fit/แนวโน้ม/หลังมาตรการ = ส้มแดง, ค่าพยากรณ์/ฤดูกาล = เขียวอมฟ้า, ส่วนเหลือ = ม่วงแดง · เส้นต่างกันด้วยลวดลายและความหนาด้วย จึงพิมพ์ขาวดำได้ และในหน้าต่างแก้ข้อความกราฟมีตัวเลือก "ขาว-ดำ (สำหรับพิมพ์ขาวดำ)" ตัวปรับความหนาเส้น (0.25–3 เท่า) แก้ชื่อแกน/ชื่อกราฟได้ · รายงาน Word เรียงเป็น ผลการวิเคราะห์ (ตาราง) · กราฟ · การแปลผล · บทสรุป ตามด้วยแนวทางการรายงานที่ใช้กับสถิตินั้น (STROBE/RECORD, EPIFORGE 2020 หรือ Jandoc et al. 2015) และเอกสารอ้างอิง · ย่อหน้าการแปลผลอ้างหัวข้อ 11.1–11.7 ของ Guide นี้ว่าเป็นที่มาของขั้นตอนและเกณฑ์การแปลผล
Right panel = results tables used for interpretation (the statistic's main table and the coefficient table with 95% CI). Left panel = the interpretation in sentences, followed by the model evaluation and the notes. Figures use the colour-blind-safe Okabe-Ito palette (Wong, 2011): observed = blue, fitted/trend/post-intervention = vermillion, forecast/seasonal = bluish green, remainder = reddish purple. Line styles and widths also differ, so the figures print in black and white, and the chart text editor offers "Black-and-white (for printing)", a line-thickness control (0.25–3×) and editable titles and axes. The Word report runs Results (tables) · Figures · Interpretation · Conclusion, then the reporting guideline for the statistic (STROBE/RECORD, EPIFORGE 2020 or Jandoc et al. 2015) and the references. The interpretation paragraph cites sections 11.1–11.7 of this Guide as the source of the procedure and the interpretation criteria.
4การตรวจสอบกับ R ทั้งบทChapter-level Verification against R
สถิติอนุกรมเวลาเปิดใช้ในแพ็กเกจ Pro, Premium, Lifetime และช่วงทดลองใช้ 30 วัน · สคริปต์ R ทุกหัวข้อ (11.1–11.7) รันได้ทันทีใน R 4.3.3 จากโฟลเดอร์ที่มีเพียง example_en.csv (ไฟล์ที่ได้จาก DAPH › File › Example dataset (EN) › File › Export › CSV) และคำนวณค่าเดียวกับที่ DAPH รายงานจากข้อมูลชุดเดียวกัน · ตัวเลขฝั่ง DAPH ในทุกตารางมาจากการรันเอนจินจริงของ DAPH บนข้อมูลเดียวกัน · แพ็กเกจ: trend 1.1.8, modifiedmk 1.6, urca 1.3.3, tseries 0.10-55, forecast 8.21.1, sandwich 3.1-0, lmtest 0.9-40, prais 1.1.4 · ผลรวม: ตรงกับ R ตามเกณฑ์ทั้ง 75 รายการ
Time-series statistics are available on the Pro, Premium and Lifetime plans and during the 30-day trial. Every R script in 11.1–11.7 runs unchanged in R 4.3.3 from a folder that holds only example_en.csv (the file from DAPH › File › Example dataset (EN) › File › Export › CSV) and computes the same quantities DAPH reports on the same data. The DAPH numbers in every table come from running DAPH's own engine on that data. Packages: trend 1.1.8, modifiedmk 1.6, urca 1.3.3, tseries 0.10-55, forecast 8.21.1, sandwich 3.1-0, lmtest 0.9-40, prais 1.1.4. Overall: all 75 checks agree with R within tolerance.
| หัวข้อSection | อนุกรมในข้อมูลตัวอย่างExample series | ตรง / ทั้งหมดAgree / checks | ข้อควรรู้Notes |
|---|---|---|---|
| 11.1 | deaths per month; new patients per month | 12 / 12 | Sen's slope 95% CI by Gilbert's ranks; season names follow the calendar |
| 11.2 | deaths per month | 9 / 9 | STL runs 2 inner loess passes per robustness iteration (R: stl(inner = 2)) |
| 11.3 | deaths per month | 7 / 7 | KPSS bandwidth chosen automatically (R: use.lag = 3) |
| 11.4 | new patients per month | 15 / 15 | Holt-Winters limits from 1,000 simulated paths (tolerance 2); the SARIMA grid tries seasonal terms even on short series |
| 11.5 | pd_monthly.csv: new patients → deaths | 8 / 8 | prewhitened with standardised residuals; the filter uses up d + D·m = 13 months |
| 11.6 | deaths per month, interruption 2023-07 | 12 / 12 | "Automatic (AICc)" K uses the fixed default (2 pairs) in ITS |
| 11.7 | pd_monthly.csv: deaths ~ new patients, lags 0–3 | 12 / 12 | stationarity verdict counts ADF p > 0.10 as non-stationary even when KPSS does not reject |
เกณฑ์: ตรงเมื่อต่างไม่เกินการปัดเศษที่แสดง หรือไม่เกินเกณฑ์ที่ระบุในตารางของหัวข้อนั้นสำหรับวิธีวนซ้ำหรือการจำลอง (เช่น SE จาก Hessian เชิงตัวเลข 0.001 และช่วงพยากรณ์จากการจำลอง 1,000 เส้นทาง 2 หน่วย) · ค่า p ของ ADF ใน R กับ DAPH ต่างกันได้ราว 0.0002 เพราะใช้การประมาณการแจกแจงคนละฉบับ (ดู 11.3)
Criterion: agreement within the printed rounding, or within the tolerance stated in the section's table for iterative or simulation methods (for example 0.001 for SEs from a numerical Hessian and 2 units for prediction limits from 1,000 simulated paths). ADF p-values in R and DAPH can differ by about 0.0002 because they use different published approximations of the distribution (see 11.3).
📖 References
- Wong, B. (2011). Points of view: Color blindness. Nature Methods, 8(6), 441. doi:10.1038/nmeth.1618
- Jandoc, R., Burden, A. M., Mamdani, M., Lévesque, L. E., & Cadarette, S. M. (2015). Interrupted time series analysis in drug utilization research is increasing: Systematic review and recommendations. Journal of Clinical Epidemiology, 68(8), 950–956. doi:10.1016/j.jclinepi.2014.12.018
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 12 — เครื่องมือทั่วไป (Descriptive / Utility)Chapter 12 — Descriptive / Utility ✓ Verified
เครื่องมือที่ใช้ก่อนหรือหลังการวิเคราะห์หลัก: ความเที่ยงของแบบวัดที่มีหลายข้อ (Cronbach's α หัวข้อ 12.1) การคำนวณขนาดตัวอย่างและอำนาจการทดสอบ 20 รูปแบบ (หัวข้อ 12.2) การตรวจวินิจฉัยตัวแบบการถดถอย (หัวข้อ 12.3) และความสอดคล้องระหว่างผู้ประเมินหรือระหว่างการวัดซ้ำ (Cohen's kappa และ ICC หัวข้อ 12.4) ตัวอย่างทั้งหมดใช้ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย) Tools used before or after the main analysis: reliability of a multi-item scale (Cronbach's α, section 12.1), sample size and power for 20 designs (section 12.2), regression diagnostics (section 12.3), and agreement between raters or between repeated measurements (Cohen's kappa and ICC, section 12.4). All examples use the DAPH example data (1,300 peritoneal-dialysis patients).
12.1Cronbach's α — Reliability Coefficient
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Cronbach's α (แอลฟา) วัด ความสอดคล้องภายใน (internal consistency) ของแบบวัดที่มีหลายข้อ คือข้อคำถามทุกข้อขึ้นลงไปด้วยกันมากน้อยเพียงใด ซึ่งเป็นเหตุผลที่จะนำคะแนนหลายข้อมารวมเป็นคะแนนเดียว เช่น คะแนนพฤติกรรมเสี่ยงหรือคะแนนความรู้ ค่าโดยทั่วไปอยู่ระหว่าง 0 ถึง 1 (ติดลบได้เมื่อข้อคำถามสัมพันธ์กันในทางตรงข้าม) และขึ้นกับทั้งความสัมพันธ์ระหว่างข้อและจำนวนข้อ (Cronbach, 1951)
Cronbach's α measures the internal consistency of a multi-item scale: how strongly the items rise and fall together, which is the justification for adding them into one score such as a risk-behaviour score or a knowledge score. It usually lies between 0 and 1 (it becomes negative when items are correlated in opposite directions) and depends on both the inter-item correlations and the number of items (Cronbach, 1951).
ใช้เมื่อ ข้อคำถามทุกข้อตั้งใจวัดเรื่องเดียวกัน ให้คะแนนเป็นตัวเลขในทิศทางเดียวกัน (เช่น มาตราส่วนแบบลิเคิร์ต) และต้องการตรวจก่อนรวมคะแนน · ไม่ควรใช้ กับรายการพฤติกรรมหลายเรื่องที่ไม่ได้วัดสิ่งเดียวกัน หรือแบบสอบถามที่มีหลายมิติ (ให้คำนวณแยกรายมิติหลังวิเคราะห์องค์ประกอบ ดูหัวข้อ 9.1) · ค่า α สูงไม่ได้พิสูจน์ว่าแบบวัดมีมิติเดียวหรือมีความตรง · ความสอดคล้องระหว่างผู้ประเมินหรือระหว่างการวัดสองครั้งให้ใช้ kappa หรือ ICC (หัวข้อ 12.4) · ข้อคำถามแบบใช่/ไม่ใช่ (0/1) ค่า α ที่ได้คือค่าเดียวกับ KR-20
Use it when all items are meant to measure one construct, are scored numerically in the same direction (for example Likert-type items), and you want to check them before adding them up. Do not use it for a checklist of different behaviours or for a multidimensional questionnaire (compute it per subscale after factor analysis, section 9.1). A high α does not prove that a scale is unidimensional or valid. Agreement between raters or between two measurement occasions needs kappa or the ICC (section 12.4). For 0/1 items, α is the same number as KR-20.
ใน DAPH · เมนู วิเคราะห์เพิ่มเติม > Cronbach's Alpha... แล้วติ๊กเลือกข้อคำถามที่เป็นตัวเลขอย่างน้อย 2 ข้อ · DAPH ใช้เฉพาะแถวที่มีค่าครบทุกข้อที่เลือก และไม่กลับทิศคะแนนให้อัตโนมัติ ข้อที่ให้คะแนนกลับทิศต้องแปลงค่าก่อน (เช่น ด้วยเครื่องมือคำนวณตัวแปรใหม่)
In DAPH: menu Additional Analysis > Cronbach's Alpha..., then tick at least two numeric items. DAPH uses only the rows that have a value for every selected item, and it does not reverse items automatically: reverse-worded items must be recoded first (for example with the compute-variable tool).
sugaryfoodfreq) อาหารมัน (Fatty food frequency, fattyfoodfreq) และอาหารเค็ม (Salty food frequency, saltyfoodfreq) รวมเป็นคะแนน "ความถี่อาหารเสี่ยง" คะแนนเดียวได้หรือไม่ · คำถามที่ 2: ข้อวิถีชีวิตทั้ง 9 ข้อ (สุรา บุหรี่ หมาก อาหาร 3 ข้อ การออกกำลังกายหนักและปานกลาง และงานอดิเรก) รวมเป็นคะแนนวิถีชีวิตคะแนนเดียวได้หรือไม่ · ผลที่คำนวณได้ด้านล่าง: α = 0.574 สำหรับอาหาร 3 ข้อ และ α = 0.319 สำหรับ 9 ข้อsugaryfoodfreq), Fatty food frequency (fattyfoodfreq) and Salty food frequency (saltyfoodfreq), be added into one "unhealthy-food frequency" score? Question 2: can all nine lifestyle items (alcohol, cigarettes, betel, the three foods, vigorous and moderate physical activity, hobbies) be added into one lifestyle score? Results computed below: α = 0.574 for the three food items and α = 0.319 for the nine items.2หลักการและสูตรLogic and Formula
- k, n
- จำนวนข้อคำถาม และจำนวนผู้ตอบที่มีค่าครบทุกข้อnumber of items and number of respondents with every item answered
- s_i², s_T²
- ความแปรปรวนของข้อ i และของคะแนนรวม T (ตัวหาร n − 1)variance of item i and of the total score T (divisor n − 1)
- r̄
- ค่าเฉลี่ยของสหสัมพันธ์เพียร์สันระหว่างข้อทุกคู่ k(k − 1)/2 คู่mean of the Pearson correlations between all k(k − 1)/2 pairs of items
- r_j
- สหสัมพันธ์ระหว่างข้อ j กับผลรวมของข้ออื่น (ไม่รวมข้อ j เอง) ซึ่ง DAPH แสดงในคอลัมน์ Item-Total Corrcorrelation of item j with the sum of the other items (item j itself excluded), shown by DAPH in the Item-Total Corr column
- s_T(−j)²
- ความแปรปรวนของคะแนนรวมเมื่อตัดข้อ j ออกvariance of the total score with item j removed
- F_q; a, b
- ควอนไทล์ที่ q ของการแจกแจง F ที่องศาอิสระ a และ bq-quantile of the F distribution with a and b degrees of freedom
สิ่งที่ DAPH คำนวณ · α แบบดิบ (จากความแปรปรวน) และ α แบบมาตรฐาน (จากสหสัมพันธ์เฉลี่ยระหว่างข้อ) · ค่าเฉลี่ย ความแปรปรวน และส่วนเบี่ยงเบนมาตรฐานของคะแนนรวม · ค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานรายข้อ · สหสัมพันธ์รายข้อกับผลรวมของข้ออื่น (corrected item–total) · α เมื่อตัดข้อนั้นออก (คำนวณได้เมื่อมีอย่างน้อย 3 ข้อ) · แล้วจัดระดับตามเกณฑ์ที่ใช้กันทั่วไป: ≥ 0.9 ดีเยี่ยม, 0.8–0.9 ดี, 0.7–0.8 ยอมรับได้, 0.6–0.7 น่าสงสัย, 0.5–0.6 ต่ำ, < 0.5 ไม่เป็นที่ยอมรับ · คำแนะนำท้ายผลแจ้งเมื่อ α < 0.7 เมื่อการตัดข้อใดทำให้ α สูงขึ้น และเมื่อข้อใดมีสหสัมพันธ์กับผลรวมของข้ออื่น < 0.3 · DAPH ไม่รายงานช่วงเชื่อมั่นของ α ไม่คำนวณ ω และไม่มีตัวเลือก KR-20 แยก
What DAPH computes. Raw α (from variances) and standardised α (from the average inter-item correlation); the mean, variance and standard deviation of the total score; each item's mean and standard deviation; the corrected item–total correlation (item versus the sum of the other items); and α if the item is deleted (available from three items upward). It then labels α with a common rule of thumb: ≥ 0.9 excellent, 0.8–0.9 good, 0.7–0.8 acceptable, 0.6–0.7 questionable, 0.5–0.6 poor, < 0.5 unacceptable. The recommendations flag α < 0.7, items whose deletion would raise α, and items whose corrected item–total correlation is below 0.3. DAPH does not report a confidence interval for α, does not compute ω, and has no separate KR-20 option.
เกณฑ์ตัวเลขข้างต้นเป็นเพียงแนวทาง ค่าที่ต้องการขึ้นกับการใช้งาน: ประมาณ 0.70 ถือว่าพอสำหรับงานวิจัยระยะเริ่มต้น ส่วนการตัดสินใจรายบุคคลต้องการค่าสูงกว่านั้นมาก (Nunnally, 1978) ค่าที่สูงเกิน 0.90 อาจหมายถึงข้อคำถามซ้ำซ้อนกัน (Tavakol & Dennick, 2011) และ α เพิ่มขึ้นตามจำนวนข้อ แม้สหสัมพันธ์ระหว่างข้อจะเท่าเดิม
These cut-offs are guidance only; the level needed depends on the use: about 0.70 is adequate for early-stage research, whereas decisions about individual people need much higher values (Nunnally, 1978). Values above about 0.90 may mean that items are redundant (Tavakol & Dennick, 2011), and α rises with the number of items even when the inter-item correlations stay the same.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(psych)
# Question 1: the three food items (0 = never ... 4 = every day of the past 14 days)
food <- d[, c("sugaryfoodfreq", "fattyfoodfreq", "saltyfoodfreq")]
a <- psych::alpha(food)
print(a$total[, c("raw_alpha", "std.alpha", "average_r")], digits = 4)
print(cbind(a$item.stats[, c("n", "mean", "sd", "r.drop")], alpha_if_deleted = a$alpha.drop$raw_alpha), digits = 4)
print(a$feldt, digits = 4) # 95% CI of alpha (Feldt 1965) - not reported by DAPH
# the same numbers from the formulas
k <- ncol(food); total <- rowSums(food); R <- cor(food); rbar <- mean(R[upper.tri(R)])
round(c(raw_alpha = k / (k - 1) * (1 - sum(apply(food, 2, var)) / var(total)),
std_alpha = k * rbar / (1 + (k - 1) * rbar), mean_r = rbar,
scale_mean = mean(total), scale_var = var(total), scale_sd = sd(total)), 4)
round(8 * rbar / (1 + 7 * rbar), 3) # same average correlation, 8 items (standardised-alpha formula)
raw_alpha std.alpha average_r
0.5743 0.6015 0.3347
n mean sd r.drop alpha_if_deleted
sugaryfoodfreq 1300 1.464 1.3035 0.3493 0.5431
fattyfoodfreq 1300 1.110 0.8884 0.4855 0.3858
saltyfoodfreq 1300 1.385 1.2507 0.3623 0.5124
95% confidence boundaries (Feldt)
lower alpha upper
0.5326 0.5743 0.6129
raw_alpha std_alpha mean_r scale_mean scale_var scale_sd
0.5743 0.6015 0.3347 3.9592 6.5672 2.5627
[1] 0.801
# Question 2: all nine lifestyle items
nine <- d[, c("alcoholfreq", "cigarettefreq", "betelfreq", "sugaryfoodfreq", "fattyfoodfreq", "saltyfoodfreq",
"vigorousphysicalactivities", "moderatephysicalactivities", "hobbiesactivities")]
a9 <- psych::alpha(nine, check.keys = FALSE, warnings = FALSE)
print(a9$total[, c("raw_alpha", "std.alpha", "average_r")], digits = 4)
print(data.frame(r.drop = a9$item.stats$r.drop, alpha_if_deleted = a9$alpha.drop$raw_alpha,
row.names = names(nine)), digits = 4)
raw_alpha std.alpha average_r
0.3188 0.3482 0.05602
r.drop alpha_if_deleted
alcoholfreq 0.15057 0.3015
cigarettefreq 0.19419 0.2507
betelfreq 0.13025 0.2917
sugaryfoodfreq 0.24536 0.2292
fattyfoodfreq 0.31147 0.2317
saltyfoodfreq 0.28471 0.2119
vigorousphysicalactivities -0.13400 0.3788
moderatephysicalactivities -0.03548 0.3821
hobbiesactivities 0.06691 0.3298
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| n (complete cases) · k | 1300 · 3 | 1300 · 3 | 0 | ✓ PASS |
| คำถามที่ 1: α แบบดิบQuestion 1: raw α | 0.5743 | 0.5743 | < 0.00005 | ✓ PASS |
| α แบบมาตรฐานstandardised α | 0.6015 | 0.6015 | < 0.00005 | ✓ PASS |
| สหสัมพันธ์เฉลี่ยระหว่างข้อmean inter-item correlation | 0.3347 | 0.3347 | < 0.00005 | ✓ PASS |
| คะแนนรวม: ค่าเฉลี่ย / ความแปรปรวน / SDtotal score: mean / variance / SD | 3.9592 / 6.5672 / 2.5627 | 3.9592 / 6.5672 / 2.5627 | < 0.00005 | ✓ PASS |
| corrected item–total r: หวาน / มัน / เค็มcorrected item–total r: sugary / fatty / salty | 0.3493 / 0.4855 / 0.3623 | 0.3493 / 0.4855 / 0.3623 | < 0.00005 | ✓ PASS |
| α เมื่อตัดข้อ: หวาน / มัน / เค็มα if deleted: sugary / fatty / salty | 0.5431 / 0.3858 / 0.5124 | 0.5431 / 0.3858 / 0.5124 | < 0.00005 | ✓ PASS |
| SD รายข้อ: หวาน / มัน / เค็มitem SD: sugary / fatty / salty | 1.3035 / 0.8884 / 1.2507 | 1.3035 / 0.8884 / 1.2507 | < 0.00005 | ✓ PASS |
| คำถามที่ 2: α แบบดิบ / แบบมาตรฐานQuestion 2: raw α / standardised α | 0.3188 / 0.3482 | 0.3188 / 0.3482 | < 0.00005 | ✓ PASS |
| สหสัมพันธ์เฉลี่ยระหว่างข้อ (9 ข้อ)mean inter-item correlation (9 items) | 0.05602 | 0.0560 | < 0.00005 | ✓ PASS |
| corrected item–total r: ออกกำลังกายหนัก / ปานกลางcorrected item–total r: vigorous / moderate activity | −0.13400 / −0.03548 | −0.1340 / −0.0355 | < 0.00005 | ✓ PASS |
| α เมื่อตัดข้อ: ออกกำลังกายหนัก / ปานกลาง / งานอดิเรกα if deleted: vigorous / moderate / hobbies | 0.3788 / 0.3821 / 0.3298 | 0.3788 / 0.3821 / 0.3298 | < 0.00005 | ✓ PASS |
4การแปลผลและตัวอย่างInterpretation and Example
คำถามที่ 1: อาหารเสี่ยง 3 ข้อมี α = 0.574 (α แบบมาตรฐาน 0.601) สหสัมพันธ์เฉลี่ยระหว่างข้อ 0.335 DAPH จัดอยู่ในระดับ "ต่ำ (Poor)" (0.5–0.6) ทุกข้อมีสหสัมพันธ์กับผลรวมของข้ออื่นอย่างน้อย 0.349 และการตัดข้อใดออกทำให้ α ลดลง (เหลือ 0.386–0.543) จึงไม่มีข้อที่ควรตัด ค่า α ที่ต่ำส่วนใหญ่มาจากการมีเพียง 3 ข้อ หากมี 8 ข้อที่สหสัมพันธ์เฉลี่ยเท่ากัน α จะประมาณ 0.801 (สูตร α แบบมาตรฐานเมื่อ k = 8 ในผล R) · ช่วงเชื่อมั่น 95% ของ α (วิธีของ Feldt คำนวณใน R เพราะ DAPH ไม่รายงาน) คือ 0.533 ถึง 0.613 · ในทางปฏิบัติ คะแนนรวม 3 ข้อนี้ใช้บรรยายภาพรวมของกลุ่มในงานเชิงสำรวจได้อย่างระมัดระวัง แต่ไม่เที่ยงพอสำหรับตัดสินรายบุคคล หรือควรวิเคราะห์ทีละข้อร่วมด้วย
Question 1: the three unhealthy-food items give α = 0.574 (standardised α 0.601) with a mean inter-item correlation of 0.335, which DAPH labels "Poor" (0.5–0.6). Every item correlates at least 0.349 with the sum of the other items, and deleting any item lowers α (to 0.386–0.543), so no item should be dropped. The low α comes mainly from having only three items: eight items with the same average correlation would give α of about 0.801 (the standardised-α formula with k = 8, R output). The 95% confidence interval of α (Feldt's method, computed in R because DAPH does not report it) is 0.533 to 0.613. In practice the three-item score can describe groups in exploratory work, with caution, but it is not reliable enough for decisions about individual patients; analysing the items one by one as well is sensible.
คำถามที่ 2: ข้อวิถีชีวิต 9 ข้อมี α = 0.319 (α แบบมาตรฐาน 0.348) สหสัมพันธ์เฉลี่ยระหว่างข้อเพียง 0.056 ข้อออกกำลังกายหนักและปานกลางมีสหสัมพันธ์กับผลรวมของข้ออื่นติดลบ (−0.134 และ −0.035) DAPH จึงแนะนำว่าการตัดข้อออกกำลังกายทั้งสองข้อและงานอดิเรกจะทำให้ α สูงขึ้น ข้อสรุปคือ 9 ข้อนี้ไม่ใช่แบบวัดเรื่องเดียว เพราะเป็นพฤติกรรมต่างชนิดกัน บางข้อเป็นพฤติกรรมเสี่ยงและบางข้อเป็นพฤติกรรมป้องกัน จึงไม่ควรรวมเป็นคะแนนเดียว ควรวิเคราะห์แยกหรือสร้างคะแนนรายด้าน การตัดข้อทีละข้อเพื่อดัน α ให้สูงขึ้นโดยไม่พิจารณาเนื้อหาจะได้แบบวัดที่ไม่มีความหมาย ควรเลือกข้อจากเนื้อหาก่อน แล้วจึงใช้ α ยืนยัน
Question 2: the nine lifestyle items give α = 0.319 (standardised 0.348) with a mean inter-item correlation of only 0.056. Vigorous and moderate physical activity correlate negatively with the sum of the other items (−0.134 and −0.035), so DAPH reports that deleting the two activity items and hobbies would raise α. The conclusion is that these nine items are not one scale: they are different behaviours, some harmful and some protective, and should not be added into one score; analyse them separately or build domain scores. Dropping items one at a time just to push α up, without regard to content, produces a meaningless scale; choose the items by content first and use α to confirm.
📖 References
- Cronbach, L. J. (1951). Coefficient alpha and the internal structure of tests. Psychometrika, 16(3), 297–334. doi:10.1007/BF02310555
- Feldt, L. S. (1965). The approximate sampling distribution of Kuder-Richardson reliability coefficient twenty. Psychometrika, 30(3), 357–370. doi:10.1007/BF02289499
- Nunnally, J. C. (1978). Psychometric theory (2nd ed.). McGraw-Hill. ISBN 978-0-07-047465-9.
- Tavakol, M., & Dennick, R. (2011). Making sense of Cronbach's alpha. International Journal of Medical Education, 2, 53–55. doi:10.5116/ijme.4dfb.8dfd
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2Sample Size Calculator — 20 designs
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
การคำนวณขนาดตัวอย่าง หาจำนวนผู้เข้าร่วมน้อยที่สุดที่ทำให้การศึกษามี อำนาจการทดสอบ (power) ตามที่กำหนด (มักใช้ 80% หรือ 90%) ในการตรวจพบผลขนาดที่กำหนดไว้ล่วงหน้า ที่ระดับนัยสำคัญ α (มักใช้ 0.05 แบบสองด้าน) ส่วน โหมดคำนวณ power ทำทางกลับกัน คือบอกว่าขนาดตัวอย่างที่มีอยู่แล้วให้ power เท่าใด DAPH มีเครื่องคำนวณ 20 รูปแบบ หัวข้อย่อย 12.2.1 ถึง 12.2.20 แสดงสูตรที่ DAPH ใช้จริง ตัวอย่างการแทนค่า สคริปต์ R ที่ให้ตัวเลขเดียวกัน และผลการตรวจเทียบ กรอบแนวคิดหลักมาจาก Cohen (1988) และ Machin et al. (2018)
Sample-size calculation finds the smallest number of participants that gives a study the required power (usually 80% or 90%) to detect an effect of a pre-specified size at significance level α (usually 0.05, two-sided). Power mode works the other way round: it reports the power that an already fixed sample size gives. DAPH has 20 calculators; sub-sections 12.2.1 to 12.2.20 show the formula DAPH actually uses, a worked example, an R script that gives the same numbers, and the verification. The framework follows Cohen (1988) and Machin et al. (2018).
ใช้เมื่อ วางแผนการศึกษาก่อนเก็บข้อมูล (โครงร่างวิจัยหรือการขอทุน) โดยเลือกรูปแบบให้ตรงกับสถิติที่จะใช้วิเคราะห์จริง เช่น 12.2.2 สำหรับ independent t-test และ 12.2.9 สำหรับ logistic regression · ไม่ควรใช้ คำนวณ power ย้อนหลังจากผลที่ได้จากข้อมูลชุดเดียวกัน (observed power) เพราะไม่ให้ข้อมูลใหม่ · การคำนวณต้องการค่าวางแผนสองชนิด คือ ขนาดผลที่ต้องการตรวจพบ (ผลต่างน้อยที่สุดที่มีความหมายทางคลินิก ผลจากงานวิจัยก่อนหน้า หรือข้อมูลนำร่อง) และค่าประกอบ (SD สัดส่วนพื้นฐาน อัตราการเกิดเหตุการณ์ สหสัมพันธ์)
Use it when planning a study before data collection (a protocol or grant application), choosing the design that matches the analysis that will really be run, for example 12.2.2 for an independent t-test and 12.2.9 for logistic regression. Do not use it to compute power after the study from the effect observed in the same data (observed power), which adds no information. Two kinds of planning values are needed: the effect to detect (the smallest clinically meaningful difference, results of earlier studies, or pilot data) and nuisance values (SD, baseline proportion, event rate, correlation).
ใน DAPH · เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... เลือกรูปแบบจากรายการด้านซ้าย เลือก "ต้องการคำนวณ: ขนาดตัวอย่าง (n)" หรือ "อำนาจการทดสอบ (Power)" (ช่อง Power จะเปลี่ยนเป็นช่อง N) ใส่ค่าวางแผน Alpha และ Power หรือ N และเลือกทิศทางการทดสอบ (สองด้านเป็นค่าเริ่มต้น ไม่มีตัวเลือกนี้สำหรับไคสแควร์ ANOVA การถดถอยเชิงเส้น และการตรวจวินิจฉัย) ผลลัพธ์แสดงขนาดตัวอย่างขั้นต่ำ จำนวนที่แนะนำหลังเผื่อการสูญหาย และส่งออกเป็นรายงาน Word ได้ ซึ่งรายงานอ้างหัวข้อนี้สำหรับสูตรและการเผื่อการสูญหาย
In DAPH: menu Additional Analysis > Sample Size Calculation..., choose the design in the list on the left, choose "Calculate: Sample size (n)" or "Power of test" (the Power box then becomes an N box), enter the planning values, Alpha and Power or N, and the tails (two-sided is the default; there is no tail option for chi-square, ANOVA, linear regression and the diagnostic design). The result shows the minimum sample size and the recommended number after allowing for attrition, and it can be exported as a Word report, which cites this section for the formulas and for the attrition allowance.
2หลักการและสูตรLogic and Formula
- Φ⁻¹, α, 1 − β
- ฟังก์ชันผกผันของการแจกแจงปกติมาตรฐาน ระดับนัยสำคัญ และ power (การทดสอบด้านเดียวใช้ z1−α)inverse standard normal distribution function, significance level and power (a one-sided test uses z1−α)
- ⌈x⌉
- ปัดขึ้นเป็นจำนวนเต็ม (แต่ละรูปแบบระบุขั้นที่ปัด)round up to a whole number (each design lists the steps that are rounded)
- d
- สัดส่วนผู้เข้าร่วมที่คาดว่าจะสูญหายหรือไม่มีข้อมูลผลลัพธ์proportion of participants expected to drop out or to lack outcome data
- n(1 − β), N
- ขนาดตัวอย่างที่รูปแบบนั้นต้องการที่ power 1 − β (รวมการปัดทุกขั้น) และขนาดตัวอย่างที่มีอยู่sample size the design requires at power 1 − β (all rounding included) and the sample size available
ค่า z: DAPH ใช้ควอนไทล์จริง (1.959964 และ 0.841621 ที่ α = 0.05 สองด้านและ power 0.80) ไม่ใช่ 1.96 และ 0.84 การคำนวณด้วยมือที่ปัดค่า z จึงอาจต่างจาก DAPH ได้ 1 คน · การปัด: ทุกรูปแบบปัดขึ้น และบางรูปแบบปัดหลายขั้น (ระบุในแต่ละหัวข้อย่อย) · รูปแบบ t-test (12.2.1–12.2.3) ใช้การประมาณด้วยการแจกแจงปกติ ได้น้อยกว่าที่คำนวณด้วยการแจกแจง t จริง 1–2 คน
z values: DAPH uses exact quantiles (1.959964 and 0.841621 at α = 0.05 two-sided and power 0.80), not 1.96 and 0.84, so a hand calculation with rounded z can differ from DAPH by one. Rounding: every design rounds up, some at several steps (listed in each sub-section). The t-test designs (12.2.1–12.2.3) use the normal approximation, which gives 1–2 fewer than the exact t distribution.
การเผื่อการสูญหาย: ขนาดตัวอย่างจากสูตรคือจำนวนที่ต้อง มีข้อมูลครบเมื่อวิเคราะห์ หากคาดว่าจะสูญหายสัดส่วน d จำนวนที่ต้องรับเข้าคือ ⌈n/(1 − d)⌉ เช่น n = 100 และ d = 0.10 ต้องรับ ⌈111.1⌉ = 112 คน (การคูณ 1.10 ได้ 110 ซึ่งเหลือหลังสูญหายเพียง 99 คน) · DAPH รายงานจำนวนที่แนะนำด้วยกฎนี้ที่ d = 0.10 (บรรทัด "แนะนำ (เผื่อข้อมูลสูญหาย 10% ตามสูตร n / (1 − 0.10))" เป็นจำนวนคนหรือจำนวนคู่ตามรูปแบบ) และรายงาน Word อ้างหัวข้อนี้สำหรับการเผื่อการสูญหาย · DAPH กำหนด d = 0.10 คงที่ หากคาดว่าจะสูญหายมากกว่านี้ ให้คำนวณ ⌈n/(1 − d)⌉ ด้วยค่า d ที่คาดจริง
Attrition: the formula gives the number who must have complete data at analysis. If a proportion d is expected to be lost, recruit ⌈n/(1 − d)⌉; for example n = 100 and d = 0.10 require ⌈111.1⌉ = 112 (multiplying by 1.10 gives 110, which leaves only 99 after the losses). DAPH reports the recommended number by this rule with d = 0.10 (the line "Recommended (allowing for 10% dropout, n / (1 − 0.10))", in persons or pairs as the design requires), and its Word report cites this section for the attrition allowance. DAPH fixes d at 0.10; when more loss is expected, compute ⌈n/(1 − d)⌉ with the expected d.
โหมด power: DAPH ไม่ได้กลับสูตรทีละรูปแบบ แต่หา power ที่มากที่สุดซึ่งขนาดตัวอย่างที่รูปแบบนั้นต้องการ (รวมการปัดทุกขั้น) ยังไม่เกิน N ด้วยการไล่ค่าบนตาราง power แล้วแบ่งครึ่งช่วง (bisection) ผลจึงตรงกับโหมดคำนวณ n เสมอ การไล่ตารางก่อนจำเป็น เพราะในสูตรสัดส่วน (12.2.4–12.2.6) n เป็นรูปตัว U เมื่อ power ต่ำมาก · ไคสแควร์ ANOVA และการถดถอยเชิงเส้นคำนวณ power จากการแจกแจง non-central โดยตรง · รูปแบบการตรวจวินิจฉัย (12.2.12) ไม่มีโหมดนี้ · ผลยังแสดงขนาดตัวอย่างที่ต้องใช้เพื่อให้ได้ power 80% ทั้งนี้ power ที่ได้คำนวณจากขนาดผลที่กำหนดล่วงหน้า ไม่ใช่ observed power
Power mode: DAPH does not invert each formula; it finds the largest power for which the design's own required n (every rounding included) still fits in N, by scanning a grid of powers and then bisecting. The two modes therefore always agree. The grid scan matters because in the proportion formulas (12.2.4–12.2.6) n is U-shaped at very low powers. Chi-square, ANOVA and linear regression compute the power directly from the non-central distribution. The diagnostic design (12.2.12) has no power mode. The result also shows the sample size needed for 80% power. The power refers to the pre-specified effect, not to observed power.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
บล็อกตั้งต้นด้านล่างอ่านข้อมูลตัวอย่าง และสร้างฟังก์ชัน power_at_N() ที่ทำโหมด power แบบเดียวกับ DAPH และ with_attrition() สำหรับกฎ ⌈n/(1 − d)⌉ ให้รันบล็อกนี้ก่อนสคริปต์ของทุกหัวข้อย่อย ตัวเลข DAPH ทุกค่ามาจากเครื่องคำนวณขนาดตัวอย่างของ DAPH รุ่น v.2026.08.22 ด้วยค่าตามที่ระบุในแต่ละหัวข้อย่อย ทั้งสองโหมด
The set-up block below reads the example data and defines power_at_N(), which runs power mode exactly as DAPH does, and with_attrition() for the ⌈n/(1 − d)⌉ rule; run it before the script of any sub-section. Every DAPH number comes from DAPH's sample-size calculator (v.2026.08.22) with the inputs listed in each sub-section, in both modes.
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
# DAPH uses the exact normal quantiles, not the rounded 1.96 and 0.84
round(qnorm(c(0.975, 0.80)), 6)
# Power mode as DAPH does it: the largest power whose required n (the design's own
# n function, every rounding-up included) still fits in the available N
power_at_N <- function(n_of_power, N) {
grid <- c(1e-4, 0.001, 0.0025, 0.005, 0.0075, 0.01, 0.015, 0.02, 0.03, 0.04,
seq(0.05, 0.99, by = 0.01), 0.995, 0.999, 0.9999, 1 - 1e-9)
ok <- sapply(grid, function(p) n_of_power(p) <= N)
if (!any(ok)) return(0)
i <- max(which(ok)); lo <- grid[i]; hi <- if (i < length(grid)) grid[i + 1] else 1 - 1e-9
for (it in 1:80) { mid <- (lo + hi) / 2; if (n_of_power(mid) <= N) lo <- mid else hi <- mid }
round(lo, 4)
}
# Number to recruit when a proportion d of participants is expected to be lost
with_attrition <- function(n, d = 0.10) ceiling(round(n / (1 - d), 8))
with_attrition(100) # 100 / 0.9 = 111.1 -> 112
[1] 1.959964 0.841621
[1] 112
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| 12.2.1 (n = 100) | 112 | 112 | 0 | ✓ PASS |
| 12.2.2 (n = 2626) | 2918 | 2918 | 0 | ✓ PASS |
| 12.2.3 (n = 80) | 89 | 89 | 0 | ✓ PASS |
| 12.2.4 (n = 99) | 110 | 110 | 0 | ✓ PASS |
| 12.2.5 (n = 550) | 612 | 612 | 0 | ✓ PASS |
| 12.2.6 (n = 155) | 173 | 173 | 0 | ✓ PASS |
| 12.2.7 (n = 543) | 604 | 604 | 0 | ✓ PASS |
| 12.2.8 (n = 635) | 706 | 706 | 0 | ✓ PASS |
| 12.2.9 (n = 555) | 617 | 617 | 0 | ✓ PASS |
| 12.2.10 (n = 495) | 550 | 550 | 0 | ✓ PASS |
| 12.2.11 (n = 518) | 576 | 576 | 0 | ✓ PASS |
| 12.2.12 (n = 695) | 773 | 773 | 0 | ✓ PASS |
| 12.2.13 (n = 348) | 387 | 387 | 0 | ✓ PASS |
| 12.2.14 (n = 3824) | 4249 | 4249 | 0 | ✓ PASS |
| 12.2.15 (n = 50) | 56 | 56 | 0 | ✓ PASS |
| 12.2.16 (n = 294) | 327 | 327 | 0 | ✓ PASS |
| 12.2.17 (n = 830) | 923 | 923 | 0 | ✓ PASS |
| 12.2.18 (n = 115) | 128 | 128 | 0 | ✓ PASS |
| 12.2.19 (n = 260) | 289 | 289 | 0 | ✓ PASS |
| 12.2.20 (n = 576) | 640 | 640 | 0 | ✓ PASS |
ขนาดตัวอย่างขั้นต่ำ power และจำนวนที่แนะนำหลังเผื่อการสูญหายของทั้ง 20 รูปแบบตรงกับ R ทุกค่า แถวที่ไม่ผ่านในหัวข้อย่อยเป็นความต่างของวิธีที่อธิบายไว้ในหัวข้อนั้น (การประมาณด้วยการแจกแจงปกติของ t-test และความแปรปรวนแบบย่อของ Poisson)
The minimum sample sizes, powers and recommended numbers after attrition of all 20 designs agree with R; the failed rows in the sub-sections are differences of method explained there (the normal approximation of the t-test designs and the simplified variance of the Poisson design).
12.2.1One-sample mean (test μ vs known μ₀)
ใช้เมื่อจะทดสอบว่าค่าเฉลี่ยของกลุ่มเดียวต่างจากค่าอ้างอิงที่ทราบแล้วหรือไม่ (one-sample t-test) เช่น ค่าเฉลี่ยของหน่วยบริการใหม่เทียบกับค่าเฉลี่ยระดับจังหวัด
Use when one group's mean is to be compared with a known reference value (one-sample t-test), for example a new unit's mean against the provincial mean.
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- μ1, μ0
- ค่าเฉลี่ยที่คาดว่าจะพบ และค่าอ้างอิงexpected mean and reference mean
- σ, d
- ส่วนเบี่ยงเบนมาตรฐานของตัวแปรผลลัพธ์ และขนาดอิทธิพล (Cohen's d)standard deviation of the outcome and the effect size (Cohen's d)
ใน DAPH: ใส่ Cohen's d โดยตรง หรือใส่ค่าเฉลี่ยที่คาดหวัง ค่าอ้างอิง และ SD แล้ว DAPH คำนวณ d ให้ · n ปัดขึ้นเป็นจำนวนเต็ม · สูตรใช้การแจกแจงปกติแทนการแจกแจง t จึงได้ n น้อยกว่าที่ t-test ต้องการจริงเล็กน้อย (ตัวอย่างนี้ 100 เทียบกับ 102)
In DAPH: enter Cohen's d directly, or the expected mean, the reference mean and the SD, from which DAPH computes d. n is rounded up. The formula uses the normal distribution instead of the t distribution, so n is slightly below what a t-test really needs (here 100 against 102).
โจทย์: ศูนย์ล้างไตทางช่องท้องแห่งใหม่ต้องการทดสอบว่าคะแนนคุณภาพชีวิตก่อนการรักษาเฉลี่ยของผู้ป่วยต่างจากค่าเฉลี่ยของข้อมูลนำร่องหรือไม่
Scenario: A new peritoneal-dialysis centre wants to test whether its patients' mean pre-treatment quality-of-life score differs from the pilot-data mean.
ค่าที่ใช้และที่มา: μ0 = 68.4 และ σ = 17.8 (ข้อมูลตัวอย่าง: ค่าเฉลี่ย 68.36 และ SD 17.85 ของ qolscore1) · μ1 = 73.4 คือ μ0 + 5 คะแนน ซึ่งเป็นผลต่างน้อยที่สุดที่ผู้วางแผนเห็นว่ามีความหมาย (สมมติฐานของผู้วางแผน) · โหมด power: ศูนย์รับผู้ป่วยได้ N = 60 ราย
Inputs and their sources: μ0 = 68.4 and σ = 17.8 (example data: mean 68.36 and SD 17.85 of qolscore1); μ1 = 73.4 = μ0 + 5 points, the smallest difference the planners consider meaningful (planner's assumption). Power mode: the centre can enrol N = 60 patients.
# 12.2.1 One-sample mean: QoL of a new PD centre vs the pilot mean
round(c(mean = mean(d$qolscore1), sd = sd(d$qolscore1)), 2) # -> mu0 = 68.4, SD = 17.8
mu0 <- 68.4; mu1 <- 73.4; s <- 17.8 # mu1 = mu0 + 5 points (smallest difference worth detecting)
n_one_mean <- function(power, alpha = 0.05) {
dd <- abs(mu1 - mu0) / s
ceiling(((qnorm(1 - alpha / 2) + qnorm(power)) / dd)^2)
}
c(d = round(abs(mu1 - mu0) / s, 4), n = n_one_mean(0.80), recruit = with_attrition(n_one_mean(0.80)))
power_at_N(n_one_mean, 60)
power.t.test(delta = 5, sd = 17.8, power = 0.80, type = "one.sample")$n # t-based n (stats)
mean sd
68.36 17.85
d n recruit
0.2809 100.0000 112.0000
[1] 0.5855
[1] 101.4111
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| d | 0.2809 | 0.2809 | < 0.00005 | ✓ PASS |
| n | 100 | 100 | 0 | ✓ PASS |
| power ที่ N = 60 คนpower at N = 60 | 0.5855 | 0.5855 | < 0.00005 | ✓ PASS |
| n ของ t-test ตามการแจกแจง t จริง (power.t.test)n for the t-test from the exact t distribution (power.t.test) | 102 (101.41) | 100 | 2 | ✗ FAIL |
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
- Machin, D., Campbell, M. J., Tan, S. B., & Tan, S. H. (2018). Sample sizes for clinical, laboratory and epidemiology studies (4th ed.). Wiley. doi:10.1002/9781118874905
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.2Two-sample mean (independent t-test)
ใช้เมื่อเปรียบเทียบค่าเฉลี่ยของตัวแปรต่อเนื่องระหว่างสองกลุ่มที่เป็นอิสระต่อกัน (independent t-test หัวข้อ 1.1) เช่น การทดลองแบบสุ่มหรือการศึกษาแบบติดตามสองกลุ่ม
Use when the mean of a continuous outcome is compared between two independent groups (independent t-test, section 1.1), for example a randomised trial or a two-group cohort.
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- μ1, μ2, σ
- ค่าเฉลี่ยที่คาดหวังของสองกลุ่ม และ SD ร่วม (pooled SD)expected means of the two groups and the pooled SD
- r, d
- อัตราส่วน n2/n1 (1 = สองกลุ่มเท่ากัน) และขนาดอิทธิพล Cohen's dallocation ratio n2/n1 (1 = equal groups) and Cohen's d
ใน DAPH: ใส่ d หรือค่าเฉลี่ยสองกลุ่มกับ SD ร่วม และอัตราส่วน n2/n1 · n1 ปัดขึ้นก่อน แล้ว n2 = ⌈r × n1⌉ · ผลรวมคือ n1 + n2 · ใช้การประมาณด้วยการแจกแจงปกติเช่นเดียวกับ 12.2.1
In DAPH: enter d, or the two means with the pooled SD, and the ratio n2/n1. n1 is rounded up first, then n2 = ⌈r × n1⌉, and the total is n1 + n2. The normal approximation is used, as in 12.2.1.
โจทย์: วางแผนการทดลองเปรียบเทียบ APD กับ CAPD ด้วยคะแนนคุณภาพชีวิตหลังการรักษา โดยใช้ผลต่างที่พบในข้อมูลนำร่องเป็นค่าที่ต้องการตรวจพบ
Scenario: Plan a trial comparing APD with CAPD on the post-treatment quality-of-life score, taking the difference seen in the pilot data as the difference to detect.
ค่าที่ใช้และที่มา: ค่าเฉลี่ย CAPD = 74.89, APD = 76.84 และ SD ร่วม = 17.83 (ข้อมูลตัวอย่าง: qolscore3 แยกตาม group) · r = 1 · เก็บทศนิยมสองตำแหน่งเพราะผลต่างมีขนาดเล็ก · โหมด power: รับได้ทั้งหมด N = 800 ราย (กลุ่มละ 400)
Inputs and their sources: means CAPD = 74.89 and APD = 76.84 with pooled SD = 17.83 (example data: qolscore3 by group); r = 1; two decimals are kept because the difference is small. Power mode: N = 800 in total (400 per group).
ผลต่างที่พบในข้อมูลนำร่อง (1.95 คะแนน, d = 0.11) มีขนาดเล็ก จึงต้องใช้ตัวอย่างจำนวนมาก หากผลต่างที่มีความหมายทางคลินิกคือ 5 คะแนน (d = 0.28) จะต้องการเพียงกลุ่มละ 201 คน (ดู nt ใน 12.2.19) การเลือกขนาดผลที่ต้องการตรวจพบจึงเป็นการตัดสินใจที่สำคัญที่สุดของการคำนวณ
The pilot difference (1.95 points, d = 0.11) is small, so a large sample is needed. If the clinically meaningful difference is 5 points (d = 0.28), only 201 per group are needed (see nt in 12.2.19): the choice of the effect to detect is the most important decision in the calculation.
# 12.2.2 Two-sample mean: post-treatment QoL, CAPD vs APD
st <- aggregate(qolscore3 ~ group, d, function(x) c(n = length(x), mean = mean(x), sd = sd(x)))
st <- data.frame(group = st$group, st$qolscore3); print(st, digits = 6)
sp <- sqrt(sum((st$n - 1) * st$sd^2) / (sum(st$n) - 2)); round(sp, 2) # pooled SD 17.83
m1 <- 74.89; m2 <- 76.84; s <- 17.83
n_two_means <- function(power, alpha = 0.05, ratio = 1) {
dd <- abs(m1 - m2) / s
n1 <- ceiling((qnorm(1 - alpha / 2) + qnorm(power))^2 * (1 + 1 / ratio) / dd^2)
n1 + ceiling(n1 * ratio) # total of the two groups
}
c(d = round(abs(m1 - m2) / s, 4), n_total = n_two_means(0.80), recruit = with_attrition(n_two_means(0.80)))
power_at_N(n_two_means, 800)
power.t.test(delta = 1.95, sd = 17.83, power = 0.80)$n # t-based n per group (stats)
group n mean sd
1 1 656 74.8864 17.3738
2 2 644 76.8424 18.2767
[1] 17.83
d n_total recruit
0.1094 2626.0000 2918.0000
[1] 0.3397
[1] 1313.376
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| SD ร่วมจากข้อมูลpooled SD from the data | 17.83 | — | — | ✓ PASS |
| d | 0.1094 | 0.1094 | < 0.00005 | ✓ PASS |
| n ต่อกลุ่ม / รวมn per group / total | 1313 / 2626 | 1313 / 2626 | 0 | ✓ PASS |
| power ที่ N = 800 คนpower at N = 800 | 0.3397 | 0.3397 | < 0.00005 | ✓ PASS |
| n ต่อกลุ่มตามการแจกแจง t จริง (power.t.test)n per group from the exact t distribution (power.t.test) | 1314 (1313.38) | 1313 | 1 | ✗ FAIL |
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
- Machin, D., Campbell, M. J., Tan, S. B., & Tan, S. H. (2018). Sample sizes for clinical, laboratory and epidemiology studies (4th ed.). Wiley. doi:10.1002/9781118874905
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.3Paired mean (paired t-test, pre-post)
ใช้เมื่อวัดผลลัพธ์ต่อเนื่องสองครั้งในคนเดียวกัน (ก่อน–หลัง) หรือในคู่ที่จับคู่กัน (paired t-test หัวข้อ 1.1)
Use when a continuous outcome is measured twice in the same people (before and after) or in matched pairs (paired t-test, section 1.1).
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- δ̄, σδ
- ค่าเฉลี่ยของผลต่างภายในคน (หลัง − ก่อน) ที่คาดหวัง และ SD ของผลต่างนั้นexpected mean within-person change (after − before) and its SD
- dz
- ขนาดอิทธิพลของข้อมูลจับคู่effect size for paired data
ใน DAPH: ใส่ d หรือค่าเฉลี่ยของผลต่างกับ SD ของผลต่าง · n ปัดขึ้น · SD ของผลต่างมักไม่มีรายงาน แต่คำนวณได้จาก SD ของการวัดแต่ละครั้ง (σ) และสหสัมพันธ์ระหว่างสองครั้ง (ρ): \( \sigma_{\delta} = \sigma\sqrt{2(1-\rho)} \)
In DAPH: enter d, or the mean change with the SD of the change. n is rounded up. The SD of the change is often not reported, but it follows from the SD of each measurement (σ) and the correlation between the two (ρ): \( \sigma_{\delta} = \sigma\sqrt{2(1-\rho)} \).
โจทย์: โปรแกรมออกกำลังกาย 6 เดือนสำหรับผู้ป่วยล้างไตทางช่องท้อง วัดคะแนนคุณภาพชีวิตก่อนและหลังโปรแกรมในคนเดียวกัน
Scenario: A 6-month exercise programme for peritoneal-dialysis patients, with the quality-of-life score measured before and after in the same patients.
ค่าที่ใช้และที่มา: ผลต่างที่ต้องการตรวจพบ δ̄ = 5 คะแนน (สมมติฐานของผู้วางแผน) · σ = 17.8 (ข้อมูลตัวอย่าง) และ ρ = 0.6 (สมมติฐาน) ได้ σδ = 15.92 · ไม่ใช้ SD ของผลต่างในข้อมูลตัวอย่าง (0.4646) และสหสัมพันธ์ (0.9997) เพราะคะแนนในข้อมูลตัวอย่างเปลี่ยนแปลงเกือบเท่ากันทุกคน ซึ่งไม่สมจริงและจะได้ n เล็กเกินจริง · โหมด power: N = 50 คู่
Inputs and their sources: change to detect δ̄ = 5 points (planner's assumption); σ = 17.8 (example data) and ρ = 0.6 (assumption) give σδ = 15.92. The example data's own SD of change (0.4646) and correlation (0.9997) are not used: every patient's score changes by almost the same amount there, which is unrealistic and would give a far too small n. Power mode: N = 50 pairs.
# 12.2.3 Paired mean: QoL before and after a 6-month programme
round(c(sd_change = sd(d$qolscore3 - d$qolscore1), r = cor(d$qolscore1, d$qolscore3)), 4) # artefact, not used
sd_change <- 17.8 * sqrt(2 * (1 - 0.6)); round(sd_change, 2) # SD of the change if r = 0.6
n_paired <- function(power, alpha = 0.05) {
dd <- 5 / 15.92
ceiling(((qnorm(1 - alpha / 2) + qnorm(power)) / dd)^2)
}
c(d = round(5 / 15.92, 4), n_pairs = n_paired(0.80), recruit = with_attrition(n_paired(0.80)))
power_at_N(n_paired, 50)
power.t.test(delta = 5, sd = 15.92, power = 0.80, type = "paired")$n # t-based (stats)
sd_change r
0.4646 0.9997
[1] 15.92
d n_pairs recruit
0.3141 80.0000 89.0000
[1] 0.6029
[1] 81.5124
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| σδ | 15.92 | — | — | ✓ PASS |
| dz | 0.3141 | 0.3141 | < 0.00005 | ✓ PASS |
| จำนวนคู่number of pairs | 80 | 80 | 0 | ✓ PASS |
| power ที่ N = 50 คู่power at N = 50 pairs | 0.6029 | 0.6029 | < 0.00005 | ✓ PASS |
| จำนวนคู่ตามการแจกแจง t จริง (power.t.test)pairs from the exact t distribution (power.t.test) | 82 (81.51) | 80 | 2 | ✗ FAIL |
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
- Machin, D., Campbell, M. J., Tan, S. B., & Tan, S. H. (2018). Sample sizes for clinical, laboratory and epidemiology studies (4th ed.). Wiley. doi:10.1002/9781118874905
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.4One-sample proportion (test π vs known π₀)
ใช้เมื่อทดสอบว่าสัดส่วนของกลุ่มเดียวต่างจากค่าอ้างอิงหรือไม่ เช่น ความชุกระดับประเทศหรือค่าเป้าหมาย
Use when one group's proportion is tested against a reference value, such as a national prevalence or a target.
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- p0, p1
- สัดส่วนภายใต้ H₀ (ค่าอ้างอิง) และสัดส่วนที่คาดว่าจะพบ (H₁)proportion under H₀ (reference) and the expected proportion (H₁)
ใน DAPH: ใส่ p0 และ p1 (ต้องอยู่ระหว่าง 0 ถึง 1 และไม่เท่ากัน) · ไม่มีการแก้ความต่อเนื่อง (continuity correction) · n ปัดขึ้น
In DAPH: enter p0 and p1 (between 0 and 1 and different). No continuity correction is applied; n is rounded up.
โจทย์: โครงการฝึกการเปลี่ยนน้ำยาเพื่อลดการติดเชื้อในช่องท้อง ต้องการทดสอบว่าสัดส่วนผู้ป่วยที่เกิดเยื่อบุช่องท้องอักเสบอย่างน้อย 1 ครั้งลดลงจากค่าเดิมหรือไม่
Scenario: A bag-exchange training programme aims to lower the proportion of patients with at least one peritonitis episode, compared with the current level.
ค่าที่ใช้และที่มา: p0 = 0.54 (ข้อมูลตัวอย่าง: 702 จาก 1,300 รายมีเยื่อบุช่องท้องอักเสบอย่างน้อย 1 ครั้งระหว่างติดตาม) · p1 = 0.40 (เป้าหมายของโครงการ) · โหมด power: N = 80
Inputs and their sources: p0 = 0.54 (example data: 702 of 1,300 patients had at least one peritonitis episode during follow-up); p1 = 0.40 (programme target). Power mode: N = 80.
# 12.2.4 One proportion: share of patients with at least one peritonitis episode
round(mean(d$n_peritonitis >= 1), 4) # pilot value 0.54
p0 <- 0.54; p1 <- 0.40
n_one_prop <- function(power, alpha = 0.05) {
ceiling(((qnorm(1 - alpha / 2) * sqrt(p0 * (1 - p0)) + qnorm(power) * sqrt(p1 * (1 - p1))) / (p1 - p0))^2)
}
c(n = n_one_prop(0.80), recruit = with_attrition(n_one_prop(0.80)))
power_at_N(n_one_prop, 80)
[1] 0.54
n recruit
99 110
[1] 0.713
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| p0 จากข้อมูลfrom the data | 0.54 | — | — | ✓ PASS |
| n | 99 | 99 | 0 | ✓ PASS |
| power ที่ N = 80 คนpower at N = 80 | 0.713 | 0.7130 | < 0.00005 | ✓ PASS |
- Fleiss, J. L., Levin, B., & Paik, M. C. (2003). Statistical methods for rates and proportions (3rd ed.). Wiley. ISBN 978-0-471-52629-2.
- Machin, D., Campbell, M. J., Tan, S. B., & Tan, S. H. (2018). Sample sizes for clinical, laboratory and epidemiology studies (4th ed.). Wiley. doi:10.1002/9781118874905
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.5Two-sample proportion (independent, Fleiss)
ใช้เมื่อเปรียบเทียบสัดส่วนของเหตุการณ์ระหว่างสองกลุ่มที่เป็นอิสระต่อกัน (chi-square test ของตาราง 2×2 หัวข้อ 2.4)
Use when an event proportion is compared between two independent groups (chi-square test of a 2×2 table, section 2.4).
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- p1, p2
- สัดส่วนเหตุการณ์ที่คาดหวังในกลุ่ม 1 และกลุ่ม 2expected event proportions in groups 1 and 2
- p̄, r
- สัดส่วนรวมถ่วงน้ำหนักภายใต้ H₀ และอัตราส่วน n2/n1weighted pooled proportion under H₀ and the ratio n2/n1
ใน DAPH: ใช้ความแปรปรวนรวม (pooled) สำหรับพจน์ของ α และความแปรปรวนแยกกลุ่มสำหรับพจน์ของ β ไม่มีการแก้ความต่อเนื่อง · n1 ปัดขึ้น แล้ว n2 = ⌈r n1⌉ · DAPH แสดง odds ratio ที่สอดคล้องกับ p1 และ p2 ด้วย · ฟังก์ชัน power.prop.test ของ R ใช้สูตรเดียวกันเมื่อ r = 1
In DAPH: the pooled variance is used for the α term and the separate variances for the β term, with no continuity correction. n1 is rounded up and n2 = ⌈r n1⌉. DAPH also shows the odds ratio implied by p1 and p2. R's power.prop.test uses the same formula when r = 1.
โจทย์: วางแผนการศึกษาเปรียบเทียบสัดส่วนผู้เสียชีวิตระหว่างการติดตามของผู้ป่วย CAPD และ APD
Scenario: Plan a study comparing the proportion of patients who die during follow-up between CAPD and APD.
ค่าที่ใช้และที่มา: p1 = 0.131 (CAPD) และ p2 = 0.222 (APD) จากข้อมูลตัวอย่าง (86/656 และ 143/644, status แยกตาม group) · r = 1 · โหมด power: N = 400 (กลุ่มละ 200)
Inputs and their sources: p1 = 0.131 (CAPD) and p2 = 0.222 (APD) from the example data (86/656 and 143/644, status by group); r = 1. Power mode: N = 400 (200 per group).
# 12.2.5 Two proportions: death during follow-up, CAPD vs APD
round(tapply(d$status, d$group, mean), 4) # 0.1311 and 0.2220
p1 <- 0.131; p2 <- 0.222
n_two_prop <- function(power, alpha = 0.05, ratio = 1) {
pbar <- (p1 + ratio * p2) / (1 + ratio)
n1 <- ceiling(((qnorm(1 - alpha / 2) * sqrt((1 + 1 / ratio) * pbar * (1 - pbar)) +
qnorm(power) * sqrt(p1 * (1 - p1) + p2 * (1 - p2) / ratio)) / (p1 - p2))^2)
n1 + ceiling(n1 * ratio)
}
c(n_total = n_two_prop(0.80), recruit = with_attrition(n_two_prop(0.80)))
power_at_N(n_two_prop, 400)
power.prop.test(p1 = 0.131, p2 = 0.222, power = 0.80)$n # same formula (stats), per group
power.prop.test(p1 = 0.131, p2 = 0.222, n = 200)$power
1 2
0.1311 0.2220
n_total recruit
550 612
[1] 0.6664
[1] 274.3445
[1] 0.6664117
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| n ต่อกลุ่ม / รวมn per group / total | 275 / 550 | 275 / 550 | 0 | ✓ PASS |
| power.prop.test (สูตรเดียวกัน) n ต่อกลุ่มpower.prop.test (same formula), n per group | 274.34 → 275 | 275 | 0 | ✓ PASS |
| power ที่ N = 400 คนpower at N = 400 | 0.6664 | 0.6664 | < 0.00005 | ✓ PASS |
- Fleiss, J. L., Levin, B., & Paik, M. C. (2003). Statistical methods for rates and proportions (3rd ed.). Wiley. ISBN 978-0-471-52629-2.
- Machin, D., Campbell, M. J., Tan, S. B., & Tan, S. H. (2018). Sample sizes for clinical, laboratory and epidemiology studies (4th ed.). Wiley. doi:10.1002/9781118874905
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.6Paired proportion (McNemar — matched pairs)
ใช้เมื่อผลลัพธ์แบบใช่/ไม่ใช่วัดสองครั้งในคนเดียวกัน หรือในคู่ที่จับคู่ 1:1 แล้วทดสอบด้วย McNemar test (หัวข้อ 2.5) ข้อมูลที่ใช้ทดสอบมาจากคู่ที่ผลไม่ตรงกันเท่านั้น (Connor, 1987)
Use when a yes/no outcome is measured twice in the same people, or in 1:1 matched pairs, and tested with McNemar's test (section 2.5); only the discordant pairs carry information (Connor, 1987).
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- p10, p01
- สัดส่วนของคู่ที่ผลไม่ตรงกันในสองทิศทาง (ช่อง b และ c ของตาราง 2×2 แบบจับคู่)proportions of pairs discordant in each direction (cells b and c of the paired 2×2 table)
- pd, δ
- สัดส่วนคู่ที่ไม่ตรงกันรวม และผลต่างของสองทิศทางtotal discordant proportion and the difference between the two directions
ใน DAPH: ใส่ p10 และ p01 (แต่ละค่ามากกว่า 0 ผลรวมไม่เกิน 1 และต้องไม่เท่ากัน) · n ปัดขึ้น
In DAPH: enter p10 and p01 (each above 0, sum at most 1, not equal). n is rounded up.
โจทย์: เปรียบเทียบสัดส่วนผู้ป่วยที่ถูกจัดว่ามีภาวะทุพโภชนาการโดยแบบคัดกรอง A กับแบบคัดกรอง B ซึ่งใช้กับผู้ป่วยคนเดียวกัน
Scenario: Compare the proportion of patients classified as malnourished by screening tool A and by screening tool B, both applied to the same patients.
ค่าที่ใช้และที่มา: p10 = 0.15 (A ผลบวก B ผลลบ) และ p01 = 0.05 (A ผลลบ B ผลบวก) เป็นสมมติฐานของผู้วางแผน เพราะข้อมูลตัวอย่างไม่มีการวัดแบบใช่/ไม่ใช่สองครั้งที่เหมาะกับคำถามนี้ · โหมด power: N = 100 คู่
Inputs and their sources: p10 = 0.15 (A positive, B negative) and p01 = 0.05 (A negative, B positive) are planner's assumptions, because the example data have no pair of yes/no measurements suited to this question. Power mode: N = 100 pairs.
# 12.2.6 Paired proportion (McNemar): two screening tools on the same patients
p10 <- 0.15; p01 <- 0.05
n_mcnemar <- function(power, alpha = 0.05) {
pd <- p10 + p01; dl <- p10 - p01
ceiling((qnorm(1 - alpha / 2) * sqrt(pd) + qnorm(power) * sqrt(pd - dl^2))^2 / dl^2)
}
c(n_pairs = n_mcnemar(0.80), recruit = with_attrition(n_mcnemar(0.80)))
power_at_N(n_mcnemar, 100)
n_pairs recruit
155 173
[1] 0.6115
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| จำนวนคู่number of pairs | 155 | 155 | 0 | ✓ PASS |
| power ที่ N = 100 คู่power at N = 100 pairs | 0.6115 | 0.6115 | < 0.00005 | ✓ PASS |
- Connor, R. J. (1987). Sample size for testing differences in proportions for the paired-sample design. Biometrics, 43(1), 207–211. doi:10.2307/2531961
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.7Pearson correlation (test H₀: ρ = 0)
ใช้เมื่อทดสอบว่าสหสัมพันธ์เพียร์สันต่างจาก 0 หรือไม่ (หัวข้อ 1.8) โดยใช้การแปลงของ Fisher
Use when a Pearson correlation is tested against 0 (section 1.8), via Fisher's z transformation.
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- r
- สหสัมพันธ์ที่ต้องการตรวจพบ (DAPH ใช้ค่าสัมบูรณ์ เครื่องหมายไม่มีผล)correlation to detect (DAPH uses its absolute value; the sign does not matter)
ใน DAPH: ใส่ r ระหว่าง −1 ถึง 1 ที่ไม่ใช่ 0 · n ปัดขึ้นหลังบวก 3 · ฟังก์ชัน pwr.r.test ของ R ใช้การประมาณต่างออกไปเล็กน้อย (ค่าวิกฤตจากการแจกแจง t และพจน์แก้ความเอนเอียงของ r) จึงได้ 542 แทน 543
In DAPH: enter r between −1 and 1, not 0. n is rounded up after adding 3. R's pwr.r.test uses a slightly different approximation (a t-based critical value and a bias term for r), so it gives 542 rather than 543.
โจทย์: อายุสัมพันธ์กับคะแนนคุณภาพชีวิตหลังการรักษาหรือไม่
Scenario: Is age correlated with the post-treatment quality-of-life score?
ค่าที่ใช้และที่มา: r = −0.12 (ข้อมูลตัวอย่าง: สหสัมพันธ์ของ age กับ qolscore3 = −0.1243) · โหมด power: N = 300
Inputs and their sources: r = −0.12 (example data: correlation of age with qolscore3 = −0.1243). Power mode: N = 300.
# 12.2.7 Correlation: age and post-treatment QoL
round(cor(d$age, d$qolscore3), 4) # -0.1243 -> r = -0.12
r <- -0.12
n_corr <- function(power, alpha = 0.05) {
ceiling(((qnorm(1 - alpha / 2) + qnorm(power)) / atanh(abs(r)))^2 + 3)
}
c(n = n_corr(0.80), recruit = with_attrition(n_corr(0.80)))
power_at_N(n_corr, 300)
library(pwr)
pwr.r.test(r = 0.12, power = 0.80)$n # pwr: slightly different method
[1] -0.1243
n recruit
543 604
[1] 0.547
[1] 541.9252
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| n | 543 | 543 | 0 | ✓ PASS |
| power ที่ N = 300 คนpower at N = 300 | 0.547 | 0.5470 | < 0.00005 | ✓ PASS |
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
- Machin, D., Campbell, M. J., Tan, S. B., & Tan, S. H. (2018). Sample sizes for clinical, laboratory and epidemiology studies (4th ed.). Wiley. doi:10.1002/9781118874905
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.8Linear regression (overall R² test, Cohen's f²)
ใช้เมื่อทดสอบว่าตัวแปรอิสระ k ตัวร่วมกันอธิบายตัวแปรผลลัพธ์ได้หรือไม่ (F-test ของ R² = 0 ในการถดถอยเชิงเส้น หัวข้อ 1.12) โดยใช้ขนาดอิทธิพล f² ของ Cohen (0.02 เล็ก, 0.15 ปานกลาง, 0.35 ใหญ่)
Use when testing whether k predictors together explain the outcome (the F test of R² = 0 in linear regression, section 1.12), with Cohen's f² (0.02 small, 0.15 medium, 0.35 large).
- k
- จำนวนตัวแปรอิสระทั้งหมดในโมเดล (นับ dummy ของตัวแปรกลุ่มด้วย)number of predictors in the model (dummy variables counted)
- R², f²
- R² ที่คาดหวังของโมเดล และขนาดอิทธิพลของ Cohenexpected R² of the model and Cohen's effect size
- Fk, N−k−1(λ)
- การแจกแจง F แบบ non-central ที่ degrees of freedom k และ N − k − 1 และ non-centrality λnon-central F distribution with k and N − k − 1 degrees of freedom and non-centrality λ
ใน DAPH: ใส่ f² หรือ R² และจำนวนตัวแปรอิสระ k · DAPH หาจำนวนเต็ม N ที่น้อยที่สุดที่ power ถึงเป้าหมาย (ไม่มีตัวเลือกด้านของการทดสอบ เพราะเป็น F-test) · ฟังก์ชัน pwr.f2.test ของ R ใช้ λ = f²(u + v + 1) = N f² เท่ากัน · ข้อจำกัด: DAPH ทดสอบตัวแปรทั้ง k ตัวพร้อมกันเสมอ (df1 = k) แม้หน้าจอจะมีตัวช่วยคำนวณ f² จาก ΔR² ของตัวแปรที่สนใจ หากต้องการทดสอบตัวแปร u ตัวที่เพิ่มเข้าไปในโมเดล k ตัว ให้ใช้ R: pwr.f2.test(u = u, f2 = ΔR²/(1 − R²full), power = 0.80) แล้ว N = v + k + 1
In DAPH: enter f² or R² and the number of predictors k. DAPH finds the smallest whole N whose power reaches the target (there is no tail option because it is an F test). R's pwr.f2.test uses the same λ = f²(u + v + 1) = N f². Limitation: DAPH always tests all k predictors together (df1 = k), although the screen offers a helper that computes f² from the ΔR² of the predictors of interest. To test u predictors added to a model of k predictors, use R: pwr.f2.test(u = u, f2 = ΔR²/(1 − R²full), power = 0.80), then N = v + k + 1.
โจทย์: ลักษณะผู้ป่วย 5 ตัว (กลุ่มการรักษา อายุ เพศ BMI โรคเรื้อรัง) ร่วมกันอธิบายคะแนนคุณภาพชีวิตหลังการรักษาได้หรือไม่
Scenario: Do five patient characteristics (treatment group, age, gender, BMI, chronic disease) together explain the post-treatment quality-of-life score?
ค่าที่ใช้และที่มา: R² = 0.02 และ k = 5 (ข้อมูลตัวอย่าง: R² ของ qolscore3 บน 5 ตัวแปรนี้ = 0.0202) · โหมด power: N = 400
Inputs and their sources: R² = 0.02 and k = 5 (example data: R² of qolscore3 on these 5 predictors = 0.0202). Power mode: N = 400.
# 12.2.8 Linear regression: five patient characteristics and post-treatment QoL
fit <- lm(qolscore3 ~ factor(group) + age + factor(gender) + bmi + factor(chronic), data = d)
round(summary(fit)$r.squared, 4) # R2 = 0.0202 -> 0.02
library(pwr)
f2 <- 0.02 / (1 - 0.02)
v <- pwr.f2.test(u = 5, f2 = f2, power = 0.80)$v # same non-central F, lambda = f2 * N
c(f2 = round(f2, 4), n = ceiling(v) + 5 + 1, recruit = with_attrition(ceiling(v) + 6))
pwr.f2.test(u = 5, v = 400 - 5 - 1, f2 = f2)$power
[1] 0.0202
f2 n recruit
0.0204 635.0000 706.0000
[1] 0.5675048
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| f² | 0.0204 | 0.0204 | < 0.00005 | ✓ PASS |
| n | 635 | 635 | 0 | ✓ PASS |
| power ที่ N = 400 คนpower at N = 400 | 0.5675 | 0.5675 | < 0.00005 | ✓ PASS |
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.9Logistic regression (univariable & multivariable)
ใช้เมื่อทดสอบ odds ratio ของตัวแปรที่สนใจหนึ่งตัวในการถดถอยโลจิสติก (หัวข้อ 2.1) ทั้งแบบตัวแปรเดียวและแบบปรับด้วยตัวแปรอื่น สูตรของ Hsieh, Bloch & Larsen (1998) แยกตามชนิดของตัวแปรที่สนใจ
Use when testing the odds ratio of one predictor of interest in logistic regression (section 2.1), alone or adjusted for other covariates. Hsieh, Bloch & Larsen (1998) give a different formula for each type of predictor.
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- P̄
- สัดส่วนการเกิดเหตุการณ์โดยรวม (ค่า p₀ ที่กรอก)overall event proportion (the p₀ entered)
- B, P1, P2
- สัดส่วนผู้สัมผัส (X = 1) และอัตราการเกิดเหตุการณ์ในกลุ่มไม่สัมผัสและกลุ่มสัมผัส ซึ่ง DAPH แก้หาจาก P̄ และ OR ให้ (1 − B)P1 + B P2 = P̄exposure prevalence (X = 1) and the event rates in the unexposed and exposed, solved by DAPH from P̄ and the OR so that (1 − B)P1 + B P2 = P̄
- OR*, σX
- odds ratio ต่อ 1 SD ของ X และ SD ของ X (ใช้แปลง OR ต่อ 1 หน่วย)odds ratio per 1 SD of X and the SD of X (used to convert a per-unit OR)
- ρ, k
- สหสัมพันธ์พหุคูณของตัวแปรที่สนใจกับตัวแปรอื่นในโมเดล และจำนวนตัวแปรอิสระทั้งหมดmultiple correlation of the predictor of interest with the other covariates, and the total number of predictors
ใน DAPH: เลือกชนิดตัวแปรทำนาย (สองกลุ่มเป็นค่าเริ่มต้น ใช้สมการ 2 กับความชุกของการสัมผัส B · ต่อเนื่องต่อ 1 SD ใช้สมการ 1 · ต่อเนื่องต่อ 1 หน่วยใช้สมการ 1 หลังคูณ ln OR ด้วย SD ของ X) ใส่สัดส่วนเหตุการณ์โดยรวม p₀ และ OR · ช่อง ρ รับ สหสัมพันธ์ ไม่ใช่ R² (DAPH ยกกำลังสองให้ เช่น ρ = 0.5 เพิ่ม n 1.33 เท่า) ถ้าเว้นว่างหรือใส่ 0 จะเป็น logistic ตัวแปรเดียวและ DAPH ตั้ง k = 1 · n ปัดขึ้น หารด้วย 1 − ρ² แล้วปัดขึ้นอีกครั้ง จากนั้นใช้ค่าที่มากกว่าระหว่างค่านี้กับเกณฑ์ขั้นต่ำ 10 เหตุการณ์ต่อตัวแปร (EPV; Peduzzi et al., 1996) · โหมด power ใช้ nadj และแจ้งแยกว่าผ่านเกณฑ์ EPV หรือไม่ · เกณฑ์ EPV ของ DAPH ใช้ p₀ เสมอ ถ้า p₀ เกิน 0.5 ให้ตรวจจำนวนคนที่ไม่เกิดเหตุการณ์ด้วยตนเอง
In DAPH: choose the predictor type (binary, the default, uses eq. 2 with the exposure prevalence B; continuous per 1 SD uses eq. 1; continuous per unit uses eq. 1 after multiplying ln OR by the SD of X), then enter the overall event proportion p₀ and the OR. The ρ box takes the correlation, not R² (DAPH squares it; ρ = 0.5 inflates n 1.33-fold); empty or 0 means a simple logistic model and DAPH then sets k = 1. n is rounded up, divided by 1 − ρ², rounded up again, and the final n is the larger of this and the floor of 10 events per variable (EPV; Peduzzi et al., 1996). Power mode works on nadj and reports separately whether the EPV floor is met. DAPH's EPV floor always uses p₀; when p₀ is above 0.5, check the number of non-events yourself.
โจทย์: การศึกษาใหม่จะทดสอบว่า APD สัมพันธ์กับการเสียชีวิตหลังปรับด้วยอายุ เพศ BMI และโรคเรื้อรังหรือไม่
Scenario: A new study will test whether APD is associated with death after adjusting for age, gender, BMI and chronic disease.
ค่าที่ใช้และที่มา: p₀ = 0.176 (ข้อมูลตัวอย่าง: เสียชีวิต 0.1762) · OR = 1.89 (OR ของ APD เทียบ CAPD ในข้อมูลตัวอย่าง 1.8918) · ตัวแปรทำนายสองกลุ่ม B = 0.5 (ข้อมูลตัวอย่าง 0.4954) · k = 5 · ρ = 0.06 (ข้อมูลตัวอย่าง: √R² ของ APD บนตัวแปรอื่น 4 ตัว = 0.0577) · โหมด power: N = 600
Inputs and their sources: p₀ = 0.176 (example data: 0.1762 died); OR = 1.89 (example-data OR of APD versus CAPD 1.8918); binary predictor with B = 0.5 (example data 0.4954); k = 5; ρ = 0.06 (example data: √R² of APD on the other 4 predictors = 0.0577). Power mode: N = 600.
# 12.2.9 Logistic regression: death and APD (binary exposure), adjusted for 4 covariates
round(c(p0 = mean(d$status), OR = exp(coef(glm(status ~ I(group == 2), binomial, data = d)))[[2]],
B = mean(d$group == 2)), 4)
rho <- sqrt(summary(lm(I(group == 2) ~ age + factor(gender) + bmi + factor(chronic), data = d))$r.squared)
round(rho, 4) # 0.0577 -> rho = 0.06
p0 <- 0.176; OR <- 1.89; B <- 0.5; k <- 5; r2 <- 0.06^2
P1 <- uniroot(function(P1) { o <- P1 / (1 - P1) * OR; (1 - B) * P1 + B * o / (1 + o) - p0 },
c(1e-12, 1 - 1e-12), tol = 1e-14)$root
P2 <- P1 / (1 - P1) * OR / (1 + P1 / (1 - P1) * OR)
n_hsieh <- function(power, alpha = 0.05) { # Hsieh et al. (1998) eq. (2)
Pb <- (1 - B) * P1 + B * P2
ceiling((qnorm(1 - alpha / 2) * sqrt(Pb * (1 - Pb) / B) +
qnorm(power) * sqrt(P1 * (1 - P1) + P2 * (1 - P2) * (1 - B) / B))^2 / ((P1 - P2)^2 * (1 - B)))
}
n_logit <- function(power) ceiling(n_hsieh(power) / (1 - r2)) # VIF = 1 / (1 - rho^2)
n_epv <- ceiling(10 * k / p0)
c(P1 = round(P1, 4), P2 = round(P2, 4), n_hsieh = n_hsieh(0.80), n_adjusted = n_logit(0.80), n_EPV = n_epv,
n = max(n_logit(0.80), n_epv), recruit = with_attrition(max(n_logit(0.80), n_epv)))
power_at_N(n_logit, 600)
p0 OR B
0.1762 1.8918 0.4954
[1] 0.0577
P1 P2 n_hsieh n_adjusted n_EPV n recruit
0.1307 0.2213 553.0000 555.0000 285.0000 555.0000 617.0000
[1] 0.8297
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| P1 / P2 | 0.1307 / 0.2213 | 0.1307 / 0.2213 | < 0.00005 | ✓ PASS |
| n สมการ 2 / nadj / nEPVn eq. 2 / nadj / nEPV | 553 / 555 / 285 | 553 / 555 / 285 | 0 | ✓ PASS |
| n สุดท้ายfinal n | 555 | 555 | 0 | ✓ PASS |
| power ที่ N = 600 คนpower at N = 600 | 0.8297 | 0.8297 | < 0.00005 | ✓ PASS |
- Hsieh, F. Y., Bloch, D. A., & Larsen, M. D. (1998). A simple method of sample size calculation for linear and logistic regression. Statistics in Medicine, 17(14), 1623–1634. doi:10.1002/(SICI)1097-0258(19980730)17:14<1623::AID-SIM871>3.0.CO;2-S
- Peduzzi, P., Concato, J., Kemper, E., Holford, T. R., & Feinstein, A. R. (1996). A simulation study of the number of events per variable in logistic regression analysis. Journal of Clinical Epidemiology, 49(12), 1373–1379. doi:10.1016/S0895-4356(96)00236-3
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.10One-way ANOVA (k groups, Cohen's f)
ใช้เมื่อเปรียบเทียบค่าเฉลี่ยของตั้งแต่ 3 กลุ่มขึ้นไป (one-way ANOVA หัวข้อ 1.2) โดยใช้ขนาดอิทธิพล f ของ Cohen (0.10 เล็ก, 0.25 ปานกลาง, 0.40 ใหญ่)
Use when the means of three or more groups are compared (one-way ANOVA, section 1.2), with Cohen's f (0.10 small, 0.25 medium, 0.40 large).
- k, n, N
- จำนวนกลุ่ม ขนาดต่อกลุ่ม และขนาดรวมnumber of groups, size per group and total size
- σμ, σ, η²
- SD ของค่าเฉลี่ยกลุ่มรอบค่าเฉลี่ยรวม SD ภายในกลุ่ม และสัดส่วนความแปรปรวนที่กลุ่มอธิบายได้SD of the group means around the grand mean, the within-group SD, and the share of variance explained by group
ใน DAPH: ใส่ f และจำนวนกลุ่ม · ขนาดต่อกลุ่มเท่ากัน · DAPH หาจำนวนเต็ม n ต่อกลุ่มที่น้อยที่สุดที่ power ถึงเป้าหมาย และโหมด power คำนวณ power จากการแจกแจงเดียวกันโดยตรง · ตรงกับ pwr.anova.test ของ R
In DAPH: enter f and the number of groups; groups are equal in size. DAPH finds the smallest whole n per group whose power reaches the target, and power mode computes the power from the same distribution directly. This matches R's pwr.anova.test.
โจทย์: คะแนนคุณภาพชีวิตหลังการรักษาต่างกันตามรายได้ครัวเรือน 3 ระดับหรือไม่
Scenario: Does the post-treatment quality-of-life score differ across three household-income groups?
ค่าที่ใช้และที่มา: f = 0.14 (ข้อมูลตัวอย่าง: f ของ qolscore3 ตาม fam_income = 0.136) · k = 3 · โหมด power: N = 300 (กลุ่มละ 100)
Inputs and their sources: f = 0.14 (example data: f of qolscore3 by fam_income = 0.136); k = 3. Power mode: N = 300 (100 per group).
# 12.2.10 One-way ANOVA: post-treatment QoL across three household-income groups
a <- anova(lm(qolscore3 ~ factor(fam_income), data = d))
round(sqrt((a[1, 2] / sum(a[, 2])) / (1 - a[1, 2] / sum(a[, 2]))), 4) # Cohen's f = 0.136 -> 0.14
library(pwr)
n_g <- pwr.anova.test(k = 3, f = 0.14, power = 0.80)$n # lambda = k * n * f^2 = N f^2
c(n_per_group = ceiling(n_g), n = 3 * ceiling(n_g), recruit = with_attrition(3 * ceiling(n_g)))
pwr.anova.test(k = 3, n = 100, f = 0.14)$power
[1] 0.136
n_per_group n recruit
165 495 550
[1] 0.5702882
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| n ต่อกลุ่ม / รวมn per group / total | 165 / 495 | 165 / 495 | 0 | ✓ PASS |
| power ที่ N = 300 คนpower at N = 300 | 0.5703 | 0.5703 | < 0.00005 | ✓ PASS |
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.11Cox PH / Survival
ใช้เมื่อเปรียบเทียบเวลาจนเกิดเหตุการณ์ระหว่างสองกลุ่ม (log-rank test หรือ Cox regression หัวข้อ 5.1–5.2) อำนาจการทดสอบขึ้นกับ จำนวนเหตุการณ์ จึงคำนวณจำนวนเหตุการณ์ก่อน แล้วแปลงเป็นจำนวนคนด้วยสัดส่วนที่คาดว่าจะเกิดเหตุการณ์ (Schoenfeld, 1983)
Use when time to an event is compared between two groups (log-rank test or Cox regression, sections 5.1–5.2). Power depends on the number of events, so the events are computed first and converted to people with the expected event proportion (Schoenfeld, 1983).
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- HR
- hazard ratio ที่ต้องการตรวจพบhazard ratio to detect
- π
- สัดส่วนผู้ป่วยในกลุ่มที่เปรียบเทียบ (0.5 เมื่อจัดสรร 1:1)proportion of patients in the comparison group (0.5 for 1:1 allocation)
- D, ē
- จำนวนเหตุการณ์ที่ต้องการ และสัดส่วนผู้ที่คาดว่าจะเกิดเหตุการณ์ภายในระยะติดตามที่วางแผน (เฉลี่ยทั้งสองกลุ่ม)required number of events and the proportion expected to have the event within the planned follow-up (both groups together)
ใน DAPH: ใส่ HR, ē และ π · D ปัดขึ้นก่อน แล้ว n = ⌈D/ē⌉ · ē ต้องเป็นสัดส่วนที่เกิดเหตุการณ์ภายในระยะเวลาติดตามของการศึกษาที่วางแผน
In DAPH: enter HR, ē and π. D is rounded up first, then n = ⌈D/ē⌉. ē must refer to the follow-up period of the planned study.
โจทย์: การศึกษาใหม่จะเปรียบเทียบการเสียชีวิตระหว่าง APD กับ CAPD
Scenario: A new study will compare death between APD and CAPD.
ค่าที่ใช้และที่มา: HR = 1.80 (Cox model ของข้อมูลตัวอย่าง: 1.8026) · ē = 0.176 (ข้อมูลตัวอย่าง: เสียชีวิตระหว่างติดตามร้อยละ 17.6 ระยะติดตามใกล้เคียงกัน) · π = 0.5 (ข้อมูลตัวอย่าง 0.4954) · โหมด power: N = 400
Inputs and their sources: HR = 1.80 (Cox model of the example data: 1.8026); ē = 0.176 (example data: 17.6% died during follow-up, assuming a similar follow-up period); π = 0.5 (example data 0.4954). Power mode: N = 400.
# 12.2.11 Cox regression: death, APD vs CAPD
library(survival)
round(exp(coef(coxph(Surv(follow_up_days, status) ~ I(group == 2), data = d))), 4) # HR 1.8026
round(c(event_rate = mean(d$status), allocation = mean(d$group == 2)), 4)
HR <- 1.80; ev <- 0.176; a1 <- 0.5
events <- function(power, alpha = 0.05) {
ceiling((qnorm(1 - alpha / 2) + qnorm(power))^2 / (a1 * (1 - a1) * log(HR)^2))
}
n_cox <- function(power) ceiling(events(power) / ev)
c(events = events(0.80), n = n_cox(0.80), recruit = with_attrition(n_cox(0.80)))
power_at_N(n_cox, 400)
I(group == 2)TRUE
1.8026
event_rate allocation
0.1762 0.4954
events n recruit
91 518 576
[1] 0.6911
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| จำนวนเหตุการณ์ Devents D | 91 | 91 | 0 | ✓ PASS |
| n | 518 | 518 | 0 | ✓ PASS |
| power ที่ N = 400 คนpower at N = 400 | 0.6911 | 0.6911 | < 0.00005 | ✓ PASS |
- Schoenfeld, D. A. (1983). Sample-size formula for the proportional-hazards regression model. Biometrics, 39(2), 499–503. doi:10.2307/2531021
- Machin, D., Campbell, M. J., Tan, S. B., & Tan, S. H. (2018). Sample sizes for clinical, laboratory and epidemiology studies (4th ed.). Wiley. doi:10.1002/9781118874905
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.12Diagnostic test (Sens / Spec CI half-width)
ใช้เมื่อต้องการประมาณความไวและความจำเพาะของการตรวจ (หัวข้อ 2.6) ให้ช่วงเชื่อมั่นกว้างไม่เกิน ±w แล้วใช้ความชุกของโรคแปลงเป็นจำนวนคนทั้งหมด (Buderer, 1996) เป็นการคำนวณจากความแม่นยำ จึงไม่มีโหมด power
Use when sensitivity and specificity (section 2.6) are to be estimated with a confidence interval no wider than ±w; the disease prevalence converts the numbers of diseased and non-diseased into a total (Buderer, 1996). It is a precision calculation, so there is no power mode.
- z1−α/2
- ควอนไทล์ของระดับความเชื่อมั่น (1.959964 สำหรับ 95%)quantile for the confidence level (1.959964 for 95%)
- Se, Sp, w
- ความไวและความจำเพาะที่คาดหวัง และความกว้างครึ่งหนึ่งของช่วงเชื่อมั่นexpected sensitivity and specificity, and the half-width of the confidence interval
- prev
- ความชุกของโรคในกลุ่มที่จะตรวจprevalence of the condition among the people to be tested
ใน DAPH: ใส่ Se, Sp, prevalence และ w (ระดับความเชื่อมั่นมาจาก α) · nD+ และ nD− ปัดขึ้นก่อน แล้วจึงหารด้วยความชุกและปัดขึ้นอีกครั้ง การปัดก่อนหารทำให้ได้มากกว่าการคำนวณขั้นเดียวเล็กน้อย (ตัวอย่างนี้ 695 เทียบกับ 692 ของ epiR::epi.ssdxsesp) ซึ่งเป็นด้านที่ปลอดภัย
In DAPH: enter Se, Sp, prevalence and w (the confidence level comes from α). nD+ and nD− are rounded up first, then divided by the prevalence and rounded up again; rounding before dividing gives slightly more than a one-step calculation (here 695 against 692 from epiR::epi.ssdxsesp), which errs on the safe side.
โจทย์: ศึกษาความแม่นยำของชุดตรวจเร็วชนิดใหม่ในผู้ป่วยล้างไตทางช่องท้อง
Scenario: Study the accuracy of a new rapid test in peritoneal-dialysis patients.
ค่าที่ใช้และที่มา: Se = 0.90, Sp = 0.90, w = 0.05 และ prevalence = 0.20 เป็นสมมติฐานของผู้วางแผนทั้งหมด (ข้อมูลตัวอย่างไม่มีผลการตรวจและมาตรฐานอ้างอิง)
Inputs and their sources: Se = 0.90, Sp = 0.90, w = 0.05 and prevalence = 0.20 are all planner's assumptions (the example data contain no test result with a reference standard).
# 12.2.12 Diagnostic accuracy (Buderer 1996): sensitivity and specificity to +/- 0.05
se <- 0.90; sp <- 0.90; prev <- 0.20; w <- 0.05; z <- qnorm(0.975)
n_dpos <- ceiling(z^2 * se * (1 - se) / w^2); n_dneg <- ceiling(z^2 * sp * (1 - sp) / w^2)
c(n_diseased = n_dpos, n_non_diseased = n_dneg, from_sens = ceiling(n_dpos / prev),
from_spec = ceiling(n_dneg / (1 - prev)), n = max(ceiling(n_dpos / prev), ceiling(n_dneg / (1 - prev))),
recruit = with_attrition(ceiling(n_dpos / prev)))
library(epiR)
epi.ssdxsesp(test = se, type = "se", Py = prev, epsilon = w, error = "absolute", nfractional = TRUE)
n_diseased n_non_diseased from_sens from_spec n recruit
139 139 695 174 695 773
[1] 691.4626
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| nD+ / nD− | 139 / 139 | 139 / 139 | 0 | ✓ PASS |
| n จากความไว / จากความจำเพาะn from sensitivity / from specificity | 695 / 174 | 695 / 174 | 0 | ✓ PASS |
| n | 695 | 695 | 0 | ✓ PASS |
- Buderer, N. M. F. (1996). Statistical methodology: I. Incorporating the prevalence of disease into the sample size calculation for sensitivity and specificity. Academic Emergency Medicine, 3(9), 895–900. doi:10.1111/j.1553-2712.1996.tb03538.x
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.13Ordered Logistic Regression (Proportional Odds)
ใช้เมื่อผลลัพธ์มีลำดับตั้งแต่ 3 ระดับและเปรียบเทียบสองกลุ่มด้วยการถดถอยโลจิสติกแบบมีลำดับ (proportional odds หัวข้อ 3.1) ตามวิธีของ Whitehead (1993)
Use when an ordered outcome with three or more levels is compared between two groups with proportional-odds (ordinal logistic) regression (section 3.1), following Whitehead (1993).
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- OR
- proportional odds ratio ที่ต้องการตรวจพบproportional odds ratio to detect
- p̄j
- สัดส่วนที่คาดในหมวด j โดยเฉลี่ยของสองกลุ่ม (รวมทุกหมวด = 1)expected proportion in category j averaged over the two groups (summing to 1)
- π, A
- สัดส่วนผู้ป่วยในกลุ่มที่เปรียบเทียบ และผลคูณ π(1 − π) (0.25 เมื่อ 1:1)proportion in the comparison group and the product π(1 − π) (0.25 for 1:1)
ใน DAPH: ใส่ OR สัดส่วนของแต่ละหมวด (คั่นด้วยจุลภาค DAPH ปรับให้รวมเป็น 1) และสัดส่วนการจัดสรร · N ปัดขึ้น · ตรงกับ posamsize ของแพ็กเกจ Hmisc
In DAPH: enter the OR, the category proportions (comma-separated; DAPH rescales them to sum to 1) and the allocation. N is rounded up. This matches posamsize in the Hmisc package.
โจทย์: การศึกษาใหม่จะเปรียบเทียบจำนวนครั้งที่นอนโรงพยาบาล (0, 1, 2, 3 ครั้งขึ้นไป) ระหว่าง APD กับ CAPD
Scenario: A new study will compare the number of hospital admissions (0, 1, 2, 3 or more) between APD and CAPD.
ค่าที่ใช้และที่มา: OR = 0.55 (proportional odds model ของข้อมูลตัวอย่าง: 0.5452 คือ APD มีโอกาสนอนโรงพยาบาลบ่อยกว่าน้อยกว่า) · สัดส่วน 0.108, 0.122, 0.152, 0.618 (ข้อมูลตัวอย่าง n_admission) · π = 0.5 · โหมด power: N = 250
Inputs and their sources: OR = 0.55 (proportional-odds model of the example data: 0.5452, i.e. lower odds of more admissions with APD); proportions 0.108, 0.122, 0.152, 0.618 (example data, n_admission); π = 0.5. Power mode: N = 250.
ฟังก์ชัน popower ของ Hmisc (โหมด power) ใช้ตัวคูณแก้สำหรับตัวอย่างเล็ก n/(n + 1) จึงให้ power ต่ำกว่าเล็กน้อย ส่วน DAPH ใช้สูตรของ Whitehead โดยตรงทั้งสองทิศทาง
Hmisc's popower (power mode) includes a small-sample factor n/(n + 1) and so gives a slightly lower power; DAPH uses Whitehead's formula directly in both directions.
# 12.2.13 Ordered logistic: number of admissions (0, 1, 2, 3 or more), APD vs CAPD
library(MASS)
d$adm <- factor(pmin(d$n_admission, 3), 0:3, c("0", "1", "2", "3+"), ordered = TRUE)
round(exp(coef(polr(adm ~ I(group == 2), data = d))), 4) # proportional OR 0.5452
round(prop.table(table(d$adm)), 4)
OR <- 0.55; p <- c(0.108, 0.122, 0.152, 0.618); A <- 0.5 * (1 - 0.5)
n_ord <- function(power, alpha = 0.05) {
ceiling(3 * (qnorm(1 - alpha / 2) + qnorm(power))^2 / (A * (1 - sum(p^3)) * log(OR)^2))
}
c(n = n_ord(0.80), recruit = with_attrition(n_ord(0.80)))
power_at_N(n_ord, 250)
library(Hmisc)
posamsize(p = p, odds.ratio = OR, fraction = 0.5, alpha = 0.05, power = 0.80)
popower(p = p, odds.ratio = OR, n = 250)
I(group == 2)TRUE
0.5452
0 1 2 3+
0.1085 0.1215 0.1523 0.6177
n recruit
348 387
[1] 0.6609
Total sample size: 347.9
Efficiency of design compared with continuous response: 0.757
Power: 0.657
Efficiency of design compared with continuous response: 0.757
Approximate standard error of log odds ratio: 0.2528
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| N | 348 | 348 | 0 | ✓ PASS |
| Hmisc::posamsizeHmisc::posamsize | 347.9 → 348 | 348 | 0 | ✓ PASS |
| power ที่ N = 250 คนpower at N = 250 | 0.6609 | 0.6609 | < 0.00005 | ✓ PASS |
- Whitehead, J. (1993). Sample size calculations for ordered categorical data. Statistics in Medicine, 12(24), 2257–2271. doi:10.1002/sim.4780122404
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.14Multinomial Logistic Regression (≥3 unordered categories)
ใช้เมื่อผลลัพธ์มีตั้งแต่ 3 หมวดที่ไม่มีลำดับและตัวแปรที่สนใจเป็นสองกลุ่ม (การถดถอยโลจิสติกพหุนาม หัวข้อ 3.2) DAPH ใช้วิธีประมาณของตนเอง: แต่ละหมวดเทียบกับหมวดอ้างอิงเหมือนการถดถอยโลจิสติกสองกลุ่มในคนที่อยู่ในสองหมวดนั้น ใช้ Bonferroni กับ α แล้วเลือกค่าที่มากที่สุด
Use when the outcome has three or more unordered categories and the predictor of interest is binary (multinomial logistic regression, section 3.2). DAPH uses its own approximation: each category is compared with the reference as a binary logistic comparison among the people in those two categories, α is Bonferroni-adjusted, and the largest requirement is taken.
- z1−α*/2, z1−β
- ควอนไทล์ที่ระดับ α* หลังปรับ Bonferroni และควอนไทล์ของ powerquantile at the Bonferroni-adjusted α* and the quantile for the power
- pref, pj, J
- สัดส่วนที่คาดในหมวดอ้างอิงและหมวด j และจำนวนหมวดทั้งหมดexpected proportions in the reference category and in category j, and the number of categories
- ORj, λ
- odds ratio ของหมวด j เทียบหมวดอ้างอิง และสัดส่วนผู้สัมผัส (ช่อง Allocation)odds ratio of category j versus the reference, and the proportion exposed (the Allocation box)
ใน DAPH: ใส่ OR ของหมวดที่ไม่ใช่หมวดอ้างอิงเรียงตามลำดับ สัดส่วนของทุกหมวดโดยใส่หมวดอ้างอิงเป็นค่าแรก และสัดส่วนการจัดสรร λ · Nj แต่ละค่าปัดขึ้น · วิธีนี้เป็นการประมาณของ DAPH ไม่มีฟังก์ชันมาตรฐานใน R ที่ให้ค่าเดียวกัน สคริปต์ R ด้านล่างจึงคำนวณตามสูตร · หมวดที่ OR ใกล้ 1 จะกำหนดขนาดตัวอย่าง
In DAPH: enter the ORs of the non-reference categories in order, the proportions of all categories with the reference first, and the allocation λ. Each Nj is rounded up. This is DAPH's own approximation; no standard R function reproduces it, so the R script below follows the formula. The category whose OR is closest to 1 sets the sample size.
โจทย์: สถานะการทำงาน (ว่างงานหรือเกษียณ เทียบกับทำงาน) สัมพันธ์กับกลุ่ม BMI หรือไม่ โดยใช้ BMI ปกติเป็นหมวดอ้างอิง (ผอม อาจเพิ่มขึ้นขณะที่น้ำหนักเกินอาจลดลง จึงไม่ใช้แบบมีลำดับ)
Scenario: Is employment status (unemployed or retired versus employed) associated with BMI group, with normal BMI as the reference? (Underweight may rise while overweight falls, so an ordered model is not used.)
ค่าที่ใช้และที่มา: OR = 2.03 (ผอม), 0.75 (น้ำหนักเกิน), 0.76 (อ้วน) และสัดส่วน 0.418 (ปกติ), 0.097, 0.223, 0.262 จากข้อมูลตัวอย่าง (OR 2.0267, 0.7531, 0.7586) · λ = 0.35 (ข้อมูลตัวอย่าง: ว่างงานหรือเกษียณ 0.3531) · หมายเหตุ: bmi_group ในข้อมูลตัวอย่างแบ่งด้วยจุดตัดของเอเชีย (≤ 18.5, 18.6–23.0, 23.1–25.0, ≥ 25.1) แม้ป้ายค่าจะระบุจุดตัดของ WHO · โหมด power: N = 2,500
Inputs and their sources: OR = 2.03 (underweight), 0.75 (overweight), 0.76 (obese) and proportions 0.418 (normal), 0.097, 0.223, 0.262 from the example data (ORs 2.0267, 0.7531, 0.7586); λ = 0.35 (example data: 0.3531 unemployed or retired). Note: bmi_group in the example data uses the Asian cut-offs (≤ 18.5, 18.6–23.0, 23.1–25.0, ≥ 25.1) although its value labels quote the WHO cut-offs. Power mode: N = 2,500.
# 12.2.14 Multinomial logistic: BMI group (normal = reference) by employment status
tb <- table(bmi = d$bmi_group, unemployed = d$occupation == 2); tb
ors <- sapply(c("1", "3", "4"), function(j) (tb[j, "TRUE"] / tb["2", "TRUE"]) / (tb[j, "FALSE"] / tb["2", "FALSE"]))
round(ors, 4) # under-, over-weight, obese vs normal
round(prop.table(table(d$bmi_group))[c("2", "1", "3", "4")], 4) # reference first
round(mean(d$occupation == 2), 4)
OR <- c(2.03, 0.75, 0.76); p <- c(0.418, 0.097, 0.223, 0.262); lam <- 0.35
n_multi_each <- function(power, alpha = 0.05) {
a_adj <- alpha / (length(p) - 1) # Bonferroni over J - 1 contrasts
sapply(1:3, function(j) ceiling((qnorm(1 - a_adj / 2) + qnorm(power))^2 * (p[1] + p[j + 1]) /
(lam * (1 - lam) * p[1] * p[j + 1] * log(OR[j])^2)))
}
n_multi <- function(power) max(n_multi_each(power))
n_multi_each(0.80)
c(n = n_multi(0.80), recruit = with_attrition(n_multi(0.80)))
power_at_N(n_multi, 2500)
unemployed
bmi FALSE TRUE
1 58 68
2 344 199
3 202 88
4 237 104
1 3 4
2.0267 0.7531 0.7586
2 1 3 4
0.4177 0.0969 0.2231 0.2623
[1] 0.3531
[1] 1166 3824 3794
n recruit
3824 4249
[1] 0.588
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| N ต่อการเปรียบเทียบ (ผอม / น้ำหนักเกิน / อ้วน)N per contrast (underweight / overweight / obese) | 1166 / 3824 / 3794 | 1166 / 3824 / 3794 | 0 | ✓ PASS |
| N | 3824 | 3824 | 0 | ✓ PASS |
| power ที่ N = 2500 คนpower at N = 2500 | 0.588 | 0.5880 | < 0.00005 | ✓ PASS |
- Hsieh, F. Y., Bloch, D. A., & Larsen, M. D. (1998). A simple method of sample size calculation for linear and logistic regression. Statistics in Medicine, 17(14), 1623–1634. doi:10.1002/(SICI)1097-0258(19980730)17:14<1623::AID-SIM871>3.0.CO;2-S
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.15Poisson Regression (count outcome)
ใช้เมื่อผลลัพธ์เป็นจำนวนครั้งของเหตุการณ์ต่อคนหรือต่อเวลา และทดสอบ incidence rate ratio (IRR) ของตัวแปรหนึ่งตัวด้วยการถดถอยปัวซง (หัวข้อ 4.1)
Use when the outcome is a count of events per person or per unit of time and the incidence rate ratio (IRR) of one predictor is tested with Poisson regression (section 4.1).
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- μ0
- จำนวนเหตุการณ์ที่คาดต่อคนในกลุ่มอ้างอิงตลอดระยะติดตามexpected number of events per person in the reference group over the follow-up
- IRR
- incidence rate ratio ต่อ 1 หน่วยของ Xincidence rate ratio per 1 unit of X
- σX²
- ความแปรปรวนของ X: B(1 − B) สำหรับ X แบบ 0/1 ที่มีสัดส่วน B และ 1 สำหรับ X ที่ปรับมาตรฐานแล้ว (IRR ต่อ 1 SD)variance of X: B(1 − B) for a 0/1 X with proportion B, and 1 for a standardised X (IRR per 1 SD)
ใน DAPH: ใส่ μ0, IRR และความแปรปรวนของ X · n ปัดขึ้น · สูตรของ DAPH ใช้ความแปรปรวนภายใต้ H₀ ทั้งสองพจน์ ซึ่งเป็นรูปย่อของ Signorini (1991) ที่แม่นเมื่อ IRR ใกล้ 1 · DAPH ไม่มีตัวปรับการกระจายเกิน (overdispersion)
In DAPH: enter μ0, the IRR and the variance of X. n is rounded up. DAPH's formula uses the variance under H₀ in both terms, a simplified form of Signorini (1991) that is accurate when the IRR is close to 1. DAPH has no adjustment for overdispersion.
โจทย์: การทดลอง 1 ปีจะเปรียบเทียบจำนวนครั้งของเยื่อบุช่องท้องอักเสบระหว่าง APD กับ CAPD (จัดสรร 1:1)
Scenario: A 1-year trial will compare the number of peritonitis episodes between APD and CAPD (1:1 allocation).
ค่าที่ใช้และที่มา: μ0 = 0.94 ครั้งต่อคนต่อปีใน CAPD (ข้อมูลตัวอย่าง: 1,178 ครั้งใน 1,252.4 คน-ปี = 0.9406) · IRR = 0.44 (ข้อมูลตัวอย่าง: APD เทียบ CAPD 0.4395) · σX² = 0.5 × 0.5 = 0.25 · โหมด power: N = 40
Inputs and their sources: μ0 = 0.94 episodes per patient-year with CAPD (example data: 1,178 episodes in 1,252.4 person-years = 0.9406); IRR = 0.44 (example data: APD versus CAPD 0.4395); σX² = 0.5 × 0.5 = 0.25. Power mode: N = 40.
ข้อควรระวัง: สูตรเต็มของ Signorini (1991) สำหรับ X แบบ 0/1 ใช้ความแปรปรวนภายใต้ H₁ ในพจน์ของ power: \( n = \bigl(z_{1-\alpha/2}\sqrt{V_0} + z_{1-\beta}\sqrt{V_1}\bigr)^2 / \bigl(\mu_0 (\ln \mathrm{IRR})^2\bigr) \) โดย V0 = 1/(B(1 − B)) = 4 และ V1 = 1/(1 − B) + 1/(B × IRR) = 6.545 ได้ n = 59 ค่าของ DAPH (50) จึงน้อยกว่าประมาณร้อยละ 15 เมื่อการสัมผัสทำให้อัตราลดลง (ถ้าทำให้อัตราเพิ่มขึ้น สูตรของ DAPH จะให้ค่ามากกว่าที่จำเป็น) และจำนวนครั้งในข้อมูลตัวอย่างกระจายมากกว่าการแจกแจงปัวซง (dispersion 1.886) จึงควรคูณ n ด้วยค่านี้โดยประมาณ DAPH ไม่ได้คำนวณทั้งสองเรื่องนี้ ให้ใช้ค่าที่ได้จาก R
Caution: Signorini's (1991) full formula for a 0/1 X uses the variance under H₁ in the power term, \( n = \bigl(z_{1-\alpha/2}\sqrt{V_0} + z_{1-\beta}\sqrt{V_1}\bigr)^2 / \bigl(\mu_0 (\ln \mathrm{IRR})^2\bigr) \), with V0 = 1/(B(1 − B)) = 4 and V1 = 1/(1 − B) + 1/(B × IRR) = 6.545, giving n = 59; DAPH's 50 is about 15% lower when the exposure lowers the rate (when it raises the rate, DAPH's formula gives more than needed). The example data's counts are also more dispersed than Poisson (dispersion 1.886), so n should be multiplied by about this factor. DAPH does neither; use the R values.
# 12.2.15 Poisson regression: peritonitis episodes per patient-year, APD vs CAPD
ev <- tapply(d$n_peritonitis, d$group, sum); py <- tapply(d$person_years, d$group, sum)
round(c(rate_CAPD = ev[[1]] / py[[1]], rate_APD = ev[[2]] / py[[2]], IRR = (ev[[2]] / py[[2]]) / (ev[[1]] / py[[1]])), 4)
mu0 <- 0.94; IRR <- 0.44; varx <- 0.5 * (1 - 0.5) # 1:1 allocation, X = 0/1
n_pois <- function(power, alpha = 0.05) {
ceiling((qnorm(1 - alpha / 2) + qnorm(power))^2 / (mu0 * varx * log(IRR)^2))
}
c(n = n_pois(0.80), recruit = with_attrition(n_pois(0.80)))
power_at_N(n_pois, 40)
# Signorini (1991) with the variance under H1 for the power term (binary X, B = 0.5)
V0 <- 1 / 0.5 + 1 / 0.5; V1 <- 1 / 0.5 + 1 / (0.5 * IRR)
ceiling((qnorm(0.975) * sqrt(V0) + qnorm(0.80) * sqrt(V1))^2 / (mu0 * log(IRR)^2))
fq <- glm(n_peritonitis ~ I(group == 2) + offset(log(person_years)), family = quasipoisson, data = d)
round(summary(fq)$dispersion, 3) # over-dispersion in the pilot data
rate_CAPD rate_APD IRR
0.9406 0.4134 0.4395
n recruit
50 56
[1] 0.7113
[1] 59
[1] 1.886
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| n | 50 | 50 | 0 | ✓ PASS |
| power ที่ N = 40 คนpower at N = 40 | 0.7113 | 0.7113 | < 0.00005 | ✓ PASS |
| n ตาม Signorini (1991) ที่ใช้ความแปรปรวนภายใต้ H₁ ในพจน์ของ powern by Signorini (1991) with the variance under H₁ in the power term | 59 | 50 | 9 | ✗ FAIL |
- Signorini, D. F. (1991). Sample size for Poisson regression. Biometrika, 78(2), 446–450. doi:10.1093/biomet/78.2.446
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.16Repeated-Measures ANOVA (two groups, time-averaged means)
ใช้เมื่อวัดผลลัพธ์ต่อเนื่องซ้ำ T ครั้งในแต่ละคน และเปรียบเทียบค่าเฉลี่ยตลอดช่วงเวลาระหว่างสองกลุ่ม (ผลหลักของกลุ่มใน repeated-measures ANOVA หัวข้อ 1.5) โดยสมมติว่าสหสัมพันธ์ระหว่างการวัดทุกคู่เท่ากับ ρ (Diggle et al., 2002)
Use when a continuous outcome is measured T times in each person and the time-averaged mean is compared between two groups (the group main effect in repeated-measures ANOVA, section 1.5), assuming the same correlation ρ between any two measurements (Diggle et al., 2002).
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- T, ρ
- จำนวนครั้งที่วัดต่อคน และสหสัมพันธ์ระหว่างการวัดของคนเดียวกันnumber of measurements per person and the correlation between measurements of the same person
- d
- ผลต่างของค่าเฉลี่ยระหว่างกลุ่มหารด้วย SD ของการวัดหนึ่งครั้งdifference between group means divided by the SD of a single measurement
ใน DAPH: ใส่ d, T, ρ และจำนวนกลุ่ม · n ต่อกลุ่มปัดขึ้น · ขนาดรวม = n ต่อกลุ่ม × จำนวนกลุ่ม แต่สูตรเป็นการเปรียบเทียบสองกลุ่ม หากใส่มากกว่า 2 กลุ่ม DAPH เพียงคูณ n เดิมด้วยจำนวนกลุ่ม · สูตรนี้ไม่ใช่สำหรับปฏิสัมพันธ์เวลา × กลุ่ม (ความชันที่ต่างกัน)
In DAPH: enter d, T, ρ and the number of groups. n per group is rounded up and the total is n per group × number of groups; the formula compares two groups, and with more than two groups DAPH only multiplies the same n. It does not size a time × group interaction (different slopes).
โจทย์: วัดคะแนนคุณภาพชีวิต 3 ครั้ง (ก่อน ระหว่าง หลังการรักษา) และเปรียบเทียบสองกลุ่มการรักษา
Scenario: Quality of life measured 3 times (before, during and after treatment), compared between two treatment groups.
ค่าที่ใช้และที่มา: d = 0.28 (ผลต่าง 5 คะแนนที่ผู้วางแผนกำหนด หารด้วย SD 17.8 ของข้อมูลตัวอย่าง) · T = 3 · ρ = 0.6 (สมมติฐาน: ค่าในข้อมูลตัวอย่าง 0.9997 ไม่สมจริงดังที่อธิบายในส่วนที่ 1) · 2 กลุ่ม · โหมด power: N = 200
Inputs and their sources: d = 0.28 (the planners' 5-point difference divided by the example data's SD of 17.8); T = 3; ρ = 0.6 (assumption: the example data's 0.9997 is unrealistic, as explained in part 1); 2 groups. Power mode: N = 200.
# 12.2.16 Repeated measures: QoL at 3 time points, two treatment groups
d0 <- 0.28; Tm <- 3; rho <- 0.6 # d = 5 / 17.8; rho assumed
n_rm <- function(power, alpha = 0.05) {
2 * ceiling(2 * (qnorm(1 - alpha / 2) + qnorm(power))^2 * (1 + (Tm - 1) * rho) / (Tm * d0^2))
}
c(factor = 1 + (Tm - 1) * rho, n_per_group = n_rm(0.80) / 2, n = n_rm(0.80), recruit = with_attrition(n_rm(0.80)))
power_at_N(n_rm, 200)
factor n_per_group n recruit
2.2 147.0 294.0 327.0
[1] 0.6376
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| ตัวคูณ 1 + (T − 1)ρfactor 1 + (T − 1)ρ | 2.2 | 2.2 | 0 | ✓ PASS |
| n ต่อกลุ่ม / รวมn per group / total | 147 / 294 | 147 / 294 | 0 | ✓ PASS |
| power ที่ N = 200 คนpower at N = 200 | 0.6376 | 0.6376 | < 0.00005 | ✓ PASS |
- Diggle, P. J., Heagerty, P., Liang, K.-Y., & Zeger, S. L. (2002). Analysis of longitudinal data (2nd ed.). Oxford University Press. ISBN 978-0-19-852484-7.
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.17GEE / GLMM (Multilevel / Cluster-randomized)
ใช้เมื่อผู้เข้าร่วมอยู่เป็นกลุ่มก้อน (cluster) เช่น ผู้ป่วยในคลินิกเดียวกัน หรือสุ่มทั้งคลินิก (cluster-randomised trial) แล้ววิเคราะห์ด้วย GEE หรือ mixed model (หัวข้อ 1.6–1.7) คำนวณ n แบบสุ่มรายบุคคลก่อน แล้วคูณด้วย design effect
Use when participants come in clusters, such as patients of the same clinic, or whole clinics are randomised (cluster-randomised trial), and the analysis is a GEE or mixed model (sections 1.6–1.7): compute the individually randomised n, then multiply by the design effect.
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- m, ICC
- ขนาดเฉลี่ยของกลุ่มก้อน และ intraclass correlation ของผลลัพธ์ภายในกลุ่มก้อนaverage cluster size and the intraclass correlation of the outcome within clusters
- d, g
- Cohen's d ระหว่างสองกลุ่ม และจำนวนกลุ่มการรักษาCohen's d between the two arms, and the number of arms
ใน DAPH: ใส่ d, m, ICC และจำนวนกลุ่ม · niid ต่อกลุ่มปัดขึ้น · N = ⌈g × niid × DEFF⌉ · ต่อกลุ่ม ⌈niid × DEFF⌉ · จำนวนกลุ่มก้อนต่อกลุ่ม ⌈(ต่อกลุ่ม)/m⌉ · DAPH รายงานจำนวนกลุ่มก้อนรวมเป็น ⌈N/m⌉ ซึ่งบางกรณีน้อยกว่า g × จำนวนต่อกลุ่ม ให้ใช้ g × จำนวนต่อกลุ่ม · เมื่อมีกลุ่มก้อนต่อกลุ่มน้อย ควรเพิ่มกลุ่มก้อนเผื่อไว้
In DAPH: enter d, m, the ICC and the number of arms. niid per arm is rounded up; N = ⌈g × niid × DEFF⌉; per arm ⌈niid × DEFF⌉; clusters per arm ⌈(per arm)/m⌉. DAPH reports the total number of clusters as ⌈N/m⌉, which can be smaller than g × clusters per arm; use g × clusters per arm. With few clusters per arm, add some clusters as a margin.
โจทย์: การทดลองแบบสุ่มทั้งคลินิกของโครงการเยี่ยมบ้านผู้ป่วยล้างไตทางช่องท้อง โดยแต่ละคลินิกมีผู้ป่วย 20 คน
Scenario: A cluster-randomised trial of a home-visit programme for peritoneal-dialysis patients, randomising clinics of 20 patients each.
ค่าที่ใช้และที่มา: d = 0.28 (5 คะแนน / SD 17.8) · m = 20 (แผนการศึกษา) · ICC = 0.056 (ข้อมูลตัวอย่าง: ICC ของ qolscore3 ระหว่าง 10 อำเภอจาก mixed model = 0.0563) · 2 กลุ่ม · โหมด power: N = 600
Inputs and their sources: d = 0.28 (5 points / SD 17.8); m = 20 (study plan); ICC = 0.056 (example data: ICC of qolscore3 among the 10 districts from a mixed model = 0.0563); 2 arms. Power mode: N = 600.
# 12.2.17 Cluster-randomised trial (GEE / GLMM): districts as clusters
library(lme4)
vc <- as.data.frame(VarCorr(lmer(qolscore3 ~ 1 + (1 | amp), data = d)))
round(vc$vcov[1] / sum(vc$vcov), 4) # ICC among districts 0.0563
d0 <- 0.28; m <- 20; icc <- 0.056; deff <- 1 + (m - 1) * icc
n_iid_g <- function(power, alpha = 0.05) ceiling(2 * (qnorm(1 - alpha / 2) + qnorm(power))^2 / d0^2)
n_gee <- function(power) ceiling(2 * n_iid_g(power) * deff)
c(DEFF = deff, n_iid_per_group = n_iid_g(0.80), n = n_gee(0.80),
clusters_per_group = ceiling(ceiling(n_iid_g(0.80) * deff) / m), clusters = ceiling(n_gee(0.80) / m),
recruit = with_attrition(n_gee(0.80)))
power_at_N(n_gee, 600)
[1] 0.0563
DEFF n_iid_per_group n clusters_per_group clusters recruit
2.064 201.000 830.000 21.000 42.000 923.000
[1] 0.6643
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| DEFF | 2.064 | 2.064 | 0 | ✓ PASS |
| niid ต่อกลุ่มniid per arm | 201 | 201 | 0 | ✓ PASS |
| N | 830 | 830 | 0 | ✓ PASS |
| กลุ่มก้อนต่อกลุ่ม / รวมclusters per arm / total | 21 / 42 | 21 / 42 | 0 | ✓ PASS |
| power ที่ N = 600 คนpower at N = 600 | 0.6643 | 0.6643 | < 0.00005 | ✓ PASS |
- Donner, A., & Klar, N. (2000). Design and analysis of cluster randomization trials in health research. Arnold. ISBN 978-0-340-69153-3.
- Eldridge, S., & Kerry, S. (2012). A practical guide to cluster randomised trials in health services research. Wiley. doi:10.1002/9781119966241
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.18Chi-square test (goodness-of-fit / independence)
ใช้กับตารางความถี่ ทดสอบความเป็นอิสระของตัวแปรจัดกลุ่มสองตัว (chi-square test หัวข้อ 2.4) หรือความสอดคล้องกับสัดส่วนที่คาด โดยใช้ขนาดอิทธิพล w ของ Cohen (0.1 เล็ก, 0.3 ปานกลาง, 0.5 ใหญ่) กับการแจกแจงไคสแควร์แบบ non-central (Cohen, 1988)
Use for frequency tables: independence of two categorical variables (chi-square test, section 2.4) or goodness of fit, with Cohen's w (0.1 small, 0.3 medium, 0.5 large) and the non-central chi-square distribution (Cohen, 1988).
- p1i, p0i
- สัดส่วนในช่อง i ภายใต้ H₁ และภายใต้ H₀proportion in cell i under H₁ and under H₀
- df
- (แถว − 1)(คอลัมน์ − 1) สำหรับความเป็นอิสระ หรือ จำนวนหมวด − 1 สำหรับความสอดคล้อง(rows − 1)(columns − 1) for independence, or categories − 1 for goodness of fit
- λ
- non-centrality ซึ่งเพิ่มตาม Nnon-centrality, growing with N
ใน DAPH: ใส่ w จำนวนแถวและคอลัมน์ (DAPH คำนวณ df) · DAPH หา N ที่น้อยที่สุดตั้งแต่ 10 ขึ้นไปที่ power ถึงเป้าหมาย และโหมด power คำนวณจากการแจกแจงเดียวกันโดยตรง · ตรงกับ pwr.chisq.test ของ R · w จากข้อมูลนำร่องคำนวณได้จาก \( w = \sqrt{\chi^2/n} \)
In DAPH: enter w and the numbers of rows and columns (DAPH computes df). DAPH searches for the smallest N from 10 upward whose power reaches the target, and power mode computes the power from the same distribution directly. This matches R's pwr.chisq.test. From pilot data, \( w = \sqrt{\chi^2/n} \).
โจทย์: การกระจายของจำนวนครั้งเยื่อบุช่องท้องอักเสบ (0, 1, 2 ครั้งขึ้นไป) ต่างกันระหว่าง APD กับ CAPD หรือไม่
Scenario: Does the distribution of peritonitis episodes (0, 1, 2 or more) differ between APD and CAPD?
ค่าที่ใช้และที่มา: w = 0.29 (ข้อมูลตัวอย่าง: ตาราง 3 × 2 ของ n_peritonitis กับ group ได้ w = 0.2891) · df = (3 − 1)(2 − 1) = 2 · โหมด power: N = 80
Inputs and their sources: w = 0.29 (example data: the 3 × 2 table of n_peritonitis by group gives w = 0.2891); df = (3 − 1)(2 − 1) = 2. Power mode: N = 80.
# 12.2.18 Chi-square: peritonitis episodes (0, 1, 2 or more) by treatment group
tb <- table(episodes = cut(d$n_peritonitis, c(-1, 0, 1, Inf), c("0", "1", "2+")), group = d$group); tb
round(sqrt(chisq.test(tb)$statistic / sum(tb)), 4) # Cohen's w = 0.2891
library(pwr)
N <- pwr.chisq.test(w = 0.29, df = 2, power = 0.80)$N
c(n = ceiling(N), recruit = with_attrition(ceiling(N)))
pwr.chisq.test(w = 0.29, N = 80, df = 2)$power
group
episodes 1 2
0 233 365
1 142 171
2+ 281 108
X-squared
0.2891
n recruit
115 128
[1] 0.6369359
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| w จากข้อมูลfrom the data | 0.2891 | — | — | ✓ PASS |
| N | 115 | 115 | 0 | ✓ PASS |
| power ที่ N = 80 คนpower at N = 80 | 0.6369 | 0.6369 | < 0.00005 | ✓ PASS |
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.19ANCOVA (two groups, k covariates)
ใช้เมื่อเปรียบเทียบค่าเฉลี่ยสองกลุ่มหลังปรับด้วย covariate เช่น ค่าก่อนการทดลอง (ANCOVA หัวข้อ 1.4) การปรับด้วย covariate ที่สัมพันธ์กับผลลัพธ์ลดความแปรปรวนที่เหลือ จึงลดขนาดตัวอย่างลงตามตัวคูณ 1 − ρ² แล้วบวกคืน 1 คนต่อ covariate 1 ตัว (Borm, Fransen & Lemmens, 2007)
Use when two group means are compared after adjusting for covariates, such as the baseline value (ANCOVA, section 1.4). A covariate correlated with the outcome shrinks the residual variance, so the sample falls by the factor 1 − ρ², and one subject per covariate is added back (Borm, Fransen & Lemmens, 2007).
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- d
- Cohen's d ของผลต่างระหว่างกลุ่มCohen's d of the difference between groups
- ρ
- สหสัมพันธ์ของ covariate กับผลลัพธ์ (เมื่อมีหลายตัวใช้สหสัมพันธ์พหุคูณ R ไม่ใช่ R²)correlation of the covariate with the outcome (with several covariates the multiple correlation R, not R²)
- k
- จำนวน covariatenumber of covariates
ใน DAPH: ใส่ d, ρ และ k · nt ปัดขึ้นก่อน (สูตรเดียวกับ 12.2.2 เมื่อ r = 1) แล้ว n ต่อกลุ่ม = ⌈(1 − ρ²) nt + k⌉ · ρ = 0 ให้ nt + k
In DAPH: enter d, ρ and k. nt is rounded up first (the 12.2.2 formula with r = 1), then n per group = ⌈(1 − ρ²) nt + k⌉; ρ = 0 gives nt + k.
โจทย์: การทดลองแบบสุ่มสองกลุ่ม วัดคะแนนคุณภาพชีวิตหลังการทดลอง โดยปรับด้วยคะแนนก่อนการทดลอง (k = 1)
Scenario: A two-arm randomised trial measuring the post-treatment quality-of-life score, adjusted for the baseline score (k = 1).
ค่าที่ใช้และที่มา: d = 0.28 (5 คะแนน / SD 17.8) · ρ = 0.6 (สมมติฐาน เพราะค่าในข้อมูลตัวอย่าง 0.9997 ไม่สมจริง) · k = 1 · โหมด power: N = 200
Inputs and their sources: d = 0.28 (5 points / SD 17.8); ρ = 0.6 (assumption, because the example data's 0.9997 is unrealistic); k = 1. Power mode: N = 200.
# 12.2.19 ANCOVA: post-treatment QoL adjusted for baseline QoL (k = 1)
d0 <- 0.28; rho <- 0.6; k <- 1
n_t <- function(power, alpha = 0.05) ceiling(2 * (qnorm(1 - alpha / 2) + qnorm(power))^2 / d0^2)
n_ancova <- function(power) 2 * ceiling((1 - rho^2) * n_t(power) + k)
c(n_ttest_per_group = n_t(0.80), n_per_group = n_ancova(0.80) / 2, n = n_ancova(0.80),
recruit = with_attrition(n_ancova(0.80)))
power_at_N(n_ancova, 200)
n_ttest_per_group n_per_group n recruit
201 130 260 289
[1] 0.6904
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| nt | 201 | 201 | 0 | ✓ PASS |
| n ต่อกลุ่ม / รวมn per group / total | 130 / 260 | 130 / 260 | 0 | ✓ PASS |
| power ที่ N = 200 คนpower at N = 200 | 0.6904 | 0.6904 | < 0.00005 | ✓ PASS |
- Borm, G. F., Fransen, J., & Lemmens, W. A. J. G. (2007). A simple sample size formula for analysis of covariance in randomized clinical trials. Journal of Clinical Epidemiology, 60(12), 1234–1238. doi:10.1016/j.jclinepi.2007.02.006
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.2.20Conditional logistic regression (matched case-control)
ใช้กับการศึกษา case-control แบบจับคู่ที่วิเคราะห์ด้วย conditional logistic regression (หัวข้อ 2.2) ข้อมูลมาจากคู่ที่การสัมผัสไม่เหมือนกันเท่านั้น จึงคำนวณจำนวนคู่ไม่สอดคล้องที่ต้องการ แล้วหารด้วยความน่าจะเป็นที่คู่หนึ่งจะไม่สอดคล้อง (Schlesselman, 1982) และใช้ตัวคูณของ Ury (1975) สำหรับการจับคู่ 1:M
Use for a matched case-control study analysed with conditional logistic regression (section 2.2). Only pairs with different exposure carry information, so the number of discordant pairs needed is divided by the probability that a pair is discordant (Schlesselman, 1982), with Ury's (1975) multiplier for 1:M matching.
- z1−α/2
- ควอนไทล์ของการแจกแจงปกติมาตรฐาน: 1.959964 ที่ α = 0.05 สองด้าน (ด้านเดียวใช้ z1−α = 1.644854)standard normal quantile: 1.959964 at α = 0.05 two-sided (a one-sided test uses z1−α = 1.644854)
- z1−β
- ควอนไทล์ของ power: 0.841621 ที่ power 0.80 และ 1.281552 ที่ 0.90quantile for the power: 0.841621 at power 0.80 and 1.281552 at 0.90
- OR, p0, p1
- odds ratio ที่ต้องการตรวจพบ สัดส่วนการสัมผัสในกลุ่มควบคุม และในกลุ่มผู้ป่วย (คำนวณจาก p0 และ OR)odds ratio to detect, exposure prevalence among controls, and among cases (implied by p0 and the OR)
- ψ, m, pd
- สัดส่วนของคู่ไม่สอดคล้องที่ผู้ป่วยเป็นฝ่ายสัมผัส (0.5 ภายใต้ H₀) จำนวนคู่ไม่สอดคล้องที่ต้องการ และความน่าจะเป็นที่คู่หนึ่งไม่สอดคล้องshare of discordant pairs in which the case is exposed (0.5 under H₀), discordant pairs required, and the probability that a pair is discordant
- M
- จำนวน control ต่อ case 1 ราย (ประโยชน์ลดลงเรื่อย ๆ หลัง M ≈ 4)controls per case (diminishing returns beyond M ≈ 4)
ใน DAPH: ใส่ p0, OR และ M · m ไม่ปัดก่อนหาร · npairs ปัดขึ้น · ผู้ป่วย ⌈npairs(M + 1)/(2M)⌉ และกลุ่มควบคุม ⌈M × ผู้ป่วย⌉ · สมมติว่าการสัมผัสของสองคนในคู่เป็นอิสระต่อกัน ซึ่งตรงกับวิธีของ Dupont (1988) เมื่อไม่มีสหสัมพันธ์ภายในคู่ (epiR::epi.sscc ให้ค่าเดียวกัน)
In DAPH: enter p0, the OR and M. m is not rounded before dividing; npairs is rounded up; cases = ⌈npairs(M + 1)/(2M)⌉ and controls = ⌈M × cases⌉. Exposure is assumed independent within pairs, which matches Dupont's (1988) method with no within-pair correlation (epiR::epi.sscc gives the same total).
โจทย์: การศึกษา case-control แบบจับคู่ 1:1 ของการเสียชีวิตในผู้ป่วยล้างไตทางช่องท้อง (case = เสียชีวิต, control = รอดชีวิต จับคู่ตามโรงพยาบาลและอายุ) โดยมีโรคเรื้อรังเป็นปัจจัยสัมผัส
Scenario: A 1:1 matched case-control study of death among peritoneal-dialysis patients (cases = died, controls = survivors matched on hospital and age), with chronic disease as the exposure.
ค่าที่ใช้และที่มา: p0 = 0.48 (ข้อมูลตัวอย่าง: โรคเรื้อรังในผู้รอดชีวิต 0.4818) · OR = 1.6 (ข้อมูลตัวอย่าง: OR ที่ยังไม่ปรับ 1.6017) · M = 1 · โหมด power: N = 400 คน (200 คู่)
Inputs and their sources: p0 = 0.48 (example data: chronic disease among survivors 0.4818); OR = 1.6 (example data: crude OR 1.6017); M = 1. Power mode: N = 400 people (200 pairs).
# 12.2.20 Conditional logistic: matched case-control study of death, exposure = chronic disease
round(c(p0 = mean(d$chronic[d$status == 0]),
OR = exp(coef(glm(status ~ chronic, binomial, data = d)))[[2]]), 4) # 0.4818 and 1.6017
p0 <- 0.48; OR <- 1.6; M <- 1
n_pairs <- function(power, alpha = 0.05) {
psi <- OR / (1 + OR)
m <- (qnorm(1 - alpha / 2) / 2 + qnorm(power) * sqrt(psi * (1 - psi)))^2 / (psi - 0.5)^2
p1 <- OR * p0 / (1 + p0 * (OR - 1)); pd <- p0 * (1 - p1) + p1 * (1 - p0)
ceiling(m / pd)
}
n_clogit <- function(power) { cases <- ceiling(n_pairs(power) * (M + 1) / (2 * M)); cases + ceiling(cases * M) }
c(n_pairs = n_pairs(0.80), n = n_clogit(0.80), recruit = with_attrition(n_clogit(0.80)))
power_at_N(n_clogit, 400)
library(epiR)
epi.sscc(OR = 1.6, p0 = 0.48, n = NA, power = 0.80, r = 1, method = "matched")$n.total # Dupont (1988)
p0 OR
0.4818 1.6017
n_pairs n recruit
288 576 640
[1] 0.643
[1] 576
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| จำนวนคู่ / รวมpairs / total | 288 / 576 | 288 / 576 | 0 | ✓ PASS |
| epiR::epi.sscc (Dupont 1988) รวมepiR::epi.sscc (Dupont 1988) total | 576 | 576 | 0 | ✓ PASS |
| power ที่ N = 400 คนpower at N = 400 | 0.643 | 0.6430 | < 0.00005 | ✓ PASS |
- Dupont, W. D. (1988). Power calculations for matched case-control studies. Biometrics, 44(4), 1157–1168. doi:10.2307/2531743
- Schlesselman, J. J. (1982). Case-control studies: Design, conduct, analysis. Oxford University Press. ISBN 978-0-19-502933-8.
- Ury, H. K. (1975). Efficiency of case-control studies with multiple controls per case: Continuous or dichotomous data. Biometrics, 31(3), 643–649. doi:10.2307/2529548
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
4การแปลผลและตัวอย่างInterpretation and Example
ขนาดตัวอย่างที่คำนวณได้เป็น ค่าขั้นต่ำภายใต้สมมติฐาน ไม่ใช่ค่าที่แน่นอน ตัวที่มีผลมากที่สุดคือขนาดผลที่ต้องการตรวจพบ: ผลต่างครึ่งหนึ่งต้องการตัวอย่างประมาณ 4 เท่า ใน 12.2.2 ผลต่าง 1.95 คะแนน (d = 0.11) ต้องการกลุ่มละ 1,313 คน ขณะที่ผลต่าง 5 คะแนน (d = 0.28) ต้องการกลุ่มละ 201 คน · ค่าประกอบก็สำคัญ: ใน 12.2.19 การปรับด้วยคะแนนก่อนการทดลองที่ ρ = 0.6 ลดจาก 402 เหลือ 260 คน ใน 12.2.17 การสุ่มทั้งคลินิกที่ ICC = 0.056 เพิ่มจาก 402 เป็น 830 คน · ควรรายงานทุกค่าที่ใช้ แหล่งที่มา และทดลองเปลี่ยนค่าที่ไม่แน่นอน (sensitivity analysis)
A calculated sample size is a minimum under assumptions, not an exact requirement. The effect to detect matters most: halving it roughly quadruples the sample. In 12.2.2 a 1.95-point difference (d = 0.11) needs 1,313 per group, whereas a 5-point difference (d = 0.28) needs 201 per group. Nuisance values matter too: in 12.2.19 adjusting for the baseline score with ρ = 0.6 lowers 402 to 260, and in 12.2.17 randomising whole clinics with ICC = 0.056 raises 402 to 830. Report every value used and its source, and vary the uncertain ones (sensitivity analysis).
ข้อควรระวัง · ผลลัพธ์นับและข้อมูลกลุ่มก้อนต้องคำนึงถึงการกระจายเกินและ design effect (12.2.15, 12.2.17) · ผลลัพธ์หลายตัวหรือการเปรียบเทียบหลายคู่ต้องปรับ α · การศึกษาที่ไม่พบนัยสำคัญเพราะตัวอย่างน้อยไม่ได้แปลว่าไม่มีผล · ขนาดตัวอย่างไม่ช่วยแก้อคติจากการออกแบบหรือการวัด
Cautions: count outcomes and clustered data need allowance for overdispersion and the design effect (12.2.15, 12.2.17); several outcomes or many pairwise comparisons need an adjusted α; a non-significant result from too small a study does not mean there is no effect; and a larger sample does not cure bias from the design or the measurement.
📖 References
- Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
- Fleiss, J. L., Levin, B., & Paik, M. C. (2003). Statistical methods for rates and proportions (3rd ed.). Wiley. ISBN 978-0-471-52629-2.
- Machin, D., Campbell, M. J., Tan, S. B., & Tan, S. H. (2018). Sample sizes for clinical, laboratory and epidemiology studies (4th ed.). Wiley. doi:10.1002/9781118874905
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.3Regression Diagnostics — VIF, Cook's D, Residuals
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
การตรวจวินิจฉัยแบบจำลองถดถอย (regression diagnostics) ตรวจหลังประมาณค่า Linear Regression (หัวข้อ 1.12) ว่าข้อสมมติเป็นจริงพอหรือไม่: ส่วนเหลือ (residual = ค่าจริง − ค่าทำนาย) แจกแจงปกติ ความแปรปรวนของส่วนเหลือคงที่ ส่วนเหลือไม่สัมพันธ์กันตามลำดับแถว ตัวแปรอิสระไม่ซ้ำซ้อนกันมาก (multicollinearity) และไม่มีบางคนที่มีอิทธิพลต่อผลมากผิดปกติ · ถ้าข้อสมมติไม่เป็นจริง ค่าคลาดเคลื่อนมาตรฐาน ช่วงเชื่อมั่น และค่า p อาจคลาดเคลื่อน ควรตรวจทุกครั้งก่อนรายงานผล
Regression diagnostics check, after a linear regression has been fitted (section 1.12), whether its assumptions hold well enough: normally distributed residuals (residual = observed − predicted), constant residual variance, residuals not correlated along the row order, predictors that do not duplicate each other (multicollinearity), and no individual with unusually large influence on the results. When assumptions fail, standard errors, confidence intervals and p-values can be wrong, so check them before reporting.
ใน DAPH: เมื่อรัน Linear regression หน้าผลลัพธ์ (Tab 3) มีหัวข้อ "การตรวจสอบข้อสมมติ" ซึ่งคำนวณจากแบบจำลองจริง และแผนภาพ Q-Q Plot (Residuals), Residual Plot และ Cook's Distance · รายงาน Word ไม่มีส่วนนี้
In DAPH: a Linear regression run adds an "Assumption Checking" block to the results page (Tab 3), computed from the fitted model, and the charts Q-Q Plot (Residuals), Residual Plot and Cook's Distance. The Word report does not include them.
2หลักการและสูตรLogic and Formula
- e_i, e_(i)
- ส่วนเหลือของคนที่ i และส่วนเหลือเมื่อเรียงจากน้อยไปมากresidual of person i, and the residuals sorted in order
- a_i
- ค่าคงที่จากค่าคาดหมายของสถิติอันดับของการแจกแจงปกติconstants from the expected normal order statistics
- S, K
- ความเบ้และความโด่งของส่วนเหลือskewness and kurtosis of the residuals
- R²_aux
- R² ของการถดถอย e² บนตัวแปรอิสระทุกคอลัมน์ของแบบจำลอง (p คอลัมน์)R² of regressing e² on all p columns of the model
- ρ̂₁
- สหสัมพันธ์ของส่วนเหลือที่อยู่ติดกันตามลำดับแถวcorrelation between residuals of neighbouring rows
- R_j²
- R² จากการถดถอยตัวแปร j บนตัวแปรอิสระอื่นR² from regressing variable j on the other predictors
- R, R_jj, R_−j
- เมทริกซ์สหสัมพันธ์ของทุกคอลัมน์ในแบบจำลอง ของคอลัมน์ของตัวแปร j และของคอลัมน์ที่เหลือcorrelation matrix of all model columns, of variable j's columns, and of the remaining columns
- k, s², s_(i)
- จำนวนสัมประสิทธิ์รวมค่าคงที่ ความแปรปรวนของส่วนเหลือ และค่านี้เมื่อตัดคนที่ i ออกnumber of coefficients including the intercept, residual variance, and the same without person i
สิ่งที่ DAPH ตรวจและเกณฑ์ที่ใช้ (✓ ผ่าน ✗ ไม่ผ่าน): (1) ขนาดตัวอย่าง n ≥ 15 × จำนวนสัมประสิทธิ์ของแบบจำลองไม่รวมค่าคงที่ (ตัวอย่างนี้ 7 ค่า จึงแนะนำ ≥ 105) (2) Shapiro-Wilk ของส่วนเหลือ (Shapiro & Wilk, 1965) เมื่อ n ≤ 5,000 หรือ Jarque-Bera (Jarque & Bera, 1980) เมื่อ n > 5,000 ไม่ผ่านถ้า p < 0.05 และเมื่อ n ≥ 30 จะเตือนว่าผลยังใช้ได้ตามทฤษฎีบทขีดจำกัดกลาง (3) Breusch-Pagan แบบ studentized (Breusch & Pagan, 1979; Koenker, 1981) ไม่ผ่านถ้า p < 0.05 และแนะนำ robust standard errors (HC3) หรือการแปลงตัวแปรตาม (4) Durbin-Watson (Durbin & Watson, 1950) แสดงเป็นข้อมูลประกอบ ไม่ตัดสินผ่านหรือไม่ผ่าน พร้อมหมายเหตุว่าแปลผลได้เฉพาะเมื่อแถวเรียงตามเวลา (ใกล้ 2 = ไม่มีสหสัมพันธ์ระหว่างแถวที่ติดกัน) (5) VIF ถ้ามีตัวแปรใดเกิน 5 จะแสดงรายชื่อ ถ้าเกิน 10 แนะนำให้ตัดหรือรวมตัวแปร (6) F test ของแบบจำลอง · แผนภาพ Cook's Distance (Cook, 1977) ลากเส้นที่ 4/n และนับจำนวนคนที่เกินเส้น · DAPH ไม่รายงาน leverage และ studentized residual (คำนวณใน R ได้ตามสคริปต์ด้านล่าง)
What DAPH checks, and its criteria (✓ pass, ✗ fail): (1) sample size n ≥ 15 × the number of model coefficients excluding the intercept (7 here, so ≥ 105 is recommended); (2) Shapiro-Wilk on the residuals (Shapiro & Wilk, 1965) when n ≤ 5,000, or Jarque-Bera (Jarque & Bera, 1980) when n > 5,000, failing when p < 0.05, with a note that with n ≥ 30 the results remain usable by the central limit theorem; (3) the studentized Breusch-Pagan test (Breusch & Pagan, 1979; Koenker, 1981), failing when p < 0.05, with a suggestion of robust (HC3) standard errors or a transformed outcome; (4) Durbin-Watson (Durbin & Watson, 1950), shown as information without pass/fail, with the note that it is interpretable only when the rows are in time order (near 2 = no correlation between consecutive rows); (5) VIF: variables above 5 are listed, and above 10 DAPH suggests dropping or combining variables; (6) the model's F test. The Cook's Distance chart (Cook, 1977) draws a line at 4/n and counts the patients above it. DAPH does not report leverage or studentized residuals (R computes them in the script below).
ข้อควรรู้เกี่ยวกับการคำนวณของ DAPH: VIF คำนวณจากตัวแปรอิสระตามรหัสตัวเลขที่บันทึกไว้ ตัวแปรกลุ่มที่มีมากกว่า 2 ระดับ (เช่น รายได้ครัวเรือน 1–3) จึงถูกใช้เป็นตัวเลขตัวเดียวแทนชุดตัวแปรหุ่นที่อยู่ในแบบจำลอง ค่าที่ถูกต้องสำหรับตัวแปรเช่นนี้คือ GVIF (Fox & Monette, 1992) ซึ่ง car::vif ให้ (เทียบ GVIF1/(2df) กับรากที่สองของเกณฑ์ VIF) · การตรวจทั้งหมดและแผนภาพ Q-Q, Residual และ Cook's Distance ใช้แบบจำลองสุดท้ายเสมอ รวมถึงหลัง Backward, Stepwise หรือ Forward
Points to know about DAPH's computation: the VIF is computed from the predictors as their stored numeric codes, so a categorical variable with more than 2 levels (for example household income 1–3) enters as a single number instead of the set of dummies used in the model. The right measure for such a variable is the GVIF (Fox & Monette, 1992), as given by car::vif (compare GVIF1/(2df) with the square root of the VIF cut-off). Every check and the Q-Q, Residual and Cook's Distance charts use the final model, also after Backward, Stepwise or Forward selection.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
num <- d # numeric codes, kept for the VIF as DAPH computes it
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
d$fam_income <- factor(d$fam_income, 1:3, c("<10,000", "10,000-30,000", ">30,000"))
fit <- lm(qolscore3 ~ age + gender + group + bmi + chronic + fam_income, data = d) # the Enter model of section 1.12
e <- residuals(fit); n <- nobs(fit); k <- length(coef(fit))
# 1. Normality of the residuals (Shapiro-Wilk; DAPH uses Jarque-Bera when n > 5000)
shapiro.test(e)
# 2. Constant variance: Breusch-Pagan, studentized (Koenker) form, on the model's regressors
library(lmtest)
bptest(fit)
# 3. Durbin-Watson (only meaningful when the rows are in time order)
sum(diff(e)^2) / sum(e^2)
set.seed(2026); o <- sample(n) # the same residuals in a random row order
sum(diff(e[o])^2) / sum(e[o]^2)
# 4. Multicollinearity: VIF of the model as fitted (GVIF for the 3-level income variable) ...
library(car)
vif(fit)
# ... and as DAPH computes it: every predictor entered as its numeric code
vars <- c("age", "gender", "group", "bmi", "chronic", "fam_income")
sapply(vars, function(v) 1 / (1 - summary(lm(reformulate(setdiff(vars, v), v), data = num))$r.squared))
# 5. Influence: Cook's distance (DAPH chart: threshold 4/n), leverage and studentized residuals
cd <- cooks.distance(fit)
c(threshold = 4 / n, n_above = sum(cd > 4 / n), max_D = max(cd), n_above_1 = sum(cd > 1))
h <- hatvalues(fit)
c(mean_h = mean(h), n_high_leverage = sum(h > 2 * k / n), n_abs_rstudent_gt3 = sum(abs(rstudent(fit)) > 3))
# 6. After Backward / Stepwise / Forward, DAPH diagnoses the final model (here age + household income)
fin <- lm(qolscore3 ~ age + fam_income, data = d)
cdf <- cooks.distance(fin)
c(W = unname(shapiro.test(residuals(fin))$statistic), n_above = sum(cdf > 4 / nobs(fin)), max_D = max(cdf))
W = 0.97464, p-value = 2.429e-14
BP = 16.282, df = 7, p-value = 0.02266
[1] 0.1173836
[1] 1.975653
GVIF Df GVIF^(1/(2*Df))
age 1.081781 1 1.040087
gender 1.019371 1 1.009639
group 1.006026 1 1.003008
bmi 1.088061 1 1.043102
chronic 1.040742 1 1.020168
fam_income 1.011317 2 1.002817
age gender group bmi chronic fam_income
1.080539 1.019343 1.006014 1.088001 1.038340 1.007242
threshold n_above max_D n_above_1
0.003076923 59.000000000 0.019631454 0.000000000
mean_h n_high_leverage n_abs_rstudent_gt3
0.006153846 17.000000000 13.000000000
W n_above max_D
0.97586948 65.00000000 0.01104491
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Shapiro-Wilk of residuals: W / p | 0.97464 / 2.429e−14 | W = 0.9746, p < 0.001 (engine 2.429e−14) | < 1e−9 | ✓ PASS |
| Breusch-Pagan (studentized): statistic / df / p | 16.282 / 7 / 0.02266 | LM = 16.282 / p = 0.023 (engine df 7) | < 1e−9 | ✓ PASS |
| Durbin-Watson (file order) | 0.1173836 | 0.117 | < 1e−12 | ✓ PASS |
| VIF, predictors as numeric codes (DAPH's method): age / gender / group / BMI / chronic / income | 1.080539 / 1.019343 / 1.006014 / 1.088001 / 1.038340 / 1.007242 | all ≤ 5 (engine 1.080539 / 1.019343 / 1.006014 / 1.088001 / 1.038340 / 1.007242) | < 1e−9 | ✓ PASS |
| VIF of the model as fitted (car::vif): age / chronic / income (GVIF, 2 df) | 1.081781 / 1.040742 / 1.011317 | 1.080539 / 1.038340 / 1.007242 | 0.0012 / 0.0024 / 0.0041 | ✗ FAIL |
| Cook's distance: 4/n line / patients above it / largest D | 0.003076923 / 59 / 0.019631454 | Threshold = 0.0031 / Influential (n=59) / 0.019631454 | < 1e−12 | ✓ PASS |
| After Stepwise (final model age + household income): Q-Q W / patients above 4/n / largest D | 0.97586948 / 65 / 0.01104491 | W=0.9759 / Influential (n=65) / 0.01104491 | < 1e−9 | ✓ PASS |
ความต่างคำนวณจากค่าเต็มของ R และค่าที่ engine ของ DAPH คำนวณก่อนปัดเศษ · แถวที่ไม่ผ่าน: DAPH คำนวณ VIF ถูกต้องตามวิธีของตัวเอง แต่วิธีนั้นใช้รหัสตัวเลขของตัวแปรกลุ่มแทนชุดตัวแปรหุ่นที่อยู่ในแบบจำลอง ค่าจึงไม่ใช่ VIF ของแบบจำลองที่ประมาณค่า · ในตัวอย่างนี้ทุกค่าใกล้ 1 ข้อสรุปว่าไม่มี multicollinearity จึงไม่เปลี่ยน
Differences are computed from R's full-precision values and the values DAPH's engine computed before rounding. The failing row: DAPH computes its VIF correctly for its own method, but that method uses the numeric code of a categorical variable instead of the dummies in the model, so the values are not the VIFs of the fitted model. Here every value is close to 1, so the conclusion of no multicollinearity does not change.
4การแปลผลและการแก้ปัญหาInterpretation and Remediation
ส่วนเหลือไม่แจกแจงปกติ (W = 0.9746, p < 0.001): เมื่อตัวอย่างใหญ่ (n = 1,300) ค่าสัมประสิทธิ์และช่วงเชื่อมั่นยังใช้ได้โดยประมาณ และ Shapiro-Wilk ไวต่อความเบี่ยงเบนเล็กน้อยมาก ควรดู Q-Q Plot ประกอบ · ถ้าตัวอย่างเล็กและเบ้มาก พิจารณาแปลงตัวแปรตาม (เช่น log) หรือใช้ช่วงเชื่อมั่นแบบ bootstrap
Non-normal residuals (W = 0.9746, p < 0.001): with a large sample (n = 1,300) the coefficients and confidence intervals remain approximately valid, and Shapiro-Wilk reacts to very small departures, so look at the Q-Q Plot as well. With a small, strongly skewed sample, consider transforming the outcome (for example a log) or bootstrap confidence intervals.
ความแปรปรวนไม่คงที่ (Breusch-Pagan = 16.282, df = 7, p = 0.023): ค่าคลาดเคลื่อนมาตรฐานแบบปกติอาจไม่ถูกต้อง ใช้ robust standard errors แบบ HC3 ใน R ได้ด้วย lmtest::coeftest(fit, vcov = sandwich::vcovHC(fit, type = "HC3")) (ตาราง Linear regression ของ DAPH ยังไม่มีตัวเลือกนี้) หรือแปลงตัวแปรตาม และดู Residual Plot ว่าความกว้างของการกระจายเปลี่ยนตามค่าทำนายอย่างไร
Non-constant variance (Breusch-Pagan = 16.282, df = 7, p = 0.023): the usual standard errors may be wrong. Use HC3 robust standard errors in R with lmtest::coeftest(fit, vcov = sandwich::vcovHC(fit, type = "HC3")) (DAPH's Linear regression table has no such option yet) or transform the outcome, and look at the Residual Plot to see how the spread changes with the predicted value.
Durbin-Watson = 0.117 แต่ข้อมูลตัวอย่างเป็นข้อมูลภาคตัดขวาง และแถวในไฟล์ไม่ได้เรียงแบบสุ่ม ผู้ป่วยที่อยู่ติดกันมีคะแนนใกล้กัน เมื่อสลับลำดับแถวแบบสุ่ม ค่าเดียวกันนี้ได้ 1.976 DAPH จึงแสดงค่านี้เป็นข้อมูลประกอบพร้อมหมายเหตุว่าข้อมูลภาคตัดขวางให้ค่าที่ขึ้นกับลำดับแถวในไฟล์ ไม่ใช่การตรวจความเป็นอิสระ · ใช้ Durbin-Watson เฉพาะเมื่อแถวเรียงตามเวลา
Durbin-Watson = 0.117, but the example data are cross-sectional and the file's rows are not in random order: neighbouring patients have similar scores; with the rows in a random order the same residuals give 1.976. DAPH therefore shows the value as information, with the note that for cross-sectional data it depends on the row order of the file and is not a check of independence. Use Durbin-Watson only when the rows are in time order.
Multicollinearity: VIF ทุกตัวใกล้ 1 (สูงสุด 1.088) ไม่มีปัญหา · เกณฑ์ 5 หรือ 10 เป็นเพียงหลักทั่วไป (O'Brien, 2007) VIF สูงร่วมกับ SE กว้างจึงควรพิจารณาตัดตัวแปรที่ซ้ำซ้อน สร้างคะแนนรวม หรือเก็บไว้ถ้าเป็นตัวแปรกวนที่จำเป็น · ค่าอิทธิพล: 59 คนเกินเส้น 4/n = 0.0031 ซึ่งเป็นเรื่องปกติในข้อมูลขนาดใหญ่ แต่ Cook's distance สูงสุดเพียง 0.0196 และไม่มีคนใดเกิน 1 จึงไม่มีผู้ป่วยรายใดกำหนดผลเพียงลำพัง ควรตรวจความถูกต้องของข้อมูลคนที่ถูกชี้ ถ้าพบข้อผิดพลาดให้แก้ และถ้าเป็นค่าจริงให้รายงานผลทั้งที่มีและไม่มีคนนั้น
Multicollinearity: every VIF is close to 1 (largest 1.088), so there is no problem. The cut-offs 5 and 10 are only rules of thumb (O'Brien, 2007); a high VIF together with wide SEs suggests dropping a redundant variable, building a combined score, or keeping it if it is a necessary confounder. Influence: 59 patients lie above the 4/n = 0.0031 line, which is usual in large samples, but the largest Cook's distance is only 0.0196 and none exceeds 1, so no single patient drives the results. Check the flagged records for data-entry errors; correct real errors, and if the values are genuine, report the results with and without them.
📖 References
- Breusch, T. S., & Pagan, A. R. (1979). A simple test for heteroscedasticity and random coefficient variation. Econometrica, 47(5), 1287–1294. doi:10.2307/1911963
- Cook, R. D. (1977). Detection of influential observation in linear regression. Technometrics, 19(1), 15–18. doi:10.1080/00401706.1977.10489493
- Durbin, J., & Watson, G. S. (1950). Testing for serial correlation in least squares regression. I. Biometrika, 37(3–4), 409–428. doi:10.1093/biomet/37.3-4.409
- Fox, J., & Monette, G. (1992). Generalized collinearity diagnostics. Journal of the American Statistical Association, 87(417), 178–183. doi:10.1080/01621459.1992.10475190
- Jarque, C. M., & Bera, A. K. (1980). Efficient tests for normality, homoscedasticity and serial independence of regression residuals. Economics Letters, 6(3), 255–259. doi:10.1016/0165-1765(80)90024-5
- Koenker, R. (1981). A note on studentizing a test for heteroscedasticity. Journal of Econometrics, 17(1), 107–112. doi:10.1016/0304-4076(81)90062-2
- O'Brien, R. M. (2007). A caution regarding rules of thumb for variance inflation factors. Quality & Quantity, 41(5), 673–690. doi:10.1007/s11135-006-9018-6
- Shapiro, S. S., & Wilk, M. B. (1965). An analysis of variance test for normality (complete samples). Biometrika, 52(3–4), 591–611. doi:10.1093/biomet/52.3-4.591
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
12.4Agreement — Cohen's kappa and ICC
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
การวัดในงานสาธารณสุขต้องเชื่อถือได้: พยาบาลสองคนอ่านผลเดียวกันได้ตรงกันหรือไม่ แบบสอบถามที่ตอบซ้ำให้ผลเหมือนเดิมหรือไม่ เครื่องมือสองชนิดวัดค่าได้เท่ากันหรือไม่ Cohen's kappa (κ) ใช้กับผลที่เป็นหมวดหมู่จากผู้ประเมินสองคน (หรือการวัดสองครั้ง) โดยวัดความตรงกันที่เกินกว่าที่จะตรงกันได้โดยบังเอิญ (Cohen, 1960) ส่วน Intraclass Correlation Coefficient (ICC) ใช้กับค่าที่เป็นตัวเลขจากผู้ประเมินหรือการวัดตั้งแต่สองครั้งขึ้นไป โดยเป็นสัดส่วนของความแปรปรวนทั้งหมดที่มาจากความแตกต่างจริงระหว่างบุคคล (Shrout & Fleiss, 1979)
Public-health measurements must be reproducible: do two nurses read the same result the same way, does a questionnaire give the same answer when repeated, do two devices give the same value? Cohen's kappa (κ) is for categorical ratings by two raters (or two occasions) and measures agreement beyond what chance alone would produce (Cohen, 1960). The intraclass correlation coefficient (ICC) is for numeric measurements by two or more raters or occasions and is the share of the total variance that comes from true differences between people (Shrout & Fleiss, 1979).
ใช้เมื่อ ผู้ประเมินหรือการวัดทุกครั้งวัดสิ่งเดียวกันในคนกลุ่มเดียวกัน · kappa ใช้กับหมวดหมู่ชุดเดียวกันจากสองแหล่ง (weighted kappa เมื่อหมวดหมู่มีลำดับ) · ICC ใช้กับคะแนนตัวเลข · ไม่ควรใช้ สหสัมพันธ์ของเพียร์สันแทนความสอดคล้อง เพราะหากผู้ประเมินคนหนึ่งให้คะแนนสูงกว่าอีกคนเท่ากันทุกราย ค่า r ยังเท่ากับ 1 ได้ · ไม่ใช้ Cronbach's α (หัวข้อ 12.1) ซึ่งเป็นความสอดคล้องระหว่างข้อคำถามคนละข้อ · kappa ขึ้นกับความชุกของหมวดหมู่ เมื่อเกือบทุกคนอยู่หมวดเดียว κ อาจต่ำแม้ร้อยละความตรงกันจะสูง
Use it when every rater or occasion measures the same thing on the same people: kappa for the same set of categories from two sources (weighted kappa when the categories are ordered), the ICC for numeric scores. Do not use Pearson's correlation as a measure of agreement: if one rater scores everyone exactly 5 points higher, r can still be 1. Do not use Cronbach's α (section 12.1), which concerns different items of one scale. Kappa depends on how common each category is: when almost everyone falls in one category, κ can be low even though the percentage agreement is high.
ใน DAPH · เมนู วิเคราะห์เพิ่มเติม > Agreement Analysis (Kappa/ICC)... · Kappa: เลือกตัวแปร Rater 1 และ Rater 2 · ICC: เลือกชนิด ICC(1,1), ICC(2,1) หรือ ICC(3,1) แล้วติ๊กตัวแปรตัวเลขอย่างน้อย 2 ตัว (แต่ละตัวแปรคือผู้ประเมินหรือการวัดหนึ่งครั้ง แต่ละแถวคือผู้ถูกวัดหนึ่งคน) · DAPH ใช้เฉพาะแถวที่มีค่าครบ
In DAPH: menu Additional Analysis > Agreement Analysis (Kappa/ICC).... Kappa: choose the Rater 1 and Rater 2 variables. ICC: choose ICC(1,1), ICC(2,1) or ICC(3,1) and tick two or more numeric variables (each variable is one rater or occasion, each row one person). DAPH uses complete rows only.
qol_g1) และระหว่างการรักษา (QoL Group (Mid), qol_g2) ตรงกันมากน้อยเพียงใด · คำถามที่ 2 (ICC): คะแนนคุณภาพชีวิตก่อน ระหว่าง และหลังการรักษา (qolscore1, qolscore2, qolscore3) ซึ่งถือเป็นการวัดสามครั้งของคนเดียวกัน สอดคล้องกันเพียงใด · เนื่องจาก "ผู้ประเมิน" ในตัวอย่างนี้คือการวัดสามครั้งระหว่างการรักษา การเปลี่ยนแปลงของคะแนนระหว่างครั้งจึงนับเป็นความไม่ตรงกันด้วย และคะแนนของแต่ละคนในข้อมูลตัวอย่างต่างกันเกือบคงที่ทุกคน (r = 0.9997) ตัวอย่างนี้จึงแสดงความต่างระหว่าง "ความสอดคล้องของลำดับ" กับ "ความตรงกันของค่า" ได้ชัด (ตัวแปร qol_g3 ไม่ได้ใช้ เพราะรหัส 1 ของตัวแปรนี้คือคะแนนต่ำ ซึ่งกลับกับป้ายชื่อ)qol_g1) and mid-treatment (QoL Group (Mid), qol_g2) assessments? Question 2 (ICC): how well do the pre, mid and post quality-of-life scores (qolscore1, qolscore2, qolscore3), treated as three measurements of the same person, agree? Because the "raters" here are three visits during treatment, any change in score between visits counts as disagreement, and in the example data each patient's three scores differ by an almost fixed amount (r = 0.9997). The example therefore shows clearly the difference between consistency of ranking and agreement of values. (qol_g3 is not used: its code 1 marks a low score, the opposite of its value label.)2หลักการและสูตรLogic and Formula
- p_ij, p_i·, p_·j
- สัดส่วนในช่อง (i, j) ของตารางไขว้ผู้ประเมินคนที่ 1 (แถว) กับคนที่ 2 (คอลัมน์) และผลรวมแถวและคอลัมน์proportion in cell (i, j) of the cross-table of rater 1 (rows) by rater 2 (columns), and the row and column totals
- p_o, p_e, q
- สัดส่วนที่ตรงกันจริง สัดส่วนที่คาดว่าจะตรงกันโดยบังเอิญ และจำนวนหมวดหมู่ (เรียงตามรหัส)observed agreement, agreement expected by chance, and number of categories (in code order)
- SE_0, SE_FCE
- SE ภายใต้ H₀: κ = 0 สำหรับการทดสอบ และ SE ของ Fleiss, Cohen & Everitt (1969) สำหรับช่วงเชื่อมั่นSE under H₀: κ = 0 (for the test) and the Fleiss, Cohen & Everitt (1969) SE (for the confidence interval)
- MS_B, MS_W, MS_R, MS_E
- mean square ระหว่างบุคคล ภายในบุคคล ระหว่างผู้ประเมิน และส่วนที่เหลือmean squares between subjects, within subjects, between raters, and residual
- n, k
- จำนวนบุคคล และจำนวนผู้ประเมินหรือครั้งที่วัดnumber of subjects and number of raters or occasions
- F*, F**
- F0.975; n−1, v และ F0.975; v, n−1F0.975; n−1, v and F0.975; v, n−1
สิ่งที่ DAPH คำนวณ (kappa) · ตารางไขว้ ร้อยละความตรงกัน κ ไม่ถ่วงน้ำหนัก κ ถ่วงน้ำหนักแบบเส้นตรงและแบบกำลังสอง (สองหมวดหมู่ให้ค่าเท่ากับ κ) และแปลผลตามเกณฑ์ของ Landis & Koch (1977): < 0 ไม่สอดคล้อง, 0–0.20 น้อยมาก, 0.21–0.40 พอใช้, 0.41–0.60 ปานกลาง, 0.61–0.80 มาก, 0.81–1.00 ดีมาก · SE และช่วงเชื่อมั่น 95% (κ ± 1.96 SE) ใช้ SE ของ Fleiss, Cohen & Everitt (1969) ส่วนการทดสอบ κ = 0 ใช้ SE ภายใต้ H₀ แสดงเป็นบรรทัด "z (ทดสอบ Kappa = 0)" พร้อมค่า p
What DAPH computes (kappa). The cross-table, percentage agreement, unweighted κ, linearly and quadratically weighted κ (with two categories both equal κ), and the Landis & Koch (1977) label: < 0 poor, 0–0.20 slight, 0.21–0.40 fair, 0.41–0.60 moderate, 0.61–0.80 substantial, 0.81–1.00 almost perfect. The standard error and the 95% confidence interval κ ± 1.96 SE use the large-sample SE of Fleiss, Cohen & Everitt (1969); the test of κ = 0 uses the SE under H₀ and is printed as "z (test of Kappa = 0)" with its p value.
สิ่งที่ DAPH คำนวณ (ICC) · mean square ทั้งสี่ ค่า ICC ตามชนิดที่เลือก ค่า F (MSB/MSW สำหรับ ICC(1,1) และ MSB/MSE สำหรับ ICC(2,1), ICC(3,1)) ค่า p และช่วงเชื่อมั่น 95% แล้วแปลผลตาม Koo & Li (2016): < 0.50 ต่ำ, 0.50–0.75 ปานกลาง, 0.75–0.90 ดี, > 0.90 ดีเยี่ยม · ช่วงเชื่อมั่นของ ICC(1,1) และ ICC(3,1) คำนวณจากการแจกแจง F ส่วน ICC(2,1) ใช้วิธีของ McGraw & Wong (1996) ที่มีองศาอิสระของ Satterthwaite ตามสูตรด้านบน · ชนิดแบบค่าเฉลี่ยของผู้ประเมินหลายคน (ICC(1,k), ICC(2,k), ICC(3,k)) ไม่มีในหน้าจอ DAPH
What DAPH computes (ICC). The four mean squares, the ICC of the chosen type, the F statistic (MSB/MSW for ICC(1,1); MSB/MSE for ICC(2,1) and ICC(3,1)), its p value and a 95% confidence interval, labelled by Koo & Li (2016): < 0.50 poor, 0.50–0.75 moderate, 0.75–0.90 good, > 0.90 excellent. The intervals for ICC(1,1) and ICC(3,1) come from the F distribution; the interval for ICC(2,1) follows McGraw & Wong (1996) with Satterthwaite's degrees of freedom, as in the formula above. The average-measure types ICC(1,k), ICC(2,k) and ICC(3,k) are not offered on the DAPH screen.
เลือกชนิด ICC ก่อนวิเคราะห์ · ICC(1,1): แต่ละคนถูกวัดโดยผู้ประเมินคนละชุด · ICC(2,1): ผู้ประเมินเป็นตัวแทนที่สุ่มมาจากผู้ประเมินทั้งหมด และต้องการให้ค่าตรงกันจริง (absolute agreement) เช่น พยาบาลสองคนวัดความดันโลหิต · ICC(3,1): สนใจเฉพาะผู้ประเมินชุดนี้ และต้องการเพียงให้ลำดับสอดคล้องกัน (consistency) ความต่างที่คงที่ระหว่างผู้ประเมินไม่ถูกนับ
Choose the ICC type before the analysis. ICC(1,1): each person is rated by a different set of raters. ICC(2,1): the raters are a random sample of possible raters and the values themselves must agree (absolute agreement), for example two nurses measuring blood pressure. ICC(3,1): only these raters matter and only consistency of ranking is needed; a constant difference between raters is not counted.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(irr); library(psych)
# Cohen's kappa: "high QoL" (score above 60) at the pre (qol_g1) and mid (qol_g2) assessments
tab <- table(pre = d$qol_g1, mid = d$qol_g2); tab
n <- sum(tab); p <- tab / n; po <- sum(diag(p)); pr <- rowSums(p); pc <- colSums(p); pe <- sum(pr * pc)
kap <- (po - pe) / (1 - pe)
se_null <- sqrt(pe + pe^2 - sum(pr * pc * (pr + pc))) / ((1 - pe) * sqrt(n)) # SE under H0: kappa = 0
round(c(agreement = po, expected = pe, kappa = kap, se_null = se_null, z_null = kap / se_null), 5)
irr::kappa2(d[, c("qol_g1", "qol_g2")]) # z test with the SE under H0
ck <- psych::cohen.kappa(d[, c("qol_g1", "qol_g2")]) # SE of Fleiss, Cohen & Everitt (1969) for the CI
round(c(se_FCE = sqrt(ck$var.kappa), ck$confid[1, ], weighted = ck$weighted.kappa), 5)
mid
pre 0 1
0 287 116
1 0 897
agreement expected kappa se_null z_null
0.91077 0.60611 0.77346 0.02701 28.63199
Cohen's Kappa for 2 Raters (Weights: unweighted)
Subjects = 1300
Raters = 2
Kappa = 0.773
z = 28.6
p-value = 0
se_FCE lower estimate upper weighted
0.01955 0.73514 0.77346 0.81178 0.77346
# ICC: the QoL score at the pre, mid and post assessments treated as three measurements
q <- as.matrix(d[, c("qolscore1", "qolscore2", "qolscore3")])
round(colMeans(q), 2)
nS <- nrow(q); k <- ncol(q); gm <- mean(q)
SSB <- k * sum((rowMeans(q) - gm)^2); SSR <- nS * sum((colMeans(q) - gm)^2); SST <- sum((q - gm)^2)
MSB <- SSB / (nS - 1); MSW <- (SST - SSB) / (nS * (k - 1)); MSR <- SSR / (k - 1)
MSE <- (SST - SSB - SSR) / ((nS - 1) * (k - 1))
round(c(MSB = MSB, MSW = MSW, MSR = MSR, MSE = MSE), 4)
ic <- psych::ICC(q, lmer = FALSE)
print(ic$results[, c("type", "ICC", "F", "df1", "df2", "lower bound", "upper bound")], digits = 4)
# ICC(2,1) interval by hand (McGraw & Wong 1996): Satterthwaite degrees of freedom v
icc2 <- ic$results["Single_random_raters", "ICC"]
a <- k * icc2 / (nS * (1 - icc2)); b <- 1 + k * icc2 * (nS - 1) / (nS * (1 - icc2))
v <- (a * MSR + b * MSE)^2 / ((a * MSR)^2 / (k - 1) + (b * MSE)^2 / ((nS - 1) * (k - 1)))
F1 <- qf(0.975, nS - 1, v); F2 <- qf(0.975, v, nS - 1)
round(c(v = v, lower = nS * (MSB - F1 * MSE) / (F1 * (k * MSR + (k * nS - k - nS) * MSE) + nS * MSB),
upper = nS * (F2 * MSB - MSE) / (k * MSR + (k * nS - k - nS) * MSE + nS * F2 * MSB)), 4)
qolscore1 qolscore2 qolscore3
68.36 73.86 75.86
MSB MSW MSR MSE
955.2969 15.1262 19570.6089 0.0720
type ICC F df1 df2 lower bound upper bound
Single_raters_absolute ICC1 0.9540 63.16 1299 2600 0.9496 0.9580
Single_random_raters ICC2 0.9546 13275.62 1299 2598 0.3539 0.9873
Single_fixed_raters ICC3 0.9998 13275.62 1299 2598 0.9998 0.9998
Average_raters_absolute ICC1k 0.9842 63.16 1299 2600 0.9826 0.9856
Average_random_raters ICC2k 0.9844 13275.62 1299 2598 0.6217 0.9957
Average_fixed_raters ICC3k 0.9999 13275.62 1299 2598 0.9999 0.9999
v lower upper
2.0195 0.3539 0.9873
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| ตาราง pre × mid: (0,0) / (0,1) / (1,0) / (1,1)pre × mid table: (0,0) / (0,1) / (1,0) / (1,1) | 287 / 116 / 0 / 897 | 287 / 116 / 0 / 897 | 0 | ✓ PASS |
| ร้อยละความตรงกันpercentage agreement | 91.077% | 91.08% | < 0.005 | ✓ PASS |
| Cohen's κ | 0.77346 | 0.7735 | < 0.00005 | ✓ PASS |
| κ ถ่วงน้ำหนัก (เส้นตรง / กำลังสอง)weighted κ (linear / quadratic) | 0.77346 | 0.7735 / 0.7735 | < 0.00005 | ✓ PASS |
| SE ของ κ (R: Fleiss, Cohen & Everitt 1969)SE of κ (R: Fleiss, Cohen & Everitt 1969) | 0.01955 | 0.0196 (0.01955) | 0.00000 | ✓ PASS |
| 95% CI ของ κ95% CI of κ | 0.73514 to 0.81178 | 0.7351 to 0.8118 | 0.0000 | ✓ PASS |
| z ทดสอบ κ = 0 (SE ภายใต้ H₀)z for the test of κ = 0 (SE under H₀) | 28.632 | 28.632 | 0.0000 | ✓ PASS |
| p ของการทดสอบ κ = 0p of the test of κ = 0 | < 0.001 | < 0.001 | 0 | ✓ PASS |
| MSB / MSW / MSR / MSE | 955.2969 / 15.1262 / 19570.6089 / 0.0720 | 955.2969 / 15.1262 / 19570.6089 / 0.0720 | < 0.00005 | ✓ PASS |
| ICC(1,1) และ 95% CIICC(1,1) and 95% CI | 0.9540 (0.9496 to 0.9580) | 0.9540 (0.9496 to 0.9580) | < 0.00005 | ✓ PASS |
| ICC(2,1) | 0.9546 | 0.9546 | < 0.00005 | ✓ PASS |
| 95% CI ของ ICC(2,1)95% CI of ICC(2,1) | 0.3539 to 0.9873 | 0.3539 to 0.9873 | 0.000 | ✓ PASS |
| ICC(3,1) และ 95% CIICC(3,1) and 95% CI | 0.9998 (0.9998 to 0.9998) | 0.9998 (0.9998 to 0.9998) | < 0.00005 | ✓ PASS |
| F ของ ICC(2,1) / ICC(3,1); dfF for ICC(2,1) / ICC(3,1); df | 13275.62; 1299, 2598 | 13275.6180 | < 0.005 | ✓ PASS |
| ICC(2,k) และ 95% CI (เรียกได้ทาง API เท่านั้น)ICC(2,k) and 95% CI (reachable through the API only) | 0.9844 (0.6217 to 0.9957) | 0.9844 (0.62173 to 0.99572) | 0.000 | ✓ PASS |
ทุกค่าที่ DAPH แสดงตรงกับ R ภายในการปัดเศษที่แสดง รวมทั้ง SE และช่วงเชื่อมั่นของ κ ค่า z ของการทดสอบ κ = 0 และช่วงเชื่อมั่นของ ICC(2,1) และ ICC(2,k)
Every value DAPH prints agrees with R within the displayed rounding, including the SE and interval of κ, the z of the test of κ = 0, and the intervals of ICC(2,1) and ICC(2,k).
4การแปลผลและตัวอย่างInterpretation and Example
คำถามที่ 1: การจัดกลุ่มคุณภาพชีวิตสูงก่อนการรักษาและระหว่างการรักษาตรงกันร้อยละ 91.1 ขณะที่คาดว่าจะตรงกันโดยบังเอิญร้อยละ 60.6 ได้ κ = 0.773 (95% CI 0.735 ถึง 0.812; z = 28.63, p < 0.001) อยู่ในระดับ "สอดคล้องมาก" ตาม Landis & Koch (1977) แต่ความไม่ตรงกันทั้ง 116 รายเป็นทิศทางเดียว คือจากกลุ่มต่ำไปกลุ่มสูง เพราะคะแนนเพิ่มขึ้นระหว่างการรักษา kappa ไม่บอกทิศทางของความไม่ตรงกัน หากต้องการทดสอบการเปลี่ยนแปลงอย่างเป็นระบบ ให้ใช้ McNemar test (หัวข้อ 2.5)
Question 1: the high-QoL classification agreed between the pre and mid assessments for 91.1% of patients, against 60.6% expected by chance, giving κ = 0.773 (95% CI 0.735 to 0.812; z = 28.63, p < 0.001), "substantial" by Landis & Koch (1977). All 116 disagreements go the same way, from low to high, because scores rose during treatment; kappa does not show the direction of disagreement, and a systematic change is tested with McNemar's test (section 2.5).
คำถามที่ 2: ค่าเฉลี่ยคะแนนเพิ่มจาก 68.36 เป็น 73.86 และ 75.86 ในสามครั้ง แต่ลำดับของผู้ป่วยแทบไม่เปลี่ยน ICC(3,1) (ความสอดคล้องของลำดับ) จึงเท่ากับ 0.9998 ขณะที่ ICC(2,1) (ความตรงกันของค่า) เท่ากับ 0.955 และ ICC(1,1) เท่ากับ 0.954 เพราะความต่างของค่าเฉลี่ยระหว่างครั้งถูกนับเป็นความคลาดเคลื่อน ช่วงเชื่อมั่น 95% ของ ICC(2,1) ที่ถูกต้องคือ 0.354 ถึง 0.987 ซึ่งกว้างมาก เพราะความแปรปรวนระหว่างครั้งประมาณจากการวัดเพียง 3 ครั้ง (องศาอิสระ v ≈ 2.02) ขอบล่างจึงอยู่ในระดับต่ำตามเกณฑ์ของ Koo & Li (2016) แม้ค่าประมาณจะ "ดีเยี่ยม" ควรตัดสินจากช่วงเชื่อมั่น ไม่ใช่ค่าประมาณเพียงอย่างเดียว
Question 2: the mean score rises from 68.36 to 73.86 and 75.86 over the three visits, but patients hardly change rank, so ICC(3,1) (consistency) is 0.9998 while ICC(2,1) (absolute agreement) is 0.955 and ICC(1,1) is 0.954, because the differences between visit means count as error. The correct 95% CI of ICC(2,1) is 0.354 to 0.987, very wide because the between-visit variance is estimated from only three visits (v ≈ 2.02 degrees of freedom). Its lower limit is "poor" on the Koo & Li (2016) scale even though the estimate is "excellent", so judge reliability by the interval, not the estimate alone.
📖 References
- Cohen, J. (1960). A coefficient of agreement for nominal scales. Educational and Psychological Measurement, 20(1), 37–46. doi:10.1177/001316446002000104
- Cohen, J. (1968). Weighted kappa: Nominal scale agreement provision for scaled disagreement or partial credit. Psychological Bulletin, 70(4), 213–220. doi:10.1037/h0026256
- Fleiss, J. L., Cohen, J., & Everitt, B. S. (1969). Large sample standard errors of kappa and weighted kappa. Psychological Bulletin, 72(5), 323–327. doi:10.1037/h0028106
- Koo, T. K., & Li, M. Y. (2016). A guideline of selecting and reporting intraclass correlation coefficients for reliability research. Journal of Chiropractic Medicine, 15(2), 155–163. doi:10.1016/j.jcm.2016.02.012
- Landis, J. R., & Koch, G. G. (1977). The measurement of observer agreement for categorical data. Biometrics, 33(1), 159–174. doi:10.2307/2529310
- McGraw, K. O., & Wong, S. P. (1996). Forming inferences about some intraclass correlation coefficients. Psychological Methods, 1(1), 30–46. doi:10.1037/1082-989X.1.1.30
- Shrout, P. E., & Fleiss, J. L. (1979). Intraclass correlations: Uses in assessing rater reliability. Psychological Bulletin, 86(2), 420–428. doi:10.1037/0033-2909.86.2.420
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
บทที่ 13 — การเลือกแบบจำลอง (Model Selection)Chapter 13 — Model Selection 📘 ระเบียบวิธีMethod notes
บทนี้รวบรวม ทุกวิธีการเลือกตัวแปรและเลือกแบบจำลองที่ DAPH มีให้ใช้ ไว้ในที่เดียว — ห้าวิธีในดรอปดาวน์ "วิธีการวิเคราะห์" ของ Linear · Logistic · Log-binomial · Poisson · Cox regression (Enter · Backward Elimination · Stepwise Regression · Forward Selection · Bivariate Analysis — หัวข้อ 13.4) · เจ็ดวิธีของ Spatial Regression และ Spatial Panel Regression (13.2) · หกวิธีของสถิติกลุ่ม Machine Learning (13.3) · และเกณฑ์ที่ใช้ตัดสินโครงสร้างของแบบจำลอง (AIC · BIC · การทดสอบ LM · Hausman · ความแม่นบนข้อมูลที่กันไว้) พร้อมกติกาว่าเมื่อใดเกณฑ์เหล่านี้จึงเทียบกันได้ และแผนที่ว่าสถิติแต่ละตัวเปิดให้ใช้วิธีใด (13.1) This chapter gathers every variable-selection and model-selection option DAPH offers in one place — the five methods in the "Analysis Method" dropdown of Linear · Logistic · Log-binomial · Poisson · Cox regression (Enter · Backward Elimination · Stepwise Regression · Forward Selection · Bivariate Analysis — 13.4), the seven methods of Spatial Regression and Spatial Panel Regression (13.2), the six of the Machine Learning statistics (13.3), and the criteria that decide a model's structure (AIC · BIC · LM tests · Hausman · held-out accuracy), with the rules for when those criteria can be compared at all and a map of which statistic offers which (13.1).
13.1หลักการเลือกแบบจำลอง — อธิบาย (explain) กับ ทำนาย (predict)Principles of Model Selection — Explaining vs Predicting
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
คำถามแรกก่อนเลือกวิธีใด ๆ ไม่ใช่ "วิธีไหนดีที่สุด" แต่คือ "แบบจำลองนี้จะถูกใช้ทำอะไร" — Shmueli (2010) แยกเป้าหมายไว้สองทาง ซึ่งนำไปสู่การเลือกคนละแบบ:
(ก) เพื่ออธิบาย (explanatory) — ต้องการค่าสัมประสิทธิ์ของตัวแปรหลักที่ตีความได้ เช่น "ผู้ป่วยที่ล้างไตทางช่องท้องด้วยเครื่องอัตโนมัติ (APD) มีโอกาสเสียชีวิตต่างจากผู้ที่เปลี่ยนน้ำยาด้วยตนเอง (CAPD) เท่าใด เมื่อคำนึงถึงอายุและโรคประจำตัวแล้ว" ตัวแปรที่ใส่ในแบบจำลองจึงมาจาก ความรู้เดิมและกรอบแนวคิด เป็นหลัก ตัวแปรกวน (confounder) ต้องคงไว้แม้ไม่มีนัยสำคัญ และไม่ควรปล่อยให้ขั้นตอนอัตโนมัติตัดออก
(ข) เพื่อทำนาย (predictive) — ต้องการค่าทำนายที่แม่นกับผู้ป่วยที่แบบจำลองยังไม่เคยเห็น ตัวแปรจึงคัดได้ด้วยเกณฑ์ประสิทธิภาพ และต้องตัดสินด้วย ข้อมูลที่กันไว้ทดสอบ ไม่ใช่ค่าที่คำนวณจากข้อมูลชุดที่ใช้สร้างแบบจำลองเอง
The first question is not "which method is best" but "what will this model be used for". Shmueli (2010) separates two goals that lead to different choices:
(a) To explain — you want an interpretable coefficient for the variable of interest, for example "how different is the odds of death for patients on automated peritoneal dialysis (APD) compared with continuous ambulatory peritoneal dialysis (CAPD), once age and chronic disease are taken into account?". The covariates come mainly from background knowledge and the conceptual framework; confounders stay in whether or not they reach significance, and no automated step should remove them.
(b) To predict — you want accurate predictions for patients the model has never seen. Predictors may be screened on performance, but the model must be judged on held-out data, not on the data it was built from.
2หลักการและสูตรLogic and Formula
เกณฑ์สารสนเทศ (information criteria) ให้คะแนนแบบจำลองโดยชั่งระหว่าง ความแนบข้อมูล กับ จำนวนพารามิเตอร์ — ยิ่งค่าน้อยยิ่งดี AIC มาจาก Akaike (1974) และ BIC มาจาก Schwarz (1978):
Information criteria trade fit against the number of parameters — lower is better. AIC is due to Akaike (1974) and BIC to Schwarz (1978):
- ℓ̂
- ค่า log-likelihood สูงสุดของแบบจำลอง (Cox regression ใช้ log partial likelihood)maximised log-likelihood of the model (Cox regression uses the log partial likelihood)
- k
- จำนวนพารามิเตอร์ที่ประมาณค่า: linear regression = สัมประสิทธิ์ทั้งหมดรวม intercept บวกความแปรปรวนของส่วนเหลือ σ² · logistic และ Poisson = สัมประสิทธิ์ทั้งหมด · negative binomial = สัมประสิทธิ์บวกพารามิเตอร์การกระจาย α · Cox = สัมประสิทธิ์ (ไม่มี intercept) · แบบจำลองเชิงพื้นที่นับ ρ หรือ λ ด้วยnumber of estimated parameters: linear regression = all coefficients including the intercept, plus the residual variance σ²; logistic and Poisson = all coefficients; negative binomial = coefficients plus the dispersion α; Cox = coefficients (no intercept); spatial models also count ρ or λ
- n
- จำนวนแถวที่แบบจำลองใช้จริง (หลังตัดแถวที่มีค่าขาดหาย)number of rows the model actually used (after rows with missing values are dropped)
- Δi, wi, R
- ส่วนต่าง AIC จากแบบจำลองที่ดีที่สุด · น้ำหนักของแบบจำลอง i (รวมกันได้ 1) · จำนวนแบบจำลองที่นำมาเทียบAIC difference from the best model · weight of model i (the weights sum to 1) · number of models compared
Burnham & Anderson (2002) ให้กติกาอ่านค่า Δ ไว้ว่า Δ ≤ 2 คือมีหลักฐานสนับสนุนพอ ๆ กับแบบจำลองที่ดีที่สุด · Δ 4–7 คือได้รับการสนับสนุนน้อยกว่าอย่างชัดเจน · Δ > 10 คือแทบไม่มีหลักฐานสนับสนุน และแนะนำให้ใช้ AICc เมื่อ n/k < 40
Burnham & Anderson (2002) read Δ as: Δ ≤ 2 = substantial support, about as good as the best model · Δ 4–7 = considerably less support · Δ > 10 = essentially no support; they advise AICc whenever n/k < 40.
DAPH พิมพ์เกณฑ์อะไรให้บ้าง — ไม่เท่ากันทุกสถิติ ตรวจได้จากหน้าผลลัพธ์ (Tab 3) และไฟล์ Word:
What DAPH prints — it differs by statistic (results view, Tab 3, and the Word report):
| สถิติStatistic | ค่าที่พิมพ์Printed | ข้อสังเกตNote |
|---|---|---|
| Linear regression | AIC และ BIC (Tab 3 หัวข้อ Model Fit) · Word พิมพ์ R² และ Adjusted R²AIC and BIC (Tab 3, Model Fit) · Word prints R² and adjusted R² | DAPH นับ k เฉพาะสัมประสิทธิ์ ไม่นับ σ² จึงได้ AIC ต่ำกว่าสูตรข้างบน 2 และ BIC ต่ำกว่า ln n เท่ากันทุกแบบจำลอง ส่วนต่างระหว่างแบบจำลองจึงไม่เปลี่ยน (ดูตารางทวนสอบ)DAPH counts only the coefficients in k (σ² is not counted), so its AIC is 2 lower and its BIC ln n lower than the formula above, by the same amount for every model; differences between models are unchanged (see the verification table) |
| Logistic regression | AIC และ BIC (Tab 3) · log-likelihood, AIC และ BIC (Word)AIC and BIC (Tab 3) · log-likelihood, AIC and BIC (Word) | ตรงกับ Rmatches R |
| Poisson / negative binomial | AIC (Tab 3 และ Word)AIC (Tab 3 and Word) | เมื่อเปลี่ยนเป็น negative binomial นับ α เป็นพารามิเตอร์ด้วย ตรงกับ Rwhen DAPH switches to the negative binomial, α is counted as a parameter, as in R |
| Cox regression | ไม่พิมพ์ AIC · พิมพ์ likelihood-ratio test, concordance (C) และการทดสอบ proportional hazardsno AIC · prints the likelihood-ratio test, concordance (C) and the proportional-hazards test | ถ้าต้องการ AIC ของ Cox ให้คำนวณใน R ด้วย AIC(coxph(...)) และเทียบเฉพาะแบบจำลอง Cox บนแถวชุดเดียวกันfor a Cox AIC use AIC(coxph(...)) in R and compare only Cox models on the same rows |
ตัวแปรเยอะ ตัวอย่างน้อย — ข้อมูลรองรับพารามิเตอร์ได้กี่ตัว ไม่มีวิธีคัดเลือกใดสร้างข้อมูลเพิ่มได้ ถ้าหน่วยข้อมูลน้อยเมื่อเทียบกับจำนวนพารามิเตอร์ การคัดเลือกจะกลายเป็นการไล่จับสัญญาณรบกวน กติกาที่ใช้กันคือ
Many variables, few observations — how many parameters can the data support? No selection method creates information: when the observations are few relative to the parameters, selection ends up chasing noise. The rules in use are:
- ตัวแปรตามต่อเนื่อง — จำนวนพารามิเตอร์ที่พิจารณาควรน้อยกว่าประมาณ n/15 (Harrell 2015, §4.4)
- ตัวแปรตามสองค่า — นับ จำนวนเหตุการณ์ในกลุ่มที่น้อยกว่า ไม่ใช่จำนวนแถว: อย่างน้อยประมาณ 10 เหตุการณ์ต่อหนึ่งพารามิเตอร์ (events per variable, EPV; Peduzzi et al. 1996)
- ข้อมูลการอยู่รอด — นับจำนวนเหตุการณ์ (เช่น จำนวนผู้เสียชีวิต) อย่างน้อยประมาณ 10 เหตุการณ์ต่อหนึ่งพารามิเตอร์ (Peduzzi et al. 1995)
- ถ้าจะคัดตัวแปรด้วยข้อมูล — Heinze et al. (2018) แนะนำว่า EPV ≤ 10 ไม่ควรคัดเลย · EPV มากกว่า 10 ถึง 25 คัดได้เมื่อใช้วิธีหดค่าสัมประสิทธิ์ (shrinkage) หรือ penalized estimation และตรวจความเสถียร · EPV > 25 คัดได้แต่ต้องตรวจความเสถียร และไม่ควรคัดตัวแปรที่รู้อยู่แล้วว่ามีผลชัด
- แบบจำลองทำนาย — คำนวณขนาดตัวอย่างขั้นต่ำด้วยสูตรของ Riley et al. (2020) แทนการใช้กติกา 10 EPV อย่างเดียว
- สถิติเชิงพื้นที่ — หน่วยข้อมูลคือ พื้นที่ ไม่ใช่ประชากรในพื้นที่ ข้อมูลระดับจังหวัด 77 จังหวัดจึงมี n = 77 ไม่ว่าประชากรรวมจะกี่ล้านคน
- Continuous outcome — keep the number of candidate parameters below about n/15 (Harrell 2015, §4.4).
- Binary outcome — count events in the smaller outcome group, not rows: at least about 10 events per parameter (events per variable, EPV; Peduzzi et al. 1996).
- Survival data — count events (for example deaths): at least about 10 per parameter (Peduzzi et al. 1995).
- If variables will be selected from the data — Heinze et al. (2018) advise no selection at EPV ≤ 10; between 10 and 25, selection only with shrinkage or penalised estimation plus a stability check; above 25, selection with a stability check; and no selection on variables already known to have strong effects.
- Prediction models — derive the minimum sample size from Riley et al. (2020) rather than from the 10-EPV rule alone.
- Spatial statistics — the unit is the area, not the people in it: 77 provinces means n = 77 however many millions live there.
เมื่อข้อมูลไม่พอ ทางออกที่ปกป้องได้คือ ลดจำนวนตัวแปรที่นำเข้าพิจารณาด้วยกรอบแนวคิดตั้งแต่ต้น หรือใช้วิธีที่มีบทลงโทษ (penalized) ซึ่งออกแบบมาเพื่อสถานการณ์นี้ ไม่ใช่การไล่ตัดด้วย stepwise จนเหลือน้อย ๆ แล้วรายงานเหมือนกำหนดไว้ล่วงหน้า
When the data cannot support the candidate set, the defensible response is to narrow the candidates by theory up front, or to use a penalised method built for this situation — not to run a stepwise search down to a small set and then report it as if it had been pre-specified.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(MASS) # glm.nb(): negative binomial, dispersion estimated by maximum likelihood
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$bmi_group <- factor(d$bmi_group, 1:4, c("Underweight", "Normal", "Overweight", "Obese"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
d$income <- factor(d$income, 1:3, c("None", "<10,000", ">=10,000"))
d$occupation <- factor(d$occupation, 1:2, c("Employed", "Unemployed/Retired"))
d$type <- factor(d$type, 1:2, c("Public", "Private"))
# n, k, log-likelihood, AIC, BIC, Delta AIC and Akaike weight of models fitted to the SAME rows
ic <- function(...) {
m <- list(...)
out <- data.frame(n = sapply(m, nobs), k = sapply(m, function(f) attr(logLik(f), "df")),
logLik = sapply(m, function(f) as.numeric(logLik(f))),
AIC = sapply(m, AIC), BIC = sapply(m, BIC))
stopifnot(length(unique(out$n)) == 1) # refuse to compare different rows
out$dAIC <- out$AIC - min(out$AIC)
out$dBIC <- out$BIC - min(out$BIC)
out$weight <- exp(-out$dAIC / 2) / sum(exp(-out$dAIC / 2))
out
}
# (1) Same outcome, same 1,300 rows: AIC and BIC may be compared
lin_full <- lm(qolscore3 ~ group + age + gender + bmi_group + chronic + income + occupation, data = d)
lin_sel <- lm(qolscore3 ~ group + age + income + occupation, data = d) # set kept in 13.4
print(ic(full = lin_full, selected = lin_sel), digits = 7)
c(R2_full = summary(lin_full)$r.squared, R2_selected = summary(lin_sel)$r.squared)
log_full <- glm(status ~ group + age + gender + bmi_group + chronic + income + occupation,
family = binomial, data = d)
log_sel <- glm(status ~ group + age + chronic, family = binomial, data = d) # set kept in 13.4
print(ic(full = log_full, selected = log_sel), digits = 7)
# (2) Different rows: Hospital Type (type) is missing for 3 patients
log_type <- glm(status ~ group + age + chronic + type, family = binomial, data = d)
c(n_selected = nobs(log_sel), n_plus_type = nobs(log_type)) # 1300 vs 1297
AIC(log_sel); AIC(log_type) # NOT comparable: different rows
same <- subset(d, !is.na(type)) # refit on the same 1,297 rows
print(ic(selected = update(log_sel, data = same), plus_type = log_type), digits = 7)
# (3) Same counts, same rows, same offset: Poisson and negative binomial share one likelihood scale
f_cnt <- n_peritonitis ~ group + age + gender + bmi_group + chronic + income + occupation +
offset(log(person_years))
pois <- glm(f_cnt, family = poisson, data = d)
nb <- glm.nb(f_cnt, data = d)
sum(residuals(pois, type = "pearson")^2) / df.residual(pois) # Pearson chi-square/df of the Poisson fit
1 / nb$theta # alpha = 1/theta
print(ic(poisson = pois, neg_binomial = nb), digits = 7)
# (4) Different scales: a model for y and a model for log(y) cannot be compared as printed
lin_log <- lm(log(qolscore3) ~ group + age + gender + bmi_group + chronic + income + occupation, data = d)
c(AIC_y = AIC(lin_full), AIC_log_y = AIC(lin_log))
aic_log_on_y <- AIC(lin_log) + 2 * sum(log(d$qolscore3)) # Jacobian of the log transform
c(AIC_y = AIC(lin_full), AIC_log_y_on_y_scale = aic_log_on_y, difference = aic_log_on_y - AIC(lin_full))
n k logLik AIC BIC dAIC dBIC weight
full 1300 12 -5567.820 11159.64 11221.68 7.882761 33.73336 0.01905138
selected 1300 7 -5568.878 11151.76 11187.95 0.000000 0.00000 0.98094862
R2_full R2_selected
0.03427629 0.03270219
n k logLik AIC BIC dAIC dBIC weight
full 1300 11 -578.8861 1179.772 1236.643 10.50487 46.69571 0.005207489
selected 1300 4 -580.6336 1169.267 1189.948 0.00000 0.00000 0.994792511
n_selected n_plus_type
1300 1297
[1] 1169.267
[1] 1169.431
n k logLik AIC BIC dAIC dBIC weight
selected 1297 4 -579.8897 1167.779 1188.451 0.000000 0.000000 0.69546
plus_type 1297 5 -579.7155 1169.431 1195.270 1.651542 6.819352 0.30454
[1] 1.774904
[1] 0.6192306
n k logLik AIC BIC dAIC dBIC weight
poisson 1300 11 -1978.76 3979.521 4036.392 272.5203 267.3502 6.65235e-60
neg_binomial 1300 12 -1841.50 3707.001 3769.042 0.0000 0.0000 1.00000e+00
AIC_y AIC_log_y
11159.6391 378.7803
AIC_y AIC_log_y_on_y_scale difference
11159.639 11544.515 384.876
# (5) A non-significant test is not evidence of no effect: gender in the death model
drop1(log_full, test = "LRT")["gender", ]
exp(cbind(OR = coef(log_full), confint.default(log_full)))["genderFemale", ] # Wald 95% CI, as DAPH
# (6) Events per candidate parameter: 229 deaths, 10 coefficients besides the intercept
sum(d$status == 1) / (length(coef(log_full)) - 1)
Single term deletions
Model:
status ~ group + age + gender + bmi_group + chronic + income +
occupation
Df Deviance AIC LRT Pr(>Chi)
gender 1 1158.5 1178.5 0.75759 0.3841
OR 2.5 % 97.5 %
1.1528544 0.8356268 1.5905106
[1] 22.9
| ค่าQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Linear เต็ม · AIC ตามสูตรข้างบน (k รวม σ²)Linear, full · AIC as defined above (k includes σ²) | 11159.64 | 11157.6 | 2.0 | ✗ FAIL |
| Linear เต็ม · BIC ตามสูตรข้างบนLinear, full · BIC as defined above | 11221.68 | 11214.5 | 7.2 (= ln 1300) | ✗ FAIL |
| Linear · ΔAIC (เต็ม − คัดแล้ว)Linear · ΔAIC (full − selected) | 7.882761 | 7.882761 | < 1e−6 | ✓ PASS |
| Linear · ΔBIC (เต็ม − คัดแล้ว)Linear · ΔBIC (full − selected) | 33.73 | 33.7 | < 0.1 | ✓ PASS |
| Logistic เต็ม · log-likelihood / AIC / BICLogistic, full · log-likelihood / AIC / BIC | −578.8861 / 1179.772 / 1236.643 | −578.886 / 1179.7721 / 1236.6 | < 0.05 | ✓ PASS |
| Logistic คัดแล้ว · log-likelihood / AIC / BICLogistic, selected · log-likelihood / AIC / BIC | −580.6336 / 1169.267 / 1189.948 | −580.634 / 1169.2673 / 1189.9 | < 0.05 | ✓ PASS |
| Logistic + Hospital Type · n / AICLogistic + Hospital Type · n / AIC | 1297 / 1169.431 | 1297 / 1169.4309 | < 0.001 | ✓ PASS |
| Poisson · Pearson χ²/df (เกณฑ์เปลี่ยนเป็น NB > 1.5)Poisson · Pearson χ²/df (switch to NB above 1.5) | 1.774904 | 1.774904 | < 1e−6 | ✓ PASS |
| Negative binomial · α / AICNegative binomial · α / AIC | 0.6192306 / 3707.001 | 0.6192306 / 3707.0006 | < 1e−6 | ✓ PASS |
| Logistic เต็ม · Gender: p (LR test) และ OR หญิง (95% CI)Logistic, full · Gender: p (LR test) and OR female (95% CI) | 0.3841 · 1.153 (0.836 to 1.591) | 0.384 · 1.153 (0.836 to 1.591) | < 0.0005 | ✓ PASS |
| EPV (229 / 10) | 22.9 | 22.9 | 0 | ✓ PASS |
เหตุที่สองแถวแรกไม่ผ่าน: Linear regression ของ DAPH คำนวณ AIC และ BIC โดยนับ k เฉพาะสัมประสิทธิ์ ไม่นับความแปรปรวนของส่วนเหลือ σ² ขณะที่สูตรในหัวข้อนี้และ AIC() ของ R นับด้วย (Burnham & Anderson 2002) ค่าของ DAPH จึงต่ำกว่า 2 (AIC) และ ln n (BIC) เท่ากันทุกแบบจำลองที่ใช้แถวชุดเดียวกัน การเทียบแบบจำลองด้วย ΔAIC และ ΔBIC จึงได้ผลเหมือนกันทุกประการ (สองแถวที่ผ่าน) แต่ห้ามนำค่า AIC ของ linear regression จาก DAPH ไปเทียบกับค่าที่คำนวณด้วย R
Why the first two rows fail: DAPH's linear regression computes AIC and BIC with k = the coefficients only, leaving out the residual variance σ², whereas the formula in this section and R's AIC() count it (Burnham & Anderson 2002). DAPH's values are therefore lower by 2 (AIC) and by ln n (BIC), by the same amount for every model on the same rows, so ΔAIC and ΔBIC — the quantities used to compare models — are identical (the two passing rows). Do not compare a DAPH linear-regression AIC with one computed in R.
4การแปลผล และสถิติใดเลือกตัวแปรได้ด้วยวิธีใดInterpretation, and Which Statistic Offers Which Method
(1) แถวชุดเดียวกัน ตัวแปรตามเดียวกัน — เทียบได้: แบบจำลองคุณภาพชีวิตหลังการรักษาที่เหลือ 4 ตัวแปร (Treatment Group, Age, Personal Income, Employment Status) มี AIC ต่ำกว่าแบบจำลอง 7 ตัวแปร 7.88 (Akaike weight 0.981 เทียบกับ 0.019) และ BIC ต่ำกว่า 33.73 ส่วนแบบจำลองการเสียชีวิตที่เหลือ 3 ตัวแปร (Treatment Group, Age, Chronic Disease) มี AIC ต่ำกว่าแบบจำลองเต็ม 10.50 (weight 0.995) แต่ทั้งสองคู่ได้แบบจำลองเล็กมาจากการค้นหาบนข้อมูลชุดเดียวกัน (หัวข้อ 13.4) ส่วนต่าง AIC นี้จึงมองโลกในแง่ดีเกินจริง ไม่ใช่หลักฐานอิสระ และแบบจำลองคุณภาพชีวิตทั้งสองอธิบายความแปรปรวนได้น้อยมาก (R² 0.034 และ 0.033)
(1) Same rows, same outcome — comparable: the 4-variable quality-of-life model (Treatment Group, Age, Personal Income, Employment Status) has an AIC 7.88 lower than the 7-variable model (Akaike weight 0.981 vs 0.019) and a BIC 33.73 lower; the 3-variable death model (Treatment Group, Age, Chronic Disease) has an AIC 10.50 lower than the full model (weight 0.995). In both pairs, however, the smaller model came out of a search on the same data (13.4), so these AIC differences are optimistic rather than independent evidence — and both quality-of-life models explain very little of the variation (R² 0.034 and 0.033).
(2) แถวต่างกัน — เทียบไม่ได้: Hospital Type ขาดหาย 3 ราย แบบจำลองที่เพิ่มตัวแปรนี้จึงใช้ 1,297 แถว ถ้าเทียบตรง ๆ จะได้ AIC 1169.267 กับ 1169.431 ดูเหมือนเท่ากัน แต่เมื่อฟิตบน 1,297 แถวเดียวกันแล้ว ได้ 1167.779 กับ 1169.431 (Δ = 1.65, weight 0.695 เทียบกับ 0.305) — การเพิ่ม Hospital Type ไม่ได้ทำให้แบบจำลองดีขึ้น แม้ Δ < 2 จะแปลว่าทั้งสองแบบจำลองยังได้รับการสนับสนุนใกล้เคียงกัน
(2) Different rows — not comparable: Hospital Type is missing for 3 patients, so the model with it uses 1,297 rows. A direct comparison gives AIC 1169.267 vs 1169.431, an apparent tie; refitted on the same 1,297 rows it is 1167.779 vs 1169.431 (Δ = 1.65, weights 0.695 vs 0.305) — adding Hospital Type does not improve the model, although Δ < 2 still means both have similar support.
(3) สเกล likelihood เดียวกัน — เทียบได้ / ต่างสเกล — เทียบไม่ได้: สำหรับจำนวนครั้งเยื่อบุช่องท้องอักเสบ (offset = log ของคน-ปี) แบบจำลอง Poisson มี Pearson χ²/df = 1.77 เกินเกณฑ์ 1.5 DAPH จึงเปลี่ยนเป็น negative binomial (α = 0.619) ซึ่ง AIC ต่ำกว่า Poisson ถึง 272.5 — เทียบกันได้เพราะเป็นความน่าจะเป็นของจำนวนครั้งชุดเดียวกัน ตรงข้ามกับแบบจำลองคุณภาพชีวิตของ y เทียบกับ log(y): AIC ที่พิมพ์คือ 11159.64 กับ 378.78 ซึ่งดูเหมือน log(y) ดีกว่าหลายพันหน่วย แต่เป็นเพียงผลของการเปลี่ยนสเกล เมื่อย้ายมาไว้บนสเกลของ y ได้ 11544.5 แบบจำลองของ y เดิมกลับดีกว่า 384.9
(3) Same likelihood scale — comparable; different scales — not: for peritonitis episodes (offset = log person-years) the Poisson fit has Pearson χ²/df = 1.77, above the 1.5 threshold, so DAPH switches to the negative binomial (α = 0.619), whose AIC is 272.5 lower — a valid comparison because both are probabilities of the same counts. By contrast, the quality-of-life models of y and log(y) print AIC 11159.64 and 378.78, which looks like an overwhelming win for log(y) but is only the change of scale: moved onto the scale of y the log model's AIC is 11544.5, and the untransformed model is better by 384.9.
(4) ไม่มีนัยสำคัญ ≠ ไม่มีผล: ในแบบจำลองการเสียชีวิต เพศได้ p = 0.384 (likelihood-ratio test) แต่ OR ของเพศหญิงเทียบชาย = 1.153 (95% CI 0.836 to 1.591) ข้อมูลจึงเข้ากันได้ทั้งกับโอกาสเสียชีวิตที่ต่ำกว่า 16% และสูงกว่า 59% ไม่ใช่หลักฐานว่าเพศไม่สัมพันธ์กับการเสียชีวิต · ข้อมูลนี้มีผู้เสียชีวิต 229 ราย ต่อพารามิเตอร์ 10 ตัว = EPV 22.9 อยู่ในช่วง 10–25 ซึ่ง Heinze et al. (2018) ให้คัดตัวแปรได้เฉพาะเมื่อใช้ shrinkage หรือ penalized estimation และตรวจความเสถียร — สำหรับคำถามแบบอธิบาย การกำหนดตัวแปรไว้ล่วงหน้าจึงปกป้องได้มากกว่า
(4) Not significant ≠ no effect: in the death model gender has p = 0.384 (likelihood-ratio test), yet the OR for women vs men is 1.153 (95% CI 0.836 to 1.591): the data are compatible with 16% lower to 59% higher odds of death, which is not evidence that gender is unrelated to death. These data have 229 deaths for 10 parameters, an EPV of 22.9 — the 10–25 band in which Heinze et al. (2018) allow selection only with shrinkage or penalised estimation and a stability check; for an explanatory question a pre-specified covariate set is the more defensible choice.
แผนที่ของทั้งบท — ช่องขวาสุดบอกว่าไปอ่านรายละเอียดต่อได้ที่หัวข้อใด (ตรวจกับหน้าจอ Tab 2 และโค้ดของ DAPH)
The map of the chapter — the last column points to the section with the details (checked against the Tab 2 screen and the DAPH engine).
| สถิติStatistic | วิธีเลือกตัวแปรที่เลือกได้Selection options | เกณฑ์เลือกโครงสร้างแบบจำลองStructure criterion | รายละเอียดDetails |
|---|---|---|---|
| กลุ่มถดถอย — ดรอปดาวน์ "วิธีการวิเคราะห์" ใน Tab 2Regression family — the "Analysis Method" dropdown in Tab 2 | |||
| Linear · Logistic · Log-binomial · Poisson (negative binomial) · Cox | 5 วิธี: Enter · Backward Elimination · Stepwise Regression · Forward Selection · Bivariate Analysis5 methods: Enter · Backward Elimination · Stepwise Regression · Forward Selection · Bivariate Analysis | ตัดออกเมื่อ p > 0.05 · นำเข้าเมื่อ p < 0.05 (Linear, Logistic, Log-binomial) หรือเมื่อ AIC ลดลง (Poisson, Cox) · ผู้วิจัยตัดสินแบบจำลองสุดท้ายจากกรอบแนวคิดremoval when p > 0.05 · entry when p < 0.05 (Linear, Logistic, Log-binomial) or when AIC falls (Poisson, Cox) · the researcher decides the final model from the conceptual framework | 13.4 |
| Conditional Logistic Regression | Enter · Backward Elimination (ตัดตัวแปรที่มีค่า p สูงสุดทีละตัวเมื่อ p ≥ 0.05 โดยไม่ตัดตัวแปรหลัก)Enter · Backward Elimination (removes the variable with the largest p, one at a time, while p ≥ 0.05; the exposure is never removed) | ผู้วิจัยกำหนดset by the researcher | 2.2 |
| Ordered · Multinomial Logistic Regression | Enter · Bivariate Analysis | ผู้วิจัยกำหนดset by the researcher | 13.4 |
| Mixed Effect (Linear · Logistic · Poisson) · GEE | Enter เท่านั้น (ไม่มีดรอปดาวน์)Enter only (no dropdown) | ผู้วิจัยกำหนดset by the researcher | 13.1 |
| กลุ่มเชิงพื้นที่ — ดรอปดาวน์วิธีเลือกตัวแปรในแผงตั้งค่าเชิงพื้นที่Spatial family — the variable-selection dropdown in the spatial settings panel | |||
| Spatial Regression OLS · SLM · SEM · SDM |
7 วิธี (รวม Enter): คัดด้วย VIF · คัดด้วย LASSO · ค้นแบบ backward/forward ที่ตัดสินด้วย AIC และวิธีผสม7 methods (Enter included): VIF screen · LASSO screen · backward/forward searches decided on AIC, and their combinations | การทดสอบ Lagrange Multiplier ตามกติกาของ Anselin · AIC/BIC เทียบเฉพาะแบบจำลองบนพื้นที่ชุดเดียวกันLagrange Multiplier tests (Anselin's decision rule) · AIC/BIC only between models on the same areas | 13.2 |
| Spatial Panel Regression Pooled OLS · FE · RE × Lag · Error |
7 วิธีเดียวกับ Spatial Regressionthe same 7 methods as Spatial Regression | ทดสอบว่ามีผลประจำพื้นที่หรือไม่ → Hausman (FE เทียบ RE) → AIC เฉพาะในตระกูลที่เลือก ไม่เทียบ AIC ข้าม FE กับ REtests for area effects → Hausman (FE vs RE) → AIC only within the chosen family, never across FE and RE | 13.2 |
| กลุ่ม Machine Learning — ดรอปดาวน์วิธีเลือกตัวแปรในแผงตั้งค่าโมเดลMachine Learning family — the variable-selection dropdown in the model settings panel | |||
| Machine Learning Comparison · Spatial Machine Learning · Spatio-Temporal Machine Learning | 6 วิธี (รวม Enter) ตัวคัดถูกฟิตใหม่ในทุก fold6 methods (Enter included), re-fitted inside every fold | cross-validation ในข้อมูลฝึกเป็นผู้เลือก · ข้อมูลที่กันไว้เป็นผู้รายงาน · Spatial ML แบ่ง fold เป็นบล็อกเชิงพื้นที่ · Spatio-Temporal ML กันช่วงเวลาท้ายไว้ทดสอบcross-validation on the training data selects; the held-out set reports · spatial block folds for Spatial ML · the last periods held out for Spatio-Temporal ML | 13.3 |
| กลุ่มอนุกรมเวลาTime-series family | |||
| Time-Series Forecast | ไม่มีการคัดตัวแปรno variable selection | AICc เลือกลำดับภายในกริด SARIMA · SARIMA เทียบ Holt-Winters ด้วย RMSE บนช่วงท้ายที่กันไว้ (ไม่เทียบ AICc ข้ามตระกูล)AICc chooses the SARIMA order within its grid · SARIMA vs Holt-Winters on held-out RMSE (AICc never compared across families) | 11.4 |
| กลุ่มตัวแปรแฝงและเส้นทางอิทธิพลLatent-variable and path family | |||
| Path Analysis · Factor Analysis · SEM · GSEM | ไม่มีการคัดอัตโนมัติ — โครงสร้างเส้นทางและองค์ประกอบมาจากทฤษฎีNo automated screening — the path and measurement structure comes from theory | ดัชนีความกลมกลืน (χ² · CFI · TLI · RMSEA · SRMR) และ AIC/BIC สำหรับเทียบแบบจำลองบนข้อมูลชุดเดียวกันfit indices (χ² · CFI · TLI · RMSEA · SRMR) and AIC/BIC for models on the same data | บทที่ 8–10Ch. 8–10 |
อ่านตารางนี้อย่างไร: การมีดรอปดาวน์คัดตัวแปรไม่ได้แปลว่าควรใช้ สำหรับคำถามแบบอธิบาย ให้เลือก Enter กับชุดตัวแปรที่กำหนดจากกรอบแนวคิด แล้วใช้ผลของวิธีคัดอัตโนมัติเป็นเพียงการวิเคราะห์ความไวประกอบ ส่วนคำถามแบบทำนายให้ตัดสินด้วยข้อมูลที่กันไว้ (13.3)
How to read it: having a selection dropdown does not mean it should be used. For an explanatory question choose Enter with a covariate set fixed by the conceptual framework, and treat an automated selection only as a sensitivity analysis; for a predictive question judge the model on held-out data (13.3).
📖 References
- Akaike, H. (1974). A new look at the statistical model identification. IEEE Transactions on Automatic Control, 19(6), 716–723. doi:10.1109/TAC.1974.1100705
- Altman, D. G., & Bland, J. M. (1995). Statistics notes: Absence of evidence is not evidence of absence. BMJ, 311(7003), 485. doi:10.1136/bmj.311.7003.485
- Berk, R., Brown, L., Buja, A., Zhang, K., & Zhao, L. (2013). Valid post-selection inference. The Annals of Statistics, 41(2), 802–837. doi:10.1214/12-AOS1077
- Burnham, K. P., & Anderson, D. R. (2002). Model Selection and Multimodel Inference: A Practical Information-Theoretic Approach (2nd ed.). New York: Springer. ISBN 978-0-387-95364-9.
- Harrell, F. E. (2015). Regression Modeling Strategies (2nd ed.). Cham: Springer. doi:10.1007/978-3-319-19425-7
- Heinze, G., Wallisch, C., & Dunkler, D. (2018). Variable selection – A review and recommendations for the practicing statistician. Biometrical Journal, 60(3), 431–449. doi:10.1002/bimj.201700067
- Hyndman, R. J., & Athanasopoulos, G. (2021). Forecasting: Principles and practice (3rd ed.). OTexts. https://otexts.com/fpp3/
- Peduzzi, P., Concato, J., Feinstein, A. R., & Holford, T. R. (1995). Importance of events per independent variable in proportional hazards regression analysis. II. Accuracy and precision of regression estimates. Journal of Clinical Epidemiology, 48(12), 1503–1510. doi:10.1016/0895-4356(95)00048-8
- Peduzzi, P., Concato, J., Kemper, E., Holford, T. R., & Feinstein, A. R. (1996). A simulation study of the number of events per variable in logistic regression analysis. Journal of Clinical Epidemiology, 49(12), 1373–1379. doi:10.1016/S0895-4356(96)00236-3
- Riley, R. D., Ensor, J., Snell, K. I. E., Harrell, F. E., Jr., Martin, G. P., Reitsma, J. B., et al. (2020). Calculating the sample size required for developing a clinical prediction model. BMJ, 368, m441. doi:10.1136/bmj.m441
- Schwarz, G. (1978). Estimating the dimension of a model. The Annals of Statistics, 6(2), 461–464. doi:10.1214/aos/1176344136
- Shmueli, G. (2010). To explain or to predict? Statistical Science, 25(3), 289–310. doi:10.1214/10-STS330
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
13.2การเลือกตัวแปรใน Spatial Regression และ Spatial Panel Regression — 7 วิธีVariable Selection in Spatial Regression and Spatial Panel Regression — 7 methods
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
ในสถิติเชิงพื้นที่ การเลือกตัวแปรมีข้อจำกัดที่ไม่มีในการถดถอยธรรมดา: พจน์เชิงพื้นที่กับตัวแปรทำนายแย่งกันอธิบายความแปรปรวนชุดเดียวกัน ถ้าตัดตัวแปรที่มีรูปแบบเชิงพื้นที่ออกไป ค่า ρ (spatial lag) หรือ λ (spatial error) จะโตขึ้นมาแทน แบบจำลองจึงยังดู "พอดี" ทั้งที่ความหมายเปลี่ยนไปแล้ว. ด้วยเหตุนี้ ขั้นตอนค้นด้วย AIC (Akaike information criterion) ของ DAPH จึง ฟิตแบบจำลองเชิงพื้นที่ใหม่ทุกก้าว และตัดสินด้วย AIC ไม่ใช่ p-value (ข้อยกเว้นอธิบายในข้อ 2). ขั้นคัดกรองด้วย VIF และ LASSO ไม่ใช้ W — เป็นการคัดก่อนเข้าสู่การค้นด้วย AIC.
Spatial models add a constraint that ordinary regression does not have: the spatial term and the predictors compete for the same variation. Drop a predictor that has spatial structure and ρ (lag) or λ (error) grows to absorb it — the model still looks well fitted while meaning something different. DAPH's AIC (Akaike information criterion) searches therefore refit the spatial model at every step and decide on AIC, not on p-values (exceptions in step 2). The VIF and LASSO screens do not use W — they screen before the AIC search.
การเลือกวิธีอยู่ในแผงตั้งค่าของ Spatial Regression และ Spatial Panel Regression (Tab 2) ค่าเริ่มต้นคือ Enter และการคัดเลือกทำงานเมื่อมีตัวแปรทำนายตั้งแต่ 2 ตัว. ชุดตัวแปรที่คัดได้ใช้กับทุกแบบจำลองที่ติ๊กไว้ (SDM สร้างพจน์ W×X จากชุดเดียวกัน) และรายงานพิมพ์วิธี ตัวแปรที่คงไว้ ตัวแปรที่ตัด เส้นทางการคัดทีละก้าว และคำเตือนเรื่องช่วงเชื่อมั่นหลังการคัดเลือก.
The method is chosen in the settings panel of Spatial Regression and Spatial Panel Regression (Tab 2); the starting value is Enter, and selection runs only with at least 2 predictors. The selected set is applied to every ticked model (the SDM builds its W×X terms from the same set), and the report prints the method, the kept and dropped predictors, the step-by-step path and the post-selection caveat.
CRIME และตัวแปรทำนายที่เป็นผู้สมัคร 9 ตัว: INC รายได้ครัวเรือน, HOVAL มูลค่าบ้าน, OPEN พื้นที่โล่ง, PLUMB ร้อยละบ้านที่ไม่มีระบบประปา, DISCBD ระยะทางถึงย่านใจกลางเมือง, CP ย่านใจกลาง (1 = ใช่), EW ฝั่งตะวันออก (1 = ใช่) และ NSA, NSB ซึ่งเป็นตัวแปร "ฝั่งเหนือ" สองตัวที่วัดสิ่งเดียวกัน — ตัวอย่างของตัวแปรซ้ำซ้อนที่ขั้น VIF ควรตัดออก. ใช้ Queen contiguity และติ๊ก OLS กับ SLM.CRIME and nine candidate predictors: INC household income, HOVAL housing value, OPEN open space, PLUMB % housing without plumbing, DISCBD distance to the central business district, CP core neighbourhood (1 = yes), EW east (1 = yes), and NSA, NSB, two "north" indicators that measure the same thing — the kind of duplicate the VIF step should remove. Queen contiguity, with OLS and SLM ticked.2ทั้งเจ็ดวิธี — หลักการและสูตรThe Seven Methods — Logic and Formula
ดรอปดาวน์เรียงจาก วิธีที่ปกป้องได้มากที่สุดไปหาน้อยที่สุด โดยมี Enter อยู่ท้ายสุด
The dropdown is ordered from the most defensible to the least, with Enter last.
| ลำดับ · ชื่อในระบบOrder · label in DAPH | ทำอะไรWhat it does | ควรใช้เมื่อใดWhen to use |
|---|---|---|
| 1 · คัด collinearity (VIF) → Backward ด้วย AIC (แนะนำ)VIF screen → Backward (AIC) (recommended) | ตัดตัวแปรที่ซ้ำซ้อนกันเชิงเส้นออกก่อน (ทำให้ค่าสัมประสิทธิ์ไม่เสถียรและอาจแบ่งผลของตัวแปรเดียวไปอยู่สองตัว) จากนั้นทยอยตัดตัวแปรทีละตัวโดยฟิตแบบจำลองเชิงพื้นที่ใหม่ทุกก้าวCollinear predictors are removed first (they make coefficients unstable and can split one effect across two variables), then predictors are dropped one at a time, refitting the spatial model at every step. | ค่าที่แนะนำสำหรับงานส่วนใหญ่ โดยเฉพาะเมื่อมีตัวแปรที่วัดสิ่งใกล้เคียงกันหลายตัวThe recommended choice for most work, especially when several predictors measure closely related things. |
| 2 · คัดกรองด้วย LASSO → Backward ด้วย AICLASSO screen → Backward (AIC) | LASSO บีบสัมประสิทธิ์ของตัวแปรที่อ่อนให้เป็นศูนย์ แล้วส่งตัวที่เหลือเข้าสู่ backward ด้วย AICThe LASSO shrinks weak predictors to exactly zero and hands the survivors to the backward AIC search. | ตัวแปรผู้สมัครมีมากเมื่อเทียบกับจำนวนพื้นที่Many candidate predictors relative to the number of areas. |
| 3 · คัดกรองด้วย LASSO (penalized regression)LASSO / Elastic Net screen | LASSO ครั้งเดียว คงตัวแปรที่สัมประสิทธิ์ไม่เป็นศูนย์ (ชื่อในเมนูภาษาอังกฤษมีคำว่า Elastic Net แต่ DAPH ใช้ LASSO ล้วน α = 1)A single LASSO fit keeps the predictors with non-zero coefficients (the menu label mentions Elastic Net, but DAPH fits the pure LASSO, α = 1). | ต้องการคัดครั้งเดียวจบโดยไม่ค้นทีละก้าวA single-pass screen without a step-by-step search. |
| 4 · Backward elimination ด้วย AICBackward elimination (AIC) | เริ่มจากชุดเต็ม ตัดทีละตัวโดยฟิตแบบจำลองเชิงพื้นที่ใหม่ทุกก้าว ตัดสินด้วย AICStarts from the full set and drops one predictor at a time, refitting the spatial model at every step; AIC decides. | ตัวแปรไม่มากและไม่มี collinearity รุนแรงA moderate predictor set without severe collinearity. |
| 5 · Forward selection ด้วย AICForward selection (AIC) | เพิ่มตัวแปรทีละตัว เลือกตัวที่ทำให้ AIC ต่ำที่สุด จนไม่มีตัวใดทำให้ AIC ลดลงอีกAdds one predictor at a time, the one giving the lowest AIC, until no addition lowers AIC. | จำนวนพื้นที่น้อยจนฟิตแบบจำลองชุดเต็มไม่ได้Too few areas to fit the full model. |
| 6 · คัด collinearity ด้วย VIF อย่างเดียวVIF screen only (collinearity) | ตัดเฉพาะตัวแปรที่ซ้ำซ้อนกันเชิงเส้น ตัวอื่นคงไว้ทั้งหมดOnly collinear predictors are removed; everything else is kept. | งานแบบอธิบาย — ขั้นนี้ไม่ดูตัวแปรตามเลย จึงไม่สร้างอคติจากการคัดเลือกต่อค่าสัมประสิทธิ์Explanatory work — this screen never looks at the outcome, so it adds no selection bias to the coefficients. |
| 7 · Enter — ใส่ตัวแปรทั้งหมด (ค่าเริ่มต้น)Enter — keep every predictor (starting value) | คงตัวแปรที่เลือกไว้ทั้งหมดEvery selected predictor stays in the model. | ชุดตัวแปรมาจากกรอบแนวคิดและต้องรายงานครบตามที่ตั้งไว้ล่วงหน้าThe predictor set is pre-specified by theory and must be reported in full. |
- Rj²
- R² จากการถดถอยตัวแปรทำนายตัวที่ j ด้วยตัวแปรทำนายที่เหลือ (มีค่าคงที่) · DAPH ตัดตัวที่ VIF สูงสุดทีละตัวและคำนวณใหม่ จนทุกตัว ≤ 10 หรือเหลือ 1 ตัว (เกณฑ์ 10 เป็นกฎหัวแม่มือ ควรอ่านร่วมกับขนาดตัวอย่าง; O'Brien, 2007) · ใน panel ใช้ข้อมูลทุกพื้นที่ทุกช่วงเวลาซ้อนกันR² from regressing predictor j on the other predictors (with a constant) · DAPH drops the largest VIF one at a time and recomputes until every VIF ≤ 10 or one predictor is left (10 is a rule of thumb to be read with the sample size; O'Brien, 2007) · in a panel, on all area-periods stacked
- Xs, yc
- ตัวแปรทำนายที่ปรับมาตรฐาน (หารด้วย SD ที่ใช้ตัวหาร n) และตัวแปรตามที่ลบค่าเฉลี่ย · ใน panel ใช้ข้อมูลที่หักค่าเฉลี่ยรายพื้นที่แล้วstandardised predictors (SD with divisor n) and the centred outcome · in a panel, the area-demeaned data
- λ
- เลือกจาก 100 ค่าในช่วงข้างต้น (ระยะห่างเท่ากันบนสเกล log) ด้วย 5-fold cross-validation แบบแบ่งต่อเนื่องตามลำดับแถว (ไม่สุ่ม) ใช้ค่าที่ MSE เฉลี่ยของ 5 fold ต่ำสุด · ตัวแปรที่สัมประสิทธิ์เป็นศูนย์ถูกตัด (ถ้าเป็นศูนย์ทุกตัว DAPH คงไว้ทั้งหมด) (Tibshirani, 1996)chosen among 100 values in that range (equally spaced on the log scale) by 5-fold cross-validation with consecutive, unshuffled folds, taking the value with the smallest mean fold MSE · predictors with a zero coefficient are dropped (if all are zero DAPH keeps them all) (Tibshirani, 1996)
ขั้นตอนการค้นด้วย AIC: Backward — ฟิตชุดเต็ม แล้วในแต่ละก้าวฟิตใหม่โดยตัดตัวแปรทีละตัว เลือกก้าวที่ได้ AIC ต่ำสุด และหยุดเมื่อไม่มีการตัดใดทำให้ AIC ลดลง; คงไว้อย่างน้อย 1 ตัว. Forward — เริ่มจากแบบจำลองตัวแปรเดียวที่ AIC ต่ำสุด (ไม่เทียบกับแบบจำลองที่มีแต่ค่าคงที่) แล้วเพิ่มทีละตัวจนไม่มีตัวใดทำให้ AIC ลดลง. AIC ตามนิยามของ DAPH ไม่นับ σ² (ดู 6.1) ซึ่งไม่เปลี่ยนการตัดสินเพราะการเปรียบเทียบใช้ผลต่าง (Burnham & Anderson, 2002).
How the AIC search runs: Backward — fit the full set, then at each step refit with each predictor removed in turn, take the step with the lowest AIC, and stop when no removal lowers AIC; at least one predictor is kept. Forward — start from the single-predictor model with the lowest AIC (it is not compared with an intercept-only model) and add one predictor at a time until no addition lowers AIC. DAPH's AIC leaves σ² out of k (see 6.1), which does not change the decisions because only differences are compared (Burnham & Anderson, 2002).
แบบจำลองที่ใช้ค้น (probe model): DAPH ค้นด้วยแบบจำลองเดียว คือแบบแรกที่ติ๊กไว้ตามลำดับ — Spatial Regression: SLM → SEM → SDM → OLS; Spatial Panel: FE-Lag → RE-Lag → FE-Error → RE-Error → FE-SDM (ใช้ Time FE ตามที่ตั้งไว้). ข้อจำกัดที่พบ: ถ้าแบบจำลองที่ใช้ค้นไม่มี AIC ใน Spatial Regression — คือเมื่อติ๊กเฉพาะ OLS กับ SDM (SDM เป็นตัวค้น) หรือเมื่อใช้ weights แบบ KNN (ตัวประมาณ GMM ไม่มี likelihood) — DAPH ใช้ AIC ของ OLS แบบ n·ln(RSS/n) + 2(k + 1) แทน จึงไม่ได้ฟิตแบบจำลองเชิงพื้นที่ใหม่ (ส่วนที่ 4 ของสคริปต์แสดงผลที่ตามมา) — ให้ติ๊ก SLM หรือ SEM ไว้ด้วยเสมอเมื่อใช้การคัดเลือก.
The probe model: DAPH searches with one model, the first ticked in this order — Spatial Regression: SLM → SEM → SDM → OLS; Spatial Panel: FE-Lag → RE-Lag → FE-Error → RE-Error → FE-SDM (with Time FE as set). Known limitation: when the probe has no AIC in Spatial Regression — only OLS and SDM ticked (the SDM is the probe), or KNN weights (the GMM estimators have no likelihood) — DAPH uses the OLS AIC n·ln(RSS/n) + 2(k + 1) instead, so the spatial model is not refitted (part 4 of the script shows the consequence). Keep SLM or SEM ticked whenever a selection method is used.
เมื่อใดจึงควรแปลผลด้วย SDM (Spatial Durbin)When the Spatial Durbin Model is the one to interpret
SDM ครอบ SLM และ SEM ไว้ จึงตัดสินด้วยการทดสอบว่าข้อจำกัดที่ทำให้ SDM ยุบเป็นแบบจำลองย่อยถูกปฏิเสธหรือไม่ ตามยุทธศาสตร์ของ Elhorst (2010) — กฎเต็มของ DAPH อยู่ในหัวข้อ 6.2 และสรุปได้ดังนี้ (ระดับนัยสำคัญ 0.05):
The SDM nests the SLM and the SEM, so the choice rests on whether the restrictions that collapse it are rejected, following Elhorst (2010) — DAPH's full rule is in 6.2; in short (significance level 0.05):
| Wald: θ = 0 | Wald: common factor (θ + ρβ = 0)Wald: common factor (θ + ρβ = 0) | แบบจำลองที่นำมาแปลผลModel to interpret |
|---|---|---|
| ปฏิเสธrejected | ปฏิเสธrejected | SDM — แปลผลผ่านผลกระทบ direct / spillover / total ไม่ใช่สัมประสิทธิ์ดิบinterpret through the direct / spillover / total effects, not the raw coefficients |
| ไม่ปฏิเสธnot rejected | ปฏิเสธrejected | SLM |
| ปฏิเสธrejected | ไม่ปฏิเสธnot rejected | SEM |
| ไม่ปฏิเสธnot rejected | ไม่ปฏิเสธnot rejected | ตาม LM cascade (6.1); ถ้า LM cascade สรุปไม่ได้ ใช้แบบจำลองเชิงพื้นที่ที่ติ๊กไว้ซึ่งมี AIC ต่ำสุดfollow the LM cascade (6.1); if it is inconclusive, the ticked spatial model with the lowest AIC |
ยกเว้นเมื่อ LM cascade ไม่พบความสัมพันธ์เชิงพื้นที่: ถ้าไม่ปฏิเสธ θ = 0 ใช้ OLS แต่ถ้าปฏิเสธ θ = 0 ใช้ SDM (การทดสอบ LM ตรวจพจน์ W×X ไม่ได้). LeSage & Pace (2009) ชี้ว่า SDM เป็นตัวเลือกที่ปลอดภัยเมื่อสงสัยว่ามีตัวแปรที่ไม่ได้วัดซึ่งเกาะกลุ่มเชิงพื้นที่และสัมพันธ์กับตัวแปรทำนาย. ตารางผลกระทบของ SDM เมื่อ SDM ไม่ใช่แบบจำลองที่เลือก เป็นข้อมูลประกอบเท่านั้น.
Except when the LM cascade finds no spatial dependence: then θ = 0 not rejected → OLS, θ = 0 rejected → SDM (the LM tests cannot detect W×X terms). LeSage & Pace (2009) argue that the SDM is the safe choice when omitted variables are suspected to be spatially clustered and correlated with the predictors. When the SDM is not the retained model, its effects table is context only.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
# Data: Columbus (Ohio) neighbourhoods from the R package spData, as in 6.1 (the DAPH
# example dataset has no map); nine candidate predictors of CRIME.
library(sf); library(spdep); library(spatialreg); library(car); library(glmnet)
shp <- system.file("shapes/columbus.shp", package = "spData")
col <- st_read(shp, quiet = TRUE)
f <- paste0(sub("\\.shp$", "", shp), c(".shp", ".shx", ".dbf"))
invisible(file.copy(f, ".", overwrite = TRUE))
utils::zip("columbus.zip", basename(f), flags = "-9Xq")
lw <- nb2listw(poly2nb(col, queen = TRUE), style = "W")
cand <- c("INC", "HOVAL", "OPEN", "PLUMB", "DISCBD", "CP", "EW", "NSA", "NSB")
fml <- function(v) reformulate(v, response = "CRIME")
# 1. VIF screen: drop the predictor with the largest VIF while any VIF > 10
keep <- cand
while (length(keep) > 1) {
v <- vif(lm(fml(keep), data = col))
if (max(v) <= 10) break
cat(sprintf("drop %s (VIF = %.2f)\n", names(which.max(v)), max(v)))
keep <- setdiff(keep, names(which.max(v)))
}
print(round(v, 2))
drop NSA (VIF = 20.65)
INC HOVAL OPEN PLUMB DISCBD CP EW NSB
2.20 1.86 1.21 2.07 4.93 4.31 1.28 1.38
# 2. LASSO screen as DAPH runs it (on all candidates): predictors standardised with the
# SD divided by n, outcome centred, 5 consecutive folds (no shuffling), 100 penalties
# from lambda_max down to lambda_max/1000, the penalty with the smallest mean fold MSE
X <- as.matrix(st_drop_geometry(col)[, cand]); n <- nrow(X)
Xs <- scale(X, scale = apply(X, 2, function(z) sqrt(mean((z - mean(z))^2))))
yc <- col$CRIME - mean(col$CRIME)
lmax <- max(abs(crossprod(Xs, yc))) / n
lam <- exp(seq(log(lmax), log(lmax / 1000), length.out = 100))
fold <- rep(1:5, times = c(rep(n %/% 5 + 1, n %% 5), rep(n %/% 5, 5 - n %% 5)))
cvm <- rowMeans(sapply(1:5, function(k) {
fit <- glmnet(Xs[fold != k, ], yc[fold != k], lambda = lam, standardize = FALSE, thresh = 1e-12)
colMeans((yc[fold == k] - predict(fit, Xs[fold == k, , drop = FALSE]))^2)
}))
best <- lam[which.min(cvm)]
b <- coef(glmnet(Xs, yc, lambda = lam, standardize = FALSE, thresh = 1e-12), s = best)[-1, 1]
cat(sprintf("lambda = %.5f; shrunk to zero: %s\n", best, paste(names(b)[b == 0], collapse = ", ")))
print(round(b, 4))
lambda = 1.53468; shrunk to zero: OPEN, EW, NSA, NSB
INC HOVAL OPEN PLUMB DISCBD CP EW NSA NSB
-4.3563 -2.2300 0.0000 0.8658 -2.5576 4.7009 0.0000 0.0000 0.0000
# 3. AIC searches that refit the spatial lag model at every step (DAPH's probe model = SLM,
# the first ticked of SLM, SEM, SDM, OLS). DAPH leaves sigma2 out of k: AIC = R's AIC - 2
aic_slm <- function(v) AIC(lagsarlm(fml(v), data = col, listw = lw)) - 2
backward <- function(v) {
cur <- aic_slm(v); cat(sprintf("full set: AIC = %.4f\n", cur))
while (length(v) > 1) {
a <- sapply(v, function(x) aic_slm(setdiff(v, x)))
if (min(a) >= cur - 1e-9) break
cat(sprintf("drop %-6s AIC = %.4f (change %+.4f)\n", names(which.min(a)), min(a), min(a) - cur))
v <- setdiff(v, names(which.min(a))); cur <- min(a)
}
v
}
forward <- function(v) {
kept <- character(0); cur <- Inf
repeat {
rest <- setdiff(v, kept); if (length(rest) == 0) break
a <- sapply(rest, function(x) aic_slm(c(kept, x)))
if (min(a) >= cur - 1e-9) break
kept <- c(kept, names(which.min(a))); cur <- min(a)
cat(sprintf("add %-6s AIC = %.4f\n", names(which.min(a)), cur))
}
kept
}
cat("VIF screen -> backward:\n"); kept_vb <- backward(keep)
cat("forward:\n"); kept_fw <- forward(cand)
cat("kept (VIF -> backward):", kept_vb, "\nkept (forward):", kept_fw, "\n")
VIF screen -> backward:
full set: AIC = 371.5674
drop OPEN AIC = 369.5674 (change -2.0000)
drop DISCBD AIC = 367.5674 (change -2.0000)
drop NSB AIC = 365.7189 (change -1.8485)
drop EW AIC = 364.6510 (change -1.0680)
forward:
add CP AIC = 375.2184
add INC AIC = 367.2541
add HOVAL AIC = 365.1034
add PLUMB AIC = 364.6510
kept (VIF -> backward): INC HOVAL PLUMB CP
kept (forward): CP INC HOVAL PLUMB
# 4. Known limitation: with only OLS and SDM ticked (SDM = probe model) DAPH ranks the steps
# by the OLS AIC n*ln(RSS/n) + 2(k + 1) instead of refitting the SDM
ols_aic <- function(v) { e <- residuals(lm(fml(v), data = col))
n * log(sum(e^2) / n) + 2 * (length(v) + 1) }
sdm_aic <- function(v) AIC(lagsarlm(fml(v), data = col, listw = lw, Durbin = TRUE)) - 2
cat(sprintf("full set: OLS AIC = %.4f, SDM AIC = %.4f\n", ols_aic(cand), sdm_aic(cand)))
print(round(sapply(cand, function(x) c(OLS = ols_aic(setdiff(cand, x)),
SDM = sdm_aic(setdiff(cand, x)))), 3))
full set: OLS AIC = 232.0918, SDM AIC = 380.6326
INC HOVAL OPEN PLUMB DISCBD CP EW NSA NSB
OLS 233.371 234.129 230.094 232.113 230.619 234.057 231.266 230.862 230.547
SDM 378.781 381.647 377.105 379.543 378.140 381.013 377.966 376.921 380.044
columbus.zip → Tab 2: Spatial Regression · Dependent = CRIME · Independent = INC, HOVAL, OPEN, PLUMB, DISCBD, CP, EW, NSA, NSB · Queen contiguity, order 1 · Models = OLS, SLM · Variable selection = (ก) VIF screen → Backward (AIC), (ข) LASSO / Elastic Net screen, (ค) Forward selection (AIC); และ (ง) Models = OLS, SDM กับ Backward elimination (AIC) — อ่านเส้นทางการคัดจากหัวข้อ "Models estimated" ของผลลัพธ์File > Open: columbus.zip → Tab 2: Spatial Regression · Dependent = CRIME · Independent = INC, HOVAL, OPEN, PLUMB, DISCBD, CP, EW, NSA, NSB · Queen contiguity, order 1 · Models = OLS, SLM · Variable selection = (a) VIF screen → Backward (AIC), (b) LASSO / Elastic Net screen, (c) Forward selection (AIC); and (d) Models = OLS, SDM with Backward elimination (AIC) — the path is printed under "Models estimated" in the results| ค่าที่วัดQuantity | R | DAPH | ความต่างDifference | สถานะStatus |
|---|---|---|---|---|
| ขั้น VIF: ตัวแปรที่ถูกตัด (VIF)VIF step: dropped predictor (VIF) | NSA (20.65) | NSA (20.7) | 0.05 (DAPH แสดง 1 ตำแหน่ง)0.05 (DAPH prints 1 dp) | ✓ PASS |
| ขั้น LASSO: บีบเป็นศูนย์LASSO step: shrunk to zero | OPEN, EW, NSA, NSB | OPEN, EW, NSA, NSB | ชุดเดียวกันsame set | ✓ PASS |
| VIF → Backward: AIC ชุดเต็ม → ตัด OPEN → DISCBD → NSB → EW (SLM)VIF → Backward: AIC full set → drop OPEN → DISCBD → NSB → EW (SLM) | 371.5674 → 369.5674 → 367.5674 → 365.7189 → 364.6510 | 371.6 → 369.6 → 367.6 → 365.7 → 364.7 | < 0.05 | ✓ PASS |
| VIF → Backward: ชุดสุดท้ายVIF → Backward: final set | INC, HOVAL, PLUMB, CP | INC, HOVAL, PLUMB, CP | ชุดเดียวกันsame set | ✓ PASS |
| Forward: เพิ่ม CP → INC → HOVAL → PLUMB (AIC ของ SLM)Forward: add CP → INC → HOVAL → PLUMB (SLM AIC) | 375.2184 → 367.2541 → 365.1034 → 364.6510 | 375.2 → 367.3 → 365.1 → 364.7 | < 0.05 | ✓ PASS |
| SDM เป็นแบบจำลองที่ใช้ค้น (OLS + SDM): AIC ชุดเต็มSDM as the probe (OLS + SDM): full-set AIC | 380.6326 (AIC ของ SDM)380.6326 (SDM AIC) | 232.1 (= AIC แบบ RSS ของ OLS 232.0918)232.1 (= the OLS RSS-based AIC 232.0918) | 148.5 | ✗ FAIL |
| SDM เป็นแบบจำลองที่ใช้ค้น: ตัวแปรที่ตัดก้าวแรกSDM as the probe: first predictor dropped | NSA (AIC ของ SDM 376.921)NSA (SDM AIC 376.921) | OPEN (ตาม AIC ของ OLS 230.094)OPEN (by the OLS AIC 230.094) | คนละตัวdifferent | ✗ FAIL |
4การแปลผลและการรายงานInterpretation and Reporting
ตัวอย่าง Columbus: ขั้น VIF ตัด NSA (VIF = 20.7) ซึ่งซ้ำกับ NSB; backward ด้วย AIC ของ SLM ตัด OPEN, DISCBD, NSB และ EW จนเหลือ INC, HOVAL, PLUMB, CP (AIC 371.6 → 364.7) และ forward ได้ชุดเดียวกัน; LASSO คง DISCBD ไว้ด้วย (ตัด OPEN, EW, NSA, NSB). การตัด OPEN และ DISCBD ลด AIC 2.0 หน่วยต่อก้าว ซึ่งเท่ากับโทษของพารามิเตอร์หนึ่งตัวพอดี — แปลว่าสองตัวแปรนี้แทบไม่เพิ่ม log-likelihood ไม่ได้แปลว่าไม่มีผล. สองก้าวสุดท้ายลด AIC น้อยกว่า 2 หน่วย (1.8 และ 1.1) ชุดตัวแปรที่ใกล้เคียงกันจึงมีหลักฐานสนับสนุนพอ ๆ กัน (Burnham & Anderson, 2002).
Columbus example: the VIF step drops NSA (VIF = 20.7), the duplicate of NSB; the backward search on the SLM's AIC drops OPEN, DISCBD, NSB and EW, leaving INC, HOVAL, PLUMB, CP (AIC 371.6 → 364.7), and forward selection reaches the same set; the LASSO also keeps DISCBD (zeroing OPEN, EW, NSA, NSB). Dropping OPEN and DISCBD lowers AIC by 2.0 per step — exactly the penalty of one parameter — meaning these variables add almost no log-likelihood, not that they have no effect. The last two steps lower AIC by less than 2 units (1.8 and 1.1), so neighbouring sets have similar support (Burnham & Anderson, 2002).
ในระเบียบวิธีวิจัย ให้ระบุสามอย่างเสมอ: (1) ชุดตัวแปรผู้สมัครทั้งหมด (2) วิธีคัดเลือก เกณฑ์ (VIF > 10, AIC) และแบบจำลองที่ใช้ค้น (3) ชุดตัวแปรสุดท้าย — การรายงานเฉพาะข้อ (3) ทำให้ผู้อ่านเข้าใจผิดว่าตัวแปรชุดนี้ถูกตั้งไว้ล่วงหน้า. เมื่อใช้การคัดอัตโนมัติ ควรรายงานแบบจำลองชุดเต็มคู่กันเป็นการวิเคราะห์ความไว เพราะช่วงเชื่อมั่นและ p-value หลังการคัดเลือกแคบกว่าความจริง (DAPH พิมพ์คำเตือนนี้ให้เสมอ).
The methods section must state three things: (1) the full candidate set, (2) the selection procedure, its criteria (VIF > 10, AIC) and the probe model, and (3) the final set — reporting only (3) misleads readers into thinking the set was pre-specified. After an automated selection, report the full model alongside as a sensitivity analysis, because post-selection confidence intervals and p-values are too narrow (DAPH always prints this caveat).
📖 References
- Burnham, K. P., & Anderson, D. R. (2002). Model selection and multimodel inference: A practical information-theoretic approach (2nd ed.). Springer. ISBN 978-0-387-95364-9. doi:10.1007/b97636
- Elhorst, J. P. (2010). Applied spatial econometrics: Raising the bar. Spatial Economic Analysis, 5(1), 9–28. doi:10.1080/17421770903541772
- LeSage, J., & Pace, R. K. (2009). Introduction to spatial econometrics. Chapman & Hall/CRC. doi:10.1201/9781420064254
- O'Brien, R. M. (2007). A caution regarding rules of thumb for variance inflation factors. Quality & Quantity, 41(5), 673–690. doi:10.1007/s11135-006-9018-6
- Tibshirani, R. (1996). Regression shrinkage and selection via the lasso. Journal of the Royal Statistical Society: Series B, 58(1), 267–288. doi:10.1111/j.2517-6161.1996.tb02080.x
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
13.3การคัดตัวแปรใน Machine Learning — 6 วิธี (ฟิตใหม่ในทุก fold)Variable Selection in Machine Learning — 6 methods (re-fitted inside every fold)
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
การคัดตัวแปรในงานทำนายมีกับดักที่ร้ายแรงกว่าในงานอธิบาย: ถ้าคัดตัวแปรครั้งเดียวจากข้อมูลทั้งก้อนแล้วค่อยทำ cross-validation ค่าประสิทธิภาพทุกตัวจะดีเกินจริง เพราะแถวที่กันไว้ตรวจสอบได้มีส่วนช่วยเลือกตัวแปรไปแล้ว Ambroise & McLachlan (2002) แสดงให้เห็นว่าวิธีนี้ทำให้ข้อมูลที่เป็นค่าสุ่มล้วน ๆ ยังรายงานความคลาดเคลื่อนต่ำได้ (ดู Hastie et al. 2009 หัวข้อ 7.10.2 ด้วย)
DAPH จึงให้ ตัวคัดตัวแปรเป็นขั้นตอนหนึ่งของสายการประมวลผล ในเมนู “วิธีเลือกตัวแปร” ของ Machine Learning Comparison: ตัวคัดถูกฟิตใหม่จากแถวฝึกของแต่ละ fold เท่านั้น เช่นเดียวกับตัวเติมค่าขาดหายและตัวปรับมาตรฐาน แถวที่กันไว้ตรวจสอบจึงไม่มีส่วนในการเลือกตัวแปร
Feature selection in a prediction study has a sharper trap than in an explanatory one: screen once on the whole dataset and then cross-validate, and every reported metric is optimistic, because the held-out rows already helped choose the predictors. Ambroise & McLachlan (2002) showed that this reports low error even on pure noise (see also Hastie et al. 2009, section 7.10.2).
DAPH therefore makes the selector a step of the pipeline, chosen in the "Variable selection" menu of Machine Learning Comparison: it is re-fitted on each fold's training rows only, exactly like the imputer and the scaler, so the held-out rows never take part in choosing the predictors.
2ทั้งหกวิธี และตารางจับคู่ของโหมด "อัตโนมัติ"The Six Methods and the "Auto" Family Table
ตัวคัดทำงานกับคอลัมน์หลังเตรียมข้อมูล: ตัวแปรต่อเนื่องหนึ่งคอลัมน์ (ปรับมาตรฐานแล้วสำหรับแบบจำลองที่ต้องปรับ) และตัวแปรกลุ่มหนึ่งคอลัมน์ 0/1 ต่อหนึ่งระดับ ตัวแปรกลุ่มหนึ่งตัวจึงอาจเหลือเพียงบางระดับ ทุกตัวคัดที่มองผลลัพธ์จะเก็บไว้อย่างน้อย 2 คอลัมน์
The screens work on the encoded columns: one column per continuous predictor (standardised for the models that need it) and one 0/1 column per level of a categorical predictor, so a categorical predictor may keep only some of its levels. Every screen that looks at the outcome keeps at least 2 columns.
| ชื่อในระบบLabel in DAPH | ทำอะไรWhat it does | มองตัวแปรตามหรือไม่Uses the outcome? |
|---|---|---|
| Enter — ใส่ตัวแปรทั้งหมด (ค่าเริ่มต้น)Enter — keep every predictor (default) | ทุกคอลัมน์เข้าแบบจำลอง ซึ่งเป็นแนวทางที่ใช้กันมากที่สุดในงานสร้างแบบจำลองทำนายEvery column goes in, the usual choice for prediction models. | ไม่No |
| อัตโนมัติ — เลือกตัวคัดให้เหมาะกับแต่ละโมเดล (แนะนำ)Auto — match the screen to each model (recommended) | ใช้ตัวคัดตามตระกูลของแบบจำลองแต่ละตัว ตามตารางที่สองด้านล่างGives each model the screen of its family, per the second table below. | แล้วแต่ตระกูลDepends on the family |
| คัด collinearity (VIF > 10)Collinearity screen (VIF > 10) | ตัดคอลัมน์ที่มี variance inflation factor สูงที่สุดออกทีละคอลัมน์จนทุกคอลัมน์มี VIF ≤ 10 · คอลัมน์ระดับของตัวแปรกลุ่มเดียวกันรวมกันได้ 1 เสมอ จึงมี VIF เป็นอนันต์ ตัวคัดจะตัดคอลัมน์ระดับแรกของตัวแปรกลุ่มแต่ละตัวออกก่อน (ไม่เสียข้อมูล เพราะระดับนั้นกลายเป็นระดับอ้างอิง) แล้วจึงตัดตัวที่ซ้ำซ้อนจริง เช่น น้ำหนักเมื่อมีส่วนสูงและ BMI อยู่ด้วยRemoves the column with the largest variance inflation factor, one at a time, until every VIF is ≤ 10. The level columns of one categorical predictor always sum to 1 and have infinite VIF, so the screen first removes the first level column of each categorical predictor (nothing is lost: that level becomes the reference) and then genuine duplicates, such as weight next to height and BMI. | ไม่เลย — จึงปลอดภัยไม่ว่าจะรันที่ขั้นตอนใดNever — so it is safe wherever it runs |
| คัดด้วย penalized regression (elastic net)Penalised screen (elastic net) | ผลลัพธ์กลุ่ม: logistic regression ที่มีบทลงโทษ elastic net (C = 1, l1_ratio 0.5) · ผลลัพธ์ต่อเนื่อง: elastic net (l1_ratio 0.5) ที่เลือกความแรงของบทลงโทษด้วย 3-fold cross-validation · เก็บคอลัมน์ที่ค่าสัมบูรณ์ของสัมประสิทธิ์ ≥ ค่าเฉลี่ยของค่าสัมบูรณ์ทั้งหมด (ไม่ใช่เฉพาะตัวที่ไม่เป็นศูนย์)Categorical outcome: elastic-net-penalised logistic regression (C = 1, l1_ratio 0.5). Continuous outcome: elastic net (l1_ratio 0.5) with the penalty chosen by 3-fold cross-validation. Keeps the columns whose absolute coefficient is ≥ the mean absolute coefficient (not merely the non-zero ones). | ใช่ (ฟิตใหม่ในทุก fold)Yes (re-fitted per fold) |
| คัดด้วยความสำคัญจากโมเดล (random forest)Model importance screen (random forest) | ป่าสุ่ม 200 ต้น เก็บคอลัมน์ที่ค่าความสำคัญแบบ impurity ≥ มัธยฐาน (ประมาณครึ่งหนึ่งของคอลัมน์) ค่าความสำคัญแบบนี้เอียงไปทางตัวแปรต่อเนื่องที่มีจุดแบ่งได้มาก (Strobl et al. 2007)A 200-tree random forest; keeps the columns whose impurity importance is ≥ the median (about half of the columns). This importance favours continuous predictors with many possible split points (Strobl et al. 2007). | ใช่ (ฟิตใหม่ในทุก fold)Yes (re-fitted per fold) |
| คัด collinearity → คัดด้วย elastic netCollinearity screen → penalised screen | คัด collinearity ก่อน แล้วใช้ตัวคัด elastic net กับคอลัมน์ที่เหลือThe collinearity screen first, then the penalised screen on what is left. | ใช่ (ขั้นที่สอง)Yes (second stage) |
ทำไมต้องจับคู่ตัวคัดกับตระกูลของโมเดล — เป็นหลักของ embedded methods (Guyon & Elisseeff 2003; Kuhn & Johnson 2013 บทที่ 19): ตัวคัดเชิงเส้นมองเห็นเฉพาะความสัมพันธ์เชิงเส้น ถ้าส่งตัวแปรที่รอดให้แบบจำลองต้นไม้ เท่ากับบังคับมุมมองเชิงเส้นใส่แบบจำลองที่เลือกมาเพราะจับความสัมพันธ์ที่ไม่เป็นเชิงเส้นได้
Why the screen is family-matched — this is the embedded-methods principle (Guyon & Elisseeff 2003; Kuhn & Johnson 2013, ch. 19): a linear screen sees only linear relations, so handing its survivors to a tree model imposes a linear view on a model chosen because it can capture non-linear ones.
| ตระกูลของโมเดลModel family | แบบจำลองใน DAPHDAPH models | ตัวคัดที่โหมด "อัตโนมัติ" เลือกให้Screen chosen by "Auto" |
|---|---|---|
| เชิงเส้นLinear | Logistic Regression · Elastic Net (Logistic) · Linear Regression · Elastic Net | คัดด้วย penalized regression (elastic net)penalised (elastic net) |
| ต้นไม้Tree | Decision Tree · Random Forest · XGBoost · LightGBM | คัดด้วยความสำคัญจากโมเดล — ต้นไม้ทนต่อ collinearity อยู่แล้ว สิ่งที่ได้คือค่า SHAP ที่เสถียรขึ้นmodel importance — trees tolerate correlated predictors; the gain is stabler SHAP |
| Kernel / ระยะทางKernel / distance | SVM (RBF) · SVR (RBF) · KNN | คัด collinearity → elastic net (ระยะทางบิดเบือนเมื่อตัวแปรซ้ำซ้อน)collinearity → elastic net (duplicated predictors distort the distance) |
| โครงข่ายประสาทเทียมNeural network | MLP | คัด collinearitycollinearity |
| Naive Bayes | Gaussian Naive Bayes | คัด collinearity — แบบจำลองนี้ถือว่าตัวทำนายเป็นอิสระต่อกันเมื่อรู้กลุ่ม ตัวแปรที่ซ้ำซ้อนจึงละเมิดข้อสมมตินี้โดยตรงcollinearity — the model assumes the predictors are independent within each class, which duplicated predictors violate directly |
สิ่งที่รายงานแสดง · Tab 3 (หัวข้อ Methods) และส่วนวิธีการของรายงาน Word ระบุตัวคัดที่แต่ละแบบจำลองใช้และจำนวนคอลัมน์ที่เหลือ เช่น “Logistic Regression: elastic-net screen, kept 6 of 11 columns” (ไม่ได้ระบุชื่อคอลัมน์)
What the reports show. Tab 3 (Methods) and the Word Methods state, for each model, the screen it used and how many columns it kept, for example "Logistic Regression: elastic-net screen, kept 6 of 11 columns" (the column names are not listed).
ตัวคัดถูกฟิตที่ใดบ้าง · (1) ก่อนฟิตแบบจำลองสุดท้าย ตัวคัดฟิตกับชุดฝึกทั้งหมด แล้วใช้คอลัมน์ชุดเดียวกันกับชุดทดสอบ (ชุดทดสอบไม่มีส่วนเลือก) · (2) ใน cross-validation ทั้งแบบ train set และ dataset ตัวเติมค่า ตัวปรับมาตรฐาน ตัวคัด และ SMOTE (ถ้ามี) ถูกฟิตใหม่จากแถวฝึกของแต่ละ fold · (3) ในการค้นหา hyperparameter ด้วย Optuna ตัวคัดถูกฟิตใหม่ในทุก fold ของการค้นหาเช่นกัน
Where the screen is fitted. (1) Before the final fit, on the whole training set; the test set then gets the same columns and plays no part in choosing them. (2) In cross-validation, both train-set and dataset scope, the imputer, scaler, screen and SMOTE (if used) are re-fitted on each fold's training rows. (3) In Optuna hyperparameter tuning, the screen is re-fitted inside every tuning fold as well.
เมื่อเปิดทั้ง Train/Test และ Cross-Validation พร้อมกัน — ใครเป็นผู้เลือก สองค่านี้วัดคนละอย่าง (CV = ทุกแถวในข้อมูลฝึก แบ่ง k รอบ · Test = ข้อมูลที่กันไว้ก้อนเดียวซึ่งแบบจำลองไม่เคยเห็น) การหยิบ "ค่าไหนสูงกว่าก็เอาอันนั้น" จึงเป็นการเลือกค่าสูงสุดจากค่าประมาณจำนวน 2 × จำนวนโมเดล ซึ่งลำเอียงขึ้นโดยโครงสร้าง และที่สำคัญกว่านั้น ถ้าข้อมูลทดสอบเป็นผู้เลือก ข้อมูลชุดนั้นก็ไม่ใช่ข้อมูลที่กันไว้อีกต่อไป
การแบ่งหน้าที่ตามมาตรฐาน (Hastie et al. 2009 หัวข้อ 7.2; Kuhn & Johnson 2013; Collins et al. 2024) คือ ให้การสุ่มซ้ำภายในข้อมูลฝึกเป็นผู้เลือก และให้ข้อมูลที่กันไว้เป็นผู้ประเมิน DAPH จึงเลือกแบบจำลองที่ดีที่สุดด้วยค่าจาก cross-validation เมื่อเปิดไว้ แล้วรายงานค่าจากข้อมูลทดสอบเป็นประสิทธิภาพของแบบจำลองที่เลือก หากไม่ได้เปิด cross-validation ข้อมูลทดสอบจะทำทั้งสองหน้าที่ และรายงานจะเขียนกำกับไว้ว่าค่าที่ได้ดีเกินจริงสำหรับแบบจำลองที่ถูกเลือก
When both Train/Test and Cross-Validation are enabled — which one chooses? The two measure different things (CV = every training row, k rounds; Test = one held-out block the model never saw). Taking "whichever number is higher" maximises over 2 × n_models estimates, which is biased upward by construction, and worse, if the test set does the choosing it is no longer held out.
The standard division of labour (Hastie et al. 2009, section 7.2; Kuhn & Johnson 2013; Collins et al. 2024) is that resampling on the training data selects and the held-out set estimates. DAPH therefore chooses the best model by the cross-validated metric when CV is on and reports the test metric as the selected model's performance. Without cross-validation the test set does both jobs, and the report states that the figures are optimistic for the selected model.
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
ส่วน A ของสคริปต์ทำตัวคัดสามแบบที่ไม่มีการสุ่มบนชุดฝึก 910 รายของการแบ่งตามเวลา (เหมือนหัวข้อ 7.1) แล้วเทียบคอลัมน์ที่เหลือกับ DAPH (ตัวคัดตามความสำคัญใช้ป่าสุ่มของ Python จึงเทียบไม่ได้) ส่วน B คือตัวอย่างที่ 1 ซึ่งคำนวณใน R เท่านั้น เพราะ DAPH ไม่ยอมให้คัดครั้งเดียวจากข้อมูลทั้งก้อน
Part A of the script runs the three deterministic screens on the 910 training patients of the temporal split (as in 7.1) and compares the kept columns with DAPH (the importance screen uses a Python random forest and cannot be compared). Part B is Example 1, computed in R only, because DAPH never screens once on the whole dataset.
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(glmnet)
## Part A - the three screens DAPH fits on the training rows (temporal split as in 7.1)
d$enroll <- as.Date(substr(d$enroll_date, 1, 10))
d <- d[order(d$enroll, seq_len(nrow(d))), ]; tr <- d[1:round(0.7 * nrow(d)), ]
num <- c("age", "weight", "height", "bmi", "qolscore1"); cat_v <- c("gender", "chronic", "group")
mu <- sapply(tr[num], mean); s <- sapply(tr[num], function(x) sqrt(mean((x - mean(x))^2)))
X <- sweep(sweep(as.matrix(tr[num]), 2, mu), 2, s, "/") # standardised with the population SD
for (v in cat_v) for (l in sort(unique(tr[[v]]))) { # one 0/1 column for every level
X <- cbind(X, as.numeric(tr[[v]] == l)); colnames(X)[ncol(X)] <- paste0(v, "_", l) }
y <- tr$status
# (1) Elastic-net screen: penalised logistic (C = 1, l1_ratio 0.5); keep |b| >= mean |b|
en_screen <- function(X, y) {
b <- abs(coef(glmnet(X, y, family = "binomial", alpha = 0.5, lambda = 1 / nrow(X),
standardize = FALSE, thresh = 1e-14))[-1, 1])
print(round(b, 4)); names(b)[b >= mean(b)]
}
cat("Elastic-net screen keeps:", en_screen(X, y), "\n")
# (2) Collinearity screen: drop the column with the largest VIF while it exceeds 10
vif_screen <- function(X) {
keep <- colnames(X)
repeat {
r2 <- sapply(keep, function(j) summary(lm(X[, j] ~ X[, setdiff(keep, j)]))$r.squared)
vif <- ifelse(r2 > 1 - 1e-9, Inf, 1 / (1 - r2))
if (max(vif) <= 10 || length(keep) <= 2) break
cat(" drop", keep[which.max(vif)], "VIF =", round(max(vif), 2), "\n")
keep <- keep[-which.max(vif)]
}
keep
}
kv <- vif_screen(X); cat("Collinearity screen keeps:", kv, "\n")
# (3) Collinearity screen, then the elastic-net screen on what is left
cat("VIF -> elastic net keeps:", en_screen(X[, kv], y), "\n")
## Part B - why the screen must be re-fitted inside every fold (pure-noise predictors)
h <- subset(d, hos == 1) # one small hospital: 96 patients
cat("Hospital 1: n =", nrow(h), "deaths =", sum(h$status), "\n")
cv_auc <- function(y, Z, inside, k = 5) {
fold <- sample(rep(1:k, length.out = length(y))); p <- numeric(length(y))
top10 <- function(i) order(-abs(cor(Z[i, ], y[i])))[1:10]
pick_all <- top10(seq_along(y)) # WRONG: chosen with every patient
for (f in 1:k) {
trn <- fold != f; s <- if (inside) top10(which(trn)) else pick_all
m <- suppressWarnings(glm(y[trn] ~ ., data = data.frame(Z[trn, s]), family = binomial))
p[!trn] <- predict(m, data.frame(Z[!trn, s]), type = "response")
}
r <- rank(p); n1 <- sum(y); (sum(r[y == 1]) - n1 * (n1 + 1) / 2) / (n1 * (length(y) - n1))
}
set.seed(2026)
res <- t(replicate(200, { Z <- matrix(rnorm(nrow(h) * 40), nrow(h)) # 40 predictors of pure noise
c(select_once = cv_auc(h$status, Z, FALSE), select_in_fold = cv_auc(h$status, Z, TRUE)) }))
print(round(colMeans(res), 3))
age weight height bmi qolscore1 gender_1 gender_2 chronic_0
0.2416 0.1215 0.1054 0.0000 0.2883 0.0202 0.0202 0.2404
chronic_1 group_1 group_2
0.2404 0.3744 0.3743
Elastic-net screen keeps: age qolscore1 chronic_0 chronic_1 group_1 group_2
drop gender_1 VIF = Inf
drop chronic_0 VIF = Inf
drop group_1 VIF = Inf
drop weight VIF = 136.88
Collinearity screen keeps: age height bmi qolscore1 gender_2 chronic_1 group_2
age height bmi qolscore1 gender_2 chronic_1 group_2
0.2416 0.1700 0.1031 0.2887 0.0400 0.4768 0.7431
VIF -> elastic net keeps: chronic_1 group_2
Hospital 1: n = 96 deaths = 21
select_once select_in_fold
0.688 0.491
| ค่าที่ตรวจQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| ตัวคัดที่โหมดอัตโนมัติให้แต่ละแบบจำลองScreen given to each model by Auto | ตามตารางในส่วนที่ 2per the table in part 2 | Logistic: elasticnet · Random Forest: importance · SVM: vif_elasticnet · MLP: vif | 0 | ✓ PASS |
| คัดด้วย elastic net (Logistic Regression)Penalised screen (Logistic Regression) | age, qolscore1, chronic_0, chronic_1, group_1, group_2 | age, qolscore1, chronic_0, chronic_1, group_1, group_2 | 0 | ✓ PASS |
| คัด collinearity (MLP): คอลัมน์ที่เหลือCollinearity screen (MLP): kept columns | age, height, bmi, qolscore1, gender_2, chronic_1, group_2 | age, height, bmi, qolscore1, gender_2, chronic_1, group_2 | 0 | ✓ PASS |
| คัด collinearity → elastic net (SVM)Collinearity → penalised screen (SVM) | chronic_1, group_2 | chronic_1, group_2 | 0 | ✓ PASS |
| คัดด้วยความสำคัญ (Random Forest)Importance screen (Random Forest) | — | age, weight, height, bmi, qolscore1, chronic_1 | — | ไม่ได้เทียบ (ป่าสุ่มของ Python)not compared (Python random forest) |
| รายงาน (Tab 3 และ Word): ตัวคัดของแต่ละแบบจำลองและจำนวนคอลัมน์ที่เหลือจาก 11Reports (Tab 3 and Word): each model's screen and columns kept of 11 | Logistic 6 · SVM 2 · MLP 7 | Logistic 6 · Random Forest 6 · SVM 2 · MLP 7 | 0 | ✓ PASS |
| ตัวอย่างที่ 1: AUC จากการคัดครั้งเดียว / คัดในทุก fold (ตัวแปรสุ่มล้วน)Example 1: AUC when screening once / inside every fold (pure noise) | 0.688 / 0.491 | — | — | R เท่านั้นR only |
ผลการทวนสอบ · ตัวคัดสามแบบที่ไม่มีการสุ่มให้คอลัมน์ที่เหลือตรงกับ DAPH ทุกคอลัมน์ และลำดับที่ตัวคัด collinearity ตัดออก (gender_1, chronic_0, group_1 แล้ว weight ที่ VIF = 136.88) ตรงกับกฎในส่วนที่ 2 · Tab 3 และรายงาน Word ระบุตัวคัดและจำนวนคอลัมน์ที่เหลือของแต่ละแบบจำลองตรงกัน
Verification result. The three deterministic screens keep exactly the columns DAPH keeps, and the order in which the collinearity screen removes columns (gender_1, chronic_0, group_1, then weight at VIF = 136.88) follows the rule in part 2. Tab 3 and the Word report state each model's screen and the number of columns it kept, matching these results.
4การแปลผลและการรายงานInterpretation and Reporting
ตัวคัดต่างกันให้ตัวแปรต่างกันมาก · ในตัวอย่างที่ 2 ตัวคัด elastic net เก็บอายุ คะแนนคุณภาพชีวิตก่อนรักษา โรคเรื้อรัง และกลุ่มการรักษา ส่วนตัวคัดตามความสำคัญเก็บตัวแปรต่อเนื่องทั้งห้าตัวรวมทั้งน้ำหนัก ส่วนสูง และ BMI ที่ซ้ำซ้อนกัน ตามความเอียงของค่าความสำคัญแบบ impurity · ตัวคัด collinearity ตัดน้ำหนักออก (VIF 136.88) · ตัวคัด collinearity → elastic net เหลือเพียงโรคเรื้อรังและกลุ่มการรักษา เพราะหลังตัดคอลัมน์ระดับแรกออก สัมประสิทธิ์ของคอลัมน์ 0/1 ที่เหลือเป็นผลต่างเต็มระหว่างสองกลุ่ม (0.4768 และ 0.7431) ซึ่งทำให้ค่าเฉลี่ยของค่าสัมบูรณ์สูงขึ้นจนอายุ (0.2416) และคุณภาพชีวิต (0.2887) ต่ำกว่าเกณฑ์ กฎ “≥ ค่าเฉลี่ย” จึงขึ้นกับวิธีเข้ารหัสตัวแปร ไม่ได้วัดว่าตัวแปรใดสำคัญทางคลินิก
Different screens keep very different variables. In Example 2 the elastic-net screen keeps age, the pre-treatment QoL score, chronic disease and treatment group, whereas the importance screen keeps all five continuous predictors, including the duplicated weight, height and BMI, in line with the bias of impurity importance. The collinearity screen removes weight (VIF 136.88). Collinearity → elastic net keeps only chronic disease and treatment group: once the first level columns are gone, the coefficient of each remaining 0/1 column is the full contrast between the two groups (0.4768 and 0.7431), which raises the mean absolute coefficient until age (0.2416) and QoL (0.2887) fall below it. The "≥ mean" rule therefore depends on how predictors are coded and does not measure clinical importance.
เพราะตัวคัดถูกฟิตใหม่ในทุก fold ชุดตัวแปรที่รอดจึงอาจไม่เหมือนกันในแต่ละ fold นั่นไม่ใช่ข้อผิดพลาด แต่เป็นภาพสะท้อนความไม่แน่นอนของการคัดเลือกที่วิธีคัดครั้งเดียวซ่อนไว้ · ตามแนวปฏิบัติ TRIPOD+AI (Collins et al. 2024) การรายงานแบบจำลองทำนายควรระบุ: จำนวนตัวแปรตั้งต้น วิธีคัดและจุดที่ตัวคัดทำงานในสายการประมวลผล วิธีแบ่งข้อมูลตรวจสอบ และค่าประสิทธิภาพจากข้อมูลที่แบบจำลองไม่เคยเห็นพร้อมช่วงเชื่อมั่น
Because the selector is re-fitted per fold, the surviving set can differ between folds. That is not a defect: it is the selection uncertainty that a select-once workflow hides. Following TRIPOD+AI (Collins et al. 2024), a prediction-model report should state the number of candidate predictors, the screening method and where it sits in the pipeline, the validation scheme, and held-out performance with confidence intervals.
สำหรับข้อมูลเชิงพื้นที่และเชิงเวลา: การแบ่ง fold แบบสุ่มธรรมดาจะให้ค่าดีเกินจริงเมื่อพื้นที่ข้างเคียงคล้ายกัน (Roberts et al. 2017) DAPH จึงแบ่ง fold เป็นบล็อกเชิงพื้นที่สำหรับ Spatial ML และกันช่วงเวลาท้ายไว้ทดสอบตามลำดับเวลาสำหรับ Spatio-Temporal ML
For spatial and temporal data: plain random folds are optimistic when neighbouring areas resemble each other (Roberts et al. 2017), so DAPH uses spatial block folds for Spatial ML and holds out the last periods in time order for Spatio-Temporal ML.
📖 References
- Ambroise, C., & McLachlan, G. J. (2002). Selection bias in gene extraction on the basis of microarray gene-expression data. Proceedings of the National Academy of Sciences of the United States of America, 99(10), 6562–6566. doi:10.1073/pnas.102102699
- Collins, G. S., Moons, K. G. M., Dhiman, P., Riley, R. D., Beam, A. L., Van Calster, B., et al. (2024). TRIPOD+AI statement: Updated guidance for reporting clinical prediction models that use regression or machine learning methods. BMJ, 385, e078378. doi:10.1136/bmj-2023-078378
- Guyon, I., & Elisseeff, A. (2003). An introduction to variable and feature selection. Journal of Machine Learning Research, 3, 1157–1182.
- Hastie, T., Tibshirani, R., & Friedman, J. (2009). The Elements of Statistical Learning (2nd ed.). New York: Springer. doi:10.1007/978-0-387-84858-7
- Kuhn, M., & Johnson, K. (2013). Applied Predictive Modeling. New York: Springer. doi:10.1007/978-1-4614-6849-3
- Roberts, D. R., Bahn, V., Ciuti, S., Boyce, M. S., Elith, J., Guillera-Arroita, G., et al. (2017). Cross-validation strategies for data with temporal, spatial, hierarchical, or phylogenetic structure. Ecography, 40(8), 913–929. doi:10.1111/ecog.02881
- Strobl, C., Boulesteix, A.-L., Zeileis, A., & Hothorn, T. (2007). Bias in random forest variable importance measures: Illustrations, sources and a solution. BMC Bioinformatics, 8, 25. doi:10.1186/1471-2105-8-25
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification
13.4การเลือกตัวแปรเข้าแบบจำลองสุดท้าย — Linear · Logistic · Poisson · CoxBuilding the Final Model — Linear · Logistic · Poisson · Cox
1บทนำและความสำคัญทางสาธารณสุขIntroduction and Public-Health Relevance
Linear · Logistic · Log-binomial · Poisson · Cox regression มีดรอปดาวน์ "วิธีการวิเคราะห์" ใน Tab 2 ให้เลือกห้าวิธี: Enter · Backward Elimination · Stepwise Regression · Forward Selection · Bivariate Analysis (Conditional Logistic Regression มี Enter และ Backward Elimination · Ordered และ Multinomial Logistic Regression มี Enter และ Bivariate Analysis · แบบจำลอง Mixed Effect และ GEE ใช้ Enter อย่างเดียว) วิธีอัตโนมัติตัดสินด้วยค่า p (และด้วย AIC ตอนนำตัวแปรเข้าใน Poisson และ Cox) โดยไม่รู้ว่าตัวแปรแต่ละตัวมีบทบาทอะไรในคำถามวิจัย หัวข้อนี้บอกว่า DAPH ทำอะไรทีละขั้นจริง ๆ และผู้วิจัยควรสร้างแบบจำลองสุดท้ายอย่างไร
สิ่งสำคัญที่สุดที่ต้องเข้าใจก่อน: บทบาทของตัวแปรเป็นตัวกำหนดว่าจะอยู่ในแบบจำลองหรือไม่ ไม่ใช่ค่า p ตัวแปรในแบบจำลองทางระบาดวิทยาแบ่งได้เป็นสี่บทบาท และแต่ละบทบาทมีกติกาต่างกัน
- ตัวแปรหลักที่สนใจ (exposure) — อยู่ในแบบจำลองเสมอ ไม่ว่าจะมีนัยสำคัญหรือไม่ แต่ Backward · Stepwise · Forward ของ DAPH ไม่มีทางบังคับให้ตัวแปรใดอยู่ในแบบจำลอง จึงอาจตัดตัวแปรหลักทิ้งได้
- ตัวแปรกวน (confounder) — สัมพันธ์กับทั้ง exposure และผลลัพธ์ และไม่ได้อยู่บนเส้นทางจาก exposure ไปผลลัพธ์ ต้องคงไว้แม้ p สูง การตัดออกเพราะไม่มีนัยสำคัญคือการปล่อยให้อคติกลับเข้ามา
- ตัวแปรคั่นกลาง (mediator) — อยู่บนเส้นทางจาก exposure ไปผลลัพธ์ การใส่เข้าไปจะตัดผลส่วนที่ผ่านตัวแปรนั้นออกไปจากผลรวมที่ต้องการวัด ถ้าสนใจผลรวม ต้องไม่ใส่
- ตัวแปรช่วยความแม่น (precision variable) — สัมพันธ์กับผลลัพธ์แต่ไม่สัมพันธ์กับ exposure จึงไม่ใช่ตัวแปรกวน ใน linear regression การใส่ไว้ช่วยให้ช่วงเชื่อมั่นของผลของ exposure แคบลง
Linear · Logistic · Log-binomial · Poisson · Cox regression have an "Analysis Method" dropdown in Tab 2 with five options: Enter · Backward Elimination · Stepwise Regression · Forward Selection · Bivariate Analysis (Conditional Logistic Regression offers Enter and Backward Elimination; Ordered and Multinomial Logistic Regression offer Enter and Bivariate Analysis; the Mixed Effect models and GEE use Enter only). The automated options decide on p-values (and, when adding variables in Poisson and Cox, on AIC) without knowing the role each variable plays in the research question. This section documents what DAPH does at each step and how the researcher should build the final model.
The key idea comes first: a variable's role decides its fate, not its p-value. Variables in an epidemiological model have four roles, each with its own rule.
- The exposure of interest — always in the model, significant or not. DAPH's Backward, Stepwise and Forward options cannot force a variable in, so they can drop the exposure itself.
- Confounders — associated with both the exposure and the outcome and not on the path from one to the other; keep them regardless of p. Dropping a confounder for being non-significant lets the bias back in.
- Mediators — on the path from exposure to outcome; including one removes the part of the effect that passes through it from the total effect you set out to measure.
- Precision variables — related to the outcome but not to the exposure, so not confounders; in linear regression including them narrows the confidence interval of the exposure effect.
2DAPH ทำอะไรในแต่ละวิธี และขั้นตอนที่ใช้กันเป็นมาตรฐานWhat Each DAPH Method Does, and the Standard Procedures
(ก) ห้าวิธีในดรอปดาวน์ "วิธีการวิเคราะห์" — สิ่งที่ DAPH ทำจริง (ตรวจจากโค้ดของ DAPH และยืนยันด้วยการรันซ้ำใน R ในส่วนที่ 3) ตัวแปรกลุ่ม (categorical) ถูกทดสอบ ทั้งตัว คือทดสอบทุกสัมประสิทธิ์ของตัวแปรนั้นพร้อมกัน ไม่ใช่ทีละกลุ่มย่อย ค่า p นี้คือค่าเดียวกับที่พิมพ์บนแถวหัวของตัวแปรในตารางผลลัพธ์ ก่อนเริ่มการค้นหา DAPH ตัดแถวที่มีค่าขาดหายในตัวแปรตามหรือในตัวแปรที่นำเข้าพิจารณาตัวใดตัวหนึ่งออก ทุกแบบจำลองในการค้นหาจึงใช้แถวชุดเดียวกัน
(a) The five options of the "Analysis Method" dropdown — what DAPH actually does (read from the DAPH engine and confirmed by re-running it in R in part 3). A categorical variable is tested as a whole — all its coefficients at once, not one category at a time; this is the p printed on the variable's header row in the results table. Before the search DAPH drops rows with a missing value in the outcome or in any candidate, so every model in the search uses the same rows.
| วิธีMethod | DAPH ทำอะไรWhat DAPH does | การทดสอบที่ใช้ตัดสินTest that decides |
|---|---|---|
| Enter | ใส่ตัวแปรที่เลือกทั้งหมดในแบบจำลองเดียว ไม่ตัดตัวใดFits every selected variable in one model; nothing is removed. | — |
| Backward Elimination | เริ่มจากตัวแปรทั้งหมด แต่ละรอบหาตัวแปรที่มีค่า p สูงสุด ถ้า p ≥ 0.05 ตัดออกแล้วฟิตใหม่ หยุดเมื่อทุกตัวที่เหลือมี p < 0.05Starts with all variables; in each round finds the variable with the largest p, removes it if p ≥ 0.05 and refits; stops when every remaining p is below 0.05. | Linear: partial F test · Logistic: likelihood-ratio (LR) test · Poisson/negative binomial: LR test โดยประมาณ α ใหม่ในแบบจำลองที่ตัดตัวแปรออก และตัดสิน Poisson หรือ negative binomial ใหม่ทุกรอบด้วยเกณฑ์ 1.5 · Cox: LR test ของตัวแปรทั้งตัวบน partial likelihoodLinear: partial F test · Logistic: likelihood-ratio (LR) test · Poisson/negative binomial: LR test with α re-estimated in the reduced model, Poisson or negative binomial re-decided every round by the 1.5 rule · Cox: LR test of the whole variable on the partial likelihood |
| Stepwise Regression | เริ่มจากไม่มีตัวแปร · ขั้นนำเข้า: Linear และ Logistic เพิ่มตัวแปรที่มีค่า p ต่ำสุดถ้า p < 0.05 (ตัวแปรต่อเนื่องใช้ p ของ Wald ในแบบจำลองที่เพิ่มแล้ว · ตัวแปรกลุ่มใช้ F หรือ LR test เทียบกับแบบจำลองเดิม) · Poisson/negative binomial และ Cox เพิ่มตัวแปรที่ทำให้ AIC ต่ำสุด ถ้าต่ำกว่า AIC ของแบบจำลองปัจจุบัน · ตรวจย้อน: หลังเพิ่มทุกครั้ง ตัดตัวแปรที่มี p ≥ 0.05 ออกทีละตัว ตัวที่ถูกตัดแล้วจะไม่ถูกนำกลับเข้ามาอีกStarts with no variable. Entry: Linear and Logistic add the candidate with the smallest p if p < 0.05 (a numeric variable: its Wald p in the enlarged model; a categorical variable: F or LR test against the current model); Poisson/negative binomial and Cox add the candidate giving the lowest AIC, if it is below the current model's AIC. Backward check: after every addition, variables with p ≥ 0.05 are removed one at a time; a removed variable is never offered again. | ขั้นตรวจย้อนใช้การทดสอบเดียวกับ Backward Eliminationthe backward check uses the same tests as Backward Elimination |
| Forward Selection | เหมือน Stepwise Regression แต่ไม่มีขั้นตรวจย้อนStepwise Regression without the backward check. | เหมือนขั้นนำเข้าของ Stepwiseas the Stepwise entry step |
| Bivariate Analysis | ฟิตแยกหนึ่งแบบจำลองต่อหนึ่งตัวแปร ได้ค่าแบบหยาบ (crude) ไม่มีการคัดตัวแปร และไม่มีแบบจำลองเดียว จึงไม่รายงาน R², AIC, C-statistic และสมการทำนายOne model per variable, giving crude estimates; nothing is selected and there is no single model, so R², AIC, the C-statistic and the prediction equation are not reported. | การทดสอบของตัวแปรนั้นในแบบจำลองตัวแปรเดียวthe variable's own test in its one-variable model |
- การคัดกรองทีละตัวแปรอัตโนมัติ — ก่อนเริ่ม Stepwise หรือ Forward ถ้ามีตัวแปรมากกว่า 25 ตัว หรือ EPV < 10 DAPH จะเก็บไว้เฉพาะตัวแปรที่ p ในแบบจำลองตัวแปรเดียว < 0.25 (EPV: Linear และ Poisson = จำนวนแถว ÷ df รวม · Logistic = จำนวนในกลุ่มผลลัพธ์ที่น้อยกว่า ÷ df · Cox = จำนวนเหตุการณ์ ÷ df · ตัวแปรกลุ่มที่มี c กลุ่มนับ c − 1 df) ตัวอย่างนี้ EPV = 130.0 สำหรับคุณภาพชีวิตและเยื่อบุช่องท้องอักเสบ และ 22.9 สำหรับการเสียชีวิต จึงไม่มีการคัดกรอง
- เมื่อไม่มีตัวแปรผ่านเกณฑ์ — Linear และ Logistic แสดงคำเตือนว่าไม่มีตัวแปรผ่านเกณฑ์ · Stepwise และ Forward ของ Poisson และ Cox แจ้งว่าไม่มีตัวแปรใดทำให้ AIC ลดลง จึงไม่เลือกตัวแปรใดและไม่แสดงตาราง · Backward Elimination ของ Poisson และ Cox ที่ตัดตัวแปรออกหมดจะหยุดพร้อมข้อความแจ้ง
- Multiple imputation — ใช้ได้กับ Enter เท่านั้น ถ้าเลือกวิธีคัดตัวแปร DAPH จะไม่รันและแจ้งเหตุผล เพราะแต่ละชุดข้อมูลที่เติมค่าอาจได้ตัวแปรต่างกัน
- Log-binomial Regression — มีห้าวิธีเดียวกัน นำเข้าและตัดออกที่ p 0.05 ด้วยการทดสอบของแต่ละตัวแปร (หัวข้อ 2.7)
- Automatic univariable screening — before Stepwise or Forward, if there are more than 25 candidates or EPV < 10, DAPH keeps only candidates whose one-variable p is below 0.25 (EPV: Linear and Poisson = rows ÷ total df; Logistic = the smaller outcome group ÷ df; Cox = events ÷ df; a categorical variable with c categories counts c − 1 df). Here EPV = 130.0 for quality of life and peritonitis and 22.9 for death, so no screening took place.
- When no variable qualifies — Linear and Logistic print a warning that no variable met the criterion; Poisson and Cox Stepwise and Forward state that no variable lowered the AIC, so none was selected and no table is shown; Poisson and Cox Backward Elimination that removes every variable stops with a message.
- Multiple imputation — works with Enter only; with a selection method DAPH refuses the run and explains why (each imputed dataset could keep different variables).
- Log-binomial Regression — the same five options, with entry and removal at p 0.05 on each variable's own test (section 2.7).
(ข) แบบตั้งไว้ล่วงหน้าทั้งหมด (pre-specified, ใช้ Enter) — กำหนดชุดตัวแปรจากความรู้เดิม (เช่น วาดแผนภาพเหตุและผล) แล้วรายงานแบบจำลองนั้นชุดเดียว ไม่มีการค้นหา ค่า p และช่วงเชื่อมั่นจึงตีความได้ตรงตามนิยาม เป็นแนวทางที่ Harrell (2015) แนะนำเมื่อขนาดตัวอย่างพอ และ Heinze et al. (2018) ให้เริ่มจากชุดตัวแปรที่กำหนดด้วยความรู้เดิมเสมอ โดยไม่คัดตัวแปรที่รู้อยู่แล้วว่ามีผลชัด
(b) Fully pre-specified (Enter) — fix the covariate set from background knowledge (for example by drawing a causal diagram), fit it once and report it. No search means the p-values and intervals mean what they claim; Harrell (2015) recommends this whenever the sample supports it, and Heinze et al. (2018) start every analysis from a working set chosen by background knowledge, with no selection on variables already known to have strong effects.
(ค) Purposeful selection (Hosmer, Lemeshow & Sturdivant 2013; เกณฑ์ตัวเลขตาม Bursac et al. 2008) — ผู้วิจัยตัดสินเองทีละขั้น DAPH ช่วยได้ด้วย Bivariate Analysis (ขั้นที่ 1) และการรัน Enter ซ้ำ (ขั้นที่ 2–4) แต่ไม่มีปุ่มทำให้อัตโนมัติ
(c) Purposeful selection (Hosmer, Lemeshow & Sturdivant 2013; numerical criteria as in Bursac et al. 2008) — the researcher decides at each step. DAPH supports it with Bivariate Analysis (step 1) and repeated Enter runs (steps 2–4); there is no button that automates it.
| ขั้นStep | ทำอะไรWhat to do | เหตุผลWhy |
|---|---|---|
| 1 | วิเคราะห์ทีละตัวแปร (DAPH: Bivariate Analysis) แล้วนำตัวที่ p < 0.25 เข้าสู่ขั้นถัดไปAnalyse each candidate on its own (DAPH: Bivariate Analysis) and carry forward those with p < 0.25. | เกณฑ์ 0.05 ตั้งแต่ขั้นแรกอาจตัดตัวแปรที่รู้ว่าสำคัญทิ้งไปA 0.05 cut at this stage can miss variables known to be important. |
| 2 | ฟิตแบบจำลองพหุตัวแปร (DAPH: Enter) แล้วตัดตัวที่ p ≥ 0.10 ออกทีละตัว เฉพาะตัวที่ไม่ใช่ตัวแปรกวน (ขั้นที่ 3)Fit the multivariable model (DAPH: Enter), then remove variables with p ≥ 0.10 one at a time — only those that are not confounders (step 3). | ตัดทีละตัวเพราะการตัดหนึ่งตัวเปลี่ยนค่าของตัวที่เหลือOne at a time, because each removal changes the remaining estimates. |
| 3 | ตรวจการเปลี่ยนของค่าประมาณ: ถ้าการตัดตัวแปรใดทำให้สัมประสิทธิ์ของตัวแปรที่เหลือตัวใดตัวหนึ่งเปลี่ยนเกินราว 15–20% ให้ถือเป็นตัวแปรกวนและ ใส่กลับ แม้ p จะไม่มีนัยสำคัญ (Bursac et al. แนะนำ 15%)Change-in-estimate check: if removing a variable changes any remaining coefficient by more than about 15–20%, treat it as a confounder and put it back even though p is non-significant (Bursac et al. recommend 15%). | เป็นขั้นที่ตรวจจับตัวแปรกวนซึ่งเกณฑ์ค่า p มองไม่เห็นThis is the step that catches confounders a p-value rule misses. |
| 4 | นำตัวแปรที่ตกรอบในขั้นที่ 1 กลับมาลองใส่ทีละตัว คงไว้ถ้า p < 0.10–0.15 (Bursac et al. แนะนำ 0.15)Re-offer the variables excluded at step 1, one at a time; keep any with p < 0.10–0.15 (Bursac et al. recommend 0.15). | บางตัวมีผลเฉพาะเมื่อมีตัวแปรอื่นอยู่ในแบบจำลองแล้วSome matter only in the presence of the others. |
| 5 | ตรวจรูปแบบความสัมพันธ์ของตัวแปรต่อเนื่อง (linearity) และปฏิสัมพันธ์ (interaction) ที่ตั้งสมมติฐานไว้ล่วงหน้าCheck the functional form of continuous variables (linearity) and any pre-specified interactions. | ปฏิสัมพันธ์ที่ไม่ได้ตั้งไว้ล่วงหน้าคือการค้นหาจากข้อมูล ต้องรายงานว่าเป็นการสำรวจUnplanned interactions are data-driven and must be reported as exploratory. |
ใช้ค่า p ของตัวแปรทั้งตัว (ค่าบนแถวหัวของตัวแปรกลุ่มในตารางของ DAPH) ในทุกขั้น เพราะ Bursac et al. (2008) ระบุว่าอัลกอริทึมของตนไม่ได้ออกแบบให้คงตัวแปรหุ่น (dummy) ของตัวแปรเดียวกันไว้ด้วยกัน
Use the whole-variable p (the header-row p of a categorical variable in DAPH's table) at every step: Bursac et al. (2008) note that their algorithm was not designed to keep the dummy variables of one variable together.
(ง) เกณฑ์การเปลี่ยนของค่าประมาณสำหรับตัวแปรกวน (change-in-estimate) — ในงานระบาดวิทยาที่สนใจผลของ exposure ตัวเดียว ให้ตัดสินว่าจะปรับตัวแปรใดจาก ขนาดที่ค่าประมาณของ exposure เปลี่ยน ไม่ใช่จากค่า p ของตัวแปรนั้น (Greenland 1989) การจำลองของ Mickey & Greenland (1989) และ Maldonado & Greenland (1993) พบว่าเกณฑ์นี้ทำงานดีที่สุดเมื่อใช้จุดตัดต่ำ (10%) ส่วนเกณฑ์ค่า p ทำงานได้ก็ต่อเมื่อตั้งระดับนัยสำคัญสูงกว่าปกติมาก (ราว 0.20)
(d) Change-in-estimate for confounders — when one exposure effect is the target, decide which covariates to adjust for by how much the exposure estimate changes, not by the covariate's own p-value (Greenland 1989). In the simulations of Mickey & Greenland (1989) and Maldonado & Greenland (1993) this criterion worked best with a low cut-point (10%), whereas significance-test rules performed acceptably only at much higher than conventional levels (about 0.20).
(จ) แบบมีบทลงโทษ (penalized) — เมื่อตัวแปรมากเมื่อเทียบกับจำนวนเหตุการณ์ Heinze et al. (2018) ให้ใช้ penalized estimation หรือ shrinkage แทนการคัดแบบ stepwise ล้วน ๆ (EPV ≤ 10 ไม่ควรคัดเลย · EPV มากกว่า 10 ถึง 25 คัดได้เฉพาะเมื่อใช้ shrinkage หรือ LASSO และตรวจความเสถียร)
(e) Penalised — when the candidates are many relative to the events, Heinze et al. (2018) advise penalised estimation or shrinkage instead of a bare stepwise search (no selection at EPV ≤ 10; between 10 and 25, selection only with shrinkage or LASSO plus a stability check).
3สคริปต์ R และการทวนสอบกับ DAPHR Script and Verification against DAPH
| สถิติStatistic | ข้อจำกัดด้านขนาดตัวอย่างSample-size constraint | สิ่งที่ต้องตรวจเพิ่มExtra checks |
|---|---|---|
| Linear regression | พารามิเตอร์ที่พิจารณาน้อยกว่าราว n/15 (Harrell 2015)fewer than about n/15 candidate parameters (Harrell 2015) | ความเป็นเชิงเส้น · ความแปรปรวนคงที่ · การแจกแจงของส่วนเหลือ · VIFlinearity · constant variance · residual distribution · VIF |
| Logistic regression | อย่างน้อยราว 10 เหตุการณ์ในกลุ่มที่น้อยกว่า ต่อพารามิเตอร์ (Peduzzi et al. 1996)at least about 10 events in the smaller outcome group per parameter (Peduzzi et al. 1996) | ความเป็นเชิงเส้นของตัวแปรต่อเนื่องกับ logit · การแยกสมบูรณ์ (separation) · Hosmer–Lemeshow (p สูงแปลว่าไม่พบหลักฐานว่าการปรับเทียบไม่ดี ไม่ใช่ข้อพิสูจน์ว่าดี)linearity in the logit · complete separation · Hosmer–Lemeshow (a high p means no evidence of poor calibration, not proof of good calibration) |
| Poisson / negative binomial regressionPoisson / negative binomial regression | ยังไม่มีกติกาที่ยอมรับทั่วไป DAPH ใช้จำนวนแถว ÷ df เพื่อตัดสินการคัดกรองno generally agreed rule; DAPH uses rows ÷ df to decide on screening | การกระจายเกิน (overdispersion) — DAPH เปลี่ยนเป็น negative binomial เองเมื่อ Pearson χ²/df หรือ deviance/df ของ Poisson เกิน 1.5 · offset ของเวลาที่เสี่ยงหรือประชากร ต้องใส่เสมอเมื่อรายงานเป็นอัตราoverdispersion — DAPH switches to the negative binomial when the Poisson Pearson χ²/df or deviance/df exceeds 1.5 · an offset for person-time or population at risk whenever a rate is reported |
| Cox regression | อย่างน้อยราว 10 เหตุการณ์ต่อพารามิเตอร์ — นับ จำนวนเหตุการณ์ ไม่ใช่จำนวนคน (Peduzzi et al. 1995)at least about 10 events per parameter — count events, not people (Peduzzi et al. 1995) | สมมติฐาน proportional hazards (ทดสอบด้วย Schoenfeld residuals; Grambsch & Therneau 1994) ถ้าละเมิด ให้ใช้ผลที่ขึ้นกับเวลาหรือแบ่งชั้น (stratify)proportional hazards (Schoenfeld-residual test; Grambsch & Therneau 1994); if violated, use a time-varying effect or stratify |
# Data: DAPH > File > Example dataset (EN), then File > Export > CSV, saved as example_en.csv
d <- read.csv("example_en.csv", fileEncoding = "UTF-8-BOM")
library(MASS) # glm.nb(): negative binomial, dispersion estimated by maximum likelihood
library(survival) # coxph(): Cox regression, Efron ties (as DAPH)
d$group <- factor(d$group, 1:2, c("CAPD", "APD"))
d$gender <- factor(d$gender, 1:2, c("Male", "Female"))
d$bmi_group <- factor(d$bmi_group, 1:4, c("Underweight", "Normal", "Overweight", "Obese"))
d$chronic <- factor(d$chronic, 0:1, c("No", "Yes"))
d$income <- factor(d$income, 1:3, c("None", "<10,000", ">=10,000"))
d$occupation <- factor(d$occupation, 1:2, c("Employed", "Unemployed/Retired"))
d$amp <- factor(d$amp) # District (10 districts)
cand <- c("group", "age", "gender", "bmi_group", "chronic", "income", "occupation")
# One model per statistic for any set of terms (none of these variables has missing values)
fit_of <- function(kind, terms) {
rhs <- if (length(terms)) paste(terms, collapse = " + ") else "1"
switch(kind,
linear = lm(as.formula(paste("qolscore3 ~", rhs)), data = d),
logistic = glm(as.formula(paste("status ~", rhs)), family = binomial, data = d),
negbin = glm.nb(as.formula(paste("n_peritonitis ~", rhs, "+ offset(log(person_years))")), data = d),
cox = coxph(as.formula(paste("Surv(follow_up_days, status) ~", rhs)), data = d))
}
# p-value of a variable already in the model, tested as a whole (all its coefficients at once)
term_p <- function(kind, terms, v) {
full <- fit_of(kind, terms); red <- fit_of(kind, setdiff(terms, v))
if (kind == "linear") return(anova(red, full)[2, "Pr(>F)"]) # partial F test
lr <- 2 * (as.numeric(logLik(full)) - as.numeric(logLik(red))) # likelihood-ratio test (NB: theta
pchisq(lr, attr(logLik(full), "df") - attr(logLik(red), "df"), lower.tail = FALSE) # re-estimated)
}
fp <- function(p) if (p < 1e-4) "p < 0.0001" else sprintf("p = %.4f", p) # p in house style
# Backward Elimination: drop the variable with the largest p while that p is 0.05 or more
backward <- function(kind, terms = cand) {
repeat {
p <- sapply(terms, function(v) term_p(kind, terms, v))
if (max(p) < 0.05) break
cat(fp(max(p)), ">= 0.0500, removing", names(which.max(p)), "\n")
terms <- setdiff(terms, names(which.max(p)))
}
terms
}
# Stepwise Regression: forward step, then a backward check after every addition;
# a variable removed by the check never re-enters
entry_p <- function(kind, sel, v) { # Linear, Logistic: p of the candidate variable
big <- fit_of(kind, c(sel, v))
if (is.numeric(d[[v]])) return(coef(summary(big))[v, 4]) # Wald p of a numeric variable
small <- fit_of(kind, sel)
if (kind == "linear") anova(small, big)[2, "Pr(>F)"] else anova(small, big, test = "LRT")[2, "Pr(>Chi)"]
}
stepwise <- function(kind, pool = cand) {
sel <- character(0); out <- character(0); aic_now <- AIC(fit_of(kind, sel))
repeat {
try_v <- setdiff(pool, c(sel, out))
if (!length(try_v)) break
if (kind %in% c("linear", "logistic")) { # entry: smallest p, if below 0.05
p <- sapply(try_v, function(v) entry_p(kind, sel, v))
if (min(p) >= 0.05) break
add <- names(which.min(p)); cat(fp(min(p)), "< 0.0500, adding", add, "\n")
} else { # Poisson/NB and Cox: entry = lowest AIC, if lower
a <- sapply(try_v, function(v) AIC(fit_of(kind, c(sel, v))))
if (min(a) >= aic_now) break
add <- names(which.min(a)); aic_now <- min(a); cat(sprintf("AIC = %.2f, adding %s\n", aic_now, add))
}
sel <- c(sel, add)
repeat { # backward check
if (kind %in% c("negbin", "cox") && length(sel) < 2) break
p <- sapply(sel, function(v) term_p(kind, sel, v))
if (max(p) < 0.05) break
cat(fp(max(p)), ">= 0.0500, removing", names(which.max(p)), "\n")
out <- c(out, names(which.max(p))); sel <- setdiff(sel, names(which.max(p)))
}
}
sel
}
for (k in c("linear", "logistic", "negbin", "cox")) {
cat("\n==", k, "== Backward Elimination\n"); b <- backward(k)
cat("--", k, "-- Stepwise Regression\n"); s <- stepwise(k)
cat("kept by Backward:", b, "| kept by Stepwise:", s, "\n")
}
== linear == Backward Elimination
p = 0.9263 >= 0.0500, removing bmi_group
p = 0.5234 >= 0.0500, removing gender
p = 0.2673 >= 0.0500, removing chronic
-- linear -- Stepwise Regression
p < 0.0001 < 0.0500, adding occupation
p = 0.0089 < 0.0500, adding age
p = 0.0337 < 0.0500, adding group
p = 0.0444 < 0.0500, adding income
kept by Backward: group age income occupation | kept by Stepwise: occupation age group income
== logistic == Backward Elimination
p = 0.9206 >= 0.0500, removing bmi_group
p = 0.5656 >= 0.0500, removing income
p = 0.4065 >= 0.0500, removing gender
p = 0.2785 >= 0.0500, removing occupation
-- logistic -- Stepwise Regression
p < 0.0001 < 0.0500, adding age
p < 0.0001 < 0.0500, adding group
p = 0.0017 < 0.0500, adding chronic
kept by Backward: group age chronic | kept by Stepwise: age group chronic
== negbin == Backward Elimination
p = 0.4960 >= 0.0500, removing income
p = 0.3878 >= 0.0500, removing gender
p = 0.1874 >= 0.0500, removing occupation
p = 0.1365 >= 0.0500, removing bmi_group
-- negbin -- Stepwise Regression
AIC = 3735.12, adding group
AIC = 3714.74, adding age
AIC = 3702.42, adding chronic
kept by Backward: group age chronic | kept by Stepwise: group age chronic
== cox == Backward Elimination
p = 0.9249 >= 0.0500, removing bmi_group
p = 0.6204 >= 0.0500, removing income
p = 0.4340 >= 0.0500, removing occupation
p = 0.3061 >= 0.0500, removing gender
-- cox -- Stepwise Regression
AIC = 3183.29, adding age
AIC = 3164.28, adding group
AIC = 3155.77, adding chronic
kept by Backward: group age chronic | kept by Stepwise: age group chronic
# The final (Backward Elimination) models, reported as DAPH reports them (Wald 95% CI)
lin <- fit_of("linear", c("group", "age", "income", "occupation"))
round(cbind(b = coef(lin), confint(lin), p = summary(lin)$coefficients[, 4])[c("groupAPD", "age"), ], 4)
lgt <- fit_of("logistic", c("group", "age", "chronic"))
round(exp(cbind(OR = coef(lgt), confint.default(lgt)))[-1, ], 3)
nbm <- fit_of("negbin", c("group", "age", "chronic"))
round(exp(cbind(IRR = coef(nbm), confint.default(nbm)))[-1, ], 2); 1 / nbm$theta
cxm <- fit_of("cox", c("group", "age", "chronic"))
round(summary(cxm)$conf.int[, c(1, 3, 4)], 2)
cbind(logistic = coef(lgt)[-1], negbin = coef(nbm)[-1], cox = coef(cxm)) # full-precision coefficients
b 2.5 % 97.5 % p
groupAPD 1.9727 0.0451 3.9003 0.0449
age -0.1699 -0.3214 -0.0183 0.0280
OR 2.5 % 97.5 %
groupAPD 2.022 1.500 2.725
age 1.045 1.024 1.065
chronicYes 1.601 1.191 2.153
IRR 2.5 % 97.5 %
groupAPD 0.45 0.39 0.52
age 1.02 1.01 1.03
chronicYes 1.31 1.14 1.50
[1] 0.6346153
exp(coef) lower .95 upper .95
groupAPD 1.89 1.44 2.47
age 1.04 1.02 1.06
chronicYes 1.54 1.18 2.01
logistic negbin cox
groupAPD 0.70397739 -0.79390042 0.63581113
age 0.04358045 0.02145297 0.03971714
chronicYes 0.47087076 0.26794146 0.43406642
# Why a categorical variable is tested as a whole (DAPH's rule): compare with the largest
# Wald p among its categories, which depends on the reference category
wald_max <- function(terms, v) {
s <- summary(fit_of("cox", terms))$coefficients
max(s[startsWith(rownames(s), v), "Pr(>|z|)"])
}
round(cbind(LR_p = sapply(cand, function(v) term_p("cox", cand, v)),
largest_Wald_p = sapply(cand, function(v) wald_max(cand, v))), 4)
# The largest per-category Wald p would drop District, which matters as a whole
two <- c("amp", "bmi_group")
round(cbind(LR_p = sapply(two, function(v) term_p("cox", two, v)),
largest_Wald_p = sapply(two, function(v) wald_max(two, v))), 4)
backward("cox", two) # the whole-variable rule (DAPH) keeps District
LR_p largest_Wald_p
group 0.0000 0.0000
age 0.0007 0.0006
gender 0.3549 0.3586
bmi_group 0.9249 0.6055
chronic 0.0020 0.0022
income 0.6295 0.5996
occupation 0.4462 0.4456
LR_p largest_Wald_p
amp 0.0041 0.8424
bmi_group 0.4219 0.2158
p = 0.4219 >= 0.0500, removing bmi_group
[1] "amp"
# Change-in-estimate: how far does the APD odds ratio move when one covariate is left out
# of the full logistic model? (in DAPH: Enter with and without that covariate)
or_apd <- function(terms) exp(coef(fit_of("logistic", terms))[["groupAPD"]])
or_full <- or_apd(cand)
or_without <- sapply(setdiff(cand, "group"), function(v) or_apd(setdiff(cand, v)))
round(c(OR_full = or_full, OR_crude = or_apd("group")), 3)
round(rbind(OR_without = or_without, change_pct = 100 * (or_without / or_full - 1)), 3)
OR_full OR_crude
2.031 1.892
age gender bmi_group chronic income occupation
OR_without 1.955 2.02 2.031 1.953 2.002 2.055
change_pct -3.733 -0.54 0.035 -3.837 -1.403 1.190
| ค่าQuantity | R | DAPH | ความต่างDifference | Status |
|---|---|---|---|---|
| Linear regression · Quality of Life Score (Post)Linear regression · Quality of Life Score (Post) | ||||
| Backward: p ที่ตัด BMI Group / Gender / Chronic DiseaseBackward: removal p, BMI Group / Gender / Chronic Disease | 0.9263 / 0.5234 / 0.2673 | 0.9263 / 0.5234 / 0.2673 | < 5e−5 | ✓ PASS |
| Stepwise: p ที่นำเข้า Employment Status / Age / Treatment Group / Personal IncomeStepwise: entry p, Employment Status / Age / Treatment Group / Personal Income | < 0.0001 / 0.0089 / 0.0337 / 0.0444 | < 0.0001 / 0.0089 / 0.0337 / 0.0444 | < 5e−5 | ✓ PASS |
| แบบจำลองสุดท้าย: APD เทียบ CAPD (95% CI) · p ของ Treatment Group · AgeFinal model: APD vs CAPD (95% CI) · Treatment Group p · Age | 1.973 (0.045 to 3.900) · 0.045 · −0.170 | 1.973 (0.045 to 3.900) · 0.045 · −0.170 | < 0.0005 | ✓ PASS |
| Logistic regression · Study Status (เสียชีวิต)Logistic regression · Study Status (died) | ||||
| Backward: p ที่ตัด BMI Group / Personal Income / Gender / Employment StatusBackward: removal p, BMI Group / Personal Income / Gender / Employment Status | 0.9206 / 0.5656 / 0.4065 / 0.2785 | 0.9206 / 0.5656 / 0.4065 / 0.2785 | < 5e−5 | ✓ PASS |
| Stepwise: p ที่นำเข้า Age / Treatment Group / Chronic DiseaseStepwise: entry p, Age / Treatment Group / Chronic Disease | < 0.0001 / < 0.0001 / 0.0017 | < 0.0001 / < 0.0001 / 0.0017 | < 5e−5 | ✓ PASS |
| แบบจำลองสุดท้าย: OR ของ APD (95% CI) · ค่าสัมประสิทธิ์ log ORFinal model: OR APD (95% CI) · log-OR coefficient | 2.022 (1.500 to 2.725) · 0.70397739 | 2.022 (1.500 to 2.725) · 0.7039773929 | < 1e−8 | ✓ PASS |
| Poisson → negative binomial · Number of Peritonitis Episodes (offset log คน-ปี)Poisson → negative binomial · Number of Peritonitis Episodes (offset log person-years) | ||||
| Backward: p ที่ตัด Personal Income / Gender / Employment Status / BMI GroupBackward: removal p, Personal Income / Gender / Employment Status / BMI Group | 0.4960 / 0.3878 / 0.1874 / 0.1365 | 0.4960 / 0.3878 / 0.1874 / 0.1365 | < 5e−5 | ✓ PASS |
| Stepwise: ลำดับที่นำเข้าด้วย AIC และ AIC สุดท้ายStepwise: entry order by AIC and final AIC | Treatment Group, Age, Chronic · 3702.42 | Treatment Group, Age, Chronic · 3702.4218 | < 0.005 | ✓ PASS |
| แบบจำลองสุดท้าย: IRR ของ APD (95% CI) · ค่าสัมประสิทธิ์ · αFinal model: IRR APD (95% CI) · coefficient · α | 0.45 (0.39 to 0.52) · −0.79390042 · 0.6346153 | 0.45 (0.39 to 0.52) · −0.7939004038 · 0.6346152 | < 1e−6 | ✓ PASS |
| Cox regression · การเสียชีวิต (Follow-up Duration (days))Cox regression · death (Follow-up Duration (days)) | ||||
| แบบจำลองเต็ม: p ของ BMI Group ทั้งตัว (ตารางผลลัพธ์ของ DAPH)Full model: whole-variable p of BMI Group (DAPH results table) | 0.9249 | 0.925 | < 0.0005 | ✓ PASS |
| Backward: p ที่ตัด BMI Group / Personal Income / Employment Status / GenderBackward: removal p, BMI Group / Personal Income / Employment Status / Gender | 0.9249 / 0.6204 / 0.4340 / 0.3061 | 0.9249 / 0.6204 / 0.4340 / 0.3061 | < 5e−5 | ✓ PASS |
| Backward และ Stepwise: ตัวแปรที่คงไว้Backward and Stepwise: variables kept | Treatment Group, Age, Chronic | Treatment Group, Age, Chronic | — | ✓ PASS |
| Stepwise: AIC สุดท้าย (partial likelihood)Stepwise: final AIC (partial likelihood) | 3155.77 | 3155.7665 | < 0.005 | ✓ PASS |
| แบบจำลองสุดท้าย: HR ของ APD (95% CI) · ค่าสัมประสิทธิ์Final model: HR APD (95% CI) · coefficient | 1.89 (1.44 to 2.47) · 0.63581113 | 1.89 (1.44 to 2.47) · 0.6358111331 | < 1e−8 | ✓ PASS |
| Backward กับ District + BMI Group: ตัวแปรที่คงไว้Backward on District + BMI Group: variables kept | District (ตัด BMI Group ที่ p = 0.4219)District (BMI Group removed at p = 0.4219) | District (ตัด BMI Group ที่ p = 0.4219)District (BMI Group removed at p = 0.4219) | < 5e−5 | ✓ PASS |
| Change-in-estimate · OR ของ APD ต่อการเสียชีวิต (Logistic, Enter)Change-in-estimate · OR of APD for death (Logistic, Enter) | ||||
| ตัวแปรครบ / ตัด Age / ตัด Chronic Disease / แบบหยาบfull set / without Age / without Chronic Disease / crude | 2.031 / 1.955 / 1.953 / 1.892 | 2.031 / 1.955 / 1.953 / 1.892 | < 0.0005 | ✓ PASS |
4การแปลผลและการรายงานในบทความInterpretation and Reporting in a Manuscript
ผลกับข้อมูลตัวอย่าง: ทั้ง Backward Elimination, Stepwise Regression และ Forward Selection เก็บตัวแปรชุดเดียวกันในแต่ละคำถาม — คุณภาพชีวิต: Treatment Group, Age, Personal Income, Employment Status · การเสียชีวิต (Logistic และ Cox) และเยื่อบุช่องท้องอักเสบ: Treatment Group, Age, Chronic Disease · ผู้ป่วย APD มีคะแนนคุณภาพชีวิตหลังการรักษาสูงกว่า CAPD 1.973 คะแนน (95% CI 0.045 to 3.900; p = 0.045) มี odds ของการเสียชีวิตระหว่างติดตามสูงกว่า (adjusted OR 2.022, 95% CI 1.500 to 2.725) มีอัตราอันตรายของการเสียชีวิตสูงกว่า (adjusted HR 1.89, 95% CI 1.44 to 2.47) และมีอัตราเยื่อบุช่องท้องอักเสบต่ำกว่า 55% (adjusted IRR 0.45, 95% CI 0.39 to 0.52) ทั้งหมดเป็นความสัมพันธ์จากข้อมูลเชิงสังเกต ไม่ใช่ผลเชิงสาเหตุ และเพราะผู้ป่วยถูกติดตามนานไม่เท่ากัน ค่า OR ของ logistic regression จึงเป็นเพียงภาพประกอบ ส่วน HR จาก Cox ใช้เวลาติดตามด้วยจึงเป็นค่าที่ควรรายงานสำหรับการเสียชีวิต (หัวข้อ 5.2)
Results on the example data: Backward Elimination, Stepwise Regression and Forward Selection kept the same variables for each question — quality of life: Treatment Group, Age, Personal Income, Employment Status; death (logistic and Cox) and peritonitis: Treatment Group, Age, Chronic Disease. Patients on APD scored 1.973 points higher on post-treatment quality of life than those on CAPD (95% CI 0.045 to 3.900; p = 0.045), had higher odds of dying during follow-up (adjusted OR 2.022, 95% CI 1.500 to 2.725), a higher hazard of death (adjusted HR 1.89, 95% CI 1.44 to 2.47) and a 55% lower peritonitis rate (adjusted IRR 0.45, 95% CI 0.39 to 0.52). These are associations in observational data, not causal effects. Because follow-up time differs between patients, the logistic OR is only an illustration here; the Cox HR uses the follow-up time and is the estimate to report for death (section 5.2).
ข้อควรอ่านให้ออก: (1) ค่า p ของ Treatment Group ในแบบจำลองคุณภาพชีวิตคือ 0.045 ใกล้เกณฑ์ตัด 0.05 มาก ตัวอย่างที่ต่างไปเล็กน้อยอาจทำให้วิธีอัตโนมัติตัดตัวแปรหลักทิ้ง ซึ่งจะทำให้ตอบคำถามวิจัยไม่ได้เลย สำหรับคำถามแบบอธิบายจึงต้องใช้ Enter กับชุดตัวแปรที่กำหนดไว้ (2) การที่ทุกวิธีเห็นตรงกันในข้อมูลนี้ไม่ได้ทำให้ช่วงเชื่อมั่นหลังการคัดถูกต้องขึ้น — ข้อความเตือนเรื่องอคติหลังการคัดเลือกยังต้องรายงาน (3) เกณฑ์ change-in-estimate บอกว่าการตัดตัวแปรใดตัวหนึ่งออกทำให้ OR ของ APD เปลี่ยนไม่เกิน 4% (มากที่สุดคือ Chronic Disease −3.837% และ Age −3.733%) จึงไม่มีตัวใดเป็นตัวแปรกวนตามเกณฑ์ 10% ส่วน Age และ Chronic Disease ที่วิธีอัตโนมัติเก็บไว้ ถูกเก็บเพราะสัมพันธ์กับการเสียชีวิตเอง ไม่ใช่เพราะเป็นตัวแปรกวนของ APD — สองเกณฑ์ตอบคนละคำถาม
How to read it: (1) Treatment Group has p = 0.045 in the quality-of-life model, very close to the 0.05 cut-off: a slightly different sample could make an automated method drop the exposure itself and leave the research question unanswerable — for an explanatory question use Enter with a pre-specified set. (2) That all methods agree on these data does not make the post-selection confidence intervals valid; the post-selection caveat must still be reported. (3) By the change-in-estimate criterion, leaving out any one covariate moves the APD odds ratio by less than 4% (largest: Chronic Disease −3.837% and Age −3.733%), so none is a confounder by the 10% rule; Age and Chronic Disease are kept by the automated methods because they are associated with death themselves, not because they confound the APD effect — the two criteria answer different questions.
ตามแนวปฏิบัติ STROBE (von Elm et al. 2007) ข้อ 12(a) ให้อธิบายวิธีทางสถิติทั้งหมด รวมถึงวิธีควบคุมตัวแปรกวน และข้อ 16(a) ให้รายงานค่าประมาณทั้งแบบไม่ปรับและแบบปรับ พร้อมระบุว่าปรับตัวแปรกวนตัวใดและเพราะเหตุใด จึงควรเขียนครบสี่อย่าง: (1) ชุดตัวแปรที่พิจารณาทั้งหมด · (2) วิธีและเกณฑ์ที่ใช้คัดเข้าหรือออก · (3) ตัวแปรที่คงไว้ในฐานะตัวแปรกวนแม้ไม่มีนัยสำคัญ · (4) ปฏิสัมพันธ์ที่ตรวจ และตั้งไว้ล่วงหน้าหรือไม่
STROBE (von Elm et al. 2007) item 12(a) asks for all statistical methods, including those used to control for confounding, and item 16(a) for unadjusted and adjusted estimates with a clear statement of which confounders were adjusted for and why. Report all four: (1) the full candidate set, (2) the selection method and its entry and removal criteria, (3) variables kept as confounders despite non-significance, and (4) which interactions were examined and whether they were pre-specified.
ประโยคตัวอย่าง (ระเบียบวิธี): "ใช้ negative binomial regression (log link, offset = log ของคน-ปี) ประมาณความสัมพันธ์ระหว่างวิธีล้างไตทางช่องท้อง (APD เทียบกับ CAPD) กับจำนวนครั้งที่เป็นเยื่อบุช่องท้องอักเสบ ตัวแปรที่นำเข้าพิจารณาได้แก่ อายุ เพศ กลุ่ม BMI โรคประจำตัว รายได้ส่วนบุคคล และการทำงาน คัดด้วย backward elimination ที่ตัดตัวแปรออกเมื่อ p ≥ 0.05 จาก likelihood-ratio test ในโปรแกรม DAPH (Sornlorm, 2026) ช่วงเชื่อมั่นหลังการคัดเลือกอาจแคบกว่าความจริง จึงรายงานแบบจำลองที่มีตัวแปรครบเป็นการวิเคราะห์ความไว" (ผลการวิจัย): "แบบจำลองสุดท้ายประกอบด้วยวิธีล้างไต อายุ และโรคประจำตัว ผู้ป่วยที่ใช้ APD มีอัตราการเกิดเยื่อบุช่องท้องอักเสบต่ำกว่าผู้ที่ใช้ CAPD (adjusted IRR 0.45, 95% CI 0.39 to 0.52)"
A sentence that works (methods): "Negative binomial regression (log link, offset = log person-years) estimated the association between peritoneal-dialysis modality (APD vs CAPD) and the number of peritonitis episodes. Candidate covariates were age, gender, BMI group, chronic disease, personal income and employment status; they were selected by backward elimination, removing a variable when its likelihood-ratio p was 0.05 or more, in DAPH (Sornlorm, 2026). Because confidence intervals after selection can be too narrow, the model with all candidates is reported as a sensitivity analysis." (results): "The final model contained modality, age and chronic disease; patients on APD had a lower peritonitis rate than those on CAPD (adjusted IRR 0.45, 95% CI 0.39 to 0.52)."
📖 References
- Bursac, Z., Gauss, C. H., Williams, D. K., & Hosmer, D. W. (2008). Purposeful selection of variables in logistic regression. Source Code for Biology and Medicine, 3, 17. doi:10.1186/1751-0473-3-17
- Grambsch, P. M., & Therneau, T. M. (1994). Proportional hazards tests and diagnostics based on weighted residuals. Biometrika, 81(3), 515–526. doi:10.1093/biomet/81.3.515
- Greenland, S. (1989). Modeling and variable selection in epidemiologic analysis. American Journal of Public Health, 79(3), 340–349. doi:10.2105/AJPH.79.3.340
- Harrell, F. E. (2015). Regression Modeling Strategies (2nd ed.). Cham: Springer. doi:10.1007/978-3-319-19425-7
- Heinze, G., Wallisch, C., & Dunkler, D. (2018). Variable selection – A review and recommendations for the practicing statistician. Biometrical Journal, 60(3), 431–449. doi:10.1002/bimj.201700067
- Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied Logistic Regression (3rd ed.). Hoboken: Wiley. doi:10.1002/9781118548387
- Maldonado, G., & Greenland, S. (1993). Simulation study of confounder-selection strategies. American Journal of Epidemiology, 138(11), 923–936. doi:10.1093/oxfordjournals.aje.a116813
- Mickey, R. M., & Greenland, S. (1989). The impact of confounder selection criteria on effect estimation. American Journal of Epidemiology, 129(1), 125–137. doi:10.1093/oxfordjournals.aje.a115101
- Peduzzi, P., Concato, J., Feinstein, A. R., & Holford, T. R. (1995). Importance of events per independent variable in proportional hazards regression analysis. II. Accuracy and precision of regression estimates. Journal of Clinical Epidemiology, 48(12), 1503–1510. doi:10.1016/0895-4356(95)00048-8
- Peduzzi, P., Concato, J., Kemper, E., Holford, T. R., & Feinstein, A. R. (1996). A simulation study of the number of events per variable in logistic regression analysis. Journal of Clinical Epidemiology, 49(12), 1373–1379. doi:10.1016/S0895-4356(96)00236-3
- von Elm, E., Altman, D. G., Egger, M., Pocock, S. J., Gøtzsche, P. C., & Vandenbroucke, J. P. (2007). The Strengthening the Reporting of Observational Studies in Epidemiology (STROBE) statement: Guidelines for reporting observational studies. The Lancet, 370(9596), 1453–1457. doi:10.1016/S0140-6736(07)61602-X
- Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification