기술통계
초급
학습 목표
이 레시피를 완료하면 다음을 할 수 있습니다:
- 중심 경향 지표 (평균, 중앙값, 최빈값) 계산
- 산포도 지표 (표준편차, 분산, IQR) 이해
- 분포 형태 파악 (왜도, 첨도)
- Pandas와 SQL로 기술통계 계산
0. 사전 준비 (Setup)
데이터 실습을 위해 CSV 파일을 로드합니다.
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats
# Load Data
orders = pd.read_csv('src_orders.csv', parse_dates=['created_at'])
items = pd.read_csv('src_order_items.csv')
products = pd.read_csv('src_products.csv')
users = pd.read_csv('src_users.csv')
# Merge for Analysis
df = orders.merge(items, on='order_id').merge(products, on='product_id').merge(users, on='user_id')1. 중심 경향 측정
이론
중심 경향(Central Tendency)은 데이터가 어디에 모여있는지를 나타냅니다.
| 지표 | 설명 | 장점 | 단점 |
|---|---|---|---|
| 평균(Mean) | 모든 값의 합 ÷ 개수 | 모든 데이터 반영 | 이상치에 민감 |
| 중앙값(Median) | 정렬 후 중간값 | 이상치에 강건 | 분포 꼬리 무시 |
| 최빈값(Mode) | 가장 빈번한 값 | 범주형에 유용 | 유일하지 않을 수 있음 |
Pandas로 계산
import pandas as pd
import numpy as np
# 기본 통계
print("=== 중심 경향 ===")
print(f"평균: ${df['sale_price'].mean():.2f}")
print(f"중앙값: ${df['sale_price'].median():.2f}")
print(f"최빈값: ${df['sale_price'].mode()[0]:.2f}")
# describe()로 한번에
print("\n=== describe() ===")
print(df['sale_price'].describe())실행 결과
=== 중심 경향 === 평균: $59.73 중앙값: $39.99 최빈값: $25.00 === describe() === count 181026.000000 mean 59.728416 std 67.142661 min 0.020000 25% 24.900000 50% 39.990002 75% 69.949997 max 999.000000 Name: sale_price, dtype: float64
SQL로 계산
SELECT
AVG(sale_price) as mean_price,
PERCENTILE_CONT(sale_price, 0.5) OVER() as median_price,
MIN(sale_price) as min_price,
MAX(sale_price) as max_price
FROM src_order_items2. 산포도 측정
이론
산포도(Dispersion)는 데이터가 얼마나 퍼져있는지를 나타냅니다.
| 지표 | 설명 | 공식 |
|---|---|---|
| 범위(Range) | 최대 - 최소 | max - min |
| 분산(Variance) | 평균과의 차이 제곱의 평균 | Σ(x-μ)² / n |
| 표준편차(SD) | 분산의 제곱근 | √Variance |
| IQR | Q3 - Q1 | 75% - 25% |
| 변동계수(CV) | 상대적 변동 | SD / Mean × 100% |
Pandas로 계산
print("=== 산포도 ===")
print(f"범위: {df['sale_price'].max() - df['sale_price'].min():.2f}")
print(f"분산: {df['sale_price'].var():.2f}")
print(f"표준편차: {df['sale_price'].std():.2f}")
print(f"IQR: {df['sale_price'].quantile(0.75) - df['sale_price'].quantile(0.25):.2f}")
print(f"변동계수: {df['sale_price'].std() / df['sale_price'].mean() * 100:.1f}%")실행 결과
=== 산포도 === 범위: 998.98 분산: 4508.14 표준편차: 67.14 IQR: 45.05 변동계수: 112.4%
변동계수 활용
# 단위가 다른 변수 비교
cv_price = df['sale_price'].std() / df['sale_price'].mean() * 100
cv_age = df['age'].std() / df['age'].mean() * 100
print(f"가격 변동계수: {cv_price:.1f}%")
print(f"나이 변동계수: {cv_age:.1f}%")
# 변동계수가 높을수록 상대적으로 더 퍼져있음실행 결과
가격 변동계수: 112.4% 나이 변동계수: 41.6%
3. 분포 형태
왜도 (Skewness)
왜도는 분포의 비대칭성을 측정합니다.
- 왜도 = 0: 대칭 분포
- 왜도 > 0: 오른쪽 꼬리 (양의 왜도)
- 왜도 < 0: 왼쪽 꼬리 (음의 왜도)
from scipy import stats
skewness = stats.skew(df['sale_price'].dropna())
print(f"왜도: {skewness:.3f}")
if skewness > 0.5:
print("→ 오른쪽으로 치우침 (고가 제품이 일부 있음)")
elif skewness < -0.5:
print("→ 왼쪽으로 치우침")
else:
print("→ 대칭에 가까움")실행 결과
왜도: 5.062 → 오른쪽으로 치우침 (고가 제품이 일부 있음)
첨도 (Kurtosis)
첨도는 분포의 뾰족한 정도를 측정합니다.
- 첨도 = 0: 정규분포와 유사
- 첨도 > 0: 더 뾰족함 (극단값 많음)
- 첨도 < 0: 더 평평함
kurtosis = stats.kurtosis(df['sale_price'].dropna())
print(f"첨도: {kurtosis:.3f}")실행 결과
첨도: 45.596
4. 그룹별 기술통계
Pandas groupby + agg
# 부서별 기술통계
dept_stats = df.groupby('department')['sale_price'].agg([
('개수', 'count'),
('평균', 'mean'),
('중앙값', 'median'),
('표준편차', 'std'),
('최소', 'min'),
('최대', 'max')
]).round(2)
print("부서별 가격 통계:")
print(dept_stats)실행 결과
부서별 가격 통계:
개수 ... 최대
department ...
Men 90612 ... 999.0
Women 90414 ... 903.0
[2 rows x 6 columns]SQL로 그룹별 통계
SELECT
department,
COUNT(*) as count,
AVG(sale_price) as mean,
STDDEV(sale_price) as std,
MIN(sale_price) as min,
MAX(sale_price) as max
FROM src_order_items oi
JOIN src_products p ON oi.product_id = p.product_id
GROUP BY department
ORDER BY mean DESC퀴즈 1: 기술통계 계산
문제
주문 데이터에서 주문당 아이템 수(num_of_item)에 대해:
- 평균, 중앙값, 표준편차 계산
- 평균과 중앙값의 차이 해석
- 변동계수 계산
정답 보기
# 1. 기본 통계
mean_items = df['num_of_item'].mean()
median_items = df['num_of_item'].median()
std_items = df['num_of_item'].std()
print(f"평균: {mean_items:.2f}")
print(f"중앙값: {median_items:.2f}")
print(f"표준편차: {std_items:.2f}")
# 2. 해석
if mean_items > median_items:
print("\n→ 평균 > 중앙값: 오른쪽 꼬리 분포 (대량 주문이 일부 있음)")
elif mean_items < median_items:
print("\n→ 평균 < 중앙값: 왼쪽 꼬리 분포")
else:
print("\n→ 대칭 분포")
# 3. 변동계수
cv = std_items / mean_items * 100
print(f"\n변동계수: {cv:.1f}%")실행 결과
평균: 1.89 중앙값: 2.00 표준편차: 1.06 → 평균 < 중앙값: 왼쪽 꼬리 분포 변동계수: 55.9%
정리
핵심 함수 요약
| 통계량 | Pandas | SQL |
|---|---|---|
| 평균 | df['col'].mean() | AVG(col) |
| 중앙값 | df['col'].median() | PERCENTILE_CONT(col, 0.5) |
| 표준편차 | df['col'].std() | STDDEV(col) |
| 분산 | df['col'].var() | VARIANCE(col) |
| 최소/최대 | min(), max() | MIN(), MAX() |
| 백분위수 | quantile(0.25) | PERCENTILE_CONT(col, 0.25) |
통계량 선택 가이드
| 상황 | 추천 |
|---|---|
| 이상치 없음 | 평균, 표준편차 |
| 이상치 있음 | 중앙값, IQR |
| 분포 비교 | 변동계수 |
| 비대칭 확인 | 왜도 |
다음 단계
기술통계를 마스터했습니다! 다음으로 상관관계 분석에서 변수 간 관계를 분석하는 방법을 배워보세요.
Last updated on