Zero부터 시작하는 상관관계

이현준·2025년 12월 22일

정리노트

목록 보기
4/4
post-thumbnail

🎯 상관 관계


분석 대상상황추천 도구
연속 vs 연속일반적인 선형 관계Pearson
이상치 많음 / 순위 데이터Spearman / Kendall
비선형 (곡선, 원형 등)MIC / Distance Corr
범주 vs 연속2개 집단 평균 비교T-test / Point-biserial
3개 이상 집단 평균 비교ANOVA / Correlation Ratio
범주 vs 범주독립성 확인 및 관계 강도Chi-square / Cramer's V
시간 데이터시차가 존재하는 관계Cross-Correlation
변수 통제제3의 변수 영향 제거Partial Correlation

▶️ Pearson, Spearman, Kendall


df.corr(method='pearson') # pearson / spearman / kendall

# 1. 피어슨 (Pearson) - 선형 관계
r, p_value = stats.pearsonr(x, y)

# 2. 스피어만 (Spearman) - 순위 기반, 단조 관계
from scipy import stats
r, p_value = stats.spearmanr(x, y)

# 3. 켄달 (Kendall) - 순위 기반, 일치 쌍(Concordant pairs) 기준
from scipy import stats
tau, p_value = stats.kendalltau(x, y)
상관계수( r )해석 (통계적 강도)
0.0 ~ 0.1거의 없음
0.1 ~ 0.3약한 상관관계
0.3 ~ 0.5중간 상관관계
0.5 ~ 0.7강한 상관관계
0.7 ~ 1.0매우 강한 상관관계

켄달 지수(tau)해석
0.0 ~ 0.2매우 낮음
0.2 ~ 0.4낮음 ~ 보통
0.4 ~ 0.6꽤 높음 (중요한 관계)
0.6 이상매우 높음

▶️ MIC


from sklearn.feature_selection import mutual_info_regression
# sklearn은 x를 2차원 배열로 기대하므로 .reshape(-1, 1)이 필요합니다.
mi_score = mutual_info_regression(x.reshape(-1, 1), y)[0]
점수해석
0.0관계 없음
0.1 ~ 0.5약한 관계
0.5 ~ 1.0뚜렷한 관계
1.0 이상매우 강력한 관계
# 0과 1사이의 값으로 바꾸기
import numpy as np
from sklearn.feature_selection import mutual_info_regression

def simple_mic_alternative(x, y):
    # x를 2차원 배열로 변환
    x_2d = np.array(x).reshape(-1, 1)
    # 상호 정보량 계산
    mi = mutual_info_regression(x_2d, y)[0]
    
    # 0~1 사이로 정규화 (보통 2.0 이상의 높은 점수를 1.0에 가깝게 변환)
    # 실제 분석에서는 mi 값 그 자체를 순위 매기기에 더 많이 씁니다.
    normalized_mi = 1 - np.exp(-mi) 
    return normalized_mi

score = simple_mic_alternative(x, y)
print(f"정규화된 MI 점수 (MIC 대안): {score:.4f}")

▶️ distance_correlation


# 참고 : ㅈㄴ 오래걸림
import dcor
d_corr = dcor.distance_correlation(x, y)
점수해석
0.0완벽한 독립
0.1 ~ 0.2매우 약한 관계
0.2 ~ 0.5중간 정도의 관계
0.5 ~ 0.8강한 상관관계
0.8 ~ 1.0매우 강력한 관계

▶️ T-test


T-test를 하기전에 만족시킬 조건

  1. 정규성 검정
  2. 등분산성 검정
  3. 알맞는 T-test 진행

1. 정규성 검정

from scipy import stats

W1, p_norm_a = stats.shapiro(group_a)
W2, p_norm_b = stats.shapiro(group_b)
# 통계량(W): 데이터가 얼마나 정규분포에 가까운지를 나타내는 수치입니다. (0~1 사이)
# p-value: 이 통계량이 우연히 나왔을 확률입니다.

2. 등분산성 검정

from scipy import stats

statistic, p_value = stats.levene(group_a, group_b)

# statistic (레빈 통계량): 계산된 F-값(F-statistic)입니다. 두 집단의 분산(데이터가 퍼진 정도)이 얼마나 차이가 나는지를 하나의 숫자로 요약
# p-value: 이 통계량이 우연히 나왔을 확률입니다.

3. 알맞는 T-test 진행

from scipy import stats

# 1. 정규성 O, 등분산성 O
result = stats.ttest_ind(group_a, group_b, equal_var=True)

# 2. 정규성 O, 등분산성 X
result = stats.ttest_ind(group_a, group_b, equal_var=False)

# 3. 정규성 X (비모수 검정)
result = stats.mannwhitneyu(group_a, group_b)

▶️ pointbiserialr


from scipy import stats
r, p_value = stats.pointbiserialr(x, y)

# x: 이분형(0 또는 1) 데이터를 담은 배열 또는 리스트.
# y: 연속형 데이터를 담은 배열 또는 리스트.
# r: 점이분 상관계수 (Point-biserial correlation coefficient)
# p_value: 통계적 유의미성을 나타내는 p-값

▶️ ANOVA


# ANOVA 검정
from scipy import stats
f_stat, p_value = stats.f_oneway(group_A, group_B, group_C)

print(f"F-통계량: {f_stat:.4f}")
print(f"p-value: {p_value:.4f}")

# 실제 사용에시

# 책의 종류별 가격으로 그룹을 분리
groups = [df['price'][df['book'] == category] for category in df['book'].unique()]

anova_result = stats.f_oneway(*groups)
# anova_result = stats.f_oneway(groups[0],groups[1],groups[2])
print(f"ANOVA 검정 결과: F={anova_result.statistic:.4f}, p-value={anova_result.pvalue:.4f}")

▶️ Cramer' V


# Cramer' V
# 범주형 변수가 3 개 이상인 경우 크래머 V계수(Cramer's V) 사용
from scipy.stats.contingency import association
from sklearn import preprocessing
from scipy.stats import chi2_contingency

# step 01. label encoding (인코딩은 필요한 경우)
base_df = df[binary_variable]
base_df = base_df.dropna()

label = preprocessing.LabelEncoder()
data_encoded = pd.DataFrame() 

for i in base_df.columns :
      data_encoded[i]=label.fit_transform(base_df[i])

# step 02.함수 정의 및 혼동행렬 생성

def cramers_V(var1,var2) :
    crosstab =np.array(pd.crosstab(var1,var2, rownames=None, colnames=None)) # Cross table building
    stat = chi2_contingency(crosstab)[0] # Keeping of the test statistic of the Chi2 test
    obs = np.sum(crosstab) # Number of observations
    phi2 = stat / obs
    r, k = crosstab.shape
    phi2corr = max(0, phi2 - (((k-1)*(r-1))/(obs - 1)))
    rcorr = r - ((r-1)**2)/(obs-1)
    kcorr = k - ((k-1)**2)/(obs-1)
    return np.sqrt(phi2corr / min((kcorr-1), (rcorr-1)))

rows= []

# 데이터 보기 쉽게 바꾸기
for var1 in data_encoded:
    col = []
    for var2 in data_encoded :
        cramers =cramers_V(data_encoded[var1], data_encoded[var2]) # Cramer's V test
        col.append(round(cramers,2)) # Keeping of the rounded value of the Cramer's V  
    rows.append(col)
cramers_results = np.array(rows)
data_encoded_df = pd.DataFrame(cramers_results, columns = data_encoded.columns, index =data_encoded.columns)

data_encoded_df


▶️ Chi-square


# 카이제곱 검정 

from scipy import stats

contingency_table = pd.crosstab(df[컬럼명1], df[컬럼명2])
chi2, p, dof, expected = stats.chi2_contingency(contingency_table)

# "두 범주형 변수가 서로 관계가 있는가, 아니면 독립적인가?"를 판단할 때 사용합니다.

# 실제 분석에서는 아래와 같이 교차표(Contingency Table)를 먼저 만듭니다.

# chi2: 카이제곱 통계량
# p: p-value
# dof: 자유도 (Degrees of Freedom)
# expected: 기대 빈도 (Expected Frequencies)
p-value해석
p<0.05p < 0.05우연이 아니다. 둘은 관계가 있다
p>=0.05p >= 0.05유의미하지 않음
profile
Re: 제로부터 시작하는 데이터분석

0개의 댓글