Improve generator quality and sync data (May 2026)
Data: - Add missing draw 2026-05-16 (7 11 20 23 27 30 SZ:9) via GitHub archive - Run retroactive learning for skipped 2026-01-07 draw Generator improvements (ported from Eurojackpot): - Add hard structural filters (sum 100-200, min 1 even + 1 odd per tip) - Add long-term frequency prior as learner dampener (alpha=0.2) - Fix ENSEMBLE strategy generating duplicate tips (greedy → weighted random) - Fix Division-by-Zero edge case in set_frequency_prior - Fix freq_alpha boundary and clip final adjusted value to [0,1] - Prevent negative weights in random.choices (floor at 0.001) - Use vectorized stack().value_counts() for frequency calculation .gitignore: - Exclude data/backups/, weekly tip CSVs, performance reports, data/data/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -146,6 +146,9 @@ class UltimateAIMLHybridGenerator:
|
||||
# 6. Initialize Real-Time Learning
|
||||
print("📚 Activating Real-Time Learning...", end=" ", flush=True)
|
||||
self.real_time_learner.initialize(self.features_df)
|
||||
_counts = self.df[['Z1','Z2','Z3','Z4','Z5','Z6']].stack().value_counts()
|
||||
freq = {n: int(_counts.get(n, 0)) for n in range(1, 50)}
|
||||
self.real_time_learner.set_frequency_prior(freq)
|
||||
print("✅")
|
||||
|
||||
self.is_trained = self.ai_ml_engine.is_trained
|
||||
@@ -230,6 +233,19 @@ class UltimateAIMLHybridGenerator:
|
||||
tip_counter += len(tips)
|
||||
print(f"✅ ({count} tips)")
|
||||
|
||||
# Strukturfilter: Summe + Parität korrigieren
|
||||
fixed_count = 0
|
||||
for tip in all_tips:
|
||||
if not self._passes_structural_constraints(tip['numbers']):
|
||||
tip['numbers'] = self._apply_structural_fix(tip['numbers'], ai_predictions)
|
||||
tip['ai_score'] = np.mean([ai_predictions.get(n, 0.1) for n in tip['numbers']])
|
||||
tip['pattern_weight'] = self.pattern_engine.calculate_pattern_weight(tip['numbers'])
|
||||
tip['confidence'] = (tip['ai_score'] + tip['pattern_weight']) / 2
|
||||
tip['quality'] = self._calculate_quality_score(tip['numbers'], ai_predictions, tip['pattern_weight'])
|
||||
fixed_count += 1
|
||||
if fixed_count:
|
||||
print(f" 🔧 {fixed_count} Tip(s) via Strukturfilter korrigiert (Summe/Parität)")
|
||||
|
||||
# Output all tips
|
||||
print(f"\n📋 RESULTS:")
|
||||
print("=" * 95)
|
||||
@@ -406,29 +422,21 @@ class UltimateAIMLHybridGenerator:
|
||||
|
||||
selected = []
|
||||
for position in range(6):
|
||||
best_candidate = None
|
||||
best_score = -1
|
||||
|
||||
for candidate in all_candidates:
|
||||
if candidate not in selected:
|
||||
ai_s = ai_predictions.get(candidate, 0.1)
|
||||
pattern_s = self.pattern_engine.get_number_pattern_score(candidate)
|
||||
diversity_s = self._calculate_diversity_score(candidate, selected) if selected else 0.5
|
||||
|
||||
ensemble_score = (ai_s * 0.4 + pattern_s * 0.3 + diversity_s * 0.3)
|
||||
|
||||
if ensemble_score > best_score:
|
||||
best_score = ensemble_score
|
||||
best_candidate = candidate
|
||||
|
||||
if best_candidate:
|
||||
selected.append(best_candidate)
|
||||
else:
|
||||
available = [n for n in range(1, 50) if n not in selected]
|
||||
if available:
|
||||
selected.append(random.choice(available))
|
||||
|
||||
selected = sorted(selected[:6])
|
||||
candidates = [c for c in all_candidates if c not in selected]
|
||||
if not candidates:
|
||||
candidates = [n for n in range(1, 50) if n not in selected]
|
||||
|
||||
scores = []
|
||||
for c in candidates:
|
||||
ai_s = ai_predictions.get(c, 0.1)
|
||||
pattern_s = self.pattern_engine.get_number_pattern_score(c)
|
||||
diversity_s = self._calculate_diversity_score(c, selected) if selected else 0.5
|
||||
scores.append(max(0.001, ai_s * 0.4 + pattern_s * 0.3 + diversity_s * 0.3))
|
||||
|
||||
choice = random.choices(candidates, weights=scores)[0]
|
||||
selected.append(choice)
|
||||
|
||||
selected = sorted(selected)
|
||||
superzahl = self._get_smart_superzahl(tip_number)
|
||||
|
||||
ai_score = np.mean([ai_predictions.get(n, 0.1) for n in selected])
|
||||
@@ -447,6 +455,55 @@ class UltimateAIMLHybridGenerator:
|
||||
'quality': quality
|
||||
}
|
||||
|
||||
def _passes_structural_constraints(self, numbers):
|
||||
"""Prüft Summenbereich (122-176) und Parität (mind. 1G + 1U)."""
|
||||
s = sum(numbers)
|
||||
if s < 100 or s > 200:
|
||||
return False
|
||||
even = sum(1 for n in numbers if n % 2 == 0)
|
||||
if even == 0 or even == 6:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _apply_structural_fix(self, numbers, ai_preds):
|
||||
"""Korrigiert Summe/Parität durch minimalen Tausch."""
|
||||
nums = list(numbers)
|
||||
even = [n for n in nums if n % 2 == 0]
|
||||
odd = [n for n in nums if n % 2 != 0]
|
||||
if len(even) == 0:
|
||||
worst = min(odd, key=lambda n: ai_preds.get(n, 0))
|
||||
cands = sorted([n for n in range(2, 50, 2) if n not in nums],
|
||||
key=lambda n: -ai_preds.get(n, 0))
|
||||
if cands:
|
||||
nums.remove(worst)
|
||||
nums.append(cands[0])
|
||||
elif len(odd) == 0:
|
||||
worst = min(even, key=lambda n: ai_preds.get(n, 0))
|
||||
cands = sorted([n for n in range(1, 50, 2) if n not in nums],
|
||||
key=lambda n: -ai_preds.get(n, 0))
|
||||
if cands:
|
||||
nums.remove(worst)
|
||||
nums.append(cands[0])
|
||||
for _ in range(10):
|
||||
s = sum(nums)
|
||||
if 100 <= s <= 200:
|
||||
break
|
||||
if s > 200:
|
||||
highest = max(nums)
|
||||
cands = sorted([n for n in range(1, highest) if n not in nums],
|
||||
key=lambda n: -ai_preds.get(n, 0))
|
||||
if cands:
|
||||
nums.remove(highest)
|
||||
nums.append(cands[0])
|
||||
else:
|
||||
lowest = min(nums)
|
||||
cands = sorted([n for n in range(lowest + 1, 50) if n not in nums],
|
||||
key=lambda n: -ai_preds.get(n, 0))
|
||||
if cands:
|
||||
nums.remove(lowest)
|
||||
nums.append(cands[0])
|
||||
return sorted(nums)
|
||||
|
||||
def _calculate_diversity_score(self, candidate, selected):
|
||||
"""Berechnet Diversitäts-Score."""
|
||||
if not selected:
|
||||
@@ -1295,6 +1352,8 @@ class RealTimeLearner:
|
||||
self.stats = defaultdict(int)
|
||||
self.cache_path = cache_path
|
||||
self.learning_state_file = os.path.join(cache_path, 'learning_state.json') if cache_path else None
|
||||
self.freq_prior = {}
|
||||
self.freq_alpha = 0.2
|
||||
|
||||
# Lade gespeicherten State
|
||||
if self.learning_state_file and os.path.exists(self.learning_state_file):
|
||||
@@ -1304,14 +1363,24 @@ class RealTimeLearner:
|
||||
"""Initialisiert Learning."""
|
||||
self.features_df = features_df
|
||||
|
||||
def adjust_predictions(self, predictions):
|
||||
"""Passt Predictions an."""
|
||||
adjusted = {}
|
||||
def set_frequency_prior(self, freq):
|
||||
"""Setzt Langzeit-Frequenz als Dämpfer (normalisiert auf [0,1])."""
|
||||
max_val = max(freq.values(), default=0)
|
||||
norm = max_val if max_val > 0 else 1
|
||||
self.freq_prior = {n: v / norm for n, v in freq.items()}
|
||||
|
||||
def adjust_predictions(self, predictions):
|
||||
"""Passt Predictions an, gedämpft durch Langzeit-Frequenz."""
|
||||
adjusted = {}
|
||||
for number, pred in predictions.items():
|
||||
adjustment = self.adjustments.get(number, 0)
|
||||
adjusted[number] = np.clip(pred + adjustment * self.learning_rate, 0, 1)
|
||||
|
||||
learner_val = np.clip(pred + adjustment * self.learning_rate, 0, 1)
|
||||
if self.freq_prior:
|
||||
alpha = max(0.0, min(1.0, self.freq_alpha))
|
||||
freq_val = self.freq_prior.get(number, 0.5)
|
||||
adjusted[number] = np.clip((1 - alpha) * learner_val + alpha * freq_val, 0, 1)
|
||||
else:
|
||||
adjusted[number] = learner_val
|
||||
return adjusted
|
||||
|
||||
def learn_from_result(self, drawing):
|
||||
|
||||
Reference in New Issue
Block a user