왜 t-검정 무더기가 아니라 분산분석인가
t-검정은 두 평균을 비교합니다. 그룹이 셋 이상이면 모든 쌍에 t-검정을 돌리고 싶어지는데, 그것이 바로 함정입니다. 0.05 수준으로 수행한 각 검정은 5%의 위양성 위험을 지고, 그 위험이 누적됩니다: 그룹이 4개면 쌍별 검정이 6번이고 적어도 하나가 허위로 "유의"할 확률이 약 26%, 5개면(검정 10번) 약 40%입니다. 순수한 잡음에서 발견을 제조하게 되는 셈이죠.
분산분석(ANalysis Of VAriance)은 하나 의 p값으로 하나 의 질문을 던져 이를 해결합니다: 모든 그룹 평균이 같은가, 아니면 적어도 하나가 다른가? 이름과 달리 평균을 비교하는데, 다만 분산을 분석하는 방식으로 그렇게 합니다: 그룹 평균들이 그룹 내부 잡음으로 설명할 수 있는 것보다 더 넓게 퍼져 있다면 실재하는 무언가가 일어나고 있는 것입니다.
aov()로 하는 일원분산분석
PlantGrowth는 이를 위해 만들어졌습니다: 대조군과 두 처리 조건에서의 식물 무게 데이터죠. aov()로 적합한 뒤 - 중요합니다 - summary()로 표를 출력하세요:
수식은 "weight가 group에 의존하는가?"로 읽습니다. 그룹 변수는 반드시 팩터여야 합니다 - PlantGrowth$group은 이미 팩터이지만, 그룹이 숫자로 코딩되어 있다면(용량, 배치 ID) 감싸 주세요: aov(y ~ factor(dose), ...). 그러지 않으면 aov()는 그룹 평균을 비교하는 대신 조용히 그룹 코드에 회귀 직선 을 적합합니다 - 잘못된 모형인데 오류 메시지도 없습니다.
분산분석표 읽기
표는 두 행 - 요인과 잔차 - 그리고 다섯 열로 이루어집니다. 칸 단위로 봅시다:
Df Sum Sq Mean Sq F value Pr(>F)
group 2 3.766 1.8832 4.846 0.0159
Residuals 27 10.492 0.3886
- Df - 자유도입니다. 요인 행은 그룹 수 − 1(그룹 3개 → 2), 잔차 행은 관측 수 − 그룹 수(30 − 3 = 27)를 받습니다. R이 여러분이 의도한 설계를 제대로 읽었는지 빠르게 점검하는 값입니다.
- Sum Sq - 변동을 두 더미로 나눈 것입니다.
group행은 그룹 간 더미입니다: 그룹 평균들이 전체 평균에서 얼마나 떨어져 있는가죠.Residuals는 그룹 내 더미입니다: 식물들이 자기 그룹의 평균 주위에서 얼마나 변동하는가입니다. 둘을 합하면 데이터의 총변동이 됩니다. - Mean Sq - 각 Sum Sq를 자신의 Df로 나눈 값으로, 변동 더미를 자유도당 비교 가능한 비율로 바꿉니다. 잔차 Mean Sq(0.389)가 잡음 수준입니다.
- F value - 그 비율입니다:
group의 Mean Sq를Residuals의 Mean Sq로 나눈 값(1.8832 / 0.3886 ≈ 4.85)이죠. 모든 그룹 평균이 정말 같다면 이 비율은 1 근처를 맴돕니다. F가 커질수록 그룹 간 차이가 잡음으로 설명할 수 있는 범위를 더 크게 앞지릅니다. - Pr(>F) - p값입니다: 세 참 평균이 모두 동일하다면 이만큼 큰 F가 나올 확률이죠. 여기서는 0.016으로, 통상적인 0.05 수준에서 "모두 같음"을 기각하기에 충분히 작습니다. 늘 그렇듯 이는 귀무가설이 참일 확률이 아니며, 어떤 그룹이 얼마나 다른지에 대해서도 아무것도 말하지 않습니다.
마지막 지점이 결정적인 한계입니다: 유의한 F는 "어딘가에 어떤 차이가 있다"고만 말합니다. 그 이상은 아닙니다.
어떤 그룹이 다를까? TukeyHSD()
후속 질문에는 사후검정이 필요합니다. Tukey의 정직유의차(Honest Significant Difference)는 모든 비교를 통틀어 집단 전체 오류율을 5%로 유지하면서 모든 쌍을 검정합니다:
쌍마다 한 행, 행마다 네 개의 숫자입니다:
- diff - 추정된 평균 차이입니다(뒤에 이름 붙은 그룹에서 앞의 그룹을 뺀 값).
- lwr, upr - 그 차이에 대한 95% 집단 전체 신뢰구간입니다.
- p adj - 비교를 세 번 한다는 점이 이미 조정된 p값입니다.
PlantGrowth의 경우: trt2-trt1은 약 0.87의 차이에 p adj ≈ 0.012이고 구간이 0을 포함하지 않습니다 - 처리 2가 처리 1보다 더 자랍니다. 처리 대 대조 행 두 개(trt1-ctrl, trt2-ctrl)는 구간이 0을 걸치고 p adj가 0.05를 훌쩍 넘습니다 - 이 표본에서는 어느 처리도 대조군과 구별되지 않습니다. 경험칙은 어디서나 신뢰구간과 같습니다: 구간이 0을 제외함 ⇔ p adj가 0.05 미만.
전체 F는 "차이가 존재한다"고 말했지만 Tukey는 그것을 정확히 한 쌍에서 찾아냅니다 - 이 두 단계 구조가 설계의 전부입니다: 정직한 전체 검정 하나, 그다음 제대로 보정된 쌍별 탐정 작업이죠.
이원분산분석: 두 요인과 그 상호작용
그룹 변수가 둘이면 한 번의 호출로 둘 다를 검정하고, 게다가 둘이 상호작용 하는지도 검정합니다. ToothGrowth는 보충제 종류(supp)와 용량(0.5, 1, 2 mg - 수치형이므로 factor()가 필요합니다)을 교차시킵니다:
supp * factor(dose)는 세 개의 효과로 확장되며 표에서 각각 한 행을 차지합니다:
- supp - 용량에 대해 평균을 냈을 때 보충제 종류가 중요한가? (그렇습니다: p ≈ 0.0002.)
- factor(dose) - 보충제에 대해 평균을 냈을 때 용량이 중요한가? (단연코 그렇습니다: p가 아주 작습니다.)
- supp:factor(dose) - 상호작용입니다: 보충제의 효과 가 용량에 따라 달라지는가? 여기서는 p ≈ 0.022로 달라집니다. 낮은 용량에서는 오렌지 주스가 아스코르브산을 앞서지만 2 mg 용량에서는 그 격차가 사라집니다.
유의한 상호작용은 주효과에 붙은 경고 라벨입니다: "보충제 종류가 중요하다"는 오직 평균적으로만 참이고, 그 평균은 용량에 따라 달라지는 이야기를 감춥니다. 상호작용이 유의하다면 주효과만 보고하지 말고 조합을 설명하세요(TukeyHSD(fit2, "supp:factor(dose)")이나 그룹별 요약으로 만든 그룹 평균표를 쓰면 됩니다). 상호작용이 없는 모형을 의도적으로 원할 때만 * 대신 +를 쓰세요.
가정 - 그리고 순위 기반 대안
분산분석의 수학은 세 가지 가정에 기대며, 타협 가능성이 낮은 순서로 나열하면 이렇습니다:
- 독립성 - 관측이 서로 영향을 주지 않아야 합니다. 위반은 사후에 고칠 수 없습니다. 연구 설계의 속성이니까요.
- 그룹 간 등분산 - 잔차 Mean Sq는 하나의 합동 잡음 추정치이므로 그룹들의 잡음 수준이 비슷해야 합니다. 한 줄 점검:
bartlett.test(weight ~ group, data = PlantGrowth)(p값이 크면 분산이 다르다는 증거가 없다는 뜻입니다). - 대체로 정규인 잔차 - 균형 잡힌 설계와 적당한 그룹 크기에서는 가장 덜 중요합니다.
residuals(fit)으로 잔차의 히스토그램이나 상자그림을 눈으로 확인하세요.
데이터가 심하게 치우쳐 있거나 순서형이거나 이상치투성이라면, 일원분산분석의 순위 기반 대안은 kruskal.test(weight ~ group, data = PlantGrowth)입니다 - wilcox.test()의 다중 그룹 형제죠. 한 줄이면 되고 약간의 검정력을 견고성과 맞바꿉니다.
핵심 정리
- 분산분석은 3개 이상 그룹 평균에 대해 하나의 p값으로 하나의 질문을 던집니다 - t-검정 다중성 문제의 해법입니다.
fit <- aov(y ~ group, data = df); summary(fit)- 그리고 그룹 변수는 반드시 팩터여야 합니다.- F 값은 그룹 간 신호를 그룹 내 잡음으로 나눈 값입니다.
Pr(>F)가 작다는 것은 "어딘가에 어떤 차이가 있다"는 뜻이며 그 이상은 아닙니다. TukeyHSD(fit)이 어느 쌍이 다른지 찾아 주며 다중비교 보정이 내장되어 있습니다.a * b는 두 요인과 그 상호작용을 적합합니다. 상호작용이 유의하면 주효과만으로는 이야기가 완성되지 않습니다.- 등분산(
bartlett.test)과 잔차 정규성을 점검하고, 순위 기반 대안으로kruskal.test()를 기억하세요.
다음 주제: 그룹 평균 비교에서 관계 모형화로 - lm()으로 하는 선형회귀입니다.
자주 묻는 질문
R에서 분산분석은 어떻게 수행하나요?
수식을 사용해 aov()로 모형을 적합한 뒤 summary()로 표를 출력합니다: fit <- aov(weight ~ group, data = PlantGrowth); summary(fit). 그룹 변수는 반드시 팩터여야 합니다 - 숫자로 저장되어 있다면 수식 안에서 factor()로 감싸세요.
R에서 분산분석표는 어떻게 해석하나요?
F 값은 그룹 간 변동(요인의 Mean Sq)을 그룹 내 변동(잔차의 Mean Sq)으로 나눈 비율입니다. Pr(>F)가 p값이며, 작다면 적어도 한 그룹의 평균이 다른 그룹과 다르다는 뜻입니다 - 하지만 표는 어느 그룹인지 말해 주지 않습니다. 그것을 알려면 TukeyHSD(fit)을 실행하세요.
R에서 Tukey HSD는 무엇을 하나요?
TukeyHSD(fit)은 여러 번 비교한다는 사실을 보정하면서 모든 그룹 쌍을 검정합니다. 각 행은 추정된 차이(diff), 집단 전체 신뢰구간(lwr, upr), 조정된 p값(p adj)을 줍니다. 구간이 0을 포함하지 않는 쌍이 유의하게 다릅니다.
분산분석 대신 그냥 여러 번 t-검정을 하면 안 되나요?
각 t-검정마다 위양성 위험이 있고 그 위험이 쌓이기 때문입니다. 그룹이 5개면 쌍별 t-검정이 10번 필요하고, 각각 0.05 기준이면 적어도 하나가 위양성일 확률이 약 40%까지 올라갑니다. 분산분석은 먼저 하나의 전체 질문을 던지고, 그다음 Tukey HSD가 오류율을 제대로 통제하면서 쌍별 비교를 수행합니다.