계층 모형과 임의·고정 효과 — HLM 의 수식과 R/Python 구현 (Buisson Ch.10.2)

Random Intercept, Nested Random Effect, Fixed vs Random Effect, lmer/mixedlm 사용법

Buisson (2021) Ch.10 의 hierarchical model 절을 자세히 정리한다. HLM 의 수식 (multi-level regression), Random Intercept 의 의미, Nested random effect 의 처리, Fixed Effect vs Random Effect 의 비교, R 의 lmer 와 Python 의 mixedlm 코드, 결과 해석을 단계별로 시연한다.

Experimentation
Causal Inference
저자

Kwangmin Kim

공개

2026년 05월 08일

1 정의

정의: Hierarchical Linear Model (HLM)

Nested 또는 grouped 데이터에 대한 회귀 모형. 각 group 의 random intercept (또는 slope) 를 도입해 group 간 baseline 차이를 모형에 통합 (Buisson, 2021, Ch.10).

기본 구조 (2-level):

Level 1 (call): y_ij = β_0j + β_1 * X_ij + ε_ij
Level 2 (center): β_0j = γ_00 + γ_01 * Group_j + u_j

ε_ij ~ Normal(0, σ²)        # call 잡음
u_j ~ Normal(0, τ²)         # center 잡음 (random effect)

해석:

  • \(\beta_{0j}\) = center j 의 baseline (각 center 다름)
  • \(\gamma_{00}\) = 전체 평균
  • \(\gamma_{01}\) = treatment 효과 (모든 center 공통)
  • \(u_j\) = center j 의 baseline 편차 (random)
직관 — 왜 HLM 이 필요한가

분석가의 자연스러운 직감: “일반 회귀에 center 변수 dummy 추가 = HLM 과 같지 않나?”

차이:

방법 특징
Standard regression + dummy 각 center 의 effect 를 fixed parameter 로 추정. 변수 수 = N_center. 작동 가능.
HLM (random effect) Center effect 를 distribution 의 sample 로 처리. 변수 수 = 1 (variance). 통계적 효율 ↑.

HLM 의 장점:

  1. 효율성: N_center 의 fixed parameter 보다 1 개의 variance 가 더 안정 추정
  2. Generalization: Cluster 가 더 큰 모집단의 sample 일 때 적합
  3. Cross-cluster pooling: 작은 cluster 의 추정이 다른 cluster 정보로 stabilize

콜센터 사례:

  • 10 cluster, 각 cluster 의 baseline 다름
  • 표준 회귀: 9 dummy 추정 → noise
  • HLM: 1 variance 추정 → 안정

→ HLM 이 cluster 데이터의 표준 도구.

2 Random Intercept

2.1 수식과 직관

단일 cluster 변수

단순 모형:

\[ y_{ij} = \beta_0 + \beta_1 \cdot X_{ij} + u_j + \epsilon_{ij} \]

여기서:

  • \(y_{ij}\) = \(j\) cluster 의 \(i\) 번째 observation
  • \(\beta_0\) = grand mean (intercept)
  • \(u_j \sim N(0, \tau^2)\) = cluster \(j\) 의 random deviation
  • \(\epsilon_{ij} \sim N(0, \sigma^2)\) = within-cluster 잡음

두 variance:

  • \(\tau^2\): between-cluster (cluster 간 baseline 차이)
  • \(\sigma^2\): within-cluster (cluster 내 individual 차이)
직관 — 두 variance 의 의미

비유: 학교의 학생 키.

  • Between-cluster variance (\(\tau^2\)): 학교마다 평균 키 다름 (한 학교가 큼, 다른 학교가 작음)
  • Within-cluster variance (\(\sigma^2\)): 같은 학교 내 학생 키 차이

전체 variance = between + within.

콜센터 사례:

  • \(\tau^2 = 1.4\) (콜센터 간 CSAT 평균 변동 큼)
  • \(\sigma^2 = 1.1\) (같은 콜센터 내 통화별 CSAT 변동)

ICC = \(\tau^2 / (\tau^2 + \sigma^2)\) = 0.56.

→ ICC 0.56 = “Variance 의 56% 가 cluster 간 차이”. 매우 큼.

2.2 Random vs Fixed Intercept

Fixed Intercept 모형

\[ y_{ij} = \beta_{0,j} + \beta_1 \cdot X_{ij} + \epsilon_{ij} \]

여기서 \(\beta_{0,j}\) 는 cluster 마다 다른 fixed parameter (회귀에서 dummy 변수로 추정).

장점:

  • 각 cluster 의 baseline 정확 추정
  • 해석 직관적

단점:

  • Cluster 수만큼 parameter (10 cluster → 10 dummy)
  • Cluster 가 많으면 over-parameterization
  • Cluster 가 일부 작으면 그 cluster 의 추정 불안정

→ Cluster 가 많거나 size 작으면 fixed intercept 부적절.

Random Intercept 모형

\[ y_{ij} = \beta_0 + \beta_1 \cdot X_{ij} + u_j + \epsilon_{ij}, \quad u_j \sim N(0, \tau^2) \]

여기서 \(u_j\) 는 random.

장점:

  • Parameter 수 작음 (\(\tau^2\) 1 개)
  • 작은 cluster 의 추정이 grand mean 으로 shrink (안정)
  • Cluster 가 모집단의 sample 라는 가정에 부합

단점:

  • 각 cluster 의 effect 를 직접 추정하지 않음
  • 정규성 가정 (random effect 분포)
직관 — Shrinkage 효과

작은 cluster 의 unique 추정 vs HLM 추정 비교:

Cluster A (10 obs): 평균 8.5
Cluster B (1000 obs): 평균 7.0
Grand mean: 7.2

Standard (fixed): A 의 추정 = 8.5 HLM (random): A 의 추정 ≈ 7.4 (grand 쪽으로 shrink)

이유:

  • A 의 small N 에서 8.5 는 noise 가능
  • HLM 이 다른 cluster 의 정보로 stabilize
  • B 의 big N 에서 7.0 은 정확 (shrink 적음)

→ HLM 의 shrinkage 가 outlier cluster 의 noise 줄임. 안정성 ↑.

3 Nested Random Effect

3.1 정의와 syntax

Center > Rep > Call

3-level nested:

Center (10) > Rep (193) > Call (695,205)

각 level 의 random intercept:

\[ y_{ijk} = \beta_0 + \beta_1 X_{ijk} + u_k + v_{jk} + \epsilon_{ijk} \]

  • \(u_k\): center \(k\) 의 random effect
  • \(v_{jk}\): rep \(j\) in center \(k\) 의 random effect
  • \(\epsilon_{ijk}\): call \(i\) 의 잡음

R syntax:

lmer(call_CSAT ~ reason + age + group + (1 | center_ID/rep_ID), data=df)

(1 | center_ID/rep_ID) 의 의미:

  • center_ID 가 outer cluster
  • rep_ID 가 inner cluster (center 안에 nested)
  • 두 level 의 random intercept 추가
Python syntax
import statsmodels.formula.api as smf

vcf = {"rep_ID": "0+C(rep_ID)"}
mixed = smf.mixedlm(
    "call_CSAT ~ reason + age + group",
    data=df,
    groups=df["center_ID"],
    vc_formula=vcf,
)

groups: outer cluster (center). vc_formula: variance components — nested rep 추가.

R 보다 약간 복잡. R 의 lmer 가 Buisson 의 default.

직관 — Nested vs Crossed

비교:

  • Nested: 각 rep 이 한 center 만 (rep_ID = “C1_R1” → center 1 만)
  • Crossed: 한 rep 이 여러 center (드뭄, R 의 multi-membership)

콜센터 사례: nested (rep 이 한 center 만).

Nested 표기: (1 | center_ID/rep_ID) 또는 (1 | center_ID) + (1 | rep_ID) (rep_ID 가 unique 하게 식별 가능 시).

3.2 결과 해석

Buisson 의 출력
Random effects:
   Groups            Name         Variance  Std.Dev
   rep_ID:center_ID  (Intercept)  0.7696    0.8772
   center_ID         (Intercept)  1.3582    1.1654
   Residual                       0.3904    0.6249

Fixed effects:
                  Estimate   Std.Error   t value
   (Intercept)    3.901      0.374       10.43
   reasonproperty 0.200      0.002       126.79
   age            0.020      0.000       298.30

해석:

Random effects (variance components):

  • Center variance = 1.3582 (큼, 콜센터 간 차이 큼)
  • Rep variance = 0.7696 (rep 간 차이 중간)
  • Residual = 0.3904 (call 잡음 작음)

Fixed effects (mean estimates):

  • Intercept = 3.901 (전체 평균 baseline)
  • Reason “property” = +0.200 (property 문의가 payment 보다 CSAT 0.2 높음)
  • Age = +0.020 (1 살 더 많을 때 CSAT 0.02 높음)

이 분해가 비즈니스 통찰 풍부히 제공.

직관 — Variance 분해의 비즈니스 함의

분해의 의미:

전체 variance = 1.36 (center) + 0.77 (rep) + 0.39 (call)
              = 2.52

비율:

  • Center: 54%
  • Rep: 31%
  • Call: 15%

비즈니스 함의:

  • 가장 큰 variation source = center (54%)
  • → Center 단위 정책 (best practices 공유) 큰 영향 가능
  • Rep 단위 (31%) 도 중요 — training quality
  • Call (15%) 자연 잡음

이 분해가 어디 투자할지 가이드.

4 Treatment 효과의 추정

4.1 Group Variable 추가

회귀 model
lmer(call_CSAT ~ reason + age + group + (1 | center_ID/rep_ID), data=df)

추가된 group 변수의 fixed effect:

Fixed effects:
   group[T.treatment]   Estimate   Std.Error   t-value
                          0.55       0.28        1.96

해석: 새 SOP 가 평균 CSAT 0.55 증가.

이 추정이 cluster experiment 의 핵심 결과.

Standard Error 의 함의

이 SE = 0.28 의 의미:

  • Standard regression 으로 같은 데이터 분석 시 SE 약 0.005 (very small, 하지만 잘못)
  • HLM 의 SE 는 cluster 효과를 inflate (정확)

차이: Standard regression 이 effective N 을 695,000 으로 가정 (잘못, 진짜는 cluster 수 제한).

→ HLM 의 SE 가 진짜 정확도. 분석가의 default 도구.

4.2 P-value 의 어려움

직관 — Mixed model 의 p-value 함정

HLM 의 p-value 는 통계학자들 사이 논쟁:

  • Satterthwaite approximation: degree of freedom 추정
  • Kenward-Roger: 더 정확하지만 느림
  • Bootstrap: 가장 안전 (이 책의 권장)

R 의 lmerTest 패키지가 자동 계산 (Satterthwaite). Python 의 statsmodels 는 z-test (큰 표본 가정).

비즈니스 분석에서 default = Bootstrap CI (E-BUI8-3 의 도구 재사용).

5 Random Effect 의 진단

5.1 Rep-level 효과 추출

각 rep 의 baseline
# R: 각 rep 의 random effect
ranef(mixed)$rep_ID

출력 (예시):

              Intercept
C1_R1         +0.45  (평균보다 좋은 rep)
C1_R2         -0.32  (평균보다 나쁜 rep)
C1_R3         +0.10
...

비즈니스 활용:

  • Top 10 reps 의 best practices 식별
  • Bottom 10 reps 의 training 필요
  • 이 정보가 production-quality coaching
직관 — Random Effect 가 추정에서 제공하는 것

Random effect 자체를 직접 추정하지는 않지만 (variance 만 추정), best linear unbiased predictors (BLUPs) 추출 가능.

각 rep 의 BLUP:

  • Shrinkage 적용된 추정
  • Grand mean 으로 약간 끌림
  • Outlier rep 의 noise 줄임

비즈니스 함의:

  • Training program 우선순위 (worst BLUP 부터)
  • Bonus structure 결정 (best BLUP 에게 추가 보상)
  • 채용 vs 유지 결정 (rep 별 contribution)

→ HLM 이 회귀 도구 + management 도구 둘 다.

5.2 Variance 의 변화 점검

모형 비교

여러 모형 비교:

Model 1: Standard regression (cluster 무시)
   Residual variance: 2.52

Model 2: + Center random effect
   Center variance: 1.40
   Residual variance: 1.12
   (Center 가 1.40 흡수)

Model 3: + Rep nested random effect
   Center variance: 1.36
   Rep variance: 0.77
   Residual variance: 0.39
   (Rep 가 추가로 0.77 흡수)

각 단계마다 residual 감소 → cluster 변수가 진짜 variation source 임을 시사.

직관 — 모형 선택의 정량 기준

AIC 또는 BIC 으로 모형 비교:

Model 1: AIC = 2,500,000 (단순)
Model 2: AIC = 2,200,000 (center 추가, 큰 개선)
Model 3: AIC = 2,100,000 (rep 추가, 추가 개선)

낮은 AIC = 더 좋은 모형 (parsimony 고려).

분석가의 default:

  • Cluster variance 가 큰 변수 (ICC > 0.05) 면 random effect 추가
  • Test of likelihood ratio (LRT) 로 정량 검증

→ 모형 선택은 도메인 직관 + 통계 검증 결합.

6 Treatment 의 Random Effect (보너스)

직관 — Random Slope

Cluster 마다 treatment 효과 다를 수 있음:

Center 1: Treatment 효과 +0.8
Center 2: Treatment 효과 +0.3
Center 3: Treatment 효과 +0.5

Random slope 모형:

lmer(CSAT ~ group + (group | center_ID), data=df)

(group | center_ID): group 효과가 center 마다 다름 (random slope).

비즈니스 활용:

  • 어느 cluster 에서 treatment 효과 큼?
  • 그 cluster 의 특성 파악 → 효과 큰 cluster 우선 implementation

이 책 (Buisson) 은 random slope 깊이 안 다룸. Random intercept 가 default.

7 AirCnC 의 R/Python 구현

7.1 R 코드

library(lme4)
library(lmerTest)

# 단순 모형 (cluster 무시)
mod_simple <- lm(call_CSAT ~ reason + age + group, data = exp_data)
summary(mod_simple)
# Standard error 매우 작음 (잘못)

# Center random intercept
mod_center <- lmer(
    call_CSAT ~ reason + age + group + (1 | center_ID),
    data = exp_data
)
summary(mod_center)

# Center + Rep nested
mod_nested <- lmer(
    call_CSAT ~ reason + age + group + (1 | center_ID/rep_ID),
    data = exp_data,
    control = lmerControl(optimizer = "Nelder_Mead")
)
summary(mod_nested)
직관 — Optimizer 변경

lmer() 가 가끔 convergence 실패:

Warning: Model failed to converge

해결:

  • optimizer = "Nelder_Mead": 더 robust
  • optimizer = "bobyqa": 빠른 표준
  • optCtrl=list(maxfun=2e5): iteration 늘림

→ 큰 데이터 + 많은 random effect 시 자주 필요. 분석가의 troubleshooting 도구.

7.2 Python 코드

import statsmodels.formula.api as smf

# Center random intercept
mixed_center = smf.mixedlm(
    "call_CSAT ~ reason + age + group",
    data=exp_data,
    groups=exp_data["center_ID"],
).fit(disp=False)
print(mixed_center.summary())

# Center + Rep nested
vcf = {"rep_ID": "0+C(rep_ID)"}
mixed_nested = smf.mixedlm(
    "call_CSAT ~ reason + age + group",
    data=exp_data,
    groups=exp_data["center_ID"],
    vc_formula=vcf,
).fit(disp=False)
print(mixed_nested.summary())
직관 — Python vs R 의 차이

같은 데이터, 같은 모형의 결과:

  • Fixed effects 의 추정값: 거의 동일
  • Random effect variance: 약간 다름 (다른 algorithm)
  • p-value: 다름 (R 의 Satterthwaite vs Python 의 z-test)

비즈니스 분석에서:

  • 점추정은 둘 다 OK
  • p-value 는 Bootstrap 으로 점검 (둘 다 사용 가능)
  • Buisson 의 default 는 R (mixed model 기능 더 성숙)

→ Python 사용자는 statsmodels 외 pymer4 (R 호출 wrapper) 또는 mlflow 같은 다른 도구 고려.

8 다른 비즈니스 사례

8.1 학교 교육 program

::: {.callout-note} ## HLM 적용

데이터:

  • 학생 5,000 명 (Level 1)
  • 교사 200 명 (Level 2, 학교 nested)
  • 학교 50 개 (Level 3)

3-level HLM:

# (단순화 — Python 의 multi-level 은 어려움)
# 또는 R 사용 권장

R:

lmer(test_score ~ program + age + (1 | school_ID/teacher_ID), data=df)

3-level nested. 각 level 의 random effect. :’’’)

직관 — 3-level 의 Variance 분해
School variance: 12.5  (학교 간 차이 큼)
Teacher variance: 5.3  (학교 내 교사 간)
Student variance: 8.2  (residual)

ICC (school): 12.5 / (12.5 + 5.3 + 8.2) = 48%.

비즈니스 함의:

  • 학교 간 차이가 가장 큰 variation source
  • 학교 단위 program 이 가장 큰 영향 가능
  • → School 단위 randomization 적합 (cluster experiment)

→ Variance 분해가 정책 우선순위 결정.

8.2 매장 청결 program

HLM 적용

데이터:

  • 매장 직원 1,000 명 (Level 1)
  • 매장 100 개 (Level 2)

2-level HLM:

lmer(cleanliness ~ program + (1 | store_ID), data=df)

분석:

  • Store random intercept: 큰 variance → 매장 간 차이 큼
  • Program effect (fixed): treatment 효과

비즈니스 결정: store-level program 이 효과 있으면 implement.

9 코드 예시 — HLM 시뮬레이션

9.1 단순 HLM 데이터 생성

import numpy as np
import pandas as pd
import statsmodels.formula.api as smf


def generate_cluster_data(n_clusters=10, n_per_cluster=1000,
                            cluster_sd=1.0, residual_sd=1.0,
                            treatment_effect=0.5, seed=42):
    """Cluster-randomized experiment 데이터 시뮬레이션."""
    np.random.seed(seed)

    # Cluster 의 baseline
    cluster_baselines = np.random.normal(7, cluster_sd, n_clusters)

    # 무작위 배정
    treatment_clusters = np.random.choice(
        n_clusters, n_clusters // 2, replace=False
    )

    # 데이터 생성
    records = []
    for cluster_idx in range(n_clusters):
        is_treatment = cluster_idx in treatment_clusters
        for obs in range(n_per_cluster):
            csat = (
                cluster_baselines[cluster_idx]
                + (treatment_effect if is_treatment else 0)
                + np.random.normal(0, residual_sd)
            )
            records.append({
                "cluster_ID": f"C{cluster_idx}",
                "group": "treatment" if is_treatment else "control",
                "csat": csat,
            })

    return pd.DataFrame(records)


df = generate_cluster_data()
print(f"Total observations: {len(df)}")
print(df.groupby(["group", "cluster_ID"]).size())
직관 — 시뮬레이션의 검증

시뮬레이션 데이터의 검증:

  • 각 cluster 의 N: 일정 (1000)
  • Group 의 분리: 5 control + 5 treatment cluster
  • Cluster 간 baseline variance ≈ cluster_sd² = 1.0
  • 실제 treatment 효과 = 0.5

이 데이터로 HLM 의 추정이 진짜 effect 에 가까운지 확인 가능.

9.2 HLM vs Standard Regression 비교

def compare_hlm_vs_standard(df):
    """HLM 과 standard regression 의 추정 비교."""
    # Standard regression (cluster 무시)
    standard = smf.ols("csat ~ group", data=df).fit()
    print("=== Standard Regression ===")
    print(f"Treatment effect: {standard.params['group[T.treatment]']:.4f}")
    print(f"Standard error: {standard.bse['group[T.treatment]']:.4f}")
    print(f"95% CI: [{standard.conf_int().iloc[2,0]:.4f}, {standard.conf_int().iloc[2,1]:.4f}]")

    # HLM
    hlm = smf.mixedlm(
        "csat ~ group",
        data=df,
        groups=df["cluster_ID"],
    ).fit(disp=False)
    print("\n=== HLM ===")
    print(f"Treatment effect: {hlm.params['group[T.treatment]']:.4f}")
    print(f"Standard error: {hlm.bse['group[T.treatment]']:.4f}")
    ci = hlm.conf_int()
    print(f"95% CI: [{ci.iloc[2,0]:.4f}, {ci.iloc[2,1]:.4f}]")

    return standard, hlm


standard, hlm = compare_hlm_vs_standard(df)
직관 — SE 차이의 의미

예상 결과:

모형 Effect SE CI
Standard 0.50 0.05 [0.40, 0.60]
HLM 0.50 0.30 [-0.09, 1.09]

Effect 추정은 거의 동일 (둘 다 unbiased). SE 가 6 배 차이 → CI 6 배 차이.

해석:

  • Standard 의 좁은 CI = 가짜 정확도 (cluster 무시)
  • HLM 의 넓은 CI = 진짜 정확도

→ HLM 의 SE 가 진짜. Standard 의 SE 는 misleading.

비즈니스 분석에서 cluster 데이터에 standard regression 사용 시 가짜 양성 매우 흔함.

9.3 ICC 계산 + 진단

def diagnose_hlm(df, cluster_col, outcome_col):
    """HLM 의 자가 진단."""
    # Empty model (없는 covariates)
    empty = smf.mixedlm(f"{outcome_col} ~ 1", data=df, groups=df[cluster_col]).fit(disp=False)

    cluster_var = empty.cov_re.iloc[0, 0]
    residual_var = empty.scale
    icc = cluster_var / (cluster_var + residual_var)

    n_clusters = df[cluster_col].nunique()
    mean_cluster_size = len(df) / n_clusters
    n_eff = len(df) / (1 + (mean_cluster_size - 1) * icc)

    return {
        "cluster_variance": cluster_var,
        "residual_variance": residual_var,
        "icc": icc,
        "n_total": len(df),
        "n_clusters": n_clusters,
        "n_eff": n_eff,
        "use_hlm": icc > 0.05,
    }


diag = diagnose_hlm(df, "cluster_ID", "csat")
print("\n=== HLM Diagnostics ===")
for k, v in diag.items():
    if isinstance(v, float):
        print(f"  {k}: {v:.4f}")
    else:
        print(f"  {k}: {v}")
직관 — 자동 진단의 의의

이 함수가 분석가에게 주는 것:

  • ICC 자동 계산
  • Effective N 계산
  • HLM 사용 여부 자동 추천

분석가의 default workflow:

  1. Empty model 적합 → ICC 점검
  2. ICC > 0.05 면 HLM 진행
  3. ICC < 0.05 면 standard regression OK

이 sequence 가 모형 선택의 표준.

10 종합 — HLM 의사결정

분석가의 default
1. Cluster 변수 식별
2. ICC 계산 (empty model)
   ICC > 0.05 → HLM
   ICC < 0.05 → standard OK
3. Random effect structure 결정
   - Single cluster: random intercept
   - Nested: nested random intercept
   - Crossed: crossed random intercept (드뭄)
4. 모형 적합
   - R: lmer() (성숙)
   - Python: mixedlm() (제한적)
5. Variance components 점검
   - Cluster variance 가 큰 source 인가
6. Fixed effect 추정
   - Treatment 효과
   - Bootstrap CI 권장
7. 모형 비교 (AIC/BIC)
   - 추가 random effect 의 가치 검증

이 워크플로가 cluster experiment 의 표준.

11 관련 주제

11.1 Ch.10 의 형제 글

11.2 이전 챕터

11.3 후속 챕터

11.4 카테고리 진입점

Subscribe

Enjoy this blog? Get notified of new posts by email: