Files
admin 33e9543b15 Upload to Server
Uploading to server
2025-08-02 05:15:23 +07:00

209 lines
7.8 KiB
R

# Tải các thư viện cần thiết
library(shiny)
library(bslib)
library(ggplot2)
library(shinycssloaders)
library(pwr)
# --- Giao diện người dùng (UI) ---
ui <- fluidPage(
theme = bs_theme(version = 5, bootswatch = "cerulean"),
withMathJax(),
titlePanel("Tính toán Cỡ mẫu cho Kiểm định t một mẫu"),
sidebarLayout(
sidebarPanel(
h4("Tham số đầu vào"),
numericInput("d",
label = "Effect Size (Cohen's d):",
value = 0.5, min = 0.1, step = 0.1),
helpText("Cohen's d đo lường độ lớn của sự khác biệt. Quy ước: 0.2 (nhỏ), 0.5 (trung bình), 0.8 (lớn)."),
selectInput("alternative", "Loại kiểm định:",
choices = c("Hai phía (Two-sided)" = "two.sided",
"Lớn hơn (Greater)" = "greater",
"Nhỏ hơn (Less)" = "less")),
sliderInput("sig_level",
label = "Mức ý nghĩa (\\(\\alpha\\)):",
min = 0.01, max = 0.10, value = 0.05, step = 0.01),
sliderInput("power",
label = "Power mong muốn (\\(1 - \\beta\\)):",
min = 0.50, max = 0.99, value = 0.80, step = 0.01),
hr(),
helpText("Ứng dụng sử dụng hàm pwr.t.test() từ gói 'pwr'. Kết quả và đồ thị sẽ tự động cập nhật ngay lập tức.")
),
mainPanel(
tabsetPanel(
id = "results_tabs",
type = "pills",
tabPanel(
"Kết quả & Diễn giải",
h4("Kết quả tính toán"),
withSpinner(uiOutput("sample_size_output"), type = 6, color = "#007bff")
),
tabPanel(
"Đồ thị Power vs. Cỡ mẫu",
h4("Mối quan hệ giữa Power và Cỡ mẫu"),
withSpinner(plotOutput("power_plot"), type = 6, color = "#007bff")
),
tabPanel(
"Phân tích Effect Size",
h4("Mối quan hệ giữa Cỡ mẫu và Effect Size"),
p("Đồ thị này cho thấy cỡ mẫu cần thiết thay đổi như thế nào khi Effect Size thay đổi."),
withSpinner(plotOutput("effect_analysis_plot"), type = 6, color = "#007bff")
),
tabPanel(
"Giả thuyết và Công thức (Helper)",
h4("Giả thuyết của Kiểm định t một mẫu"),
p("Kiểm định này so sánh trung bình của một mẫu duy nhất (\\(\\mu\\)) với một giá trị trung bình đã biết hoặc giả định (\\(\\mu_0\\))."),
p("$$H_0: \\mu = \\mu_0$$"),
p("$$H_a: \\mu \\neq \\mu_0 \\quad (\\text{hoặc } > \\text{ hoặc } <\\text{)}$$"),
hr(),
h4("Công thức tính toán"),
tags$b("1. Thống kê kiểm định (Test Statistic):"),
p("Giá trị thống kê t được tính như sau:"),
p("$$ t = \\frac{\\bar{x} - \\mu_0}{s / \\sqrt{n}} $$"),
p("Trong đó \\(\\bar{x}\\) là trung bình mẫu, \\(s\\) là độ lệch chuẩn mẫu, và \\(n\\) là cỡ mẫu."),
tags$b("2. Effect Size (Cohen's d):"),
p("Cohen's d cho trường hợp một mẫu được định nghĩa là:"),
p("$$ d = \\frac{|\\mu_{alternative} - \\mu_0|}{\\sigma} $$"),
p("Trong đó \\(\\mu_{alternative}\\) là trung bình thực sự dưới giả thuyết đối, và \\(\\sigma\\) là độ lệch chuẩn của tổng thể."),
tags$b("3. Tính toán Power:"),
p("Ứng dụng này sử dụng hàm `pwr.t.test` với tham số `type = 'one.sample'`. Hàm này giải phương trình power dựa trên phân phối t phi trung tâm để tìm ra cỡ mẫu `n`.")
)
)
)
)
)
# --- Logic của máy chủ (Server) ---
server <- function(input, output, session) {
# --- PHẦN TÍNH TOÁN CHÍNH ---
main_results <- reactive({
req(input$d, input$sig_level, input$power, input$alternative)
pwr_result <- tryCatch({
pwr.t.test(
d = input$d,
sig.level = input$sig_level,
power = input$power,
type = "one.sample", # THAY ĐỔI QUAN TRỌNG
alternative = input$alternative
)
}, error = function(e) NULL)
if (is.null(pwr_result)) return(NULL)
required_n <- ceiling(pwr_result$n)
sample_sizes <- seq(5, required_n + 50, by = 1)
power_data <- tryCatch({
pwr.t.test(
n = sample_sizes,
d = input$d,
sig.level = input$sig_level,
type = "one.sample", # THAY ĐỔI QUAN TRỌNG
alternative = input$alternative
)
}, error = function(e) NULL)
if(is.null(power_data)) return(list(required_n = required_n, power_plot_data = NULL))
list(
required_n = required_n,
power_plot_data = data.frame(SampleSize = power_data$n, Power = power_data$power)
)
})
output$sample_size_output <- renderUI({
res <- main_results()
if (is.null(res)) {
return(tags$div(class = "alert alert-danger", "Có lỗi xảy ra trong quá trình tính toán. Vui lòng kiểm tra lại các tham số."))
}
tagList(
tags$p("Để phát hiện một effect size (Cohen's d) là", tags$b(input$d), "với power là", tags$b(input$power), "và mức ý nghĩa", tags$b(input$sig_level), ", bạn cần một cỡ mẫu ước tính là:"),
tags$h3(style = "color: #007bff; text-align: center;", res$required_n)
)
})
output$power_plot <- renderPlot({
res <- main_results()
req(res$power_plot_data)
ggplot(res$power_plot_data, aes(x = SampleSize, y = Power)) +
geom_line(color = "#007bff", size = 1.2) +
geom_hline(yintercept = input$power, linetype = "dashed", color = "red") +
geom_vline(xintercept = res$required_n, linetype = "dashed", color = "darkgreen") +
labs(title = "Power vs. Cỡ mẫu", x = "Cỡ mẫu (n)", y = "Power (1 - β)") +
scale_y_continuous(limits = c(0, 1)) + theme_minimal(base_size = 14)
})
# --- PHẦN PHÂN TÍCH EFFECT SIZE ---
effect_analysis_plot_data <- reactive({
req(input$sig_level, input$power, input$alternative)
effect_sizes <- seq(0.1, 1.5, by = 0.05)
required_n_values <- sapply(effect_sizes, function(d_val) {
res <- tryCatch({
pwr.t.test(
d = d_val,
sig.level = input$sig_level,
power = input$power,
type = "one.sample", # THAY ĐỔI QUAN TRỌNG
alternative = input$alternative
)$n
}, error = function(e) NA)
ceiling(res)
})
data.frame(EffectSize = effect_sizes, RequiredN = required_n_values)
})
output$effect_analysis_plot <- renderPlot({
plot_data <- effect_analysis_plot_data()
res <- main_results() # Lấy kết quả chính để đánh dấu
p <- ggplot(plot_data, aes(x = EffectSize, y = RequiredN)) +
geom_line(color = "#28a745", size = 1.2) +
geom_point(color = "#28a745", size = 3, na.rm = TRUE) +
labs(
title = paste("Cỡ mẫu cần thiết vs. Effect Size (Power cố định =", input$power, ")"),
x = "Effect Size (Cohen's d)",
y = "Cỡ mẫu cần thiết (n)"
) +
theme_minimal(base_size = 14)
# THÊM ĐÁNH DẤU TRỰC QUAN (IMPROVED)
if (!is.null(res) && !is.na(res$required_n)) {
p <- p +
geom_vline(xintercept = input$d, linetype = "dotted", color = "blue", size = 1) +
geom_point(aes(x = input$d, y = res$required_n), color = "blue", size = 5, shape = 18) +
annotate("text", x = input$d, y = res$required_n,
label = paste("n =", res$required_n), vjust = -1.5, color = "blue", fontface = "bold")
}
p # In đồ thị
})
}
# Chạy ứng dụng Shiny
shinyApp(ui = ui, server = server)