데이터분석 및 시각화 2일차 수업에서는 EDA(Exploratory Data Analysis)의 기본 개념 및
어떤 단계를 거치며 분석을 진행하는지 직접 실습해보며 알아가보는 시간을 가졌다.
ADsP를 준비하며 개념적인 부분을 배우긴 했지만, 직접적으로 와닿지는 않았었는데
직접 데이터를 다뤄보니 훨씬 흐름이 보였다.
그럼 배운 내용 및 과제를 어떤 식으로 해결했는지 정리해보겠다.
* 예시 코드 및 과제의 출처는 오즈코딩스쿨임
EDA(Exploratory Data Analysis)란 데이터의 특성과 패턴을 이해하기 위해
다양한 통계적 기법 및 시각화를 이용하여 데이터를 탐색하는 초기 과정으로서
가설을 만들어내는 단계이다.
숨겨진 패턴 발견: 데이터 속에 감춰진 의미 있는 관계와 트렌드 파악
수 많은 데이터 간에 이미 관계성을 예측하고 가설을 세울 수 있는 데이터도 있겠지만,
미처 생각하지 못한 관계를 이 과정을 통해서 발견할 수 있다.
문제 조기 발견: 결측치, 이상치, 데이터 품질 문제 사전 탐지
결측치, 이상치, 데이터 품질에 이상이 있을 경우, 정확하지 않은 분석 결과를 얻게 된다.
이 과정을 통해 이러한 값들을 미리 확인함으로써 분석의 정확도도 높아지고, 시간을 세이브할 수 있다.
가설 생성 및 검증: 데이터 기반의 과학적 가설 수립
분석 방향 설정: 후속 분석과 모델링의 전략적 로드맵 구축
후속 분석 및 모델링의 전략을 짜서 이후 어떠한 방향으로 업무를 진행할 것인지 계획을 세울 수 있도록 해준다.
위의 네 단계로 진행된다.
시각화 라이브러리인 Matplotlib 등은 기본적으로 영문 폰트만 사용하도록 설정되어 있다.
이 상태에서 한글 데이터를 그래프 제목이나 레이블에 사용하면, 한글이 깨지는 현상이 발생하기 때문에
미리 설치하여 설정하는 과정이 필요하다.
설치는 아래와 같이 입력하여 해줄 수 있다.
!sudo apt-get install -y fonts-nanum
!sudo fc-cache -fv
!rm ~/.cache/matplotlib -rf
import matplotlib.pyplot as plt # Matplotlib import
plt.rc('font', family='NanumBarunGothic') # 폰트 설정
plt.rcParams['axes.unicode_minus'] = False # 마이너스 기호 깨짐 방지
from scipy import statsimport pandas as pdimport numpy as npcf) 경고 메시지 숨기는 법
import warnings
warnings.filterwarnings('ignore')
plus!
print("라이브러리 로딩 완료!")를 입력하여 라이브러리 로딩 완료 여부를 직관적으로 확인하자.
!pip install kagglehubimport 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()
# 기본 데이터 정보 확인
print("=== 데이터 기본 정보 ===")
print(f"데이터 크기: {df.shape}")
print(f"총 환자 수: {df.shape[0]:,}명")
print(f"총 변수 수: {df.shape[1]}개")
# 데이터 정보 출력
print("=== 데이터 타입 정보 ===")
df.info()
.info()메소드를 통해 얻어지는 정보.describe(): 수치형 변수들의 주요 통계량을 한 번에 계산count (개수): 결측치를 제외한 실제 데이터 개수
mean (평균): 모든 값의 합계를 개수로 나눈 값, 중심경향성의 대표값
std (표준편차): 데이터가 평균에서 얼마나 퍼져있는지 나타내는 지표
min (최솟값): 가장 작은 값, 데이터 범위의 하한선
25% (1사분위수): 하위 25% 지점의 값, Q1
50% (중앙값): 중간 지점의 값, Q2, 중앙값과 같음
75% (3사분위수): 상위 25% 지점의 값, Q3
max (최댓값): 가장 큰 값, 데이터 범위의 상한선
.idxmin(), .idxmax()가우시안 분포(Gaussian distribution)라고도 불리며, 평균을 중심으로 좌우 대칭인 종 모양의 확률 분포이다.
✔️ 핵심 특징
[대표값(3m)의 종류] - 결측치 대체(imputation)에서 평균이나 중앙값으로 빈 데이터를 채울 때 사용
.mean() .median().mode()데이터 정규화(Normalization)에서 표준편차를 이용해 서로 다른 단위의 변수들을 동일한 스케일로 맞출 때 사용
.std().var(): 분산 계산용 메소드🔹 모집단 표준편차 (Population Standard Deviation)
σ : 모집단 표준편차
: 각 데이터 값
𝑚: 모집단 평균
𝑁: 전체 데이터 개수
👉 전체 모집단 데이터를 모두 알고 있을 때 사용하는 공식
🔹 표본 표준편차 (Sample Standard Deviation)
👉 분모가 인 이유는
표본이 모집단의 분산을 과소추정하는 문제를 보정(Bessel’s correction) 하기 위함
사분위간범위(IQR): 중앙 50% 데이터의 범위(Q3 - Q1).
가장 극단적인 값들을 제외하고 “중앙부의 퍼짐 정도”를 본다. 이상치에 강하며 데이터가 한쪽으로 치우쳐 있거나 outlier가 많은 경우 IQR 기반 분석이 훨씬 신뢰도가 높다.
.quantile(0.25): Q1 지점의 값
.quantile(0.75): Q3 지점의 값
❓ 언제 쓰나?
박스플롯(Boxplot)
이상치 탐지
정규 분포가 아닐 때 분산을 설명해야 하는 경우
.value_counts(): 빈도.value_counts(normalize=True): 상대빈도pd.crosstab(변수1(반환되는 데이터프레임의 행), 변수2(반환되는 데이터프레임의 열), (*옵션: margins=True(총액 계산해서 행, 열 추가해줌)): 교차표 반환pd.crosstab(변수1, 변수2, normalize='index'): 행별 비율클래스 불균형이란 타깃 클래스의 비율이 심하게 한쪽으로 치우친 상태.
✔️ 예:
❓ 왜 문제가 되는가?
모델이 이렇게 예측해도 된다.
“전부 정상입니다” → 정확도 90%
하지만 실제로 중요한 소수 클래스(질병, 사기, 이상)를 전혀 잡지 못한다.
🧐 해결을 위한 분석 관점
1) 정확도 대신 다른 지표 사용
2) 데이터 분포 자체를 먼저 분석
3) 가중치 조정 (Weighting) — ⭐ 핵심
결과적으로 모델은
👉 “적은 클래스라도 틀리면 안 된다”라고 학습한다.
❓ 왜 중요한가?
타겟 변수의 각 범주에서 다른 변수들이 어떻게 분포하는지 비교
Feature Selection에서 타겟 변수와 가장 관련성이 높은 변수들을 사전에 파악하기 위해 사용
분리(Split) → 적용(Apply) → 결합(Combine)의 단계를 거쳐서 도출됨
타겟 변수의 각 범주별로 다른 변수들의 분포 비교
.groupby() + (.mean() or .std() or .count() 등).agg(['count', 'mean', 'median', 'std'])와 같이 작성연속형 변수들 간의 관련성을 숫자로 나타내는 기법.
두 변수가 얼마나 예측 가능하게 함께 움직이는지를 -1 ~ 1 스케일로 표준화한 값이다.
# 상관관계 분석할 주요 변수들 선택
correlation_vars = [
'Diabetes_binary', # 당뇨병 (타겟)
'BMI', # 체질량지수
'HighBP', # 고혈압
'MentHlth', # 정신건강 불량일수
'GenHlth', # 전반적 건강상태
'Education' # 교육 수준
]
# 상관계수 행렬 생성 (.corr()는 모든 변수 쌍의 상관계수를 계산)
corr_matrix = df[correlation_vars].corr()
+1.0: 완전한 양의 상관관계 (한 변수 증가 시 다른 변수도 증가)0.0: 상관관계 없음-1.0: 완전한 음의 상관관계 (한 변수 증가 시 다른 변수는 감소)|r| ≥ 0.7: 강한 상관관계0.3 ≤ |r| < 0.7: 중간 상관관계|r| < 0.3: 약한 상관관계* 상관관계의 강도를 해석하는 기준은 상황에 따라 변동될 수 있다(주관적 해석 가능)
상관 ≠ 인과
상관이 있다고 원인이 되는 것은 아니다.
제3의 변수, 우연, 구조적 요인이 있을 수 있다.
언제 쓰나?

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

[캡쳐 1-2. 1번 미션 코드 작성 비교]
✔️ 장점
.groupby().agg(['mean','std']) 결과(이미 계산된 표)를 재사용해서.iloc[]으로 평균 차이를 구한 건 연산을 한 번 덜 하는 구조display(round(...))로 출력한 것도 가독성 측면에서 장점✔️ 단점
.iloc[1,0] - .iloc[0,0]는 행/열 순서가 바뀌면 깨질 가능성이 큼✔️ 장점
✔️ 단점
.groupby()를 두 번 할 수 있어서(agg 한 번, mean 한 번) 데이터가 매우 크면 비효율이 될 수 있음
[캡쳐 1-3. 2번 미션 코드 작성 비교]
✔️ 장점
value_counts() 결과를 바로 인덱스로 꺼내서 계산해서 짧고 직관적이야..items()로 돌려서 출력한 흐름이 깔끔✔️ 단점
✔️ 장점
value_counts(normalize=True)를 써서 비율을 별도로 안전하게 확보for category in sex_counts.index: 형태는 존재하는 범주만 순회해서 누락/결측 상황에 더 강함{ratio:.1%} 를 써서 “퍼센트 표현”이 깔끔✔️ 단점

[캡쳐 1-4. 3번 미션 코드 작성 비교]
문법이 아직 익숙하지 않아 margins=True 나 normalize='index' 가 떠오르지 않았다.
특히, index를 따옴표''로 감싸주지 않아 에러가 떴는데, 앞으로는 까먹지 않고 잘 작성해야겠다.