คู่มือสถิติทางวิชาการStatistical Methods Reference

DAPH Guide DAPH Guide

เอกสารฉบับนี้รวบรวมและอธิบายวิธีการทางสถิติทุกตัวที่ใช้งานในระบบ DAPH (Data Analysis for Public health Research) โดยครอบคลุมบทนำและความสำคัญทางสาธารณสุข หลักการและสูตรการคำนวณ การทวนสอบผลด้วยสคริปต์ R ตลอดจนการแปลผลทางวิชาการ. ทุกการอ้างอิงผ่านการตรวจสอบกับฐานข้อมูลบรรณานุกรมสากล (DOI/ISBN) เพื่อยืนยันว่าระเบียบวิธีทุกประการอยู่บนมาตรฐานสากลที่สามารถตรวจสอบและทำซ้ำได้ This guide compiles and documents every statistical method implemented in the DAPH (Data Analysis for Public health Research) platform, spanning the introduction and public-health relevance, mathematical principles and formulas, verification with R scripts, and academic interpretation. All references have been validated through international bibliographic databases (DOI/ISBN), ensuring that each methodology adheres to internationally verifiable and reproducible standards.

🔬 ตรวจทานทั้งเล่ม 2026-10: ทั้ง 64 หัวข้อถูกตรวจใหม่ทุกสูตร ตัวอย่าง และสคริปต์ · สคริปต์ R ทั้ง 107 ชุดรันได้จริงบน R 4.3.3 กับข้อมูลตัวอย่างของ DAPH (หรือข้อมูลแผนที่สาธารณะที่ระบุในหัวข้อเชิงพื้นที่) · ตารางทวนสอบ 880 แถวเทียบค่าจากการรัน DAPH จริงกับ R บนข้อมูลชุดเดียวกัน ตรงกัน 860 แถว ส่วนอีก 20 แถวที่ยังไม่ตรงแสดงเป็น ✗ FAIL พร้อมบอกว่าต่างเท่าไรและเพราะอะไร 🔬 Full review 2026-10: all 64 sections were re-checked formula by formula, example by example and script by script. All 107 R scripts run in R 4.3.3 on the DAPH example data (or on the public map data named in the spatial sections), and the 880 verification rows compare values from real DAPH runs with R on the same data: 860 agree, and the 20 that do not are shown as ✗ FAIL with the size of the difference and its reason.

🧪 วิธีทำซ้ำผลในคู่มือนี้How to reproduce the results in this guide

  1. ใน 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 opens DAPH-Data-(EN): 1,300 peritoneal-dialysis patients, 41 variables. (The Thai dataset holds the same values except the district code amp and the hospital codes hos and hos2, which are numbered in Thai alphabetical order; analyses that use these variables need the English dataset.)
  2. เลือก File → Export → Export CSV (.csv) แล้วบันทึกเป็น example_en.csv ในโฟลเดอร์ทำงานของ RChoose File → Export → Export CSV (.csv) and save it as example_en.csv in R's working folder.
  3. ใช้ R 4.3.3 ขึ้นไป ติดตั้งแพ็กเกจที่ระบุเหนือสคริปต์ด้วย install.packages() แล้วรันสคริปต์ของหัวข้อนั้นทั้งชุดตามลำดับ ทุกหัวข้ออ่านข้อมูลเองตั้งแต่บรรทัดแรก ไม่ต้องใช้ผลจากหัวข้ออื่นUse R 4.3.3 or newer, install the packages named above each script with install.packages(), and run the section's scripts in order. Every section reads the data in its first lines and needs nothing from other sections.
  4. ข้อมูลตัวอย่างไม่มีแผนที่ หัวข้อเชิงพื้นที่จึงใช้ข้อมูลแผนที่สาธารณะที่ติดมากับแพ็กเกจ 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 .zip file to import into DAPH with File → Import → Shapefile (.zip).
  5. ตารางทวนสอบของทุกหัวข้อเทียบค่าที่ 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 12 stats ✓ 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).

ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย) · คำถามที่ 1 (Independent t-test): คะแนนคุณภาพชีวิตหลังการรักษา (Quality of Life Score (Post), 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 และการแปลผลในส่วนที่ 4
DAPH example data (1,300 peritoneal-dialysis patients). Question 1 (independent t-test): does the post-treatment quality-of-life score (Quality of Life Score (Post), qolscore3) 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

Student's t-test (equal variances, pooled SD)
$$ t = \frac{\bar{x}_1 - \bar{x}_2}{s_p\sqrt{\dfrac{1}{n_1} + \dfrac{1}{n_2}}},\qquad s_p^2 = \frac{(n_1-1)s_1^2 + (n_2-1)s_2^2}{n_1 + n_2 - 2},\qquad df = n_1 + n_2 - 2 $$
Welch's t-test (unequal variances)
$$ t_W = \frac{\bar{x}_1 - \bar{x}_2}{\sqrt{\dfrac{s_1^2}{n_1} + \dfrac{s_2^2}{n_2}}},\qquad df_W = \frac{\left(\dfrac{s_1^2}{n_1} + \dfrac{s_2^2}{n_2}\right)^2}{\dfrac{(s_1^2/n_1)^2}{n_1-1} + \dfrac{(s_2^2/n_2)^2}{n_2-1}} $$
Two-sided p-value and 95% confidence interval of the mean difference
$$ p = 2\,P\bigl(T_{df} \ge \lvert t \rvert\bigr),\qquad (\bar{x}_1 - \bar{x}_2) \pm t_{0.975,\,df}\times SE,\qquad SE = s_p\sqrt{\tfrac{1}{n_1}+\tfrac{1}{n_2}}\ \text{(Student)}\ \ \text{or}\ \ \sqrt{\tfrac{s_1^2}{n_1}+\tfrac{s_2^2}{n_2}}\ \text{(Welch)} $$
Levene's test centred on the median (Brown-Forsythe)
$$ z_{ij} = \lvert x_{ij} - \tilde{x}_j \rvert,\qquad F_{\text{Lev}} = \frac{(N-k)\sum_{j} n_j(\bar{z}_j - \bar{z})^2}{(k-1)\sum_{j}\sum_{i}(z_{ij} - \bar{z}_j)^2},\qquad df = (k-1,\ N-k) $$
Cohen's d (independent groups)
$$ d = \frac{\bar{x}_1 - \bar{x}_2}{s_p} $$
Paired t-test and Cohen's dz
$$ d_i = y_i^{\text{post}} - y_i^{\text{pre}},\qquad t = \frac{\bar{d}}{s_d/\sqrt{n}},\qquad df = n-1,\qquad \bar{d} \pm t_{0.975,\,n-1}\,\frac{s_d}{\sqrt{n}},\qquad d_z = \frac{\lvert \bar{d} \rvert}{s_d} $$
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

R script Independent t-test บนข้อมูลตัวอย่าง (แพ็กเกจ stats และ car)independent t-test on the example data (packages stats and car)
# 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)
Expected R output (R 4.3.3)
#   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
R script Paired t-test (ต่อจากสคริปต์ข้างบน แพ็กเกจ stats)paired t-test (continues the script above; package stats)
# 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
Expected R output (R 4.3.3)
#  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
DAPH Tab 2 > Outcome type: Continuous > ติ๊ก Intervention/Interested Factor? · Independent: Dependent Variable = Quality of Life Score (Post), Independent Variables = Treatment Group (เลือกเป็น Intervention), Statistic = t-test และรันซ้ำด้วย Employment Status · Paired: Statistic = paired t-test, Dependent Variable = Quality of Life Score (Post), Matching Variable = Quality of Life Score (Pre) · ค่า DAPH มาจากผลของเครื่องคำนวณ (หน้าผลลัพธ์ Tab 3, รายงาน Word และค่าภายในที่ทศนิยมเต็ม)Tab 2 > Outcome type: Continuous > tick Intervention/Interested Factor?. Independent: Dependent Variable = Quality of Life Score (Post), Independent Variables = Treatment Group (chosen as the Intervention), Statistic = t-test, and again with Employment Status. Paired: Statistic = paired t-test, Dependent Variable = Quality of Life Score (Post), Matching Variable = Quality of Life Score (Pre). DAPH values come from the engine (Tab 3, the Word report and its internal values at full precision).
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
CAPD: n / mean / SD656 / 74.88643 / 17.37379656 / 74.88643 / 17.37379< 1e−5✓ PASS
APD: n / mean / SD644 / 76.84239 / 18.27674644 / 76.84239 / 18.27674< 1e−5✓ PASS
Shapiro-Wilk W: CAPD / APD0.97476 / 0.971590.9748 / 0.9716< 5e−5✓ PASS
Levene's test แบบใช้มัธยฐาน: F / pLevene's test centred on the median: F / p4.2336 / 0.039834.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 tWelch · −1.97700Welch · −1.97700< 1e−10✓ PASS
Welch's df1291.81291.8364< 1e−6✓ PASS
Welch's p0.048250.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.43320.615 / 0.433< 0.0005✓ PASS
Employment Status: Student's t / df / pEmployment Status: Student's t / df / p5.0785 / 1298 / 4.359e−075.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.109720.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 / df581.37 / 1299581.3704 / 1299< 1e−6✓ PASS
Paired: SD ของผลต่าง / dzPaired: SD of the differences / dz0.46461 / 16.1240.46461 / 16.124< 5e−6 / < 1e−6✓ PASS
Paired: Shapiro-Wilk W ของผลต่างPaired: Shapiro-Wilk W of the differences0.0436510.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).

รูปแบบการรายงาน: "คะแนนคุณภาพชีวิตหลังการรักษาเฉลี่ยของผู้ป่วย CAPD (n = 656) เท่ากับ 74.89 (SD 17.37) และของผู้ป่วย APD (n = 644) เท่ากับ 76.84 (SD 18.28) ผลต่างเท่ากับ −1.96 คะแนน (95% CI −3.90 ถึง −0.02; Welch's t(1291.8) = −1.98, p = 0.048; Cohen's d = −0.11) ซึ่งมีขนาดเล็กมาก และมีความต่างขนาดเดียวกันตั้งแต่ก่อนการรักษา"
How to report it: "The mean post-treatment quality-of-life score was 74.89 (SD 17.37) in CAPD patients (n = 656) and 76.84 (SD 18.28) in APD patients (n = 644), a difference of −1.96 points (95% CI −3.90 to −0.02; Welch's t(1291.8) = −1.98, p = 0.048; Cohen's d = −0.11), a negligible difference that was already present before treatment."

คำถามที่ 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".

รูปแบบการรายงาน: "คะแนนคุณภาพชีวิตเพิ่มขึ้นจาก 68.36 (SD 17.85) ก่อนการรักษา เป็น 75.86 (SD 17.85) หลังการรักษา ผลต่างเฉลี่ย 7.49 คะแนน (95% CI 7.47 ถึง 7.52; paired t(1299) = 581.37, p < 0.001)"
How to report it: "The quality-of-life score rose from 68.36 (SD 17.85) before treatment to 75.86 (SD 17.85) after treatment, a mean change of 7.49 points (95% CI 7.47 to 7.52; paired t(1299) = 581.37, p < 0.001)."
📖 References
  1. 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
  2. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
  3. Levene, H. (1960). Robust tests for equality of variances. In I. Olkin (Ed.), Contributions to probability and statistics (pp. 278–292). Stanford University Press.
  4. 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
  5. Student [Gosset, W. S.]. (1908). The probable error of a mean. Biometrika, 6(1), 1–25. doi:10.1093/biomet/6.1.1
  6. 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
  7. 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).

ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย) · คำถามหลัก: คะแนนคุณภาพชีวิตหลังการรักษา (Quality of Life Score (Post), qolscore3) ต่างกันตามรายได้ครัวเรือนหรือไม่ (Household Income, fam_income: 1 = < 10,000 บาท/เดือน 380 ราย, 2 = 10,000-30,000 บาท/เดือน 338 ราย, 3 = > 30,000 บาท/เดือน 582 ราย) ถ้าต่าง คู่ใดต่างกัน · คำถามที่สอง (ความแปรปรวนไม่เท่ากัน): คะแนนเดียวกันต่างกันระหว่าง 10 อำเภอหรือไม่ (District, amp) · ผลอยู่ในส่วนที่ 3 และการแปลผลในส่วนที่ 4
DAPH example data (1,300 peritoneal-dialysis patients). Main question: does the post-treatment quality-of-life score (Quality of Life Score (Post), qolscore3) 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

F test
$$ F = \frac{MS_B}{MS_W} = \frac{SS_B/(k-1)}{SS_W/(N-k)},\qquad SS_B = \sum_{j=1}^{k} n_j(\bar{x}_j - \bar{x})^2,\qquad SS_W = \sum_{j=1}^{k}\sum_{i=1}^{n_j}(x_{ij} - \bar{x}_j)^2,\qquad p = P\bigl(F_{k-1,\,N-k} \ge F\bigr) $$
Effect size: η² (eta-squared), ω² (omega-squared) and the 95% CI of η²
$$ \eta^2 = \frac{SS_B}{SS_B + SS_W},\qquad \omega^2 = \max\Bigl(0,\ \frac{SS_B - (k-1)\,MS_W}{SS_B + SS_W + MS_W}\Bigr) $$ $$ P\bigl(F'_{k-1,\,N-k}(\lambda_L) \le F\bigr) = 0.975,\qquad P\bigl(F'_{k-1,\,N-k}(\lambda_U) \le F\bigr) = 0.025,\qquad \text{95\% CI of } \eta^2 = \Bigl[\tfrac{\lambda_L}{\lambda_L + N - k},\ \tfrac{\lambda_U}{\lambda_U + N - k}\Bigr] $$
Levene's test centred on the median (Brown-Forsythe)
$$ z_{ij} = \lvert x_{ij} - \tilde{x}_j \rvert,\qquad F_{\text{Lev}} = \frac{(N-k)\sum_{j} n_j(\bar{z}_j - \bar{z})^2}{(k-1)\sum_{j}\sum_{i}(z_{ij} - \bar{z}_j)^2},\qquad df = (k-1,\ N-k) $$
Welch's ANOVA (unequal variances)
$$ w_j = \frac{n_j}{s_j^2},\quad \bar{x}_w = \frac{\sum_j w_j\bar{x}_j}{\sum_j w_j},\quad \Lambda = \sum_j \frac{\bigl(1 - w_j/\sum_l w_l\bigr)^2}{n_j - 1},\quad F_W = \frac{\sum_j w_j(\bar{x}_j - \bar{x}_w)^2/(k-1)}{1 + \frac{2(k-2)}{k^2-1}\,\Lambda},\quad df = \Bigl(k-1,\ \frac{k^2-1}{3\Lambda}\Bigr) $$
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
Post hoc: Tukey HSD / Tukey-Kramer (pooled variance, studentized range)
$$ SE_{ij} = \sqrt{MS_W\Bigl(\frac{1}{n_i} + \frac{1}{n_j}\Bigr)},\qquad q_{ij} = \frac{\sqrt{2}\,\lvert\bar{x}_i - \bar{x}_j\rvert}{SE_{ij}},\qquad p = P\bigl(Q_{k,\,N-k} \ge q_{ij}\bigr),\qquad (\bar{x}_i - \bar{x}_j) \pm \frac{q_{0.95;\,k,\,N-k}}{\sqrt{2}}\,SE_{ij} $$
Games-Howell (each pair's own variances, Welch df)
$$ SE_{ij} = \sqrt{\frac{s_i^2}{n_i} + \frac{s_j^2}{n_j}},\quad df_{ij} = \frac{\bigl(s_i^2/n_i + s_j^2/n_j\bigr)^2}{\frac{(s_i^2/n_i)^2}{n_i-1} + \frac{(s_j^2/n_j)^2}{n_j-1}},\quad q_{ij} = \frac{\sqrt{2}\,\lvert\bar{x}_i - \bar{x}_j\rvert}{SE_{ij}},\quad p = P\bigl(Q_{k,\,df_{ij}} \ge q_{ij}\bigr),\quad (\bar{x}_i - \bar{x}_j) \pm \frac{q_{0.95;\,k,\,df_{ij}}}{\sqrt{2}}\,SE_{ij} $$
t on the pooled variance: Bonferroni · Holm · Šidák · Fisher's LSD
$$ t_{ij} = \frac{\bar{x}_i - \bar{x}_j}{SE_{ij}},\qquad SE_{ij} = \sqrt{MS_W\Bigl(\tfrac{1}{n_i} + \tfrac{1}{n_j}\Bigr)},\qquad p_{ij} = 2\,P\bigl(T_{N-k} \ge \lvert t_{ij} \rvert\bigr),\qquad m = \tfrac{k(k-1)}{2} $$ $$ p^{\text{Bonf}} = \min(1,\ m\,p),\qquad p^{\text{Holm}}_{(r)} = \max_{s \le r}\ \min\bigl(1,\ (m-s+1)\,p_{(s)}\bigr),\qquad p^{\text{\v{S}id\'{a}k}} = 1-(1-p)^m,\qquad p^{\text{LSD}} = p $$ $$ (\bar{x}_i - \bar{x}_j) \pm t_{1-\alpha^{*}/2,\,N-k}\,SE_{ij},\qquad \alpha^{*} = \alpha/m\ \ \text{(Bonferroni, Holm)},\quad 1-(1-\alpha)^{1/m}\ \ \text{(\v{S}id\'{a}k)},\quad \alpha\ \ \text{(LSD)} $$
Scheffé
$$ F_{ij} = \frac{t_{ij}^2}{k-1},\qquad p = P\bigl(F_{k-1,\,N-k} \ge F_{ij}\bigr),\qquad (\bar{x}_i - \bar{x}_j) \pm \sqrt{(k-1)\,F_{0.95;\,k-1,\,N-k}}\;SE_{ij} $$
Dunnett: each group i against the reference group 0
$$ t_i = \frac{\bar{x}_i - \bar{x}_0}{\sqrt{MS_W\bigl(\tfrac{1}{n_i} + \tfrac{1}{n_0}\bigr)}},\quad \operatorname{corr}(t_i, t_{i'}) = \lambda_i \lambda_{i'},\ \ \lambda_i = \sqrt{\frac{n_i}{n_i + n_0}},\quad p_i = 1 - P\Bigl(\max_{i'} \lvert T_{i'} \rvert \le \lvert t_i \rvert\Bigr),\quad (\bar{x}_i - \bar{x}_0) \pm c_{0.95}\,SE_i $$
Hedges' g of each pair
$$ g_{ij} = \frac{\bar{x}_i - \bar{x}_j}{s_{p,ij}}\Bigl(1 - \frac{3}{4(n_i + n_j) - 9}\Bigr),\qquad s_{p,ij}^2 = \frac{(n_i-1)s_i^2 + (n_j-1)s_j^2}{n_i + n_j - 2} $$
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

R script การทดสอบรวม ขนาดอิทธิพล และข้อตกลงเบื้องต้น (แพ็กเกจ stats และ car)overall test, effect sizes and assumption checks (packages stats and car)
# 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)
Expected R output (R 4.3.3)
#   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
R script post hoc ทุกตัวเลือกในดรอปดาวน์ (ต่อจากสคริปต์ข้างบน แพ็กเกจ emmeans และ multcomp)every option in the post hoc dropdown (continues the script above; packages emmeans and multcomp)
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))
Expected R output (R 4.3.3, abridged)
# -- 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
R script ความแปรปรวนไม่เท่ากัน (Welch's ANOVA และ Games-Howell) และตัวแปรสองกลุ่ม (ต่อจากสคริปต์ข้างบน)unequal variances (Welch's ANOVA and Games-Howell) and a two-group variable (continues the script above)
# 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)
Expected R output (R 4.3.3, abridged)
# 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
DAPH Tab 2 > Outcome type: Continuous > Statistic: One-way ANOVA · Dependent Variable = Quality of Life Score (Post) · Independent Variables = Household Income (และในการรันที่สอง District, ที่สาม Employment Status) · Post Hoc ติ๊กไว้ "อัตโนมัติ (แนะนำ)" แล้วเลือกทีละตัวเลือกในดรอปดาวน์ (Dunnett: กลุ่มอ้างอิง = กลุ่มแรก) · ค่า DAPH มาจาก Tab 3, รายงาน Word และค่าภายในของเครื่องคำนวณที่ทศนิยมเต็มTab 2 > Outcome type: Continuous > Statistic: One-way ANOVA; Dependent Variable = Quality of Life Score (Post); Independent Variables = Household Income (second run District, third run Employment Status); Post Hoc ticked, "Automatic (recommended)", then each dropdown option in turn (Dunnett: reference = first group). DAPH values come from Tab 3, the Word report and the engine's internal values at full precision.
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
Household Income · n / mean / SD: < 10,000 · 10,000-30,000 · > 30,000380 / 79.36842 / 17.60756 · 338 / 75.69379 / 17.61440 · 582 / 73.65550 / 17.80397380 / 79.36842 / 17.60756 · 338 / 75.69379 / 17.61440 · 582 / 73.65550 / 17.80397< 1e−5✓ PASS
F(2, 1297) / p11.99721 / 6.875246e−0611.99721 / 6.875246e−06< 1e−5✓ PASS
η² / ω² (ω² ค่าภายใน ไม่แสดงในรายงาน)(ω² internal, not shown)0.0181639 / 0.01663730.0181639 / 0.0166373< 1e−7✓ PASS
95% CI ของ η² (รายงาน Word)95% CI of η² (Word report)0.00598 to 0.034230.006 to 0.034< 0.0005✓ PASS
Levene's test แบบใช้มัธยฐาน: F / pLevene's test centred on the median: F / p0.0591 / 0.94260.05912 / 0.94260< 5e−5✓ PASS
Shapiro-Wilk W: < 10,000 · 10,000-30,000 · > 30,0000.9584394 · 0.9763782 · 0.97909970.9584394 · 0.9763782 · 0.9790997< 1e−7✓ PASS
วิธีที่เลือกอัตโนมัติ (Levene p ≥ 0.05, ขนาดกลุ่มไม่เท่ากัน)Automatic choice (Levene p ≥ 0.05, unequal group sizes)Tukey-KramerTukey-Kramer—✓ PASS
Tukey-Kramer · ผลต่าง (95% CI)difference (95% CI): Low−Middle · Low−High · Middle−High3.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 p0.01535475 · 3.314807e−06 · 0.21164270.01535475 · 3.314808e−06 · 0.2116427< 1e−8✓ PASS
Games-Howell · adjusted p · df0.01491232 · 3.489799e−06 · 0.2114754 · df 706.2092 · 816.5431 · 710.46450.01491232 · 3.489799e−06 · 0.2114754 · df 706.2092 · 816.5431 · 710.4645< 1e−8 · < 1e−4✓ PASS
Games-Howell · 95% CI Low−Middle0.582054 to 6.7672140.582054 to 6.767214< 1e−6✓ PASS
Bonferroni · adjusted p · 95% CI Low−Middle0.01669191 · 3.327588e−06 · 0.2771868 · 0.502801 to 6.8464670.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.092395610.01112794 · 3.327588e−06 · 0.09239562< 1e−8✓ PASS
Šidák · adjusted p · 95% CI Low−Middle0.01659921 · 3.327584e−06 · 0.2523648 · 0.511089 to 6.8381790.01659921 · 3.327584e−06 · 0.2523648 · 0.511089 to 6.838179< 1e−8✓ PASS
Scheffé · adjusted p · 95% CI Low−Middle0.02139364 · 7.004993e−06 · 0.2425343 · 0.432027 to 6.9172410.02139364 · 7.004993e−06 · 0.2425343 · 0.432027 to 6.917241< 1e−8✓ PASS
Fisher's LSD · p (ไม่ปรับunadjusted) · 95% CI Low−Middle0.005563969 · 1.109196e−06 · 0.09239561 · 1.078784 to 6.2704840.005563969 · 1.109196e−06 · 0.09239561 · 1.078784 to 6.270484< 1e−8✓ PASS
Dunnett (อ้างอิงreference < 10,000) · adjusted p: Middle−Low · High−Low0.01060309 · 2.212029e−060.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.7497091.0e−4✓ PASS
Hedges' g: Low−Middle · Low−High · Middle−High0.2084396 · 0.3220262 · 0.11483890.2084396 · 0.3220262 · 0.1148389< 1e−7✓ PASS
District · Levene F / p8.0684 / 1.044e−118.06842 / 1.0436e−11< 5e−5✓ PASS
District · การทดสอบที่รายงาน (Levene p < 0.05)test reported (Levene p < 0.05)Welch's ANOVAWelch's ANOVA—✓ PASS
District · Welch's F / df2 / p10.014 / 362.61 / 9.095e−1410.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.063856.870618 / 1.044469e−09 / 0.04574193 / 0.021 to 0.064< 0.0005✓ PASS
District · วิธีอัตโนมัติ · จำนวนคู่ที่ต่างกันautomatic method · pairs that differGames-Howell · 13 of 45Games-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 p5.210256 (3.197574 to 7.222939) / 4.358639e−07 / 4.358639e−075.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.

ประโยคในรายงาน Word (DAPH เขียนวิธี เหตุผล และเอกสารอ้างอิง แล้วชี้มาที่หัวข้อนี้): "เนื่องจากความแปรปรวนไม่ต่างกัน (Levene's test แบบใช้มัธยฐาน p = 0.943; Levene, 1960; Brown & Forsythe, 1974) แต่ขนาดกลุ่มไม่เท่ากัน จึงเปรียบเทียบรายคู่ด้วย Tukey-Kramer (Tukey, 1949; Kramer, 1956) ขั้นตอน เกณฑ์การเลือกวิธี post hoc และเกณฑ์การแปลผลอธิบายไว้ใน DAPH Guide หัวข้อ 1.2 (Sornlorm, 2026b)" ตามด้วย "พบความแตกต่างอย่างมีนัยสำคัญ 2 จาก 3 คู่ ได้แก่ < 10,000 Baht/month กับ 10,000-30,000 Baht/month (ผลต่างค่าเฉลี่ย 3.67, 95% CI 0.57 ถึง 6.78, p = 0.015, Hedges' g = 0.21); < 10,000 Baht/month กับ > 30,000 Baht/month (ผลต่างค่าเฉลี่ย 5.71, 95% CI 2.97 ถึง 8.45, p < 0.001, Hedges' g = 0.32)"
The Word report sentence (DAPH states the method, the reason and the references, then points to this section): "Because the variances did not differ (Levene's test centred on the median, p = 0.943; Levene, 1960; Brown & Forsythe, 1974) but the group 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.2 (Sornlorm, 2026b)." followed by "2 of 3 pairs differed significantly: < 10,000 Baht/month vs 10,000-30,000 Baht/month (mean difference 3.67, 95% CI 0.57 to 6.78, p = 0.015, Hedges' g = 0.21); < 10,000 Baht/month vs > 30,000 Baht/month (mean difference 5.71, 95% CI 2.97 to 8.45, p < 0.001, Hedges' g = 0.32)."

การอ่านตาราง 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.

ข้อมูลรายได้ครัวเรือนเมื่อเลือกวิธีเอง: ทุกวิธีที่เทียบครบทุกคู่ให้ข้อสรุปเดียวกันว่า 2 คู่แรกต่างกันและคู่ 10,000-30,000 กับ > 30,000 ไม่ต่าง (ค่า p ของคู่ < 10,000 กับ 10,000-30,000: Holm 0.011, Games-Howell 0.015, Šidák 0.017, Bonferroni 0.017, Scheffé 0.021 และ Fisher's LSD 0.006 ซึ่งไม่ได้ปรับ) · ถ้าเลือก Dunnett โดยใช้กลุ่ม < 10,000 เป็นกลุ่มอ้างอิง จะตอบอีกคำถามหนึ่ง คือ "กลุ่มรายได้อื่นต่างจากกลุ่มรายได้ต่ำสุดหรือไม่" ได้ 10,000-30,000 ต่ำกว่า 3.67 คะแนน (p = 0.011) และ > 30,000 ต่ำกว่า 5.71 คะแนน (p < 0.001) · ให้เลือกวิธีตามคำถามวิจัยก่อนดูผล ไม่ใช่ลองหลายวิธีแล้วเลือกวิธีที่ได้ผลตามต้องการ
Household income with a method chosen by hand: every all-pairs method reaches the same conclusion, the first two pairs differ and 10,000-30,000 versus > 30,000 does not (p of < 10,000 versus 10,000-30,000: Holm 0.011, Games-Howell 0.015, Šidák 0.017, Bonferroni 0.017, Scheffé 0.021, and the unadjusted Fisher's LSD 0.006). Choosing Dunnett with < 10,000 as the reference answers a different question, "do the other income groups differ from the lowest one?": 10,000-30,000 is 3.67 points lower (p = 0.011) and > 30,000 is 5.71 points lower (p < 0.001). Choose the method from the research question before looking at the results, not by trying several and keeping the one you like.

คำถามที่สอง (ความแปรปรวนไม่เท่ากัน): ค่าเฉลี่ยของ 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
  1. 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
  2. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
  3. Dunn, O. J. (1961). Multiple comparisons among means. Journal of the American Statistical Association, 56(293), 52–64. doi:10.1080/01621459.1961.10482090
  4. 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
  5. Fisher, R. A. (1925). Statistical methods for research workers. Oliver and Boyd.
  6. Fisher, R. A. (1935). The design of experiments. Oliver and Boyd.
  7. 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
  8. 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
  9. Holm, S. (1979). A simple sequentially rejective multiple test procedure. Scandinavian Journal of Statistics, 6(2), 65–70.
  10. 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
  11. Levene, H. (1960). Robust tests for equality of variances. In I. Olkin (Ed.), Contributions to probability and statistics (pp. 278–292). Stanford University Press.
  12. 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
  13. 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
  14. Š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
  15. 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
  16. Tukey, J. W. (1949). Comparing individual means in the analysis of variance. Biometrics, 5(2), 99–114. doi:10.2307/3001913
  17. 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
  18. 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).

ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย) · คำถามหลัก: คะแนนคุณภาพชีวิตหลังการรักษา (Quality of Life Score (Post), qolscore3) ต่างกันตามรายได้ส่วนบุคคล (Personal Income, income: 1 = ไม่มีรายได้, 2 = < 10,000, 3 = ≥ 10,000 บาท/เดือน) และตามการมีโรคเรื้อรัง (Chronic Disease, chronic: 0 = ไม่มี, 1 = มี) หรือไม่ และความต่างตามรายได้ขึ้นกับการมีโรคเรื้อรังหรือไม่ (แบบ 3 × 2 เซลล์ละ 78 ถึง 494 ราย) · คำถามที่สอง (ความแปรปรวนของเซลล์ไม่เท่ากัน): คะแนนเดียวกันตามเพศ (Gender) และประเภทโรงพยาบาล (Hospital Type: รัฐ/เอกชน) · ผลอยู่ในส่วนที่ 3 และการแปลผลในส่วนที่ 4
DAPH example data (1,300 peritoneal-dialysis patients). Main question: does the post-treatment quality-of-life score (Quality of Life Score (Post), qolscore3) 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

Model and F tests
$$ y_{ijl} = \mu + \alpha_i + \beta_j + (\alpha\beta)_{ij} + \varepsilon_{ijl},\qquad \varepsilon_{ijl} \sim N(0, \sigma^2),\qquad \sum_i \alpha_i = \sum_j \beta_j = \sum_i (\alpha\beta)_{ij} = \sum_j (\alpha\beta)_{ij} = 0 $$ $$ F_{\text{effect}} = \frac{SS_{\text{effect}}/df_{\text{effect}}}{MS_E},\qquad MS_E = \frac{SS_E}{N - ab},\qquad df_A = a-1,\ \ df_B = b-1,\ \ df_{AB} = (a-1)(b-1) $$
Effect sizes: partial η², partial ω² and the 95% CI of partial η²
$$ \eta^2_p = \frac{SS_{\text{effect}}}{SS_{\text{effect}} + SS_E},\qquad \omega^2_p = \max\Bigl(0,\ \frac{SS_{\text{effect}} - df_{\text{effect}}\,MS_E}{SS_{\text{effect}} + (N - df_{\text{effect}})\,MS_E}\Bigr) $$ $$ P\bigl(F'_{df_{\text{effect}},\,df_E}(\lambda_L) \le F\bigr) = 0.975,\qquad P\bigl(F'_{df_{\text{effect}},\,df_E}(\lambda_U) \le F\bigr) = 0.025,\qquad \text{95\% CI} = \Bigl[\tfrac{\lambda_L}{\lambda_L + df_E},\ \tfrac{\lambda_U}{\lambda_U + df_E}\Bigr] $$
Estimated marginal means (each level of the other factor weighted equally)
$$ \widehat{EM}_i = \frac{1}{k}\sum_{j=1}^{k} \bar{y}_{ij},\qquad SE(\widehat{EM}_i) = \sqrt{\frac{MS_E}{k^2}\sum_{j=1}^{k}\frac{1}{n_{ij}}},\qquad \widehat{EM}_i \pm t_{0.975,\,df_E}\,SE $$
Simple main effect of A at level j of B (pooled error of the full model)
$$ SS_{A|j} = \sum_{i} n_{ij}(\bar{y}_{ij} - \bar{y}_{\cdot j})^2,\qquad F_{A|j} = \frac{SS_{A|j}/(a-1)}{MS_E},\qquad p^{\text{Bonf}} = \min\bigl(1,\ b \cdot P(F_{a-1,\,df_E} \ge F_{A|j})\bigr),\qquad \eta^2_{p,A|j} = \frac{SS_{A|j}}{SS_{A|j} + SS_E} $$
α_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.

Post hoc on the estimated marginal means: Tukey (HSD or Tukey-Kramer)
$$ SE_{\text{diff}} = \sqrt{\frac{MS_E}{k^2}\Bigl(\sum_{j}\frac{1}{n_{ij}} + \sum_{j}\frac{1}{n_{i'j}}\Bigr)},\qquad q = \frac{\sqrt{2}\,\lvert \widehat{EM}_i - \widehat{EM}_{i'} \rvert}{SE_{\text{diff}}},\qquad p = P\bigl(Q_{a,\,df_E} \ge q\bigr),\qquad \text{diff} \pm \frac{q_{0.95;\,a,\,df_E}}{\sqrt{2}}\,SE_{\text{diff}} $$
t-based options and Scheffé (same SE_diff, m = a(a−1)/2 pairs)
$$ t = \frac{\widehat{EM}_i - \widehat{EM}_{i'}}{SE_{\text{diff}}},\quad p = 2\,P\bigl(T_{df_E} \ge \lvert t \rvert\bigr),\quad p^{\text{Bonf}} = \min(1,\ m\,p),\quad p^{\text{Holm}}_{(r)} = \max_{s \le r}\min\bigl(1,\ (m-s+1)\,p_{(s)}\bigr),\quad p^{\text{\v{S}id\'{a}k}} = 1-(1-p)^m,\quad p^{\text{LSD}} = p $$ $$ F^{\text{Scheff\'{e}}} = \frac{t^2}{a-1},\ \ p = P\bigl(F_{a-1,\,df_E} \ge F\bigr),\qquad \text{CI: } t_{1-\alpha^{*}/2,\,df_E}\ (\alpha^{*} = \alpha/m \text{ Bonferroni and Holm},\ 1-(1-\alpha)^{1/m} \text{ \v{S}id\'{a}k},\ \alpha \text{ LSD}),\ \ \sqrt{(a-1)F_{0.95;\,a-1,\,df_E}}\ \text{Scheff\'{e}} $$
Games-Howell-type comparison of marginal means (each cell's own variance)
$$ SE_{\text{diff}}^2 = \sum_{c} v_c,\quad v_c = \frac{s_c^2}{k^2\,n_c},\qquad df = \frac{\bigl(\sum_c v_c\bigr)^2}{\sum_c v_c^2/(n_c - 1)},\qquad p = P\bigl(Q_{a,\,df} \ge \sqrt{2}\,\lvert t \rvert\bigr),\qquad \text{diff} \pm \frac{q_{0.95;\,a,\,df}}{\sqrt{2}}\,SE_{\text{diff}} $$
Hedges' g
$$ g_{\text{EM}} = \frac{\widehat{EM}_i - \widehat{EM}_{i'}}{\sqrt{MS_E}}\Bigl(1 - \frac{3}{4\,df_E - 1}\Bigr)\ \ \text{(main-effect pairs)},\qquad g = \frac{\bar{y}_1 - \bar{y}_2}{s_{p}}\Bigl(1 - \frac{3}{4(n_1 + n_2) - 9}\Bigr)\ \ \text{(pairs inside a simple effect)} $$
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

R script ตาราง ANOVA แบบ Type III ขนาดอิทธิพล และข้อตกลงเบื้องต้น (แพ็กเกจ stats และ car)Type III ANOVA table, effect sizes and assumption checks (packages stats and car)
# 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
Expected R output (R 4.3.3, abridged)
#           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
R script ค่าเฉลี่ยชายขอบและ post hoc ทุกตัวเลือก (ต่อจากสคริปต์ข้างบน แพ็กเกจ emmeans)marginal means and every post hoc option (continues the script above; package emmeans)
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)
Expected R output (R 4.3.3, abridged)
#     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
R script simple main effects และคู่ภายในระดับ (ต่อจากสคริปต์ข้างบน)simple main effects and the pairs within a level (continues the script above)
# 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"]))
Expected R output (R 4.3.3, abridged)
#                       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
R script ความแปรปรวนของเซลล์ไม่เท่ากัน: HC3 และวิธีแบบ Games-Howell (ต่อจากสคริปต์ข้างบน)unequal cell variances: HC3 and the Games-Howell-type procedure (continues the script above)
# 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
Expected R output (R 4.3.3, abridged)
# 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
DAPH Tab 2 > Outcome type: Continuous > Statistic: Two-way ANOVA · Dependent Variable = Quality of Life Score (Post) · ปัจจัย A = Personal Income, ปัจจัย B = Chronic Disease · ผลรวมกำลังสอง Type III (และ Type II ในการรันที่สอง) · ติ๊ก Simple effects · Post Hoc "อัตโนมัติ (แนะนำ)" แล้วเลือกทีละตัวเลือก · คำถามที่สอง: ปัจจัย Gender และ Hospital Type · ค่า DAPH มาจาก Tab 3, รายงาน Word และค่าภายในของเครื่องคำนวณที่ทศนิยมเต็มTab 2 > Outcome type: Continuous > Statistic: Two-way ANOVA; Dependent Variable = Quality of Life Score (Post); factor A = Personal Income, factor B = Chronic Disease; Sums of squares Type III (Type II in a second run); Simple effects ticked; Post Hoc "Automatic (recommended)", then each option in turn. Second question: factors Gender and Hospital Type. DAPH values come from Tab 3, the Word report and the engine's internal values at full precision.
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
ขนาดเซลล์ (None, Under10k, Over10k × No, Yes)Cell sizes (None, Under10k, Over10k × No, Yes)82, 81 · 105, 78 · 460, 49482, 81 · 105, 78 · 460, 4940✓ PASS
Type III SS: income · chronic · income × chronic3818.756138 · 3.607939 · 1918.6319843818.756138 · 3.607939 · 1918.631984< 1e−6✓ PASS
F6.076440 · 0.011482 · 3.0529456.076440 · 0.011482 · 3.052945< 1e−6✓ PASS
p0.002362387 · 0.914683451 · 0.0475599410.002362387 · 0.914683451 · 0.047559941< 1e−9✓ PASS
partial η² · partial ω²0.0093043 · 0.0000089 · 0.0046965 | 0.0077494 · 0 · 0.00314840.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.01344112406609.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.013950.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 / p0.3074 / 0.9087 · 0.9771 / 1.655e−130.30736 / 0.90868 · 0.97710 / 1.6551e−13< 5e−5✓ PASS
Type II F / p: income · chronic · income × chronic5.9611 / 0.002648 · 4.3037 / 0.038227 · 3.0529 / 0.0475605.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 · Over10k80.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 significantTukey-Kramer · yesTukey-Kramer · yes—✓ PASS
Tukey-Kramer · ผลต่าง (95% CI) / pdifference (95% CI) / p: None−Under10k · None−Over10k · Under10k−Over10k3.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.39428683.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−Over10k0.1815333 · 0.2875324 · 0.10599910.181533 · 0.287532 · 0.105999< 5e−7✓ PASS
Bonferroni · Holm · Šidák · Scheffé · LSD: p ของ None−Over10kp of None−Over10k0.002127648 · 0.002127648 · 0.002126139 · 0.003231907 · 0.00070921580.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−Over10k0.2809275, 0.5794380 · 0.1872850, 0.1931460 · 0.2554419, 0.4747272 · 0.2451585, 0.4286754 · 0.0936425, 0.19314600.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 · df0.2037740 · 0.001911561 · 0.3871831 · df 333.3773 · 220.6778 · 250.51630.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 · Yes1.123159 / 0.6511350 / 0.0017329 · 7.890914 / 0.0007848368 / 0.01204921.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 · Over10k0.243258 / 1 · 0.926792 / 1 · 9.239519 / 0.0072480330.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) / p2.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.060550122.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 = Yes3.491225 (1.237984 to 5.744466) / 0.002416011 · 0.43738023.491225 (1.237984 to 5.744466) / 0.002416011 · 0.4373802< 1e−6✓ PASS
Gender × Hospital Type · Type III F / p: gender · type · gender × type0.1276 / 0.72095 · 4.4125 / 0.03587 · 1.2178 / 0.270000.12764 / 0.72095 · 4.41253 / 0.03587 · 1.21778 / 0.27000< 5e−5✓ PASS
Gender × Hospital Type · Levene (4 เซลล์cells): F / p4.0541 / 0.0070154.05412 / 0.0070150< 5e−5✓ PASS
Gender × Hospital Type · HC3 F / p0.0965 / 0.75607 · 3.3375 / 0.06795 · 0.9211 / 0.337360.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 / pGames-Howell-type · 2.817936 / 194.4864 / −0.210018 to 5.845890 / 0.06796727Games-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.

รูปแบบการรายงาน: "การวิเคราะห์ความแปรปรวนสองทางแบบ 3 × 2 (sum of squares แบบ Type III) พบปฏิสัมพันธ์ระหว่างรายได้ส่วนบุคคลกับการมีโรคเรื้อรัง F(2, 1294) = 3.05, p = 0.048, partial η² = 0.005 ในผู้ที่มีโรคเรื้อรัง คะแนนคุณภาพชีวิตต่างกันตามรายได้ F(2, 1294) = 7.89, p < 0.001 (ปรับ Bonferroni) โดยผู้ไม่มีรายได้สูงกว่าผู้มีรายได้ ≥ 10,000 บาท 7.53 คะแนน (95% CI 2.54 ถึง 12.52) ขณะที่ในผู้ที่ไม่มีโรคเรื้อรังไม่พบความต่างตามรายได้ (p = 0.651)"
How to report it: "A 3 × 2 factorial ANOVA (Type III sums of squares) showed a personal income × chronic disease interaction, F(2, 1294) = 3.05, p = 0.048, partial η² = 0.005. Among patients with a chronic disease, quality of life differed by income, F(2, 1294) = 7.89, p < 0.001 (Bonferroni-adjusted), patients without income scoring 7.53 points higher than those earning ≥ 10,000 Baht (95% CI 2.54 to 12.52); among patients without a chronic disease there was no significant income difference (p = 0.651)."

ประโยคในรายงาน 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
  1. 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
  2. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
  3. Dunn, O. J. (1961). Multiple comparisons among means. Journal of the American Statistical Association, 56(293), 52–64. doi:10.1080/01621459.1961.10482090
  4. Fisher, R. A. (1935). The design of experiments. Oliver and Boyd.
  5. 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
  6. Holm, S. (1979). A simple sequentially rejective multiple test procedure. Scandinavian Journal of Statistics, 6(2), 65–70.
  7. 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
  8. 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
  9. Levene, H. (1960). Robust tests for equality of variances. In I. Olkin (Ed.), Contributions to probability and statistics (pp. 278–292). Stanford University Press.
  10. 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
  11. Maxwell, S. E., Delaney, H. D., & Kelley, K. (2018). Designing experiments and analyzing data: A model comparison perspective (3rd ed.). Routledge.
  12. 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
  13. 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
  14. 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
  15. Š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
  16. 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
  17. Tukey, J. W. (1949). Comparing individual means in the analysis of variance. Biometrics, 5(2), 99–114. doi:10.2307/3001913
  18. 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).

ตัวอย่างในข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย): คุณภาพชีวิตหลังการรักษา (Quality of Life Score (Post), 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 จึงถามว่าเมื่อเริ่มจากจุดเดียวกัน ความต่างหลังการรักษายังเหลืออยู่เท่าไร
Example in the DAPH data (1,300 peritoneal-dialysis patients): does quality of life after treatment (Quality of Life Score (Post), 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

ANCOVA model, fitted by ordinary least squares
$$ y_j=\beta_0+\sum_{g=2}^{k}\tau_g D_{gj}+\sum_{c}\gamma_c\,x_{cj}+\sum_{m}\sum_{l=2}^{L_m}\delta_{ml}E_{mlj}+\varepsilon_j,\qquad \varepsilon_j\sim\mathcal{N}(0,\sigma^2),\qquad \hat{\beta}=(X^{\top}X)^{-1}X^{\top}y $$
Adjusted (estimated marginal) mean of group g: one linear combination of the coefficients
$$ \widehat{\mathrm{EMM}}_g=L_g^{\top}\hat{\beta},\qquad L_g=\sum_r w_r\,x_r(g),\qquad SE_g=\sqrt{L_g^{\top}V L_g},\qquad \text{95\% CI}=\widehat{\mathrm{EMM}}_g\pm t_{0.975,\,n-p}\,SE_g $$
Difference from the reference group and effect sizes
$$ \hat{\tau}_g=\widehat{\mathrm{EMM}}_g-\widehat{\mathrm{EMM}}_1,\qquad t=\frac{\hat{\tau}_g}{SE(\hat{\tau}_g)}\ \ (df=n-p),\qquad d=\frac{\hat{\tau}_g}{\sqrt{MSE}},\qquad MSE=\frac{SS_{\text{res}}}{n-p} $$
Omnibus test of each term (Type III), partial η², Cohen's f and the 95% CI of partial η²
$$ F_{\text{term}}=\frac{SS^{\text{III}}_{\text{term}}/df_{\text{term}}}{SS_{\text{res}}/(n-p)},\qquad \eta^2_p=\frac{SS^{\text{III}}_{\text{term}}}{SS^{\text{III}}_{\text{term}}+SS_{\text{res}}},\qquad f=\sqrt{\frac{\eta^2_p}{1-\eta^2_p}} $$ $$ \eta^2_{p,\text{low}}=\frac{\lambda_L}{\lambda_L+df_2},\quad \eta^2_{p,\text{high}}=\frac{\lambda_U}{\lambda_U+df_2},\qquad P\bigl(F'_{df_1,df_2,\lambda_L}\le F_{\text{obs}}\bigr)=0.975,\quad P\bigl(F'_{df_1,df_2,\lambda_U}\le F_{\text{obs}}\bigr)=0.025 $$
Assumption checks
$$ \text{slopes (each continuous covariate } c\text{):}\quad F=\frac{(RSS_0-RSS_1)/(k-1)}{RSS_1/(n-p-k+1)},\qquad \text{model 1 = model 0 (the reported ANCOVA)} + \text{group}\times c $$ $$ \text{Levene (median):}\quad z_{ij}=\lvert y_{ij}-\tilde{y}_i\rvert,\qquad W=\frac{N-k}{k-1}\cdot\frac{\sum_i n_i(\bar{z}_{i\cdot}-\bar{z}_{\cdot\cdot})^2}{\sum_i\sum_j(z_{ij}-\bar{z}_{i\cdot})^2}\ \sim F(k-1,\,N-k) $$
Variance of the coefficients: classical, or HC3 when an assumption check fails
$$ V=(X^{\top}X)^{-1}\hat{\sigma}^2\ \ \text{(classical)},\qquad V_{\text{HC3}}=(X^{\top}X)^{-1}X^{\top}\operatorname{diag}\!\Bigl(\frac{e_j^2}{(1-h_{jj})^2}\Bigr)X(X^{\top}X)^{-1} $$
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

R script แพ็กเกจ 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))
Expected R output (R 4.3.3, abridged)
# 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
DAPH Tab 2 > Continuous > ANCOVA · ตัวแปรตาม = Quality of Life Score (Post) · ตัวแปรกลุ่ม = Treatment Group · ตัวแปรร่วม / ค่าก่อนเริ่ม = Quality of Life Score (Pre), Age (years), Gender · ค่าจากผลลัพธ์ Tab 3 และรายงาน WordTab 2 > Continuous > ANCOVA · Dep. variable = Quality of Life Score (Post) · Group variable = Treatment Group · Covariates / Baseline = Quality of Life Score (Pre), Age (years), Gender · values from the Tab 3 result and the Word report
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
Equal slopes, Quality of Life Score (Pre): F · df · p0.0442 · 1, 1294 · 0.83340.0442 · 1, 1294 · 0.8334< 5e−5✓ PASS
Equal slopes, Age: F · df · p0.0371 · 1, 1294 · 0.84730.0371 · 1, 1294 · 0.8473< 5e−5✓ PASS
Levene (median), outcome by group: F · p4.2336 · 0.039834.2336 · 0.03983< 5e−5✓ PASS
Shapiro-Wilk W (residuals)0.0508690.0509< 5e−5✓ PASS
Group (Type III): F(1, 1295) · p0.1403 · 0.70810.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% CI75.85059 · 0.01335416 · 75.82439 to 75.8767875.85059 · 0.01335416 · 75.82439 to 75.87678< 1e−5✓ PASS
Adjusted mean APD · SE (HC3) · 95% CI75.86027 · 0.02235657 · 75.81641 to 75.9041375.86027 · 0.02235657 · 75.81641 to 75.90413< 1e−5✓ PASS
APD − CAPD: adjusted difference · 95% CI (HC3) · p0.00968649 · −0.04161786 to 0.06099083 · 0.71110.00968649 · −0.04161786 to 0.06099083 · 0.7111< 1e−8✓ PASS
Cohen's d (difference / √MSE)0.02081960.0208196< 1e−7✓ PASS
Quality of Life Score (Pre): B · SE (HC3)0.99974730 · 0.000233500.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.0190.9993 · 1.018, 1.018, 1.002 · 0.2555 · 34.019< 5e−4✓ PASS
AIC (Word model note)1706.811704.812.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.

ผลในข้อมูล DAPH: ความชันของคุณภาพชีวิตก่อนการรักษาและของอายุไม่ต่างกันระหว่างกลุ่ม (p = 0.833 และ 0.847) · Levene ของคุณภาพชีวิตหลังการรักษาได้ F = 4.23, p = 0.040 DAPH จึงใช้ HC3 (Levene ของส่วนเหลือได้ p = 0.890) · Shapiro-Wilk ของส่วนเหลือ W = 0.051, p < 0.001 เพราะเกือบทุกคนมีคะแนนหลังการรักษาสูงกว่าก่อนการรักษาประมาณ 7.5 คะแนน ส่วนเหลือจึงกองอยู่ที่ค่าเดียว มีเพียง 7 รายที่ห่างมาก (studentized residual สูงสุด 34.02) แต่ Cook's distance สูงสุดเพียง 0.256 และทุกกลุ่มมีมากกว่า 30 ราย · ค่าเฉลี่ยปรับ CAPD 75.85 (SE 0.013, 95% CI 75.82 ถึง 75.88) APD 75.86 (SE 0.022, 95% CI 75.82 ถึง 75.90) ผลต่าง 0.01 (95% CI −0.04 ถึง 0.06), F(1, 1295) = 0.14, p = 0.708, partial η² = 0.0001 (95% CI 0.000 ถึง 0.004), Cohen's d = 0.02 · คุณภาพชีวิตก่อนการรักษาสัมพันธ์กับหลังการรักษาเกือบหนึ่งต่อหนึ่ง (B = 1.000, R² = 0.999) · สรุป: ความต่างดิบหลังการรักษา (1.96 คะแนน) เกือบเท่ากับความต่างที่มีอยู่ก่อนการรักษา (1.95 คะแนน) เมื่อปรับแล้วไม่พบหลักฐานว่าคุณภาพชีวิตหลังการรักษาของ APD ต่างจาก CAPD และช่วงเชื่อมั่นบอกว่าความต่างที่ข้อมูลยังเข้ากันได้มีไม่เกินประมาณ 0.06 คะแนน · ประโยคแบบวารสาร: "หลังปรับคุณภาพชีวิตก่อนการรักษา อายุ และเพศ คุณภาพชีวิตหลังการรักษาไม่ต่างกันระหว่าง APD กับ CAPD (ค่าเฉลี่ยปรับ 75.86 เทียบ 75.85; ผลต่าง 0.01, 95% CI −0.04 ถึง 0.06; F(1, 1295) = 0.14, p = 0.708)" · เป็นข้อมูลเชิงสังเกต ผลนี้เป็นความสัมพันธ์ที่ปรับแล้ว ไม่ใช่ผลของวิธีล้างไต
Result in the DAPH data: the slopes of baseline quality of life and of age did not differ between groups (p = 0.833 and 0.847). Levene's test of post-treatment quality of life gave F = 4.23, p = 0.040, so DAPH used HC3 (Levene's test of the residuals gives p = 0.890). Shapiro-Wilk on the residuals gave W = 0.051, p < 0.001: almost every patient scored about 7.5 points higher after treatment than before, so the residuals pile up at one value and only 7 patients lie far away (largest studentised residual 34.02); the largest Cook's distance is only 0.256 and every group has more than 30 patients. Adjusted means: CAPD 75.85 (SE 0.013, 95% CI 75.82 to 75.88), APD 75.86 (SE 0.022, 95% CI 75.82 to 75.90); difference 0.01 (95% CI −0.04 to 0.06), F(1, 1295) = 0.14, p = 0.708, partial η² = 0.0001 (95% CI 0.000 to 0.004), Cohen's d = 0.02. Baseline quality of life tracks post-treatment quality of life almost one to one (B = 1.000, R² = 0.999). Conclusion: the raw post-treatment difference (1.96 points) is almost exactly the difference that already existed before treatment (1.95 points); after adjustment there is no evidence that post-treatment quality of life differs between APD and CAPD, and the interval shows that any difference compatible with the data is at most about 0.06 points. Journal sentence: "After adjustment for baseline quality of life, age and sex, post-treatment quality of life did not differ between APD and CAPD (adjusted means 75.86 vs 75.85; difference 0.01, 95% CI −0.04 to 0.06; F(1, 1295) = 0.14, p = 0.708)." The data are observational, so this is an adjusted association, not an effect of the dialysis mode.
📖 References
  1. 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
  2. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
  3. Fisher, R. A. (1932). Statistical methods for research workers (4th ed.). Oliver & Boyd.
  4. Levene, H. (1960). Robust tests for equality of variances. In I. Olkin (Ed.), Contributions to probability and statistics (pp. 278–292). Stanford University Press.
  5. 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
  6. Searle, S. R. (1971). Linear models. Wiley.
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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.

ตัวอย่างในข้อมูล DAPH: คุณภาพชีวิต (Quality of Life Score) ของผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย วัด 3 ครั้ง ก่อน (qolscore1) ระหว่าง (qolscore2) และหลังการรักษา (qolscore3) · คำถาม (ก) คุณภาพชีวิตเปลี่ยนตามเวลาหรือไม่ และเปลี่ยนในช่วงใด (ข) การเปลี่ยนแปลงต่างกันระหว่าง CAPD (Continuous Ambulatory PD) กับ APD (Automated PD) หรือไม่ (ตัวแปรกลุ่ม Treatment Group) และ (ค) ตัวอย่างสามกลุ่ม: รายได้ส่วนตัว (Personal Income) เพื่อแสดงการเปรียบเทียบทุกคู่ของกลุ่ม
Example in the DAPH data: quality of life (Quality of Life Score) of 1,300 peritoneal-dialysis patients measured three times, before (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

F tests (Type III; the matrix of N people × T time points, people with every time point only)
$$ F_{\text{time}}=\frac{SS_{\text{time}}/(T-1)}{SS_{\text{time}\times\text{subj}}/\bigl((T-1)(N-G)\bigr)},\qquad F_{\text{group}}=\frac{SS_{\text{group}}/(G-1)}{SS_{\text{subj(group)}}/(N-G)},\qquad F_{\text{time}\times\text{group}}=\frac{SS_{\text{time}\times\text{group}}/\bigl((G-1)(T-1)\bigr)}{SS_{\text{time}\times\text{subj}}/\bigl((T-1)(N-G)\bigr)} $$
Mauchly's sphericity test, on the covariance of the orthonormal contrasts of the time points
$$ W=\frac{\lvert\hat{\Sigma}\rvert}{\bigl(\operatorname{tr}\hat{\Sigma}/q\bigr)^{q}},\qquad \chi^2=-d_e\,\rho\,\ln W,\qquad \rho=1-\frac{2q^2+q+2}{6\,q\,d_e},\qquad f=\frac{q(q+1)}{2}-1,\qquad q=T-1,\ d_e=N-G $$ $$ p=P(\chi^2_f>\chi^2)+\omega_2\bigl[P(\chi^2_{f+4}>\chi^2)-P(\chi^2_f>\chi^2)\bigr],\qquad \omega_2=\frac{(q+2)(q-1)(q-2)(2q^3+6q^2+3T+2)}{288\,(d_e\,q\,\rho)^2} $$
Sphericity corrections: Greenhouse-Geisser, and Huynh-Feldt with Lecoutre's correction
$$ \hat{\varepsilon}=\frac{(\operatorname{tr}\hat{\Sigma})^2}{q\,\operatorname{tr}(\hat{\Sigma}^2)},\qquad \tilde{\varepsilon}=\min\!\Bigl(1,\ \frac{(d_e+1)\,q\,\hat{\varepsilon}-2}{q\,(d_e-q\,\hat{\varepsilon})}\Bigr),\qquad df^{*}=\varepsilon\,df,\qquad p^{*}=P\bigl(F_{\varepsilon\,df_1,\ \varepsilon\,df_2}>F_{\text{obs}}\bigr) $$
Effect size: partial η² and its 95% CI (Steiger, 2004), from the df that are reported
$$ \eta^2_p=\frac{SS_{\text{effect}}}{SS_{\text{effect}}+SS_{\text{error}}},\qquad \eta^2_{p,\text{low}}=\frac{\lambda_L}{\lambda_L+df_2},\quad \eta^2_{p,\text{high}}=\frac{\lambda_U}{\lambda_U+df_2},\quad P\bigl(F'_{df_1,df_2,\lambda_L}\le F_{\text{obs}}\bigr)=0.975,\ P\bigl(F'_{df_1,df_2,\lambda_U}\le F_{\text{obs}}\bigr)=0.025 $$
Means at each time point (in each group), and the group difference averaged over time
$$ \bar{y}_t\pm t_{0.975,\,n_t-1}\,\frac{s_t}{\sqrt{n_t}};\qquad \bar{m}_b-\bar{m}_a\pm t_{1-\alpha^{*}/2,\,N-G}\sqrt{MSE_m\Bigl(\frac{1}{n_a}+\frac{1}{n_b}\Bigr)},\qquad m_s=\frac{1}{T}\sum_t y_{st} $$
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.

Post hoc: paired t-test for each pair of time points a, b
$$ d_s=y_{sb}-y_{sa},\qquad t_{ab}=\frac{\bar{d}}{s_d/\sqrt{n_{ab}}},\qquad df=n_{ab}-1,\qquad p_{ab}=2\,P\bigl(T_{df}\ge\lvert t_{ab}\rvert\bigr),\qquad d_z=\frac{\bar{d}}{s_d} $$
Adjustment across the m = T(T − 1)/2 pairs, and the matching 95% CI
$$ p^{\text{Holm}}_{(r)}=\max_{s\le r}\ \min\bigl(1,\ (m-s+1)\,p_{(s)}\bigr)\ \ \text{(automatic)},\qquad p^{\text{Bonf}}=\min(1,\ m\,p),\qquad p^{\text{\v{S}id\'{a}k}}=1-(1-p)^m $$ $$ \text{CI}_{95\%}=\bar{d}\pm t_{1-\alpha^{*}/2,\,n_{ab}-1}\,\frac{s_d}{\sqrt{n_{ab}}},\qquad \alpha^{*}=\alpha/m\ \ \text{(Holm, Bonferroni)},\quad 1-(1-\alpha)^{1/m}\ \ \text{(\v{S}id\'{a}k)},\quad \alpha\ \ \text{(no adjustment)} $$
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

R script แพ็กเกจ 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)
Expected R output (R 4.3.3, abridged)
## 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
DAPH Tab 2 > Continuous > Repeated Measures ANOVA · รูปแบบข้อมูล = Wide format · Subject ID = id · ตัวแปรตามที่วัดซ้ำ = qolscore1, qolscore2, qolscore3 · ตัวแปรกลุ่ม: ไม่เลือก (A), group (B), income (C) · Post Hoc ติ๊ก อัตโนมัติ (แนะนำ) และ Šidák / ไม่ปรับค่า p สำหรับแถวช่วงเชื่อมั่น · ค่าจาก Tab 3 รายงาน Word และค่าภายใน engineTab 2 > Continuous > Repeated Measures ANOVA · Data Format = Wide format · Subject ID = id · Repeated measure variables = qolscore1, qolscore2, qolscore3 · Group Variable: none (A), group (B), income (C) · Post Hoc ticked, Automatic (recommended), and Šidák / No adjustment for the CI row · values from Tab 3, the Word report and the engine
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
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) · p0.591249 · 682.121 · 7.57e−1490.591249 · 682.121 · 7.57e−149< 1e−6✓ PASS
A · ε GG · ε HF · GG-corrected df0.709849 · 0.710402 · 1.42, 1844.190.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.334868.3638 / 73.8619 / 75.8554 · 0.4949 · 67.3929 to 69.3348< 1e−7✓ PASS
A · Mid − Pre · 95% CI (Bonferroni level) · dz5.4981 · 5.4717 to 5.5245 · 13.8495.4981 · 5.4717 to 5.5245 · 13.849< 1e−7✓ PASS
A · Post − Pre · 95% CI · dz7.4915 · 7.4606 to 7.5224 · 16.1247.4915 · 7.4606 to 7.5224 · 16.124< 1e−7✓ PASS
A · Post − Mid · 95% CI · dz1.9935 · 1.9774 to 2.0095 · 8.2581.9935 · 1.9774 to 2.0095 · 8.258< 1e−7✓ PASS
A · Holm-adjusted p, all three pairs0 (too small to print)< 0.001—✓ PASS
A · Mid − Pre 95% CI with Šidák / with no adjustment5.471751 to 5.524402 / 5.476475 to 5.5196785.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.74130.1996 · 0.8191 · 0.7411 · 0.7413< 1e−6✓ PASS
B · Mauchly W · χ²(2) · ε GG · ε HF0.590991 · 682.163 · 0.709719 · 0.7102720.590991 · 682.163 · 0.709719 · 0.710272< 1e−6✓ PASS
B · APD − CAPD averaged over time (95% CI) · t1.9486 (0.0088 to 3.8884) · 1.97071.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.14441.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.7407.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.01596.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)."

ผลในข้อมูล DAPH (B, สองกลุ่ม): Word เขียนว่า "การทดสอบของ Mauchly (Mauchly, 1940) พบว่าละเมิดข้อตกลง sphericity W = 0.5910, χ²(2) = 682.163, p < 0.001 และ ε = 0.710 ต่ำกว่า 0.75 จึงรายงานผลภายในผู้ถูกวัดด้วยการแก้แบบ Greenhouse-Geisser (Greenhouse & Geisser, 1959; Girden, 1992)" · เวลา: F(1.42, 1842.43) = 271781.080, p < 0.001, partial η² = 0.995 (95% CI 0.995 ถึง 0.996) คุณภาพชีวิตเพิ่มจาก 68.36 (ก่อน) เป็น 73.86 (ระหว่าง) และ 75.86 (หลังการรักษา) และ post hoc (A, Holm) พบว่าทุกคู่ต่างกัน (p < 0.001): ระหว่างลบก่อน 5.50 (95% CI 5.47 ถึง 5.52) หลังลบก่อน 7.49 (7.46 ถึง 7.52) หลังลบระหว่าง 1.99 (1.98 ถึง 2.01) · ปฏิสัมพันธ์เวลา × กลุ่ม: F(1.42, 1842.43) = 0.200, p = 0.741, partial η² = 0.0002 (95% CI 0.000 ถึง 0.003) ไม่พบหลักฐานว่าการเปลี่ยนแปลงต่างกันระหว่าง CAPD กับ APD (ไม่ได้พิสูจน์ว่าเท่ากัน) · กลุ่ม: F(1, 1298) = 3.884, p = 0.049, partial η² = 0.003 (95% CI 0.000 ถึง 0.012) เมื่อเฉลี่ยทุกช่วงเวลา APD สูงกว่า CAPD 1.95 คะแนน (95% CI 0.01 ถึง 3.89) แต่เมื่อดูทีละช่วงเวลาและปรับแบบ Bonferroni ไม่มีช่วงใดต่างอย่างมีนัยสำคัญ (p = 0.148, 0.149, 0.144; Hedges' g ประมาณ 0.11) ความต่างนี้เล็กและมีอยู่ตั้งแต่ก่อนการรักษา จึงบอกว่าผู้ป่วยที่ได้ APD มีคุณภาพชีวิตสูงกว่าอยู่แล้ว ไม่ได้บอกว่า APD ทำให้คุณภาพชีวิตดีขึ้น · (C) ปฏิสัมพันธ์เวลา × รายได้มีนัยสำคัญ (p = 0.016 หลังแก้ Greenhouse-Geisser) จึงควรอ่านผลแยกตามกลุ่มรายได้ · หมายเหตุข้อมูล: การเปลี่ยนแปลงของแต่ละคนแทบเท่ากันทุกคน (เช่น ทุกคนในกลุ่ม CAPD เพิ่ม 5.5 คะแนนพอดีจากก่อนถึงช่วงกลาง) ค่า F และ dz จึงสูงมาก ข้อมูลจริงมักกระจายกว่านี้ · ประโยคแบบวารสาร: "คุณภาพชีวิตเพิ่มขึ้นตามเวลา (F(1.42, 1842.43) = 271781.08, p < 0.001, แก้แบบ Greenhouse-Geisser) และการเปลี่ยนแปลงไม่ต่างกันระหว่าง CAPD กับ APD (ปฏิสัมพันธ์ F(1.42, 1842.43) = 0.20, p = 0.741)"
Result in the DAPH data (B, two groups): the Word report reads "Mauchly's test indicated that sphericity was violated (Mauchly, 1940), W = 0.5910, χ²(2) = 682.163, p < 0.001; because ε = 0.710 was below 0.75, the within-subject effects are reported with the Greenhouse-Geisser correction (Greenhouse & Geisser, 1959; Girden, 1992)". Time: F(1.42, 1842.43) = 271781.080, p < 0.001, partial η² = 0.995 (95% CI 0.995 to 0.996); quality of life rose from 68.36 (before) to 73.86 (during) and 75.86 (after treatment), and the post hoc tests (A, Holm) found every pair different (p < 0.001): during minus before 5.50 (95% CI 5.47 to 5.52), after minus before 7.49 (7.46 to 7.52), after minus during 1.99 (1.98 to 2.01). Time × group interaction: F(1.42, 1842.43) = 0.200, p = 0.741, partial η² = 0.0002 (95% CI 0.000 to 0.003): no evidence that the change differed between CAPD and APD (which does not prove it was the same). Group: F(1, 1298) = 3.884, p = 0.049, partial η² = 0.003 (95% CI 0.000 to 0.012); averaged over time APD scored 1.95 points higher than CAPD (95% CI 0.01 to 3.89), but at each time point separately, with Bonferroni adjustment, no difference was significant (p = 0.148, 0.149, 0.144; Hedges' g about 0.11). The difference is small and was already present before treatment, so it says that the patients on APD already had higher quality of life, not that APD improved it. (C) The time × income interaction is significant (p = 0.016 after the Greenhouse-Geisser correction), so the results should be read by income group. A note on the data: the change is almost identical for everyone (for example every CAPD patient gained exactly 5.5 points from before to during treatment), which is why F and dz are so large; real data are usually more spread. Journal sentence: "Quality of life increased over time (F(1.42, 1842.43) = 271781.08, p < 0.001, Greenhouse-Geisser corrected), and the change did not differ between CAPD and APD (interaction F(1.42, 1842.43) = 0.20, p = 0.741)."
📖 References
  1. Dunn, O. J. (1961). Multiple comparisons among means. Journal of the American Statistical Association, 56(293), 52–64. doi:10.1080/01621459.1961.10482090
  2. Girden, E. R. (1992). ANOVA: Repeated measures. Sage.
  3. Greenhouse, S. W., & Geisser, S. (1959). On methods in the analysis of profile data. Psychometrika, 24(2), 95–112. doi:10.1007/BF02289823
  4. 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
  5. Holm, S. (1979). A simple sequentially rejective multiple test procedure. Scandinavian Journal of Statistics, 6(2), 65–70.
  6. 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
  7. 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
  8. 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
  9. Maxwell, S. E. (1980). Pairwise multiple comparisons in repeated measures designs. Journal of Educational Statistics, 5(3), 269–287. doi:10.3102/10769986005003269
  10. Š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
  11. 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
  12. 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.

ตัวอย่างในข้อมูล DAPH: คุณภาพชีวิต (Quality of Life Score) ของผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย วัดก่อน (qolscore1) ระหว่าง (qolscore2) และหลังการรักษา (qolscore3) · คำถาม: เมื่อเฉลี่ยทั้งสามช่วงเวลา คุณภาพชีวิตของกลุ่ม APD (Automated PD) ต่างจาก CAPD (Continuous Ambulatory PD) เท่าไร (ตัวแปรกลุ่ม Treatment Group) และเมื่อปรับอายุ (age) และเพศ (gender) แล้วต่างกันเท่าไร
Example in the DAPH data: quality of life (Quality of Life Score) of 1,300 peritoneal-dialysis patients measured before (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

Mean model that DAPH fits (Gaussian family, identity link)
$$ E(y_{it})=\beta_0+\sum_{g=2}^{G}\tau_g\,\text{Group}_{gi}+\sum_{t=2}^{T}\gamma_t\,\text{Time}_{t}+\sum_c\delta_c\,x_{ci} $$
Estimating equations with an exchangeable working correlation
$$ \sum_{i=1}^{K}X_i^{\top}V_i^{-1}\bigl(y_i-X_i\beta\bigr)=0,\qquad V_i=\phi\,R_i(\alpha),\qquad R_i(\alpha)_{tt'}=\begin{cases}1 & t=t'\\ \alpha & t\neq t'\end{cases} $$ $$ \hat{\phi}=\frac{\sum_i\sum_t e_{it}^2}{N-p},\qquad \hat{\alpha}=\frac{\sum_i\sum_{t<t'}e_{it}\,e_{it'}}{\hat{\phi}\,(M-p)},\qquad M=\sum_i\frac{n_i(n_i-1)}{2},\qquad e_{it}=y_{it}-\hat{\mu}_{it} $$
Sandwich (robust) variance, 95% CI and test
$$ \widehat{\mathrm{Var}}(\hat{\beta})=A^{-1}BA^{-1},\qquad A=\sum_i X_i^{\top}V_i^{-1}X_i,\qquad B=\sum_i X_i^{\top}V_i^{-1}e_i\,e_i^{\top}V_i^{-1}X_i $$ $$ \hat{\tau}_g\pm z_{0.975}\,SE(\hat{\tau}_g),\qquad z=\frac{\hat{\tau}_g}{SE(\hat{\tau}_g)},\qquad p=2\bigl\{1-\Phi(\lvert z\rvert)\bigr\}\quad(\text{Wald }\chi^2_1=z^2) $$
τ_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

R script แพ็กเกจ 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)
Expected R output (R 4.3.3, geepack 1.3.10)
# 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
DAPH Tab 2 > Continuous > GEE (Repeated Measures) · รูปแบบข้อมูล = Wide format · Subject ID = id · ตัวแปรกลุ่ม = group · ตัวแปรตามที่วัดซ้ำ = qolscore1, qolscore2, qolscore3 · Covariates: ไม่เลือก; age, gender; bmi_group · ค่าจาก Tab 3 รายงาน Word และค่าภายใน engineTab 2 > Continuous > GEE (Repeated Measures) · Data Format = Wide format · Subject ID = id · Group Variable = group · Repeated measure variables = qolscore1, qolscore2, qolscore3 · Covariates: none; age, gender; bmi_group · values from Tab 3, the Word report and the engine
ค่าที่ตรวจQuantityR (geepack)DAPHความต่างDifferenceStatus
Pre: Mean (SD) CAPD · APD67.40 (17.37) · 69.35 (18.28)67.40 (17.37) · 69.35 (18.28)< 0.005✓ PASS
Adj. Mean diff. APD − CAPD · robust SE1.9486142 · 0.98849001.9486142 · 0.9884900< 1e−9✓ PASS
95% CI · p0.0112094 to 3.8860189 · 0.04868910.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.99977340.9997734< 1e−9✓ PASS
With age and gender: Adj. Mean diff. (95% CI) · p1.7893510 (−0.1311351 to 3.7098371) · 0.06783021.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) · p1.9257738 (−0.0083089 to 3.8598566) · 0.05099241.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().

ผลในข้อมูล DAPH: เมื่อเฉลี่ยทั้งสามช่วงเวลาและปรับช่วงเวลา APD มีคุณภาพชีวิตสูงกว่า CAPD 1.95 คะแนน (95% CI 0.01 ถึง 3.89, p = 0.049) เท่ากับผลต่างของค่าเฉลี่ยรายคนใน RM-ANOVA (หัวข้อ 1.5 ส่วน B) เพราะข้อมูลครบทุกคนทุกช่วงเวลา · α = 0.9998 คือคะแนนสามครั้งของคนเดียวกันแทบเท่ากันหลังหักผลของเวลา ข้อมูลจึงมีข้อมูลเกี่ยวกับความต่างระหว่างกลุ่มเกือบเท่ากับการวัดครั้งเดียวต่อคน (SE 0.99 ขณะที่ SE ของผลของเวลาเพียง 0.011) · เมื่อปรับอายุและเพศ ผลต่างเหลือ 1.79 คะแนน (95% CI −0.13 ถึง 3.71, p = 0.068) ไม่มีนัยสำคัญ ข้อมูลยังเข้ากันได้ทั้งกับการไม่มีความต่างและความต่างได้ถึง 3.71 คะแนน · ประโยคแบบวารสาร: "เมื่อวิเคราะห์ด้วย GEE (working correlation แบบ exchangeable, robust SE) และปรับช่วงเวลา อายุ และเพศ คุณภาพชีวิตเฉลี่ยของผู้ป่วย APD ไม่ต่างจาก CAPD อย่างมีนัยสำคัญ (ผลต่าง 1.79, 95% CI −0.13 ถึง 3.71, p = 0.068)" · เป็นข้อมูลเชิงสังเกต จึงเป็นความสัมพันธ์ ไม่ใช่ผลของวิธีล้างไต
Result in the DAPH data: averaged over the three time points and adjusted for time, APD scored 1.95 points higher than CAPD (95% CI 0.01 to 3.89, p = 0.049), the same difference of person means as in RM-ANOVA (section 1.5, part B), because every person has every time point. α = 0.9998: after the time effect, a person's three scores are almost identical, so the data carry about as much information on the group difference as one measurement per person (SE 0.99, against 0.011 for the time effects). Adjusted for age and sex, the difference is 1.79 points (95% CI −0.13 to 3.71, p = 0.068), not significant: the data are compatible with no difference and with a difference of up to 3.71 points. Journal sentence: "In a GEE model (exchangeable working correlation, robust SE) adjusted for time, age and sex, mean quality of life did not differ significantly between APD and CAPD patients (difference 1.79, 95% CI −0.13 to 3.71, p = 0.068)." The data are observational, so this is an association, not an effect of the dialysis mode.
📖 References
  1. 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
  2. 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
  3. 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
  4. Zeger, S. L., & Liang, K.-Y. (1986). Longitudinal data analysis for discrete and continuous outcomes. Biometrics, 42(1), 121–130. doi:10.2307/2531248
  5. 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).

ตัวอย่างในข้อมูล DAPH: คุณภาพชีวิตหลังการรักษา (Quality of Life Score (Post), qolscore3) ของผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย สัมพันธ์กับกลุ่มรักษา (Treatment Group: CAPD, APD) อายุ (age) และเพศ (gender) อย่างไร เมื่อผู้ป่วยซ้อนอยู่ใน 10 อำเภอ (District, amp; 55 ถึง 264 รายต่ออำเภอ) · ใช้อำเภอเป็นค่าคงที่สุ่ม เพราะผู้ป่วยในอำเภอเดียวกันได้รับบริการและสภาพแวดล้อมคล้ายกัน
Example in the DAPH data: how is quality of life after treatment (Quality of Life Score (Post), 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

Random-intercept model (patient i in cluster j)
$$ y_{ij}=x_{ij}^{\top}\beta+u_j+\varepsilon_{ij},\qquad u_j\sim\mathcal{N}(0,\tau^2),\qquad \varepsilon_{ij}\sim\mathcal{N}(0,\sigma^2),\qquad V_j=\sigma^2 I_{n_j}+\tau^2 J_{n_j} $$
REML (restricted maximum likelihood) for τ² and σ², then generalised least squares for β
$$ \ell_{\text{REML}}(\tau^2,\sigma^2)=-\tfrac{1}{2}\Bigl[\sum_j\log\lvert V_j\rvert+\log\Bigl\lvert\sum_j X_j^{\top}V_j^{-1}X_j\Bigr\rvert+\sum_j(y_j-X_j\hat{\beta})^{\top}V_j^{-1}(y_j-X_j\hat{\beta})\Bigr]+\text{const} $$ $$ \hat{\beta}=\Bigl(\sum_j X_j^{\top}\hat{V}_j^{-1}X_j\Bigr)^{-1}\sum_j X_j^{\top}\hat{V}_j^{-1}y_j,\qquad \widehat{\mathrm{Var}}(\hat{\beta})=\Bigl(\sum_j X_j^{\top}\hat{V}_j^{-1}X_j\Bigr)^{-1} $$
Wald tests and 95% CI (normal distribution), ICC, and information criteria from an ML refit
$$ z=\frac{\hat{\beta}_k}{SE_k},\qquad p=2\bigl\{1-\Phi(\lvert z\rvert)\bigr\},\qquad \hat{\beta}_k\pm z_{0.975}\,SE_k;\qquad \chi^2_{L-1}=\hat{\beta}_L^{\top}\bigl[\widehat{\mathrm{Var}}(\hat{\beta}_L)\bigr]^{-1}\hat{\beta}_L\ \ \text{(variable with } L\ge 3\text{ levels)} $$ $$ \mathrm{ICC}=\frac{\hat{\tau}^2}{\hat{\tau}^2+\hat{\sigma}^2},\qquad \mathrm{AIC}=-2\ell_{\text{ML}}+2k,\qquad \mathrm{BIC}=-2\ell_{\text{ML}}+k\ln n,\qquad k=\text{number of fixed effects}+2 $$
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

R script แพ็กเกจ 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)
Expected R output (R 4.3.3, lme4 1.1-35.1)
# 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
DAPH Tab 2 > Continuous > ติ๊ก Mixed Effects Model > Mixed Effect Linear Regression · ตัวแปรตาม = Quality of Life Score (Post) · ตัวแปรอิสระ = Treatment Group, Age (years), Gender · Random Effect Variable = District (amp) · ค่าจาก Tab 3 รายงาน Word และค่าภายใน engineTab 2 > Continuous > tick Mixed Effects Model > Mixed Effect Linear Regression · Dependent = Quality of Life Score (Post) · Independent = Treatment Group, Age (years), Gender · Random Effect Variable = District (amp) · values from Tab 3, the Word report and the engine
ค่าที่ตรวจQuantityR (lme4)DAPHความต่างDifferenceStatus
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.060.0625 · 9.06< 1e−4✓ PASS
APD vs CAPD: estimate−0.5676−0.5676< 1e−4✓ PASS
APD vs CAPD: SE · 95% CI · p2.5920 · −5.648 to 4.513 · 0.8272.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.5311142.51 · 11173.53< 0.01✓ PASS
Mean (SD): CAPD · APD · Male · Female74.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()).

ผลในข้อมูล DAPH: ความแปรปรวนระหว่างอำเภอ τ² = 20.15 (SD 4.49) ภายในอำเภอ σ² = 302.13 (SD 17.38) ICC = 0.063 คือ 6.3% ของความแปรปรวนของคุณภาพชีวิตหลังการรักษาอยู่ระหว่างอำเภอ (Tab 3 จัดเป็นระดับต่ำ และแสดง design effect = 9.06 คือถ้าไม่คำนึงถึงอำเภอ SE ของค่าที่ต่างกันระหว่างอำเภออาจเล็กเกินจริงได้ถึงประมาณ 3 เท่า) · อายุ: อายุมากขึ้น 1 ปี คุณภาพชีวิตเฉลี่ยต่ำลง 0.300 คะแนน (95% CI −0.436 ถึง −0.165, p < 0.001) เมื่อเทียบผู้ป่วยในอำเภอเดียวกันที่กลุ่มรักษาและเพศเดียวกัน · เพศ: หญิงต่างจากชาย −0.258 (95% CI −2.258 ถึง 1.743, p = 0.801) · กลุ่มรักษา: APD ต่างจาก CAPD −0.568 (95% CI −5.648 ถึง 4.513, p = 0.827) ไม่พบหลักฐานว่าต่างกัน ทั้งที่ค่าเฉลี่ยดิบ APD สูงกว่า (76.84 เทียบ 74.89) · ช่วงเชื่อมั่นกว้างเพราะสัดส่วนผู้ป่วย APD ในแต่ละอำเภอมีตั้งแต่ 0 ถึง 1 (บางอำเภอมีแต่ CAPD บางอำเภอมีแต่ APD) กลุ่มรักษาจึงปนกับอำเภอ และ df แบบ Satterthwaite ของกลุ่มรักษาเหลือเพียง 17.3 (p = 0.829) ข้อสรุปไม่เปลี่ยน · AIC = 11142.51 (ML) · ประโยคแบบวารสาร: "ในแบบจำลองเชิงเส้นผสมที่มีค่าคงที่สุ่มของอำเภอ (10 อำเภอ, ICC = 0.063) อายุที่มากขึ้นสัมพันธ์กับคุณภาพชีวิตหลังการรักษาที่ต่ำลง (B = −0.30 ต่อปี, 95% CI −0.44 ถึง −0.16) ส่วนกลุ่มรักษาไม่สัมพันธ์อย่างมีนัยสำคัญ (B = −0.57, 95% CI −5.65 ถึง 4.51)" · เป็นข้อมูลเชิงสังเกต จึงเป็นความสัมพันธ์ ไม่ใช่ผลเชิงเหตุ
Result in the DAPH data: between-district variance τ² = 20.15 (SD 4.49), within-district σ² = 302.13 (SD 17.38), ICC = 0.063: 6.3% of the variance of post-treatment quality of life lies between districts (Tab 3 rates it low and adds a design effect of 9.06: ignoring the districts could understate the SE of an estimate that varies between districts by up to about 3 times). Age: each additional year is associated with a 0.300-point lower mean quality of life (95% CI −0.436 to −0.165, p < 0.001), comparing patients in the same district with the same treatment group and sex. Sex: women versus men −0.258 (95% CI −2.258 to 1.743, p = 0.801). Treatment group: APD versus CAPD −0.568 (95% CI −5.648 to 4.513, p = 0.827): no evidence of a difference, although the raw mean of APD is higher (76.84 against 74.89). The interval is wide because the share of APD patients ranges from 0 to 1 across districts (some districts treat only CAPD, others only APD), so treatment group is entangled with district, and the Satterthwaite df for treatment group is only 17.3 (p = 0.829); the conclusion does not change. AIC = 11142.51 (ML). Journal sentence: "In a linear mixed model with a random intercept for district (10 districts, ICC = 0.063), older age was associated with lower post-treatment quality of life (B = −0.30 per year, 95% CI −0.44 to −0.16), while treatment group was not significantly associated with it (B = −0.57, 95% CI −5.65 to 4.51)." The data are observational, so these are associations, not causal effects.
📖 References
  1. 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
  2. Laird, N. M., & Ware, J. H. (1982). Random-effects models for longitudinal data. Biometrics, 38(4), 963–974. doi:10.2307/2529876
  3. 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.

ผู้ป่วยล้างไตทางช่องท้อง 1,300 คนในข้อมูลตัวอย่าง: ผู้ป่วยที่อายุมากกว่ามีคะแนนคุณภาพชีวิตหลังการรักษา (Quality of Life Score (Post), 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)
The 1,300 peritoneal-dialysis patients in the example data: do older patients have a lower post-treatment quality-of-life score (Quality of Life Score (Post), 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

Pearson's r
$$ r = \frac{\sum_{i=1}^{n}(x_i-\bar{x})(y_i-\bar{y})}{\sqrt{\sum_{i=1}^{n}(x_i-\bar{x})^2\,\sum_{i=1}^{n}(y_i-\bar{y})^2}} $$
Spearman's ρ = Pearson's r on the ranks
$$ \rho = r\bigl(R(x),\,R(y)\bigr) \qquad\text{shortcut, valid only without ties: }\ \rho = 1-\frac{6\sum_{i} d_i^{2}}{n(n^{2}-1)},\quad d_i = R(x_i)-R(y_i) $$
Test of H₀: no correlation (two-sided)
$$ t = \frac{r\sqrt{n-2}}{\sqrt{1-r^{2}}},\qquad df = n-2,\qquad p = 2\,P\bigl(T_{n-2} > |t|\bigr) $$
95% CI: Fisher's z transformation
$$ z = \tfrac{1}{2}\ln\frac{1+r}{1-r},\qquad SE_z = \frac{1}{\sqrt{n-3}},\qquad 95\%\ \text{CI} = \tanh\bigl(z - 1.96\,SE_z\bigr)\ \text{to}\ \tanh\bigl(z + 1.96\,SE_z\bigr) $$
Column R² of the DAPH table
$$ R^{2} = r^{2}\quad(\text{for Spearman: } \rho^{2},\ \text{the share of variation in the ranks}) $$
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

R script R base (แพ็กเกจ stats) เท่านั้นbase R only (package 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")

# 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)
Expected R output (R 4.3.3)
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
DAPH Tab 2 → Continuous → Correlation coefficient, Dependent = Quality of Life Score (Post), Independent = Age (years), Body Mass Index (kg/m²) · แถว Pearson: Data Tools → Filter Data (hos = 4) ก่อนวิเคราะห์ · ค่า DAPH จากตารางผลและค่าที่ engine คำนวณTab 2 → Continuous → Correlation coefficient, Dependent = Quality of Life Score (Post), Independent = Age (years), Body Mass Index (kg/m²) · Pearson rows: Data Tools → Filter Data (hos = 4) first · DAPH values from the results table and the engine's own values
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
Shapiro-Wilk of Quality of Life Score (Post): W / p → method0.97559 / 5.012e−14 → Spearman0.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: p1.338e−051.338e−05 (table <0.001)< 1e−15✓ PASS
BMI: Spearman ρ / R² / 95% CI0.0479 / 0.0023 / −0.0065 to 0.10200.0479 / 0.0023 / −0.0065 to 0.1020< 1e−12✓ PASS
BMI: p0.084470.084< 1e−12✓ PASS
hos = 4 (n = 94): Shapiro-Wilk p → method0.1996 → Pearson0.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 / p0.0456 / −0.1585 to 0.2459 / 0.662800.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.

ประโยครายงานผล: “อายุมีความสัมพันธ์ทางลบระดับอ่อนกับคะแนนคุณภาพชีวิตหลังการรักษา (Spearman's ρ = −0.12, 95% CI −0.17 ถึง −0.07, p < 0.001, n = 1,300) ส่วนดัชนีมวลกายไม่พบความสัมพันธ์ที่มีนัยสำคัญทางสถิติ (ρ = 0.05, 95% CI −0.006 ถึง 0.10, p = 0.084)” (ทศนิยมเท่ากับตารางในรายงาน Word ของ DAPH)
Results sentence: “Age was weakly and negatively correlated with the post-treatment quality-of-life score (Spearman's ρ = −0.12, 95% CI −0.17 to −0.07, p < 0.001, n = 1,300), whereas body mass index showed no statistically significant correlation (ρ = 0.05, 95% CI −0.006 to 0.10, p = 0.084).” (decimals as in DAPH's Word table)
📖 References
  1. 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
  2. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
  3. 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
  4. 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
  5. Spearman, C. (1904). The proof and measurement of association between two things. American Journal of Psychology, 15(1), 72–101. doi:10.2307/1412159
  6. 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).

คะแนนคุณภาพชีวิตหลังการรักษา (Quality of Life Score (Post), 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.0581
Does the post-treatment quality-of-life score (Quality of Life Score (Post), qolscore3) 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.

U statistic (DAPH reports U₁, the first group = lowest code)
$$ U_1 = R_1 - \frac{n_1(n_1+1)}{2},\qquad U_2 = n_1 n_2 - U_1 $$
Variance of U with tie correction
$$ \sigma_U^{2} = \frac{n_1 n_2}{12}\left[(N+1) - \frac{\sum_{j}(t_j^{3}-t_j)}{N(N-1)}\right],\qquad N = n_1 + n_2 $$
Z in the DAPH table (no continuity correction) and the p-value (with continuity correction)
$$ Z = \frac{U_1 - n_1 n_2/2}{\sigma_U},\qquad p = 2\,P\!\left(Z_0 > \frac{\lvert U_1 - n_1 n_2/2\rvert - 0.5}{\sigma_U}\right) $$
Effect size
$$ r = \frac{\lvert Z\rvert}{\sqrt{N}} $$
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

R script R base (แพ็กเกจ stats) เท่านั้นbase R only (package 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")
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))
Expected R output (R 4.3.3)
        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
DAPH Tab 2 → Continuous → Mann-Whitney U test, Dependent = Quality of Life Score (Post), Independent = Treatment Group · ค่าจากตารางผลและค่าที่ engine คำนวณTab 2 → Continuous → Mann-Whitney U test, Dependent = Quality of Life Score (Post), Independent = Treatment Group · values from the results table and the engine's own values
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
n: CAPD / APD656 / 644656 / 6440✓ PASS
Median (IQR): CAPD76.5 (64.5–86.5)76.50 (64.50-86.50)0✓ PASS
Median (IQR): APD78.5 (63.5–90.5)78.50 (63.50-90.50)0✓ PASS
Mean rank: CAPD / APD628.8849 / 672.5179628.88 / 672.52< 1e−9✓ PASS
U (= R's W)197052.5197052.50✓ PASS
Z (tie-corrected)−2.09552068−2.0955< 1e−12✓ PASS
p (normal approximation, tie and continuity corrections)0.036130.036< 1e−15✓ PASS
Effect size r0.058119290.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.

ประโยครายงานผล: “คะแนนคุณภาพชีวิตหลังการรักษาของกลุ่ม APD (มัธยฐาน 78.50, IQR 63.50–90.50) สูงกว่ากลุ่ม CAPD (มัธยฐาน 76.50, IQR 64.50–86.50) เล็กน้อยอย่างมีนัยสำคัญทางสถิติ (Mann-Whitney U = 197052.50, Z = −2.10, p = 0.036) แต่ขนาดผลน้อยมาก (r = 0.06)” (ทศนิยมเท่ากับตารางในรายงาน Word ของ DAPH)
Results sentence: “Post-treatment quality-of-life scores were slightly but significantly higher in the APD group (median 78.50, IQR 63.50–90.50) than in the CAPD group (median 76.50, IQR 64.50–86.50; Mann-Whitney U = 197052.50, Z = −2.10, p = 0.036), with a negligible effect size (r = 0.06).” (decimals as in DAPH's Word table)
📖 References
  1. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
  2. 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
  3. 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).

คะแนนคุณภาพชีวิตหลังการรักษา (Quality of Life Score (Post), 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 กับอีกสองกลุ่ม)
Does the post-treatment quality-of-life score (Quality of Life Score (Post), 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

H with the tie correction (the value DAPH reports)
$$ H = \frac{\dfrac{12}{N(N+1)}\sum_{k=1}^{K}\dfrac{R_k^{2}}{n_k} - 3(N+1)}{1 - \dfrac{\sum_{j}(t_j^{3}-t_j)}{N^{3}-N}},\qquad p = P\bigl(\chi^{2}_{K-1} > H\bigr) $$
Mean rank of group k (all groups ranked together, ties = average rank)
$$ \bar{R}_k = \frac{R_k}{n_k} $$
Effect size: eta-squared based on H (Tomczak & Tomczak, 2014)
$$ \eta^{2}_{H} = \frac{H - K + 1}{N - K} $$
Dunn's test for groups a and b (same joint ranks, tie-corrected)
$$ z_{ab} = \frac{\bar{R}_a - \bar{R}_b}{\sqrt{\left[\dfrac{N(N+1)}{12} - \dfrac{\sum_{j}(t_j^{3}-t_j)}{12(N-1)}\right]\left(\dfrac{1}{n_a} + \dfrac{1}{n_b}\right)}},\qquad p_{ab} = 2\,P\bigl(Z_0 > \lvert z_{ab}\rvert\bigr),\qquad r_{ab} = \frac{\lvert z_{ab}\rvert}{\sqrt{N}} $$
Adjusting the m = K(K − 1)/2 p-values
$$ p^{\text{Holm}}_{(i)} = \max_{s \le i}\ \min\bigl(1,\ (m-s+1)\,p_{(s)}\bigr),\qquad p^{\text{Bonf}} = \min(1,\ m\,p),\qquad p^{\text{Šidák}} = 1-(1-p)^{m} $$
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

R script R base (แพ็กเกจ stats) และ rstatix เพื่อตรวจไขว้base R (package stats), with rstatix as a cross-check
# 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")]
Expected R output (R 4.3.3)
     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
DAPH Tab 2 → Continuous → Kruskal-Wallis test, Dependent = Quality of Life Score (Post), Independent = Household Income, Post Hoc ติ๊กไว้ เลือกทีละตัวเลือก (อัตโนมัติ / Bonferroni / Šidák) · ค่าจากตารางผลและค่าที่ engine คำนวณTab 2 → Continuous → Kruskal-Wallis test, Dependent = Quality of Life Score (Post), Independent = Household Income, Post Hoc ticked, each option in turn (Automatic / Bonferroni / Šidák) · values from the results tables and the engine's own values
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
n per group380 / 338 / 582380 / 338 / 5820✓ PASS
Median (IQR) per group81.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 group730.3618 / 645.3121 / 601.3694730.36 / 645.31 / 601.37< 1e−9✓ PASS
H, df, p27.2371588, 2, 1.218e−06H(2) = 27.24, p <0.001 (engine 27.2371588, 1.218e−06)< 1e−12✓ PASS
η²H0.01945810.019< 1e−12✓ PASS
Automatic choiceDunn's test + HolmDunn's test with Holm adjustment—✓ PASS
Dunn's z (first − second)3.0305 / 5.2106 / 1.71193.031 / 5.211 / 1.712< 1e−12✓ PASS
p unadjusted2.441e−03 / 1.883e−07 / 8.692e−020.002 / <0.001 / 0.087< 1e−15✓ PASS
Holm (automatic), adjusted p4.883e−03 / 5.648e−07 / 8.692e−020.005 / <0.001 / 0.087< 1e−15✓ PASS
Bonferroni, adjusted p7.324e−03 / 5.648e−07 / 2.608e−010.007 / <0.001 / 0.261< 1e−15✓ PASS
Šidák, adjusted p7.306e−03 / 5.648e−07 / 2.388e−010.007 / <0.001 / 0.239< 1e−15✓ PASS
r = |z| ÷ √N0.0841 / 0.1445 / 0.04750.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.

ประโยครายงานผล: “คะแนนคุณภาพชีวิตหลังการรักษาแตกต่างกันตามรายได้ครัวเรือน (Kruskal-Wallis H(2) = 27.24, p < 0.001, η² = 0.019) โดยกลุ่มรายได้ < 10,000 บาท/เดือน (มัธยฐาน 81.50, IQR 69.38–93.50) มีคะแนนสูงกว่ากลุ่ม 10,000–30,000 บาท/เดือน (z = 3.03, p = 0.005) และกลุ่ม > 30,000 บาท/เดือน (z = 5.21, p < 0.001) จาก Dunn's test ปรับค่า p ด้วย Holm”
Results sentence: “The post-treatment quality-of-life score differed by household income (Kruskal-Wallis H(2) = 27.24, p < 0.001, η² = 0.019); patients from households earning < 10,000 Baht/month (median 81.50, IQR 69.38–93.50) scored higher than those earning 10,000–30,000 (z = 3.03, p = 0.005) and > 30,000 Baht/month (z = 5.21, p < 0.001; Dunn's test with Holm's adjustment).”
📖 References
  1. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
  2. Dunn, O. J. (1961). Multiple comparisons among means. Journal of the American Statistical Association, 56(293), 52–64. doi:10.1080/01621459.1961.10482090
  3. Dunn, O. J. (1964). Multiple comparisons using rank sums. Technometrics, 6(3), 241–252. doi:10.1080/00401706.1964.10490181
  4. Holm, S. (1979). A simple sequentially rejective multiple test procedure. Scandinavian Journal of Statistics, 6(2), 65–70.
  5. 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
  6. Š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
  7. 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.
  8. 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).

คะแนนคุณภาพชีวิตของผู้ป่วย 1,300 คนเปลี่ยนไปหรือไม่ระหว่างก่อน (Quality of Life Score (Pre), 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.9962
Did the quality-of-life score of the 1,300 patients change between before (Quality of Life Score (Pre), qolscore1) 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.

Differences, signed ranks and DAPH's W
$$ d_i = y_i^{\text{post}} - y_i^{\text{pre}},\qquad R^{+} = \sum_{d_i>0}\operatorname{rank}\lvert d_i\rvert,\qquad R^{-} = \sum_{d_i<0}\operatorname{rank}\lvert d_i\rvert,\qquad R^{+}+R^{-} = \frac{n'(n'+1)}{2} $$ $$ W = \min\bigl(R^{+},\,R^{-}\bigr)\qquad(\text{R's } V = R^{+}) $$
Normal approximation with the tie correction (no continuity correction)
$$ \sigma_W^{2} = \frac{n'(n'+1)(2n'+1)}{24} - \frac{\sum_{j}(t_j^{3}-t_j)}{48},\qquad Z = \frac{W - n'(n'+1)/4}{\sigma_W},\qquad p = 2\,P\bigl(Z_0 > \lvert Z\rvert\bigr) $$
Effect size and median difference
$$ r = \frac{\lvert Z\rvert}{\sqrt{n}},\qquad \text{Median Diff} = \operatorname{median}(d_1,\dots,d_n) $$
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

R script R base (แพ็กเกจ stats) เท่านั้นbase R only (package 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")

# 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)))
Expected R output (R 4.3.3)
 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
DAPH Tab 2 → Continuous → ติ๊ก Intervention/Interested Factor? → Wilcoxon Signed-Rank test, Dependent = Quality of Life Score (Post), Matching Variable = Quality of Life Score (Pre) · ค่าจากตารางผลและค่าที่ engine คำนวณTab 2 → Continuous → tick Intervention/Interested Factor? → Wilcoxon Signed-Rank test, Dependent = Quality of Life Score (Post), Matching Variable = Quality of Life Score (Pre) · values from the results table and the engine's own values
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
Median Pre / Post / Median Diff (Post − Pre)70.0 / 77.5 / 7.570.00 / 77.50 / 7.500✓ PASS
Positive ranks (Post > Pre) / Negative ranks / Ties1299 / 1 / 01299 / 1 / 00✓ PASS
W = min(R⁺, R⁻)3 (R's V = R⁺ = 845647)3.00✓ 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 r0.99620380.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.

ประโยครายงานผล: “คะแนนคุณภาพชีวิตเพิ่มขึ้นจากมัธยฐาน 70.00 ก่อนการรักษาเป็น 77.50 หลังการรักษา (มัธยฐานของผลต่าง 7.50 คะแนน เพิ่มขึ้น 1,299 จาก 1,300 คน) อย่างมีนัยสำคัญทางสถิติ (Wilcoxon signed-rank test, W = 3.0, Z = −35.92, p < 0.001, r = 0.996)”
Results sentence: “Quality-of-life scores increased from a median of 70.00 before treatment to 77.50 after treatment (median difference 7.50 points; 1,299 of 1,300 patients improved; Wilcoxon signed-rank test, W = 3.0, Z = −35.92, p < 0.001, r = 0.996).”
📖 References
  1. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
  2. 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
  3. Wilcoxon, F. (1945). Individual comparisons by ranking methods. Biometrics Bulletin, 1(6), 80–83. doi:10.2307/3001968
  4. 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).

ปัจจัยใดสัมพันธ์กับคะแนนคุณภาพชีวิตหลังการรักษา (Quality of Life Score (Post), 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 ได้แบบจำลองสุดท้ายเป็นอายุกับรายได้ครัวเรือน
Which characteristics are associated with the post-treatment quality-of-life score (Quality of Life Score (Post), 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

Model and least-squares estimates
$$ Y_i = \beta_0 + \beta_1 X_{1i} + \dots + \beta_p X_{pi} + \varepsilon_i,\qquad \varepsilon_i \sim N(0,\sigma^{2}),\qquad \hat{\beta} = (X^{\top}X)^{-1}X^{\top}y $$
Standard error, t test and 95% CI of each coefficient
$$ \hat{\sigma}^{2} = \frac{\sum_{i} e_i^{2}}{n-p-1},\qquad SE(\hat{\beta}_j) = \sqrt{\hat{\sigma}^{2}\,\bigl[(X^{\top}X)^{-1}\bigr]_{jj}},\qquad t_j = \frac{\hat{\beta}_j}{SE(\hat{\beta}_j)},\qquad \hat{\beta}_j \pm t_{0.975,\,n-p-1}\,SE(\hat{\beta}_j) $$
Fit of the model
$$ R^{2} = 1 - \frac{SS_{\text{res}}}{SS_{\text{tot}}},\qquad R^{2}_{\text{adj}} = 1 - (1-R^{2})\,\frac{n-1}{n-p-1},\qquad F = \frac{(SS_{\text{tot}}-SS_{\text{res}})/p}{SS_{\text{res}}/(n-p-1)} \sim F(p,\ n-p-1) $$
One p-value per variable: partial F test (q = number of coefficients of the variable)
$$ F_{\text{partial}} = \frac{(SS_{\text{res, without the variable}} - SS_{\text{res, full}})/q}{SS_{\text{res, full}}/(n-p-1)} \sim F(q,\ n-p-1),\qquad q = 1 \Rightarrow F_{\text{partial}} = t^{2} $$
AIC and BIC as DAPH prints them (k = p + 1 coefficients; σ² not counted)
$$ AIC = -2\ln L + 2k,\qquad BIC = -2\ln L + k\ln n $$
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

R script R base (แพ็กเกจ stats) เท่านั้น ทุกวิธีในดรอปดาวน์base R only (package stats), every option in the dropdown
# 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")
Expected R output (R 4.3.3, abridged)
  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
DAPH Tab 2 → Continuous → Linear regression, Dependent = Quality of Life Score (Post), Independent = Age (years), Gender, Treatment Group, Body Mass Index (kg/m²), Chronic Disease, Household Income, เลือกทีละวิธี · ค่าจากตารางผล หน้าผลลัพธ์ และค่าที่ engine คำนวณTab 2 → Continuous → Linear regression, Dependent = Quality of Life Score (Post), Independent = Age (years), Gender, Treatment Group, Body Mass Index (kg/m²), Chronic Disease, Household Income, each method in turn · values from the results table, the results page and the engine's own values
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
Enter: n / reference levels1300 / Male, CAPD, No, <10,0001300 / Male, CAPD, No chronic disease, < 10,0000✓ 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 / chronic0.165 / 1.503 / −0.014 / −1.8460.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) / p0.036726 / 0.031507 / 7.037007 / 2.925291e−080.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.7011148.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 orderBMI 0.9214, gender 0.8795, group 0.1248, chronic 0.0514BMI 0.9214, Gender 0.8795, Treatment Group 0.1248, Chronic Disease 0.05140 (4 dp)✓ PASS
Stepwise / Forward: variables added in orderfam_income, ageHousehold 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.33210.0321 / 0.0299 / 14.33< 0.005 (display)✓ PASS
Missing values (age + gender + hos, n = 1297): p of Hospital0.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.

ประโยครายงานผล: “จากการวิเคราะห์ถดถอยเชิงเส้นพหุคูณ (n = 1,300) อายุที่มากขึ้นสัมพันธ์กับคะแนนคุณภาพชีวิตหลังการรักษาที่ต่ำลง (B = −0.288 ต่อปี, 95% CI −0.429 ถึง −0.146, p < 0.001) และผู้ป่วยจากครัวเรือนรายได้ 10,000–30,000 และ > 30,000 บาท/เดือน มีคะแนนต่ำกว่ากลุ่ม < 10,000 บาท/เดือน (B = −3.848, 95% CI −6.429 ถึง −1.267 และ B = −5.443, 95% CI −7.723 ถึง −3.162; p ของตัวแปร < 0.001) หลังปรับเพศ กลุ่มการรักษา ดัชนีมวลกาย และโรคเรื้อรัง แบบจำลองอธิบายความผันแปรได้น้อย (R² = 0.037, F(7, 1292) = 7.04, p < 0.001)”
Results sentence: “In multiple linear regression (n = 1,300), older age was associated with a lower post-treatment quality-of-life score (B = −0.288 per year, 95% CI −0.429 to −0.146, p < 0.001), and patients from households earning 10,000–30,000 and > 30,000 Baht/month scored lower than those earning < 10,000 Baht/month (B = −3.848, 95% CI −6.429 to −1.267, and B = −5.443, 95% CI −7.723 to −3.162; variable p < 0.001), adjusted for gender, treatment group, body mass index and chronic disease. The model explained little of the variation (R² = 0.037, F(7, 1292) = 7.04, p < 0.001).”
📖 References
  1. 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
  2. Schwarz, G. (1978). Estimating the dimension of a model. The Annals of Statistics, 6(2), 461–464. doi:10.1214/aos/1176344136
  3. 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 7 stats ✓ 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.

ตัวอย่างในข้อมูล DAPH: ผู้ป่วยล้างไตทางช่องท้อง 1,300 คน เสียชีวิตระหว่างติดตาม 229 คน (Study Status = Died/Event) เป็นร้อยละ 13.11 ในกลุ่ม CAPD (ล้างไตทางช่องท้องด้วยตนเองต่อเนื่อง) และร้อยละ 22.20 ในกลุ่ม APD (ล้างไตทางช่องท้องด้วยเครื่องอัตโนมัติ) · คำถาม: Treatment Group แบบ APD สัมพันธ์กับ odds ของการเสียชีวิตที่สูงกว่าหรือไม่ เมื่อปรับด้วย Age (years), Gender, Chronic Disease และ BMI Group · ผล: Crude OR 1.89 (95% CI 1.41 to 2.54) และ Adjusted OR 2.03 (95% CI 1.50 to 2.73)
Example in the DAPH data: of 1,300 peritoneal-dialysis patients, 229 died during follow-up (Study Status = Died/Event): 13.11% on CAPD (continuous ambulatory PD) and 22.20% on APD (automated PD). Question: is APD treatment associated with higher odds of death after adjustment for Age (years), Gender, Chronic Disease and BMI Group? Result: crude OR 1.89 (95% CI 1.41 to 2.54), adjusted OR 2.03 (95% CI 1.50 to 2.73).

2หลักการและสูตรLogic and Formula

Model, log-likelihood, odds ratio
$$ \log\!\left(\frac{p_i}{1-p_i}\right) = \beta_0 + \beta_1 x_{1i} + \dots + \beta_k x_{ki},\qquad p_i = \Pr(Y_i = 1 \mid x_i) $$ $$ \ell(\beta) = \sum_{i=1}^{n} \bigl[\, y_i \log p_i + (1-y_i)\log(1-p_i) \,\bigr] $$ $$ \mathrm{OR}_j = e^{\hat\beta_j},\qquad 95\%\ \mathrm{CI} = \exp\!\bigl(\hat\beta_j \pm 1.96\, SE_j\bigr),\qquad z_j = \hat\beta_j / SE_j $$
Likelihood-ratio (LR) tests
$$ G_v = 2\bigl[\ell(\hat\beta) - \ell(\hat\beta_{(-v)})\bigr] \sim \chi^2_{d_v},\qquad \chi^2_{\mathrm{LR}} = 2\bigl[\ell(\hat\beta) - \ell_0\bigr] \sim \chi^2_{k} $$
Pseudo R², information criteria, discrimination
$$ R^2_{\mathrm{McFadden}} = 1 - \frac{\ell(\hat\beta)}{\ell_0},\qquad R^2_{\mathrm{Nagelkerke}} = \frac{1 - \exp(-\chi^2_{\mathrm{LR}}/n)}{1 - \exp(2\ell_0/n)} $$ $$ \mathrm{AIC} = -2\ell(\hat\beta) + 2q,\qquad \mathrm{BIC} = -2\ell(\hat\beta) + q\ln n,\qquad \mathrm{AUC} = \Pr\bigl(\hat p_i > \hat p_j\bigr) + \tfrac{1}{2}\Pr\bigl(\hat p_i = \hat p_j\bigr),\ \ y_i = 1,\ y_j = 0 $$
Hosmer-Lemeshow goodness of fit (G = 10 groups of predicted risk)
$$ \hat C = \sum_{g=1}^{G} \left[ \frac{(O_{1g} - E_{1g})^2}{E_{1g}} + \frac{(O_{0g} - E_{0g})^2}{E_{0g}} \right] \sim \chi^2_{G-2},\qquad E_{1g} = \sum_{i \in g} \hat p_i,\quad E_{0g} = n_g - E_{1g} $$
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

R script R 4.3.3 · แพ็กเกจ stats (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)
Expected R output (ตัดบางส่วน)(abridged)
# 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
DAPH Tab 2 → Outcome type: Categorical → Dependent Variable = Study Status → Independent Variables = Treatment Group, Age (years), Gender, Chronic Disease, BMI Group → Statistic: Logistic Regression → Analysis Method: Enter (แล้วรันซ้ำด้วย Backward Elimination และ Bivariate Analysis) · ติ๊ก Intervention/Interested Factor? และเลือก Treatment Group จะได้ Unconditional Logistic Regression ที่ให้ OR, CI, ค่า p และค่าความเหมาะสมเท่ากันทุกค่าTab 2 → Outcome type: Categorical → Dependent Variable = Study Status → Independent Variables = Treatment Group, Age (years), Gender, Chronic Disease, BMI Group → Statistic: Logistic Regression → Analysis Method: Enter (run again with Backward Elimination and Bivariate Analysis). Ticking Intervention/Interested Factor? with Treatment Group as the intervention gives Unconditional Logistic Regression with identical ORs, CIs, p values and fit statistics.
QuantityR 4.3.3DAPHความต่างDifferenceStatus
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 group0.320477 / 0.001901 / 0.8874570.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 + type0.66310.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 group0.1858 / 0.48020.186 / 0.480< 0.0005✓ PASS
Model LR χ²(7)50.698450.698< 0.0005✓ PASS
McFadden R² / Nagelkerke R²0.0419 / 0.06310.0419 / 0.0631< 0.00005✓ PASS
AIC / BIC / log-likelihood1175.6301 / 1216.9911 / −579.81511175.6 / 1217.0 / −579.815< 0.05✓ PASS
AUC0.64120.6412< 0.00005✓ PASS
Hosmer-Lemeshow χ²(8), p6.1585, p = 0.62956.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.061BMI 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
  1. 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
  2. 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
  3. Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied logistic regression (3rd ed.). Wiley. ISBN 978-0-470-58247-3.
  4. 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
  5. 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).

ตัวอย่างในข้อมูล DAPH: ข้อมูลตัวอย่างเป็นการศึกษาติดตามผู้ป่วย (cohort) ไม่ใช่ case-control แบบจับคู่ และไม่มีรหัสชุดจับคู่ จึงสาธิตด้วยการใช้ โรงพยาบาล (Hospital, 7 แห่ง) เป็นชั้น: Matching Variable = Hospital · ผลคือการเปรียบเทียบผู้ป่วย APD กับ CAPD ที่รักษาในโรงพยาบาลเดียวกัน ความต่างของความเสี่ยงพื้นฐานระหว่างโรงพยาบาลทั้งที่วัดและไม่ได้วัดถูกตัดออก · ทุกโรงพยาบาลมีทั้งผู้เสียชีวิตและผู้รอดชีวิต จึงใช้ได้ทั้ง 7 ชุด (ผู้ป่วย 1,297 คน เสียชีวิต 229 คน) · APD มี OR ภายในโรงพยาบาล 2.05 (95% CI 1.52 to 2.76) ใกล้กับ 2.03 จาก logistic regression ปกติในหัวข้อ 2.1 · ข้อมูล case-control จริงใช้รหัสชุดจับคู่เป็น Matching Variable
Example in the DAPH data: the example data are a cohort, not a matched case-control study, and contain no matched-set ID. The method is therefore shown with each hospital (Hospital, 7 hospitals) as a stratum: Matching Variable = Hospital. The OR then compares APD with CAPD patients treated in the same hospital, removing every difference in baseline risk between hospitals, measured or not. Every hospital has both deaths and survivors, so all 7 sets are used (1,297 patients, 229 deaths). APD has a within-hospital OR of 2.05 (95% CI 1.52 to 2.76), close to the 2.03 from ordinary logistic regression in 2.1. With real matched case-control data, the Matching Variable is the matched-set ID.

2หลักการและสูตรLogic and Formula

Exact conditional likelihood (matched set s has ns people, ms of them cases)
$$ L_c(\beta) = \prod_{s=1}^{S} \frac{\exp\!\Bigl(\sum_{i \in D_s} x_i^{\top}\beta\Bigr)}{\sum_{R \subseteq \{1,\dots,n_s\},\ |R| = m_s} \exp\!\Bigl(\sum_{i \in R} x_i^{\top}\beta\Bigr)} $$ $$ \text{1:M matching } (m_s = 1):\qquad L_c(\beta) = \prod_{s=1}^{S} \frac{\exp(x_{s,\text{case}}^{\top}\beta)}{\sum_{j=1}^{n_s} \exp(x_{sj}^{\top}\beta)} $$
Denominator by recursion (Gail, Lubin & Rubinstein, 1981), computed on the log scale
$$ B_i(k) = B_{i-1}(k) + e^{x_i^{\top}\beta}\, B_{i-1}(k-1),\qquad B_0(0) = 1,\qquad \text{denominator} = B_{n_s}(m_s) $$
Odds ratio, Wald interval and tests
$$ \mathrm{OR}_j = e^{\hat\beta_j},\qquad 95\%\ \mathrm{CI} = \exp\!\bigl(\hat\beta_j \pm 1.96\, SE_j\bigr),\qquad z_j = \hat\beta_j / SE_j $$ $$ W_v = \hat\beta_v^{\top}\, \widehat{V}_v^{-1}\, \hat\beta_v \sim \chi^2_{d_v},\qquad \chi^2_{\mathrm{LR}} = 2\bigl[\ell_c(\hat\beta) - \ell_c(0)\bigr] \sim \chi^2_{k} $$
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

R script R 4.3.3 · แพ็กเกจ survival (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"))
Expected R output (ตัดบางส่วน)(abridged)
# 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
DAPH Tab 2 → Outcome type: Categorical → Dependent Variable = Study Status → Independent Variables = Treatment Group, Age (years), Gender, Chronic Disease, BMI Group → ติ๊ก Intervention/Interested Factor? และเลือก Treatment Group → Matching Variable = Hospital → Statistic: Conditional Logistic Regression → Analysis Method: Enter · แถว District รันซ้ำโดยเปลี่ยน Matching Variable เป็น District · แถว Backward Elimination ใช้ Analysis Method: Backward Elimination · แถว Hospital Type ใช้ Independent Variables = Treatment Group, Age (years), Chronic Disease, Hospital TypeTab 2 → Outcome type: Categorical → Dependent Variable = Study Status → Independent Variables = Treatment Group, Age (years), Gender, Chronic Disease, BMI Group → tick Intervention/Interested Factor? and choose Treatment Group → Matching Variable = Hospital → Statistic: Conditional Logistic Regression → Analysis Method: Enter. The District row repeats the run with Matching Variable = District; the Backward Elimination row uses Analysis Method: Backward Elimination; the Hospital Type row uses Independent Variables = Treatment Group, Age (years), Chronic Disease, Hospital Type.
QuantityR 4.3.3DAPHความต่างDifferenceStatus
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), p1.6122 (1.1944 to 2.1762), 0.00181.61 (1.19 to 2.18), 0.002< 0.005✓ PASS
OR, female (95% CI), p1.1662 (0.8498 to 1.6005), 0.34101.17 (0.85 to 1.60), 0.341< 0.005✓ PASS
BMI group, joint Wald χ²(3) p0.89310.893< 0.0005✓ PASS
n, events, LR χ²(7)1297, 229, 51.5001,297, 229, 51.500< 0.0005✓ PASS
Crude conditional OR, APD / chronic disease1.9058 / 1.60621.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.09710, 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.955BMI 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 diseaseNANA (not estimable), LR χ²(3) = 49.9550✓ 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
  1. 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.
  2. 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
  3. 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
  4. 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.

ตัวอย่างในข้อมูล DAPH: แบบจำลอง A การเสียชีวิต (Study Status) กับ Treatment Group, Age (years), Gender, Chronic Disease, BMI Group โดยมีค่าคงที่สุ่มของ Hospital (7 แห่ง ผู้ป่วยที่มีรหัสโรงพยาบาล 1,297 คน): ความแปรปรวนระหว่างโรงพยาบาลประมาณได้ 0 (ค่าที่ขอบ) แบบจำลองจึงเท่ากับ logistic regression ปกติ และ APD มี OR 2.04 (95% CI 1.51 to 2.75) · แบบจำลอง B คุณภาพชีวิตสูงหลังการรักษา (QoL Group (Post) = High quality of life) กับ Treatment Group, Age (years), Gender โดยมีค่าคงที่สุ่มของ District (10 อำเภอ): ความแปรปรวนระหว่างอำเภอ 0.1973, ICC 0.0566, LR test ของความแปรปรวน p < 0.001 และ APD มี OR 1.31 (95% CI 0.72 to 2.39)
Example in the DAPH data: Model A: death (Study Status) on Treatment Group, Age (years), Gender, Chronic Disease and BMI Group with a random intercept for Hospital (7 hospitals; the 1,297 patients with a hospital code): the between-hospital variance is estimated at 0 (the boundary), so the model equals ordinary logistic regression, and APD has an OR of 2.04 (95% CI 1.51 to 2.75). Model B: high quality of life after treatment (QoL Group (Post) = High quality of life) on Treatment Group, Age (years) and Gender with a random intercept for District (10 districts): between-district variance 0.1973, ICC 0.0566, LR test of the variance p < 0.001, and APD has an OR of 1.31 (95% CI 0.72 to 2.39).

2หลักการและสูตรLogic and Formula

Random-intercept logistic model (GLMM) — the model DAPH fits
$$ \mathrm{logit}\,\Pr(Y_{ij} = 1 \mid b_j) = x_{ij}^{\top}\beta + b_j,\qquad b_j \sim N(0, \sigma^2),\qquad j = 1,\dots,J $$ $$ L(\beta, \sigma) = \prod_{j=1}^{J} \int_{-\infty}^{\infty} \prod_{i=1}^{n_j} p_{ij}^{\,y_{ij}} (1 - p_{ij})^{1 - y_{ij}}\ \frac{1}{\sigma}\,\phi\!\left(\frac{b}{\sigma}\right) db,\qquad p_{ij} = \mathrm{logit}^{-1}(x_{ij}^{\top}\beta + b) $$
Laplace approximation (the integral of each cluster, u = b / σ)
$$ \log L_j \approx h_j(\hat u_j) - \tfrac{1}{2}\log D_j,\qquad h_j(u) = \sum_{i=1}^{n_j} \log \Pr(y_{ij} \mid x_{ij}^{\top}\beta + \sigma u) - \frac{u^2}{2},\qquad D_j = 1 + \sigma^2 \sum_{i=1}^{n_j} \hat p_{ij}(1 - \hat p_{ij}) $$
Odds ratio, intraclass correlation and the test of σ² = 0
$$ \mathrm{OR}_k = e^{\hat\beta_k},\qquad 95\%\ \mathrm{CI} = \exp\!\bigl(\hat\beta_k \pm 1.96\, SE_k\bigr),\qquad \mathrm{ICC} = \frac{\sigma^2}{\sigma^2 + \pi^2/3},\qquad \mathrm{DE} = 1 + (\bar m - 1)\,\mathrm{ICC} $$ $$ \chi^2 = 2\bigl[\ell_{\mathrm{GLMM}} - \ell_{\mathrm{logistic}}\bigr],\qquad p = \tfrac{1}{2}\Pr\bigl(\chi^2_1 > \chi^2\bigr),\qquad \mathrm{AIC} = -2\ell + 2(q + 1),\quad \mathrm{BIC} = -2\ell + (q + 1)\ln n $$
GEE logistic (population-averaged) — not available in DAPH
$$ \mathrm{logit}\,\Pr(Y_{ij} = 1) = x_{ij}^{\top}\beta^{\mathrm{PA}},\qquad \beta^{\mathrm{PA}} \approx \frac{\beta}{\sqrt{1 + 0.346\,\sigma^2}} $$
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

R script R 4.3.3 · แพ็กเกจ lme4 (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)
Expected R output (ตัดบางส่วน)(abridged)
# 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
DAPH แบบจำลอง A: Tab 2 → Outcome type: Categorical → Dependent Variable = Study Status → Independent Variables = Treatment Group, Age (years), Gender, Chronic Disease, BMI Group → Statistic: Logistic Regression → ติ๊ก Mixed Effects Model → Random Effect Variable = Hospital → Analysis Method: Enter · แบบจำลอง B: Dependent Variable = QoL Group (Post), Independent Variables = Treatment Group, Age (years), Gender, Random Effect Variable = DistrictModel A: Tab 2 → Outcome type: Categorical → Dependent Variable = Study Status → Independent Variables = Treatment Group, Age (years), Gender, Chronic Disease, BMI Group → Statistic: Logistic Regression → tick Mixed Effects Model → Random Effect Variable = Hospital → Analysis Method: Enter. Model B: Dependent Variable = QoL Group (Post), Independent Variables = Treatment Group, Age (years), Gender, Random Effect Variable = District.
QuantityR 4.3.3DAPHความต่างDifferenceStatus
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.88510.339 / 0.885< 0.0005✓ PASS
A: ordinary logistic log-likelihood (LR test of σ² = 0)−579.1006 (χ² = 0)χ² = 0.000, p = 1.0000✓ PASS
B: σ², SD, ICC (district)0.1973, 0.4442, 0.05660.1973, 0.4442, 0.0566< 0.00005✓ PASS
B: design effect (mean 130 per district)8.29938.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), p1.3069 (0.7159 to 2.3856), 0.38341.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
  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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).

ตัวอย่างในข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย): สัดส่วนผู้เสียชีวิตระหว่างการติดตาม (Study Status = Died/Event) แตกต่างกันตามกลุ่มการรักษา (Treatment Group: CAPD กับ APD) และตามกลุ่มดัชนีมวลกาย (BMI Group 4 กลุ่ม) หรือไม่ · ผลด้านล่าง: เสียชีวิตร้อยละ 13.1 ในกลุ่ม CAPD (86 จาก 656 ราย) และร้อยละ 22.2 ในกลุ่ม APD (143 จาก 644 ราย) ซึ่งเป็นตาราง 2×2 · ในกลุ่ม BMI เสียชีวิตร้อยละ 22.2, 17.9, 15.9 และ 17.0 (Underweight, Normal, Overweight, Obese) ซึ่งเป็นตาราง 4×2
Example in the DAPH data (1,300 peritoneal-dialysis patients): does the proportion who died during follow-up (Study Status = Died/Event) differ by treatment (Treatment Group: CAPD vs APD) and by BMI Group (4 groups)? Results below: 13.1% died with CAPD (86 of 656) and 22.2% with APD (143 of 644), a 2×2 table; across the BMI groups 22.2%, 17.9%, 15.9% and 17.0% died (Underweight, Normal, Overweight, Obese), a 4×2 table.

2หลักการและสูตรLogic and Formula

Pearson χ² (tables larger than 2×2)
$$ \chi^2 = \sum_{i=1}^{r}\sum_{j=1}^{c} \frac{(O_{ij} - E_{ij})^2}{E_{ij}}, \qquad E_{ij} = \frac{R_i\,C_j}{N}, \qquad df = (r-1)(c-1) $$
2×2 table: Yates' continuity correction (Yates, 1934), applied automatically by DAPH
$$ \chi^2_{Y} = \sum_{i=1}^{2}\sum_{j=1}^{2} \frac{\bigl[\max\bigl(|O_{ij} - E_{ij}| - 0.5,\ 0\bigr)\bigr]^2}{E_{ij}}, \qquad df = 1 $$
2×2 table: Fisher's exact test (Fisher, 1922) and the odds ratio printed beside it
$$ P(a) = \frac{\binom{R_1}{a}\binom{R_2}{C_2 - a}}{\binom{N}{C_2}}, \qquad p = \sum_{P(a') \le P(a_{\text{obs}})} P(a'), \qquad OR = \frac{O_{11}\,O_{22}}{O_{12}\,O_{21}} $$
Effect size: Cramér's V from the uncorrected Pearson χ² (Cramér, 1946); for a 2×2 table V = φ
$$ V = \sqrt{\frac{\chi^2}{N\,\bigl(\min(r,c) - 1\bigr)}}, \qquad 0 \le V \le 1 $$
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

R script R พื้นฐาน (stats: 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
Expected R output (R 4.3.3, abridged)
      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
DAPH Tab 2 > ชนิดตัวแปรตาม Categorical > สถิติ Chi-square test > Dependent Variable = Study Status (status) > Independent Variables = Treatment Group (group) และ BMI Group (bmi_group) > Run · ค่าจากตารางผล รายงาน Word และค่าละเอียดจากฟังก์ชันที่ DAPH ใช้Tab 2 > outcome type Categorical > statistic Chi-square test > Dependent Variable = Study Status (status) > Independent Variables = Treatment Group (group) and BMI Group (bmi_group) > Run. Values from the results table, the Word report and full-precision values from the function DAPH runs
QuantityRDAPHความต่างDifferenceStatus
Died: CAPD / APD (row %)13.1 / 22.213.1% / 22.2%0✓ PASS
Smallest expected count (group × status)113.4113.40✓ PASS
χ²(1) with Yates' correction17.90317.90254 (table: 17.90)< 0.0005✓ PASS
p (χ², Yates)2.325e−052.3251e−05 (table: <0.001)< 1e−8✓ PASS
Fisher's exact p (two-sided)1.669228e−051.669228e−05< 1e−11✓ PASS
Odds ratio in the Fisher row (APD vs CAPD)1.8917981.891798 (table: 1.892)< 1e−6✓ PASS
Cramér's V = φ, 2×2 (from the uncorrected χ² 18.524)0.11940.11937 (table: 0.119)< 0.00005✓ PASS
BMI group: χ²(3)2.56652.56646 (table: 2.57)< 0.00005✓ PASS
BMI group: p0.46340.46340 (table: 0.463)< 0.00005✓ PASS
BMI group: Cramér's V; smallest expected count0.0444; 22.20.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
  1. Cochran, W. G. (1954). Some methods for strengthening the common χ² tests. Biometrics, 10(4), 417–451. doi:10.2307/3001616
  2. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates.
  3. Cramér, H. (1946). Mathematical methods of statistics. Princeton University Press.
  4. 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
  5. 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
  6. 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
  7. 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.

ตัวอย่างในข้อมูล DAPH: ในผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย สัดส่วนผู้มีคุณภาพชีวิตต่ำ (Low quality of life) เปลี่ยนไประหว่างตอนเริ่มการศึกษา (QoL Group (Pre), qol_g1) กับกลางการศึกษา (QoL Group (Mid), qol_g2) หรือไม่ · ผลด้านล่าง: ร้อยละ 31.0 ตอนเริ่ม และร้อยละ 22.1 ตอนกลางการศึกษา ผู้ป่วย 116 รายเปลี่ยนจากต่ำเป็นสูง และไม่มีผู้ใดเปลี่ยนจากสูงเป็นต่ำ · ตัวอย่างที่สองใช้เฉพาะผู้ป่วยของ Bangkok Hospital (96 ราย) ซึ่งมีคู่ที่เปลี่ยนกลุ่มเพียง 7 คู่ เพื่อแสดงว่า DAPH เปลี่ยนไปใช้ exact binomial test เมื่อคู่ที่เปลี่ยนกลุ่มน้อย
Example in the DAPH data: among 1,300 peritoneal-dialysis patients, did the proportion with low quality of life change between baseline (QoL Group (Pre), qol_g1) and mid-study (QoL Group (Mid), qol_g2)? Results below: 31.0% at baseline and 22.1% at mid-study; 116 patients moved from Low to High and none from High to Low. A second example uses only the patients of Bangkok Hospital (96 patients), where just 7 pairs changed category, to show that DAPH switches to the exact binomial test when discordant pairs are few.

2หลักการและสูตรLogic and Formula

Paired 2×2 table (rows = first measurement, columns = second measurement)
$$ \begin{array}{c|cc} & \text{second} = 0 & \text{second} = 1 \\ \hline \text{first} = 0 & a & c \\ \text{first} = 1 & b & d \end{array} \qquad n = a + b + c + d $$
McNemar χ² with Edwards' continuity correction (b + c ≥ 25)
$$ \chi^2_{cc} = \frac{\bigl[\max\bigl(|b - c| - 1,\ 0\bigr)\bigr]^2}{b + c} \sim \chi^2(1) $$
Exact binomial test (b + c < 25)
$$ p = \min\Bigl(1,\ 2\sum_{k=0}^{\min(b,c)} \binom{b+c}{k}\, 0.5^{\,b+c}\Bigr) $$
Change in the proportion of level 0 (second minus first) with its Wald 95% CI (Agresti, 2013)
$$ \hat\delta = \frac{b - c}{n} = \hat p_{\text{second}} - \hat p_{\text{first}}, \qquad SE(\hat\delta) = \frac{1}{n}\sqrt{(b + c) - \frac{(b - c)^2}{n}}, \qquad 95\%\ \text{CI} = \hat\delta \pm 1.96\,SE $$
Ratio of discordant pairs (shown only when b > 0 and c > 0)
$$ OR = \frac{b}{c}, \qquad 95\%\ \text{CI} = \exp\Bigl(\ln\frac{b}{c} \pm 1.96\sqrt{\tfrac{1}{b} + \tfrac{1}{c}}\Bigr) $$
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

R script R พื้นฐาน (stats: 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)
Expected R output (R 4.3.3, abridged)
      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
DAPH Tab 2 > ชนิดตัวแปรตาม Categorical > ติ๊ก Intervention/Interested Factor? > สถิติ McNemar test > Dependent Variable = QoL Group (Mid) (qol_g2) > Matching Variable = QoL Group (Pre) (qol_g1) > Run · ตัวอย่างที่สอง: Data Tools > Filter: hos = 1 ก่อน แล้วรันเหมือนเดิม · McNemar ใช้เฉพาะตัวแปรตามและตัวแปรจับคู่ ตัวแปรในช่อง Independent Variables ไม่ถูกใช้Tab 2 > outcome type Categorical > tick Intervention/Interested Factor? > statistic McNemar test > Dependent Variable = QoL Group (Mid) (qol_g2) > Matching Variable = QoL Group (Pre) (qol_g1) > Run. Second example: Data Tools > Filter: hos = 1 first, then the same run. McNemar uses only the dependent and matching variables; a variable in the Independent Variables box is not used.
QuantityRDAPHความต่างDifferenceStatus
Low QoL: Pre / Mid (% of 1,300 pairs)31.00 / 22.0831.0 / 22.077 (table: 31.0% / 22.1%)< 0.005✓ PASS
Discordant pairs b (High→Low) / c (Low→High)0 / 1160 / 1160✓ PASS
McNemar χ²(1), Edwards' correction114.0086114.00862 (note and Tab 3: χ²(1) = 114.01, continuity-corrected)< 0.00005✓ PASS
p1.297432e−261.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 CInot estimable (b = 0)row not shown—✓ PASS
Bangkok Hospital (n = 96): b / c0 / 70 / 70✓ PASS
Bangkok Hospital: test used and pexact binomial, 0.015625exact 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
  1. Agresti, A. (2013). Categorical data analysis (3rd ed.). Wiley. ISBN 978-0-470-46363-5.
  2. 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
  3. 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
  4. 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.

ตัวอย่างในข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย เสียชีวิตระหว่างติดตาม 229 ราย): คะแนนคุณภาพชีวิตตอนเริ่ม (Quality of Life Score (Pre), qolscore1) บอกได้ดีเพียงใดว่าใครจะเสียชีวิตระหว่างการติดตาม (Study Status = Died/Event) · ผลด้านล่าง: AUC = 0.617 จุดตัดที่ดีที่สุดคือคะแนน 63 ลงมา (sensitivity ร้อยละ 56.3, specificity ร้อยละ 68.8) · ส่วนกลุ่มคุณภาพชีวิตต่ำที่มีอยู่แล้ว (QoL Group (Pre) = Low quality of life คือคะแนน 60 ลงมา) เมื่อใช้เป็นผลตรวจบวก ได้ sensitivity ร้อยละ 48.9, specificity ร้อยละ 72.8, PPV ร้อยละ 27.8 และ NPV ร้อยละ 87.0
Example in the DAPH data (1,300 peritoneal-dialysis patients, 229 died during follow-up): how well does the baseline quality-of-life score (Quality of Life Score (Pre), qolscore1) identify the patients who die during follow-up (Study Status = Died/Event)? Results below: AUC = 0.617, and the best cut-off is a score of 63 or less (sensitivity 56.3%, specificity 68.8%). Using the existing low-QoL group (QoL Group (Pre) = Low quality of life, a score of 60 or less) as a positive test gives sensitivity 48.9%, specificity 72.8%, PPV 27.8% and NPV 87.0%.

2หลักการและสูตรLogic and Formula

2×2 table against the reference standard
$$ \mathrm{Se} = \frac{TP}{TP+FN},\quad \mathrm{Sp} = \frac{TN}{TN+FP},\quad \mathrm{PPV} = \frac{TP}{TP+FP},\quad \mathrm{NPV} = \frac{TN}{TN+FN},\quad \mathrm{Acc} = \frac{TP+TN}{N},\quad \text{prevalence} = \frac{TP+FN}{N} $$
Wilson score 95% CI for each proportion p̂ = x/m (Wilson, 1927), z = 1.96
$$ \frac{\hat p + \frac{z^2}{2m} \pm z\sqrt{\frac{\hat p(1-\hat p)}{m} + \frac{z^2}{4m^2}}}{1 + \frac{z^2}{m}} $$
Likelihood ratios and diagnostic odds ratio (log-scale CI, Woolf, 1955)
$$ \mathrm{LR}^{+} = \frac{\mathrm{Se}}{1-\mathrm{Sp}},\quad \mathrm{LR}^{-} = \frac{1-\mathrm{Se}}{\mathrm{Sp}},\quad \mathrm{DOR} = \frac{TP\cdot TN}{FP\cdot FN},\quad 95\%\ \text{CI} = \exp\Bigl(\ln \mathrm{DOR} \pm 1.96\sqrt{\tfrac{1}{TP}+\tfrac{1}{FP}+\tfrac{1}{FN}+\tfrac{1}{TN}}\Bigr) $$
ROC curve, AUC (Hanley & McNeil, 1982) and Youden's index (Youden, 1950)
$$ \mathrm{Se}(t) = \Pr(X \ge t \mid D^{+}),\quad \mathrm{Sp}(t) = \Pr(X < t \mid D^{-}),\quad \mathrm{AUC} = \Pr(X_{D^{+}} > X_{D^{-}}) + \tfrac{1}{2}\Pr(X_{D^{+}} = X_{D^{-}}) $$ $$ J(t) = \mathrm{Se}(t) + \mathrm{Sp}(t) - 1, \qquad t^{*} = \arg\max_{t} J(t) $$
95% CI of the AUC in DAPH: percentile bootstrap (Efron, 1979)
$$ \bigl[\mathrm{AUC}^{*}_{(2.5\%)},\ \mathrm{AUC}^{*}_{(97.5\%)}\bigr] \ \text{over}\ B = 1{,}000\ \text{resamples of the}\ N\ \text{patients} $$
Predictive values at another prevalence π (Bayes' theorem; Altman & Bland, 1994)
$$ \mathrm{PPV}_{\pi} = \frac{\mathrm{Se}\,\pi}{\mathrm{Se}\,\pi + (1-\mathrm{Sp})(1-\pi)},\qquad \mathrm{NPV}_{\pi} = \frac{\mathrm{Sp}\,(1-\pi)}{\mathrm{Sp}\,(1-\pi) + (1-\mathrm{Se})\,\pi} $$
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

R script แพ็กเกจ 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
Expected R output (R 4.3.3, pROC 1.18.5, epiR 2.0.67, abridged)
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)
DAPH (1) Data Tools > Compute: ชื่อตัวแปร qol_neg สูตร -qolscore1 แล้ว วิเคราะห์เพิ่มเติม > ROC Curve Analysis: Score Variable = qol_neg, Outcome Variable = status (Study Status), Positive Label value = 1 · (2) วิเคราะห์เพิ่มเติม > Diagnostic Test Accuracy: Test Variable = qol_g1 (QoL Group (Pre)), Gold Standard = status, Positive Test Value = 0, Positive Gold Value = 1(1) Data Tools > Compute: variable name qol_neg, formula -qolscore1; then Additional Analysis > ROC Curve Analysis: Score Variable = qol_neg, Outcome Variable = status (Study Status), Positive Label value = 1. (2) Additional Analysis > Diagnostic Test Accuracy: Test Variable = qol_g1 (QoL Group (Pre)), Gold Standard = status, Positive Test Value = 0, Positive Gold Value = 1
QuantityRDAPHความต่างDifferenceStatus
AUC (score reversed)0.61690.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.25150✓ PASS
Sensitivity / specificity at the cut-off0.5633 / 0.68810.5633 / 0.6881< 0.00005✓ PASS
AUC if the score is not reversed (higher = positive)0.38310.3831 (with the “⚠ AUC < 0.5” warning)< 0.00005✓ PASS
TP / FP / FN / TN (qol_g1 = Low vs death)112 / 291 / 117 / 780112 / 291 / 117 / 7800✓ 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); prevalence0.6862 (0.6604 to 0.7108); 0.17620.6862 (0.6604 to 0.7108); 0.1762< 0.00005✓ PASS
LR⁺ / LR⁻1.8000 / 0.70151.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
  1. 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
  2. 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
  3. Efron, B. (1979). Bootstrap methods: Another look at the jackknife. The Annals of Statistics, 7(1), 1–26. doi:10.1214/aos/1176344552
  4. 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
  5. Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied logistic regression (3rd ed.). Wiley. doi:10.1002/9781118548387
  6. 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
  7. 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
  8. 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
  9. 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).

ตัวอย่างในข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย): ปัจจัยใดสัมพันธ์กับความเสี่ยงของการมีโรคเรื้อรัง (Chronic Disease) เมื่อพิจารณาอายุ เพศ กลุ่ม BMI กลุ่มการรักษา และรายได้พร้อมกัน · มีโรคเรื้อรังร้อยละ 50.2 (653 ราย) · ผู้หญิงมีความเสี่ยงเป็น 1.19 เท่าของผู้ชาย (RR ปรับแล้ว 95% CI 1.05 ถึง 1.34) ขณะที่ OR ของตัวแปรเดียวกันจาก logistic regression ที่มีตัวแปรชุดเดียวกันคือ 1.43 ถ้าอ่าน OR เป็น "เสี่ยงสูงกว่าร้อยละ 43" จะเกินค่าจริง (ร้อยละ 19) มากกว่าสองเท่า · ตัวอย่างที่สอง: ความเสี่ยงของการเสียชีวิตระหว่างติดตาม (Study Status) ซึ่ง log-binomial ประมาณค่าไม่ได้ DAPH จึงเปลี่ยนเป็น modified Poisson เอง
Example in the DAPH data (1,300 peritoneal-dialysis patients): which factors are associated with the risk of having a chronic disease (Chronic Disease) when age, gender, BMI group, treatment group and income are considered together? 50.2% (653 patients) have a chronic disease. Women had 1.19 times the risk of men (adjusted RR, 95% CI 1.05 to 1.34), while the OR for the same variable from a logistic regression with the same variables is 1.43; reading the OR as "43% higher risk" more than doubles the actual 19%. Second example: the risk of death during follow-up (Study Status), where log-binomial cannot be fitted and DAPH switches to modified Poisson by itself.

2หลักการและสูตรLogic and Formula

Log-binomial (maximum likelihood)
$$ \log p_i = \beta_0 + \beta_1 X_{1i} + \dots + \beta_k X_{ki},\qquad Y_i \sim \mathrm{Bernoulli}(p_i),\qquad \mathrm{RR}_j = e^{\beta_j} $$ $$ \ell(\beta) = \sum_i \bigl[\,y_i \log p_i + (1-y_i)\log(1-p_i)\,\bigr],\qquad 0 < p_i < 1 $$
Modified Poisson (Zou, 2004) — robust sandwich variance (HC0)
$$ \log \mu_i = X_i\beta,\qquad \widehat{V}(\hat\beta) = A^{-1} B A^{-1},\quad A = \sum_i \hat\mu_i X_i X_i^{\top},\quad B = \sum_i (y_i - \hat\mu_i)^2 X_i X_i^{\top} $$
95% CI and p of each coefficient (Wald)
$$ 95\%\,\mathrm{CI} = \exp\bigl(\hat\beta_j \pm z_{0.975}\,SE_j\bigr),\quad z_{0.975} = 1.96,\qquad z_j = \hat\beta_j / SE_j $$
One p per variable with q parameters (q = levels − 1 for a categorical variable)
$$ \text{log-binomial: } LR = 2\bigl(\ell_{\text{full}} - \ell_{\text{without the variable}}\bigr) \sim \chi^2(q),\qquad \text{modified Poisson: } W = \hat b^{\top}\,\widehat{V}_{b}^{-1}\,\hat b \sim \chi^2(q) $$
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

R script stats 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)
Expected R output (R 4.3.3, sandwich, lmtest; abridged)
[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
DAPH Tab 2 > ชนิดตัวแปรตาม Categorical > สถิติ Log-binomial Regression > Dependent Variable = Chronic Disease (chronic) > Independent Variables = Age, Gender, BMI Group, Treatment Group, Personal Income > วิธี Enter แล้ววิธี Backward Elimination · ตัวอย่างการเสียชีวิต: Dependent Variable = Study Status (status), Independent Variables = Age, Treatment Group, Number of Peritonitis Episodes, Number of Infections, Chronic Disease, Enter · แถว modified Poisson ของแบบจำลองโรคเรื้อรังมาจากคำขอ API ที่ใส่ rr_settings = {"method": "modified_poisson"} · OR มาจาก Logistic Regression (Enter) ด้วยตัวแปรชุดเดียวกันTab 2 > outcome type Categorical > statistic Log-binomial Regression > Dependent Variable = Chronic Disease (chronic) > Independent Variables = Age, Gender, BMI Group, Treatment Group, Personal Income > method Enter, then Backward Elimination. Death example: Dependent Variable = Study Status (status), Independent Variables = Age, Treatment Group, Number of Peritonitis Episodes, Number of Infections, Chronic Disease, Enter. The modified Poisson rows of the chronic-disease model come from an API request with rr_settings = {"method": "modified_poisson"}; the OR comes from Logistic Regression (Enter) with the same variables.
QuantityR 4.3.3DAPHความต่างDifferenceStatus
Log-binomial RR gender (Female), 95% CI, SE1.18993 (1.05357 to 1.34393), SE 0.062101.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), SE1.54149, SE 0.114831.54149, SE 0.11483< 0.000005✓ PASS
Log-binomial RR age (per year), p1.01236, p 0.000811.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.171720.00413 / 0.0000143 / 0.08383 / 0.17172 (table: 0.004 / <0.001 / 0.084 / 0.172)< 0.000005✓ PASS
Model LR χ²(8); AIC52.643; 1767.51252.643; 1767.51< 0.005✓ PASS
Adjusted OR gender (Female), logistic regression, same variables1.4261.426< 0.0005✓ PASS
Backward: removed (p), then final LR χ²(5)income (0.17172), group (0.10053) · 46.422income (0.17172), group (0.10053) · 46.422< 0.000005✓ PASS
Modified Poisson RR BMI group (Obese), sandwich SE1.59829, SE 0.116101.59829, SE 0.11610 (table: 1.598)< 0.000005✓ PASS
Robust Wald χ² BMI group (3 df)29.2170229.21702< 0.000005✓ PASS
Death model: methodlog-binomial stops at a fitted risk of 1log-binomial "did not converge" → Modified Poisson—✓ PASS
Death model (modified Poisson): RR treatment group (APD); chronic disease1.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
  1. 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
  2. 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
  3. 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 2 stats ✓ 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).

ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย): ความถี่การกินอาหารเค็ม (Salty food frequency) มี 5 ระดับเรียงจากน้อยไปมาก คือ Never (0) 269 ราย · A few days (1-4) 674 ราย · About half the days (5-9) 124 ราย · Most days (10-13) 53 ราย · All day (14) 180 ราย คำถามคือ อายุ เพศ กลุ่ม BMI โรคเรื้อรัง และรายได้ครัวเรือน สัมพันธ์กับความถี่การกินเค็มหรือไม่ · ผล: เมื่อปรับตัวแปรอื่นแล้ว ผู้ที่มีโรคเรื้อรังมี odds ของการอยู่ในระดับความถี่ที่สูงกว่าเป็น 1.255 เท่าของผู้ไม่มีโรคเรื้อรัง (adjusted OR 1.255, 95% CI 1.019 to 1.547, p = 0.033)
DAPH example data (1,300 peritoneal-dialysis patients): Salty food frequency has five ordered levels: Never (0) 269 patients · A few days (1-4) 674 · About half the days (5-9) 124 · Most days (10-13) 53 · All day (14) 180. Question: are age, gender, BMI group, chronic disease and household income associated with how often patients eat salty food? Result: after adjustment, patients with a chronic disease had 1.255 times the odds of being in a higher frequency level than patients without one (adjusted OR 1.255, 95% CI 1.019 to 1.547, p = 0.033).

2หลักการและสูตรLogic and Formula

Cumulative logit (proportional odds) model
$$ \operatorname{logit} P(Y \le j \mid \mathbf{x}) = \theta_j - \mathbf{x}^{\top}\boldsymbol{\beta},\qquad j = 1,\dots,J-1,\qquad \theta_1 < \theta_2 < \dots < \theta_{J-1} $$ $$ P(Y = j \mid \mathbf{x}) = F(\theta_j - \mathbf{x}^{\top}\boldsymbol{\beta}) - F(\theta_{j-1} - \mathbf{x}^{\top}\boldsymbol{\beta}),\qquad F(t) = \frac{1}{1 + e^{-t}},\quad \theta_0 = -\infty,\ \theta_J = +\infty $$
Odds ratio (the same at every cut-point j) and 95% CI
$$ \mathrm{OR}_m = \frac{\mathrm{odds}(Y > j \mid x_m + 1)}{\mathrm{odds}(Y > j \mid x_m)} = e^{\beta_m},\qquad 95\%\,\mathrm{CI} = \exp\bigl(\hat{\beta}_m \pm 1.96\,SE_m\bigr) $$
p values (one per variable)
$$ z_m = \hat{\beta}_m / SE_m \ \ \text{(continuous)},\qquad W = \hat{\boldsymbol{\beta}}_G^{\top}\,\widehat{\mathbf{V}}_G^{-1}\,\hat{\boldsymbol{\beta}}_G \sim \chi^2_{q} \ \ \text{(categorical, } q \text{ dummy columns)} $$
Model fit
$$ \mathrm{LR} = 2(\ell - \ell_0) \sim \chi^2_{k},\qquad R^2_{\mathrm{McF}} = 1 - \ell/\ell_0,\qquad \mathrm{AIC} = -2\ell + 2(J-1+k),\qquad \mathrm{BIC} = -2\ell + (J-1+k)\ln n $$
Checking proportional odds (likelihood-ratio test, one variable at a time)
$$ \mathrm{LR}_{\mathrm{PO}} = 2(\ell_{\text{separate slopes}} - \ell) \sim \chi^2_{(J-2)\,q} $$
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

R script แพ็กเกจ 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)
R script ตรวจข้อตกลง PO (DAPH ไม่ได้คำนวณ) ต่อจากสคริปต์ข้างบนchecking the PO assumption (not computed by DAPH), continuing the script above
# 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)
Expected R output (R 4.3.3, ordinal 2023.12-4, abridged)
                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
DAPH Tab 2 → ตัวแปรตามแบบกลุ่ม (Categorical) → Dependent = Salty food frequency (ต้องเป็นชนิด ordinal) → Ordered Logistic Regression → Method = Enter → Independent = Age (years), Gender, BMI Group, Chronic Disease, Household IncomeTab 2 → Categorical outcome → Dependent = Salty food frequency (must be of type ordinal) → Ordered Logistic Regression → Method = Enter → Independent = Age (years), Gender, BMI Group, Chronic Disease, Household Income
QuantityR 4.3.3DAPH|R − DAPH|Status
Age (per year): OR (95% CI), p0.994 (0.979 to 1.009), 0.4120.994 (0.979 to 1.009), 0.412<1e−6✓ PASS
Gender, Female vs Male: OR (95% CI), p1.034 (0.832 to 1.285), 0.7601.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.0230.023<1e−6✓ PASS
Chronic disease, Yes vs No: OR (95% CI), p1.255 (1.019 to 1.547), 0.0331.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.0170.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.15163e−9✓ PASS
SE of θ1 / θ2 / θ3 / θ4 (Tab 3 summary)0.5909 / 0.5880 / 0.5883 / 0.58900.5909 / 0.5880 / 0.5883 / 0.5890<5e−5 (4 decimals shown)✓ PASS
LR χ² against the thresholds-only model (8 df), p22.897, 0.003522.897, 0.003<5e−4 (3 decimals shown)✓ PASS
McFadden R²0.00680.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
  1. Brant, R. (1990). Assessing proportionality in the proportional odds model for ordinal logistic regression. Biometrics, 46(4), 1171–1178. doi:10.2307/2532457
  2. 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
  3. 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
  4. 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).

ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย): กลุ่ม BMI (BMI Group) มี 4 ระดับ คือ Underweight 126 ราย · Normal 543 ราย · Overweight 290 ราย · Obese 341 ราย และเก็บเป็นตัวแปรชนิด nominal แบบจำลองนี้เทียบแต่ละกลุ่มกับกลุ่มน้ำหนักน้อย (Underweight) โดยไม่บังคับว่าตัวแปรต้องเลื่อน BMI ไปทางเดียว คำถามคือ อายุ เพศ โรคเรื้อรัง กลุ่มการรักษา (CAPD/APD) และรายได้ส่วนบุคคล สัมพันธ์กับกลุ่ม BMI หรือไม่ · ผล: ผู้มีโรคเรื้อรังมีโอกาสอยู่ในกลุ่มอ้วนเมื่อเทียบกับกลุ่มน้ำหนักน้อยสูงกว่าผู้ไม่มีโรคเรื้อรัง (RRR 2.61, 95% CI 1.69 to 4.03, p < 0.001)
DAPH example data (1,300 peritoneal-dialysis patients): BMI Group has four categories: Underweight 126 patients · Normal 543 · Overweight 290 · Obese 341, stored as a nominal variable. The model compares each group with Underweight without forcing a predictor to shift BMI in one direction. Question: are age, gender, chronic disease, treatment group (CAPD/APD) and personal income associated with BMI group? Result: patients with a chronic disease had a higher relative risk of being obese rather than underweight than patients without one (RRR 2.61, 95% CI 1.69 to 4.03, p < 0.001).

2หลักการและสูตรLogic and Formula

Baseline-category logit model (reference category r)
$$ \ln\frac{P(Y = j \mid \mathbf{x})}{P(Y = r \mid \mathbf{x})} = \beta_{0j} + \mathbf{x}^{\top}\boldsymbol{\beta}_j,\qquad j \ne r $$ $$ P(Y = j \mid \mathbf{x}) = \frac{\exp(\beta_{0j} + \mathbf{x}^{\top}\boldsymbol{\beta}_j)}{1 + \sum_{k \ne r} \exp(\beta_{0k} + \mathbf{x}^{\top}\boldsymbol{\beta}_k)},\qquad \boldsymbol{\beta}_r \equiv \mathbf{0} $$
Relative risk ratio and 95% CI
$$ \mathrm{RRR}_{jm} = \frac{P(Y=j \mid x_m+1)\,/\,P(Y=r \mid x_m+1)}{P(Y=j \mid x_m)\,/\,P(Y=r \mid x_m)} = e^{\beta_{jm}},\qquad 95\%\,\mathrm{CI} = \exp\bigl(\hat{\beta}_{jm} \pm 1.96\,SE_{jm}\bigr) $$
Tests
$$ z_{jm} = \hat{\beta}_{jm} / SE_{jm},\qquad W_{jG} = \hat{\boldsymbol{\beta}}_{jG}^{\top}\,\widehat{\mathbf{V}}_{jG}^{-1}\,\hat{\boldsymbol{\beta}}_{jG} \sim \chi^2_{q},\qquad \mathrm{LR}_G = 2(\ell - \ell_{-G}) \sim \chi^2_{(J-1)q} $$
Model fit
$$ \mathrm{LR} = 2(\ell - \ell_0) \sim \chi^2_{(J-1)k},\qquad R^2_{\mathrm{McF}} = 1 - \ell/\ell_0,\qquad \mathrm{AIC} = -2\ell + 2(J-1)(k+1),\qquad \mathrm{BIC} = -2\ell + (J-1)(k+1)\ln n $$
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

R script แพ็กเกจ 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
Expected R output (R 4.3.3, nnet 7.3-19, car 3.1-2, abridged)
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
DAPH Tab 2 → ตัวแปรตามแบบกลุ่ม (Categorical) → Dependent = BMI Group → Multinomial Logistic Regression → Method = Enter → Independent = Age (years), Gender, Chronic Disease, Treatment Group, Personal IncomeTab 2 → Categorical outcome → Dependent = BMI Group → Multinomial Logistic Regression → Method = Enter → Independent = Age (years), Gender, Chronic Disease, Treatment Group, Personal Income
Quantity (Normal / Overweight / Obese, each vs Underweight)R 4.3.3DAPH|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.2940.194 / 0.089 / 0.2943e−10✓ PASS
Chronic disease: Wald p per comparison0.108 / 0.044 / <0.0010.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.0951e−8✓ PASS
LR χ² of gender (3 df) / income (6 df) in the Word text11.89 / 10.8011.89 / 10.801e−8✓ PASS
Chronic disease = Yes: % Normal / Overweight / Obese39.05 / 21.29 / 31.7039.05 / 21.29 / 31.700✓ PASS
Log-likelihood / AIC / BIC−1596.088 / 3234.18 / 3342.75−1596.088 / 3234.18 / 3342.751e−6✓ PASS
LR χ²(18) against the intercept-only model, p · McFadden R²126.857, <0.001 · 0.0382126.857, <0.001 · 0.03821e−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
  1. Agresti, A. (2013). Categorical data analysis (3rd ed.). Wiley. ISBN 978-0-470-46363-5.
  2. Hausman, J., & McFadden, D. (1984). Specification tests for the multinomial logit model. Econometrica, 52(5), 1219–1240. doi:10.2307/1910997
  3. Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied logistic regression (3rd ed.). Wiley. doi:10.1002/9781118548387
  4. 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.
  5. 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 2 stats ✓ 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).

ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย): จำนวนครั้งที่ติดเชื้อในช่องท้อง (Number of Peritonitis Episodes) รวม 1,648 ครั้ง ในระยะติดตามรวม 2,389.42 คน-ปี (Follow-up Duration (years)) อัตราการติดเชื้อในช่องท้องเป็นตัวชี้วัดคุณภาพสำคัญของการล้างไตทางช่องท้อง คำถามคือ อัตรานี้ต่างกันระหว่าง APD กับ CAPD หรือไม่ เมื่อปรับอายุ เพศ และโรคเรื้อรัง · ผล: CAPD 94.06 ครั้งต่อ 100 คน-ปี และ APD 41.34 ครั้งต่อ 100 คน-ปี หลังปรับแล้ว APD มีอัตราเป็น 0.45 เท่าของ CAPD (adjusted IRR 0.45, 95% CI 0.39 to 0.52, p < 0.001)
DAPH example data (1,300 peritoneal-dialysis patients): 1,648 peritonitis episodes (Number of Peritonitis Episodes) over 2,389.42 person-years of follow-up (Follow-up Duration (years)). The peritonitis rate is a key quality indicator of a peritoneal-dialysis programme. Question: does the rate differ between APD and CAPD after adjusting for age, gender and chronic disease? Result: 94.06 episodes per 100 person-years with CAPD and 41.34 with APD; after adjustment APD had 0.45 times the CAPD rate (adjusted IRR 0.45, 95% CI 0.39 to 0.52, p < 0.001).

2หลักการและสูตรLogic and Formula

Poisson rate model with an offset
$$ Y_i \sim \mathrm{Poisson}(\mu_i),\qquad \ln \mu_i = \ln t_i + \beta_0 + \beta_1 x_{1i} + \dots + \beta_k x_{ki},\qquad \mathrm{Var}(Y_i) = \mu_i $$
Negative binomial (NB2)
$$ \mathrm{Var}(Y_i) = \mu_i + \alpha\,\mu_i^2,\qquad \alpha = 1/\theta \ge 0\quad(\alpha = 0 \text{ gives the Poisson model}) $$
Incidence rate ratio and 95% CI
$$ \mathrm{IRR}_m = e^{\beta_m},\qquad 95\%\,\mathrm{CI} = \exp\bigl(\hat{\beta}_m \pm 1.96\,SE_m\bigr),\qquad \mathrm{IR}_g = 100 \times \frac{\sum_{i \in g} y_i}{\sum_{i \in g} t_i}\ \text{per 100 person-years} $$
Overdispersion check on the Poisson fit
$$ \frac{X^2}{n-p} = \frac{1}{n-p}\sum_i \frac{(y_i - \hat{\mu}_i)^2}{\hat{\mu}_i},\qquad \frac{D}{n-p},\quad D = 2\sum_i \Bigl[\,y_i \ln\frac{y_i}{\hat{\mu}_i} - (y_i - \hat{\mu}_i)\Bigr]\ \ (y_i \ln y_i = 0 \text{ when } y_i = 0) $$
Tests and fit
$$ z_m = \hat{\beta}_m / SE_m,\qquad \mathrm{LR}_G = 2(\ell - \ell_{-G}) \sim \chi^2_{q},\qquad \mathrm{AIC}_{\mathrm{NB}} = -2\ell + 2(p + 1) $$
Likelihood-ratio test of α = 0 (Poisson nested in NB)
$$ \mathrm{LR}_\alpha = 2(\ell_{\mathrm{NB}} - \ell_{\mathrm{Poisson}}),\qquad p = \tfrac{1}{2}\,P\bigl(\chi^2_1 > \mathrm{LR}_\alpha\bigr) $$
μ_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

R script R 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
R script การทดสอบ α = 0 (DAPH ไม่ได้คำนวณ) ต่อจากสคริปต์ข้างบนtest of α = 0 (not computed by DAPH), continuing the script above
# 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)
Expected R output (R 4.3.3, MASS 7.3-60.0.1)
      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
DAPH Tab 2 → ตัวแปรตามแบบนับ (Count) → Poisson regression → ตัวแปรนับ = Number of Peritonitis Episodes → Offset (person-time) = Follow-up Duration (years) (ตัวแปรที่มีอยู่) → Independent = Treatment Group, Age (years), Gender, Chronic Disease → Method = EnterTab 2 → Count outcome → Poisson regression → count variable = Number of Peritonitis Episodes → Offset (person-time) = Follow-up Duration (years) (existing variable) → Independent = Treatment Group, Age (years), Gender, Chronic Disease → Method = Enter
QuantityR 4.3.3DAPH|R − DAPH|Status
Events / person-years; IR per 100 person-years CAPD / APD1648 / 2389.42; 94.06 / 41.341,648 / 2,389.4; 94.06 / 41.340✓ PASS
Poisson fit: Pearson χ²/df / deviance/df1.784 / 1.6831.784 / 1.683<5e−5✓ PASS
Model usedNB (Pearson χ²/df > 1.5)Negative binomial—✓ PASS
α (θ) by maximum likelihood · SE(α)0.634 (θ 1.5778) · 0.0650.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.783e−7✓ PASS
APD vs CAPD: adjusted IRR (95% CI), LR p0.45 (0.39 to 0.52), <0.0010.45 (0.39 to 0.52), <0.0011e−8✓ PASS
Age per year: adjusted IRR (95% CI), Wald p1.02 (1.01 to 1.03), <0.0011.02 (1.01 to 1.03), <0.0011e−8✓ PASS
Female vs Male: adjusted IRR (95% CI), LR p0.94 (0.82 to 1.09), 0.4210.94 (0.82 to 1.09), 0.4211e−8✓ PASS
Chronic disease Yes vs No: adjusted IRR (95% CI), LR p1.32 (1.15 to 1.51), <0.0011.32 (1.15 to 1.51), <0.0011e−8✓ PASS
Crude IRR: group / age / gender / chronic0.45 / 1.02 / 1.02 / 1.390.45 / 1.02 / 1.02 / 1.39<5e−3✓ PASS
LR χ²(4) against the intercept-only NB model · NB deviance/df153.715 · 0.986153.715 · 0.9862e−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
  1. Cameron, A. C., & Trivedi, P. K. (2013). Regression analysis of count data (2nd ed.). Cambridge University Press. doi:10.1017/CBO9781139013567
  2. 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
  3. 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.

ข้อมูลตัวอย่าง DAPH: คำถามเดียวกับหัวข้อ 4.1 (อัตราการติดเชื้อในช่องท้อง APD เทียบ CAPD ปรับอายุ เพศ และโรคเรื้อรัง โดยใช้ระยะเวลาติดตามเป็น offset) แต่คำนึงว่าผู้ป่วยมาจาก 7 โรงพยาบาล (Hospital) ผู้ป่วย 3 รายไม่มีรหัสโรงพยาบาลจึงถูกตัดออก เหลือ 1,297 ราย 1,644 ครั้ง · ผล: APD มีอัตราเป็น 0.449 เท่าของ CAPD (IRR 0.449, 95% CI 0.403 to 0.500, p < 0.001) ความแปรปรวนระหว่างโรงพยาบาล 0.0062 (likelihood-ratio test p = 0.036) และ ICC = 0.0087
DAPH example data: the question of section 4.1 (peritonitis rate, APD versus CAPD, adjusted for age, gender and chronic disease, with follow-up time as the offset), now allowing for the 7 hospitals (Hospital). Three patients without a hospital code are dropped, leaving 1,297 patients and 1,644 episodes. Result: APD had 0.449 times the CAPD rate (IRR 0.449, 95% CI 0.403 to 0.500, p < 0.001); the between-hospital variance was 0.0062 (likelihood-ratio test p = 0.036) and ICC = 0.0087.

2หลักการและสูตรLogic and Formula

Random-intercept Poisson model (GLMM) with an offset
$$ Y_{ij} \mid b_j \sim \mathrm{Poisson}(\mu_{ij}),\qquad \ln \mu_{ij} = \ln t_{ij} + \beta_0 + \mathbf{x}_{ij}^{\top}\boldsymbol{\beta} + b_j,\qquad b_j \sim N(0, \sigma^2) $$ $$ L(\boldsymbol{\beta}, \sigma) = \prod_{j=1}^{J} \int \prod_{i} \frac{\mu_{ij}^{\,y_{ij}} e^{-\mu_{ij}}}{y_{ij}!}\;\frac{1}{\sigma\sqrt{2\pi}}\, e^{-b^2/(2\sigma^2)}\, db $$
IRR, 95% CI and tests
$$ \mathrm{IRR}_m = e^{\beta_m},\qquad 95\%\,\mathrm{CI} = \exp\bigl(\hat{\beta}_m \pm 1.96\,SE_m\bigr),\qquad \mathrm{LR} = 2(\ell_{\mathrm{GLMM}} - \ell_{\mathrm{Poisson}}),\quad p = \tfrac{1}{2}\,P\bigl(\chi^2_1 > \mathrm{LR}\bigr) $$
ICC on the count scale (Nakagawa et al., 2017) and dispersion
$$ \mathrm{ICC} = \frac{\sigma^2}{\sigma^2 + \ln(1 + 1/\lambda)},\qquad \lambda = \exp\Bigl(\overline{\ln t_{ij} + \mathbf{x}_{ij}^{\top}\hat{\boldsymbol{\beta}}} + \sigma^2/2\Bigr),\qquad \phi = \frac{1}{n - p - 1}\sum_{ij} \frac{(y_{ij} - \hat{\mu}_{ij})^2}{\hat{\mu}_{ij}} $$ $$ \mathrm{Deff} = 1 + (\bar{m} - 1)\,\mathrm{ICC},\qquad \bar{m} = n / J $$
Fit
$$ \mathrm{AIC} = -2\ell + 2(p + 1),\qquad \mathrm{BIC} = -2\ell + (p + 1)\ln n $$
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

R script แพ็กเกจ 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)
R script GEE Poisson เพื่อเปรียบเทียบ (DAPH ไม่มี) แพ็กเกจ 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)
Expected R output (R 4.3.3, lme4 1.1-35.1, geepack 1.3.10)
           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
DAPH Tab 2 → ตัวแปรตามแบบนับ (Count) → ติ๊ก “โมเดล Mixed Effects” → Mixed Effect Poisson Regression → ตัวแปรนับ = Number of Peritonitis Episodes → Offset (Person-time) = Follow-up Duration (years) → Random Effect Variable = Hospital → Independent = Treatment Group, Age (years), Gender, Chronic Disease → Method = EnterTab 2 → Count outcome → tick “Mixed Effects Model” → Mixed Effect Poisson Regression → count variable = Number of Peritonitis Episodes → Offset (Person-time) = Follow-up Duration (years) → Random Effect Variable = Hospital → Independent = Treatment Group, Age (years), Gender, Chronic Disease → Method = Enter
QuantityR 4.3.3DAPH|R − DAPH|Status
Patients / hospitals / events / person-years1297 / 7 / 1644 / 2383.731,297 / 7 / 1,644 / 2,383.70✓ PASS
APD vs CAPD: IRR (95% CI), p0.449 (0.403 to 0.500), <0.0010.449 (0.403 to 0.500), <0.0011.6e−5✓ PASS
Age per year: IRR (95% CI), p1.019 (1.012 to 1.026), <0.0011.019 (1.012 to 1.026), <0.0012e−6✓ PASS
Female vs Male: IRR (95% CI), p0.965 (0.870 to 1.069), 0.4910.965 (0.870 to 1.069), 0.4911.3e−4✓ PASS
Chronic disease Yes vs No: IRR (95% CI), p1.345 (1.218 to 1.485), <0.0011.345 (1.218 to 1.485), <0.0014.7e−5✓ PASS
Between-hospital variance / SD0.0062 / 0.07880.0062 / 0.07887e−7✓ PASS
LR test of σ² = 0: χ², p (half χ²₁)3.224, 0.0363.224, 0.0363e−7✓ PASS
ICC (count scale)0.00870.00879e−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.771.77<5e−5✓ PASS
Log-likelihood / AIC / BIC−1981.902 / 3975.8 / 4006.8−1981.902 / 3975.8 / 4006.81e−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
  1. 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
  2. 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
  3. 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
  4. 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
  5. 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 2 stats ✓ 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.

ข้อมูลตัวอย่าง DAPH: ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย ติดตามนานสุด 1,095 วัน เสียชีวิต 229 ราย (Study Status = 1 Died/Event) คำถามคือ การรอดชีพต่างกันระหว่าง CAPD กับ APD หรือไม่ · ผล: อัตรารอดชีพ 1 ปี CAPD 90.7% (95% CI 88.5 to 93.0) และ APD 84.6% (95% CI 81.8 to 87.4) · 2 ปี CAPD 86.1% และ APD 77.8% · log-rank χ²(1) = 19.18, p < 0.001 · ทั้งสองกลุ่มยังไม่ถึงค่ามัธยฐานของเวลารอดชีพ (not reached)
DAPH example data: 1,300 peritoneal-dialysis patients followed for up to 1,095 days; 229 died (Study Status = 1 Died/Event). Question: does survival differ between CAPD and APD? Result: 1-year survival 90.7% with CAPD (95% CI 88.5 to 93.0) and 84.6% with APD (95% CI 81.8 to 87.4); 2-year survival 86.1% and 77.8%; log-rank χ²(1) = 19.18, p < 0.001. Median survival was not reached in either group.

2หลักการและสูตรLogic and Formula

Kaplan-Meier estimator and Greenwood variance
$$ \hat{S}(t) = \prod_{t_i \le t} \Bigl(1 - \frac{d_i}{n_i}\Bigr),\qquad \widehat{\mathrm{Var}}\bigl(\ln \hat{S}(t)\bigr) = \sum_{t_i \le t} \frac{d_i}{n_i\,(n_i - d_i)} = v(t) $$
95% CI of survival at a fixed time (log scale; DAPH table, R default)
$$ \hat{S}(t)\,\exp\bigl(\pm 1.96\sqrt{v(t)}\bigr)\quad(\text{upper limit capped at } 1) $$
Median survival and its 95% CI (log−log scale; DAPH)
$$ \hat{t}_{0.5} = \min\{t : \hat{S}(t) \le 0.5\},\qquad \hat{S}(t)^{\exp(\pm 1.96\, s(t))},\quad s(t) = \frac{\sqrt{v(t)}}{\lvert \ln \hat{S}(t) \rvert} $$
Log-rank test (two groups)
$$ E_{1j} = d_j\,\frac{n_{1j}}{n_j},\qquad V_{1j} = \frac{n_{1j}\,n_{2j}\,d_j\,(n_j - d_j)}{n_j^2\,(n_j - 1)},\qquad \chi^2 = \frac{\bigl[\sum_j (d_{1j} - E_{1j})\bigr]^2}{\sum_j V_{1j}} \sim \chi^2_1 $$
Incidence rate
$$ \mathrm{IR} = 100 \times \frac{\text{events}}{\text{person-years}},\qquad \text{person-years} = \frac{\sum \text{follow-up days}}{365.25} $$
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

R script แพ็กเกจ 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)
Expected R output (R 4.3.3, survival 3.5-8)
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
DAPH Tab 2 → ตัวแปรตามแบบเวลาเกิดเหตุการณ์ (Survival) → Kaplan-Meier → Event variable = Study Status, ค่าที่หมายถึง Event = 1 (Died/Event) → ตัวแปรเวลา: ใช้ตัวแปรเวลาที่มีอยู่ = Follow-up Duration (days), หน่วย Days → ตัวแปรแบ่งกลุ่ม (Independent) = Treatment GroupTab 2 → Survival outcome → Kaplan-Meier → Event variable = Study Status, Event Value = 1 (Died/Event) → Time Variable: use existing = Follow-up Duration (days), unit Days → grouping (Independent) = Treatment Group
Quantity (CAPD / APD)R 4.3.3DAPH|R − DAPH|Status
n / events656 / 86 · 644 / 143656 / 86 · 644 / 1430✓ PASS
Median survival (95% CI)not reached (NA)NR—✓ PASS
Person-years · deaths per 100 person-years1252.50 / 1137.01 · 6.87 / 12.581252.5 / 1137.0 · 6.87 / 12.580✓ 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), p19.18 (1), <0.00119.18 (1), <0.001<5e−7✓ PASS
Tab 3 summary: events per group · log-rank line86 / 143 · χ²(1) = 19.1886 / 143 · χ²(1) = 19.180✓ 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
  1. Brookmeyer, R., & Crowley, J. (1982). A confidence interval for the median survival time. Biometrics, 38(1), 29–41. doi:10.2307/2530286
  2. 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
  3. 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
  4. 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
  5. 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.

ข้อมูลตัวอย่าง DAPH: ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย เสียชีวิต 229 ราย (หัวข้อ 5.1 พบว่าการรอดชีพของ APD ต่ำกว่า CAPD) คำถามคือ เมื่อปรับอายุ เพศ โรคเรื้อรัง และกลุ่ม BMI แล้ว APD ยังสัมพันธ์กับการเสียชีวิตที่สูงกว่าหรือไม่ · ผล: adjusted HR 1.89 (95% CI 1.45 to 2.48, p < 0.001) · การทดสอบ PH พบว่าตัวแปรโรคเรื้อรังอาจไม่เป็นไปตามข้อตกลง (p = 0.027)
DAPH example data: 1,300 peritoneal-dialysis patients, 229 deaths (section 5.1 found lower survival with APD). Question: is APD still associated with higher mortality after adjusting for age, gender, chronic disease and BMI group? Result: adjusted HR 1.89 (95% CI 1.45 to 2.48, p < 0.001). The PH test suggests that chronic disease may not meet the assumption (p = 0.027).

2หลักการและสูตรLogic and Formula

Model and partial likelihood with Efron's handling of tied event times
$$ h(t \mid \mathbf{x}) = h_0(t)\,\exp(\mathbf{x}^{\top}\boldsymbol{\beta}) $$ $$ L(\boldsymbol{\beta}) = \prod_{j} \frac{\exp\Bigl(\sum_{i \in D_j} \mathbf{x}_i^{\top}\boldsymbol{\beta}\Bigr)}{\prod_{r=0}^{d_j - 1}\Bigl[\sum_{i \in R_j} e^{\mathbf{x}_i^{\top}\boldsymbol{\beta}} - \frac{r}{d_j}\sum_{i \in D_j} e^{\mathbf{x}_i^{\top}\boldsymbol{\beta}}\Bigr]} $$
Hazard ratio, 95% CI and tests
$$ \mathrm{HR}_m = e^{\beta_m},\qquad 95\%\,\mathrm{CI} = \exp\bigl(\hat{\beta}_m \pm 1.96\,SE_m\bigr),\qquad \mathrm{LR}_G = 2(\ell - \ell_{-G}) \sim \chi^2_{q},\qquad \mathrm{LR} = 2(\ell - \ell_0) \sim \chi^2_{k} $$
Proportional-hazards test (Grambsch & Therneau, 1994)
$$ \beta_m(t) = \beta_m + \gamma_m\, g(t),\quad g(t) = 1 - \hat{S}(t^-)\ \text{(Kaplan-Meier scale, centred)},\qquad T_m = U_{\gamma_m}^{\top}\,\bigl[\mathcal{I}^{-1}\bigr]_{\gamma_m}\,U_{\gamma_m} \sim \chi^2_{q_m} \ \ (H_0: \gamma_m = 0) $$
Harrell's concordance (C)
$$ C = \frac{\#\{\text{concordant pairs}\} + \tfrac{1}{2}\#\{\text{pairs tied on } \hat{\eta}\}}{\#\{\text{comparable pairs}\}},\qquad \hat{\eta}_i = \mathbf{x}_i^{\top}\hat{\boldsymbol{\beta}} $$
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

R script แพ็กเกจ 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)
Expected R output (R 4.3.3, survival 3.5-8)
                        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
DAPH Tab 2 → ตัวแปรตามแบบเวลาเกิดเหตุการณ์ (Survival) → Cox regression → Event variable = Study Status, ค่าที่หมายถึง Event = 1 → ตัวแปรเวลา: ใช้ตัวแปรเวลาที่มีอยู่ = Follow-up Duration (days), หน่วย Days → Independent = Treatment Group, Age (years), Gender, Chronic Disease, BMI Group → Method = EnterTab 2 → Survival outcome → Cox regression → Event variable = Study Status, Event Value = 1 → Time Variable: use existing = Follow-up Duration (days), unit Days → Independent = Treatment Group, Age (years), Gender, Chronic Disease, BMI Group → Method = Enter
QuantityR 4.3.3DAPH|R − DAPH|Status
APD vs CAPD: adjusted HR (95% CI), LR p1.89 (1.45 to 2.48), <0.0011.89 (1.45 to 2.48), <0.001<1e−8✓ PASS
Age per year: adjusted HR (95% CI), Wald p1.04 (1.02 to 1.06), <0.0011.04 (1.02 to 1.06), <0.001<1e−8✓ PASS
Female vs Male: adjusted HR (95% CI), LR p1.16 (0.87 to 1.54), 0.3021.16 (0.87 to 1.54), 0.302<1e−8✓ PASS
Chronic disease Yes vs No: adjusted HR (95% CI), LR p1.54 (1.18 to 2.02), 0.0011.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.8960.88 / 0.84 / 0.84; 0.896<1e−8✓ PASS
Crude HR: group / age / gender / chronic1.80 / 1.04 / 1.20 / 1.571.80 / 1.04 / 1.20 / 1.57<5e−3✓ PASS
Concordance C · model LR χ²(7)0.6349 · 53.040.6349 · 53.04<5e−5✓ PASS
PH test χ² (p): group / age / gender / chronic / BMI group0.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), p11.062, 0.13611.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
  1. 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
  2. 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
  3. 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
  4. 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
  5. Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied logistic regression (3rd ed.). Wiley. doi:10.1002/9781118548387
  6. Therneau, T. M., & Grambsch, P. M. (2000). Modeling survival data: Extending the Cox model. Springer. doi:10.1007/978-1-4757-3294-8
  7. 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 10 stats ✓ 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.

📐 ทุกหัวข้อในบทนี้มีสคริปต์ R ที่รันได้และตารางเทียบตัวเลขของ DAPH กับ R (spdep, spatialreg, splm และ package อื่นตามที่ระบุในแต่ละหัวข้อ) บนข้อมูลชุดเดียวกัน — แถวที่ระบุ ✗ FAIL คือจุดที่ DAPH ยังต่างจาก R โดยมีคำอธิบายเหตุผลไว้ใต้ตาราง Every section in this chapter has a runnable R script and a table comparing DAPH's numbers with R (spdep, spatialreg, splm and the other packages named in each section) on the same data — rows marked ✗ FAIL show where DAPH still differs from R, with the reason given under each table
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).

ข้อมูลที่ใช้ในหัวข้อนี้: ข้อมูลตัวอย่างของ DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย) เป็นข้อมูลรายบุคคลที่ไม่มีแผนที่หรือพิกัด จึงสร้าง spatial weights ไม่ได้. หัวข้อนี้จึงใช้ข้อมูลสาธารณะ Columbus ที่มากับ R package spData ซึ่งเปิดได้ทั้งใน R และใน DAPH (สคริปต์ในข้อ 3 สร้างไฟล์ columbus.zip ให้): 49 ย่านของเมือง Columbus รัฐโอไฮโอ ปี 1980 · ผลลัพธ์ CRIME = จำนวนการลักทรัพย์ในบ้านและการขโมยรถต่อ 1,000 ครัวเรือน · INC = รายได้ครัวเรือน (พันดอลลาร์สหรัฐ) · HOVAL = มูลค่าบ้าน (พันดอลลาร์สหรัฐ). คำถามวิจัย: ในระดับย่าน รายได้และมูลค่าบ้านสัมพันธ์กับอัตราอาชญากรรมอย่างไร และอัตราของย่านข้างเคียงยังสัมพันธ์กันหลังคุมสองตัวแปรนี้แล้วหรือไม่ — เป็นคำถามระดับพื้นที่ (ecological) แบบเดียวกับการศึกษาอัตราป่วยรายอำเภอ.
Data used in this section: the DAPH example dataset (1,300 peritoneal-dialysis patients) holds individual records with no map or coordinates, so no spatial weights can be built from it. This section therefore uses the public Columbus data that ship with the R package 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):

Spatial weights (row-standardised)
$$ w_{ij}=\frac{c_{ij}}{\sum_{j} c_{ij}},\qquad c_{ij}=1 \text{ if } i \text{ and } j \text{ share an edge or a corner},\quad c_{ii}=0 $$
OLS · SLM · SEM
$$ \text{OLS: } y = X\beta + \varepsilon \qquad \text{SLM: } y = \rho W y + X\beta + \varepsilon \qquad \text{SEM: } y = X\beta + u,\; u = \lambda W u + \varepsilon $$ $$ \varepsilon \sim \mathcal{N}(0,\sigma^2 I) $$
Maximum likelihood (concentrated log-likelihood)Maximum likelihood (concentrated log-likelihood)
$$ \ell_{\text{SLM}}(\rho) = -\tfrac{n}{2}\ln(2\pi) - \tfrac{n}{2}\ln\hat\sigma^2(\rho) - \tfrac{n}{2} + \ln\lvert I-\rho W\rvert,\qquad \hat\sigma^2(\rho)=\tfrac{1}{n}\lVert (I-\rho W)y - X\hat\beta(\rho)\rVert^2 $$ $$ \ell_{\text{SEM}}(\lambda) = -\tfrac{n}{2}\ln(2\pi) - \tfrac{n}{2}\ln\hat\sigma^2(\lambda) - \tfrac{n}{2} + \ln\lvert I-\lambda W\rvert,\qquad \hat\sigma^2(\lambda)=\tfrac{1}{n}\lVert (I-\lambda W)\bigl(y - X\hat\beta(\lambda)\bigr)\rVert^2 $$
ρ, λ
ค่าที่ทำให้ 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.

R² ในตารางผลของ DAPHThe R² in DAPH's results table
$$ \text{OLS: } R^2 = 1-\frac{e'e}{\sum_i (y_i-\bar y)^2} \qquad \text{SLM, SEM: } R^2_{\text{pseudo}} = 1-\frac{\hat\sigma^2}{\tfrac{1}{n}\sum_i (y_i-\bar y)^2} $$
Moran's I ของส่วนเหลือ OLSof the OLS residuals
$$ I=\frac{n}{S_0}\,\frac{e'We}{e'e},\qquad E(I)=\frac{n}{S_0}\,\frac{\operatorname{tr}(MW)}{n-k},\qquad M=I_n-X(X'X)^{-1}X' $$ $$ \operatorname{Var}(I)=\Bigl(\frac{n}{S_0}\Bigr)^{2}\frac{\operatorname{tr}(MWMW')+\operatorname{tr}(MWMW)+\bigl[\operatorname{tr}(MW)\bigr]^{2}}{(n-k)(n-k+2)}-E(I)^{2},\qquad z=\frac{I-E(I)}{\sqrt{\operatorname{Var}(I)}} $$
Lagrange multiplier (LM) tests — Anselin et al. (1996)
$$ s^2=\frac{e'e}{n},\qquad T=\operatorname{tr}(W'W+W^2),\qquad D=\frac{(WX\hat\beta)'M(WX\hat\beta)}{s^2}+T $$ $$ \mathrm{LM}_{\text{err}}=\frac{(e'We/s^2)^2}{T},\qquad \mathrm{LM}_{\text{lag}}=\frac{(e'Wy/s^2)^2}{D} $$ $$ \mathrm{RLM}_{\text{err}}=\frac{\bigl(e'We/s^2-(T/D)\,e'Wy/s^2\bigr)^2}{T\,(1-T/D)},\qquad \mathrm{RLM}_{\text{lag}}=\frac{\bigl(e'Wy/s^2-e'We/s^2\bigr)^2}{D-T},\qquad \mathrm{SARMA}=\mathrm{RLM}_{\text{lag}}+\mathrm{LM}_{\text{err}} $$
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).

AIC · BIC · likelihood-ratio test
$$ \mathrm{AIC}=-2\ell+2k,\qquad \mathrm{BIC}=-2\ell+k\ln n,\qquad \mathrm{LR}=2\bigl(\ell_{\text{spatial}}-\ell_{\text{OLS}}\bigr)\sim\chi^2(1) $$
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's AIC() 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
ผลกระทบของ SLM แยกตามแนวทาง LeSage & Pace (2009)Effects of the SLM following LeSage & Pace (2009)
$$ S_r(W)=(I-\rho W)^{-1}\beta_r,\qquad \text{Direct}_r=\tfrac{1}{n}\operatorname{tr}S_r(W),\qquad \text{Total}_r=\tfrac{1}{n}\mathbf{1}'S_r(W)\mathbf{1},\qquad \text{Indirect}_r=\text{Total}_r-\text{Direct}_r $$
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):

R script ส่วนที่ 1 — ข้อมูล, weights, OLS และการวินิจฉัย · packages: sf, spdepPart 1 — data, weights, OLS and diagnostics · packages: sf, spdep
# 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
Expected R output (ตัดบางส่วน)(abridged)
   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 * 
R script ส่วนที่ 2 — SLM, SEM, ค่าความเหมาะสม และผลกระทบ · package: spatialregPart 2 — SLM, SEM, fit and effects · package: spatialreg
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)
Expected R output (ตัดบางส่วน)(abridged)
# 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
DAPH File > Open: 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
📊 ตารางเปรียบเทียบค่าหลัก (R 4.3.3: spdep 1.3-1, spatialreg 1.3-1 · DAPH v.2026.08.22, รันวันที่ 2026-10-02)Side-by-side comparison (R 4.3.3: spdep 1.3-1, spatialreg 1.3-1 · DAPH v.2026.08.22, run 2026-10-02)
ค่าที่วัด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²OLS0.5524040.552404< 1e−6✓ PASS
Moran's I ของส่วนเหลือ (z; p)Moran's I of residuals (z; p)OLS0.222109 (2.8393; 0.004521)0.222109 (2.8393; 0.004521)< 1e−6✓ PASS
LM-lag (p)OLS8.897999 (0.002855)8.897999 (0.002855)< 1e−6✓ PASS
LM-error (p)OLS5.206214 (0.022506)5.206214 (0.022506)< 1e−6✓ PASS
Robust LM-lag (p)OLS3.735691 (0.053262)3.735691 (0.053262)< 1e−6✓ PASS
Robust LM-error (p)OLS0.043906 (0.834029)0.043906 (0.834029)< 1e−6✓ PASS
SARMA (p)OLS8.941905 (0.011436)8.941905 (0.011436)< 1e−6✓ PASS
ρSLM0.4233250.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
λSEM0.5467530.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-likelihoodOLS · SLM · SEM−187.3772 · −182.6740 · −183.7494−187.3772 · −182.6740 · −183.7494< 0.0001✓ PASS
Pseudo-R² = 1 − σ̂²/Var(y)SLM · SEM0.646828 · 0.6438490.646828 · 0.643849< 1e−6✓ PASS
AIC (ไม่นับ σ²)AIC (σ² not counted)OLS · SLM · SEM380.7545 · 373.3479 · 375.4989380.7545 · 373.3479 · 375.4989< 0.0001✓ PASS
BIC (ไม่นับ σ²)BIC (σ² not counted)OLS · SLM · SEM386.4299 · 380.9152 · 383.0661386.4299 · 380.9152 · 383.0661< 0.0001✓ PASS
LR เทียบกับ OLS (p)LR vs OLS (p)SLM9.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.

ตัวอย่างการเขียนผล: ส่วนเหลือของแบบจำลอง OLS มี spatial autocorrelation (Moran's I = 0.222, p = 0.005) และการทดสอบ LM ไม่สามารถแยกรูปแบบ lag กับ error ได้ (robust LM-lag p = 0.053; robust LM-error p = 0.834) จึงเลือก spatial lag model ซึ่งมี AIC ต่ำสุด (373.35) และดีกว่า OLS (LR = 9.41, df = 1, p = 0.002). อัตราอาชญากรรมของย่านสัมพันธ์ทางบวกกับของย่านข้างเคียง (ρ = 0.423). รายได้ครัวเรือนที่สูงขึ้น 1,000 ดอลลาร์สัมพันธ์กับการลักทรัพย์และขโมยรถที่น้อยลง 1.10 ครั้งต่อ 1,000 ครัวเรือนในย่านเดียวกัน (direct effect, 95% CI −1.72 to −0.49) และน้อยลง 1.82 ครั้งเมื่อรวมผลผ่านย่านข้างเคียง (total effect, 95% CI −3.17 to −0.86).
Example write-up: The OLS residuals were spatially autocorrelated (Moran's I = 0.222, p = 0.005) and the LM tests did not discriminate between lag and error dependence (robust LM-lag p = 0.053; robust LM-error p = 0.834), so the spatial lag model, which had the lowest AIC (373.35) and improved on OLS (LR = 9.41, df = 1, p = 0.002), was retained. Neighbourhood crime was positively associated with neighbours' crime (ρ = 0.423). USD 1,000 more household income was associated with 1.10 fewer burglaries and vehicle thefts per 1,000 households in the same neighbourhood (direct effect, 95% CI −1.72 to −0.49) and 1.82 fewer when effects through neighbouring areas are included (total effect, 95% CI −3.17 to −0.86).
📖 References
  1. Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
  2. 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
  3. 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
  4. 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
  5. 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
  6. LeSage, J., & Pace, R. K. (2009). Introduction to spatial econometrics. Chapman & Hall/CRC. doi:10.1201/9781420064254
  7. 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.

ตัวอย่างในหัวข้อนี้: ใช้ข้อมูล Columbus ชุดเดียวกับ 6.1 (49 ย่าน ปี 1980 จาก R package spData; ข้อมูลตัวอย่างผู้ป่วยของ DAPH ไม่มีแผนที่จึงใช้ไม่ได้). คำถามวิจัย: รายได้ครัวเรือน (INC) และมูลค่าบ้าน (HOVAL) ของ ย่านข้างเคียง สัมพันธ์กับอัตราการลักทรัพย์และขโมยรถ (CRIME) ของย่านหนึ่ง นอกเหนือจากรายได้และมูลค่าบ้านของย่านนั้นเองหรือไม่ และ SDM จำเป็นกว่า SLM หรือ SEM หรือไม่.
Example in this section: the same Columbus data as 6.1 (49 neighbourhoods, 1980, R package 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

SDM · Spatial Durbin Model
$$ y = \rho W y + X\beta + W X\theta + \varepsilon, \qquad \varepsilon \sim \mathcal{N}(0,\sigma^2 I) $$
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).

การทดสอบว่าแบบจำลองย่อยเพียงพอหรือไม่ (Wald tests ที่ DAPH ใช้)Are the nested models adequate? (the Wald tests DAPH uses)
$$ H_0^{(1)}:\ \theta = 0 \ \ (\text{SDM} \to \text{SLM}),\qquad W_\theta=\hat\theta'\,\widehat{V}_{\theta\theta}^{-1}\,\hat\theta \sim \chi^2(k) $$ $$ H_0^{(2)}:\ \theta + \rho\beta = 0 \ \ (\text{SDM} \to \text{SEM}),\qquad g=\hat\theta+\hat\rho\hat\beta,\quad G=\bigl[\,\hat\rho I_k \;\; I_k \;\; \hat\beta\,\bigr],\quad W_{\text{cf}}=g'\bigl(G\widehat{V}G'\bigr)^{-1}g \sim \chi^2(k) $$
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 rejectedOLS
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 rejectedSDM — แปลผลผ่านตารางผลกระทบ ไม่ใช่สัมประสิทธิ์ดิบ— interpret through the effects table, not the raw coefficients
ไม่ปฏิเสธ θ = 0 แต่ปฏิเสธ common factorθ = 0 not rejected, common factor rejectedSLM
ปฏิเสธ θ = 0 แต่ไม่ปฏิเสธ common factorθ = 0 rejected, common factor not rejectedSEM
ไม่ปฏิเสธทั้งสองข้อ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.

ผลกระทบตามแนวทาง LeSage & Pace (2009) — direct · spillover · totalEffects following LeSage & Pace (2009) — direct · spillover · total
$$ S_r(W) = (I - \rho W)^{-1}\bigl(I\beta_r + W\theta_r\bigr) $$ $$ \text{Direct}_r = \tfrac{1}{n}\,\operatorname{tr}\bigl[S_r(W)\bigr],\qquad \text{Total}_r = \tfrac{1}{n}\,\mathbf{1}' S_r(W)\,\mathbf{1},\qquad \text{Spillover}_r = \text{Total}_r - \text{Direct}_r $$
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):

R script ส่วนที่ 1 — ฟิต SDM · packages: sf, spdep, spatialregPart 1 — fit the SDM · packages: sf, spdep, spatialreg
# 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)))
Expected R output
              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
R script ส่วนที่ 2 — Wald tests, LR tests และผลกระทบPart 2 — Wald tests, LR tests and effects
# 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)
Expected R output (ตัดบางส่วน)(abridged)
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
DAPH File > Open: 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)
📊 ตารางเปรียบเทียบค่าหลัก (R 4.3.3: spatialreg 1.3-1 · DAPH v.2026.08.22, รันวันที่ 2026-10-02)Side-by-side comparison (R 4.3.3: spatialreg 1.3-1 · DAPH v.2026.08.22, run 2026-10-02)
ค่าที่วัด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.2785375.2785< 0.0001✓ PASS
Pseudo-R² = 1 − σ̂²/Var(y)0.6599000.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 draws0.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 draws0.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.

ตัวอย่างการเขียนผล: การทดสอบ Wald ของ Spatial Durbin Model ไม่ปฏิเสธข้อจำกัด θ = 0 (χ²(2) = 2.13, p = 0.344) และข้อจำกัด common factor (χ²(2) = 4.47, p = 0.107) จึงไม่มีหลักฐานว่าลักษณะของย่านข้างเคียงสัมพันธ์กับอัตราอาชญากรรมเพิ่มเติม และแบบจำลองที่ง่ายกว่าเพียงพอ (Elhorst, 2010); เมื่อเทียบด้วย AIC แบบจำลอง spatial lag เหมาะสมที่สุด.
Example write-up: The Wald tests of the spatial Durbin model rejected neither the θ = 0 restriction (χ²(2) = 2.13, p = 0.344) nor the common-factor restriction (χ²(2) = 4.47, p = 0.107), so there was no evidence that neighbouring neighbourhoods' characteristics were associated with the crime rate beyond the spatial lag, and a nested specification sufficed (Elhorst, 2010); on AIC the spatial lag model fitted best.
📖 References
  1. 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
  2. Elhorst, J. P. (2010). Applied spatial econometrics: Raising the bar. Spatial Economic Analysis, 5(1), 9–28. doi:10.1080/17421770903541772
  3. LeSage, J., & Pace, R. K. (2009). Introduction to spatial econometrics. Chapman & Hall/CRC. doi:10.1201/9781420064254
  4. 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.

ข้อมูลที่ใช้ในหัวข้อนี้: ข้อมูลตัวอย่างผู้ป่วยของ DAPH ไม่มีพื้นที่และไม่มีช่วงเวลาซ้ำของพื้นที่เดียวกัน จึงใช้ข้อมูลสาธารณะ Produc ของ R package 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 = อัตราการว่างงาน (%). คำถาม: ภายในรัฐเดียวกันตามเวลา ผลผลิตสัมพันธ์กับทุนและแรงงานอย่างไร และรัฐข้างเคียงสัมพันธ์กันในปีเดียวกันหรือไม่ — โครงสร้างเดียวกับการศึกษาอัตราป่วยรายอำเภอ × ปี กับปัจจัยด้านบริการและเศรษฐกิจ.
Data used in this section: the DAPH patient example has neither areas nor repeated periods of the same area, so this section uses the public Produc data of the R package 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):

Pooled OLS · FE (non-spatial)
$$ y_{it} = c + x_{it}'\beta + \alpha_t + \varepsilon_{it} \qquad\qquad y_{it} = x_{it}'\beta + \mu_i + \alpha_t + \varepsilon_{it} $$
FE-Lag (SAR) · FE-Error (SEM) · FE-SDM (Durbin)
$$ y_{it} = \rho\,(Wy_t)_i + x_{it}'\beta + \mu_i + \alpha_t + \varepsilon_{it} $$ $$ y_{it} = x_{it}'\beta + \mu_i + \alpha_t + u_{it},\qquad u_t = \lambda W u_t + \varepsilon_t $$ $$ y_{it} = \rho\,(Wy_t)_i + x_{it}'\beta + (WX_t)_i\,\theta + \mu_i + \alpha_t + \varepsilon_{it} $$
RE-Lag (SAR) (RE-Error ใช้ส่วนคลาดเคลื่อนแบบ SEM แทน ρWy)(RE-Error uses the SEM error instead of ρWy)
$$ y_{it} = c + \rho\,(Wy_t)_i + x_{it}'\beta + \alpha_t + \mu_i + \varepsilon_{it},\qquad \mu_i \sim \mathcal{N}(0,\sigma^2_\mu),\quad \varphi^2=\frac{\sigma^2_\varepsilon}{T\sigma^2_\mu+\sigma^2_\varepsilon},\quad \mathrm{ICC}=\frac{\sigma^2_\mu}{\sigma^2_\mu+\sigma^2_\varepsilon} $$
μ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.

การทดสอบที่ DAPH คำนวณ (บนแบบจำลองที่มี dummy รายช่วงเวลาเหมือนกัน)Tests DAPH computes (on the same design with period dummies)
$$ F=\frac{(\mathrm{RSS}_{\text{pooled}}-\mathrm{RSS}_{\text{FE}})/(n-1)}{\mathrm{RSS}_{\text{FE}}/(nT-n-k)} \qquad \mathrm{LM}_{\text{BP}}=\frac{nT}{2(T-1)}\left[\frac{\sum_i\bigl(\sum_t e_{it}\bigr)^2}{\sum_i\sum_t e_{it}^2}-1\right]^2\sim\chi^2(1) $$ $$ H=(\hat b_{FE}-\hat b_{RE})'\,\bigl[\widehat V_{FE}-\widehat V_{RE}\bigr]^{+}\,(\hat b_{FE}-\hat b_{RE}) \sim \chi^2(q) $$ $$ \mathrm{LR}_{\theta=0}=2\bigl(\ell_{\text{FE-SDM}}-\ell_{\text{FE-Lag}}\bigr)\sim\chi^2(k_x),\qquad \mathrm{LR}_{\alpha=0}=2\bigl(\ell_{\text{with dummies}}-\ell_{\text{without}}\bigr)\sim\chi^2(T-1) $$
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

R script ส่วนที่ 1 — ข้อมูล, ไฟล์ wide สำหรับ DAPH และ weights · packages: sf, spdep, plm, splmPart 1 — data, the wide file for DAPH and weights · packages: sf, spdep, plm, splm
# 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
Expected R output
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   3.000   4.000   4.458   6.000   8.000 
R script ส่วนที่ 2 — หกแบบจำลอง · package: sandwichPart 2 — the six models · package: sandwich
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))
Expected R output
                 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
R script ส่วนที่ 3 — การทดสอบ · package: MASSPart 3 — specification tests · package: MASS
# 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")
Expected R output (ตัดบางส่วน)(abridged)
  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 
R script ส่วนที่ 4 — ความแปรปรวนร่วมเต็มของ FE-SDM, common factor และผลกระทบ · package: spatialregPart 4 — full covariance of FE-SDM, common factor and effects · package: spatialreg
# 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)
Expected R output
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
DAPH File > Open: 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
📊 ตารางเปรียบเทียบค่าหลัก (R 4.3.3: splm 1.6-5, plm 2.6-3, spatialreg 1.3-1 · DAPH v.2026.08.22, รันวันที่ 2026-10-02) · ลำดับตัวแปร lpcap · lpc · lemp · unempSide-by-side comparison (R 4.3.3: splm 1.6-5, plm 2.6-3, spatialreg 1.3-1 · DAPH v.2026.08.22, run 2026-10-02) · variables in the order lpcap · lpc · lemp · unemp
ค่าที่วัดQuantity โมเดลModel R DAPH ความต่างDifference สถานะStatus
β (SE)Pooled OLS0.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-Lag0.023512 · 0.220508 · 0.725794 · −0.004000 · ρ 0.087218 · φ 0.0677720.023512 · 0.220507 · 0.725794 · −0.004000 · ρ 0.087219 · φ 0.067772< 1e−5✓ PASS
SE(ρ)RE-Lag0.025715 (numerical Hessian ของ splm)0.025715 (splm numerical Hessian)0.0199540.005761✗ FAIL
R²Pooled OLS · FE (non-spatial)0.9929 · 0.99900.992866 · 0.998965< 0.00005✓ PASS
Log-likelihoodPooled · FE · FE-Lag · FE-Error · FE-SDM · RE-Lag842.2573 · 1629.963 · 1659.487 · 1672.8237 · 1680.623 · 1486.447842.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 FE93.80293.8023< 0.0005✓ PASS
Breusch–Pagan LMPooled4458.54458.536< 0.05✓ PASS
Hausman χ²(8) (Durbin)FE-SDM vs RE-SDM49.291549.31700.0255✗ FAIL
Hausman χ²(4) (คู่ Lag, อ้างอิง)Hausman χ²(4) (Lag pair, reference)FE-Lag vs RE-Lag67.876255.135012.7412✗ FAIL
LR θ = 0: χ²(4)FE-SDM vs FE-Lag42.271942.2719< 0.0001✓ PASS
Wald common factor: χ²(4) (p)FE-SDM15.6587 (0.0035)15.6587 (0.0035)< 0.0001✓ PASS
LR ผลรายช่วงเวลา: χ²(16)LR period effects: χ²(16)FE-SDM51.207751.2077< 0.0001✓ PASS
LM-lag · LM-error · robust LM-lag · robust LM-errorส่วนเหลือ two-way withintwo-way within residuals69.1663 · 98.7246 · 9.7175 · 39.275869.1663 · 98.7246 · 9.7175 · 39.2758< 0.0001✓ PASS
Moran's I (z)ส่วนเหลือ two-way withintwo-way within residuals0.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-SDM0.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-SDM0.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.

ตัวอย่างการเขียนผล: จากข้อมูล panel 48 รัฐ × 17 ปี ที่คุมผลประจำรัฐและผลประจำปี การทดสอบ Hausman ปฏิเสธสมมติฐานของ random effects (χ²(8) = 49.32, p < 0.001) การทดสอบ LR และ Wald สนับสนุน spatial Durbin model (θ = 0: χ²(4) = 42.27, p < 0.001; common factor: χ²(4) = 15.66, p = 0.004) ซึ่งมี AIC ต่ำสุด. ผลผลิตของรัฐสัมพันธ์ทางบวกกับของรัฐข้างเคียง (ρ = 0.370, p < 0.001) และการจ้างงานที่สูงขึ้น 1% สัมพันธ์กับผลผลิตที่สูงขึ้น 0.750% ในรัฐเดียวกัน (direct effect, 95% CI 0.694 to 0.805).
Example write-up: In a panel of 48 states × 17 years with state and year fixed effects, the Hausman-type test rejected the random-effects assumption (χ²(8) = 49.32, p < 0.001), and the LR and Wald tests supported the spatial Durbin model (θ = 0: χ²(4) = 42.27, p < 0.001; common factor: χ²(4) = 15.66, p = 0.004), which had the lowest AIC. State output was positively associated with neighbouring states' output (ρ = 0.370, p < 0.001), and 1% higher employment was associated with 0.750% higher output in the same state (direct effect, 95% CI 0.694 to 0.805).
📖 References
  1. 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
  2. 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
  3. Baltagi, B. H. (2021). Econometric analysis of panel data (6th ed.). Springer. doi:10.1007/978-3-030-53953-5
  4. 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
  5. 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
  6. Elhorst, J. P. (2014). Spatial econometrics: From cross-sectional data to spatial panels. Springer. doi:10.1007/978-3-642-40340-8
  7. Hausman, J. A. (1978). Specification tests in econometrics. Econometrica, 46(6), 1251–1271. doi:10.2307/1913827
  8. LeSage, J., & Pace, R. K. (2009). Introduction to spatial econometrics. Chapman & Hall/CRC. doi:10.1201/9781420064254
  9. 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
  10. 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).

ตัวอย่างในหัวข้อนี้: ข้อมูลตัวอย่างของ DAPH (กลุ่มผู้ป่วยล้างไตทางช่องท้อง) ไม่มีแผนที่ จึงคำนวณสถิติเชิงพื้นที่ไม่ได้ หัวข้อนี้จึงใช้ข้อมูลสาธารณะ Columbus, Ohio (ปี 1980) ที่มากับ R package spData (Anselin, 1988): 49 ย่านที่พักอาศัย ตัวแปร CRIME = จำนวนการลักทรัพย์ในบ้านและการขโมยรถต่อ 1,000 ครัวเรือน · คำถาม: "ย่านที่มีอัตราเหตุสูงอยู่ติดกันเป็นกลุ่มหรือไม่ และกลุ่มนั้นอยู่ที่ใด" — โครงสร้างเดียวกับคำถามด้านสาธารณสุข เช่น อัตราป่วยรายตำบล
Example in this section: the DAPH example dataset (the peritoneal-dialysis cohort) has no map, so no spatial statistic can be computed on it. This section therefore uses the public Columbus, Ohio (1980) data shipped with the R package 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:

Local Moran's I at area i
$$ z_i = \frac{x_i - \bar{x}}{s},\qquad s^2 = \frac{1}{n-1}\sum_{j=1}^{n}(x_j - \bar{x})^2,\qquad I_i = z_i \sum_{j \ne i} w_{ij}\, z_j $$
Global Moran's I and its link to the local values
$$ I = \frac{n}{S_0}\,\frac{\sum_i \sum_j w_{ij}(x_i - \bar{x})(x_j - \bar{x})}{\sum_i (x_i - \bar{x})^2},\qquad S_0 = \sum_i\sum_j w_{ij},\qquad E[I] = -\frac{1}{n-1} $$ $$ \text{row-standardised } W,\ \text{every area has a neighbour } (S_0 = n):\qquad I = \frac{1}{n-1}\sum_{i=1}^{n} I_i $$
Pseudo-p (folded, one-sided) from R permutations
$$ p = \frac{\min(k,\; R - k) + 1}{R + 1},\qquad k = \#\{\, r : I^{(r)} \ge I_{\text{obs}} \,\} $$
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.

🔒 ค่าที่ DAPH ใช้:🔒 DAPH's configuration: DAPH ไม่คำนวณค่าคาดหมายและความแปรปรวนเชิงวิเคราะห์ของ Ii — ใช้ pseudo-p จากการสุ่มเท่านั้น · จำนวนรอบ 999 (ปรับได้ 99–9999) · seed สุ่มคงที่ 12345 (ไม่มีช่องให้เปลี่ยน) จึงได้ pseudo-p เดิมทุกครั้งที่รันข้อมูลและค่าตั้งเดิม แต่โปรแกรมอื่นหรือ seed อื่นจะได้ pseudo-p ต่างไปเล็กน้อยตามความคลาดเคลื่อนของการสุ่ม (ประมาณ √(p(1−p)/R); Bivand & Wong, 2018) · ไม่มีการปรับการทดสอบหลายครั้ง (Bonferroni/FDR) · ถ้าตัวแปรมีค่าว่าง DAPH เติมด้วยค่าเฉลี่ยของตัวแปรก่อนคำนวณ จึงควรจัดการค่าว่างเองก่อนรัน DAPH does not compute the analytic expectation and variance of Ii; it uses permutation pseudo-p only · 999 permutations (adjustable 99–9999) · a fixed random seed 12345 (no box to change it), so the same data and settings give the same pseudo-p on every run, while another program or seed gives slightly different pseudo-p within Monte Carlo error (about √(p(1−p)/R); Bivand & Wong, 2018) · no multiple-testing adjustment (Bonferroni/FDR) · a missing value is replaced by the variable's mean before the computation, so handle missing values yourself before running.

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.

R script 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
Expected R output (abridged)
   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
DAPH Tab 1: อัปโหลด columbus.zip · Tab 2: Outcome = Spatial > Local Moran (Univariate) · ตัวแปรที่สนใจ = CRIME · Spatial Weights = Queen Contiguity (order 1) · Permutations = 999 · p threshold = 0.05 · Label Column = ใช้เลขแถว (#1 … #49 = แถวที่ 1 … 49 = POLYID)Tab 1: upload columbus.zip · Tab 2: Outcome = Spatial > Local Moran (Univariate) · Interested variable = CRIME · Spatial Weights = Queen Contiguity (order 1) · Permutations = 999 · p threshold = 0.05 · Label Column = row index (#1 … #49 = rows 1 … 49 = POLYID)
📊 การเปรียบเทียบ R กับ DAPHR versus DAPH
ค่าที่เทียบQuantity R DAPH ความต่างDifference สถานะStatus
จำนวนเพื่อนบ้าน ต่ำสุด / เฉลี่ย / สูงสุดNeighbours min / mean / max2 / 4.816 / 102 / 4.816 / 100✓ PASS
Global Moran's I0.5001890.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.5895.7050.116 (≤ 0.387)✓ PASS
pseudo-p ของ Global Ipseudo-p of global I0.0010.0010✓ PASS
Ii ทั้ง 49 พื้นที่ (ความต่างสูงสุด)Ii, all 49 areas (largest difference)49 ค่าvalues49 ค่าvalues7e−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.0040.038 / 0.001 / 0.030 / 0.003≤ 0.013✓ PASS
pseudo-p ทั้ง 49 พื้นที่ ³pseudo-p, all 49 areas ³49 ค่าvalues49 ค่า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 / 2911 / 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.

ตัวอย่างการเขียนผล: อัตราการลักทรัพย์ในบ้านและการขโมยรถของ 49 ย่านในเมือง Columbus มีความสัมพันธ์เชิงพื้นที่เป็นบวก (Global Moran's I = 0.50, pseudo-p = 0.001; น้ำหนัก Queen contiguity แบบ row-standardised; สุ่ม 999 รอบ) Local Moran's I พบย่าน High-High 11 ย่าน, Low-Low 9 ย่าน และพื้นที่ต่างจากรอบข้าง 2 ย่าน (High-Low 1, Low-High 1) ที่ pseudo-p < 0.05 โดยไม่ได้ปรับการทดสอบหลายครั้ง
Reporting example: Residential burglary and vehicle-theft rates in 49 Columbus neighbourhoods were positively spatially autocorrelated (global Moran's I = 0.50, pseudo-p = 0.001; row-standardised queen contiguity weights; 999 permutations). Local Moran's I identified 11 High-High and 9 Low-Low neighbourhoods and two spatial outliers (one High-Low, one Low-High) at pseudo-p < 0.05, without adjustment for multiple testing.
📖 References
  1. Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
  2. Anselin, L. (1995). Local indicators of spatial association—LISA. Geographical Analysis, 27(2), 93–115. doi:10.1111/j.1538-4632.1995.tb00338.x
  3. 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
  4. Moran, P. A. P. (1950). Notes on continuous stochastic phenomena. Biometrika, 37(1–2), 17–23. doi:10.1093/biomet/37.1-2.17
  5. 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.

ตัวอย่างในหัวข้อนี้: ข้อมูลตัวอย่างของ DAPH (กลุ่มผู้ป่วยล้างไตทางช่องท้อง) ไม่มีแผนที่ จึงใช้ข้อมูลสาธารณะ Columbus, Ohio (ปี 1980) ใน R package spData (Anselin, 1988) ชุดเดียวกับหัวข้อ 6.4: X = INC รายได้ครัวเรือน (พันดอลลาร์สหรัฐ) ของย่าน i และ Y = CRIME อัตราการลักทรัพย์ในบ้านและการขโมยรถต่อ 1,000 ครัวเรือนของย่านรอบข้าง · คำถาม: "ย่านรายได้ต่ำถูกล้อมด้วยย่านที่อัตราเหตุสูงหรือไม่ และอยู่ที่ใด"
Example in this section: the DAPH example dataset (the peritoneal-dialysis cohort) has no map, so this section uses the public Columbus, Ohio (1980) data in the R package 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:

Bivariate local Moran's I at area i
$$ z^{x}_i = \frac{x_i - \bar{x}}{s_x},\qquad z^{y}_j = \frac{y_j - \bar{y}}{s_y},\qquad I^{xy}_i = z^{x}_i \sum_{j \ne i} w_{ij}\, z^{y}_j $$
Global bivariate Moran's I
$$ I^{xy} = \frac{1}{n-1}\sum_{i=1}^{n} I^{xy}_i = \frac{\sum_i z^{x}_i \sum_j w_{ij} z^{y}_j}{\sum_i \left(z^{x}_i\right)^2} $$
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 < α.

🔒 ค่าที่ DAPH ใช้:🔒 DAPH's configuration: ช่อง Dependent Variable = Y (ค่ารอบข้าง ใช้ตัวเดียว) และช่อง ตัวแปรที่สนใจ = X (ค่าที่พื้นที่ i เลือกได้หลายตัว แต่ละตัวได้หนึ่งแถวในตาราง) · ค่าตั้งอื่นเหมือนหัวข้อ 6.4: 999 รอบ, α = 0.05, seed คงที่ 12345, ไม่ปรับการทดสอบหลายครั้ง และค่าว่างถูกเติมด้วยค่าเฉลี่ย The Dependent Variable box = Y (the neighbourhood variable, one only) and the Interested Variables box = X (the value at area i; several allowed, one table row each) · other settings as in section 6.4: 999 permutations, α = 0.05, fixed seed 12345, no multiple-testing adjustment, missing values filled with the mean.

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).

R script 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), ]
Expected R output (abridged)
[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
DAPH Tab 1: อัปโหลด columbus.zip · Tab 2: Outcome = Spatial > Local Moran (Bivariate) · Dependent Variable (Y) = CRIME · ตัวแปรที่สนใจ (X) = INC · Spatial Weights = Queen Contiguity (order 1) · Permutations = 999 · p threshold = 0.05Tab 1: upload columbus.zip · Tab 2: Outcome = Spatial > Local Moran (Bivariate) · Dependent Variable (Y) = CRIME · Interested variable (X) = INC · Spatial Weights = Queen Contiguity (order 1) · Permutations = 999 · p threshold = 0.05
📊 การเปรียบเทียบ R กับ DAPHR versus DAPH
ค่าที่เทียบQuantityRDAPHความต่างDifferenceสถานะStatus
Global bivariate Moran's I−0.451623−0.451623< 1e−6✓ PASS
z จากการสุ่ม (ทั้งสองโปรแกรม) ²permutation z (both programs) ²−4.545−4.3290.216 (≤ 0.442)✓ PASS
pseudo-p ภาพรวมglobal pseudo-p0.0010.0010✓ PASS
Ixyi ทั้ง 49 พื้นที่ (ความต่างสูงสุด)Ixyi, all 49 areas (largest difference)49 ค่าvalues49 ค่าvalues2e−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.0080.038 / 0.001 / 0.003 / 0.008≤ 0.006✓ PASS
pseudo-p ทั้ง 49 พื้นที่ ³pseudo-p, all 49 areas ³49 ค่าvalues49 ค่า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 / 291 / 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.

ตัวอย่างการเขียนผล: รายได้ครัวเรือนของย่านมีความสัมพันธ์เชิงพื้นที่เชิงลบกับอัตราการลักทรัพย์และขโมยรถของย่านข้างเคียง (Global bivariate Moran's I = −0.45, pseudo-p = 0.001; น้ำหนัก Queen contiguity แบบ row-standardised; สุ่ม 999 รอบ) Bivariate Local Moran's I พบย่าน Low-High 11 ย่าน และ High-Low 9 ย่าน ที่ pseudo-p < 0.05 (ไม่ปรับการทดสอบหลายครั้ง)
Reporting example: Neighbourhood household income was negatively associated with burglary and vehicle-theft rates in the surrounding neighbourhoods (global bivariate Moran's I = −0.45, pseudo-p = 0.001; row-standardised queen contiguity; 999 permutations). Bivariate local Moran's I identified 11 Low-High and 9 High-Low neighbourhoods at pseudo-p < 0.05 (no multiple-testing adjustment).
📖 References
  1. Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
  2. 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.
  3. 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.

ตัวอย่างในหัวข้อนี้: ข้อมูลตัวอย่างของ DAPH (กลุ่มผู้ป่วยล้างไตทางช่องท้อง) ไม่มีแผนที่ จึงใช้ข้อมูลสาธารณะ Columbus, Ohio (ปี 1980) ใน R package spData (Anselin, 1988) ชุดเดียวกับหัวข้อ 6.4: 49 ย่าน, CRIME = การลักทรัพย์ในบ้านและการขโมยรถต่อ 1,000 ครัวเรือน (ไม่มีค่าลบ) · คำถาม: "อัตราเหตุสูงกระจุกตัวหรือไม่ และย่านใดเป็นจุดร้อน/จุดเย็น"
Example in this section: the DAPH example dataset (the peritoneal-dialysis cohort) has no map, so this section uses the public Columbus, Ohio (1980) data in the R package 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).

Global G (binary weights: wij = 1 if j is a neighbour of i, else 0)
$$ G = \frac{\sum_{i}\sum_{j \ne i} w_{ij}\, x_i\, x_j}{\sum_{i}\sum_{j \ne i} x_i\, x_j},\qquad E[G] = \frac{S_0}{n(n-1)},\quad S_0 = \sum_i\sum_{j \ne i} w_{ij} $$
Local Gi (area i excluded) and G*i (area i included) — values as DAPH prints them (row-standardised)
$$ G_i = \frac{\tfrac{1}{k_i}\sum_{j \in N(i)} x_j}{\sum_{j \ne i} x_j},\qquad G^{*}_i = \frac{\tfrac{1}{k_i+1}\left(x_i + \sum_{j \in N(i)} x_j\right)}{\sum_{j} x_j} $$
Analytic z (Ord & Getis, 1995) — DAPH's "z-score" column
$$ z(G_i) = \frac{\sum_{j \in N(i)} x_j - k_i\,\bar{x}_{(i)}}{s_{(i)}\sqrt{\dfrac{k_i\,(n-1-k_i)}{n-2}}},\qquad z(G^{*}_i) = \frac{\sum_{j \in N(i)\cup\{i\}} x_j - k^{*}_i\,\bar{x}}{s\sqrt{\dfrac{k^{*}_i\,(n-k^{*}_i)}{n-1}}},\quad k^{*}_i = k_i + 1 $$
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.

🔒 ค่าที่ DAPH ใช้:🔒 DAPH's configuration: 999 รอบ (ปรับได้ 99–9999) · seed สุ่มคงที่ 123456789 (ไม่มีช่องให้เปลี่ยน; คนละค่ากับ 12345 ของ Local Moran) จึงได้ผลเดิมทุกครั้ง แต่โปรแกรมอื่นจะได้ pseudo-p ต่างไปเล็กน้อยตามความคลาดเคลื่อนของการสุ่ม · ถ้าตัวแปรมีค่า ≤ 0 แม้แต่ค่าเดียว DAPH จะเลื่อนทุกค่าเป็น x − min(x) + 0.000001 ก่อนคำนวณ Global G (ค่า G จึงต่างจากการคำนวณด้วยค่าเดิม) · ค่าว่างถูกเติมด้วยค่าเฉลี่ย (แผนที่แสดงพื้นที่นั้นเป็น No Data) · ไม่ปรับการทดสอบหลายครั้ง 999 permutations (adjustable 99–9999) · a fixed random seed 123456789 (no box to change it; not the 12345 of Local Moran), so a re-run gives the same result while another program gives slightly different pseudo-p within Monte Carlo error · if even one value is ≤ 0, DAPH shifts every value to x − min(x) + 0.000001 before computing Global G (so G differs from G on the original values) · missing values are filled with the mean (the map shows such areas as No Data) · no multiple-testing adjustment.

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.

R script 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)])
Expected R output (abridged)
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
DAPH Tab 1: อัปโหลด columbus.zip · Tab 2: Outcome = Spatial > Getis-Ord G (Global) แล้วรันซ้ำด้วย Getis-Ord Gi และ Getis-Ord Gi* · ตัวแปรที่สนใจ = CRIME · Spatial Weights = Queen Contiguity (order 1) · Permutations = 999 · p threshold = 0.05Tab 1: upload columbus.zip · Tab 2: Outcome = Spatial > Getis-Ord G (Global), then again with Getis-Ord Gi and Getis-Ord Gi* · Interested variable = CRIME · Spatial Weights = Queen Contiguity (order 1) · Permutations = 999 · p threshold = 0.05
📊 การเปรียบเทียบ R กับ DAPHR versus DAPH
ค่าที่เทียบQuantityRDAPHความต่างDifferenceสถานะStatus
Global G0.1278070.127807< 1e−6✓ PASS
E[G]0.1003400.100340< 1e−6✓ PASS
z ของ G (R: สูตรวิเคราะห์ · DAPH: การสุ่ม) ²z of G (R: analytic · DAPH: permutation) ²4.6384.4620.176 (≤ 0.325)✓ PASS
pseudo-p สองด้านของ Gtwo-sided pseudo-p of G0.0020.0020✓ PASS
Gi และ G*i ทั้ง 49 พื้นที่ (ความต่างสูงสุด)Gi and G*i, all 49 areas (largest difference)98 ค่าvalues98 ค่าvalues1e−17✓ PASS
z ของ Gi และ G*i ทั้ง 49 พื้นที่z of Gi and G*i, all 49 areas98 ค่าvalues98 ค่าvalues3e−15✓ PASS
Gi #7 / #16 / #17 / #32: G · z0.0289 · 1.799 / 0.0314 · 3.282 / 0.0107 · −1.799 / 0.0081 · −2.6960.0289 · 1.799 / 0.0314 · 3.282 / 0.0107 · −1.799 / 0.0081 · −2.696< 0.001✓ PASS
Gi* #7 / #16 / #17 / #32: G · z0.0231 · 0.661 / 0.0306 · 3.475 / 0.0132 · −1.540 / 0.0087 · −2.8510.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.0030.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.0050.032 / 0.001 / 0.027 / 0.003≤ 0.010✓ PASS
pseudo-p ทั้ง 49 พื้นที่ (Gi · Gi*) ³pseudo-p, all 49 areas (Gi · Gi*) ³98 ค่าvalues98 ค่า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 / 295 / 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 / 295 / 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.

ตัวอย่างการเขียนผล: อัตราการลักทรัพย์และขโมยรถใน 49 ย่านของเมือง Columbus กระจุกตัวในกลุ่มค่าสูง (Global G = 0.128 เทียบกับค่าคาดหมาย 0.100; z จากการสุ่ม = 4.46, pseudo-p = 0.002) Getis-Ord Gi* (น้ำหนัก Queen contiguity, conditional permutation 999 รอบ) พบจุดร้อน 12 ย่าน และจุดเย็น 8 ย่าน ที่ pseudo-p < 0.05 โดยไม่ได้ปรับการทดสอบหลายครั้ง
Reporting example: Burglary and vehicle-theft rates in 49 Columbus neighbourhoods showed clustering of high values (global G = 0.128 versus an expected 0.100; permutation z = 4.46, pseudo-p = 0.002). Getis-Ord Gi* (queen contiguity, 999 conditional permutations) identified 12 hot-spot and 8 cold-spot neighbourhoods at pseudo-p < 0.05, without multiple-testing adjustment.
📖 References
  1. Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
  2. 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
  3. 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
  4. 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.

ตัวอย่างในหัวข้อนี้: ข้อมูลตัวอย่างของ DAPH (กลุ่มผู้ป่วยล้างไตทางช่องท้อง) ไม่มีแผนที่ จึงใช้แผนที่สาธารณะ Columbus, Ohio 49 ย่านใน R package 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)
Example in this section: the DAPH example dataset (the peritoneal-dialysis cohort) has no map, so this section uses the public Columbus, Ohio map of 49 neighbourhoods in the R package 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

Neighbour indicator cij (1 = neighbour, 0 = not) and row-standardised weight
$$ \text{Queen: } c_{ij}=1 \text{ if polygons } i, j \text{ share at least one boundary point};\qquad \text{KNN: } c_{ij}=1 \text{ if } j \text{ is among the } k \text{ centroids nearest to } i $$ $$ \text{Distance band: } c_{ij}=1 \text{ if } d_{ij} \le d^{*},\qquad d^{*} = 1.001 \times \max_i \min_{j \ne i} d_{ij} $$ $$ w_{ij} = \frac{c_{ij}}{\sum_{j} c_{ij}} \qquad\text{(each row sums to 1, so } \textstyle\sum_j w_{ij} x_j \text{ is the mean of the neighbours)} $$
Arc (great-circle) distance between centroids at longitude λ and latitude φ (degrees)
$$ d_{ij} = 2R\,\arcsin\sqrt{\sin^2\!\frac{\varphi_j-\varphi_i}{2} + \cos\varphi_i\cos\varphi_j\,\sin^2\!\frac{\lambda_j-\lambda_i}{2}},\qquad R \approx 6371\ \text{km} $$
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).

R script 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
Expected R output
              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
DAPH Tab 1: อัปโหลด columbus.zip · Tab 2: Outcome = Spatial > Local Moran (Univariate), ตัวแปรที่สนใจ = CRIME, รันซ้ำทีละแบบ: Queen Contiguity order 1 และ order 2 · Inverse Distance Weight + Euclidean Distance (Power 1 และ 2) · K-Nearest Neighbors k = 4 + Euclidean · Inverse Distance Weight + Arc Distance (km) · และ Spatial Regression (CRIME ~ INC + HOVAL) ด้วย Queen order 2Tab 1: upload columbus.zip · Tab 2: Outcome = Spatial > Local Moran (Univariate), Interested variable = CRIME, run once per W: Queen Contiguity order 1 and order 2 · Inverse Distance Weight + Euclidean Distance (Power 1 and 2) · K-Nearest Neighbors k = 4 + Euclidean · Inverse Distance Weight + Arc Distance (km) · and Spatial Regression (CRIME ~ INC + HOVAL) with Queen order 2
📊 การเปรียบเทียบ R กับ DAPHR versus DAPH
W และค่าที่เทียบW and quantityRDAPHความต่างDifferenceสถานะStatus
Queen order 1: เพื่อนบ้าน ต่ำสุด/เฉลี่ย/สูงสุด · Moran's IQueen order 1: neighbours min/mean/max · Moran's I2 / 4.816 / 10 · 0.5001892 / 4.816 / 10 · 0.500189< 1e−6✓ PASS
Queen order 2 ใน Spatial Regression: เพื่อนบ้าน ต่ำสุด/เฉลี่ย/สูงสุดQueen order 2 in Spatial Regression: neighbours min/mean/max4 / 13.306 / 244 / 13.306 / 240✓ PASS
Queen order 2 ใน Local Moran: เพื่อนบ้าน ต่ำสุด/เฉลี่ย/สูงสุด · Moran's IQueen order 2 in Local Moran: neighbours min/mean/max · Moran's I4 / 13.306 / 24 · 0.3007804 / 13.306 / 24 · 0.300780< 1e−6✓ PASS
Distance band (Euclidean): รัศมี d* · เพื่อนบ้าน · Moran's IDistance band (Euclidean): radius d* · neighbours · Moran's I0.619483 · 1 / 5.143 / 11 · 0.5518260.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.5901970.551826 · 0.5518260.018986 · 0.038371✗ FAIL
KNN k = 4 (Euclidean): เพื่อนบ้าน · Moran's IKNN k = 4 (Euclidean): neighbours · Moran's I4 / 4 / 4 · 0.5825524 / 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 degrees67.550 km67.550 km0.0001✓ PASS
Queen order 1: จำนวนกลุ่มที่แยกกันQueen order 1: number of separate groups11 (ไม่มีคำเตือน)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.

ตัวอย่างจริง (แผนที่ 77 จังหวัด ขอบเขตจังหวัดสาธารณะของ OCHA, Spatial Regression ใน DAPH): Queen ปกติ → "⚠ เชื่อมกันไม่ครบ: แยกเป็น 2 กลุ่มที่ไม่มีเพื่อนบ้านร่วมกัน (76 + 1) · มี 1 พื้นที่ที่ไม่มีเพื่อนบ้านเลย" (ภูเก็ต) · Queen ปรับ → "ระยะเชื่อมสูงสุด 112 km (ค่าเริ่มต้น) · เชื่อมเกาะ 1 แห่ง: แถวที่ 67 เชื่อมกับ แถวที่ 66 (ระยะขอบ 0.44 กม.)" คือภูเก็ตเชื่อมกับพังงาข้ามช่องแคบปากพระ และคำเตือนหายไป
Real example (a 77-province map of Thailand from the public OCHA boundaries, Spatial Regression in DAPH): plain Queen → "⚠ not fully connected: 2 separate groups (76 + 1), 1 area(s) with no neighbour" (Phuket) · modified Queen → "distance cap 112 km (default) · linked 1 island(s): row 67 linked with row 66 (edge 0.44 km)", i.e. Phuket linked with Phang Nga across the Pak Phra strait, and the warning disappears.

หลักการเลือก: เลือก 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
  1. Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
  2. 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
  3. 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.

ตัวอย่างในหัวข้อนี้: ข้อมูลตัวอย่างของ DAPH (กลุ่มผู้ป่วยล้างไตทางช่องท้อง) ไม่มีแผนที่ จึงใช้ข้อมูลสาธารณะ Columbus, Ohio (ปี 1980) ใน R package spData (Anselin, 1988): 49 ย่าน, CRIME = การลักทรัพย์ในบ้านและการขโมยรถต่อ 1,000 ครัวเรือน · คำถาม: "ควรแบ่ง 5 ช่วงสีอย่างไรให้ผู้อ่านเห็นการกระจายของอัตรานี้ และ heat map ของ DAPH เกลี่ยค่ากว้างเท่าใด"
Example in this section: the DAPH example dataset (the peritoneal-dialysis cohort) has no map, so this section uses the public Columbus, Ohio (1980) data in the R package 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.

Quantile (about n/K areas per class; linear-interpolation quantile, R type 7)
$$ c_k = Q\!\left(\tfrac{k}{K}\right),\qquad Q(p) = x_{(\lfloor h \rfloor)} + (h - \lfloor h \rfloor)\bigl(x_{(\lfloor h \rfloor + 1)} - x_{(\lfloor h \rfloor)}\bigr),\quad h = (n-1)p + 1 $$
Equal Interval
$$ c_k = x_{\min} + k\,\frac{x_{\max} - x_{\min}}{K},\qquad k = 1, \dots, K $$
Natural Breaks (Jenks) — classes that minimise the within-class sum of squares
$$ \min \;\text{SDCM} = \sum_{k=1}^{K}\; \sum_{i \in \text{class } k} \bigl(x_i - \bar{x}_k\bigr)^2 \qquad (c_k = \text{largest value in class } k) $$
Standard Deviation — mean plus whole multiples of the sample SD
$$ c = \bar{x} + m\,s,\quad K{=}3: m \in \{-1, 1\},\; K{=}4: \{-1, 0, 1\},\; K{=}5: \{-2,-1,1,2\},\; K{=}6: \{-2,-1,0,1,2\},\; K{=}7: \{-3,-2,-1,1,2,3\} $$
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.

Heat Map (KDE): bivariate Gaussian kernel with a full bandwidth matrix H
$$ \hat{f}(\mathbf{s}) = \sum_{i=1}^{n} \frac{w_i}{2\pi\,|H|^{1/2}} \exp\!\left(-\tfrac{1}{2}(\mathbf{s}-\mathbf{p}_i)^{\top} H^{-1} (\mathbf{s}-\mathbf{p}_i)\right),\qquad \text{map value} = 100 \times \frac{\hat{f}(\mathbf{s})}{\max_{\mathbf{s}} \hat{f}(\mathbf{s})}\ \% $$ $$ \text{Lat/Lon point mode: } w_i = \tfrac{1}{n},\quad H = n^{-1/3}\,S \quad (\text{Scott's rule for 2 dimensions: factor } n^{-1/6}) $$ $$ \text{Polygon-centroid mode: } w_i = \frac{x_i - x_{\min} + 10^{-9}}{\sum_j (x_j - x_{\min} + 10^{-9})},\quad H = f^2 S_w,\quad f = \frac{0.03\,L}{(s_\lambda + s_\varphi)/2}\ \ (n < 1000) $$
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.

R script 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
Expected R output
[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
DAPH Tab 1: อัปโหลด columbus.zip · Tab 2: Outcome = Spatial > Distribution Map · ตัวแปรที่สนใจ = CRIME · Map Mode = Choropleth, Classes = 5, รันทีละวิธี (Quantile, Equal Interval, Natural Breaks, Standard Deviation) — ขอบบนของแต่ละช่วงอยู่ในหัวข้อ "3. ช่วงการแบ่งสี" ของ Tab 3 · Heat Map (KDE): แบบ Polygon centroid กับ CRIME และแบบ Lat/Lon ที่ Latitude = Y, Longitude = X (ค่า H อ่านจากโค้ดที่วาดแผนที่ของ DAPH)Tab 1: upload columbus.zip · Tab 2: Outcome = Spatial > Distribution Map · Interested variable = CRIME · Map Mode = Choropleth, Classes = 5, one run per method (Quantile, Equal Interval, Natural Breaks, Standard Deviation) — the class upper bounds are listed under "3. Color class breaks" in Tab 3 · Heat Map (KDE): Polygon-centroid mode with CRIME, and Lat/Lon mode with Latitude = Y, Longitude = X (H read from DAPH's map-drawing code)
📊 การเปรียบเทียบ R กับ DAPHR versus DAPH
ค่าที่เทียบQuantityRDAPHความต่างDifferenceสถานะStatus
Quantile: ขอบบน 5 ช่วงQuantile: 5 upper bounds19.0226 / 29.3260 / 39.0252 / 53.1610 / 68.892019.0226 / 29.3260 / 39.0252 / 53.1610 / 68.8920< 1e−6✓ PASS
Equal Interval: ขอบบน 5 ช่วงEqual Interval: 5 upper bounds13.9210 / 27.6638 / 41.4065 / 55.1493 / 68.892013.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.89200.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.1552 / 12 / 11 / 12 / 12 · 601.1550✓ PASS
Standard Deviation (5 ช่วง): ขอบบนStandard Deviation (5 classes): upper bounds1.6646 / 18.3967 / 51.8609 / 68.5930 / 68.89201.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 / H220.522758 · 11.326657 / 0.013216 / 6.4690840.522758 · 11.326657 / 0.013216 / 6.469084< 1e−6✓ PASS
KDE โหมด Polygon centroid: factor · neffKDE polygon-centroid mode: factor · neff0.158340 · 40.01600.158340 · 40.0160< 1e−6✓ PASS
KDE โหมด Polygon centroid: H11 / H12 / H22KDE polygon-centroid mode: H11 / H12 / H220.020334 / −0.001398 / 0.0138880.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.

ตัวอย่างการเขียนผล: แผนที่ choropleth แสดงอัตราการลักทรัพย์และขโมยรถต่อ 1,000 ครัวเรือนของ 49 ย่าน แบ่ง 5 ช่วงด้วยวิธี Quantile (ขอบบน 19.0, 29.3, 39.0, 53.2 และ 68.9) ช่วงละ 9–10 ย่าน
Reporting example: The choropleth map shows burglary and vehicle-theft rates per 1,000 households in 49 neighbourhoods, in five quantile classes (upper bounds 19.0, 29.3, 39.0, 53.2 and 68.9), 9–10 neighbourhoods per class.
📖 References
  1. Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic. doi:10.1007/978-94-015-7799-1
  2. 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
  3. 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
  4. Scott, D. W. (1992). Multivariate density estimation: Theory, practice, and visualization. Wiley. doi:10.1002/9780470316849
  5. 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).

ตัวอย่าง: ชุดข้อมูลตัวอย่างของ DAPH (ผู้ป่วยล้างไตทางช่องท้อง) ไม่มีแผนที่ หัวข้อนี้จึงใช้ข้อมูลสาธารณะที่มากับแพ็กเกจ sf ของ R และนำเข้า DAPH ได้: การเสียชีวิตกะทันหันในทารก (sudden infant death syndrome, SIDS) ของ 100 เคาน์ตีในรัฐ North Carolina ปี 1974–78 (Cressie & Chan, 1989) ตัวแปร SID74 = จำนวนทารกที่เสียชีวิตด้วย SIDS (รวม 667 ราย) BIR74 = จำนวนเกิดมีชีพ (ตัวหาร รวม 329,962 ราย) และ PNW74 = ร้อยละของการเกิดมีชีพที่ไม่ใช่คนผิวขาว (= 100 × NWBIR74 ÷ BIR74 สร้างในสคริปต์ R ด้านล่าง) คำถาม: (1) เคาน์ตีใดมีความเสี่ยง SIDS สูงกว่าระดับที่คาดจากอัตราของทั้งรัฐและ PNW74 (2) PNW74 สัมพันธ์กับความเสี่ยงมากเพียงใด (3) ความต่างระหว่างเคาน์ตีที่เหลืออยู่เกาะกลุ่มตามเพื่อนบ้านหรือไม่ DAPH ได้ RR ต่อ 1 SD ของ PNW74 = 1.506 (95% CrI 1.325 ถึง 1.730), φ = 0.433 (95% CrI 0.021 ถึง 0.952) และ 8 จาก 100 เคาน์ตีเข้าเกณฑ์ P(RR > 1) ≥ 0.80
Example: the DAPH example dataset (peritoneal-dialysis patients) has no map, so this section uses public data that ship with the R package sf and can be opened in DAPH: sudden infant death syndrome (SIDS) in the 100 counties of North Carolina, 1974–78 (Cressie & Chan, 1989). SID74 = SIDS deaths (667 in all), BIR74 = live births (the denominator, 329,962 in all) and PNW74 = percentage of live births that were non-white (= 100 × NWBIR74 ÷ BIR74, made in the R script below). Questions: (1) which counties have a SIDS risk above the level expected from the state rate and their PNW74; (2) how strongly PNW74 goes with the risk; (3) whether the remaining differences between counties cluster by neighbourhood. DAPH gives an RR per 1 SD of PNW74 of 1.506 (95% CrI 1.325 to 1.730), φ = 0.433 (95% CrI 0.021 to 0.952), and 8 of 100 counties with P(RR > 1) ≥ 0.80.

2หลักการและสูตรLogic and Formula

BYM2 (Besag, York & Mollié, 1991; Riebler et al., 2016)
$$ y_i \sim \text{Poisson}(E_i\,\theta_i), \qquad \log\theta_i = \alpha + \mathbf z_i^{\top}\boldsymbol\beta + b_i, \qquad E_i = n_i\,\frac{\sum_j y_j}{\sum_j n_j} $$ $$ \mathbf b = \sigma\left(\sqrt{1-\phi}\;\mathbf v + \sqrt{\phi/s}\;\mathbf u\right), \qquad \mathbf v \sim N(\mathbf 0, \mathbf I), \qquad p(\mathbf u) \propto \exp\!\Big(-\tfrac12 \sum_{i\sim j} (u_i-u_j)^2\Big),\ \ \textstyle\sum_i u_i = 0 $$ $$ \mathbf Q = \mathbf D - \mathbf W, \qquad s = \exp\!\Big(\tfrac1n \sum_{i=1}^{n} \log\,[\mathbf Q^{+}]_{ii}\Big), \qquad \operatorname{Var}(\mathbf b) = \sigma^2\Big[(1-\phi)\,\mathbf I + \tfrac{\phi}{s}\,\mathbf Q^{+}\Big] $$
การแจกแจงก่อนเห็นข้อมูล (prior) ที่ DAPH ใช้Priors DAPH uses
$$ \alpha \sim N(0,\,5^2), \quad \beta_k \sim N(0,\,1), \quad \sigma \sim \text{half-}N(0,\,1), \quad \phi \sim \text{Beta}(1,\,1), \quad \gamma_1 = 0,\ \ \gamma_t \sim N(0,\,0.5^2)\ \ (t \ge 2) $$
สิ่งที่ DAPH รายงานWhat DAPH reports
$$ \text{SIR}_i = \frac{O_i}{E_i}, \qquad \text{RR}_i = e^{b_i}, \qquad \text{RR per 1 SD of } x_k = e^{\beta_k}, \qquad z_{ik} = \frac{x_{ik} - \bar x_k}{\text{SD}(x_k)} $$ $$ P(\text{RR}_i > c) = \frac{1}{S}\sum_{s=1}^{S} \mathbf 1\!\left[b_i^{(s)} > \log c\right], \qquad \text{flag}_i \iff P(\text{RR}_i > c_1) \ge 0.80, \qquad \text{MCSE}(P) = \sqrt{P(1-P)/\text{ESS}_i} $$
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).

📋 ค่าเริ่มต้นและที่มา (BYM2 / แบบจำลองสองโรค)Defaults and where they come from (BYM2 / two outcomes)
ช่องFieldBYM2สองโรคTwo outcomesที่มาSource
draws15005000ข้อกำหนดการออกแบบของ 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
tune15004000ข้อกำหนดการออกแบบของ DAPH (สองโรคมีสองสนามกับ ρ จึงปรับนานกว่า)DAPH module specification (two fields and ρ, so longer tuning)
chains44Vehtari et al. (2021): อย่างน้อย 4 โซ่at least four chains
target accept0.950.97ข้อกำหนดการออกแบบของ DAPH สูงกว่าค่าทั่วไป 0.8 เพราะผลรายพื้นที่เป็นแบบหลายระดับDAPH module specification; above the usual 0.8 because the area effects are multilevel
seed1234512345เลขเดียวกับสถิติอื่นของ DAPHthe same seed as the other DAPH statistics
เกณฑ์ RRRR thresholds1.0, 1.51.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.800.80Richardson 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 ruleQueen*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.

R สคริปต์ตรวจสอบ (R 4.3.3: sf, spdep, MASS, brms, posterior, zip)verification script (R 4.3.3: sf, spdep, MASS, brms, posterior, zip)
# 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)
Expected R output (abridged; brms 2.20.4, seed 12345)
          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 
R การเปรียบเทียบแบบจำลอง (ต่อจากสคริปต์ข้างบน ใช้เวลาเพิ่มราว 5 นาที; brms, loo)model comparison (continues the script above, about 5 more minutes; brms, loo)
# 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))
Expected R output
     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
DAPH ขั้นตอนใน DAPHSteps in DAPH

ไฟล์ > นำเข้า > 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.

📊 ผลการตรวจสอบVerification results
รายการItemRDAPHความต่าง / เกณฑ์Difference / ruleสถานะStatus
กราฟ Queen: จำนวนพื้นที่ / เส้นเชื่อม / เพื่อนบ้านเฉลี่ยQueen graph: areas / edges / mean neighbours100 / 245 / 4.9100 / 245 / 4.900✓ PASS
scaling factor s ของกราฟ North Carolinascaling factor s, North Carolina graph0.58597960.5859796< 1e−7✓ PASS
scaling factor ที่ brms คำนวณเอง (เติมค่าเล็กมากบนแนวทแยงของ Q)scaling factor computed by brms itself (adds a tiny value to the diagonal of Q)0.58597910.58597965.4e−7 < 1e−6✓ PASS
scaling factor, เส้นทาง 3 พื้นที่ = (50/729)1/3scaling factor, path of 3 areas = (50/729)1/30.4093370.409337< 1e−6✓ PASS
scaling factor, กราฟสมบูรณ์ K4 = 3/16scaling factor, complete graph K4 = 3/160.1875000.187500< 1e−6✓ PASS
scaling factor, วงรอบ C4 = 5/16scaling factor, cycle C4 = 5/160.3125000.312500< 1e−6✓ PASS
scaling factor, ตาราง 3 × 3 rookscaling factor, 3 × 3 rook grid0.4097090.409709< 1e−6✓ PASS
scaling factor, ตาราง 3 × 3 queenscaling factor, 3 × 3 queen grid0.2107480.210748< 1e−6✓ PASS
scaling factor, ตาราง 4 × 4 queenscaling factor, 4 × 4 queen grid0.2244330.224433< 1e−6✓ PASS
ΣE = ΣO (การปรับมาตรฐานทางอ้อม)ΣE = ΣO (indirect standardisation)6676670✓ PASS
SD ของ PNW74 (หน่วยของ 1 SD)SD of PNW74 (the unit of 1 SD)20.8604820.86048< 1e−5✓ PASS
φ มัธยฐานภายหลังφ posterior median0.43610.43280.0033 ≤ 0.0396✓ PASS
φ ขอบล่าง 95% CrIφ lower 95% CrI limit0.02540.02080.0046 ≤ 0.0089✓ PASS
φ ขอบบน 95% CrIφ upper 95% CrI limit0.94350.95190.0084 ≤ 0.0169✓ PASS
σ มัธยฐานภายหลังσ posterior median0.27380.27450.0007 ≤ 0.0058✓ PASS
σ ขอบล่าง 95% CrIσ lower 95% CrI limit0.13690.13480.0021 ≤ 0.0168✓ PASS
σ ขอบบน 95% CrIσ upper 95% CrI limit0.42390.42780.0040 ≤ 0.0129✓ PASS
RR ต่อ 1 SD ของ PNW74 มัธยฐานRR per 1 SD of PNW74, median1.50681.50620.0006 ≤ 0.0097✓ PASS
RR ต่อ 1 SD ขอบล่าง 95% CrIRR per 1 SD, lower 95% CrI limit1.32331.32480.0015 ≤ 0.0170✓ PASS
RR ต่อ 1 SD ขอบบน 95% CrIRR per 1 SD, upper 95% CrI limit1.73631.73020.0061 ≤ 0.0227✓ PASS
α มัธยฐานα median−0.0654−0.06690.0014 ≤ 0.0033✓ PASS
Onslow: RR มัธยฐานOnslow: RR median1.38761.39030.0027 ≤ 0.0140✓ PASS
Onslow: P(RR > 1)Onslow: P(RR > 1)0.97320.98300.0098 ≤ 0.0138✓ PASS
Rutherford: RR มัธยฐานRutherford: RR median1.45621.45290.0033 ≤ 0.0302✓ PASS
Rutherford: P(RR > 1)Rutherford: P(RR > 1)0.95400.95400.0000 ≤ 0.0218✓ PASS
Anson: RR มัธยฐานAnson: RR median1.43441.43530.0009 ≤ 0.0295✓ PASS
Anson: P(RR > 1)Anson: P(RR > 1)0.94420.95200.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.8078Transylvania: 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 / divergent1.002 / 1471, 2768 / 01.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
  1. 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
  2. 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
  3. 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
  4. 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
  5. Kruschke, J. K. (2021). Bayesian analysis reporting guidelines. Nature Human Behaviour, 5(10), 1282–1291. doi:10.1038/s41562-021-01177-7
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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).

ตัวอย่าง: ข้อมูล SIDS ของ 100 เคาน์ตีในรัฐ North Carolina ชุดเดียวกับหัวข้อ 6.9 (Cressie & Chan, 1989) ซึ่งมีโรคเดียวแต่สองช่วงเวลา: โรคที่ 1 = SID74 (ตาย 1974–78) ตัวหาร BIR74 และโรคที่ 2 = SID79 (ตาย 1979–84) ตัวหาร BIR79 ทารกคนละกลุ่มกันจึงไม่มีการนับซ้ำ ในตัวอย่างนี้ ρ จึงบอกว่ารูปแบบเชิงพื้นที่ของ SIDS ในช่วงแรกคงอยู่ในช่วงหลังมากเพียงใด และ P(RR1 > RR2) บอกว่าเคาน์ตีใดมีตำแหน่งเทียบกับทั้งรัฐสูงขึ้นหรือต่ำลงระหว่างสองช่วง ถ้าเป็นสองโรคจริงอ่านค่าเดียวกันนี้แบบเดียวกัน DAPH ได้ ρ = 0.596 (95% CrI 0.125 ถึง 0.893; P(ρ > 0) = 0.993)
Example: the North Carolina SIDS data of section 6.9 (100 counties; Cressie & Chan, 1989), which hold one outcome in two periods: outcome 1 = SID74 (deaths 1974–78) with denominator BIR74, outcome 2 = SID79 (deaths 1979–84) with denominator BIR79; the infants differ, so nobody is counted twice. Here ρ says how far the spatial pattern of SIDS in the first period persisted into the second, and P(RR1 > RR2) says in which counties the position relative to the state rose or fell between the periods; with two diseases the same quantities are read the same way. DAPH gives ρ = 0.596 (95% CrI 0.125 to 0.893; P(ρ > 0) = 0.993).

2หลักการและสูตรLogic and Formula

แบบจำลองสองโรคที่มีโครงสร้างร่วม (co-regionalised)Co-regionalised two-outcome model
$$ y_{ki} \sim \text{Poisson}\big(E_{ki}\, e^{\alpha_k + b_{ki}}\big), \qquad E_{ki} = n_{ki}\,\frac{\sum_j y_{kj}}{\sum_j n_{kj}}, \qquad k = 1, 2 $$ $$ \mathbf b_1 = \frac{\sigma_1\,\mathbf u}{\sqrt s}, \qquad \mathbf b_2 = \frac{\sigma_2\big(\rho\,\mathbf u + \sqrt{1-\rho^2}\;\mathbf w\big)}{\sqrt s}, \qquad \mathbf u,\ \mathbf w \sim \text{ICAR}(\mathbf W)\ \text{independent},\ \ \textstyle\sum_i u_i = \sum_i w_i = 0 $$ $$ \operatorname{Var}(\mathbf b_k) = \sigma_k^2\,\mathbf Q^{+}/s, \qquad \operatorname{Cov}(\mathbf b_1, \mathbf b_2) = \rho\,\sigma_1\sigma_2\,\mathbf Q^{+}/s, \qquad \operatorname{Corr}(b_{1i}, b_{2i}) = \rho $$
การแจกแจงก่อนเห็นข้อมูล (prior) ที่ DAPH ใช้Priors DAPH uses
$$ \alpha_1, \alpha_2 \sim N(0,\,5^2), \qquad \sigma_1, \sigma_2 \sim \text{half-}N(0,\,0.5^2), \qquad \rho = 2B - 1,\ \ B \sim \text{Beta}(2,\,2) $$
สิ่งที่ DAPH รายงานWhat DAPH reports
$$ \text{RR}_{ki} = e^{b_{ki}}, \qquad \frac{\text{RR}_{1i}}{\text{RR}_{2i}} = e^{\,b_{1i} - b_{2i}}, \qquad P(\text{RR}_{1i} > \text{RR}_{2i}) = \frac{1}{S}\sum_{s=1}^{S}\mathbf 1\!\left[b_{1i}^{(s)} > b_{2i}^{(s)}\right], \qquad \frac{\sigma_1}{\sigma_2} $$ $$ \text{flag}_{ki} \iff P(\text{RR}_{ki} > c_1) \ge 0.80, \qquad \text{side}_i = \begin{cases} 1 & P(\text{RR}_{1i} > \text{RR}_{2i}) \ge 0.80 \\ 2 & P(\text{RR}_{1i} > \text{RR}_{2i}) \le 0.20 \end{cases} $$
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.

R สคริปต์ตรวจสอบ (R 4.3.3: sf, spdep, MASS, rstan, posterior, zip)verification script (R 4.3.3: sf, spdep, MASS, rstan, posterior, zip)
# 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)
Expected R output (abridged; rstan 2.32.5, seed 12345)
         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 
DAPH ขั้นตอนใน DAPHSteps in DAPH

ไฟล์ > นำเข้า > 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.

📊 ผลการตรวจสอบVerification results
รายการItemRDAPHความต่าง / เกณฑ์Difference / ruleสถานะStatus
กราฟ Queen: พื้นที่ / เส้นเชื่อมQueen graph: areas / edges100 / 245100 / 2450✓ PASS
scaling factor sscaling factor s0.58597960.5859796< 1e−7✓ PASS
ΣE1 = ΣO1 และ ΣE2 = ΣO2 (เหตุการณ์รวม)ΣE1 = ΣO1 and ΣE2 = ΣO2 (total events)667, 836 (1503)667, 836 (1503)0✓ PASS
ρ มัธยฐานภายหลังρ posterior median0.58280.59580.0131 ≤ 0.0237✓ PASS
ρ ขอบล่าง 95% CrIρ lower 95% CrI limit0.11170.12520.0135 ≤ 0.0295✓ PASS
ρ ขอบบน 95% CrIρ upper 95% CrI limit0.88540.89280.0074 ≤ 0.0232✓ PASS
σ1 มัธยฐานภายหลังσ1 posterior median0.50410.50280.0013 ≤ 0.0079✓ PASS
σ1 ขอบล่าง 95% CrIσ1 lower 95% CrI limit0.34610.35100.0049 ≤ 0.0097✓ PASS
σ1 ขอบบน 95% CrIσ1 upper 95% CrI limit0.68340.68340.0000 ≤ 0.0144✓ PASS
σ2 มัธยฐานภายหลังσ2 posterior median0.36870.37030.0017 ≤ 0.0052✓ PASS
σ2 ขอบล่าง 95% CrIσ2 lower 95% CrI limit0.23180.23390.0021 ≤ 0.0098✓ PASS
σ2 ขอบบน 95% CrIσ2 upper 95% CrI limit0.52720.52880.0016 ≤ 0.0112✓ PASS
σ1/σ2 มัธยฐานภายหลังσ1/σ2 posterior median1.36631.36030.0061 ≤ 0.0253✓ PASS
σ1/σ2 ขอบล่าง 95% CrIσ1/σ2 lower 95% CrI limit0.83320.83710.0038 ≤ 0.0264✓ PASS
σ1/σ2 ขอบบน 95% CrIσ1/σ2 upper 95% CrI limit2.30092.30940.0084 ≤ 0.1223✓ PASS
Northampton: RR1/RR2 มัธยฐานNorthampton: RR1/RR2 median1.82491.80220.0227 ≤ 0.0325✓ PASS
Northampton: P(RR1 > RR2)Northampton: P(RR1 > RR2)0.98450.98190.0026 ≤ 0.0057✓ PASS
Catawba: RR1/RR2 มัธยฐานCatawba: RR1/RR2 median0.63840.64430.0059 ≤ 0.0099✓ PASS
Catawba: P(RR1 > RR2)Catawba: P(RR1 > RR2)0.01920.01910.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)2222เคาน์ตีเดียวกันsame counties✓ PASS
P(RR1 > RR2) ≤ 0.20 (SID79 สูงกว่าเชิงสัมพัทธ์)P(RR1 > RR2) ≤ 0.20 (SID79 relatively higher)2223ต่างกันเฉพาะเคาน์ตีที่อยู่ใกล้เกณฑ์: 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.802625ต่างกันเฉพาะเคาน์ตีที่อยู่ใกล้เกณฑ์: 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.802123ต่างกันเฉพาะเคาน์ตีที่อยู่ใกล้เกณฑ์: 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 / divergent1.003 / 912, 1548 / 01.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
  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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 6 topics ✓ 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.

ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย เสียชีวิต 229 ราย) · คำถาม: ข้อมูลพื้นฐานตอนเริ่มรักษา 6 ตัว ได้แก่ อายุ (Age), เพศ (Gender), ดัชนีมวลกาย (Body Mass Index), โรคเรื้อรัง (Chronic Disease), กลุ่มการรักษา CAPD/APD (Treatment Group) และคะแนนคุณภาพชีวิตก่อนรักษา (Quality of Life Score (Pre)) ทำนายได้หรือไม่ว่าผู้ป่วยรายใดจะเสียชีวิตระหว่างการติดตาม (Study Status) · การตรวจสอบตามเวลา (temporal validation): สร้างแบบจำลองจากผู้ป่วย 910 รายแรกที่เข้าโครงการ (2022-01-01 ถึง 2023-01-23 เสียชีวิต 169 ราย) แล้วทดสอบกับผู้ป่วย 390 รายที่เข้าโครงการทีหลัง (2023-01-25 ถึง 2023-06-29 เสียชีวิต 60 ราย) · เปรียบเทียบ 4 แบบจำลอง: Logistic Regression ให้ AUC 0.634 (95% CI 0.552 ถึง 0.710), Random Forest 0.637 (95% CI 0.555 ถึง 0.711; DeLong p = 0.926 เมื่อเทียบกับ Logistic), XGBoost 0.597 · ทุกแบบจำลองมี AUC ต่ำกว่า 0.70 รายงาน Word ของ DAPH จึงสรุปว่าความสามารถในการจำแนกต่ำและไม่แนะนำให้นำไปใช้
DAPH example data (1,300 peritoneal-dialysis patients, 229 deaths). Question: can six characteristics recorded at the start of treatment, namely Age, Gender, Body Mass Index, Chronic Disease, Treatment Group (CAPD/APD) and Quality of Life Score (Pre), predict which patients will die during follow-up (Study Status)? Temporal validation: the models are built on the first 910 patients enrolled (2022-01-01 to 2023-01-23, 169 deaths) and tested on the 390 enrolled later (2023-01-25 to 2023-06-29, 60 deaths). Four models are compared: Logistic Regression gives AUC 0.634 (95% CI 0.552 to 0.710), Random Forest 0.637 (95% CI 0.555 to 0.711; DeLong p = 0.926 against Logistic) and XGBoost 0.597. Every AUC is below 0.70, so DAPH's Word report concludes that discrimination is poor and does not recommend the models for use.

2หลักการและสูตรLogic and Formula

Logistic Regression and Elastic Net (Logistic) as DAPH fits them
$$ \min_{\beta_0,\boldsymbol\beta}\ \tfrac{1}{2}\lVert\boldsymbol\beta\rVert_2^2 + C\sum_{i=1}^{n}\log\!\bigl(1+e^{-\tilde y_i(\beta_0+\mathbf x_i^{\top}\boldsymbol\beta)}\bigr),\qquad C = 1 $$ $$ \min_{\beta_0,\boldsymbol\beta}\ C\sum_{i=1}^{n}\log\!\bigl(1+e^{-\tilde y_i(\beta_0+\mathbf x_i^{\top}\boldsymbol\beta)}\bigr) + \rho\lVert\boldsymbol\beta\rVert_1 + \tfrac{1-\rho}{2}\lVert\boldsymbol\beta\rVert_2^2,\qquad C = 1,\ \rho = 0.5 $$
Discrimination and overall accuracy of the predicted risks
$$ \mathrm{AUC} = \frac{1}{n_1 n_0}\sum_{i:\,y_i=1}\ \sum_{j:\,y_j=0}\Bigl[\mathbf{1}(\hat p_i>\hat p_j)+\tfrac12\,\mathbf{1}(\hat p_i=\hat p_j)\Bigr],\qquad \mathrm{Brier} = \frac1n\sum_{i=1}^{n}(y_i-\hat p_i)^2 $$
Cut-off by Youden's J and the classification metrics (Youden 1950)
$$ J(t) = \mathrm{Sens}(t)+\mathrm{Spec}(t)-1,\qquad t^{*} = \max\bigl\{t : J(t) = \max_{s} J(s)\bigr\},\qquad \hat y_i = \mathbf{1}(\hat p_i \ge t^{*}) $$ $$ \mathrm{Sens}=\tfrac{TP}{TP+FN},\quad \mathrm{Spec}=\tfrac{TN}{TN+FP},\quad \mathrm{PPV}=\tfrac{TP}{TP+FP},\quad \mathrm{NPV}=\tfrac{TN}{TN+FN},\quad F_1=\tfrac{2\,TP}{2\,TP+FP+FN} $$ $$ \mathrm{MCC}=\frac{TP\cdot TN-FP\cdot FN}{\sqrt{(TP+FP)(TP+FN)(TN+FP)(TN+FN)}},\qquad \text{log-loss} = -\frac1n\sum_{i=1}^{n}\bigl[y_i\ln\hat p_i+(1-y_i)\ln(1-\hat p_i)\bigr] $$
Clinical usefulness: net benefit (Decision Curve Analysis)
$$ \mathrm{NB}(p_t) = \frac{TP(p_t)}{n}-\frac{FP(p_t)}{n}\cdot\frac{p_t}{1-p_t},\qquad \mathrm{NB}_{\text{treat all}}(p_t) = \pi-(1-\pi)\,\frac{p_t}{1-p_t},\qquad \mathrm{NB}_{\text{treat none}} = 0 $$
DeLong test (paired AUCs on the same test patients) and the bootstrap 95% CI
$$ z = \frac{\widehat{\mathrm{AUC}}_A-\widehat{\mathrm{AUC}}_B}{\sqrt{\widehat{\mathrm{Var}}_A+\widehat{\mathrm{Var}}_B-2\,\widehat{\mathrm{Cov}}_{AB}}},\qquad p = 2\bigl[1-\Phi(\lvert z\rvert)\bigr] $$ $$ \text{95\% CI} = \bigl[\,Q_{0.025}(\hat\theta^{*}_{1},\dots,\hat\theta^{*}_{1000}),\ Q_{0.975}(\hat\theta^{*}_{1},\dots,\hat\theta^{*}_{1000})\,\bigr] $$
Minimum sample size, Riley et al. (2020) criteria 1 to 3
$$ n_1=\frac{P}{(S-1)\ln\bigl(1-R^2_{CS}/S\bigr)},\ S=0.9;\qquad n_2=\frac{P}{(S_2-1)\ln\bigl(1-R^2_{CS}/S_2\bigr)},\ S_2=\frac{R^2_{CS}}{R^2_{CS}+0.05\,\max R^2_{CS}};\qquad n_3=\Bigl(\frac{1.96}{0.05}\Bigr)^{2}\phi(1-\phi) $$ $$ \max R^2_{CS} = 1-\exp\bigl\{2\bigl[\phi\ln\phi+(1-\phi)\ln(1-\phi)\bigr]\bigr\},\qquad R^2_{CS} = 0.15\times\max R^2_{CS}\ \ (\text{3 decimals}),\qquad n_{\min}=\max(n_1,n_2,n_3) $$
SHAP value of predictor j for one patient
$$ \phi_j = \sum_{S\subseteq F\setminus\{j\}} \frac{|S|!\,(|F|-|S|-1)!}{|F|!}\,\bigl[f(S\cup\{j\})-f(S)\bigr] $$
ỹ_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.

R script แบบจำลองทำนายการเสียชีวิต แบ่งตามเวลา 70/30 (แพ็กเกจ glmnet และ pROC)death prediction models, temporal 70/30 split (packages glmnet and pROC)
# 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")
Expected R output (R 4.3.3)
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
DAPH Tab 2 > Statistic = Machine Learning Comparison · Dependent Variable = Study Status · Independent Variables = Age, Gender, Body Mass Index, Chronic Disease, Treatment Group, Quality of Life Score (Pre) · Train/Test Split 70/30 แบบ Temporal ตัวแปรเวลา enroll_date · ปิด Cross-Validation · วิธีเลือกตัวแปร = Enter · โมเดล = Logistic Regression, Elastic Net (Logistic), Random Forest, XGBoost · ตั้งค่าขั้นสูง: ความไม่สมดุลกลุ่ม = ไม่ปรับ, การจูนพารามิเตอร์ = Library defaults, Threshold = Youden's J, Random seed = 12345 · ค่า DAPH มาจาก Tab 3 รายงาน Word และค่าภายในที่ทศนิยมเต็มTab 2 > Statistic = Machine Learning Comparison; Dependent Variable = Study Status; Independent Variables = Age, Gender, Body Mass Index, Chronic Disease, Treatment Group, Quality of Life Score (Pre); Train/Test Split 70/30, Temporal, time variable enroll_date; Cross-Validation off; Variable selection = Enter; Models = Logistic Regression, Elastic Net (Logistic), Random Forest, XGBoost; Advanced settings: Class imbalance = None, HPO tuning = Library defaults, Threshold = Youden's J, Random seed = 12345. DAPH values come from Tab 3, the Word report and the engine's full-precision values.
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
ชุดฝึก: n · ช่วงวันที่เข้าโครงการ · จำนวนเสียชีวิตTraining set: n · enrolment dates · deaths910 · 2022-01-01 to 2023-01-23 · 169910 · 2022-01-01 to 2023-01-23 · 1690✓ PASS
ชุดทดสอบ: n · ช่วงวันที่ · สัดส่วนเสียชีวิตTest set: n · dates · death rate390 · 2023-01-25 to 2023-06-29 · 0.1538390 · 2023-01-25 to 2023-06-29 · 0.15380✓ PASS
Logistic: AUC / BrierLogistic: AUC / Brier0.6337 / 0.12490.6337 / 0.1249< 0.000001✓ PASS
Logistic: จุดตัด Youden บนชุดทดสอบLogistic: Youden cut-off on the test set0.13060.1306< 0.00001✓ PASS
Logistic: Sens / Spec ที่จุดตัดLogistic: Sens / Spec at the cut-off0.8167 / 0.38180.8167 / 0.38180✓ PASS
Logistic: PPV / NPV / F1Logistic: PPV / NPV / F10.1937 / 0.9197 / 0.31310.1937 / 0.9197 / 0.31310✓ PASS
Logistic: MCC / accuracy / balanced accuracy (Tab 3)Logistic: MCC / accuracy / balanced accuracy (Tab 3)0.1500 / 0.4487 / 0.59920.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.00260.413 / 0.000 / 0.0026< 0.0005✓ PASS
Elastic Net: AUC / BrierElastic Net: AUC / Brier0.6341 / 0.12480.6341 / 0.1248< 0.000001✓ PASS
Elastic Net: จุดตัด / Sens / SpecElastic Net: cut-off / Sens / Spec0.1533 / 0.7167 / 0.48180.1533 / 0.7167 / 0.4818< 0.00001 / 0 / 0✓ PASS
Elastic Net: PPV / NPV / F1 / MCCElastic Net: PPV / NPV / F1 / MCC0.2009 / 0.9034 / 0.3139 / 0.14390.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.00510.413 / 0.518 / 0.599 / 0.0051< 0.0005✓ PASS
DeLong p: Elastic Net เทียบกับ LogisticDeLong p: Elastic Net vs Logistic0.63660.6366< 0.000001✓ PASS
Logistic: 95% CI ของ AUC (bootstrap)*Logistic: AUC 95% CI (bootstrap)*0.5558 to 0.71340.5521 to 0.71000.0037 (≤ 0.015)✓ PASS
Logistic: 95% CI ของ Brier (bootstrap)*Logistic: Brier 95% CI (bootstrap)*0.1062 to 0.14630.1035 to 0.14720.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 n0.1857 · 0.093 · 551/183/233 · 5510.1857 · 0.093 · 551/183/233 · 5510✓ 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
  1. Breiman, L. (2001). Random forests. Machine Learning, 45(1), 5–32. doi:10.1023/A:1010933404324
  2. 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
  3. 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
  4. Cortes, C., & Vapnik, V. (1995). Support-vector networks. Machine Learning, 20(3), 273–297. doi:10.1007/BF00994018
  5. 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
  6. Lundberg, S. M., & Lee, S.-I. (2017). A unified approach to interpreting model predictions. Advances in Neural Information Processing Systems (NeurIPS), 30, 4765–4774.
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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).

ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,297 รายที่ทราบโรงพยาบาล) · คำถาม: ลักษณะของผู้ป่วยตอนเริ่มรักษา 10 ตัว ได้แก่ อายุ, เพศ, ดัชนีมวลกาย, โรคเรื้อรัง, กลุ่มการรักษา CAPD/APD, คะแนนคุณภาพชีวิตก่อนรักษา, รายได้ส่วนบุคคล (Personal Income), รายได้ครัวเรือน (Household Income), สถานะการทำงาน (Employment Status) และอำเภอที่อยู่ (District) บอกได้หรือไม่ว่าผู้ป่วยรักษาที่โรงพยาบาลใดใน 7 แห่ง (Hospital) · เหตุผลที่ใช้คำถามนี้: Hospital เป็นตัวแปรกลุ่มที่ไม่มีลำดับเพียงตัวเดียวในข้อมูลที่มีความหมายในทางปฏิบัติ ถ้าแบบจำลองแยกโรงพยาบาลได้ดี แปลว่าแต่ละโรงพยาบาลรักษาผู้ป่วยต่างลักษณะกัน (case-mix) และการเทียบผลลัพธ์ดิบระหว่างโรงพยาบาลจะมีตัวกวน ถ้าแยกไม่ได้ ลักษณะที่วัดได้ของผู้ป่วยก็ใกล้เคียงกัน · แบ่งตามเวลา: ชุดฝึก 908 รายแรก ชุดทดสอบ 389 รายหลัง · ผลจาก DAPH: macro-AUC ของ Logistic Regression 0.479 (95% CI 0.434 ถึง 0.527), macro-F1 0.099 และ accuracy 0.447 ซึ่งต่ำกว่า 0.468 ที่ได้จากการทายโรงพยาบาลใหญ่ที่สุดให้ทุกคน
DAPH example data (1,297 peritoneal-dialysis patients with a known hospital). Question: can ten characteristics at the start of treatment, namely Age, Gender, Body Mass Index, Chronic Disease, Treatment Group (CAPD/APD), Quality of Life Score (Pre), Personal Income, Household Income, Employment Status and District, tell which of the seven hospitals (Hospital) treats a patient? Why this question: Hospital is the only unordered categorical variable in these data with a practical meaning. If a model separates the hospitals well, the hospitals treat different kinds of patients (case-mix), and a crude comparison of hospital outcomes would be confounded; if it cannot, the measured patient profiles are similar. Temporal split: the first 908 patients for training, the later 389 for testing. Result from DAPH: Logistic Regression macro-AUC 0.479 (95% CI 0.434 to 0.527), macro-F1 0.099 and accuracy 0.447, below the 0.468 obtained by guessing the largest hospital for everyone.

2หลักการและสูตรLogic and Formula

Multinomial (softmax) Logistic Regression as DAPH fits it
$$ \hat p_{ik} = \frac{\exp(\beta_{0k}+\mathbf x_i^{\top}\boldsymbol\beta_k)}{\sum_{l=1}^{K}\exp(\beta_{0l}+\mathbf x_i^{\top}\boldsymbol\beta_l)},\qquad \min\ \tfrac12\sum_{k=1}^{K}\lVert\boldsymbol\beta_k\rVert_2^2 - C\sum_{i=1}^{n}\ln\hat p_{i,y_i},\qquad C = 1,\qquad \hat y_i = \arg\max_k \hat p_{ik} $$

Elastic Net (Logistic) ใช้บทลงโทษ ρ Σ|β| + (1 − ρ)/2 Σβ² กับทุกสัมประสิทธิ์ (ρ = 0.5) แทน ½Σβ²

Elastic Net (Logistic) replaces ½Σβ² by ρ Σ|β| + (1 − ρ)/2 Σβ² over all coefficients (ρ = 0.5).

Macro-AUC, one-vs-rest (what DAPH reports)
$$ \mathrm{AUC}_{\text{macro}} = \frac{1}{K}\sum_{k=1}^{K}\mathrm{AUC}_k,\qquad \mathrm{AUC}_k = \text{AUC of } \hat p_{ik} \text{ for category } k \text{ against all other categories} $$
Per-category and averaged classification metrics
$$ F_{1,k} = \frac{2\,TP_k}{2\,TP_k+FP_k+FN_k},\qquad F_{1,\text{macro}} = \frac1K\sum_{k=1}^{K}F_{1,k},\qquad \text{accuracy} = \frac1n\sum_{k=1}^{K}TP_k,\qquad \text{balanced accuracy} = \frac1K\sum_{k=1}^{K}\frac{TP_k}{TP_k+FN_k} $$ $$ \kappa = \frac{p_o-p_e}{1-p_e},\qquad p_o = \frac1n\sum_{k}n_{kk},\qquad p_e = \frac{1}{n^2}\sum_{k}n_{k+}\,n_{+k},\qquad \text{log-loss} = -\frac1n\sum_{i=1}^{n}\ln\hat p_{i,y_i} $$
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.

R script ทำนายโรงพยาบาลจากลักษณะผู้ป่วย แบ่งตามเวลา 70/30 (แพ็กเกจ glmnet)predicting the hospital from patient characteristics, temporal 70/30 split (package glmnet)
# 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))
Expected R output (R 4.3.3)
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
DAPH Tab 2 > Statistic = Machine Learning Comparison · Dependent Variable = Hospital · Independent Variables = Age, Gender, Body Mass Index, Chronic Disease, Treatment Group, Quality of Life Score (Pre), Personal Income, Household Income, Employment Status, District · Train/Test Split 70/30 แบบ Temporal ตัวแปรเวลา enroll_date · ปิด Cross-Validation · วิธีเลือกตัวแปร = Enter · โมเดล = Logistic Regression, Elastic Net (Logistic), Random Forest · ตั้งค่าขั้นสูง: ความไม่สมดุลกลุ่ม = ไม่ปรับ, การจูนพารามิเตอร์ = Library defaults, Random seed = 12345Tab 2 > Statistic = Machine Learning Comparison; Dependent Variable = Hospital; Independent Variables = Age, Gender, Body Mass Index, Chronic Disease, Treatment Group, Quality of Life Score (Pre), Personal Income, Household Income, Employment Status, District; Train/Test Split 70/30, Temporal, time variable enroll_date; Cross-Validation off; Variable selection = Enter; Models = Logistic Regression, Elastic Net (Logistic), Random Forest; Advanced settings: Class imbalance = None, HPO tuning = Library defaults, Random seed = 12345.
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
ชนิดของผลลัพธ์ (Hospital, 7 กลุ่ม)Outcome type (Hospital, 7 categories)multiclassmulticlass—✓ PASS
n ที่ใช้ · ชุดฝึก · ชุดทดสอบn used · training · test1297 · 908 · 3891297 · 908 · 3890✓ PASS
Logistic: macro-AUC / macro-F1 / accuracyLogistic: macro-AUC / macro-F1 / accuracy0.4792 / 0.0988 / 0.44730.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.52920.4339 to 0.52670.0025 (≤ 0.015)✓ PASS
Elastic Net: macro-AUC / macro-F1 / accuracyElastic Net: macro-AUC / macro-F1 / accuracy0.4760 / 0.0970 / 0.44990.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
  1. Cohen, J. (1960). A coefficient of agreement for nominal scales. Educational and Psychological Measurement, 20(1), 37–46. doi:10.1177/001316446002000104
  2. Fawcett, T. (2006). An introduction to ROC analysis. Pattern Recognition Letters, 27(8), 861–874. doi:10.1016/j.patrec.2005.10.010
  3. 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
  4. 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
  5. 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).

ข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย) · คำถาม: ลักษณะตอนเริ่มรักษา 8 ตัว ได้แก่ อายุ, เพศ, ดัชนีมวลกาย, โรคเรื้อรัง, กลุ่มการรักษา CAPD/APD, รายได้ส่วนบุคคล, รายได้ครัวเรือน และสถานะการทำงาน ทำนายคะแนนคุณภาพชีวิตหลังรักษา (Quality of Life Score (Post), 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) แย่กว่าการทายค่าเฉลี่ย
DAPH example data (1,300 peritoneal-dialysis patients). Question: how well do eight characteristics at the start of treatment, namely Age, Gender, Body Mass Index, Chronic Disease, Treatment Group (CAPD/APD), Personal Income, Household Income and Employment Status, predict the post-treatment quality-of-life score (Quality of Life Score (Post), 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

Linear Regression and Elastic Net as DAPH fits them
$$ \min_{\beta_0,\boldsymbol\beta}\ \sum_{i=1}^{n}\bigl(y_i-\beta_0-\mathbf x_i^{\top}\boldsymbol\beta\bigr)^2\qquad\text{(Linear Regression, ordinary least squares)} $$ $$ \min_{\beta_0,\boldsymbol\beta}\ \frac{1}{2n}\sum_{i=1}^{n}\bigl(y_i-\beta_0-\mathbf x_i^{\top}\boldsymbol\beta\bigr)^2+\alpha\rho\lVert\boldsymbol\beta\rVert_1+\frac{\alpha(1-\rho)}{2}\lVert\boldsymbol\beta\rVert_2^2,\qquad \alpha = 1,\ \rho = 0.5 $$

ส่วน 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.

Test-set metrics
$$ R^2 = 1-\frac{\sum_{i}(y_i-\hat y_i)^2}{\sum_{i}(y_i-\bar y)^2},\qquad \mathrm{RMSE} = \sqrt{\frac1n\sum_{i=1}^{n}(y_i-\hat y_i)^2},\qquad \mathrm{MAE} = \frac1n\sum_{i=1}^{n}\lvert y_i-\hat y_i\rvert $$ $$ \mathrm{MAPE} = \frac{100}{n}\sum_{i=1}^{n}\left\lvert\frac{y_i-\hat y_i}{y_i}\right\rvert\ (\%),\qquad R^2_{\text{adj}} = 1-(1-R^2)\,\frac{n-1}{n-p-1} $$
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.

R script ทำนายคะแนนคุณภาพชีวิตหลังรักษา แบ่งตามเวลา 70/30 (แพ็กเกจ stats)predicting post-treatment quality of life, temporal 70/30 split (package 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")

# 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))
Expected R output (R 4.3.3)
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
DAPH Tab 2 > Statistic = Machine Learning Comparison · Dependent Variable = Quality of Life Score (Post) · Independent Variables = Age, Gender, Body Mass Index, Chronic Disease, Treatment Group, Personal Income, Household Income, Employment Status · Train/Test Split 70/30 แบบ Temporal ตัวแปรเวลา enroll_date · ปิด Cross-Validation · วิธีเลือกตัวแปร = Enter · โมเดล = Linear Regression, Elastic Net, Random Forest, XGBoost · การจูนพารามิเตอร์ = Library defaults · Random seed = 12345Tab 2 > Statistic = Machine Learning Comparison; Dependent Variable = Quality of Life Score (Post); Independent Variables = Age, Gender, Body Mass Index, Chronic Disease, Treatment Group, Personal Income, Household Income, Employment Status; Train/Test Split 70/30, Temporal, time variable enroll_date; Cross-Validation off; Variable selection = Enter; Models = Linear Regression, Elastic Net, Random Forest, XGBoost; HPO tuning = Library defaults; Random seed = 12345.
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
ชุดฝึก / ชุดทดสอบ (n)Training / test set (n)910 / 390910 / 3900✓ PASS
Linear: R² / RMSE / MAELinear: R² / RMSE / MAE0.0415 / 17.1242 / 13.71110.04155 / 17.12419 / 13.71107< 0.00005✓ PASS
Linear: MAPE / adjusted R² (Tab 3)Linear: MAPE / adjusted R² (Tab 3)22.6569% / 0.000422.7% / 0.000< 0.05 / < 0.0005✓ PASS
Elastic Net: R² / RMSE / MAEElastic Net: R² / RMSE / MAE0.0206 / 17.3100 / 13.95950.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.021423.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.07620.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.727115.9676 to 18.3644 / 12.7642 to 14.78030.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 reportR² 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
  1. Breiman, L. (2001). Random forests. Machine Learning, 45(1), 5–32. doi:10.1023/A:1010933404324
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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.

คำถาม: จากมูลค่าบ้านและรายได้ครัวเรือน แบบจำลองทำนายอัตราอาชญากรรมของย่านที่ไม่เคยเห็นได้ดีเพียงใด และ residual ยังจับกลุ่มตามพื้นที่หรือไม่? ใน DAPH: Spatial Machine Learning, ผลลัพธ์ = 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).
Question: from housing value and household income, how well can a model predict the crime rate of neighbourhoods it has never seen, and do its residuals still cluster in space? In DAPH: Spatial Machine Learning, outcome = 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

Spatial weights and spatial lag of a predictor (row-standardised)
$$ w_{ij} = \frac{c_{ij}}{\sum_{k} c_{ik}}, \qquad (Wx)_i = \sum_{j} w_{ij}\,x_j = \frac{1}{m_i}\sum_{j \in N(i)} x_j $$
Centroid coordinates
$$ \bigl(cx_i,\ cy_i\bigr) = \Bigl(\frac{1}{A_i}\iint_{P_i} x\,dA,\ \ \frac{1}{A_i}\iint_{P_i} y\,dA\Bigr) $$
Spatial blocks (k-means on the centroids) and folds
$$ K = \max\bigl(2,\ \min(B,\ \lfloor n/5 \rfloor)\bigr), \qquad \{G_1,\dots,G_K\} \approx \arg\min \sum_{k=1}^{K} \sum_{i \in G_k} \lVert c_i - \bar c_k \rVert^2, \qquad \text{fold}(i) = \text{block}(i) $$
Out-of-fold prediction and pooled metrics
$$ \hat y_i = \hat f_{-k}(x_i)\ \ \text{for } i \in G_k, \qquad R^2 = 1 - \frac{\sum_i (y_i - \hat y_i)^2}{\sum_i (y_i - \bar y)^2}, \quad \mathrm{RMSE} = \sqrt{\frac{1}{n}\sum_i (y_i - \hat y_i)^2}, \quad \mathrm{MAE} = \frac{1}{n}\sum_i \lvert y_i - \hat y_i \rvert $$
Moran's I of the out-of-fold residuals
$$ I = \frac{n}{S_0}\cdot\frac{\sum_i \sum_j w_{ij}\,(e_i - \bar e)(e_j - \bar e)}{\sum_i (e_i - \bar e)^2}, \qquad S_0 = \sum_i \sum_j w_{ij}, \qquad e_i = y_i - \hat y_i $$
Permutation p value and z (999 random permutations of e)
$$ p = \frac{\min(m,\ 999 - m) + 1}{999 + 1}, \qquad z = \frac{I - \bar I_{\mathrm{perm}}}{s_{\mathrm{perm}}} $$
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 column W_name for 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.

R script packages: sf, spdep, spData, glmnetpackages: sf, spdep, spData, glmnet
# 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)
Expected R output (ตัดบางส่วน; R 4.3.3, spdep 1.3-1, glmnet 4.1-8)(abridged; R 4.3.3, spdep 1.3-1, glmnet 4.1-8)
      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
DAPH File > Open: 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)
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceสถานะStatus
จำนวนคู่เพื่อนบ้าน Queen (49 ย่าน)Queen neighbour links (49 areas)2362360✓ PASS
coord_x · coord_y ของย่านที่ 1 (ตรวจครบ 49 ย่าน)coord_x · coord_y of area 1 (all 49 areas checked)8.8272 · 14.36918.8272 · 14.36910✓ PASS
W_HOVAL · W_INC ของย่านที่ 1 (ตรวจครบ 49 ย่าน)W_HOVAL · W_INC of area 1 (all 49 areas checked)35.4585 · 18.594035.4585 · 18.59400✓ 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 · MAE0.396546 · 12.864555 · 10.0540370.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.9434990.372293 · 13.120523 · 10.9434870.000004 · 0.000039 · 0.000012✓ PASS
Linear Regression, ชุดทดสอบ 15 ย่าน: R² · RMSE · MAELinear Regression, test set of 15 areas: R² · RMSE · MAE0.095520 · 9.274555 · 8.3205250.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.5942610.002683 · 9.738907 · 8.5942980.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.2271490.227149< 0.000001✓ PASS
|r| สูงสุดระหว่างตัวแปรทำนาย (HOVAL, INC)Largest |r| between predictors (HOVAL, INC)0.50.500✓ 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
  1. Anselin, L. (1988). Spatial econometrics: Methods and models. Kluwer Academic Publishers. doi:10.1007/978-94-015-7799-1
  2. Breiman, L. (2001). Random forests. Machine Learning, 45(1), 5–32. doi:10.1023/A:1010933404324
  3. Moran, P. A. P. (1950). Notes on continuous stochastic phenomena. Biometrika, 37(1–2), 17–23. doi:10.1093/biomet/37.1-2.17
  4. 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
  5. 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
  6. 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.

ข้อมูลตัวอย่าง DAPH · คำถาม: แบบจำลองทำนายการเสียชีวิตที่สร้างจากผู้ป่วยโรงพยาบาลรัฐ ใช้กับผู้ป่วยโรงพยาบาลเอกชนได้หรือไม่ (ตัวทำนาย 6 ตัวเหมือนหัวข้อ 7.1) · พัฒนา: เมนู เครื่องมือข้อมูล > กรองข้อมูล (Filter) Hospital Type = 1 (โรงพยาบาลรัฐ 1,061 ราย) แล้วรัน Logistic Regression แบบ Temporal split 70/30 (ชุดฝึก 743 ราย ชุดทดสอบ 318 ราย) จากนั้นกด Save Model · ตรวจสอบ: นำเข้าข้อมูลตัวอย่างใหม่ กรอง Hospital Type = 2 (โรงพยาบาลเอกชน 236 ราย) แนบไฟล์ .daphmodel แล้วกด Run · ผล: จุดตัดที่ล็อกไว้ 0.227 · AUC ตอนพัฒนา 0.656 กับข้อมูลโรงพยาบาลเอกชน 0.663 (Δ = −0.007) · Brier 0.122 เป็น 0.144 · specificity 0.815 เป็น 0.734
DAPH example data. Question: does a death-prediction model built on public-hospital patients work for private-hospital patients (the six predictors of 7.1)? Development: Data Tools > Filter Data, Hospital Type = 1 (1,061 public-hospital patients), then Logistic Regression with a temporal 70/30 split (743 training, 318 test patients), then Save Model. Validation: load the example data again, filter Hospital Type = 2 (236 private-hospital patients), attach the .daphmodel file and Run. Result: locked cut-off 0.227; AUC 0.656 at development and 0.663 in the private hospitals (Δ = −0.007); Brier 0.122 to 0.144; specificity 0.815 to 0.734.

2หลักการและสูตรLogic and Formula

Temporal split as DAPH does it
$$ t_{(1)}\le t_{(2)}\le\dots\le t_{(n)}\ \ \text{(stable sort: ties keep the file order)},\qquad n_{\text{train}} = \operatorname{round}(r\,n),\qquad \text{train} = \{(1),\dots,(n_{\text{train}})\},\quad \text{test} = \{(n_{\text{train}}+1),\dots,(n)\} $$
Cut-off locked at development, reused unchanged (Youden 1950)
$$ t^{*} = \max\bigl\{t : J_{\text{dev}}(t) = \max_s J_{\text{dev}}(s)\bigr\},\qquad J_{\text{dev}}(t) = \mathrm{Sens}_{\text{dev}}(t)+\mathrm{Spec}_{\text{dev}}(t)-1,\qquad \hat y_i^{\text{ext}} = \mathbf{1}\bigl(\hat p_i^{\text{ext}} \ge t^{*}\bigr) $$
Change in each metric and DAPH's verdict
$$ \Delta_M = M_{\text{dev}}-M_{\text{ext}},\qquad \text{verdict from } \Delta_{\text{AUC}} \text{ (binary) or } \Delta_{R^2} \text{ (continuous)}:\ \le 0.05,\ \ 0.05\text{ to }0.10,\ \ >0.10 $$
Calibration in the new data (computed in R; not reported by DAPH)
$$ \operatorname{logit}\Pr(y_i=1) = a + \operatorname{logit}(\hat p_i)\ \ \Rightarrow\ \text{calibration-in-the-large } a,\qquad \operatorname{logit}\Pr(y_i=1) = a' + b\,\operatorname{logit}(\hat p_i)\ \ \Rightarrow\ \text{slope } b $$
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

R script พัฒนาที่โรงพยาบาลรัฐ ตรวจที่โรงพยาบาลเอกชน ด้วยจุดตัดที่ล็อกไว้ (แพ็กเกจ glmnet และ pROC)develop in public hospitals, validate in private hospitals at the locked cut-off (packages glmnet and pROC)
# 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))
Expected R output (R 4.3.3)
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
DAPH พัฒนา: เมนู เครื่องมือข้อมูล > กรองข้อมูล (Filter) Hospital Type = 1 · Tab 2 > Statistic = Machine Learning Comparison · Dependent Variable = Study Status · Independent Variables = Age, Gender, Body Mass Index, Chronic Disease, Treatment Group, Quality of Life Score (Pre) · Train/Test Split 70/30 แบบ Temporal ตัวแปรเวลา enroll_date · ปิด Cross-Validation · โมเดล = Logistic Regression · ความไม่สมดุลกลุ่ม = ไม่ปรับ · กด Save Model · ตรวจสอบ: นำเข้าข้อมูลตัวอย่างใหม่ กรอง Hospital Type = 2 แล้วแนบไฟล์ใน External Validation (โมเดลที่บันทึกไว้) และกด RunDevelopment: Data Tools > Filter Data, Hospital Type = 1; Tab 2 > Statistic = Machine Learning Comparison; Dependent Variable = Study Status; Independent Variables = Age, Gender, Body Mass Index, Chronic Disease, Treatment Group, Quality of Life Score (Pre); Train/Test Split 70/30, Temporal, time variable enroll_date; Cross-Validation off; Model = Logistic Regression; Class imbalance = None; then Save Model. Validation: load the example data again, filter Hospital Type = 2, attach the file under External Validation (saved model) and Run.
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
ข้อมูลพัฒนา (Hospital Type = 1): n · ชุดฝึก · ชุดทดสอบDevelopment data (Hospital Type = 1): n · training · test1061 · 743 · 3181061 · 743 · 3180✓ PASS
จุดตัดที่ล็อกไว้Locked cut-off0.22710.2271< 0.000001✓ PASS
ตอนพัฒนา: AUC / BrierDevelopment: AUC / Brier0.65633 / 0.122020.65633 / 0.12202< 0.000005✓ PASS
ตอนพัฒนา: Sens / Spec / PPV / NPV / F1Development: Sens / Spec / PPV / NPV / F10.45833 / 0.81481 / 0.30556 / 0.89431 / 0.366670.45833 / 0.81481 / 0.30556 / 0.89431 / 0.366670✓ PASS
ข้อมูลภายนอก (Hospital Type = 2): nExternal data (Hospital Type = 2): n2362360✓ PASS
ภายนอก: AUC / BrierExternal: AUC / Brier0.66323 / 0.144380.66323 / 0.14438< 0.000001✓ PASS
ภายนอก: Sens / Spec / PPV / NPV / F1 ที่จุดตัดเดิมExternal: Sens / Spec / PPV / NPV / F1 at the locked cut-off0.47727 / 0.73438 / 0.29167 / 0.85976 / 0.362070.47727 / 0.73438 / 0.29167 / 0.85976 / 0.362070✓ 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.74690.5715 to 0.75000.0031 (≤ 0.015)✓ PASS
ข้อความคำวินิจฉัยVerdict textAUC เพิ่มขึ้น 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 data0.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
  1. 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
  2. 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.
  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
  4. 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
  5. 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.

คำถาม: แบบจำลองที่เรียนจากปี 1970–1981 ทำนาย 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).
Question: how well does a model trained on 1970–1981 predict each state's 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

Wide file → one row per area and period
$$ \bigl(y_{it},\ x_{1it},\dots,x_{pit},\ z_{1i},\dots\bigr), \qquad i = 1,\dots,N \text{ areas}, \quad t = 1,\dots,T \text{ periods} $$
Hold-out of the later periods
$$ T_{\text{train}} = \min\bigl(T-1,\ \max(1,\ \operatorname{round}(\rho\,T))\bigr), \qquad \text{train} = \{t \le T_{\text{train}}\}, \quad \text{test} = \{t > T_{\text{train}}\} $$
Spatial features (W built once over the N areas, applied within each period)
$$ (Wx)_{it} = \sum_{j} w_{ij}\,x_{jt}, \qquad \bigl(cx_i,\ cy_i\bigr)\ \text{as in 7.4}, \qquad \text{block}(i,t) = \text{block}(i) $$
Optional time features
$$ y^{\text{lag}}_{it} = y_{i,t-1}, \qquad (W y^{\text{lag}})_{it} = \sum_j w_{ij}\,y_{j,t-1}, \qquad \tau_t = t - t_0 \ \ (0, 1, 2, \dots) $$
Moran's I of the out-of-fold residuals, period by period
$$ I_t = \frac{N}{S_0}\cdot\frac{\sum_i\sum_j w_{ij}(e_{it}-\bar e_t)(e_{jt}-\bar e_t)}{\sum_i (e_{it}-\bar e_t)^2}, \qquad \text{DAPH reports } \bar I = \frac{1}{T}\sum_t I_t $$
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.

R script packages: sf, spdep, spData, plm, glmnetpackages: sf, spdep, spData, plm, glmnet
# 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)
Expected R output (ตัดบางส่วน; R 4.3.3, spdep 1.3-1, glmnet 4.1-8)(abridged; R 4.3.3, spdep 1.3-1, glmnet 4.1-8)
  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 
DAPH File > Open: 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
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceสถานะStatus
คู่เพื่อนบ้าน Queen (48 รัฐ) · จำนวนแถวหลังแปลงQueen neighbour links (48 states) · rows after reshaping214 · 816214 · 8160✓ 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.292230✓ 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.469.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 states238, 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 · MAE0.991610 · 0.091482 · 0.0719160.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.4902330.650274 · 0.590636 · 0.4902350.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.1225440.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.5147710.629120 · 0.621487 · 0.5147740.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.887411.70596 · 0 · 10.88740✓ PASS
B: Linear Regression, ปีทดสอบB: Linear Regression, test years0.998318 · 0.040965 · 0.0343030.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.4732420.674370 · 0.569925 · 0.4732390.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.0435360.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.4958230.652020 · 0.600080 · 0.4958190.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.78430.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.89670.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
  1. Breiman, L. (2001). Random forests. Machine Learning, 45(1), 5–32. doi:10.1023/A:1010933404324
  2. 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
  3. 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
  4. Moran, P. A. P. (1950). Notes on continuous stochastic phenomena. Biometrika, 37(1–2), 17–23. doi:10.1093/biomet/37.1-2.17
  5. 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
  6. 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
  7. 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) 3 topics ✓ 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.

ตัวอย่างในข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 คน): วิธีล้างไตแบบ APD (เทียบกับ CAPD) สัมพันธ์กับคะแนนคุณภาพชีวิตหลังติดตาม (Quality of Life Score (Post)) ผ่านจำนวนครั้งของเยื่อบุช่องท้องอักเสบ (Number of Peritonitis Episodes) หรือไม่ · ผล: กลุ่ม APD มีเยื่อบุช่องท้องอักเสบน้อยกว่ากลุ่ม CAPD เฉลี่ย 1.066 ครั้ง และการอักเสบเพิ่มขึ้น 1 ครั้งสัมพันธ์กับคะแนนคุณภาพชีวิตที่ต่ำลง 0.836 คะแนน (p = 0.003) · อิทธิพลทางอ้อม B = 0.891 (95% CI แบบ bootstrap 0.331 ถึง 1.480) · อิทธิพลทางตรง B = 1.065 (95% CI −0.954 ถึง 3.085, p = 0.301) · อิทธิพลรวม B = 1.956 · เมื่อตัดเส้นทางตรงออก (โมเดล full mediation, df = 1) โมเดลยังกลมกลืนกับข้อมูล: χ²(1) = 1.070, p = 0.301, CFI = 0.999, RMSEA = 0.007, SRMR = 0.011
Example in the DAPH data (1,300 peritoneal-dialysis patients): is APD (versus CAPD) associated with the quality-of-life score at the end of follow-up (Quality of Life Score (Post)) through the number of peritonitis episodes (Number of Peritonitis Episodes)? Results: APD patients had on average 1.066 fewer peritonitis episodes than CAPD patients, and each additional episode was associated with a 0.836-point lower QoL score (p = 0.003). Indirect effect B = 0.891 (bootstrap 95% CI 0.331 to 1.480); direct effect B = 1.065 (95% CI −0.954 to 3.085, p = 0.301); total effect B = 1.956. With the direct path removed (full-mediation model, df = 1) the model still fits the data: χ²(1) = 1.070, p = 0.301, CFI = 0.999, RMSEA = 0.007, SRMR = 0.011.

2หลักการและสูตรLogic and Formula

Structural equations (recursive path model, one equation per mediator and for the outcome)
$$ M_j = \alpha_j + \sum_k a_{kj}\,X_k + \varepsilon_{M_j}, \qquad Y = \beta_0 + \sum_k c'_k\,X_k + \sum_j b_j\,M_j + \varepsilon_Y $$
Effect decomposition (product of coefficients)
$$ \text{Direct}_k = c'_k, \qquad \text{Indirect}_{kj} = a_{kj}\,b_j, \qquad \text{Total}_k = c'_k + \sum_j a_{kj}\,b_j $$

เมื่อตัวแปรต้นทุกตัวที่มีเส้นทางไป 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).

Estimation of each equation (ordinary least squares) and its interval
$$ \hat{\boldsymbol\beta} = (\mathbf{X}^{\top}\mathbf{X})^{-1}\mathbf{X}^{\top}\mathbf{y}, \qquad SE(\hat\beta_j) = \sqrt{\hat\sigma^2\,[(\mathbf{X}^{\top}\mathbf{X})^{-1}]_{jj}}, \quad \hat\sigma^2 = \frac{RSS}{N-k-1}, \qquad \hat\beta_j \pm 1.96\,SE(\hat\beta_j) $$
Model-implied covariance (reticular action model)
$$ \hat{\Sigma} = (I - A)^{-1}\,\Psi\,(I - A)^{-\top} $$
Maximum-likelihood discrepancy, χ² and degrees of freedom
$$ F_{ML} = \log|\hat{\Sigma}| + \operatorname{tr}\!\bigl(S\,\hat{\Sigma}^{-1}\bigr) - \log|S| - p, \qquad \chi^2 = (N-1)\,F_{ML}, \qquad df = \tfrac{p(p+1)}{2} - q $$
Approximate-fit indices
$$ \mathrm{RMSEA} = \sqrt{\frac{\max(\chi^2 - df,\ 0)}{df\,(N-1)}}, \qquad \mathrm{CFI} = 1 - \frac{\max(\chi^2 - df,\ 0)}{\max(\chi^2_0 - df_0,\ \chi^2 - df,\ 0)} $$ $$ \mathrm{TLI} = \frac{\chi^2_0/df_0 - \chi^2/df}{\chi^2_0/df_0 - 1}, \qquad \mathrm{SRMR} = \sqrt{\frac{2}{p(p+1)}\sum_{i \le j}\bigl(r_{ij} - \hat{r}_{ij}\bigr)^2} $$
Indirect and total effects: percentile bootstrap
$$ \mathrm{CI}_{95\%} = \bigl[\,\widehat{ab}^{*}_{(0.025)},\ \widehat{ab}^{*}_{(0.975)}\,\bigr], \qquad p = 2\min\bigl\{\Pr(\widehat{ab}^{*} \le 0),\ \Pr(\widehat{ab}^{*} \ge 0)\bigr\}, \qquad B = 1{,}000 $$
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

R script สองสมการด้วย OLS, bootstrap 1,000 ชุด, ดัชนีความกลมกลืนของโมเดล 2 (แพ็กเกจ stats และ lavaan)both equations by OLS, 1,000-resample bootstrap, fit indices of model 2 (packages stats and lavaan)
# 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))
Expected R output (R 4.3.3, lavaan 0.6-21)
# 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
DAPH Tab 2 > Outcome type: Continuous > Statistic: Path Analysis · ตัวแปรตาม (Outcome, Y) = Quality of Life Score (Post), ตัวแปรกลาง (Mediators, M) = Number of Peritonitis Episodes, ตัวแปรต้น (Predictors, X) = Treatment Group · โมเดล 1 = เส้นทางทั้งสามตามค่าเริ่มต้น · โมเดล 2 = เอาเครื่องหมายเส้นทาง Treatment Group → Quality of Life Score (Post) ออกในตารางการเชื่อมโยงตัวแปร (Paths)Tab 2 > Outcome type: Continuous > Statistic: Path Analysis · Outcome (Y) = Quality of Life Score (Post), Mediators (M) = Number of Peritonitis Episodes, Predictors (X) = Treatment Group · model 1 = the three default paths · model 2 = untick the path Treatment Group → Quality of Life Score (Post) in the Variable Connections (Paths) table
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
เส้นทาง 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 / p1.0651 / −0.954 to 3.085 / 0.30151.065 / −0.954 to 3.085 / 0.301< 5e−4✓ PASS
อิทธิพลทางอ้อม a × b / อิทธิพลรวมIndirect a × b / total effect0.8909 / 1.95600.8909 / 1.956< 5e−5✓ PASS
R² ของสมการ M / สมการ YR² of the M equation / Y equation0.0844 / 0.00980.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.5170.331 to 1.4800.040 / 0.037✓ PASS
Bootstrap p ของอิทธิพลทางอ้อม (เกณฑ์ ±0.013)*Bootstrap p of the indirect effect (tolerance ±0.013)*0.0080.0020.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.8560.262 / 0.019✓ PASS
Bootstrap p ของอิทธิพลรวม (เกณฑ์ ±0.047)*Bootstrap p of the total effect (tolerance ±0.047)*0.0420.0720.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 / p1.0697 / 1 / 0.30101.0697 / 1 / 0.3010< 5e−5✓ PASS
โมเดล 2: CFI / TLI / RMSEA / SRMRModel 2: CFI / TLI / RMSEA / SRMR0.9994 / 0.9983 / 0.0073 / 0.01120.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
  1. Wright, S. (1934). The method of path coefficients. The Annals of Mathematical Statistics, 5(3), 161–215. doi:10.1214/aoms/1177732676
  2. Bollen, K. A. (1989). Structural Equations with Latent Variables. New York: Wiley. ISBN 978-0-471-01171-2.
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. Browne, M. W., & Cudeck, R. (1992). Alternative ways of assessing model fit. Sociological Methods & Research, 21(2), 230–258. doi:10.1177/0049124192021002005
  9. Kline, R. B. (2016). Principles and Practice of Structural Equation Modeling (4th ed.). New York: Guilford Press. ISBN 978-1-4625-2334-4.
  10. 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
  11. 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.

ตัวอย่างในข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 คน): โมเดลเดียวกับ 8.1 แต่ตัวแปรตามเป็นกลุ่มคุณภาพชีวิตช่วงกลางการติดตาม (QoL Group (Mid): 1 = สูง คือคะแนน 60.5 ขึ้นไป, 0 = ต่ำ; มีคุณภาพชีวิตสูง 1,013 คน) · ตัวแปรต้น = Treatment Group (APD เทียบ CAPD) · ตัวแปรส่งผ่าน = Number of Peritonitis Episodes · ผล: NIE OR = 1.099 (95% CI 1.022 ถึง 1.188, p = 0.011) คือ APD สัมพันธ์กับ odds ของคุณภาพชีวิตสูงที่มากขึ้นผ่านการอักเสบที่น้อยกว่า · NDE OR = 0.874 (95% CI 0.664 ถึง 1.155, p = 0.339) · Total OR = 0.960 (95% CI 0.738 ถึง 1.252, p = 0.777) = NDE × NIE · ทางตรงและทางอ้อมมีทิศตรงข้ามกัน ผลรวมจึงใกล้ 1 และไม่รายงานสัดส่วนการส่งผ่าน
Example in the DAPH data (1,300 peritoneal-dialysis patients): the model of 8.1 with a binary outcome, the quality-of-life group at mid-follow-up (QoL Group (Mid): 1 = high, a score of 60.5 or more, 0 = low; 1,013 patients high). Predictor = Treatment Group (APD versus CAPD); mediator = Number of Peritonitis Episodes. Results: NIE OR = 1.099 (95% CI 1.022 to 1.188, p = 0.011), i.e. APD is associated with higher odds of high QoL through fewer peritonitis episodes; NDE OR = 0.874 (95% CI 0.664 to 1.155, p = 0.339); Total OR = 0.960 (95% CI 0.738 to 1.252, p = 0.777) = NDE × NIE. The direct and indirect effects point in opposite directions, so the total is close to 1 and no proportion mediated is reported.

2หลักการและสูตรLogic and Formula

Outcome model (logit) and mediator model (normal linear, for a continuous mediator)
$$ \operatorname{logit}\Pr(Y=1\mid X,M,C) = \beta_0 + \theta X + \beta_M M + \gamma^{\top} C, \qquad M = \alpha_0 + \alpha X + \alpha_C^{\top} C + \varepsilon_M,\ \ \varepsilon_M \sim \mathcal{N}(0,\sigma_M^2) $$
Natural effects via potential outcomes (Robins & Greenland 1992; Pearl 2001)
$$ p_{x x^{*}} = E\bigl[Y\bigl(x, M(x^{*})\bigr)\bigr], \qquad \mathrm{NDE} = p_{10} - p_{00}, \qquad \mathrm{NIE} = p_{11} - p_{10} $$
The mediation formula (g-formula), evaluated by 24-node Gauss–Hermite quadrature
$$ p_{x x^{*}} = \frac{1}{n}\sum_{i=1}^{n} \int \operatorname{expit}\bigl(\beta_0 + \theta x + \beta_M m + \gamma^{\top} C_i\bigr)\, dF_{M\mid x^{*}, C_i}(m) \approx \frac{1}{n}\sum_{i=1}^{n}\sum_{q=1}^{24} w_q\,\operatorname{expit}\bigl(\beta_0 + \theta x + \beta_M \mu_i(x^{*}) + \gamma^{\top} C_i + \beta_M \sigma_M z_q\bigr) $$
Odds-ratio decomposition (multiplicative, exact by construction)
$$ \mathrm{OR}_{\mathrm{NDE}} = \frac{\operatorname{odds}(p_{10})}{\operatorname{odds}(p_{00})}, \quad \mathrm{OR}_{\mathrm{NIE}} = \frac{\operatorname{odds}(p_{11})}{\operatorname{odds}(p_{10})}, \quad \mathrm{OR}_{\mathrm{Total}} = \frac{\operatorname{odds}(p_{11})}{\operatorname{odds}(p_{00})} = \mathrm{OR}_{\mathrm{NDE}}\times\mathrm{OR}_{\mathrm{NIE}} $$
Proportion mediated on the OR scale (VanderWeele 2015)
$$ \mathrm{PM} = \frac{\mathrm{OR}_{\mathrm{NDE}}\,(\mathrm{OR}_{\mathrm{NIE}} - 1)}{\mathrm{OR}_{\mathrm{NDE}}\,\mathrm{OR}_{\mathrm{NIE}} - 1} $$
Several continuous mediators: joint (interventional) effect — Vansteelandt & Daniel (2017)
$$ \sum_j \beta_{M_j} M_j \;\sim\; \mathcal{N}\Bigl(\textstyle\sum_j \beta_{M_j}\,\mu_j(x^{*}),\ \ \mathbf{b}^{\top}\Sigma_{\varepsilon}\,\mathbf{b}\Bigr) $$
Inference: quasi-Bayesian Monte Carlo (Imai et al. 2010)
$$ \boldsymbol\theta^{(s)} \sim \mathcal{N}\bigl(\hat{\boldsymbol\theta},\ \hat{V}\bigr),\ s = 1,\dots,10{,}000; \qquad 95\%\ \text{CI} = \text{2.5th and 97.5th percentiles of } \mathrm{OR}^{(s)}; \qquad p = 2\min\bigl\{\Pr(\mathrm{OR}^{(s)} \le 1),\ \Pr(\mathrm{OR}^{(s)} \ge 1)\bigr\} $$
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

R script g-formula เขียนเองตามสูตร + quasi-Bayesian 10,000 ชุด และตรวจซ้ำด้วย mediation::mediate (แพ็กเกจ stats, MASS และ mediation)g-formula written from the formulas + 10,000 quasi-Bayesian draws, cross-checked with mediation::mediate (packages stats, MASS and mediation)
# 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)
Expected R output (R 4.3.3, mediation 4.5.1)
# 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
DAPH Tab 2 > Outcome type: Categorical > Statistic: Path Analysis · ตัวแปรตาม (Outcome, Y) = QoL Group (Mid), ตัวแปรกลาง (Mediators, M) = Number of Peritonitis Episodes, ตัวแปรต้น (Predictors, X) = Treatment Group · เส้นทางตามค่าเริ่มต้นทั้งสาม · ค่าที่มีทศนิยมมากกว่าในตารางของ DAPH มาจากฟังก์ชัน g-formula ของ DAPH ที่เรียกด้วยข้อมูลชุดเดียวกันTab 2 > Outcome type: Categorical > Statistic: Path Analysis · Outcome (Y) = QoL Group (Mid), Mediators (M) = Number of Peritonitis Episodes, Predictors (X) = Treatment Group · the three default paths · DAPH values with more decimals than its table come from DAPH's g-formula function called on the same data
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
จำนวนครั้งที่อักเสบ → Y: OR แบบมีเงื่อนไข (Wald 95% CI) / pEpisodes → Y: conditional OR (Wald 95% CI) / p0.9151 (0.8536 to 0.9810) / 0.01240.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 OR0.874121 / 1.098759 / 0.9604480.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.33240.6644 to 1.1546 / 0.33920.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.01121.0223 to 1.1879 / 0.01120.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.75340.7382 to 1.2521 / 0.77720.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.00690.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
  1. 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
  2. Pearl, J. (2001). Direct and indirect effects. Proceedings of the 17th Conference on Uncertainty in Artificial Intelligence (UAI), 411–420.
  3. Imai, K., Keele, L., & Tingley, D. (2010). A general approach to causal mediation analysis. Psychological Methods, 15(4), 309–334. doi:10.1037/a0020761
  4. 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
  5. VanderWeele, T. J. (2015). Explanation in Causal Inference: Methods for Mediation and Interaction. New York: Oxford University Press. ISBN 978-0-19-932587-0.
  6. 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
  7. Vansteelandt, S., & Daniel, R. M. (2017). Interventional effects for mediation analysis with multiple mediators. Epidemiology, 28(2), 258–265. doi:10.1097/EDE.0000000000000596
  8. 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.

ตัวอย่างในข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 คน): A. ตัวแปรตามอันดับ ความถี่ของกิจกรรมงานอดิเรกใน 14 วัน (Hobbies activities frequency: ไม่เคย / 1–4 วัน / 5–9 วัน / 10–13 วัน / ทุกวัน) · ตัวแปรต้น = Treatment Group (APD เทียบ CAPD) และ Household Income (3 ระดับ, อ้างอิง < 10,000 บาท/เดือน) · ตัวแปรส่งผ่าน = Number of Peritonitis Episodes · ผล: APD มี NDE OR = 1.113 (95% CI 0.902 ถึง 1.359), NIE OR = 0.969 (0.910 ถึง 1.029), Total OR = 1.078 (0.883 ถึง 1.307) ไม่มีนัยสำคัญทุกค่า · รายได้ครัวเรือนโดยรวม: Wald χ²(2) = 3.99, p = 0.136 · B. ตัวแปรตามนามบัญญัติ กลุ่ม BMI (อ้างอิง = น้ำหนักต่ำกว่าเกณฑ์) ตัวแปรต้น Treatment Group ตัวแปรส่งผ่านเดียวกัน · ผลเป็น RRR รายกลุ่ม เช่น กลุ่มอ้วนเทียบกลุ่มน้ำหนักต่ำ: NIE RRR = 1.101 (95% CI 0.977 ถึง 1.241, p = 0.110) ไม่มีนัยสำคัญ
Example in the DAPH data (1,300 peritoneal-dialysis patients): A. Ordinal outcome: frequency of hobby activities in 14 days (Hobbies activities frequency: never / 1–4 days / 5–9 days / 10–13 days / every day); predictors = Treatment Group (APD versus CAPD) and Household Income (3 levels, reference < 10,000 Baht/month); mediator = Number of Peritonitis Episodes. Results: for APD, NDE OR = 1.113 (95% CI 0.902 to 1.359), NIE OR = 0.969 (0.910 to 1.029), Total OR = 1.078 (0.883 to 1.307), none statistically significant; household income as a whole: Wald χ²(2) = 3.99, p = 0.136. B. Nominal outcome: BMI group (reference = underweight) with the same predictor Treatment Group and the same mediator; the results are per-category RRRs, e.g. obese versus underweight: NIE RRR = 1.101 (95% CI 0.977 to 1.241, p = 0.110), not statistically significant.

2หลักการและสูตรLogic and Formula

Ordinal outcome: proportional-odds model (McCullagh 1980)
$$ \operatorname{logit}\Pr(Y \le c \mid X) = \tau_c - X^{\top}\beta,\quad c = 1,\dots,K-1, \qquad \mathrm{OR}_{\mathrm{PO}} = e^{\beta}\ \ \text{(odds of a higher category)} $$
Nominal outcome: multinomial (baseline-category) logit (Agresti 2013)
$$ \log\frac{\Pr(Y=k)}{\Pr(Y=\text{ref})} = \beta_{0k} + X^{\top}\beta_k, \qquad \mathrm{RRR}_k = e^{\beta_k} $$
Categorical predictor with k levels: joint test of its k − 1 dummies
$$ W = (\mathbf{R}\hat{\beta})^{\top}\bigl[\mathbf{R}\,\widehat{\operatorname{Cov}}(\hat{\beta})\,\mathbf{R}^{\top}\bigr]^{-1}(\mathbf{R}\hat{\beta}) \sim \chi^2_{k-1}\ \ \text{(ordinal or binary Y)}, \qquad \mathrm{LR} = 2(\ell_{\text{full}} - \ell_{\text{without}}) \sim \chi^2_{(k-1)(J-1)}\ \ \text{(nominal Y, J categories)} $$
g-formula: counterfactual category probabilities
$$ p_k(x, x^{*}) = \frac{1}{n}\sum_{i=1}^{n} \int \Pr\bigl(Y=k \mid x, m, C_i\bigr)\, dF_{M\mid x^{*}, C_i}(m) $$
Ordinal effects: mean cumulative logit over the K − 1 splits
$$ \bar{\ell}(x, x^{*}) = \frac{1}{K-1}\sum_{c=1}^{K-1} \operatorname{logit}\Pr\bigl(Y \ge c \mid x, x^{*}\bigr), \qquad \mathrm{NDE}_{\mathrm{OR}} = e^{\bar{\ell}(1,0) - \bar{\ell}(0,0)},\ \ \mathrm{NIE}_{\mathrm{OR}} = e^{\bar{\ell}(1,1) - \bar{\ell}(1,0)},\ \ \mathrm{Total}_{\mathrm{OR}} = e^{\bar{\ell}(1,1) - \bar{\ell}(0,0)} $$
Nominal effects: per-category relative-risk ratios
$$ \mathrm{NDE}_{\mathrm{RRR},k} = \frac{p_k(1,0)/p_{\text{ref}}(1,0)}{p_k(0,0)/p_{\text{ref}}(0,0)}, \qquad \mathrm{NIE}_{\mathrm{RRR},k} = \frac{p_k(1,1)/p_{\text{ref}}(1,1)}{p_k(1,0)/p_{\text{ref}}(1,0)}, \qquad \mathrm{Total} = \mathrm{NDE}\times\mathrm{NIE} $$
Contrast for one level j of a categorical predictor (all its dummies are set together)
$$ x = \bigl(D_j = 1,\ D_{l} = 0\ \forall\, l \ne j\bigr) \quad \text{versus} \quad x^{*} = \bigl(D_l = 0\ \forall\, l\bigr) $$
τ_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

R script proportional odds, Wald test, g-formula แบบ ordinal และ nominal พร้อม quasi-Bayesian 5,000 ชุด (แพ็กเกจ stats, MASS และ nnet) · ใช้เวลารันประมาณ 2 นาทีproportional odds, Wald test, ordinal and nominal g-formula with 5,000 quasi-Bayesian draws (packages stats, MASS and nnet); runs in about 2 minutes
# 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)
Expected R output (R 4.3.3)
# 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
DAPH Tab 2 > Outcome type: Categorical > Statistic: Path Analysis · A: ตัวแปรตาม (Outcome, Y) = Hobbies activities frequency, ตัวแปรกลาง (Mediators, M) = Number of Peritonitis Episodes, ตัวแปรต้น (Predictors, X) = Treatment Group และ Household Income · B: Y = BMI Group, M = Number of Peritonitis Episodes, X = Treatment Group · เส้นทางตามค่าเริ่มต้นทั้งหมด · ค่าที่มีทศนิยมมากกว่าในตารางของ DAPH มาจากฟังก์ชัน g-formula ของ DAPH ที่เรียกด้วยข้อมูลชุดเดียวกันTab 2 > Outcome type: Categorical > Statistic: Path Analysis · A: Outcome (Y) = Hobbies activities frequency, Mediators (M) = Number of Peritonitis Episodes, Predictors (X) = Treatment Group and Household Income · B: Y = BMI Group, M = Number of Peritonitis Episodes, X = Treatment Group · all default paths · DAPH values with more decimals than its table come from DAPH's g-formula function called on the same data
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
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.02980.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) / p1.0302 (0.9736 to 1.0902) / 0.30211.030 (0.974 to 1.090) / 0.302< 5e−4✓ PASS
A: Household Income การทดสอบร่วม χ²(2) / pA: Household Income joint test χ²(2) / p3.9916 / 0.13593.9919 / 0.13590.0003✓ PASS
A: APD NDE / NIE / Total (OR สะสม)A: APD NDE / NIE / Total (cumulative OR)1.1131 / 0.9687 / 1.07831.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.31360.9023 to 1.3587 / 0.30280.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.29240.9098 to 1.0293 / 0.30480.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.44640.8832 to 1.3073 / 0.44280.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.76030.7600 / 1.0004 / 0.76034e−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.86380.8660 / 0.9975 / 0.86386e−6✓ PASS
B: จำนวนครั้งที่อักเสบ → Y: RRR ปกติ / น้ำหนักเกิน / อ้วน (เทียบน้ำหนักต่ำ)B: episodes → Y: RRR normal / overweight / obese (vs underweight)0.9792 / 0.9272 / 0.91370.979 / 0.927 / 0.914< 5e−4✓ PASS
B: Wald 95% CI ของ RRR ข้างบนB: Wald 95% CIs of these RRRs0.8847–1.0837 / 0.8267–1.0398 / 0.8160–1.02320.885–1.084 / 0.827–1.040 / 0.816–1.023< 5e−4✓ PASS
B: APD NDE ปกติ / น้ำหนักเกิน / อ้วนB: APD NDE normal / overweight / obese0.9453 / 0.9241 / 0.99940.945 / 0.924 / 0.999< 5e−4✓ PASS
B: APD NIE ปกติ / น้ำหนักเกิน / อ้วนB: APD NIE normal / overweight / obese1.0226 / 1.0836 / 1.10061.023 / 1.084 / 1.101< 5e−4✓ PASS
B: APD Total ปกติ / น้ำหนักเกิน / อ้วนB: APD Total normal / overweight / obese0.9667 / 1.0014 / 1.10000.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.1272obese 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
  1. 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
  2. Agresti, A. (2013). Categorical Data Analysis (3rd ed.). Hoboken: Wiley. ISBN 978-0-470-46363-5.
  3. 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
  4. VanderWeele, T. J. (2015). Explanation in Causal Inference: Methods for Mediation and Interaction. New York: Oxford University Press. ISBN 978-0-19-932587-0.
  5. Imai, K., Keele, L., & Tingley, D. (2010). A general approach to causal mediation analysis. Psychological Methods, 15(4), 309–334. doi:10.1037/a0020761
  6. 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) 2 topics ✓ 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.

ตัวอย่างในข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 คน): คำถามความถี่ของพฤติกรรม 9 ข้อในช่วง 14 วัน (0 = ไม่เคย … 4 = ทุกวัน): ดื่มสุรา สูบบุหรี่ เคี้ยวหมาก อาหารหวาน อาหารมัน อาหารเค็ม กิจกรรมทางกายหนัก กิจกรรมทางกายปานกลาง และกิจกรรมงานอดิเรก จะจับกลุ่มเป็นองค์ประกอบใดบ้าง · ผล: KMO = 0.623 (พอใช้, mediocre), Bartlett χ²(36) = 813.8, p < 0.001 · parallel analysis คงไว้ 3 องค์ประกอบ · หลังสกัดแบบ MINRES และหมุนแกน promax: องค์ประกอบ "อาหารไม่เหมาะสม" (อาหารหวาน 0.47, มัน 0.77, เค็ม 0.55) ชัดเจน · องค์ประกอบ "การใช้สารเสพติด" อ่อน (บุหรี่ 0.59, สุรา 0.34, หมาก 0.20 ไม่ถึงเกณฑ์) · องค์ประกอบที่สามมีเพียงงานอดิเรก (0.63) ที่ถึงเกณฑ์ จึงใช้เป็นองค์ประกอบไม่ได้ และข้อกิจกรรมทางกายไม่ถึงเกณฑ์ในองค์ประกอบใดเลย · communality 0.09–0.56 · ความเชื่อมั่นขององค์ประกอบอาหาร α = 0.574, ω = 0.629
Example in the DAPH data (1,300 peritoneal-dialysis patients): how do nine 14-day behaviour-frequency items (0 = never … 4 = every day) group together: alcohol, cigarettes, betel, sugary food, fatty food, salty food, vigorous activity, moderate activity and hobbies? Results: KMO = 0.623 (mediocre), Bartlett χ²(36) = 813.8, p < 0.001; parallel analysis retained 3 factors. After MINRES extraction and promax rotation, an "unhealthy diet" factor is clear (sugary 0.47, fatty 0.77, salty 0.55); a "substance use" factor is weak (cigarettes 0.59, alcohol 0.34, betel 0.20, below the salience cut-off); on the third factor only hobbies (0.63) is salient, so it is not a usable factor, and the physical-activity items are salient on no factor. Communalities 0.09–0.56. Reliability of the diet factor: α = 0.574, ω = 0.629.

2หลักการและสูตรLogic and Formula

Common-factor model (indicators = loadings × factors + unique part)
$$ \mathbf{x} = \boldsymbol{\Lambda}\mathbf{f} + \boldsymbol{\varepsilon}, \qquad \mathbf{R} \approx \boldsymbol{\Lambda}\boldsymbol{\Phi}\boldsymbol{\Lambda}^{\top} + \boldsymbol{\Psi} $$
Sampling adequacy — Kaiser–Meyer–Olkin (overall KMO and per-item MSA)
$$ \mathrm{KMO} = \frac{\sum_{i\ne j} r_{ij}^{2}}{\sum_{i\ne j} r_{ij}^{2} + \sum_{i\ne j} q_{ij}^{2}}, \qquad \mathrm{MSA}_i = \frac{\sum_{j\ne i} r_{ij}^{2}}{\sum_{j\ne i} r_{ij}^{2} + \sum_{j\ne i} q_{ij}^{2}}, \qquad q_{ij} = \frac{-(\mathbf{R}^{-1})_{ij}}{\sqrt{(\mathbf{R}^{-1})_{ii}(\mathbf{R}^{-1})_{jj}}} $$
Bartlett's test of sphericity (Bartlett 1950)
$$ \chi^2 = -\Bigl(N-1-\tfrac{2p+5}{6}\Bigr)\ln|\mathbf{R}|, \qquad df = \tfrac{p(p-1)}{2} $$
Factor retention — parallel analysis (Horn 1965), as DAPH runs it
$$ \text{retained} = \#\bigl\{\,j : e_j > e^{\text{random}}_{j,(95)}\bigr\}, \qquad e_j = j\text{th eigenvalue of } \mathbf{R}, \quad e^{\text{random}}_{j,(95)} = \text{95th percentile over 100 random normal } N \times p \text{ data sets} $$
Communality and uniqueness (oblique rotation: pattern × structure)
$$ h_i^2 = \bigl(\boldsymbol{\Lambda}\boldsymbol{\Phi}\boldsymbol{\Lambda}^{\top}\bigr)_{ii} = \sum_j \lambda_{ij}\,s_{ij}, \qquad \mathbf{S} = \boldsymbol{\Lambda}\boldsymbol{\Phi}, \qquad \psi_i = 1 - h_i^2 \quad \Bigl(h_i^2 = \textstyle\sum_j \lambda_{ij}^2 \text{ only when } \boldsymbol{\Phi} = \mathbf{I}\Bigr) $$
Variance explained
$$ \text{common variance} = \frac{1}{p}\sum_i h_i^2, \qquad \text{DAPH per factor} = \frac{1}{p}\sum_i \lambda_{ij}^2 \ \ \text{(additive only for an orthogonal rotation)} $$
Reliability of a factor's salient items — Cronbach's α and McDonald's ω
$$ \alpha = \frac{k}{k-1}\Bigl(1 - \frac{\sum_i \sigma_i^2}{\sigma_T^2}\Bigr), \qquad \omega = \frac{\bigl(\sum_i |\lambda_{ij}|\bigr)^2}{\bigl(\sum_i |\lambda_{ij}|\bigr)^2 + \sum_i \psi_i} $$
Λ (λ_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

R script KMO, Bartlett, parallel analysis, MINRES + promax, α และ ω (แพ็กเกจ psych และ GPArotation)KMO, Bartlett, parallel analysis, MINRES + promax, α and ω (packages psych and GPArotation)
# 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))
}
Expected R output (R 4.3.3, psych 2.4.1)
# 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
DAPH Tab 2 > Statistic: Factor Analysis > EFA · ตัวชี้วัด = ข้อพฤติกรรมทั้ง 9 ข้อ · Extraction = MINRES, Rotation = promax, Number of factors = Auto (parallel analysis), ไม่ติ๊กข้อมูลอันดับ (ค่าเริ่มต้นทั้งหมด)Tab 2 > Statistic: Factor Analysis > EFA · indicators = the nine behaviour items · Extraction = MINRES, Rotation = promax, Number of factors = Auto (parallel analysis), ordinal option unticked (all defaults)
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
KMO รวม / MSA รายข้อ (ต่ำสุด–สูงสุด)Overall KMO / per-item MSA (min–max)0.623 / 0.507–0.7030.623 / 0.507–0.703 (all 9 equal)< 5e−4✓ PASS
Bartlett χ² / df / pBartlett χ² / df / p813.777 / 36 / 1.32e−147813.777 / 36 / < 0.001< 5e−4✓ PASS
Eigenvalue ที่สังเกตได้ (9 ค่า)Observed eigenvalues (9)1.9394 / 1.3211 / 1.0949 / … / 0.52571.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 > 13 / 33 / 30✓ PASS
ค่าน้ำหนัก pattern (27 ค่า) เช่น อาหารมัน F1Pattern loadings (27 values), e.g. fatty food on F10.773 (all 27 to 3 decimals)0.7727 (all 27)< 5e−4✓ PASS
Communality h² (9 ค่า) เช่น อาหารมัน / กิจกรรมหนักCommunalities h² (9), e.g. fatty food / vigorous activity0.559 / 0.0940.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 proportion1.2373 / 0.5895 / 0.5588; 0.26511.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 reports0.24810.26510.0170✗ FAIL
α / ω: F1 (อาหาร 3 ข้อ) / F3 (สารเสพติด 2 ข้อ); F2 มีข้อเด่นข้อเดียวα / ω: F1 (diet, 3 items) / F3 (substance, 2 items); F2 has one salient item0.574 / 0.629; 0.212 / 0.3610.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
  1. 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
  2. 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.
  3. 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
  4. Kaiser, H. F. (1974). An index of factorial simplicity. Psychometrika, 39(1), 31–36. doi:10.1007/BF02291575
  5. 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
  6. 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
  7. 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).

ตัวอย่างในข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 คน): ข้อพฤติกรรม 6 ข้อวัดสององค์ประกอบที่สัมพันธ์กันได้หรือไม่: การใช้สารเสพติด (สุรา บุหรี่ หมาก) และ อาหารไม่เหมาะสม (อาหารหวาน มัน เค็ม) ตามที่ EFA ใน 9.1 ชี้ไว้ · ผล (ML): χ²(8) = 42.221, p < 0.001, CFI = 0.942, TLI = 0.891, RMSEA = 0.057 (90% CI 0.041 ถึง 0.075), SRMR = 0.036 · ค่าน้ำหนักมาตรฐาน 0.32–0.72 · CR = 0.324 (สารเสพติด) และ 0.615 (อาหาร), AVE = 0.139 และ 0.353 ต่ำกว่าเกณฑ์ทั้งคู่ · สหสัมพันธ์ระหว่างสององค์ประกอบ 0.491 มากกว่า √AVE ของสารเสพติด (0.373) จึงไม่ผ่าน Fornell–Larcker แต่ HTMT2 = 0.551 < 0.85
Example in the DAPH data (1,300 peritoneal-dialysis patients): do six behaviour items measure two correlated factors, substance use (alcohol, cigarettes, betel) and unhealthy diet (sugary, fatty, salty food), as the EFA in 9.1 suggested? Results (ML): χ²(8) = 42.221, p < 0.001, CFI = 0.942, TLI = 0.891, RMSEA = 0.057 (90% CI 0.041 to 0.075), SRMR = 0.036. Standardized loadings 0.32–0.72; CR = 0.324 (substance use) and 0.615 (diet), AVE = 0.139 and 0.353, both below the criteria. The factor correlation 0.491 exceeds √AVE of substance use (0.373), so Fornell–Larcker fails, while HTMT2 = 0.551 < 0.85.

2หลักการและสูตรLogic and Formula

Measurement model and model-implied covariance
$$ \mathbf{x} = \boldsymbol{\tau} + \boldsymbol{\Lambda}\boldsymbol{\xi} + \boldsymbol{\delta}, \qquad \boldsymbol{\Sigma}(\theta) = \boldsymbol{\Lambda}\boldsymbol{\Phi}\boldsymbol{\Lambda}^{\top} + \boldsymbol{\Theta}_\delta $$
Maximum-likelihood discrepancy, χ², log-likelihood
$$ F_{ML} = \log|\boldsymbol{\Sigma}| + \operatorname{tr}\!\bigl(\mathbf{S}\,\boldsymbol{\Sigma}^{-1}\bigr) - \log|\mathbf{S}| - p, \qquad \chi^2 = N\,F_{ML}, \qquad \ell = -\tfrac{N}{2}\bigl(p\ln 2\pi + \ln|\mathbf{S}| + p\bigr) - \tfrac{\chi^2}{2} $$
Approximate-fit indices (as DAPH computes them)
$$ \mathrm{RMSEA} = \sqrt{\tfrac{\max(\chi^2-df,\,0)}{df\,(N-1)}}, \quad \mathrm{CFI} = 1 - \tfrac{\max(\chi^2-df,\,0)}{\max(\chi^2_0-df_0,\,0)}, \quad \mathrm{TLI} = \tfrac{\chi^2_0/df_0 - \chi^2/df}{\chi^2_0/df_0 - 1}, \quad \mathrm{SRMR} = \sqrt{\tfrac{2}{p(p+1)}\textstyle\sum_{i\le j}(r_{ij}-\hat r_{ij})^2} $$
Convergent validity — composite reliability and AVE (Fornell & Larcker 1981)
$$ \mathrm{CR} = \frac{\bigl(\sum_i \lambda_i\bigr)^2}{\bigl(\sum_i \lambda_i\bigr)^2 + \sum_i (1-\lambda_i^2)}, \qquad \mathrm{AVE} = \frac{1}{k}\sum_i \lambda_i^2 $$
Discriminant validity — Fornell–Larcker and HTMT2 (Roemer, Schuberth & Henseler 2021)
$$ \sqrt{\mathrm{AVE}_i} > \bigl|\phi_{ij}\bigr|\ \forall j\ne i, \qquad \mathrm{HTMT2}_{ij} = \frac{\mathrm{GM}\,|r|_{\text{between } i,j}}{\sqrt{\mathrm{GM}\,|r|_{\text{within } i}\ \cdot\ \mathrm{GM}\,|r|_{\text{within } j}}} $$
95% CI of a standardized loading (delta method)
$$ \lambda^{*}_{if}=\lambda_{if}\sqrt{\phi_{ff}}\,/\sqrt{\sigma_{ii}},\quad \sigma=\Lambda\Phi\Lambda^{\top}+\Theta,\qquad SE(\lambda^{*})=\sqrt{J\,\widehat{V}(\hat\theta)\,J^{\top}},\quad \lambda^{*}\pm1.96\,SE $$
Modification index for an error covariance (exact likelihood-ratio drop)
$$ \mathrm{MI}_{ab} = \chi^2_{\text{current}} - \chi^2_{\text{with } \theta_{ab} \text{ free}}, \qquad \mathrm{EPC}_{ab} = \hat\theta_{ab}\big/\sqrt{\hat\sigma_{aa}\,\hat\sigma_{bb}} $$
Λ, Φ (φ_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

R script CFA แบบ ML, ดัชนีความกลมกลืน, CR/AVE/α, Fornell–Larcker, HTMT2 และ modification index (แพ็กเกจ lavaan, semTools และ psych)ML CFA, fit indices, CR/AVE/α, Fornell–Larcker, HTMT2 and the modification index (packages lavaan, semTools and psych)
# 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)
Expected R output (R 4.3.3, lavaan 0.6-21, semTools 0.5-8)
# 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
DAPH Tab 2 > Statistic: Factor Analysis > CFA · องค์ประกอบ "Substance use" = Alcohol, Cigarette, Betel frequency · องค์ประกอบ "Unhealthy diet" = Sugary, Fatty, Salty food frequency · Estimator = Maximum likelihood (ML), ไม่ติ๊กตัวชี้วัดอันดับTab 2 > Statistic: Factor Analysis > CFA · factor "Substance use" = Alcohol, Cigarette, Betel frequency · factor "Unhealthy diet" = Sugary, Fatty, Salty food frequency · Estimator = Maximum likelihood (ML), ordinal option unticked
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
χ² / df / p42.2211 / 8 / < 0.00142.221 / 8 / < 0.001< 5e−4✓ PASS
CFI / TLI0.9418 / 0.89090.9418 / 0.8909< 5e−5✓ PASS
RMSEA (90% CI) หารด้วย N − 1RMSEA (90% CI), divisor N − 10.0574 (0.0411 to 0.0750)0.0574 (0.0411 to 0.0750)< 5e−5✓ PASS
SRMR (เกณฑ์ ±0.001)*SRMR (tolerance ±0.001)*0.03630.03640.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.06273.6170 / 3.2111 / 0.9848 / 1.06260.0029 (betel)✗ FAIL
SE ของค่าน้ำหนักข้างบนSEs of these loadings0.6919 / 0.6439 / 0.0922 / 0.09380.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.54890.3668 / 0.4207 / 0.3242 / 0.4955 / 0.7160 / 0.5487≤ 0.0002✓ PASS
Std. 95% CI เช่น บุหรี่ / อาหารมันStd. 95% CI, e.g. cigarettes / fatty food0.3244 to 0.5168 / 0.6502 to 0.78150.324 to 0.517 / 0.650 to 0.782< 5e−4✓ PASS
CR / AVE / α: สารเสพติด; อาหารCR / AVE / α: substance use; diet0.324 / 0.139 / 0.225; 0.615 / 0.353 / 0.5740.324 / 0.139 / 0.225; 0.615 / 0.353 / 0.574< 5e−4✓ PASS
สหสัมพันธ์ระหว่างองค์ประกอบ / √AVE / HTMT2Factor correlation / √AVE / HTMT20.491 / 0.373, 0.594 / 0.5510.491 / 0.373, 0.594 / 0.551< 5e−4✓ PASS
MI สูงสุด (สุรา–บุหรี่) / EPCLargest MI (alcohol–cigarettes) / EPC18.357 / 0.14518.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
  1. Brown, T. A. (2015). Confirmatory Factor Analysis for Applied Research (2nd ed.). New York: Guilford Press. ISBN 978-1-4625-1779-4.
  2. 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
  3. Browne, M. W., & Cudeck, R. (1992). Alternative ways of assessing model fit. Sociological Methods & Research, 21(2), 230–258. doi:10.1177/0049124192021002005
  4. 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
  5. 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
  6. 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
  7. 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
  8. Sörbom, D. (1989). Model modification. Psychometrika, 54(3), 371–384. doi:10.1007/BF02294623
  9. 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
  10. Kline, R. B. (2016). Principles and Practice of Structural Equation Modeling (4th ed.). New York: Guilford Press. ISBN 978-1-4625-2334-4.
  11. 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
  12. 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) 2 topics ✓ 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.

ตัวอย่างในข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 คน): โมเดลการวัดเดียวกับ 9.2 (การใช้สารเสพติด: สุรา บุหรี่ หมาก · อาหารไม่เหมาะสม: อาหารหวาน มัน เค็ม) และโมเดลเชิงโครงสร้าง "การใช้สารเสพติด → อาหารไม่เหมาะสม → ดัชนีมวลกาย (BMI)" พร้อมเส้นทางตรง การใช้สารเสพติด → BMI · ผล: การใช้สารเสพติดสัมพันธ์กับอาหารไม่เหมาะสม (β = 0.489, p < 0.001) แต่อาหารไม่เหมาะสมไม่สัมพันธ์กับ BMI (β = 0.008, p = 0.869) อิทธิพลทางอ้อม β = 0.004 (95% CI แบบ Monte Carlo −0.044 ถึง 0.054) · ความกลมกลืน: χ²(12) = 45.549, p < 0.001, CFI = 0.943, TLI = 0.900, RMSEA = 0.046 (90% CI 0.033 ถึง 0.061), SRMR = 0.033 · โมเดลการวัดยังอ่อน (CR 0.324 และ 0.615)
Example in the DAPH data (1,300 peritoneal-dialysis patients): the measurement model of 9.2 (substance use: alcohol, cigarettes, betel; unhealthy diet: sugary, fatty, salty food) with the structural model "substance use → unhealthy diet → body mass index (BMI)" plus a direct path substance use → BMI. Results: substance use is associated with an unhealthy diet (β = 0.489, p < 0.001), but the diet factor is not associated with BMI (β = 0.008, p = 0.869); indirect effect β = 0.004 (Monte Carlo 95% CI −0.044 to 0.054). Fit: χ²(12) = 45.549, p < 0.001, CFI = 0.943, TLI = 0.900, RMSEA = 0.046 (90% CI 0.033 to 0.061), SRMR = 0.033. The measurement model remains weak (CR 0.324 and 0.615).

2หลักการและสูตรLogic and Formula

Measurement model (reflective) and structural model
$$ \mathbf{x} = \boldsymbol{\Lambda}\boldsymbol{\xi} + \boldsymbol{\delta}, \qquad \boldsymbol{\eta} = \mathbf{B}\,\boldsymbol{\eta} + \boldsymbol{\Gamma}\,\boldsymbol{\xi} + \boldsymbol{\zeta}, \qquad \boldsymbol{\Sigma}(\theta)\ \text{implied by } \boldsymbol{\Lambda}, \mathbf{B}, \boldsymbol{\Gamma}, \boldsymbol{\Phi}, \boldsymbol{\Psi}, \boldsymbol{\Theta} $$
Joint ML discrepancy and fit indices
$$ F_{ML}=\log|\hat\Sigma|+\operatorname{tr}(S\hat\Sigma^{-1})-\log|S|-p, \quad \chi^2=N\,F_{ML}, \quad \mathrm{RMSEA}=\sqrt{\tfrac{\max(\chi^2-df,0)}{df(N-1)}}, \quad \mathrm{NFI}=\tfrac{\chi^2_0-\chi^2}{\chi^2_0} $$ $$ \mathrm{GFI} = 1 - \frac{\operatorname{tr}\bigl[(\hat\Sigma^{-1}S - I)^2\bigr]}{\operatorname{tr}\bigl[(\hat\Sigma^{-1}S)^2\bigr]}, \qquad \mathrm{AGFI} = 1 - \frac{p(p+1)}{2\,df}\,(1-\mathrm{GFI}) $$
Reliability and validity (as in 9.2)
$$ \mathrm{CR}=\frac{\bigl(\sum_i|\lambda_i|\bigr)^2}{\bigl(\sum_i|\lambda_i|\bigr)^2+\sum_i(1-\lambda_i^2)}, \qquad \mathrm{AVE}=\frac{1}{k}\sum_i \lambda_i^2, \qquad \sqrt{\mathrm{AVE}_j} > \bigl|\,\mathrm{corr}(\xi_j,\xi_k)\,\bigr|, \qquad \mathrm{HTMT2}_{jk} < 0.85 $$
Standardized path, DAPH's standard error and interval
$$ \beta = B\,\frac{SD(x)}{SD(y)}, \qquad SE(\beta) = SE(B)\,\Bigl|\frac{\beta}{B}\Bigr|, \qquad \beta \pm 1.96\,SE(\beta) $$
Indirect and total effects (product of standardized paths) with a Monte Carlo interval
$$ \widehat{ab}=\beta_a\,\beta_b, \quad \text{total} = \beta_c + \sum \beta_a\beta_b, \quad \beta_a^{(s)}\sim N\bigl(\beta_a, SE(\beta_a)^2\bigr),\ \beta_b^{(s)}\sim N\bigl(\beta_b, SE(\beta_b)^2\bigr),\ s = 1,\dots,20{,}000, \quad 95\%\ \text{CI} = \text{2.5th and 97.5th percentiles} $$
λ, ξ, η
ค่าน้ำหนัก / ตัวแปรแฝงต้นทาง (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

R script SEM แบบ ML, ดัชนีความกลมกลืน, β และ CI แบบที่ DAPH ใช้, CR/AVE/α, HTMT2, Monte Carlo CI ของอิทธิพลทางอ้อม, เทียบ delta method และ MLR (แพ็กเกจ lavaan, semTools และ psych)ML SEM, fit indices, β and DAPH's CIs, CR/AVE/α, HTMT2, Monte Carlo CI of the indirect effect, comparison with the delta method and MLR (packages lavaan, semTools and psych)
# 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)
Expected R output (R 4.3.3, lavaan 0.6-21, semTools 0.5-8)
# 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
DAPH Tab 2 > Outcome type: Continuous > Statistic: Structural Equation Modeling · ตัวแปรแฝง "Substance use" = Alcohol, Cigarette, Betel frequency · "Unhealthy diet" = Sugary, Fatty, Salty food frequency · ตัวแปรสังเกตได้ = Body Mass Index (kg/m²) และกำหนดเป็นตัวแปรตาม · เส้นทาง: Substance use → Unhealthy diet, Unhealthy diet → Body Mass Index, Substance use → Body Mass Index · Estimator = ML (และรันซ้ำด้วย MLR เพื่อตรวจ)Tab 2 > Outcome type: Continuous > Statistic: Structural Equation Modeling · latent "Substance use" = Alcohol, Cigarette, Betel frequency · "Unhealthy diet" = Sugary, Fatty, Salty food frequency · observed variable = Body Mass Index (kg/m²), set as the outcome · paths: Substance use → Unhealthy diet, Unhealthy diet → Body Mass Index, Substance use → Body Mass Index · Estimator = ML (rerun with MLR as a check)
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
χ² / df / p45.5487 / 12 / < 0.00145.549 / 12 / < 0.001< 5e−4✓ PASS
CFI / TLI / NFI0.9430 / 0.9002 / 0.92520.943 / 0.9002 / 0.9252< 5e−5✓ PASS
RMSEA (90% CI) หารด้วย N − 1RMSEA (90% CI), divisor N − 10.0464 (0.0326 to 0.0611)0.0464 (0.0326 to 0.0611)< 5e−5✓ PASS
SRMR / GFI / AGFI0.0326 / 0.9903 / 0.97730.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.71513.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 → BMI1.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 paths0.4895, 0.0082, −0.0785 / < 0.001, 0.8686, 0.21870.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.04660.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 method0.3731 to 0.6058 / −0.0885 to 0.1048 / −0.2011 to 0.04420.295 to 0.684 / −0.089 to 0.105 / −0.203 to 0.0470.078 (substance → diet)✗ FAIL
R² ของอาหาร / BMIR² of diet / BMI0.2396 / 0.00560.2396 / 0.0056< 5e−5✓ PASS
CR / AVE / α: สารเสพติด; อาหาร · HTMT2CR / AVE / α: substance; diet · HTMT20.324 / 0.139 / 0.225; 0.615 / 0.353 / 0.574 · 0.5510.324 / 0.139 / 0.225; 0.615 / 0.353 / 0.574 · 0.551< 5e−4✓ PASS
Fornell–Larcker: สหสัมพันธ์ระหว่างองค์ประกอบFornell–Larcker: factor correlation0.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.85730.004 / −0.044 to 0.054 / 0.86670.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.27770.0001 / 0.0014 / 0.0047✓ PASS
ตัวเลือก MLR: SE แบบ sandwich ของเส้นทางสารเสพติด → อาหาร / ค่าน้ำหนักอาหารเค็ม / ค่าน้ำหนักบุหรี่MLR option: sandwich SE of substance → diet / salty-food loading / cigarette loading0.4021 / 0.1185 / 0.81780.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
  1. Bollen, K. A. (1989). Structural Equations with Latent Variables. New York: Wiley. ISBN 978-0-471-01171-2.
  2. Kline, R. B. (2016). Principles and Practice of Structural Equation Modeling (4th ed.). New York: Guilford Press. ISBN 978-1-4625-2334-4.
  3. 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
  4. Browne, M. W., & Cudeck, R. (1992). Alternative ways of assessing model fit. Sociological Methods & Research, 21(2), 230–258. doi:10.1177/0049124192021002005
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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
  10. 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.

ตัวอย่างในข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 คน): โมเดลการวัดเดียวกับ 9.2 และ 10.1 กับโมเดลเชิงโครงสร้าง "การใช้สารเสพติด → อาหารไม่เหมาะสม → โรคเรื้อรัง (มี/ไม่มี)" พร้อมเส้นทางตรง · ผลต่อการเพิ่มคะแนนองค์ประกอบ 1 SD: อาหารไม่เหมาะสมสัมพันธ์กับ odds ของโรคเรื้อรัง OR = 1.130 (95% CI 0.966 ถึง 1.321, p = 0.127) · การใช้สารเสพติด: NDE OR = 0.969 (95% CI 0.832 ถึง 1.134), NIE OR = 1.091 (95% CI 0.975 ถึง 1.217, p = 0.132), Total OR = 1.057 (95% CI 0.948 ถึง 1.177) ไม่มีนัยสำคัญทุกค่า · McFadden R² = 0.002
Example in the DAPH data (1,300 peritoneal-dialysis patients): the measurement model of 9.2 and 10.1 with the structural model "substance use → unhealthy diet → chronic disease (yes/no)" plus a direct path. Effects per 1-SD higher factor score: an unhealthy diet is associated with the odds of chronic disease with OR = 1.130 (95% CI 0.966 to 1.321, p = 0.127); for substance use, NDE OR = 0.969 (95% CI 0.832 to 1.134), NIE OR = 1.091 (95% CI 0.975 to 1.217, p = 0.132) and Total OR = 1.057 (95% CI 0.948 to 1.177), none statistically significant. McFadden R² = 0.002.

2หลักการและสูตรLogic and Formula

Stage 1: ML CFA and regression-method factor scores, standardized to mean 0, SD 1
$$ \tilde{\eta}_i = \hat{\boldsymbol\Phi}\hat{\boldsymbol\Lambda}^{\top}\hat{\boldsymbol\Sigma}^{-1}(\mathbf{x}_i - \bar{\mathbf{x}}), \qquad \hat{\eta}_i = \frac{\tilde{\eta}_i - \bar{\tilde{\eta}}}{\sqrt{\tfrac{1}{N}\sum_i (\tilde{\eta}_i - \bar{\tilde{\eta}})^2}} $$
Stage 2: generalized structural model (binary outcome shown)
$$ \operatorname{logit}\Pr(Y=1\mid\hat\eta, M, Z)=\beta_0+\beta_1\hat\eta+\beta_M M+\gamma^{\!\top}Z, \qquad \mathrm{OR}=e^{\beta}\ \text{per 1 SD} \quad (\text{ordinal: proportional-odds OR; nominal: RRR}) $$
Mediation by the g-formula (as in 8.2): x = 1 SD versus x* = 0 (the mean)
$$ p_{x x^{*}} = E\bigl[Y\bigl(x, M(x^{*})\bigr)\bigr], \qquad \mathrm{OR}_{\mathrm{NDE}}=\frac{\operatorname{odds}(p_{10})}{\operatorname{odds}(p_{00})}, \quad \mathrm{OR}_{\mathrm{NIE}}=\frac{\operatorname{odds}(p_{11})}{\operatorname{odds}(p_{10})}, \quad \mathrm{OR}_{\mathrm{Total}}=\mathrm{OR}_{\mathrm{NDE}}\times\mathrm{OR}_{\mathrm{NIE}} $$
Model quality of the outcome equation (χ²-based fit indices are not defined here)
$$ R^2_{\text{McFadden}} = 1-\frac{\ell_{\text{model}}}{\ell_{\text{null}}}, \qquad R^2_{\text{Nagelkerke}} = \frac{1-e^{2(\ell_{\text{null}}-\ell_{\text{model}})/N}}{1-e^{2\ell_{\text{null}}/N}}, \qquad \mathrm{AIC}=2k-2\ell, \qquad \mathrm{BIC}=k\ln N-2\ell $$
Λ̂, Φ̂, Σ̂
ค่าน้ำหนัก / ความแปรปรวนร่วมขององค์ประกอบ / เมทริกซ์ที่โมเดลกำหนด จาก 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

R script ขั้นที่ 1 CFA และคะแนนองค์ประกอบ, ขั้นที่ 2 logit และ g-formula (แพ็กเกจ lavaan, stats และ MASS)stage 1 CFA and factor scores, stage 2 logit and g-formula (packages lavaan, stats and MASS)
# 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)
Expected R output (R 4.3.3, lavaan 0.6-21)
# 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
DAPH Tab 2 > Outcome type: Categorical > Statistic: Generalized SEM · ตัวแปรแฝง "Substance use" = Alcohol, Cigarette, Betel frequency · "Unhealthy diet" = Sugary, Fatty, Salty food frequency · ตัวแปรสังเกตได้ = Chronic Disease · ตัวแปรตาม = Chronic Disease, ชนิด = อัตโนมัติ (binary logit) · เส้นทาง: Substance use → Unhealthy diet, Unhealthy diet → Chronic Disease, Substance use → Chronic DiseaseTab 2 > Outcome type: Categorical > Statistic: Generalized SEM · latent "Substance use" = Alcohol, Cigarette, Betel frequency · "Unhealthy diet" = Sugary, Fatty, Salty food frequency · observed variable = Chronic Disease · outcome = Chronic Disease, family = auto (binary logit) · paths: Substance use → Unhealthy diet, Unhealthy diet → Chronic Disease, Substance use → Chronic Disease
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
ขั้นที่ 1: ค่าน้ำหนักมาตรฐาน 6 ข้อ (เกณฑ์ ±0.001)*Stage 1: six standardized loadings (tolerance ±0.001)*0.3666 / 0.4206 / 0.3244 / 0.4956 / 0.7159 / 0.54890.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.12671.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.51320.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.00340.0019 / 0.0034< 5e−5✓ PASS
NDE / NIE / Total OR0.9687 / 1.0911 / 1.05690.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.70180.832 to 1.134 / 0.7090.0032 / 0.0001 / 0.0072✓ PASS
NIE: 95% CI / pNIE: 95% CI / p0.9745 to 1.2183 / 0.12580.975 to 1.217 / 0.1320.0005 / 0.0013 / 0.0062✓ PASS
Total: 95% CI / pTotal: 95% CI / p0.9473 to 1.1812 / 0.32280.948 to 1.177 / 0.3010.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
  1. 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
  2. VanderWeele, T. J. (2015). Explanation in Causal Inference: Methods for Mediation and Interaction. New York: Oxford University Press. ISBN 978-0-19-932587-0.
  3. 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.
  4. 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
  5. 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 8 stats ✓ 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.

ตรวจเทียบกับ R 4.3.3 (trend · modifiedmk · urca · forecast · sandwich · lmtest · prais · stats) บนข้อมูลตัวอย่าง DAPH: ตรงกันทั้ง 75 รายการ (สรุปใน 11.8) Checked against R 4.3.3 (trend · modifiedmk · urca · forecast · sandwich · lmtest · prais · stats) on the DAPH example data: all 75 checks agree (summary in 11.8)
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.

คำถามในข้อมูลตัวอย่าง DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย): (1) จำนวนผู้ป่วยเสียชีวิตต่อเดือน (Study Status = Died/Event นับตามเดือนของ End Date) ระหว่าง ก.พ. 2565 (2022-02) ถึง ธ.ค. 2567 (2024-12) รวม 35 เดือน เพิ่มหรือลดตามเวลาหรือไม่ · (2) จำนวนผู้ป่วยใหม่ที่รับเข้าต่อเดือน (นับตามเดือนของ Enrollment Date) ระหว่างช่วงรับผู้ป่วย 2022-01 ถึง 2023-06 รวม 18 เดือน คงที่หรือไม่ · ผล: อนุกรมการเสียชีวิตมีค่าเฉลี่ย 6.54 รายต่อเดือน (SD 4.15) และครบ 2 รอบฤดูกาล DAPH จึงเลือก Seasonal Kendall ให้เอง: S = −10, z = −1.435, p = 0.151, Sen's slope = −0.083 รายต่อเดือน (95% CI −0.292 ถึง 0.083) — ไม่พบแนวโน้มทิศทางเดียวที่มีนัยสำคัญ เพราะอนุกรมขึ้นในช่วงรับผู้ป่วยแล้วลดลงหลังปิดรับ (รูปแบบที่การทดสอบนี้ไม่ได้ออกแบบมาตรวจ ดู 11.6) · ผู้ป่วยใหม่เฉลี่ย 72.22 รายต่อเดือน (SD 6.41) มีเพียง 18 เดือน จึงใช้ Mann-Kendall: S = 11, z = 0.38, p = 0.702, Sen's slope = 0.14 รายต่อเดือน (95% CI −0.73 ถึง 0.60) ไม่พบสหสัมพันธ์ของอันดับที่ต้องแก้แบบ Hamed-Rao — การรับผู้ป่วยคงที่ตลอดช่วง
Question in the DAPH example data (1,300 peritoneal-dialysis patients): (1) did the number of deaths per month (Study Status = Died/Event, counted by the month of End Date) rise or fall between Feb 2022 (2022-02) and Dec 2024 (2024-12), 35 months; (2) was the number of new patients enrolled per month (counted by the month of Enrollment Date) stable over the recruitment period 2022-01 to 2023-06, 18 months? Result: deaths averaged 6.54 per month (SD 4.15) and the series covers two seasonal cycles, so DAPH chose the Seasonal Kendall test: S = −10, z = −1.435, p = 0.151, Sen's slope = −0.083 deaths per month (95% CI −0.292 to 0.083) — no significant monotonic trend, because the series rose during recruitment and fell after recruitment closed (a shape this test is not designed for; see 11.6). New patients averaged 72.22 per month (SD 6.41) over only 18 months, so the Mann-Kendall test was used: S = 11, z = 0.38, p = 0.702, Sen's slope = 0.14 patients per month (95% CI −0.73 to 0.60); no rank autocorrelation needed the Hamed-Rao correction — recruitment was steady throughout.

2หลักการและสูตรLogic and Formula

Mann-Kendall (Mann 1945) — S, Var(S) (Gilbert 1987) และ z
$$ S = \sum_{i<j} \operatorname{sgn}(x_j - x_i),\qquad \operatorname{Var}(S) = \frac{n(n-1)(2n+5) - \sum_{g} t_g(t_g-1)(2t_g+5)}{18},\qquad z = \frac{S - \operatorname{sgn}(S)}{\sqrt{\operatorname{Var}(S)}},\qquad \tau = \frac{S}{n(n-1)/2} $$
Seasonal Kendall (Hirsch, Slack & Smith 1982) — เทียบเฉพาะฤดูเดียวกันข้ามปี
$$ S' = \sum_{k=1}^{m} S_k,\qquad \operatorname{Var}(S') = \sum_{k=1}^{m} \operatorname{Var}(S_k),\qquad z' = \frac{S' - \operatorname{sgn}(S')}{\sqrt{\operatorname{Var}(S')}},\qquad \tau' = \frac{S'}{\sum_{k} n_k(n_k-1)/2} $$
Hamed & Rao (1998) — ขยาย Var(S) เมื่อมีสหสัมพันธ์ในตัวเอง (เฉพาะทาง Mann-Kendall)
$$ \operatorname{Var}^*(S) = \operatorname{Var}(S)\Bigl[1 + \frac{2}{n(n-1)(n-2)}\sum_{i=1}^{n-1} (n-i)(n-i-1)(n-i-2)\,\rho^*_i\Bigr],\qquad \rho^*_i = \begin{cases}\rho_i & |\rho_i| > 1.96/\sqrt{n}\\ 0 & \text{otherwise}\end{cases} $$
Sen's slope (Sen 1968) และ 95% CI (Gilbert 1987)
$$ \hat\beta = \operatorname{median}\Bigl\{\frac{x_j - x_i}{j - i}\Bigr\}_{i<j},\qquad M_1 = \frac{N - 1.96\sqrt{\operatorname{Var}(S)}}{2},\quad M_2 = \frac{N + 1.96\sqrt{\operatorname{Var}(S)}}{2},\qquad 95\%\ \text{CI} = \bigl[\hat\beta_{(M_1)},\ \hat\beta_{(M_2+1)}\bigr] $$
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

R script แพ็กเกจ trend, modifiedmk · สร้างอนุกรมรายเดือนจากข้อมูลรายบุคคลแบบเดียวกับที่ DAPH รวมให้packages trend, modifiedmk · builds the monthly series from the patient records exactly as DAPH aggregates them
# 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
Expected R output (R 4.3.3, trend 1.1.8, modifiedmk 1.6)
      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 
DAPH Tab 2 › ชนิดผลลัพธ์ Time-Series › Time Plot & Trend · แผงตั้งค่าอนุกรมเวลา: "ข้อมูลมีคอลัมน์วันที่หรือช่วงเวลา" · (1) ตัวแปรเวลา = end_date, ความถี่ = รายเดือน, อนุกรม = Study Status (status) แถว "ตัวแปรกลุ่มเป็นอนุกรม" = นับจำนวนที่เป็นระดับ, ระดับ = Died/Event (ค่าเริ่มต้นคือระดับแรก Alive/Censored ต้องเปลี่ยน) · (2) ตัวแปรเวลา = enroll_date, ความถี่ = รายเดือน (ถ้าปล่อยอัตโนมัติ DAPH จะอ่านเป็นรายวัน), อนุกรม = Treatment Group (group) = นับจำนวนแถวทั้งหมดTab 2 › outcome type Time-Series › Time Plot & Trend · Time-Series settings: "Data has a date / period column" · (1) Time variable = end_date, Frequency = Monthly, series = Study Status (status), row "Categorical series" = Count rows equal to level, level = Died/Event (the default is the first level, Alive/Censored, so change it) · (2) Time variable = enroll_date, Frequency = Monthly (left on Auto, DAPH reads these dates as daily), series = Treatment Group (group) = Count all rows
QuantityR (trend, modifiedmk)DAPH|R − DAPH|Status
Deaths: periods n / Seasonal Kendall S35 / −1035 / −100✓ 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.29410✓ 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 bound0.08330.083333< 0.0001✓ PASS
Deaths: lag-1 autocorrelation0.36090.36090✓ PASS
Deaths: month with the highest / lowest seasonal meanDec (10.00) / Sep (4.67)Dec / Sep0✓ PASS
New patients: Mann-Kendall S / z / p11 / 0.3825 / 0.702111 / 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 month0.14290.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
  1. Mann, H. B. (1945). Nonparametric tests against trend. Econometrica, 13(3), 245–259. doi:10.2307/1907187
  2. 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
  3. 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
  4. 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
  5. Gilbert, R. O. (1987). Statistical methods for environmental pollution monitoring. Van Nostrand Reinhold. ISBN 978-0-471-28878-7.
  6. 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
  7. 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
  8. 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.

คำถามในข้อมูลตัวอย่าง DAPH: จำนวนผู้เสียชีวิตต่อเดือนของผู้ป่วยล้างไตทางช่องท้อง (Study Status = Died/Event นับตามเดือนของ End Date, 2022-02 ถึง 2024-12, 35 เดือน = 2.9 รอบฤดูกาล) มีฤดูกาลหรือไม่ · ผล STL (seasonal window 7, degree 0, robust): ความแรงของฤดูกาล FS = 0.03 และของแนวโน้ม FT = 0.28 ทั้งสองอยู่ในระดับต่ำ — ข้อมูลชุดนี้ไม่มีฤดูกาลที่ชัดเจน ดัชนีฤดูกาลอยู่ระหว่าง −3.64 (มี.ค.) ถึง 1.72 (ธ.ค.) แต่มีค่าน้อยเมื่อเทียบกับความผันผวนระหว่างเดือน · การเปลี่ยนแปลงหลักคือแนวโน้มที่ขึ้นแล้วลง (ราว 5.1 → 6.9 → ต่ำกว่า 1 รายต่อเดือน) และสองเดือนที่สูงผิดปกติ (2023-07: 19 ราย, 2024-12: 13 ราย) ถูกแยกไปอยู่ในส่วนเหลือ (12.46 และ 11.82) · วิธีคลาสสิกซึ่งไม่ทนค่าผิดปกติให้ FS = 0.57 เพราะยกยอดผู้เสียชีวิตเดือน ก.ค. 2566 ไปเป็น "ฤดูกาลเดือนกรกฎาคม" (+8.55) — ตัวอย่างที่ดีว่าทำไมจึงใช้ STL แบบ robust เป็นค่าเริ่มต้น
Question in the DAPH example data: do deaths per month among the peritoneal-dialysis patients (Study Status = Died/Event counted by the month of End Date, 2022-02 to 2024-12, 35 months = 2.9 seasonal cycles) follow a season? STL result (seasonal window 7, degree 0, robust): strength of season FS = 0.03 and of trend FT = 0.28, both weak — these data have no clear seasonality. The seasonal index runs from −3.64 (Mar) to 1.72 (Dec) but is small next to the month-to-month variation. The main movement is a trend that rises and then falls (about 5.1 → 6.9 → below 1 death per month), and the two unusually high months (2023-07: 19 deaths; 2024-12: 13) are placed in the remainder (12.46 and 11.82). The classical method, which is not robust to outliers, gives FS = 0.57 because it turns the July 2023 deaths into a "July season" (+8.55) — a clear illustration of why robust STL is the default.

2หลักการและสูตรLogic and Formula

แบบบวก / แบบคูณ (additive / multiplicative)
$$ y_t = T_t + S_t + R_t \qquad\text{or}\qquad y_t = T_t \times S_t \times R_t \;\;\bigl(\log y_t = \log T_t + \log S_t + \log R_t\bigr) $$
STL (Cleveland et al. 1990) — ค่าตั้งของ DAPH
$$ \text{s.window} = 7,\quad \text{s.degree} = 0,\quad \text{t.window} = \operatorname{nextodd}\Bigl\lceil \frac{1.5\,m}{1 - 1.5/\text{s.window}}\Bigr\rceil,\quad \text{l.window} = \operatorname{nextodd}(m),\quad \text{jump} = \Bigl\lceil \frac{\text{window}}{10}\Bigr\rceil,\quad n_{\text{inner}} = 2,\ n_{\text{outer}} = 15 $$
ความแรงของแนวโน้มและฤดูกาล (Hyndman & Athanasopoulos 2021)
$$ F_T = \max\Bigl(0,\ 1 - \frac{\operatorname{Var}(R_t)}{\operatorname{Var}(T_t + R_t)}\Bigr),\qquad F_S = \max\Bigl(0,\ 1 - \frac{\operatorname{Var}(R_t)}{\operatorname{Var}(S_t + R_t)}\Bigr) $$
วิธีคลาสสิก — ค่าเฉลี่ยเคลื่อนที่กึ่งกลาง 2×m แล้วเฉลี่ยส่วนที่หักแนวโน้มตามตำแหน่งในรอบ (m คู่)
$$ \hat T_t = \frac{1}{m}\Bigl(\tfrac{1}{2}y_{t-m/2} + \sum_{j=-m/2+1}^{m/2-1} y_{t+j} + \tfrac{1}{2}y_{t+m/2}\Bigr),\qquad \hat S_k = \bar d_k - \frac{1}{m}\sum_{k'=1}^{m}\bar d_{k'},\quad \bar d_k = \operatorname{mean}\bigl(y_t - \hat T_t \mid t \in k\bigr) $$
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

R script แพ็กเกจ stats (stl, decompose) · อนุกรมผู้เสียชีวิตรายเดือนเดียวกับ 11.1package stats (stl, decompose) · the same monthly death series as 11.1
# 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)
Expected R output (R 4.3.3)
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 
DAPH Tab 2 › Time-Series › Seasonal Decomposition · ตัวแปรเวลา = end_date, ความถี่ = รายเดือน, อนุกรม = Study Status (status) นับจำนวนที่เป็นระดับ Died/Event · วิธี = STL (ค่าเริ่มต้น) หรือแบบคลาสสิก, แบบบวก (ข้อมูลมีเดือนที่เป็นศูนย์ จึงใช้แบบคูณไม่ได้)Tab 2 › Time-Series › Seasonal Decomposition · Time variable = end_date, Frequency = Monthly, series = Study Status (status), Count rows equal to level Died/Event · method = STL (default) or classical, additive (the series has a zero month, so the multiplicative form cannot be used)
QuantityR (stats)DAPH|R − DAPH|Status
STL strength of trend FT / of season FS0.2756 / 0.02620.2756 / 0.02620✓ PASS
STL 2023-07: trend / seasonal / remainder6.8715 / −0.3284 / 12.45696.8715 / −0.3284 / 12.45690✓ PASS
STL 2024-12: trend / seasonal / remainder−0.2991 / 1.4770 / 11.8221−0.2991 / 1.477 / 11.82210✓ PASS
STL trend and seasonal, all 35 months (R inner = 2)35 + 35 values35 + 35 valuesmax 5.0e−05 (4-decimal rounding)✓ PASS
STL seasonal index (12 values) and amplitudeMar −3.6383 … Dec 1.7164; 5.3547same 12 values; 5.35470✓ PASS
Season names in the index table and summary (STL)peak Dec, trough MarDec / Mar (table rows Jan … Dec in calendar order)0✓ PASS
Classical seasonal figure (12 values)Jul 8.5521 … Sep −2.51048.5521 … −2.5104≤ 0.0001✓ PASS
Classical FT / FS0.5881 / 0.56540.5881 / 0.56540✓ PASS
Season names (classical)peak Jul, trough SepJul / Sep0✓ 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
  1. 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.
  2. Hyndman, R. J., & Athanasopoulos, G. (2021). Forecasting: Principles and practice (3rd ed.). OTexts. https://otexts.com/fpp3/
  3. 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.

คำถามในข้อมูลตัวอย่าง DAPH: จำนวนผู้เสียชีวิตต่อเดือน (35 เดือน, 2022-02 ถึง 2024-12 เหมือน 11.1) พึ่งพาเดือนก่อน ๆ แค่ไหน และคงที่หรือไม่ · ผล: ACF ที่ lag 1 = 0.36 และ lag 2 = 0.45 เกินขอบเขต ±0.33 · PACF มีค่าสูงที่ lag 1–2 (0.36, 0.37) แล้วลดลงใกล้ศูนย์ · Ljung-Box Q(16) = 65.47, p < 0.001 จึงไม่ใช่สัญญาณรบกวนขาว · ACF ที่ lag 12 = −0.43 เป็นค่าลบ ซึ่งเกิดจากรูปขึ้นแล้วลงของอนุกรม (เดือนที่ห่างกัน 12 เดือนอยู่คนละด้านของยอด) ไม่ใช่ฤดูกาล (11.2 พบความแรงของฤดูกาลเพียง 0.03) · ADF (มีค่าคงที่, 1 lag เลือกด้วย AIC) = −2.174, p = 0.216 ไม่ปฏิเสธ unit root · KPSS (รอบระดับ, bandwidth 3) = 0.2433 ต่ำกว่าค่าวิกฤต 5% (0.463) จึงไม่ปฏิเสธความคงที่ (p > 0.10) — สองการทดสอบขัดกัน ผลจึงไม่ชัดเจน ซึ่งพบบ่อยในอนุกรมสั้นที่ระดับเปลี่ยน
Question in the DAPH example data: how far do monthly deaths (35 months, 2022-02 to 2024-12, as in 11.1) depend on earlier months, and is the series stationary? Result: the ACF at lag 1 = 0.36 and at lag 2 = 0.45 exceed the ±0.33 bound; the PACF is high at lags 1–2 (0.36, 0.37) and then drops towards zero; Ljung-Box Q(16) = 65.47, p < 0.001, so the series is not white noise. The ACF at lag 12 = −0.43 is negative: it comes from the rise-and-fall shape of the series (months 12 apart sit on opposite sides of the peak), not from seasonality (11.2 found a seasonal strength of only 0.03). ADF (constant, 1 lag chosen by AIC) = −2.174, p = 0.216, does not reject a unit root; KPSS (level, bandwidth 3) = 0.2433 is below the 5% critical value (0.463) and does not reject stationarity (p > 0.10) — the two tests disagree, so the result is inconclusive, which is common in short series whose level shifts.

2หลักการและสูตรLogic and Formula

ACF และ PACF
$$ r_k = \frac{\sum_{t=k+1}^{n}(y_t - \bar y)(y_{t-k} - \bar y)}{\sum_{t=1}^{n}(y_t - \bar y)^2},\qquad \phi_{kk} = \operatorname{corr}\bigl(y_t, y_{t-k} \mid y_{t-1},\dots,y_{t-k+1}\bigr),\qquad \text{bound} = \pm\frac{1.96}{\sqrt n} $$
Ljung-Box (1978) — ทดสอบอนุกรมดิบ (ไม่หักองศาอิสระ)
$$ Q(h) = n(n+2)\sum_{k=1}^{h}\frac{r_k^2}{n-k} \;\sim\; \chi^2_{h} \ \text{under white noise} $$
Augmented Dickey-Fuller (1979) — H0: มี unit root (γ = 0) · มีค่าคงที่
$$ \Delta y_t = \alpha + \gamma\,y_{t-1} + \sum_{i=1}^{p}\delta_i\,\Delta y_{t-i} + \varepsilon_t,\qquad \tau = \hat\gamma / \operatorname{SE}(\hat\gamma),\qquad p \in \{0,\dots,p_{\max}\},\ p_{\max} = \Bigl\lceil 12\,(n/100)^{1/4}\Bigr\rceil $$
KPSS (Kwiatkowski et al. 1992) — H0: คงที่รอบระดับ
$$ \eta_\mu = \frac{1}{n^2\,\hat\sigma^2_{\text{LR}}}\sum_{t=1}^{n} S_t^2,\qquad S_t = \sum_{i=1}^{t} e_i,\quad e_i = y_i - \bar y,\qquad \hat\sigma^2_{\text{LR}} = \frac{1}{n}\sum_{t} e_t^2 + \frac{2}{n}\sum_{s=1}^{\ell}\Bigl(1 - \frac{s}{\ell+1}\Bigr)\sum_{t=s+1}^{n} e_t e_{t-s} $$
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

R script แพ็กเกจ stats (acf, pacf, Box.test), urca (ur.df, punitroot, ur.kpss) · ADF เลือก lag ด้วย AIC แบบเดียวกับ DAPHpackages stats (acf, pacf, Box.test), urca (ur.df, punitroot, ur.kpss) · the ADF lag is chosen by AIC as DAPH does
# 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
Expected R output (R 4.3.3, urca 1.3.3)
       [,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
DAPH Tab 2 › Time-Series › Autocorrelation · ตัวแปรเวลา = end_date, ความถี่ = รายเดือน, อนุกรม = Study Status (status) นับจำนวนที่เป็นระดับ Died/Event · lag สูงสุดเว้นว่าง (อัตโนมัติ = 16)Tab 2 › Time-Series › Autocorrelation · Time variable = end_date, Frequency = Monthly, series = Study Status (status), Count rows equal to level Died/Event · maximum lag left empty (automatic = 16)
QuantityR (stats, urca)DAPH|R − DAPH|Status
ACF lag 1 / 2 / 120.3609 / 0.4495 / −0.42670.3609 / 0.4495 / −0.42670✓ PASS
ACF and PACF, all 16 lags32 values32 values0 (4 dp)✓ PASS
95% bound ±1.96/√n0.33130.33130✓ PASS
Ljung-Box Q(16) / p65.474 / 6.1e−0865.4737 / < 0.000001< 0.001✓ PASS
ADF lag chosen by AIC / τ statistic1 / −2.1741 / −2.1740✓ PASS
ADF p (R: MacKinnon 1996; DAPH: MacKinnon 1994; tolerance 0.001)0.2160120.2157990.0002✓ PASS
KPSS statistic (level, bandwidth 3) / 5% critical value0.2433 / 0.4630.2433 / 0.4630✓ 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
  1. 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.
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. 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).

คำถามในข้อมูลตัวอย่าง DAPH: สมมติว่า ณ สิ้นเดือนมิถุนายน 2566 แผนงานล้างไตทางช่องท้องต้องวางแผนวัสดุสำหรับผู้ป่วยใหม่ใน 12 เดือนข้างหน้า จะมีผู้ป่วยใหม่เดือนละกี่ราย (นับตามเดือนของ Enrollment Date, 2022-01 ถึง 2023-06, 18 เดือน; ในข้อมูลจริงการรับผู้ป่วยหยุดหลังเดือนนี้ ตัวอย่างนี้จึงเป็นการฝึกวางแผนสมมติ) · ผล: DAPH กัน 4 เดือนสุดท้าย (2023-03 ถึง 2023-06) ไว้ตรวจ · ตระกูล SARIMA: ADF บน 14 เดือนแรกให้ p = 0.0015 จึงไม่หาผลต่าง (d = 0) และ AICc เลือก ARIMA(0,0,1) มีค่าคงที่ (AICc 91.24) · Holt-Winters ใช้แนวโน้มลดทอนไม่มีฤดูกาล (ข้อมูลไม่ถึง 2 รอบ) · บนช่วงที่กันไว้ Holt-Winters แม่นกว่า (RMSE 9.11 เทียบ 9.57) จึงถูกเลือก: MAE 8.25, MAPE 10.99%, MASE 1.37, ช่วงพยากรณ์ 95% ครอบค่าจริง 3 ใน 4 เดือน (75%) · ประมาณใหม่ด้วย 18 เดือน: α = 0, β = 0, φ = 0.995 · พยากรณ์ 72.88 รายในเดือน 2023-07 ถึง 73.60 รายใน 2024-06 (95% PI ราว 58 ถึง 88 รายต่อเดือน) — การรับผู้ป่วยคงที่ ค่าพยากรณ์จึงเกือบเป็นเส้นตรงที่ระดับเฉลี่ย
Question in the DAPH example data: suppose that at the end of June 2023 the peritoneal-dialysis programme had to plan supplies for the next 12 months: how many new patients per month should it expect (counted by the month of Enrollment Date, 2022-01 to 2023-06, 18 months; in the data recruitment actually stopped after that month, so this is a hypothetical planning exercise)? Result: DAPH held back the last 4 months (2023-03 to 2023-06). SARIMA family: ADF on the first 14 months gave p = 0.0015, so no differencing (d = 0), and AICc chose ARIMA(0,0,1) with a constant (AICc 91.24). Holt-Winters used a damped trend without season (fewer than two cycles). On the held-back months Holt-Winters was more accurate (RMSE 9.11 vs 9.57) and was selected: MAE 8.25, MAPE 10.99%, MASE 1.37, and the 95% prediction interval covered 3 of the 4 actual values (75%). Refitted on all 18 months: α = 0, β = 0, φ = 0.995. Forecast: 72.88 new patients in 2023-07 to 73.60 in 2024-06 (95% PI about 58 to 88 per month) — recruitment was steady, so the forecast is an almost flat line at the average level.

2หลักการและสูตรLogic and Formula

SARIMA(p,d,q)(P,D,Q)m (Box et al. 2015)
$$ \phi_p(B)\,\Phi_P(B^m)\,(1-B)^d(1-B^m)^D\,(y_t - \mu) = \theta_q(B)\,\Theta_Q(B^m)\,\varepsilon_t,\qquad \varepsilon_t \sim N(0, \sigma^2) $$
Regression with ARIMA errors (ตัวทำนาย; Hyndman & Athanasopoulos 2021 บทที่ 10)
$$ y_t = \beta_0 + \sum_j \beta_j\,x_{j,\,t-k_j} + \eta_t,\qquad \eta_t \sim \text{SARIMA}(p,d,q)(P,D,Q)_m $$
Holt-Winters แบบบวก แนวโน้มลดทอน (Holt 2004; Winters 1960)
$$ \ell_t = \alpha(y_t - s_{t-m}) + (1-\alpha)(\ell_{t-1} + \phi b_{t-1}),\quad b_t = \beta(\ell_t - \ell_{t-1}) + (1-\beta)\phi b_{t-1},\quad s_t = \gamma(y_t - \ell_{t-1} - \phi b_{t-1}) + (1-\gamma)s_{t-m} $$ $$ \hat y_{t+h|t} = \ell_t + (\phi + \phi^2 + \dots + \phi^h)\,b_t + s_{t+h-m(k+1)},\qquad k = \lfloor (h-1)/m \rfloor $$
การเลือกและการตรวจ
$$ \text{AICc} = \text{AIC} + \frac{2k(k+1)}{n-k-1},\qquad \text{RMSE} = \sqrt{\tfrac{1}{H}\sum e_t^2},\qquad \text{MASE} = \frac{\tfrac{1}{H}\sum|e_t|}{\frac{1}{T-m}\sum_{t=m+1}^{T}|y_t - y_{t-m}|} $$ $$ R^2_{\text{stationary}} = 1 - \frac{\text{SSE}}{\sum_t (z_t - \bar z)^2},\ z = \nabla^d\nabla_m^D y,\qquad \text{Normalized BIC} = \ln\frac{\text{SSE}}{n} + \frac{k\ln n}{n} $$
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

R script แพ็กเกจ forecast (Arima, forecast, accuracy), urca (ur.df, punitroot), stats (optim) · ทำซ้ำทุกขั้นตอนของ DAPH บนผู้ป่วยใหม่รายเดือนpackages forecast (Arima, forecast, accuracy), urca (ur.df, punitroot), stats (optim) · repeats every DAPH step on the monthly new patients
# 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
Expected R output (R 4.3.3, forecast 8.21.1, urca 1.3.3)
    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
DAPH Tab 2 › Time-Series › Time-Series Forecast · ตัวแปรเวลา = enroll_date, ความถี่ = รายเดือน, อนุกรม = Treatment Group (group) นับจำนวนแถวทั้งหมด · แบบจำลอง = อัตโนมัติ, ระยะพยากรณ์ 0 (อัตโนมัติ = 12), ไม่มีตัวทำนายTab 2 › Time-Series › Time-Series Forecast · Time variable = enroll_date, Frequency = Monthly, series = Treatment Group (group), Count all rows · Model = Auto, horizon 0 (automatic = 12), no predictors
QuantityR (forecast, urca, optim)DAPH|R − DAPH|Status
Held-back months / training months4 / 144 / 140✓ PASS
SARIMA grid choice (d = 0) and its AICc / AIC / BICARIMA(0,0,1)+mean; 91.24416 / 88.84 / 90.76ARIMA(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.40169.5643 / 8.4084 / 1.40140.0020✓ PASS
ARIMA 95% PI coverage on held-back months0.7575.0%0✓ PASS
Holt-Winters training fit α / β / φ0 / 0 / 0.80 / 0 / 0.80✓ PASS
Holt-Winters held-back RMSE / MAE / MAPE / MASE9.1113 / 8.2486 / 10.9889 / 1.37489.1113 / 8.2486 / 10.99 / 1.3748< 0.0001✓ PASS
Selected model (lower held-back RMSE)Holt-WintersHolt-Winters (damped trend)—✓ PASS
Refit on 18 months: φ / initial level / initial trend0.995 / 71.5394 / 0.07430.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.9950✓ PASS
Forecast 2023-07 / 2023-08 / 2024-0672.8826 / 72.9498 / 73.603772.8826 / 72.9498 / 73.60370✓ PASS
95% PI, 12 months (R: exact normal limits; DAPH: 1,000 simulated paths; tolerance 2)2023-07: 58.5342 to 87.23102023-07: 58.4781 to 86.9951max 1.59 over 24 limits✓ PASS
R² (first month excluded) / AIC of the final model0.0145 / 75.80740.0145 / 75.80740✓ PASS
AICc of the final model (k = 5 estimated values)80.807480.80740✓ PASS
Normalized BIC of the final model (k = 5, 17 months)4.41124.411< 0.001✓ PASS
Residual Ljung-Box Q(4), df = 1 / p3.6815 / 0.055023.6815 / 0.0550210✓ 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
  1. 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.
  2. Hyndman, R. J., & Athanasopoulos, G. (2021). Forecasting: Principles and practice (3rd ed.). OTexts. https://otexts.com/fpp3/
  3. 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
  4. Harvey, A. C. (1989). Forecasting, structural time series models and the Kalman filter. Cambridge University Press. ISBN 978-0-521-40573-7.
  5. 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
  6. Winters, P. R. (1960). Forecasting sales by exponentially weighted moving averages. Management Science, 6(3), 324–342. doi:10.1287/mnsc.6.3.324
  7. 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
  8. 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.

คำถามในข้อมูลตัวอย่าง DAPH: จำนวนผู้ป่วยใหม่ในเดือนหนึ่งนำหน้าจำนวนผู้เสียชีวิตในเดือนต่อ ๆ ไปหรือไม่ และกี่เดือน — เหตุผลทางคลินิกคือความเสี่ยงตายสูงในช่วงแรกหลังเริ่มล้างไต (ในผู้เสียชีวิต 229 ราย มี 34, 24 และ 19 รายเสียชีวิตในเดือนที่ 1, 2 และ 3 หลังเดือนที่รับเข้า) · สร้างตารางรายเดือน 36 เดือน (2022-01 ถึง 2024-12) ด้วย R แล้วเปิดใน DAPH · ผล: CCF ดิบเกินขอบเขต ±0.33 ถึง 16 lag (บวกที่ lag +2 ถึง +11 และลบที่ lag −12 ถึง −7) เป็นรูปกว้างที่มาจากแนวโน้มร่วม (รับผู้ป่วย 18 เดือนแล้วหยุด ส่วนการเสียชีวิตขึ้นแล้วลง) จึงบอก lag ไม่ได้ · หลัง prewhiten ด้วย ARIMA(1,1,0)(1,1,0)12 ที่ประมาณจากผู้ป่วยใหม่ (ตัด 13 เดือนแรก เหลือ 23 เดือน ขอบเขต ±0.41) ไม่มี lag ใดมีนัยสำคัญ — อนุกรมผู้ป่วยใหม่เกือบเป็นขั้นบันได (ราว 72 รายต่อเดือนแล้วเป็นศูนย์) ความผันผวนรายเดือนน้อยเกินกว่าจะเห็นผลต่อการเสียชีวิต และตัวกรองกินข้อมูลไป 13 จาก 36 เดือน ผลของการรับผู้ป่วยต่อการเสียชีวิตจึงควรประมาณด้วย distributed-lag regression (11.7) ซึ่งใช้ขั้นบันไดนั้นโดยตรง
Question in the DAPH example data: does the number of new patients in a month lead the number of deaths in the following months, and by how many months? The clinical reason is the high risk of death soon after starting dialysis (of the 229 deaths, 34, 24 and 19 occurred in the 1st, 2nd and 3rd month after the month of enrolment). A 36-month table (2022-01 to 2024-12) is built in R and opened in DAPH. Result: the raw CCF exceeds the ±0.33 bound at 16 lags (positive at lags +2 to +11, negative at −12 to −7) — a broad pattern from the shared trend (18 months of recruitment then none; deaths rising then falling) that cannot point to a lag. After prewhitening with ARIMA(1,1,0)(1,1,0)12 fitted to new patients (13 start-up months dropped, 23 left, bound ±0.41) no lag is significant — the new-patient series is almost a step (about 72 a month, then zero), its month-to-month variation is too small to move deaths visibly, and the filter uses up 13 of the 36 months. The effect of recruitment on deaths is better estimated with a distributed-lag regression (11.7), which uses the step directly.

2หลักการและสูตรLogic and Formula

Cross-correlation function — เครื่องหมาย lag ของ DAPH: k > 0 = x นำหน้า y
$$ r_{xy}(k) = \frac{\sum_{t} (x_{t-k} - \bar x)(y_t - \bar y)}{n\,s_x\,s_y},\qquad s_x^2 = \frac{1}{n}\sum_t (x_t - \bar x)^2,\qquad \text{bound} = \pm\frac{1.96}{\sqrt{n'}} $$
Prewhitening (Box et al. 2015) — ตัวกรองจาก ARIMA ของ x ใช้กับทั้ง x และ y
$$ a_t = \frac{\phi(B)\,\Phi(B^m)\,(1-B)^d(1-B^m)^D}{\theta(B)\,\Theta(B^m)}\,x_t,\qquad b_t = \frac{\phi(B)\,\Phi(B^m)\,(1-B)^d(1-B^m)^D}{\theta(B)\,\Theta(B^m)}\,y_t,\qquad r_{ab}(k) $$
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

R script แพ็กเกจ stats (ccf), forecast (Arima), urca (ur.df, punitroot) · สร้าง pd_monthly.csv จากข้อมูลตัวอย่างเพื่อเปิดใน DAPHpackages stats (ccf), forecast (Arima), urca (ur.df, punitroot) · builds pd_monthly.csv from the example data for 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)
Expected R output (R 4.3.3, forecast 8.21.1, urca 1.3.3)

  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
DAPH File › Open › pd_monthly.csv แล้ว Tab 2 › Time-Series › Cross-Correlation · ตัวแปรเวลา = month, ความถี่ = รายเดือน · อนุกรมที่วิเคราะห์ (กล่องซ้าย) = deaths · อนุกรมอธิบาย (กล่องขวา) = new_patients · Prewhiten = เปิด (ค่าเริ่มต้น) · lag สูงสุดเว้นว่าง (อัตโนมัติ = 12) · CCF ดิบ: ปิด PrewhitenFile › Open › pd_monthly.csv, then Tab 2 › Time-Series › Cross-Correlation · Time variable = month, Frequency = Monthly · series to analyse (left box) = deaths · explanatory series (right box) = new_patients · Prewhiten = on (default) · maximum lag empty (automatic = 12) · raw CCF: Prewhiten off
QuantityR (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 lags0.3267 / 160.3267 / 160✓ PASS
Filter: ADF p for new patients (so d = 1) / chosen order0.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.0672192.0580.009✓ PASS
Filter ar1 / sar1 (tolerance 0.005)−0.5844 / −0.9623−0.5849 / −0.96240.0005✓ PASS
Start-up residuals dropped / bound ±1.96/√n′13 / 0.408713 / 0.40870✓ 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.313max 0.0003 over 25 lags✓ PASS
Prewhitened: number of significant lags000✓ 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
  1. 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.
  2. 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
  3. 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.

คำถามในข้อมูลตัวอย่าง DAPH: ข้อมูลตัวอย่างไม่มีนโยบายสุขภาพ จึงใช้เหตุการณ์ที่มีวันที่ชัดเจนเพียงอย่างเดียวในข้อมูล คือ การปิดรับผู้ป่วยใหม่หลังเดือนมิถุนายน 2566 (ผู้ป่วยรายสุดท้ายเข้าวันที่ 29 มิ.ย. 2566) ตั้งแต่ 2023-07 จำนวนผู้ป่วยที่อยู่ในการติดตามจึงหยุดเพิ่ม · จำนวนผู้เสียชีวิตต่อเดือน (35 เดือน: ก่อน 17 เดือน 2022-02 ถึง 2023-06, หลัง 18 เดือน 2023-07 ถึง 2024-12) เปลี่ยนระดับหรือแนวโน้มหรือไม่ · ผล (Newey-West bandwidth 3, Fourier 2 คู่): ก่อนปิดรับ การเสียชีวิตเพิ่มเดือนละ 0.44 ราย (95% CI 0.26 ถึง 0.62) · การเปลี่ยนระดับ −0.09 ราย (95% CI −5.06 ถึง 4.87, p = 0.971) · การเปลี่ยนความชัน −0.96 รายต่อเดือน (95% CI −1.34 ถึง −0.57, p < 0.001) · ความชันหลังปิดรับ −0.52 รายต่อเดือน (95% CI −0.90 ถึง −0.14) · ณ 2024-12 ต่ำกว่าเส้นสมมติ 17.33 ราย (95% CI −23.42 ถึง −11.23) เฉลี่ยตลอดช่วงหลังต่ำกว่า 60.9% · Durbin-Watson 2.14 — แนวโน้มเปลี่ยนจากขาขึ้นเป็นขาลงเมื่อปิดรับผู้ป่วย โดยพจน์การเปลี่ยนระดับใกล้ศูนย์ ซึ่งเป็นสิ่งที่คาดได้จากการออกแบบการศึกษา ไม่ใช่ผลของมาตรการทางสุขภาพ
Question in the DAPH example data: the example data contain no health policy, so this section uses the one dated event they do contain: recruitment closed after June 2023 (the last patient enrolled on 29 June 2023), so from 2023-07 the number of patients under follow-up stopped growing. Did the number of deaths per month (35 months: 17 before, 2022-02 to 2023-06; 18 after, 2023-07 to 2024-12) change level or trend? Result (Newey-West bandwidth 3, 2 Fourier pairs): before closure deaths rose by 0.44 a month (95% CI 0.26 to 0.62); level change −0.09 deaths (95% CI −5.06 to 4.87, p = 0.971); slope change −0.96 deaths per month (95% CI −1.34 to −0.57, p < 0.001); slope after closure −0.52 per month (95% CI −0.90 to −0.14); at 2024-12, 17.33 deaths below the counterfactual (95% CI −23.42 to −11.23), 60.9% below on average over the post period; Durbin-Watson 2.14 — the trend turned from rising to falling when recruitment closed, with a level-change term close to zero, as the study design would lead one to expect; this is not the effect of a health intervention.

2หลักการและสูตรLogic and Formula

Segmented regression — พจน์ความชันคือเวลานับจากจุดแทรกแซง (Bernal et al. 2017; Xiao et al. 2021)
$$ y_t = \beta_0 + \beta_1 t + \beta_2 D_t + \beta_3 (t - t_0 + 1)D_t + \sum_{k=1}^{K}\bigl[\gamma_k \sin(2\pi k t/m) + \delta_k \cos(2\pi k t/m)\bigr] + \varepsilon_t,\qquad D_t = \mathbb{1}(t \ge t_0) $$
ผลที่รายงาน (เส้นสมมติ = ทุกพจน์ของมาตรการเป็น 0)
$$ \text{level change} = \beta_2,\quad \text{slope change} = \beta_3,\quad \text{post slope} = \beta_1 + \beta_3,\quad \text{effect at } t = \beta_2 + \beta_3 (t - t_0 + 1),\quad \text{SE} = \sqrt{c'\hat V c} $$
Newey-West HAC (1987) — bandwidth อัตโนมัติ (Newey & West 1994) ปัดเศษเป็นจำนวนเต็มที่ใกล้ที่สุด
$$ \hat V = (X'X)^{-1}\Bigl[\sum_t \hat e_t^2 x_t x_t' + \sum_{l=1}^{L}\Bigl(1 - \tfrac{l}{L+1}\Bigr)\sum_{t=l+1}^{n}\bigl(x_t \hat e_t \hat e_{t-l} x_{t-l}' + x_{t-l}\hat e_{t-l}\hat e_t x_t'\bigr)\Bigr](X'X)^{-1},\qquad L = \operatorname{round}\bigl(4 (n/100)^{2/9}\bigr) $$
Prais-Winsten (ทางเลือก) — FGLS สำหรับ εt = ρεt−1 + ut (สูตรการแปลงใน 11.7)
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

R script แพ็กเกจ sandwich (NeweyWest), lmtest (coeftest, coefci, dwtest), prais (prais_winsten)packages sandwich (NeweyWest), lmtest (coeftest, coefci, dwtest), prais (prais_winsten)
# 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
Expected R output (R 4.3.3, sandwich 3.1-0, lmtest 0.9-40, prais 1.1.4)
[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
DAPH Tab 2 › Time-Series › Interrupted Time Series · ตัวแปรเวลา = end_date, ความถี่ = รายเดือน, อนุกรม = Study Status (status) นับจำนวนที่เป็นระดับ Died/Event · จุดแทรกแซง = 2023-07 · ลักษณะมาตรการ = จุดเดียว · ผลล่าช้า 0 · ปรับฤดูกาล = เปิด · ค่าคลาดเคลื่อนมาตรฐาน = Newey-West (และรันซ้ำด้วย Prais-Winsten) · แบนด์วิดท์ HAC เว้นว่างTab 2 › Time-Series › Interrupted Time Series · Time variable = end_date, Frequency = Monthly, series = Study Status (status), Count rows equal to level Died/Event · Interruption at = 2023-07 · Intervention type = Single point · Delayed effect 0 · Adjust for seasonality = on · Standard errors = Newey-West (and a second run with Prais-Winsten) · HAC bandwidth empty
QuantityR (sandwich, lmtest, prais)DAPH|R − DAPH|Status
Interruption position / periods before / after / NW bandwidth / Fourier pairs18 / 17 / 18 / 3 / 218 / 17 / 18 / 3 / 20✓ 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.9709670✓ 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.940✓ PASS
R² / adjusted R² / Durbin-Watson0.4697 / 0.3322 / 2.14220.4697 / 0.3322 / 2.14220✓ PASS
Ljung-Box Q(8) / p4.8691 / 0.77154.8691 / 0.7714710✓ 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 residuals1.6165 / 1.31411.6165 / 1.31410✓ 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
  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  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
  8. 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
  9. 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.

คำถามในข้อมูลตัวอย่าง DAPH: ผู้ป่วยใหม่หนึ่งรายสัมพันธ์กับการเสียชีวิตเพิ่มขึ้นกี่รายในเดือนที่รับเข้าและ 3 เดือนถัดไป (ต่อจาก 11.5 ที่ CCF บอก lag ไม่ได้) · ตารางรายเดือน pd_monthly.csv (36 เดือน ใช้ได้ 33 เดือนหลังตัด 3 เดือนแรก) · deathst = β0 + δt + Σl=0..3 βl new_patientst−l + εt · AICc เลือกไม่ใส่พจน์ฤดูกาล (K = 0) · ผล (Newey-West bandwidth 3): ผลสะสม 0.0655 รายต่อผู้ป่วยใหม่ 1 ราย (95% CI −0.0278 ถึง 0.1588, p = 0.169) หรือราว 6.6 รายต่อผู้ป่วยใหม่ 100 ราย ใกล้กับสัดส่วนที่เห็นจริงในข้อมูลรายบุคคล (ผู้ป่วย 5.92% เสียชีวิตภายใน 0–3 เดือนหลังเดือนที่รับเข้า) แต่ช่วงเชื่อมั่นกว้างและครอบศูนย์ · ค่าราย lag (−0.122, 0.108, 0.019, 0.061) ไม่นิ่ง (lag 0 ติดลบทั้งที่ไม่มีผู้ป่วยรายใดเสียชีวิตในเดือนที่รับเข้า) จึงอ่านผลสะสมเป็นหลัก · R² 0.447, Durbin-Watson 1.48, Ljung-Box p = 0.983 · วิธีอื่นให้ผลสะสมใกล้กัน: Prais-Winsten (ρ = 0.22) 0.0669, ARIMA(0,1,1) errors 0.0523, เพิ่มพจน์ AR 1 พจน์ 0.0567
Question in the DAPH example data: how many extra deaths go with one new patient in the month of enrolment and the following 3 months (continuing 11.5, where the CCF could not point to a lag)? Monthly table pd_monthly.csv (36 months; 33 usable after the first 3 are dropped): deathst = β0 + δt + Σl=0..3 βl new_patientst−l + εt; AICc chose no seasonal terms (K = 0). Result (Newey-West bandwidth 3): cumulative effect 0.0655 deaths per new patient (95% CI −0.0278 to 0.1588, p = 0.169), about 6.6 deaths per 100 new patients — close to what the patient records show (5.92% of patients died within 0–3 months after the month of enrolment), but the interval is wide and covers zero. The lag coefficients (−0.122, 0.108, 0.019, 0.061) are unstable (lag 0 is negative although no patient died in the month of enrolment), so the cumulative effect is the quantity to read. R² 0.447, Durbin-Watson 1.48, Ljung-Box p = 0.983. The other methods give similar cumulative effects: Prais-Winsten (ρ = 0.22) 0.0669, ARIMA(0,1,1) errors 0.0523, one AR term 0.0567.

2หลักการและสูตรLogic and Formula

แบบจำลองรวม (distributed lags + พจน์ AR + แนวโน้ม + ฤดูกาล Fourier)
$$ y_t = \beta_0 + \delta\,t + \sum_{k=1}^{K}\bigl[\gamma_k \sin(2\pi k t/m) + \eta_k \cos(2\pi k t/m)\bigr] + \sum_{j}\sum_{l=0}^{L_j} \beta_{jl}\,x_{j,t-l} + \sum_{i=1}^{p}\phi_i\,y_{t-i} + \varepsilon_t $$
ผลสะสมของตัวทำนาย j (รายงานเมื่อ Lj ≥ 1) และผลระยะยาวเมื่อมีพจน์ AR
$$ \hat\beta_{j,\text{cum}} = \sum_{l=0}^{L_j}\hat\beta_{jl},\qquad \operatorname{SE} = \sqrt{c'\,\hat V\,c},\qquad 95\%\,\text{CI} = \hat\beta_{j,\text{cum}} \pm 1.96\,\operatorname{SE},\qquad \text{long run} = \frac{\hat\beta_{j,\text{cum}}}{1 - \sum_i \hat\phi_i} $$
Newey-West HAC (Newey & West 1987; ค่าเริ่มต้น; สูตร V̂ ใน 11.6) — bandwidth = round(4(nused/100)2/9) (Newey & West 1994)
Prais-Winsten (Prais & Winsten 1954) — εt = ρεt−1 + ut วนซ้ำจน ρ นิ่ง (ต่างกันน้อยกว่า 10−6, ไม่เกิน 50 รอบ)
$$ \hat\rho = \frac{\sum_{t=2}^{n} \hat e_t \hat e_{t-1}}{\sum_{t=2}^{n}\hat e_{t-1}^2},\qquad y_1^* = \sqrt{1-\hat\rho^2}\,y_1,\quad y_t^* = y_t - \hat\rho\,y_{t-1}\ (t \ge 2),\ \text{same for } X,\qquad \hat V = s^2 (X^{*\prime}X^*)^{-1} $$
Regression with ARIMA errors — εt ~ ARIMA(p,d,q): d จาก ADF ของผลลัพธ์, p, q ∈ {0,1,2} เลือกด้วย AICc, exact ML
การเลือกจำนวนคู่ Fourier (K = 0 … Kmax) บนสเปคและตัวอย่างเดียวกัน
$$ \text{AICc}(K) = -2\ln L + 2p_K + \frac{2p_K(p_K+1)}{n_{\text{used}} - p_K - 1},\qquad p_K = \text{coefficients} + 1\ (\sigma^2),\qquad K_{\max} = \min\bigl(m/2,\ \lfloor (n-10)/8 \rfloor,\ 4\bigr) $$
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

R script แพ็กเกจ sandwich, lmtest, prais, forecast, urca, tseries · ตารางรายเดือนเดียวกับ 11.5packages sandwich, lmtest, prais, forecast, urca, tseries · the same monthly table as 11.5
# 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)
Expected R output (R 4.3.3, sandwich 3.1-0, lmtest 0.9-40, prais 1.1.4, forecast 8.21.1)
[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
DAPH File › Open › pd_monthly.csv แล้ว Tab 2 › Time-Series › Time-Series Regression · ตัวแปรเวลา = month, ความถี่ = รายเดือน · อนุกรมผลลัพธ์ = deaths · ตัวทำนาย = new_patients · lag สูงสุดของตัวทำนาย (L) = 3 · พจน์ AR = 0 · สหสัมพันธ์ของส่วนเหลือ = Newey-West (รันซ้ำด้วย Prais-Winsten, ARIMA errors และพจน์ AR = 1) · แนวโน้มเชิงเส้น = เปิด · ปรับฤดูกาล = เปิด · คู่ฤดูกาล (K) = อัตโนมัติ (AICc) · แบนด์วิดท์ HAC เว้นว่างFile › Open › pd_monthly.csv, then Tab 2 › Time-Series › Time-Series Regression · Time variable = month, Frequency = Monthly · outcome series = deaths · predictor = new_patients · Max lag of predictors (L) = 3 · AR terms = 0 · Residual autocorrelation = Newey-West (repeated with Prais-Winsten, ARIMA errors and AR terms = 1) · Linear trend = on · Adjust for seasonality = on · Seasonal pairs (K) = Automatic (AICc) · HAC bandwidth empty
QuantityRDAPH|R − DAPH|Status
Periods used / Newey-West bandwidth33 / 333 / 30✓ PASS
AICc for K = 0 / 1 / 2 / 3 (K = 0 chosen)184.8480 / 186.4712 / 193.4626 / 203.9758184.848 / 186.4712 / 193.4626 / 203.97580✓ PASS
β lag 0 / 1 / 2 / 3−0.1217 / 0.1076 / 0.0190 / 0.0606−0.1217 / 0.1076 / 0.019 / 0.06060✓ PASS
Newey-West SE lag 0 / 1 / 2 / 30.0312 / 0.0267 / 0.0151 / 0.02980.0312 / 0.0267 / 0.0151 / 0.02980✓ PASS
Cumulative effect (SE) [95% CI] p0.0655 (0.0476) [−0.0278, 0.1588] 0.16870.0655 (0.0476) [−0.0278, 0.1588] 0.1686940✓ PASS
R² / adjusted R² / Durbin-Watson / Ljung-Box Q(8), p0.4474 / 0.3451 / 1.4775 / 1.9172, 0.98340.4474 / 0.3451 / 1.4775 / 1.9172, 0.9834450✓ 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.10420✓ PASS
Prais-Winsten ρ / cumulative (SE) / R² / DW of transformed residuals0.2193 / 0.0669 (0.0445) / 0.4446 / 1.78000.2193 / 0.0669 (0.0445) / 0.4446 / 1.780✓ PASS
ARIMA errors: ADF p (so d = 1) / order / AICc0.3539 / (0,1,1) / 183.1705d = 1 / (0,1,1) / 183.17050✓ PASS
ARIMA errors: cumulative / SE (tolerance 0.001: numerical Hessian)0.0523 / 0.04410.0523 / 0.04350 / 0.0006✓ PASS
ARIMA errors: Durbin-Watson / Ljung-Box Q(8), df 7 (tolerance 0.01: start-up residuals)1.6828 / 1.29411.6856 / 1.29490.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
  1. 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
  2. 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
  3. Prais, S. J., & Winsten, C. B. (1954). Trend estimators and serial correlation (Cowles Commission Discussion Paper No. 383). Cowles Commission for Research in Economics.
  4. 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
  5. 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.1deaths per month; new patients per month12 / 12Sen's slope 95% CI by Gilbert's ranks; season names follow the calendar
11.2deaths per month9 / 9STL runs 2 inner loess passes per robustness iteration (R: stl(inner = 2))
11.3deaths per month7 / 7KPSS bandwidth chosen automatically (R: use.lag = 3)
11.4new patients per month15 / 15Holt-Winters limits from 1,000 simulated paths (tolerance 2); the SARIMA grid tries seasonal terms even on short series
11.5pd_monthly.csv: new patients → deaths8 / 8prewhitened with standardised residuals; the filter uses up d + D·m = 13 months
11.6deaths per month, interruption 2023-0712 / 12"Automatic (AICc)" K uses the fixed default (2 pairs) in ITS
11.7pd_monthly.csv: deaths ~ new patients, lags 0–312 / 12stationarity 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
  1. Wong, B. (2011). Points of view: Color blindness. Nature Methods, 8(6), 441. doi:10.1038/nmeth.1618
  2. 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
  3. 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 4 tools ✓ 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).

ตัวอย่างจากข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย) มีข้อคำถามวิถีชีวิต 9 ข้อ แต่ละข้อให้คะแนน 0–4 ตามจำนวนวันใน 14 วันที่ผ่านมา (0 = ไม่เคย, 1 = 1–4 วัน, 2 = 5–9 วัน, 3 = 10–13 วัน, 4 = ทุกวัน) · คำถามที่ 1: ข้ออาหาร 3 ข้อ ได้แก่ ความถี่อาหารหวาน (Sugary food frequency, sugaryfoodfreq) อาหารมัน (Fatty food frequency, fattyfoodfreq) และอาหารเค็ม (Salty food frequency, saltyfoodfreq) รวมเป็นคะแนน "ความถี่อาหารเสี่ยง" คะแนนเดียวได้หรือไม่ · คำถามที่ 2: ข้อวิถีชีวิตทั้ง 9 ข้อ (สุรา บุหรี่ หมาก อาหาร 3 ข้อ การออกกำลังกายหนักและปานกลาง และงานอดิเรก) รวมเป็นคะแนนวิถีชีวิตคะแนนเดียวได้หรือไม่ · ผลที่คำนวณได้ด้านล่าง: α = 0.574 สำหรับอาหาร 3 ข้อ และ α = 0.319 สำหรับ 9 ข้อ
Example from the DAPH data (1,300 peritoneal-dialysis patients): nine lifestyle items, each scored 0–4 by the number of days in the past 14 days (0 = never, 1 = 1–4 days, 2 = 5–9 days, 3 = 10–13 days, 4 = every day). Question 1: can the three food items, Sugary food frequency (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

Cronbach's α (raw, from variances)
$$ \alpha = \frac{k}{k-1}\left(1 - \frac{\sum_{i=1}^{k} s_i^2}{s_T^2}\right),\qquad T = \sum_{i=1}^{k} x_i $$
Standardised α (from the average inter-item correlation)
$$ \alpha_{\text{std}} = \frac{k\,\bar{r}}{1 + (k-1)\,\bar{r}} $$
Corrected item–total correlation and α if item j is deleted
$$ r_{j} = \operatorname{cor}\bigl(x_j,\ T - x_j\bigr),\qquad \alpha_{(-j)} = \frac{k-1}{k-2}\left(1 - \frac{\sum_{i \ne j} s_i^2}{s_{T(-j)}^2}\right) $$
Feldt (1965) 95% confidence interval (computed in R; DAPH does not report it)
$$ \Bigl[\,1 - (1-\hat{\alpha})\,F_{0.975;\,n-1,\,(n-1)(k-1)},\ \ 1 - (1-\hat{\alpha})\,F_{0.025;\,n-1,\,(n-1)(k-1)}\,\Bigr] $$
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

R script คำถามที่ 1: อาหาร 3 ข้อ (แพ็กเกจ psych)question 1: the three food items (package psych)
# 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)
Expected R output (R 4.3.3)
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
R script คำถามที่ 2: ข้อวิถีชีวิต 9 ข้อ (ต่อจากสคริปต์ข้างบน แพ็กเกจ psych)question 2: the nine lifestyle items (continues the script above; package psych)
# 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)
Expected R output (R 4.3.3)
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
DAPH เมนู วิเคราะห์เพิ่มเติม > Cronbach's Alpha... · คำถามที่ 1 ติ๊ก Sugary food frequency, Fatty food frequency, Salty food frequency · คำถามที่ 2 ติ๊กข้อวิถีชีวิตทั้ง 9 ข้อ · กด Run Cronbach's Alpha (DAPH แสดง 4 ตำแหน่งทศนิยม)menu Additional Analysis > Cronbach's Alpha... · Question 1: tick Sugary food frequency, Fatty food frequency and Salty food frequency · Question 2: tick all nine lifestyle items · press Run Cronbach's Alpha (DAPH prints 4 decimals)
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
n (complete cases) · k1300 · 31300 · 30✓ PASS
คำถามที่ 1: α แบบดิบQuestion 1: raw α0.57430.5743< 0.00005✓ PASS
α แบบมาตรฐานstandardised α0.60150.6015< 0.00005✓ PASS
สหสัมพันธ์เฉลี่ยระหว่างข้อmean inter-item correlation0.33470.3347< 0.00005✓ PASS
คะแนนรวม: ค่าเฉลี่ย / ความแปรปรวน / SDtotal score: mean / variance / SD3.9592 / 6.5672 / 2.56273.9592 / 6.5672 / 2.5627< 0.00005✓ PASS
corrected item–total r: หวาน / มัน / เค็มcorrected item–total r: sugary / fatty / salty0.3493 / 0.4855 / 0.36230.3493 / 0.4855 / 0.3623< 0.00005✓ PASS
α เมื่อตัดข้อ: หวาน / มัน / เค็มα if deleted: sugary / fatty / salty0.5431 / 0.3858 / 0.51240.5431 / 0.3858 / 0.5124< 0.00005✓ PASS
SD รายข้อ: หวาน / มัน / เค็มitem SD: sugary / fatty / salty1.3035 / 0.8884 / 1.25071.3035 / 0.8884 / 1.2507< 0.00005✓ PASS
คำถามที่ 2: α แบบดิบ / แบบมาตรฐานQuestion 2: raw α / standardised α0.3188 / 0.34820.3188 / 0.3482< 0.00005✓ PASS
สหสัมพันธ์เฉลี่ยระหว่างข้อ (9 ข้อ)mean inter-item correlation (9 items)0.056020.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 / hobbies0.3788 / 0.3821 / 0.32980.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.

รูปแบบการรายงาน: "คะแนนความถี่อาหารเสี่ยง 3 ข้อ (อาหารหวาน มัน และเค็ม) มีความสอดคล้องภายในต่ำ (Cronbach's α = 0.57, 95% CI 0.53 ถึง 0.61 ตามวิธีของ Feldt; α แบบมาตรฐาน = 0.60; สหสัมพันธ์เฉลี่ยระหว่างข้อ 0.33; n = 1,300)"
How to report it: "Internal consistency of the three-item unhealthy-food frequency score (sugary, fatty and salty food) was low (Cronbach's α = 0.57, 95% CI 0.53 to 0.61 by Feldt's method; standardised α = 0.60; mean inter-item correlation 0.33; n = 1,300)."
📖 References
  1. Cronbach, L. J. (1951). Coefficient alpha and the internal structure of tests. Psychometrika, 16(3), 297–334. doi:10.1007/BF02310555
  2. Feldt, L. S. (1965). The approximate sampling distribution of Kuder-Richardson reliability coefficient twenty. Psychometrika, 30(3), 357–370. doi:10.1007/BF02289499
  3. Nunnally, J. C. (1978). Psychometric theory (2nd ed.). McGraw-Hill. ISBN 978-0-07-047465-9.
  4. 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
  5. 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.

ตัวอย่างทั้ง 20 รูปแบบ วางแผนการศึกษาใหม่ในผู้ป่วยล้างไตทางช่องท้อง ค่าวางแผนที่ข้อมูลนำร่องให้ได้ (SD สัดส่วน อัตราการเกิดเหตุการณ์ สหสัมพันธ์ และผลต่างที่พบ) นำมาจากข้อมูลตัวอย่าง DAPH (ผู้ป่วย 1,300 ราย CAPD และ APD) และคำนวณให้เห็นในสคริปต์ R ส่วนค่าที่ทีมวิจัยต้องกำหนดเอง (ผลต่างน้อยที่สุดที่มีความหมาย ความไม่ตรงกันของแบบคัดกรองสองชนิด ความแม่นยำเป้าหมาย) ระบุว่าเป็นสมมติฐาน · ข้อมูลตัวอย่างมีลักษณะเฉพาะสองข้อที่เกี่ยวข้อง: (1) คะแนนคุณภาพชีวิตสามครั้งของแต่ละคนต่างกันเกือบคงที่ สหสัมพันธ์จึงเป็น 0.9997 ซึ่งไม่สมจริง รูปแบบที่ต้องใช้สหสัมพันธ์ระหว่างการวัดซ้ำจึงใช้ค่าสมมติ ρ = 0.6 (2) กลุ่ม BMI ถูกแบ่งด้วยจุดตัดของเอเชียแม้ป้ายค่าจะระบุจุดตัดของ WHO
All 20 examples plan a new study of peritoneal-dialysis patients. Planning values that pilot data can supply (SDs, proportions, event rates, correlations, observed differences) are taken from the DAPH example data (1,300 patients, CAPD and APD) and computed in the R scripts; values the research team must choose (the smallest meaningful difference, the expected disagreement of two screening tools, the target precision) are labelled as assumptions. Two features of the example data matter: (1) each patient's three quality-of-life scores differ by an almost fixed amount, so their correlation is 0.9997, which is unrealistic, and designs that need a correlation between repeated measurements use an assumed ρ = 0.6; (2) the BMI groups are coded with the Asian cut-offs although the value labels quote the WHO cut-offs.

2หลักการและสูตรLogic and Formula

Normal quantiles used by every design based on the normal approximation
$$ z_{1-\alpha/2} = \Phi^{-1}(1-\alpha/2),\qquad z_{1-\beta} = \Phi^{-1}(1-\beta) $$
Rounding and the allowance for attrition
$$ n = \left\lceil n_{\text{formula}} \right\rceil,\qquad n_{\text{recruit}} = \left\lceil \frac{n}{1-d} \right\rceil $$
Power mode
$$ \text{Power}(N) = \max\bigl\{\,1-\beta \;:\; n(1-\beta) \le N \,\bigr\} $$
Φ⁻¹, α, 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.

R script บล็อกตั้งต้นของทุกหัวข้อย่อย (base R)set-up block for every sub-section (base R)
# 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
Expected R output (R 4.3.3)
[1] 1.959964 0.841621
[1] 112
DAPH จำนวนที่แนะนำเมื่อเผื่อการสูญหายร้อยละ 10: R ตามกฎ ⌈n/(1 − 0.10)⌉ (ค่า recruit ในผล R ของแต่ละหัวข้อย่อย) เทียบกับบรรทัด "แนะนำ (เผื่อข้อมูลสูญหาย 10% ตามสูตร n / (1 − 0.10))" ของ DAPHrecommended number with 10% attrition: R by the rule ⌈n/(1 − 0.10)⌉ (the recruit value in each sub-section's R output) against DAPH's line "Recommended (allowing for 10% dropout, n / (1 − 0.10))"
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
12.2.1 (n = 100)1121120✓ PASS
12.2.2 (n = 2626)291829180✓ PASS
12.2.3 (n = 80)89890✓ PASS
12.2.4 (n = 99)1101100✓ PASS
12.2.5 (n = 550)6126120✓ PASS
12.2.6 (n = 155)1731730✓ PASS
12.2.7 (n = 543)6046040✓ PASS
12.2.8 (n = 635)7067060✓ PASS
12.2.9 (n = 555)6176170✓ PASS
12.2.10 (n = 495)5505500✓ PASS
12.2.11 (n = 518)5765760✓ PASS
12.2.12 (n = 695)7737730✓ PASS
12.2.13 (n = 348)3873870✓ PASS
12.2.14 (n = 3824)424942490✓ PASS
12.2.15 (n = 50)56560✓ PASS
12.2.16 (n = 294)3273270✓ PASS
12.2.17 (n = 830)9239230✓ PASS
12.2.18 (n = 115)1281280✓ PASS
12.2.19 (n = 260)2892890✓ PASS
12.2.20 (n = 576)6406400✓ 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.

One-sample mean (normal approximation)
$$ n = \left(\frac{z_{1-\alpha/2} + z_{1-\beta}}{d}\right)^2,\qquad d = \frac{|\mu_1 - \mu_0|}{\sigma} $$
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.

d = |73.4 − 68.4| / 17.8 = 0.2809
n = ((1.959964 + 0.841621) / 0.2809)² = 99.47 → 100
โหมด power: N = 60 → power = 0.5855
Power mode: N = 60 → power = 0.5855
→ n = 100 คน (เผื่อสูญหายร้อยละ 10: 112 คน) · ถ้ามีเพียง 60 คน power = 58.6%
→ n = 100 patients (112 to recruit with 10% attrition); with only 60 patients the power is 58.6%.
R script ต้องรันบล็อกตั้งต้นในส่วนที่ 3 ก่อน (base R)run the set-up block in part 3 first (base R)
# 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)
Expected R output (R 4.3.3)
mean    sd 
68.36 17.85 
       d        n  recruit 
  0.2809 100.0000 112.0000 
[1] 0.5855
[1] 101.4111
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
d0.28090.2809< 0.00005✓ PASS
n1001000✓ PASS
power ที่ N = 60 คนpower at N = 600.58550.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)1002✗ FAIL
📖 อ้างอิงReferences
  1. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
  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
  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.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.

Two independent means (normal approximation)
$$ n_1 = \frac{(z_{1-\alpha/2} + z_{1-\beta})^2\,(1 + 1/r)}{d^2},\qquad n_2 = r\,n_1,\qquad d = \frac{|\mu_1 - \mu_2|}{\sigma} $$
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).

d = 1.95 / 17.83 = 0.1094
n1 = 7.8489 × 2 / 0.1094² = 1312.41 → 1313 = n2; total 2626
โหมด power: N = 800 → power = 0.3397
Power mode: N = 800 → power = 0.3397
→ กลุ่มละ 1,313 คน รวม 2,626 คน (เผื่อสูญหายร้อยละ 10: 2,918 คน) · ถ้ามีรวม 800 คน power = 34.0%
→ 1,313 per group, 2,626 in total (2,918 to recruit with 10% attrition); with 800 in total the power is 34.0%.

ผลต่างที่พบในข้อมูลนำร่อง (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.

R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R)continues the set-up block in part 3 (base R)
# 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)
Expected R output (R 4.3.3)
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
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
SD ร่วมจากข้อมูลpooled SD from the data17.83——✓ PASS
d0.10940.1094< 0.00005✓ PASS
n ต่อกลุ่ม / รวมn per group / total1313 / 26261313 / 26260✓ PASS
power ที่ N = 800 คนpower at N = 8000.33970.3397< 0.00005✓ PASS
n ต่อกลุ่มตามการแจกแจง t จริง (power.t.test)n per group from the exact t distribution (power.t.test)1314 (1313.38)13131✗ FAIL
📖 อ้างอิงReferences
  1. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
  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
  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.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).

Paired mean (normal approximation)
$$ n_{\text{pairs}} = \left(\frac{z_{1-\alpha/2} + z_{1-\beta}}{d_z}\right)^2,\qquad d_z = \frac{|\bar{\delta}|}{\sigma_{\delta}} $$
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.

σδ = 17.8 × √(2 × 0.4) = 15.92; dz = 5 / 15.92 = 0.3141
n = (2.801585 / 0.3141)² = 79.57 → 80 pairs
โหมด power: N = 50 คู่ → power = 0.6029
Power mode: N = 50 pairs → power = 0.6029
→ n = 80 คู่ (เผื่อสูญหายร้อยละ 10: 89 คู่) · ถ้ามี 50 คู่ power = 60.3%
→ n = 80 pairs (89 to recruit with 10% attrition); with 50 pairs the power is 60.3%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R)continues the set-up block in part 3 (base R)
# 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)
Expected R output (R 4.3.3)
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
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
σδ15.92——✓ PASS
dz0.31410.3141< 0.00005✓ PASS
จำนวนคู่number of pairs80800✓ PASS
power ที่ N = 50 คู่power at N = 50 pairs0.60290.6029< 0.00005✓ PASS
จำนวนคู่ตามการแจกแจง t จริง (power.t.test)pairs from the exact t distribution (power.t.test)82 (81.51)802✗ FAIL
📖 อ้างอิงReferences
  1. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
  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
  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.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.

One proportion (variance under H₀ for the α term, under H₁ for the β term)
$$ n = \left(\frac{z_{1-\alpha/2}\sqrt{p_0(1-p_0)} + z_{1-\beta}\sqrt{p_1(1-p_1)}}{p_1 - p_0}\right)^2 $$
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.

1.959964 × √(0.54 × 0.46) = 0.9768; 0.841621 × √(0.40 × 0.60) = 0.4123
n = ((0.9768 + 0.4123) / (0.40 − 0.54))² = 98.46 → 99
โหมด power: N = 80 → power = 0.7130
Power mode: N = 80 → power = 0.7130
→ n = 99 คน (เผื่อสูญหายร้อยละ 10: 110 คน) · ถ้ามี 80 คน power = 71.3%
→ n = 99 patients (110 to recruit with 10% attrition); with 80 patients the power is 71.3%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R)continues the set-up block in part 3 (base R)
# 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)
Expected R output (R 4.3.3)
[1] 0.54
      n recruit 
     99     110 
[1] 0.713
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
p0 จากข้อมูลfrom the data0.54——✓ PASS
n99990✓ PASS
power ที่ N = 80 คนpower at N = 800.7130.7130< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. Fleiss, J. L., Levin, B., & Paik, M. C. (2003). Statistical methods for rates and proportions (3rd ed.). Wiley. ISBN 978-0-471-52629-2.
  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
  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.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).

Two proportions without continuity correction (Fleiss et al. 2003)
$$ n_1 = \left(\frac{z_{1-\alpha/2}\sqrt{(1 + 1/r)\,\bar{p}(1-\bar{p})} + z_{1-\beta}\sqrt{p_1(1-p_1) + p_2(1-p_2)/r}}{p_1 - p_2}\right)^2,\qquad \bar{p} = \frac{p_1 + r\,p_2}{1 + r},\qquad n_2 = r\,n_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
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).

p̄ = (0.131 + 0.222) / 2 = 0.1765
1.959964 × √(2 × 0.1765 × 0.8235) = 1.0567; 0.841621 × √(0.131 × 0.869 + 0.222 × 0.778) = 0.4505
n1 = ((1.0567 + 0.4505) / (0.131 − 0.222))² = 274.34 → 275 = n2; total 550
โหมด power: N = 400 → power = 0.6664
Power mode: N = 400 → power = 0.6664
→ กลุ่มละ 275 คน รวม 550 คน (เผื่อสูญหายร้อยละ 10: 612 คน) · ถ้ามีรวม 400 คน power = 66.6%
→ 275 per group, 550 in total (612 to recruit with 10% attrition); with 400 in total the power is 66.6%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R: stats)continues the set-up block in part 3 (base R: stats)
# 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
Expected R output (R 4.3.3)
1      2 
0.1311 0.2220 
n_total recruit 
    550     612 
[1] 0.6664
[1] 274.3445
[1] 0.6664117
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
n ต่อกลุ่ม / รวมn per group / total275 / 550275 / 5500✓ PASS
power.prop.test (สูตรเดียวกัน) n ต่อกลุ่มpower.prop.test (same formula), n per group274.34 → 2752750✓ PASS
power ที่ N = 400 คนpower at N = 4000.66640.6664< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. Fleiss, J. L., Levin, B., & Paik, M. C. (2003). Statistical methods for rates and proportions (3rd ed.). Wiley. ISBN 978-0-471-52629-2.
  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
  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.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).

Matched pairs (Connor 1987)
$$ n_{\text{pairs}} = \frac{\bigl(z_{1-\alpha/2}\sqrt{p_d} + z_{1-\beta}\sqrt{p_d - \delta^2}\bigr)^2}{\delta^2},\qquad p_d = p_{10} + p_{01},\qquad \delta = p_{10} - p_{01} $$
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.

pd = 0.20, δ = 0.10; 1.959964 × √0.20 = 0.8765; 0.841621 × √(0.20 − 0.01) = 0.3669
n = (0.8765 + 0.3669)² / 0.01 = 154.60 → 155 pairs
โหมด power: N = 100 คู่ → power = 0.6115
Power mode: N = 100 pairs → power = 0.6115
→ n = 155 คู่ (เผื่อสูญหายร้อยละ 10: 173 คู่) · ถ้ามี 100 คู่ power = 61.2%
→ n = 155 pairs (173 to recruit with 10% attrition); with 100 pairs the power is 61.2%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R)continues the set-up block in part 3 (base R)
# 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)
Expected R output (R 4.3.3)
n_pairs recruit 
    155     173 
[1] 0.6115
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
จำนวนคู่number of pairs1551550✓ PASS
power ที่ N = 100 คู่power at N = 100 pairs0.61150.6115< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. 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
  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.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.

Fisher z transformation
$$ n = \left(\frac{z_{1-\alpha/2} + z_{1-\beta}}{\frac{1}{2}\ln\frac{1+|r|}{1-|r|}}\right)^2 + 3 $$
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.

½ ln(1.12 / 0.88) = 0.1206
n = (2.801585 / 0.1206)² + 3 = 539.82 + 3 = 542.82 → 543
โหมด power: N = 300 → power = 0.5470
Power mode: N = 300 → power = 0.5470
→ n = 543 คน (เผื่อสูญหายร้อยละ 10: 604 คน) · ถ้ามี 300 คน power = 54.7%
→ n = 543 (604 to recruit with 10% attrition); with 300 patients the power is 54.7%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R และ pwr)continues the set-up block in part 3 (base R and pwr)
# 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
Expected R output (R 4.3.3)
[1] -0.1243
      n recruit 
    543     604 
[1] 0.547
[1] 541.9252
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
n5435430✓ PASS
power ที่ N = 300 คนpower at N = 3000.5470.5470< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
  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
  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.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).

Smallest N whose power reaches 1 − β (non-central F)
$$ \text{Power}(N) = \Pr\bigl(F_{k,\,N-k-1}(\lambda) > F_{1-\alpha;\,k,\,N-k-1}\bigr),\qquad \lambda = N f^2,\qquad f^2 = \frac{R^2}{1-R^2} $$
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.

f² = 0.02 / 0.98 = 0.0204
N ที่น้อยที่สุดที่ power ≥ 0.80 คือ 635 (pwr.f2.test ให้ค่าเดียวกัน)
the smallest N with power ≥ 0.80 is 635 (pwr.f2.test agrees)
โหมด power: N = 400 → power = 0.5675
Power mode: N = 400 → power = 0.5675
→ n = 635 คน (เผื่อสูญหายร้อยละ 10: 706 คน) · ถ้ามี 400 คน power = 56.8%
→ n = 635 (706 to recruit with 10% attrition); with 400 patients the power is 56.8%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R และ pwr)continues the set-up block in part 3 (base R and pwr)
# 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
Expected R output (R 4.3.3)
[1] 0.0202
      f2        n  recruit 
  0.0204 635.0000 706.0000 
[1] 0.5675048
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
f²0.02040.0204< 0.00005✓ PASS
n6356350✓ PASS
power ที่ N = 400 คนpower at N = 4000.56750.5675< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
  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.

Binary predictor (Hsieh et al. 1998, eq. 2)
$$ n = \frac{\bigl(z_{1-\alpha/2}\sqrt{\bar{P}(1-\bar{P})/B} + z_{1-\beta}\sqrt{P_1(1-P_1) + P_2(1-P_2)(1-B)/B}\bigr)^2}{(P_1 - P_2)^2\,(1-B)} $$
Continuous predictor, odds ratio per 1 SD (Hsieh et al. 1998, eq. 1)
$$ n = \frac{(z_{1-\alpha/2} + z_{1-\beta})^2}{\bar{P}(1-\bar{P})\,(\ln\mathrm{OR}^{*})^2},\qquad \ln\mathrm{OR}^{*} = \ln\mathrm{OR}_{\text{unit}}\times\sigma_X $$
Adjustment for other covariates and the events-per-variable floor
$$ n_{\text{adj}} = \frac{n}{1-\rho^2},\qquad n_{\text{EPV}} = \frac{10\,k}{\bar{P}},\qquad n_{\text{final}} = \max(n_{\text{adj}},\ n_{\text{EPV}}) $$
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.

P1 = 0.1307 and P2 = 0.2213 (0.5 × P1 + 0.5 × P2 = 0.176, odds ratio 1.89)
n (eq. 2) = 553; nadj = 553 / (1 − 0.06²) = 555.00 → 555; nEPV = 10 × 5 / 0.176 = 284.09 → 285
nfinal = 555 (มีเหตุการณ์ ⌈555 × 0.176⌉ = 98 ครั้ง, EPV = 19.6) · โหมด power: N = 600 → power = 0.8297
nfinal = 555 (⌈555 × 0.176⌉ = 98 events, EPV = 19.6); power mode: N = 600 → power = 0.8297
→ n = 555 คน (เผื่อสูญหายร้อยละ 10: 617 คน) · ถ้ามี 600 คน power = 83.0% และผ่านเกณฑ์ EPV
→ n = 555 (617 to recruit with 10% attrition); with 600 patients the power is 83.0% and the EPV floor is met.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R)continues the set-up block in part 3 (base R)
# 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)
Expected R output (R 4.3.3)
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
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
P1 / P20.1307 / 0.22130.1307 / 0.2213< 0.00005✓ PASS
n สมการ 2 / nadj / nEPVn eq. 2 / nadj / nEPV553 / 555 / 285553 / 555 / 2850✓ PASS
n สุดท้ายfinal n5555550✓ PASS
power ที่ N = 600 คนpower at N = 6000.82970.8297< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. 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
  2. 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
  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).

Smallest equal group size whose power reaches 1 − β (non-central F)
$$ \text{Power} = \Pr\bigl(F_{k-1,\,N-k}(\lambda) > F_{1-\alpha;\,k-1,\,N-k}\bigr),\qquad \lambda = N f^2,\qquad N = k\,n $$
Cohen's f
$$ f = \frac{\sigma_{\mu}}{\sigma} = \sqrt{\frac{\eta^2}{1-\eta^2}} $$
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).

λ = N × 0.14² = 0.0196 N
n ต่อกลุ่มที่น้อยที่สุดที่ power ≥ 0.80 คือ 165 (N = 495; pwr.anova.test ให้ค่าเดียวกัน)
the smallest n per group with power ≥ 0.80 is 165 (N = 495; pwr.anova.test agrees)
โหมด power: N = 300 → power = 0.5703
Power mode: N = 300 → power = 0.5703
→ กลุ่มละ 165 คน รวม 495 คน (เผื่อสูญหายร้อยละ 10: 550 คน) · ถ้ามีรวม 300 คน power = 57.0%
→ 165 per group, 495 in total (550 to recruit with 10% attrition); with 300 in total the power is 57.0%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R และ pwr)continues the set-up block in part 3 (base R and pwr)
# 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
Expected R output (R 4.3.3)
[1] 0.136
n_per_group           n     recruit 
        165         495         550 
[1] 0.5702882
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
n ต่อกลุ่ม / รวมn per group / total165 / 495165 / 4950✓ PASS
power ที่ N = 300 คนpower at N = 3000.57030.5703< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
  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).

Required events and sample size (Schoenfeld 1983)
$$ D = \frac{(z_{1-\alpha/2} + z_{1-\beta})^2}{\pi(1-\pi)\,(\ln\mathrm{HR})^2},\qquad n = \frac{D}{\bar{e}} $$
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.

(ln 1.8)² = 0.3455
D = 7.8489 / (0.25 × 0.3455) = 90.87 → 91 events; n = 91 / 0.176 = 517.05 → 518
โหมด power: N = 400 → power = 0.6911
Power mode: N = 400 → power = 0.6911
→ ต้องการ 91 เหตุการณ์ หรือ 518 คน (เผื่อสูญหายร้อยละ 10: 576 คน) · ถ้ามี 400 คน power = 69.1%
→ 91 events, i.e. 518 patients (576 to recruit with 10% attrition); with 400 patients the power is 69.1%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R และ survival)continues the set-up block in part 3 (base R and survival)
# 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)
Expected R output (R 4.3.3)
I(group == 2)TRUE 
           1.8026 
event_rate allocation 
    0.1762     0.4954 
 events       n recruit 
     91     518     576 
[1] 0.6911
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
จำนวนเหตุการณ์ Devents D91910✓ PASS
n5185180✓ PASS
power ที่ N = 400 คนpower at N = 4000.69110.6911< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. Schoenfeld, D. A. (1983). Sample-size formula for the proportional-hazards regression model. Biometrics, 39(2), 499–503. doi:10.2307/2531021
  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
  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.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.

Diseased and non-diseased needed for the precision w (Buderer 1996)
$$ n_{D+} = \frac{z_{1-\alpha/2}^2\,\mathrm{Se}(1-\mathrm{Se})}{w^2},\qquad n_{D-} = \frac{z_{1-\alpha/2}^2\,\mathrm{Sp}(1-\mathrm{Sp})}{w^2} $$
Total sample
$$ n = \max\left(\frac{n_{D+}}{\text{prev}},\ \frac{n_{D-}}{1-\text{prev}}\right) $$
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).

nD+ = 1.959964² × 0.09 / 0.0025 = 138.29 → 139; 139 / 0.20 = 695
nD− = 139; 139 / 0.80 = 173.75 → 174
n = max(695, 174) = 695
→ n = 695 คน (ผู้ป่วยที่เป็นโรคประมาณ 139 คน; เผื่อสูญหายร้อยละ 10: 773 คน)
→ n = 695 (about 139 with the condition; 773 to recruit with 10% attrition).
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R และ epiR)continues the set-up block in part 3 (base R and epiR)
# 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)
Expected R output (R 4.3.3)
n_diseased n_non_diseased      from_sens      from_spec              n        recruit 
           139            139            695            174            695            773 
[1] 691.4626
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
nD+ / nD−139 / 139139 / 1390✓ PASS
n จากความไว / จากความจำเพาะn from sensitivity / from specificity695 / 174695 / 1740✓ PASS
n6956950✓ PASS
📖 อ้างอิงReferences
  1. 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
  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.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).

Total sample (Whitehead 1993)
$$ N = \frac{3\,(z_{1-\alpha/2} + z_{1-\beta})^2}{A\,\bigl(1 - \sum_j \bar{p}_j^{\,3}\bigr)\,(\ln\mathrm{OR})^2},\qquad A = \pi(1-\pi) $$
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.

Σ p̄j³ = 0.2426; 1 − Σ p̄j³ = 0.7574; (ln 0.55)² = 0.3574
N = 3 × 7.8489 / (0.25 × 0.7574 × 0.3574) = 347.94 → 348
โหมด power: N = 250 → power = 0.6609
Power mode: N = 250 → power = 0.6609
→ N = 348 คน (เผื่อสูญหายร้อยละ 10: 387 คน) · ถ้ามี 250 คน power = 66.1%
→ N = 348 (387 to recruit with 10% attrition); with 250 patients the power is 66.1%.

ฟังก์ชัน 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.

R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R, MASS และ Hmisc)continues the set-up block in part 3 (base R, MASS and Hmisc)
# 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)
Expected R output (R 4.3.3)
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
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
N3483480✓ PASS
Hmisc::posamsizeHmisc::posamsize347.9 → 3483480✓ PASS
power ที่ N = 250 คนpower at N = 2500.66090.6609< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. Whitehead, J. (1993). Sample size calculations for ordered categorical data. Statistics in Medicine, 12(24), 2257–2271. doi:10.1002/sim.4780122404
  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.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.

Per contrast j versus the reference (DAPH approximation)
$$ N_j = \frac{(z_{1-\alpha^{*}/2} + z_{1-\beta})^2\,(p_{\text{ref}} + p_j)}{\lambda(1-\lambda)\,p_{\text{ref}}\,p_j\,(\ln\mathrm{OR}_j)^2},\qquad \alpha^{*} = \frac{\alpha}{J-1},\qquad N = \max_j N_j $$
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.

α* = 0.05 / 3 = 0.01667; z1−α*/2 = 2.3940; (2.3940 + 0.841621)² = 10.469
Nunderweight = 1166; Noverweight = 3824; Nobese = 3794 → N = 3824
โหมด power: N = 2,500 → power = 0.5880
Power mode: N = 2,500 → power = 0.5880
→ N = 3,824 คน (เผื่อสูญหายร้อยละ 10: 4,249 คน) · ถ้ามี 2,500 คน power = 58.8%
→ N = 3,824 (4,249 to recruit with 10% attrition); with 2,500 patients the power is 58.8%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R)continues the set-up block in part 3 (base R)
# 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)
Expected R output (R 4.3.3)
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
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
N ต่อการเปรียบเทียบ (ผอม / น้ำหนักเกิน / อ้วน)N per contrast (underweight / overweight / obese)1166 / 3824 / 37941166 / 3824 / 37940✓ PASS
N382438240✓ PASS
power ที่ N = 2500 คนpower at N = 25000.5880.5880< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. 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
  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.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).

Poisson regression as DAPH computes it (variance under H₀ in both terms)
$$ n = \frac{(z_{1-\alpha/2} + z_{1-\beta})^2}{\mu_0\,\sigma_X^2\,(\ln\mathrm{IRR})^2} $$
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.

(ln 0.44)² = 0.6740
n = 7.8489 / (0.94 × 0.25 × 0.6740) = 49.55 → 50
โหมด power: N = 40 → power = 0.7113
Power mode: N = 40 → power = 0.7113
→ n = 50 คน (เผื่อสูญหายร้อยละ 10: 56 คน) · ถ้ามี 40 คน power = 71.1%
→ n = 50 (56 to recruit with 10% attrition); with 40 patients the power is 71.1%.

ข้อควรระวัง: สูตรเต็มของ 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.

R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R)continues the set-up block in part 3 (base R)
# 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
Expected R output (R 4.3.3)
rate_CAPD  rate_APD       IRR 
   0.9406    0.4134    0.4395 
      n recruit 
     50      56 
[1] 0.7113
[1] 59
[1] 1.886
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
n50500✓ PASS
power ที่ N = 40 คนpower at N = 400.71130.7113< 0.00005✓ PASS
n ตาม Signorini (1991) ที่ใช้ความแปรปรวนภายใต้ H₁ ในพจน์ของ powern by Signorini (1991) with the variance under H₁ in the power term59509✗ FAIL
📖 อ้างอิงReferences
  1. Signorini, D. F. (1991). Sample size for Poisson regression. Biometrika, 78(2), 446–450. doi:10.1093/biomet/78.2.446
  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.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).

Two groups, time-averaged difference (Diggle et al. 2002)
$$ n_{\text{per group}} = \frac{2\,(z_{1-\alpha/2} + z_{1-\beta})^2\,\bigl(1 + (T-1)\rho\bigr)}{T\,d^2} $$
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.

1 + (3 − 1) × 0.6 = 2.2
n = 2 × 7.8489 × 2.2 / (3 × 0.28²) = 146.83 → 147 per group; total 294
โหมด power: N = 200 → power = 0.6376
Power mode: N = 200 → power = 0.6376
→ กลุ่มละ 147 คน รวม 294 คน (เผื่อสูญหายร้อยละ 10: 327 คน) · ถ้ามีรวม 200 คน power = 63.8%
→ 147 per group, 294 in total (327 to recruit with 10% attrition); with 200 in total the power is 63.8%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R)continues the set-up block in part 3 (base R)
# 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)
Expected R output (R 4.3.3)
factor n_per_group           n     recruit 
        2.2       147.0       294.0       327.0 
[1] 0.6376
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
ตัวคูณ 1 + (T − 1)ρfactor 1 + (T − 1)ρ2.22.20✓ PASS
n ต่อกลุ่ม / รวมn per group / total147 / 294147 / 2940✓ PASS
power ที่ N = 200 คนpower at N = 2000.63760.6376< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. 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.
  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.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.

Design effect
$$ \mathrm{DEFF} = 1 + (m-1)\,\mathrm{ICC},\qquad n_{\text{iid}} = \frac{2\,(z_{1-\alpha/2} + z_{1-\beta})^2}{d^2}\ \text{per group} $$
Clustered sample
$$ N = g\,n_{\text{iid}}\,\mathrm{DEFF},\qquad \text{clusters per group} = \frac{n_{\text{iid}}\,\mathrm{DEFF}}{m} $$
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.

DEFF = 1 + 19 × 0.056 = 2.064; niid = 2 × 7.8489 / 0.28² = 200.23 → 201 per arm
N = 2 × 201 × 2.064 = 829.73 → 830; per arm 201 × 2.064 = 414.86 → 415; 415 / 20 = 20.75 → 21 clusters per arm (42 in total)
โหมด power: N = 600 → power = 0.6643
Power mode: N = 600 → power = 0.6643
→ N = 830 คน ใน 42 คลินิก (กลุ่มละ 21 คลินิก; เผื่อสูญหายร้อยละ 10: 923 คน) · ถ้ามี 600 คน power = 66.4%
→ N = 830 patients in 42 clinics (21 per arm; 923 to recruit with 10% attrition); with 600 patients the power is 66.4%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R และ lme4)continues the set-up block in part 3 (base R and lme4)
# 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)
Expected R output (R 4.3.3)
[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
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
DEFF2.0642.0640✓ PASS
niid ต่อกลุ่มniid per arm2012010✓ PASS
N8308300✓ PASS
กลุ่มก้อนต่อกลุ่ม / รวมclusters per arm / total21 / 4221 / 420✓ PASS
power ที่ N = 600 คนpower at N = 6000.66430.6643< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. Donner, A., & Klar, N. (2000). Design and analysis of cluster randomization trials in health research. Arnold. ISBN 978-0-340-69153-3.
  2. Eldridge, S., & Kerry, S. (2012). A practical guide to cluster randomised trials in health services research. Wiley. doi:10.1002/9781119966241
  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.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).

Effect size and non-centrality
$$ w = \sqrt{\sum \frac{(p_{1i} - p_{0i})^2}{p_{0i}}},\qquad \lambda = N w^2 $$
Power
$$ \text{Power} = \Pr\bigl(\chi^2_{df}(\lambda) > \chi^2_{1-\alpha;\,df}\bigr) $$
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.

λ = 0.29² × N = 0.0841 N
N ที่น้อยที่สุดที่ power ≥ 0.80 คือ 115 (pwr.chisq.test ให้ค่าเดียวกัน)
the smallest N with power ≥ 0.80 is 115 (pwr.chisq.test agrees)
โหมด power: N = 80 → power = 0.6369
Power mode: N = 80 → power = 0.6369
→ N = 115 คน (เผื่อสูญหายร้อยละ 10: 128 คน) · ถ้ามี 80 คน power = 63.7%
→ N = 115 (128 to recruit with 10% attrition); with 80 patients the power is 63.7%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R และ pwr)continues the set-up block in part 3 (base R and pwr)
# 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
Expected R output (R 4.3.3)
group
episodes   1   2
      0  233 365
      1  142 171
      2+ 281 108
X-squared 
   0.2891 
      n recruit 
    115     128 
[1] 0.6369359
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
w จากข้อมูลfrom the data0.2891——✓ PASS
N1151150✓ PASS
power ที่ N = 80 คนpower at N = 800.63690.6369< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
  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).

Unadjusted two-sample size
$$ n_t = \frac{2\,(z_{1-\alpha/2} + z_{1-\beta})^2}{d^2} $$
ANCOVA design factor (Borm et al. 2007)
$$ n_{\text{per group}} = (1-\rho^2)\,n_t + k $$
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.

nt = 2 × 7.8489 / 0.28² = 200.23 → 201
n = 0.64 × 201 + 1 = 129.64 → 130 per group; total 260 (402 without adjustment)
โหมด power: N = 200 → power = 0.6904
Power mode: N = 200 → power = 0.6904
→ กลุ่มละ 130 คน รวม 260 คน (เผื่อสูญหายร้อยละ 10: 289 คน) · ถ้ามีรวม 200 คน power = 69.0%
→ 130 per group, 260 in total (289 to recruit with 10% attrition); with 200 in total the power is 69.0%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R)continues the set-up block in part 3 (base R)
# 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)
Expected R output (R 4.3.3)
n_ttest_per_group       n_per_group                 n           recruit 
              201               130               260               289 
[1] 0.6904
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
nt2012010✓ PASS
n ต่อกลุ่ม / รวมn per group / total130 / 260130 / 2600✓ PASS
power ที่ N = 200 คนpower at N = 2000.69040.6904< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. 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
  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.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.

Discordant pairs required (Schlesselman 1982)
$$ \psi = \frac{\mathrm{OR}}{1 + \mathrm{OR}},\qquad m = \frac{\bigl(z_{1-\alpha/2}/2 + z_{1-\beta}\sqrt{\psi(1-\psi)}\bigr)^2}{(\psi - 0.5)^2} $$
Probability that a pair is discordant
$$ p_1 = \frac{\mathrm{OR}\,p_0}{1 + p_0(\mathrm{OR} - 1)},\qquad p_d = p_0(1 - p_1) + p_1(1 - p_0) $$
Pairs, and 1:M matching (Ury 1975)
$$ n_{\text{pairs}} = \frac{m}{p_d},\qquad n_{\text{cases}} = n_{\text{pairs}}\cdot\frac{M + 1}{2M},\qquad n_{\text{controls}} = M\cdot n_{\text{cases}} $$
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).

ψ = 1.6 / 2.6 = 0.6154; m = (0.979982 + 0.841621 × √(0.6154 × 0.3846))² / 0.1154² = 145.00
p1 = 1.6 × 0.48 / (1 + 0.48 × 0.6) = 0.5963; pd = 0.48 × 0.4037 + 0.5963 × 0.52 = 0.5039
npairs = 145.00 / 0.5039 = 287.79 → 288 pairs (576 people)
โหมด power: N = 400 → power = 0.6430
Power mode: N = 400 → power = 0.6430
→ 288 คู่ (case 288 + control 288 = 576 คน; เผื่อสูญหายร้อยละ 10: 640 คน) · ถ้ามี 400 คน power = 64.3%
→ 288 pairs (288 cases + 288 controls = 576; 640 to recruit with 10% attrition); with 400 people the power is 64.3%.
R script ต่อจากบล็อกตั้งต้นในส่วนที่ 3 (base R และ epiR)continues the set-up block in part 3 (base R and epiR)
# 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)
Expected R output (R 4.3.3)
p0     OR 
0.4818 1.6017 
n_pairs       n recruit 
    288     576     640 
[1] 0.643
[1] 576
DAPH เมนู วิเคราะห์เพิ่มเติม > คำนวณขนาดตัวอย่าง... ใส่ค่าตามโจทย์ (α = 0.05, power 0.80, สองด้านเมื่อมีตัวเลือก) ทั้งโหมด ขนาดตัวอย่าง (n) และโหมด อำนาจการทดสอบ (Power)menu Additional Analysis > Sample Size Calculation..., inputs as in the scenario (α = 0.05, power 0.80, two-sided where offered), in both the Sample size (n) and the Power of test modes
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
จำนวนคู่ / รวมpairs / total288 / 576288 / 5760✓ PASS
epiR::epi.sscc (Dupont 1988) รวมepiR::epi.sscc (Dupont 1988) total5765760✓ PASS
power ที่ N = 400 คนpower at N = 4000.6430.6430< 0.00005✓ PASS
📖 อ้างอิงReferences
  1. Dupont, W. D. (1988). Power calculations for matched case-control studies. Biometrics, 44(4), 1157–1168. doi:10.2307/2531743
  2. Schlesselman, J. J. (1982). Case-control studies: Design, conduct, analysis. Oxford University Press. ISBN 978-0-19-502933-8.
  3. 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
  4. 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.

รูปแบบการรายงาน (จาก 12.2.5): "เมื่อกำหนดสัดส่วนการเสียชีวิตระหว่างติดตามเท่ากับร้อยละ 13.1 ในกลุ่ม CAPD และร้อยละ 22.2 ในกลุ่ม APD (จากข้อมูลนำร่อง) ระดับนัยสำคัญ 0.05 แบบสองด้าน และอำนาจการทดสอบร้อยละ 80 ต้องใช้ผู้ป่วยกลุ่มละ 275 คน รวม 550 คน (สูตรเปรียบเทียบสองสัดส่วนของ Fleiss et al., 2003) เมื่อเผื่อการสูญหายร้อยละ 10 จะรับผู้ป่วย 612 คน คำนวณด้วยโปรแกรม DAPH"
How to report it (from 12.2.5): "Assuming that 13.1% of CAPD and 22.2% of APD patients die during follow-up (pilot data), 275 patients per group (550 in total) give 80% power at a two-sided significance level of 0.05 (two-proportion formula of Fleiss et al., 2003). Allowing for 10% attrition, 612 patients will be recruited. The calculation was done in DAPH."
📖 References
  1. Cohen, J. (1988). Statistical power analysis for the behavioral sciences (2nd ed.). Lawrence Erlbaum Associates. ISBN 978-0-8058-0283-2.
  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.
  3. 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
  4. 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.

ตรวจแบบจำลอง Enter ของหัวข้อ 1.12 (คะแนนคุณภาพชีวิตหลังการรักษา กับอายุ เพศ กลุ่มการรักษา ดัชนีมวลกาย โรคเรื้อรัง และรายได้ครัวเรือน n = 1,300) · ผล: ส่วนเหลือไม่แจกแจงปกติ (Shapiro-Wilk W = 0.9746, p < 0.001) · ความแปรปรวนไม่คงที่ (Breusch-Pagan = 16.282, p = 0.023) · Durbin-Watson = 0.117 (เป็นผลจากการเรียงแถวของไฟล์ ไม่ใช่ข้อมูลอนุกรมเวลา) · VIF ทุกตัวต่ำกว่า 5 · Cook's distance สูงสุด 0.0196 มี 59 คนเกินเส้น 4/n และไม่มีคนใดเกิน 1
Checking the Enter model of section 1.12 (post-treatment quality-of-life score on age, gender, treatment group, body mass index, chronic disease and household income, n = 1,300). Results: residuals not normal (Shapiro-Wilk W = 0.9746, p < 0.001); variance not constant (Breusch-Pagan = 16.282, p = 0.023); Durbin-Watson = 0.117 (a result of the file's row order, not time-series data); every VIF below 5; the largest Cook's distance is 0.0196, 59 patients lie above the 4/n line and none above 1.

2หลักการและสูตรLogic and Formula

Normality of the residuals
$$ W = \frac{\bigl(\sum_{i=1}^{n} a_i\, e_{(i)}\bigr)^{2}}{\sum_{i=1}^{n}(e_i-\bar{e})^{2}}\quad(\text{Shapiro-Wilk}),\qquad JB = \frac{n}{6}\Bigl(S^{2} + \frac{(K-3)^{2}}{4}\Bigr)\sim\chi^{2}_{2}\quad(\text{Jarque-Bera, used when } n > 5000) $$
Constant variance: studentized Breusch-Pagan (Koenker) test
$$ e_i^{2} = \gamma_0 + \gamma_1 X_{1i} + \dots + \gamma_p X_{pi} + u_i,\qquad BP = n\,R^{2}_{\text{aux}} \sim \chi^{2}_{p} $$
Durbin-Watson
$$ DW = \frac{\sum_{i=2}^{n}(e_i - e_{i-1})^{2}}{\sum_{i=1}^{n} e_i^{2}} \approx 2(1-\hat{\rho}_1) $$
Multicollinearity: VIF, and GVIF for a variable with several dummies
$$ \mathrm{VIF}_j = \frac{1}{1-R_j^{2}},\qquad \mathrm{GVIF}_j = \frac{\det \mathbf{R}_{jj}\,\det \mathbf{R}_{-j}}{\det \mathbf{R}} $$
Leverage, studentized residual and Cook's distance
$$ h_{ii} = \bigl[X(X^{\top}X)^{-1}X^{\top}\bigr]_{ii},\quad \sum_i h_{ii} = k,\qquad t_i = \frac{e_i}{s_{(i)}\sqrt{1-h_{ii}}},\qquad D_i = \frac{e_i^{2}}{k\,s^{2}}\cdot\frac{h_{ii}}{(1-h_{ii})^{2}} $$
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

R script R base, lmtest, carbase R, lmtest, car
# 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))
Expected R output (R 4.3.3, abridged)
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
DAPH Linear regression แบบ Enter ของหัวข้อ 1.12 · ค่าจากหัวข้อ "การตรวจสอบข้อสมมติ" ใน Tab 3 แผนภาพ Q-Q Plot และ Cook's Distance และค่าที่ engine คำนวณthe Enter linear regression of section 1.12 · values from the Tab 3 "Assumption Checking" block, the Q-Q Plot and Cook's Distance charts, and the engine's own values
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
Shapiro-Wilk of residuals: W / p0.97464 / 2.429e−14W = 0.9746, p < 0.001 (engine 2.429e−14)< 1e−9✓ PASS
Breusch-Pagan (studentized): statistic / df / p16.282 / 7 / 0.02266LM = 16.282 / p = 0.023 (engine df 7)< 1e−9✓ PASS
Durbin-Watson (file order)0.11738360.117< 1e−12✓ PASS
VIF, predictors as numeric codes (DAPH's method): age / gender / group / BMI / chronic / income1.080539 / 1.019343 / 1.006014 / 1.088001 / 1.038340 / 1.007242all ≤ 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.0113171.080539 / 1.038340 / 1.0072420.0012 / 0.0024 / 0.0041✗ FAIL
Cook's distance: 4/n line / patients above it / largest D0.003076923 / 59 / 0.019631454Threshold = 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 D0.97586948 / 65 / 0.01104491W=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
  1. 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
  2. Cook, R. D. (1977). Detection of influential observation in linear regression. Technometrics, 19(1), 15–18. doi:10.1080/00401706.1977.10489493
  3. 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
  4. Fox, J., & Monette, G. (1992). Generalized collinearity diagnostics. Journal of the American Statistical Association, 87(417), 178–183. doi:10.1080/01621459.1992.10475190
  5. 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
  6. 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
  7. 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
  8. 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
  9. 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.

ตัวอย่างจากข้อมูล DAPH (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย) ไม่มีผู้ประเมินสองคน จึงใช้การวัดซ้ำในคนเดียวกันแทน · คำถามที่ 1 (kappa): การจัดกลุ่ม "คุณภาพชีวิตสูง" (คะแนนเกิน 60) ก่อนการรักษา (QoL Group (Pre), qol_g1) และระหว่างการรักษา (QoL Group (Mid), qol_g2) ตรงกันมากน้อยเพียงใด · คำถามที่ 2 (ICC): คะแนนคุณภาพชีวิตก่อน ระหว่าง และหลังการรักษา (qolscore1, qolscore2, qolscore3) ซึ่งถือเป็นการวัดสามครั้งของคนเดียวกัน สอดคล้องกันเพียงใด · เนื่องจาก "ผู้ประเมิน" ในตัวอย่างนี้คือการวัดสามครั้งระหว่างการรักษา การเปลี่ยนแปลงของคะแนนระหว่างครั้งจึงนับเป็นความไม่ตรงกันด้วย และคะแนนของแต่ละคนในข้อมูลตัวอย่างต่างกันเกือบคงที่ทุกคน (r = 0.9997) ตัวอย่างนี้จึงแสดงความต่างระหว่าง "ความสอดคล้องของลำดับ" กับ "ความตรงกันของค่า" ได้ชัด (ตัวแปร qol_g3 ไม่ได้ใช้ เพราะรหัส 1 ของตัวแปรนี้คือคะแนนต่ำ ซึ่งกลับกับป้ายชื่อ)
Example from the DAPH data (1,300 peritoneal-dialysis patients). The data have no two raters, so repeated measurements of the same patients stand in for them. Question 1 (kappa): how well does the "high quality of life" classification (score above 60) agree between the pre-treatment (QoL Group (Pre), 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

Cohen's kappa and weighted kappa
$$ \kappa = \frac{p_o - p_e}{1 - p_e},\qquad p_o = \sum_i p_{ii},\qquad p_e = \sum_i p_{i\cdot}\,p_{\cdot i},\qquad \kappa_w = \frac{\sum_{ij} w_{ij}p_{ij} - \sum_{ij} w_{ij}p_{i\cdot}p_{\cdot j}}{1 - \sum_{ij} w_{ij}p_{i\cdot}p_{\cdot j}} $$ $$ w_{ij} = 1 - \frac{|i-j|}{q-1}\ \text{(linear)},\qquad w_{ij} = 1 - \left(\frac{i-j}{q-1}\right)^{2}\ \text{(quadratic)} $$
Standard errors: under H₀ for the z test, Fleiss, Cohen & Everitt (1969) for the 95% CI
$$ z = \frac{\kappa}{SE_0},\qquad SE_0 = \frac{\sqrt{p_e + p_e^2 - \sum_i p_{i\cdot}p_{\cdot i}(p_{i\cdot} + p_{\cdot i})}}{(1-p_e)\sqrt{n}} $$ $$ SE_{\text{FCE}}^2 = \frac{\sum_i p_{ii}\bigl[1 - (p_{i\cdot} + p_{\cdot i})(1-\kappa)\bigr]^2 + (1-\kappa)^2\sum_{i\ne j} p_{ij}(p_{\cdot i} + p_{j\cdot})^2 - \bigl[\kappa - p_e(1-\kappa)\bigr]^2}{n(1-p_e)^2} $$
ICC from the two-way ANOVA mean squares (Shrout & Fleiss 1979)
$$ \text{ICC}(1,1) = \frac{MS_B - MS_W}{MS_B + (k-1)MS_W},\quad \text{ICC}(2,1) = \frac{MS_B - MS_E}{MS_B + (k-1)MS_E + \frac{k}{n}(MS_R - MS_E)},\quad \text{ICC}(3,1) = \frac{MS_B - MS_E}{MS_B + (k-1)MS_E} $$
95% CI: ICC(1,1) and ICC(3,1) from F; ICC(2,1) with Satterthwaite degrees of freedom v (McGraw & Wong 1996)
$$ F_L = \frac{F}{F_{0.975;\,df_1,df_2}},\quad F_U = F\cdot F_{0.975;\,df_2,df_1},\quad \Bigl[\tfrac{F_L - 1}{F_L + k - 1},\ \tfrac{F_U - 1}{F_U + k - 1}\Bigr],\qquad F = \tfrac{MS_B}{MS_W}\ \text{or}\ \tfrac{MS_B}{MS_E} $$ $$ v = \frac{(a\,MS_R + b\,MS_E)^2}{\frac{(a\,MS_R)^2}{k-1} + \frac{(b\,MS_E)^2}{(n-1)(k-1)}},\quad a = \frac{k\,\widehat{\text{ICC}}}{n(1-\widehat{\text{ICC}})},\quad b = 1 + \frac{k\,\widehat{\text{ICC}}(n-1)}{n(1-\widehat{\text{ICC}})} $$ $$ L = \frac{n(MS_B - F^{*}MS_E)}{F^{*}\bigl[k\,MS_R + (kn-k-n)MS_E\bigr] + n\,MS_B},\qquad U = \frac{n(F^{**}MS_B - MS_E)}{k\,MS_R + (kn-k-n)MS_E + n\,F^{**}MS_B} $$
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

R script คำถามที่ 1: Cohen's kappa (แพ็กเกจ irr และ psych)question 1: Cohen's kappa (packages irr and psych)
# 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)
Expected R output (R 4.3.3)
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
R script คำถามที่ 2: ICC (ต่อจากสคริปต์ข้างบน แพ็กเกจ psych)question 2: ICC (continues the script above; package psych)
# 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)
Expected R output (R 4.3.3)
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
DAPH เมนู วิเคราะห์เพิ่มเติม > Agreement Analysis (Kappa/ICC)... · Kappa: Rater 1 = qol_g1, Rater 2 = qol_g2 · ICC: ICC(1,1), ICC(2,1) และ ICC(3,1) ทีละครั้ง ติ๊ก qolscore1, qolscore2, qolscore3 · กด Run (DAPH แสดง 4 ตำแหน่งทศนิยม)menu Additional Analysis > Agreement Analysis (Kappa/ICC)... · Kappa: Rater 1 = qol_g1, Rater 2 = qol_g2 · ICC: ICC(1,1), ICC(2,1) and ICC(3,1) one at a time, ticking qolscore1, qolscore2, qolscore3 · press Run (DAPH prints 4 decimals)
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
ตาราง pre × mid: (0,0) / (0,1) / (1,0) / (1,1)pre × mid table: (0,0) / (0,1) / (1,0) / (1,1)287 / 116 / 0 / 897287 / 116 / 0 / 8970✓ PASS
ร้อยละความตรงกันpercentage agreement91.077%91.08%< 0.005✓ PASS
Cohen's κ0.773460.7735< 0.00005✓ PASS
κ ถ่วงน้ำหนัก (เส้นตรง / กำลังสอง)weighted κ (linear / quadratic)0.773460.7735 / 0.7735< 0.00005✓ PASS
SE ของ κ (R: Fleiss, Cohen & Everitt 1969)SE of κ (R: Fleiss, Cohen & Everitt 1969)0.019550.0196 (0.01955)0.00000✓ PASS
95% CI ของ κ95% CI of κ0.73514 to 0.811780.7351 to 0.81180.0000✓ PASS
z ทดสอบ κ = 0 (SE ภายใต้ H₀)z for the test of κ = 0 (SE under H₀)28.63228.6320.0000✓ PASS
p ของการทดสอบ κ = 0p of the test of κ = 0< 0.001< 0.0010✓ PASS
MSB / MSW / MSR / MSE955.2969 / 15.1262 / 19570.6089 / 0.0720955.2969 / 15.1262 / 19570.6089 / 0.0720< 0.00005✓ PASS
ICC(1,1) และ 95% CIICC(1,1) and 95% CI0.9540 (0.9496 to 0.9580)0.9540 (0.9496 to 0.9580)< 0.00005✓ PASS
ICC(2,1)0.95460.9546< 0.00005✓ PASS
95% CI ของ ICC(2,1)95% CI of ICC(2,1)0.3539 to 0.98730.3539 to 0.98730.000✓ PASS
ICC(3,1) และ 95% CIICC(3,1) and 95% CI0.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); df13275.62; 1299, 259813275.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.

รูปแบบการรายงาน: "การจัดกลุ่มคุณภาพชีวิตสูง (คะแนนเกิน 60) ก่อนและระหว่างการรักษามีความสอดคล้องมาก (κ = 0.77, 95% CI 0.74 ถึง 0.81; ตรงกันร้อยละ 91.1; n = 1,300) · คะแนนคุณภาพชีวิตสามครั้งมีความสอดคล้องของลำดับเกือบสมบูรณ์ (ICC(3,1) = 1.00) แต่ความตรงกันของค่าต่ำกว่า (ICC(2,1) = 0.95, 95% CI 0.35 ถึง 0.99) เนื่องจากคะแนนเฉลี่ยเพิ่มขึ้นระหว่างการรักษา"
How to report it: "The high-QoL classification (score above 60) agreed substantially between the pre-treatment and mid-treatment assessments (κ = 0.77, 95% CI 0.74 to 0.81; 91.1% agreement; n = 1,300). The three QoL scores were almost perfectly consistent in ranking (ICC(3,1) = 1.00) but agreed less in absolute value (ICC(2,1) = 0.95, 95% CI 0.35 to 0.99) because mean scores rose during treatment."
📖 References
  1. Cohen, J. (1960). A coefficient of agreement for nominal scales. Educational and Psychological Measurement, 20(1), 37–46. doi:10.1177/001316446002000104
  2. 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
  3. 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
  4. 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
  5. Landis, J. R., & Koch, G. G. (1977). The measurement of observer agreement for categorical data. Biometrics, 33(1), 159–174. doi:10.2307/2529310
  6. 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
  7. 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
  8. 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 4 topics 📘 ระเบียบวิธี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.

ข้อมูลตัวอย่างของ DAPH เป็นผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย (CAPD 656 ราย · APD 644 ราย) งานแบบอธิบาย: "APD สัมพันธ์กับการเสียชีวิตระหว่างติดตามต่างจาก CAPD หรือไม่ เมื่อปรับอายุและโรคประจำตัว" คำตอบคือ odds ratio ของ APD พร้อมช่วงเชื่อมั่นจากแบบจำลองที่กำหนดตัวแปรไว้ล่วงหน้า (หัวข้อ 13.4 แสดงว่าวิธีคัดตัวแปรอัตโนมัติของ DAPH เก็บตัวแปรใดไว้สำหรับคำถามนี้) งานแบบทำนาย: "สร้างแบบจำลองชี้ผู้ป่วยที่มีความเสี่ยงสูงจะเสียชีวิตระหว่างติดตาม" คัดตัวแปรได้ แต่ต้องตัดสินด้วยผู้ป่วยที่กันไว้ทดสอบ (Machine Learning Comparison หัวข้อ 13.3) สคริปต์ R ด้านล่างใช้สี่แบบจำลองจากข้อมูลชุดนี้ — คุณภาพชีวิตหลังการรักษา (linear) · การเสียชีวิตระหว่างติดตาม (logistic) · จำนวนครั้งเยื่อบุช่องท้องอักเสบต่อคน-ปี (count) — และเทียบ AIC/BIC เฉพาะคู่ที่เทียบกันได้จริง
The DAPH example data are 1,300 peritoneal-dialysis patients (CAPD 656, APD 644). An explanatory question: "Is APD associated with death during follow-up, compared with CAPD, after adjusting for age and chronic disease?" — the answer is the odds ratio of APD with its confidence interval from a model whose covariates were fixed in advance (13.4 shows which variables DAPH's automated selection keeps for this question). A predictive question: "Build a model that flags patients at high risk of dying during follow-up" — predictors may be screened, but the model is judged on patients held out for testing (Machine Learning Comparison, 13.3). The R script below uses models from these data — post-treatment quality of life (linear), death during follow-up (logistic) and peritonitis episodes per person-year (count) — and compares AIC/BIC only where the comparison is valid.

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):

$$ \mathrm{AIC} = -2\hat{\ell} + 2k \qquad\qquad \mathrm{BIC} = -2\hat{\ell} + k\ln n $$
AICc — AIC ที่ปรับสำหรับตัวอย่างน้อย (ใช้เมื่อ n/k < 40)AIC corrected for small samples (use when n/k < 40)
$$ \mathrm{AICc} = \mathrm{AIC} + \frac{2k(k+1)}{n-k-1} $$
Akaike weights และอัตราส่วนหลักฐานระหว่างสองแบบจำลองand the evidence ratio between two models
$$ \Delta_i = \mathrm{AIC}_i - \mathrm{AIC}_{\min}, \qquad w_i = \frac{\exp(-\Delta_i/2)}{\sum_{r=1}^{R}\exp(-\Delta_r/2)}, \qquad \frac{w_i}{w_j} = \exp\!\left(\frac{\Delta_j-\Delta_i}{2}\right) $$
ย้าย AIC ของแบบจำลอง log(y) มาไว้บนสเกลของ yMoving the AIC of a log(y) model onto the scale of y
$$ \mathrm{AIC}_{y} = \mathrm{AIC}_{\log y} + 2\sum_{i=1}^{n}\log y_i $$
ℓ̂
ค่า 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.

กติกาสี่ข้อเมื่อเทียบแบบจำลอง: Four rules for comparing models: (1) แถวชุดเดียวกัน — AIC และ BIC เป็นผลรวมจากทุกแถว ถ้าตัวแปรตัวหนึ่งมีค่าขาดหายจนจำนวนแถวต่างกัน ค่าที่ได้เทียบกันไม่ได้ ต้องฟิตทุกแบบจำลองใหม่บนแถวชุดเดียวกันก่อน · (2) ตัวแปรตามเดียวกันบนสเกล likelihood เดียวกัน — เทียบได้เช่น Poisson กับ negative binomial ของจำนวนครั้งชุดเดียวกัน (ทั้งคู่เป็นความน่าจะเป็นของค่านับเดียวกัน) แต่เทียบไม่ได้ระหว่างแบบจำลองของ y กับของ log(y) (ต้องปรับด้วยสูตรข้างบนก่อน) · ระหว่าง partial likelihood ของ Cox กับ likelihood เต็มของแบบจำลองการอยู่รอดแบบมีพารามิเตอร์ · ระหว่าง ML กับ REML · และระหว่างตระกูล ARIMA กับ exponential smoothing ซึ่งคำนวณ likelihood คนละแบบ จึงต้องเทียบด้วยความแม่นบนช่วงที่กันไว้ (Hyndman & Athanasopoulos 2021, §9.10; หัวข้อ 11.4) · (3) แปลผลจากแบบจำลองที่ถูกเลือกจริง — ตาราง ค่าผลกระทบ และข้อความแปลผลต้องมาจากแบบจำลองที่เกณฑ์เลือก ไม่ใช่แบบจำลองอื่นที่ฟิตไว้ด้วย · (4) การไม่ปฏิเสธสมมติฐานไม่ใช่การยืนยัน — ค่า p ที่ไม่มีนัยสำคัญของตัวแปรหรือของการทดสอบข้อตกลง (เช่น Hosmer–Lemeshow, proportional hazards) แปลว่า "ไม่พบหลักฐาน" ไม่ใช่ "ไม่มีผล" หรือ "เป็นไปตามข้อตกลง" (Altman & Bland 1995) (1) Same rows — AIC and BIC are sums over rows; if a variable with missing values changes the number of rows, the values cannot be compared until every model is refitted on the same rows. · (2) Same outcome on the same likelihood scale — Poisson and negative binomial models of the same counts can be compared (both are probabilities of the same counts), but not a model of y with a model of log(y) (adjust with the formula above first), not Cox's partial likelihood with the full likelihood of a parametric survival model, not ML with REML, and not ARIMA with exponential smoothing, whose likelihoods are computed differently — those are compared on held-out accuracy (Hyndman & Athanasopoulos 2021, §9.10; section 11.4). · (3) Interpret the model that was chosen — tables, effect estimates and interpretation must come from the model the criterion selected, not from another model that was also fitted. · (4) Not rejecting is not confirming — a non-significant p for a variable or for an assumption check (Hosmer–Lemeshow, proportional hazards) means "no evidence", not "no effect" or "assumption met" (Altman & Bland 1995).

DAPH พิมพ์เกณฑ์อะไรให้บ้าง — ไม่เท่ากันทุกสถิติ ตรวจได้จากหน้าผลลัพธ์ (Tab 3) และไฟล์ Word:

What DAPH prints — it differs by statistic (results view, Tab 3, and the Word report):

สถิติStatisticค่าที่พิมพ์Printedข้อสังเกตNote
Linear regressionAIC และ 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 regressionAIC และ BIC (Tab 3) · log-likelihood, AIC และ BIC (Word)AIC and BIC (Tab 3) · log-likelihood, AIC and BIC (Word)ตรงกับ Rmatches R
Poisson / negative binomialAIC (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
ต้องรายงานเสมอ — อคติหลังการคัดเลือก (post-selection inference): Always report — post-selection inference: ช่วงเชื่อมั่นและค่า p ที่รายงานหลังการคัดเลือกตัวแปรอัตโนมัติยังไม่ได้รวมความไม่แน่นอนจากขั้นตอนการคัดเลือก จึงแคบกว่าความจริง (Berk et al. 2013) ควรระบุวิธีคัดเลือกไว้ในระเบียบวิธีวิจัย และรายงานแบบจำลองชุดเต็มเป็นการวิเคราะห์ความไว (sensitivity analysis) ประกอบ — DAPH พิมพ์ข้อความเตือนนี้ใต้ผลของวิธีคัดตัวแปรเชิงพื้นที่ (หัวข้อ 13.2) แต่ Backward Elimination, Stepwise Regression และ Forward Selection ของ Linear · Logistic · Poisson · Cox พิมพ์ขั้นตอนการคัดครบโดยไม่มีข้อความเตือนนี้ ผู้วิจัยต้องเขียนเพิ่มเอง (หัวข้อ 13.4) Confidence intervals and p-values shown after an automated selection do not account for the selection itself and are therefore too narrow (Berk et al. 2013). State the selection procedure in the methods and report the full model as a sensitivity analysis. DAPH prints this caveat under the spatial selection methods (13.2); Backward Elimination, Stepwise Regression and Forward Selection in Linear · Logistic · Poisson · Cox regression print every selection step but not this caveat, so add it yourself (13.4).

ตัวแปรเยอะ ตัวอย่างน้อย — ข้อมูลรองรับพารามิเตอร์ได้กี่ตัว ไม่มีวิธีคัดเลือกใดสร้างข้อมูลเพิ่มได้ ถ้าหน่วยข้อมูลน้อยเมื่อเทียบกับจำนวนพารามิเตอร์ การคัดเลือกจะกลายเป็นการไล่จับสัญญาณรบกวน กติกาที่ใช้กันคือ

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

R script base R (stats) + MASS · เทียบ AIC/BIC เฉพาะคู่ที่เทียบได้ และสาธิตสองกรณีที่เทียบไม่ได้base R (stats) + MASS · AIC/BIC compared only where valid, plus the two cases that are not
# 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))
Expected R output (R 4.3.3)
            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 
R script ต่อจากข้างบน — ค่า p ที่ไม่มีนัยสำคัญ และ EPVcontinued — a non-significant p, and the EPV
# (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)
Expected R output (R 4.3.3)
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
DAPH การตั้งค่าที่ใช้: Tab 2 › Continuous › Linear regression, ตัวแปรตาม = Quality of Life Score (Post), ตัวแปรอิสระ = Treatment Group, Age (years), Gender, BMI Group, Chronic Disease, Personal Income, Employment Status, วิธีการวิเคราะห์ = Enter (แบบจำลองเต็ม) และ Backward Elimination (แบบจำลองที่คัดแล้ว) · Tab 2 › Categorical › Logistic Regression, ตัวแปรตาม = Study Status, ตัวแปรอิสระชุดเดียวกัน, Enter และ Backward Elimination และอีกครั้งด้วย Enter กับ Treatment Group, Age (years), Chronic Disease, Hospital Type · Tab 2 › Count › Poisson regression, ตัวแปรนับ = Number of Peritonitis Episodes, เวลาที่เสี่ยง (offset) = Follow-up Duration (years), ตัวแปรอิสระชุดเดียวกัน, Enter (DAPH เปลี่ยนเป็น negative binomial เอง) · ค่า AIC ละเอียดของ DAPH มาจากผลลัพธ์ที่ DAPH ส่งไปหน้าทำนาย ส่วนค่าอื่นมาจาก Tab 3 และ WordSettings used: Tab 2 › Continuous › Linear regression, Dependent = Quality of Life Score (Post), Independent = Treatment Group, Age (years), Gender, BMI Group, Chronic Disease, Personal Income, Employment Status, Analysis Method = Enter (full model) and Backward Elimination (selected model) · Tab 2 › Categorical › Logistic Regression, Dependent = Study Status, the same independents, Enter and Backward Elimination, and once more with Enter on Treatment Group, Age (years), Chronic Disease, Hospital Type · Tab 2 › Count › Poisson regression, count = Number of Peritonitis Episodes, person-time offset = Follow-up Duration (years), the same independents, Enter (DAPH switches to the negative binomial itself). Full-precision AICs are those DAPH passes to the prediction page; everything else is read from Tab 3 and Word.
ค่าQuantityRDAPHความต่างDifferenceStatus
Linear เต็ม · AIC ตามสูตรข้างบน (k รวม σ²)Linear, full · AIC as defined above (k includes σ²)11159.6411157.62.0✗ FAIL
Linear เต็ม · BIC ตามสูตรข้างบนLinear, full · BIC as defined above11221.6811214.57.2 (= ln 1300)✗ FAIL
Linear · ΔAIC (เต็ม − คัดแล้ว)Linear · ΔAIC (full − selected)7.8827617.882761< 1e−6✓ PASS
Linear · ΔBIC (เต็ม − คัดแล้ว)Linear · ΔBIC (full − selected)33.7333.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 / AIC1297 / 1169.4311297 / 1169.4309< 0.001✓ PASS
Poisson · Pearson χ²/df (เกณฑ์เปลี่ยนเป็น NB > 1.5)Poisson · Pearson χ²/df (switch to NB above 1.5)1.7749041.774904< 1e−6✓ PASS
Negative binomial · α / AICNegative binomial · α / AIC0.6192306 / 3707.0010.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.922.90✓ 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
  1. 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
  2. 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
  3. 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
  4. 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.
  5. Harrell, F. E. (2015). Regression Modeling Strategies (2nd ed.). Cham: Springer. doi:10.1007/978-3-319-19425-7
  6. 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
  7. Hyndman, R. J., & Athanasopoulos, G. (2021). Forecasting: Principles and practice (3rd ed.). OTexts. https://otexts.com/fpp3/
  8. 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
  9. 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
  10. 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
  11. Schwarz, G. (1978). Estimating the dimension of a model. The Annals of Statistics, 6(2), 461–464. doi:10.1214/aos/1176344136
  12. Shmueli, G. (2010). To explain or to predict? Statistical Science, 25(3), 289–310. doi:10.1214/10-STS330
  13. 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.

ตัวอย่างในหัวข้อนี้: ข้อมูล Columbus ชุดเดียวกับ 6.1 (49 ย่าน; ข้อมูลตัวอย่างผู้ป่วยของ DAPH ไม่มีแผนที่) ผลลัพธ์ CRIME และตัวแปรทำนายที่เป็นผู้สมัคร 9 ตัว: INC รายได้ครัวเรือน, HOVAL มูลค่าบ้าน, OPEN พื้นที่โล่ง, PLUMB ร้อยละบ้านที่ไม่มีระบบประปา, DISCBD ระยะทางถึงย่านใจกลางเมือง, CP ย่านใจกลาง (1 = ใช่), EW ฝั่งตะวันออก (1 = ใช่) และ NSA, NSB ซึ่งเป็นตัวแปร "ฝั่งเหนือ" สองตัวที่วัดสิ่งเดียวกัน — ตัวอย่างของตัวแปรซ้ำซ้อนที่ขั้น VIF ควรตัดออก. ใช้ Queen contiguity และติ๊ก OLS กับ SLM.
Example in this section: the Columbus data of 6.1 (49 neighbourhoods; the DAPH patient example has no map), outcome 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.
Variance Inflation Factor — ขั้น VIFthe VIF step
$$ \mathrm{VIF}_j = \frac{1}{1-R_j^2} $$
LASSO — ขั้นคัดกรองด้วยบทลงโทษthe penalised screen
$$ \hat{\beta}(\lambda) = \arg\min_{\beta}\ \tfrac{1}{2n}\lVert y_c - X_s\beta \rVert_2^2 + \lambda\lVert\beta\rVert_1,\qquad \lambda \in \bigl[\lambda_{\max}/1000,\ \lambda_{\max}\bigr],\quad \lambda_{\max}=\tfrac{1}{n}\max_j\lvert x_{s,j}'y_c\rvert $$
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: θ = 0Wald: common factor (θ + ρβ = 0)Wald: common factor (θ + ρβ = 0)แบบจำลองที่นำมาแปลผลModel to interpret
ปฏิเสธrejectedปฏิเสธrejectedSDM — แปลผลผ่านผลกระทบ direct / spillover / total ไม่ใช่สัมประสิทธิ์ดิบinterpret through the direct / spillover / total effects, not the raw coefficients
ไม่ปฏิเสธnot rejectedปฏิเสธrejectedSLM
ปฏิเสธrejectedไม่ปฏิเสธnot rejectedSEM
ไม่ปฏิเสธ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

R script ส่วนที่ 1 — ข้อมูลและขั้น VIF · packages: sf, spdep, spatialreg, car, glmnetPart 1 — data and the VIF step · packages: sf, spdep, spatialreg, car, glmnet
# 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))
Expected R output
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 
R script ส่วนที่ 2 — ขั้น LASSO แบบเดียวกับ DAPHPart 2 — the LASSO step as DAPH runs it
# 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))
Expected R output
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 
R script ส่วนที่ 3 — Backward และ Forward ด้วย AIC ที่ฟิต SLM ใหม่ทุกก้าวPart 3 — backward and forward AIC searches refitting the SLM at every step
# 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")
Expected R output
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 
R script ส่วนที่ 4 — ข้อจำกัดเมื่อ SDM เป็นแบบจำลองที่ใช้ค้นPart 4 — the limitation when the SDM is the probe model
# 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))
Expected R output
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
DAPH 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 = (ก) 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
📊 ตารางเปรียบเทียบ (R 4.3.3: spatialreg 1.3-1, car 3.1-2, glmnet 4.1-8 · DAPH v.2026.08.22, รันวันที่ 2026-10-02; DAPH พิมพ์ AIC ทศนิยม 1 ตำแหน่ง)Side-by-side comparison (R 4.3.3: spatialreg 1.3-1, car 3.1-2, glmnet 4.1-8 · DAPH v.2026.08.22, run 2026-10-02; DAPH prints AIC to 1 decimal)
ค่าที่วัด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 zeroOPEN, EW, NSA, NSBOPEN, 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.6510371.6 → 369.6 → 367.6 → 365.7 → 364.7< 0.05✓ PASS
VIF → Backward: ชุดสุดท้ายVIF → Backward: final setINC, HOVAL, PLUMB, CPINC, 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.6510375.2 → 367.3 → 365.1 → 364.7< 0.05✓ PASS
SDM เป็นแบบจำลองที่ใช้ค้น (OLS + SDM): AIC ชุดเต็มSDM as the probe (OLS + SDM): full-set AIC380.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 droppedNSA (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).

ตัวอย่างการเขียนผล: จากตัวแปรผู้สมัคร 9 ตัว ตัดตัวแปรที่มี VIF > 10 ออก 1 ตัว (NSA) แล้วคัดด้วย backward elimination ตามค่า AIC ของ spatial lag model ที่ฟิตใหม่ทุกก้าว ได้ตัวแปรสุดท้าย 4 ตัว (INC, HOVAL, PLUMB, CP); แบบจำลองชุดเต็มรายงานไว้ในภาคผนวกเป็นการวิเคราะห์ความไว.
Example write-up: Of nine candidate predictors, one with VIF > 10 (NSA) was removed and the rest were selected by backward elimination on the AIC of the spatial lag model, refitted at every step, leaving four predictors (INC, HOVAL, PLUMB, CP); the full model is reported in the appendix as a sensitivity analysis.
📖 References
  1. 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
  2. Elhorst, J. P. (2010). Applied spatial econometrics: Raising the bar. Spatial Economic Analysis, 5(1), 9–28. doi:10.1080/17421770903541772
  3. LeSage, J., & Pace, R. K. (2009). Introduction to spatial econometrics. Chapman & Hall/CRC. doi:10.1201/9781420064254
  4. 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
  5. 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
  6. 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.

ข้อมูลตัวอย่าง DAPH · ตัวอย่างที่ 1 (ทำไมต้องคัดในทุก fold): ผู้ป่วยของ Bangkok Hospital 96 ราย (เสียชีวิต 21 ราย) กับตัวแปรสุ่มล้วน 40 ตัวที่ไม่มีข้อมูลจริงเลย ถ้าเลือก 10 ตัวที่สัมพันธ์กับการเสียชีวิตมากที่สุดจากผู้ป่วยทั้ง 96 รายก่อน แล้วค่อยทำ 5-fold cross-validation ค่า AUC เฉลี่ยจากการทำซ้ำ 200 ครั้งเท่ากับ 0.688 แต่เมื่อคัดใหม่ในทุก fold ค่าเฉลี่ยเหลือ 0.491 ซึ่งตรงกับความจริง (ประมาณ 0.5) · ตัวอย่างที่ 2 (ตัวคัดทั้งสี่แบบของ DAPH): ทำนายการเสียชีวิต (Study Status) จากตัวแปรตั้งต้น 8 ตัว ได้แก่ อายุ, เพศ, น้ำหนัก, ส่วนสูง, ดัชนีมวลกาย, โรคเรื้อรัง, กลุ่มการรักษา และคะแนนคุณภาพชีวิตก่อนรักษา ด้วยโหมด “อัตโนมัติ” แต่ละแบบจำลองได้ตัวคัดตามตระกูลของตน และเหลือตัวแปรต่างกันมาก (ตารางในส่วนที่ 3)
DAPH example data. Example 1 (why screen inside every fold): the 96 patients of Bangkok Hospital (21 deaths) with 40 columns of pure random noise. Picking the 10 noise columns most correlated with death using all 96 patients and only then running 5-fold cross-validation gives an average AUC of 0.688 over 200 repetitions; re-picking inside every fold gives 0.491, the truth (about 0.5). Example 2 (DAPH's four screens): predicting death (Study Status) from eight candidate predictors, namely Age, Gender, Weight, Height, Body Mass Index, Chronic Disease, Treatment Group and Quality of Life Score (Pre), in "Auto" mode; each model receives the screen of its family and keeps a very different set (table in part 3).

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"
เชิงเส้นLinearLogistic Regression · Elastic Net (Logistic) · Linear Regression · Elastic Netคัดด้วย penalized regression (elastic net)penalised (elastic net)
ต้นไม้TreeDecision Tree · Random Forest · XGBoost · LightGBMคัดด้วยความสำคัญจากโมเดล — ต้นไม้ทนต่อ collinearity อยู่แล้ว สิ่งที่ได้คือค่า SHAP ที่เสถียรขึ้นmodel importance — trees tolerate correlated predictors; the gain is stabler SHAP
Kernel / ระยะทางKernel / distanceSVM (RBF) · SVR (RBF) · KNNคัด collinearity → elastic net (ระยะทางบิดเบือนเมื่อตัวแปรซ้ำซ้อน)collinearity → elastic net (duplicated predictors distort the distance)
โครงข่ายประสาทเทียมNeural networkMLPคัด collinearitycollinearity
Naive BayesGaussian 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.

ข้อจำกัดที่ต้องทราบ:Known limitation: เมื่อใช้ Auto-SMOTE ร่วมกับการค้นหา hyperparameter ด้วย Optuna การค้นหาจะแบ่ง fold จากชุดฝึกที่เพิ่มผู้ป่วยสังเคราะห์แล้ว ผู้ป่วยสังเคราะห์ที่สร้างจากผู้ป่วยในแถวตรวจสอบของ fold นั้นจึงอยู่ในแถวฝึกด้วย คะแนนภายในของการค้นหาจึงดีเกินจริง (ค่าจากข้อมูลที่กันไว้ทดสอบไม่ได้รับผลกระทบ) When Auto-SMOTE is combined with Optuna tuning, the tuning folds are drawn from the training set after synthetic patients have been added, so synthetic patients made from a validation-fold patient also sit in the training rows and the internal tuning scores are optimistic (the held-out test metrics are unaffected).

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.

R script ตัวคัดตัวแปรของ DAPH และผลของการคัดนอก fold (แพ็กเกจ glmnet)DAPH's screens and the effect of screening outside the folds (package glmnet)
# 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))
Expected R output (R 4.3.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
DAPH Tab 2 > Statistic = Machine Learning Comparison · Dependent Variable = Study Status · Independent Variables = Age, Gender, Weight, Height, Body Mass Index, Chronic Disease, Treatment Group, Quality of Life Score (Pre) · Train/Test Split 70/30 แบบ Temporal ตัวแปรเวลา enroll_date · Cross-Validation 5-fold (Train set) · วิธีเลือกตัวแปร = อัตโนมัติ · โมเดล = Logistic Regression, Random Forest, SVM (RBF), MLP (1×64) · ความไม่สมดุลกลุ่ม = ไม่ปรับ · การจูนพารามิเตอร์ = Library defaults · Random seed = 12345 · คอลัมน์ที่เหลืออ่านจากค่าภายในของผลการวิเคราะห์Tab 2 > Statistic = Machine Learning Comparison; Dependent Variable = Study Status; Independent Variables = Age, Gender, Weight, Height, Body Mass Index, Chronic Disease, Treatment Group, Quality of Life Score (Pre); Train/Test Split 70/30, Temporal, time variable enroll_date; Cross-Validation 5-fold (Train set); Variable selection = Auto; Models = Logistic Regression, Random Forest, SVM (RBF), MLP (1×64); Class imbalance = None; HPO tuning = Library defaults; Random seed = 12345. The kept columns are read from the analysis result's internal values.
ค่าที่ตรวจQuantityRDAPHความต่างDifferenceStatus
ตัวคัดที่โหมดอัตโนมัติให้แต่ละแบบจำลองScreen given to each model by Autoตามตารางในส่วนที่ 2per the table in part 2Logistic: elasticnet · Random Forest: importance · SVM: vif_elasticnet · MLP: vif0✓ PASS
คัดด้วย elastic net (Logistic Regression)Penalised screen (Logistic Regression)age, qolscore1, chronic_0, chronic_1, group_1, group_2age, qolscore1, chronic_0, chronic_1, group_1, group_20✓ PASS
คัด collinearity (MLP): คอลัมน์ที่เหลือCollinearity screen (MLP): kept columnsage, height, bmi, qolscore1, gender_2, chronic_1, group_2age, height, bmi, qolscore1, gender_2, chronic_1, group_20✓ PASS
คัด collinearity → elastic net (SVM)Collinearity → penalised screen (SVM)chronic_1, group_2chronic_1, group_20✓ 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 11Logistic 6 · SVM 2 · MLP 7Logistic 6 · Random Forest 6 · SVM 2 · MLP 70✓ 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
  1. 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
  2. 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
  3. Guyon, I., & Elisseeff, A. (2003). An introduction to variable and feature selection. Journal of Machine Learning Research, 3, 1157–1182.
  4. 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
  5. Kuhn, M., & Johnson, K. (2013). Applied Predictive Modeling. New York: Springer. doi:10.1007/978-1-4614-6849-3
  6. 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
  7. 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
  8. 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.
คำถามวิจัยจากข้อมูลตัวอย่าง (ผู้ป่วยล้างไตทางช่องท้อง 1,300 ราย): "วิธีล้างไต APD เทียบกับ CAPD (Treatment Group) สัมพันธ์กับ (1) คุณภาพชีวิตหลังการรักษา (2) การเสียชีวิตระหว่างติดตาม (3) อัตราการเกิดเยื่อบุช่องท้องอักเสบต่อคน-ปี และ (4) อัตราอันตรายของการเสียชีวิต หรือไม่ เมื่อคำนึงถึงลักษณะของผู้ป่วย" exposure คือ Treatment Group ตัวแปรที่นำเข้าพิจารณาอีกหกตัวคือ อายุ เพศ กลุ่ม BMI โรคประจำตัว รายได้ส่วนบุคคล และการทำงาน · ส่วนจำนวนครั้งที่เป็นเยื่อบุช่องท้องอักเสบอาจอยู่บนเส้นทางจากวิธีล้างไตไปสู่การเสียชีวิต (mediator) ถ้าต้องการผลรวมของวิธีล้างไตต่อการเสียชีวิต จึงไม่ควรนำมาปรับ · ส่วนที่ 3 รันห้าวิธีของ DAPH กับคำถามทั้งสี่ และแสดงว่าแต่ละวิธีเก็บตัวแปรใดไว้
The research question in the example data (1,300 peritoneal-dialysis patients): "Is APD, compared with CAPD (Treatment Group), associated with (1) post-treatment quality of life, (2) death during follow-up, (3) the rate of peritonitis per person-year and (4) the hazard of death, once patient characteristics are taken into account?" The exposure is Treatment Group; the six other candidates are age, gender, BMI group, chronic disease, personal income and employment status. The number of peritonitis episodes may lie on the path from dialysis modality to death (a mediator), so it should not be adjusted for when the total effect of modality on death is the target. Part 3 runs DAPH's methods on all four questions and shows which variables each method keeps.

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.

วิธีMethodDAPH ทำอะไร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).

สิ่งที่ควรหลีกเลี่ยง — การคัดด้วยค่า p ล้วน ๆ แล้วรายงานเหมือนตั้งไว้ล่วงหน้า: What to avoid — a pure p-value search reported as if pre-specified: Harrell (2015, §4.3) สรุปปัญหาของ stepwise ไว้ว่า R² ค่าสัมประสิทธิ์ และค่าสถิติทดสอบมีอคติ ช่วงเชื่อมั่นแคบและค่า p เล็กเกินจริง ตัวแปรที่ได้มักมีสัญญาณรบกวนปน และเมื่อใช้คัดตัวแปรกวนจะเหลืออคติจากตัวแปรกวนอยู่ Greenland (1989) ชี้ว่า stepwise แบบทั่วไปให้ค่าประมาณและการทดสอบที่ไม่ถูกต้องได้ง่าย Heinze et al. (2018) แนะนำให้หลีกเลี่ยงการคัดกรองด้วยการวิเคราะห์ทีละตัวแปร ถ้าจำเป็นต้องค้นหา ให้ใช้ backward elimination เพราะเริ่มจากแบบจำลองเต็มที่ไม่มีอคติ โดยใช้ AIC เป็นเกณฑ์หยุด (เทียบเท่า LR test ที่ α = 0.157 สำหรับตัวแปร 1 df) — เกณฑ์ 0.05 ของ DAPH เข้มกว่านั้นมาก จึงตัดตัวแปรมากกว่า · ไม่ว่าใช้วิธีใด ต้องรายงานว่ามีการค้นหา และรายงานแบบจำลองเต็มคู่กันเป็นการวิเคราะห์ความไว (DAPH ยังไม่พิมพ์ข้อความเตือนเรื่องนี้ให้) Harrell (2015, §4.3) lists the problems of stepwise selection: biased R², coefficients and test statistics, standard errors and p-values too small, noise variables in the final model, and residual confounding when it is used to pick confounders. Greenland (1989) concluded that conventional stepwise regression can easily give invalid estimates and tests of effect. Heinze et al. (2018) advise against univariable screening; if a search is needed they prefer backward elimination, because it starts from the unbiased full model, with AIC as the stopping rule (equivalent to an LR test at α = 0.157 for a 1-df variable) — DAPH's 0.05 is much stricter and drops more variables. Whatever the method, state that a search took place and report the full model beside it as a sensitivity analysis (DAPH does not yet print this caveat for you).

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
R script base R (stats) + MASS + survival · ทำซ้ำ Backward Elimination และ Stepwise Regression ของ DAPH กับทั้งสี่สถิติbase R (stats) + MASS + survival · DAPH's Backward Elimination and Stepwise Regression for all four statistics
# 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")
}
Expected R output (R 4.3.3)
== 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 
R script ต่อ — แบบจำลองสุดท้ายที่ Backward Elimination เก็บไว้continued — the final models kept by Backward Elimination
# 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
Expected R output (R 4.3.3)
               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
R script ต่อ — เหตุที่ต้องทดสอบตัวแปรกลุ่มทั้งตัวcontinued — why a categorical variable is tested as a whole
# 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
Expected R output (R 4.3.3)
             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"
R script ต่อ — การเปลี่ยนของค่าประมาณ (change-in-estimate)continued — change-in-estimate
# 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)
Expected R output (R 4.3.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
DAPH การตั้งค่าที่ใช้ (ตัวแปรอิสระ = Treatment Group, Age (years), Gender, BMI Group, Chronic Disease, Personal Income, Employment Status ทุกครั้ง): Tab 2 › Continuous › Linear regression, ตัวแปรตาม = Quality of Life Score (Post) · Tab 2 › Categorical › Logistic Regression, ตัวแปรตาม = Study Status · Tab 2 › Count › Poisson regression, ตัวแปรนับ = Number of Peritonitis Episodes, offset = Follow-up Duration (years) (DAPH เปลี่ยนเป็น negative binomial เอง) · Tab 2 › Survival › Cox regression, เหตุการณ์ = Study Status (1 = Died/Event), เวลา = Follow-up Duration (days) · วิธีการวิเคราะห์ = Backward Elimination, Stepwise Regression และ Forward Selection · สำหรับ change-in-estimate ใช้ Logistic Regression แบบ Enter กับตัวแปรครบ และแบบตัด Age หรือ Chronic Disease ออก · ค่าสัมประสิทธิ์ละเอียดของ DAPH มาจากสมการที่ DAPH พิมพ์ในหน้าผลลัพธ์Settings used (Independent = Treatment Group, Age (years), Gender, BMI Group, Chronic Disease, Personal Income, Employment Status throughout): Tab 2 › Continuous › Linear regression, Dependent = Quality of Life Score (Post) · Tab 2 › Categorical › Logistic Regression, Dependent = Study Status · Tab 2 › Count › Poisson regression, count = Number of Peritonitis Episodes, offset = Follow-up Duration (years) (DAPH switches to the negative binomial itself) · Tab 2 › Survival › Cox regression, event = Study Status (1 = Died/Event), time = Follow-up Duration (days) · Analysis Method = Backward Elimination, Stepwise Regression and Forward Selection · for change-in-estimate, Logistic Regression with Enter on the full set and with Age or Chronic Disease left out. Full-precision DAPH coefficients are read from the prediction equation DAPH prints in the results view.
ค่าQuantityRDAPHความต่างDifferenceStatus
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 Disease0.9263 / 0.5234 / 0.26730.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 · Age1.973 (0.045 to 3.900) · 0.045 · −0.1701.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 Status0.9206 / 0.5656 / 0.4065 / 0.27850.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 coefficient2.022 (1.500 to 2.725) · 0.703977392.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 Group0.4960 / 0.3878 / 0.1874 / 0.13650.4960 / 0.3878 / 0.1874 / 0.1365< 5e−5✓ PASS
Stepwise: ลำดับที่นำเข้าด้วย AIC และ AIC สุดท้ายStepwise: entry order by AIC and final AICTreatment Group, Age, Chronic · 3702.42Treatment 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.63461530.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.92490.925< 0.0005✓ PASS
Backward: p ที่ตัด BMI Group / Personal Income / Employment Status / GenderBackward: removal p, BMI Group / Personal Income / Employment Status / Gender0.9249 / 0.6204 / 0.4340 / 0.30610.9249 / 0.6204 / 0.4340 / 0.3061< 5e−5✓ PASS
Backward และ Stepwise: ตัวแปรที่คงไว้Backward and Stepwise: variables keptTreatment Group, Age, ChronicTreatment Group, Age, Chronic—✓ PASS
Stepwise: AIC สุดท้าย (partial likelihood)Stepwise: final AIC (partial likelihood)3155.773155.7665< 0.005✓ PASS
แบบจำลองสุดท้าย: HR ของ APD (95% CI) · ค่าสัมประสิทธิ์Final model: HR APD (95% CI) · coefficient1.89 (1.44 to 2.47) · 0.635811131.89 (1.44 to 2.47) · 0.6358111331< 1e−8✓ PASS
Backward กับ District + BMI Group: ตัวแปรที่คงไว้Backward on District + BMI Group: variables keptDistrict (ตัด 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 / crude2.031 / 1.955 / 1.953 / 1.8922.031 / 1.955 / 1.953 / 1.892< 0.0005✓ PASS
ข้อจำกัดที่ต้องทราบ: Limitations to know: (1) Backward · Stepwise · Forward ของ Linear · Logistic · Poisson · Cox ไม่มีทางบังคับให้ตัวแปรหลักหรือตัวแปรกวนอยู่ในแบบจำลอง จึงอาจตัดตัวแปรหลักทิ้งได้ (Conditional Logistic Regression ไม่ตัดตัวแปรหลัก) · (2) ขั้นนำเข้าของ Poisson และ Cox พิมพ์เพียง "adding …" ไม่แสดงค่า AIC ที่ใช้ตัดสิน ดูค่า AIC ได้จากสคริปต์ R ข้างบน · (3) ไม่มีวิธีใดพิมพ์ข้อความเตือนเรื่องอคติหลังการคัดเลือก ผู้วิจัยต้องเขียนไว้ในระเบียบวิธีวิจัยเอง (1) Backward, Stepwise and Forward in Linear · Logistic · Poisson · Cox cannot force the exposure or a confounder into the model, so they can drop the exposure itself (Conditional Logistic Regression never removes the exposure). · (2) Poisson and Cox entry steps print only "adding …", not the AIC that decided the entry; the AICs are shown by the R script above. · (3) No method prints the post-selection caveat; state it in the methods yourself.

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
  1. 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
  2. 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
  3. 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
  4. Harrell, F. E. (2015). Regression Modeling Strategies (2nd ed.). Cham: Springer. doi:10.1007/978-3-319-19425-7
  5. 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
  6. Hosmer, D. W., Lemeshow, S., & Sturdivant, R. X. (2013). Applied Logistic Regression (3rd ed.). Hoboken: Wiley. doi:10.1002/9781118548387
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. Sornlorm, K. (2026). DAPH Guide: Statistical methods in DAPH (Data Analysis for Public health Research). Retrieved from https://innovageotech.com/statistics-verification