Le Deep Learning et le hasard – Prédiction du Loto

L’étude mathématique de la loterie est aussi ancienne que les mathématiques. On peut citer les travaux de Leonard Euler qui ont conduit à la théorie de la probabilité de Kolmogorov [Kolmogorov, 1933]. À ce jour peu d’ouvrages existent sur la résolution du problème très difficile voire impossible de prédire des tirages de numéros de loterie à cause de l’indépendance des tirages (aléatoires) et donc de l’inexistence de patterns à apprendre pour les modèles.

Une grande question me vient alors en tête : et si malgré leur caractère aléatoire, les boules lors des tirages se retrouvent dans les mêmes positions que certains tirages passés, et sont mélangés à la même vitesse, ces informations ne peuvent-elles pas permettre à des modèles d’apprendre ces patterns et nous conduire à prédire les prochains numéros tirés ?

L’apprentissage profond a prouvé ses capacités dans la résolution de nombreux problèmes différents, qu’il s’agisse de la reconnaissance vocale, la reconnaissance d’images ou encore la reconnaissance d’écriture manuscrite. Ses algorithmes dont la structure est inspirée du fonctionnement du cerveau humain sont capables de capturer la structure sous-jacente de n’importe quel jeu de données avec des résultats très concluants.

Ainsi l’objectif de cet article est de montrer les résultats de l’apprentissage profond sur un cas concret de hasard.

Pour ce faire je présenterai dans cet article un modèle de prédiction des tirages du loto français en utilisant les tirages du passé comme données d’apprentissage.

Généralités et présentation du loto français

Le Loto est un jeu célèbre qui fait appel au hasard. Celui-ci est tellement répandu dans le monde entier que même les petits états comme le Vatican dont la papauté était initialement contre les jeux d’argent et de hasard, dispose aujourd’hui de leur propre loto permettant de lever des fonds pour des actions caritatives.[1] La dynastie Han a même utilisé les bénéfices du loto pour financer la grande muraille de chine.[2]

Le principe de la loterie est très simple : les gens achètent un ticket qui correspond à un pari combiné sur un ensemble général de chiffres. Un tirage au sort sans remise est finalement effectué à une date et une heure fixes. Les gains sont liés à la façon dont la combinaison correspond au tirage au sort. Le jackpot est gagné si la combinaison est correcte.

Dans cet article, je me concentrerai sur le loto français.

Pour jouer, il suffit de cocher 6 numéros :

  • 5 numéros sur une grille de 49 numéros
  • 1 numéro de chance sur une grille de 10 numéros

Le jackpot est remporté si on a parié les 5 bons numéros plus le numéro de chance.

Le prix d’une grille est de 2,20 € et le jackpot minimum est de 2 millions d’euros.[3]

Collecte des données et calcul de features

Les données ont été scrapées sur le site de la française des jeux (fdj) qui recense tous les tirages du loto depuis 2008 à ce jour. Le dernier tirage à la date de rédaction de cet article datait du 21 octobre 2020 avec un total de 1921 tirages entre le 6 octobre 2008 et cette date.

Obtention dataset

La prédiction des numéros de loto est une tâche supervisée : les tirages du passé sont utilisés comme données d’entrées en supposant les tirages dépendants même si ce n’est pas le cas dans la réalité. Ainsi en apprenant ces numéros du passé, on suppose que ce sont des numéros obtenus à partir d’une certaine position initiale des boules dans l’urne et un mélange à une certaine vitesse.

Les données que j’ai retenues après calcul pour chaque tirage sont :

  • Le nombre de fois que chaque numéro est apparu dans les tirages précédents
  • La présence de nombre pair ou impair
  • La somme de la différence au carré entre chaque couple de numéros successifs dans le tirage
  • Le nombre de numéros en dessous de 24
  • Le nombre de numéros en dessous de 40
Code dataset

Modèle

Les réseaux de neurones récurrents (RNN) se sont révélés comme étant l’un des modèles les plus puissants pour le traitement de données séquentielles. La mémoire à long court terme est l’une des architectures RNN la plus réussie. LSTM introduit la cellule mémoire, une unité de calcul qui remplace les neurones artificiels traditionnels dans la couche cachée du réseau. Avec ces cellules de mémoire, les réseaux sont capables d’associer efficacement des mémoires et d’entrer dans le temps, ce qui permet de saisir la structure des données de manière dynamique dans le temps avec une capacité de prédiction élevée.

Architecture du LSTM
Architecture d’un LSTM [4]
\[f_t=\sigma(w_f[h_t-1, X_t]+b_f)\] \[i_t=\sigma(W_I[h_t-1, X_t] + b_i)\] \[c_t=tan(W_c[h_t-1, X_t] + b_c)\] \[O_t=\sigma(W_o[h_t-1, X_t] + b_o)\] \[C_t=f_t*C_t-1 + i_t*c_t\] \[h_t=O_t*\tanh(C_t)\]
- \(f_t\) : Porte d'oubli, décide s'il faut remettre à 0 le contenu de la cellule.
- \(O_t\) : porte de sortie, décide si le contenu de la cellule doit influer sur la sortie du neurone.
- \(i_t\) : Porte d'entrée, décide si l'entrée doit modifier le contenu de la cellule.

[5]

- \(C_t\) : Mise à jour de l'état de la cellule.
- \(h_t\) : Sortie de la cellule.

Formation du réseau

Notre modèle LSTM est composé d'une couche d'entrée séquentielle suivie d’une couche LSTM et d'une couche de sortie dense avec fonction d'activation linéaire.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pickle
from sklearn.preprocessing import StandardScaler
from keras.models import Sequential
from keras.layers import LSTM, Dense, Bidirectional, TimeDistributed, RepeatVector, Flatten
from keras.callbacks import EarlyStopping

UNITS = 100
BATCHSIZE = 30
EPOCH = 1000
#ACTIVATION = "softmax"
OPTIMIZER ='adam' # rmsprop, adam, sgd
LOSS = 'mae'#'categorical_crossentropy' #mse
DROPOUT = 0.1
window_length =12 #12 
number_of_features = df.shape[1]

#Architecture du modèle
def define_model(number_of_features,nb_label_feature):
    #initialisation du rnn
    model = Sequential()
    #ajout de la premiere couche lstm
    model.add(LSTM(UNITS, input_shape=(window_length, number_of_features), return_sequences=True))
    model.add(LSTM(UNITS, dropout=0.1, return_sequences=False))
    #ajout de la couche de sortie
    model.add(Dense(nb_label_feature))
    model.compile(loss=LOSS, optimizer=OPTIMIZER, metrics=['acc'])
    return model

Optimiseur

J'ai choisi d'utiliser l'optimiseur Adam. L'optimiseur Adam combine les avantages de deux autres optimiseurs : ADAgrad et RMSprop. Cette méthode calcule les taux d'apprentissage adaptatif pour chaque paramètre en considérant la moyenne en décroissance exponentielle des gradients carrés passés et la moyenne en décroissance exponentielle des gradients passés.[6] Cela peut être représenté par :

Optimimiseur

Où v et m peuvent être considérés comme les estimations du premier et du deuxième moment des gradients respectivement, d'où le nom d'estimation de moment adaptatif.[7]

Les avantages de cet optimiseur sont résumés comme suit :

  • Le taux d’apprentissage est différent pour chaque paramètre et chaque itération
  • L’apprentissage ne diminue pas comme avec l’ADAgrad
  • Une descente plus solide d’un point de vue statistique.[6

Entraînement

Avant d’entraîner un modèle LSTM, il faut une préparation minimum de la donnée afin de s’accommoder à la dimension voulue par les RNNs en particulier le LSTM. En effet, la donnée en entrée doit avoir trois dimensions (samples, timesteps, feature).

  • Samples désigne le nombre d’échantillons ou d’observations
  • Timesteps est le pas de temps
  • Feature est le nombre de caractéristiques ou de variables à étudier

Ainsi pour notre suite de tirage, j’ai dû implémenter une fonction permettant de transformer la séquence initiale à la forme attendue en entrée du LSTM en choisissant un timesteps sur un mois soit 12 tirages car trois tirages sont réalisés par semaine pour le loto français.

Par exemple pour la première séquence de 13 tirages \(S=[t_1, t_2, t_3, ..., t_{13}]\)
L’entrée \(X = [[t_1], [t_2], [t_3], [t_4], ..., [t_{12}]]\) avec \(X\) de la forme \((1, 12, 19)\) car ayant \(19\) features calculés au total pour chaque tirage
La sortie \(Y = [[t_{13}]]\) avec Y de la forme \((1,1,6)\) car l’on désire ici prédire les bons numéros du tirage \(13\).

On peut donc concrètement représenter les entrées et sorties à partir des 13 premiers tirages avec des LSTM comme suit :

Architecture des entrées et sorties LSTM des 13 premiers tirages
Architecture des entrées et sorties LSTM des 13 premiers tirages

où les xi représentent les différents tirages.

Une fois l’architecture de mon modèle LSTM prête, il ne reste qu’à entrainer le modèle.

Pour ce faire, mon dataset d’entrainement est constitué de tous les tirages scrapés et ma donnée de test représente le prochain tirage.

C’est à dire que j’entraine le modèle sur toutes les données disponibles, et j’effectue une prédiction sur le prochain tirage qui représente ma donnée de test. Je procède de la sorte afin de m’assurer qu’à chaque tirage, le modèle ait appris du tirage précédent. Ainsi à chaque nouvelle date de tirage, un nouveau modèle est entrainé. Cette méthode a fait ces preuves, dans la mesure où j’arrive très souvent à prédire 3 numéros parmi les 6 tout en étant proche des autres numéros non trouvés. Voyons un exemple concret.

Résultats d’apprentissage sur le tirage du 21 octobre 2020

Pour ce test j’ai commencé par supprimer du dataset d’entraînement le tirage du 21 octobre afin de l’utiliser comme donnée de test.

Le modèle converge après 830 epochs avec une précision de 92% sur les données de train.

Epochs
Epochs

Résultats de prédiction pour le tirage du 21 octobre 2020

Résultats

Le résultat officiel du tirage du 21 octobre 2020 sur le site de la fdj est donné par les numéros suivants : [15 21 33 35 48 01]. [8]

Et comme vous pouvez le constater le modèle prédit bien 3 numéros à savoir le 15 le 21 et 1 pour le numéro de chance.

Résultats de prédiction pour le tirage du 24 octobre 2020

Résultat

Le résultat officiel du tirage du 24 octobre 2020 sur le site de la fdj est donné par les numéros suivants : [4 8 12 25 45 02]. [9]

Comme vous pouvez le constater pour ce tirage le numéro 8 a été bien prédit par contre deux autres numéros dont le 3 et le 46 sont très proches du vrai résultat respectivement à une somme et différence près de 1.

Jusque-là mon modèle n’arrive qu’à prédire au maximum pour certains tirages 3 bons numéros sur 6 ou s’en rapproche ce qui permet d’évaluer sa précision globale sur le loto français à ce jour à 50%.

Remarque

Le réapprentissage du modèle sur les mêmes données d’apprentissage risque de donner une prédiction différente s’approchant encore plus du vrai tirage ou même s’en éloignant. Quelqu'un me dira mais pourquoi ne pas effectuer une cross-validation sur le training set afin d’avoir un modèle robuste qui prédira toujours la même sortie même après plusieurs entraînements du modèle sur les mêmes données ?

Le principe même de la validation croisée qui consiste à diviser le dataset en plusieurs portions et d’utiliser de manière itérative chaque petite portion comme valeur de test et les grandes comme valeurs de train en supposant que les échantillons sont indépendants n’est pas adapté aux LSTM qui apprennent des valeurs historiques pour prédire l’avenir. Je laisse cette question ouverte à tout commentaire 😃

Conclusion

En dépit de l’indépendance des tirages, le modèle LSTM arrive très souvent à prédire certains bon numéros en supposant que ceux-ci sont dépendants. Ces résultats proviennent-ils du hasard ? non je ne pense pas. Plus de travail est nécessaire pour optimiser le modèle afin de pouvoir éventuellement remporter le jackpot un de ces jours. J’envisage par exemple de personnaliser le calcul de l’erreur en prenant en compte les erreurs de prédictions qui se traduisent par de petites différences de 1 ou 2 en plus ou en moins.

Pour avoir accès au code entier, veuillez m’écrire à l’adresse : wilfriedkouadio3009@gmail.com

N’hésitez pas à laisser votre avis si vous avez aimé cet article 😊

Laisser un commentaire

Votre adresse email ne sera pas publiée.

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

Voulez-vous en savoir plus sur la Data Science ?

Inscrivez-vous alors à notre newsletter et vous receverez gratuitement nos derniers articles et actualités ! 
S'INSCRIRE MAINTENANT 
close-link