1 두 예제가 보여주는 것
§6.3 의 두 예제는 로그선형 모형의 두 가지 전형을 담고 있다.
| 예제 | 반응의 본질 | 모형 포인트 |
|---|---|---|
| 결핵균 검정(§6.3.1) | 측정값(mm) — 본래 카운트가 아님 | 곱셈적 평균 + 평균비례 분산 → 로그선형으로 접근, 라틴 정방 설계 |
| 선박 손상(§6.3.2) | 사고 건수 | offset \(\log(\text{노출})\) 을 통한 rate 회귀, 과산포 |
두 예제 모두 “이 데이터가 왜 로그선형 구조에 맞는가” 를 엔지니어링적으로 설명한다는 공통점이 있다. 카운트라고 자동으로 포아송을 쓰지 않고, 카운트가 아니어도 곱셈적 구조와 linear variance 가 맞으면 로그선형 프레임을 쓴다.
2 예제 1: 결핵균 생물학적 검정 (§6.3.1)
2.1 실험 설계 — 라틴 정방 (Latin Square)
Fisher (1949) 의 고전 실험. 120 마리의 소를 네 반(I, II, III, IV) × 30 마리 로 나누고, 각 소의 목 네 부위(site 1–4) 에 네 결핵균 처리를 적용.
| 처리 | 제제 | 용량 |
|---|---|---|
| A | Standard | double (0.10 mg) |
| B | Standard | single (0.05 mg) |
| C | Weybridge | single (0.05 mg) |
| D | Weybridge | half (0.025 mg) |
라틴 정방 배치:
| Site | I | II | III | IV |
|---|---|---|---|---|
| 1 | A | B | C | D |
| 2 | B | A | D | C |
| 3 | C | D | A | B |
| 4 | D | C | B | A |
왜 라틴 정방인가: 소 개체 간 변동(between-animal) 이 부위 간 변동(between-site) 과 처리 간 변동을 가리지 않도록 세 요인을 모두 직교 하게 배치. 각 처리가 모든 반에 한 번씩, 모든 부위에 한 번씩 등장하므로 세 주효과가 교락되지 않는다.
2.2 반응과 모형
반응 \(y_{ij}\) = site \(i\), class \(j\) 에서 30마리의 피부 비후(skin thickening) 합계 (mm). 카운트가 아니지만 Fisher 는 예비 분석에서 다음 두 사실을 확인했다.
- 처리와 부위의 효과는 곱셈적 (로그 척도에서 더하기)
- \(\mathrm{Var}(Y) \propto \mathrm{E}(Y)\) — 평균에 비례하는 분산
이 두 조건이 맞으면 측정값이라도 로그선형 GLM 이 자연스럽다. 포아송이 아니어도 quasi-Poisson (\(\mathrm{Var}(Y) = \sigma^2 \mu\)) 로 적합.
2.3 모형식
\[ \text{site} + \text{class} + \text{volume} + \text{tuberculin} \]
site,class: 4-수준 factortuberculin: 2-수준 factor (Standard vs Weybridge)volume: 2-수준 factor (low vs high) 또는 정량 공변량 (−1, 0, 1)
\(2 \times 2\) factorial (volume × tuberculin) 로 네 처리를 재구성 — 교호작용 없이. 이것이 “Standard 와 Weybridge 의 용량 효과가 로그 척도에서 동일하다” 는 생물학적 가정의 수학적 표현.
2.4 적합 결과
\[ \hat{\beta}_{\text{high-low}} = 0.2095, \quad \text{SE} = 0.0124 \]
\[ \hat{\beta}_{\text{Weybridge-Standard}} = 0.0026, \quad \text{SE} = 0.0123 \]
과산포 추정: \(\hat\sigma^2 = 1.410/7 = 0.2014\) — Fisher 의 비반복적 추정치 0.2018 과 거의 일치.
2.5 해석 — 곱셈적 효과의 직관
용량 2배 → 반응 \(\exp(0.2095) = 1.233\) 배. 즉 23.3% 증가. 이것이 Standard 와 Weybridge 모두에 적용된다 (교호작용 없음 가정 하).
Weybridge vs Standard 의 상대 효능(relative potency):
\[ 2^{\hat\beta_C / \hat\beta_A} = 2^{0.2121/0.2095} = 2.017. \]
“같은 반응을 내기 위해 Standard 는 Weybridge 의 약 2배 용량이 필요” — 즉 Weybridge 의 효능이 Standard 의 약 2배. Fisher 의 값 2.009 (또는 2.013) 와 본질적으로 같음.
왜 \(0.2121/0.2095\) 인가: 용량이 \(\exp(\beta)\) 로 반응에 영향을 주므로 “동일 반응을 위한 용량비” 는 로그 척도에서 \(\beta\) 의 비율. \(2^{\text{ratio}}\) 로 변환하는 것은 volume 을 \(\log_2\) 로 코딩했기 때문 (half = \(-1\), single = \(0\), double = \(+1\)).
2.6 곱셈성 가정의 검정
volume × tuberculin 교호작용을 포함한 포화 \(2 \times 2\) 모형(즉 4-수준 factor 로 취급)과 비교해 \(F\)-검정 (1, 6 자유도, \(\sigma^2\) 미지이므로 \(\chi^2\) 아님). 유의하지 않으면 곱셈성 가정 유지.
2.7 잔차 설계의 중요성
라틴 정방 덕분에 처리 간 대조는 같은 동물 내 부위 간 차이로 계산되어 동물 간 변동이 제거된다. 만약 다른 설계(랜덤 완전 블록 등) 였다면 동물 간 변동성이 처리 대조의 SE 에 추가로 기여했을 것. 교재 지적: “class 간 대조는 동물 간 변동을 포함하므로 여기 보고된 SE 가 적절하지 않다”는 미묘한 뉘앙스가 있다 — 관심 대조(처리·용량)는 동물 내이므로 SE 가 유효.
현대적 관점: 이 구조는 반복측정 혼합효과 모형 (소를 랜덤효과) 으로 더 명시적으로 다룰 수 있다. 교재 §14.3 에서 상세히 전개된다.
3 예제 2: Lloyd’s 선박 파도 손상 (§6.3.2)
3.1 데이터 구조
Crilley & Heminway, Lloyd’s Register of Shipping. 카고선의 전방부에 파도가 주는 손상 건수와 노출 기간을 세 요인으로 분류.
| 요인 | 수준 |
|---|---|
| Ship type (선종) | A, B, C, D, E |
| Year of construction (건조 연도) | 1960–64, 65–69, 70–74, 75–79 |
| Period of operation (운항 시기) | 1960–74, 1975–79 |
\(5 \times 4 \times 2 = 40\) 셀. 각 셀에 (사고 건수, 총 운항 개월) 이 기록됨. 1975 이후 건조된 배가 1974 이전에 운항할 수 없으므로 6 셀이 구조적으로 빈 셀(structurally empty).
핵심: 반응은 한 배당 손상 건수가 아니라 셀 전체의 손상 건수. 같은 배가 두 번 손상될 수 있고, 두 기간 모두 운항할 수도 있다.
3.2 모형 — offset 을 통한 rate 회귀
\[ \log(\text{기대 손상 건수}) = \beta_0 + \log(\text{총 운항 개월}) + \text{선종} + \text{건조 연도} + \text{운항 시기} \tag{6.5} \]
offset 의 정체: \(\log(\text{운항 개월})\) 앞의 계수가 1로 고정 된 항. 이것을 다시 쓰면
\[ \log\!\left(\frac{\text{기대 손상 건수}}{\text{운항 개월}}\right) = \beta_0 + \text{선종} + \cdots \]
즉 “단위 시간당 사고율(rate)” 의 로그가 요인들에 선형. 이것이 로그선형 모형의 가장 흔한 응용 형태이다.
왜 offset 인가: “운항 기간이 두 배면 사고도 두 배” 라는 선험적 지식 을 모형에 강제로 반영. 이 계수를 자유 모수로 두면 데이터에서 추정되지만, 여기서는 물리적으로 \(\beta = 1\) 이 자명하다. (나중에 이 가정을 점검함 — 3번 포인트 참조.)
3.3 과산포 가정
배마다 “사고 성향(accident-proneness)” 이 다르므로 inter-ship variability 가 존재. 이는 클러스터 포아송 메커니즘(§6.2.3) 의 전형 — 과산포가 예상된다. 따라서
\[ \mathrm{E}(Y) = \mu, \quad \mathrm{Var}(Y) = \sigma^2 \mu, \quad \sigma^2 > 1 \]
을 가정하되 점추정은 포아송 우도로 진행.
3.4 적합 결과 — 주효과 모형
과산포 추정: \(\hat\sigma^2 = 1.69\). 예상대로 \(> 1\), 즉 실제 분산이 포아송보다 약 70% 더 크다.
주요 결과:
- 모든 주효과 유의
- offset 의 계수를 자유롭게 두면 \(\hat\beta_{\log(\text{service})} = 0.903\), SE \(= 0.13\) → 1과 유의하게 다르지 않음 ← offset 가정 확인
service period × 다른 요인2-요인 교호작용 없음ship type × year of construction교호작용은 유의할 듯 하지만 과산포 보정 후 \(F\)-비가 \(0.92\) 로 유의하지 않음- 관측 21 (C 선종, 1970–74, 1960–74) 의 표준화 잔차 2.87 — 단일 이상치
3.5 과산포가 결론을 바꾸는 장면
포아송 가정 하에서는 type × year 교호작용의 이탈도 감소 \(38.7 - 14.6 = 24.1\) on 15 df 가 \(\chi^2_{15}\) 에서 유의해 보인다. 그러나 \(\sigma^2 = 1.74\) 로 보정한 \(F\)-비
\[ F = \frac{(38.7 - 14.6)/15}{1.74} = \frac{24.1}{15 \times 1.74} = 0.92 \]
는 \(F_{15, \text{...}}\) 의 1%도 안 되는 분위수. “유의” 가 “비유의” 로 완전히 뒤집힌다.
교훈: 과산포를 무시하면 교호작용을 부풀려 감지한다. “효과가 시간에 따라 달라진다”는 잘못된 결론이 내려질 수 있다. 과산포 보정은 단순히 SE 를 키우는 기술이 아니라 질적 결론 자체 를 뒤집을 수 있다.
3.6 해석 — 주효과의 물리적 의미
운항 시기 효과 (1974 오일 쇼크 이후 vs 이전):
\[ \hat\beta = 0.385, \quad \text{SE} = 0.154 \]
\(\exp(0.385) = 1.47\). 1974년 이후 사고율이 47% 증가, 95% CI 약 \((8\%, 100\%)\). 선종에 관계없이 균일하게 적용 (교호작용 없음).
왜 1974년 이후 사고가 늘었는가: 오일 쇼크로 에너지 가격이 오르자 선박 연료 절약을 위해 항로·속도 최적화가 요구되고 유지보수가 지연된 결과로 추측된다. 경영 환경의 변화가 유지보수 품질에 영향을 준 거시경제 → 미시 안전의 고리.
선종별 위험: B, C 가 가장 안전, E 가 가장 위험.
건조 연도별 위험 (Table 6.3):
| 연도 | 계수 | 상대 위험 |
|---|---|---|
| 1960–64 | 0 (기준) | 1.00 |
| 1965–69 | 0.70 | 2.01 |
| 1970–74 | 0.82 | 2.27 |
| 1975–79 | 0.45 | 1.57 |
1965–74년 건조된 배가 가장 위험. 가장 오래된 1960–64 선박이 오히려 더 안전 — 생존 편향 (survivor bias) 가능성. 위험한 배는 일찍 사라지고 살아남은 오래된 배들이 본질적으로 견고할 수 있다.
3.7 조건부 자유도 계산의 미묘함
교호작용 포함 모형에서 잔차 자유도를 계산할 때 표준 공식 은 13을 주지만, 적절한 조건부 참조 분포 에서는 10이 맞다.
이유: 교호작용 모형의 충분통계량 이 type × year 주변 합 (Table 6.4)을 고정. 이 표의 4×4 에서 (4개의 0셀 + 1개 오일쇼크 이후 단일 관측 열) 을 제외하면 실질 자유도는 11, 그리고 service period 주효과가 1 을 더 빼서 10.
실무적 함의: GLM 소프트웨어가 자동으로 주는 자유도가 희소 테이블 / 구조적 결측 / 조건부 충분통계량 상황에서는 잘못될 수 있다. 분할표의 정확 추론에서는 직접 계산이 필요.
3.8 이상치 (관측 21) 논의
선종 C × 1970–74 × 1960–74 (6 사고 / 783 개월). 기대치 1.47 대비 잔차 2.87. 모형을 확장해도 잔차가 2.48 정도로 남음. 단일 관측의 설명되지 않은 높은 사고율.
가능한 설명: (i) C형 선박의 특정 설계 결함이 이 건조 연도 일부 배에 집중, (ii) 특정 운항 지역·날씨 노출, (iii) 기록 오류. 이 관측을 제외하면 해석이 일부 달라지지만, 제외 없이도 주결론은 견고.
4 두 예제의 대비 — 무엇이 다른가
| 항목 | 결핵균 | 선박 손상 |
|---|---|---|
| 반응 | 측정값 (mm) | 카운트 |
| 분포 가정 | quasi-Poisson (\(\hat\sigma^2 = 0.20\)) | quasi-Poisson (\(\hat\sigma^2 = 1.69\)) |
| offset | 없음 | \(\log(\text{운항 개월})\) |
| 설계 | 라틴 정방 (균형) | 관측 연구 (불균형) |
| 주 관심 | 곱셈적 처리 효과 | rate 변화 + 요인별 위험 |
| 과산포 방향 | under (\(\sigma^2 < 1\)) | over (\(\sigma^2 > 1\)) |
| 교호작용 판단 | 곱셈성 가정 검정 | 과산포 보정 후 비유의 |
특히 주목: 결핵균은 \(\hat\sigma^2 < 1\) 의 과소산포. 실험실에서 철저히 통제된 설계이므로 자연 변동이 포아송보다 작다. 선박은 현실 관찰이라 과산포. 두 방향 모두 quasi 프레임으로 수용된다 (§6.2.3 의 “\(0 \le \sigma^2\)” 확장).
5 코드 예시
5.1 Step 1: 결핵균 검정 — 라틴 정방 quasi-Poisson
import numpy as np
import pandas as pd
import statsmodels.api as sm
import statsmodels.formula.api as smf
# Table 6.1b — 사이트 × 클래스 반응 (30마리 합)
# 라틴 정방 배치: Site×Class → 처리 A/B/C/D
y = np.array([
[454, 249, 349, 249], # site 1: A B C D
[408, 322, 312, 347], # site 2: B A D C
[523, 268, 411, 285], # site 3: C D A B
[364, 283, 266, 290], # site 4: D C B A
])
site = np.repeat(np.arange(1, 5), 4)
cls = np.tile(np.arange(1, 5), 4)
y_flat = y.ravel()
treat_map = [
["A", "B", "C", "D"],
["B", "A", "D", "C"],
["C", "D", "A", "B"],
["D", "C", "B", "A"],
]
treat = np.array([treat_map[s-1][c-1] for s, c in zip(site, cls)])
# volume: A=+1, B=0, C=0, D=-1 (Standard double, single / Weybridge single, half)
volume = np.array([{"A":1, "B":0, "C":0, "D":-1}[t] for t in treat])
# tuberculin: Standard (A,B) = 0, Weybridge (C,D) = 1
tuber = np.array([{"A":0, "B":0, "C":1, "D":1}[t] for t in treat])
df = pd.DataFrame({
"y": y_flat, "site": site.astype(str), "cls": cls.astype(str),
"volume": volume, "tuber": tuber,
})
# quasi-Poisson (scale 자동 추정)
fit = smf.glm("y ~ C(site) + C(cls) + volume + tuber", data=df,
family=sm.families.Poisson()).fit(scale="X2")
print(fit.summary().tables[1])
print(f"\nScale = {fit.scale:.4f} (교재: 0.2014)")
# 상대 효능
beta_volume = fit.params["volume"]
beta_tuber = fit.params["tuber"]
print(f"\n고용량 효과 = {beta_volume:.4f} → 용량 2배 시 {np.exp(beta_volume):.3f}배")
print(f"Weybridge 효과 = {beta_tuber:.4f}")
print(f"상대 효능 (Weybridge/Standard) = 2^{(beta_tuber + beta_volume)/beta_volume:.4f}")5.2 Step 2: 선박 사고 — offset rate 회귀
import numpy as np
import pandas as pd
import statsmodels.api as sm
import statsmodels.formula.api as smf
# Table 6.2 의 축약 — 구조적 0 셀 제외
records = [
# ship, year, period, service, incidents
("A", "1960-64", "1960-74", 127, 0),
("A", "1960-64", "1975-79", 63, 0),
("A", "1965-69", "1960-74", 1095, 3),
("A", "1965-69", "1975-79", 1095, 4),
("A", "1970-74", "1960-74", 1512, 6),
("A", "1970-74", "1975-79", 3353, 18),
("A", "1975-79", "1975-79", 2244, 11),
("B", "1960-64", "1960-74", 44882, 39),
("B", "1960-64", "1975-79", 17176, 29),
("B", "1965-69", "1960-74", 28609, 58),
("B", "1965-69", "1975-79", 20370, 53),
("B", "1970-74", "1960-74", 7064, 12),
("B", "1970-74", "1975-79", 13099, 44),
("B", "1975-79", "1975-79", 7117, 18),
("C", "1960-64", "1960-74", 1179, 1),
("C", "1960-64", "1975-79", 552, 1),
("C", "1965-69", "1960-74", 781, 0),
("C", "1965-69", "1975-79", 676, 1),
("C", "1970-74", "1960-74", 783, 6), # 관측 21 — 이상치
("C", "1970-74", "1975-79", 1948, 2),
("C", "1975-79", "1975-79", 274, 1),
("D", "1960-64", "1960-74", 251, 0),
("D", "1960-64", "1975-79", 105, 0),
("D", "1965-69", "1960-74", 288, 0),
("D", "1965-69", "1975-79", 192, 0),
("D", "1970-74", "1960-74", 349, 2),
("D", "1970-74", "1975-79", 1208, 11),
("D", "1975-79", "1975-79", 2051, 4),
("E", "1960-64", "1960-74", 45, 0),
("E", "1965-69", "1960-74", 789, 7),
("E", "1965-69", "1975-79", 437, 7),
("E", "1970-74", "1960-74", 1157, 5),
("E", "1970-74", "1975-79", 2161, 12),
("E", "1975-79", "1975-79", 542, 1),
]
df = pd.DataFrame(records, columns=["ship", "year", "period", "service", "y"])
df["log_service"] = np.log(df["service"])
# 주효과 모형 (offset 고정)
fit_main = smf.glm(
"y ~ C(ship) + C(year) + C(period)",
data=df,
family=sm.families.Poisson(),
offset=df["log_service"],
).fit(scale="X2")
print("=== Main effects (quasi-Poisson) ===")
print(fit_main.summary().tables[1])
print(f"Scale sigma^2 = {fit_main.scale:.3f} (교재: 1.69)")
# offset 계수를 자유롭게 두어 1인지 확인
fit_free = smf.glm(
"y ~ C(ship) + C(year) + C(period) + log_service",
data=df, family=sm.families.Poisson(),
).fit(scale="X2")
print(f"\n자유 offset 계수 = {fit_free.params['log_service']:.3f} "
f"(SE = {fit_free.bse['log_service']:.3f}) — 1과 유의차 없으면 offset 가정 확인")
# 운항 시기 효과 해석
beta_period = fit_main.params["C(period)[T.1975-79]"]
print(f"\n1975-79 vs 1960-74 효과 = {beta_period:.3f}")
print(f"rate 증가 배수 = exp({beta_period:.3f}) = {np.exp(beta_period):.3f}")
print(f"95% CI (점근 정규): "
f"({np.exp(beta_period - 1.96 * fit_main.bse['C(period)[T.1975-79]']):.3f}, "
f"{np.exp(beta_period + 1.96 * fit_main.bse['C(period)[T.1975-79]']):.3f})")
# type × year 교호작용 F-test (과산포 보정)
fit_inter = smf.glm(
"y ~ C(ship) * C(year) + C(period)",
data=df, family=sm.families.Poisson(),
offset=df["log_service"],
).fit(scale="X2")
dD = fit_main.deviance - fit_inter.deviance
df_diff = fit_main.df_resid - fit_inter.df_resid
F = (dD / df_diff) / fit_inter.scale
print(f"\n=== type × year 교호작용 검정 (과산포 보정) ===")
print(f"Delta D = {dD:.2f} on {df_diff} df")
print(f"scale = {fit_inter.scale:.3f}")
print(f"F = {F:.3f} (교재: 0.92 — 비유의)")5.3 R 대응
# 결핵균
df_fisher <- # ... as above
fit <- glm(y ~ site + cls + volume + tuber, data = df_fisher,
family = quasipoisson())
# 선박
fit_ship <- glm(y ~ ship + year + period, data = df_ship,
offset = log(service),
family = quasipoisson())
summary(fit_ship)
anova(fit_ship, update(fit_ship, . ~ . + ship:year), test = "F")6 자주 걸리는 함정
| 함정 | 증상 | 처방 |
|---|---|---|
| 카운트 아니라고 로그선형 포기 | OLS 로 돌리고 SE 편향 | 평균-분산 관계·곱셈성 확인 후 quasi-Poisson |
| offset 대신 비율을 반응으로 | 분산 구조 깨짐 | 원본 카운트 + offset(log(exposure)) |
| 과산포 무시하고 \(\chi^2\) LRT | 교호작용 과잉 감지 | \(F\)-검정 + \(\hat\sigma^2\) 보정 |
| offset 계수 고정 가정 없이 사용 | 계수가 1 아닐 때 편향 | 먼저 자유 계수로 추정해 1 인지 확인 |
| 희소 분할표 자동 자유도 신뢰 | p-value 부정확 | 충분통계량 기반 수동 계산 |
| 이상치 하나로 결론 좌우 | 잔차 3 근처 관측 방임 | sensitivity analysis (제거 전후 비교) |
| 생존 편향 간과 | 오래된 배가 안전해 보임 | 시간 효과 해석 시 맥락 제시 |
| under-dispersion 이 비정상이라고 오해 | \(\sigma^2 < 1\) 버림 | 통제된 설계에서 정상적 현상 |
7 관련 주제
선행 지식
- Log-linear Models — 개관
- Likelihood Functions for Log-linear Models
- Over-dispersion in Polytomous GLMs — 클러스터 메커니즘
- GLM 적합 알고리즘 IRLS
후속 주제 (placeholder)
- Log-linear 과 Multinomial Response 의 쌍대성 (§6.4)
- Multiple Responses 와 정준상관 (§6.5)
- 3원 분할표 — 독립성·조건부 독립성 (§6.6)
관련 개념
8 참고문헌
- McCullagh, P. & Nelder, J. A. (1989). Generalized Linear Models (2nd ed.), §6.3. Chapman & Hall.
- Fisher, R. A. (1949). A biological assay of tuberculins. Biometrics, 5, 300–316.
- Crilley, J. & Heminway, L. N. — Lloyd’s Register of Shipping, wave damage data (1985).
- Aitkin, M. & Francis, B. (1995). Fitting overdispersed generalized linear models by nonparametric maximum likelihood. GLIM Newsletter.
- Cameron, A. C. & Trivedi, P. K. (2013). Regression Analysis of Count Data (2nd ed.). Cambridge.