데이터분석 6기/본캠프

2025-04-16 통계 총 정리

seyeon1130 2025. 4. 16. 21:19

데이터
├── 수치형 
│   ├── 연속형 (소수점으로 나눠지는 거)
│   └── 이산형 (정수형)
└── 범주형 
    ├── 명목형 (순서없음)
    ├── 서열형 (순서 있음)
    └── (이분형 - Binary, 보통 명목형에 포함)

 

 

독립변수, 종속변수가 모두 연속형일 때, 두 변수의 상관관계

 

 

 

 

정규분포인지 확인하기

 

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from scipy import stats

# 예시용 데이터 (원래 분석 중인 data 쓰면 됨)
data = np.random.normal(170, 10, size=1000)

# 히스토그램 
sns.histplot(data, stat='density', color='skyblue')  # stat='density'로 맞춰줘야 정규분포랑 비교 가능

# 정규분포 곡선 추가
mean = np.mean(data)
std = np.std(data)

xmin, xmax = plt.xlim() #x최소 최댓값 가져오기
x = np.linspace(xmin, xmax, 100) #두 숫자 사이를 균등한 간격으로 나눈 숫자들을 만들어주는 함수
p = stats.norm.pdf(x, mean, std) # y값 생성

plt.plot(x, p, 'r', linewidth=2, label='Normal Distribution Curve')  # r = 빨간 선
plt.title('normal distribution histogram')
plt.legend()
plt.show()

 

 

 

 

CASE 1. 두 변수 모두 정규분포를 따를때

 

 

피어슨 상관계수 사용

from scipy.stats import pearsonr
from scipy.stats import spearmanr, kendalltau

#피어슨
pearson_corr, p = pearsonr(df['Study Hours'], df['Exam Scores'])
print(f"피어슨 상관계수: {pearson_corr}")
print(f'p-value:{p}')

# 피어슨 상관관계 히트맵 시각화
sns.heatmap(df[['Study Hours', 'Exam Scores']].corr(), annot=True, cmap='coolwarm', vmin=-1, vmax=1)

 

 

CASE 2.  두 변수 중 하나라도 정규분포를 따르지 않을 때

 

스피어만 상관계수 사용

범주형이어도 순서형이라면 사용 가능!

from scipy.stats import spearmanr, kendalltau

spearman_corr, p = spearmanr(df['Customer Satisfaction'], df['Repurchase Intent'])
print(f"스피어만 상관계수: {spearman_corr}")
print(f'p-value : {p}')

sns.heatmap(df[['Customer Satisfaction', 'Repurchase Intent']].corr(method='spearman'), annot=True, cmap='YlGnBu', vmin=-1, vmax=1)

 

 

켄달의 타우 사용

# 켄달의 타우 상관계수 계산
kendall_corr, _ = kendalltau(df['Customer Satisfaction'], df['Repurchase Intent'])
print(f"켄달의 타우 상관계수: {kendall_corr}")

 

 

 

 

이분형 독립변수에 따른 연속형 변수의 차이를 알고 싶을 때

 

예) 성별에 따른 점수 차이 -> 각 성적(연속형)의 차이를 비교

예) 두 그룹의 평균 비교

 

CASE 1. 모집단의 표준편차를 모르고 표본의 크기가 작을 때

 

T검정 사용

(대부분 모집단의 표준편차를 알 수 없으므로 T검정을 사용)

import scipy.stats as stats  # scipy.stats 모듈 임포트

# 예시 데이터
# f_df와 m_df는 각각 두 그룹에 해당하는 데이터 (예: 여성과 남성 그룹)
t, pvalue = stats.ttest_ind(f_df, m_df)  # 두 그룹 간 평균 차이에 대한 t검정 수행

print(f"t값: {t}")
print(f"p값: {pvalue}")

 

  • t값의 부호는 어느 집단의 평균이 더 높은지에 대한 방향성에 대한 내용이므로, 아래와 같이 해석해주세요.
    • t > 0: 첫 번째 그룹 평균이 더 큼
    • t < 0: 두 번째 그룹 평균이 더 큼

 

CASE 2. 모집단의 표준편차를 알고 표본의 크기가 클 때

 

Z검정 사용

from statsmodels.stats.weightstats import ztest

z_stat, p_value = ztest(data1, data2)

print(f"z값: {z_stat}")
print(f"p값: {p_value}")

 

+ 특정 집단의 평균을 예측 할 때

z_stat , pvalue = ztest(df['review'], value = 3.0)

 

 

독립변수가 명목형 범주형(그룹이 3개 이상), 종속변수가 연속형 일 때

 

예) 반 별 성적 비교

대신 순서형은 안됨! ->스피어만 사용하기

 

그룹은 몇 개든 제한이 없음, 따라서 혈액형별이든 뭐든 옷 종류별로도 가능

ANOVA 사용

import pandas as pd
import scipy.stats as stats

# 각 반별 성적을 추출
a_scores = df[df['반'] == 'A']['성적']
b_scores = df[df['반'] == 'B']['성적']
c_scores = df[df['반'] == 'C']['성적']

# 아노바 수행
f_stat, p_value = stats.f_oneway(a_scores, b_scores, c_scores)

print(f"F-값: {f_stat}")
print(f"P-값: {p_value}")

 

만약 F값이 높고 P가 0.05 이하면 반별로 성적이 다르다! 라고 결론 맺을 수 있다.

 

독립변수와 종속변수가 범주형(이분형이든 세 개 이상이든)일 때

 

둘이 연관성이 있냐 없냐만 판단하려면

 

카이제곱 검정

import pandas as pd
from scipy.stats import chi2_contingency

result = pd.crosstab(df['Gender'], df['Subscription Status'])

chi2, p, dof, expected = chi2_contingency(result)
print(f"카이제곱 통계량: {chi2:.3f}, p-value값: {p:.3f}, 자유도: {dof}")

 

여기서는 카이제곱 통계량이 의미 없음.

P-value가 0.05 이상이면 독립적. 즉, 두 변수 연관 없음

 

 

 

그 연관이 얼마나 연관이 있냐

 

크래머's V

def cramers_v(x, y):
    confusion_matrix = pd.crosstab(x, y)
    chi2, p, dof, expected = chi2_contingency(confusion_matrix)
    n = confusion_matrix.sum().sum()
    phi2 = chi2 / n
    r, k = confusion_matrix.shape
    phi2corr = max(0, phi2 - ((k-1)*(r-1))/(n-1))  # Bias correction
    rcorr = r - ((r-1)**2)/(n-1)
    kcorr = k - ((k-1)**2)/(n-1)
    return np.sqrt(phi2corr / min((kcorr-1), (rcorr-1)))
    
    # 범주형과 범주형 - Carmer's V
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from scipy.stats import chi2_contingency

cat_features = ['yr','mnth','weekday','holiday','season','workingday','weathersit','hr']
# 모든 변수 쌍에 대해 Cramér's V 계산
cramer_matrix = pd.DataFrame(index=cat_features, columns=cat_features)

for col1 in cat_features:
    for col2 in cat_features:
        if col1 == col2:
            cramer_matrix.loc[col1, col2] = 1.0
        else:
            cramer_matrix.loc[col1, col2] = cramers_v(df[col1], df[col2])

cramer_matrix = cramer_matrix.astype(float)

# 히트맵 그리기
plt.figure(figsize=(8, 6))
sns.heatmap(cramer_matrix, annot=True, cmap="YlOrRd", vmin=0, vmax=1)
plt.title("Cramér's V Heatmap (Categorical Correlations)")
plt.tight_layout()
plt.show()

 

 

 

 

 


+ 시각화 한 번에 보여주는 코드

cat_features = ['yr','mnth','weekday','holiday','season','workingday','weathersit','hr']
fig, axs = plt.subplots(figsize= (25,8), ncols=4, nrows=2)

for i, feature in enumerate(cat_features):
    row = i//4
    col = i%4
    sns.barplot(x=feature, y='cnt',data=df,ax=axs[row][col])

 

+z스코어 이상치 찾기

def z_score_outliers(data, threshold=3
    mean = np.mean(data)
    std = np.std(data)
    z_scores = (data - mean) / std
    outliers = data[np.abs(z_scores) > threshold]
    return outliers