Add popularity score for EV-optimized number selection
Adds _calculate_popularity_score() which favors number combinations unlikely to be picked by other players (numbers > 31, no consecutive sequences, avoiding common "lucky numbers"). This doesn't improve hit probability (lottery draws are i.i.d. random) but increases expected value by reducing the chance of sharing a jackpot. - New 20% weight in quality score - New Popularity_Score column in tip CSV export Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -461,6 +461,13 @@
|
|||||||
"file": "weekly_tips_20260610_123037.csv",
|
"file": "weekly_tips_20260610_123037.csv",
|
||||||
"avg_confidence": 0.48925897711447985,
|
"avg_confidence": 0.48925897711447985,
|
||||||
"avg_quality": 0.6018162578186794
|
"avg_quality": 0.6018162578186794
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"timestamp": "2026-06-10T13:32:25.391718",
|
||||||
|
"num_tips": 10,
|
||||||
|
"file": "weekly_tips_20260610_133225.csv",
|
||||||
|
"avg_confidence": 0.48925897711447985,
|
||||||
|
"avg_quality": 0.6080343315716299
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -623,27 +623,54 @@ class UltimateAIMLEurojackpotGenerator:
|
|||||||
random.seed(42 + tip_number * 7)
|
random.seed(42 + tip_number * 7)
|
||||||
return sorted(random.sample(top_euros, 2))
|
return sorted(random.sample(top_euros, 2))
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _calculate_popularity_score(main_numbers):
|
||||||
|
"""
|
||||||
|
Schätzt den Erwartungswert-Vorteil durch Vermeidung populärer Zahlenkombinationen.
|
||||||
|
Höher = unpopulärer = höherer Gewinnanteil bei einem Treffer.
|
||||||
|
Basis: Spieler bevorzugen Geburtstagszahlen (1-31), Glückszahlen und Zahlenfolgen.
|
||||||
|
"""
|
||||||
|
n = len(main_numbers)
|
||||||
|
sorted_nums = sorted(main_numbers)
|
||||||
|
|
||||||
|
# Anteil Zahlen > 31 (Geburtstags-Range vermeiden)
|
||||||
|
above_31_ratio = sum(1 for x in main_numbers if x > 31) / n
|
||||||
|
|
||||||
|
# Aufeinanderfolgende Zahlen vermeiden (visuelle Muster)
|
||||||
|
consecutive_pairs = sum(1 for i in range(n - 1) if sorted_nums[i + 1] - sorted_nums[i] == 1)
|
||||||
|
consecutive_ratio = consecutive_pairs / (n - 1) if n > 1 else 0
|
||||||
|
|
||||||
|
# Häufig gespielte "Glückszahlen" vermeiden
|
||||||
|
lucky_numbers = {3, 7, 9, 11, 13, 17, 19, 21, 23}
|
||||||
|
lucky_ratio = sum(1 for x in main_numbers if x in lucky_numbers) / n
|
||||||
|
|
||||||
|
score = above_31_ratio * 0.5 + (1 - consecutive_ratio) * 0.3 + (1 - lucky_ratio) * 0.2
|
||||||
|
return min(max(score, 0.0), 1.0)
|
||||||
|
|
||||||
def _calculate_quality_score(self, main_numbers, euro_numbers, main_preds, euro_preds, pattern_weight):
|
def _calculate_quality_score(self, main_numbers, euro_numbers, main_preds, euro_preds, pattern_weight):
|
||||||
"""Berechnet Qualität."""
|
"""Berechnet Qualität."""
|
||||||
# Main quality
|
# Main quality
|
||||||
main_scores = [main_preds.get(n, 0.1) for n in main_numbers]
|
main_scores = [main_preds.get(n, 0.1) for n in main_numbers]
|
||||||
main_quality = np.mean(main_scores) * (1 + np.std(main_scores) * 0.5)
|
main_quality = np.mean(main_scores) * (1 + np.std(main_scores) * 0.5)
|
||||||
|
|
||||||
# Euro quality
|
# Euro quality
|
||||||
euro_scores = [euro_preds.get(n, 0.1) for n in euro_numbers]
|
euro_scores = [euro_preds.get(n, 0.1) for n in euro_numbers]
|
||||||
euro_quality = np.mean(euro_scores)
|
euro_quality = np.mean(euro_scores)
|
||||||
|
|
||||||
# Pattern quality
|
# Pattern quality
|
||||||
pattern_quality = pattern_weight
|
pattern_quality = pattern_weight
|
||||||
|
|
||||||
# Diversity
|
# Diversity
|
||||||
distances = []
|
distances = []
|
||||||
for i, n1 in enumerate(main_numbers):
|
for i, n1 in enumerate(main_numbers):
|
||||||
for n2 in main_numbers[i+1:]:
|
for n2 in main_numbers[i+1:]:
|
||||||
distances.append(abs(n1 - n2))
|
distances.append(abs(n1 - n2))
|
||||||
diversity_quality = min(np.mean(distances) / 10.0, 1.0) if distances else 0.5
|
diversity_quality = min(np.mean(distances) / 10.0, 1.0) if distances else 0.5
|
||||||
|
|
||||||
quality = (main_quality * 0.4 + euro_quality * 0.25 + pattern_quality * 0.2 + diversity_quality * 0.15)
|
# Popularity (EV-Vorteil bei Gewinn)
|
||||||
|
popularity_quality = self._calculate_popularity_score(main_numbers)
|
||||||
|
|
||||||
|
quality = (main_quality * 0.35 + euro_quality * 0.2 + pattern_quality * 0.15 + diversity_quality * 0.1 + popularity_quality * 0.2)
|
||||||
return min(quality, 1.0)
|
return min(quality, 1.0)
|
||||||
|
|
||||||
def _print_tip_line(self, tip):
|
def _print_tip_line(self, tip):
|
||||||
@@ -748,7 +775,8 @@ class UltimateAIMLEurojackpotGenerator:
|
|||||||
'Euro_AI_Score': f"{tip['euro_ai_score']:.4f}",
|
'Euro_AI_Score': f"{tip['euro_ai_score']:.4f}",
|
||||||
'Pattern_Weight': f"{tip['pattern_weight']:.4f}",
|
'Pattern_Weight': f"{tip['pattern_weight']:.4f}",
|
||||||
'Confidence': f"{tip['confidence']:.4f}",
|
'Confidence': f"{tip['confidence']:.4f}",
|
||||||
'Quality': f"{tip['quality']:.4f}"
|
'Quality': f"{tip['quality']:.4f}",
|
||||||
|
'Popularity_Score': f"{self._calculate_popularity_score(tip['main_numbers']):.4f}"
|
||||||
})
|
})
|
||||||
|
|
||||||
df_export = pd.DataFrame(rows)
|
df_export = pd.DataFrame(rows)
|
||||||
|
|||||||
Reference in New Issue
Block a user