การวิเคราะห์ผลกระทบด้านงบประมาณในทางปฏิบัติ: นับคนให้ชัดก่อนคำนวณเงิน

On this page
Read the English version
บทคัดย่อ
กองทุนสุขภาพของอำเภอแห่งหนึ่งต้องตัดสินใจว่าจะจ่ายค่าบริการวัดความดันโลหิตที่บ้านให้ผู้ป่วยหลังโรคหลอดเลือดสมองหรือไม่ บริการนี้คือเครื่องวัดความดันที่บ้านและพยาบาลโทรติดตามทุกเดือน มีต้นทุนมากกว่าการดูแลตามปกติปีละ 2,000 บาทต่อผู้ใช้หนึ่งคน วันนี้มีผู้ป่วยที่มีสิทธิ 500 คน คำตอบเร็วคือคูณคนด้วยราคาและจำนวนปี 500 × 2,000 × 3 = 3,000,000 บาท แต่คำตอบนี้ผิด เพราะกลุ่มคนเปลี่ยนไปทุกปี แต่ละปีมีผู้ป่วยรายใหม่ที่เข้าเกณฑ์ 100 คน มีคน 10% ของกลุ่มออกไปเมื่อสิ้นปี และสัดส่วนผู้ป่วยที่ใช้บริการเพิ่มจาก 20% เป็น 40% และ 60% การนับคนก่อนจึงได้ผู้ใช้บริการ 120, 256 และ 405.6 คน และเงินสดส่วนเพิ่ม 240,000, 512,000 และ 811,200 บาท รวม 1,563,200 บาทในสามปี การนับเงินสดส่วนเพิ่มของผู้จ่ายทีละปีแบบนี้เรียกว่าการวิเคราะห์ผลกระทบด้านงบประมาณ (budget impact analysis) บทความนี้คิดรายจ่ายของแต่ละปีทั้งเมื่อมีและไม่มีบริการ เก็บทุกจำนวนเป็นเงินสดในปีที่จ่ายจริง และตรวจว่าพยาบาลรับผู้ใช้บริการได้ครบตามที่งบประมาณสมมติไว้หรือไม่
กองทุนอำเภอเดียว ผู้ป่วย 500 คน และบริการปีละ 2,000 บาท
กองทุนสุขภาพของอำเภอแห่งหนึ่งในจังหวัดหนึ่งของไทยจ่ายค่าดูแลผู้ป่วยหลังโรคหลอดเลือดสมองในพื้นที่ คลินิกของอำเภอนับผู้ป่วยที่เข้าเกณฑ์ของบริการใหม่ได้ 500 คน บริการนี้คือการวัดความดันโลหิตที่บ้าน โดยมีเครื่องวัดความดันไว้ที่บ้านและพยาบาลโทรติดตามทุกเดือน ผู้ป่วยแต่ละคนที่ใช้บริการทำให้กองทุนจ่ายมากกว่าการดูแลตามปกติ ปีละ 2,000 บาท ในทุกปีที่ยังใช้บริการอยู่
คณะกรรมการกองทุนถามคำถามเดียว คือในสามปีข้างหน้า แต่ละปีต้องหาเงินสดเพิ่มเท่าไร คำตอบเร็วคือคูณจำนวนคนด้วยราคาและจำนวนปี 500 × 2,000 × 3 = 3,000,000 บาท บทความนี้จะแก้วิธีคิดแบบนี้ กลุ่มผู้ป่วยเปลี่ยนไปทุกปี และไม่ใช่ทุกคนจะเริ่มใช้บริการพร้อมกัน
การนับคนก่อนให้ผลรวม 1,563,200 บาทในสามปี ประมาณครึ่งหนึ่งของคำตอบเร็ว ตัวเลขทั้งหมดเป็นตัวอย่างสมมติเพื่อการสอน
ใครมีสิทธิ: กลุ่มที่มีคนเข้าและคนออก
ก่อนนับเงิน กองทุนต้องรู้ว่าในแต่ละปีใครบ้างที่อาจใช้บริการได้ กลุ่มนี้ไม่คงที่ โรคหลอดเลือดสมองรายใหม่ทำให้มีผู้ป่วยใหม่เข้ามาในกลุ่ม และผู้ป่วยบางคนออกจากกลุ่มไป เพราะเสียชีวิต ย้ายที่อยู่ หรือไม่เข้าเกณฑ์แล้ว
ลองนึกถึงอ่างอาบน้ำ น้ำในอ่างคือทุกคนที่มีสิทธิ ณ ขณะหนึ่ง ก๊อกน้ำคือผู้ป่วยใหม่ 100 คนที่มีสิทธิในแต่ละปี และรูระบายคือคน 10% ของกลุ่มที่ออกไปเมื่อสิ้นปี ผู้ที่มีสิทธิ ณ ขณะหนึ่งเรียกว่ากลุ่มผู้มีสิทธิ (eligible stock) ส่วนผู้มาใหม่ในแต่ละปีเรียกว่าผู้มีสิทธิรายใหม่ (incident inflow)
การออกในที่นี้รวมทุกสาเหตุไว้ด้วยกัน ตัวอย่างนี้ไม่ได้แยกการเสียชีวิตออกจากการย้ายที่อยู่ ผู้ป่วยใหม่นับเต็มทั้งปีที่เข้ามา แม้จะเป็นโรคหลอดเลือดสมองในช่วงกลางปีก็ตาม
ใครใช้บริการ: สัดส่วนที่ค่อย ๆ เพิ่ม
ไม่ใช่ทุกคนที่มีสิทธิจะใช้บริการตั้งแต่ปีแรก พยาบาลต้องได้รับการอบรม ต้องจัดหาเครื่องวัดความดัน และแพทย์ต้องเริ่มส่งผู้ป่วยเข้าบริการ กองทุนคาดว่าสัดส่วนผู้ป่วยที่ใช้บริการจะเป็น 20% ในปีที่ 1, 40% ในปีที่ 2 และ 60% ในปีที่ 3 เมื่อบริการเข้าที่เข้าทาง
สัดส่วนรายปีนี้เรียกว่าสัดส่วนผู้ใช้บริการ (uptake) ซึ่งเป็นสัดส่วนของทุกคนที่มีสิทธิในปีนั้น ไม่ใช่สัดส่วนของผู้มาใหม่ ในปีที่ 1 ผู้ป่วยใหม่ 100 คนเข้ามาร่วมกับ 500 คนเดิมเมื่อต้นปี ผู้มีสิทธิจึงเป็น 600 คน และ 600 × 0.20 = 120 คนใช้บริการ
ทุกคนที่ใช้บริการในปีหนึ่ง ไม่ว่าจะเริ่มในปีนี้หรือก่อนหน้า เรียกว่าจำนวนผู้ใช้บริการทั้งหมดในปี (treated prevalence) นี่คือจำนวนที่กองทุนต้องจ่าย เพราะ 2,000 บาทเกิดซ้ำกับผู้ใช้ทุกคนในทุกปี
ลำดับภายในหนึ่งปี
แต่ละปีมีสี่ขั้น คือเพิ่มผู้มีสิทธิใหม่เมื่อต้นปี นับผู้ใช้บริการ คิดต้นทุนของผู้ใช้คนละ 2,000 บาท แล้วจึงให้ 10% พ้นสิทธิออกจากกลุ่มเมื่อสิ้นปี ผู้ที่พ้นสิทธิยังได้ใช้บริการในปีนั้น จึงต้องนับก่อนที่จะออกไป
ลำดับนี้เปลี่ยนคำตอบได้ ในปีที่ 1 ผู้มีสิทธิ 600 คนรวม 60 คนที่จะพ้นสิทธิเมื่อสิ้นปีไว้ด้วย ถ้าให้ 60 คนนั้นออกจากกลุ่มก่อน จะนับได้เพียง 540 คน คือผู้ใช้ 540 × 0.20 = 108 คน และ 108 × 2,000 = 216,000 บาท แทนที่จะเป็น 120 × 2,000 = 240,000 บาท กองทุนจะขาดเงินเท่ากับต้นทุนของผู้ป่วยที่ใช้บริการจริง
ตัวอย่างคำนวณ: สามปีของคน แล้วจึงเป็นเงินสด
แต่ละขั้นคือหนึ่งปี ทำตามลำดับข้างต้น
-
ปีที่ 1
\[ (500 + 100) \times 0.20 = 120 \]
ผู้ป่วยใหม่ 100 คนเข้ามาร่วมกับ 500 คนเมื่อต้นปี ผู้มีสิทธิจึงเป็น 600 คน และ 120 คนใช้บริการ กองทุนจ่าย 120 × 2,000 = 240,000 บาท เมื่อสิ้นปี 10% ของ 600 คนออกไป คือ 60 คน และเหลือ 540 คน
-
ปีที่ 2
\[ (540 + 100) \times 0.40 = 256 \]
ผู้มีสิทธิจึงเป็น 640 คน และ 256 คนใช้บริการ กองทุนจ่าย 256 × 2,000 = 512,000 บาท เมื่อสิ้นปี 64 คนจาก 640 คนออกไป และเหลือ 576 คน
-
ปีที่ 3
\[ (576 + 100) \times 0.60 = 405.6 \]
ผู้มีสิทธิจึงเป็น 676 คน และ 405.6 คนใช้บริการ กองทุนจ่าย 405.6 × 2,000 = 811,200 บาท ค่า 405.6 เป็นจำนวนคนคาดหมาย ซึ่งเป็นค่าเฉลี่ย จึงคงทศนิยมไว้ เมื่อสิ้นปี 10% ของ 676 คนออกไป คือ 67.6 คน และเหลือ 608.4 คน การนับสามปีจบที่ตรงนี้
-
รวมทุกปี
รวมสามปี 240,000 + 512,000 + 811,200 = 1,563,200 บาท ยอดสะสมคือ 240,000 บาท หลังปีที่ 1 และ 752,000 บาทหลังปีที่ 2
ผลลัพธ์: ในสามปี กองทุนต้องใช้เงินสดเพิ่ม 1,563,200 บาท ไม่ใช่ 3,000,000 บาทของคำตอบเร็ว คำตอบเร็วคิดต้นทุนของผู้ป่วยทั้ง 500 คนตั้งแต่วันแรก เหมือนกับว่าทุกคนใช้บริการในทุกปี
ชื่อเรียก: การวิเคราะห์ผลกระทบด้านงบประมาณ
การนับเงินสดส่วนเพิ่มของผู้จ่ายรายเดียวทีละปีแบบนี้เรียกว่าการวิเคราะห์ผลกระทบด้านงบประมาณ (budget impact analysis) ผู้จ่ายคือผู้ที่จ่ายค่าดูแล ในที่นี้คือกองทุนของอำเภอ การวิเคราะห์นี้ถามว่าผู้จ่ายจ่ายไหวหรือไม่ในแต่ละปี ไม่ได้ถามว่าการเปลี่ยนแปลงนั้นคุ้มค่าหรือไม่ (Sullivan and colleagues)
เขียนเป็นสัญลักษณ์ได้ว่า ให้ $E_y$ แทนกลุ่มผู้มีสิทธิในปี $y$ หลังผู้มาใหม่เข้ามาแล้ว $I$ แทนผู้มีสิทธิรายใหม่ (100) $x$ แทนสัดส่วนที่ออกเมื่อสิ้นปี (0.10) $u_y$ แทนสัดส่วนผู้ใช้บริการของปีนั้น และ $c$ แทนต้นทุนส่วนเพิ่มต่อผู้ใช้ (2,000 บาท) ปีที่ 1 เริ่มจากผู้มีสิทธิ 500 คนในปัจจุบัน จึงได้ $E_1 = 500 + I$ ตั้งแต่ปีที่ 2 เป็นต้นไป $E_y = E_{y-1}(1-x) + I$ เงินสดส่วนเพิ่มของปีคือ $B_y = E_y u_y c$ และยอดรวมคือผลบวกของ $B_y$ ทุกปี
ตรวจจำนวนคนด้วย R
# Illustrative district: stroke survivors who qualify for a home blood-pressure service.
# Writes: nothing to disk; the results print in the console.
prevalent <- 500
annual_incident <- 100
exit_fraction <- 0.10
uptake <- c(0.20,0.40,0.60)
eligible <- prevalent+annual_incident
for (year in 2:length(uptake)) eligible[year] <- eligible[year-1]*(1-exit_fraction)+annual_incident
treated <- eligible*uptake
cat("Year order:",seq_along(uptake),"\n")
cat("Eligible at year start (people):",eligible,"\n")
cat("Treated prevalence (people):",treated,"\n")
cat("Year-end exits (people):",eligible*exit_fraction,"\n")
cat("Remaining stock (people):",eligible*(1-exit_fraction),"\n")
Year order: 1 2 3
Eligible at year start (people): 600 640 676
Treated prevalence (people): 120 256 405.6
Year-end exits (people): 60 64 67.6
Remaining stock (people): 540 576 608.4
ต้องใช้ R ≥ 4.5.2 · tibble 3.3.1 · dplyr 1.2.1 · ggplot2 4.0.3 · ใช้ได้กับ R 4.6.1 · ดาวน์โหลด budget-impact-analysis-in-practice.R
สคริปต์ฉบับเต็ม
# Budget Impact Analysis in Practice: Count People Before Counting Money
# Follow one district's stroke survivors from eligible people to the extra cash the fund pays.
# ติดตามผู้ป่วยหลังโรคหลอดเลือดสมองของอำเภอหนึ่ง จากผู้มีสิทธิจนถึงเงินสดส่วนเพิ่มที่กองทุนจ่าย
# 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 years as an explicit table.
library(dplyr) # Calculate people and money for each year.
library(ggplot2) # Display the yearly cash without saving files.
stopifnot(getRversion() >= "4.5.2")
#%%@note 1. Define the illustrative inputs
# Every input is synthetic and written out once, in the order the article uses it.
# ค่าตั้งต้นทั้งหมดเป็นข้อมูลสมมติ เขียนไว้ครั้งเดียวตามลำดับที่บทความใช้
prevalent <- 500
annual_incident <- 100
exit_fraction <- 0.10
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
current_care_cost <- 4500
nurse_places <- 300
discount_rate <- 0.03
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
#%%@note 2. Follow the eligible people year by year
# New survivors join at the year start, the year's users are counted, then exits leave at year end.
# ผู้มีสิทธิใหม่เข้าต้นปี นับผู้ใช้บริการของปีนั้น แล้วผู้ที่ออกจึงออกเมื่อสิ้นปี
stock <- rep(prevalent + annual_incident, length(uptake))
for (year_index in 2:length(uptake)) {
stock[year_index] <- stock[year_index - 1] * (1 - exit_fraction) + annual_incident
}
eligible <- c(600,640,676)
stopifnot(all(abs(stock - eligible) < 1e-9))
years <- tibble::tibble(year = seq_along(uptake), eligible = stock, uptake = uptake) |>
dplyr::mutate(treated = eligible * uptake, exits = eligible * exit_fraction,
remaining = eligible * (1 - exit_fraction),
annual_budget = treated * annual_incremental_cost,
cumulative_budget = cumsum(annual_budget))
stopifnot(all(abs(years$exits + years$remaining - years$eligible) < 1e-9))
treated <- years$treated
budget <- years$annual_budget
#%%@note 3. Price the two scenarios
# Everyone costs current care in both; only the service users add the extra cost.
# ทุกคนมีต้นทุนการดูแลเดิมในทั้งสองสถานการณ์ เฉพาะผู้ใช้บริการที่มีต้นทุนเพิ่ม
current <- eligible * current_care_cost
new <- (eligible - treated) * current_care_cost +
treated * (current_care_cost + annual_incremental_cost)
stopifnot(all(abs(new - current - budget) < 1e-6))
#%%@note 4. Check timing, rounding and the nurse places
# Wrong timing and early rounding change the cash; the nurse places cap year 3; uptake moves 0.10.
# ลำดับเวลาที่ผิดและการปัดเศษก่อนเวลาเปลี่ยนเงินสด จำนวนผู้ใช้ที่พยาบาลรับได้จำกัดปีที่ 3
exits_first <- treated[1] * c(1, 1 - exit_fraction) * annual_incremental_cost
rounded <- c(treated[3], round(treated[3]))
today_value <- 1834 / (1 + discount_rate)^3
capped <- pmin(treated, nurse_places)
shift <- 0.10 * sum(eligible)
users <- sum(eligible * uptake) + c(0, -1, 1) * shift
#%%@note 5. Display the model
# Plot the yearly extra cash; the script does not save a graphics file.
# แสดงเงินสดส่วนเพิ่มรายปี โดยไม่บันทึกไฟล์ภาพ
print(ggplot2::ggplot(years, ggplot2::aes(x = year, y = annual_budget)) +
ggplot2::geom_col() + ggplot2::labs(x = "Year", y = "Extra cash in the year (THB)"))
#%%@note 6. Numbers the article quotes
# Print exactly the short boxes in their reading order.
# พิมพ์ผลลัพธ์ตรงกับกล่องตัวอย่างตามลำดับในบทความ
cat("Year order:",seq_along(uptake),"\n")
cat("Eligible at year start (people):",eligible,"\n")
cat("Treated prevalence (people):",treated,"\n")
cat("Year-end exits (people):",eligible*exit_fraction,"\n")
cat("Remaining stock (people):",eligible*(1-exit_fraction),"\n")
cat("Annual incremental budget (THB):",big(budget),"\n")
cat("Cumulative incremental budget (THB):",big(cumsum(budget)),"\n")
cat("Shortcut, 500 x 2,000 x 3 years (THB):",big(prevalent*annual_incremental_cost*3),"\n")
cat("Cost per person (THB):",big(current_care_cost+c(0,annual_incremental_cost)),"\n")
cat("Current-care scenario (THB):",big(current),"\n")
cat("New scenario (THB):",big(new),"\n")
cat("New minus current (THB):",big(new-current),"\n")
cat("Year 1 users, exits counted after and before:",treated[1]*c(1,1-exit_fraction),"\n")
cat("Year 1, exits counted after and before (THB):",big(exits_first),"\n")
cat("Year 3 people, expected and rounded:",rounded,"\n")
cat("Year 3 budget, expected and rounded (THB):",big(rounded*annual_incremental_cost),"\n")
cat("Yearly rate back to today (%):",100*discount_rate,"\n")
cat("1,834 THB due in year 3, worth today (THB):",big(today_value),"\n")
cat("Year 3 wanted, offered, waiting:",treated[3],nurse_places,treated[3]-nurse_places,"\n")
cat("Year 3 and three years within the places (THB):",
big(c(capped[3],sum(capped))*annual_incremental_cost),"\n")
cat("Users over three years, shift of 0.10:",users[1],shift,"\n")
cat("Users, every share 0.10 lower and higher:",users[2:3],"\n")
cat("Three years, every share 0.10 lower and higher (THB):",
big(users[2:3]*annual_incremental_cost),"\n")
ตรวจเงินสดด้วย R
# Illustrative district: the extra cash the fund pays each year for the home service.
# Writes: nothing to disk; the results print in the console.
prevalent <- 500
annual_incident <- 100
exit_fraction <- 0.10
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
eligible <- prevalent+annual_incident
for (year in 2:length(uptake)) eligible[year] <- eligible[year-1]*(1-exit_fraction)+annual_incident
budget <- eligible*uptake*annual_incremental_cost
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
cat("Annual incremental budget (THB):",big(budget),"\n")
cat("Cumulative incremental budget (THB):",big(cumsum(budget)),"\n")
cat("Shortcut, 500 x 2,000 x 3 years (THB):",big(prevalent*annual_incremental_cost*3),"\n")
Annual incremental budget (THB): 240,000 512,000 811,200
Cumulative incremental budget (THB): 240,000 752,000 1,563,200
Shortcut, 500 x 2,000 x 3 years (THB): 3,000,000
ต้องใช้ R ≥ 4.5.2 · tibble 3.3.1 · dplyr 1.2.1 · ggplot2 4.0.3 · ใช้ได้กับ R 4.6.1 · ดาวน์โหลด budget-impact-analysis-in-practice.R
สคริปต์ฉบับเต็ม
# Budget Impact Analysis in Practice: Count People Before Counting Money
# Follow one district's stroke survivors from eligible people to the extra cash the fund pays.
# ติดตามผู้ป่วยหลังโรคหลอดเลือดสมองของอำเภอหนึ่ง จากผู้มีสิทธิจนถึงเงินสดส่วนเพิ่มที่กองทุนจ่าย
# 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 years as an explicit table.
library(dplyr) # Calculate people and money for each year.
library(ggplot2) # Display the yearly cash without saving files.
stopifnot(getRversion() >= "4.5.2")
#%%@note 1. Define the illustrative inputs
# Every input is synthetic and written out once, in the order the article uses it.
# ค่าตั้งต้นทั้งหมดเป็นข้อมูลสมมติ เขียนไว้ครั้งเดียวตามลำดับที่บทความใช้
prevalent <- 500
annual_incident <- 100
exit_fraction <- 0.10
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
current_care_cost <- 4500
nurse_places <- 300
discount_rate <- 0.03
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
#%%@note 2. Follow the eligible people year by year
# New survivors join at the year start, the year's users are counted, then exits leave at year end.
# ผู้มีสิทธิใหม่เข้าต้นปี นับผู้ใช้บริการของปีนั้น แล้วผู้ที่ออกจึงออกเมื่อสิ้นปี
stock <- rep(prevalent + annual_incident, length(uptake))
for (year_index in 2:length(uptake)) {
stock[year_index] <- stock[year_index - 1] * (1 - exit_fraction) + annual_incident
}
eligible <- c(600,640,676)
stopifnot(all(abs(stock - eligible) < 1e-9))
years <- tibble::tibble(year = seq_along(uptake), eligible = stock, uptake = uptake) |>
dplyr::mutate(treated = eligible * uptake, exits = eligible * exit_fraction,
remaining = eligible * (1 - exit_fraction),
annual_budget = treated * annual_incremental_cost,
cumulative_budget = cumsum(annual_budget))
stopifnot(all(abs(years$exits + years$remaining - years$eligible) < 1e-9))
treated <- years$treated
budget <- years$annual_budget
#%%@note 3. Price the two scenarios
# Everyone costs current care in both; only the service users add the extra cost.
# ทุกคนมีต้นทุนการดูแลเดิมในทั้งสองสถานการณ์ เฉพาะผู้ใช้บริการที่มีต้นทุนเพิ่ม
current <- eligible * current_care_cost
new <- (eligible - treated) * current_care_cost +
treated * (current_care_cost + annual_incremental_cost)
stopifnot(all(abs(new - current - budget) < 1e-6))
#%%@note 4. Check timing, rounding and the nurse places
# Wrong timing and early rounding change the cash; the nurse places cap year 3; uptake moves 0.10.
# ลำดับเวลาที่ผิดและการปัดเศษก่อนเวลาเปลี่ยนเงินสด จำนวนผู้ใช้ที่พยาบาลรับได้จำกัดปีที่ 3
exits_first <- treated[1] * c(1, 1 - exit_fraction) * annual_incremental_cost
rounded <- c(treated[3], round(treated[3]))
today_value <- 1834 / (1 + discount_rate)^3
capped <- pmin(treated, nurse_places)
shift <- 0.10 * sum(eligible)
users <- sum(eligible * uptake) + c(0, -1, 1) * shift
#%%@note 5. Display the model
# Plot the yearly extra cash; the script does not save a graphics file.
# แสดงเงินสดส่วนเพิ่มรายปี โดยไม่บันทึกไฟล์ภาพ
print(ggplot2::ggplot(years, ggplot2::aes(x = year, y = annual_budget)) +
ggplot2::geom_col() + ggplot2::labs(x = "Year", y = "Extra cash in the year (THB)"))
#%%@note 6. Numbers the article quotes
# Print exactly the short boxes in their reading order.
# พิมพ์ผลลัพธ์ตรงกับกล่องตัวอย่างตามลำดับในบทความ
cat("Year order:",seq_along(uptake),"\n")
cat("Eligible at year start (people):",eligible,"\n")
cat("Treated prevalence (people):",treated,"\n")
cat("Year-end exits (people):",eligible*exit_fraction,"\n")
cat("Remaining stock (people):",eligible*(1-exit_fraction),"\n")
cat("Annual incremental budget (THB):",big(budget),"\n")
cat("Cumulative incremental budget (THB):",big(cumsum(budget)),"\n")
cat("Shortcut, 500 x 2,000 x 3 years (THB):",big(prevalent*annual_incremental_cost*3),"\n")
cat("Cost per person (THB):",big(current_care_cost+c(0,annual_incremental_cost)),"\n")
cat("Current-care scenario (THB):",big(current),"\n")
cat("New scenario (THB):",big(new),"\n")
cat("New minus current (THB):",big(new-current),"\n")
cat("Year 1 users, exits counted after and before:",treated[1]*c(1,1-exit_fraction),"\n")
cat("Year 1, exits counted after and before (THB):",big(exits_first),"\n")
cat("Year 3 people, expected and rounded:",rounded,"\n")
cat("Year 3 budget, expected and rounded (THB):",big(rounded*annual_incremental_cost),"\n")
cat("Yearly rate back to today (%):",100*discount_rate,"\n")
cat("1,834 THB due in year 3, worth today (THB):",big(today_value),"\n")
cat("Year 3 wanted, offered, waiting:",treated[3],nurse_places,treated[3]-nurse_places,"\n")
cat("Year 3 and three years within the places (THB):",
big(c(capped[3],sum(capped))*annual_incremental_cost),"\n")
cat("Users over three years, shift of 0.10:",users[1],shift,"\n")
cat("Users, every share 0.10 lower and higher:",users[2:3],"\n")
cat("Three years, every share 0.10 lower and higher (THB):",
big(users[2:3]*annual_incremental_cost),"\n")
เมื่อมีและไม่มีบริการ: ผลต่างเท่านั้นคืองบประมาณ
กองทุนจ่ายค่าการดูแลตามปกติอยู่แล้ว คือการมาตรวจที่คลินิกและยาลดความดัน สมมติว่าการดูแลตามปกติมีต้นทุน 4,500 บาท ต่อผู้ป่วยหนึ่งคนต่อปี ผู้ป่วยที่ใช้บริการที่บ้านจึงมีต้นทุน 4,500 + 2,000 = 6,500 บาท
ทีนี้ลองคิดรายจ่ายของปีเดียวกันสองแบบ เมื่อไม่มีบริการ ผู้ป่วยทั้ง 600 คนได้รับการดูแลตามปกติ และปีที่ 1 มีต้นทุน 600 × 4,500 = 2,700,000 บาท เมื่อมีบริการ ผู้ป่วยทุกคนยังมีต้นทุนการดูแลตามปกติ 4,500 บาท และผู้ใช้ 120 คนเพิ่มคนละ 2,000 บาท ดังนั้นรายจ่ายเมื่อมีบริการเป็น 2,700,000 + 240,000 = 2,940,000 บาท ผลต่างจึงเท่ากับ 240,000 บาทที่นับไว้ข้างต้นพอดี
ปีที่ 2 และ 3 คิดแบบเดียวกัน เมื่อไม่มีบริการ ปีที่ 2 มีต้นทุน 640 × 4,500 = 2,880,000 และปีที่ 3 มีต้นทุน 676 × 4,500 = 3,042,000 บาท เมื่อมีบริการจะเพิ่มอีก 512,000 และ 811,200 บาท ต้นทุนการดูแลตามปกติหักล้างกันเพราะอยู่ทั้งสองฝั่ง
สองแบบนี้เรียกว่าสถานการณ์ปัจจุบัน (current scenario) และสถานการณ์ใหม่ (new scenario) ผลกระทบด้านงบประมาณคือสถานการณ์ใหม่ลบสถานการณ์ปัจจุบันทีละปี อ่านตารางทีละแถว เงินสดส่วนเพิ่มของปีนั้นคือคอลัมน์มีบริการลบคอลัมน์ไม่มีบริการ
รายจ่ายเมื่อมีและไม่มีบริการ เป็นเงินสดในปีที่จ่าย
| ปี | ผู้ใช้บริการ | ไม่มีบริการ (บาท) | มีบริการ (บาท) | เงินสดส่วนเพิ่มในปีนั้น (บาท) | ยอดสะสม (บาท) |
|---|---|---|---|---|---|
| 1 | 120 | 2,700,000 | 2,940,000 | 240,000 | 240,000 |
| 2 | 256 | 2,880,000 | 3,392,000 | 512,000 | 752,000 |
| 3 | 405.6 | 3,042,000 | 3,853,200 | 811,200 | 1,563,200 |
ตรวจสองสถานการณ์ด้วย R
# Illustrative district: total spending with and without the home service, year by year.
# Writes: nothing to disk; the results print in the console.
eligible <- c(600,640,676)
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
current_care_cost <- 4500
treated <- eligible*uptake
current <- eligible*current_care_cost
new <- (eligible-treated)*current_care_cost+treated*(current_care_cost+annual_incremental_cost)
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
cat("Cost per person (THB):",big(current_care_cost+c(0,annual_incremental_cost)),"\n")
cat("Current-care scenario (THB):",big(current),"\n")
cat("New scenario (THB):",big(new),"\n")
cat("New minus current (THB):",big(new-current),"\n")
Cost per person (THB): 4,500 6,500
Current-care scenario (THB): 2,700,000 2,880,000 3,042,000
New scenario (THB): 2,940,000 3,392,000 3,853,200
New minus current (THB): 240,000 512,000 811,200
ต้องใช้ R ≥ 4.5.2 · tibble 3.3.1 · dplyr 1.2.1 · ggplot2 4.0.3 · ใช้ได้กับ R 4.6.1 · ดาวน์โหลด budget-impact-analysis-in-practice.R
สคริปต์ฉบับเต็ม
# Budget Impact Analysis in Practice: Count People Before Counting Money
# Follow one district's stroke survivors from eligible people to the extra cash the fund pays.
# ติดตามผู้ป่วยหลังโรคหลอดเลือดสมองของอำเภอหนึ่ง จากผู้มีสิทธิจนถึงเงินสดส่วนเพิ่มที่กองทุนจ่าย
# 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 years as an explicit table.
library(dplyr) # Calculate people and money for each year.
library(ggplot2) # Display the yearly cash without saving files.
stopifnot(getRversion() >= "4.5.2")
#%%@note 1. Define the illustrative inputs
# Every input is synthetic and written out once, in the order the article uses it.
# ค่าตั้งต้นทั้งหมดเป็นข้อมูลสมมติ เขียนไว้ครั้งเดียวตามลำดับที่บทความใช้
prevalent <- 500
annual_incident <- 100
exit_fraction <- 0.10
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
current_care_cost <- 4500
nurse_places <- 300
discount_rate <- 0.03
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
#%%@note 2. Follow the eligible people year by year
# New survivors join at the year start, the year's users are counted, then exits leave at year end.
# ผู้มีสิทธิใหม่เข้าต้นปี นับผู้ใช้บริการของปีนั้น แล้วผู้ที่ออกจึงออกเมื่อสิ้นปี
stock <- rep(prevalent + annual_incident, length(uptake))
for (year_index in 2:length(uptake)) {
stock[year_index] <- stock[year_index - 1] * (1 - exit_fraction) + annual_incident
}
eligible <- c(600,640,676)
stopifnot(all(abs(stock - eligible) < 1e-9))
years <- tibble::tibble(year = seq_along(uptake), eligible = stock, uptake = uptake) |>
dplyr::mutate(treated = eligible * uptake, exits = eligible * exit_fraction,
remaining = eligible * (1 - exit_fraction),
annual_budget = treated * annual_incremental_cost,
cumulative_budget = cumsum(annual_budget))
stopifnot(all(abs(years$exits + years$remaining - years$eligible) < 1e-9))
treated <- years$treated
budget <- years$annual_budget
#%%@note 3. Price the two scenarios
# Everyone costs current care in both; only the service users add the extra cost.
# ทุกคนมีต้นทุนการดูแลเดิมในทั้งสองสถานการณ์ เฉพาะผู้ใช้บริการที่มีต้นทุนเพิ่ม
current <- eligible * current_care_cost
new <- (eligible - treated) * current_care_cost +
treated * (current_care_cost + annual_incremental_cost)
stopifnot(all(abs(new - current - budget) < 1e-6))
#%%@note 4. Check timing, rounding and the nurse places
# Wrong timing and early rounding change the cash; the nurse places cap year 3; uptake moves 0.10.
# ลำดับเวลาที่ผิดและการปัดเศษก่อนเวลาเปลี่ยนเงินสด จำนวนผู้ใช้ที่พยาบาลรับได้จำกัดปีที่ 3
exits_first <- treated[1] * c(1, 1 - exit_fraction) * annual_incremental_cost
rounded <- c(treated[3], round(treated[3]))
today_value <- 1834 / (1 + discount_rate)^3
capped <- pmin(treated, nurse_places)
shift <- 0.10 * sum(eligible)
users <- sum(eligible * uptake) + c(0, -1, 1) * shift
#%%@note 5. Display the model
# Plot the yearly extra cash; the script does not save a graphics file.
# แสดงเงินสดส่วนเพิ่มรายปี โดยไม่บันทึกไฟล์ภาพ
print(ggplot2::ggplot(years, ggplot2::aes(x = year, y = annual_budget)) +
ggplot2::geom_col() + ggplot2::labs(x = "Year", y = "Extra cash in the year (THB)"))
#%%@note 6. Numbers the article quotes
# Print exactly the short boxes in their reading order.
# พิมพ์ผลลัพธ์ตรงกับกล่องตัวอย่างตามลำดับในบทความ
cat("Year order:",seq_along(uptake),"\n")
cat("Eligible at year start (people):",eligible,"\n")
cat("Treated prevalence (people):",treated,"\n")
cat("Year-end exits (people):",eligible*exit_fraction,"\n")
cat("Remaining stock (people):",eligible*(1-exit_fraction),"\n")
cat("Annual incremental budget (THB):",big(budget),"\n")
cat("Cumulative incremental budget (THB):",big(cumsum(budget)),"\n")
cat("Shortcut, 500 x 2,000 x 3 years (THB):",big(prevalent*annual_incremental_cost*3),"\n")
cat("Cost per person (THB):",big(current_care_cost+c(0,annual_incremental_cost)),"\n")
cat("Current-care scenario (THB):",big(current),"\n")
cat("New scenario (THB):",big(new),"\n")
cat("New minus current (THB):",big(new-current),"\n")
cat("Year 1 users, exits counted after and before:",treated[1]*c(1,1-exit_fraction),"\n")
cat("Year 1, exits counted after and before (THB):",big(exits_first),"\n")
cat("Year 3 people, expected and rounded:",rounded,"\n")
cat("Year 3 budget, expected and rounded (THB):",big(rounded*annual_incremental_cost),"\n")
cat("Yearly rate back to today (%):",100*discount_rate,"\n")
cat("1,834 THB due in year 3, worth today (THB):",big(today_value),"\n")
cat("Year 3 wanted, offered, waiting:",treated[3],nurse_places,treated[3]-nurse_places,"\n")
cat("Year 3 and three years within the places (THB):",
big(c(capped[3],sum(capped))*annual_incremental_cost),"\n")
cat("Users over three years, shift of 0.10:",users[1],shift,"\n")
cat("Users, every share 0.10 lower and higher:",users[2:3],"\n")
cat("Three years, every share 0.10 lower and higher (THB):",
big(users[2:3]*annual_incremental_cost),"\n")
จ่ายให้ผู้ใช้ทุกคนทุกปี และคงทศนิยมไว้
ค่า 2,000 บาทเกิดซ้ำ เพราะค่าบริการเครื่องวัดความดันและการโทรของพยาบาลทุกเดือนเกิดขึ้นทุกปีที่ผู้ป่วยยังใช้บริการ เงินสดของแต่ละปีจึงครอบคลุมผู้ใช้ทุกคนในปีนั้น ไม่ใช่เฉพาะผู้มาใหม่หรือส่วนที่เพิ่มจากปีก่อน ในปีที่ 3 กองทุนจ่ายให้ผู้ใช้ 405.6 คน ซึ่งรวมผู้ที่เริ่มในปีที่ 1 และ 2 แล้วยังใช้ต่อด้วย
ต้นทุนครั้งเดียวคิดต่างออกไป ถ้าผู้ใช้ใหม่แต่ละคนได้รับเครื่องวัดความดันไปเลย ซื้อเพียงครั้งเดียว กองทุนต้องรู้จำนวนผู้เริ่มใช้ในแต่ละปี สัดส่วนผู้ใช้บริการอย่างเดียวบอกจำนวนนั้นไม่ได้ เพราะผู้ใช้ 256 คนในปีที่ 2 มีทั้งผู้ใช้ต่อเนื่องและผู้เริ่มใหม่ปนกัน และข้อมูลนำเข้าไม่ได้บอกว่าแต่ละแบบมีกี่คน การรักษาที่ให้ครั้งเดียวก็คิดงบประมาณแบบนี้ เช่น การรักษาผ่านสายสวนหลอดเลือดสำหรับโรคหลอดเลือดสมอง ที่ Rattanavipapong and colleagues ประเมินในไทย ให้เพียงครั้งเดียวในช่วงที่เกิดโรค งบประมาณจึงนับผู้ป่วยใหม่ในแต่ละปี
ค่า 405.6 เป็นจำนวนคาดหมาย คือค่าเฉลี่ยจากความเป็นไปได้หลายแบบของปีนั้น จึงไม่จำเป็นต้องเป็นจำนวนเต็ม ให้คงค่านี้ไว้จนถึงขั้นสุดท้าย ถ้าปัดเป็น 406 ก่อน ต้นทุนจะเป็น 812,000 บาท แทนที่จะเป็น 811,200 บาท ซึ่งเป็นความต่างที่ไม่ได้มาจากข้อเท็จจริงใดของผู้ป่วยเลย
ตรวจลำดับเวลาและการปัดเศษด้วย R
# Illustrative district: what changes if exits leave too early or people are rounded too soon.
# Writes: nothing to disk; the results print in the console.
eligible <- c(600,640,676)
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
exit_fraction <- 0.10
treated <- eligible*uptake
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
cat("Year 1 users, exits counted after and before:",treated[1]*c(1,1-exit_fraction),"\n")
cat("Year 1, exits counted after and before (THB):",
big(treated[1]*c(1,1-exit_fraction)*annual_incremental_cost),"\n")
cat("Year 3 people, expected and rounded:",treated[3],round(treated[3]),"\n")
cat("Year 3 budget, expected and rounded (THB):",
big(c(treated[3],round(treated[3]))*annual_incremental_cost),"\n")
Year 1 users, exits counted after and before: 120 108
Year 1, exits counted after and before (THB): 240,000 216,000
Year 3 people, expected and rounded: 405.6 406
Year 3 budget, expected and rounded (THB): 811,200 812,000
ต้องใช้ R ≥ 4.5.2 · tibble 3.3.1 · dplyr 1.2.1 · ggplot2 4.0.3 · ใช้ได้กับ R 4.6.1 · ดาวน์โหลด budget-impact-analysis-in-practice.R
สคริปต์ฉบับเต็ม
# Budget Impact Analysis in Practice: Count People Before Counting Money
# Follow one district's stroke survivors from eligible people to the extra cash the fund pays.
# ติดตามผู้ป่วยหลังโรคหลอดเลือดสมองของอำเภอหนึ่ง จากผู้มีสิทธิจนถึงเงินสดส่วนเพิ่มที่กองทุนจ่าย
# 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 years as an explicit table.
library(dplyr) # Calculate people and money for each year.
library(ggplot2) # Display the yearly cash without saving files.
stopifnot(getRversion() >= "4.5.2")
#%%@note 1. Define the illustrative inputs
# Every input is synthetic and written out once, in the order the article uses it.
# ค่าตั้งต้นทั้งหมดเป็นข้อมูลสมมติ เขียนไว้ครั้งเดียวตามลำดับที่บทความใช้
prevalent <- 500
annual_incident <- 100
exit_fraction <- 0.10
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
current_care_cost <- 4500
nurse_places <- 300
discount_rate <- 0.03
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
#%%@note 2. Follow the eligible people year by year
# New survivors join at the year start, the year's users are counted, then exits leave at year end.
# ผู้มีสิทธิใหม่เข้าต้นปี นับผู้ใช้บริการของปีนั้น แล้วผู้ที่ออกจึงออกเมื่อสิ้นปี
stock <- rep(prevalent + annual_incident, length(uptake))
for (year_index in 2:length(uptake)) {
stock[year_index] <- stock[year_index - 1] * (1 - exit_fraction) + annual_incident
}
eligible <- c(600,640,676)
stopifnot(all(abs(stock - eligible) < 1e-9))
years <- tibble::tibble(year = seq_along(uptake), eligible = stock, uptake = uptake) |>
dplyr::mutate(treated = eligible * uptake, exits = eligible * exit_fraction,
remaining = eligible * (1 - exit_fraction),
annual_budget = treated * annual_incremental_cost,
cumulative_budget = cumsum(annual_budget))
stopifnot(all(abs(years$exits + years$remaining - years$eligible) < 1e-9))
treated <- years$treated
budget <- years$annual_budget
#%%@note 3. Price the two scenarios
# Everyone costs current care in both; only the service users add the extra cost.
# ทุกคนมีต้นทุนการดูแลเดิมในทั้งสองสถานการณ์ เฉพาะผู้ใช้บริการที่มีต้นทุนเพิ่ม
current <- eligible * current_care_cost
new <- (eligible - treated) * current_care_cost +
treated * (current_care_cost + annual_incremental_cost)
stopifnot(all(abs(new - current - budget) < 1e-6))
#%%@note 4. Check timing, rounding and the nurse places
# Wrong timing and early rounding change the cash; the nurse places cap year 3; uptake moves 0.10.
# ลำดับเวลาที่ผิดและการปัดเศษก่อนเวลาเปลี่ยนเงินสด จำนวนผู้ใช้ที่พยาบาลรับได้จำกัดปีที่ 3
exits_first <- treated[1] * c(1, 1 - exit_fraction) * annual_incremental_cost
rounded <- c(treated[3], round(treated[3]))
today_value <- 1834 / (1 + discount_rate)^3
capped <- pmin(treated, nurse_places)
shift <- 0.10 * sum(eligible)
users <- sum(eligible * uptake) + c(0, -1, 1) * shift
#%%@note 5. Display the model
# Plot the yearly extra cash; the script does not save a graphics file.
# แสดงเงินสดส่วนเพิ่มรายปี โดยไม่บันทึกไฟล์ภาพ
print(ggplot2::ggplot(years, ggplot2::aes(x = year, y = annual_budget)) +
ggplot2::geom_col() + ggplot2::labs(x = "Year", y = "Extra cash in the year (THB)"))
#%%@note 6. Numbers the article quotes
# Print exactly the short boxes in their reading order.
# พิมพ์ผลลัพธ์ตรงกับกล่องตัวอย่างตามลำดับในบทความ
cat("Year order:",seq_along(uptake),"\n")
cat("Eligible at year start (people):",eligible,"\n")
cat("Treated prevalence (people):",treated,"\n")
cat("Year-end exits (people):",eligible*exit_fraction,"\n")
cat("Remaining stock (people):",eligible*(1-exit_fraction),"\n")
cat("Annual incremental budget (THB):",big(budget),"\n")
cat("Cumulative incremental budget (THB):",big(cumsum(budget)),"\n")
cat("Shortcut, 500 x 2,000 x 3 years (THB):",big(prevalent*annual_incremental_cost*3),"\n")
cat("Cost per person (THB):",big(current_care_cost+c(0,annual_incremental_cost)),"\n")
cat("Current-care scenario (THB):",big(current),"\n")
cat("New scenario (THB):",big(new),"\n")
cat("New minus current (THB):",big(new-current),"\n")
cat("Year 1 users, exits counted after and before:",treated[1]*c(1,1-exit_fraction),"\n")
cat("Year 1, exits counted after and before (THB):",big(exits_first),"\n")
cat("Year 3 people, expected and rounded:",rounded,"\n")
cat("Year 3 budget, expected and rounded (THB):",big(rounded*annual_incremental_cost),"\n")
cat("Yearly rate back to today (%):",100*discount_rate,"\n")
cat("1,834 THB due in year 3, worth today (THB):",big(today_value),"\n")
cat("Year 3 wanted, offered, waiting:",treated[3],nurse_places,treated[3]-nurse_places,"\n")
cat("Year 3 and three years within the places (THB):",
big(c(capped[3],sum(capped))*annual_incremental_cost),"\n")
cat("Users over three years, shift of 0.10:",users[1],shift,"\n")
cat("Users, every share 0.10 lower and higher:",users[2:3],"\n")
cat("Three years, every share 0.10 lower and higher (THB):",
big(users[2:3]*annual_incremental_cost),"\n")
เงินสดในปีที่จ่าย ไม่ใช่ความคุ้มค่า
การประเมินทางเศรษฐศาสตร์มักย่อจำนวนเงินในอนาคตให้เป็นมูลค่าวันนี้ เพราะคนและผู้จ่ายชอบจ่ายทีหลังและได้ประโยชน์เร็ว การปรับลดค่าตามเวลา (discounting) คือการแปลงต้นทุนหรือผลทางสุขภาพในอนาคตเป็นมูลค่าวันนี้ โดยลดลงตามอัตราการปรับลดในแต่ละปี ที่อัตรา 3% ต้นทุน 1,834 บาทที่ต้องจ่ายในปีที่ 3 มีค่าเท่ากับ 1,678 บาทในวันนี้ อ่านบทเรียนเต็มได้ที่ ต้นทุนของใคร ณ ปีใด: มุมมองการวิเคราะห์ ต้นทุนค่าเสียโอกาส การปรับค่าเงินเฟ้อ และการปรับลดค่าตามเวลา
งบประมาณไม่ทำแบบนั้น ในปีที่ 3 กองทุนต้องจ่ายเงินสด 811,200 บาท ไม่ว่าเงินจำนวนนี้จะมีมูลค่าวันนี้เท่าไร ทุกจำนวนในบทความนี้จึงเป็นเงินสดในปีที่จ่ายจริง
งบประมาณตอบว่ากองทุนจ่ายไหวหรือไม่ แต่ไม่ได้บอกว่าบริการนี้คุ้มค่าหรือไม่ คำถามเรื่องความคุ้มค่าชั่งต้นทุนที่เพิ่มกับสุขภาพที่ได้เพิ่ม ซึ่งการคำนวณนี้ไม่ได้นับ (Drummond and colleagues) บริการหนึ่งอาจคุ้มค่าแต่ยังใส่ในงบประมาณของปีที่ 3 ไม่ได้
ตรวจตัวเลขในย่อหน้าทบทวนด้วย R
# Illustrative district: what a future cost is worth today, for contrast with cash as paid.
# Writes: nothing to disk; the results print in the console.
discount_rate <- 0.03
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
cat("Yearly rate back to today (%):",100*discount_rate,"\n")
cat("1,834 THB due in year 3, worth today (THB):",big(1834/(1+discount_rate)^3),"\n")
Yearly rate back to today (%): 3
1,834 THB due in year 3, worth today (THB): 1,678
ต้องใช้ R ≥ 4.5.2 · tibble 3.3.1 · dplyr 1.2.1 · ggplot2 4.0.3 · ใช้ได้กับ R 4.6.1 · ดาวน์โหลด budget-impact-analysis-in-practice.R
สคริปต์ฉบับเต็ม
# Budget Impact Analysis in Practice: Count People Before Counting Money
# Follow one district's stroke survivors from eligible people to the extra cash the fund pays.
# ติดตามผู้ป่วยหลังโรคหลอดเลือดสมองของอำเภอหนึ่ง จากผู้มีสิทธิจนถึงเงินสดส่วนเพิ่มที่กองทุนจ่าย
# 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 years as an explicit table.
library(dplyr) # Calculate people and money for each year.
library(ggplot2) # Display the yearly cash without saving files.
stopifnot(getRversion() >= "4.5.2")
#%%@note 1. Define the illustrative inputs
# Every input is synthetic and written out once, in the order the article uses it.
# ค่าตั้งต้นทั้งหมดเป็นข้อมูลสมมติ เขียนไว้ครั้งเดียวตามลำดับที่บทความใช้
prevalent <- 500
annual_incident <- 100
exit_fraction <- 0.10
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
current_care_cost <- 4500
nurse_places <- 300
discount_rate <- 0.03
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
#%%@note 2. Follow the eligible people year by year
# New survivors join at the year start, the year's users are counted, then exits leave at year end.
# ผู้มีสิทธิใหม่เข้าต้นปี นับผู้ใช้บริการของปีนั้น แล้วผู้ที่ออกจึงออกเมื่อสิ้นปี
stock <- rep(prevalent + annual_incident, length(uptake))
for (year_index in 2:length(uptake)) {
stock[year_index] <- stock[year_index - 1] * (1 - exit_fraction) + annual_incident
}
eligible <- c(600,640,676)
stopifnot(all(abs(stock - eligible) < 1e-9))
years <- tibble::tibble(year = seq_along(uptake), eligible = stock, uptake = uptake) |>
dplyr::mutate(treated = eligible * uptake, exits = eligible * exit_fraction,
remaining = eligible * (1 - exit_fraction),
annual_budget = treated * annual_incremental_cost,
cumulative_budget = cumsum(annual_budget))
stopifnot(all(abs(years$exits + years$remaining - years$eligible) < 1e-9))
treated <- years$treated
budget <- years$annual_budget
#%%@note 3. Price the two scenarios
# Everyone costs current care in both; only the service users add the extra cost.
# ทุกคนมีต้นทุนการดูแลเดิมในทั้งสองสถานการณ์ เฉพาะผู้ใช้บริการที่มีต้นทุนเพิ่ม
current <- eligible * current_care_cost
new <- (eligible - treated) * current_care_cost +
treated * (current_care_cost + annual_incremental_cost)
stopifnot(all(abs(new - current - budget) < 1e-6))
#%%@note 4. Check timing, rounding and the nurse places
# Wrong timing and early rounding change the cash; the nurse places cap year 3; uptake moves 0.10.
# ลำดับเวลาที่ผิดและการปัดเศษก่อนเวลาเปลี่ยนเงินสด จำนวนผู้ใช้ที่พยาบาลรับได้จำกัดปีที่ 3
exits_first <- treated[1] * c(1, 1 - exit_fraction) * annual_incremental_cost
rounded <- c(treated[3], round(treated[3]))
today_value <- 1834 / (1 + discount_rate)^3
capped <- pmin(treated, nurse_places)
shift <- 0.10 * sum(eligible)
users <- sum(eligible * uptake) + c(0, -1, 1) * shift
#%%@note 5. Display the model
# Plot the yearly extra cash; the script does not save a graphics file.
# แสดงเงินสดส่วนเพิ่มรายปี โดยไม่บันทึกไฟล์ภาพ
print(ggplot2::ggplot(years, ggplot2::aes(x = year, y = annual_budget)) +
ggplot2::geom_col() + ggplot2::labs(x = "Year", y = "Extra cash in the year (THB)"))
#%%@note 6. Numbers the article quotes
# Print exactly the short boxes in their reading order.
# พิมพ์ผลลัพธ์ตรงกับกล่องตัวอย่างตามลำดับในบทความ
cat("Year order:",seq_along(uptake),"\n")
cat("Eligible at year start (people):",eligible,"\n")
cat("Treated prevalence (people):",treated,"\n")
cat("Year-end exits (people):",eligible*exit_fraction,"\n")
cat("Remaining stock (people):",eligible*(1-exit_fraction),"\n")
cat("Annual incremental budget (THB):",big(budget),"\n")
cat("Cumulative incremental budget (THB):",big(cumsum(budget)),"\n")
cat("Shortcut, 500 x 2,000 x 3 years (THB):",big(prevalent*annual_incremental_cost*3),"\n")
cat("Cost per person (THB):",big(current_care_cost+c(0,annual_incremental_cost)),"\n")
cat("Current-care scenario (THB):",big(current),"\n")
cat("New scenario (THB):",big(new),"\n")
cat("New minus current (THB):",big(new-current),"\n")
cat("Year 1 users, exits counted after and before:",treated[1]*c(1,1-exit_fraction),"\n")
cat("Year 1, exits counted after and before (THB):",big(exits_first),"\n")
cat("Year 3 people, expected and rounded:",rounded,"\n")
cat("Year 3 budget, expected and rounded (THB):",big(rounded*annual_incremental_cost),"\n")
cat("Yearly rate back to today (%):",100*discount_rate,"\n")
cat("1,834 THB due in year 3, worth today (THB):",big(today_value),"\n")
cat("Year 3 wanted, offered, waiting:",treated[3],nurse_places,treated[3]-nurse_places,"\n")
cat("Year 3 and three years within the places (THB):",
big(c(capped[3],sum(capped))*annual_incremental_cost),"\n")
cat("Users over three years, shift of 0.10:",users[1],shift,"\n")
cat("Users, every share 0.10 lower and higher:",users[2:3],"\n")
cat("Three years, every share 0.10 lower and higher (THB):",
big(users[2:3]*annual_incremental_cost),"\n")
พยาบาลรองรับสัดส่วนผู้ใช้บริการได้หรือไม่
งบประมาณสมมติว่าบริการเข้าถึงทุกคนที่นับไว้ได้ สมมติว่าพยาบาลของอำเภอติดตามผู้ใช้ได้มากที่สุดปีละ 300 คน ตามแผนงบประมาณ ปีที่ 3 มีผู้ใช้ 405.6 คน จึงมีผู้ป่วย 405.6 − 300 = 105.6 คนที่ต้องรอ
เงินสดของปีที่ 3 จึงเป็น 300 × 2,000 = 600,000 บาท ไม่ใช่ 811,200 บาท และสามปีรวมกันเป็น 240,000 + 512,000 + 600,000 = 1,352,000 บาท ให้รายงานทั้งสองตัวเลข คือเงินสดที่กองทุนจะจ่าย และผู้ป่วยที่บริการยังเข้าไม่ถึง คณะกรรมการจะได้เห็นความต้องการที่ยังไม่ได้รับบริการ ไม่ใช่เห็นเพียงยอดเงินที่ลดลง
ตรวจเครื่องวัดความดัน ช่องทางส่งต่อ และเวลาของพยาบาลก่อนเชื่อสัดส่วนผู้ใช้บริการที่เพิ่มขึ้น สัดส่วนผู้ใช้บริการเองก็เป็นการคาดการณ์ จึงควรรายงานเป็นช่วง ตามแผน ผู้ใช้รวมทุกปีคือ 120 + 256 + 405.6 = 781.6 คน ถ้าลดสัดส่วนทุกปีลง 0.10 ผู้ใช้จะหายไป 0.10 × (600 + 640 + 676) = 191.6 คน เหลือ 590 คน จึงมีต้นทุน 590 × 2,000 = 1,180,000 บาท ถ้าเพิ่มสัดส่วนทุกปีขึ้น 0.10 ผู้ใช้จะเพิ่มอีก 191.6 คน เป็น 973.2 คน และมีต้นทุน 1,946,400 บาท ก่อนคิดขีดจำกัดของพยาบาล
ตรวจขีดจำกัดของพยาบาลด้วย R
# Illustrative district: the users the nurses can follow in year 3.
# Writes: nothing to disk; the results print in the console.
eligible <- c(600,640,676)
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
nurse_places <- 300
treated <- eligible*uptake
capped <- pmin(treated,nurse_places)
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
cat("Year 3 wanted, offered, waiting:",treated[3],nurse_places,treated[3]-nurse_places,"\n")
cat("Year 3 and three years within the places (THB):",
big(c(capped[3],sum(capped))*annual_incremental_cost),"\n")
Year 3 wanted, offered, waiting: 405.6 300 105.6
Year 3 and three years within the places (THB): 600,000 1,352,000
ต้องใช้ R ≥ 4.5.2 · tibble 3.3.1 · dplyr 1.2.1 · ggplot2 4.0.3 · ใช้ได้กับ R 4.6.1 · ดาวน์โหลด budget-impact-analysis-in-practice.R
สคริปต์ฉบับเต็ม
# Budget Impact Analysis in Practice: Count People Before Counting Money
# Follow one district's stroke survivors from eligible people to the extra cash the fund pays.
# ติดตามผู้ป่วยหลังโรคหลอดเลือดสมองของอำเภอหนึ่ง จากผู้มีสิทธิจนถึงเงินสดส่วนเพิ่มที่กองทุนจ่าย
# 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 years as an explicit table.
library(dplyr) # Calculate people and money for each year.
library(ggplot2) # Display the yearly cash without saving files.
stopifnot(getRversion() >= "4.5.2")
#%%@note 1. Define the illustrative inputs
# Every input is synthetic and written out once, in the order the article uses it.
# ค่าตั้งต้นทั้งหมดเป็นข้อมูลสมมติ เขียนไว้ครั้งเดียวตามลำดับที่บทความใช้
prevalent <- 500
annual_incident <- 100
exit_fraction <- 0.10
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
current_care_cost <- 4500
nurse_places <- 300
discount_rate <- 0.03
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
#%%@note 2. Follow the eligible people year by year
# New survivors join at the year start, the year's users are counted, then exits leave at year end.
# ผู้มีสิทธิใหม่เข้าต้นปี นับผู้ใช้บริการของปีนั้น แล้วผู้ที่ออกจึงออกเมื่อสิ้นปี
stock <- rep(prevalent + annual_incident, length(uptake))
for (year_index in 2:length(uptake)) {
stock[year_index] <- stock[year_index - 1] * (1 - exit_fraction) + annual_incident
}
eligible <- c(600,640,676)
stopifnot(all(abs(stock - eligible) < 1e-9))
years <- tibble::tibble(year = seq_along(uptake), eligible = stock, uptake = uptake) |>
dplyr::mutate(treated = eligible * uptake, exits = eligible * exit_fraction,
remaining = eligible * (1 - exit_fraction),
annual_budget = treated * annual_incremental_cost,
cumulative_budget = cumsum(annual_budget))
stopifnot(all(abs(years$exits + years$remaining - years$eligible) < 1e-9))
treated <- years$treated
budget <- years$annual_budget
#%%@note 3. Price the two scenarios
# Everyone costs current care in both; only the service users add the extra cost.
# ทุกคนมีต้นทุนการดูแลเดิมในทั้งสองสถานการณ์ เฉพาะผู้ใช้บริการที่มีต้นทุนเพิ่ม
current <- eligible * current_care_cost
new <- (eligible - treated) * current_care_cost +
treated * (current_care_cost + annual_incremental_cost)
stopifnot(all(abs(new - current - budget) < 1e-6))
#%%@note 4. Check timing, rounding and the nurse places
# Wrong timing and early rounding change the cash; the nurse places cap year 3; uptake moves 0.10.
# ลำดับเวลาที่ผิดและการปัดเศษก่อนเวลาเปลี่ยนเงินสด จำนวนผู้ใช้ที่พยาบาลรับได้จำกัดปีที่ 3
exits_first <- treated[1] * c(1, 1 - exit_fraction) * annual_incremental_cost
rounded <- c(treated[3], round(treated[3]))
today_value <- 1834 / (1 + discount_rate)^3
capped <- pmin(treated, nurse_places)
shift <- 0.10 * sum(eligible)
users <- sum(eligible * uptake) + c(0, -1, 1) * shift
#%%@note 5. Display the model
# Plot the yearly extra cash; the script does not save a graphics file.
# แสดงเงินสดส่วนเพิ่มรายปี โดยไม่บันทึกไฟล์ภาพ
print(ggplot2::ggplot(years, ggplot2::aes(x = year, y = annual_budget)) +
ggplot2::geom_col() + ggplot2::labs(x = "Year", y = "Extra cash in the year (THB)"))
#%%@note 6. Numbers the article quotes
# Print exactly the short boxes in their reading order.
# พิมพ์ผลลัพธ์ตรงกับกล่องตัวอย่างตามลำดับในบทความ
cat("Year order:",seq_along(uptake),"\n")
cat("Eligible at year start (people):",eligible,"\n")
cat("Treated prevalence (people):",treated,"\n")
cat("Year-end exits (people):",eligible*exit_fraction,"\n")
cat("Remaining stock (people):",eligible*(1-exit_fraction),"\n")
cat("Annual incremental budget (THB):",big(budget),"\n")
cat("Cumulative incremental budget (THB):",big(cumsum(budget)),"\n")
cat("Shortcut, 500 x 2,000 x 3 years (THB):",big(prevalent*annual_incremental_cost*3),"\n")
cat("Cost per person (THB):",big(current_care_cost+c(0,annual_incremental_cost)),"\n")
cat("Current-care scenario (THB):",big(current),"\n")
cat("New scenario (THB):",big(new),"\n")
cat("New minus current (THB):",big(new-current),"\n")
cat("Year 1 users, exits counted after and before:",treated[1]*c(1,1-exit_fraction),"\n")
cat("Year 1, exits counted after and before (THB):",big(exits_first),"\n")
cat("Year 3 people, expected and rounded:",rounded,"\n")
cat("Year 3 budget, expected and rounded (THB):",big(rounded*annual_incremental_cost),"\n")
cat("Yearly rate back to today (%):",100*discount_rate,"\n")
cat("1,834 THB due in year 3, worth today (THB):",big(today_value),"\n")
cat("Year 3 wanted, offered, waiting:",treated[3],nurse_places,treated[3]-nurse_places,"\n")
cat("Year 3 and three years within the places (THB):",
big(c(capped[3],sum(capped))*annual_incremental_cost),"\n")
cat("Users over three years, shift of 0.10:",users[1],shift,"\n")
cat("Users, every share 0.10 lower and higher:",users[2:3],"\n")
cat("Three years, every share 0.10 lower and higher (THB):",
big(users[2:3]*annual_incremental_cost),"\n")
ตรวจช่วงของสัดส่วนผู้ใช้บริการด้วย R
# Illustrative district: the three-year cash if every year's uptake is 0.10 lower or higher.
# Writes: nothing to disk; the results print in the console.
eligible <- c(600,640,676)
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
shift <- 0.10*sum(eligible)
users <- sum(eligible*uptake)+c(0,-1,1)*shift
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
cat("Users over three years, shift of 0.10:",users[1],shift,"\n")
cat("Users, every share 0.10 lower and higher:",users[2:3],"\n")
cat("Three years, every share 0.10 lower and higher (THB):",
big(users[2:3]*annual_incremental_cost),"\n")
Users over three years, shift of 0.10: 781.6 191.6
Users, every share 0.10 lower and higher: 590 973.2
Three years, every share 0.10 lower and higher (THB): 1,180,000 1,946,400
ต้องใช้ R ≥ 4.5.2 · tibble 3.3.1 · dplyr 1.2.1 · ggplot2 4.0.3 · ใช้ได้กับ R 4.6.1 · ดาวน์โหลด budget-impact-analysis-in-practice.R
สคริปต์ฉบับเต็ม
# Budget Impact Analysis in Practice: Count People Before Counting Money
# Follow one district's stroke survivors from eligible people to the extra cash the fund pays.
# ติดตามผู้ป่วยหลังโรคหลอดเลือดสมองของอำเภอหนึ่ง จากผู้มีสิทธิจนถึงเงินสดส่วนเพิ่มที่กองทุนจ่าย
# 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 years as an explicit table.
library(dplyr) # Calculate people and money for each year.
library(ggplot2) # Display the yearly cash without saving files.
stopifnot(getRversion() >= "4.5.2")
#%%@note 1. Define the illustrative inputs
# Every input is synthetic and written out once, in the order the article uses it.
# ค่าตั้งต้นทั้งหมดเป็นข้อมูลสมมติ เขียนไว้ครั้งเดียวตามลำดับที่บทความใช้
prevalent <- 500
annual_incident <- 100
exit_fraction <- 0.10
uptake <- c(0.20,0.40,0.60)
annual_incremental_cost <- 2000
current_care_cost <- 4500
nurse_places <- 300
discount_rate <- 0.03
big <- function(value) formatC(value, format = "f", digits = 0, big.mark = ",")
#%%@note 2. Follow the eligible people year by year
# New survivors join at the year start, the year's users are counted, then exits leave at year end.
# ผู้มีสิทธิใหม่เข้าต้นปี นับผู้ใช้บริการของปีนั้น แล้วผู้ที่ออกจึงออกเมื่อสิ้นปี
stock <- rep(prevalent + annual_incident, length(uptake))
for (year_index in 2:length(uptake)) {
stock[year_index] <- stock[year_index - 1] * (1 - exit_fraction) + annual_incident
}
eligible <- c(600,640,676)
stopifnot(all(abs(stock - eligible) < 1e-9))
years <- tibble::tibble(year = seq_along(uptake), eligible = stock, uptake = uptake) |>
dplyr::mutate(treated = eligible * uptake, exits = eligible * exit_fraction,
remaining = eligible * (1 - exit_fraction),
annual_budget = treated * annual_incremental_cost,
cumulative_budget = cumsum(annual_budget))
stopifnot(all(abs(years$exits + years$remaining - years$eligible) < 1e-9))
treated <- years$treated
budget <- years$annual_budget
#%%@note 3. Price the two scenarios
# Everyone costs current care in both; only the service users add the extra cost.
# ทุกคนมีต้นทุนการดูแลเดิมในทั้งสองสถานการณ์ เฉพาะผู้ใช้บริการที่มีต้นทุนเพิ่ม
current <- eligible * current_care_cost
new <- (eligible - treated) * current_care_cost +
treated * (current_care_cost + annual_incremental_cost)
stopifnot(all(abs(new - current - budget) < 1e-6))
#%%@note 4. Check timing, rounding and the nurse places
# Wrong timing and early rounding change the cash; the nurse places cap year 3; uptake moves 0.10.
# ลำดับเวลาที่ผิดและการปัดเศษก่อนเวลาเปลี่ยนเงินสด จำนวนผู้ใช้ที่พยาบาลรับได้จำกัดปีที่ 3
exits_first <- treated[1] * c(1, 1 - exit_fraction) * annual_incremental_cost
rounded <- c(treated[3], round(treated[3]))
today_value <- 1834 / (1 + discount_rate)^3
capped <- pmin(treated, nurse_places)
shift <- 0.10 * sum(eligible)
users <- sum(eligible * uptake) + c(0, -1, 1) * shift
#%%@note 5. Display the model
# Plot the yearly extra cash; the script does not save a graphics file.
# แสดงเงินสดส่วนเพิ่มรายปี โดยไม่บันทึกไฟล์ภาพ
print(ggplot2::ggplot(years, ggplot2::aes(x = year, y = annual_budget)) +
ggplot2::geom_col() + ggplot2::labs(x = "Year", y = "Extra cash in the year (THB)"))
#%%@note 6. Numbers the article quotes
# Print exactly the short boxes in their reading order.
# พิมพ์ผลลัพธ์ตรงกับกล่องตัวอย่างตามลำดับในบทความ
cat("Year order:",seq_along(uptake),"\n")
cat("Eligible at year start (people):",eligible,"\n")
cat("Treated prevalence (people):",treated,"\n")
cat("Year-end exits (people):",eligible*exit_fraction,"\n")
cat("Remaining stock (people):",eligible*(1-exit_fraction),"\n")
cat("Annual incremental budget (THB):",big(budget),"\n")
cat("Cumulative incremental budget (THB):",big(cumsum(budget)),"\n")
cat("Shortcut, 500 x 2,000 x 3 years (THB):",big(prevalent*annual_incremental_cost*3),"\n")
cat("Cost per person (THB):",big(current_care_cost+c(0,annual_incremental_cost)),"\n")
cat("Current-care scenario (THB):",big(current),"\n")
cat("New scenario (THB):",big(new),"\n")
cat("New minus current (THB):",big(new-current),"\n")
cat("Year 1 users, exits counted after and before:",treated[1]*c(1,1-exit_fraction),"\n")
cat("Year 1, exits counted after and before (THB):",big(exits_first),"\n")
cat("Year 3 people, expected and rounded:",rounded,"\n")
cat("Year 3 budget, expected and rounded (THB):",big(rounded*annual_incremental_cost),"\n")
cat("Yearly rate back to today (%):",100*discount_rate,"\n")
cat("1,834 THB due in year 3, worth today (THB):",big(today_value),"\n")
cat("Year 3 wanted, offered, waiting:",treated[3],nurse_places,treated[3]-nurse_places,"\n")
cat("Year 3 and three years within the places (THB):",
big(c(capped[3],sum(capped))*annual_incremental_cost),"\n")
cat("Users over three years, shift of 0.10:",users[1],shift,"\n")
cat("Users, every share 0.10 lower and higher:",users[2:3],"\n")
cat("Three years, every share 0.10 lower and higher (THB):",
big(users[2:3]*annual_incremental_cost),"\n")
คำศัพท์ที่ควรแยกให้ชัด
- Budget impact analysis (การวิเคราะห์ผลกระทบด้านงบประมาณ)
- เงินสดส่วนเพิ่มที่ผู้จ่ายรายหนึ่งต้องใช้ในแต่ละปีถ้ารับการเปลี่ยนแปลงหนึ่ง ในที่นี้คือ 1,563,200 บาทในสามปี
- Eligible stock (กลุ่มผู้มีสิทธิ)
- ทุกคนที่มีสิทธิ ณ ขณะหนึ่ง ในที่นี้คือ 600 คนเมื่อต้นปีแรก
- Incident inflow (ผู้มีสิทธิรายใหม่)
- คนใหม่ที่มีสิทธิในแต่ละปี ในที่นี้คือปีละ 100 คน
- Uptake (สัดส่วนผู้ใช้บริการ)
- สัดส่วนของทุกคนที่มีสิทธิในปีนั้นที่ใช้บริการ ในที่นี้คือ 20%, 40% และ 60%
- Treated prevalence (จำนวนผู้ใช้บริการทั้งหมดในปี)
- ทุกคนที่ใช้บริการในปีหนึ่ง ทั้งผู้เริ่มใหม่และผู้ใช้ต่อเนื่อง ปีที่ 3 มีผู้ใช้ 405.6 คน
- Recurring and one-off cost (ต้นทุนที่เกิดซ้ำและต้นทุนครั้งเดียว)
- ต้นทุนที่เกิดซ้ำเกิดทุกปีที่ใช้บริการ ส่วนต้นทุนครั้งเดียวจ่ายครั้งเดียวเมื่อผู้ใช้เริ่มบริการ
- Current and new scenario (สถานการณ์ปัจจุบันและสถานการณ์ใหม่)
- รายจ่ายเมื่อไม่มีและมีการเปลี่ยนแปลง ผลกระทบด้านงบประมาณคือสถานการณ์ใหม่ลบสถานการณ์ปัจจุบัน
เชื่อมกับบทความพื้นฐาน
บทความพื้นฐานเรื่องผลกระทบด้านงบประมาณและความเป็นธรรม แสดงว่าทำไมบริการที่คุ้มค่าจึงยังอาจจ่ายไม่ไหว ส่วนบทความเรื่องการประเมินระยะแรกและการกำหนดราคา หาราคาสูงสุดที่ผู้จ่ายอาจยอมจ่ายได้ก่อนที่หลักฐานจะครบ บทความตอนหลังของชุดนี้เปรียบเทียบหลายทางเลือกพร้อมกัน
ลองใช้ในแอป
เปิดแอปการประเมินทางเศรษฐศาสตร์ของเราเพื่อลองเปลี่ยนค่าข้อมูลนำเข้าและดูผลลัพธ์เปลี่ยนตาม ต้องเข้าสู่ระบบและใช้แผน Pro หรือ Max
แอปเริ่มจากค่าตัวอย่างของแอปเอง ตัวเลขในแอปจึงไม่ตรงกับบทความนี้
เอกสารอ้างอิง
- Sullivan Sean D., Mauskopf Josephine A., Augustovski Federico, Jaime Caro J., Lee Karen M., Minchin Mark, Orlewska Ewa, Penna Pete, Rodriguez Barrios Jose-Manuel, Shau Wen-Yi. Budget Impact Analysis-Principles of Good Practice: Report of the ISPOR 2012 Budget Impact Analysis Good Practice II Task Force. Value in Health. 2014;17(1):5-14. doi:10.1016/j.jval.2013.08.2291. https://doi.org/10.1016/j.jval.2013.08.2291
- 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
- Rattanavipapong Waranya, Worakijthamrongchai Thanaboon, Soboon Budsadee, Luankongsomchit Vilawan, Kongmuangpuk Mananchaya, Isaranuwatchai Wanrudee, Teerawattananon Yot, Nilanont Yongchai. Economic evaluation of endovascular treatment for acute ischaemic stroke in Thailand. BMJ Open. 2022;12(9):e064403. doi:10.1136/bmjopen-2022-064403. https://doi.org/10.1136/bmjopen-2022-064403
ลำดับการเรียนในชุดนี้
- คู่มือชุดบทความการสร้างแบบจำลองเศรษฐศาสตร์สุขภาพ: จากหลักฐานสู่การตัดสินใจ
- การเลือกแบบจำลองเพื่อการตัดสินใจ: ให้เส้นทางทางคลินิกกำหนดโครงสร้าง
- ข้อมูลนำเข้าของแบบจำลองที่ตรวจสอบได้: สร้างตารางพารามิเตอร์ที่สืบย้อนถึงที่มา
- การค้นหาข้อมูลนำเข้าของแบบจำลองจากวรรณกรรม: เลือกค่าประมาณให้ตรงกับคำถาม
- อัตรา ความน่าจะเป็น และความน่าจะเป็นของการเปลี่ยนสถานะ: คำนวณโดยไม่หลงหน่วยเวลา
- สร้างแผนภูมิต้นไม้การตัดสินใจทีละขั้น: ตามรอยผลลัพธ์ ต้นทุน และสุขภาพ
- สร้างแบบจำลองมาร์คอฟแบบกลุ่มประชากรทีละขั้น: ติดตามประชากรผ่านเวลา
- การวิเคราะห์ผลกระทบด้านงบประมาณในทางปฏิบัติ: นับคนให้ชัดก่อนคำนวณเงิน (บทความนี้)
- ICER และผลประโยชน์สุทธิในรูปตัวเงินเมื่อมีหลายทางเลือก: หาขอบเขตทางเลือกที่มีประสิทธิภาพ
- การวิเคราะห์ความไวแบบอาศัยความน่าจะเป็น: จากการแจกแจงพารามิเตอร์สู่ CEAC
- การประเมินความสมเหตุสมผลและตรวจสอบแบบจำลอง: ทดสอบคำถาม สมการ และโค้ด
- มูลค่าคาดหมายของข้อมูลสมบูรณ์: หลักฐานที่ดีขึ้นอาจมีมูลค่าเพียงใด
ประเด็นสำคัญ
- นับคนก่อนนับเงิน: ผู้มีสิทธิ 500 คนกลายเป็น 600, 640 และ 676 คน เมื่อมีคนใหม่ 100 คนเข้ามาและ 10% ออกไปทุกปี
- ใช้สัดส่วนผู้ใช้บริการกับทุกคนที่มีสิทธิในปีนั้น ได้ผู้ใช้ 120, 256 และ 405.6 คน และคิดต้นทุนที่เกิดซ้ำคนละ 2,000 บาทให้ทุกคน
- ภายในหนึ่งปี ให้เพิ่มผู้มาใหม่ นับผู้ใช้และคิดต้นทุน แล้วจึงให้ผู้ที่พ้นสิทธิออกจากกลุ่ม ลำดับแบบอื่นทำให้ปีที่ 1 ลดจาก 240,000 เหลือ 216,000 บาท
- งบประมาณคือสถานการณ์ใหม่ลบสถานการณ์ปัจจุบัน เป็นเงินสดในปีที่จ่าย: 1,563,200 บาทในสามปี ไม่ใช่ 3,000,000 บาท
- ตรวจกำลังการให้บริการ: ถ้าพยาบาลรับได้ 300 คนในปีที่ 3 เงินสดปีนั้นจะเป็น 600,000 บาท รวมสามปี 1,352,000 บาท และผู้ป่วย 105.6 คนต้องรอ
อ่านต่อในวิกิ: คุ้มค่าไม่ได้แปลว่าจ่ายไหว มีประสิทธิภาพไม่ได้แปลว่าเป็นธรรม: ผลกระทบด้านงบประมาณและความเป็นธรรมทางสุขภาพ · การประเมินเทคโนโลยีสุขภาพระยะเริ่มต้น เพดานราคาที่คุ้มค่า และการตัดสินใจชุดสิทธิประโยชน์