Skip to content

Pmupredict #301

@sory215

Description

@sory215

pmupredict/
├── core/
│ ├── init.py
│ ├── config.py # Paramètres généraux (seuils, poids, etc.)
│ ├── data_manager.py # Gestion des données (CSV, SQLite, vectorDB)
│ ├── feature_engineering.py # Extraction des caractéristiques (XYZ)
│ ├── model_manager.py # Gestion du modèle SecretPMUPredictor
│ ├── probability_matrix.py # Calcul des probabilités (Plackett-Luce, Monte Carlo)
│ └── tracker.py # Traqueurs de chevaux performants
├── data/
│ ├── historical/ # CSV des 3 derniers mois
│ └── vector_db/ # Index vectoriel (Milvus/Pinecone)
├── api/
│ └── app.py # Serveur Flask/FastAPI pour Android
├── android/
│ ├── PmuPredictor.kt # Intégration Android
│ └── RetrofitService.kt # Appels API
└── scripts/
├── ingest_historical.py # Indexation des données historiques
└── train_model.py # Entraînement du modèle
Index Feature Description Plage
0 Musique moyenne (3 dernières) Moyenne des places 0-10
1 Tendance récente Pente des 5 dernières courses -5/+5
2 Poids normalisé (Poids - 53) / 7 0-1
3 Âge normalisé (Âge - 3) / 7 0-1
4 Gains normalisés Gains / 300 000 0-1
5 Driver score Hash du driver 0-1
6 Corde score 1-6 = 1, 7-12 = 0.5, 13-18 = 0 0-1
7 Spécialité Attelé 1 si attelé, 0 sinon 0/1
8 Spécialité Plat 1 si plat, 0 sinon 0/1
9 Spécialité Haie 1 si haie, 0 sinon 0/1
10 Ferrures (déferré) 1 si déferré, 0 sinon 0/1
11 Oeillères 1 si oeillères, 0 sinon 0/1
12 Gains récents Gains des 6 derniers mois 0-1
13 Podiums récents Nombre de podiums (5 dernières) 0-5
14 Appétence Ratio places / courses 0-1
15 Coefficient de forme Note entraîneur / driver 0-10
16 Coefficient de réussite % de victoires 0-10
17 Écart actuel Nombre de courses depuis dernière place 0-100
import pickle
import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor
from sklearn.neural_network import MLPRegressor
import joblib

class PmuPredictor:
def init(self):
self.scaler = StandardScaler()
self.pca = PCA(n_components=0.95)
self.rf = None
self.gb = None
self.mlp = None
self.trained = False
self.weights = None
self.bias = 0.0

    # Paramètres de configuration
    self.params = {
        'voting_power': [0.35, 0.35, 0.30],
        'feature_names': [
            'musique_avg', 'tendance', 'poids_norm', 'age_norm',
            'gains_norm', 'driver_score', 'corde_score',
            'special_attelé', 'special_plat', 'special_haie',
            'deferre', 'oeilleres', 'gains_recents', 'podiums_recents',
            'appetence', 'coefficient_forme', 'coefficient_reussite',
            'ecart_actuel'
        ]
    }
    
    # Traqueurs de chevaux
    self.trackers = {
        'top_gains': [],          # Cheval avec les + gros gains
        'top_forme': [],          # Cheval avec la meilleure forme
        'top_regulier': [],       # Cheval le plus régulier
        'top_corde': [],          # Meilleur numéro à la corde
        'top_driver': []          # Meilleur driver du jour
    }
    
def extract_features(self, horse):
    """Extrait les 18 dimensions du vecteur XYZ"""
    # Simuler l'extraction (à remplacer par vos vraies données)
    return np.random.rand(18)

def train(self, X, y):
    """Entraîne le modèle sur les données historiques"""
    X_scaled = self.scaler.fit_transform(X)
    X_pca = self.pca.fit_transform(X_scaled)
    
    self.rf = RandomForestRegressor(n_estimators=200, max_depth=12)
    self.gb = GradientBoostingRegressor(n_estimators=150, learning_rate=0.05)
    self.mlp = MLPRegressor(hidden_layer_sizes=(64,32), max_iter=500)
    
    self.rf.fit(X_pca, y)
    self.gb.fit(X_pca, y)
    self.mlp.fit(X_pca, y)
    
    self.trained = True
    return self

def predict(self, X):
    """Prédiction avec softmax"""
    if not self.trained:
        raise ValueError("Modèle non entraîné")
    
    X_scaled = self.scaler.transform(X)
    X_pca = self.pca.transform(X_scaled)
    
    pred_rf = self.rf.predict(X_pca)
    pred_gb = self.gb.predict(X_pca)
    pred_mlp = self.mlp.predict(X_pca)
    
    pred = (self.params['voting_power'][0] * pred_rf +
            self.params['voting_power'][1] * pred_gb +
            self.params['voting_power'][2] * pred_mlp)
    
    # Softmax pour obtenir des probabilités
    exp_pred = np.exp(pred - np.max(pred))
    return exp_pred / np.sum(exp_pred)

def save(self, path):
    """Sauvegarde le modèle"""
    with open(path, 'wb') as f:
        pickle.dump(self, f)

def load(self, path):
    """Charge le modèle"""
    with open(path, 'rb') as f:
        obj = pickle.load(f)
        self.__dict__.update(obj.__dict__)

def compute_place_probabilities(scores, n_sim=10000):
"""
Calcule les probabilités de chaque place (1er à 5e) via Monte Carlo.
"""
n = len(scores)
weights = np.exp(scores - np.max(scores))
prob_win = weights / np.sum(weights)

# Simulation
win_counts = np.zeros(n)
top3_counts = np.zeros(n)
top5_counts = np.zeros(n)
place_counts = np.zeros((n, 5))

for _ in range(n_sim):
    order = np.random.choice(n, size=n, replace=False, p=weights/np.sum(weights))
    win_counts[order[0]] += 1
    for idx in order[:3]:
        top3_counts[idx] += 1
    for idx in order[:5]:
        top5_counts[idx] += 1
    for pos, idx in enumerate(order[:5]):
        place_counts[idx, pos] += 1

return {
    'win': win_counts / n_sim,
    'top3': top3_counts / n_sim,
    'top5': top5_counts / n_sim,
    'places': place_counts / n_sim
}

class HorseTracker:
"""
Suit les performances des chevaux sur différentes conditions.
"""
def init(self, db_connection):
self.db = db_connection

def track_horse(self, horse_id, race_data):
    """
    Met à jour les statistiques d'un cheval après une course.
    """
    # Mise à jour des gains, podiums, tendance, etc.
    pass

def get_top_horses(self, condition='all', limit=10):
    """
    Retourne les chevaux les plus performants selon un critère.
    condition : 'gains', 'forme', 'regularite', 'corde', 'driver'
    """
    query = f"SELECT * FROM horses ORDER BY {condition} DESC LIMIT {limit}"
    return pd.read_sql(query, self.db)

def get_top_forme(self):
    """Chevaux avec la meilleure forme (moyenne des 3 dernières places)"""
    return self.get_top_horses('forme', 5)

def get_top_gains(self):
    """Chevaux avec les gains les plus élevés"""
    return self.get_top_horses('gains', 5)

def get_top_reguliers(self):
    """Chevaux avec le meilleur taux de places"""
    return self.get_top_horses('regularite', 5)

import pinecone # ou pymilvus

class VectorDatabase:
def init(self, index_name='pmu_vectors'):
pinecone.init(api_key="your-api-key", environment="us-west1-gcp")
self.index = pinecone.Index(index_name)

def upsert_vectors(self, vectors):
    """
    vectors : liste de tuples (id, vector, metadata)
    """
    self.index.upsert(vectors=vectors)

def query_similar(self, vector, top_k=10):
    """
    Retourne les chevaux les plus similaires à un vecteur donné.
    """
    return self.index.query(vector=vector, top_k=top_k, include_metadata=True)

def build_historical_index(self, df):
    """
    Indexe 3 mois de données historiques.
    """
    for _, row in df.iterrows():
        vector = row[['feature1', 'feature2', ...]].values.tolist()
        metadata = {'nom': row['nom'], 'gains': row['gains'], 'hippodrome': row['hippodrome']}
        self.upsert_vectors([(str(row['id']), vector, metadata)])

from flask import Flask, request, jsonify
from flask_cors import CORS
from pmupredict.core.model_manager import PmuPredictor
from pmupredict.core.probability_matrix import compute_place_probabilities

app = Flask(name)
CORS(app)

model = PmuPredictor()
model.load("secret_pmu_model.pkl")

@app.route("/predict", methods=["POST"])
def predict():
data = request.get_json()
horses = data.get("horses", [])
features = [model.extract_features(h) for h in horses]
X = np.array(features)
probs = model.predict(X)
prob_matrix = compute_place_probabilities(X.dot(model.weights) + model.bias)

result = []
for i, h in enumerate(horses):
    result.append({
        "numero": h["numero"],
        "nom": h["nom"],
        "probabilite": round(probs[i] * 100, 2),
        "prob_win": round(prob_matrix['win'][i] * 100, 2),
        "prob_top3": round(prob_matrix['top3'][i] * 100, 2),
        "prob_top5": round(prob_matrix['top5'][i] * 100, 2),
        "places": [round(p * 100, 2) for p in prob_matrix['places'][i]]
    })
result.sort(key=lambda x: x["probabilite"], reverse=True)
return jsonify(result)

@app.route("/tracker/top_forme", methods=["GET"])
def top_forme():
tracker = HorseTracker(db)
return jsonify(tracker.get_top_forme().to_dict('records'))

@app.route("/tracker/top_gains", methods=["GET"])
def top_gains():
tracker = HorseTracker(db)
return jsonify(tracker.get_top_gains().to_dict('records'))

if name == "main":
app.run(host="0.0.0.0", port=5000)
import retrofit2.http.*

interface PmuApiService {
@post("predict")
suspend fun predict(@Body request: Map<String, List>): List

@GET("tracker/top_forme")
suspend fun getTopForme(): List<HorseStat>

@GET("tracker/top_gains")
suspend fun getTopGains(): List<HorseStat>

}

data class HorseRequest(
val musique: String,
val driver: String,
val poids: Double,
val age: Int,
val gains: Double,
val numero: Int,
val nom: String
)

data class PredictionResponse(
val numero: Int,
val nom: String,
val probabilite: Double,
val prob_win: Double,
val prob_top3: Double,
val prob_top5: Double,
val places: List
)

data class HorseStat(
val nom: String,
val score: Double,
val hippodrome: String,
val gains: Double
)
class PmuPredictor(private val context: Context) {
private val api = RetrofitInstance.api
private val viewModel = ViewModelProvider(context).get(PredictionViewModel::class.java)

suspend fun getPrediction(horses: List<HorseRequest>): List<PredictionResponse> {
    return api.predict(mapOf("horses" to horses))
}

suspend fun getTopForme(): List<HorseStat> {
    return api.getTopForme()
}

suspend fun getTopGains(): List<HorseStat> {
    return api.getTopGains()
}

}
Traqueur Condition Utilisation
Top Gains Gains > 250 000 € Base solide
Top Forme Moyenne des 3 dernières places < 2 Favori
Top Régulier Ratio places / courses > 0.7 Outsider de valeur
Top Corde Numéro de corde 1 à 4 Avantage à la corde
Top Driver Jockey avec > 20% de victoires Plus-value
import pandas as pd
from pmupredict.core.data_manager import DataManager
from pmupredict.core.vector_database import VectorDatabase

Charger les 3 mois de données

df = pd.read_csv("historical_3months.csv")

Indexer dans la base vectorielle

db = VectorDatabase()
db.build_historical_index(df)

Entraîner le modèle

model = PmuPredictor()
X = df[['feature1', 'feature2', ...]].values
y = df['arrivee'].values
model.train(X, y)
model.save("secret_pmu_model_updated.pkl")

print("✅ Données indexées et modèle entraîné.")
// Dans votre fragment
val predictions = viewModel.predictions.value
recyclerView.adapter = PredictionAdapter(predictions)

// Affichage :
// 1. CHESS (n°1) – 24.5%
// Vainqueur : 22.1% | Podium : 58.3% | Top5 : 81.2%
// Places : 22.1% | 18.2% | 14.3% | 10.5% | 7.2%

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions