Post

상관분석(Correlation Analysis) 정리

상관분석(Correlation Analysis) 정리

오늘은 상관분석(Correlation Analysis)에 대해 공부한 내용을 정리해보겠습니다. 데이터 분석에서 변수 간의 관계를 이해하는 것은 매우 중요한데요, 상관분석은 두 변수 간의 선형적 관계를 측정하는 데 사용되는 기본적이면서도 강력한 방법입니다. 이번 포스팅에서는 상관분석의 기본 개념부터 다양한 상관계수, 척도, 고유값 분해 등을 다루어보려고 합니다.


1. 상관분석이란?

상관분석은 종속변수와 독립변수 간의 관계를 분석하는 방법 중 하나입니다. 여기서 주의할 점은 다중공선성이나 노이즈, 자기상관 등의 문제가 발생할 수 있다는 것입니다. 특히 시계열 데이터에서는 이전 데이터가 이후 데이터에 영향을 미치는 자기상관 현상을 고려해야 합니다.


2. 분산, 공분산, 상관계수

- 분산(Variance)

  • 하나의 변수가 평균에서 얼마나 떨어져 있는지 측정합니다.
  • 공식:
    \(\text{분산} = \frac{\sum_{i=1}^n (x_i - \bar{x})^2}{n-1}\)

- 공분산(Covariance)

  • 두 변수가가 함께 변하는 정도를 나타냅니다.
  • 공식:
    \(S_{xy} = \frac{\sum_{i=1}^n (x_i - \bar{x})(y_i - \bar{y})}{n-1}\)
  • 범위: -∞ ~ +∞ (단위에 의존적).

- 상관계수(Correlation Coefficient)

  • 공분산을 표준화하여 단위의 영향을 제거한 값입니다.
  • 공식:
    \(\text{상관계수} = \frac{\text{cov}(X,Y)}{\sigma_x \sigma_y}\)
  • 범위: -1 ~ +1.
    • 1: 완전한 양의 상관관계
    • -1: 완전한 음의 상관관계
    • 0: 선형 관계 없음

3. 상관계수의 종류

- 피어슨 상관계수(Pearson’s 𝜸)

  • 연속형 데이터에 사용되며, 정규성을 가정합니다(모수적 방법).
  • 검정 방법: t-test.

- 스피어만 상관계수(Spearman’s 𝜌)

  • 순위형 데이터나 정규분포를 따르지 않는 연속형 데이터에 사용됩니다(비모수적 방법).
  • 검정 방법: Kruskal-Wallis test.

- 켄달 상관계수(Kendall’s 𝜏)

  • 순위 데이터에 적용되며, 작은 데이터셋에 강점을 가집니다.

4. 척도(Scale)의 종류

  • 이산형 척도
    • 명목 척도: 이름만 부여된 데이터 (예: 성별).
    • 순위 척도: 순서만 의미가 있는 데이터 (예: 학년).
  • 연속형 척도
    • 등간 척도: 간격이 일정하지만 절대적 0점이 없음 (예: 온도).
    • 비율 척도: 절대적 0점이 존재하며 비율 계산 가능 (예: 무게, 나이).

5. 상관계수 행렬과 고유값 분해

- 상관계수 행렬

  • 정방행렬이며 대칭행렬입니다.
  • 각 행과 열은 변수 간의 상관계수를 나타냅니다.

- 고유값 분해(Eigen Decomposition)

  • 상관계수 행렬을 고유값(분산의 크기)고유벡터(방향)로 분해합니다.
  • 고유값: 0.85 이상이면 주성분(Principal Component), 이하는 노이즈로 간주됩니다.
  • 고유벡터: 서로 정직교하며, 내적 시 0입니다.
  • 주성분 분석(PCA)을 통해 고차원 데이터를 저차원으로 축소할 수 있습니다.

6. 일반화

언더피팅 (Underfitting)

정의

모델이 데이터의 핵심 패턴을 충분히 학습하지 못한 상태입니다.
훈련 데이터와 테스트 데이터 모두에서 낮은 정확도를 보입니다.

원인

  • 모델 복잡도가 너무 낮음 (예: 선형 모델로 비선형 데이터 학습 시)
  • 훈련 데이터가 부족하거나 노이즈가 과도함
  • 특징(Feature) 선택이 적절하지 않음

결과

  • 데이터의 주요 패턴을 놓쳐 예측 성능이 현저히 낮음
  • 훈련 오차와 테스트 오차가 모두 높음

오버피팅 (Overfitting)

정의

모델이 훈련 데이터의 잡음(Noise)까지 학습한 상태입니다.
훈련 데이터에서는 높은 성능을 보이지만, 새로운 데이터(테스트 데이터) 성능이 급격히 하락합니다.

원인

  • 모델 복잡도가 너무 높음 (예: 고차원 다항식 사용)
  • 훈련 데이터가 적거나 불균형함
  • 훈련 시간이 지나치게 길어 노이즈까지 학습

결과

  • 훈련 데이터에 대한 과도한 적합
  • 테스트 데이터에서 일반화 실패

일반화 오류 (Generalization Error)

정의

모델이 새로운 데이터에서 예측할 때 발생하는 오차를 의미합니다.
훈련 데이터와 테스트 데이터의 성능 차이로 측정됩니다.

낮은 일반화 오류

  • 모델이 새로운 데이터에서 안정적인 성능을 보임
  • 예: 훈련 정확도 90% vs 테스트 정확도 88%

높은 일반화 오류

  • 모델이 오버피팅되었음을 의심해야 함
  • 예: 훈련 정확도 99% vs 테스트 정확도 70%

일반화된 모델 (Generalized Model)

정의

훈련 데이터의 핵심 패턴을 학습하면서도, 새로운 데이터에서도 높은 성능을 내는 모델입니다.

주요 특징

  1. 적절한 복잡도: 너무 단순하지도, 복잡하지도 않은 구조
  2. 규제 기법 사용: L1/L2 정규화, 드롭아웃(Dropout) 등
  3. 데이터 다양성: 다양한 환경의 데이터로 훈련됨
  4. 검증 성능: 훈련 데이터와 테스트 데이터의 성능 차이가 작음

예제

공분산 & 상관계수 계산

# 데이터 생성 data1 <- 1:5 data2 <- 2:6 # 분산 계산 var(data1) # R 내장 함수 sum((data1-mean(data1))^2)/(length(data1)-1) # 수식 구현 # 공분산 계산 cov(data1, data2) # R 내장 함수 sum((data1-mean(data1))*(data2-mean(data2)))/(length(data1)-1) # 수식 구현 # 상관계수 계산 cor(data1, data2) # 피어슨 상관계수 sum((data1-mean(data1))*(data2-mean(data2))) / ((length(data1)-1)*sd(data1)*sd(data2)) # 수식 구현 # 상관계수 행렬 예제 m <- matrix(c(1:10, (1:10)^2), ncol=2) cor(m, method = "pearson") # 선형 관계 cor(m, method = "spearman") # 순위 기반

시각화

library(dplyr) data(iris) # 상관계수 행렬 생성 m_cor <- cor(iris[,1:4]) # 시각화 library(pheatmap) pheatmap(m_cor, cutree_rows = 4, main = "Iris Feature Correlation Heatmap") # 상관계수 검정 cor.test(iris$Sepal.Length, iris$Petal.Length, method = "pearson") # 출력 결과 해석: # t = 21.646, df = 148, p-value < 2.2e-16 # 95% 신뢰구간 [0.827, 0.905] # 상관계수 0.872 → 강한 양의 상관관계 # 시각화 예제 str(airquality) head(airquality) # 분석대상 변수만 성택하고, na는 제거 # 데이터의 상관정도를 확인, 상관계수 행렬을 시각화 data <- airquality[, c("Ozone", "Solar.R", "Wind", "Temp")] data <- na.omit(data) cor(data) symnum(cor(data)) corrgram(data, upper.panel = panel.conf) chart.Correlation(data, histogram=T, pch="+") # 결측치 수 확인 sapply(airquality_1, function(x) sum(is.na(x))) airquality_cor <- cor(airquality_2) par(mfrow=c(1,1)) library(corrplot) plot(airquality_2) # ellipse, number, shade, pie corrplot(airquality_cor, method = "circle") corrplot(airquality_cor, method = "square") col <- colorRampPalette(c("darkblue", "white", "darkorange"))(20) col # 20개의 color로 heatmap heatmap(x=airquality_cor, col=col, symm = T) install.packages("psych") library(psych) pairs.panels(airquality_cor, bg=c("red","yellow","blue")[iris$Species], pch=21+as.numeric(iris$Species), main="Fisher Iris data by Species",hist.col = "red")

고유값 분해

# 임의의 상관계수 행렬 생성 d <- data.frame(x1=rnorm(10), x2=rnorm(10), x3=rnorm(10)) M <- cor(d) # 고유값 분해 eig_decomp <- eigen(M) # 고유벡터 직교성 확인 eig_decomp$vectors[,1] %*% eig_decomp$vectors[,2] # ≈ 0 eig_decomp$vectors[,1] %*% eig_decomp$vectors[,3] # ≈ 0 # 단위 벡터 확인 sqrt(sum(eig_decomp$vectors[,1]^2)) # = 1 # 데이터 적용 data(mtcars) mtcars_cor <- cor(mtcars) mtcars_eig <- eigen(mtcars_cor) # 고유값 분포 barplot(mtcars_eig$values, main = "Eigenvalues of mtcars Correlation Matrix", xlab = "Principal Components", ylab = "Eigenvalues")

범주형, 결측치, 이상치 제외 방법

# 범주형 데이터 제외 방법 : select_if(is.numeric) airquality_1 <- airquality %>% select_if(is.numeric) # 여기선 날짜도 숫자라 제외 안됨. 이럴 때는 airquality_1 <- airquality %>% select(-c(Month, Day)) airquality_1 <- airquality[, c(1:4)] # 결측치 제외 방법 airquality_2 <- na.omit(airquality_1) # 예제 library(dplyr) weather<-read.csv("weather.csv", header = T) length(weather) nrow(weather) str(weather) # 결측치 제거 weather <- na.omit(weather) # 범주형 제거 weather$key=1:nrow(weather) outdata=select_if(weather, is.numeric) str(weather) str(outdata) # 범주형 제외된 것 확인 # 이상치 제거 fivenum(outdata[,1]) # 1 최소값(Minimum) 2 1사분위수(Q1, 1st Quartile) 3 중위수(Median) 4 3사분위수(Q3, 3rd Quartile) 5 최대값(Maximum) library(dplyr) for(i in 1:(ncol(outdata)-1)){ uppercut <- fivenum(outdata[,i], na.rm = TRUE)[4] + 1.5 * IQR(outdata[,i]) lowercut <- fivenum(outdata[,i], na.rm = TRUE)[2] - 1.5 * IQR(outdata[,i]) outdata <- filter(outdata, outdata[,i] <= uppercut & outdata[,i] >= lowercut) } str(outdata) outdata <- as.data.frame(scale(outdata)) (res_cor<-cor(outdata)) (res_eig<-eigen(res_cor)) # eigen vector : 11by11 # eigen value : 11 names(res_eig) res_eig$values res_eig$vectors # 행렬곱을할 때 앞의 행렬의 열수와 뒤의 행렬의 행수가 일치해야한다. res_cor_inverse <- solve(res_cor) # 역행렬 res_cor_transpose<- t(res_cor) # 전치행렬 (identity_check <- round(res_cor%*%res_cor_inverse, 10)) # 단위행렬 (transpose_inverse_check <-all.equal(res_cor_transpose, res_cor_inverse)) cat("\n전치행렬이 역행렬과 동일한가?:", transpose_inverse_check, "\n") # Mean relative difference: 11.12394 다름 res_eig res_eig_inverse <- solve(res_eig$vectors) res_eig_transpose<- t(res_eig$vectors) (identity_check <- round(res_eig$vectors%*%res_eig_inverse, 10)) (transpose_inverse_check <-all.equal(res_eig_transpose, res_eig_inverse)) cat("\n전치행렬이 역행렬과 동일한가?:", transpose_inverse_check, "\n") # TRUE # 고유값 분해한 고유벡터만 전치행렬이 역행렬이다.

PCA (principle component analysis) : 주성분 분석

data(USArrests) str(USArrests) head(USArrests) pairs(USArrests, panel=panel.smooth, main="USArrests data") prcomp(USArrests) # 주성분 분석 # 주성분 (Pc1, pc2, pc3, pc4) 새로운 축 # 모든 변수가 모든 주성분에 영향을 미쳐서 새로운 축을 생성 prcomp(USArrests, scale=T) # 정규화 후 주성분 분석 prcomp(~ Murder + Assault + Rape, data=USArrests, scale=T) plot(prcomp(USArrests)) (fit<-prcomp(USArrests, scale. = T)) names(fit) # "sdev" 표준편차 "rotation" 주성분 로딩(loading) 행렬(각 원래 변수와 주성분 간의 관계를 나타내는 벡터) "center" 원래 데이터의 중심 "scale" 원래 데이터의 스케일링 값 "x" 원래 데이터의 주성분 점수 plot(fit, type="lines") # 분산크기값을 시각화 : 주성분을 선택하기 위해서 fit$sdev fit$center biplot(prcomp(USArrests, scale=T))

개체 분포 시각화

library(FactoMineR) library(factoextra) res.pca <- prcomp(iris[,-5], scale = TRUE) # 고유값 확인 get_eig(res.pca) # 개체 분포 시각화 fviz_pca_ind(res.pca, label = "none", habillage = iris$Species, addEllipses = TRUE)

회귀분석

data(mtcars) mtcars_pca <- prcomp(mtcars, scale = TRUE) # 회귀분석 적용 pca_data <- as.data.frame(mtcars_pca$x[,1:5]) model <- lm(mpg ~ ., data = cbind(mpg=mtcars$mpg, pca_data)) summary(model)$r.squared # 0.9997

요인분석(Factor Analysis)

library(psych) # 요인 부하량 확인 med.factor <- principal(med.data, nfactors=2, rotate="varimax") print(med.factor$loadings, cutoff=0.4) # 비직교 회전 적용 stats.fact <- factanal(med.data, factors=3, rotation="oblimin") print(stats.fact$loadings, cutoff=0.4)

다차원 척도법(MDS)

mydata <- mtcars[c(1,3,4,5,6,7)] d <- dist(mydata) # MDS 수행 fit <- cmdscale(d, eig=TRUE, k=2) # 시각화 plot(fit$points, main="Metric MDS", xlab="Dimension 1", ylab="Dimension 2") text(fit$points, labels=rownames(mydata), pos=3, cex=0.7)
기법장점단점적합 사례
PCA직관적 해석 가능선형 관계 가정변수 수 축소
요인분석잠재 변수 발견회전 방법 선택 필요심리측정 분석
MDS비수치적 데이터 처리 가능거리 계산 방법 영향브랜드 인지도 분석
This post is licensed under CC BY 4.0 by the author.