๊ธฐ์ ํต๊ณ
์ด๊ธ
ํ์ต ๋ชฉํ
์ด ๋ ์ํผ๋ฅผ ์๋ฃํ๋ฉด ๋ค์์ ํ ์ ์์ต๋๋ค:
- ์ค์ฌ ๊ฒฝํฅ ์งํ (ํ๊ท , ์ค์๊ฐ, ์ต๋น๊ฐ) ๊ณ์ฐ
- ์ฐํฌ๋ ์งํ (ํ์คํธ์ฐจ, ๋ถ์ฐ, 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