연속형 분포

연속형 분포
확률분포
균등분포
정규분포
지수분포
감마분포
베타분포
저자

이광춘

공개

2024-05-07

연속확률분포를 시각화하고 상호작용하는 Shiny 애플리케이션과 관련 코드를 설명합니다.

  1. Shiny 앱: 사용자가 주요 연속확률분포(균등, 정규, 지수, 감마, 베타 분포) 중 하나를 선택하고 해당 분포의 매개변수를 조정할 수 있는 웹 기반 인터페이스를 제공합니다. 사용자는 선택한 분포에 따라 확률밀도함수(PDF)와 누적밀도함수(CDF)를 그래프로 시각화할 수 있습니다.

  2. 코딩: 분석 대상 데이터가 어떤 분포를 따르는지를 이해하고, 이를 그래픽으로 표현하여 데이터의 분포 형태와 경향을 확인할 수 있습니다. continuous_dist_summary 함수는 주어진 분포와 매개변수를 기반으로 요약통계량과 검정통계량, 히스토그램, 확률밀도함수(PDF)와 누적분포함수(CDF)를 계산하고 시각화합니다.

#| label: shinylive-discrete-distribution
#| viewerHeight: 700
#| standalone: true

library(shiny)
library(ggplot2)

library(bslib)
library(showtext)
tryCatch(sysfonts::font_add_google("Nanum Myeongjo", "kr"), error = function(e) NULL)
showtext_auto()

# ── Tufte 팔레트 · 테마 (자동 주입) ──────────────────────────
bit_cream <- "#fffff8"; bit_ink <- "#111111"; bit_rust <- "#8a1500"
bit_muted <- "#4a4a44"; bit_grid <- "#e8e6dc"; bit_axis <- "#8a8578"
theme_tufte_bit <- function(base_size = 13) {
  ggplot2::theme_minimal(base_size = base_size) +
    ggplot2::theme(
      text = ggplot2::element_text(family = "kr", colour = bit_ink),
      plot.title = ggplot2::element_text(family = "kr", size = base_size, hjust = 0),
      plot.background = ggplot2::element_rect(fill = bit_cream, colour = NA),
      panel.background = ggplot2::element_rect(fill = bit_cream, colour = NA),
      panel.grid.major = ggplot2::element_line(colour = bit_grid, linewidth = 0.3),
      panel.grid.minor = ggplot2::element_blank(),
      axis.line = ggplot2::element_line(colour = bit_axis, linewidth = 0.3),
      axis.ticks = ggplot2::element_line(colour = bit_axis, linewidth = 0.3)
    )
}
if (requireNamespace("ggplot2", quietly = TRUE)) ggplot2::theme_set(theme_tufte_bit())
bit_theme <- bs_theme(
  version = 5, bg = bit_cream, fg = bit_ink, primary = bit_rust,
  base_font = font_collection("Palatino Linotype", "Georgia", "Times New Roman", "serif"),
  "card-box-shadow" = "none"
)
# ─────────────────────────────────────────────────────────────

ui <- fluidPage(
  theme = bit_theme,
  titlePanel("연속형 분포"),
  sidebarLayout(
    sidebarPanel(
      radioButtons("dist", "분포 선택:",
                   choices = c("균등" = "Uniform", "정규" = "Normal",
                               "지수" = "Exponential", "감마" = "Gamma", "베타" = "Beta"),
                   inline = TRUE),
      conditionalPanel(
        condition = "input.dist == 'Uniform'",
        sliderInput("unif_min", "최솟값 (a):", min = -10, max = 0, value = -1, step = 0.1),
        sliderInput("unif_max", "최댓값 (b):", min = 0, max = 10, value = 1, step = 0.1)
      ),
      conditionalPanel(
        condition = "input.dist == 'Normal'",
        sliderInput("norm_mean", "평균 (μ):", min = -10, max = 10, value = 0, step = 0.1),
        sliderInput("norm_sd", "표준편차 (σ):", min = 0.1, max = 5, value = 1, step = 0.1),
        sliderInput("x_range_norm", "x 범위:", min = -10, max = 10, value = c(-5, 5), step = 0.1)
      ),
      conditionalPanel(
        condition = "input.dist == 'Exponential'",
        sliderInput("exp_rate", "비율 (λ):", min = 0.1, max = 5, value = 1, step = 0.1),
        sliderInput("x_range_exp", "x 범위:", min = 0, max = 10, value = c(0, 5), step = 0.1)
      ),
      conditionalPanel(
        condition = "input.dist == 'Gamma'",
        sliderInput("gamma_shape", "형상 (α):", min = 0.1, max = 5, value = 1, step = 0.1),
        sliderInput("gamma_rate", "비율 (β):", min = 0.1, max = 5, value = 1, step = 0.1),
        sliderInput("x_range_gamma", "x 범위:", min = 0, max = 10, value = c(0, 5), step = 0.1)
      ),
      conditionalPanel(
        condition = "input.dist == 'Beta'",
        sliderInput("beta_shape1", "형상1 (α):", min = 0.1, max = 5, value = 1, step = 0.1),
        sliderInput("beta_shape2", "형상2 (β):", min = 0.1, max = 5, value = 1, step = 0.1),
        sliderInput("x_range_beta", "x 범위:", min = 0, max = 1, value = c(0, 1), step = 0.01)
      )
    ),
    mainPanel(
      tabsetPanel(
        tabPanel("PDF 그래프", plotOutput("pdf_plot")),
        tabPanel("CDF 그래프", plotOutput("cdf_plot"))
      ),
      h4("사용 방법:"),
      tags$ol(
        tags$li("라디오 버튼으로 분포 종류를 선택합니다."),
        tags$li("슬라이더로 선택한 분포의 모수를 조정합니다."),
        tags$li("'x 범위' 슬라이더로 x축의 범위를 조절합니다."),
        tags$li("각 탭에서 PDF와 CDF 그래프를 살펴봅니다.")
      )
    )
  )
)

server <- function(input, output) {

  dist_data <- reactive({
    if (input$dist == "Uniform") {
      x <- seq(input$unif_min-1, input$unif_max+1, length.out = 500)
      data.frame(x = x, pdf = dunif(x, min = input$unif_min, max = input$unif_max),
                 cdf = punif(x, min = input$unif_min, max = input$unif_max))
    } else if (input$dist == "Normal") {
      x <- seq(input$x_range_norm[1], input$x_range_norm[2], length.out = 500)
      data.frame(x = x, pdf = dnorm(x, mean = input$norm_mean, sd = input$norm_sd),
                 cdf = pnorm(x, mean = input$norm_mean, sd = input$norm_sd))
    } else if (input$dist == "Exponential") {
      x <- seq(input$x_range_exp[1], input$x_range_exp[2], length.out = 500)
      data.frame(x = x, pdf = dexp(x, rate = input$exp_rate),
                 cdf = pexp(x, rate = input$exp_rate))
    } else if (input$dist == "Gamma") {
      x <- seq(input$x_range_gamma[1], input$x_range_gamma[2], length.out = 500)
      data.frame(x = x, pdf = dgamma(x, shape = input$gamma_shape, rate = input$gamma_rate),
                 cdf = pgamma(x, shape = input$gamma_shape, rate = input$gamma_rate))
    } else if (input$dist == "Beta") {
      x <- seq(input$x_range_beta[1], input$x_range_beta[2], length.out = 500)
      data.frame(x = x, pdf = dbeta(x, shape1 = input$beta_shape1, shape2 = input$beta_shape2),
                 cdf = pbeta(x, shape1 = input$beta_shape1, shape2 = input$beta_shape2))
    }
  })

  output$pdf_plot <- renderPlot({
    ggplot(dist_data(), aes(x = x, y = pdf)) +
      geom_line(color = "#4a4a44") +
      labs(title = "확률밀도함수 (PDF)",
           x = "x", y = "밀도")
  })

  output$cdf_plot <- renderPlot({
    ggplot(dist_data(), aes(x = x, y = cdf)) +
      geom_line(color = "#4a4a44") +
      labs(title = "누적분포함수 (CDF)",
           x = "x", y = "누적확률")
  })
}

shinyApp(ui, server)

라이센스