iBetter Books
수정

상관분석 (Pearson, Spearman)

두 변수가 함께 변하는 경향이 있는지 수치로 표현하는 방법이 상관분석입니다. "키가 클수록 몸무게도 많이 나가는가?", "공부 시간이 길수록 성적이 높은가?" 같은 질문에 답합니다.

상관계수란 무엇인가

상관계수(correlation coefficient)는 두 변수의 선형적 관계를 -1에서 1 사이의 값으로 나타냅니다.

  • 1에 가까울수록 한 변수가 증가할 때 다른 변수도 증가합니다.
  • -1에 가까울수록 한 변수가 증가할 때 다른 변수는 감소합니다.
  • 0에 가까울수록 두 변수 사이에 선형 관계가 없습니다.
# 상관계수 크기별 해석 기준 (Cohen, 1988)
# |r| < 0.10  : 무시할 수 있는 수준
# 0.10 ~ 0.29 : 약한 상관
# 0.30 ~ 0.49 : 중간 상관
# 0.50 이상   : 강한 상관

Pearson vs Spearman, 무엇을 쓸까

두 가지 대표적인 상관계수가 있습니다.

Pearson r은 두 변수가 연속형이고, 선형 관계이며, 정규분포를 따를 때 적합합니다. 가장 많이 쓰이고, 통계 교과서에서 "상관계수"라고 하면 보통 Pearson을 가리킵니다.

Spearman ρ(rho)는 순위(rank)를 기반으로 계산합니다. 정규분포 가정이 필요 없고, 이상치의 영향을 덜 받습니다. 서열 척도 데이터(만족도 1~5점 등)나 정규성을 만족하지 못할 때 선택합니다.

# 선택 기준 요약
# 연속형 + 정규분포 + 선형 관계  → Pearson
# 서열형 or 정규성 위반 or 이상치  → Spearman

cor()로 상관계수 계산하기

R의 내장 데이터 mtcars를 사용합니다. 자동차 32종의 연비, 배기량, 마력 등의 정보가 담겨 있습니다.

# mtcars 데이터 확인
head(mtcars)
str(mtcars)
# mpg: 연비(마일/갤런), cyl: 실린더 수, disp: 배기량
# hp: 마력, wt: 차체 무게

# 두 변수의 Pearson 상관계수
cor(mtcars$mpg, mtcars$wt)
# [1] -0.8676594
# 연비와 무게는 강한 음의 상관관계 — 무거울수록 연비가 낮다

# Spearman 상관계수
cor(mtcars$mpg, mtcars$wt, method = "spearman")
# [1] -0.8864161

# 여러 변수의 상관행렬
cor(mtcars[, c("mpg", "cyl", "disp", "hp", "wt")])
         mpg        cyl       disp         hp         wt
mpg  1.0000000 -0.8521620 -0.8475514 -0.7761684 -0.8676594
cyl -0.8521620  1.0000000  0.9020329  0.8324475  0.7824958
disp -0.8475514  0.9020329  1.0000000  0.7909486  0.8879799
hp  -0.7761684  0.8324475  0.7909486  1.0000000  0.6587479
wt  -0.8676594  0.7824958  0.8879799  0.6587479  1.0000000

cor.test()로 통계적 유의성 검정하기

상관계수가 실제로 유의미한지, 아니면 우연히 나온 값인지 확인해야 합니다.

귀무가설은 "두 변수 사이의 상관계수는 0이다(관계없다)"입니다.

# Pearson 상관 검정
result <- cor.test(mtcars$mpg, mtcars$wt)
result
	Pearson's product-moment correlation

data:  mtcars$mpg and mtcars$wt
t = -9.559, df = 30, p-value = 1.294e-10
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 -0.9338264 -0.7440872
sample estimates:
       cor 
-0.8676594 
# 결과 해석
# cor = -0.868 : 강한 음의 상관관계
# p-value < 0.001 : 통계적으로 매우 유의미함
# 95% CI : -0.934 ~ -0.744, 0을 포함하지 않으므로 유의함

# Spearman 검정
cor.test(mtcars$mpg, mtcars$wt, method = "spearman")

# 결과에서 주요 값 추출
result$estimate    # 상관계수
result$p.value     # p-value
result$conf.int    # 신뢰구간

산점도와 추세선 그리기

숫자만 보는 것보다 그래프로 확인하는 것이 직관적입니다.

library(ggplot2)

# 기본 산점도 + 추세선
ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point(color = "steelblue", size = 3, alpha = 0.7) +
  geom_smooth(method = "lm", se = TRUE, color = "tomato") +
  labs(
    title    = "자동차 무게와 연비의 관계",
    subtitle = "r = -0.87, p < 0.001",
    x        = "차체 무게 (1000 lbs)",
    y        = "연비 (mpg)"
  ) +
  theme_classic()
# 상관행렬 히트맵 — corrplot 패키지 활용
install.packages("corrplot")
library(corrplot)

cor_mat <- cor(mtcars[, c("mpg", "cyl", "disp", "hp", "wt", "qsec")])

corrplot(cor_mat,
         method  = "color",      # 색으로 표현
         type    = "upper",      # 위 삼각형만
         tl.col  = "black",      # 변수명 색
         addCoef.col = "black",  # 계수 숫자 추가
         number.cex  = 0.8)      # 숫자 크기

상관관계 ≠ 인과관계

가장 중요한 원칙입니다.

아이스크림 판매량과 익사 사고 수는 강한 양의 상관관계를 보입니다. 아이스크림을 많이 팔면 익사가 늘어나는 것이 아닙니다. 둘 다 여름 더위라는 공통 원인(교란 변수)의 영향을 받을 뿐입니다.

# 예시: 스트크 데이터가 없어도 논리로 생각하기
# 소방차 수 ↔ 화재 피해액 → 양의 상관
# 소방차가 피해를 키우는 게 아니라, 큰 불에 소방차가 더 많이 출동하는 것

# 상관분석 결론 작성 시 주의
# 잘못된 표현: "A가 B를 증가시킨다"
# 올바른 표현: "A와 B 사이에 유의한 양의 상관관계가 있다 (r = .XX, p < .05)"

상관분석은 "관계가 있는지"를 확인합니다. "왜 그런지"를 설명하려면 실험 설계나 인과 추론 방법이 필요합니다.

여러 변수의 산점도 행렬

# pairs()로 산점도 행렬
pairs(mtcars[, c("mpg", "cyl", "hp", "wt")],
      pch   = 19,
      col   = "steelblue",
      lower.panel = panel.smooth,   # 아래쪽에 추세선
      upper.panel = function(x, y, ...) {
        r <- cor(x, y)
        text(0.5, 0.5, round(r, 2),
             cex = abs(r) * 2,      # 상관계수 크기에 비례한 글자 크기
             col = ifelse(r > 0, "steelblue", "tomato"))
      })
# GGally 패키지 — 더 깔끔한 시각화
install.packages("GGally")
library(GGally)

ggpairs(mtcars[, c("mpg", "hp", "wt", "qsec")],
        lower = list(continuous = wrap("smooth", alpha = 0.5)),
        diag  = list(continuous = "densityDiag"),
        upper = list(continuous = wrap("cor", size = 4)))

결측값이 있을 때

# 결측값이 있으면 cor()는 NA를 반환합니다
x <- c(1, 2, NA, 4, 5)
y <- c(2, 4, 6, 8, 10)
cor(x, y)           # NA

# use 인자로 처리 방법 지정
cor(x, y, use = "complete.obs")    # 결측값 있는 행 제거 후 계산
cor(x, y, use = "pairwise.complete.obs")  # 각 쌍마다 별도 처리

상관분석은 탐색적 분석의 시작점입니다. 의미 있는 상관이 발견되면 그다음 단계인 회귀분석으로 나아갑니다.