[PYTHON] Apprentissage automatique du sport-Analyse de la J-League à titre d'exemple-②

Cela fait un moment, mais j'aimerais faire un rapport sur la poursuite du post suivant. https://qiita.com/ryouta0506/items/100a2b252fbaeb73f493

Même si c'est une continuation, j'essaye de changer le modèle utilisé. Dans le rapport précédent, nous avons supposé que les scores suivaient la distribution de Poisson. En conséquence, il n'y avait presque aucun cas où le score prévu était concentré sur 0 point et 1 point et prédit sur 2 points. Au football, il est rare d'avoir plus de 3 points, donc même si vous ne pouvez pas le prédire, vous ne pouvez pas vous empêcher mais ce n'est pas bon si vous ne pouvez pas prédire 2 à 3 points à un taux raisonnable. Par conséquent, j'aimerais essayer d'autres distributions de probabilité.

Utiliser une distribution binomiale négative

Par définition, la distribution de Poisson a une relation de valeur attendue = variance. Cela signifie que plus la valeur attendue est petite, plus la variation est petite et plus la valeur attendue est grande, plus la variation est grande. Si vous vous concentrez essentiellement sur 0 point / 1 point comme un score de football, la valeur attendue sera proche de 0 point, et par conséquent, la variation sera faible, donc la probabilité d'apparition de 2 points / 3 points sera faible. Je vais finir. Par conséquent, nous utiliserons la distribution binomiale négative, qui est un modèle statistique qui a les caractéristiques de la distribution de Poisson mais qui a une variance plus généralisée. La distribution binomiale négative est la distribution de probabilité qui correspond aux parents de la distribution binomiale. La distribution binomiale est la distribution du nombre de fois qu'un événement apparaît dans un nombre prédéterminé d'essais (par exemple, 10 fois) à la condition que la probabilité d'apparition de l'événement (par exemple, la probabilité que le tableau apparaisse dans le tirage au sort est de 0,5) est donnée. D'autre part, la distribution binomiale négative est la distribution du nombre d'essais compte tenu de la probabilité d'occurrence de l'événement et du nombre d'occurrences d'événements. (Note: en fait, il y a aussi d'autres définitions. Je l'ai fait la plus facile à comprendre ici.) Dans le domaine de la modélisation statistique réelle, la généralisation de la distribution de Poisson (c'est-à-dire la condition de contrainte de valeur attendue = variance est exclue. Puisqu'il est souvent traité comme quelque chose qui a été fait, il est également appliqué à ce modèle.

Le code pour stan est ci-dessous.

model_code = """
data {
    int N;  // N Games
    int K;  // K Teams
    int home_team[N]; // Home Team ID
    int away_team[N]; // Away Team ID
    int ht_score[N] ; // Home Team score 
    int at_score[N] ; // Away Team score
}

parameters {
    real<lower=-1,upper=1> atk[K]; // atack
    real<lower=-1,upper=1> def[K]; // defence
    real<lower=0> home_adv[K];     // home advantage
    real<lower=0> sigma[K];        // sigma 
    real<lower=0> hadv_sigma;      // sigma home_advantage
    real<lower=0> phi[K] ;            // 
}

model {
    real param1 ;
    real param2 ;
    
    for (k in 1:K) {
        atk[k] ~ normal(0, sigma[k]);
        def[k] ~ normal(0, sigma[k]);
        home_adv[k] ~ normal(0, hadv_sigma);
        phi[k] ~ normal(0,10);
    }

    for (n in 1:N) {
        param1 = exp(home_adv[home_team[n]] + atk[home_team[n]] - def[away_team[n]]) ;
        param2 = exp((atk[away_team[n]]) - (def[home_team[n]] + home_adv[home_team[n]])) ;
        
        ht_score[n] ~ neg_binomial_2(param1,phi[home_team[n]]) ;
        at_score[n] ~ neg_binomial_2(param2,phi[away_team[n]]) ;
        
    }

}

generated quantities {
    int ht_predict[N] ;
    int at_predict[N] ;
    
    for (i in 1:N) {
        ht_predict[i] = neg_binomial_2_rng(exp(home_adv[home_team[i]] + atk[home_team[i]] - def[away_team[i]]),
                                                phi[home_team[i]]) ;
        at_predict[i] = neg_binomial_2_rng(exp((atk[away_team[i]]) - (def[home_team[i]] + home_adv[home_team[i]])),
                                                phi[away_team[i]]) ;
    }
}

"""

La fonction qui représente une distribution binomiale négative avec stan est neg_binomial_2 (). En fait, il existe une autre fonction, mais cela dépend du paramètre à appliquer. Il est préférable d'utiliser neg_binomial lors de la définition des paramètres en fonction de la forme de fonction réelle. Ici, puisque param1 et param2 ont été utilisés comme modèle moyen pour la distribution de Poisson, neg_binomial_2, qui utilise la moyenne et la variance comme arguments, est utilisé. Pour référence, la répartition des scores côté Kawasaki de Kawasaki F vs Kashima (domicile Kashima) est indiquée.

fig02_negbinom_dist.png

Kawasaki F a marqué 4 points dans ce match, donc l'idéal est de maximiser la probabilité de 3 ou 4 points. La probabilité d'un point est le maximum pour la distribution de Poisson et la distribution binomiale négative. Cependant, la distribution binomiale négative réduit la probabilité de 0 point et 1 point, et ce montant est attribué à 2 points ou plus. Par conséquent, on peut dire que le résultat de 4 points dans ce jeu peut avoir été plus élevé dans la distribution binomiale négative que dans la distribution de Poisson. Ce qui précède est une étude de cas d'un match spécifique entre Kawasaki F et Kashima. Par conséquent, nous utiliserons la probabilité pour vérifier lequel du modèle de distribution de Poisson et du modèle de distribution binomiale négative est le meilleur pour exprimer la réalité partout.

Évaluation du modèle par vraisemblance

La probabilité est la probabilité que les données disponibles apparaissent à partir de cette distribution de probabilité sous une distribution de probabilité particulière. Cette probabilité est la probabilité que les données disponibles apparaissent sous l'hypothèse que la distribution de probabilité est correcte, mais elle représente la certitude du modèle statistique estimé que les données disponibles sont correctes. Ce sera un index. Par conséquent, j'aimerais utiliser cela pour évaluer le modèle. Dans ce cas, il s'agit de la probabilité que les données disponibles (les 306 jeux) soient établies en même temps, de sorte que le résultat de la multiplication des probabilités individuelles sera la probabilité globale. Cependant, comme le calcul n'est pas bon avec la multiplication, nous calculerons la vraisemblance de l'ensemble des données de la main par conversion logarithmique et addition.

fig03_log_likehood.png

Ce qui précède est la distribution de la vraisemblance logarithmique estimée à l'aide de Stan. À l'origine, la probabilité logarithmique prend une valeur négative, mais elle est négative et plus la valeur est élevée, meilleures sont les performances. En d'autres termes, cela montre que la distribution binomiale négative pour l'équipe à domicile et pour l'équipe à l'extérieur est une distribution de probabilité qui exprime mieux les valeurs observées. Le calcul par niveau de vraisemblance peut être obtenu sous forme de distribution en ajoutant le code suivant à la partie quantités générées.

Calcul de la vraisemblance de la distribution de Poisson
    real ht_log_likehood ;
    real at_log_likehood ;

    ht_log_likehood = 0;
    at_log_likehood = 0;
    
    for (i in 1:N) {
        ht_log_likehood = ht_log_likehood + 
                          poisson_lpmf(ht_score[i] | exp((home_adv[home_team[i]] + atk[home_team[i]]) - (def[away_team[i]])));
        at_log_likehood = at_log_likehood +
                          poisson_lpmf(at_score[i] | exp((atk[away_team[i]]) - (def[home_team[i]] + home_adv[home_team[i]])));
        
    }
Calcul de la fiabilité de la distribution binomiale négative

    real ht_log_likehood ;
    real at_log_likehood ;
    
    ht_log_likehood = 0;
    at_log_likehood = 0;
    
    for (i in 1:N) {
        
        ht_log_likehood = ht_log_likehood +
                            neg_binomial_2_lpmf(ht_score[i] | 
                                exp(home_adv[home_team[i]] + atk[home_team[i]] - def[away_team[i]]),phi[home_team[i]]) ;
                                
        at_log_likehood = at_log_likehood +
                            neg_binomial_2_lpmf(at_score[i] |
                                exp((atk[away_team[i]]) - (def[home_team[i]] + home_adv[home_team[i]])),phi[away_team[i]]) ;

    }

Distribution de Poisson sans excès

Dans le cas des modèles précédents, on a supposé que le score était déterminé sous un seul modèle. Cependant, il est également possible de supposer que le résultat de zéro point est un processus de génération différent du cas où des points sont marqués. Par exemple, il existe une distribution indiquant s'il y a ou non une chance de marquer tout au long de la correspondance, et un processus qui suit la distribution de Poisson uniquement lorsqu'il y a une chance peut être envisagé. Dans ce cas, le résultat du point zéro n'apparaît pas simplement dans la distribution de Poisson. Au contraire, en raison de l'influence de la distribution de Bernoulli (la distribution qui détermine la présence ou l'absence de chances), le taux d'apparition de zéro point est plus grand que celui de la distribution de Poisson. De cette manière, il y a une distribution de Poisson en excès de zéro qui suit la distribution de Poisson et rend la probabilité d'apparition de zéro plus grande que celle d'origine. Ici, nous appliquons un modèle légèrement personnalisé de cela. Le code réel est ci-dessous.

model_code = """
data {
    int N;  // N Games
    int K;  // K Teams
    int home_team[N]; // Home Team ID
    int away_team[N]; // Away Team ID
    int ht_score[N] ; // Home Team score 
    int at_score[N] ; // Away Team score
}

transformed data {
    int ht_score_over_zero[N] ;
    int ht_score_trans[N]     ;
    int at_score_over_zero[N] ;
    int at_score_trans[N]     ;
    
    for (i in 1:N) {
        if (ht_score[i]>0) { 
            ht_score_over_zero[i] = 1 ;
            ht_score_trans[i] = ht_score[i]-1 ;
            }
        else {
            ht_score_over_zero[i] = 0 ;
            ht_score_trans[i] = 0 ;
            }
            
        if (at_score[i]>0) { 
            at_score_over_zero[i] = 1 ;
            at_score_trans[i] =at_score[i]-1 ;
            }
        else {
            at_score_over_zero[i] = 0 ;
            at_score_trans[i] = 0;
            }
    }
}

parameters {
    real<lower=-1,upper=1> atk[K]; // atack
    real<lower=-1,upper=1> def[K]; // defence
    real<lower=0> home_adv[K];     // home advantage
    real<lower=0> sigma[K];        // sigma 
    real<lower=0> hadv_sigma;      // sigma home_advantage

}

model {
    real param1 ;
    real param2 ;
    
    for (k in 1:K) {
        atk[k] ~ normal(0, sigma[k]);
        def[k] ~ normal(0, sigma[k]);
        home_adv[k] ~ normal(0, hadv_sigma);
    }

    for (n in 1:N) {
        param1 = home_adv[home_team[n]] + atk[home_team[n]] - def[away_team[n]] ;
        param2 = atk[away_team[n]] - (def[home_team[n]] + home_adv[home_team[n]]) ;
        
        ht_score_over_zero[n] ~ bernoulli(inv_logit(param1)) ;
        at_score_over_zero[n] ~ bernoulli(inv_logit(param2)) ;
        
        if (ht_score_over_zero[n] >0 ) 
            ht_score_trans[n] ~ poisson(exp(param1));

            at_score_trans[n] ~ poisson(exp(param2));
    }

}

generated quantities {
    int ht_predict_score[N] ;
    int at_predict_score[N] ;
    real ht_log_likehood ;
    real at_log_likehood ;
    
    ht_log_likehood = 0 ;
    at_log_likehood = 0 ;
    
    for (i in 1:N) {
        ht_log_likehood = ht_log_likehood + 
                            bernoulli_lpmf(ht_score_over_zero[i]|
                                                inv_logit(home_adv[home_team[i]] + atk[home_team[i]] - def[away_team[i]])) ;
        at_log_likehood = at_log_likehood +
                            bernoulli_lpmf(at_score_over_zero[i]|
                                                inv_logit(atk[away_team[i]] - (def[home_team[i]] + home_adv[home_team[i]]))) ;
                            
        if (ht_score_over_zero[i]>0) {
            ht_log_likehood = ht_log_likehood +
                            poisson_lpmf(ht_score_trans[i]|
                                                exp(home_adv[home_team[i]] + atk[home_team[i]] - def[away_team[i]])) ;
        }
        if (at_score_over_zero[i]>0) {
            at_log_likehood = at_log_likehood +
                            poisson_lpmf(at_score_trans[i]|
                                                exp(atk[away_team[i]] - (def[home_team[i]] + home_adv[home_team[i]]))) ;
        }
    }
}
                                                
                                                
                                                
        if (bernoulli_rng(inv_logit(home_adv[home_team[i]] + atk[home_team[i]] - def[away_team[i]]))==0) {
            ht_predict_score[i] = 0 ;
        }
        else {
            ht_predict_score[i] = poisson_rng(exp(home_adv[home_team[i]] + atk[home_team[i]] - def[away_team[i]])) +1 ;
        }
        
        if (bernoulli_rng(inv_logit(home_adv[home_team[i]] + atk[home_team[i]] - def[away_team[i]]))==0) {
            at_predict_score[i] = 0;
        }
        else {
            at_predict_score[i] = poisson_rng(exp(atk[away_team[i]] - def[home_team[i]] + home_adv[home_team[i]])) +1 ;
        }

"""

La structure de base de ce modèle est un mélange de la distribution de Bernoulli de «notation» et de «non notation» et de la distribution de Poisson lorsque la notation est possible. Parmi ceux-ci, pour la distribution de Bernoulli, les résultats calculés à partir de la puissance offensive, de la puissance défensive et de l'avantage du domicile sont convertis en probabilités à l'aide de la fonction sigmoïde (la fonction inverse de la fonction logit). S'il est jugé par ce modèle «qu'il ne peut pas être noté», il sera fixé à zéro. S'il est jugé que «cela peut être noté», la distribution de Poisson est utilisée. La distribution de Poisson d'origine existe, bien qu'il existe une possibilité plus ou moins grande d'un point zéro. Cependant, puisque le cas de l'application de la distribution de Poisson cette fois est "notable", il est incohérent que le point zéro apparaisse. Par conséquent, déplacez la distribution de Poisson vers la droite de 1,0 pour empêcher l'apparition du point zéro. Tout d'abord, vérifiez la répartition des scores côté Kawasaki de Kawasaki F vs Kashima (domicile Kashima).

fig04_ZIP.png

Le pourcentage de 0 point est le plus élevé, ce qui indique si le score a été atteint ou non. Le ratio de 0 point était de 41,8%, il semble donc préférable de penser que Kawasaki F a pu marquer dans ce match. Dans ce cas, il faut s'attendre à ce que Kawasaki F marque deux points dans ce match. Cela semble être un assez bon résultat par rapport à ce qui devrait être un point de distribution de Poisson et de distribution binomiale négative. De plus, dans le cas de ce modèle, le cas où Kawasaki F marque 4 points est assez grand à 11,9%.

Enfin, vérifiez la probabilité de ce modèle. Dans le cas de ce modèle, la vraisemblance est le cas où la distribution de Bernoulli et la distribution de Poisson sont satisfaites en même temps, c'est donc la multiplication de chaque vraisemblance. Par conséquent, si cela est logarithmique, il peut être calculé en ajoutant la vraisemblance logarithmique de la distribution de Bernoulli et la vraisemblance logarithmique de la distribution de Poisson. Si ce qui précède est converti en code standard, ce sera comme suit.

generated quantities {

    real ht_log_likehood ;
    real at_log_likehood ;
    
    ht_log_likehood = 0 ;
    at_log_likehood = 0 ;
    
    for (i in 1:N) {
        ht_log_likehood = ht_log_likehood + 
                            bernoulli_lpmf(ht_score_over_zero[i]|
                                                inv_logit(home_adv[home_team[i]] + atk[home_team[i]] - def[away_team[i]])) ;
        at_log_likehood = at_log_likehood +
                            bernoulli_lpmf(at_score_over_zero[i]|
                                                inv_logit(atk[away_team[i]] - (def[home_team[i]] + home_adv[home_team[i]]))) ;
                            
        if (ht_score_over_zero[i]>0) {
            ht_log_likehood = ht_log_likehood +
                            poisson_lpmf(ht_score_trans[i]|
                                                exp(home_adv[home_team[i]] + atk[home_team[i]] - def[away_team[i]])) ;
        }
        if (at_score_over_zero[i]>0) {
            at_log_likehood = at_log_likehood +
                            poisson_lpmf(at_score_trans[i]|
                                                exp(atk[away_team[i]] - (def[home_team[i]] + home_adv[home_team[i]]))) ;
        }                                  
    }
}

Le résultat est le suivant. La probabilité globale était supérieure à la distribution binomiale négative, indiquant que ce modèle représentait le mieux les valeurs observées.

fig05_ZIP_loglikehood.png

Résumé

Nous avons constaté que la distribution de Poisson en excès nul est la meilleure façon de représenter les valeurs observées pour prédire les scores de football. Cela permet de définir la puissance offensive et défensive de chaque équipe. La puissance offensive et défensive est déterminée par les membres réguliers et leurs caractéristiques (puissance de course, etc.). Par conséquent, à l'avenir, si cette relation peut être bien modélisée, il sera possible de prédire le score dans l'ordre des caractéristiques de l'équipe → puissance offensive / défensive → score.

Recommended Posts

Apprentissage automatique du sport-Analyse de la J-League à titre d'exemple-②
À propos du contenu de développement de l'apprentissage automatique (exemple)
Une introduction à l'apprentissage automatique
Bases de l'apprentissage automatique (mémoire)
Importance des ensembles de données d'apprentissage automatique
Un exemple de mécanisme qui renvoie une prédiction par HTTP à partir du résultat de l'apprentissage automatique
Importance de l'apprentissage automatique et de l'apprentissage par mini-lots
Apprentissage automatique ③ Résumé de l'arbre de décision
Ansible comme outil d'apprentissage de l'infrastructure
Comprendre la fonction de convolution en utilisant le traitement d'image comme exemple
[Apprentissage automatique Python] Recommandation d'utilisation de Spyder pour les débutants (à partir d'août 2020)
Algorithme d'apprentissage automatique (généralisation de la régression linéaire)
Une introduction à OpenCV pour l'apprentissage automatique
Un lecteur d'introduction à la théorie de l'apprentissage automatique pour les ingénieurs informatiques a essayé Kaggle
20 sélections recommandées en 2020 de livres d'introduction à l'apprentissage automatique
Apprentissage automatique
Algorithme d'apprentissage automatique (implémentation de la classification multi-classes)
[Python] Lorsqu'un amateur commence l'apprentissage automatique
Une introduction à Python pour l'apprentissage automatique
[Apprentissage automatique] Liste des packages fréquemment utilisés
Python> fonction> Exemple de prise de fonction comme argument> map (lambda x: 2 ** x, [1, 2, 3]) / locals () ['myprint'] (3.1415, 2.718)
Mémo d'apprentissage automatique d'un ingénieur débutant Partie 1
Une introduction à l'apprentissage automatique pour les développeurs de robots
Classification des images de guitare par apprentissage automatique Partie 1
Début de l'apprentissage automatique (matériel didactique / informations recommandés)
Exemple de prise de Python> function> * args comme argument
Mémo d'étude Python & Machine Learning ⑤: Classification d'Ayame
Tournoi Numerai - Fusion de quants traditionnels et apprentissage automatique -
Mémo d'étude Python & Machine Learning ②: Introduction de la bibliothèque
Divulgation complète des méthodes utilisées dans l'apprentissage automatique
Liste des liens que les débutants en apprentissage automatique apprennent
Vue d'ensemble des techniques d'apprentissage automatique apprises grâce à scikit-learn
Résumé des fonctions d'évaluation utilisées dans l'apprentissage automatique
Analyse de l'utilisation de l'espace partagé par l'apprentissage automatique
[Français] scikit-learn 0.18 Introduction de l'apprentissage automatique par le didacticiel scikit-learn
Mémo d'apprentissage automatique d'un ingénieur débutant Partie 2
Estimation raisonnable du prix de Mercari par apprentissage automatique
Classification des images de guitare par apprentissage automatique, partie 2
Touchons une partie de l'apprentissage automatique avec Python
Essayez d'utiliser le bloc-notes Jupyter à partir d'Azure Machine Learning
Disposition des éléments auto-mentionnés liés à l'apprentissage automatique
Raisonnement causal utilisant l'apprentissage automatique (organisation des méthodes de raisonnement causal)
[Memo] Apprentissage automatique
Classification de l'apprentissage automatique
Exemple d'apprentissage automatique
[Bouclier d'épée Pokémon] J'ai essayé de visualiser la base de jugement de l'apprentissage en profondeur en utilisant la classification des trois familles comme exemple
Écriture intelligente lors de l'ajout de statistiques d'apprentissage automatique en tant que fonctionnalités
Points clés de «Machine learning avec Azure ML Studio»
Créez un environnement interactif pour l'apprentissage automatique avec Python
[Balisage recommandé dans le machine learning # 2] Extension du script de scraping
[Balisage recommandé dans le machine learning # 2.5] Modification du script de scraping
À propos du prétraitement des données des systèmes utilisant l'apprentissage automatique
Impressions d'avoir obtenu le nano-diplôme Udacity Machine Learning Engineer
Installation de TensorFlow, une bibliothèque d'apprentissage automatique de Google
À propos des tests dans la mise en œuvre de modèles d'apprentissage automatique
Un exemple très simple de problème d'optimisation avec ortoolpy
Prédire le sexe des utilisateurs de Twitter grâce à l'apprentissage automatique
[Python] [Windows] Enregistrer une capture d'écran sous forme d'image
Résumé du flux de base de l'apprentissage automatique avec Python
Bilan du premier défi du machine learning avec Keras