chore: initial backend + travel-proxy dockerized setup for NAS deployment
This commit is contained in:
68
backend/app/recommender.py
Normal file
68
backend/app/recommender.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import random
|
||||
from collections import Counter
|
||||
from typing import Dict, Any, List, Tuple
|
||||
|
||||
def recommend_numbers(
|
||||
draws: List[Tuple[int, List[int]]],
|
||||
*,
|
||||
recent_window: int = 200,
|
||||
recent_weight: float = 2.0,
|
||||
avoid_recent_k: int = 5,
|
||||
seed: int | None = None,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
가벼운 통계 기반 추천:
|
||||
- 전체 빈도 + 최근(recent_window) 빈도에 가중치를 더한 가중 샘플링
|
||||
- 최근 avoid_recent_k 회차에 나온 번호는 확률을 낮춤(완전 제외는 아님)
|
||||
"""
|
||||
if seed is not None:
|
||||
random.seed(seed)
|
||||
|
||||
# 전체 빈도
|
||||
all_nums = [n for _, nums in draws for n in nums]
|
||||
freq_all = Counter(all_nums)
|
||||
|
||||
# 최근 빈도
|
||||
recent = draws[-recent_window:] if len(draws) >= recent_window else draws
|
||||
recent_nums = [n for _, nums in recent for n in nums]
|
||||
freq_recent = Counter(recent_nums)
|
||||
|
||||
# 최근 k회차 번호(패널티)
|
||||
last_k = draws[-avoid_recent_k:] if len(draws) >= avoid_recent_k else draws
|
||||
last_k_nums = set(n for _, nums in last_k for n in nums)
|
||||
|
||||
# 가중치 구성
|
||||
weights = {}
|
||||
for n in range(1, 46):
|
||||
w = freq_all[n] + recent_weight * freq_recent[n]
|
||||
if n in last_k_nums:
|
||||
w *= 0.6 # 최근에 너무 방금 나온 건 살짝 덜 뽑히게
|
||||
weights[n] = max(w, 0.1)
|
||||
|
||||
# 중복 없이 6개 뽑기(가중 샘플링)
|
||||
chosen = []
|
||||
pool = list(range(1, 46))
|
||||
for _ in range(6):
|
||||
total = sum(weights[n] for n in pool)
|
||||
r = random.random() * total
|
||||
acc = 0.0
|
||||
for n in pool:
|
||||
acc += weights[n]
|
||||
if acc >= r:
|
||||
chosen.append(n)
|
||||
pool.remove(n)
|
||||
break
|
||||
|
||||
chosen_sorted = sorted(chosen)
|
||||
|
||||
explain = {
|
||||
"recent_window": recent_window,
|
||||
"recent_weight": recent_weight,
|
||||
"avoid_recent_k": avoid_recent_k,
|
||||
"top_all": [n for n, _ in freq_all.most_common(10)],
|
||||
"top_recent": [n for n, _ in freq_recent.most_common(10)],
|
||||
"last_k_draws": [d for d, _ in last_k],
|
||||
}
|
||||
|
||||
return {"numbers": chosen_sorted, "explain": explain}
|
||||
|
||||
Reference in New Issue
Block a user