데이터분석 및 시각화 2일차 수업에서는 EDA(Exploratory Data Analysis)의 기본 개념 및
어떤 단계를 거치며 분석을 진행하는지 직접 실습해보며 알아가보는 시간을 가졌다.
ADsP를 준비하며 개념적인 부분을 배우긴 했지만, 직접적으로 와닿지는 않았었는데
직접 데이터를 다뤄보니 훨씬 흐름이 보였다.

그럼 배운 내용 및 과제를 어떤 식으로 해결했는지 정리해보겠다.


* 예시 코드 및 과제의 출처는 오즈코딩스쿨임



1. EDA(Exploratory Data Analysis)가 무엇인가? 🧐

EDA(Exploratory Data Analysis)란 데이터의 특성패턴을 이해하기 위해
다양한 통계적 기법시각화를 이용하여 데이터를 탐색하는 초기 과정으로서
가설을 만들어내는 단계이다.

cf) EDA를 왜 거쳐야하는가

  • 숨겨진 패턴 발견: 데이터 속에 감춰진 의미 있는 관계와 트렌드 파악
    수 많은 데이터 간에 이미 관계성을 예측하고 가설을 세울 수 있는 데이터도 있겠지만,
    미처 생각하지 못한 관계를 이 과정을 통해서 발견할 수 있다.

  • 문제 조기 발견: 결측치, 이상치, 데이터 품질 문제 사전 탐지
    결측치, 이상치, 데이터 품질에 이상이 있을 경우, 정확하지 않은 분석 결과를 얻게 된다.
    이 과정을 통해 이러한 값들을 미리 확인함으로써 분석의 정확도도 높아지고, 시간을 세이브할 수 있다.

  • 가설 생성 및 검증: 데이터 기반의 과학적 가설 수립

  • 분석 방향 설정: 후속 분석과 모델링의 전략적 로드맵 구축
    후속 분석 및 모델링의 전략을 짜서 이후 어떠한 방향으로 업무를 진행할 것인지 계획을 세울 수 있도록 해준다.


1.1. EDA 분석 로드맵

  • 1단계: 데이터 전체 파악 → 데이터 전반적 특성 이해 - 기술통계
  • 2단계: 타겟별 차이 탐색 → "당뇨병 환자와 정상인이 다를까?" - 그룹분석
  • 3단계: 차이의 진위 검증 → "관찰된 차이가 진짜일까?" - 통계검정
  • 4단계: 변수간 관계 파악 → "어떤 변수들이 함께 움직일까?" - 상관관계

위의 네 단계로 진행된다.



2. 실습을 통해 알아보기

2.1. 필요한 라이브러리 import하기

2.1.1. 나눔폰트 설치하기(Linux 명령어)

시각화 라이브러리인 Matplotlib 등은 기본적으로 영문 폰트만 사용하도록 설정되어 있다.
이 상태에서 한글 데이터를 그래프 제목이나 레이블에 사용하면, 한글이 깨지는 현상이 발생하기 때문에
미리 설치하여 설정하는 과정이 필요하다.

설치는 아래와 같이 입력하여 해줄 수 있다.

!sudo apt-get install -y fonts-nanum
!sudo fc-cache -fv
!rm ~/.cache/matplotlib -rf

2.1.2. 시각화 라이브러리 import 및 font setting

import matplotlib.pyplot as plt    # Matplotlib import

plt.rc('font', family='NanumBarunGothic')    # 폰트 설정
plt.rcParams['axes.unicode_minus'] = False    # 마이너스 기호 깨짐 방지

2.1.3. 통계 분석 라이브러리

  • from scipy import stats

2.1.4. 데이터 분석 및 처리용 라이브러리(Pandas, NumPy)

  • import pandas as pd
  • import numpy as np

cf) 경고 메시지 숨기는 법

import warnings
warnings.filterwarnings('ignore')

plus!
print("라이브러리 로딩 완료!")를 입력하여 라이브러리 로딩 완료 여부를 직관적으로 확인하자.


2.2. 데이터셋 가져오기

2.2.1. 라이브러리 설치(최초 1회만 진행하면 된다)

  • !pip install kagglehub

2.2.2. 데이터 다운로드

import kagglehub

# 당뇨병 건강지표 데이터셋 다운로드 (자동으로 최신 버전 받아옴)
path = kagglehub.dataset_download("alexteboul/diabetes-health-indicators-dataset")

print("데이터가 다운로드된 경로:", path)

# 3. 다운로드된 경로에서 파일 불러오기
df = pd.read_csv(f"{path}/diabetes_binary_health_indicators_BRFSS2015.csv")

df.head()

2.2.3. 데이터셋 변수(Feature) 확인하기


2.3. 기본 데이터 정보 확인하기

# 기본 데이터 정보 확인
print("=== 데이터 기본 정보 ===")
print(f"데이터 크기: {df.shape}")
print(f"총 환자 수: {df.shape[0]:,}명")
print(f"총 변수 수: {df.shape[1]}개")

# 데이터 정보 출력
print("=== 데이터 타입 정보 ===")
df.info()

ℹ️ .info()메소드를 통해 얻어지는 정보

  • Index: 인덱스 범위와 타입 (예: RangeIndex: 0 to 253679)
  • Entries: 전체 행(레코드) 개수
  • Data columns: 전체 컬럼 수와 각 컬럼명 리스트
  • Column: 각 컬럼의 순서번호와 이름
  • Non-Null Count: 각 컬럼별 결측치가 아닌 실제 데이터 개수(이걸 통해 결측치 존재 여부 확인 가능)
  • Dtype: 각 컬럼의 데이터 타입 (int64, float64, object 등)
  • Memory usage: 데이터프레임이 메모리에서 차지하는 용량
  • Dtypes summary: 데이터 타입별 컬럼 개수 요약

2.4. 기술통계 분석

🧮 .describe(): 수치형 변수들의 주요 통계량을 한 번에 계산

  • count (개수): 결측치를 제외한 실제 데이터 개수

  • mean (평균): 모든 값의 합계를 개수로 나눈 값, 중심경향성의 대표값

  • std (표준편차): 데이터가 평균에서 얼마나 퍼져있는지 나타내는 지표

  • min (최솟값): 가장 작은 값, 데이터 범위의 하한선

  • 25% (1사분위수): 하위 25% 지점의 값, Q1

  • 50% (중앙값): 중간 지점의 값, Q2, 중앙값과 같음

  • 75% (3사분위수): 상위 25% 지점의 값, Q3

  • max (최댓값): 가장 큰 값, 데이터 범위의 상한선

    • cf) 최솟값, 최댓값 인덱스 번호 찾기: .idxmin(), .idxmax()

2.4.1. 정규 분포(Normal Distribution)

가우시안 분포(Gaussian distribution)라고도 불리며, 평균을 중심으로 좌우 대칭인 종 모양의 확률 분포이다.

✔️ 핵심 특징

  • 평균(mean)을 중심으로 좌우 대칭
  • 평균 = 중앙값 = 최빈값
  • 데이터 대부분이 평균 근처에 몰려 있음

2.4.2. 중심경향성 분석(Central Tendency) & 분산성 분석 (Variability)

🎯 중심 경향성 분석(Central Tendency) - 데이터가 어떤 값 주변에 모여있는가?

[대표값(3m)의 종류] - 결측치 대체(imputation)에서 평균이나 중앙값으로 빈 데이터를 채울 때 사용

  • 평균 (Mean): 모든 값을 더해 N으로 나눈 것. (이상치에 취약. 정규 분포를 가지는 데이터의 분석에 사용하기 좋음)
    • .mean()
  • 중앙값 (Median): 데이터를 줄 세웠을 때 정중앙에 위치한 값. (이상치에 강하다)
    • .median()
  • 최빈값 (Mode): 가장 자주 나타나는 값. (범주형 데이터에서 주로 사용된다)
    • .mode()

💥 분산성 분석(Variability) - 데이터가 중심값을 기준으로 얼마나 퍼져있는가?

데이터 정규화(Normalization)에서 표준편차를 이용해 서로 다른 단위의 변수들을 동일한 스케일로 맞출 때 사용

  • 표준편차(Standard Deviation): “데이터가 평균으로부터 얼마나 퍼져 있는가”를 나타내는 지표
    표준편차는 “안정성”과 “변동성”을 함께 보여준다. 이상치(outlier)에 매우 민감하다는 문제점이 있다.
    • .std()
    • cf) .var(): 분산 계산용 메소드

🔹 모집단 표준편차 (Population Standard Deviation)

σ=(x1m)2+(x2m)2++(xNm)2N\sigma = \sqrt{ \frac{(x_1 - m)^2 + (x_2 - m)^2 + \cdots + (x_N - m)^2}{N} }
  • σ : 모집단 표준편차

  • 𝑥𝑖𝑥_𝑖 : 각 데이터 값

  • 𝑚: 모집단 평균

  • 𝑁: 전체 데이터 개수

👉 전체 모집단 데이터를 모두 알고 있을 때 사용하는 공식

🔹 표본 표준편차 (Sample Standard Deviation)

s=(xnxˉ)2n1s = \sqrt{ \frac{\sum (x_n - \bar{x})^2}{n - 1} }
  • s : 표본 표준편차
  • 𝑥n𝑥_n : 각 데이터 값
  • xˉ\bar{x} : 표본 평균
  • 𝑛 : 표본의 개수

👉 분모가 𝑛1𝑛−1 인 이유는
표본이 모집단의 분산을 과소추정하는 문제를 보정(Bessel’s correction) 하기 위함

  • 사분위간범위(IQR): 중앙 50% 데이터의 범위(Q3 - Q1).
    가장 극단적인 값들을 제외하고 “중앙부의 퍼짐 정도”를 본다. 이상치에 강하며 데이터가 한쪽으로 치우쳐 있거나 outlier가 많은 경우 IQR 기반 분석이 훨씬 신뢰도가 높다.

    • .quantile(0.25): Q1 지점의 값

    • .quantile(0.75): Q3 지점의 값

      언제 쓰나?

    • 박스플롯(Boxplot)

    • 이상치 탐지

    • 정규 분포가 아닐 때 분산을 설명해야 하는 경우


2.4.3. 빈도 및 교차분석

빈도분석: 범주형 데이터에서 각 카테고리가 얼마나 자주 나타나는지 확인하는 기법

  • .value_counts(): 빈도
  • .value_counts(normalize=True): 상대빈도

교차분석(Crosstab): 두 범주형 변수 간의 관계 분석

  • pd.crosstab(변수1(반환되는 데이터프레임의 행), 변수2(반환되는 데이터프레임의 열), (*옵션: margins=True(총액 계산해서 행, 열 추가해줌)): 교차표 반환
  • pd.crosstab(변수1, 변수2, normalize='index'): 행별 비율

2.4.4. 클래스 불균형(Class Imbalance) 분석과 가중치 조정

클래스 불균형이란 타깃 클래스의 비율이 심하게 한쪽으로 치우친 상태.

✔️ 예:

  • 정상 90%, 질병 10%
  • 스팸 1%, 정상 메일 99%

왜 문제가 되는가?
모델이 이렇게 예측해도 된다.

“전부 정상입니다” → 정확도 90%

하지만 실제로 중요한 소수 클래스(질병, 사기, 이상)를 전혀 잡지 못한다.

🧐 해결을 위한 분석 관점

  • 1) 정확도 대신 다른 지표 사용

    • Precision, Recall, F1-score
    • ROC-AUC
  • 2) 데이터 분포 자체를 먼저 분석

    • 클래스 비율 확인
    • 교차표, 비율 기반 분석
  • 3) 가중치 조정 (Weighting) — ⭐ 핵심

    • 소수 클래스의 오류에 더 큰 패널티를 주는 방식
    • 다수 클래스 오답 → 작은 손실
    • 소수 클래스 오답 → 큰 손실

결과적으로 모델은

👉 “적은 클래스라도 틀리면 안 된다”라고 학습한다.

왜 중요한가?

  • 데이터 자체를 바꾸지 않아도 적용 가능
  • 현실 문제(의료, 금융, 보안)에서 필수적인 접근법

2.5. 그룹별 분석

타겟 변수의 각 범주에서 다른 변수들이 어떻게 분포하는지 비교
Feature Selection에서 타겟 변수와 가장 관련성이 높은 변수들을 사전에 파악하기 위해 사용
분리(Split) → 적용(Apply) → 결합(Combine)의 단계를 거쳐서 도출됨

2.5.1. 그룹별 분석:

타겟 변수의 각 범주별로 다른 변수들의 분포 비교

2.5.2. 집계함수:

  • .groupby() + (.mean() or .std() or .count() 등)
  • 여러 통계 연산을 한번에 하고 싶으면
    .agg(['count', 'mean', 'median', 'std'])와 같이 작성

2.5.3. 효과크기: 차이가 얼마나 실질적으로 의미 있는지 측정


2.6. 상관관계 분석

연속형 변수들 간의 관련성을 숫자로 나타내는 기법.
두 변수가 얼마나 예측 가능하게 함께 움직이는지를 -1 ~ 1 스케일로 표준화한 값이다.

# 상관관계 분석할 주요 변수들 선택
correlation_vars = [
    'Diabetes_binary',  # 당뇨병 (타겟)
    'BMI',             # 체질량지수
    'HighBP',          # 고혈압
    'MentHlth',        # 정신건강 불량일수
    'GenHlth',          # 전반적 건강상태
    'Education'         # 교육 수준
]

# 상관계수 행렬 생성 (.corr()는 모든 변수 쌍의 상관계수를 계산)
corr_matrix = df[correlation_vars].corr()

2.6.1. 상관계수 해석 가이드

  • +1.0: 완전한 양의 상관관계 (한 변수 증가 시 다른 변수도 증가)
  • 0.0: 상관관계 없음
  • -1.0: 완전한 음의 상관관계 (한 변수 증가 시 다른 변수는 감소)
  • |r| ≥ 0.7: 강한 상관관계
  • 0.3 ≤ |r| < 0.7: 중간 상관관계
  • |r| < 0.3: 약한 상관관계

* 상관관계의 강도를 해석하는 기준은 상황에 따라 변동될 수 있다(주관적 해석 가능)

2.6.2. 반드시 기억할 점

상관 ≠ 인과

상관이 있다고 원인이 되는 것은 아니다.
제3의 변수, 우연, 구조적 요인이 있을 수 있다.

언제 쓰나?

  • 변수 선택(Feature Selection)
  • 다중공선성 확인
  • 데이터 탐색 단계(EDA)의 핵심 도구


3. 과제 분석

3.1. 요구사항 및 출력 예시


[캡쳐 1-1. 요구사항 및 출력 예시

3.2. 1번 미션 코드 비교


[캡쳐 1-2. 1번 미션 코드 작성 비교]

내가 작성한 코드

✔️ 장점

  • .groupby().agg(['mean','std']) 결과(이미 계산된 표)를 재사용해서
    .iloc[]으로 평균 차이를 구한 건 연산을 한 번 덜 하는 구조
  • display(round(...))로 출력한 것도 가독성 측면에서 장점

✔️ 단점

  • .iloc[1,0] - .iloc[0,0]는 행/열 순서가 바뀌면 깨질 가능성이 큼
    (예: 라벨 순서가 바뀌거나, 어떤 그룹이 빠지거나, 컬럼 순서가 바뀌면 바로 오답/오류로 갈 수 있다)

정답 코드

✔️ 장점

  • “표(요약 통계) 출력”과 “추가 계산(평균차)”을 분리해서 가독성/유지보수성이 더 좋음.

✔️ 단점

  • 같은 데이터를 .groupby()를 두 번 할 수 있어서(agg 한 번, mean 한 번) 데이터가 매우 크면 비효율이 될 수 있음

3.3. 2번 미션 코드 비교


[캡쳐 1-3. 2번 미션 코드 작성 비교]

내가 작성한 코드

✔️ 장점

  • value_counts() 결과를 바로 인덱스로 꺼내서 계산해서 짧고 직관적이야.
  • Education을 .items()로 돌려서 출력한 흐름이 깔끔

✔️ 단점

  • 유지 보수 및 확장성 측면에서 떨어짐

정답 코드

✔️ 장점

  • value_counts(normalize=True)를 써서 비율을 별도로 안전하게 확보
  • for category in sex_counts.index: 형태는 존재하는 범주만 순회해서 누락/결측 상황에 더 강함
  • {ratio:.1%} 를 써서 “퍼센트 표현”이 깔끔

✔️ 단점

  • 단순히 두 개만 출력할 땐 for문보다 내 코드가 더 짧고 간결

3.4. 3번 미션 코드 비교


[캡쳐 1-4. 3번 미션 코드 작성 비교]

문법이 아직 익숙하지 않아 margins=Truenormalize='index' 가 떠오르지 않았다.
특히, index를 따옴표''로 감싸주지 않아 에러가 떴는데, 앞으로는 까먹지 않고 잘 작성해야겠다.

profile
R&D 분야의 경험을 토대로 커리어 확장에 도전중인 개발꿈나무입니다.

0개의 댓글