Compare commits

...
5 Commits
Author SHA1 Message Date
cbazzaandClaude Sonnet 5 5cc34d95b9 Update draws, retrain models and log tip generation run
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 19:08:52 +02:00
cbazzaandClaude Sonnet 5 ab42a13048 Rewrite README to match the actual active system
The old README documented almost exclusively the legacy scripts
removed in the previous commit and never mentioned the real
automation (auto_update_and_learn.py, weekly_tip_generator.py,
launchd) at all. Rewritten to describe what's actually running: the
4-strategy generator, the EV-optimized quality score, the launchd
schedule (not crontab - setup_cron.sh is stale), and the real data
update chain. Links to the new ARCHITECTURE.md for details.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 18:59:38 +02:00
cbazzaandClaude Sonnet 5 0285a1c5fa Ground popularity/EV score in empirical player-choice biases
Ports the fix already applied to the sibling Lotto 6aus49 project.
Since draws are i.i.d., only expected value (jackpot-sharing
avoidance) is improvable, not hit probability. Replaces the ad-hoc
"lucky numbers" list with empirically-documented picks, adds general
arithmetic-progression detection (not just +1 consecutive pairs), and
scores extreme odd/even splits higher (adjusted for 5 main numbers:
distance from the 2.5 midpoint, not 3 as in the 6-number Lotto case).
Deliberately omits a sum-near-mean component - testing against known
overplayed combinations (1-2-3-4-5, 5-10-15-20-25) during the Lotto
port showed it inverted the ranking for tightly clustered sequences.

Raises popularity's weight in the quality score from 20% to 45%
(main/euro/pattern/recency reduced accordingly), since those signals
carry no real predictive value for hit probability.

Also fixes _get_smart_euro_numbers(), which previously returned the
literal same Euro-number pair for tips #1-3 every single run (top-2
AI predictions, no randomization) and had zero EV consideration. Now
weighted-random across all 12 candidates with lucky numbers (3, 7)
downweighted - deliberately more conservative than the main-number
heuristic since 1-12 overlaps with calendar months and has no clear
birthday-range split to exploit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 18:57:55 +02:00
cbazzaandClaude Sonnet 5 f23922e05e Remove unreferenced legacy generators, updater, and analysis scripts
The graphify code-graph pass confirmed nothing in the active pipeline
(scripts/automation/, shell entrypoints) imports or calls any of
these - only scripts/generators/ultimate_ai_ml_eurojackpot_generator.py
is wired into automation. Removes:

- ultimate_ai_ml_eurojackpot_generator_v2.1_backup.py, a verbatim
  duplicate of the active generator's classes (UltimateAIMLEurojackpot-
  Generator, EurojackpotAIMLEngine, PatternEngine, HybridOptimizer)
- optimized_eurojackpot_generator.py, a third standalone generator
  documented in README but never imported
- update_historical_data.py, a second data updater never imported
- 12 standalone analysis/utility scripts (bereichsanalyse, positions-
  analyse, NMMHH generators, processors, etc.) with no automation ties

History is preserved in git if anything here turns out to still be
wanted. README still documents most of these - follow-up needed there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 18:53:39 +02:00
cbazzaandClaude Sonnet 5 5703e6a12c Add ARCHITECTURE.md documenting data flow and active vs. legacy code
Built with a graphify code-graph pass, mirroring the audit done on the
sibling Lotto 6aus49 project. Documents the ingestion -> training ->
tip generation -> notification flow and several findings:

- The data-fetch fallback chain (lottoAPI/Lottoland/Sazka.cz + web
  scraper) is already more robust here than Lotto's was before its fix.
- UltimateAIMLEurojackpotGenerator (and its EurojackpotAIMLEngine/
  PatternEngine/HybridOptimizer) is duplicated verbatim in an unused
  ultimate_ai_ml_eurojackpot_generator_v2.1_backup.py.
- A third standalone generator (optimized_eurojackpot_generator.py)
  and a second updater (update_historical_data.py) exist but aren't
  wired into automation, alongside ~12 unreferenced analysis scripts.
- The popularity/quality score still uses the pre-fix Lotto approach
  (ad-hoc lucky-number list, no arithmetic-progression detection, no
  odd/even split heuristic, popularity only 20% of quality) and Euro
  number selection has no EV consideration at all - a follow-up to
  port the Lotto fix has not been done yet.

graphify-out/ itself is gitignored as a regenerable build artifact.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 18:50:02 +02:00
29 changed files with 723 additions and 5310 deletions
+3
View File
@@ -33,3 +33,6 @@ data/backups/
data/*.backup*
data/generated_tips/weekly_tips_*.csv
data/performance_reports/
# graphify Code-Graph (regenerierbar via /graphify --update)
graphify-out/
+131 -95
View File
@@ -1,120 +1,156 @@
# Eurojackpot Analyse & Generator
Sammlung von Python-Skripten zur Analyse von Eurojackpot-Daten und Generierung von Tipps basierend auf historischen Daten.
Automatisiertes System zur Analyse von Eurojackpot-Daten und Generierung von KI-gestützten Tipps mit Telegram-Benachrichtigungen. Schwesterprojekt von [Lotto 6aus49](../Lotto) — gleiche Architektur, angepasst an das Eurojackpot-Format (5 Hauptzahlen aus 50 + 2 Eurozahlen aus 12).
## Verzeichnisstruktur
Eine detaillierte Architektur- und Datenfluss-Beschreibung steht in [documentation/ARCHITECTURE.md](documentation/ARCHITECTURE.md).
```
.
├── README.md # Diese Datei
├── data/ # Alle CSV-Dateien und Rohdaten
## 🎲 Features
- **🧠 AI/ML-basierte Tipp-Generierung**: Random Forest + LSTM (PyTorch) Hybrid-Predictor
- **🎨 Pattern-Analyse**: Historische Verteilungsmuster
- **⚡ 4-Strategien-System**: HYBRID-OPT, BALANCED-SPREAD, HIGH-EV, SOFT-CONTRARIAN mit adaptiver Gewichtung
- **💰 EV-Optimierung**: Quality-Score gewichtet gezielt auf unpopuläre (aber gleich wahrscheinliche) Zahlenkombinationen, um den Gewinnanteil im Trefferfall zu erhöhen
- **📚 Real-Time Learning**: Kontinuierliches Retraining bei neuen Ziehungen
- **🤖 Automatisierung**: Tipp-Generierung & Datenupdate via launchd
- **📲 Telegram-Benachrichtigungen**: Automatische Tipps direkt aufs Smartphone
- **🔄 Data-Updates**: API-Kette (lottoAPI → Lottoland → Sazka.cz) mit Web-Scraper-Fallback
## 📁 Verzeichnisstruktur
```text
Eurojackpot/
├── README.md
├── config/
│ └── notifications.json # Telegram/Email Config
├── data/
│ ├── AlleEurojackpotzahlen.csv # Ziehungshistorie
│ ├── eurojackpot_ml_models/ # Trainierte Modelle (RF + LSTM)
│ └── generated_tips/ # Generierte Tipps
├── scripts/
│ ├── analysis/ # Analyse-Skripte
│ │ ── bereichskombinationen_analyse.py
│ ├── eurojackpot_bereichsanalyse.py
│ │ ├── positionsanalyse.py
│ │ ├── simple_bereichsanalyse.py
│ │ ── treffer_analyse_umschluesselt.py
├── generators/ # Tipp-Generatoren
│ ├── eurojackpot_generator.py
├── optimized_eurojackpot_generator.py
├── tipp_generator_nmmhh.py
├── tipp_generator_nmmhh_v2.py
── ultimate_ai_ml_eurojackpot_generator.py
└── utils/ # Hilfsskripte
│ ├── create_example_files.py
│ ├── eurojackpot_processor.py
── eurojackpot_processor_fixed.py
│ ├── eurojackpot_simple.py
└── zahlen_umschluesseln.py
├── results/ # Ausgabedateien und Grafiken
── documentation/ # Alte Dokumentation
│ ├── generators/
│ │ ── ultimate_ai_ml_eurojackpot_generator.py # aktiver Generator
│ ├── automation/
│ │ ├── auto_update_and_learn.py # Update + Retraining
│ │ ├── weekly_tip_generator.py # Tipp-Generierung
│ │ ── com.eurojackpot.update.plist
│ └── com.eurojackpot.weekly.plist
└── utils/
├── notifier.py # Telegram/Email
├── update_from_api.py # API-Updater (aktiv)
├── update_from_eurojackpot_zahlen_eu.py # Web-Scraper-Fallback
── deep_learning_engine_pytorch.py # LSTM Engine
├── simple_update.py # Manuelle Eingabe
│ ├── validate_csv.py # manuelles Utility
│ ├── verify_draws.py # manuelles Utility
── health_check.py # manuelles Utility
├── documentation/
└── ARCHITECTURE.md
├── run_tip_generator.sh
── run_update_and_learn.sh
└── logs/
```
## Voraussetzungen
## 🚀 Quick Start
### 1. Installation
```bash
pip install pandas numpy matplotlib scikit-learn
python3 -m venv venv
source venv/bin/activate
pip install pandas numpy scikit-learn requests torch
```
## Verwendung
### 2. Telegram-Bot einrichten
### Analyse ausführen
```bash
cd scripts/analysis
python eurojackpot_bereichsanalyse.py
1. Erstelle einen Bot mit [@BotFather](https://t.me/botfather)
2. Kopiere den Bot-Token, hole deine Chat-ID (z.B. mit [@userinfobot](https://t.me/userinfobot))
3. Konfiguriere `config/notifications.json`:
```json
{
"telegram": {
"enabled": true,
"bot_token": "YOUR_BOT_TOKEN",
"chat_id": "YOUR_CHAT_ID"
}
}
```
### Tipps generieren
```bash
cd scripts/generators
python ultimate_ai_ml_eurojackpot_generator.py
```
### Daten verarbeiten
```bash
cd scripts/utils
python eurojackpot_processor.py
```
## Hauptkomponenten
### Analyse-Skripte
- **bereichskombinationen_analyse.py**: Analysiert Zahlenbereiche in Kombinationen
- **eurojackpot_bereichsanalyse.py**: Detaillierte Bereichsanalyse mit Visualisierung
- **positionsanalyse.py**: Analysiert Zahlen nach Position
- **treffer_analyse_umschluesselt.py**: Trefferanalyse mit Umschlüsselung
### Generatoren
- **ultimate_ai_ml_eurojackpot_generator.py**: ML-basierter Generator mit intelligentem Retraining
- **optimized_eurojackpot_generator.py**: Optimierter Generator mit mehreren Strategien
- **tipp_generator_nmmhh.py**: Generator basierend auf NMMHH-Prinzip
### 🤖 Automatisches ML-Retraining
Das System verwendet **intelligentes Retraining**:
-**Automatische Erkennung**: Prüft ob CSV neuer als ML-Cache
-**Smart Caching**: Nutzt Cache wenn Daten unverändert
-**Auto-Retrain**: Trainiert neu wenn neue Daten verfügbar
**So funktioniert es:**
1. Nach `update_from_eurojackpot_zahlen_eu.py` wird CSV aktualisiert
2. Beim nächsten Generator-Start: CSV-Timestamp > Cache-Timestamp
3. ✅ Automatisches Retraining mit neuen Daten
4. Neue ML-Modelle berücksichtigen aktuelle Ziehungen
**Manuelles Cache-Löschen (falls nötig):**
Test-Benachrichtigung senden:
```bash
cd Eurojackpot
rm -rf cache/
python scripts/generators/ultimate_ai_ml_eurojackpot_generator.py
python scripts/utils/notifier.py --test
```
### Utilities
- **eurojackpot_processor.py**: Verarbeitet und markiert Kombinationen
- **zahlen_umschluesseln.py**: Konvertiert Zahlenkombinationen
- **create_example_files.py**: Erstellt Testdaten
### 3. Tipps manuell generieren
## Datenformat
```bash
python scripts/automation/weekly_tip_generator.py --force --num-tips 10
# Nur Historie anzeigen
python scripts/automation/weekly_tip_generator.py --history
```
### 4. Daten manuell aktualisieren + Modelle neu trainieren
```bash
./run_update_and_learn.sh
```
## 🧠 Generator-Strategien
Der Ultimate AI/ML Hybrid Generator (`scripts/generators/ultimate_ai_ml_eurojackpot_generator.py`) verteilt pro Lauf 10 Tipps über 4 Strategien, deren Gewichtung sich anhand der bisherigen Trefferleistung selbst anpasst (Startwerte in Klammern):
1. **HYBRID-OPT** (40%): AI-Score + historisches Pattern-Gewicht kombiniert
2. **BALANCED-SPREAD** (30%): erzwingt Verteilung über Zonen, kontrollierter Summenbereich
3. **HIGH-EV** (20%): 2 Hauptzahlen >31, meidet empirisch belegte populäre Einzelzahlen — auf EV statt Trefferwahrscheinlichkeit optimiert
4. **SOFT-CONTRARIAN** (10%): bevorzugt in den letzten 30 Ziehungen unterrepräsentierte Zahlen
### Warum EV statt Trefferwahrscheinlichkeit?
Eurojackpot-Ziehungen sind unabhängige Zufallsereignisse — kein Modell kann
die Trefferwahrscheinlichkeit über den statistischen Erwartungswert heben.
Der Quality-Score optimiert deshalb bewusst auf **Expected Value**: unpopuläre
Zahlenkombinationen haben bei einem Treffer weniger Mitgewinner und damit eine
höhere Auszahlung. Details und Quellen dazu in
[documentation/ARCHITECTURE.md](documentation/ARCHITECTURE.md#3-design-entscheidung-quality-score--ev-optimierung).
## 🤖 Automatisierung
Läuft über **launchd** (`~/Library/LaunchAgents/`), nicht crontab:
| Job | Plist | Zeitplan |
| --- | --- | --- |
| Tipp-Generierung | `com.eurojackpot.weekly.plist` | Mo + Do, 21:00 Uhr (Abend vor Di/Fr-Ziehung) |
| Update & Learning | `com.eurojackpot.update.plist` | Mi + Sa, 08:00 Uhr (Morgen nach Di/Fr-Ziehung) |
Beide Plists liegen unter `scripts/automation/` und müssen für die Aktivierung
nach `~/Library/LaunchAgents/` verlinkt/kopiert und mit `launchctl load`
geladen werden.
## 📲 Telegram-Benachrichtigungen
Bei erfolgreicher Tipp-Generierung bzw. nach jeder ausgewerteten Ziehung
verschickt `EurojackpotNotifier` automatisch eine Zusammenfassung (bester
Tipp, Ø Confidence/Quality, Trefferauswertung).
## 📈 Performance Tracking
Alle Generierungen werden in `data/generated_tips/generation_history.json`
protokolliert, alle Ziehungsauswertungen in `data/learning_log.json`.
## 🗂️ Datenformat
`data/AlleEurojackpotzahlen.csv` (Semikolon-getrennt):
Die CSV-Dateien im [data](data/)-Ordner folgen dem Format:
```csv
Zahl1,Zahl2,Zahl3,Zahl4,Zahl5,bereits_gezogen
1,2,3,4,5,0
5,12,23,34,45,1
datum;Z1;Z2;Z3;Z4;Z5;SZ1;SZ2
2012-03-23;5;8;21;37;46;6;8
```
## Hinweise
- Eurojackpot: 5 aus 50 Zahlen + 2 aus 12 Eurozahlen
- Alle Kombinationen: ~139 Millionen Möglichkeiten
- Die Skripte benötigen ausreichend RAM für große Datenmengen
## Weitere Dokumentation
Siehe [documentation/README.md](documentation/README.md) für die ursprüngliche Dokumentation.
- Eurojackpot: 5 aus 50 Hauptzahlen + 2 aus 12 Eurozahlen
- `setup_cron.sh` beschreibt einen älteren, crontab-basierten Zeitplan, der
nicht mehr dem tatsächlich aktiven launchd-Setup entspricht — nicht als
aktuelle Referenz verwenden.
+13
View File
@@ -962,3 +962,16 @@ datum;Z1;Z2;Z3;Z4;Z5;SZ1;SZ2
2026-06-16;9;26;29;37;42;1;7
2026-06-19;16;27;37;42;45;5;12
2026-06-23;24;27;43;48;50;4;12
2026-06-26;17;25;35;39;41;5;9
2026-06-30;12;19;34;44;50;3;8
2026-07-03;4;9;20;25;28;1;3
2026-07-07;6;16;24;41;46;2;3
2026-07-10;13;25;28;42;45;5;12
2026-07-14;5;6;17;34;36;3;11
2026-07-17;6;21;31;47;48;2;9
2026-07-21;4;8;10;17;37;5;7
2026-07-24;4;6;8;17;22;7;10
2026-07-28;11;25;40;41;45;1;5
2026-07-31;4;10;20;40;41;4;6
2026-08-04;3;17;30;35;43;1;12
2026-08-07;1;3;6;13;23;5;7
1 datum Z1 Z2 Z3 Z4 Z5 SZ1 SZ2
962 2026-06-16 9 26 29 37 42 1 7
963 2026-06-19 16 27 37 42 45 5 12
964 2026-06-23 24 27 43 48 50 4 12
965 2026-06-26 17 25 35 39 41 5 9
966 2026-06-30 12 19 34 44 50 3 8
967 2026-07-03 4 9 20 25 28 1 3
968 2026-07-07 6 16 24 41 46 2 3
969 2026-07-10 13 25 28 42 45 5 12
970 2026-07-14 5 6 17 34 36 3 11
971 2026-07-17 6 21 31 47 48 2 9
972 2026-07-21 4 8 10 17 37 5 7
973 2026-07-24 4 6 8 17 22 7 10
974 2026-07-28 11 25 40 41 45 1 5
975 2026-07-31 4 10 20 40 41 4 6
976 2026-08-04 3 17 30 35 43 1 12
977 2026-08-07 1 3 6 13 23 5 7
@@ -1,9 +1,9 @@
{
"trained_at": "2026-06-26T14:12:09.271071",
"num_samples": 943,
"trained_at": "2026-08-08T08:00:38.014984",
"num_samples": 956,
"num_features": 20,
"final_loss": 0.3350204216937224,
"final_val_loss": 0.3224504888057709,
"best_val_loss": 0.32012996077537537,
"epochs_trained": 22
"final_loss": 0.3359047199289004,
"final_val_loss": 0.32727712392807007,
"best_val_loss": 0.32497593263785046,
"epochs_trained": 21
}
@@ -1,9 +1,9 @@
{
"trained_at": "2026-06-26T14:12:02.493679",
"num_samples": 943,
"trained_at": "2026-08-08T08:00:31.473921",
"num_samples": 956,
"num_features": 20,
"final_loss": 0.32751141612728435,
"final_val_loss": 0.3300037036339442,
"best_val_loss": 0.3280275712410609,
"epochs_trained": 30
"final_loss": 0.33306921894351643,
"final_val_loss": 0.32881902654965717,
"best_val_loss": 0.3284312884012858,
"epochs_trained": 20
}
+69 -69
View File
@@ -1,78 +1,78 @@
{
"adjustments_main": {
"1": -0.12619836608746318,
"2": -0.15221250479165757,
"3": -0.16725576971060133,
"4": -0.17991956083653718,
"5": -0.16628347544855948,
"6": -0.1938443906543706,
"7": -0.18109772210361866,
"8": -0.15931078508418037,
"9": -0.1667508747810567,
"10": -0.1557650408354652,
"11": -0.16650629495977046,
"12": -0.19539844102264076,
"13": -0.15613737904077563,
"14": -0.16645817071995633,
"15": -0.14482271091270074,
"16": -0.1281450473660133,
"17": -0.10479049324048999,
"18": -0.11507907310647222,
"19": -0.1425584638001938,
"20": -0.16707436524451125,
"21": -0.12810585677132857,
"22": -0.1790876250355349,
"23": -0.10261991330687453,
"24": -0.20565400571670125,
"25": -0.18120728566028785,
"26": -0.16865521208798265,
"27": -0.15137349832884742,
"28": -0.16645968576456524,
"29": -0.1571303945901751,
"30": -0.1819025385106489,
"31": -0.16653919395700817,
"32": -0.15523736200969857,
"33": -0.1664821604084597,
"34": -0.15664428220600507,
"35": -0.15273288355762948,
"36": -0.1396388962359922,
"37": -0.07551254965229758,
"38": -0.1330577090551517,
"39": -0.11639308425633971,
"40": -0.16813563743232532,
"41": -0.16730757643637156,
"42": -0.14793711630571973,
"43": -0.151292585302194,
"44": -0.12935107126420056,
"45": -0.16951003107554743,
"46": -0.1520774638732381,
"47": -0.11406441743860245,
"48": -0.1279729118208299,
"49": -0.19351903302230727,
"50": -0.1790542892546445
"1": -0.16608198398936372,
"2": -0.20538001276393666,
"3": -0.18969889369537835,
"4": -0.17318339990945472,
"5": -0.2041529162618371,
"6": -0.17167194971141891,
"7": -0.23244299727053913,
"8": -0.1828461769270083,
"9": -0.20480590652032585,
"10": -0.17937672521502113,
"11": -0.20406983228000747,
"12": -0.23171720884079933,
"13": -0.1797939414402776,
"14": -0.218726986482017,
"15": -0.19845640630138875,
"16": -0.1685642063246048,
"17": -0.08845082339173124,
"18": -0.17058915502103805,
"19": -0.18221065780965467,
"20": -0.1903328663635429,
"21": -0.1683113303354663,
"22": -0.21593097649650866,
"23": -0.14399098514385758,
"24": -0.2411834882331731,
"25": -0.17525602370144946,
"26": -0.2207854268205856,
"27": -0.20459393528150874,
"28": -0.19019474357700644,
"29": -0.20998765597413135,
"30": -0.2183466665873564,
"31": -0.20432008864113324,
"32": -0.2082140459353828,
"33": -0.2187494627736534,
"34": -0.18099747238166455,
"35": -0.17696346788244138,
"36": -0.179189218511983,
"37": -0.11896311021030447,
"38": -0.18743360319929292,
"39": -0.15776655098075973,
"40": -0.19082026405727728,
"41": -0.16172406919338378,
"42": -0.18703599479832891,
"43": -0.18966775167799174,
"44": -0.16983645768805158,
"45": -0.19254573310504927,
"46": -0.1909868389863429,
"47": -0.15515569951545483,
"48": -0.1681867722579999,
"49": -0.2440807059750868,
"50": -0.21640413290670632
},
"adjustments_euro": {
"1": -0.1274952805859072,
"2": -0.08356248943314629,
"3": -0.15514841761166354,
"4": -0.16769641312863537,
"5": -0.04496226390910391,
"6": -0.07576564462854152,
"7": -0.031991927667788016,
"8": -0.12741033551216618,
"9": -0.1323058522512846,
"10": -0.15347090287457343,
"11": -0.11382875262351197,
"12": -0.10983575407388531
"1": -0.13847414603178812,
"2": -0.11231134304899443,
"3": -0.15113400421047893,
"4": -0.20511099086305523,
"5": -0.03232079204789439,
"6": -0.11897970312758545,
"7": -0.048634268732921454,
"8": -0.16801815384697347,
"9": -0.15819264741746886,
"10": -0.19193029312048415,
"11": -0.15500731573611248,
"12": -0.13648789370458764
},
"stats": {
"incorrect_main": 2250,
"correct_main": 250,
"incorrect_euro": 500,
"correct_euro": 100,
"cycles": 50,
"last_update": "2026-06-24T08:00:34.777510"
"incorrect_main": 2835,
"correct_main": 315,
"incorrect_euro": 630,
"correct_euro": 126,
"cycles": 63,
"last_update": "2026-08-08T08:00:38.020167"
},
"learning_rate": 0.1,
"last_saved": "2026-06-24T08:00:34.777550"
"last_saved": "2026-08-08T08:00:38.020225"
}
Binary file not shown.
@@ -517,6 +517,83 @@
"file": "weekly_tips_20260704_165830.csv",
"avg_confidence": 0.5226028457900052,
"avg_quality": 0.5218641480233097
},
{
"timestamp": "2026-07-06T21:00:15.960297",
"num_tips": 10,
"file": "weekly_tips_20260706_210015.csv",
"avg_confidence": 0.5226028457900052,
"avg_quality": 0.5218641480233097
},
{
"timestamp": "2026-07-09T21:00:10.431328",
"num_tips": 10,
"file": "weekly_tips_20260709_210010.csv",
"avg_confidence": 0.4576759604396684,
"avg_quality": 0.4899123425520503
},
{
"timestamp": "2026-07-13T21:00:12.010153",
"num_tips": 10,
"file": "weekly_tips_20260713_210012.csv",
"avg_confidence": 0.5001572202836366,
"avg_quality": 0.5060097206485906
},
{
"timestamp": "2026-07-16T21:00:19.490697",
"num_tips": 10,
"file": "weekly_tips_20260716_210019.csv",
"avg_confidence": 0.5238483846177105,
"avg_quality": 0.5258664812725949
},
{
"timestamp": "2026-07-20T21:00:16.518596",
"num_tips": 10,
"file": "weekly_tips_20260720_210016.csv",
"avg_confidence": 0.4854339474855488,
"avg_quality": 0.5006247522288646
},
{
"timestamp": "2026-07-23T21:00:16.708518",
"num_tips": 10,
"file": "weekly_tips_20260723_210016.csv",
"avg_confidence": 0.5152142706004199,
"avg_quality": 0.5145964865224885
},
{
"timestamp": "2026-07-27T21:08:59.062626",
"num_tips": 10,
"file": "weekly_tips_20260727_210859.csv",
"avg_confidence": 0.47424985238563194,
"avg_quality": 0.49870618646900783
},
{
"timestamp": "2026-07-30T21:00:21.594441",
"num_tips": 10,
"file": "weekly_tips_20260730_210021.csv",
"avg_confidence": 0.5101750540191647,
"avg_quality": 0.5123943650959577
},
{
"timestamp": "2026-08-03T21:00:13.073096",
"num_tips": 10,
"file": "weekly_tips_20260803_210013.csv",
"avg_confidence": 0.5409446644482934,
"avg_quality": 0.5203607130907963
},
{
"timestamp": "2026-08-06T21:00:19.537139",
"num_tips": 10,
"file": "weekly_tips_20260806_210019.csv",
"avg_confidence": 0.5060792548620471,
"avg_quality": 0.5070598024768673
},
{
"timestamp": "2026-08-10T19:03:55.303406",
"num_tips": 10,
"file": "weekly_tips_20260810_190355.csv",
"avg_confidence": 0.4962393376563816,
"avg_quality": 0.5413046258517413
}
]
}
+169
View File
@@ -676,6 +676,175 @@
"main": 1.0,
"euro": 0.1
}
},
{
"timestamp": "2026-06-27T08:00:35.750434",
"draw_date": "2026-06-26",
"evaluation": {
"main": 1,
"euro": 1,
"tip": 2
},
"avg_matches": {
"main": 0.6,
"euro": 0.5
}
},
{
"timestamp": "2026-07-01T08:01:25.937379",
"draw_date": "2026-06-30",
"evaluation": {
"main": 1,
"euro": 1,
"tip": 10
},
"avg_matches": {
"main": 0.1,
"euro": 0.4
}
},
{
"timestamp": "2026-07-04T08:01:20.071498",
"draw_date": "2026-07-03",
"evaluation": {
"main": 2,
"euro": 0,
"tip": 1
},
"avg_matches": {
"main": 1.0,
"euro": 0.1
}
},
{
"timestamp": "2026-07-08T08:00:38.507652",
"draw_date": "2026-07-07",
"evaluation": {
"main": 1,
"euro": 1,
"tip": 7
},
"avg_matches": {
"main": 0.4,
"euro": 0.4
}
},
{
"timestamp": "2026-07-11T08:00:36.708330",
"draw_date": "2026-07-10",
"evaluation": {
"main": 2,
"euro": 1,
"tip": 3
},
"avg_matches": {
"main": 1.0,
"euro": 0.2
}
},
{
"timestamp": "2026-07-15T08:00:36.445887",
"draw_date": "2026-07-14",
"evaluation": {
"main": 0,
"euro": 1,
"tip": 2
},
"avg_matches": {
"main": 0.3,
"euro": 0.1
}
},
{
"timestamp": "2026-07-18T08:09:22.468950",
"draw_date": "2026-07-17",
"evaluation": {
"main": 2,
"euro": 1,
"tip": 4
},
"avg_matches": {
"main": 0.4,
"euro": 0.3
}
},
{
"timestamp": "2026-07-22T08:15:54.062417",
"draw_date": "2026-07-21",
"evaluation": {
"main": 1,
"euro": 0,
"tip": 4
},
"avg_matches": {
"main": 0.4,
"euro": 0.2
}
},
{
"timestamp": "2026-07-25T08:10:35.829667",
"draw_date": "2026-07-24",
"evaluation": {
"main": 1,
"euro": 0,
"tip": 2
},
"avg_matches": {
"main": 0.4,
"euro": 0.0
}
},
{
"timestamp": "2026-07-29T08:00:37.275495",
"draw_date": "2026-07-28",
"evaluation": {
"main": 1,
"euro": 0,
"tip": 3
},
"avg_matches": {
"main": 0.3,
"euro": 0.2
}
},
{
"timestamp": "2026-08-01T08:00:38.526101",
"draw_date": "2026-07-31",
"evaluation": {
"main": 1,
"euro": 1,
"tip": 2
},
"avg_matches": {
"main": 0.3,
"euro": 0.3
}
},
{
"timestamp": "2026-08-05T08:00:36.980662",
"draw_date": "2026-08-04",
"evaluation": {
"main": 1,
"euro": 0,
"tip": 1
},
"avg_matches": {
"main": 0.3,
"euro": 0.0
}
},
{
"timestamp": "2026-08-08T08:00:38.021759",
"draw_date": "2026-08-07",
"evaluation": {
"main": 1,
"euro": 1,
"tip": 4
},
"avg_matches": {
"main": 0.1,
"euro": 1.0
}
}
]
}
+161
View File
@@ -0,0 +1,161 @@
# Architektur
Dieses Dokument beschreibt den aktiven Datenfluss, die Kernkomponenten und
bekannte Schwachstellen des Eurojackpot-Systems. Erstellt mit Hilfe einer
Code-Graph-Analyse (`graphify-out/`) analog zum Schwesterprojekt Lotto 6aus49
— siehe dort `documentation/ARCHITECTURE.md` für den Vergleich. Format: 5
Hauptzahlen (150) + 2 Eurozahlen.
## 1. Aktiver Datenfluss
```mermaid
flowchart LR
subgraph Ingestion["1. Daten-Ingestion"]
A1[lottoAPI / Lottoland / Sazka.cz] -->|EurojackpotAPIUpdater| B[AlleEurojackpotzahlen.csv]
A2[eurojackpot-zahlen.eu<br/>Web-Scraper Fallback] -.->|nur falls API leer| B
end
subgraph Training["2. Training"]
B --> C[EurojackpotFeatureEngineer]
C --> D[EurojackpotAIMLEngine<br/>RandomForest]
C --> E[DeepLearningEngine<br/>LSTM, PyTorch]
D --> F[Hybrid Predictor]
E --> F
end
subgraph Generation["3. Tipp-Generierung"]
F --> G[UltimateAIMLEurojackpotGenerator]
G --> H1[HYBRID-OPT]
G --> H2[BALANCED-SPREAD]
G --> H3[HIGH-EV]
G --> H4[SOFT-CONTRARIAN]
H1 & H2 & H3 & H4 --> I[Quality/Popularity Score<br/>5 Hauptzahlen + 2 Eurozahlen]
I --> J[10 Tipps als CSV]
end
subgraph Learning["4. Learning-Loop"]
B -->|neue Ziehung| K[AutoUpdateAndLearn]
K -->|evaluiert| J
K -->|retrained| D
K -->|retrained| E
K --> L[EurojackpotRealTimeLearner /<br/>strategy_weights]
end
J --> M[EurojackpotNotifier<br/>Telegram]
K --> M
L -.->|beeinflusst nächsten Lauf| G
```
**Zwei launchd-Jobs** (nicht crontab — siehe Abschnitt 4):
| Schritt | Entrypoint | Zeitplan (tatsächlich) |
|---|---|---|
| Ingestion + Training + Learning | `run_update_and_learn.sh``scripts/automation/auto_update_and_learn.py` | Mi + Sa, 08:00 Uhr (Morgen nach Di/Fr-Ziehung) |
| Tipp-Generierung | `run_tip_generator.sh``scripts/automation/weekly_tip_generator.py` | Mo + Do, 21:00 Uhr (Abend vor Di/Fr-Ziehung) |
Anders als beim Lotto-Projekt prüft der Update-Job hier erst am **nächsten
Morgen**, nicht noch am Ziehungsabend — das gibt den Datenquellen mehr Zeit,
die Ziehung zu veröffentlichen.
## 2. Kernkomponenten (aktive Pipeline)
Alle Pfade relativ zum Projekt-Root.
| Komponente | Datei | Rolle |
|---|---|---|
| `EurojackpotAPIUpdater` | `scripts/utils/update_from_api.py` | Holt neue Ziehungen über `fetch_from_all_apis()`: lottoAPI, Lottoland, Sazka.cz. `AutoUpdateAndLearn.update_data()` nutzt bereits `api_name='all'` **und** fällt bei leerem API-Ergebnis zusätzlich auf einen Web-Scraper zurück — robuster als die Lotto-Pipeline vor deren Fix. |
| `WebScraper` (`EurojackpotUpdater`) | `scripts/utils/update_from_eurojackpot_zahlen_eu.py` | Zweiter Fallback, wird nur aktiv wenn die API-Kette keine neuen Daten liefert. |
| `AutoUpdateAndLearn` | `scripts/automation/auto_update_and_learn.py` | Orchestriert: Daten aktualisieren → neue Ziehung prüfen → letzte Tipps evaluieren → Learning-Update (Retraining). |
| `EurojackpotFeatureEngineer` | `scripts/generators/ultimate_ai_ml_eurojackpot_generator.py` | Feature-Engineering (Frequenzen, Gaps, Momentum) für Haupt- und Eurozahlen. |
| `EurojackpotAIMLEngine` | `scripts/generators/ultimate_ai_ml_eurojackpot_generator.py` | RandomForest-Modelle. **Achtung:** eine Klasse mit identischem Namen existiert nochmal in der Backup-Datei (siehe Abschnitt 5) — beim Editieren die richtige Datei prüfen. |
| `DeepLearningEngine` | `scripts/utils/deep_learning_engine_pytorch.py` | LSTM (PyTorch), analog zu Lotto. |
| `UltimateAIMLEurojackpotGenerator` | `scripts/generators/ultimate_ai_ml_eurojackpot_generator.py` | **God Node der Pipeline** (40 Kanten im Code-Graph) — zentraler Einstiegspunkt `generate_ultimate_tips()`. |
| `EurojackpotPatternEngine`, `EurojackpotHybridOptimizer` | `scripts/generators/ultimate_ai_ml_eurojackpot_generator.py` | Wie bei Lotto: historische Muster bzw. Kandidaten-Generierung für HYBRID-OPT. |
| `EurojackpotRealTimeLearner` | `scripts/generators/ultimate_ai_ml_eurojackpot_generator.py` | Persistiert Learning-State, passt `strategy_weights` an. |
| `EurojackpotPerformanceTracker` | `scripts/generators/ultimate_ai_ml_eurojackpot_generator.py` | Loggt Trefferauswertungen. |
| `EurojackpotNotifier` | `scripts/utils/notifier.py` | Telegram-Benachrichtigungen. |
### Die 4 Tipp-Strategien
Analog zu Lotto: HYBRID-OPT, BALANCED-SPREAD, HIGH-EV, SOFT-CONTRARIAN —
gleiche Namen, gleiches Grundprinzip, aber Zahlenraum 150 (5 Hauptzahlen)
statt 149 (6 Zahlen) plus zusätzlich 2 Eurozahlen (`_get_smart_euro_numbers`).
## 3. Design-Entscheidung: Quality-Score = EV-Optimierung — hier noch nicht nachgezogen
Wie beim Lotto-Projekt gilt: Eurojackpot-Ziehungen sind unabhängige
Zufallsereignisse, kein Modell kann die Trefferwahrscheinlichkeit über den
Zufalls-Erwartungswert heben. `_calculate_quality_score()` sollte deshalb auf
Expected Value (unpopuläre Kombinationen → höhere Auszahlung bei Treffer)
optimieren.
**Der Code hier entspricht noch dem alten, unrevidierten Lotto-Stand
(vor der Überarbeitung dort):**
- `_calculate_popularity_score()` (Zeile 688) nutzt weiterhin die ad-hoc
`lucky_numbers = {3, 7, 9, 11, 13, 17, 19, 21, 23}`-Liste ohne empirische
Grundlage, statt der bei Lotto inzwischen verwendeten
`POPULAR_PLAYER_PICKS = {5, 7, 9, 11, 12, 13}`.
- Nur direkte ±1-Nachbarn werden als Muster erkannt, keine allgemeinen
arithmetischen Folgen (z.B. 5-10-15-20-25).
- Kein Odd/Even-Split-Kriterium.
- Popularity zählt nur 20% der Quality-Formel (`main_quality` 25%,
`euro_quality` 15%, `pattern_quality` 15%, `diversity` 10%, `popularity`
20%, `recency` 15%) — Recency/Pattern-Anteile folgen Heuristiken, die auch
andere Systemspieler nutzen und damit das EV-Ziel eher unterlaufen.
- **`_get_smart_euro_numbers()`** (Zeile 673) hat **gar keine**
EV-Betrachtung — die 2 Eurozahlen werden rein nach AI-Score gewählt, analog
zur alten (inzwischen bei Lotto durch eine EV-Heuristik ersetzten)
Superzahl-Logik.
Eine Übertragung der Lotto-Fixes (siehe dortiges `ARCHITECTURE.md` Abschnitt 3)
auf dieses Projekt steht noch aus.
## 4. Automatisierung
Läuft über **launchd** (`~/Library/LaunchAgents/`), nicht über `crontab`:
| launchd Job | Plist | Zeitplan |
|---|---|---|
| `com.eurojackpot.update` | `scripts/automation/com.eurojackpot.update.plist` | Mi + Sa, 08:00 Uhr |
| `com.eurojackpot.weekly` | `scripts/automation/com.eurojackpot.weekly.plist` | Mo + Do, 21:00 Uhr |
## 5. Bekannte Schwachstellen / offene Punkte
- **Echtes Klassen-Duplikat:** `UltimateAIMLEurojackpotGenerator` (inkl.
`EurojackpotAIMLEngine`, `EurojackpotPatternEngine`,
`EurojackpotHybridOptimizer`) ist **wortgleich** sowohl in der aktiven
`scripts/generators/ultimate_ai_ml_eurojackpot_generator.py` als auch in
`scripts/generators/ultimate_ai_ml_eurojackpot_generator_v2.1_backup.py`
definiert. Nur die erste Datei wird importiert
(`auto_update_and_learn.py`, `weekly_tip_generator.py`).
- **Dritter, eigenständiger Generator:** `optimized_eurojackpot_generator.py`
(Klasse `UltimativerEurojackpotGenerator`) ist im README als Feature
dokumentiert, aber nirgends in der Automatisierung importiert.
- **Ungenutzter zweiter Updater:** `scripts/utils/update_historical_data.py`
(`EurojackpotDataUpdater`, eigene Quellen euro-jackpot.net/eurojackpot.de)
wird von keinem aktiven Skript referenziert.
- **~12 Standalone-Analyse-/Utility-Skripte** ohne Anbindung an die
Automatisierung: `eurojackpot_processor.py`, `eurojackpot_processor_fixed.py`,
`eurojackpot_simple.py`, `bereichskombinationen_analyse.py`,
`positionsanalyse.py`, `zahlen_umschluesseln.py`,
`treffer_analyse_umschluesselt.py`, `simple_bereichsanalyse.py`,
`create_example_files.py`, `tipp_generator_nmmhh.py`,
`tipp_generator_nmmhh_v2.py`, `eurojackpot_bereichsanalyse.py`,
`eurojackpot_generator.py`.
- **Popularity/Quality-Score veraltet** — siehe Abschnitt 3.
- **`documentation/`-Ordner** enthält laut README selbst "Alte Dokumentation"
(`README 2.md`, `NOTIFICATIONS_SETUP.md`, `ULTIMATE_GENERATOR_GUIDE.md`) —
Aktualität gegenüber dem laufenden Code nicht verifiziert.
## 6. Code-Graph
Navigierbare Graph-Ansicht unter `graphify-out/`:
- `graphify-out/graph.html` — interaktive Visualisierung
- `graphify-out/GRAPH_REPORT.md` — God Nodes, Communities, auffällige Verbindungen
- `graphify-out/graph.json` — Rohdaten
Bei strukturellen Änderungen: `/graphify --update` zum inkrementellen
Neuaufbau.
@@ -1,188 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot Bereichskombinationen-Analyse
Analysiert die Kombinationen von Zahlenbereichen in den gezogenen 5er-Kombinationen.
Focus auf Z1-Z4 wie gewünscht.
"""
import pandas as pd
from collections import Counter, defaultdict
def get_range_for_number(number):
"""Bestimmt den Bereich für eine gegebene Zahl."""
if 1 <= number <= 10:
return 'A(1-10)'
elif 11 <= number <= 20:
return 'B(11-20)'
elif 21 <= number <= 30:
return 'C(21-30)'
elif 31 <= number <= 40:
return 'D(31-40)'
elif 41 <= number <= 50:
return 'E(41-50)'
else:
return 'Unknown'
def analyze_range_combinations():
"""Analysiert Bereichskombinationen in Eurojackpot-Ziehungen."""
# Daten laden
df = pd.read_csv("/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/data/AlleEurojackpotzahlen.csv", sep=';')
print(f"🎲 EUROJACKPOT BEREICHSKOMBINATIONEN-ANALYSE")
print(f"Anzahl analysierte Ziehungen: {len(df)}")
print("="*60)
# Analyse für Z1-Z4 (wie gewünscht)
z_columns_z1_z4 = ['Z1', 'Z2', 'Z3', 'Z4']
# Alle Kombinationen sammeln
combinations_z1_z4 = []
range_patterns_z1_z4 = []
for _, row in df.iterrows():
# Bereiche für Z1-Z4 bestimmen
ranges = [get_range_for_number(row[col]) for col in z_columns_z1_z4]
range_pattern = '|'.join(sorted(ranges)) # Sortiert für einheitliche Muster
combinations_z1_z4.append(tuple(ranges))
range_patterns_z1_z4.append(range_pattern)
# Auch vollständige Z1-Z5 Analyse
z_columns_all = ['Z1', 'Z2', 'Z3', 'Z4', 'Z5']
combinations_all = []
range_patterns_all = []
for _, row in df.iterrows():
ranges = [get_range_for_number(row[col]) for col in z_columns_all]
range_pattern = '|'.join(sorted(ranges))
combinations_all.append(tuple(ranges))
range_patterns_all.append(range_pattern)
# Häufigkeitsanalyse
print("\n📊 ANALYSE Z1-Z4 (4 Zahlen):")
print("="*40)
pattern_counts_z1_z4 = Counter(range_patterns_z1_z4)
print(f"Häufigste Bereichskombinationen (Z1-Z4):")
for i, (pattern, count) in enumerate(pattern_counts_z1_z4.most_common(15), 1):
percentage = (count / len(df)) * 100
print(f"{i:2}. {pattern:30} {count:3}x ({percentage:4.1f}%)")
print(f"\n📊 VERGLEICH: ANALYSE Z1-Z5 (alle 5 Zahlen):")
print("="*40)
pattern_counts_all = Counter(range_patterns_all)
print(f"Häufigste Bereichskombinationen (Z1-Z5):")
for i, (pattern, count) in enumerate(pattern_counts_all.most_common(15), 1):
percentage = (count / len(df)) * 100
print(f"{i:2}. {pattern:35} {count:3}x ({percentage:4.1f}%)")
# Analyse der Bereichsverteilung in Kombinationen
print(f"\n🎯 BEREICHSVERTEILUNG IN KOMBINATIONEN:")
print("="*50)
# Wie oft kommt jeder Bereich in Z1-Z4 vor?
range_in_combination_counts = defaultdict(int)
for combination in combinations_z1_z4:
for range_name in set(combination): # set() um Duplikate zu vermeiden
range_in_combination_counts[range_name] += 1
print("Häufigkeit der Bereiche in Z1-Z4 Kombinationen:")
for range_name in ['A(1-10)', 'B(11-20)', 'C(21-30)', 'D(31-40)', 'E(41-50)']:
count = range_in_combination_counts[range_name]
percentage = (count / len(df)) * 100
print(f"{range_name}: {count:3} Kombinationen ({percentage:4.1f}%)")
# Analyse: Wie viele verschiedene Bereiche pro Kombination?
print(f"\n📈 BEREICHSVIELFALT PRO KOMBINATION (Z1-Z4):")
print("="*45)
diversity_counts = defaultdict(int)
for combination in combinations_z1_z4:
unique_ranges = len(set(combination))
diversity_counts[unique_ranges] += 1
for num_ranges in sorted(diversity_counts.keys()):
count = diversity_counts[num_ranges]
percentage = (count / len(df)) * 100
print(f"{num_ranges} verschiedene Bereiche: {count:3} Kombinationen ({percentage:4.1f}%)")
# Spezielle Muster
print(f"\n🔍 SPEZIELLE MUSTER (Z1-Z4):")
print("="*35)
# Alle aus dem gleichen Bereich
same_range_count = sum(1 for combo in combinations_z1_z4 if len(set(combo)) == 1)
print(f"Alle 4 Zahlen aus gleichem Bereich: {same_range_count} ({(same_range_count/len(df)*100):.1f}%)")
# Alle aus verschiedenen Bereichen (4 verschiedene)
all_different_count = sum(1 for combo in combinations_z1_z4 if len(set(combo)) == 4)
print(f"Alle 4 Zahlen aus verschiedenen Bereichen: {all_different_count} ({(all_different_count/len(df)*100):.1f}%)")
# Benachbarte Bereiche-Analyse
print(f"\n🏠 BENACHBARTE BEREICHE-ANALYSE (Z1-Z4):")
print("="*40)
adjacent_patterns = {
'A+B': 0, # 1-10 + 11-20
'B+C': 0, # 11-20 + 21-30
'C+D': 0, # 21-30 + 31-40
'D+E': 0, # 31-40 + 41-50
}
for combination in combinations_z1_z4:
ranges_set = set(combination)
if 'A(1-10)' in ranges_set and 'B(11-20)' in ranges_set:
adjacent_patterns['A+B'] += 1
if 'B(11-20)' in ranges_set and 'C(21-30)' in ranges_set:
adjacent_patterns['B+C'] += 1
if 'C(21-30)' in ranges_set and 'D(31-40)' in ranges_set:
adjacent_patterns['C+D'] += 1
if 'D(31-40)' in ranges_set and 'E(41-50)' in ranges_set:
adjacent_patterns['D+E'] += 1
for pattern, count in adjacent_patterns.items():
percentage = (count / len(df)) * 100
print(f"Benachbarte Bereiche {pattern}: {count:3} Kombinationen ({percentage:4.1f}%)")
# Export der Ergebnisse
print(f"\n💾 EXPORT DER ERGEBNISSE:")
print("="*30)
# DataFrame für Z1-Z4 Kombinationen erstellen
results_data = []
for i, row in df.iterrows():
ranges_z1_z4 = [get_range_for_number(row[col]) for col in z_columns_z1_z4]
pattern = '|'.join(sorted(ranges_z1_z4))
diversity = len(set(ranges_z1_z4))
results_data.append({
'datum': row['datum'],
'Z1': row['Z1'],
'Z2': row['Z2'],
'Z3': row['Z3'],
'Z4': row['Z4'],
'Z1_bereich': ranges_z1_z4[0],
'Z2_bereich': ranges_z1_z4[1],
'Z3_bereich': ranges_z1_z4[2],
'Z4_bereich': ranges_z1_z4[3],
'bereichsmuster': pattern,
'anzahl_bereiche': diversity
})
results_df = pd.DataFrame(results_data)
output_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/bereichskombinationen_z1_z4.csv"
results_df.to_csv(output_file, sep=';', index=False)
print(f"✅ Detailergebnisse gespeichert: bereichskombinationen_z1_z4.csv")
return pattern_counts_z1_z4, pattern_counts_all
if __name__ == "__main__":
analyze_range_combinations()
@@ -1,217 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot Bereichsanalyse
Analysiert, in welchen Zahlenbereichen am häufigsten Zahlen gezogen wurden.
"""
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
from collections import Counter
def load_drawn_numbers(filepath):
"""Lädt die gezogenen Eurojackpot-Zahlen."""
try:
df = pd.read_csv(filepath, sep=';')
print(f"Gezogene Zahlen geladen: {len(df)} Ziehungen")
print(f"Spalten: {list(df.columns)}")
return df
except Exception as e:
print(f"Fehler beim Laden: {e}")
return None
def analyze_number_ranges(df):
"""Analysiert die Häufigkeit von Zahlen in verschiedenen Bereichen."""
# Alle gezogenen Zahlen sammeln (Z1-Z5)
all_numbers = []
for col in ['Z1', 'Z2', 'Z3', 'Z4', 'Z5']:
all_numbers.extend(df[col].tolist())
print(f"Gesamtanzahl gezogene Zahlen: {len(all_numbers)}")
# Häufigkeit jeder Zahl
number_counts = Counter(all_numbers)
# Bereiche definieren
ranges = {
'1-10': (1, 10),
'11-20': (11, 20),
'21-30': (21, 30),
'31-40': (31, 40),
'41-50': (41, 50)
}
# Analyse pro Bereich
range_analysis = {}
for range_name, (start, end) in ranges.items():
numbers_in_range = [num for num in all_numbers if start <= num <= end]
range_analysis[range_name] = {
'anzahl_ziehungen': len(numbers_in_range),
'prozent': (len(numbers_in_range) / len(all_numbers)) * 100,
'haeufigste_zahl': max(number_counts.items(),
key=lambda x: x[1] if start <= x[0] <= end else 0),
'durchschnitt': np.mean(numbers_in_range) if numbers_in_range else 0,
'zahlen_im_bereich': sorted(set(numbers_in_range))
}
return range_analysis, number_counts
def create_visualizations(range_analysis, number_counts, output_dir):
"""Erstellt Visualisierungen der Analyse."""
# 1. Balkendiagramm: Häufigkeit pro Bereich
plt.figure(figsize=(12, 8))
ranges = list(range_analysis.keys())
counts = [range_analysis[r]['anzahl_ziehungen'] for r in ranges]
percentages = [range_analysis[r]['prozent'] for r in ranges]
plt.subplot(2, 2, 1)
bars = plt.bar(ranges, counts, color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FECA57'])
plt.title('Anzahl gezogener Zahlen pro Bereich', fontsize=14, fontweight='bold')
plt.ylabel('Anzahl Ziehungen')
plt.xticks(rotation=45)
# Prozente auf Balken anzeigen
for bar, pct in zip(bars, percentages):
plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 5,
f'{pct:.1f}%', ha='center', va='bottom', fontweight='bold')
# 2. Heatmap: Häufigkeit einzelner Zahlen
plt.subplot(2, 2, 2)
numbers = list(range(1, 51))
frequencies = [number_counts.get(num, 0) for num in numbers]
# Als 5x10 Matrix darstellen
freq_matrix = np.array(frequencies).reshape(5, 10)
sns.heatmap(freq_matrix, annot=True, fmt='d', cmap='YlOrRd',
xticklabels=list(range(1, 11)),
yticklabels=[f'{i*10+1}-{(i+1)*10}' for i in range(5)])
plt.title('Häufigkeit einzelner Zahlen', fontsize=14, fontweight='bold')
# 3. Liniendiagramm: Häufigkeit aller Zahlen
plt.subplot(2, 2, 3)
plt.plot(numbers, frequencies, marker='o', linewidth=2, markersize=4)
plt.title('Häufigkeitsverteilung aller Zahlen (1-50)', fontsize=14, fontweight='bold')
plt.xlabel('Zahl')
plt.ylabel('Häufigkeit')
plt.grid(True, alpha=0.3)
# Bereiche farblich markieren
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FECA57']
for i, (range_name, color) in enumerate(zip(range_analysis.keys(), colors)):
start = i * 10 + 1
end = (i + 1) * 10
plt.axvspan(start, end, alpha=0.2, color=color, label=range_name)
plt.legend()
# 4. Pie Chart: Prozentuale Verteilung
plt.subplot(2, 2, 4)
plt.pie(percentages, labels=ranges, autopct='%1.1f%%',
colors=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FECA57'],
startangle=90)
plt.title('Prozentuale Verteilung nach Bereichen', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig(f'{output_dir}/eurojackpot_bereichsanalyse.png', dpi=300, bbox_inches='tight')
plt.show()
def print_detailed_analysis(range_analysis, number_counts):
"""Gibt detaillierte Analyseergebnisse aus."""
print("\n" + "="*60)
print("🎯 EUROJACKPOT BEREICHSANALYSE")
print("="*60)
total_numbers = sum(analysis['anzahl_ziehungen'] for analysis in range_analysis.values())
for range_name, analysis in range_analysis.items():
print(f"\n📊 BEREICH {range_name}:")
print(f" Anzahl Ziehungen: {analysis['anzahl_ziehungen']:,}")
print(f" Prozentanteil: {analysis['prozent']:.2f}%")
print(f" Durchschnittswert: {analysis['durchschnitt']:.1f}")
# Top 3 Zahlen in diesem Bereich
start, end = map(int, range_name.split('-'))
range_numbers = [(num, count) for num, count in number_counts.items()
if start <= num <= end]
range_numbers.sort(key=lambda x: x[1], reverse=True)
print(f" Top 3 Zahlen: ", end="")
for i, (num, count) in enumerate(range_numbers[:3]):
print(f"{num} ({count}x)", end="")
if i < 2 and i < len(range_numbers) - 1:
print(", ", end="")
print()
# Allgemeine Statistiken
print(f"\n📈 ALLGEMEINE STATISTIKEN:")
print(f" Gesamte gezogene Zahlen: {total_numbers:,}")
print(f" Durchschnitt pro Bereich: {total_numbers/5:.1f}")
# Häufigste und seltenste Zahlen insgesamt
most_common = number_counts.most_common(5)
least_common = number_counts.most_common()[-5:]
print(f"\n🔥 HÄUFIGSTE ZAHLEN GESAMT:")
for i, (num, count) in enumerate(most_common, 1):
print(f" {i}. Zahl {num}: {count} mal gezogen")
print(f"\n❄️ SELTENSTE ZAHLEN GESAMT:")
for i, (num, count) in enumerate(reversed(least_common), 1):
print(f" {i}. Zahl {num}: {count} mal gezogen")
# Empfehlungen
print(f"\n💡 ERKENNTNISSE:")
best_range = max(range_analysis.keys(), key=lambda x: range_analysis[x]['prozent'])
worst_range = min(range_analysis.keys(), key=lambda x: range_analysis[x]['prozent'])
print(f" • Bester Bereich: {best_range} ({range_analysis[best_range]['prozent']:.1f}%)")
print(f" • Schwächster Bereich: {worst_range} ({range_analysis[worst_range]['prozent']:.1f}%)")
print(f" • Unterschied: {range_analysis[best_range]['prozent'] - range_analysis[worst_range]['prozent']:.1f} Prozentpunkte")
def main():
"""Hauptfunktion."""
# Pfade
input_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/data/AlleEurojackpotzahlen.csv"
output_dir = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot"
# Daten laden
print("🔄 Lade Eurojackpot-Daten...")
df = load_drawn_numbers(input_file)
if df is None:
print("❌ Fehler beim Laden der Daten!")
return
# Analyse durchführen
print("\n🔍 Führe Bereichsanalyse durch...")
range_analysis, number_counts = analyze_number_ranges(df)
# Ergebnisse ausgeben
print_detailed_analysis(range_analysis, number_counts)
# Visualisierungen erstellen
print(f"\n📊 Erstelle Visualisierungen...")
try:
create_visualizations(range_analysis, number_counts, output_dir)
print(f"✅ Diagramm gespeichert: {output_dir}/eurojackpot_bereichsanalyse.png")
except Exception as e:
print(f"⚠️ Visualisierung konnte nicht erstellt werden: {e}")
print("💡 Installieren Sie matplotlib und seaborn: pip install matplotlib seaborn")
# CSV-Export der Analyse
results_df = pd.DataFrame.from_dict(range_analysis, orient='index')
results_df.to_csv(f'{output_dir}/bereichsanalyse_ergebnisse.csv', sep=';')
print(f"✅ Ergebnisse gespeichert: {output_dir}/bereichsanalyse_ergebnisse.csv")
if __name__ == "__main__":
main()
-208
View File
@@ -1,208 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot Positionsanalyse
Analysiert, welche Bereiche an welchen Positionen (Z1, Z2, Z3, Z4, Z5) am häufigsten stehen.
"""
import pandas as pd
from collections import defaultdict
import numpy as np
def get_range_for_number(number):
"""Bestimmt den Bereich für eine gegebene Zahl."""
if 1 <= number <= 10:
return 'A(1-10)'
elif 11 <= number <= 20:
return 'B(11-20)'
elif 21 <= number <= 30:
return 'C(21-30)'
elif 31 <= number <= 40:
return 'D(31-40)'
elif 41 <= number <= 50:
return 'E(41-50)'
else:
return 'Unknown'
def analyze_positions():
"""Führt eine detaillierte Positionsanalyse durch."""
# Daten laden
df = pd.read_csv("/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/data/AlleEurojackpotzahlen.csv", sep=';')
print(f"🎯 EUROJACKPOT POSITIONSANALYSE")
print(f"Anzahl analysierte Ziehungen: {len(df)}")
print("="*60)
# Positionen definieren
positions = ['Z1', 'Z2', 'Z3', 'Z4', 'Z5']
ranges = ['A(1-10)', 'B(11-20)', 'C(21-30)', 'D(31-40)', 'E(41-50)']
# Matrix für Positions-Bereich-Kombinationen
position_range_matrix = defaultdict(lambda: defaultdict(int))
# Daten sammeln
for _, row in df.iterrows():
for pos in positions:
range_name = get_range_for_number(row[pos])
position_range_matrix[pos][range_name] += 1
# 1. Übersichtstabelle erstellen
print(f"\n📊 POSITIONS-BEREICH-MATRIX:")
print("="*60)
print(f"{'Position':<8} {'A(1-10)':<12} {'B(11-20)':<12} {'C(21-30)':<12} {'D(31-40)':<12} {'E(41-50)':<12}")
print("-" * 60)
for pos in positions:
line = f"{pos:<8} "
for range_name in ranges:
count = position_range_matrix[pos][range_name]
percentage = (count / len(df)) * 100
line += f"{count:3}({percentage:4.1f}%) "
print(line)
# 2. Beste Bereiche pro Position
print(f"\n🏆 BESTE BEREICHE PRO POSITION:")
print("="*40)
for pos in positions:
best_range = max(ranges, key=lambda r: position_range_matrix[pos][r])
best_count = position_range_matrix[pos][best_range]
best_percentage = (best_count / len(df)) * 100
# Alle Bereiche für diese Position sortiert
sorted_ranges = sorted(ranges, key=lambda r: position_range_matrix[pos][r], reverse=True)
print(f"\n{pos}: {best_range} führt mit {best_count} ({best_percentage:.1f}%)")
print(f" Ranking: ", end="")
for i, range_name in enumerate(sorted_ranges, 1):
count = position_range_matrix[pos][range_name]
percentage = (count / len(df)) * 100
print(f"{i}.{range_name}({percentage:.1f}%)", end="")
if i < len(sorted_ranges):
print(" > ", end="")
print()
# 3. Beste Positionen pro Bereich
print(f"\n🎯 BESTE POSITIONEN PRO BEREICH:")
print("="*40)
for range_name in ranges:
best_position = max(positions, key=lambda p: position_range_matrix[p][range_name])
best_count = position_range_matrix[best_position][range_name]
best_percentage = (best_count / len(df)) * 100
# Alle Positionen für diesen Bereich sortiert
sorted_positions = sorted(positions, key=lambda p: position_range_matrix[p][range_name], reverse=True)
print(f"\n{range_name}: Position {best_position} führt mit {best_count} ({best_percentage:.1f}%)")
print(f" Ranking: ", end="")
for i, pos in enumerate(sorted_positions, 1):
count = position_range_matrix[pos][range_name]
percentage = (count / len(df)) * 100
print(f"{i}.{pos}({percentage:.1f}%)", end="")
if i < len(sorted_positions):
print(" > ", end="")
print()
# 4. Spezielle Analysen
print(f"\n📈 SPEZIELLE POSITIONSANALYSEN:")
print("="*45)
# Niedrige vs. hohe Bereiche pro Position
for pos in positions:
low_ranges = position_range_matrix[pos]['A(1-10)'] + position_range_matrix[pos]['B(11-20)']
high_ranges = position_range_matrix[pos]['D(31-40)'] + position_range_matrix[pos]['E(41-50)']
middle_range = position_range_matrix[pos]['C(21-30)']
low_pct = (low_ranges / len(df)) * 100
high_pct = (high_ranges / len(df)) * 100
middle_pct = (middle_range / len(df)) * 100
print(f"{pos}: Niedrig(A+B)={low_pct:4.1f}% | Mitte(C)={middle_pct:4.1f}% | Hoch(D+E)={high_pct:4.1f}%")
# 5. Gleichverteilungs-Analyse
print(f"\n⚖️ GLEICHVERTEILUNGS-ANALYSE:")
print("="*35)
expected_per_range = len(df) / 5 # Erwartete Gleichverteilung
print(f"Erwartete Gleichverteilung pro Bereich und Position: {expected_per_range:.1f}")
print(f"\nAbweichungen von der Gleichverteilung:")
for pos in positions:
print(f"\n{pos}:")
for range_name in ranges:
actual = position_range_matrix[pos][range_name]
deviation = actual - expected_per_range
deviation_pct = (deviation / expected_per_range) * 100
symbol = "📈" if deviation > 0 else "📉" if deviation < 0 else "⚖️"
print(f" {range_name}: {actual:3} ({deviation:+4.1f}, {deviation_pct:+5.1f}%) {symbol}")
# 6. Heatmap-Daten für Export
print(f"\n💾 DATENEXPORT:")
print("="*20)
# Erstelle eine Matrix für bessere Visualisierung
matrix_data = []
for pos in positions:
row_data = {'Position': pos}
for range_name in ranges:
count = position_range_matrix[pos][range_name]
percentage = (count / len(df)) * 100
row_data[range_name] = count
row_data[f"{range_name}_Prozent"] = percentage
matrix_data.append(row_data)
matrix_df = pd.DataFrame(matrix_data)
# Zusätzliche Statistiken hinzufügen
stats_data = []
for _, row in df.iterrows():
row_data = {'datum': row['datum']}
for pos in positions:
row_data[f"{pos}_Zahl"] = row[pos]
row_data[f"{pos}_Bereich"] = get_range_for_number(row[pos])
stats_data.append(row_data)
stats_df = pd.DataFrame(stats_data)
# Export
matrix_output = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/positions_matrix.csv"
stats_output = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/positions_details.csv"
matrix_df.to_csv(matrix_output, sep=';', index=False)
stats_df.to_csv(stats_output, sep=';', index=False)
print(f"✅ Positionsmatrix gespeichert: positions_matrix.csv")
print(f"✅ Detaildaten gespeichert: positions_details.csv")
# 7. Strategische Empfehlungen
print(f"\n💡 STRATEGISCHE EMPFEHLUNGEN:")
print("="*35)
# Finde die besten Kombinationen pro Position
recommendations = {}
for pos in positions:
best_range = max(ranges, key=lambda r: position_range_matrix[pos][r])
recommendations[pos] = best_range
print(f"Optimale Bereichsauswahl pro Position:")
for pos, best_range in recommendations.items():
count = position_range_matrix[pos][best_range]
percentage = (count / len(df)) * 100
print(f" {pos}: {best_range} ({percentage:.1f}%)")
# Berechne theoretische Erfolgswahrscheinlichkeit
theoretical_success = 1.0
for pos, best_range in recommendations.items():
prob = position_range_matrix[pos][best_range] / len(df)
theoretical_success *= prob
print(f"\nTheoretische Erfolgswahrscheinlichkeit dieser Kombination: {theoretical_success*100:.4f}%")
return position_range_matrix, matrix_df
if __name__ == "__main__":
analyze_positions()
@@ -1,54 +0,0 @@
#!/usr/bin/env python3
"""
Einfache Eurojackpot Bereichsanalyse
"""
import pandas as pd
from collections import Counter
def analyze_ranges():
"""Analysiert Zahlenbereiche in Eurojackpot-Daten."""
# Daten laden
df = pd.read_csv("/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/data/AlleEurojackpotzahlen.csv", sep=';')
print(f"Anzahl Ziehungen: {len(df)}")
# Alle Zahlen sammeln
all_numbers = []
for col in ['Z1', 'Z2', 'Z3', 'Z4', 'Z5']:
all_numbers.extend(df[col].tolist())
# Bereiche definieren
ranges = {
'1-10': list(range(1, 11)),
'11-20': list(range(11, 21)),
'21-30': list(range(21, 31)),
'31-40': list(range(31, 41)),
'41-50': list(range(41, 51))
}
print(f"\nGesamt gezogene Zahlen: {len(all_numbers)}")
print("="*50)
# Analyse pro Bereich
for range_name, range_numbers in ranges.items():
count = sum(1 for num in all_numbers if num in range_numbers)
percentage = (count / len(all_numbers)) * 100
print(f"{range_name:6}: {count:4} Zahlen ({percentage:5.1f}%)")
print("="*50)
# Häufigste Zahlen
number_counts = Counter(all_numbers)
print("\nHäufigste 10 Zahlen:")
for num, count in number_counts.most_common(10):
print(f"Zahl {num:2}: {count:3} mal")
print("\nSeltenste 10 Zahlen:")
for num, count in number_counts.most_common()[-10:]:
print(f"Zahl {num:2}: {count:3} mal")
if __name__ == "__main__":
analyze_ranges()
@@ -1,270 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot Treffer-Analyse (umschlüsselte Werte)
Analysiert, wo die größten Treffer-Wahrscheinlichkeiten bei den umschlüsselten Werten liegen.
"""
import pandas as pd
from collections import Counter, defaultdict
import numpy as np
def analyze_hit_probabilities():
"""Analysiert die Treffer-Wahrscheinlichkeiten der umschlüsselten Werte."""
# Umschlüsselte Daten laden
df = pd.read_csv("/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/AlleEurojackpotzahlen_umschluesselt.csv", sep=';')
print("🎯 TREFFER-ANALYSE UMSCHLÜSSELTE WERTE (1-10)")
print("="*60)
print(f"Analysierte Ziehungen: {len(df)}")
# 1. Einzelne Gruppen-Wahrscheinlichkeiten pro Position
print(f"\n🏆 HÖCHSTE TREFFER-WAHRSCHEINLICHKEITEN PRO POSITION:")
print("="*55)
positions = ['z1', 'z2', 'z3', 'z4', 'z5']
position_stats = {}
for pos in positions:
group_counts = Counter(df[pos])
total = len(df)
# Beste Gruppe für diese Position
best_group = max(group_counts, key=group_counts.get)
best_count = group_counts[best_group]
best_probability = (best_count / total) * 100
position_stats[pos] = {
'best_group': best_group,
'probability': best_probability,
'count': best_count,
'all_groups': group_counts
}
print(f"\n{pos.upper()}: Gruppe {best_group} führt mit {best_probability:.1f}% ({best_count}/{total})")
# Top 3 für diese Position
top_3 = group_counts.most_common(3)
print(f" Top 3: ", end="")
for i, (group, count) in enumerate(top_3):
prob = (count / total) * 100
print(f"{i+1}.Gruppe {group}({prob:.1f}%)", end="")
if i < 2:
print(" > ", end="")
print()
# 2. Beste Gesamtkombination
print(f"\n🔥 OPTIMAL-KOMBINATION (höchste Einzelwahrscheinlichkeiten):")
print("="*60)
optimal_combination = []
total_probability = 1.0
for pos in positions:
best_group = position_stats[pos]['best_group']
probability = position_stats[pos]['probability'] / 100
optimal_combination.append(best_group)
total_probability *= probability
print(f"{pos}: Gruppe {best_group} ({position_stats[pos]['probability']:.1f}%)")
optimal_string = '-'.join(map(str, optimal_combination))
print(f"\nOptimal-Kombination: {optimal_string}")
print(f"Theoretische Wahrscheinlichkeit: {total_probability*100:.6f}%")
print(f"Das entspricht etwa 1 in {1/total_probability:,.0f} Ziehungen")
# 3. Tatsächlich aufgetretene häufigste Kombinationen
print(f"\n📊 REAL AUFGETRETENE HÄUFIGSTE KOMBINATIONEN:")
print("="*50)
combination_counts = Counter(df['kombination_umschluesselt'])
print(f"Top 20 real aufgetretene Kombinationen:")
for i, (combination, count) in enumerate(combination_counts.most_common(20), 1):
probability = (count / len(df)) * 100
print(f"{i:2}. {combination:15} {count}x ({probability:.2f}%)")
# 4. Bereichs-Kombinationen mit höchster Wahrscheinlichkeit
print(f"\n🎲 BEREICHS-KOMBINATIONEN MIT HÖCHSTER WAHRSCHEINLICHKEIT:")
print("="*60)
# Niedrig (1-3), Mittel (4-7), Hoch (8-10) Kombinationen
range_combinations = defaultdict(int)
for _, row in df.iterrows():
ranges = []
for pos in positions:
val = row[pos]
if 1 <= val <= 3:
ranges.append('N') # Niedrig
elif 4 <= val <= 7:
ranges.append('M') # Mittel
else:
ranges.append('H') # Hoch
range_pattern = ''.join(ranges)
range_combinations[range_pattern] += 1
print(f"Häufigste Bereichsmuster (N=Niedrig1-3, M=Mittel4-7, H=Hoch8-10):")
sorted_patterns = sorted(range_combinations.items(), key=lambda x: x[1], reverse=True)
for i, (pattern, count) in enumerate(sorted_patterns[:15], 1):
probability = (count / len(df)) * 100
pattern_readable = pattern.replace('N', 'Niedrig').replace('M', 'Mittel').replace('H', 'Hoch')
print(f"{i:2}. {pattern:5} ({pattern_readable:25}) {count:3}x ({probability:5.1f}%)")
# 5. Positions-spezifische Empfehlungen
print(f"\n💡 POSITIONS-SPEZIFISCHE EMPFEHLUNGEN:")
print("="*45)
recommendations = {}
for pos in positions:
group_counts = position_stats[pos]['all_groups']
total = len(df)
# Top 3 Gruppen für maximale Abdeckung
top_groups = [group for group, count in group_counts.most_common(3)]
top_coverage = sum(group_counts[group] for group in top_groups)
coverage_percentage = (top_coverage / total) * 100
recommendations[pos] = {
'top_groups': top_groups,
'coverage': coverage_percentage
}
print(f"\n{pos.upper()}: Empfohlene Gruppen {top_groups}")
print(f" Abdeckung: {coverage_percentage:.1f}% aller Ziehungen")
# Wahrscheinlichkeitsverteilung
print(f" Verteilung: ", end="")
for group in top_groups:
prob = (group_counts[group] / total) * 100
print(f"Gruppe {group}({prob:.1f}%)", end="")
if group != top_groups[-1]:
print(", ", end="")
print()
# 6. Strategische Kombinationen
print(f"\n🎯 STRATEGISCHE KOMBINATIONEN FÜR MAXIMALE TREFFER:")
print("="*55)
# Berechne verschiedene Strategien
strategies = {
'Konservativ': {
'z1': [1, 2], # Top 2 der Position z1
'z2': [3, 4], # Top 2 der Position z2
'z3': [5, 6], # Top 2 der Position z3
'z4': [7, 8], # Top 2 der Position z4
'z5': [9, 10] # Top 2 der Position z5
},
'Ausgewogen': {
'z1': [1, 2, 3], # Top 3 jeder Position
'z2': [3, 4, 5],
'z3': [4, 5, 6, 7],
'z4': [6, 7, 8],
'z5': [8, 9, 10]
},
'Optimal': {} # Wird basierend auf tatsächlichen Daten gefüllt
}
# Optimal-Strategie basierend auf echten Top-3 pro Position
for pos in positions:
top_3_groups = recommendations[pos]['top_groups']
strategies['Optimal'][pos] = top_3_groups
for strategy_name, strategy in strategies.items():
if strategy: # Nur wenn Strategie gefüllt ist
print(f"\n{strategy_name}-Strategie:")
total_combinations = 1
coverage_per_position = []
for pos in positions:
recommended_groups = strategy[pos]
pos_stats = position_stats[pos]['all_groups']
total_pos = len(df)
# Abdeckung dieser Gruppen
coverage = sum(pos_stats.get(group, 0) for group in recommended_groups)
coverage_pct = (coverage / total_pos) * 100
coverage_per_position.append(coverage_pct)
total_combinations *= len(recommended_groups)
print(f" {pos}: Gruppen {recommended_groups} ({coverage_pct:.1f}% Abdeckung)")
avg_coverage = np.mean(coverage_per_position)
print(f" Durchschnittliche Abdeckung: {avg_coverage:.1f}%")
print(f" Mögliche Kombinationen: {total_combinations:,}")
# 7. Heiße und kalte Zahlen
print(f"\n🔥❄️ HEISSE UND KALTE GRUPPEN:")
print("="*35)
# Alle Gruppen über alle Positionen sammeln
all_groups = []
for pos in positions:
all_groups.extend(df[pos].tolist())
group_total_counts = Counter(all_groups)
total_appearances = len(all_groups)
expected_per_group = total_appearances / 10 # 10 Gruppen
print(f"Erwartete Häufigkeit pro Gruppe: {expected_per_group:.1f}")
print(f"\nHeisse Gruppen (über Erwartung):")
hot_groups = []
for group in range(1, 11):
actual = group_total_counts.get(group, 0)
deviation = actual - expected_per_group
if deviation > 0:
hot_groups.append((group, actual, deviation))
hot_groups.sort(key=lambda x: x[2], reverse=True)
for group, count, deviation in hot_groups:
percentage = (count / total_appearances) * 100
print(f" Gruppe {group}: {count} (+{deviation:.1f}, {percentage:.1f}%)")
print(f"\nKalte Gruppen (unter Erwartung):")
cold_groups = []
for group in range(1, 11):
actual = group_total_counts.get(group, 0)
deviation = actual - expected_per_group
if deviation < 0:
cold_groups.append((group, actual, deviation))
cold_groups.sort(key=lambda x: x[2])
for group, count, deviation in cold_groups:
percentage = (count / total_appearances) * 100
print(f" Gruppe {group}: {count} ({deviation:.1f}, {percentage:.1f}%)")
# 8. Export der Empfehlungen
print(f"\n💾 EMPFEHLUNGEN EXPORT:")
print("="*25)
# Erstelle Empfehlungs-DataFrame
recommendation_data = []
# Für jede Position die besten Empfehlungen
for pos in positions:
pos_recommendations = recommendations[pos]
for group in pos_recommendations['top_groups']:
prob = (position_stats[pos]['all_groups'][group] / len(df)) * 100
recommendation_data.append({
'position': pos,
'gruppe': group,
'wahrscheinlichkeit_prozent': prob,
'anzahl_auftreten': position_stats[pos]['all_groups'][group],
'empfehlung_rang': pos_recommendations['top_groups'].index(group) + 1
})
rec_df = pd.DataFrame(recommendation_data)
output_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/treffer_empfehlungen_umschluesselt.csv"
rec_df.to_csv(output_file, sep=';', index=False)
print(f"✅ Empfehlungen gespeichert: treffer_empfehlungen_umschluesselt.csv")
return position_stats, recommendations
if __name__ == "__main__":
analyze_hit_probabilities()
-141
View File
@@ -1,141 +0,0 @@
import csv
from itertools import combinations
import time
print("=== EUROJACKPOT KOMBINATIONS-GENERATOR ===")
print("Erstellt alle möglichen Kombinationen mit Status (gezogen/nicht gezogen)")
print()
# Pfade
eurojackpot_file = '/Users/sebastianfrohlich/Downloads/EJ_ab_2018.csv'
output_file = '/Users/sebastianfrohlich/Desktop/Alle_Eurojackpot_Kombinationen_mit_Status.csv'
missing_file = '/Users/sebastianfrohlich/Desktop/Fehlende_Eurojackpot_Kombinationen.csv'
# Schritt 1: Einlesen der gezogenen Kombinationen
print("Schritt 1: Lade gezogene Eurojackpot-Kombinationen...")
existing_combinations = set()
try:
with open(eurojackpot_file, 'r', encoding='utf-8') as file:
lines = file.readlines()
for line in lines[1:]: # Header überspringen
parts = line.strip().split(';')
if len(parts) >= 6: # Mindestens Datum + 5 Zahlen
try:
numbers = []
for i in range(1, 6): # Spalten 1-5 (nach Datum)
if i < len(parts) and parts[i].strip().isdigit():
numbers.append(int(parts[i].strip()))
if len(numbers) == 5: # Vollständige Kombination
combo = frozenset(numbers)
existing_combinations.add(combo)
except (ValueError, IndexError):
continue
print(f"{len(existing_combinations)} gezogene Kombinationen geladen")
# Beispiele anzeigen
if existing_combinations:
print(" Beispiele:")
for i, combo in enumerate(list(existing_combinations)[:3]):
sorted_combo = sorted(list(combo))
print(f" {sorted_combo}")
if len(existing_combinations) > 3:
print(f" ... und {len(existing_combinations)-3} weitere")
except FileNotFoundError:
print(f" ⚠️ Datei nicht gefunden: {eurojackpot_file}")
existing_combinations = set()
except Exception as e:
print(f" ⚠️ Fehler beim Lesen: {e}")
existing_combinations = set()
print()
# Schritt 2: Generierung aller möglichen Kombinationen
print("Schritt 2: Generiere alle möglichen Kombinationen (5 aus 50)...")
total_combinations = 2118760 # C(50,5)
print(f" Gesamtanzahl zu verarbeitender Kombinationen: {total_combinations:,}")
all_combinations = []
count = 0
start_time = time.time()
for combo in combinations(range(1, 51), 5):
count += 1
# Fortschritt anzeigen
if count % 100000 == 0:
elapsed = time.time() - start_time
rate = count / elapsed if elapsed > 0 else 0
remaining = (total_combinations - count) / rate if rate > 0 else 0
print(f" Fortschritt: {count:,} / {total_combinations:,} "
f"({count/total_combinations*100:.1f}%) "
f"- {rate:,.0f}/s - noch ~{remaining/60:.1f} min")
# Prüfen ob Kombination bereits gezogen wurde
sorted_combo = sorted(combo)
is_drawn = 1 if frozenset(combo) in existing_combinations else 0
# Zur Liste hinzufügen (Z1, Z2, Z3, Z4, Z5, gezogen)
combination_row = sorted_combo + [is_drawn]
all_combinations.append(combination_row)
print(f" ✓ Alle {len(all_combinations):,} Kombinationen generiert")
print()
# Schritt 3: Statistiken berechnen
print("Schritt 3: Berechne Statistiken...")
drawn_combinations = sum(1 for combo in all_combinations if combo[5] == 1)
undrawn_combinations = len(all_combinations) - drawn_combinations
print(f" Gesamt mögliche Kombinationen: {len(all_combinations):,}")
print(f" Bereits gezogene Kombinationen: {drawn_combinations:,}")
print(f" Noch nicht gezogene Kombinationen: {undrawn_combinations:,}")
if len(all_combinations) > 0:
percentage = drawn_combinations / len(all_combinations) * 100
print(f" Anteil gezogener Kombinationen: {percentage:.6f}%")
print()
# Schritt 4: Hauptdatei speichern
print("Schritt 4: Speichere Hauptdatei...")
try:
with open(output_file, 'w', newline='', encoding='utf-8') as outfile:
writer = csv.writer(outfile, delimiter=';')
writer.writerow(['Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'gezogen']) # Header
for combo in all_combinations:
writer.writerow(combo)
print(f" ✓ Hauptdatei gespeichert: {output_file}")
except Exception as e:
print(f" ⚠️ Fehler beim Speichern der Hauptdatei: {e}")
# Schritt 5: Datei mit fehlenden Kombinationen speichern
print("Schritt 5: Speichere Datei mit fehlenden Kombinationen...")
try:
missing_combinations = [combo[:5] for combo in all_combinations if combo[5] == 0]
with open(missing_file, 'w', newline='', encoding='utf-8') as outfile:
writer = csv.writer(outfile, delimiter=';')
writer.writerow(['Z1', 'Z2', 'Z3', 'Z4', 'Z5']) # Header
for combo in missing_combinations:
writer.writerow(combo)
print(f" ✓ Datei mit fehlenden Kombinationen gespeichert: {missing_file}")
print(f"{len(missing_combinations):,} fehlende Kombinationen")
except Exception as e:
print(f" ⚠️ Fehler beim Speichern der fehlenden Kombinationen: {e}")
print()
print("=== FERTIG ===")
print("Erstellte Dateien:")
print(f"1. {output_file}")
print(f" - Alle {len(all_combinations):,} Kombinationen mit Status")
print(f"2. {missing_file}")
if 'missing_combinations' in locals():
print(f" - {len(missing_combinations):,} noch nicht gezogene Kombinationen")
print()
print("Format der Hauptdatei:")
print("Z1;Z2;Z3;Z4;Z5;gezogen")
print("1;2;3;4;5;0")
print("...")
@@ -1,806 +0,0 @@
#!/usr/bin/env python3
"""
Ultimativer Eurojackpot Tipp-Generator mit Multi-Ziehungs-Trend-Analyse
Kombiniert multiple Optimierungsstrategien:
- Historische Häufigkeitsanalyse
- Positionsbasierte Gewichtung
- Multi-Ziehungs-Trend-Analyse (NEU!)
- Zahlen-Momentum-Tracking
- Sequenzielle Abhängigkeiten
- Zyklische Muster-Erkennung
"""
import pandas as pd
import random
import numpy as np
from itertools import combinations
from collections import Counter, defaultdict, deque
import datetime
class UltimativerEurojackpotGenerator:
def __init__(self, data_path="/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/AlleEurojackpotzahlen.csv"):
self.data_path = data_path
self.df = None
self.drawn_combinations = set()
# Basis-Analyse (Original)
self.number_frequencies = Counter()
self.position_frequencies = defaultdict(Counter)
self.pattern_frequencies = Counter()
self.supernumber_frequencies = {'sz1': Counter(), 'sz2': Counter()}
self.number_distances = []
# Multi-Ziehungs-Trend-Analyse (NEU!)
self.number_sequences = defaultdict(list)
self.momentum_scores = {}
self.trend_predictions = {}
self.sequential_dependencies = defaultdict(lambda: defaultdict(int))
self.cycle_patterns = {}
self.hot_numbers = []
self.warm_numbers = []
self.cold_numbers = []
# Initialisierung
self.load_and_analyze_all_data()
def load_and_analyze_all_data(self):
"""Lädt Daten und führt alle Analysen durch."""
try:
self.df = pd.read_csv(self.data_path, sep=';')
# Chronologische Sortierung für Trend-Analyse
if 'Datum' in self.df.columns:
self.df['Datum'] = pd.to_datetime(self.df['Datum'], format='%d.%m.%Y')
self.df = self.df.sort_values('Datum')
print(f"🚀 ULTIMATIVER EUROJACKPOT GENERATOR")
print("=" * 60)
print(f"📊 Analysiere {len(self.df)} Ziehungen mit Multi-Trend-Analyse...")
# Basis-Analysen durchführen
self._perform_basic_analysis()
# Multi-Ziehungs-Trend-Analysen durchführen (NEU!)
self._perform_momentum_analysis()
self._perform_sequential_analysis()
self._perform_cycle_analysis()
self._generate_trend_predictions()
print(f"✅ Komplette Analyse abgeschlossen!")
self._print_ultimate_analysis_summary()
except Exception as e:
print(f"❌ Fehler beim Laden der Daten: {e}")
return False
return True
def _perform_basic_analysis(self):
"""Führt die ursprünglichen Basis-Analysen durch."""
for _, row in self.df.iterrows():
# Gezogene Kombinationen
combo = tuple(sorted([row['Z1'], row['Z2'], row['Z3'], row['Z4'], row['Z5']]))
self.drawn_combinations.add(combo)
# Zahlenfrequenzen
numbers = [row['Z1'], row['Z2'], row['Z3'], row['Z4'], row['Z5']]
for num in numbers:
self.number_frequencies[num] += 1
# Positionsfrequenzen
sorted_numbers = sorted(numbers)
for i, num in enumerate(sorted_numbers):
self.position_frequencies[f'pos_{i+1}'][num] += 1
# Muster analysieren
pattern = self._get_pattern(sorted_numbers)
self.pattern_frequencies[pattern] += 1
# Superzahlen
self.supernumber_frequencies['sz1'][row['SZ1']] += 1
self.supernumber_frequencies['sz2'][row['SZ2']] += 1
# Zahlenabstände
distances = [sorted_numbers[i+1] - sorted_numbers[i] for i in range(4)]
self.number_distances.extend(distances)
def _perform_momentum_analysis(self, window_size=15):
"""Führt Multi-Ziehungs-Momentum-Analyse durch (NEU!)"""
print(f"\n🔥 MOMENTUM-ANALYSE (Fenster: {window_size})")
# Zahlensequenzen über Zeit aufbauen
for number in range(1, 51):
sequence = []
for _, row in self.df.iterrows():
drawn_numbers = [row['Z1'], row['Z2'], row['Z3'], row['Z4'], row['Z5']]
sequence.append(1 if number in drawn_numbers else 0)
self.number_sequences[number] = sequence
# Momentum-Scores berechnen
momentum_results = {}
for number in range(1, 51):
recent_sequence = self.number_sequences[number][-window_size:]
hit_rate = sum(recent_sequence) / len(recent_sequence)
trend_score = self._calculate_trend_score(recent_sequence)
recency_score = self._calculate_recency_score(recent_sequence)
# Kombinierter Momentum-Score mit Gewichtung
momentum_score = (hit_rate * 0.4) + (trend_score * 0.4) + (recency_score * 0.2)
momentum_results[number] = {
'hit_rate': hit_rate,
'trend_score': trend_score,
'recency_score': recency_score,
'momentum_score': momentum_score,
'status': self._get_momentum_status(momentum_score)
}
self.momentum_scores = momentum_results
# Zahlen in Kategorien einteilen
sorted_momentum = sorted(momentum_results.items(),
key=lambda x: x[1]['momentum_score'], reverse=True)
self.hot_numbers = [num for num, data in sorted_momentum[:20]
if data['momentum_score'] > 0.35]
self.warm_numbers = [num for num, data in sorted_momentum[20:35]
if 0.2 <= data['momentum_score'] <= 0.35]
self.cold_numbers = [num for num, data in sorted_momentum[35:]
if data['momentum_score'] < 0.2][:15]
print(f"🔥 {len(self.hot_numbers)} heiße Zahlen identifiziert")
print(f"🌡️ {len(self.warm_numbers)} warme Zahlen identifiziert")
print(f"🧊 {len(self.cold_numbers)} kalte Zahlen identifiziert")
def _perform_sequential_analysis(self, look_back=3):
"""Analysiert sequenzielle Abhängigkeiten zwischen Ziehungen (NEU!)"""
print(f"\n🔗 SEQUENZIELLE ABHÄNGIGKEITEN (Look-back: {look_back})")
for i in range(look_back, len(self.df)):
current_numbers = set([self.df.iloc[i]['Z1'], self.df.iloc[i]['Z2'],
self.df.iloc[i]['Z3'], self.df.iloc[i]['Z4'],
self.df.iloc[i]['Z5']])
for j in range(1, look_back + 1):
prev_numbers = set([self.df.iloc[i-j]['Z1'], self.df.iloc[i-j]['Z2'],
self.df.iloc[i-j]['Z3'], self.df.iloc[i-j]['Z4'],
self.df.iloc[i-j]['Z5']])
for prev_num in prev_numbers:
for curr_num in current_numbers:
self.sequential_dependencies[f"lag_{j}"][f"{prev_num}_{curr_num}"] += 1
print(f"🔗 Sequenzielle Muster für {look_back} Ziehungen analysiert")
def _perform_cycle_analysis(self, max_cycle_length=15):
"""Analysiert zyklische Muster (NEU!)"""
print(f"\n🔄 ZYKLUS-ANALYSE")
pattern_sequence = []
for _, row in self.df.iterrows():
numbers = sorted([row['Z1'], row['Z2'], row['Z3'], row['Z4'], row['Z5']])
pattern = self._get_pattern(numbers)
pattern_sequence.append(pattern)
# Zyklen erkennen
self.cycle_patterns = {}
for cycle_length in range(3, max_cycle_length + 1):
cycles = self._find_pattern_cycles(pattern_sequence, cycle_length)
if cycles:
self.cycle_patterns[cycle_length] = cycles
cycle_count = sum(len(cycles) for cycles in self.cycle_patterns.values())
print(f"🔄 {cycle_count} zyklische Muster erkannt")
def _generate_trend_predictions(self):
"""Generiert Trend-basierte Vorhersagen (NEU!)"""
print(f"\n🎯 TREND-VORHERSAGEN GENERIEREN")
for number in range(1, 51):
if number in self.momentum_scores:
momentum_data = self.momentum_scores[number]
# Multi-Faktor-Vorhersage-Score
momentum_weight = momentum_data['momentum_score'] * 0.4
frequency_weight = (self.number_frequencies[number] / len(self.df)) * 0.3
trend_weight = max(0, momentum_data['trend_score']) * 0.3
prediction_score = momentum_weight + frequency_weight + trend_weight
self.trend_predictions[number] = {
'prediction_score': prediction_score,
'recommendation': self._get_prediction_recommendation(prediction_score),
'confidence': self._get_confidence_level(prediction_score)
}
print(f"🎯 Trend-Vorhersagen für alle 50 Zahlen generiert")
def _calculate_trend_score(self, sequence):
"""Berechnet Trend-Score für eine Zahlensequenz."""
if len(sequence) < 2:
return 0
x = np.arange(len(sequence))
y = np.array(sequence)
weights = np.exp(x / len(x)) # Neuere Ziehungen wichtiger
try:
coeffs = np.polyfit(x, y, 1, w=weights)
return coeffs[0] # Steigung = Trend
except:
return 0
def _calculate_recency_score(self, sequence):
"""Berechnet Recency-Score."""
try:
last_hit_index = len(sequence) - 1 - sequence[::-1].index(1)
recency = 1 - (len(sequence) - 1 - last_hit_index) / len(sequence)
return recency
except ValueError:
return 0
def _get_momentum_status(self, score):
"""Klassifiziert Momentum-Status."""
if score > 0.5:
return "🔥 SEHR HEISS"
elif score > 0.35:
return "🌡️ HEISS"
elif score > 0.2:
return "😐 WARM"
elif score > 0.1:
return "🧊 KÜHL"
else:
return "❄️ EISKALT"
def _get_prediction_recommendation(self, score):
"""Empfehlung basierend auf Vorhersage-Score."""
if score > 0.4:
return "SEHR EMPFOHLEN"
elif score > 0.25:
return "EMPFOHLEN"
elif score > 0.15:
return "NEUTRAL"
else:
return "VERMEIDEN"
def _get_confidence_level(self, score):
"""Konfidenz-Level für Vorhersagen."""
if score > 0.4:
return "HOCH"
elif score > 0.25:
return "MITTEL"
else:
return "NIEDRIG"
def _find_pattern_cycles(self, sequence, cycle_length):
"""Findet zyklische Muster."""
cycle_patterns = defaultdict(list)
for i in range(len(sequence) - cycle_length):
pattern = ''.join(sequence[i:i+cycle_length])
cycle_patterns[pattern].append(i)
return {pattern: positions for pattern, positions in cycle_patterns.items()
if len(positions) >= 2}
def _get_pattern(self, numbers):
"""Bestimmt N/M/H-Muster."""
pattern = []
for num in numbers:
if 1 <= num <= 15:
pattern.append('N')
elif 16 <= num <= 35:
pattern.append('M')
else:
pattern.append('H')
return ''.join(pattern)
def _print_ultimate_analysis_summary(self):
"""Gibt detaillierte Analyse-Zusammenfassung aus."""
print(f"\n📈 ULTIMATE ANALYSE-ZUSAMMENFASSUNG:")
print("=" * 55)
# Top Trend-Empfehlungen
print("\n🎯 TOP 10 TREND-EMPFEHLUNGEN:")
top_predictions = sorted(self.trend_predictions.items(),
key=lambda x: x[1]['prediction_score'], reverse=True)[:10]
for i, (number, data) in enumerate(top_predictions):
momentum_status = self.momentum_scores[number]['status']
print(f"{i+1:2}. Zahl {number:2}: Score {data['prediction_score']:.3f} "
f"({data['recommendation']}) {momentum_status}")
# Top Muster mit Trend-Integration
print(f"\n🎨 TOP MUSTER (kombiniert mit Trends):")
for pattern, count in self.pattern_frequencies.most_common(5):
percentage = (count / len(self.drawn_combinations)) * 100
print(f" {pattern}: {count}x ({percentage:.1f}%)")
# Zyklische Erkenntnisse
if self.cycle_patterns:
print(f"\n🔄 ERKANNTE ZYKLEN:")
total_cycles = sum(len(cycles) for cycles in self.cycle_patterns.values())
print(f" Insgesamt {total_cycles} zyklische Muster erkannt")
def generate_ultimate_combination(self):
"""Generiert ultimativ optimierte Kombination mit allen Methoden."""
max_attempts = 1000
for attempt in range(max_attempts):
numbers = []
# Strategie-Mix basierend auf Trends:
# 40% Top-Trend-Zahlen, 30% Heiße Zahlen, 20% Position-optimiert, 10% Balance
# 2 Zahlen aus Top-Trend-Empfehlungen (40%)
top_trend_numbers = [num for num, data in sorted(self.trend_predictions.items(),
key=lambda x: x[1]['prediction_score'], reverse=True)[:15]
if data['recommendation'] in ['SEHR EMPFOHLEN', 'EMPFOHLEN']]
if len(top_trend_numbers) >= 2:
trend_picks = random.sample(top_trend_numbers[:10], 2)
numbers.extend(trend_picks)
# 2 Zahlen aus heißen Zahlen (30%)
if len(self.hot_numbers) >= 2:
remaining_hot = [n for n in self.hot_numbers if n not in numbers]
if len(remaining_hot) >= 2:
hot_picks = random.sample(remaining_hot[:8], min(2, len(remaining_hot)))
numbers.extend(hot_picks)
# 1 Zahl positions-optimiert oder warm (30%)
remaining_slots = 5 - len(numbers)
if remaining_slots > 0:
if self.warm_numbers:
remaining_warm = [n for n in self.warm_numbers if n not in numbers]
if remaining_warm:
warm_pick = random.choice(remaining_warm[:5])
numbers.append(warm_pick)
# Auffüllen bis 5 Zahlen
while len(numbers) < 5:
available_numbers = [n for n in range(1, 51) if n not in numbers]
# Gewichtete Auswahl basierend auf Trend-Scores
weights = [self.trend_predictions[n]['prediction_score'] for n in available_numbers]
if sum(weights) > 0:
additional_number = random.choices(available_numbers, weights=weights)[0]
else:
additional_number = random.choice(available_numbers)
numbers.append(additional_number)
# Sortieren und validieren
numbers = sorted(numbers[:5])
if self._validate_ultimate_combination(numbers):
return numbers
# Fallback
return self._generate_fallback_combination()
def _validate_ultimate_combination(self, numbers):
"""Erweiterte Validierung mit Trend-Kriterien."""
# Basis-Validierung
if tuple(numbers) in self.drawn_combinations:
return False
if len(set(numbers)) != 5:
return False
# Trend-Validierung
hot_count = sum(1 for n in numbers if n in self.hot_numbers)
high_trend_count = sum(1 for n in numbers
if self.trend_predictions[n]['recommendation'] == 'SEHR EMPFOHLEN')
# Mindestens 1 heiße oder 1 sehr empfohlene Zahl
if hot_count == 0 and high_trend_count == 0:
return False
# Standard-Validierungen
distances = [numbers[i+1] - numbers[i] for i in range(4)]
if min(distances) < 2 or max(distances) > 18:
return False
even_count = sum(1 for n in numbers if n % 2 == 0)
if even_count == 0 or even_count == 5:
return False
total = sum(numbers)
if total < 80 or total > 170:
return False
return True
def _generate_fallback_combination(self):
"""Fallback mit Trend-Integration."""
numbers = []
# Basis: NMMHH mit Trend-Gewichtung
ranges = {
'N': [n for n in range(1, 16) if n in self.hot_numbers + self.warm_numbers] or list(range(1, 16)),
'M': [n for n in range(16, 36) if n in self.hot_numbers + self.warm_numbers] or list(range(16, 36)),
'H': [n for n in range(36, 51) if n in self.hot_numbers + self.warm_numbers] or list(range(36, 51))
}
numbers.extend(random.sample(ranges['N'][:10], 1))
numbers.extend(random.sample(ranges['M'][:15], 2))
numbers.extend(random.sample(ranges['H'][:10], 2))
return sorted(numbers)
def get_optimized_supernumbers(self):
"""Trend-optimierte Superzahlen-Auswahl."""
# Integration von Trend-Daten für Superzahlen
sz1_trends = {}
sz2_trends = {}
# Letzte 10 Ziehungen analysieren
recent_df = self.df.tail(10)
for sz1 in range(1, 13): # Eurojackpot SZ1: 1-12
recent_count = (recent_df['SZ1'] == sz1).sum()
total_count = self.supernumber_frequencies['sz1'][sz1]
trend_score = (recent_count / 10) * 0.6 + (total_count / len(self.df)) * 0.4
sz1_trends[sz1] = trend_score
for sz2 in range(1, 11): # Eurojackpot SZ2: 1-10
recent_count = (recent_df['SZ2'] == sz2).sum()
total_count = self.supernumber_frequencies['sz2'][sz2]
trend_score = (recent_count / 10) * 0.6 + (total_count / len(self.df)) * 0.4
sz2_trends[sz2] = trend_score
# Gewichtete Auswahl
sz1_candidates = list(sz1_trends.keys())
sz1_weights = list(sz1_trends.values())
sz1 = random.choices(sz1_candidates, weights=sz1_weights)[0]
sz2_candidates = list(sz2_trends.keys())
sz2_weights = list(sz2_trends.values())
sz2 = random.choices(sz2_candidates, weights=sz2_weights)[0]
return sz1, sz2
def generate_ultimate_tips(self, num_tips=10):
"""Generiert ultimative Tipps mit kompletter Multi-Trend-Integration."""
print(f"\n🚀 ULTIMATE TIPP-GENERIERUNG")
print("=" * 50)
print(f"🎯 Kombiniert ALLE Optimierungsstrategien:")
print(f" ✅ Historische Häufigkeitsanalyse")
print(f" ✅ Positionsbasierte Gewichtung")
print(f" ✅ Multi-Ziehungs-Momentum-Analyse")
print(f" ✅ Sequenzielle Abhängigkeiten")
print(f" ✅ Zyklische Muster-Erkennung")
print(f" ✅ Trend-Vorhersage-Algorithmus")
generated_tips = []
strategy_distribution = Counter()
print(f"\n🎲 GENERIERE {num_tips} ULTIMATE TIPPS:")
print("=" * 60)
print(f"{'Nr':<3} {'Zahlen':<20} {'Muster':<7} {'🔥':<3} {'🎯':<3} {'Status'}")
print("-" * 60)
attempts = 0
max_attempts = num_tips * 50
while len(generated_tips) < num_tips and attempts < max_attempts:
attempts += 1
combination = self.generate_ultimate_combination()
if combination and tuple(combination) not in [tuple(tip['zahlen']) for tip in generated_tips]:
pattern = self._get_pattern(combination)
# Trend-Analyse des Tipps
hot_count = sum(1 for n in combination if n in self.hot_numbers)
trend_count = sum(1 for n in combination
if self.trend_predictions[n]['recommendation'] in ['SEHR EMPFOHLEN', 'EMPFOHLEN'])
# Superzahlen
sz1, sz2 = self.get_optimized_supernumbers()
# Strategie-Klassifikation
if hot_count >= 3:
strategy = "🔥 MOMENTUM"
elif trend_count >= 3:
strategy = "🎯 TREND"
elif pattern in ['NMMHH', 'MNMHH', 'NHMHM']:
strategy = "🎨 MUSTER"
else:
strategy = "⚖️ BALANCE"
strategy_distribution[strategy] += 1
tip = {
'tipp_nr': len(generated_tips) + 1,
'zahlen': combination,
'z1': combination[0],
'z2': combination[1],
'z3': combination[2],
'z4': combination[3],
'z5': combination[4],
'sz1': sz1,
'sz2': sz2,
'muster': pattern,
'summe': sum(combination),
'hot_count': hot_count,
'trend_count': trend_count,
'strategy': strategy
}
generated_tips.append(tip)
# Status ausgeben
zahlen_str = f"{combination[0]:2}-{combination[1]:2}-{combination[2]:2}-{combination[3]:2}-{combination[4]:2}"
print(f"{len(generated_tips):2}. {zahlen_str:<20} {pattern:<7} {hot_count:<3} {trend_count:<3} {strategy}")
# Ultimate Zusammenfassung
print(f"\n🏆 ULTIMATE OPTIMIERUNGS-ZUSAMMENFASSUNG:")
print("=" * 50)
print(f"{len(generated_tips)} Ultimate Tipps generiert")
print(f"🎯 Erfolgsrate: {(len(generated_tips)/attempts)*100:.1f}%")
print(f"📊 Durchschnitt {sum(tip['hot_count'] for tip in generated_tips)/len(generated_tips):.1f} heiße Zahlen pro Tipp")
print(f"🔮 Durchschnitt {sum(tip['trend_count'] for tip in generated_tips)/len(generated_tips):.1f} Trend-Zahlen pro Tipp")
# Strategie-Verteilung
print(f"\n📈 STRATEGIE-VERTEILUNG:")
for strategy, count in strategy_distribution.most_common():
print(f" {strategy}: {count} Tipps")
# Komplette Tipp-Ausgabe
print(f"\n🎯 ULTIMATE TIPP-EMPFEHLUNGEN:")
print("=" * 70)
print(f"{'Nr':<3} {'Hauptzahlen':<20} {'SZ1':<4} {'SZ2':<4} {'Muster':<7} {'Strategie':<12} {'Score'}")
print("-" * 70)
for tip in generated_tips:
zahlen_str = f"{tip['z1']:2}-{tip['z2']:2}-{tip['z3']:2}-{tip['z4']:2}-{tip['z5']:2}"
# Ultimate Score berechnen
ultimate_score = (tip['hot_count'] * 0.3 + tip['trend_count'] * 0.4 +
(5 if tip['muster'] in ['NMMHH', 'MNMHH'] else 3) * 0.3)
print(f"{tip['tipp_nr']:2}. {zahlen_str:<20} {tip['sz1']:<4} {tip['sz2']:<4} "
f"{tip['muster']:<7} {tip['strategy']:<12} {ultimate_score:.1f}")
# Export mit Ultimate Features
self._export_ultimate_tips(generated_tips)
return generated_tips
def _export_ultimate_tips(self, tips):
"""Exportiert Ultimate Tipps mit erweiterten Daten."""
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
output_file = f"/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/ultimate_tipps_{timestamp}.csv"
# Erweiterte Daten für Export
export_data = []
for tip in tips:
tip_data = tip.copy()
# Zusätzliche Trend-Daten hinzufügen
tip_data['trend_scores'] = [self.trend_predictions[n]['prediction_score']
for n in tip['zahlen']]
tip_data['avg_trend_score'] = np.mean(tip_data['trend_scores'])
tip_data['momentum_ratings'] = [self.momentum_scores[n]['status']
for n in tip['zahlen']]
export_data.append(tip_data)
tips_df = pd.DataFrame(export_data)
tips_df.to_csv(output_file, sep=';', index=False)
print(f"\n💾 ULTIMATE EXPORT:")
print("=" * 25)
print(f"✅ Ultimate Tipps gespeichert: ultimate_tipps_{timestamp}.csv")
print(f"🚀 Multi-Trend-Analyse integriert")
print(f"🎯 Höchste Optimierungsstufe erreicht")
print(f"📊 Erweiterte Trend-Daten enthalten")
def main():
"""Hauptfunktion für Ultimate Generator."""
print("🚀 ULTIMATE EUROJACKPOT GENERATOR")
print("🎯 Mit Multi-Ziehungs-Trend-Integration")
print("=" * 50)
# Generator initialisieren (lädt und analysiert automatisch alle Daten)
generator = UltimativerEurojackpotGenerator()
# Ultimate Tipps generieren
tips = generator.generate_ultimate_tips(10)
print(f"\n🏆 ULTIMATE OPTIMIERUNG ABGESCHLOSSEN!")
print("=" * 45)
print(f"🚀 10 Ultimate Tipps mit Multi-Trend-Analyse generiert")
print(f"📈 Maximale Trefferwahrscheinlichkeit durch:")
print(f" • Momentum-Analyse über 15 Ziehungen")
print(f" • Sequenzielle Abhängigkeiten")
print(f" • Zyklische Muster-Erkennung")
print(f" • Positionsbasierte Optimierung")
print(f" • Trend-Vorhersage-Algorithmus")
print(f"🍀 Viel Erfolg bei der nächsten Ziehung!")
# Zusätzliche Ultimate Insights
print(f"\n💡 ULTIMATE INSIGHTS:")
print("=" * 30)
# Top 5 Trend-Zahlen für nächste Ziehung
top_trend_numbers = sorted(generator.trend_predictions.items(),
key=lambda x: x[1]['prediction_score'], reverse=True)[:5]
print(f"🎯 TOP 5 TREND-ZAHLEN für nächste Ziehung:")
for i, (number, data) in enumerate(top_trend_numbers):
momentum_status = generator.momentum_scores[number]['status']
print(f" {i+1}. Zahl {number:2}: {data['recommendation']} {momentum_status}")
# Empfohlene Muster basierend auf Zyklen
if generator.cycle_patterns:
print(f"\n🔄 ZYKLUS-EMPFEHLUNG:")
# Finde das wahrscheinlichste nächste Muster basierend auf Zyklen
recent_patterns = []
for _, row in generator.df.tail(5).iterrows():
numbers = sorted([row['Z1'], row['Z2'], row['Z3'], row['Z4'], row['Z5']])
pattern = generator._get_pattern(numbers)
recent_patterns.append(pattern)
print(f" Letzte 5 Muster: {''.join(recent_patterns)}")
# Empfehlung basierend auf häufigsten Mustern
top_pattern = generator.pattern_frequencies.most_common(1)[0]
print(f" Empfohlenes Muster: {top_pattern[0]} ({(top_pattern[1]/len(generator.df))*100:.1f}% Erfolgsrate)")
# Momentum-Warnung
very_hot = [n for n in generator.hot_numbers
if generator.momentum_scores[n]['momentum_score'] > 0.5]
if very_hot:
print(f"\n🔥 MOMENTUM-ALERT:")
print(f" SEHR HEIßE Zahlen: {very_hot[:5]}")
print(f" → Mindestens 1-2 dieser Zahlen in Tipps verwenden!")
return tips
# Zusätzliche Utility-Funktionen für erweiterte Analyse
def analyze_tip_quality(generator, tip_numbers):
"""Analysiert die Qualität eines einzelnen Tipps."""
quality_score = 0
analysis = {}
# Momentum-Analyse
hot_count = sum(1 for n in tip_numbers if n in generator.hot_numbers)
analysis['hot_numbers'] = hot_count
quality_score += hot_count * 0.2
# Trend-Analyse
trend_scores = [generator.trend_predictions[n]['prediction_score'] for n in tip_numbers]
avg_trend = np.mean(trend_scores)
analysis['avg_trend_score'] = avg_trend
quality_score += avg_trend * 0.3
# Positions-Analyse
position_quality = 0
for i, num in enumerate(sorted(tip_numbers)):
pos_freq = generator.position_frequencies[f'pos_{i+1}'][num]
if pos_freq > 0:
position_quality += pos_freq
analysis['position_quality'] = position_quality
quality_score += (position_quality / len(generator.df)) * 0.2
# Muster-Analyse
pattern = generator._get_pattern(sorted(tip_numbers))
pattern_freq = generator.pattern_frequencies[pattern]
pattern_score = pattern_freq / len(generator.df)
analysis['pattern'] = pattern
analysis['pattern_score'] = pattern_score
quality_score += pattern_score * 0.3
analysis['total_quality_score'] = quality_score
analysis['quality_rating'] = get_quality_rating(quality_score)
return analysis
def get_quality_rating(score):
"""Konvertiert Quality-Score in Rating."""
if score > 0.8:
return "🏆 PREMIUM"
elif score > 0.6:
return "🥇 SEHR GUT"
elif score > 0.4:
return "🥈 GUT"
elif score > 0.2:
return "🥉 DURCHSCHNITT"
else:
return "⚠️ SCHWACH"
def predict_jackpot_probability(generator, tip_numbers):
"""Schätzt Jackpot-Wahrscheinlichkeit basierend auf Trends."""
base_probability = 1 / 139838160 # Mathematische Grundwahrscheinlichkeit
# Trend-Multiplikator berechnen
trend_multiplier = 1.0
for number in tip_numbers:
momentum_score = generator.momentum_scores[number]['momentum_score']
trend_score = generator.trend_predictions[number]['prediction_score']
# Zahlen mit hohem Momentum/Trend erhöhen die relative Wahrscheinlichkeit
number_multiplier = 1 + (momentum_score * 0.1) + (trend_score * 0.15)
trend_multiplier *= number_multiplier
# Pattern-Bonus
pattern = generator._get_pattern(sorted(tip_numbers))
pattern_frequency = generator.pattern_frequencies[pattern] / len(generator.df)
pattern_multiplier = 1 + (pattern_frequency * 0.2)
estimated_probability = base_probability * trend_multiplier * pattern_multiplier
return {
'base_probability': base_probability,
'trend_multiplier': trend_multiplier,
'pattern_multiplier': pattern_multiplier,
'estimated_probability': estimated_probability,
'improvement_factor': (estimated_probability / base_probability)
}
def export_detailed_analysis(generator, tips, filename_suffix="detailed"):
"""Exportiert detaillierte Analyse aller Tipps."""
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
output_file = f"/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/analysis_{filename_suffix}_{timestamp}.csv"
detailed_data = []
for tip in tips:
tip_analysis = analyze_tip_quality(generator, tip['zahlen'])
probability_analysis = predict_jackpot_probability(generator, tip['zahlen'])
detailed_entry = {
**tip,
**tip_analysis,
**probability_analysis,
'individual_momentum_scores': [generator.momentum_scores[n]['momentum_score'] for n in tip['zahlen']],
'individual_trend_scores': [generator.trend_predictions[n]['prediction_score'] for n in tip['zahlen']],
'number_frequencies': [generator.number_frequencies[n] for n in tip['zahlen']]
}
detailed_data.append(detailed_entry)
# DataFrame erstellen und exportieren
df_detailed = pd.DataFrame(detailed_data)
df_detailed.to_csv(output_file, sep=';', index=False)
print(f"\n📊 DETAILLIERTE ANALYSE EXPORTIERT:")
print(f" 📁 Datei: analysis_{filename_suffix}_{timestamp}.csv")
print(f" 📈 Enthält Quality-Scores, Trend-Analysen und Wahrscheinlichkeits-Schätzungen")
if __name__ == "__main__":
# Reproduzierbarer Zufallsseed
random.seed(42)
np.random.seed(42)
# Ultimate Generator starten
tips = main()
# Optional: Detaillierte Analyse exportieren
if tips:
print(f"\n📊 ERWEITERTE ANALYSE VERFÜGBAR:")
print("=" * 40)
# Beispiel: Analysiere ersten Tipp detailliert
if len(tips) > 0:
generator = UltimativerEurojackpotGenerator()
sample_tip = tips[0]['zahlen']
quality_analysis = analyze_tip_quality(generator, sample_tip)
probability_analysis = predict_jackpot_probability(generator, sample_tip)
print(f"\n🔍 BEISPIEL-ANALYSE für Tipp 1 ({sample_tip}):")
print(f" 🏆 Quality-Rating: {quality_analysis['quality_rating']}")
print(f" 📈 Quality-Score: {quality_analysis['total_quality_score']:.3f}")
print(f" 🔥 Heiße Zahlen: {quality_analysis['hot_numbers']}/5")
print(f" 🎯 Avg. Trend-Score: {quality_analysis['avg_trend_score']:.3f}")
print(f" 🎨 Muster: {quality_analysis['pattern']} (Score: {quality_analysis['pattern_score']:.3f})")
print(f" 📊 Verbesserungs-Faktor: {probability_analysis['improvement_factor']:.2f}x")
# Optional: Detaillierte Analyse aller Tipps exportieren
export_detailed_analysis(generator, tips)
-234
View File
@@ -1,234 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot Tipp-Generator für NMMHH-Muster
Generiert 10 Tipp-Felder basierend auf dem erfolgreichsten NMMHH-Muster,
die keine bereits gezogenen Kombinationen enthalten.
"""
import pandas as pd
import random
from itertools import combinations
def load_drawn_numbers():
"""Lädt alle bereits gezogenen Kombinationen."""
df = pd.read_csv("/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/AlleEurojackpotzahlen.csv", sep=';')
drawn_combinations = set()
for _, row in df.iterrows():
# Sortierte Kombination für Vergleich
combo = tuple(sorted([row['Z1'], row['Z2'], row['Z3'], row['Z4'], row['Z5']]))
drawn_combinations.add(combo)
print(f"🚫 {len(drawn_combinations)} bereits gezogene Kombinationen geladen")
return drawn_combinations
def generate_nmmhh_numbers():
"""Generiert Zahlen nach dem NMMHH-Muster."""
# Bereichsdefinition basierend auf umschlüsselter Analyse
ranges = {
'N': list(range(1, 16)), # Niedrig: Gruppen 1-3 (Zahlen 1-15)
'M': list(range(16, 36)), # Mittel: Gruppen 4-7 (Zahlen 16-35)
'H': list(range(36, 51)) # Hoch: Gruppen 8-10 (Zahlen 36-50)
}
# NMMHH-Muster: 1 Niedrig, 2 Mittel, 2 Hoch
selected_numbers = []
# 1 Niedrige Zahl (Position z1)
selected_numbers.extend(random.sample(ranges['N'], 1))
# 2 Mittlere Zahlen (Positionen z2, z3)
selected_numbers.extend(random.sample(ranges['M'], 2))
# 2 Hohe Zahlen (Positionen z4, z5)
selected_numbers.extend(random.sample(ranges['H'], 2))
# Sortieren für Eurojackpot-Format
return sorted(selected_numbers)
def generate_optimized_nmmhh_numbers():
"""Generiert optimierte NMMHH-Zahlen basierend auf Positionsanalyse."""
# Optimierte Bereiche basierend auf Treffer-Analyse
optimized_ranges = {
'z1': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], # Niedrig (sehr wahrscheinlich)
'z2': [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25], # Niedrig-Mittel
'z3': [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], # Mittel
'z4': [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], # Mittel-Hoch
'z5': [41, 42, 43, 44, 45, 46, 47, 48, 49, 50] # Hoch (sehr wahrscheinlich)
}
selected_numbers = []
# Position z1: Niedrig
selected_numbers.append(random.choice(optimized_ranges['z1'][:10])) # Fokus auf 1-10
# Position z2: Niedrig-Mittel
selected_numbers.append(random.choice(optimized_ranges['z2'][5:])) # Fokus auf 16-25
# Position z3: Mittel
selected_numbers.append(random.choice(optimized_ranges['z3'])) # 21-35
# Position z4: Mittel-Hoch
selected_numbers.append(random.choice(optimized_ranges['z4'][5:])) # Fokus auf 36-45
# Position z5: Hoch
selected_numbers.append(random.choice(optimized_ranges['z5'])) # 41-50
# Duplikate vermeiden und sortieren
selected_numbers = list(set(selected_numbers))
# Falls durch Duplikat-Entfernung weniger als 5 Zahlen
while len(selected_numbers) < 5:
all_available = list(range(1, 51))
missing_number = random.choice([n for n in all_available if n not in selected_numbers])
selected_numbers.append(missing_number)
return sorted(selected_numbers[:5])
def generate_tips_nmmhh(num_tips=10):
"""Generiert Tipps basierend auf NMMHH-Muster ohne bereits gezogene Kombinationen."""
print("🎯 EUROJACKPOT TIPP-GENERATOR (NMMHH-MUSTER)")
print("="*50)
# Bereits gezogene Kombinationen laden
drawn_combinations = load_drawn_numbers()
# Häufigste Zahlen pro Position aus der Analyse
frequent_numbers = {
'z1': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
'z2': [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25],
'z3': [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35],
'z4': [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45],
'z5': [36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
}
print(f"\n📋 NMMHH-MUSTER BEDEUTUNG:")
print("N = Niedrig (1-15), M = Mittel (16-35), H = Hoch (36-50)")
print("Muster: 1 Niedrig + 2 Mittel + 2 Hoch = 14.7% Erfolgsrate!")
generated_tips = []
attempts = 0
max_attempts = 10000
print(f"\n🎲 GENERIERE {num_tips} OPTIMIERTE TIPPS:")
print("="*40)
while len(generated_tips) < num_tips and attempts < max_attempts:
attempts += 1
# Verschiedene Generierungsstrategien abwechseln
if attempts % 3 == 0:
tip = generate_optimized_nmmhh_numbers()
else:
tip = generate_nmmhh_numbers()
# Prüfen ob bereits gezogen
tip_tuple = tuple(sorted(tip))
if tip_tuple not in drawn_combinations and tip not in generated_tips:
generated_tips.append(tip)
# Muster-Verifikation
pattern = []
for num in tip:
if 1 <= num <= 15:
pattern.append('N')
elif 16 <= num <= 35:
pattern.append('M')
else:
pattern.append('H')
pattern_str = ''.join(pattern)
print(f"Tipp {len(generated_tips):2}: {tip[0]:2}-{tip[1]:2}-{tip[2]:2}-{tip[3]:2}-{tip[4]:2} (Muster: {pattern_str})")
if len(generated_tips) < num_tips:
print(f"\n⚠️ Nur {len(generated_tips)} von {num_tips} Tipps generiert nach {attempts} Versuchen")
else:
print(f"\n✅ Alle {num_tips} Tipps erfolgreich generiert!")
print(f"\n📊 MUSTER-ANALYSE DER GENERIERTEN TIPPS:")
print("="*45)
pattern_counts = {}
for tip in generated_tips:
pattern = []
for num in tip:
if 1 <= num <= 15:
pattern.append('N')
elif 16 <= num <= 35:
pattern.append('M')
else:
pattern.append('H')
pattern_str = ''.join(pattern)
pattern_counts[pattern_str] = pattern_counts.get(pattern_str, 0) + 1
for pattern, count in sorted(pattern_counts.items(), key=lambda x: x[1], reverse=True):
print(f"Muster {pattern}: {count} Tipps")
# Zusätzliche Superzahlen-Empfehlungen
print(f"\n🎲 SUPERZAHLEN-EMPFEHLUNGEN:")
print("="*30)
# Lade Superzahlen-Statistiken
df = pd.read_csv("/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/AlleEurojackpotzahlen.csv", sep=';')
sz1_counts = df['SZ1'].value_counts().head(5)
sz2_counts = df['SZ2'].value_counts().head(5)
print(f"Top 5 SZ1: {list(sz1_counts.index)}")
print(f"Top 5 SZ2: {list(sz2_counts.index)}")
# Empfohlene Superzahlen für die Tipps
recommended_sz1 = list(sz1_counts.index)[:3]
recommended_sz2 = list(sz2_counts.index)[:3]
print(f"\n🎯 KOMPLETTE TIPP-EMPFEHLUNGEN:")
print("="*40)
print(f"{'Tipp':<5} {'Hauptzahlen':<20} {'SZ1':<4} {'SZ2':<4}")
print("-" * 40)
final_tips = []
for i, tip in enumerate(generated_tips, 1):
sz1 = random.choice(recommended_sz1)
sz2 = random.choice(recommended_sz2)
tip_str = f"{tip[0]:2}-{tip[1]:2}-{tip[2]:2}-{tip[3]:2}-{tip[4]:2}"
print(f"{i:2}. {tip_str:<20} {sz1:<4} {sz2:<4}")
final_tips.append({
'tipp_nr': i,
'z1': tip[0],
'z2': tip[1],
'z3': tip[2],
'z4': tip[3],
'z5': tip[4],
'sz1': sz1,
'sz2': sz2,
'muster': ''.join(['N' if n <= 15 else 'M' if n <= 35 else 'H' for n in tip])
})
# Export der Tipps
print(f"\n💾 TIPPS EXPORTIEREN:")
print("="*25)
tips_df = pd.DataFrame(final_tips)
output_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/eurojackpot_tipps_nmmhh.csv"
tips_df.to_csv(output_file, sep=';', index=False)
print(f"✅ 10 Tipps gespeichert: eurojackpot_tipps_nmmhh.csv")
print(f"📈 Basierend auf NMMHH-Muster mit 14.7% historischer Erfolgsrate")
print(f"🚫 Keine bereits gezogenen Kombinationen enthalten")
return final_tips
if __name__ == "__main__":
# Zufallsseed für reproduzierbare Ergebnisse (optional)
random.seed(42)
tips = generate_tips_nmmhh(10)
@@ -1,234 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot Tipp-Generator für NMMHH-Muster
Generiert 10 Tipp-Felder basierend auf dem erfolgreichsten NMMHH-Muster,
die keine bereits gezogenen Kombinationen enthalten.
"""
import pandas as pd
import random
from itertools import combinations
def load_drawn_numbers():
"""Lädt alle bereits gezogenen Kombinationen."""
df = pd.read_csv("/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/AlleEurojackpotzahlen.csv", sep=';')
drawn_combinations = set()
for _, row in df.iterrows():
# Sortierte Kombination für Vergleich
combo = tuple(sorted([row['Z1'], row['Z2'], row['Z3'], row['Z4'], row['Z5']]))
drawn_combinations.add(combo)
print(f"🚫 {len(drawn_combinations)} bereits gezogene Kombinationen geladen")
return drawn_combinations
def generate_nmmhh_numbers():
"""Generiert Zahlen nach dem NMMHH-Muster."""
# Bereichsdefinition basierend auf umschlüsselter Analyse
ranges = {
'N': list(range(1, 16)), # Niedrig: Gruppen 1-3 (Zahlen 1-15)
'M': list(range(16, 36)), # Mittel: Gruppen 4-7 (Zahlen 16-35)
'H': list(range(36, 51)) # Hoch: Gruppen 8-10 (Zahlen 36-50)
}
# NMMHH-Muster: 1 Niedrig, 2 Mittel, 2 Hoch
selected_numbers = []
# 1 Niedrige Zahl (Position z1)
selected_numbers.extend(random.sample(ranges['N'], 1))
# 2 Mittlere Zahlen (Positionen z2, z3)
selected_numbers.extend(random.sample(ranges['M'], 2))
# 2 Hohe Zahlen (Positionen z4, z5)
selected_numbers.extend(random.sample(ranges['H'], 2))
# Sortieren für Eurojackpot-Format
return sorted(selected_numbers)
def generate_optimized_nmmhh_numbers():
"""Generiert optimierte NMMHH-Zahlen basierend auf Positionsanalyse."""
# Optimierte Bereiche basierend auf Treffer-Analyse
optimized_ranges = {
'z1': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], # Niedrig (sehr wahrscheinlich)
'z2': [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25], # Niedrig-Mittel
'z3': [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35], # Mittel
'z4': [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45], # Mittel-Hoch
'z5': [41, 42, 43, 44, 45, 46, 47, 48, 49, 50] # Hoch (sehr wahrscheinlich)
}
selected_numbers = []
# Position z1: Niedrig
selected_numbers.append(random.choice(optimized_ranges['z1'][:10])) # Fokus auf 1-10
# Position z2: Niedrig-Mittel
selected_numbers.append(random.choice(optimized_ranges['z2'][5:])) # Fokus auf 16-25
# Position z3: Mittel
selected_numbers.append(random.choice(optimized_ranges['z3'])) # 21-35
# Position z4: Mittel-Hoch
selected_numbers.append(random.choice(optimized_ranges['z4'][5:])) # Fokus auf 36-45
# Position z5: Hoch
selected_numbers.append(random.choice(optimized_ranges['z5'])) # 41-50
# Duplikate vermeiden und sortieren
selected_numbers = list(set(selected_numbers))
# Falls durch Duplikat-Entfernung weniger als 5 Zahlen
while len(selected_numbers) < 5:
all_available = list(range(1, 51))
missing_number = random.choice([n for n in all_available if n not in selected_numbers])
selected_numbers.append(missing_number)
return sorted(selected_numbers[:5])
def generate_tips_nmmhh(num_tips=10):
"""Generiert Tipps basierend auf NMMHH-Muster ohne bereits gezogene Kombinationen."""
print("🎯 EUROJACKPOT TIPP-GENERATOR (NMMHH-MUSTER)")
print("="*50)
# Bereits gezogene Kombinationen laden
drawn_combinations = load_drawn_numbers()
# Häufigste Zahlen pro Position aus der Analyse
frequent_numbers = {
'z1': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
'z2': [11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25],
'z3': [21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35],
'z4': [31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45],
'z5': [36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
}
print(f"\n📋 NMMHH-MUSTER BEDEUTUNG:")
print("N = Niedrig (1-15), M = Mittel (16-35), H = Hoch (36-50)")
print("Muster: 1 Niedrig + 2 Mittel + 2 Hoch = 14.7% Erfolgsrate!")
generated_tips = []
attempts = 0
max_attempts = 10000
print(f"\n🎲 GENERIERE {num_tips} OPTIMIERTE TIPPS:")
print("="*40)
while len(generated_tips) < num_tips and attempts < max_attempts:
attempts += 1
# Verschiedene Generierungsstrategien abwechseln
if attempts % 3 == 0:
tip = generate_optimized_nmmhh_numbers()
else:
tip = generate_nmmhh_numbers()
# Prüfen ob bereits gezogen
tip_tuple = tuple(sorted(tip))
if tip_tuple not in drawn_combinations and tip not in generated_tips:
generated_tips.append(tip)
# Muster-Verifikation
pattern = []
for num in tip:
if 1 <= num <= 15:
pattern.append('N')
elif 16 <= num <= 35:
pattern.append('M')
else:
pattern.append('H')
pattern_str = ''.join(pattern)
print(f"Tipp {len(generated_tips):2}: {tip[0]:2}-{tip[1]:2}-{tip[2]:2}-{tip[3]:2}-{tip[4]:2} (Muster: {pattern_str})")
if len(generated_tips) < num_tips:
print(f"\n⚠️ Nur {len(generated_tips)} von {num_tips} Tipps generiert nach {attempts} Versuchen")
else:
print(f"\n✅ Alle {num_tips} Tipps erfolgreich generiert!")
print(f"\n📊 MUSTER-ANALYSE DER GENERIERTEN TIPPS:")
print("="*45)
pattern_counts = {}
for tip in generated_tips:
pattern = []
for num in tip:
if 1 <= num <= 15:
pattern.append('N')
elif 16 <= num <= 35:
pattern.append('M')
else:
pattern.append('H')
pattern_str = ''.join(pattern)
pattern_counts[pattern_str] = pattern_counts.get(pattern_str, 0) + 1
for pattern, count in sorted(pattern_counts.items(), key=lambda x: x[1], reverse=True):
print(f"Muster {pattern}: {count} Tipps")
# Zusätzliche Superzahlen-Empfehlungen
print(f"\n🎲 SUPERZAHLEN-EMPFEHLUNGEN:")
print("="*30)
# Lade Superzahlen-Statistiken
df = pd.read_csv("/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/AlleEurojackpotzahlen.csv", sep=';')
sz1_counts = df['SZ1'].value_counts().head(5)
sz2_counts = df['SZ2'].value_counts().head(5)
print(f"Top 5 SZ1: {list(sz1_counts.index)}")
print(f"Top 5 SZ2: {list(sz2_counts.index)}")
# Empfohlene Superzahlen für die Tipps
recommended_sz1 = list(sz1_counts.index)[:3]
recommended_sz2 = list(sz2_counts.index)[:3]
print(f"\n🎯 KOMPLETTE TIPP-EMPFEHLUNGEN:")
print("="*40)
print(f"{'Tipp':<5} {'Hauptzahlen':<20} {'SZ1':<4} {'SZ2':<4}")
print("-" * 40)
final_tips = []
for i, tip in enumerate(generated_tips, 1):
sz1 = random.choice(recommended_sz1)
sz2 = random.choice(recommended_sz2)
tip_str = f"{tip[0]:2}-{tip[1]:2}-{tip[2]:2}-{tip[3]:2}-{tip[4]:2}"
print(f"{i:2}. {tip_str:<20} {sz1:<4} {sz2:<4}")
final_tips.append({
'tipp_nr': i,
'z1': tip[0],
'z2': tip[1],
'z3': tip[2],
'z4': tip[3],
'z5': tip[4],
'sz1': sz1,
'sz2': sz2,
'muster': ''.join(['N' if n <= 15 else 'M' if n <= 35 else 'H' for n in tip])
})
# Export der Tipps
print(f"\n💾 TIPPS EXPORTIEREN:")
print("="*25)
tips_df = pd.DataFrame(final_tips)
output_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/eurojackpot_tipps_nmmhh.csv"
tips_df.to_csv(output_file, sep=';', index=False)
print(f"✅ 10 Tipps gespeichert: eurojackpot_tipps_nmmhh.csv")
print(f"📈 Basierend auf NMMHH-Muster mit 14.7% historischer Erfolgsrate")
print(f"🚫 Keine bereits gezogenen Kombinationen enthalten")
return final_tips
if __name__ == "__main__":
# Zufallsseed für reproduzierbare Ergebnisse (optional)
random.seed(42)
tips = generate_tips_nmmhh(10)
@@ -92,7 +92,12 @@ class UltimateAIMLEurojackpotGenerator:
"""
Ultimate Eurojackpot Generator - ALLE Strategien kombiniert
"""
# Empirisch belegte "griffige" Einzelzahlen, die Spieler überproportional oft frei
# wählen (Quelle: Analysen realer Tippscheine, z.B. frz. 6aus49 über 25 Jahre:
# populärste Zahlen 5,7,9,11,12,13). Unabhängig vom Geburtstags-Bias (<=31).
POPULAR_PLAYER_PICKS = {5, 7, 9, 11, 12, 13}
def __init__(self, data_path, fast_mode=True):
self.data_path = data_path
self.df = None
@@ -441,7 +446,7 @@ class UltimateAIMLEurojackpotGenerator:
"""High-EV: 2 Zahlen >31, max. 1 Lucky Number, soft Consecutive-Vermeidung."""
random.seed(42 + tip_number * 41)
lucky_numbers = {3, 7, 9, 11, 13, 17, 19, 21, 23}
lucky_numbers = UltimateAIMLEurojackpotGenerator.POPULAR_PLAYER_PICKS
above_31_target = 2 # für 5 Zahlen: 2 above-31 = solide EV-Basis
selected_main = []
@@ -671,41 +676,91 @@ class UltimateAIMLEurojackpotGenerator:
return (distance_score * 0.6 + range_score * 0.4)
def _get_smart_euro_numbers(self, tip_number, euro_preds):
"""Intelligente Euro-Zahlen Auswahl."""
sorted_euro = sorted(euro_preds.items(), key=lambda x: x[1], reverse=True)
# Strategy based on tip number
if tip_number <= 3:
# Top predictions
return sorted([num for num, _ in sorted_euro[:2]])
else:
# Mix of top and diversity
top_euros = [num for num, _ in sorted_euro[:6]]
random.seed(42 + tip_number * 7)
return sorted(random.sample(top_euros, 2))
"""
EV-bewusste Euro-Zahlen-Auswahl: gewichtete Zufallswahl aus den
AI-Predictions statt starrer Top-2 (vorher: Tipps 1-3 bekamen IMMER
exakt dasselbe Euro-Paar), mit Abwertung klassischer Glückszahlen
(3, 7) - analog zur Hauptzahlen-Logik in _generate_high_ev_tip().
Schwächer empirisch belegt als die Hauptzahlen-Heuristik: 1-12
überschneidet sich mit Kalendermonaten, es gibt keine klare
Geburtstags-Grenze wie bei den Hauptzahlen (>31). Deshalb bewusst
konservativ: nur die zwei bekanntesten Glückszahlen abgewertet,
keine erfundene Rangfolge aller 12 Ziffern.
"""
random.seed(100 + tip_number * 13)
lucky_euro = {3, 7}
pool = list(euro_preds.keys())
weights = []
for n in pool:
w = euro_preds.get(n, 0.1)
if n in lucky_euro:
w *= 0.5
weights.append(max(0.001, w))
chosen = []
for _ in range(2):
pick = random.choices(pool, weights=weights)[0]
idx = pool.index(pick)
pool.pop(idx)
weights.pop(idx)
chosen.append(pick)
return sorted(chosen)
@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.
Höher = unpopulärer bei Mitspielern = höherer Gewinnanteil bei einem Treffer
(Hit-Wahrscheinlichkeit selbst ist bei i.i.d. Ziehungen nicht beeinflussbar).
Basis: dokumentierte Spielerverhalten-Biases (Henze/Riedwyl-artige Analysen
realer Tippscheine): Geburtstagszahlen (<=31), einzelne "griffige" Zahlen,
Zahlenfolgen/arithmetische Muster (z.B. 5-10-15-20-25) und "zufällig
aussehende" ausgeglichene Odd/Even-Splits werden von Menschen
überproportional oft gewählt - jede einzelne Kombination ist aber exakt
gleich wahrscheinlich, unabhängig von diesen Eigenschaften.
Hinweis: eine "Summe nahe am Mittel"-Komponente wurde bewusst NICHT
aufgenommen - sie widerspricht sich mit der Muster-Erkennung, da gerade
die meistgespielten sequenziellen Kombinationen (z.B. 1-2-3-4-5) durch
ihre enge Zahlen-Clusterung zugleich eine extreme Summe erzeugen.
"""
n = len(main_numbers)
sorted_nums = sorted(main_numbers)
# Anteil Zahlen > 31 (Geburtstags-Range vermeiden)
# 1) Geburtstags-Range (1-31) meiden
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
# 2) Empirisch belegte populäre Einzelzahlen meiden
popular_ratio = sum(
1 for x in main_numbers
if x in UltimateAIMLEurojackpotGenerator.POPULAR_PLAYER_PICKS
) / n
# 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
# 3) Muster/Zahlenfolgen meiden: direkte Nachbarn UND allgemeine
# arithmetische Folgen (konstante Schrittweite, z.B. 5-10-15-20-25
# zählt zu den meistgespielten Kombinationen überhaupt)
diffs = [sorted_nums[i + 1] - sorted_nums[i] for i in range(n - 1)]
small_step_ratio = sum(1 for d in diffs if d <= 5) / (n - 1) if diffs else 0
is_perfect_progression = len(diffs) > 1 and len(set(diffs)) == 1
pattern_penalty = small_step_ratio * (0.6 if not is_perfect_progression else 1.0)
score = above_31_ratio * 0.5 + (1 - consecutive_ratio) * 0.3 + (1 - lucky_ratio) * 0.2
# 4) Odd/Even-Split: Menschen bevorzugen "ausgeglichen aussehende" Splits,
# obwohl jede einzelne Kombination gleich wahrscheinlich ist. Bei 5
# Zahlen ist der ausgeglichenste Split 2-3/3-2 (kein exaktes Halbieren
# möglich), daher Distanz zum Mittelpunkt 2.5 statt n/2.
even_count = sum(1 for x in main_numbers if x % 2 == 0)
split_extremity = abs(even_count - (n / 2)) / (n / 2)
score = (
above_31_ratio * 0.30
+ (1 - popular_ratio) * 0.20
+ (1 - pattern_penalty) * 0.30
+ split_extremity * 0.20
)
return min(max(score, 0.0), 1.0)
def _calculate_quality_score(self, main_numbers, euro_numbers, main_preds, euro_preds, pattern_weight):
@@ -741,13 +796,17 @@ class UltimateAIMLEurojackpotGenerator:
else:
recency_quality = 0.5
# Popularity/EV dominiert bewusst: AI-Score, Pattern und Recency sagen nichts
# über die (unbeeinflussbare) Trefferwahrscheinlichkeit aus - Recency/Pattern
# folgen zudem Heuristiken, die auch andere Systemspieler nutzen und damit die
# Popularity eher untergraben statt sie zu unterstützen.
quality = (
main_quality * 0.25
+ euro_quality * 0.15
+ pattern_quality * 0.15
main_quality * 0.15
+ euro_quality * 0.10
+ pattern_quality * 0.10
+ diversity_quality * 0.10
+ popularity_quality * 0.20
+ recency_quality * 0.15
+ popularity_quality * 0.45
+ recency_quality * 0.10
)
return min(quality, 1.0)
File diff suppressed because it is too large Load Diff
-77
View File
@@ -1,77 +0,0 @@
#!/usr/bin/env python3
"""
Erstellt Beispiel-CSV-Dateien für das Eurojackpot-Processing
"""
import pandas as pd
import itertools
from datetime import datetime, timedelta
import random
def create_all_combinations():
"""Erstellt eine CSV mit allen möglichen 5-aus-50 Kombinationen (Beispiel mit ersten 100)."""
print("Erstelle Beispiel-Kombinationsdatei...")
# Für Demo: nur erste 100 Kombinationen von 5 aus 20 Zahlen
# (Vollständige 5-aus-50 Kombinationen wären über 2 Millionen!)
combinations = []
count = 0
for combo in itertools.combinations(range(1, 21), 5): # 5 aus 20 für Demo
combinations.append({
'Zahl1': combo[0],
'Zahl2': combo[1],
'Zahl3': combo[2],
'Zahl4': combo[3],
'Zahl5': combo[4]
})
count += 1
if count >= 100: # Limitierung für Demo
break
df = pd.DataFrame(combinations)
df.to_csv('alle_kombinationen_beispiel.csv', index=False)
print(f"Beispiel-Kombinationsdatei erstellt: {len(df)} Kombinationen")
return df
def create_drawn_numbers():
"""Erstellt eine CSV mit gezogenen Zahlen (Beispieldaten)."""
print("Erstelle Beispiel-Datei mit gezogenen Zahlen...")
drawn_numbers = []
start_date = datetime(2023, 1, 1)
# 20 zufällige Ziehungen erstellen
for i in range(20):
date = start_date + timedelta(days=i*7) # Wöchentliche Ziehungen
# 5 zufällige Zahlen zwischen 1 und 20 (ohne Wiederholung)
numbers = sorted(random.sample(range(1, 21), 5))
drawn_numbers.append({
'Datum': date.strftime('%Y-%m-%d'),
'Z1': numbers[0],
'Z2': numbers[1],
'Z3': numbers[2],
'Z4': numbers[3],
'Z5': numbers[4]
})
df = pd.DataFrame(drawn_numbers)
df.to_csv('gezogene_zahlen_beispiel.csv', index=False)
print(f"Beispiel-Datei mit gezogenen Zahlen erstellt: {len(df)} Ziehungen")
return df
if __name__ == "__main__":
print("=== Erstelle Beispiel-CSV-Dateien ===\n")
# Seed für reproduzierbare Ergebnisse
random.seed(42)
combinations_df = create_all_combinations()
drawn_df = create_drawn_numbers()
print("\n=== Beispieldateien erstellt ===")
print("- alle_kombinationen_beispiel.csv")
print("- gezogene_zahlen_beispiel.csv")
print("\nSie können jetzt das Hauptscript testen:")
-165
View File
@@ -1,165 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot CSV Processor
Dieses Script liest zwei CSV-Dateien ein:
1. Alle möglichen Zahlenkombinationen (5 Zahlen)
2. Bereits gezogene Zahlen mit Datumsstempel
Es markiert in der ersten Datei alle bereits gezogenen Kombinationen mit 1 (sonst 0).
"""
import pandas as pd
import sys
from pathlib import Path
def load_combinations_file(filepath):
"""Lädt die Datei mit allen möglichen Kombinationen."""
try:
df = pd.read_csv(filepath)
print(f"Kombinationen geladen: {len(df)} Zeilen")
print(f"Spalten: {list(df.columns)}")
return df
except Exception as e:
print(f"Fehler beim Laden der Kombinationsdatei: {e}")
return None
def load_drawn_numbers_file(filepath):
"""Lädt die Datei mit bereits gezogenen Zahlen."""
try:
df = pd.read_csv(filepath)
print(f"Gezogene Zahlen geladen: {len(df)} Zeilen")
print(f"Spalten: {list(df.columns)}")
return df
except Exception as e:
print(f"Fehler beim Laden der gezogenen Zahlen: {e}")
return None
def create_combination_key(row, z_columns):
"""Erstellt einen eindeutigen Schlüssel aus den 5 Zahlen (sortiert)."""
numbers = [row[col] for col in z_columns]
return tuple(sorted(numbers))
def process_eurojackpot_data(combinations_file, drawn_numbers_file, output_file):
"""Hauptfunktion zur Verarbeitung der Eurojackpot-Daten."""
# CSV-Dateien laden
print("Lade Kombinationsdatei...")
combinations_df = load_combinations_file(combinations_file)
if combinations_df is None:
return False
print("\nLade Datei mit gezogenen Zahlen...")
drawn_df = load_drawn_numbers_file(drawn_numbers_file)
if drawn_df is None:
return False
# Spalten für Zahlen identifizieren
# Annahme: In der Kombinationsdatei sind die ersten 5 Spalten die Zahlen
# In der gezogenen Zahlen-Datei sind es Z1, Z2, Z3, Z4, Z5
# Für Kombinationsdatei - erste 5 numerische Spalten verwenden
numeric_cols = combinations_df.select_dtypes(include=['number']).columns
if len(numeric_cols) >= 5:
combo_z_columns = numeric_cols[:5].tolist()
else:
# Fallback: erste 5 Spalten nehmen
combo_z_columns = combinations_df.columns[:5].tolist()
print(f"Verwendete Spalten für Kombinationen: {combo_z_columns}")
# Für gezogene Zahlen - Z1 bis Z5 Spalten suchen
z_columns = [col for col in drawn_df.columns if col.startswith('Z') and col[1:].isdigit()]
z_columns = sorted(z_columns)[:5] # Ersten 5 Z-Spalten nehmen
if not z_columns:
# Fallback: nach Spalten mit "Zahl" im Namen suchen oder numerische Spalten
z_columns = [col for col in drawn_df.columns if 'zahl' in col.lower()][:5]
if not z_columns:
z_columns = drawn_df.select_dtypes(include=['number']).columns[:5].tolist()
print(f"Verwendete Spalten für gezogene Zahlen: {z_columns}")
# Set mit allen gezogenen Kombinationen erstellen
print("\nErstelle Set mit gezogenen Kombinationen...")
drawn_combinations = set()
for _, row in drawn_df.iterrows():
combo_key = create_combination_key(row, z_columns)
drawn_combinations.add(combo_key)
print(f"Anzahl eindeutige gezogene Kombinationen: {len(drawn_combinations)}")
# Neue Spalte für Markierungen hinzufügen
print("\nMarkiere gezogene Kombinationen...")
combinations_df['bereits_gezogen'] = 0
marked_count = 0
for idx, row in combinations_df.iterrows():
combo_key = create_combination_key(row, combo_z_columns)
if combo_key in drawn_combinations:
combinations_df.at[idx, 'bereits_gezogen'] = 1
marked_count += 1
print(f"Anzahl markierte Kombinationen: {marked_count}")
# Ergebnis speichern
print(f"\nSpeichere Ergebnis in: {output_file}")
combinations_df.to_csv(output_file, index=False)
# Statistiken ausgeben
total_combinations = len(combinations_df)
drawn_percentage = (marked_count / total_combinations) * 100 if total_combinations > 0 else 0
print(f"\n=== STATISTIKEN ===")
print(f"Gesamte Kombinationen: {total_combinations:,}")
print(f"Bereits gezogene Kombinationen: {marked_count:,}")
print(f"Prozentsatz bereits gezogen: {drawn_percentage:.4f}%")
print(f"Noch nicht gezogene Kombinationen: {total_combinations - marked_count:,}")
return True
def main():
"""Hauptfunktion mit Benutzerinteraktion."""
print("=== Eurojackpot CSV Processor ===\n")
# Dateipfade abfragen oder Standard verwenden
if len(sys.argv) >= 4:
combinations_file = sys.argv[1]
drawn_numbers_file = sys.argv[2]
output_file = sys.argv[3]
else:
print("Geben Sie die Dateipfade ein (oder drücken Sie Enter für Standard):")
combinations_file = input("Pfad zur Kombinationsdatei (alle_kombinationen.csv): ").strip()
if not combinations_file:
combinations_file = "alle_kombinationen.csv"
drawn_numbers_file = input("Pfad zur Datei mit gezogenen Zahlen (gezogene_zahlen.csv): ").strip()
if not drawn_numbers_file:
drawn_numbers_file = "gezogene_zahlen.csv"
output_file = input("Pfad für Ausgabedatei (kombinationen_markiert.csv): ").strip()
if not output_file:
output_file = "kombinationen_markiert.csv"
# Überprüfen ob Dateien existieren
if not Path(combinations_file).exists():
print(f"Fehler: Kombinationsdatei '{combinations_file}' nicht gefunden!")
return
if not Path(drawn_numbers_file).exists():
print(f"Fehler: Datei mit gezogenen Zahlen '{drawn_numbers_file}' nicht gefunden!")
return
# Verarbeitung starten
success = process_eurojackpot_data(combinations_file, drawn_numbers_file, output_file)
if success:
print(f"\n✅ Verarbeitung erfolgreich abgeschlossen!")
print(f"Ergebnis gespeichert in: {output_file}")
else:
print("\n❌ Fehler bei der Verarbeitung!")
if __name__ == "__main__":
main()
@@ -1,220 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot CSV Processor - Angepasst für Semikolon-getrennte CSV-Dateien
Dieses Script liest zwei CSV-Dateien ein:
1. Alle möglichen Zahlenkombinationen (5 Zahlen)
2. Bereits gezogene Zahlen mit Datumsstempel
Es markiert in der ersten Datei alle bereits gezogenen Kombinationen mit 1 (sonst 0).
"""
import pandas as pd
import sys
from pathlib import Path
def detect_separator(filepath):
"""Erkennt das CSV-Trennzeichen automatisch."""
try:
with open(filepath, 'r', encoding='utf-8') as f:
first_line = f.readline()
if ';' in first_line and first_line.count(';') > first_line.count(','):
return ';'
return ','
except:
return ','
def load_combinations_file(filepath):
"""Lädt die Datei mit allen möglichen Kombinationen."""
try:
sep = detect_separator(filepath)
print(f"Erkanntes Trennzeichen für Kombinationen: '{sep}'")
df = pd.read_csv(filepath, sep=sep)
print(f"Kombinationen geladen: {len(df)} Zeilen")
print(f"Spalten: {list(df.columns)}")
return df
except Exception as e:
print(f"Fehler beim Laden der Kombinationsdatei: {e}")
return None
def load_drawn_numbers_file(filepath):
"""Lädt die Datei mit bereits gezogenen Zahlen."""
try:
sep = detect_separator(filepath)
print(f"Erkanntes Trennzeichen für gezogene Zahlen: '{sep}'")
df = pd.read_csv(filepath, sep=sep)
print(f"Gezogene Zahlen geladen: {len(df)} Zeilen")
print(f"Spalten: {list(df.columns)}")
return df
except Exception as e:
print(f"Fehler beim Laden der gezogenen Zahlen: {e}")
return None
def identify_number_columns(df, is_combinations=True):
"""Identifiziert die Spalten mit den Zahlen."""
columns = df.columns.tolist()
if is_combinations:
# Für Kombinationsdatei: Z1, Z2, Z3, Z4, Z5 suchen
z_cols = [col for col in columns if col.startswith('Z') and len(col) == 2 and col[1:].isdigit()]
z_cols = sorted(z_cols)[:5]
if len(z_cols) >= 5:
return z_cols
# Fallback: erste 5 numerische Spalten
numeric_cols = df.select_dtypes(include=['number']).columns[:5].tolist()
if len(numeric_cols) >= 5:
return numeric_cols
# Fallback: erste 5 Spalten
return columns[:5]
else:
# Für gezogene Zahlen: Z1-Z5 suchen (nicht SZ1, SZ2)
z_cols = [col for col in columns if col.startswith('Z') and len(col) == 2 and col[1:].isdigit()]
z_cols = [col for col in z_cols if not col.startswith('SZ')] # Superzahlen ausschließen
z_cols = sorted(z_cols)[:5]
if len(z_cols) >= 5:
return z_cols
# Fallback: numerische Spalten (ohne Datum)
numeric_cols = df.select_dtypes(include=['number']).columns
numeric_cols = [col for col in numeric_cols if 'datum' not in col.lower()][:5]
if len(numeric_cols) >= 5:
return numeric_cols.tolist()
# Letzter Fallback
return columns[:5]
def create_combination_key(row, z_columns):
"""Erstellt einen eindeutigen Schlüssel aus den 5 Zahlen (sortiert)."""
try:
numbers = [int(row[col]) for col in z_columns]
return tuple(sorted(numbers))
except:
return None
def process_eurojackpot_data(combinations_file, drawn_numbers_file, output_file):
"""Hauptfunktion zur Verarbeitung der Eurojackpot-Daten."""
# CSV-Dateien laden
print("Lade Kombinationsdatei...")
combinations_df = load_combinations_file(combinations_file)
if combinations_df is None:
return False
print("\nLade Datei mit gezogenen Zahlen...")
drawn_df = load_drawn_numbers_file(drawn_numbers_file)
if drawn_df is None:
return False
# Spalten für Zahlen identifizieren
combo_z_columns = identify_number_columns(combinations_df, is_combinations=True)
drawn_z_columns = identify_number_columns(drawn_df, is_combinations=False)
print(f"\nVerwendete Spalten für Kombinationen: {combo_z_columns}")
print(f"Verwendete Spalten für gezogene Zahlen: {drawn_z_columns}")
# Datencheck
print(f"\nErste Kombination: {combinations_df[combo_z_columns].iloc[0].tolist()}")
print(f"Erste gezogene Zahlen: {drawn_df[drawn_z_columns].iloc[0].tolist()}")
# Set mit allen gezogenen Kombinationen erstellen
print("\nErstelle Set mit gezogenen Kombinationen...")
drawn_combinations = set()
for _, row in drawn_df.iterrows():
combo_key = create_combination_key(row, drawn_z_columns)
if combo_key:
drawn_combinations.add(combo_key)
print(f"Anzahl eindeutige gezogene Kombinationen: {len(drawn_combinations)}")
# Beispiele anzeigen
if drawn_combinations:
print(f"Erste 5 gezogene Kombinationen: {list(drawn_combinations)[:5]}")
# Neue Spalte für Markierungen hinzufügen (falls noch nicht vorhanden)
if 'bereits_gezogen' not in combinations_df.columns:
combinations_df['bereits_gezogen'] = 0
else:
combinations_df['bereits_gezogen'] = 0 # Zurücksetzen
print("\nMarkiere gezogene Kombinationen...")
marked_count = 0
for idx, row in combinations_df.iterrows():
combo_key = create_combination_key(row, combo_z_columns)
if combo_key and combo_key in drawn_combinations:
combinations_df.at[idx, 'bereits_gezogen'] = 1
marked_count += 1
if marked_count <= 5: # Erste 5 Treffer anzeigen
print(f"Treffer gefunden: {combo_key}")
print(f"Anzahl markierte Kombinationen: {marked_count}")
# Ergebnis speichern
print(f"\nSpeichere Ergebnis in: {output_file}")
sep = detect_separator(combinations_file) # Gleiches Trennzeichen wie Eingabe verwenden
combinations_df.to_csv(output_file, sep=sep, index=False)
# Statistiken ausgeben
total_combinations = len(combinations_df)
drawn_percentage = (marked_count / total_combinations) * 100 if total_combinations > 0 else 0
print(f"\n=== STATISTIKEN ===")
print(f"Gesamte Kombinationen: {total_combinations:,}")
print(f"Bereits gezogene Kombinationen: {marked_count:,}")
print(f"Prozentsatz bereits gezogen: {drawn_percentage:.4f}%")
print(f"Noch nicht gezogene Kombinationen: {total_combinations - marked_count:,}")
return True
def main():
"""Hauptfunktion mit Benutzerinteraktion."""
print("=== Eurojackpot CSV Processor (Fixed) ===\n")
# Dateipfade abfragen oder Standard verwenden
if len(sys.argv) >= 4:
combinations_file = sys.argv[1]
drawn_numbers_file = sys.argv[2]
output_file = sys.argv[3]
else:
print("Geben Sie die Dateipfade ein (oder drücken Sie Enter für Standard):")
combinations_file = input("Pfad zur Kombinationsdatei: ").strip()
if not combinations_file:
combinations_file = "Alle_Eurojackpot_Kombinationen_mit_Status.csv"
drawn_numbers_file = input("Pfad zur Datei mit gezogenen Zahlen: ").strip()
if not drawn_numbers_file:
drawn_numbers_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/data/AlleEurojackpotzahlen.csv"
output_file = input("Pfad für Ausgabedatei: ").strip()
if not output_file:
output_file = "Kombinationen_markiert_fixed.csv"
# Überprüfen ob Dateien existieren
if not Path(combinations_file).exists():
print(f"Fehler: Kombinationsdatei '{combinations_file}' nicht gefunden!")
return
if not Path(drawn_numbers_file).exists():
print(f"Fehler: Datei mit gezogenen Zahlen '{drawn_numbers_file}' nicht gefunden!")
return
# Verarbeitung starten
success = process_eurojackpot_data(combinations_file, drawn_numbers_file, output_file)
if success:
print(f"\n✅ Verarbeitung erfolgreich abgeschlossen!")
print(f"Ergebnis gespeichert in: {output_file}")
else:
print("\n❌ Fehler bei der Verarbeitung!")
if __name__ == "__main__":
main()
-62
View File
@@ -1,62 +0,0 @@
#!/usr/bin/env python3
"""
Vereinfachte Version des Eurojackpot Processors
Für spezifische Spaltenstrukturen
"""
import pandas as pd
def process_eurojackpot_simple(combinations_csv, drawn_numbers_csv, output_csv):
"""
Vereinfachte Verarbeitung mit festen Spaltenstrukturen
Parameter:
- combinations_csv: CSV mit allen Kombinationen (Spalten: Zahl1, Zahl2, Zahl3, Zahl4, Zahl5)
- drawn_numbers_csv: CSV mit gezogenen Zahlen (Spalten: Datum, Z1, Z2, Z3, Z4, Z5)
- output_csv: Ausgabedatei
"""
# Dateien laden
print("Lade Kombinationsdatei...")
combinations = pd.read_csv(combinations_csv)
print("Lade gezogene Zahlen...")
drawn = pd.read_csv(drawn_numbers_csv)
# Gezogene Kombinationen als Set erstellen (sortiert für Vergleich)
drawn_sets = set()
for _, row in drawn.iterrows():
# Annahme: Spalten Z1, Z2, Z3, Z4, Z5 enthalten die Zahlen
numbers = sorted([row['Z1'], row['Z2'], row['Z3'], row['Z4'], row['Z5']])
drawn_sets.add(tuple(numbers))
print(f"Gefundene gezogene Kombinationen: {len(drawn_sets)}")
# Neue Spalte hinzufügen
combinations['bereits_gezogen'] = 0
# Jede Kombination prüfen
marked = 0
for idx, row in combinations.iterrows():
# Annahme: erste 5 Spalten enthalten die Zahlenkombination
combo_cols = combinations.columns[:5]
numbers = sorted([row[col] for col in combo_cols])
if tuple(numbers) in drawn_sets:
combinations.at[idx, 'bereits_gezogen'] = 1
marked += 1
# Ergebnis speichern
combinations.to_csv(output_csv, index=False)
print(f"Verarbeitung abgeschlossen!")
print(f"Markierte Kombinationen: {marked}")
print(f"Ergebnis gespeichert in: {output_csv}")
# Beispielaufruf
if __name__ == "__main__":
process_eurojackpot_simple(
"alle_kombinationen.csv",
"gezogene_zahlen.csv",
"kombinationen_markiert.csv"
)
-681
View File
@@ -1,681 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot Historical Data Updater
Lädt automatisch die neuesten Eurojackpot-Ziehungen von der offiziellen Website
und aktualisiert die lokale CSV-Datei.
Quellen:
- https://www.eurojackpot.de/de/eurojackpot/gewinnzahlen.html
- Oder alternative APIs/Websites
Features:
- Automatisches Scraping der neuesten Ziehungen
- Duplikate-Vermeidung
- Backup vor Update
- Validierung der neuen Daten
"""
import pandas as pd
import requests
from bs4 import BeautifulSoup
from datetime import datetime
import shutil
import os
import re
from typing import List, Dict, Optional
import time
class EurojackpotDataUpdater:
"""Aktualisiert historische Eurojackpot-Daten automatisch."""
def __init__(self, data_file: str):
"""
Initialisiert den Updater.
Args:
data_file: Pfad zur lokalen CSV-Datei
"""
self.data_file = data_file
self.backup_file = None
self.df_existing = None
# API/Scraping URLs
self.sources = {
'eurojackpot_de': 'https://www.eurojackpot.de/de/eurojackpot/gewinnzahlen.html',
'euro-jackpot_net': 'https://www.euro-jackpot.net/de/gewinnzahlen',
'lottode': 'https://www.lotto.de/eurojackpot/gewinnzahlen'
}
print("🔄 EUROJACKPOT DATA UPDATER")
print("=" * 60)
def load_existing_data(self) -> bool:
"""Lädt existierende Daten."""
try:
if not os.path.exists(self.data_file):
print(f"⚠️ Datei nicht gefunden: {self.data_file}")
print(" Erstelle neue Datei...")
self.df_existing = pd.DataFrame(columns=['datum', 'Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'SZ1', 'SZ2'])
return True
self.df_existing = pd.read_csv(self.data_file, sep=';')
# Datum als datetime
if 'datum' in self.df_existing.columns:
self.df_existing['datum'] = pd.to_datetime(
self.df_existing['datum'],
format='%Y-%m-%d',
errors='coerce'
)
print(f"✅ Existierende Daten geladen: {len(self.df_existing)} Ziehungen")
if len(self.df_existing) > 0:
latest = self.df_existing['datum'].max()
print(f" Neueste Ziehung: {latest.strftime('%Y-%m-%d') if pd.notna(latest) else 'Unbekannt'}")
return True
except Exception as e:
print(f"❌ Fehler beim Laden: {e}")
return False
def create_backup(self) -> bool:
"""Erstellt Backup der existierenden Datei."""
if not os.path.exists(self.data_file):
return True
try:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_dir = os.path.join(os.path.dirname(self.data_file), "backups")
os.makedirs(backup_dir, exist_ok=True)
filename = os.path.basename(self.data_file)
self.backup_file = os.path.join(backup_dir, f"{filename}.backup_{timestamp}")
shutil.copy2(self.data_file, self.backup_file)
print(f"✅ Backup erstellt: {os.path.basename(self.backup_file)}")
return True
except Exception as e:
print(f"⚠️ Backup-Fehler: {e}")
return False
def fetch_from_eurojackpot_de(self) -> List[Dict]:
"""
Scrapt Daten von eurojackpot.de
Returns:
Liste von Ziehungen als Dictionaries
"""
print("\n🌐 Versuche eurojackpot.de...")
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
}
response = requests.get(self.sources['eurojackpot_de'], headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
# Suche nach Ziehungsergebnissen
# Dies ist ein generisches Beispiel - muss an tatsächliche Website-Struktur angepasst werden
draws = []
# Beispiel-Parsing (muss angepasst werden!)
result_blocks = soup.find_all('div', class_='drawing-result')
for block in result_blocks[:10]: # Letzte 10 Ziehungen
try:
# Datum extrahieren
date_elem = block.find('span', class_='date')
if not date_elem:
continue
date_str = date_elem.text.strip()
date_obj = self._parse_german_date(date_str)
# Zahlen extrahieren
numbers = []
number_elems = block.find_all('span', class_='ball')
for num_elem in number_elems[:5]:
num = int(num_elem.text.strip())
numbers.append(num)
# Eurozahlen extrahieren
euro_numbers = []
euro_elems = block.find_all('span', class_='euro-ball')
for euro_elem in euro_elems[:2]:
euro_num = int(euro_elem.text.strip())
euro_numbers.append(euro_num)
if len(numbers) == 5 and len(euro_numbers) == 2:
draws.append({
'datum': date_obj,
'Z1': numbers[0],
'Z2': numbers[1],
'Z3': numbers[2],
'Z4': numbers[3],
'Z5': numbers[4],
'SZ1': euro_numbers[0],
'SZ2': euro_numbers[1]
})
except Exception as e:
continue
if draws:
print(f"{len(draws)} Ziehungen gefunden")
return draws
else:
print(" ⚠️ Keine Ziehungen gefunden (HTML-Struktur möglicherweise geändert)")
return []
except Exception as e:
print(f" ❌ Fehler: {e}")
return []
def fetch_from_euro_jackpot_net(self) -> List[Dict]:
"""
Scrapt Daten von euro-jackpot.net
Returns:
Liste von Ziehungen
"""
print("\n🌐 Versuche euro-jackpot.net...")
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
}
response = requests.get(self.sources['euro-jackpot_net'], headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
draws = []
# Parsing-Logik für diese Website
# (Platzhalter - muss an tatsächliche Struktur angepasst werden)
result_rows = soup.find_all('tr', class_='result-row')
for row in result_rows[:10]:
try:
cells = row.find_all('td')
if len(cells) < 8:
continue
# Datum
date_str = cells[0].text.strip()
date_obj = self._parse_german_date(date_str)
# Hauptzahlen
numbers = [int(cells[i].text.strip()) for i in range(1, 6)]
# Eurozahlen
euro_numbers = [int(cells[i].text.strip()) for i in range(6, 8)]
draws.append({
'datum': date_obj,
'Z1': numbers[0],
'Z2': numbers[1],
'Z3': numbers[2],
'Z4': numbers[3],
'Z5': numbers[4],
'SZ1': euro_numbers[0],
'SZ2': euro_numbers[1]
})
except Exception as e:
continue
if draws:
print(f"{len(draws)} Ziehungen gefunden")
else:
print(" ⚠️ Keine Ziehungen gefunden")
return draws
except Exception as e:
print(f" ❌ Fehler: {e}")
return []
def fetch_from_manual_input(self) -> List[Dict]:
"""
Manuelle Eingabe von neuen Ziehungen.
Returns:
Liste von Ziehungen
"""
print("\n⌨️ MANUELLE EINGABE")
print("=" * 60)
print("Gib die neuesten Ziehungen manuell ein.")
print("Format: YYYY-MM-DD Z1 Z2 Z3 Z4 Z5 SZ1 SZ2")
print("Beispiel: 2025-01-24 7 18 26 37 46 3 11")
print("Leer lassen zum Beenden.\n")
draws = []
while True:
user_input = input(f"Ziehung {len(draws) + 1}: ").strip()
if not user_input:
break
try:
parts = user_input.split()
if len(parts) != 8:
print(" ❌ Ungültiges Format. Bitte 8 Werte eingeben.")
continue
date_obj = datetime.strptime(parts[0], '%Y-%m-%d')
numbers = [int(parts[i]) for i in range(1, 6)]
euro_numbers = [int(parts[i]) for i in range(6, 8)]
# Validierung
if not all(1 <= n <= 50 for n in numbers):
print(" ❌ Hauptzahlen müssen zwischen 1 und 50 liegen.")
continue
if not all(1 <= n <= 12 for n in euro_numbers):
print(" ❌ Eurozahlen müssen zwischen 1 und 12 liegen.")
continue
if len(set(numbers)) != 5:
print(" ❌ Hauptzahlen müssen eindeutig sein.")
continue
if len(set(euro_numbers)) != 2:
print(" ❌ Eurozahlen müssen eindeutig sein.")
continue
draws.append({
'datum': date_obj,
'Z1': numbers[0],
'Z2': numbers[1],
'Z3': numbers[2],
'Z4': numbers[3],
'Z5': numbers[4],
'SZ1': euro_numbers[0],
'SZ2': euro_numbers[1]
})
print(f" ✅ Ziehung hinzugefügt: {date_obj.strftime('%Y-%m-%d')}")
except ValueError as e:
print(f" ❌ Fehler: {e}")
continue
if draws:
print(f"\n{len(draws)} Ziehungen manuell eingegeben")
return draws
def _parse_german_date(self, date_str: str) -> datetime:
"""
Parst deutsches Datumsformat.
Args:
date_str: Datum als String (z.B. "24.01.2025" oder "24. Januar 2025")
Returns:
datetime Objekt
"""
# Entferne zusätzliche Leerzeichen
date_str = re.sub(r'\s+', ' ', date_str.strip())
# Monatsnamen-Mapping
months_de = {
'januar': 1, 'februar': 2, 'märz': 3, 'april': 4,
'mai': 5, 'juni': 6, 'juli': 7, 'august': 8,
'september': 9, 'oktober': 10, 'november': 11, 'dezember': 12
}
# Versuche verschiedene Formate
formats = [
'%d.%m.%Y',
'%d.%m.%y',
'%Y-%m-%d',
'%d/%m/%Y'
]
for fmt in formats:
try:
return datetime.strptime(date_str, fmt)
except ValueError:
continue
# Versuche mit Monatsnamen
for month_name, month_num in months_de.items():
if month_name.lower() in date_str.lower():
# Extrahiere Tag und Jahr
match = re.search(r'(\d{1,2})\.?\s+' + month_name + r'\s+(\d{4})', date_str, re.IGNORECASE)
if match:
day = int(match.group(1))
year = int(match.group(2))
return datetime(year, month_num, day)
# Fallback: aktuelles Datum
print(f" ⚠️ Konnte Datum nicht parsen: {date_str}, nutze aktuelles Datum")
return datetime.now()
def fetch_new_draws(self, source: str = 'auto') -> List[Dict]:
"""
Holt neue Ziehungen von der gewählten Quelle.
Args:
source: 'auto', 'eurojackpot_de', 'euro_jackpot_net', 'manual'
Returns:
Liste von neuen Ziehungen
"""
print(f"\n🔍 SUCHE NACH NEUEN ZIEHUNGEN (Quelle: {source})")
print("=" * 60)
all_draws = []
if source == 'auto':
# Versuche alle Quellen
sources_to_try = [
('eurojackpot_de', self.fetch_from_eurojackpot_de),
('euro_jackpot_net', self.fetch_from_euro_jackpot_net)
]
for source_name, fetch_func in sources_to_try:
draws = fetch_func()
if draws:
all_draws.extend(draws)
break # Erste erfolgreiche Quelle nutzen
time.sleep(1) # Pause zwischen Requests
if not all_draws:
print("\n⚠️ Automatisches Scraping fehlgeschlagen.")
print(" Möchtest du Daten manuell eingeben? (j/n): ", end='')
if input().lower() in ['j', 'ja', 'y', 'yes']:
all_draws = self.fetch_from_manual_input()
elif source == 'eurojackpot_de':
all_draws = self.fetch_from_eurojackpot_de()
elif source == 'euro_jackpot_net':
all_draws = self.fetch_from_euro_jackpot_net()
elif source == 'manual':
all_draws = self.fetch_from_manual_input()
else:
print(f"❌ Unbekannte Quelle: {source}")
return all_draws
def validate_draw(self, draw: Dict) -> bool:
"""
Validiert eine Ziehung.
Args:
draw: Ziehungs-Dictionary
Returns:
True wenn valide
"""
try:
# Prüfe Pflichtfelder
required_fields = ['datum', 'Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'SZ1', 'SZ2']
if not all(field in draw for field in required_fields):
return False
# Prüfe Hauptzahlen (1-50)
main_numbers = [draw[f'Z{i}'] for i in range(1, 6)]
if not all(1 <= n <= 50 for n in main_numbers):
return False
if len(set(main_numbers)) != 5: # Eindeutig
return False
# Prüfe Eurozahlen (1-12)
euro_numbers = [draw['SZ1'], draw['SZ2']]
if not all(1 <= n <= 12 for n in euro_numbers):
return False
if len(set(euro_numbers)) != 2: # Eindeutig
return False
# Prüfe Datum
if not isinstance(draw['datum'], datetime):
return False
return True
except Exception:
return False
def merge_with_existing(self, new_draws: List[Dict]) -> pd.DataFrame:
"""
Merged neue Ziehungen mit existierenden Daten.
Args:
new_draws: Liste von neuen Ziehungen
Returns:
Zusammengeführter DataFrame
"""
print(f"\n🔀 MERGE MIT EXISTIERENDEN DATEN")
print("=" * 60)
# Validiere neue Ziehungen
valid_draws = [draw for draw in new_draws if self.validate_draw(draw)]
if len(valid_draws) < len(new_draws):
invalid_count = len(new_draws) - len(valid_draws)
print(f"⚠️ {invalid_count} ungültige Ziehung(en) übersprungen")
if not valid_draws:
print("❌ Keine gültigen neuen Ziehungen zum Hinzufügen")
return self.df_existing
# Erstelle DataFrame aus neuen Ziehungen
df_new = pd.DataFrame(valid_draws)
# Kombiniere
if self.df_existing is None or len(self.df_existing) == 0:
df_combined = df_new
else:
df_combined = pd.concat([self.df_existing, df_new], ignore_index=True)
# Entferne Duplikate (basierend auf Datum + Zahlen)
before_dedup = len(df_combined)
df_combined = df_combined.drop_duplicates(
subset=['datum', 'Z1', 'Z2', 'Z3', 'Z4', 'Z5'],
keep='first'
)
after_dedup = len(df_combined)
duplicates_removed = before_dedup - after_dedup
if duplicates_removed > 0:
print(f"🗑️ {duplicates_removed} Duplikat(e) entfernt")
# Sortiere nach Datum
df_combined = df_combined.sort_values('datum', ascending=True)
df_combined = df_combined.reset_index(drop=True)
# Berechne neue Einträge
new_entries = len(df_combined) - len(self.df_existing) if self.df_existing is not None else len(df_combined)
print(f"✅ Merge abgeschlossen:")
print(f" Vorher: {len(self.df_existing) if self.df_existing is not None else 0} Ziehungen")
print(f" Neu hinzugefügt: {new_entries} Ziehungen")
print(f" Nachher: {len(df_combined)} Ziehungen")
return df_combined
def save_updated_data(self, df: pd.DataFrame) -> bool:
"""
Speichert aktualisierte Daten.
Args:
df: DataFrame zum Speichern
Returns:
True bei Erfolg
"""
try:
# Format Datum als String
df_to_save = df.copy()
df_to_save['datum'] = df_to_save['datum'].dt.strftime('%Y-%m-%d')
# Speichern
df_to_save.to_csv(self.data_file, sep=';', index=False)
print(f"\n💾 Daten gespeichert: {self.data_file}")
print(f" {len(df)} Ziehungen total")
if len(df) > 0:
latest = df['datum'].max()
print(f" Neueste Ziehung: {latest.strftime('%Y-%m-%d')}")
return True
except Exception as e:
print(f"❌ Fehler beim Speichern: {e}")
# Restore backup
if self.backup_file and os.path.exists(self.backup_file):
print("🔄 Stelle Backup wieder her...")
shutil.copy2(self.backup_file, self.data_file)
print("✅ Backup wiederhergestellt")
return False
def update(self, source: str = 'auto', dry_run: bool = False) -> bool:
"""
Führt komplettes Update durch.
Args:
source: Datenquelle ('auto', 'eurojackpot_de', 'euro_jackpot_net', 'manual')
dry_run: Wenn True, keine Änderungen speichern
Returns:
True bei Erfolg
"""
print(f"\n{'🧪 DRY RUN MODE' if dry_run else '🚀 UPDATE STARTEN'}")
print("=" * 60)
# 1. Lade existierende Daten
if not self.load_existing_data():
return False
# 2. Backup erstellen
if not dry_run:
self.create_backup()
# 3. Hole neue Ziehungen
new_draws = self.fetch_new_draws(source=source)
if not new_draws:
print("\n✅ Keine neuen Ziehungen gefunden - Daten sind aktuell")
return True
# 4. Merge mit existierenden Daten
df_updated = self.merge_with_existing(new_draws)
# 5. Speichern
if not dry_run:
return self.save_updated_data(df_updated)
else:
print("\n🧪 DRY RUN - Keine Änderungen gespeichert")
print(f" Würde {len(df_updated)} Ziehungen speichern")
return True
def main():
"""Hauptfunktion für interaktive Nutzung."""
print("=" * 70)
print(" EUROJACKPOT HISTORICAL DATA UPDATER")
print("=" * 70)
print()
# Konfiguration
default_data_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/data/AlleEurojackpotzahlen.csv"
print("📁 KONFIGURATION")
print("=" * 60)
print(f"Standard-Datei: {default_data_file}")
print()
use_default = input("Standard-Datei verwenden? (j/n): ").lower().strip()
if use_default in ['j', 'ja', 'y', 'yes', '']:
data_file = default_data_file
else:
data_file = input("Pfad zur Datendatei: ").strip()
print()
print("🌐 DATENQUELLE WÄHLEN")
print("=" * 60)
print("1. Auto (versucht alle Quellen)")
print("2. eurojackpot.de")
print("3. euro-jackpot.net")
print("4. Manuelle Eingabe")
print()
source_choice = input("Wahl (1-4): ").strip()
source_map = {
'1': 'auto',
'2': 'eurojackpot_de',
'3': 'euro_jackpot_net',
'4': 'manual'
}
source = source_map.get(source_choice, 'auto')
print()
print("🧪 DRY RUN?")
print("=" * 60)
print("Dry Run = Keine Änderungen, nur Vorschau")
dry_run_choice = input("Dry Run aktivieren? (j/n): ").lower().strip()
dry_run = dry_run_choice in ['j', 'ja', 'y', 'yes']
print()
# Update durchführen
updater = EurojackpotDataUpdater(data_file)
success = updater.update(source=source, dry_run=dry_run)
print()
print("=" * 70)
if success:
print("✅ UPDATE ERFOLGREICH ABGESCHLOSSEN")
else:
print("❌ UPDATE FEHLGESCHLAGEN")
print("=" * 70)
return success
if __name__ == "__main__":
import sys
# Einfache CLI
if len(sys.argv) > 1:
# Kommandozeilen-Modus
data_file = sys.argv[1]
source = sys.argv[2] if len(sys.argv) > 2 else 'auto'
dry_run = '--dry-run' in sys.argv
updater = EurojackpotDataUpdater(data_file)
success = updater.update(source=source, dry_run=dry_run)
sys.exit(0 if success else 1)
else:
# Interaktiver Modus
main()
-210
View File
@@ -1,210 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot Zahlen-Umschlüsselung
Fügt neue Spalten z1, z2, z3, z4, z5 hinzu mit umschlüsselten Werten:
1-5 1, 6-10 2, 11-15 3, 16-20 4, 21-25 5,
26-30 6, 31-35 7, 36-40 8, 41-45 9, 46-50 10
"""
import pandas as pd
def convert_number_to_group(number):
"""Konvertiert eine Zahl (1-50) in eine Gruppe (1-10)."""
if 1 <= number <= 5:
return 1
elif 6 <= number <= 10:
return 2
elif 11 <= number <= 15:
return 3
elif 16 <= number <= 20:
return 4
elif 21 <= number <= 25:
return 5
elif 26 <= number <= 30:
return 6
elif 31 <= number <= 35:
return 7
elif 36 <= number <= 40:
return 8
elif 41 <= number <= 45:
return 9
elif 46 <= number <= 50:
return 10
else:
return 0 # Fehlerfall
def process_number_conversion():
"""Führt die Zahlenumschlüsselung durch."""
# Eingabedatei laden
input_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/data/AlleEurojackpotzahlen.csv"
print("🔢 EUROJACKPOT ZAHLEN-UMSCHLÜSSELUNG")
print("="*50)
# Daten laden
print(f"📁 Lade Daten aus: AlleEurojackpotzahlen.csv")
df = pd.read_csv(input_file, sep=';')
print(f"{len(df)} Ziehungen geladen")
# Umschlüsselungsschema anzeigen
print(f"\n📋 UMSCHLÜSSELUNGSSCHEMA:")
print("="*30)
ranges = [
(1, 5, 1), (6, 10, 2), (11, 15, 3), (16, 20, 4), (21, 25, 5),
(26, 30, 6), (31, 35, 7), (36, 40, 8), (41, 45, 9), (46, 50, 10)
]
for start, end, group in ranges:
print(f"Zahlen {start:2}-{end:2} → Gruppe {group:2}")
# Neue Spalten erstellen
print(f"\n🔄 Erstelle neue Spalten z1, z2, z3, z4, z5...")
source_columns = ['Z1', 'Z2', 'Z3', 'Z4', 'Z5']
target_columns = ['z1', 'z2', 'z3', 'z4', 'z5']
for source_col, target_col in zip(source_columns, target_columns):
df[target_col] = df[source_col].apply(convert_number_to_group)
print(f" {source_col}{target_col}")
# Erste 5 Beispiele anzeigen
print(f"\n📊 BEISPIEL-UMSCHLÜSSELUNGEN (erste 5 Ziehungen):")
print("="*60)
print(f"{'Datum':<12} {'Z1→z1':<8} {'Z2→z2':<8} {'Z3→z3':<8} {'Z4→z4':<8} {'Z5→z5':<8}")
print("-" * 60)
for i in range(min(5, len(df))):
row = df.iloc[i]
datum = row['datum']
conversions = []
for source_col, target_col in zip(source_columns, target_columns):
original = row[source_col]
converted = row[target_col]
conversions.append(f"{original:2}{converted}")
print(f"{datum:<12} {conversions[0]:<8} {conversions[1]:<8} {conversions[2]:<8} {conversions[3]:<8} {conversions[4]:<8}")
# Statistiken der Umschlüsselung
print(f"\n📈 STATISTIKEN DER UMSCHLÜSSELTEN WERTE:")
print("="*45)
# Häufigkeit der Gruppen über alle Positionen
all_converted_values = []
for target_col in target_columns:
all_converted_values.extend(df[target_col].tolist())
from collections import Counter
group_counts = Counter(all_converted_values)
print(f"Verteilung der Gruppen (1-10) über alle Positionen:")
total_values = len(all_converted_values)
for group in range(1, 11):
count = group_counts.get(group, 0)
percentage = (count / total_values) * 100
original_range = f"{(group-1)*5 + 1}-{group*5}"
print(f"Gruppe {group:2} ({original_range:5}): {count:4}x ({percentage:5.1f}%)")
# Statistiken pro Position
print(f"\n📊 VERTEILUNG PRO POSITION:")
print("="*35)
for i, target_col in enumerate(target_columns, 1):
position_counts = Counter(df[target_col])
print(f"\nPosition z{i} ({target_col}):")
for group in range(1, 11):
count = position_counts.get(group, 0)
percentage = (count / len(df)) * 100
print(f" Gruppe {group:2}: {count:3}x ({percentage:4.1f}%)")
# Häufigste Kombinationen der umschlüsselten Werte
print(f"\n🎯 HÄUFIGSTE KOMBINATIONEN (umschlüsselt):")
print("="*45)
# Kombinationen als Strings erstellen
df['kombination_umschluesselt'] = df.apply(
lambda row: f"{row['z1']}-{row['z2']}-{row['z3']}-{row['z4']}-{row['z5']}", axis=1
)
combination_counts = Counter(df['kombination_umschluesselt'])
print(f"Top 15 Kombinationen (z1-z2-z3-z4-z5):")
for i, (combination, count) in enumerate(combination_counts.most_common(15), 1):
percentage = (count / len(df)) * 100
print(f"{i:2}. {combination:15} {count:3}x ({percentage:4.1f}%)")
# Muster-Analyse
print(f"\n🔍 MUSTER-ANALYSE:")
print("="*25)
# Aufsteigende Kombinationen
ascending_count = 0
descending_count = 0
for _, row in df.iterrows():
values = [row[col] for col in target_columns]
if values == sorted(values):
ascending_count += 1
elif values == sorted(values, reverse=True):
descending_count += 1
print(f"Aufsteigende Kombinationen: {ascending_count} ({(ascending_count/len(df)*100):.1f}%)")
print(f"Absteigende Kombinationen: {descending_count} ({(descending_count/len(df)*100):.1f}%)")
# Gleiche Werte
same_values_stats = {}
for num_same in range(2, 6):
count = 0
for _, row in df.iterrows():
values = [row[col] for col in target_columns]
value_counts = Counter(values)
if max(value_counts.values()) >= num_same:
count += 1
same_values_stats[num_same] = count
print(f"Mindestens {num_same} gleiche Werte: {count} ({(count/len(df)*100):.1f}%)")
# Bereiche der umschlüsselten Werte
print(f"\n📋 BEREICHSANALYSE (umschlüsselt):")
print("="*35)
# Niedrig (1-3), Mittel (4-7), Hoch (8-10)
for i, target_col in enumerate(target_columns, 1):
low_count = sum(1 for val in df[target_col] if 1 <= val <= 3)
mid_count = sum(1 for val in df[target_col] if 4 <= val <= 7)
high_count = sum(1 for val in df[target_col] if 8 <= val <= 10)
low_pct = (low_count / len(df)) * 100
mid_pct = (mid_count / len(df)) * 100
high_pct = (high_count / len(df)) * 100
print(f"z{i}: Niedrig(1-3)={low_pct:4.1f}% | Mittel(4-7)={mid_pct:4.1f}% | Hoch(8-10)={high_pct:4.1f}%")
# Ausgabedatei speichern
output_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/AlleEurojackpotzahlen_umschluesselt.csv"
print(f"\n💾 DATEI SPEICHERN:")
print("="*25)
# Spalten neu ordnen (Original + neue Spalten)
column_order = ['tag', 'datum', 'Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'z1', 'z2', 'z3', 'z4', 'z5', 'SZ1', 'SZ2', 'kombination_umschluesselt']
# Prüfen welche Spalten existieren
available_columns = [col for col in column_order if col in df.columns]
df_output = df[available_columns]
df_output.to_csv(output_file, sep=';', index=False)
print(f"✅ Umschlüsselte Daten gespeichert: AlleEurojackpotzahlen_umschluesselt.csv")
print(f"📊 Anzahl Spalten: {len(df_output.columns)}")
print(f"📈 Anzahl Zeilen: {len(df_output)}")
print(f"\n🔍 NEUE SPALTEN:")
for col in ['z1', 'z2', 'z3', 'z4', 'z5', 'kombination_umschluesselt']:
if col in df_output.columns:
print(f"{col}")
return df_output
if __name__ == "__main__":
result_df = process_number_conversion()