데이터분석 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