빅데이터분석기사 실기 학습자료 3과목 파트1 - 기술통계 정규성 검정 상관분석 실전

2026. 4. 28. 20:28ㆍ빅데이터분석기사

11111

 

 
[샘플데이터] 3유형 실습 데이터:
   id   salary   age   score   dept   gender
   1    4500.0   32    85.0     IT      M
   2    3800.0   45    72.0     HR      F
   3    5200.0   28    91.0  Finance    M
   4    3100.0   55    68.0   Sales     F
   5    8200.0   41    88.0     IT      M   ←
이상치 가능성
   (1000
행, 일부 결측 포함)

 

1. 작업형 3유형 개요

 
[기출패턴] 20점(2문제 × 10점). 가설 설정→검정→결론 순서 준수. 통계량과 p-value를 지정 자릿수로 print().

 

2. 가설검정 기본 원칙 (반드시 암기)

 
[핵심암기] 가설검정 핵심 원칙:
H0(
귀무가설): 차이/관계 없다 → 이것을 기각하거나 채택
H1(
대립가설): 차이/관계 있다 → 기각 실패 시 H0 채택

p ≤ 0.05  → H0
기각  → 유의한 차이/관계 있음 (★)
p > 0.05  → H0
채택  → 유의한 차이/관계 없음

α(유의수준) = 0.05 기본 사용. 문제에서 다른 값 명시 시 그 값 사용.
양측검정(two-sided): 크거나 작거나 모두 / 단측검정(one-sided): 방향 지정

 

3. 기술통계 완전 정복

3.1 수치형 기술통계

import pandas as pd, numpy as np
df = pd.read_csv("/data/data.csv")
 
# describe(): 수치형 열의 핵심 통계량 한번에 확인
print(df.describe())
 
# 특정 열 상세 통계
col = df['salary']
print(f"평균(mean)    : {col.mean():.4f}")       # 산술 평균
print(f"중앙값(median): {col.median():.4f}")     # 중간값 (이상치에 강건)
print(f"최빈값(mode)  : {col.mode()[0]:.4f}")    # 가장 많이 등장한 값 ★[0]필수
print(f"표준편차(std) : {col.std():.4f}")        # 퍼짐 정도
print(f"분산(var)     : {col.var():.4f}")        # 표준편차의 제곱
print(f"왜도(skew)    : {col.skew():.4f}")       # 분포 비대칭도 (+양수=오른쪽 꼬리)
print(f"첨도(kurtosis): {col.kurtosis():.4f}")   # 분포 뾰족함 (정규=0, 양수=뾰족)
print(f"Q1, Q3        : {col.quantile(0.25):.4f}, {col.quantile(0.75):.4f}")
────────────────────────────────────────────────────  실행 결과
         salary
count   1000.000
mean    4423.820    ← 평균
std      980.340    ← 표준편차
min     1800.000
25%     3750.000    ← Q1
50%     4380.000    ← 중앙값
75%     5050.000    ← Q3
max     8200.000
 
평균(mean)    : 4423.8200
중앙값(median): 4380.0000    ← 평균>중앙값 → 우측 꼬리 (양의 왜도)
최빈값(mode)  : 4200.0000
표준편차(std) : 980.3400
분산(var)     : 961066.5600
왜도(skew)    : 0.8234       ← 양수: 오른쪽에 긴 꼬리 (고소득자 소수 존재)
첨도(kurtosis): 0.4521       ← 정규분포(0)보다 약간 뾰족
Q1, Q3        : 3750.0000, 5050.0000

 

3.2 범주형 기술통계

import pandas as pd
df = pd.read_csv("/data/data.csv")
 
# value_counts(): 범주별 빈도
print(df['dept'].value_counts())
 
# normalize=True: 비율로 출력
print(df['dept'].value_counts(normalize=True).round(4))
 
# 교차표: 두 범주형 변수의 빈도
ct = pd.crosstab(df['dept'], df['gender'])
print(ct)
 
# margins=True: 행합/열합 추가
print(pd.crosstab(df['dept'], df['gender'], margins=True))
────────────────────────────────────────────────────  실행 결과
IT         320    ← 가장 많은 부서
HR         280
Finance    240
Sales      145
Other       15
Name: dept, dtype: int64
 
IT         0.3200    ← 32% 차지
HR         0.2800
Finance    0.2400
Sales      0.1450
Other      0.0150
 
gender     F    M
dept
Finance  112  128
HR       145  135
IT       158  162
Sales     72   73
 
gender  F    M  All
dept
Finance 112  128  240    ← 합계 포함
All     487  498  985

 

4. 정규성 검정 완전 정복

4.1 Shapiro-Wilk (n < 5000, 시험 표준)

 
[기출패턴] 기출: "데이터가 정규분포를 따르는지 Shapiro-Wilk 검정으로 확인하라"

 

from scipy import stats
import pandas as pd
 
df = pd.read_csv("/data/data.csv")
data = df['salary'].dropna()   # 결측값 반드시 제거 후 검정!
 
# H0: 데이터가 정규분포를 따른다
# H1: 데이터가 정규분포를 따르지 않는다
# W(통계량): 1에 가까울수록 정규분포에 가까움
stat, p = stats.shapiro(data)
print(f"Shapiro-Wilk W : {round(stat, 4)}")
print(f"p-value        : {round(p, 4)}")
 
if p > 0.05:
    print("→ 정규분포 O (p > 0.05, H0 채택) → 모수 검정 사용 가능")
else:
    print("→ 정규분포 X (p ≤ 0.05, H0 기각) → 비모수 검정 사용 권장")
────────────────────────────────────────────────────  실행 결과
Shapiro-Wilk W : 0.9812    ← 1에 가깝고 (정규에 가까움)
p-value        : 0.1423    ← 0.05보다 크므로
 
→ 정규분포 O (p > 0.05, H0 채택) → 모수 검정 사용 가능

 

4.2 기타 정규성 검정

from scipy import stats
import pandas as pd
 
df   = pd.read_csv("/data/data.csv")
data = df['salary'].dropna()
 
# Anderson-Darling: 모든 표본 크기에서 사용 가능
ad_result = stats.anderson(data, dist='norm')
print(f"Anderson-Darling 통계량: {round(ad_result.statistic, 4)}")
# critical_values[2] = 5% 유의수준 임계값 (인덱스 2)
print(f"5% 임계값: {ad_result.critical_values[2]:.4f}")
if ad_result.statistic < ad_result.critical_values[2]:
    print("→ 정규분포 O (통계량 < 임계값)")
else:
    print("→ 정규분포 X (통계량 ≥ 임계값)")
 
# Kolmogorov-Smirnov: n > 5000 대규모 데이터에서 사용
stat, p = stats.kstest(data, 'norm',
                       args=(data.mean(), data.std()))  # 평균, 표준편차 지정
print(f"
KS 통계량: {round(stat, 4)}, p={round(p, 4)}")
────────────────────────────────────────────────────  실행 결과
Anderson-Darling 통계량: 0.4823
5% 임계값: 0.7520
→ 정규분포 O (0.4823 < 0.7520)
 
KS 통계량: 0.0234, p=0.4821    ← p>0.05: 정규분포 O

 

4.3 정규성에 따른 검정 선택 기준

 
[핵심암기] 정규성 검정 → 검정 방법 선택:
┌──────────────┬────────────────────┬──────────────────────┐
│
상황         │ 정규 O (p>0.05)    │ 정규 X (p≤0.05)      │
├──────────────┼────────────────────┼──────────────────────┤
│
독립 2집단   │ 독립표본 t-검정   │ Mann-Whitney U       │
│
대응 2집단   │ 대응표본 t-검정   │ Wilcoxon 부호순위    │
│ 3
집단 이상   │ 일원 ANOVA        │ Kruskal-Wallis       │
│
단일표본     │ 단일표본 t-검정   │ Wilcoxon 부호검정    │
└──────────────┴────────────────────┴──────────────────────┘

 

5. 상관 分석 완전 정복

5.1 피어슨 상관계수 (수치형-수치형, 정규분포 가정)

 
[기출패턴] 기출: "두 변수 간 상관관계를 분석하고 상관계수와 p-value를 출력하라"

 

from scipy.stats import pearsonr
import pandas as pd
 
df = pd.read_csv("/data/data.csv")
x = df['age'].dropna().reset_index(drop=True)
y = df['salary'].dropna().reset_index(drop=True)
 
# 두 변수 길이 맞추기
n = min(len(x), len(y))
x, y = x[:n], y[:n]
 
# H0: 두 변수 간 선형 상관관계 없다 (r=0)
# H1: 두 변수 간 선형 상관관계 있다 (r≠0)
r, p = pearsonr(x, y)
print(f"피어슨 상관계수(r): {round(r, 4)}")   # -1~1: 부호=방향, 절대값=강도
print(f"p-value           : {round(p, 4)}")
 
# 강도 해석: |r| 0.1↑=약함, 0.3↑=보통, 0.5↑=강함, 0.7↑=매우강함
if abs(r) < 0.3:    strength = "약한"
elif abs(r) < 0.5:  strength = "보통의"
elif abs(r) < 0.7:  strength = "강한"
else:               strength = "매우 강한"
direction = "양" if r > 0 else "음"
 
print(f"→ {strength} {direction}의 상관관계")
print(f"→ 유의성: {'있음 (★)' if p<=0.05 else '없음'}")
────────────────────────────────────────────────────  실행 결과
피어슨 상관계수(r): 0.6234    ← 양수: 나이↑ → 급여↑ 경향
p-value           : 0.0000    ← 0.05보다 매우 작음
 
→ 강한 양의 상관관계     (|0.62| ≥ 0.5)
→ 유의성: 있음 (★)       (p < 0.05)

 

5.2 스피어만 & 켄달 상관계수 (비정규/순서형)

from scipy.stats import spearmanr, kendalltau
import pandas as pd
 
df = pd.read_csv("/data/data.csv")
x = df['age'].dropna().reset_index(drop=True)
y = df['score'].dropna().reset_index(drop=True)
n = min(len(x), len(y))
x, y = x[:n], y[:n]
 
# 스피어만: 순위(rank) 기반 상관계수 (비정규 데이터에도 사용 가능)
rho, p_s = spearmanr(x, y)
print(f"스피어만 rho: {round(rho, 4)}, p={round(p_s, 4)}")
 
# 켄달 타우: 소표본 또는 순서형 데이터에 적합
tau, p_k = kendalltau(x, y)
print(f"켄달 tau   : {round(tau, 4)}, p={round(p_k, 4)}")
 
# 전체 상관행렬 (수치형 열 전체)
corr_matrix = df[['age','salary','score']].corr()
print(f"
상관행렬(피어슨):
{corr_matrix.round(4)}")
────────────────────────────────────────────────────  실행 결과
스피어만 rho: 0.5823, p=0.0000    ← 비정규 데이터에서 피어슨 대신 사용
켄달 tau   : 0.4012, p=0.0000
 
상관행렬(피어슨):
           age   salary    score
age     1.0000   0.6234   0.3821
salary  0.6234   1.0000   0.4512
score   0.3821   0.4512   1.0000
  → age-salary 상관(0.62)이 가장 강함

 

5.3 상관분석 실전 패턴

import pandas as pd
from scipy.stats import pearsonr
 
df = pd.read_csv("/data/data.csv")
 
# 패턴1: 특정 변수와 가장 강한 상관관계인 변수 찾기
num_cols = df.select_dtypes(include='number').columns
corr = df[num_cols].corr()
# 자기 자신(대각선=1.0) 제외 후 최대값 위치
corr_no_diag = corr.where(~(corr == 1.0))
max_pair = corr_no_diag.stack().abs().idxmax()
print(f"가장 강한 상관 쌍: {max_pair}")
print(f"상관계수: {corr.loc[max_pair]:.4f}")
 
# 패턴2: target과의 상관계수 전체 (특성 선택에 활용)
target_corr = df[num_cols].corr()['salary'].drop('salary')
print(f"
salary와의 상관계수 (절대값 내림차순):")
print(target_corr.abs().sort_values(ascending=False).round(4))
────────────────────────────────────────────────────  실행 결과
가장 강한 상관 쌍: ('age', 'salary')
상관계수: 0.6234    ← age와 salary가 가장 강한 상관
 
salary와의 상관계수 (절대값 내림차순):
age       0.6234    ← 1위
score     0.4512
tenure    0.3821
id        0.0234    ← 거의 무관 (id는 의미 없는 상관)

 

2222