상관분석
import numpy as np; import pandas as pd
from sklearn.datasets import load_iris
iris = load_iris(as_frame=True).frame; df = iris
피어슨 / 스피어만 / 켄달 / 크레머 / 자기상관
| 기법 | 정의 | 특성 | 해석 및 범위 | 관계 강도 해석 (가이드라인) |
|---|---|---|---|---|
| Pearson | 두 연속형 변수 간의 선형적 관계 강도 / 방향 측정 | 모수적 방법. 정규성 가정 필요, 이상치에 민감함. | . 0은 선형 관계 없음. | : 약함 : 뚜렷함(중간) : 강함 |
| Spearman | 두 변수의 순위를 이용한 단조 관계 강도 측정 | 비모수적 방법. 서열 척도 사용 가능, 비선형 단조 관계 포착. | . +1 완벽 단조 증가, -1 완벽 단조 감소. | Pearson의 기준을 차용하여 동일하게 해석함 |
| Kendall | 순위 일치 쌍과 불일치 쌍의 비율 측정 | 비모수적 방법. 소표본 또는 동순위(Tie)가 많을 때 권장됨. | . 확률적 해석 용이. | Spearman보다 대개 낮은 값을 가짐 수준에서 유의미한 관계 검토 |
| Cramer’s V | 두 범주형(명목) 변수 간의 연관성 강도 측정 | 카이제곱 통계량 기반. 범주 개수가 달라도 비교 가능. | . 1에 가까울수록 강한 연관성. | : 작은 효과 : 중간 효과 이상: 큰 효과 (자유도에 따라 변동 가능) |
| Autocorrelation | 시차(Lag)를 가진 자기 자신과의 관련성 측정 | 시계열 분석 필수 지표. 정상성 및 계절성 파악에 사용. | . 시차 에 따른 상관성. | 신뢰구간(약 ) 초과 시 해당 시차에서 유의미한 상관성 존재 |
Kramer-V
- : 카이제곱 통계량
- : 전체 샘플 수
- : 열(column)의 개수
- : 행(row)의 개수
시계열 에서 시차 k에 대한 자기상관계수는 다음과 같이 정의된다:
# df = pd.DataFrame([[10, 20, 30],[20, 20, 20],[30, 20, 10]], columns=['x', 'y','z'])
# 입력 데이터 중 특정 변수의 모든 값이 동일하여 분산(Variance)이 0이기 때문에 발생한
# 계산 불능 상태를 의미한다.
# 상관계수(Pearson, Spearman 등)를 계산할 때는 분모에 각 변수의 표준편차(σ)가 들어간다.
# 하지만 y처럼 모든 값이 같으면 표준편차가 0이 되며, 수학적으로
# 0으로 나누기(Division by zero) 문제가 발생한다.
# petal length (cm) petal width (cm)
if 'np':
np.corrcoef(df['sepal length (cm)'], df['sepal width (cm)']) # 피어슨 상관계수
if 'pd':
df.corr() # 피어슨 상관계수
df.corr(method='spearman') # 스피어만
df.corr(method='kendall') # 켄달
# kramer
df['sepal length (cm)'].autocorr(lag=1) # 1시차 자기상관계수
if 'scipy':
import scipy.stats as stats
r, p_value = stats.pearsonr(df['sepal length (cm)'], df['sepal width (cm)'])
rs, p_value = stats.spearmanr(df['sepal length (cm)'], df['sepal width (cm)'])
tau, p_value = stats.kendalltau(df['sepal length (cm)'], df['sepal width (cm)'])
'''
chi2, p, dof, expected = stats.chi2_contingency(df)
n = np.sum(df); r=df.shape[0], k=df.shape[1]
V = np.sqrt((chi2/n) / np.min([r-1, k-1]))
'''
stats.contingency.association(df, method="cramer")
from statsmodels.tsa.stattools import acf
# 여러 시차에 대한 자기상관계수 계산, 최대 4시차까지의 자기상관계수
acf(df['sepal length (cm)'], nlags=4)
단순 / 편 / 중
| 분석 기법 | 관심 변수 | 제3의 변수 | 주요 지표 | 값의 범위 | 해석 목적 |
|---|---|---|---|---|---|
| 단순상관 (Simple) | 1대1 () | 전혀 고려하지 않음 | 두 변수 간의 직접적인 선형 연관성 파악 | ||
| 편상관 (Partial) | 1대1 () | 통제함 (영향력 제거, ) | 외부 요인을 배제한 두 변수 간의 순수한 연관성 파악 | ||
| 중상관 (Multiple) | 다대1 () | 독립변수로 함께 포함함 | 여러 요인이 결합하여 결과 변수에 미치는 전체 설명력 파악 |
단순상관분석 (Simple Correlation Analysis)
- 오직 두 변수 X와 Y 사이의 선형적 관계 방향과 강도만을 측정
- 다른 외부 변수의 개입을 전혀 고려하지 않음
- 제3의 요인에 의한 ‘허위 상관(Spurious Correlation)‘을 진짜 관계로 오인할 위험
편상관분석
-
다변량 데이터 상황
-
두 변수 간의 상관관계에서 다른 변수들의 영향을 제거한 상관관계 분석
-
순수한 상관관계를 도출
-
분석 결과 해석
- 편상관계수가 0.5 이상일 때 강한 관계로 해석
- 신뢰 구간이 좁을수록 결과의 신뢰도 높음
| 구분 | 단순 상관분석 (Simple Correlation) | 편상관분석 (Partial Correlation) |
|---|---|---|
| 통제 변수 | 없음 | 하나 이상의 제3의 변수()를 고정 |
| 상관계수 의미 | 전체적인 선형 연관성 | 제3의 변수를 제외한 순수한 직접적 연관성 |
| 수학적 원리 | 공분산 기반 | 통제 변수에 대한 잔차(Residuals) 간의 상관계수 |
import pingouin as pg
import statsmodels.api as sm
macrodata = sm.datasets.macrodata.load_pandas().data
df = macrodata[['realgdp', 'realcons', 'realinv', 'realgovt']]
# =================================================================
#
# =================================================================
if 'pg.pairwise_corr':
# pg.compute_bootci(
# df[['realgdp', 'realcons', 'realinv', 'realgovt']], func=pg.partial_corr, n_boot=1000
# )
None
if '단순 상관관계 행렬 계산 (다변량 데이터)':
display(pg.pairwise_corr(data=df))
if '편상관관계 계산 (다변량 데이터)':
df.pcorr()
if '편상관관계 계산 (X와 Y 사이에서 Z,w의 영향을 제거)':
display(pg.partial_corr(data=df, x='realgdp', y='realcons', covar=['제외하려는변수']))
# display(pg.partial_corr(data=df, x='realgdp', y='realcons', covar=['realinv','realgovt']))
# pg.partial_corr(
# data=df, x='realgdp', y='realcons', covar=['realinv', 'realgovt'], method='spearman'
# )
if '편상관관계 계산의 CI':
# 신뢰구간 계산. 편상관계수의 신뢰구간을 계산하여 결과에 대한 불확실성을 평가할 수 있다.
print(pg.partial_corr(
data=df, x='realgdp', y='realcons', covar=['realinv','realgovt']
)['CI95%'])
| X | Y | method | tail | n | r | CI95% | r2 | adj_r2 | z | p-unc | BF10 | power | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | realgdp | realcons | pearson | two-sided | 203 | 0.999229 | [1.0, 1.0] | 0.998459 | 0.998443 | 3.930376 | 1.344198e-284 | 5.794e+278 | 1.0 |
| 1 | realgdp | realinv | pearson | two-sided | 203 | 0.977708 | [0.97, 0.98] | 0.955913 | 0.955472 | 2.242735 | 3.255579e-138 | 6.986e+133 | 1.0 |
| 2 | realgdp | realgovt | pearson | two-sided | 203 | 0.868651 | [0.83, 0.9] | 0.754554 | 0.752100 | 1.327557 | 3.167737e-63 | 4.472e+59 | 1.0 |
| 3 | realcons | realinv | pearson | two-sided | 203 | 0.976290 | [0.97, 0.98] | 0.953142 | 0.952674 | 2.211542 | 1.491275e-135 | 1.623e+131 | 1.0 |
| 4 | realcons | realgovt | pearson | two-sided | 203 | 0.870713 | [0.83, 0.9] | 0.758140 | 0.755722 | 1.336018 | 7.200745e-64 | 1.934e+60 | 1.0 |
| 5 | realinv | realgovt | pearson | two-sided | 203 | 0.794797 | [0.74, 0.84] | 0.631702 | 0.628019 | 1.084324 | 1.783585e-45 | 1.297e+42 | 1.0 |
| n | r | CI95% | r2 | adj_r2 | p-val | BF10 | power | |
|---|---|---|---|---|---|---|---|---|
| pearson | 203 | 0.965811 | [0.96, 0.97] | 0.93279 | 0.932118 | 8.350263e-120 | 4.201e+115 | 1.0 |
pearson [0.96, 0.97]
Name: CI95%, dtype: object
- 신뢰구간(CI, Confidence Interval) 95%가 [0.96, 0.97]로 산출되었다
- 실제 편상관계수(모편상관계수)가 0.96에서 0.97 사이에 존재한다고 95% 확신할 수 있다
- GDP와 소비 사이에 매우 강력한 양(+)의 선형 관계가 존재함
- 신뢰구간이 0을 포함하지 않고 양(+)의 구간에만 매우 좁게 형성되어 있다.
- 따라서 이 편상관관계는 우연에 의한 것이 아니며, 통계적으로 매우 유의미하다.
- 별도의 p-value를 확인하지 않아도 귀무가설(편상관계수가 0이다)이 기각됨을 알 수 있다.
중상관분석
-
다변량 데이터 상황
-
하나의 종속변수 와, 두 개 이상의 독립변수 그룹() 이 맺고 있는 전체적인 상관관계의 강도를 측정
-
다중회귀분석(Multiple Regression)의 결과와 직결
-
변수 그룹 전체가 Y를 얼마나 잘 설명하는지 확인하는 목적
- 따라서 방향성 (음/양)의 개념이 없음
- 항상 양수
- 이를 제곱하면 회귀모델의 설명력을 나타내는 결정계수 ()
일반화된 중상관계수 (결정계수 기반)
- 독립변수가 3개 이상으로 늘어나면 위 1번 공식이 행렬을 써야 할 만큼 매우 복잡
- 따라서 실제 분석 환경에서는 다중회귀모델을 만들고,
- 모델의 총제곱합(SST)과 회귀제곱합(SSR) 또는 오차제곱합(SSE)을 이용해 계산하는 것이 일반적
import pingouin as pg
import statsmodels.api as sm
macrodata = sm.datasets.macrodata.load_pandas().data
df = macrodata[['realgdp', 'realcons', 'realinv', 'realgovt']]
# =====================================================================
#
# =====================================================================
if 'sklearn':
from sklearn.linear_model import LinearRegression
X = df[['realcons', 'realinv', 'realgovt']]
y = df['realgdp']
# sm.add_constant(X) # (scikit-learn은 상수항 자동처리)
model = LinearRegression() # OLS(최소제곱법) 모델 적합
model.fit(X, y) # <<<<<<<<<<<<<<<<<<<<<<<<<<<< X,y
# 3. R^2 스코어 계산 및 중상관계수 도출
r_squared = model.score(X, y)
multiple_r = np.sqrt(r_squared)
print(f"결정계수 (R-squared): {r_squared:.4f}")
print(f"중상관계수 (Multiple R): {multiple_r:.4f}")
if 'statsmodels':
# import statsmodels.api as sm
X = df[['realcons', 'realinv', 'realgovt']]
y = df['realgdp']
X = sm.add_constant(X) # statsmodels는 상수항(Intercept) 수동 추가 필요
model = sm.OLS(y, X).fit() # OLS(최소제곱법) 모델 적합 <<<<<<<<<<<<<<<<<<<<<<<<<<<< y,X
# print(model.summary())
r_squared = model.rsquared
multiple_r = np.sqrt(r_squared)
print(f"결정계수 (R-squared): {r_squared:.4f}")
print(f"중상관계수 (Multiple R): {multiple_r:.4f}")무상관검정 (상관계수 검정)
상관계수의 유의성을 판단
표본 상관계수(r)와 표본의 크기(n)를 이용하여 t-통계량 (피어슨 상관계수의 검정통계량) 을 계산.
- 이 통계량은 자유도가 n−2인 t-분포를 따름.
가설검정:
- 귀무가설 (): (모집단에서 두 변수 간에 상관관계가 없다.)
- 대립가설 (): (모집단에서 두 변수 간에 상관관계가 존재한다.)
scipy.stats.pearsonr()이나 pingouin.corr() 에서 반환되는 p-value가 바로 이 무상관검정의 결과
- 별도의 복잡한 검정 코드를 짤 필요 없음
- 상관분석 함수가 뱉어내는 p값만 보고 0.05보다 작은지 큰지만 판별