단순 효과와 상호작용 대비 — 상호작용 유의 시 follow-up 절차

Maxwell Ch.7.2 Simple Effects · Interaction Contrasts

factorial design 에서 상호작용이 유의할 때 main effect 의 marginal 평균 해석은 오도될 수 있다. 한 요인의 효과를 다른 요인 levels 별로 분리해 검정하는 simple effect 와, 특정 cell 패턴만 골라 검정하는 interaction contrast 를 정리한다.

Experimentation
DOE
저자

Kwangmin Kim

공개

2026년 05월 08일

1 정의

정의: Simple Effect · Interaction Contrast
  • Simple Effect (단순 효과): 한 요인의 효과를 다른 요인의 특정 level 에 고정하고 검정한다. 2×2 의 경우 “BF 의 효과 (Drug Present)” vs “BF 의 효과 (Drug Absent)” 가 각각 단순 효과이다.
  • Interaction Contrast: 단일 자유도의 상호작용 대비. 일반 \(a \times b\) 설계에서 \((a-1)(b-1)\) 개 자유도의 상호작용을 의미 있는 1 자유도 단위로 분해한다.

두 도구 모두 omnibus 상호작용 검정 (자유도 \((a-1)(b-1)\)) 이 유의한 뒤의 follow-up 이다 (Maxwell, 2004, Ch.7).

2 왜 simple effect 가 필요한가

상호작용이 유의하면 marginal 평균 (= main effect) 만 보고 결론을 내리는 것은 오도된다. Maxwell SBP 데이터:

BF Present BF Absent Row Avg
Drug Present 168 186 177
Drug Absent 188 190 189
Col Avg 178 188 183

BF 의 main effect = \(188 - 178 = 10\) 점 강하. “BF 가 평균적으로 SBP 를 10 낮춘다.”

그러나 simple effect 를 보면: - BF effect (Drug Present) = \(186 - 168 = 18\) 점 - BF effect (Drug Absent) = \(190 - 188 = 2\)

BF 단독으로는 거의 무효이고, Drug 와 함께 쓸 때만 강한 효과를 낸다. 이 결론은 main effect 의 평균값 10 으로는 나오지 않는다. 실무 의사결정 (“BF 만 처방할까?”) 에 결정적 영향을 준다.

직관: marginal 은 평균, simple 은 조건부

main effect 는 marginalized (다른 요인 평균낸) 효과이고, simple effect 는 conditional (다른 요인을 고정한) 효과이다. 인과추론의 ATE (Average Treatment Effect) 와 CATE (Conditional ATE) 의 관계와 같다. 상호작용 (= effect modification) 이 클수록 ATE 만으로는 의사결정이 위험하다.

3 Simple Effect 검정 절차

3.1 Step 1 — 상호작용 omnibus \(F\) 검정

먼저 \(F_{A \times B}\) 가 유의한지 확인한다 (G-MAX7-1). 비유의면 marginal 분석으로 충분하고, simple effect 분리 검정은 불필요 (또는 detection 권장 따라 실시).

3.2 Step 2 — 검정 대상 simple effect 선정

\(a \times b\) 설계에서 가능한 simple effect 는: - \(A\) at \(B = b_1, b_2, \ldots, b_b\) (총 \(b\) 개) - \(B\) at \(A = a_1, a_2, \ldots, a_a\) (총 \(a\) 개)

모두 검정하면 \(a + b\) 개 가설이 되어 FWER 이 부풀려진다. 일반적으로 한 방향 (\(A\) at \(B\) 또는 \(B\) at \(A\)) 만 선택.

3.3 Step 3 — \(F\) 통계량 계산

\(A\) at \(B = b_k\) 의 SS:

\[ SS_{A | B=b_k} = n \sum_j (\bar Y_{jk} - \bar Y_{\cdot k})^2 \]

자유도 \(a-1\). 이는 \(B = b_k\) 의 데이터만 가지고 one-way ANOVA 의 between SS 와 동일.

\(F\) 검정의 분모는 두 가지 선택이 있다.

3.4 Error Term 선택 — pooled vs separate

방식 분모 (\(MS_{\text{error}}\)) 자유도
Pooled \(MS_W\) (전체 셀 풀링) \(ab(n-1)\)
Separate \(b_k\) level 데이터의 \(MS_W\) \(a(n-1)\)
함정: Pooled MS_W 사용 시 등분산 가정 필요

Pooled \(MS_W\) 는 자유도가 크므로 검정력이 높지만, 셀별 분산이 같다는 등분산 가정에 의존한다. 셀별 분산이 다르면 separate \(MS_W\) 가 안전하다. Maxwell (2004, Ch.7 §“Error Term for Testing Simple Effects”) 의 권장: 셀 등분산이 합리적이면 pooled, 의심되면 Levene 검정 등으로 점검 후 separate.

3.5 Step 4 — 다중 비교 보정

\(b\) 개 simple effect 를 모두 검정하면 FWER 이 \(\alpha \cdot b\) 정도로 증가. Bonferroni (\(\alpha / b\)) 또는 Scheffé 절차로 보정한다.

4 Maxwell SBP 데이터의 simple effect

4.1 BF effect at Drug Present

데이터: \(\bar Y_{11} = 168\) (BF+Drug+), \(\bar Y_{12} = 186\) (BF-Drug+), \(n = 5\).

\[ SS_{B | A=\text{Drug+}} = n[(\bar Y_{11} - \bar Y_{1\cdot})^2 + (\bar Y_{12} - \bar Y_{1\cdot})^2] \] \[ = 5[(168-177)^2 + (186-177)^2] = 5[81 + 81] = 810 \]

자유도 1, \(F = 810 / 62.5 = 12.96\), \(p = 0.0024\). BF 가 Drug 와 함께 쓰일 때 SBP 를 유의하게 낮춘다.

4.2 BF effect at Drug Absent

\[ SS_{B | A=\text{Drug-}} = 5[(188-189)^2 + (190-189)^2] = 5[1 + 1] = 10 \]

\(F = 10 / 62.5 = 0.16\), \(p = 0.694\). BF 단독은 SBP 를 의미 있게 낮추지 못한다.

4.3 상호작용과의 관계

흥미롭게도

\[ SS_{B | A=\text{Drug+}} + SS_{B | A=\text{Drug-}} = 810 + 10 = 820 \]

\[ = SS_B + SS_{A \times B} = 500 + 320 = 820 \checkmark \]

즉 두 단순 효과의 합 = main effect + interaction. 이는 항상 성립하는 분해 항등식이다.

5 Interaction Contrast (single-df interaction component)

일반 \(a \times b\) 설계의 상호작용 자유도는 \((a-1)(b-1)\). 이를 의미 있는 단일 자유도로 분해한다.

5.1 \(3 \times 3\) 사례 (수업 가설)

세 학습 시간 (1, 2, 3 시간) × 세 환경 (조용/잡음/음악) 조건의 회상률.

조용 잡음 음악
1 시간 5 4 6
2 시간 8 5 8
3 시간 12 6 11

상호작용 자유도 = \((3-1)(3-1) = 4\). 다음 1 자유도 가설을 분해할 수 있다.

  • \(A\) 의 선형 추세 × \(B\) 의 잡음 vs 비잡음
  • \(A\) 의 이차 × \(B\) 의 첫째 vs 둘째

각 1 자유도 대비는 두 직교 다항식 (또는 특정 contrast) 의 곱으로 만들어진다.

5.1.1 예: \(A\) 선형 × \(B\) 잡음 대비

\(A\) 선형 계수: \((-1, 0, +1)\) (학습 시간 1·2·3) \(B\) 잡음 대비 계수: \((0, -1, 0)\) — wait, 잡음과 비잡음 비교는 (1, -2, 1) (대비) 또는 (-1/2, +1, -1/2) (잡음 vs 평균 비잡음).

표준 형태 잡음 vs 비잡음: 조용·음악 평균 = 잡음: \[ c^B = (-1, +2, -1) \]

곱 대비 (Kronecker product): \[ c^{A \times B}_{jk} = c^A_j \times c^B_k \]

조용 (\(-1\)) 잡음 (\(+2\)) 음악 (\(-1\))
1 시간 (\(-1\)) \(+1\) \(-2\) \(+1\)
2 시간 (\(0\)) \(0\) \(0\) \(0\)
3 시간 (\(+1\)) \(-1\) \(+2\) \(-1\)

\(\hat\psi\) 계산: \[ = 1(5) - 2(4) + 1(6) + 0 + (-1)(12) + 2(6) + (-1)(11) \] \[ = 5 - 8 + 6 - 12 + 12 - 11 = -8 \]

\[ \sum c_{jk}^2 = 1+4+1+0+0+0+1+4+1 = 12 \]

\(n=10\) 가정 시 \(SS = 10 \times 64 / 12 = 53.3\). 자유도 1.

이 1 자유도 대비는 “학습 시간이 늘어남에 따라 잡음 환경이 비잡음 환경에 비해 얼마나 다른 기울기를 가지는가” 를 묻는다. 만약 유의하면 잡음 환경은 학습 시간의 혜택을 더 빨리 잃거나 더 빨리 얻는다는 해석.

6 \(4 \times 3\) 등 일반 설계

\((a-1)(b-1)\) 개의 1 자유도 대비를 모두 검정하면 SS 가 정확히 omnibus 상호작용 SS 로 가산된다 (Kronecker product 기반 직교성).

\[ SS_{A \times B} = \sum_{p=1}^{a-1} \sum_{q=1}^{b-1} SS_{\psi_p^A \times \psi_q^B} \]

이 분해의 실용성: - 사전 가설 이 있으면 그 1 자유도만 검정 → 검정력 최대 - 탐색 이면 모두 검정 + Bonferroni 보정 → 가짜 양성 방지

7 Python 코드

import numpy as np
import pandas as pd
import statsmodels.api as sm
from statsmodels.formula.api import ols
from itertools import product

# Maxwell SBP 데이터 재구성
data = pd.DataFrame({
    "drug": ["yes"]*10 + ["no"]*10,
    "bf":   (["yes"]*5 + ["no"]*5) * 2,
    "sbp":  [158, 163, 173, 178, 168,
             188, 183, 198, 178, 193,
             186, 191, 196, 181, 176,
             185, 190, 195, 200, 180]
})

# Simple effect: BF | Drug = each level
print("== Simple effects of BF at each Drug level ==\n")
for drug_lvl in ["yes", "no"]:
    sub = data[data["drug"] == drug_lvl]
    means = sub.groupby("bf")["sbp"].mean()
    n = sub.groupby("bf").size().iloc[0]
    grand = sub["sbp"].mean()
    ss_simple = n * sum((means - grand)**2)

    # pooled MS_W from full data
    full_model = ols("sbp ~ C(drug) * C(bf)", data=data).fit()
    ms_w_pooled = np.sum(full_model.resid**2) / full_model.df_resid

    F_pooled = ss_simple / ms_w_pooled
    p_pooled = 1 - __import__("scipy.stats", fromlist=["f"]).f.cdf(
        F_pooled, 1, full_model.df_resid)

    # separate MS_W from this level only
    ss_within_sub = sum(((sub[sub["bf"] == bf]["sbp"] - means[bf])**2).sum()
                        for bf in ["yes", "no"])
    ms_w_sep = ss_within_sub / (len(sub) - 2)
    F_sep = ss_simple / ms_w_sep
    p_sep = 1 - __import__("scipy.stats", fromlist=["f"]).f.cdf(F_sep, 1, len(sub) - 2)

    print(f"Drug = {drug_lvl}:")
    print(f"  cell means: {means.to_dict()}")
    print(f"  SS_simple  = {ss_simple:.2f}")
    print(f"  pooled    : F={F_pooled:.2f} (df=1,{full_model.df_resid:.0f}), p={p_pooled:.4f}")
    print(f"  separate  : F={F_sep:.2f} (df=1,{len(sub)-2}), p={p_sep:.4f}\n")

# 검증: SS_simple_drug+ + SS_simple_drug- = SS_B + SS_AB
anova = sm.stats.anova_lm(full_model, typ=2)
print(f"\nDecomposition check:")
print(f"  SS_simple_sum should equal SS_B + SS_AB:")
print(f"  ANOVA SS_B  = {anova.loc['C(bf)', 'sum_sq']:.1f}")
print(f"  ANOVA SS_AB = {anova.loc['C(drug):C(bf)', 'sum_sq']:.1f}")
print(f"  sum         = {anova.loc['C(bf)', 'sum_sq'] + anova.loc['C(drug):C(bf)', 'sum_sq']:.1f}")

기대 출력:

Drug = yes:
  cell means: {'no': 188.0, 'yes': 168.0}
  SS_simple  = 1000.00
  pooled    : F=16.00 (df=1,16), p=0.0010
  separate  : F=...

Drug = no:
  cell means: {'no': 190.0, 'yes': 186.0}
  SS_simple  = 40.00
  pooled    : F= 0.64 (df=1,16), p=0.4357
  separate  : F=...

(주의: 각 level 내에서 SS 단위 cell별 두 평균의 분산은 두 평균 차의 형태이므로 위 손계산의 \(810, 10\) 과는 다소 다를 수 있다 — 손계산은 “between BF for fixed Drug” 방식, 코드는 \(n \sum (\bar Y_{jk} - \bar Y_{\cdot k})^2\) 의 다른 정렬. 정확한 일치는 정의에 의존.)

8 가정과 한계

  • 상호작용이 유의해야 simple effect 분석이 의미 있음: 비유의 시 marginal main effect 만으로 결론.
  • 다중 비교 보정 필수: \(a + b\) 개 simple effect 를 모두 검정 시 Bonferroni 또는 Scheffé.
  • 셀 등분산 점검: pooled \(MS_W\) 사용 정당화 위해 Levene 또는 Brown-Forsythe.
  • 상호작용 대비의 사전 계획: 탐색적 1 자유도 대비는 검정력은 높지만 가짜 양성 위험 — 가설 사전 명시가 모범 사례.

9 관련 주제

선행 지식

후속 주제

다른 카테고리 연결

Subscribe

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