데이터 통계 분석 정리

TaeHyun·2026년 2월 14일

TIL

목록 보기
156/186

시작하며

오늘은 그동안 배웠던 내용들을 정리하면서 데이터 통계 분석을 할 때 나만의 워크플로우를 만들어봤다.

📊 데이터 통계 분석 워크플로우

전체 흐름

1단계 : 척도 파악 → 2단계 : 탐색적 데이터 분석(EDA) → 3단계 : 분석 방법 선택 → 4단계 : 귀무가설 및 사후 검정

사용 라이브러리 정리

import os, hds
import numpy as np
import pandas as pd
from plt_rcs import *
from scipy import stats
import pingouin as pg
import scikit_posthocs as sp
  • os : 데이터 파일 경로 제어
  • hds : 데이터 시각화 및 통계분석
  • numpy pandas : 데이터 분석
  • plt_rcs : matplotlib seaborn 기본 설정 모듈
    • plt_rcs.py
      import seaborn as sns
      import matplotlib.pyplot as plt
      
      plt.rc(group='font', family='Gowun Batang', size=10)
      plt.rc(group='figure', figsize=(8, 4), dpi=120)
      plt.rc(group='axes', unicode_minus=False)
      plt.rc(group='legend', frameon=True, fc='0.9', ec='0.9')
  • scipy : 기본적인 통계 공식
  • pingouin : scipy 보다 사용하기 편한 통계 라이브러리
  • scikit_posthocs : 사후 분석 라이브러리

1단계 : 척도 파악

데이터 척도 분류

척도설명예시판별법
명목순서가 없는 범주형 데이터성별, 혈액형, 지역순서 의미 없음
서열순서가 있는 범주형 데이터학접(A/B/C), 만족도(상/중/하)순서 있으나 간격 불균등
등간균동 간격, 절대 0 없음온도, 연도0이 “없음”이 아님
비율균등 간격, 절대 0 있음나이, 소득, 무게0 = 실제로 없음
  • 범주형 = 명목 + 서열
  • 연속형 = 등간 + 비울

데이터 척도 파악

  • info() 를 통해 데이터와 Dtype확인
    • 실제 데이터와 Dtype이 다르면 astype() 으로 변환
    • 자료형 변환 및 구간화 예시
      • 자료형 변환
        • 하나의 컬럼에 대해 변경

          df['가격'] = df['가격'].astype(int)
        • 여러개의 컬럼 한번에 변경

          apt = apt.astype(dtype={
              '계약년도': int,
              '계약월': int,
              '계약일': int
          })
          cols = ['계약년도', '계약월', '계약일']
          apt[cols] = apt[cols].astype(str)
      • 구간화
        • np.where() np.select() pd.cut() pd.qcut() 등 사용해서 구간화 진행

          cond = apt['경과년수'].ge(30)
          apt['재건축'] = np.where(cond, '충족', '부족')
          apt['재건축']
          # 0         부족
          # 1         부족
          # 2         충족
          # 3         부족
          # 4         충족
          #           ..
          # 231899    부족
          # 231900    부족
          # 231901    부족
          # 231902    부족
          # 231903    부족
          # Name: 재건축, Length: 231904, dtype: object
          np.select(
              condlist=[
                  apt['경과년수'].le(5),
                  apt['경과년수'].le(10),
                  apt['경과년수'].gt(10)
              ],
              choicelist=['신축', '준신축', '구축'],
              default='0'
          )
          pd.cut(
              x=apt['경과년수'],
              bins=[-2, 5, 10, 62],
              labels=['신축', '준신축', '구축']
          )
          pd.qcut(
              x=apt['경과년수'],
              q=3,
              labels=['신축', '준신축', '구축']
          )
  • describe()columns 확인
    • 소수점이 너무 길면 describe().round(n)
    • mean - median 확인
    • min - max 확인
    • 25% - median - 75% 확인
  • 무게, 길이 등 단위 통일 확인
  • unique() 로 고유값 개수 확인

2단계 : 탐색적 데이터 분석(EDA)

일변량 분석

데이터 타입확인 함수그래프목적
범주형value_counts()hds.plot.bar_freq()빈도 비교
연속형describe() agg()histplot()
kdeplot() + axvline()분포 형태 확인
연속형mean() median()kdeplot() + axvline()밀도 곡선 + 평균/중앙값
연속형quantile()boxplot()이상치 확인
연속형skew() kurtosis()-정규성 확인
  • 일변량 분석 시각화 예시
    • 막대 그래프
      • hds.plot.bar_freq()

        hds.plot.bar_freq(
            data=df, x='admit', palette=['skyblue', 'orange']
        )
    • 히스토그램
      • histplot()

        sns.histplot(
            df, x='Price', binrange=[4000, 16000],
            binwidth=1000, facecolor='0.8'
        )
        plt.show()
    • 박스 플롯
      • boxplot()

        sns.boxplot(
            data=apt,
            y='거래금액',
            color='0.8',
            linewidth=0.5
        )
        plt.show()
    • 밀도 그래프
      • kdeplot() + axvline()

        sns.kdeplot(
            df, x='Price',
            fill=True, color='0.8'
        )
        plt.axvline(df['Price'].mean())
        plt.axvline(df['Price'].median(), color='red', linestyle='--')
        plt.show()

이변량 분석

데이터 타입확인 함수그래프목적
범주 vs 범주crosstab()hds.plot.bar_freq()범주별 비교
범주 vs 범주crosstab()hds.plot.bar_dodge_freq() hds.plot.bar_stack_freq()
hds.plot.bar_stack_prop()범주 그룹별 비교
범주 vs 연속groupby() pivot_table()hds.plot.box_group()그룹별 분포 비교
연속 vs 연속corr()regplot() hds.plot.regline()
scatterplot()관계 파악
(산점도 + 회귀선)
  • 이변량 분석 시각화 예시
    • 막대 그래프
      • hds.plot.bar_freq()

        hds.plot.bar_freq(
            data=df, x='admit', palette=['skyblue', 'orange']
        )
      • hds.plot.bar_dodge_freq()

        hds.plot.bar_dodge_freq(
            data=df, x='rank', g='admit',
            palette=['skyblue', 'orange']
        )
      • hds.plot.bar_stack_freq()

        hds.plot.bar_stack_freq(
            data=df, x='rank', g='admit',
            palette=['skyblue', 'orange']
        )
      • hds.plot.bar_stack_prop()

        hds.plot.bar_stack_prop(
            data=df, x='rank', g='admit',
            palette=['skyblue', 'orange']
        )
    • 박스 플롯
      • hds.plot.box_group()

        hds.plot.box_group(
            data=df, x='admit', y='gre',
            palette=['skyblue', 'orange']
        )
    • 산점도+회귀선
      • scatterplot() + regplot()

        plt.figure(figsize=(4, 4))
        sns.regplot(
            data=df, x='Age', y='Price', ci=None,
            scatter_kws={'color': '0.8', 's': 10, 'ec': '0.8'},
            line_kws={'color': 'red', 'lw': 1.5}
        )
        sns.scatterplot(
            data=df.loc[out_index, :], x='Age', y='Price',
            fc='red', ec='red', s=20, label='Outlier'
        )
        plt.legend()
        plt.show()
      • hds.plot.regline()

        hds.plot.regline(
            df, x='Age', y='Price'
        )

상관관계 분석

  • df.corr(numeric_only=True) : 상관계수 행렬
  • hds.plot.corr_heatmap() : 전체 상관행렬 확인
    • 타겟 변수와 상관계수가 높은 변수 확인
    • 변수간 다중공선성 여부 확인
  • 상관관계 시각화 예시
    hds.plot.corr_heatmap(df)
    corr = df.corr(numeric_only=True)
    sns.heatmap(
        corr, annot=True, fmt='.2f',
        annot_kws={'size': 8},
        cmap='RdYlBu', linewidths=1
    )
    plt.show()
  • 분석 코드 예시
    • agg() 사용해서 여러 집계 함수 한번에 사용

      apt['거래금액'].agg(func=['count', 'sum', 'mean', 'std'])
    • value_counts() 상대도수 확인

      df['rank'].value_counts(normalize=True).sort_index()
    • describe() 범주형 조회

      df.describe(include=object)

타겟 변수에 대한 영향 탐색

  • 연속형 : 히트맵 + 산점도 사용
  • 범주형 : 박스플롯 사용

##3단계 : 분석 방법 선택

⏺ X, Y 척도 확인
  │
  ├── 연속형-연속형
  │   └── 가정 검정: 각 변수 정규성
  │       ├── n>5000: pg.normality(method='jarque_bera')
  │       └── n≤5000: pg.normality()
  │       │
  │       ├── 정규성O → Pearson 상관분석 (pg.corr())
  │       └── 정규성X → Spearman 상관분석 (pg.corr(method='spearman'))
  │
  ├── 범주형-연속형
  │   └── 가정 검정: 그룹별 정규성 + 등분산
  │       ├── pg.normality(data, dv='Y', group='X')
  │       └── pg.homoscedasticity(data, dv='Y', group='X')
  │       │
  │       ├── 2 그룹
  │       │   ├── 정규성O, 등분산성O → 독립표본 t-test (pg.ttest())
  │       │   ├── 정규성O, 등분산성X → Welch's t-test (pg.ttest(correction=True))
  │       │   └── 정규성X → Mann-Whitney U (pg.mwu())
  │       │
  │       └── 3+ 그룹
  │           ├── 정규성O, 등분산성O → One-way ANOVA (pg.anova())
  │           ├── 정규성O, 등분산성X → Welch's ANOVA (pg.welch_anova())
  │           └── 정규성X → Kruskal-Wallis (pg.kruskal())
  │
  └── 범주형-범주형
      └── 가정 검정 불필요
          └── 카이제곱 검정 (pg.chi2_independence())

가정 검정

검정 목적함수비고판단 기준
정규성 검정pg.normality()n ≤ 5000p > 0.05 → 정규
pg.normality(method='jarque_bera')n > 5000p > 0.05 → 정규
등분산성 검정pg.homoscedasticity()-p > 0.05 → 등분산
  • 가정 검정 예시 코드
    • 정규성 검정
      • 개별 검정(연속형-연속형)

        pg.normality(df1['before'])
      • 그룹별 검정(범주형-연속형)

        pg.normality(data=df, dv='Price', group='MetColor')
    • 등분산성 검정
      pg.homoscedasticity(data=df, dv='Price', group='MetColor')

상관분석(연속형-연속형)

방법함수특징/조건
Pearsonpg.corr()정규성O, 선형 관계 (기본)
Spearmanpg.corr(method='spearman')정규성X, 단조 관계
Kendallpg.corr(method='kendall')작은 샘플(n<30), 동점 많을 때
  • 상관분석 예시 코드
    • Pearson

      pg.corr(x=df['Age'], y=df['Price'])
    • Spearman

      pg.corr(x=df['Age'], y=df['Price'], method='spearman')
    • Kendall

      pg.corr(x=df['Age'], y=df['Price'], method='kendall')

가설 검정(그 외)

X (독립변수)Y (종속변수)조건분석 방법함수
범주형범주형-카이제곱 검정pg.chi2_independence()
범주형 (2그룹)연속형정규성O, 등분산O독립표본 t-testpg.ttest()
정규성O, 등분산XWelch's t-testpg.ttest(correction=True)
정규성XMann-Whitney Upg.mwu()
범주형 (3+그룹)연속형정규성O, 등분산OOne-way ANOVApg.anova()
정규성O, 등분산XWelch's ANOVApg.welch_anova()
정규성XKruskal-Wallispg.kruskal()
대응표본(전/후)연속형정규성O대응표본 t-testpg.ttest(paired=True)
정규성XWilcoxon 부호순위pg.wilcoxon()
  • 가설 검정 예시 코드
    • 범주형-범주형
      • 카이제곱 검정

        test = pg.chi2_independence(data=df2, x='Coupon', y='Purchase', correction=True)
        test[2]
    • 범주형(2그룹)-연속형
      • 독립표본 t-test
        • 그룹 추출 방식

          auto_y1 = df.loc[df['Automatic'].eq('0'), 'Price']
          auto_y2 = df.loc[df['Automatic'].eq('1'), 'Price']
          
          pg.ttest(x=auto_y1, y=auto_y2, correction=False)
        • 데이터프레임 방식

          pg.ttest(data=df, dv='Price', between='Automatic')
      • Welch's t-test
        • 그룹 추출 방식

            y1 = df.loc[df['MetColor'].eq('0'), 'Price']
            y2 = df.loc[df['MetColor'].eq('1'), 'Price']
          
            pg.ttest(x=y1, y=y2, correction=True)
        • 데이터프레임 방식

          pg.ttest(data=df, dv='Price', between='MetColor', correction=True)
      • Mann-Whitney U
        • 그룹 추출 방식

          y1 = df.loc[df['MetColor'].eq('0'), 'Price']
          y2 = df.loc[df['MetColor'].eq('1'), 'Price']
          
          pg.mwu(x=y1, y=y2)
        • 데이터프레임 방식

          pg.mwu(data=df, dv='Price', between='MetColor')
    • 범주형(3+그룹)-연속형
      • One-way ANOVA

        pg.anova(data=df, dv='Price', between='FuelType')
      • Welch's ANOVA

        pg.welch_anova(data=df, dv='Price', between='FuelType')
      • Kruskal-Wallis

        pg.kruskal(data=df, dv='Price', between='FuelType')
    • 대응표본(전/후)-연속형
      • 대응표본 t-test

        pg.ttest(x=df1['before'], y=df1['after'], paired=True)
      • Wilcoxon 부호순위

        pg.wilcoxon(x=df1['before'], y=df1['after'])

4단계 : 귀무가설 및 사후 분석

가설 설정 및 해석 방향

검정 유형검정귀무가설 (H0)p < 0.05 의미사후 분석
상관분석Pearson / Spearman / Kendall두 변수 간 상관이 없다 (ρ = 0)유의한 상관 있음 ✅-
평균 비교 (독립표본)독립표본 t-test두 그룹의 평균이 같다 (μ₁ = μ₂)평균 차이 있음 ✅-
Welch's t-test두 그룹의 평균이 같다 (μ₁ = μ₂)평균 차이 있음 ✅-
Mann-Whitney U두 그룹의 분포가 같다분포 차이 있음 ✅-
One-way ANOVA모든 그룹의 평균이 같다 (μ₁ = μ₂ = μ₃)그룹 간 차이 있음 ✅Tukey HSD
Welch's ANOVA모든 그룹의 평균이 같다 (μ₁ = μ₂ = μ₃)그룹 간 차이 있음 ✅Tamhane
Kruskal-Wallis모든 그룹의 분포가 같다그룹 간 차이 있음 ✅Nemenyi
평균 비교 (대응표본)대응표본 t-test전후 평균 차이가 0이다 (μd = 0)전후 차이 있음 ✅-
Wilcoxon 부호순위전후 분포가 같다전후 차이 있음 ✅-
독립성 검정카이제곱 검정두 변수는 독립적이다연관성 있음 ✅-

사후 분석

방법전제 조건특징함수
Tukey HSD정규성O, 등분산O균형 잡힌 검정력 모든 쌍 비교sp.posthoc_tukey()
Scheffe정규성O, 등분산O매우 보수적, 복잡한 대비 가능sp.posthoc_scheffe()
Tamhane정규성O, 등분산XWelch 기반 보수적sp.posthoc_tamhane()
Nemenyi정규성X비모수Kruskal 기반 순위 사용sp.posthoc_nemenyi()

p < 0.05 → 쌍 간 차이 ✅

  • 사후 분석 예시 코드
    • Tukey HSD

      sp.posthoc_tukey(a=df, val_col='Price', group_col='FuelType')
    • Scheffe

      sp.posthoc_scheffe(a=df, val_col='Price', group_col='FuelType')
    • Tamhane

      sp.posthoc_tamhane(a=df, val_col='Price', group_col='FuelType')
    • Nemenyi

      sp.posthoc_nemenyi(a=df, val_col='Price', group_col='FuelType')

마치며

이번 연휴 간 통계 이론 공부와 데이터 전처리 템플릿 제작, SQLD 자격증 공부 등 부족한 부분을 최대한 보충할 수 있도록 해봐야겠다.

profile
Hello I'm TaeHyunAn, Currently Studying Data Analysis

0개의 댓글