1 왜 “모형식 대수” 가 필요한가
통계 소프트웨어를 처음 쓰면 다음 같은 코드를 자주 만난다.
이 문자열은 단순 표기 이상이다 — 설계 행렬 \(\mathbf{X}\) 를 자동으로 생성하는 프로그램 언어다. 연산자 +, *, :, /, -, ** 각각이 수학적 정의와 우선순위를 갖고, 파서가 이를 해석해 더미 변수·교호작용·중첩 구조의 열을 조립한다.
이 표기법의 창시자는 Wilkinson & Rogers (1973) 이며, McCullagh & Nelder §3.4 가 이를 GLM 전 영역의 표준으로 정리했다. GLIM·Genstat 에서 출발해 S·R·SAS·Stata·Python(statsmodels, patsy) 모두가 이 문법을 계승한다.
§3.4 를 이해하면 얻는 것은 두 가지다.
- 모형식을 읽고 설계 행렬의 모양을 예측할 수 있다.
(A + B + C)**2가 몇 개 열을 만드는지 머릿속에서 계산 가능. - 같은 모형을 여러 표기로 쓸 수 있는 이유를 안다.
A*B와A + 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 핵심 관찰 — 항은 부분공간이다
가장 중요한 개념적 관찰:
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 statsmodels 는 x1: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 + C 가 A.(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 모형” 을 한 기호로 표현. 특히 공변량이 많을 때 유용.
이 한 줄이 \(5 + \binom{5}{2} = 15\) 개 항을 생성 (주효과 5 + 2-way 교호 10). 없었다면 15 줄을 손으로 써야 한다.
8.3 우선순위
** 는 최고 우선순위. A + B ** 2 는 A + (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 를 파싱해 보자.
**먼저:A.B**2 = A.B * A.B = A.B + A.B.A.B = A.B + A.B = A.B(멱등) → 사실상A.B..다음:C.D는 단일 복합항./없음.*:A*B = A + B + A.B.+, -최저:(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 예시 비교
기본 연산자는 호환이지만 지수 연산자 기호가 다른 점만 조심하면 된다.
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:B 가 A + 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/B 를 A*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(요인) vsX.X ≠ X(연속). - 우선순위:
**>.>/>*>+, -. 애매한 식은 괄호로. - Crossing vs Nesting:
A*B는 \(B\) 주효과 있음,A/B는 없음. 실험 설계 맥락 (완전 교차 vs 중첩) 에 따라 선택. - R·Python 관례 차이: 지수 연산자 (
^vs**) 외에는 거의 호환.
한 줄 요약: 모형식 대수는 “설계 행렬을 한 줄로 압축하는 속기법” 이자 “가설을 부분공간으로 번역하는 대수 시스템”이다. 연산자 다섯 개의 의미와 우선순위만 확실히 익히면, 어떤 복잡한 모형도 한 줄에 담아낼 수 있다.
14 관련 주제
선행 지식
- 선형 예측자의 구성 — Systematic Component — 연속·범주·혼합 항의 설계 행렬 구조
- 정규-항등 GLM 개관
관련 개념
후속 주제
- Aliasing (McCullagh §3.5) — 모형식이 낳는 식별불가 구조
- Model selection — 주효과·교호의 포함 전략
- GAM model formulae —
s(x),te(x1, x2)등 스무딩 확장