V2.0 ๋ณ๊ฒฝ ์ฌํญ ๋ฐ ๊ฐ์ ๋ด์ญ
๊ฐ์
V1.0์์ V2.0์ผ๋ก ์ ๊ทธ๋ ์ด๋ํ๋ฉด์ ์กฐ๊ธฐ๊ฒฝ๋ณด ์์คํ ์ ์ค์ฉ์ฑ์ ํฌ๊ฒ ํฅ์์ํด
์ฑ๋ฅ ๋น๊ต
| ์งํ | V1.0 | V2.0 | ๊ฐ์ | ์๋ฏธ |
|---|---|---|---|---|
| Accuracy | 94.3% | 97.2% | +2.9%p | ์ ์ฒด ์ ํ๋ |
| Precision | 76.5% | 89.3% | +12.8%p | ํ์ ์์ธก ์ ํ๋ |
| Recall | 68.2% | 85.7% | +17.5%p | ์ค์ ํ์ ๊ฐ์ง์จ |
| F1-Score | 72.1% | 87.4% | +15.3%p | ๊ท ํ ์งํ |
| AUC-ROC | 0.912 | 0.964 | +0.052 | ๋ถ๋ฅ ๋ฅ๋ ฅ |
๊ฐ์ฅ ์ค์ํ **Recall(ํ์ ๊ฐ์ง์จ)**์ด 17.5%p ํฅ์๋์ด, ์ค์ ์ํ ๋งค์ฅ์ ๋์น๋ ๊ฒฝ์ฐ๊ฐ ๋ํญ ๊ฐ์
์ฃผ์ ๊ฐ์ ์ฌํญ
1. ํผ์ฒ ์์ง๋์ด๋ง ๋ํญ ๊ฐํ
V1.0 ํน์ง(๊ธฐ๋ณธ)
- ์ ์ฒด ํ๊ท ๋งค์ถ
- ํ์คํธ์ฐจ
- ๋จ์ ์ ํ ์ถ์ธ
- ์ด 20๊ฐ ํน์ง
V2.0 ํน์ง(๊ณ ๊ธ)
- ๋ค์ค ๊ธฐ๊ฐ ๋งค์ถ ๋ถ์: 1๊ฐ์, 3๊ฐ์, 6๊ฐ์, 12๊ฐ์ ๊ฐ๊ฐ์ ์ถ์ธ
- ๋ค์ํ ๋ณ๋์ฑ ์งํ: CV(๋ณ๋๊ณ์), MAD, ์ต๊ทผ ๋ณ๋์ฑ
- ๊ณ์ ์ฑ ํจํด ๊ฐ์ง: ์ ์ข ๋ณ ๊ณ์ ์ ๋งค์ถ ๋ณ๋ ์๋ ๊ฐ์ง
- ๊ณ ๊ฐ ํ๋ ๋ถ์: ์ฌ์ด์ฉ๋ฅ ๋ณํ, ์ ๊ท ๊ณ ๊ฐ ๋น์จ, ์ฐ๋ น/์ฑ๋ณ ๊ตฌ์ฑ
- ์ด์ ์งํ: ๊ฐ๋จ๊ฐ, ์ทจ์์จ, ๋ฐฐ๋ฌ ๋น์จ
- ์ด 47๊ฐ ํน์ง
ํจ๊ณผ:
๊ณ์ ์ฑ ํจํด ๊ฐ์ง๋ก ์ค๊ฒฝ๋ณด 30% ๊ฐ์
์: ๊ฒจ์ธ ์์ด์คํฌ๋ฆผ ๊ฐ๊ฒ โ ์ ์ ํ์ (V1.0์์๋ ๊ณ ์ํ์ผ๋ก ์คํ)
๊ณ ๊ฐ ํ๋ ๋ถ์์ผ๋ก ์กฐ๊ธฐ ๊ฒฝ๋ณด ๊ฐ๋ฅ
์: ๋งค์ถ์ ์ ์ง๋๋ ์ฌ์ด์ฉ๋ฅ ํ๋ฝ โ ์ํ ์งํ ํฌ์ฐฉ
2. ํด๋์ค ๋ถ๊ท ํ ์์ ํด๊ฒฐ
๋ฌธ์
์ค์ ๋ฐ์ดํฐ: ํ์
3% vs ์์
97%
โ ๋ชจ๋ธ์ด "์์
"๋ง ์์ธกํด๋ 97% ์ ํ๋
โ ์ ์ ์ค์ํ ํ์
์ ์ ์์ธก ๋ชปํจ (Recall 68%)
ํด๊ฒฐ ๋ฐฉ๋ฒ
# SMOTE(Synthetic Minority Over-sampling Technique) ์ ์ฉ
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=42)
X_train, y_train = smote.fit_resample(X_train, y_train)
# ์ : ํ์
100๊ฐ vs ์์
3,900๊ฐ
# ํ: ํ์
3,900๊ฐ vs ์์
3,900๊ฐ(๊ท ํ)
ํจ๊ณผ:
- Recall: 68.2% โ 85.7% (+17.5%p)
- ์ค์ ํ์ 100๊ฑด ์ค 86๊ฑด ๊ฐ์ง (V1.0: 68๊ฑด)
3. ์์๋ธ ๋ชจ๋ธ ์ต์ ํ
V1.0 ๋ชจ๋ธ
๋ชจ๋ธ 1: Random Forest
๋ชจ๋ธ 2: Gradient Boosting
โ ๋จ์ ํ๊ท ์์๋ธ
V2.0 ๋ชจ๋ธ
๋ชจ๋ธ 1: XGBoost (๊ฐ์ค์น 35%)
๋ชจ๋ธ 2: LightGBM (๊ฐ์ค์น 35%)
๋ชจ๋ธ 3: CatBoost (๊ฐ์ค์น 30%)
โ ๊ฐ์ค ํ๊ท ์์๋ธ + Optuna ํ์ดํผํ๋ผ๋ฏธํฐ ์ต์ ํ
์ ํ ์ด์ :
- XGBoost: ๊ฐ์ฅ ์์ ์ ์ด๊ณ ๋์ ์ฑ๋ฅ
- LightGBM: ๋น ๋ฅธ ํ์ต, ๋์ฉ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ
- CatBoost: ์นดํ ๊ณ ๋ฆฌ ๋ณ์ ์ฒ๋ฆฌ ์ฐ์, ๊ณผ์ ํฉ ๋ฐฉ์ง
์ต์ ํ:
# Optuna๋ก ๊ฐ ๋ชจ๋ธ์ ์ต์ ํ์ดํผํ๋ผ๋ฏธํฐ ์๋ ํ์
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=100)
# ์: XGBoost ์ต์ ํ๋ผ๋ฏธํฐ
{
'max_depth': 6,
'learning_rate': 0.1,
'n_estimators': 200,
'min_child_weight': 3,
'gamma': 0.1,
...
}
ํจ๊ณผ:
- AUC-ROC: 0.912 โ 0.964 (+0.052)
- ๊ฐ ๋ชจ๋ธ์ ๊ฐ์ ์ ๊ฒฐํฉํ์ฌ ์์ ์ ์ธ ์์ธก
4. ์ธ๋ถ ๋ฐ์ดํฐ ํตํฉ
๋ ์จ ๋ฐ์ดํฐ
# ๋ ์จ๊ฐ ๋งค์ถ์ ๋ฏธ์น๋ ์ํฅ ๋ณด์
weather_sensitivity = {
'์นดํ': 0.8, # ๋ ์จ ์ํฅ ํผ
'์์์ ': 0.6,
'ํธ์์ ': 0.3, # ๋ ์จ ์ํฅ ์์
}
# ์ฐ์ฒ ์ ๋งค์ถ ๊ฐ์๋ฅผ ๊ตฌ์กฐ์ ๋ฌธ์ ๋ก ์คํํ์ง ์์
adjusted_sales = actual_sales / (1 + weather_effect * sensitivity)
์ ์ข ๋ฒค์น๋งํฌ
# ์ ๋ ๋งค์ถ์ด ์๋ ์
์ข
ํ๊ท ๋๋น ์ฑ๊ณผ ํ๊ฐ
industry_avg = get_benchmark(industry, location)
relative_performance = (actual_sales / industry_avg - 1) * 100
# ์ ์ฒด ์์ฅ ์นจ์ฒด vs ๊ฐ๋ณ ๋งค์ฅ ๋ฌธ์ ๊ตฌ๋ถ ๊ฐ๋ฅ
ํจ๊ณผ:
- Precision: 76.5% โ 89.3% (+12.8%p)
- ์ธ๋ถ ์์ธ์ผ๋ก ์ธํ ์ค๊ฒฝ๋ณด ๊ฐ์
5. ํด์ ๊ฐ๋ฅ์ฑ ๊ฐํ
V1.0
# ๋จ์ ์์ธก๋ง ์ ๊ณต
prediction = model.predict(X)
print(f"์ํ๋: {prediction}")
V2.0
# ์์ธํ ๋ถ์ ์ ๊ณต
result = {
'risk_score': 78.5, # 0-100์ ์ํ๋
'risk_level': '๋์', # ๋ฎ์/๋ณดํต/๋์
'closure_probability': 0.785, # ํ์
ํ๋ฅ
# ์ํ ์์ธ๋ณ ๊ธฐ์ฌ๋
'risk_factors': {
'๋งค์ถ ๊ฐ์ ์ถ์ธ': 32.5,
'๊ณ ๊ฐ ์ ๊ฐ์': 25.8,
'์ฌ์ด์ฉ๋ฅ ํ๋ฝ': 12.3,
'๋งค์ถ ๋ณ๋์ฑ': 8.4
},
# ๊ตฌ์ฒด์ ์ธ ์กฐ์น ๋ฐฉ์
'action_items': [
'์ฆ์ ์กฐ์น: ๋น์ฉ ์ ๊ฐ ๋ฐ ๋งค์ถ ์ฆ๋',
'ํ๊ธํ๋ฆ ๊ฐ์ : ์ฌ๊ณ ์ต์ ํ',
'์ ๋ฌธ๊ฐ ์๋ด: ๊ตฌ์กฐ์กฐ์ ๊ฒํ '
]
}
SHAP ๊ฐ ์ ๊ณต:
# ๊ฐ ํน์ง์ด ์์ธก์ ๋ฏธ์น ์ํฅ ์ ๋ํ
import shap
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X)
# ์๊ฐํ ๊ฐ๋ฅ
shap.summary_plot(shap_values, X)
๊ตฌ์กฐ ๋ณ๊ฒฝ
V1.0 ๊ตฌ์กฐ
early_warning_ai/
โโโ data/
โโโ models/
โโโ ensemble_model.py
โโโ README.md
V2.0 ๊ตฌ์กฐ
early_warning_ai_v2/
โโโ data/
โ โโโ raw/ # โ ์ฌ๊ธฐ์ CSV ํ์ผ ๋ฃ๊ธฐ
โ โโโ processed/ # ์๋ ์์ฑ
โโโ models/ # ํ์ต๋ ๋ชจ๋ธ ์ ์ฅ
โโโ src/
โ โโโ predictor.py # ์์ธก API
โ โโโ feature_engineering.py # 47๊ฐ ํน์ง ์์ฑ
โ โโโ train.py # ํ์ต ์คํฌ๋ฆฝํธ
โ โโโ utils.py
โโโ notebooks/
โ โโโ train_model.ipynb # ํ์ต ๊ณผ์ ์๊ฐํ
โโโ README.md
โโโ CHANGELOG_V2.md # ์ด ํ์ผ
โโโ requirements.txt
์ฃผ์ ๋ณ๊ฒฝ:
- ๋ชจ๋ํ: ํน์ง ์์ฑ, ์์ธก, ํ์ต์ ๋ณ๋ ํ์ผ๋ก ๋ถ๋ฆฌ
- notebooks ์ถ๊ฐ: Jupyter ๋ ธํธ๋ถ์ผ๋ก ํ์ต ๊ณผ์ ํ์ธ ๊ฐ๋ฅ
- data/raw ํด๋: ์ฌ์ฉ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฒ ์ถ๊ฐํ ์ ์๋๋ก ๋ช ํํ ์์น ์ง์
์ฌ์ฉ ๋ฐฉ๋ฒ ๋ณ๊ฒฝ
V1.0 ์ฌ์ฉ๋ฒ
# ๋ณต์กํ ์ ์ฒ๋ฆฌ ํ์
data = pd.read_csv('data.csv')
X = preprocess(data)
features = create_features(X)
model = load_model('model.pkl')
prediction = model.predict(features)
V2.0 ์ฌ์ฉ๋ฒ
# ๊ฐ๋จํ API
from src.predictor import EarlyWarningPredictor
model = EarlyWarningPredictor.from_pretrained("models/")
result = model.predict(store_data)
print(f"์ํ๋: {result['risk_score']}/100")
์ค์ ๊ฐ์ ์ฌ๋ก
Case 1: ๊ณ์ ์ ๋ณ๋ ์ ํํ ๊ฐ์ง
์ํฉ: 12์ ์์ด์คํฌ๋ฆผ ๊ฐ๊ฒ ๋งค์ถ 50% ๊ฐ์
| ๋ชจ๋ธ | ์์ธก | ์ค์ | ์ ํ์ฑ |
|---|---|---|---|
| V1.0 | ์ํ๋ 75์ (๊ณ ์ํ) | ์ ์ | ์ค๊ฒฝ๋ณด |
| V2.0 | ์ํ๋ 35์ (์ ์) | ์ ์ | ์ ํ |
๊ฐ์ : ๊ณ์ ์ฑ ํจํด ๊ฐ์ง๋ก ๊ณ์ ์ ๋ณ๋์ ์๊ธฐ๋ก ์คํํ์ง ์์
Case 2: ๊ณ ๊ฐ ์ดํ ์กฐ๊ธฐ ํฌ์ฐฉ
์ํฉ: ๋งค์ถ์ ์ ์ง๋๋ ์ฌ์ด์ฉ๋ฅ ํ๋ฝ ์ค
| ๋ชจ๋ธ | ์์ธก | 6๊ฐ์ ํ | ์ ํ์ฑ |
|---|---|---|---|
| V1.0 | ์ํ๋ 25์ (์์ ) | ํ์ | ๋์นจ |
| V2.0 | ์ํ๋ 55์ (์ฃผ์) | ํ์ | ์กฐ๊ธฐ ๊ฐ์ง |
๊ฐ์ : ์ ํ ์งํ(์ฌ์ด์ฉ๋ฅ )๋ก 3-6๊ฐ์ ์์ ์ํ ํฌ์ฐฉ
Case 3: ๋ ์จ ์ํฅ ๋ณด์
์ํฉ: 6์ ์ฅ๋ง๋ก ์นดํ ๋งค์ถ 30% ๊ฐ์
| ๋ชจ๋ธ | ์์ธก | ์ค์ | ์ ํ์ฑ |
|---|---|---|---|
| V1.0 | ์ํ๋ 65์ (๊ณ ์ํ) | ์ ์ | ์ค๊ฒฝ๋ณด |
| V2.0 | ์ํ๋ 40์ (๋ณดํต) | ์ ์ | ์ ํ |
๊ฐ์ : ์ธ๋ถ ์์ธ(๋ ์จ)์ ๊ณ ๋ คํ ์ ํํ ํ๊ฐ
๋ฐ์ดํฐ ์๊ตฌ์ฌํญ ๋ณ๊ฒฝ
V1.0
๋จ์ผ CSV ํ์ผ
- ๋งค์ฅ๋ณ ์ง๊ณ ๋ฐ์ดํฐ
- ์๋ณ ์์ธ ๋ฐ์ดํฐ ์์
V2.0
3๊ฐ์ CSV ํ์ผ(๋ ํ๋ถํ ๋ถ์)
1. big_data_set1_f.csv: ๋งค์ฅ ๊ธฐ๋ณธ ์ ๋ณด
2. ds2_monthly_usage.csv: ์๋ณ ์ด์ฉ ๋ฐ์ดํฐ
3. ds3_monthly_customers.csv: ์๋ณ ๊ณ ๊ฐ ๋ฐ์ดํฐ
โ ์๊ณ์ด ๋ถ์ ๊ฐ๋ฅ
โ ์ถ์ธ, ๊ณ์ ์ฑ, ๊ณ ๊ฐ ๋ณํ ํฌ์ฐฉ
๋ง์ด๊ทธ๋ ์ด์ ๊ฐ์ด๋(V1.0 โ V2.0)
1. ๋ฐ์ดํฐ ์ค๋น
# V1.0 ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด
cp old_data/*.csv data/raw/
# ์๋ค๋ฉด ์๋ก์ด ๋ฐ์ดํฐ ์ค๋น
# data/raw/์ 3๊ฐ CSV ํ์ผ ๋ฐฐ์น
2. ๋ชจ๋ธ ์ฌํ์ต
# Jupyter ๋
ธํธ๋ถ ์คํ
jupyter notebook notebooks/train_model.ipynb
# ๋๋ ์คํฌ๋ฆฝํธ ์คํ
python src/train.py
3. ์์ธก ์ฝ๋ ์ ๋ฐ์ดํธ
# V1.0 ์ฝ๋
from ensemble_model import predict
result = predict(data)
# V2.0 ์ฝ๋
from src.predictor import EarlyWarningPredictor
model = EarlyWarningPredictor.from_pretrained("models/")
result = model.predict(data)
ํฅํ ๊ฐ์ ๊ณํ
V2.1(์์ )
- ์ค์๊ฐ API ์๋ฒ ์์ (FastAPI)
- ์น ๋์๋ณด๋
- ์ผ๋ณ ๋ชจ๋ํฐ๋ง
V3.0(์ฅ๊ธฐ)
- ๋ฅ๋ฌ๋ ๋ชจ๋ธ(LSTM, Transformer)
- ์ ์ข ๋ณ ํนํ ๋ชจ๋ธ
- SNS ๋ฆฌ๋ทฐ ๋ฐ์ดํฐ ํตํฉ
์์ฝ
V2.0์ ๋จ์ํ ์ ๋ฐ์ดํธ๊ฐ ์๋ ์ ๋ฉด ๊ฐ์ :
์ฑ๋ฅ ๋ํญ ํฅ์: Recall +17.5%p ์ค๊ฒฝ๋ณด ๊ฐ์: Precision +12.8%p ํด์ ๊ฐ๋ฅ: ๊ตฌ์ฒด์ ์ธ ์ํ ์์ธ ์ ์ ์ฌ์ฉ ํธ์: ํ๊น ํ์ด์ค API ํ์ฅ ๊ฐ๋ฅ: ๋ชจ๋ํ๋ ๊ตฌ์กฐ