๋ก๋ ๋ฒํธ ์์ธก์ ์ํ ์ถ๊ฐ ํ ์คํธ๋ฅผ ์งํํ์๋ค. ์ด๋ฒ ํ ์คํธ์์๋ ๋จธ์ ๋ฌ๋ ๊ธฐ๋ฐ ๋ชจ๋ธ์ ํ์ฉํ์ฌ ๋ก๋ ๋น์ฒจ ๋ฒํธ๋ฅผ ์์ธกํ๊ณ , ๊ทธ ์ฑ๋ฅ์ ํ๊ฐํ๋ ๊ณผ์ ์ ์งํํ์๋ค.
1. ์์ธก ๋ชจ๋ธ ๊ฐ์
์์ธก์ ์ํด CatBoost, XGBoost, LightGBM, RandomForest ์ด 4๊ฐ์ง ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ ์ฌ์ฉํ์๋ค.
๊ฐ ๋ชจ๋ธ์ ๋ก๋ ๊ณผ๊ฑฐ ๋ฐ์ดํฐ๋ฅผ ํ์ตํ๊ณ , ํน์ ํ์ฐจ์์ ๋น์ฒจ๋ ๊ฐ๋ฅ์ฑ์ด ๋์ ์ซ์๋ฅผ ์์ธกํ๋ ๋ฐฉ์์ผ๋ก ๋์ํ๋ค.
์ฃผ์ ํน์ง
- ๊ณผ๊ฑฐ 10ํ์ฐจ ๋ฐ์ดํฐ๋ฅผ ํ์ฉํ ํผ์ฒ ์์ฑ
- ๊ฐ์ฅ ์์ฃผ ๋ฑ์ฅํ ๋ฒํธ
- ํ์/์ง์ ๋น์จ
- ๋ฎ์ ์ซ์(1~22)์ ๋น์จ
- ์ต๊ทผ 10ํ ๋์ ๊ฐ ๋ฒํธ๊ฐ ๋ฑ์ฅํ ํ์ (1~45๊น์ง 45์ฐจ์ ๋ฒกํฐ)
- ํ๋ จ ๋ฐ ํ
์คํธ ๋ฐ์ดํฐ ๊ตฌ์ฑ
- ํ์ฐจ 11~800: ํ๋ จ ๋ฐ์ดํฐ (train data)
- ํ์ฐจ 801~1000: ๊ฒ์ฆ ๋ฐ์ดํฐ (validation data)
- ํ์ฐจ 1001~1159: ํ ์คํธ ๋ฐ์ดํฐ(test data)
- 4๊ฐ ๋ชจ๋ธ์ ๊ฐ๊ฐ ํ์ตํ์ฌ ์์ธก ํ๋ฅ ์ ํ๊ท ํ
- ๊ฐ ์ซ์(1~45)์ ๋ํด ์์ธก ํ๋ฅ ์ ๊ณ์ฐ
- ํ๋ฅ ์ด ๋์ 6๊ฐ ๋ฒํธ๋ฅผ ์ ํํ์ฌ ์ต์ข ์์ธก๊ฐ์ผ๋ก ์ฌ์ฉ
2. ๋ชจ๋ธ ํ์ต ๊ณผ์
๊ฐ ๋ฒํธ(1~45)์ ๋ํด ๊ฐ๋ณ์ ์ธ ์ด์ง ๋ถ๋ฅ ๋ชจ๋ธ์ ํ์ตํ์๋ค.์ฆ, ์ซ์ 1~45 ๊ฐ๊ฐ์ ๋ํด ๋น์ฒจ๋ ํ๋ฅ ์ ์์ธกํ๋ ๋ชจ๋ธ์ ๋ฐ๋ก ํ์ตํ์ฌ ์ต์ข
์ ์ผ๋ก ์กฐํฉํ๋ ๋ฐฉ์์ด๋ค.
ํ๋ จ๋ ๋ชจ๋ธ์ predict_numbers(X_test) ํจ์๋ฅผ ํตํด ํ ์คํธ ๋ฐ์ดํฐ์์ ๋น์ฒจ ํ๋ฅ ์ด ๋์ ๋ฒํธ๋ฅผ ์์ธกํ๊ฒ ๋๋ค.
์ ์ฒด ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
import pandas as pd
import numpy as np
from catboost import CatBoostClassifier
import xgboost as xgb
import lightgbm as lgb
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score, average_precision_score
# CSV ํ์ผ์์ ๋ฐ์ดํฐ ์ฝ๊ธฐ (์ปฌ๋ผ: 'ํ์ฐจ', '๋ฒํธ1', '๋ฒํธ2', ..., '๋ฒํธ6')
data = pd.read_csv('./lotto/lotto.csv')
# ํ์ฐจ ์์ผ๋ก ์ ๋ ฌ
data = data.sort_values('ํ์ฐจ').reset_index(drop=True)
# ๊ฐ ํ์ฐจ ๋น์ฒจ๋ฒํธ๋ฅผ ์งํฉ ํํ๋ก ๋ณํ
def row_to_set(row):
return set([row['๋ฒํธ1'], row['๋ฒํธ2'], row['๋ฒํธ3'], row['๋ฒํธ4'], row['๋ฒํธ5'], row['๋ฒํธ6']])
data['winning_set'] = data.apply(row_to_set, axis=1)
# ํผ์ฒ ๋ฐ ํ๊น ๋ฐ์ดํฐ ์์ฑ (์ง์ 10ํ ๋ฐ์ดํฐ๋ฅผ ํ์ฉํ๊ธฐ ์ํด 11ํ์ฐจ๋ถํฐ ์ฌ์ฉ)
features = []
targets = []
indices = [] # ํ์ฐจ ๋ฒํธ ์ ์ฅ
for i in range(10, len(data)): # i=10๋ 11ํ์ฐจ์ ํด๋น
# ํ์ฌ ํ์ฐจ ์ด์ ์ ์ ์ฒด ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ฅ ์์ฃผ ๋น์ฒจ๋ ๋ฒํธ ๊ณ์ฐ
past_draws = data.iloc[:i]
freq = np.zeros(46) # ์ธ๋ฑ์ค 0์ ์ฌ์ฉํ์ง ์์
for ws in past_draws['winning_set']:
for num in ws:
freq[num] += 1
most_freq = np.argmax(freq[1:]) + 1 # ์ธ๋ฑ์ค ๋ณด์
# ์ต๊ทผ 10ํ ๋ฐ์ดํฐ ํ์ฉ
window = data.iloc[i-10:i]
window_numbers = []
for ws in window['winning_set']:
window_numbers.extend(list(ws))
window_numbers = np.array(window_numbers)
# ํ์/์ง์ ๋น์จ
odd_count = np.sum(window_numbers % 2 == 1)
odd_ratio = odd_count / len(window_numbers)
# 1~22๋ฒ (๋ฎ์ ๋ฒํธ) ๋น์จ
low_count = np.sum(window_numbers <= 22)
low_ratio = low_count / len(window_numbers)
# ์ต๊ทผ 10ํ ๋น์ฒจ๋ฒํธ์ ๋ฑ์ฅ ํ์๋ฅผ 1~45๊น์ง ๊ณ์ฐ (45์ฐจ์ ๋ฒกํฐ)
window_count = [np.sum(window_numbers == num) for num in range(1, 46)]
# ์ต์ข
ํผ์ฒ: [๊ฐ์ฅ ์์ฃผ ๋น์ฒจ๋ ๋ฒํธ, ํ์ ๋น์จ, ๋ฎ์ ๋ฒํธ ๋น์จ] + [์ต๊ทผ 10ํ ๊ฐ ๋ฒํธ ๋ฑ์ฅ ํ์]
feat = [most_freq, odd_ratio, low_ratio] + window_count
features.append(feat)
# ํ๊น: ํ์ฌ ํ์ฐจ ๋น์ฒจ๋ฒํธ๋ฅผ 45์ฐจ์ ์ด์ง ๋ฒกํฐ๋ก ํํ
target = [1 if num in data.iloc[i]['winning_set'] else 0 for num in range(1, 46)]
targets.append(target)
indices.append(data.iloc[i]['ํ์ฐจ'])
features = np.array(features)
targets = np.array(targets)
# ํ์ฐจ ๋ฒํธ๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ฐ์ดํฐ ๋ถํ
# ํ๋ จ: ํ์ฐจ 11~800, ๊ฒ์ฆ: ํ์ฐจ 801~1000, ํ
์คํธ: ํ์ฐจ 1001 ์ด์
train_idx = [i for i, x in enumerate(indices) if x <= 800]
val_idx = [i for i, x in enumerate(indices) if 801 <= x <= 1000]
test_idx = [i for i, x in enumerate(indices) if x >= 1001]
X_train, y_train = features[train_idx], targets[train_idx]
X_val, y_val = features[val_idx], targets[val_idx]
X_test, y_test = features[test_idx], targets[test_idx]
# ๊ฐ ๋ฒํธ๋ณ ๋ชจ๋ธ ํ์ต์ ์ํ ๋ฆฌ์คํธ ์ด๊ธฐํ
models_cat = []
models_xgb = []
models_lgb = []
models_rf = []
for num in range(45): # ๋ฒํธ 1~45 (์ธ๋ฑ์ค 0๋ถํฐ 44)
y_train_num = y_train[:, num]
y_val_num = y_val[:, num]
# CatBoost ๋ชจ๋ธ
model_cat = CatBoostClassifier(
verbose=False,
random_state=42
)
model_cat.fit(X_train, y_train_num, eval_set=(X_val, y_val_num), verbose=False)
models_cat.append(model_cat)
# XGBoost ๋ชจ๋ธ
model_xgb = xgb.XGBClassifier(
eval_metric='logloss',
random_state=42
)
model_xgb.fit(X_train, y_train_num, eval_set=[(X_val, y_val_num)], verbose=False)
models_xgb.append(model_xgb)
# LGBM ๋ชจ๋ธ
model_lgb = lgb.LGBMClassifier(
random_state=42,
verbosity=-1
)
model_lgb.fit(X_train, y_train_num, eval_set=[(X_val, y_val_num)])
models_lgb.append(model_lgb)
# RandomForest ๋ชจ๋ธ
model_rf = RandomForestClassifier(
random_state=42
)
model_rf.fit(X_train, y_train_num)
models_rf.append(model_rf)
# ๊ฒ์ฆ ๋๋ ํ
์คํธ ์, ๋ค ๋ชจ๋ธ์ ์์ธก ํ๋ฅ ์ ํ๊ท ํ์ฌ ์ต์ข
ํ๋ฅ ์ฐ์ถ
def predict_numbers(X):
preds = []
for i in range(len(X)):
probs = []
for j in range(45):
prob_cat = models_cat[j].predict_proba(X[i].reshape(1, -1))[0][1]
prob_xgb = models_xgb[j].predict_proba(X[i].reshape(1, -1))[0][1]
prob_lgb = models_lgb[j].predict_proba(X[i].reshape(1, -1))[0][1]
prob_rf = models_rf[j].predict_proba(X[i].reshape(1, -1))[0][1]
avg_prob = (prob_cat + prob_xgb + prob_lgb + prob_rf) / 4.0
probs.append(avg_prob)
preds.append(probs)
return np.array(preds)
# ํ
์คํธ ๋ฐ์ดํฐ์ ๋ํ ํ๋ฅ ์์ธก
test_probs = predict_numbers(X_test)
# ์์ 6๊ฐ ๋ฒํธ ์ ํ: ์์ธก ํ๋ฅ ์ด ๊ฐ์ฅ ๋์ ๋ฒํธ 6๊ฐ ์ ํ
test_predictions = []
for probs in test_probs:
top6 = np.argsort(probs)[-6:] + 1 # ์ธ๋ฑ์ค ๋ณด์
test_predictions.append(np.sort(top6))
# ๊ธฐ์กด ํ๊ฐ: Accuracy ๋ฐ F1-Score (๋ค์ค ๋ ์ด๋ธ ํ๊ฐ)
def evaluate_predictions(y_true, y_pred):
accuracies = []
f1s = []
for true, pred in zip(y_true, y_pred):
true_set = set(np.where(true==1)[0])
pred_set = set(np.array(pred) - 1) # ์ธ๋ฑ์ค ์กฐ์
tp = len(true_set & pred_set)
fp = len(pred_set - true_set)
fn = len(true_set - pred_set)
accuracy = (tp + (45 - len(true_set) - fp)) / 45
if tp == 0:
f1 = 0
else:
precision = tp / (tp + fp)
recall = tp / (tp + fn)
f1 = 2 * precision * recall / (precision + recall)
accuracies.append(accuracy)
f1s.append(f1)
return np.mean(accuracies), np.mean(f1s)
acc, f1 = evaluate_predictions(y_test, test_predictions)
print("ํ
์คํธ Accuracy:", acc)
print("ํ
์คํธ F1-Score:", f1)
# ROC-AUC ๋ฐ PR-AUC ํ๊ฐ (๋ค์ค ๋ ์ด๋ธ์ ๊ฒฝ์ฐ Macro Average ์ฌ์ฉ)
roc_auc = roc_auc_score(y_test, test_probs, average='macro')
pr_auc = average_precision_score(y_test, test_probs, average='macro')
print("ํ
์คํธ ROC-AUC:", roc_auc)
print("ํ
์คํธ PR-AUC:", pr_auc)
# ํ
์คํธ ํ์ฐจ ๋น 5์ธํธ ์์ธก (์ค์ ๋ก๋ ๊ตฌ๋งค ์ 5ํ ๊ตฌ๋งค ๋ชจ์ฌ)
def generate_multiple_predictions(X, models_cat, models_xgb, models_lgb, models_rf, num_sets=5):
all_sets = []
for i in range(len(X)):
probs = []
for j in range(45):
prob_cat = models_cat[j].predict_proba(X[i].reshape(1, -1))[0][1]
prob_xgb = models_xgb[j].predict_proba(X[i].reshape(1, -1))[0][1]
prob_lgb = models_lgb[j].predict_proba(X[i].reshape(1, -1))[0][1]
prob_rf = models_rf[j].predict_proba(X[i].reshape(1, -1))[0][1]
avg_prob = (prob_cat + prob_xgb + prob_lgb + prob_rf) / 4.0
probs.append(avg_prob)
probs = np.array(probs)
sets = []
sorted_idx = np.argsort(probs)[::-1]
# ์ฒซ ๋ฒ์งธ ์ธํธ: ์์ 6๊ฐ ๋ฒํธ
sets.append(np.sort(sorted_idx[:6] + 1))
# ์ถ๊ฐ ์ธํธ: ์์ ๋ฒํธ ์กฐํฉ์์ ์ผ๋ถ ๋ฒํธ๋ฅผ ๊ต์ฒดํ์ฌ ๋ณํ ์ ์ฉ
for s in range(1, num_sets):
candidate = list(sorted_idx[:6])
idx_to_swap = s % 6
for cand in sorted_idx:
if cand not in candidate:
candidate[idx_to_swap] = cand
break
sets.append(np.sort(np.array(candidate) + 1))
all_sets.append(sets)
return all_sets
multiple_predictions = generate_multiple_predictions(X_test, models_cat, models_xgb, models_lgb, models_rf, num_sets=5)
# ์์: ์ฒซ ๋ฒ์งธ ํ
์คํธ ํ์ฐจ์ 5์ธํธ ์์ธก ๋ฒํธ ์ถ๋ ฅ
print("์ฒซ ๋ฒ์งธ ํ
์คํธ ํ์ฐจ ์์ธก ๋ฒํธ 5์ธํธ:")
for s in multiple_predictions[-1]:
print(s)
print("1160ํ ๋น์ฒจ ๋ฒํธ")
print('[7, 13, 18, 36, 39, 45]')
3. ๋ชจ๋ธ ํ๊ฐ ๊ฒฐ๊ณผ
์ฑ๋ฅ ์งํ
- ํ ์คํธ Accuracy: 0.7741
- ํ ์คํธ F1-Score: 0.1530
- ํ ์คํธ ROC-AUC: 0.5049
- ํ ์คํธ PR-AUC: 0.1652
โ Accuracy๊ฐ 77.4%๋ก ๋์ ๊ฒ์ฒ๋ผ ๋ณด์ด์ง๋ง, ์ด๋ ์ ์ฒด 45๊ฐ ๋ฒํธ ์ค์์ 6๊ฐ๋ง ์ ๋ต์ด๋ฏ๋ก ์๋ฏธ๊ฐ ํฌ์ง๋ ์๋ค.
โ F1-score์ PR-AUC๊ฐ ๋ฎ๊ฒ ๋์จ ๊ฒ์ ์์ธก๋ ๋ฒํธ์ ์ค์ ๋น์ฒจ ๋ฒํธ๊ฐ ๋ง์ด ์ผ์นํ์ง ์๋๋ค๋ ์๋ฏธ์ด๋ค.
4. ์์ธก ๊ฒฐ๊ณผ ๋ถ์
์ฒซ ๋ฒ์งธ ํ ์คํธ ํ์ฐจ ์์ธก ๋ฒํธ (1160ํ)
์ค์ ๋ก๋๋ฅผ ๊ตฌ๋งคํ๋ค๊ณ ๊ฐ์ ํ๊ณ , ๊ฐ ํ์ฐจ๋ณ 5์ธํธ์ฉ ๋ฒํธ๋ฅผ ์์ธกํ์๋ค.
์ฒซ ๋ฒ์งธ ํ
์คํธ ํ์ฐจ ์์ธก ๋ฒํธ 5์ธํธ:
[14 17 40 41 42 43]
[13 14 17 40 42 43]
[13 14 17 40 41 43]
[13 14 17 41 42 43]
[13 14 40 41 42 43]
1160ํ ์ค์ ๋น์ฒจ ๋ฒํธ
[7, 13, 18, 36, 39, 45]
๋ถ์
- ์์ธก๋ ๋ฒํธ์ ์ค์ ๋น์ฒจ ๋ฒํธ๋ฅผ ๋น๊ตํ์ ๋, 13 ํ๋๋ง ์ผ์นํ์๋ค.
- ์ฆ, ์ ํํ ์์ธก ์ฑ๋ฅ์ ๋ฎ์๋ค.
- ์์ธก ํ๋ฅ ์ด ๋์ ๋ฒํธ๋ฅผ ์ ํํ๋ ๋ฐฉ์์ด์ง๋ง, ์ค์ ๋ก๋๋ ์์ ํ ๋์์ ๊ฐ๊น์ด ๋ถํฌ๋ฅผ ๋ณด์ด๊ธฐ ๋๋ฌธ์ ์์ธก์ด ์ฝ์ง ์๋ค.
5. ๊ฒฐ๋ก ๋ฐ ๊ฐ์ ๋ฐฉํฅ
๊ฒฐ๋ก
- ๋จธ์ ๋ฌ๋ ๋ชจ๋ธ์ ํ์ฉํ์ฌ ๋ก๋ ๋ฒํธ๋ฅผ ์์ธกํ๋ ๊ฒ์ ๋งค์ฐ ์ด๋ ต๋ค.
- ๊ณผ๊ฑฐ ๋ฐ์ดํฐ ํจํด์ ํ์ฉํ๋ค๊ณ ํด๋ ์ค์ ๋น์ฒจ ๋ฒํธ์์ ์ผ์น์จ์ ๋ฎ๋ค.
- ๋จ์ ํ๋ฅ ๊ธฐ๋ฐ ์ ๊ทผ๋ณด๋ค, ์ถ์ฒจ ํจํด์ ๋ํ ์ฌ์ธต ๋ถ์์ด ํ์ํ๋ค.
๊ฐ์ ๋ฐฉํฅ
- ๋ ๋ค์ํ ํผ์ฒ ์ถ๊ฐ
- ํ์ฌ๋ ์ต๊ทผ 10ํ ๋ฐ์ดํฐ๋ง ํ์ฉํ์ง๋ง, ๋ ๊ธด ๊ธฐ๊ฐ์ ํจํด์ ๋ฐ์ํ๋ ๋ฐฉ์์ ๊ณ ๋ คํ ์ ์๋ค.
- ์๋ฅผ ๋ค์ด, ํน์ ๋ฒํธ๊ฐ ๋์จ ์ดํ ๋ค์ ํ์ฐจ์์ ๋ฑ์ฅํ ํ๋ฅ ๋ฑ์ ๋ถ์ํ ์ ์๋ค.
- ๋ค์ํ ๋ชจ๋ธ ์กฐํฉ
- CNN(Convolutional Neural Network) ๋๋ Transformer ๋ชจ๋ธ์ ์ ์ฉํ์ฌ ๋ ์ ๊ตํ ํจํด ํ์ต์ ์๋ํ ์ ์๋ค.
6. ๋ก๋ ๋ฒํธ ์์ธก, ๊ณผ์ฐ ๊ฐ๋ฅํ ๊น?
- ๋จธ์ ๋ฌ๋์ ํ์ฉํ ๋ก๋ ๋ฒํธ ์์ธก์ ๋จ์ํ ๋๋ค ์ ํ๋ณด๋ค ์ผ๋ถ ํ๋ฅ ์ ๊ณ ๋ คํ ์ ์๋ ์ฅ์ ์ด ์์ง๋ง, ์๋ฒฝํ ์์ธก์ ์ฌ์ค์ ๋ถ๊ฐ๋ฅ์ ๊ฐ๊น๋ค.
- ๋ค๋ง, ํน์ ํจํด์ ๋ถ์ํ๊ณ ํ์ฉํ๋ ์ฐ๊ตฌ๋ ์๋ฏธ๊ฐ ์์ ์ ์์ผ๋ฉฐ, ์ฅ๊ธฐ์ ์ธ ๋ถ์์ ํตํด ์ผ๋ถ ์ ์๋ฏธํ ๊ฒฝํฅ์ ์ฐพ์ ์๋ ์๋ค.
โก ๋ก๋ ๋ฒํธ ์์ธก์ ๋จ์ํ ํ๋ฅ ๊ฒ์์ด์ง๋ง, ๋จธ์ ๋ฌ๋์ ํ์ฉํ ๋ค์ํ ํจํด ๋ถ์์ ํตํด ๋์ฑ ์ ๊ตํ ์ ๋ต์ ๋ง๋ค์ด๋ณผ ์ ์์ ๊ฒ์ด๋ค.