데이터 분석 기본_집계와 시각화
한 변수의 집계와 시각화
1. 기술통계량과 차이
-통계량(Statistics): 데이터로부터 계산된 모든 숫자
→ 기술 통계량(Descriptive Statistics): 변수나 변수의 관계 등 데이터의 특성을 설명하는 통계량(합계, 평균, 표준편차 등)
- 절대적인 차이: 관측치의 실제 값/데이터를 요약해서 얻은 숫자의 차이(ex.상품별 매출액)
- 상대적인 차이: 절대적인 차이를 상대적인 값으로 바꾼 숫자의 차이(ex.상품 매출 순위)
2. 범주형(categorical) 변수
1) 범주형 변수와 수준
-관측치들이 몇 개의 정해진 값만 가질 수 있음
-수준: 범주형 변수의 관측치들이 가질 수 있는 값들의 묶음(treatment / group)
ex) "성별"의 수준: 남, 여 / "연령대"의 수준: 10대, 20대, 30대, 40대 이상
2) 범주형 변수의 집계
-빈도표(frequenct table): 테이블에 항목을 나열하고 해당 항목이 발생할 횟수 표시
-상대빈도(relative frequency): 빈도표에서 각 수준의 비율 계산. 수준 간 상대적인 차이 나타냄

3. 수치형(numerical) 변수
1) 수치형 변수의 집계
-관측치들이 연속적인 숫자 값을 가짐
-구간: 수치형 변수의 값 범위를 여러 조각으로 나눈 범위
2) 도수분포표와 히스토그램
-도수분포표(frequency table): 각 구간의 관측치 수를 정리한 표
-히스토그램(histogram): 도수분포표를 바 차트로 표현한 그림(분포 확인)
3) 사분위수와 상자 그림
-사분위수(quantile): 측정값을 낮은 수에서 높은 순으로 정렬 후 4등분 했을 때, 각 등위에 해당하는 값
-상자 그림(box plot): 사분위수를 이용하여 수치형 데이터의 분포 그리는 그래프
- 최댓값(maximum): 정렬 후 100% 위치 값
- Q3(3rd quntaile): 장렬 후 75% 위치 값
- Q2(중앙값, median): 정렬 후 50% 위치 값
- Q1(1st quntaile): 정렬 후 25% 위치 값
- 최솟값(minimum): 정렬 후 0% 위치 값
- IQR(InterQuartile Range) = Q3 - Q1: 가운데 50% 데이터가 퍼져 있는 촉
- 하한 경계(하위 이상치 기준) = Q1 - 1.5*IQR
- 상한 경계(상위 이상치 기준) = Q3 + 1.5*IQR


변수 관계의 집계와 시각화
1. 두 범주형 변수
1) 두 범주형 변수의 요약과 시각화
-교차표(contingency table): 두 범주형 변수의 수준 조합에 대한 빈도표(수준 조합의 절대적인 차이 확인)
-열지도/히트맵(heatmap): 2차원 교차표를 숫자 대신 색의 진하기로 크기를 표현한 그림

2) 행백분율과 열백분율
-교차표의 상대적인 차이의 확인 필요할 때 사용
-행백분율: 각 행의 합을 100%로 두고, 각 열 범주가 차지하는 비율
-열백분율: 각 열의 합을 100%로 두고, 각 행 범주가 차지하는 비율

2. 두 수치형 변수
1) 산점도(scatterplot)
-두 수치형 변수 값을 좌표로 활용하여 그린 그래프
-2차원 공간에 관측치의 수만큼 찍힌 점의 패턴 파악
2) 사분면과 상관관계
① 산점도의 패턴과 두 변수의 관계
-제1, 3사분면의 관측치 수 多: 두 변수가 양의 상관관계
-제2, 4사분면의 관측치 수 多: " 음의 "
② 양의 상관과 음의 상관
-양의 상관: 두 변수의 증가, 감소가 같은 방향
-음의 상관: " 다른
③ 다앙한 산점도와 상관관계

④ 상관관계
-두 수치형 변수의 상관성을 나타내는 척도(점들이 직선에 얼마나 모여있는가)
-공분산을 -1에서 1 사이가 되도록 표준화한 것
- r_xy = 0: 두 변수가 상관이 없음
- r_xy > 0: 두 변수가 양의 상관을 가짐
- r_xt < 0: 두 변수가 음의 상관을 가짐
※상관관계 vs. 인과관계
-상관관계: a와 b가 서로 관계가 있다
-인과관계: a(b)가 b(a)에 영향을 미친다(방향성 o)
※e: 10의 제곱
1e-1 = 1*0.1
3.14e-3 = 3.14*0.001
3.14e+4 = 3.14*10000
집계와 시각화 실습
0. 라이브러리 설치 및 데이터 파악
1) 라이브러리 설치
# 윈도우 검색창 → anaconda prompt 실행
# pip install seaborn==0.13.2
# pip install selenium
# pip install statsmodels
-pandas: 데이터 분석 기본 기능. 데이터를 표(table) 형태로 다루는데 최적화
-numpy: 행렬 연산의 기초. 대규모 숫자 데이터를 빠르게 계산
-matplotlib: 그래프 기능 담당
import pandas as pd # 데이터 분석 기본 기능. 데이터를 표(table) 형태로 다루는데 최적화
import numpy as np # 행렬 연산의 기초. 대규모 숫자 데이터를 빠르게 계산
# 그래프 라이브러리
import matplotlib.pyplot as plt # 그래프 기능 담당(제목, 사이즈, x축/y축 조절, 색상 변경, ...)
import seaborn as sns # 세련된 그래프 그리기
# 워닝 무시(버전에 따라 주는 경고를 무시함)
import warnings
warnings.filterwarnings('ignore')
-pd.read_csv('폴더명/세부 폴더 or 파일명'): 컴퓨터에 저장된 엑셀/텍스트 형태의 데이터를 파이썬으로 가져옴
※분석하고자 하는 파일이 현재 내 경로와 같은 폴더에 위치해야 함
df_ins = pd.read_csv('data/insurance.csv')
print(df_ins.shape)
df_ins.head(3)

2) 데이터 파악
-.dtypes: 각 컬럼명마다 해당 컬럼의 데이터 타입 출력
-.info(): 데이터프레임의 전체적인 상태 상세히 출력
| .dtypes | .info() | |
| 주요 목적 | 데이터 타입만 확인 | 데이터 전반(타입, 결측치, 메모리) 확인 |
| 결측치 확인 | 불가 | 가능(Non-Null Count 제공) |
| 출력 가독성 | 단순하고 깔끔 | 상세하지만 정보 多 |


-.describe(): 수치형 기술통계량 확인
df_ins.describe()

※확인 결과 charges의 평균과 중앙값이 많이 차이남
→ 봉우리가 왼쪽으로 치우치고 오른쪽 꼬리가 긴 형태일 것임
→ 보험료를 많이 내는 몇몇 VIP들 선별 가능
-.describe(include='object') / .decribe(include='O'): 범주형 기술통계량 확인
※평균 없음, count 기반, unique=group
df_ins.describe(include='object')

1. 범주형 변수의 집계와 시각화
-.unique(): 데이터의 중복 제거 후 어떤 종류가 있는지 목록으로 보여줌
# 흡연여부(smoker) 변수의 수준(level) 확인
df_ins['smoker'].unique()
# >>> array(['no', 'yes'], dtype=object)
-.value_counts(): 수준별 관측치 수(내림차순)
※오름차순 정렬
-.value_counts(ascending=True)
-.sort.values(ascending=True)
# 흡연자, 비흡연자가 각각 count
df_ins["smoker"].value_counts()
# >>> smoker
# no 1067
# yes 286
# Name: count, dtype: int64
-sns.countplot(data=데이터프레임, x='컬럼명'): 바 차트(막대그래프) 그리기
※x='컬럼명' → 막대가 세로로 세워진 형태
y='컬럼명' → 막대가 가로로 누운 형태
※"data=" 생략 가능(sns.countplot(데이터프레임, x='컬럼명')으로 사용 가능)
-plt.show(): 그래프 보여주기
※안써도 그려짐 but 필요없는 추가설명이 붙음
→ 세미콜론 ; 사용하여 간소화
-plt.figure(figsize=(가로, 세로)): 그래프 사이즈 조절(기본은 (6, 6))
※사이즈 조절 코드는 항상 그래프 코드 가장 위에 위치해야 함
# 막대그래프로 흡연자, 비흡연자 수 비교
sns.countplot(data=df_ins, x='smoker')
plt.show()
plt.figure(figsize=(6, 2))
graph = sns.countplot(data=df_ins, x='smoker');


# 보험 데이터 (df_ins)에서 region 수준별 관측치 막대그래프로 표현
region_graph = sns.countplot(df_ins, x="region");

2. 수치형 변수의 집계외 시각화
1) 수치형 변수의 기술통계량
-.mean(): 평균
-.sum(): 합계
-.var(): 분산
-.std(): 표준편차
※소수점 자리수 표현
-round(실수, 자리수): 해당 숫자의 데이터를 반올림하여 데이터 자체를 변경
-:.nf: 데이터 원본은 건드리지 않고 출력할 때만 소수점 n자리까지 보여줌(출력용이므로 결과는 항상 문자열)
# charges의 기술통계량
print(round(df_ins["charges"].mean())) # >>> 13259.083
print(round(df_ins["charges"].sum())) # >>> 17939539.626
print(round(df_ins["charges"].var())) # >>> 143363959.102
print(round(df_ins["charges"].std())) # >>> 11973.469
2) 히스토그램_수치형 변수의 분포 파악
-sns.hisplot(data=데이터프레임, x='컬럼명', 기타 옵션...): 히스토그램 그리기
# df_ins에서 charges 분포 확인
sns.histplot(df_ins, x="charges");

-binwidth: 데이터 간격 설정
-color: 색깔 설정
-binrange[최소값, 최대값]: 데이터 범위 지정
-stat='percent': 퍼센트 기반으로 변경(count(디폴트), percent, dencity 등 有)
# 히스토그램 간격과 색 수정하기
sns.histplot(df_ins, x="charges", binwidth=5000, color="red", binrange=[0, 65000]);
sns.histplot(df_ins, x="charges", binwidth=5000, color="red", binrange=[0, 65000],
stat="percent");


-.bar_label(대상, 기타 옵션...): 각 막대에 값 레이블 표시
-.containers[]: 인덱스 사용하여 컨테이너 지정
-padding: 그래프와 레이블 사이의 간격 조정
-fmt: 단위 세팅(format의 약자) → %.nf 사용(※바 레이블에서만!)
graph_charges = sns.histplot(df_ins, x="charges", binwidth=5000, color="red", binrange=[0, 65000])
# 그래프를 변수로 받음(흔치 않음)
graph_charges.bar_label(graph_charges.containers[0], size=8, padding=2, fmt="%.1f");

-.datavalues: 레이블 값 추출
graph_charges.containers[0].datavalues
# >>> array([355, 350, 296, 82, 73, 36, 29, 54, 40, 31, 2, 2, 3],
# dtype=int64)
# [실습]
# StuedntsPerformance 데이터에서 math score의 히스토그램을 퍼센트 기반으로 그리고 레이블 표시
graph = sns.histplot(df_sp, x='math score',
binwidth=10,
color='orange',
stat='percent')
graph.bar_label(graph.containers[0], size=8, padding=2, fmt="%.2f");

3) 사분위수와 상자그림, 이상치 데이터
-.quantile(분위값): 데이터 크기 순 나열 후 특정 위치 값 찾아줌
# reading score의 사분위수
# Q1(25%값)
Q1 = df_sp['reading score'].quantile(0.25) # >>> 59.0
# Q2(50값)
Q2 = df_sp['reading score'].quantile(0.5) # >>> 70.0
# Q3(75%값)
Q3 = df_sp['reading score'].quantile(0.75) # >>> 79.0
# IQR(Q1과 Q3의 간격)
IQR = Q3 - Q1
IQR # >>> 20.0
-.min(): 최소값 추출
-.max(): 최대값 추출
reading_min = df_sp["reading score"].min()
reading_max = df_sp["reading score"].max()
print(reading_min, reading_max)
# >>> 17 100
-sns.boxplot(data=데이터프레임, y='변수명'): 박스플랏 그리기
# reading score의 상자 그림 그리기
plt.figure(figsize=(4,3))
sns.boxplot(df_sp, y='reading score');

# 이상치 경계값 구하기(둘 다 있을수도, 하나만 있을수도, 둘 다 없을수도)
# 상위 경계값
upper_bound = Q3-1.5*IQR
print(upper_bound) # >>> 109.0
# 하위 경계값
lower_bound = Q1-1.5*IQR
print(lower_bound) # >>> 29.0
# 중간 결론
# 1) 상위 경계값보다 크면 상위 이상치
# → 상위 경계값 109인데 현재 최대값이 100이므로 해당 데이터에서는 상위 이상치 x
# 2) 하위 경계값보다 작으면 하위 이상치
# → 하위 경계값 29, 최소값 17이므로 하위 이상치 o
# 몇몇 학생들은 어떤 이유인지 극단적으로 낮은 점수를 가짐(확인 必)
# reading score 이상치 데이터 추출 후 변수에 저장
reading_outlier = df_sp[df_sp['reading score'] < lower_bound]
reading outlier
reading_normal = df_sp[~ (df_sp['reading score'] < lower_bound)]
reading_normal
# ~: 여집합


-.to_csv('저장하고자 하는 파일명.csv'): csv 파일로 저장
reading_outlier.to_csv("reading_outlier.csv")
-박스플롯의 x축 나누기
# df_sp 데이터의 math score 남녀 구분하여 boxplot 그리기
sns.boxplot(df_sp, x='sex', y='math score');

3. 두 범주형 변수의 관계 탐색
1) 교차표(crosstab)
-pd.crosstab(컬럼명1, 컬럼명2, 기타 옵션...): 교차표 그리기
-margins = True: 합계 표시
# df_ins의 성별(남, 여)과 흡연 여부(예, 아니오)
tab1 = pd.crosstab(df_ins["sex"], df_ins["smoker"], margins = True)
tab1

2) 열지도(heatmap)
-sns.heatmap(data=집계표, 기타 옵션...): 히트맵 그리기
-raw data보다는 집계가 완료(가공)된 표를 받음
-cmap: 컬러 맵('Reds', 'YlGnBu', ...(대문자 주의))
-annot = True: 수치 표시
-fmt: 수치의 포맷 지정('d': 정수형, '.nf': 실수형)
sns.heatmap(data=tab1, cmap="Reds", annot=True, fmt='d')

-normalize='all': 전체 데이터를 100%로 하여 상대적 비율 계산
-nomalize='index': 행(가로) 하나하나를 100%로 하여 상대적 비율 계산
-normalize='columns': 열(세로) 하나하나를 100%로 하여 상대적 비율 계산
# 전체 비율 → 모두 더해 1
df_ratio = pd.crosstab(df_ins["sex"], df_ins["smoker"], normalize='all').round(2)
df_ratio
# 행 비율 → 가로로 더해 1
df_row = pd.crosstab(df_ins["sex"], df_ins["smoker"], normalize='index').round(2)
df_row
# 열 비율 → 세로로 더해 1
df_column = pd.crosstab(df_ins["sex"], df_ins["smoker"], normalize='columns').round(2)
df_column



※백분율(% 표현) vs. 비율(소수점(0~1) 표현)
-.applymap(함수명): 데이터프레임에서 각 값마다 함수 적용
# 각 값을 %로 바꾸는 함수 생성
def to_percent(num):
return f"{int(num*100)%}"
df_ratio.applymap(to_percent)

4. 두 수치형 변수의 관계 탐색
1) 산점도(scatterplot)
-sns.scatterplot(data=데이터프레임, x='컬럼명1', y='컬럼명2'): 산점도 그리기(주로 예측하고자 하는 변수가 y)
# 아빠 키와 아들 키의 상관관계 분석
sns.scatterplot(data=df_h, x='father', y='son');
-sns.lmplot(data=데이터프레임, x='컬럼명1', y='컬럼명2'): 산점도와 회귀선(추세선) 한번에 그리기
-line_kws={}: 회귀선에 대한 명령(딕셔너리 형태)
sns.lmplot(data=df_h, x='father', y='son', line_kws={'color':'red'});


2) 상관계수(correlation / coefficient)
-.corr(): 변수들 간 상관계수 표 형태로 구해줌(피어슨 상관계수가 디폴트)
※전체 컬럼에 대해 볼 때는 바로 데이터프레임.corr()
특정 컬럼만 보고싶을 때는 리스트로 묶어 데이터프레임[['컬럼명1, 컬럼명2, ...']].corr()
df_h.corr()
# df_h에는 변수가 son과 father 두 가지이므로 corr 바로 사용 가능

# [실습]
# df_ins 데이터에서 bmi와 charges 간 상관관계 파악
sns.scatterplot(df_ins, x='bmo', y='charges');

# bmi와 charges의 상관계수 파악
df_ins[['bmi', 'charges']].corr()

-hue='컬럼명(범주형)': 그룹을 색상으로 나누어 차원 추가
# 흡연 여부로 구분하여 bmi, charges의 상관관계 파악
sns.scatterplot(df_ins, x='bmi', y='charges', hue='smoker');

>>> 비흡연자이면 bmi가 높아도 건강에 큰 위험에 없다고 판단
>>> 흡연과 비만이 동시에 일어날 경우 위험
즉 bmi, smokers → charges에 영향(다변수 영향)
# 흡연자, 비흡연자 데이터 분리
smoker_yes = df_ins[df_ins['smoker'] == 'yes']
smoker_no = df_ins[df_ins['smoker'] == 'no']
# 흡연자의 bmi와 charges 상관계수
print(smoker_yes[['bmi', 'charges']].corr())
# 비흡연자의 bmi와 charges 상관계수
print(smoker_no[['bmi', 'charges']].corr())


>>> 결론: 흡연자의 경우 bmi와 charges 간 상당한 양의 상관관계가 보임
비흡연자의 경우 bmi와 charges 간 상관관계가 거의 없음
※groupby를 활용한 상관계수 구하기
df_ins[['bmi', 'charges']].groupby(df_ins['smoker']).corr()
# =
df_ins.groupby('smoker')[['bmi', 'charges']].corr()

5. 범주형 변수와 수치형 변수의 관계 탐색
1) 피벗테이블
-.groupby('범주형 변수')['수치형 변수']: 특정 기준에 따라 데이터 묶어 분석
※두 개의 그룹으로 나누려면 대괄호[] 사용
# sex별 reading score 평균이 가장 높은 race는?
# 그룹 2번 짓기
df_sp.groupby(['sex', 'race'])['readingscore'].mean()

-.idmax(): 가장 큰 값을 가진 그룹 반환
# 여성 중 reading score 평균이 가장 높은 인종은?
print(df_sp.groupby(['sex', 'race'])['reading score'].mean()['female'].idmax()) # >>> group E
print(df_sp.groupby(['sex', 'race'])['reading score'].mean()['female'].max()) # >>> 75.38235294117646
-피벗테이블: 데이터프레임에서 범주형 변수의 수준별 수치형 변수에 대한 집계 실행
-데이터프레임.pivot_table(index='범주형변수1', columns='범주형변수2', values='수치형변수', aggfunc='집계함수')
# 성별, 인종별 reading score 평균값 구하기
print(df_sp.pivot_table(index='sex', columns='race', values='reading score', aggfunc='mean'))
print(df_sp.pivot_table(index='sex', values='reading score', aggfunc='mean'))

2) 범주형 변수와 수치형 변수의 히스토그램
# 남녀 구분해서 보험료 히스토그램 그리기
sns.histplot(df_ins, x='charges', hue='sex');

-multiple='dodge': 나란히
-shrink=0.8: 공백
sns.histplot(df_ins, x='charges', hue='sex',
multiple = 'dodge', shrink = 0.8);

3) 범주형 변수와 수치형 변수의 상자그림
# 지역별 보험료 상자그림 그리기
# hue 사용
sns.boxplot(df_ins, y='charges', hue='region');

# hue 대신 x축 사용(x축 이용한 그룹화는 상자그림이 거의 유일)
sns.boxplot(df_ins, y='charges', x='region');

-plt.legend(loc=(가로, 세로)): 좌표 사용하여 범례 오른쪽으로 위치 조정
# 지역별 성별별 보험료 상자그림 그리기
sns.boxplot(df_ins, y='charges', x='region', hue='sex');
# x와 hue 동시 사용 가능(두 번 그룹화)
plt.legend(loc=(1.1, 0.8))

-plt.xticks(rotation=각도): x축 레이블 회전
sns.boxplot(df_sp, y='reading score', x='parental education', hue='sex')
plt.xticks(rotation=45);
# xticks: x축 레이블

#부트캠프후기 #멀티캠퍼스부트캠프 # 데이터마케팅부트캠프
'부트캠프 > 멀티캠퍼스_퍼포먼스 마케팅과 데이터 분석' 카테고리의 다른 글
| [멀티캠퍼스 부트캠프 5주차(2)] 데이터 분석 기본_웹 크롤링(requests, beautifulsoup) (0) | 2026.02.08 |
|---|---|
| [멀티캠퍼스 부트캠프 5주차(1)] 데이터 분석 기본_웹 통신 개념 (0) | 2026.02.03 |
| [멀티캠퍼스 부트캠프 4주차(1)] 데이터 분석 기본_파이썬 기초(자료구조, 판다스) (0) | 2026.01.23 |
| [멀티캠퍼스 부트캠프 3주차] 데이터 분석 기본_파이썬 기초(조건문과 반복문, 함수 기초) (2) | 2026.01.20 |
| [멀티캠퍼스 부트캠프 2주차] 광고 플랫폼 이해_콘텐츠 기획, 뉴미디어(X, 당근, 토스), META, 카카오, 구글 (0) | 2026.01.13 |