[PYTHON] Maschinelles Lernen des Sports - Analyse der J-League als Beispiel - ②

Es ist schon eine Weile her, aber ich möchte über die Fortsetzung des folgenden Beitrags berichten. https://qiita.com/ryouta0506/items/100a2b252fbaeb73f493

Obwohl es sich um eine Fortsetzung handelt, versuche ich, das verwendete Modell zu ändern. Im vorherigen Bericht haben wir angenommen, dass die Scores der Poisson-Verteilung folgen. Infolgedessen gab es fast keine Fälle, in denen sich die vorhergesagte Punktzahl auf 0 Punkte und 1 Punkt konzentrierte und als 2 Punkte vorhergesagt wurde. Im Fußball gibt es selten mehr als 3 Punkte. Selbst wenn Sie es nicht vorhersagen können, können Sie nicht anders, aber es ist nicht gut, wenn Sie nicht 2 bis 3 Punkte mit einer angemessenen Rate vorhersagen können. Daher möchte ich andere Wahrscheinlichkeitsverteilungen ausprobieren.

Verwenden Sie eine negative Binomialverteilung

Per Definition hat die Poisson-Verteilung eine Beziehung von erwartetem Wert = Varianz. Dies bedeutet, dass je kleiner der erwartete Wert ist, desto kleiner die Variation ist und je größer der erwartete Wert ist, desto größer ist die Variation. Wenn Sie sich wie bei einem Fußballergebnis im Wesentlichen auf 0 Punkte / 1 Punkt konzentrieren, liegt der erwartete Wert nahe bei 0 Punkten. Infolgedessen ist die Abweichung gering, sodass die Wahrscheinlichkeit eines Auftretens von 2 Punkten / 3 Punkten gering ist. Ich werde am Ende. Daher werden wir die negative Binomialverteilung verwenden, ein statistisches Modell, das die Eigenschaften der Poisson-Verteilung aufweist, jedoch eine allgemeinere Varianz aufweist. Die negative Binomialverteilung ist die Wahrscheinlichkeitsverteilung, die den Verwandten der Binomialverteilung entspricht. Die Binomialverteilung ist die Verteilung der Häufigkeit, mit der ein Ereignis in einer vorgegebenen Anzahl von Versuchen (z. B. 10 Mal) auftritt, unter der Bedingung, dass die Auftrittswahrscheinlichkeit des Ereignisses (z. B. die Wahrscheinlichkeit, dass die Tabelle beim Münzwurf angezeigt wird, 0,5 beträgt) angegeben wird. Andererseits ist die negative Binomialverteilung die Verteilung der Anzahl von Versuchen unter Berücksichtigung der Wahrscheinlichkeit des Auftretens eines Ereignisses und der Anzahl des Auftretens eines Ereignisses. (Hinweis: Tatsächlich gibt es auch andere Definitionen. Ich habe es hier am einfachsten zu verstehen gemacht.) Im Bereich der tatsächlichen statistischen Modellierung ist die Verallgemeinerung der Poisson-Verteilung (dh die Randbedingung des erwarteten Werts = Varianz) ausgeschlossen. Da es oft als etwas behandelt wird, das getan wurde, wird es auch auf dieses Modell angewendet.

Der Code für Stan ist unten.

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]]) ;
    }
}

"""

Die Funktion, die eine negative Binomialverteilung mit stan darstellt, ist neg_binomial_2 (). Eigentlich gibt es eine andere Funktion, die jedoch vom anzuwendenden Parameter abhängt. Es ist besser, neg_binomial zu verwenden, wenn die Parameter gemäß der tatsächlichen Funktionsform eingestellt werden. Da hier param1 und param2 als Durchschnittsmodell für die Poisson-Verteilung verwendet wurden, wird neg_binomial_2 verwendet, das den Mittelwert und die Varianz als Argumente verwendet. Als Referenz wird die Verteilung der Punktzahlen auf der Kawasaki-Seite von Kawasaki F gegen Kashima (Heimat Kashima) gezeigt.

fig02_negbinom_dist.png

Kawasaki F hat in diesem Spiel 4 Punkte erzielt, daher ist es ideal, die Wahrscheinlichkeit von 3 oder 4 Punkten zu maximieren. Die Wahrscheinlichkeit eines Punktes ist das Maximum sowohl für die Poisson-Verteilung als auch für die negative Binomialverteilung. Die negative Binomialverteilung verringert jedoch die Wahrscheinlichkeit von 0 Punkten und 1 Punkt, und dieser Betrag wird 2 Punkten oder mehr zugewiesen. Daher kann gesagt werden, dass das Ergebnis von 4 Punkten in diesem Spiel ausdrücken könnte, dass die negative Binomialverteilung höher gewesen sein könnte als die Poisson-Verteilung. Das Obige ist eine Fallstudie einer bestimmten Übereinstimmung zwischen Kawasaki F und Kashima. Daher werden wir die Wahrscheinlichkeit nutzen, um zu überprüfen, welches der Poisson-Verteilungsmodelle und des negativen Binomialverteilungsmodells die Realität durchgehend besser darstellen kann.

Modellbewertung nach Wahrscheinlichkeit

Die Wahrscheinlichkeit ist die Wahrscheinlichkeit, dass die vorliegenden Daten aus dieser Wahrscheinlichkeitsverteilung unter einer bestimmten Wahrscheinlichkeitsverteilung erscheinen. Diese Wahrscheinlichkeit ist die Wahrscheinlichkeit, dass die vorliegenden Daten unter der Annahme angezeigt werden, dass die Wahrscheinlichkeitsverteilung korrekt ist, repräsentiert jedoch die Gewissheit des statistischen Modells, das die Richtigkeit der vorliegenden Daten schätzt. Es wird ein Index sein. Daher möchte ich dies zur Bewertung des Modells nutzen. In diesem Fall ist es die Wahrscheinlichkeit, dass die vorliegenden Daten (alle 306 Spiele) gleichzeitig erstellt werden, sodass das Ergebnis der Multiplikation der einzelnen Wahrscheinlichkeiten die Gesamtwahrscheinlichkeit ist. Da die Berechnung mit der Multiplikation jedoch nicht gut ist, berechnen wir die Wahrscheinlichkeit der gesamten Handdaten durch logarithmische Umwandlung und Summierung.

fig03_log_likehood.png

Das Obige ist die Verteilung der mit Stan geschätzten Log-Wahrscheinlichkeit. Ursprünglich nimmt die logarithmische Wahrscheinlichkeit einen negativen Wert an, ist jedoch minus und je größer der Wert, desto besser die Leistung. Mit anderen Worten, es zeigt, dass die negative Binomialverteilung sowohl für die Heimmannschaft als auch für die Auswärtsmannschaft eine Wahrscheinlichkeitsverteilung ist, die die beobachteten Werte besser ausdrückt. Die Berechnung nach Wahrscheinlichkeitsstandard kann als Verteilung erhalten werden, indem der folgende Code zum Teil der generierten Mengen hinzugefügt wird.

Berechnung der Poisson-Verteilungswahrscheinlichkeit
    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]])));
        
    }
Eignungsberechnung der negativen Binomialverteilung

    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]]) ;

    }

Keine überschüssige Poisson-Verteilung

Bei den Vorgängermodellen wurde angenommen, dass die Punktzahl unter einem Modell ermittelt wird. Es kann jedoch auch angenommen werden, dass das Ergebnis von Nullpunkten ein anderer Generierungsprozess ist als der Fall, in dem Punkte erzielt werden. Zum Beispiel gibt es eine Verteilung, ob während des Spiels eine Torchance besteht oder nicht, und ein Prozess, der der Poisson-Verteilung nur dann folgt, wenn eine Chance besteht, kann in Betracht gezogen werden. In diesem Fall erscheint das Nullpunktergebnis nicht einfach in der Poisson-Verteilung. Aufgrund des Einflusses der Bernoulli-Verteilung (der Verteilung, die das Vorhandensein oder Fehlen von Chancen bestimmt) ist die Auftrittsrate von Nullpunkten vielmehr größer als die der Poisson-Verteilung. Auf diese Weise gibt es eine Poisson-Verteilung mit einem Überschuss von Null, die der Poisson-Verteilung folgt und die Auftrittswahrscheinlichkeit von Null größer als die ursprüngliche macht. Hier wenden wir ein leicht angepasstes Modell davon an. Der tatsächliche Code ist unten.

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 ;
        }

"""

Die Grundstruktur dieses Modells ist eine Mischung aus der Bernoulli-Verteilung von "Scoring" und "Not Scoring" und der Poisson-Verteilung, wenn Scoring möglich ist. Von diesen werden für die Bernoulli-Verteilung die aus Offensivkraft, Defensivkraft und Heimvorteil berechneten Ergebnisse unter Verwendung der Sigmoidfunktion (der Umkehrfunktion der Logit-Funktion) in Wahrscheinlichkeiten umgewandelt. Wenn dieses Modell beurteilt, dass "es nicht bewertet werden kann", wird es auf Null festgelegt. Wenn beurteilt wird, dass "es bewertet werden kann", wird die Poisson-Verteilung verwendet. Die ursprüngliche Poisson-Verteilung existiert, obwohl es mehr oder weniger wahrscheinlich einen Nullpunkt gibt. Da der Fall der Anwendung der Poisson-Verteilung dieses Mal "bewertbar" ist, ist es inkonsistent, dass der Nullpunkt erscheint. Verschieben Sie daher die Poisson-Verteilung um 1,0 nach rechts, um zu verhindern, dass der Nullpunkt angezeigt wird. Überprüfen Sie zunächst die Verteilung der Ergebnisse auf der Kawasaki-Seite von Kawasaki F gegen Kashima (Heim-Kashima).

fig04_ZIP.png

Der Prozentsatz von 0 Punkten ist der höchste, der angibt, ob die Punktzahl erreicht wurde oder nicht. Die Quote von 0 Punkten betrug 41,8%, daher scheint es besser zu sein, zu glauben, dass Kawasaki F in diesem Spiel ein Tor erzielen konnte. In diesem Fall sollten wir erwarten, dass Kawasaki F in diesem Spiel zwei Punkte erzielt. Dies scheint im Vergleich zu dem einen Punkt der Poisson-Verteilung und der negativen Binomialverteilung ein ziemlich gutes Ergebnis zu sein. Bei diesem Modell ist der Fall, in dem Kawasaki F 4 Punkte erzielt, mit 11,9% recht groß.

Überprüfen Sie abschließend die Wahrscheinlichkeit dieses Modells. Bei diesem Modell ist die Wahrscheinlichkeit der Fall, bei dem die Bernoulli-Verteilung und die Poisson-Verteilung gleichzeitig erfüllt sind, also die Multiplikation jeder Wahrscheinlichkeit. Wenn dies logarithmisch ist, kann es daher berechnet werden, indem die logarithmische Wahrscheinlichkeit der Bernoulli-Verteilung und die logarithmische Wahrscheinlichkeit der Poisson-Verteilung addiert werden. Wenn das Obige in Stan-Code konvertiert wird, sieht es wie folgt aus.

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]]))) ;
        }                                  
    }
}

Das Ergebnis ist wie folgt. Die Gesamtwahrscheinlichkeit war größer als die negative Binomialverteilung, was darauf hinweist, dass dieses Modell die beobachteten Werte am besten darstellt.

fig05_ZIP_loglikehood.png

Zusammenfassung

Wir haben festgestellt, dass die Poisson-Verteilung ohne Überschuss der beste Weg ist, um die beobachteten Werte bei der Vorhersage von Fußballergebnissen darzustellen. Dies ermöglicht es, die Offensiv- und Defensivkraft jedes Teams zu definieren. Offensiv- und Defensivkraft wird von regulären Mitgliedern und ihren Eigenschaften (Laufkraft usw.) bestimmt. Wenn diese Beziehung in Zukunft gut modelliert werden kann, ist es daher möglich, die Punktzahl in der Reihenfolge der Teammerkmale → Offensiv- / Defensivkraft → Punktzahl vorherzusagen.

Recommended Posts

Maschinelles Lernen des Sports - Analyse der J-League als Beispiel - ②
Über die Entwicklungsinhalte des maschinellen Lernens (Beispiel)
Eine Einführung in das maschinelle Lernen
Grundlagen des maschinellen Lernens (Denkmal)
Bedeutung von Datensätzen für maschinelles Lernen
Ein Beispiel für einen Mechanismus, der eine Vorhersage von HTTP aus dem Ergebnis des maschinellen Lernens zurückgibt
Bedeutung des maschinellen Lernens und des Mini-Batch-Lernens
Maschinelles Lernen ③ Zusammenfassung des Entscheidungsbaums
Ansible als Infrastruktur-Lernwerkzeug
Verstehen Sie die Funktion der Faltung am Beispiel der Bildverarbeitung
[Python Machine Learning] Empfehlung zur Verwendung von Spyder für Anfänger (Stand August 2020)
Algorithmus für maschinelles Lernen (Verallgemeinerung der linearen Regression)
Eine Einführung in OpenCV für maschinelles Lernen
Ein einführender Leser der Theorie des maschinellen Lernens für IT-Ingenieure versuchte es mit Kaggle
2020 Empfohlen 20 Auswahlmöglichkeiten für einführende Bücher zum maschinellen Lernen
Maschinelles Lernen
Algorithmus für maschinelles Lernen (Implementierung einer Klassifizierung mit mehreren Klassen)
[Python] Wenn ein Amateur mit dem maschinellen Lernen beginnt
Eine Einführung in Python für maschinelles Lernen
[Maschinelles Lernen] Liste der häufig verwendeten Pakete
Python> Funktion> Beispiel für die Übernahme der Funktion als Argument> Karte (Lambda x: 2 ** x, [1, 2, 3]) / local () ['myprint'] (3.1415, 2.718)
Maschinelles Lernen eines jungen Ingenieurs Teil 1
Eine Einführung in maschinelles Lernen für Bot-Entwickler
Klassifizierung von Gitarrenbildern durch maschinelles Lernen Teil 1
Beginn des maschinellen Lernens (empfohlene Unterrichtsmaterialien / Informationen)
Beispiel für die Verwendung von Python> function> * args als Argument
Python & Machine Learning Study Memo ⑤: Klassifikation von Ayame
Numerai Turnier-Fusion von traditionellen Quants und maschinellem Lernen-
Python & Machine Learning Study Memo Introduction: Einführung in die Bibliothek
Vollständige Offenlegung der beim maschinellen Lernen verwendeten Methoden
Liste der Links, die Anfänger des maschinellen Lernens lernen
Überblick über maschinelle Lerntechniken, die aus Scikit-Learn gelernt wurden
Zusammenfassung der beim maschinellen Lernen verwendeten Bewertungsfunktionen
Analyse der gemeinsamen Raumnutzung durch maschinelles Lernen
[Übersetzung] scikit-learn 0.18 Einführung in maschinelles Lernen durch Tutorial scikit-learn
Maschinelles Lernen eines jungen Ingenieurs Teil 2
Angemessene Preisschätzung von Mercari durch maschinelles Lernen
Klassifizierung von Gitarrenbildern durch maschinelles Lernen Teil 2
Lassen Sie uns einen Teil des maschinellen Lernens mit Python berühren
Versuchen Sie es mit dem Jupyter Notebook von Azure Machine Learning
Anordnung von selbst erwähnten Dingen im Zusammenhang mit maschinellem Lernen
Kausales Denken mit maschinellem Lernen (Organisation von Methoden des kausalen Denkens)
[Memo] Maschinelles Lernen
Klassifikation des maschinellen Lernens
Beispiel für maschinelles Lernen
[Pokemon-Schwertschild] Ich habe versucht, die Urteilsgrundlage des tiefen Lernens anhand der Drei-Familien-Klassifikation als Beispiel zu visualisieren
Intelligentes Schreiben beim Hinzufügen von Statistiken zum maschinellen Lernen als Funktionen
Wichtige Punkte von "Maschinelles Lernen mit Azure ML Studio"
Erstellen Sie mit Python eine interaktive Umgebung für maschinelles Lernen
[Empfohlenes Tagging beim maschinellen Lernen # 2] Erweiterung des Scraping-Skripts
[Empfohlenes Tagging beim maschinellen Lernen # 2.5] Änderung des Scraping-Skripts
Informationen zur Datenvorverarbeitung von Systemen, die maschinelles Lernen verwenden
Eindrücke vom Udacity Machine Learning Engineer Nano-Abschluss
Installation von TensorFlow, einer Bibliothek für maschinelles Lernen von Google
Über das Testen bei der Implementierung von Modellen für maschinelles Lernen
Ein sehr einfaches Beispiel für ein Optimierungsproblem mit ortoolpy
Prognostizieren Sie das Geschlecht von Twitter-Nutzern durch maschinelles Lernen
[Python] [Windows] Speichern Sie einen Screenshot als Bild
Zusammenfassung des grundlegenden Ablaufs des maschinellen Lernens mit Python
Aufzeichnung der ersten Herausforderung des maschinellen Lernens mit Keras