상관분석

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%'])
 
XYmethodtailnrCI95%r2adj_r2zp-uncBF10power
0realgdprealconspearsontwo-sided2030.999229[1.0, 1.0]0.9984590.9984433.9303761.344198e-2845.794e+2781.0
1realgdprealinvpearsontwo-sided2030.977708[0.97, 0.98]0.9559130.9554722.2427353.255579e-1386.986e+1331.0
2realgdprealgovtpearsontwo-sided2030.868651[0.83, 0.9]0.7545540.7521001.3275573.167737e-634.472e+591.0
3realconsrealinvpearsontwo-sided2030.976290[0.97, 0.98]0.9531420.9526742.2115421.491275e-1351.623e+1311.0
4realconsrealgovtpearsontwo-sided2030.870713[0.83, 0.9]0.7581400.7557221.3360187.200745e-641.934e+601.0
5realinvrealgovtpearsontwo-sided2030.794797[0.74, 0.84]0.6317020.6280191.0843241.783585e-451.297e+421.0
nrCI95%r2adj_r2p-valBF10power
pearson2030.965811[0.96, 0.97]0.932790.9321188.350263e-1204.201e+1151.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보다 작은지 큰지만 판별