모형식 대수 — Model Formulae for Linear Predictors

McCullagh & Nelder §3.4 — Wilkinson-Rogers 표기법의 연산 규칙

McCullagh & Nelder (1989) §3.4 의 모형식 (model formula) 대수를 심화한다. Wilkinson-Rogers (1973) 표기법의 다섯 연산자 — 점(.)·합(+)·교차(*)· 중첩(/)·제거(-)·지수(**) — 의 정의, 우선순위, 대수 법칙, 설계 행렬 생성 규칙까지. R, SAS, Python(statsmodels) 의 공통 문법의 뿌리가 되는 이 표기법이 왜 그렇게 설계됐는지를 수식과 직관으로 정리한다.

Statistics
GLM
Math
저자

Kwangmin Kim

공개

2026년 04월 14일

1 왜 “모형식 대수” 가 필요한가

통계 소프트웨어를 처음 쓰면 다음 같은 코드를 자주 만난다.

lm(y ~ x1 + x2 * group + I(x1^2), data = df)
smf.ols("y ~ (age + dose) ** 2 + group/subject", data=df).fit()

이 문자열은 단순 표기 이상이다 — 설계 행렬 \(\mathbf{X}\) 를 자동으로 생성하는 프로그램 언어다. 연산자 +, *, :, /, -, ** 각각이 수학적 정의와 우선순위를 갖고, 파서가 이를 해석해 더미 변수·교호작용·중첩 구조의 열을 조립한다.

이 표기법의 창시자는 Wilkinson & Rogers (1973) 이며, McCullagh & Nelder §3.4 가 이를 GLM 전 영역의 표준으로 정리했다. GLIM·Genstat 에서 출발해 S·R·SAS·Stata·Python(statsmodels, patsy) 모두가 이 문법을 계승한다.

§3.4 를 이해하면 얻는 것은 두 가지다.

  1. 모형식을 읽고 설계 행렬의 모양을 예측할 수 있다. (A + B + C)**2 가 몇 개 열을 만드는지 머릿속에서 계산 가능.
  2. 같은 모형을 여러 표기로 쓸 수 있는 이유를 안다. A*BA + B + A:B 가 동치임을 증명하는 대수 법칙.

직관: 모형식 대수는 “가설을 수식으로 압축하는 속기법” 이다. 한 줄의 y ~ drug * time + patient_id/visit 이 수백 개의 더미 열을 자동 전개한다. 이 속기법의 규칙을 이해하면 회귀 모델링의 효율이 급격히 올라간다.


2 표기 관례와 기본 항 (§3.4.1)

2.1 명명 규칙

McCullagh & Nelder 의 관례.

  • 알파벳 전반부 (A, B, C, …): 범주형 요인 (factor). 수준 인덱스는 \(i, j, k, \dots\).
  • 알파벳 후반부 (X, Y, Z): 연속 공변량 (continuous covariate).
  • \(\lambda, \beta\): 계수. 연속 변수 계수는 \(\lambda\) (요인 모수 \(\beta\) 와 구분).

2.2 다섯 가지 기본 항

항 유형 대수식 모형식 표기 설계 행렬 기여
연속 공변량 \(\lambda x\) X 1 열 (벡터 \(\mathbf{x}\))
범주 요인 \(\alpha_i\) A \(k_A\) 열 (더미 벡터)
혼합 (범주×연속) \(\lambda_i x\) A.X \(k_A\) 열 (더미 × x)
교호 (범주×범주) \((\alpha\beta)_{ij}\) A.B \(k_A k_B\)
복합 혼합 \(\lambda_{ij} x\) A.B.X \(k_A k_B\) 열 (더미곱 × x)

2.3 핵심 관찰 — 항은 부분공간이다

가장 중요한 개념적 관찰:

항은 부분공간 (Subspace) 을 표현한다

X\(\mathbb R^n\) 안의 1차원 부분공간 (벡터 \(\mathbf{x}\) 가 spanning). A\(k_A\) 차원 부분공간 (\(k_A\) 개 더미 벡터가 span). A.B\(k_A k_B\) 차원 부분공간 (교호작용 더미들이 span).

모수 \(\alpha_i, \beta_j\) 는 각 부분공간의 기저 좌표일 뿐이다. 모형식은 기하학적 대상 (부분공간) 을 가리킨다.

이 관점이 왜 중요한가? 두 개의 서로 다른 모수화 (예: treatment coding vs sum-to-zero) 가 같은 모형식 을 표현할 수 있기 때문. 부분공간은 같고, 그 안에서 기저 선택만 다를 뿐. 따라서 “어떤 부분공간을 모형에 포함시키는가” 가 중요하고, “어떤 기저를 쓰는가” 는 해석 편의의 문제다.

직관: 회귀 모형은 “관측 벡터 \(\mathbf{y}\) 를 어떤 부분공간에 사영할 것인가” 다. 모형식이 그 부분공간을 지정한다. 이 추상화 덕에 소프트웨어 내부가 놀랄 만큼 단순해진다.


3 Dot 연산자 . — 원소별 곱 (§3.4.2)

3.1 정의

A.B\(A\)\(B\)모든 더미 벡터 쌍의 원소별 곱.

\[ (\mathbf{u}\mathbf{v})_{ij}[n] \;=\; \mathbf{u}_i[n] \cdot \mathbf{v}_j[n] \]

예: \(A\) 가 3 수준, \(B\) 가 2 수준이면 A.B\(3 \times 2 = 6\) 개의 더미 벡터를 생성.

3.2 대수 법칙

법칙 설명
교환 (commutative) \(A.B \equiv B.A\) 순서 무관
결합 (associative) \((A.B).C \equiv A.(B.C)\) A.B.C 로 단순화 가능
멱등 (idempotent on factors) \(A.A \equiv A\) 같은 요인의 자기 곱은 자기 자신
연속에는 멱등 아님 \(X.X \neq X\) \(X.X\)\(x_i^2\) 벡터. 원 \(x\) 와 다름

3.3\(A.A = A\) 인가

요인 \(A\) 의 더미 \(\mathbf{u}_i\) 에 대해 \(\mathbf{u}_i \cdot \mathbf{u}_j\)\(i=j\) 일 때는 \(\mathbf{u}_i\) (0 과 1 의 곱은 그대로), \(i \ne j\) 일 때는 영벡터 (한쪽이 0). 따라서 A.A\(k^2\) 개 벡터 중 \(k\) 개만 비영이며 원 더미와 같다. 영벡터는 설계 행렬에서 무의미하므로 제거.

반면 연속 변수는 \(x_i^2\) 이 일반적으로 \(x_i\) 와 다른 벡터 — 멱등성 깨짐.

3.4 실무 제한

McCullagh 가 명시: GLIM·Genstat 에서는 X.Y (연속 × 연속) 형태의 교호 항은 모형식에서 직접 지원하지 않음. 사용자가 명시적으로 I(x1*x2) 같은 파생 변수를 만들어야 한다. 이유 — 수치적 스케일 문제로 중앙화 후 곱을 쓰도록 강제.

R 에서는 x1:x2 가 작동하지만 SAS/GLIM 의 전통에서는 x1 * x2 는 명시 계산 후 사용. Python statsmodelsx1:x2 를 허용.

직관: dot 연산은 “두 변수의 조합 수준마다 별도의 더미” 를 만드는 작업이다. 요인끼리는 자연스럽지만 연속끼리는 제곱·곱이라는 수학적 함정이 있어 명시 처리가 안전하다.


4 Plus 연산자 + — 부분공간 합 (§3.4.3)

4.1 정의

A + B\(A\) 가 span 하는 부분공간과 \(B\) 가 span 하는 부분공간의 합집합이 span 하는 공간.

\[ \text{span}(A + B) \;=\; \text{span}(A) + \text{span}(B) \]

4.2 대수 법칙

법칙 설명
멱등 \(A + A \equiv A\) 같은 부분공간은 한 번만
교환 \(A + B \equiv B + A\)
결합 \((A + B) + C \equiv A + (B + C)\)
Dot 우선 (priority) \(A.B + C \equiv (A.B) + C\) .+ 보다 우선
분배 (distributive) \(A.(B + C) \equiv A.B + A.C\) dot 이 + 에 분배

4.3 왜 우선순위가 필요한가

연산자 우선순위는 모호성 제거용. A.B + CA.(B + C) 인지 (A.B) + C 인지를 한 가지로 고정. McCullagh 의 관례:

\[ \text{우선순위: } \quad \text{**} > \text{.} > \text{/} > \text{*} > \text{+, -} \]

따라서 A*B + C.D(A*B) + (C.D) 로 파싱된다.

직관: +“이 부분공간도 모형에 포함” 이라는 선언이다. 설계 행렬이 점점 넓어진다. 중복된 부분공간은 한 번만 카운트되므로 \(A + A = A\).


5 Crossing * — 완전 교호 요인 (§3.4.4)

5.1 정의

A * B두 요인의 주효과 + 교호작용 을 한꺼번에 지정.

\[ A * B \;\equiv\; A + B + A.B \]

삼요인 확장:

\[ A * B * C \;\equiv\; A + B + C + A.B + A.C + B.C + A.B.C \]

* 는 “해당 요인들의 모든 차수 교호작용을 포함” 이라는 속기.

5.2 대수 법칙

법칙
결합 \(A*(B*C) \equiv (A*B)*C\)
분배 \(A*(B+C) \equiv A*B + A*C\)
+ 와의 혼합 \(A*B + C \equiv A + B + A.B + C\)
. 과의 혼합 \(A*B.C \equiv A + B.C + A.B.C\)

5.3 해석: Interaction 의 정확한 정의

복합 항 A.B 가 모형식에 등장할 때, 앞에 \(A\)\(B\) 의 주효과가 모두 있으면 A.B 를 “교호작용 (interaction)” 이라 부른다. 주효과 중 하나라도 빠지면 “단순 조합 항” 일 뿐 interaction 이 아니다.

이 구분이 중요한 이유: 교호작용의 통계적 해석은 “주효과를 넘어서는 추가 효과” 이므로, 주효과가 없으면 그런 해석이 불가능하다. Hierarchical principle 의 기원.

5.4 확장된 표기

A*B 내의 A, B 자체도 모형식일 수 있다.

\[ (A + B) * C \;\equiv\; (A + B) + C + (A + B).C \;\equiv\; A + B + C + A.C + B.C \]

분배 법칙의 반복 적용.

직관: *“두 요인을 완전히 교차시켜라” 라는 명령이다. 실험 설계의 factorial design 을 한 기호로 표현. ANOVA 의 2-way full factorial, 3-way full factorial 이 각각 A*B, A*B*C 로 압축된다.


6 Nesting / — 중첩 설계 (§3.4.4)

6.1 정의

A/B\(B\)\(A\) 안에 중첩 (nested) 된 구조.

\[ A / B \;\equiv\; A + A.B \]

교차 * 와의 차이:

  • A*B: \(A\), \(B\), \(A.B\) 모두 포함 (B 의 주효과 있음).
  • A/B: \(A\), \(A.B\) 만 포함 (\(B\) 의 주효과 없음).

6.2\(B\) 주효과가 없는가

중첩 구조에서는 \(B\) 수준이 \(A\) 수준 안에서만 의미를 갖는다. 예: \(A\) 가 “학교”, \(B\) 가 “학급”. 학교 1 의 학급 1 과 학교 2 의 학급 1 은 완전히 다른 학급이다. 따라서 “학급 1” 이라는 수준은 학교와 무관하게 존재할 수 없다 — \(B\) 의 주효과가 정의되지 않음.

6.3 일반화

\(A\) 가 복합 요인이면 \(\text{pt}(A)\) (product term — 모든 요소의 dot 곱) 로 정의:

\[ A / B \;\equiv\; A + \text{pt}(A).B \]

예: \(\text{pt}(A*B) = A.B\) 이므로

\[ (A * B) / C \;\equiv\; A*B + A.B.C \;\equiv\; A + B + A.B + A.B.C \]

6.4 대수 법칙

법칙
결합 \(A/(B/C) \equiv (A/B)/C\)
+ 분배 \(A/(B+C) \equiv A/B + A/C\)
우선순위 /* 보다 높음

6.5 실무 예시

  • 학교 / 학급: school/class — 학급은 학교 안에서만 정의.
  • 블록 / 플롯: block/plot — 농업 실험의 완전 확률화 블록 설계.
  • 피험자 / 시행: subject/trial — 반복 측정의 피험자 내 시행.

직관: 중첩은 “안쪽 요인이 바깥쪽 요인 없이는 의미가 없다” 는 관계. \(A.B\) 교호작용은 있지만 \(B\) 주효과는 없다 — 교호가 “유일한 실체” 가 되는 특이한 구조.


7 Minus - — 항 제거 (§3.4.5)

7.1 기본 용법

\[ A * B - A.B \;\equiv\; A + B \]

* 로 만든 완전 교호에서 교호항만 제거 → 주효과만 남김. 2-way 교호 없는 설계를 짧게 표현.

7.2 고차 교호만 제거

\[ A * B * C - A.B.C \;\equiv\; A + B + C + A.B + A.C + B.C \]

“3차 교호만 제외하고 2차까지 포함” 이라는 실무에서 흔한 모형.

7.3 -/-* 확장

  • -/A: “\(A\) 가 포함된 복합항” 만 제거, \(A\) 자체는 보존.
  • -*A: “\(A\) 가 포함된 모든 항” 제거, \(A\) 자체도 제거.

\[ A * B * C - / A \;\equiv\; A + B + C + B.C \]

\[ A * B * C - * A \;\equiv\; B + C + B.C \]

직관: 완전 교호 모형에서 시작해 불필요한 고차 교호나 특정 요인을 제거하는 속기법. 실험 설계에서 혼란변수 (confounded effects) 를 명시적으로 뺄 때 유용.


8 Exponential ** — 최대 차수 (§3.4.6)

8.1 정의

M ** I 는 모형식 \(M\)\(I\) 중 교차.

\[ M ** I \;\equiv\; M * M * \dots * M\;(I\text{ copies}) \]

예:

\[ (A + B + C) ** 2 \;\equiv\; A + B + C + A.B + A.C + B.C \]

즉 “주효과 + 2-way 교호까지만”. 3-way 교호는 빠짐.

8.2 용도

최대 차수를 제한한 factorial 모형” 을 한 기호로 표현. 특히 공변량이 많을 때 유용.

y ~ (x1 + x2 + x3 + x4 + x5) ** 2

이 한 줄이 \(5 + \binom{5}{2} = 15\) 개 항을 생성 (주효과 5 + 2-way 교호 10). 없었다면 15 줄을 손으로 써야 한다.

8.3 우선순위

**최고 우선순위. A + B ** 2A + (B**2) = A + B (단일 요인의 **2 는 자기 자신).

직관: ** 는 “몇 차까지” 의 속기다. ** 2 가 실무에서 가장 흔하며 3차 이상은 해석 곤란 + 과적합 위험으로 잘 쓰지 않는다.


9 우선순위와 파싱 — 전체 그림

연산자 우선순위를 한 표로 정리.

우선순위 연산자 역할 예시
1 (최고) ** 최대 차수 (A+B)**2
2 . 원소별 곱 A.B.X
3 / 중첩 A/B
4 * 완전 교차 A*B
5 (최저) +, - 항 추가·제거 A + B - C

9.1 파싱 예시

A*B + C.D - A.B**2 를 파싱해 보자.

  1. ** 먼저: A.B**2 = A.B * A.B = A.B + A.B.A.B = A.B + A.B = A.B (멱등) → 사실상 A.B.
  2. . 다음: C.D 는 단일 복합항.
  3. / 없음.
  4. * : A*B = A + B + A.B.
  5. +, - 최저: (A + B + A.B) + (C.D) - (A.B) = A + B + C.D.

결과: 주효과 \(A, B\) 와 복합 \(C.D\). 원래 식을 알아보기 어렵지만 파싱 후 단순해졌다.

직관: 파싱 규칙은 “어느 쪽을 먼저 묶을 것인가” 의 기계적 규칙이다. 애매한 식은 괄호로 강제하면 안전. (A*B) + C.D - A.B 처럼.


10 R 과 statsmodels 의 관례 차이

문법은 같지만 미묘한 차이가 있다.

항목 R Python (statsmodels/patsy)
Dot 연산 : (예: A:B) : (동일)
Crossing * *
Nesting / /
Minus - -
Exponential ^ (예: (A+B)^2) **
절편 제거 -1 또는 0 + -1 또는 0 +
. (all vars) y ~ . 미지원
I(expression) I(x^2) (에스케이프) I(x**2)

10.1 예시 비교

# R
lm(y ~ A * B + I(x^2) + x:group, data = df)
# Python / statsmodels
smf.ols("y ~ A * B + I(x**2) + x:group", data=df).fit()

기본 연산자는 호환이지만 지수 연산자 기호가 다른 점만 조심하면 된다.


11 코드 예시

11.1 Step 1: 모형식 → 설계 행렬

import numpy as np, pandas as pd
from patsy import dmatrices

rng = np.random.default_rng(0)
n = 30
df = pd.DataFrame({
    "y": rng.normal(size=n),
    "x1": rng.uniform(0, 10, size=n),
    "x2": rng.uniform(0, 5, size=n),
    "A": pd.Categorical(rng.choice(["a","b","c"], size=n)),
    "B": pd.Categorical(rng.choice(["p","q"], size=n)),
})

# 모형식을 설계 행렬로 컴파일
for formula in [
    "y ~ x1 + x2",           # 주효과만
    "y ~ x1 * x2",           # 연속×연속 교호
    "y ~ A * B",             # 범주×범주 완전 교차
    "y ~ A / B",             # B 가 A 안에 중첩
    "y ~ (x1 + x2 + A) ** 2",# 2차까지
    "y ~ A * B - A:B",       # 교호만 제거
]:
    _, X = dmatrices(formula, df, return_type='dataframe')
    print(f"{formula:35s} → 열 수 {X.shape[1]:2d}, 이름: {list(X.columns)[:5]}...")

각 모형식이 생성하는 설계 행렬의 크기·열 이름을 직접 확인. A * B - A:BA + B 와 동일한 열 수를 갖는 등 대수 법칙의 수치 확인.

11.2 Step 2: 중첩 vs 교차 차이 검증

# A*B 와 A/B 의 rank 차이
_, X_cross  = dmatrices("y ~ A * B",  df, return_type='dataframe')
_, X_nested = dmatrices("y ~ A / B",  df, return_type='dataframe')
print(f"A * B (cross) : 열 수 {X_cross.shape[1]},  rank {np.linalg.matrix_rank(X_cross)}")
print(f"A / B (nested): 열 수 {X_nested.shape[1]}, rank {np.linalg.matrix_rank(X_nested)}")
# 교차는 A + B + A:B (주효과 포함), 중첩은 A + A:B (B 주효과 없음)

중첩 모형이 교차 모형보다 자유도가 적음을 수치로 확인. \(B\) 의 주효과가 빠진 만큼.

11.3 Step 3: 완전 factorial 자동 생성

# 3-way factorial 모형을 "**" 로 압축
_, X_full = dmatrices("y ~ A * B + A:x1 + B:x2 + (x1 + x2) ** 2", df, return_type='dataframe')
print(f"복합 모형 열 수: {X_full.shape[1]}")
print(list(X_full.columns))

# 5변수 2차까지 — `**2` 없이는 15줄 수동
_, X_wide = dmatrices("y ~ (x1 + x2 + A + B) ** 2", df, return_type='dataframe')
print(f"\n(x1+x2+A+B)**2 열 수: {X_wide.shape[1]}")

**2 한 기호가 얼마나 많은 수동 작업을 절약하는지 체감. 실제 연구에서는 10 변수 factorial 도 흔하다.


12 흔한 실수

실수 처방
A*B 에서 A:B 부분만 보고 “주효과 없다” 고 가정 A*B\(A+B+A.B\). 주효과 자동 포함
A/BA*B 대신 쓰고 “같다” 고 가정 중첩은 \(B\) 주효과 없음. 완전히 다른 모형
x1*x2 에서 주효과 누락을 모름 (R 의 경우) R 의 * 도 동일 — 주효과 자동 포함. 순수 교호만은 x1:x2
I(x**2) 없이 x**2 ** 는 모형식 연산자. 제곱 원하면 I(x**2) 로 에스케이프
우선순위 모호한 식을 괄호 없이 씀 애매하면 괄호 사용. (A + B) * C vs A + (B * C) 명시
A + A:B (주효과+교호) 를 A/B 대체로 씀 동등하지만, A/B 는 의미가 “중첩” 임을 선언. 해석 의도가 다름

13 요약

  • 모형식은 부분공간 지정 언어. 모수·기저가 아니라 기하학적 부분공간을 가리킨다. 같은 부분공간은 여러 모수화로 표현 가능.
  • 5대 연산자: . (dot, 원소곱), + (합), * (완전 교차 = A + B + A.B), / (중첩 = A + A.B), - (제거), ** (최대 차수).
  • 대수 법칙: dot 은 + 에 분배, *+ 에 분배, A.A = A (요인) vs X.X ≠ X (연속).
  • 우선순위: ** > . > / > * > +, -. 애매한 식은 괄호로.
  • Crossing vs Nesting: A*B\(B\) 주효과 있음, A/B 는 없음. 실험 설계 맥락 (완전 교차 vs 중첩) 에 따라 선택.
  • R·Python 관례 차이: 지수 연산자 (^ vs **) 외에는 거의 호환.

한 줄 요약: 모형식 대수는 “설계 행렬을 한 줄로 압축하는 속기법” 이자 “가설을 부분공간으로 번역하는 대수 시스템”이다. 연산자 다섯 개의 의미와 우선순위만 확실히 익히면, 어떤 복잡한 모형도 한 줄에 담아낼 수 있다.


14 관련 주제

선행 지식

관련 개념

후속 주제

  • Aliasing (McCullagh §3.5) — 모형식이 낳는 식별불가 구조
  • Model selection — 주효과·교호의 포함 전략
  • GAM model formulae — s(x), te(x1, x2) 등 스무딩 확장

Subscribe

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