0Pricing
R Academy · 강의

R에서 Stan 모델 작성하기

Stan 문법으로 데이터 블록, 매개변수 및 모델 블록을 정의합니다.

R에서 Stan 모델 작성하기은(는) CoddyKit의 무료 R Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 R Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

Stan이란?

Stan은 베이지안 통계 모델링을 위한 확률 프로그래밍 언어입니다. RStan은 Stan에 연결하는 R 인터페이스입니다. Stan 언어(C++와 유사)로 모델을 작성하면 Stan이 이를 효율적인 C++ 코드로 컴파일하고, 해밀토니안 몬테카를로(HMC) 샘플링을 실행해 사후 분포를 근사합니다.

# Stan installation check
library(rstan)

# Check version
cat('RStan version:', as.character(packageVersion('rstan')), '\n')

# Enable parallel chains
options(mc.cores = parallel::detectCores())

# Reuse compiled models across sessions
rstan_options(auto_write = TRUE)

cat('Stan ready. Cores:', parallel::detectCores(), '\n')

Stan 모델 구조

Stan 모델에는 이름이 지정된 블록이 최대 6개 있습니다. data, transformed data, parameters, transformed parameters, model, generated quantities입니다. 이 중 필수 블록은 data, parameters, model입니다.

library(rstan)

# Stan model as a character string in R
stan_code <- '
data {
  int<lower=0> N;       // number of observations
  vector[N] x;          // predictor
  vector[N] y;          // response
}
parameters {
  real alpha;           // intercept
  real beta;            // slope
  real<lower=0> sigma;  // noise (must be positive)
}
model {
  // Priors
  alpha ~ normal(0, 10);
  beta  ~ normal(0, 10);
  sigma ~ exponential(1);

  // Likelihood
  y ~ normal(alpha + beta * x, sigma);
}
'

cat('Stan model defined as a string in R\n')
cat('Blocks: data, parameters, model\n')

data{}: 입력 데이터 선언

data 블록은 모델이 R에서 받는 모든 외부 데이터를 선언합니다. 자료형에는 int, real, vector[N], matrix[M,N], array가 있습니다. <lower=0>과 같은 제약 조건은 실행 중에 확인됩니다.

library(rstan)

# Comprehensive data block examples
data_block_examples <- '
data {
  // Scalars
  int<lower=1> N;               // at least 1 observation
  int<lower=2> K;               // at least 2 groups

  // Constrained scalars
  real<lower=0, upper=1> rate;  // probability

  // Vectors
  vector[N] y;                  // continuous response
  array[N] int<lower=0, upper=1> z;  // binary outcomes

  // Matrix
  matrix[N, K] X;               // design matrix

  // Integer array
  array[N] int group;           // group membership 1..K
}
'

cat(data_block_examples)

parameters{}: 매개변수 유형

parameters 블록은 Stan이 표본 추출할 미지의 값을 선언합니다. 이 블록의 제약 조건은 매개변수 공간을 정의합니다. 양수인 양에는 <lower=0>을, 확률에는 <lower=0, upper=1>을 사용합니다. Stan은 제약이 있는 매개변수에 대해 로그 확률 야코비안 보정을 자동으로 적용합니다.

library(rstan)

# Common parameter declarations
param_examples <- '
parameters {
  // Unconstrained
  real mu;                        // mean
  vector[K] beta;                 // regression coefficients

  // Positive (sigma, lambda, variance)
  real<lower=0> sigma;
  real<lower=0> lambda;

  // Probability
  real<lower=0, upper=1> theta;

  // Simplex (sums to 1, for mixture weights)
  simplex[K] pi;

  // Correlation matrix
  corr_matrix[K] Omega;

  // Cholesky factor of covariance
  cholesky_factor_cov[K] L_Sigma;
}
'
cat(param_examples)

model{}: 사전분포와 가능도

model 블록은 ~(틸드) 구문을 통해 로그 사후분포를 누적합니다. y ~ normal(mu, sigma)는 정규 PDF의 로그를 target에 더하는 축약 표현입니다. target += normal_lpdf(y | mu, sigma)를 사용하면 로그 확률 증가분을 명시적으로 작성할 수 있습니다.

library(rstan)

model_block_example <- '
model {
  // --- Priors ---
  mu    ~ normal(0, 10);          // weakly informative
  sigma ~ cauchy(0, 2.5);         // half-Cauchy for scale
  beta  ~ normal(0, 1);           // standardised coefficients

  // --- Likelihood ---
  // Tilde notation (most common)
  y ~ normal(mu + X * beta, sigma);

  // Equivalent explicit notation:
  // target += normal_lpdf(y | mu + X * beta, sigma);

  // For loop (less common but valid)
  // for (i in 1:N)
  //   target += normal_lpdf(y[i] | mu, sigma);
}
'
cat(model_block_example)

간단한 정규 모델 적합

다음은 완전하면서도 최소한으로 구성된 Stan 작업 흐름입니다. 모델 문자열을 정의하고, 데이터 목록을 준비한 다음, stan()을 호출하고, print()로 결과를 확인합니다. Stan은 처음 실행할 때 모델을 컴파일하고 이후 실행을 위해 캐시합니다.

library(rstan)

# Stan model: estimate mean and SD of a normal distribution
normal_model <- '
data {
  int<lower=0> N;
  vector[N] y;
}
parameters {
  real mu;
  real<lower=0> sigma;
}
model {
  mu    ~ normal(0, 10);
  sigma ~ exponential(0.1);
  y     ~ normal(mu, sigma);
}
'

# Simulate data
set.seed(42)
y_data <- rnorm(50, mean = 5, sd = 2)

# Fit the model
fit <- stan(
  model_code = normal_model,
  data       = list(N = length(y_data), y = y_data),
  chains     = 2,
  iter       = 1000,
  warmup     = 500,
  refresh    = 0  # suppress iteration output
)

print(fit, pars = c('mu', 'sigma'))

Stan에서의 선형 회귀

Stan을 사용하면 베이지안 선형 회귀를 간단하게 구현할 수 있습니다. 계수에는 정규 사전분포를 지정하고 sigma에는 지수분포 또는 반 코시 사전분포를 지정합니다. 사후분포는 점 추정치만이 아니라 각 계수의 전체 불확실성 분포를 제공합니다.

library(rstan)

lin_reg_model <- '
data {
  int<lower=0> N;
  vector[N] x;
  vector[N] y;
}
parameters {
  real alpha;
  real beta;
  real<lower=0> sigma;
}
model {
  alpha ~ normal(0, 10);
  beta  ~ normal(0, 10);
  sigma ~ exponential(1);
  y ~ normal(alpha + beta * x, sigma);
}
generated quantities {
  vector[N] y_rep;  // posterior predictive
  for (i in 1:N)
    y_rep[i] = normal_rng(alpha + beta * x[i], sigma);
}
'

set.seed(7)
n <- 80
x <- rnorm(n); y <- 2 + 3 * x + rnorm(n, 0, 1)

fit <- stan(model_code = lin_reg_model,
            data = list(N = n, x = x, y = y),
            chains = 2, iter = 1000, refresh = 0)
print(fit, pars = c('alpha', 'beta', 'sigma'))

transformed parameters{} 블록

transformed parameters 블록은 표본 추출된 매개변수에서 파생된 값을 계산합니다. 기본 매개변수의 해석 가능성을 유지하면서 수치적으로 안정적인 방식(예: 촐레스키 분해, 로그 변환)으로 모델을 매개변수화할 때 유용합니다.

library(rstan)

# Model with transformed parameters
trans_param_example <- '
data {
  int<lower=0> N;
  array[N] int<lower=0> y;  // counts
}
parameters {
  real log_lambda;           // work in log space for stability
}
transformed parameters {
  real<lower=0> lambda;
  lambda = exp(log_lambda);  // transform back to original scale
}
model {
  log_lambda ~ normal(1, 2);  // prior on log scale
  y ~ poisson(lambda);
}
'

set.seed(42)
y_counts <- rpois(30, lambda = 5)

fit_poisson <- stan(
  model_code = trans_param_example,
  data       = list(N = length(y_counts), y = y_counts),
  chains     = 2, iter = 1000, refresh = 0
)
print(fit_poisson, pars = c('log_lambda', 'lambda'))

generated quantities{} 블록

generated quantities 블록은 표본 추출이 끝난 후 실행되어 추가 값을 계산합니다. 예를 들어 사후 예측 표본(y_rep), LOO-CV를 위한 로그 가능도, 요약을 위한 변환된 매개변수 등을 계산할 수 있습니다. 이 블록의 값은 사후 예측 분포에서 표본 추출됩니다.

library(rstan)

# Use generated quantities for posterior predictive checks
model_with_gq <- '
data {
  int<lower=0> N;
  vector[N] y;
}
parameters {
  real mu;
  real<lower=0> sigma;
}
model {
  mu    ~ normal(0, 10);
  sigma ~ exponential(0.5);
  y     ~ normal(mu, sigma);
}
generated quantities {
  vector[N] y_rep;           // replicated datasets
  real mean_y_rep;           // mean of replicated data
  for (i in 1:N)
    y_rep[i] = normal_rng(mu, sigma);
  mean_y_rep = mean(y_rep);
}
'

set.seed(1)
y_obs <- rnorm(40, 3, 1.5)
fit <- stan(model_code = model_with_gq,
            data = list(N = length(y_obs), y = y_obs),
            chains = 2, iter = 1000, refresh = 0)
print(fit, pars = c('mu', 'sigma', 'mean_y_rep'))

R에서 Stan으로 데이터 전달하기

stan()의 data 인수는 이름이 지정된 R 목록입니다. 이름은 Stan의 data{} 블록에서 선언한 변수 이름과 정확히 일치해야 합니다. 벡터는 Stan의 vector[N]가 되고, 정수는 int가 되며, R 행렬은 Stan의 matrix[M,N]이 됩니다.

library(rstan)

# Data preparation: names must match Stan data block exactly
set.seed(42)
n <- 60
x1 <- rnorm(n)
x2 <- rnorm(n)
y  <- 1.5 + 2 * x1 - 0.8 * x2 + rnorm(n, 0, 0.5)

# Build the design matrix
X <- cbind(x1, x2)  # 60 x 2 matrix

# Named list passed to stan(data = ...)
stan_data <- list(
  N = n,          # int
  K = ncol(X),    # int
  X = X,          # matrix[N, K]
  y = y           # vector[N]
)

cat('Stan data list elements:\n')
for (nm in names(stan_data)) {
  cat(' ', nm, ': class =', class(stan_data[[nm]]),
      'dim =', paste(dim(stan_data[[nm]]), collapse = 'x'),
      '\n')
}

컴파일된 모델 확인하기

적합이 끝난 후 print(fit)을 사용하면 모든 매개변수에 대한 사후분포 요약(평균, se_mean, sd, 분위수, Rhat, n_eff)을 확인할 수 있습니다. 시각적 구간 도표에는 stan_plot(fit)을, 연쇄 혼합 상태를 평가하려면 traceplot(fit)을 사용합니다.

library(rstan)

# Reuse the simple normal model from scene 6
normal_model <- '
data { int<lower=0> N; vector[N] y; }
parameters { real mu; real<lower=0> sigma; }
model {
  mu ~ normal(0, 10);
  sigma ~ exponential(0.1);
  y ~ normal(mu, sigma);
}
'

set.seed(5)
fit <- stan(model_code = normal_model,
            data = list(N = 50, y = rnorm(50, 7, 3)),
            chains = 2, iter = 1000, refresh = 0)

# Detailed summary table
print(fit)

# Extract as data frame
posterior_df <- as.data.frame(fit)
cat('\nPosterior samples shape:', nrow(posterior_df),
    'rows x', ncol(posterior_df), 'cols\n')

빠른 확인

Stan 모델에서 매개변수가 엄밀히 양수가 되도록 제한하려고 합니다(예: 표준편차). 어떤 선언이 올바를까요?

복습: Stan 모델 작성하기

핵심 요점:

  • Stan 모델에는 세 가지 필수 블록이 있습니다: data{}, parameters{}, model{}
  • 제약 조건: 확률에는 <lower=0>, <upper=1>, <lower=0, upper=1>을 사용합니다
  • 유형: int, real, vector[N], matrix[M,N], simplex[K]
  • 모델 블록: 사전분포와 가능도에는 틸드 구문 y ~ normal(mu, sigma)을 사용합니다
  • 파생된 값에는 transformed parameters{}를, 표본 추출 후 계산에는 generated quantities{}를 사용합니다
  • 데이터는 Stan 블록 이름과 정확히 일치하는 이름 지정 R 목록으로 전달합니다
  • rstan_options(auto_write = TRUE)는 컴파일된 모델을 캐시합니다
library(rstan)

# Stan model skeleton
model_skeleton <- '
data    { int N; vector[N] y; }
parameters { real mu; real<lower=0> sigma; }
model   { mu ~ normal(0,10); sigma ~ exponential(1); y ~ normal(mu, sigma); }
'
cat(model_skeleton)
cat('\nFit with: stan(model_code = model_skeleton, data = list(N=..., y=...), chains=4)\n')

자주 묻는 질문

“R에서 Stan 모델 작성하기” 강의는 무료인가요?

네 — “R에서 Stan 모델 작성하기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 R Academy 강의 전체를 잠금 해제할 수 있습니다. R Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“R에서 Stan 모델 작성하기”에서 뭘 배우나요?

Stan 문법으로 데이터 블록, 매개변수 및 모델 블록을 정의합니다. 브라우저에서 직접 실행하는 실습 코드로 R Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

R Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 R Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.

“R에서 Stan 모델 작성하기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 R Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 R Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 베이지안 사고 입문
  2. R에서 Stan 모델 작성하기
  3. MCMC 표본추출과 진단
  4. 사후예측검사
← R Academy(으)로 돌아가기