คู่มือชุดบทความการสร้างแบบจำลองเศรษฐศาสตร์สุขภาพ: จากหลักฐานสู่การตัดสินใจ

On this page
Read the English version
บทคัดย่อ
คำตอบเรื่องความคุ้มค่าเป็นบรรทัดสุดท้ายของแบบจำลอง ชุดบทความนี้เปิดแบบจำลองที่อยู่เบื้องหลังบรรทัดนั้น คู่มือนี้ติดตามการตัดสินใจสมมติเรื่องเดียวผ่านทุกบทความ คณะกรรมการของโรงพยาบาลอำเภอต้องตัดสินใจว่าจะจ่ายให้การรักษาเชิงป้องกันแบบใหม่ C แทนการดูแลตามปกติ A หรือไม่ ในการทดลอง ผู้ป่วยที่ได้ C เกิดภาวะแทรกซ้อนรุนแรง 8 จาก 66 คน และผู้ที่ได้ A เกิด 13 จาก 60 คน ส่วน C มีต้นทุนมากกว่า A 150,000 บาทต่อผู้ป่วย นักวิเคราะห์รายงานว่า C ซื้อปีสุขภาพสมบูรณ์เพิ่มได้ 1.00 ปี และคณะกรรมการยอมจ่ายได้ถึง 160,000 บาทต่อหนึ่งปีนั้น สี่บทความเตรียมข้อมูลนำเข้า ได้แก่ รูปร่างของแบบจำลอง ตารางที่สืบย้อนได้ แหล่งที่มาที่ตรงคำถาม และหน่วยเวลาที่ตรงกัน อีกสี่บทความสร้างและเปรียบเทียบแบบจำลอง และนับค่าใช้จ่ายต่อปี อีกสามบทความทดสอบคำตอบในด้านความไม่แน่นอน ความผิดพลาด และมูลค่าของหลักฐานที่ดีขึ้น ความคุ้มค่า นโยบาย และงบประมาณยังเป็นคนละคำถามกัน
การตัดสินใจหนึ่งเรื่อง กับบรรทัดที่ปิดท้าย
คณะกรรมการของโรงพยาบาลอำเภอต้องตัดสินใจว่าจะจ่ายให้การรักษาเชิงป้องกันแบบใหม่ C สำหรับผู้ใหญ่ที่เพิ่งได้รับการวินิจฉัยโรคเรื้อรังหรือไม่ ทางเลือกอีกทางคือการดูแลตามปกติ A ในการทดลอง ผู้ป่วยที่ได้ C เกิดภาวะแทรกซ้อนรุนแรง 8 จาก 66 คน และผู้ที่ได้ A เกิด 13 จาก 60 คน C มีต้นทุนมากกว่า A 150,000 บาทต่อผู้ป่วย
รายงานของนักวิเคราะห์จบด้วยบรรทัดเดียว คือ C ซื้อปีสุขภาพสมบูรณ์เพิ่มได้ 1.00 ปีต่อผู้ป่วย และคณะกรรมการยอมจ่ายได้ถึง 160,000 บาทต่อหนึ่งปีแบบนั้น ผู้อ่านที่รีบจะหยุดตรงนั้นแล้วตอบว่าอนุมัติ
ตัวเลข 1.00 นั้นไม่ได้อยู่ในการทดลอง การทดลองนับภาวะแทรกซ้อนในช่วงติดตามสั้น ๆ แบบจำลองต่างหากที่แปลงจำนวนนั้นเป็นจำนวนปี โดยติดตามผู้ป่วยไปตามเวลา ถ่วงแต่ละปีด้วยคุณภาพชีวิต และรวมต้นทุนทั้งหมด
ความเชื่อที่พบบ่อยคือแบบจำลองเลือกได้จากเมนูของโปรแกรม และผลของมันคือคำตอบ ในชุดนี้ แบบจำลองคือสายเหตุผลที่เขียนไว้ให้เห็นชัด มันบอกว่าผู้ป่วยคือใคร ทางเลือกใดแข่งกัน ผู้ป่วยเดินผ่านเส้นทางใด และตัวเลขใดเติมแต่ละขั้น ผู้อ่านจึงตรวจได้ทุกช่วงของสายเหตุผลนั้น (Briggs และคณะ)
ทางเลือกแต่ละทางเรียกว่า strategy หรือ option คือเส้นทางการดูแลทั้งเส้น เช่น A หรือ C รวมทุกอย่างที่ตามมาหลังการรักษาแรก หลังคู่มือนี้ มีสี่บทความที่เตรียมข้อมูลนำเข้า สี่บทความที่สร้างและเปรียบเทียบแบบจำลอง และสามบทความที่ทดสอบคำตอบ คู่มือนี้พากรณีของคณะกรรมการเดินผ่านแต่ละขั้นหนึ่งรอบ
ตัวเลขบนบรรทัดของคณะกรรมการ
ปีสุขภาพสมบูรณ์ที่เพิ่มขึ้นนี้มีชื่อเรียก ปีสุขภาวะ (quality-adjusted life year, QALY) คือปีชีวิตที่ถ่วงน้ำหนักด้วยคุณภาพ ตั้งแต่ 1 สำหรับสุขภาพสมบูรณ์ถึง 0 สำหรับการเสียชีวิต การอยู่ 10 ปีในสภาวะสุขภาพที่มีค่าคุณภาพชีวิต 0.70 เท่ากับ 7.0 QALY ถ้ากลับมาสุขภาพสมบูรณ์ตลอดช่วงนั้นจะได้เพิ่มอีก 3.0 QALY อ่านบทเรียนเต็มได้ที่ ปีสุขภาวะ ปีสุขภาวะที่สูญเสีย และค่าอรรถประโยชน์: เรากำลังวัดอะไรกันแน่
แบบจำลองของคณะกรรมการรวมปีที่ถ่วงน้ำหนักแบบนี้ตลอดช่วงเวลาที่ติดตามผู้ป่วย (horizon) ยอดรวมของแบบจำลองมาจากการรวมนี้ ผู้ป่วยแต่ละคนที่ได้ A ได้ 8.00 QALY ด้วยต้นทุน 50,000 บาท ส่วนผู้ป่วยแต่ละคนที่ได้ C ได้ 9.00 QALY ด้วยต้นทุน 200,000 บาท เกณฑ์ของคณะกรรมการคือ 160,000 บาท ซึ่งเป็นเงินสูงสุดที่ยอมจ่ายเพื่อให้ได้หนึ่ง QALY
อัตราส่วนต้นทุนประสิทธิผลส่วนเพิ่ม (incremental cost-effectiveness ratio, ICER) คือต้นทุนที่เพิ่มหารด้วยสุขภาพที่ได้เพิ่ม เมื่อเทียบกับทางเลือกที่ดีรองลงมา ทางเลือก C มีต้นทุนมากกว่า A 150,000 บาท และได้เพิ่ม 1.00 QALY จึงมี ICER 150,000 บาทต่อ QALY เทียบกับเกณฑ์ 160,000 อ่านบทเรียนเต็มได้ที่บทความเรื่อง ICER และเกณฑ์ความคุ้มค่า
การเปรียบเทียบเดียวกันนี้เขียนเป็นตัวเงินได้ ผลประโยชน์สุทธิในรูปตัวเงิน (net monetary benefit, NMB) คือสุขภาพที่ตีค่าด้วยเกณฑ์ลบด้วยต้นทุน ผลประโยชน์สุทธิส่วนเพิ่ม (incremental NMB, INMB) ที่เป็นบวกจึงแปลว่าต้นทุนที่เพิ่มคุ้มที่จะจ่าย ที่เกณฑ์ 160,000 บาทต่อ QALY การได้เพิ่ม 1.00 QALY โดยต้นทุนเพิ่มขึ้น 150,000 บาท ให้ INMB 10,000 บาท อ่านบทเรียนเต็มได้ที่บทความเรื่อง ICER และเกณฑ์ความคุ้มค่า เมื่อคิดทีละทางเลือก NMB ของ A คือ 8.00 × 160,000 - 50,000 = 1,230,000 บาท ของ C คือ 1,240,000 บาท และ INMB คือผลต่างของสองค่านี้
ตัวอย่างคำนวณ: บรรทัดของคณะกรรมการจากยอดรวมของแบบจำลอง
แต่ละขั้นใช้เพียงยอดรวมต่อผู้ป่วยจากแบบจำลองและเกณฑ์ จึงตรวจทุกผลลัพธ์ได้ด้วยเครื่องคิดเลข
-
อ่านยอดรวมของแบบจำลอง
ต่อผู้ป่วยหนึ่งคนตลอดช่วงเวลาของแบบจำลอง A มีต้นทุน 50,000 บาทและได้ 8.00 QALY ส่วน C มีต้นทุน 200,000 บาทและได้ 9.00 QALY
-
หัก A ออกจาก C
\[ 200000-50000=150000,\quad 9.00-8.00=1.00 \]
ต้นทุนของ C สูงกว่า A อยู่ 150,000 บาท และ QALY สูงกว่า A อยู่ 1.00 ต่อผู้ป่วย
-
หารต้นทุนที่เพิ่มด้วยสุขภาพที่เพิ่ม
\[ \frac{150000}{1.00}=150000 \]
150,000 บาทต่อ QALY ต่ำกว่าเกณฑ์ 160,000
-
ตีค่าสุขภาพ แล้วหักต้นทุน
\[ 160000\times 1.00-150000=10000 \]
INMB เท่ากับ 10,000 บาทต่อผู้ป่วย เป็นบวก ต้นทุนที่เพิ่มจึงคุ้มที่จะจ่าย
-
ลองเกณฑ์ที่ต่ำกว่าสองค่า
\[ 150000\times 1.00-150000=0,\quad 140000\times 1.00-150000=-10000 \]
ที่ 150,000 บาทต่อ QALY C เท่าทุนพอดี ส่วนที่ 140,000 INMB ของ C เท่ากับ -10,000 บาท
ผลลัพธ์: ที่ 160,000 บาทต่อ QALY C มีมูลค่าสูงกว่าต้นทุนที่เพิ่มขึ้นอยู่ 10,000 บาทต่อผู้ป่วย และคำตอบจะกลายเป็นไม่คุ้มเมื่อเกณฑ์ต่ำกว่า 150,000 ซึ่งเท่ากับ ICER
ตามรอยบรรทัดของคณะกรรมการด้วย R
# The committee's case per patient over the model's horizon: usual care A against treatment C.
nice <- function(value, places = 0) formatC(value, format = "f", digits = places, big.mark = ",")
cost <- c(50000, 200000)
qaly <- c(8, 9)
threshold <- c(160000, 150000, 140000)
gap <- c(diff(cost), diff(qaly))
cat("Cost per patient on A and on C (THB):", nice(cost), "\n")
cat("QALYs per patient on A and on C:", nice(qaly, 2), "\n")
cat("NMB of A and of C at 160,000 THB per QALY (THB):", nice(threshold[1] * qaly - cost), "\n")
cat("Extra cost (THB) and extra QALYs of C:", nice(gap[1]), nice(gap[2], 2), "\n")
cat("Cost per extra QALY (THB):", nice(gap[1] / gap[2]), "\n")
cat("INMB of C at 160,000, 150,000 and 140,000 (THB):", nice(threshold * gap[2] - gap[1]), "\n")
Cost per patient on A and on C (THB): 50,000 200,000
QALYs per patient on A and on C: 8.00 9.00
NMB of A and of C at 160,000 THB per QALY (THB): 1,230,000 1,240,000
Extra cost (THB) and extra QALYs of C: 150,000 1.00
Cost per extra QALY (THB): 150,000
INMB of C at 160,000, 150,000 and 140,000 (THB): 10,000 0 -10,000
ต้องใช้ R ≥ 4.5.2 · tibble 3.3.1 · dplyr 1.2.1 · ggplot2 4.0.3 · ใช้ได้กับ R 4.6.1 · ดาวน์โหลด health-economic-modelling-series-guide.R
สคริปต์ฉบับเต็ม
# Health Economic Modelling Series Guide: From Evidence to a Decision
# คู่มือชุดบทความ: ติดตามกรณีของคณะกรรมการ ตั้งแต่ข้อมูลนำเข้า แบบจำลอง จนถึงการทดสอบคำตอบ
# Requires: R >= 4.5.2
# Tested: works in R 4.6.1
# tibble 3.3.1 (stable)
# dplyr 1.2.1 (stable)
# ggplot2 4.0.3 (stable)
# install.packages(c("tibble", "dplyr", "ggplot2"))
# update.packages(oldPkgs = c("tibble", "dplyr", "ggplot2"))
# remotes::install_version("tibble", "3.3.1")
# remotes::install_version("dplyr", "1.2.1")
# remotes::install_version("ggplot2", "4.0.3")
library(tibble) # Write the two strategies as one explicit input table.
library(dplyr) # Add each strategy's net benefit at the threshold.
library(ggplot2) # Display the two strategies without saving files.
stopifnot(getRversion() >= "4.5.2")
#%%@note 1. The committee's case
# Per patient over the model's horizon: cost and QALYs of usual care A and of treatment C.
# ต้นทุนและ QALY ต่อผู้ป่วยตลอดช่วงเวลาของแบบจำลอง ของการดูแลตามปกติ A และการรักษา C
nice <- function(value, places = 0) formatC(value, format = "f", digits = places, big.mark = ",")
cost <- c(50000, 200000)
qaly <- c(8, 9)
threshold <- c(160000, 150000, 140000)
gap <- c(diff(cost), diff(qaly))
strategies <- tibble::tibble(strategy = c("A", "C"), cost = cost, qaly = qaly) |>
dplyr::mutate(net_benefit = threshold[1] * qaly - cost)
stopifnot(abs(diff(strategies$net_benefit) - (threshold[1] * gap[2] - gap[1])) < 1e-9)
#%%@note 2. Inputs the model needs
# The trial's two risks, the weight behind a QALY, and one yearly rate as a cycle's chance.
# ความเสี่ยงสองค่าจากการทดลอง ค่าน้ำหนักเบื้องหลัง QALY และอัตรารายปีที่แปลงเป็นโอกาสในหนึ่งรอบ
events <- c(8, 13)
treated <- c(66, 60)
weight <- 0.70
years <- 10
rate <- 0.12
cycle <- 0.25
#%%@note 3. The model and the yearly bill
# One cycle of the cohort, an option that costs more for less health, and the yearly bill.
# หนึ่งรอบของกลุ่มประชากร ทางเลือกที่มีต้นทุนมากกว่าแต่ได้สุขภาพน้อยกว่า และค่าใช้จ่ายต่อปี
start <- 1000
move <- c(0.80, 0.15, 0.05)
d_cost <- 20000
d_loss <- 0.10
new_patients <- 100
extra_cost <- 150000
stopifnot(extra_cost == gap[1], abs(sum(move) - 1) < 1e-9)
#%%@note 4. Testing the answer
# How often C wins when its INMB is uncertain, and the value of knowing the true state first.
# C ชนะบ่อยเพียงใดเมื่อ INMB ไม่แน่นอน และมูลค่าของการรู้สถานการณ์จริงก่อนเลือก
mean_inmb <- 10000
sd_inmb <- 40000
runs <- 1000
share <- stats::pnorm(mean_inmb / sd_inmb)
option_1 <- c(100, 140, 90, 130)
option_2 <- c(120, 110, 150, 100)
known <- mean(pmax(option_1, option_2))
single <- max(mean(option_1), mean(option_2))
stopifnot(mean_inmb == threshold[1] * gap[2] - gap[1])
#%%@note 5. Display the two strategies
# Plot cost against QALYs for A and C; the script saves no graphics file.
# แสดงต้นทุนเทียบกับ QALY ของ A และ C โดยไม่บันทึกไฟล์ภาพ
print(ggplot2::ggplot(strategies, ggplot2::aes(x = qaly, y = cost, label = strategy)) +
ggplot2::geom_point() + ggplot2::geom_text(nudge_y = 8000))
#%%@note 6. Numbers the article quotes
# Print the four short boxes' lines in their reading order.
# พิมพ์ผลลัพธ์ตรงกับกล่องสั้นทั้งสี่ตามลำดับในบทความ
cat("Cost per patient on A and on C (THB):", nice(cost), "\n")
cat("QALYs per patient on A and on C:", nice(qaly, 2), "\n")
cat("NMB of A and of C at 160,000 THB per QALY (THB):", nice(threshold[1] * qaly - cost), "\n")
cat("Extra cost (THB) and extra QALYs of C:", nice(gap[1]), nice(gap[2], 2), "\n")
cat("Cost per extra QALY (THB):", nice(gap[1] / gap[2]), "\n")
cat("INMB of C at 160,000, 150,000 and 140,000 (THB):", nice(threshold * gap[2] - gap[1]), "\n")
cat("Complication risk on C and on A:", paste0(nice(100 * events / treated, 2), "%"), "\n")
cat("QALYs over 10 years at 0.70, and the gain to full health:", nice(weight * years, 1),
nice(years * (1 - weight), 1), "\n")
cat("Chance of moving in one cycle, exact and shortcut:", nice(1 - exp(-rate * cycle), 4),
nice(rate * cycle, 4), "\n")
cat("Of 1,000 well people after one cycle (well, sick, dead):", start * move, "\n")
cat("D against C: extra cost (THB) and QALYs lost:", nice(d_cost), nice(d_loss, 2), "\n")
cat("D costs more and gives less health:", d_cost > 0 && d_loss > 0, "\n")
cat("Extra spending a year (THB):", nice(new_patients * extra_cost), "\n")
cat("Mean INMB over its spread:", formatC(mean_inmb / sd_inmb, format = "f", digits = 2), "\n")
cat("Share above zero, and the part past the centre:", round(c(share, share - 0.5), 4), "\n")
cat("Runs of 1,000 for C, and as a share:", round(runs * share), sprintf("%.2f", share), "\n")
cat("Best choice per state, best single choice, the gain:", known, single, known - single, "\n")
ขั้นที่หนึ่ง: เตรียมข้อมูลนำเข้า
ก่อนตัวเลขใด ๆ แบบจำลองต้องมีรูปร่าง สถานะ (state) คือที่ที่ผู้ป่วยอยู่ ณ เวลาหนึ่ง เช่น สุขภาพดี ป่วย หรือเสียชีวิต ส่วนเหตุการณ์ (event) เช่น ภาวะแทรกซ้อน คือสิ่งที่เกิดขึ้นระหว่างทาง ผู้ป่วยของคณะกรรมการเจอภาวะแทรกซ้อนครั้งเดียวในช่วงแรก แล้วใช้เวลาหลายปีย้ายไปมาระหว่างสถานะ แผนภาพแตกกิ่งที่วาดครั้งเดียว (ต้นไม้การตัดสินใจ) เหมาะกับเหตุการณ์ช่วงแรก ส่วนหลายปีหลังจากนั้น แบบจำลองเดินไปตามเวลาเป็นรอบ (cycle) ซึ่งแต่ละรอบคือช่วงเวลาหนึ่งก้าวที่ยาวเท่ากัน และย้ายผู้ป่วยระหว่างสถานะทุกก้าว (Siebert และคณะ)
บทความที่สองให้เส้นทางทางคลินิกนี้เป็นตัวกำหนดโครงสร้างของแบบจำลอง การเลือกแบบจำลองเพื่อการตัดสินใจ: ให้เส้นทางทางคลินิกกำหนดโครงสร้าง จากนั้นจึงถึงตัวเลขที่เติมลงในโครงสร้าง พารามิเตอร์ (parameter) คือข้อมูลนำเข้าหนึ่งตัวที่แบบจำลองต้องใช้ เช่น ความเสี่ยงของภาวะแทรกซ้อน ค่าคุณภาพชีวิตของหนึ่งปีที่ป่วย หรือต้นทุนของการมาตรวจหนึ่งครั้ง บทความที่สามใส่แต่ละตัวลงตาราง พร้อมค่า แหล่งที่มา และระดับความมั่นใจ ข้อมูลนำเข้าของแบบจำลองที่ตรวจสอบได้: สร้างตารางพารามิเตอร์ที่สืบย้อนถึงที่มา
ข้อมูลนำเข้าส่วนใหญ่มาจากงานวิจัยที่ตีพิมพ์ บทความที่สี่ตรวจว่าค่าประมาณแต่ละค่าตอบคำถามของแบบจำลองจริง การค้นหาข้อมูลนำเข้าของแบบจำลองจากวรรณกรรม: เลือกค่าประมาณให้ตรงกับคำถาม การทดลองให้ความเสี่ยงของภาวะแทรกซ้อน คือ 8 จาก 66 เท่ากับ 12.12% เมื่อได้ C และ 13 จาก 60 เท่ากับ 21.67% เมื่อได้ A ก่อนนำค่าเหล่านี้เข้าแบบจำลอง ให้ถามว่าผู้ป่วยและช่วงติดตามของการทดลองตรงกับผู้ใหญ่ในอำเภอหรือไม่
ขั้นสุดท้ายของข้อมูลนำเข้าคือเวลา ซึ่งเป็นเรื่องของบทความที่ห้า ความน่าจะเป็นของการเปลี่ยนสถานะ (transition probability) คือโอกาสย้ายระหว่างสองสถานะภายในหนึ่งรอบ ซึ่งต้องแปลงมาจากอัตราโดยนำความยาวของรอบมาคิดด้วย ตัวอย่างเช่น อัตรา 0.12 ต่อปี ถ้ารอบยาว 0.25 ปี โอกาสที่ถูกต้องคือ 0.0296 ไม่ใช่ 0.0300 จากทางลัดที่เอาอัตราคูณความยาวรอบ อ่านบทเรียนเต็มได้ที่ อัตรา ความน่าจะเป็น และความน่าจะเป็นของการเปลี่ยนสถานะ: คำนวณโดยไม่หลงหน่วยเวลา การแปลงแบบเดียวกันโดยใช้ความยาวรอบของแบบจำลองเอง ให้โอกาสทุกค่าที่แบบจำลองของคณะกรรมการใช้
ตามรอยข้อมูลนำเข้าของขั้นที่หนึ่งด้วย R
# Inputs: the trial's two risks, the weight behind a QALY, and a yearly rate as one cycle's chance.
nice <- function(value, places = 0) formatC(value, format = "f", digits = places, big.mark = ",")
events <- c(8, 13)
treated <- c(66, 60)
cat("Complication risk on C and on A:", paste0(nice(100 * events / treated, 2), "%"), "\n")
weight <- 0.70
years <- 10
cat("QALYs over 10 years at 0.70, and the gain to full health:", nice(weight * years, 1),
nice(years * (1 - weight), 1), "\n")
rate <- 0.12
cycle <- 0.25
cat("Chance of moving in one cycle, exact and shortcut:", nice(1 - exp(-rate * cycle), 4),
nice(rate * cycle, 4), "\n")
Complication risk on C and on A: 12.12% 21.67%
QALYs over 10 years at 0.70, and the gain to full health: 7.0 3.0
Chance of moving in one cycle, exact and shortcut: 0.0296 0.0300
ต้องใช้ R ≥ 4.5.2 · tibble 3.3.1 · dplyr 1.2.1 · ggplot2 4.0.3 · ใช้ได้กับ R 4.6.1 · ดาวน์โหลด health-economic-modelling-series-guide.R
สคริปต์ฉบับเต็ม
# Health Economic Modelling Series Guide: From Evidence to a Decision
# คู่มือชุดบทความ: ติดตามกรณีของคณะกรรมการ ตั้งแต่ข้อมูลนำเข้า แบบจำลอง จนถึงการทดสอบคำตอบ
# Requires: R >= 4.5.2
# Tested: works in R 4.6.1
# tibble 3.3.1 (stable)
# dplyr 1.2.1 (stable)
# ggplot2 4.0.3 (stable)
# install.packages(c("tibble", "dplyr", "ggplot2"))
# update.packages(oldPkgs = c("tibble", "dplyr", "ggplot2"))
# remotes::install_version("tibble", "3.3.1")
# remotes::install_version("dplyr", "1.2.1")
# remotes::install_version("ggplot2", "4.0.3")
library(tibble) # Write the two strategies as one explicit input table.
library(dplyr) # Add each strategy's net benefit at the threshold.
library(ggplot2) # Display the two strategies without saving files.
stopifnot(getRversion() >= "4.5.2")
#%%@note 1. The committee's case
# Per patient over the model's horizon: cost and QALYs of usual care A and of treatment C.
# ต้นทุนและ QALY ต่อผู้ป่วยตลอดช่วงเวลาของแบบจำลอง ของการดูแลตามปกติ A และการรักษา C
nice <- function(value, places = 0) formatC(value, format = "f", digits = places, big.mark = ",")
cost <- c(50000, 200000)
qaly <- c(8, 9)
threshold <- c(160000, 150000, 140000)
gap <- c(diff(cost), diff(qaly))
strategies <- tibble::tibble(strategy = c("A", "C"), cost = cost, qaly = qaly) |>
dplyr::mutate(net_benefit = threshold[1] * qaly - cost)
stopifnot(abs(diff(strategies$net_benefit) - (threshold[1] * gap[2] - gap[1])) < 1e-9)
#%%@note 2. Inputs the model needs
# The trial's two risks, the weight behind a QALY, and one yearly rate as a cycle's chance.
# ความเสี่ยงสองค่าจากการทดลอง ค่าน้ำหนักเบื้องหลัง QALY และอัตรารายปีที่แปลงเป็นโอกาสในหนึ่งรอบ
events <- c(8, 13)
treated <- c(66, 60)
weight <- 0.70
years <- 10
rate <- 0.12
cycle <- 0.25
#%%@note 3. The model and the yearly bill
# One cycle of the cohort, an option that costs more for less health, and the yearly bill.
# หนึ่งรอบของกลุ่มประชากร ทางเลือกที่มีต้นทุนมากกว่าแต่ได้สุขภาพน้อยกว่า และค่าใช้จ่ายต่อปี
start <- 1000
move <- c(0.80, 0.15, 0.05)
d_cost <- 20000
d_loss <- 0.10
new_patients <- 100
extra_cost <- 150000
stopifnot(extra_cost == gap[1], abs(sum(move) - 1) < 1e-9)
#%%@note 4. Testing the answer
# How often C wins when its INMB is uncertain, and the value of knowing the true state first.
# C ชนะบ่อยเพียงใดเมื่อ INMB ไม่แน่นอน และมูลค่าของการรู้สถานการณ์จริงก่อนเลือก
mean_inmb <- 10000
sd_inmb <- 40000
runs <- 1000
share <- stats::pnorm(mean_inmb / sd_inmb)
option_1 <- c(100, 140, 90, 130)
option_2 <- c(120, 110, 150, 100)
known <- mean(pmax(option_1, option_2))
single <- max(mean(option_1), mean(option_2))
stopifnot(mean_inmb == threshold[1] * gap[2] - gap[1])
#%%@note 5. Display the two strategies
# Plot cost against QALYs for A and C; the script saves no graphics file.
# แสดงต้นทุนเทียบกับ QALY ของ A และ C โดยไม่บันทึกไฟล์ภาพ
print(ggplot2::ggplot(strategies, ggplot2::aes(x = qaly, y = cost, label = strategy)) +
ggplot2::geom_point() + ggplot2::geom_text(nudge_y = 8000))
#%%@note 6. Numbers the article quotes
# Print the four short boxes' lines in their reading order.
# พิมพ์ผลลัพธ์ตรงกับกล่องสั้นทั้งสี่ตามลำดับในบทความ
cat("Cost per patient on A and on C (THB):", nice(cost), "\n")
cat("QALYs per patient on A and on C:", nice(qaly, 2), "\n")
cat("NMB of A and of C at 160,000 THB per QALY (THB):", nice(threshold[1] * qaly - cost), "\n")
cat("Extra cost (THB) and extra QALYs of C:", nice(gap[1]), nice(gap[2], 2), "\n")
cat("Cost per extra QALY (THB):", nice(gap[1] / gap[2]), "\n")
cat("INMB of C at 160,000, 150,000 and 140,000 (THB):", nice(threshold * gap[2] - gap[1]), "\n")
cat("Complication risk on C and on A:", paste0(nice(100 * events / treated, 2), "%"), "\n")
cat("QALYs over 10 years at 0.70, and the gain to full health:", nice(weight * years, 1),
nice(years * (1 - weight), 1), "\n")
cat("Chance of moving in one cycle, exact and shortcut:", nice(1 - exp(-rate * cycle), 4),
nice(rate * cycle, 4), "\n")
cat("Of 1,000 well people after one cycle (well, sick, dead):", start * move, "\n")
cat("D against C: extra cost (THB) and QALYs lost:", nice(d_cost), nice(d_loss, 2), "\n")
cat("D costs more and gives less health:", d_cost > 0 && d_loss > 0, "\n")
cat("Extra spending a year (THB):", nice(new_patients * extra_cost), "\n")
cat("Mean INMB over its spread:", formatC(mean_inmb / sd_inmb, format = "f", digits = 2), "\n")
cat("Share above zero, and the part past the centre:", round(c(share, share - 0.5), 4), "\n")
cat("Runs of 1,000 for C, and as a share:", round(runs * share), sprintf("%.2f", share), "\n")
cat("Best choice per state, best single choice, the gain:", known, single, known - single, "\n")
ขั้นที่สอง: สร้างและเปรียบเทียบแบบจำลอง
ภาวะแทรกซ้อนช่วงแรกเหมาะกับต้นไม้การตัดสินใจ ซึ่งเป็นเรื่องของบทความที่หก สร้างแผนภูมิต้นไม้การตัดสินใจทีละขั้น: ตามรอยผลลัพธ์ ต้นทุน และสุขภาพ เมื่อได้ A ผู้ป่วย 21.67% เข้ากิ่งที่เกิดภาวะแทรกซ้อน ที่เหลือเข้าอีกกิ่ง ส่วนเมื่อได้ C มี 12.12% ที่เข้ากิ่งนั้น ต้นไม้ถ่วงต้นทุนและ QALY ของแต่ละกิ่งด้วยสัดส่วนเหล่านี้ แล้วรวมกัน
หลายปีหลังจากนั้นต้องใช้สถานะและรอบ ซึ่งเป็นเรื่องของบทความที่เจ็ด แบบจำลองมาร์คอฟ (Markov model) คือการติดตามกลุ่มคนที่ย้ายระหว่างสถานะสุขภาพไม่กี่สถานะทีละรอบ ใน 1,000 คนที่เริ่มสุขภาพดี รอบแรก 800 คนยังสุขภาพดี, 150 คนป่วย และ 50 คนเสียชีวิต อ่านบทเรียนเต็มได้ที่ สร้างแบบจำลองมาร์คอฟแบบกลุ่มประชากรทีละขั้น: ติดตามประชากรผ่านเวลา การทำซ้ำรอบแบบนี้ตลอดช่วงเวลาของแบบจำลอง แล้วรวมจำนวนคน ต้นทุน และคุณภาพชีวิตของทุกรอบ ทำให้ A ได้ 8.00 QALY ที่ต้นทุน 50,000 บาท ส่วน C ได้ 9.00 QALY ที่ต้นทุน 200,000 บาท
บทความที่แปดนับคนก่อนนับเงิน การวิเคราะห์ผลกระทบด้านงบประมาณในทางปฏิบัติ: นับคนให้ชัดก่อนคำนวณเงิน สมมติว่ามีผู้ป่วยใหม่ราว 100 คนต่อปีเริ่มได้รับ C และต้นทุนที่เพิ่ม 150,000 บาทของแต่ละคนจ่ายในปีที่เริ่มรักษา อำเภอจะใช้เงินเพิ่ม 15,000,000 บาทต่อปี ถ้าต้นทุนของผู้ป่วยกลุ่มหนึ่งกระจายไปหลายปี ค่าใช้จ่ายของกลุ่มนั้นในแต่ละปีจะน้อยลงแต่ต้องจ่ายนานขึ้น ค่าใช้จ่ายต่อปีของอำเภอนี้ตอบคนละคำถามกับความคุ้มค่า
คณะกรรมการตัวจริงไม่ค่อยเทียบแค่สองทางเลือก บทความที่เก้าจึงเรียงหลายทางเลือกตามต้นทุน ICER และผลประโยชน์สุทธิในรูปตัวเงินเมื่อมีหลายทางเลือก: หาขอบเขตทางเลือกที่มีประสิทธิภาพ การครอบงำ (dominance) คือกฎที่ตัดทางเลือกออกเมื่อมีอีกทางเลือกที่ต้นทุนต่ำกว่าและให้สุขภาพไม่น้อยกว่า สมมติมีทางเลือกที่สาม D ซึ่งมีต้นทุนมากกว่า C อยู่ 20,000 บาท แต่ได้ QALY น้อยกว่า C อยู่ 0.10 ดังนั้น C ครอบงำ D อ่านบทเรียนเต็มได้ที่ อัตราส่วนต้นทุนประสิทธิผลส่วนเพิ่มและระนาบต้นทุนประสิทธิผล: ทางเลือกที่ด้อยกว่า ผลประโยชน์สุทธิ และเกณฑ์ 160,000 บาทต่อปีสุขภาวะ
ตามรอยแบบจำลองและค่าใช้จ่ายต่อปีด้วย R
# The model: one cycle of the cohort, an option that is beaten outright, and the yearly bill.
nice <- function(value, places = 0) formatC(value, format = "f", digits = places, big.mark = ",")
start <- 1000
move <- c(0.80, 0.15, 0.05)
cat("Of 1,000 well people after one cycle (well, sick, dead):", start * move, "\n")
d_cost <- 20000
d_loss <- 0.10
cat("D against C: extra cost (THB) and QALYs lost:", nice(d_cost), nice(d_loss, 2), "\n")
cat("D costs more and gives less health:", d_cost > 0 && d_loss > 0, "\n")
new_patients <- 100
extra_cost <- 150000
cat("Extra spending a year (THB):", nice(new_patients * extra_cost), "\n")
Of 1,000 well people after one cycle (well, sick, dead): 800 150 50
D against C: extra cost (THB) and QALYs lost: 20,000 0.10
D costs more and gives less health: TRUE
Extra spending a year (THB): 15,000,000
ต้องใช้ R ≥ 4.5.2 · tibble 3.3.1 · dplyr 1.2.1 · ggplot2 4.0.3 · ใช้ได้กับ R 4.6.1 · ดาวน์โหลด health-economic-modelling-series-guide.R
สคริปต์ฉบับเต็ม
# Health Economic Modelling Series Guide: From Evidence to a Decision
# คู่มือชุดบทความ: ติดตามกรณีของคณะกรรมการ ตั้งแต่ข้อมูลนำเข้า แบบจำลอง จนถึงการทดสอบคำตอบ
# Requires: R >= 4.5.2
# Tested: works in R 4.6.1
# tibble 3.3.1 (stable)
# dplyr 1.2.1 (stable)
# ggplot2 4.0.3 (stable)
# install.packages(c("tibble", "dplyr", "ggplot2"))
# update.packages(oldPkgs = c("tibble", "dplyr", "ggplot2"))
# remotes::install_version("tibble", "3.3.1")
# remotes::install_version("dplyr", "1.2.1")
# remotes::install_version("ggplot2", "4.0.3")
library(tibble) # Write the two strategies as one explicit input table.
library(dplyr) # Add each strategy's net benefit at the threshold.
library(ggplot2) # Display the two strategies without saving files.
stopifnot(getRversion() >= "4.5.2")
#%%@note 1. The committee's case
# Per patient over the model's horizon: cost and QALYs of usual care A and of treatment C.
# ต้นทุนและ QALY ต่อผู้ป่วยตลอดช่วงเวลาของแบบจำลอง ของการดูแลตามปกติ A และการรักษา C
nice <- function(value, places = 0) formatC(value, format = "f", digits = places, big.mark = ",")
cost <- c(50000, 200000)
qaly <- c(8, 9)
threshold <- c(160000, 150000, 140000)
gap <- c(diff(cost), diff(qaly))
strategies <- tibble::tibble(strategy = c("A", "C"), cost = cost, qaly = qaly) |>
dplyr::mutate(net_benefit = threshold[1] * qaly - cost)
stopifnot(abs(diff(strategies$net_benefit) - (threshold[1] * gap[2] - gap[1])) < 1e-9)
#%%@note 2. Inputs the model needs
# The trial's two risks, the weight behind a QALY, and one yearly rate as a cycle's chance.
# ความเสี่ยงสองค่าจากการทดลอง ค่าน้ำหนักเบื้องหลัง QALY และอัตรารายปีที่แปลงเป็นโอกาสในหนึ่งรอบ
events <- c(8, 13)
treated <- c(66, 60)
weight <- 0.70
years <- 10
rate <- 0.12
cycle <- 0.25
#%%@note 3. The model and the yearly bill
# One cycle of the cohort, an option that costs more for less health, and the yearly bill.
# หนึ่งรอบของกลุ่มประชากร ทางเลือกที่มีต้นทุนมากกว่าแต่ได้สุขภาพน้อยกว่า และค่าใช้จ่ายต่อปี
start <- 1000
move <- c(0.80, 0.15, 0.05)
d_cost <- 20000
d_loss <- 0.10
new_patients <- 100
extra_cost <- 150000
stopifnot(extra_cost == gap[1], abs(sum(move) - 1) < 1e-9)
#%%@note 4. Testing the answer
# How often C wins when its INMB is uncertain, and the value of knowing the true state first.
# C ชนะบ่อยเพียงใดเมื่อ INMB ไม่แน่นอน และมูลค่าของการรู้สถานการณ์จริงก่อนเลือก
mean_inmb <- 10000
sd_inmb <- 40000
runs <- 1000
share <- stats::pnorm(mean_inmb / sd_inmb)
option_1 <- c(100, 140, 90, 130)
option_2 <- c(120, 110, 150, 100)
known <- mean(pmax(option_1, option_2))
single <- max(mean(option_1), mean(option_2))
stopifnot(mean_inmb == threshold[1] * gap[2] - gap[1])
#%%@note 5. Display the two strategies
# Plot cost against QALYs for A and C; the script saves no graphics file.
# แสดงต้นทุนเทียบกับ QALY ของ A และ C โดยไม่บันทึกไฟล์ภาพ
print(ggplot2::ggplot(strategies, ggplot2::aes(x = qaly, y = cost, label = strategy)) +
ggplot2::geom_point() + ggplot2::geom_text(nudge_y = 8000))
#%%@note 6. Numbers the article quotes
# Print the four short boxes' lines in their reading order.
# พิมพ์ผลลัพธ์ตรงกับกล่องสั้นทั้งสี่ตามลำดับในบทความ
cat("Cost per patient on A and on C (THB):", nice(cost), "\n")
cat("QALYs per patient on A and on C:", nice(qaly, 2), "\n")
cat("NMB of A and of C at 160,000 THB per QALY (THB):", nice(threshold[1] * qaly - cost), "\n")
cat("Extra cost (THB) and extra QALYs of C:", nice(gap[1]), nice(gap[2], 2), "\n")
cat("Cost per extra QALY (THB):", nice(gap[1] / gap[2]), "\n")
cat("INMB of C at 160,000, 150,000 and 140,000 (THB):", nice(threshold * gap[2] - gap[1]), "\n")
cat("Complication risk on C and on A:", paste0(nice(100 * events / treated, 2), "%"), "\n")
cat("QALYs over 10 years at 0.70, and the gain to full health:", nice(weight * years, 1),
nice(years * (1 - weight), 1), "\n")
cat("Chance of moving in one cycle, exact and shortcut:", nice(1 - exp(-rate * cycle), 4),
nice(rate * cycle, 4), "\n")
cat("Of 1,000 well people after one cycle (well, sick, dead):", start * move, "\n")
cat("D against C: extra cost (THB) and QALYs lost:", nice(d_cost), nice(d_loss, 2), "\n")
cat("D costs more and gives less health:", d_cost > 0 && d_loss > 0, "\n")
cat("Extra spending a year (THB):", nice(new_patients * extra_cost), "\n")
cat("Mean INMB over its spread:", formatC(mean_inmb / sd_inmb, format = "f", digits = 2), "\n")
cat("Share above zero, and the part past the centre:", round(c(share, share - 0.5), 4), "\n")
cat("Runs of 1,000 for C, and as a share:", round(runs * share), sprintf("%.2f", share), "\n")
cat("Best choice per state, best single choice, the gain:", known, single, known - single, "\n")
ขั้นที่สาม: ทดสอบคำตอบ
ข้อมูลนำเข้าทุกตัวข้างต้นไม่แน่นอน และการทดลองขนาดเล็กเช่นนี้ทำให้ผลของการรักษาไม่แน่นอนเป็นพิเศษ ซึ่งเป็นเรื่องของบทความที่สิบ การวิเคราะห์ความไวเชิงความน่าจะเป็น (probabilistic sensitivity analysis, PSA) คือการรันแบบจำลองซ้ำหลายครั้ง โดยสุ่มค่าของข้อมูลนำเข้าที่ไม่แน่นอนทุกตัวจากการแจกแจงของมัน ผลจึงเป็นสัดส่วนของการรันซ้ำ ไม่ใช่ตัวเลขเดียว เมื่อผลประโยชน์สุทธิส่วนเพิ่มเฉลี่ย 10,000 บาท และส่วนเบี่ยงเบนมาตรฐาน 40,000 บาท จะมีราว 599 จาก 1,000 ครั้งที่การรักษาคุ้มค่า อ่านบทเรียนเต็มได้ที่ การวิเคราะห์ความไวแบบอาศัยความน่าจะเป็น: จากการแจกแจงพารามิเตอร์สู่ CEAC
ตัวเลข 599 มาจากไหน ส่วนเบี่ยงเบนมาตรฐานคือระยะห่างโดยทั่วไปของผลแต่ละครั้งจากค่าเฉลี่ย ในที่นี้ค่าเฉลี่ย 10,000 อยู่สูงกว่าศูนย์ 0.25 เท่าของระยะนั้น (10,000 / 40,000) ถ้าผลกระจายเป็นเส้นโค้งรูประฆังสมมาตร ส่วนของเส้นโค้งที่อยู่เหนือศูนย์คือ 0.5987 ได้แก่ครึ่งหนึ่งที่อยู่เหนือค่าเฉลี่ย บวกอีก 0.0987 ระหว่างศูนย์กับค่าเฉลี่ย จึงเป็นสัดส่วน 0.60 ของครั้งที่รันซ้ำ หรือราว 599 จาก 1,000 ครั้ง
เส้นโค้งการยอมรับความคุ้มค่า (cost-effectiveness acceptability curve, CEAC) คือเส้นที่แสดงสัดส่วนของครั้งที่รันซ้ำที่การรักษาคุ้มที่สุด คือมีผลประโยชน์สุทธิสูงกว่า ในแต่ละระดับเกณฑ์ ที่ 160,000 บาทต่อ QALY เส้นนี้อยู่ที่ 0.60 เพราะราว 599 จาก 1,000 ครั้งให้ผลเข้าข้างการรักษา ดูเส้นนี้แบบเต็มได้ที่ การวิเคราะห์ความไวแบบอาศัยความน่าจะเป็น: จากการแจกแจงพารามิเตอร์สู่ CEAC
แบบจำลองยังผิดได้อีกแบบหนึ่งที่พื้นฐานกว่านั้น บทความที่สิบเอ็ดทดสอบสองเรื่อง การประเมินความสมเหตุสมผลและตรวจสอบแบบจำลอง: ทดสอบคำถาม สมการ และโค้ด การตรวจสอบการคำนวณ (verification) ถามว่าโค้ดคำนวณตรงกับสมการหรือไม่ เช่น 160,000 × 1.00 - 150,000 ที่คิดด้วยมือต้องได้ 10,000 เท่ากับแบบจำลอง การประเมินความสมเหตุสมผล (validation) ถามว่าแบบจำลองเป็นภาพที่น่าเชื่อของเส้นทางจริงหรือไม่ โครงสร้างสมเหตุสมผลทางคลินิกหรือไม่ และผลที่ทำนายตรงกับที่สังเกตได้หรือไม่ เช่น ความเสี่ยงภาวะแทรกซ้อน 21.67% เมื่อได้การดูแลตามปกติ (Eddy และคณะ)
บทความที่สิบสองถามว่าหลักฐานที่ดีขึ้นคุ้มที่จะซื้อก่อนตัดสินใจหรือไม่ มูลค่าคาดหมายของข้อมูลสมบูรณ์ (expected value of perfect information, EVPI) คือประโยชน์เฉลี่ยที่ได้จากการรู้ว่าสถานการณ์จริงเป็นแบบใดก่อนเลือก ลองดูตัวอย่างสมมติเล็ก ๆ ที่วัดเป็นหน่วยผลประโยชน์สุทธิ ในสี่สถานการณ์ที่มีโอกาสเท่ากัน ทางเลือกแรกได้ 100, 140, 90 และ 130 ส่วนทางเลือกที่สองได้ 120, 110, 150 และ 100 ตามลำดับ ถ้ารู้สถานการณ์ก่อนแล้วเลือกทางที่ดีกว่าในแต่ละสถานการณ์ (120, 140, 150 และ 130) จะได้เฉลี่ย 135 ถ้าต้องเลือกทางเดียวโดยไม่รู้ ทางที่ดีที่สุดคือทางเลือกที่สอง ได้เฉลี่ย 120 EVPI จึงเท่ากับ 15 อ่านบทเรียนเต็มได้ที่ มูลค่าคาดหมายของข้อมูลสมบูรณ์: หลักฐานที่ดีขึ้นอาจมีมูลค่าเพียงใด
หลักฐานเพิ่มเติมที่ราคาสูงกว่า 15 ในหน่วยนี้จึงไม่มีทางคุ้ม
ตามรอยการทดสอบคำตอบด้วย R
# Testing the answer: how often C wins when its INMB is uncertain; what perfect knowledge is worth.
mean_inmb <- 10000
sd_inmb <- 40000
runs <- 1000
share <- stats::pnorm(mean_inmb / sd_inmb)
cat("Mean INMB over its spread:", formatC(mean_inmb / sd_inmb, format = "f", digits = 2), "\n")
cat("Share above zero, and the part past the centre:", round(c(share, share - 0.5), 4), "\n")
cat("Runs of 1,000 for C, and as a share:", round(runs * share), sprintf("%.2f", share), "\n")
option_1 <- c(100, 140, 90, 130)
option_2 <- c(120, 110, 150, 100)
known <- mean(pmax(option_1, option_2))
single <- max(mean(option_1), mean(option_2))
cat("Best choice per state, best single choice, the gain:", known, single, known - single, "\n")
Mean INMB over its spread: 0.25
Share above zero, and the part past the centre: 0.5987 0.0987
Runs of 1,000 for C, and as a share: 599 0.60
Best choice per state, best single choice, the gain: 135 120 15
ต้องใช้ R ≥ 4.5.2 · tibble 3.3.1 · dplyr 1.2.1 · ggplot2 4.0.3 · ใช้ได้กับ R 4.6.1 · ดาวน์โหลด health-economic-modelling-series-guide.R
สคริปต์ฉบับเต็ม
# Health Economic Modelling Series Guide: From Evidence to a Decision
# คู่มือชุดบทความ: ติดตามกรณีของคณะกรรมการ ตั้งแต่ข้อมูลนำเข้า แบบจำลอง จนถึงการทดสอบคำตอบ
# Requires: R >= 4.5.2
# Tested: works in R 4.6.1
# tibble 3.3.1 (stable)
# dplyr 1.2.1 (stable)
# ggplot2 4.0.3 (stable)
# install.packages(c("tibble", "dplyr", "ggplot2"))
# update.packages(oldPkgs = c("tibble", "dplyr", "ggplot2"))
# remotes::install_version("tibble", "3.3.1")
# remotes::install_version("dplyr", "1.2.1")
# remotes::install_version("ggplot2", "4.0.3")
library(tibble) # Write the two strategies as one explicit input table.
library(dplyr) # Add each strategy's net benefit at the threshold.
library(ggplot2) # Display the two strategies without saving files.
stopifnot(getRversion() >= "4.5.2")
#%%@note 1. The committee's case
# Per patient over the model's horizon: cost and QALYs of usual care A and of treatment C.
# ต้นทุนและ QALY ต่อผู้ป่วยตลอดช่วงเวลาของแบบจำลอง ของการดูแลตามปกติ A และการรักษา C
nice <- function(value, places = 0) formatC(value, format = "f", digits = places, big.mark = ",")
cost <- c(50000, 200000)
qaly <- c(8, 9)
threshold <- c(160000, 150000, 140000)
gap <- c(diff(cost), diff(qaly))
strategies <- tibble::tibble(strategy = c("A", "C"), cost = cost, qaly = qaly) |>
dplyr::mutate(net_benefit = threshold[1] * qaly - cost)
stopifnot(abs(diff(strategies$net_benefit) - (threshold[1] * gap[2] - gap[1])) < 1e-9)
#%%@note 2. Inputs the model needs
# The trial's two risks, the weight behind a QALY, and one yearly rate as a cycle's chance.
# ความเสี่ยงสองค่าจากการทดลอง ค่าน้ำหนักเบื้องหลัง QALY และอัตรารายปีที่แปลงเป็นโอกาสในหนึ่งรอบ
events <- c(8, 13)
treated <- c(66, 60)
weight <- 0.70
years <- 10
rate <- 0.12
cycle <- 0.25
#%%@note 3. The model and the yearly bill
# One cycle of the cohort, an option that costs more for less health, and the yearly bill.
# หนึ่งรอบของกลุ่มประชากร ทางเลือกที่มีต้นทุนมากกว่าแต่ได้สุขภาพน้อยกว่า และค่าใช้จ่ายต่อปี
start <- 1000
move <- c(0.80, 0.15, 0.05)
d_cost <- 20000
d_loss <- 0.10
new_patients <- 100
extra_cost <- 150000
stopifnot(extra_cost == gap[1], abs(sum(move) - 1) < 1e-9)
#%%@note 4. Testing the answer
# How often C wins when its INMB is uncertain, and the value of knowing the true state first.
# C ชนะบ่อยเพียงใดเมื่อ INMB ไม่แน่นอน และมูลค่าของการรู้สถานการณ์จริงก่อนเลือก
mean_inmb <- 10000
sd_inmb <- 40000
runs <- 1000
share <- stats::pnorm(mean_inmb / sd_inmb)
option_1 <- c(100, 140, 90, 130)
option_2 <- c(120, 110, 150, 100)
known <- mean(pmax(option_1, option_2))
single <- max(mean(option_1), mean(option_2))
stopifnot(mean_inmb == threshold[1] * gap[2] - gap[1])
#%%@note 5. Display the two strategies
# Plot cost against QALYs for A and C; the script saves no graphics file.
# แสดงต้นทุนเทียบกับ QALY ของ A และ C โดยไม่บันทึกไฟล์ภาพ
print(ggplot2::ggplot(strategies, ggplot2::aes(x = qaly, y = cost, label = strategy)) +
ggplot2::geom_point() + ggplot2::geom_text(nudge_y = 8000))
#%%@note 6. Numbers the article quotes
# Print the four short boxes' lines in their reading order.
# พิมพ์ผลลัพธ์ตรงกับกล่องสั้นทั้งสี่ตามลำดับในบทความ
cat("Cost per patient on A and on C (THB):", nice(cost), "\n")
cat("QALYs per patient on A and on C:", nice(qaly, 2), "\n")
cat("NMB of A and of C at 160,000 THB per QALY (THB):", nice(threshold[1] * qaly - cost), "\n")
cat("Extra cost (THB) and extra QALYs of C:", nice(gap[1]), nice(gap[2], 2), "\n")
cat("Cost per extra QALY (THB):", nice(gap[1] / gap[2]), "\n")
cat("INMB of C at 160,000, 150,000 and 140,000 (THB):", nice(threshold * gap[2] - gap[1]), "\n")
cat("Complication risk on C and on A:", paste0(nice(100 * events / treated, 2), "%"), "\n")
cat("QALYs over 10 years at 0.70, and the gain to full health:", nice(weight * years, 1),
nice(years * (1 - weight), 1), "\n")
cat("Chance of moving in one cycle, exact and shortcut:", nice(1 - exp(-rate * cycle), 4),
nice(rate * cycle, 4), "\n")
cat("Of 1,000 well people after one cycle (well, sick, dead):", start * move, "\n")
cat("D against C: extra cost (THB) and QALYs lost:", nice(d_cost), nice(d_loss, 2), "\n")
cat("D costs more and gives less health:", d_cost > 0 && d_loss > 0, "\n")
cat("Extra spending a year (THB):", nice(new_patients * extra_cost), "\n")
cat("Mean INMB over its spread:", formatC(mean_inmb / sd_inmb, format = "f", digits = 2), "\n")
cat("Share above zero, and the part past the centre:", round(c(share, share - 0.5), 4), "\n")
cat("Runs of 1,000 for C, and as a share:", round(runs * share), sprintf("%.2f", share), "\n")
cat("Best choice per state, best single choice, the gain:", known, single, known - single, "\n")
แยกความคุ้มค่า นโยบาย และงบประมาณออกจากกัน
ผลของแบบจำลองมีเงื่อนไข ที่ 160,000 บาทต่อ QALY C มีมูลค่าสูงกว่าต้นทุนที่เพิ่มขึ้นอยู่ 10,000 บาทต่อผู้ป่วย เกณฑ์นั้นเป็นการเลือกเชิงนโยบาย ไม่ใช่ผลของแบบจำลอง ที่ 150,000 INMB เท่ากับ 0 และที่ 140,000 เท่ากับ -10,000 บาท โดยที่ผู้ป่วยและหลักฐานเหมือนเดิม
งบประมาณเป็นคำถามที่สาม ค่าใช้จ่าย 15,000,000 บาทต่อปีอาจเกินงบของอำเภอ แม้ C จะคุ้มค่าที่เกณฑ์ 160,000 บาทต่อ QALY ก็ตาม รายงานที่แยกความคุ้มค่า นโยบาย และงบประมาณออกจากกัน ช่วยให้คณะกรรมการเห็นว่ากำลังตัดสินใจเรื่องใดในสามเรื่องนี้ (Drummond และคณะ)
ชุดบทความพื้นฐานอยู่ตรงไหน
ชุดนี้ต่อยอดจากชุดบทความพื้นฐาน บทความเรื่องต้นไม้การตัดสินใจ แบบจำลองมาร์คอฟ และ PSA แสดงเครื่องมือทั้งสามเทียบกัน และบทความเรื่อง ICER การครอบงำ และเกณฑ์ความคุ้มค่า สอนบรรทัดของคณะกรรมการแบบเต็ม ถ้าขั้นใดข้างต้นรู้สึกเร็วไป ให้อ่านสองบทความนั้นก่อน
คำศัพท์ที่เราใช้
- Strategy (ทางเลือก)
- เส้นทางการดูแลทั้งเส้นที่คณะกรรมการเลือกได้ เช่น A หรือ C รวมทุกอย่างที่ตามมา
- Parameter (พารามิเตอร์)
- ข้อมูลนำเข้าหนึ่งตัวที่แบบจำลองต้องใช้ เช่น ความเสี่ยง 12.12% เมื่อได้ C หรือค่าคุณภาพชีวิต 0.70 ของปีที่ป่วย
- State and event (สถานะและเหตุการณ์)
- สถานะคือที่ที่ผู้ป่วยอยู่ ณ เวลาหนึ่ง (สุขภาพดี ป่วย เสียชีวิต) ส่วนเหตุการณ์ เช่น ภาวะแทรกซ้อน คือสิ่งที่เกิดระหว่างทาง
- Cycle and horizon (รอบและช่วงเวลาของแบบจำลอง)
- รอบคือช่วงเวลาหนึ่งก้าวที่ยาวเท่ากันของแบบจำลอง ส่วนช่วงเวลาของแบบจำลองคือระยะทั้งหมดที่แบบจำลองติดตามผู้ป่วย
- Threshold (เกณฑ์ความคุ้มค่า)
- เงินสูงสุดที่คณะกรรมการยอมจ่ายเพื่อให้ได้หนึ่ง QALY ในที่นี้คือ 160,000 บาท เป็นการเลือกเชิงนโยบาย ไม่ใช่ผลของแบบจำลอง
- Verification and validation (การตรวจสอบการคำนวณและการประเมินความสมเหตุสมผล)
- การตรวจสอบการคำนวณดูว่าโค้ดคำนวณตรงกับสมการ ส่วนการประเมินความสมเหตุสมผลดูว่าแบบจำลองเป็นภาพที่น่าเชื่อของเส้นทางจริง
ลองใช้ในแอป
เปิดแอปการประเมินทางเศรษฐศาสตร์ของเราเพื่อลองเปลี่ยนค่าข้อมูลนำเข้าและดูผลลัพธ์เปลี่ยนตาม ต้องเข้าสู่ระบบและใช้แผน Pro หรือ Max
แอปเริ่มจากค่าตัวอย่างของแอปเอง ตัวเลขในแอปจึงไม่ตรงกับบทความนี้
เอกสารอ้างอิง
- Andrew Briggs, Karl Claxton, Mark Sculpher. Decision Modelling for Health Economic Evaluation (Handbooks for Health Economic Evaluation). Oxford University Press; 2006. ISBN 9780198526629. https://openlibrary.org/isbn/9780198526629
- Siebert Uwe, Alagoz Oguzhan, Bayoumi Ahmed M., Jahn Beate, Owens Douglas K., Cohen David J., Kuntz Karen M.. State-Transition Modeling: A Report of the ISPOR-SMDM Modeling Good Research Practices Task Force-3. Value in Health. 2012;15(6):812-820. doi:10.1016/j.jval.2012.06.014. https://doi.org/10.1016/j.jval.2012.06.014
- Eddy David M., Hollingworth William, Caro J. Jaime, Tsevat Joel, McDonald Kathryn M., Wong John B.. Model Transparency and Validation: A Report of the ISPOR-SMDM Modeling Good Research Practices Task Force-7. Value in Health. 2012;15(6):843-850. doi:10.1016/j.jval.2012.04.012. https://doi.org/10.1016/j.jval.2012.04.012
- Michael F. Drummond, Mark J. Sculpher, Karl Claxton, Greg L. Stoddart, George W. Torrance. Methods for the Economic Evaluation of Health Care Programmes. Oxford University Press; 2015. ISBN 9780199665884. https://openlibrary.org/isbn/9780199665884
ลำดับการเรียนในชุดนี้
- คู่มือชุดบทความการสร้างแบบจำลองเศรษฐศาสตร์สุขภาพ: จากหลักฐานสู่การตัดสินใจ (บทความนี้)
- การเลือกแบบจำลองเพื่อการตัดสินใจ: ให้เส้นทางทางคลินิกกำหนดโครงสร้าง
- ข้อมูลนำเข้าของแบบจำลองที่ตรวจสอบได้: สร้างตารางพารามิเตอร์ที่สืบย้อนถึงที่มา
- การค้นหาข้อมูลนำเข้าของแบบจำลองจากวรรณกรรม: เลือกค่าประมาณให้ตรงกับคำถาม
- อัตรา ความน่าจะเป็น และความน่าจะเป็นของการเปลี่ยนสถานะ: คำนวณโดยไม่หลงหน่วยเวลา
- สร้างแผนภูมิต้นไม้การตัดสินใจทีละขั้น: ตามรอยผลลัพธ์ ต้นทุน และสุขภาพ
- สร้างแบบจำลองมาร์คอฟแบบกลุ่มประชากรทีละขั้น: ติดตามประชากรผ่านเวลา
- การวิเคราะห์ผลกระทบด้านงบประมาณในทางปฏิบัติ: นับคนให้ชัดก่อนคำนวณเงิน
- ICER และผลประโยชน์สุทธิในรูปตัวเงินเมื่อมีหลายทางเลือก: หาขอบเขตทางเลือกที่มีประสิทธิภาพ
- การวิเคราะห์ความไวแบบอาศัยความน่าจะเป็น: จากการแจกแจงพารามิเตอร์สู่ CEAC
- การประเมินความสมเหตุสมผลและตรวจสอบแบบจำลอง: ทดสอบคำถาม สมการ และโค้ด
- มูลค่าคาดหมายของข้อมูลสมบูรณ์: หลักฐานที่ดีขึ้นอาจมีมูลค่าเพียงใด
ประเด็นสำคัญ
- บรรทัดความคุ้มค่าเป็นปลายทางของแบบจำลอง 1.00 QALY ของ C มาจากการติดตามผู้ป่วยหลายปี ไม่ได้มาจากการทดลองอย่างเดียว
- เตรียมข้อมูลนำเข้าก่อนคำนวณผล ได้แก่ รูปร่างที่เส้นทางผู้ป่วยกำหนด ตารางที่สืบย้อนได้ แหล่งที่มาที่ตรงคำถาม และโอกาสต่อรอบที่คงเวลาไว้
- อ่านบรรทัดของคณะกรรมการได้สองแบบ คือ 150,000 บาทต่อ QALY เทียบกับเกณฑ์ 160,000 หรือ INMB 10,000 บาทต่อผู้ป่วย
- ทดสอบคำตอบ ราว 599 จาก 1,000 ครั้งที่รันซ้ำยังให้ C คุ้มค่า โค้ดต้องคำนวณตัวเลขของตัวเองได้ตรง และหลักฐานที่ดีขึ้นมีมูลค่าที่ควรรู้
- แยกความคุ้มค่า นโยบาย และงบประมาณออกจากกัน ที่ 140,000 บาทต่อ QALY หลักฐานเดิมให้คำตอบว่าไม่คุ้ม และค่าใช้จ่าย 15,000,000 บาทต่อปี เมื่อจ่ายในปีที่ผู้ป่วยเริ่มรักษา เป็นอีกคำถามหนึ่ง
อ่านต่อในวิกิ: ต้นไม้การตัดสินใจ แบบจำลองมาร์คอฟ และการวิเคราะห์ความไวเชิงความน่าจะเป็น: แบบจำลองแปลงหลักฐานเป็นการตัดสินใจได้อย่างไร · อัตราส่วนต้นทุนประสิทธิผลส่วนเพิ่มและระนาบต้นทุนประสิทธิผล: ทางเลือกที่ด้อยกว่า ผลประโยชน์สุทธิ และเกณฑ์ 160,000 บาทต่อปีสุขภาวะ