Add final_BallFilter, train-based params, ncue run script and README notes

Made-with: Cursor
This commit is contained in:
2026-04-08 19:18:31 +09:00
parent 2bd4ad8fcb
commit 013206ef67
6 changed files with 1006 additions and 0 deletions

307
final_BallFilter.py Normal file
View File

@@ -0,0 +1,307 @@
# -*- coding: utf-8 -*-
"""
학습 구간(1~800회)에서 산출한 final_filter_params 를 사용하는 BallFilter.
BallFilter_25 의 filterOneDigitPattern 버그(인자 덮어쓰기)를 수정했습니다.
"""
from __future__ import annotations
import final_filter_params as P
from BallFilter_25 import BallFilter as BallFilter25
_MAX_CONT = max(P.ALLOW_CONTINUS_MAX)
_TRIPLE_FS = tuple(frozenset(t) for t in P.TRIPLE_BLOCKLIST)
class BallFilter(BallFilter25):
"""학습 데이터 기반 허용 집합을 쓰는 최종 필터."""
def filterOneDigitPattern(self, ball):
digit = set()
for b in ball:
digit.add(b % 10)
return len(digit)
def filterTriplePairBall(self, ball):
s = set(ball)
for t in _TRIPLE_FS:
if t <= s:
return 1
return None
def extract_final_candidates(self, ball, no=None, until_end=False, df=None):
p_ball = df[df["no"] == no - 1].values.tolist()[0]
p_ball = p_ball[1:7]
filter_set = set()
if no is not None:
if self.hasWon(ball, no):
filter_set.add("이전 당첨 번호")
if not until_end:
return filter_set
acc = sum(ball)
if acc not in P._F_SUM6:
filter_set.add("6개 합: {}".format(acc))
if not until_end:
return filter_set
p_acc = sum(p_ball)
if abs(acc - p_acc) not in P._F_SUM6_DIFF:
filter_set.add("6개 합 전주차: {}".format(abs(acc - p_acc)))
if not until_end:
return filter_set
avg = acc // 6
if avg not in P._F_AVG6:
filter_set.add("6개 평균: {}".format(avg))
if not until_end:
return filter_set
p_avg = sum(p_ball) // 6
if abs(avg - p_avg) not in P._F_AVG6_DIFF:
filter_set.add("6개 평균 전주차: {}".format(abs(avg - p_avg)))
if not until_end:
return filter_set
s3f = ball[0] + ball[1] + ball[2]
if s3f not in P._F_SUM3F:
filter_set.add("b1+b2+b3: {}".format(s3f))
if not until_end:
return filter_set
ps3f = p_ball[0] + p_ball[1] + p_ball[2]
if abs(s3f - ps3f) not in P._F_SUM3F_DIFF:
filter_set.add("b1+b2+b3 전주차: {}".format(abs(s3f - ps3f)))
if not until_end:
return filter_set
s3b = ball[3] + ball[4] + ball[5]
if s3b not in P._F_SUM3B:
filter_set.add("b4+b5+b6: {}".format(s3b))
if not until_end:
return filter_set
ps3b = p_ball[3] + p_ball[4] + p_ball[5]
if abs(s3b - ps3b) not in P._F_SUM3B_DIFF:
filter_set.add("b4+b5+b6 전주차: {}".format(abs(s3b - ps3b)))
if not until_end:
return filter_set
l, h = self.getHigLowRate(ball)
if (l in (0, 1) or h in (0, 1)) and (l, h) not in P._F_HL_SEEN:
filter_set.add("high/low: {}".format((l, h)))
if not until_end:
return filter_set
gh = ball[0] + ball[5]
if gh not in P._F_GO_SUM:
filter_set.add("고저합: {}".format(gh))
if not until_end:
return filter_set
pgh = p_ball[0] + p_ball[5]
if abs(gh - pgh) not in P._F_GO_SUM_DIFF:
filter_set.add("고저합 전주차: {}".format(abs(gh - pgh)))
if not until_end:
return filter_set
interval_sum = self.get_ball_interval(ball)
if interval_sum not in P._F_INTERVAL:
filter_set.add("Interval_sum: {}".format(interval_sum))
if not until_end:
return filter_set
p_interval_sum = self.get_ball_interval(p_ball)
if abs(interval_sum - p_interval_sum) not in P._F_INTERVAL_DIFF:
filter_set.add("Interval_sum 전주차: {}".format(abs(interval_sum - p_interval_sum)))
if not until_end:
return filter_set
firstLetterSum = self.getFirstLetterSumBall(ball)
if firstLetterSum not in P._F_FIRST_LETTER:
filter_set.add("첫수합: {}".format(firstLetterSum))
if not until_end:
return filter_set
p_firstLetterSum = self.getFirstLetterSumBall(p_ball)
if abs(firstLetterSum - p_firstLetterSum) not in P._F_FIRST_LETTER_DIFF:
filter_set.add("첫수합 전주차: {}".format(abs(firstLetterSum - p_firstLetterSum)))
if not until_end:
return filter_set
lastLetterSum = self.getLastLetterSumBall(ball)
if lastLetterSum not in P._F_LAST_LETTER:
filter_set.add("끝수합: {}".format(lastLetterSum))
if not until_end:
return filter_set
p_lastLetterSum = self.getLastLetterSumBall(p_ball)
if abs(lastLetterSum - p_lastLetterSum) not in P._F_LAST_LETTER_DIFF:
filter_set.add("끝수합 전주차: {}".format(abs(lastLetterSum - p_lastLetterSum)))
if not until_end:
return filter_set
if ball[0] not in P._F_B0:
filter_set.add("첫수: {}".format(ball[0]))
if not until_end:
return filter_set
if abs(ball[0] - p_ball[0]) not in P._F_B0_DIFF:
filter_set.add("전주와 첫수 차: {}".format(abs(ball[0] - p_ball[0])))
if not until_end:
return filter_set
if ball[5] not in P._F_B5:
filter_set.add("마지막 공: {}".format(ball[5]))
if not until_end:
return filter_set
if abs(ball[5] - p_ball[5]) not in P._F_B5_DIFF:
filter_set.add("마지막 공 전주차: {}".format(abs(ball[5] - p_ball[5])))
if not until_end:
return filter_set
uniq_last_count = self.filterOneDigitPattern(ball)
if uniq_last_count not in P._F_UNIQ_END:
filter_set.add("Unique 끝수 개수: {}".format(uniq_last_count))
if not until_end:
return filter_set
p_uniq = self.filterOneDigitPattern(p_ball)
if abs(uniq_last_count - p_uniq) not in P._F_UNIQ_END_DIFF:
filter_set.add("Unique 끝수 전주차: {}".format(abs(uniq_last_count - p_uniq)))
if not until_end:
return filter_set
ac_value = self.getACValue(ball)
if ac_value not in P._F_AC:
filter_set.add("ac: {}".format(ac_value))
if not until_end:
return filter_set
p_ac_value = self.getACValue(p_ball)
if abs(ac_value - p_ac_value) not in P._F_AC_DIFF:
filter_set.add("ac 전주: {}".format(abs(ac_value - p_ac_value)))
if not until_end:
return filter_set
def _mulchk(n_mul, allow, allow_diff):
bn = len([b for b in ball if b % n_mul == 0])
if bn not in allow:
filter_set.add("{}의배수: {}".format(n_mul, bn))
if not until_end:
return True
pbn = len([b for b in p_ball if b % n_mul == 0])
if abs(bn - pbn) not in allow_diff:
filter_set.add("{}의배수 전주차: {}".format(n_mul, abs(bn - pbn)))
if not until_end:
return True
return False
_pairs = (
(3, P._F_MUL3, P._F_MUL3_DIFF),
(4, P._F_MUL4, P._F_MUL4_DIFF),
(5, P._F_MUL5, P._F_MUL5_DIFF),
(6, P._F_MUL6, P._F_MUL6_DIFF),
(7, P._F_MUL7, P._F_MUL7_DIFF),
(8, P._F_MUL8, P._F_MUL8_DIFF),
(9, P._F_MUL9, P._F_MUL9_DIFF),
(10, P._F_MUL10, P._F_MUL10_DIFF),
(11, P._F_MUL11, P._F_MUL11_DIFF),
(13, P._F_MUL13, P._F_MUL13_DIFF),
(17, P._F_MUL17, P._F_MUL17_DIFF),
(19, P._F_MUL19, P._F_MUL19_DIFF),
(23, P._F_MUL23, P._F_MUL23_DIFF),
)
for n_mul, fa, fd in _pairs:
if _mulchk(n_mul, fa, fd):
return filter_set
pn_acc = len(set(ball) & set(self.primeNumber))
if pn_acc not in P._F_PRIME_N:
filter_set.add("소수: {}".format(pn_acc))
if not until_end:
return filter_set
cn_acc = len(set(ball) & set(self.compositeNumber))
if cn_acc not in P._F_COMPOSITE_N:
filter_set.add("복소수: {}".format(cn_acc))
if not until_end:
return filter_set
diff = abs(cn_acc - len(set(p_ball) & set(self.compositeNumber)))
if diff not in P._F_COMPOSITE_DIFF:
filter_set.add("복소수 전주차: {}".format(diff))
if not until_end:
return filter_set
even_count = len([b for b in ball if b % 2 == 0])
if even_count not in P._F_EVEN_N:
filter_set.add("짝수: {}".format(even_count))
if not until_end:
return filter_set
p_even_count = len([b for b in p_ball if b % 2 == 0])
if abs(even_count - p_even_count) not in P._F_EVEN_DIFF:
filter_set.add("짝수 전주차: {}".format(abs(even_count - p_even_count)))
if not until_end:
return filter_set
for fn in (
self.filterPatternInPaper1,
self.filterPatternInPaper2,
self.filterPatternInPaper3,
self.filterPatternInPaper4,
self.filterPatternInPaper5,
self.filterPatternInPaper6,
):
v = fn(ball)
if v is not None:
filter_set.add(v)
if not until_end:
return filter_set
if not P.DISABLE_FILTER_PREVIOUS_NUMBER:
if self.filterPreviousNumber(ball, no):
filter_set.add("이전회차 수/좌우수")
if not until_end:
return filter_set
count_section10 = self.getNumberOfAppearancesInSection10(ball)
if count_section10 not in P._F_SEC10:
filter_set.add("같은 10구간대만 출현: {}".format(count_section10))
if not until_end:
return filter_set
p_count_section10 = self.getNumberOfAppearancesInSection10(p_ball)
if abs(count_section10 - p_count_section10) not in P._F_SEC10_DIFF:
filter_set.add("같은 10구간대만 출현 전주차: {}".format(abs(count_section10 - p_count_section10)))
if not until_end:
return filter_set
for wk, fw, fwd in (
(8, P._F_W8, P._F_W8_DIFF),
(12, P._F_W12, P._F_W12_DIFF),
(16, P._F_W16, P._F_W16_DIFF),
(20, P._F_W20, P._F_W20_DIFF),
):
exist_ball = self.getWeeksFrequency(ball, df, no, week=wk)
if exist_ball not in fw:
filter_set.add("{} weeks: {}".format(wk, exist_ball))
if not until_end:
return filter_set
p_exist_ball = self.getWeeksFrequency(p_ball, df, no, week=wk)
if abs(exist_ball - p_exist_ball) not in fwd:
filter_set.add("{} weeks 전주차: {}".format(wk, abs(exist_ball - p_exist_ball)))
if not until_end:
return filter_set
type3 = self.filterTriplePairBall(ball)
if type3 is not None:
filter_set.add("직관 3개 볼을 제거: {}".format(type3))
if not until_end:
return filter_set
if not P.DISABLE_FILTER_ALL_PREVIOUS_7:
if self.filterAllPreivous7(ball, no):
filter_set.add("이전 7회차 전부 포함")
if not until_end:
return filter_set
continous_ball = self.getContinusNumber(ball)
if continous_ball > _MAX_CONT:
filter_set.add("연속볼")
if not until_end:
return filter_set
return filter_set
def filter(self, ball, no, until_end=False, df=None, filter_ball=None):
return self.extract_final_candidates(ball=ball, no=no, until_end=until_end, df=df)