J'ai essayé de prédire les courses de chevaux en faisant tout, de la collecte de données à l'apprentissage en profondeur

Aperçu

Je suis un étudiant spécialisé en systèmes d'information dans une certaine université T. Quand je regardais divers articles sur Qiita, j'ai trouvé cet article.

Concernant l'atteinte du taux de récupération de 100% dans cet article, puisque le nombre de billets de paris simulés à l'achat est faible, je ne sais pas s'il sera établi sur d'autres périodes. Le code source est également facturé, donc je ne connais pas les détails sur la façon de le faire. Cependant, j'ai pensé qu'il serait intéressant de prédire moi-même les courses de chevaux, alors je l'ai essayé avec l'intention d'étudier.

Ce sera une excellente expérience d'apprentissage car vous ferez toute la collecte de données, l'analyse et la prévision.

Pourquoi les courses de chevaux?

Il y avait un désir que ce soit de l'argent, mais les courses de chevaux semblent avoir un taux de déduction élevé, donc je ne peux pas m'attendre à grand chose. La raison principale est que cela a été un sujet brûlant récemment et que je voulais essayer l'apprentissage profond.

Une autre raison de choisir les courses de chevaux est

――Le résultat de la course est moins influencé par les spectateurs

Cela est mentionné.

Il semble bon de faire le thème des actions, mais comme le prix fluctue en fonction des décisions de nombreuses personnes, il est difficile de prévoir avec une bonne précision à moins que des informations telles que les nouvelles que les traders voient souvent ne soient incorporées. C'est vrai. De plus, de nombreux investisseurs institutionnels passent des ordres automatiquement selon l'algorithme, qui en dépendra probablement.

De ce qui précède, j'ai pensé que ce ne serait pas facile avec la technologie actuelle, alors j'ai pensé que les courses de chevaux étaient plus adaptées à l'apprentissage en profondeur.

Le nombre de chevaux qui participent aux courses de chevaux varie d'une course à l'autre, mais il semble que le nombre d'athlètes participant aux courses de bateaux soit constant. Il semble que l'apprentissage automatique sera plus facile si des données détaillées peuvent être obtenues.

Explication à ceux qui sont nouveaux dans les courses de chevaux

"Les courses de chevaux (Keiba, anglais: courses de chevaux) sont une compétition de courses dans laquelle des chevaux sur lesquels sont montés des chevaux sont concourus, et un jeu de hasard qui prédit l'ordre d'arrivée de celui-ci" (citation: [courses de chevaux --Wikipedia](https: //) ja.wikipedia.org/wiki/horse racing)).

J'avais peu de connaissances sur les courses de chevaux jusqu'à ce que j'analyse ces données, je vais donc résumer les connaissances que je pensais nécessaires pour lire cet article.

Tout d'abord, connaissons les types de billets de paris en tant que connaissances de base. Il est normal de lire simplement une victoire simple ou une double victoire. Référence: [Type de ticket de pari: JRA pour les nouveaux utilisateurs](https://www.google.com/url?sa=t&rct=j&q½esrc=s&source=web&cd=1&ved=2ahUKEwjj9cC71eHlAhXgy4sBHXKtA0QQFjAAegQIAh jra.go.jp% 2Fkouza% 2Fbeginner% 2Fbaken% 2F & usg = AOvVaw12f8T5GSlozZG9tnRspGtC)

Pour les autres termes, reportez-vous à ce qui suit

--Odds: Multiplicateur qui montre combien de fois l'argent que vous gagnez est le nombre d'argent que vous dépensez ――Rise: La fin de la course et l'entraînement --Umaban: un numéro attribué uniquement à un cheval courant

Référence: Horse Racing Glossary JRA

Je ne suis pas si familier avec cela, alors faites-le moi savoir si vous faites une erreur ...

La connaissance du domaine est considérée comme importante dans l'apprentissage automatique, il sera donc nécessaire de se familiariser avec les courses de chevaux afin d'améliorer la précision des prévisions.

Procédure approximative

Même si vous faites des prédictions sur les courses de chevaux, il y a beaucoup de choses à penser et à faire. La procédure peut être grossièrement divisée comme suit.

  1. Collecte de données (exploration et grattage)
  2. Formatage des données (pandas, SQL, etc.)
  3. Modélisation (apprentissage automatique)

Le premier enjeu majeur pour ceux qui veulent prédire les courses de chevaux est la collecte et la mise en forme des données. Dans des compétitions comme Kaggle, c'est assez facile car le jeu de données est donné depuis le début, mais cette fois, nous devons commencer par collecter les données.

De plus, il est difficile de créer un modèle car diverses méthodes peuvent être envisagées. De nos jours, vous pouvez facilement utiliser l'amplification de gradient, l'apprentissage en profondeur, etc. dans la bibliothèque, mais vous devrez essayer différentes méthodes pour améliorer la précision de la prédiction.

Connaissances préalables

Résumé des résultats

Des données d'utilisation

--Données d'apprentissage: janvier 2008-23 juillet 2017 --Données de vérification: 23 juillet 2017-novembre 2019

résultat

J'ai fait un modèle avec une précision plus élevée que moi en tant que débutant en courses de chevaux

Commençons par collecter des données

L'apprentissage automatique n'est pas possible soudainement même s'il n'y a pas de données. Faisons l'exploration et le grattage.

Tout d'abord, récupérez les résultats des courses et les informations sur les chevaux du site cible.

Les données obtenues ici doivent être aussi proches que possible des données brutes, et les données seront formatées ultérieurement pour la formation.

Site cible

Il s'agit du plus grand site d'information sur les courses de chevaux au Japon. Des données de course passées aux informations sur le pedigree du cheval, vous pouvez obtenir gratuitement des données assez détaillées.

Il semble que des données plus détaillées puissent être obtenues en devenant membre payant. Il est efficace lorsque vous souhaitez améliorer la précision du modèle.

Données collectées

Cette fois, nous avons décidé de collecter des données en se concentrant sur les résultats de la course à l'hippodrome central, qui dispose d'une grande quantité d'informations et d'un système unifié.

Comme il y a beaucoup de données, vous pouvez créer un bon modèle en collectant et en utilisant diverses données. Cependant, il est assez difficile de collecter des informations et des données généalogiques telles que les propriétaires et les formateurs, j'ai donc décidé de ne pas le faire cette fois. Il semble que la précision des prévisions s'améliorera si vous ajoutez des données ici.

Tout d'abord, obtenez l'URL de toutes les races

Depuis l 'Écran de recherche détaillée de la course sur le site, utilisez Selenium pour obtenir toutes les URL des résultats de la course.

La raison de ne pas utiliser les requêtes et Beautiful Soup, qui sont souvent utilisés lors de l'exploration et du scraping en Python, est que l'URL de recherche et l'URL du résultat de la recherche sont [https://db.netkeiba.com/?pid=race_search_detail](https :: //db.netkeiba.com/?pid=race_search_detail) n'a pas changé.

Si l'écran est généré dynamiquement par JavaScript ou PHP, vous ne pouvez pas obtenir les données souhaitées en téléchargeant simplement le html.

Avec Selenium, les transitions d'écran peuvent être effectuées par des opérations réelles du navigateur, de sorte que l'exploration Web peut être effectuée même sur des sites où l'affichage change en cliquant sur un bouton ou des sites nécessitant une connexion. (Veuillez noter que de nombreux sites nécessitant une connexion interdisent l'exploration en raison d'accords d'adhésion, etc.).

Tout d'abord, préparez ce dont vous avez besoin

import time

from selenium import webdriver
from selenium.webdriver.support.ui import Select,WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument('--headless')    #En mode sans tête
driver = webdriver.Chrome(chrome_options=options) 
wait = WebDriverWait(driver,10)

Remplissez le formulaire de saisie

Remplissez les champs obligatoires du formulaire. Après l'envoi, attendez que les résultats de la recherche s'affichent. スクリーンショット 2019-11-18 18.09.14.png

URL = "https://db.netkeiba.com/?pid=race_search_detail"
driver.get(URL)
time.sleep(1)
wait.until(EC.presence_of_all_elements_located)

#Recherche par mois
year = 2019
month = 1

#Sélectionnez une période
start_year_element = driver.find_element_by_name('start_year')
start_year_select = Select(start_year_element)
start_year_select.select_by_value(str(year))
start_mon_element = driver.find_element_by_name('start_mon')
start_mon_select = Select(start_mon_element)
start_mon_select.select_by_value(str(month))
end_year_element = driver.find_element_by_name('end_year')
end_year_select = Select(end_year_element)
end_year_select.select_by_value(str(year))
end_mon_element = driver.find_element_by_name('end_mon')
end_mon_select = Select(end_mon_element)
end_mon_select.select_by_value(str(month))

#Découvrez l'hippodrome central
for i in range(1,11):
    terms = driver.find_element_by_id("check_Jyo_"+ str(i).zfill(2))
    terms.click()
        
#Sélectionnez le numéro à afficher(20,50,De 100 au maximum 100)
list_element = driver.find_element_by_name('list')
list_select = Select(list_element)
list_select.select_by_value("100")

#Soumettre le formulaire
frm = driver.find_element_by_css_selector("#db_search_detail_form > form")
frm.submit()
time.sleep(5)
wait.until(EC.presence_of_all_elements_located)

Par souci de simplicité, j'essaie d'obtenir l'URL de janvier 2019. Si vous souhaitez une plus large gamme de données, effectuez l'une des opérations suivantes:

--Ne remplissez pas le formulaire année / mois

(Dans le code github, nous essayons de collecter des données de course qui n'ont pas été acquises depuis 2008.)

Si vous ne remplissez pas la sélection de l'hippodrome, les données sur les courses organisées à l'étranger seront également incluses. Vérifions correctement 10 hippodromes centraux.

J'ai décidé de ne pas utiliser les données autres que l'hippodrome central cette fois car il peut y avoir peu de chevaux en course ou les données peuvent être incomplètes.

Enregistrer l'URL lors du changement de page

Cliquez sur le bouton dans Selenium et enregistrez les URL affichées pour chaque 100 éléments. スクリーンショット 2019-11-18 18.11.48.png

with open(str(year)+"-"+str(month)+".txt", mode='w') as f:
    while True:
        time.sleep(5)
        wait.until(EC.presence_of_all_elements_located)
        all_rows = driver.find_element_by_class_name('race_table_01').find_elements_by_tag_name("tr")
        for row in range(1, len(all_rows)):
            race_href=all_rows[row].find_elements_by_tag_name("td")[4].find_element_by_tag_name("a").get_attribute("href")
            f.write(race_href+"\n")
        try:
            target = driver.find_elements_by_link_text("Suivant")[0]
            driver.execute_script("arguments[0].click();", target) #Traitement des clics avec javascript
        except IndexError:
            break

Ouvrez le fichier et écrivez l'URL obtenue ligne par ligne. L'URL de la course est dans la 5ème colonne du tableau, donc en Python où les éléments du tableau commencent à 0, sélectionnez quelque chose comme find_elements_by_tag_name (" td ") [4].

La pagination est effectuée dans une boucle while. J'utilise try pour attraper l'exception car je ne peux pas cliquer sur la dernière page.

Le driver.execute_script (" arguments [0] .click (); ", target) fait partie de l'essai, mais si vous en faites un simple target.click (), vous obtiendrez une ʻElementClickInterceptedException` en mode sans tête. Cela s'est produit. Apparemment, il a été reconnu que les éléments se chevauchaient et je ne pouvais pas bien cliquer dessus. Il y avait une solution dans ici, mais j'ai pu le faire bien en cliquant avec JavaScript comme ci-dessus.

Obtenez du HTML basé sur l'URL obtenue

Le html que j'ai obtenu plus tôt ne semble pas utiliser beaucoup PHP ou JavaScript pour afficher la page, je vais donc enfin utiliser les requêtes ici. Sur la base des informations de l'URL ci-dessus, j'obtiens le html et je l'enregistre, mais cela prend quelques secondes pour obtenir chaque page, donc cela prend beaucoup de temps.

import os
import requests

save_dir = "html"+"/"+str(year)+"/"+str(month)
if not os.path.isdir(save_dir):
    os.makedirs(save_dir)
        
with open(str(year)+"-"+str(month)+".txt", "r") as f:
    urls = f.read().splitlines()
    for url in urls:
        list = url.split("/")
        race_id = list[-2]
        save_file_path = save_dir+"/"+race_id+'.html'
        response = requests.get(url)
        response.encoding = response.apparent_encoding
        html = response.text
        time.sleep(5)
        with open(save_file_path, 'w') as file:
            file.write(html)

En raison du code de caractère, si vous l'obtenez avec obéissance, il peut être déformé. Je l'ai fait avec response.encoding = response.apparent_encoding et cela a fonctionné. Référence: Corriger les caractères brouillés lors du traitement du japonais dans les requêtes

Analyser html et créer csv

Détails de la course ・ Les informations sur chaque coureur sont stockées dans csv. J'ai décidé de créer un csv avec le format suivant.

Il y a d'autres informations qui peuvent être obtenues. Il semble que les membres payants peuvent également obtenir ce qu'on appelle un indice de vitesse.

import numpy as np
import pandas as pd
from bs4 import BeautifulSoup

CSV_DIR = "csv"
if not os.path.isdir(CSV_DIR):
    os.makedirs(CSV_DIR)
save_race_csv = CSV_DIR+"/race-"+str(year)+"-"+str(month)+".csv"
horse_race_csv = CSV_DIR+"/horse-"+str(year)+"-"+str(month)+".csv"

# race_data_columns, horse_data_Les colonnes seront longues, donc omettez
race_df = pd.DataFrame(columns=race_data_columns )
horse_df = pd.DataFrame(columns=horse_data_columns )

html_dir = "html"+"/"+str(year)+"/"+str(month)
if os.path.isdir(html_dir):
    file_list = os.listdir(html_dir)
    for file_name in file_list:
        with open(html_dir+"/"+file_name, "r") as f:
            html = f.read()
            list = file_name.split(".")
            race_id = list[-2]
            race_list, horse_list_list = get_rade_and_horse_data_by_html(race_id, html) #Omis car ce sera long
            for horse_list in horse_list_list:
                horse_se = pd.Series( horse_list, index=horse_df.columns)
                horse_df = horse_df.append(horse_se, ignore_index=True)
            race_se = pd.Series(race_list, index=race_df.columns )
            race_df = race_df.append(race_se, ignore_index=True )
            
race_df.to_csv(save_race_csv, header=True, index=False)
horse_df.to_csv(horse_race_csv, header=True, index=False)

Pour chaque course, ajoutez les détails de la course, des informations sur chaque coureur, etc. à la liste et ajoutez une ligne au bloc de données pandas.

La fonction get_rade_and_horse_data_by_html, race_data_columns et horse_data_columns seront compliquées et ne seront pas incluses ici. Pour expliquer brièvement, la fonction get_rade_and_horse_data_by_html est une fonction qui utilise BeautifulSoup pour lister et renvoyer les données souhaitées à partir de html. race_data_columns et horse_data_columns sont les noms de colonne des données à acquérir.

Autres notes

Lors de l'exploration, assurez-vous de laisser du temps pour y accéder afin qu'il n'attaque pas le serveur.

Il y a d'autres personnes qui ont résumé les précautions juridiques détaillées, donc si vous le faites réellement, Liste des précautions pour le scraping Web-Qiita ) Etc., veuillez vous référer à.

Une fois les données obtenues, nous procéderons à la mise en forme et à l'analyse.

Maintenant que nous avons les données au format csv, nettoyons-les pour qu'elles soient faciles à gérer.

Ensuite, réfléchissez au type de modèle à créer tout en regardant l'état des données. Après cela, créons des données de train en fonction du modèle que vous souhaitez créer.

Formater les données pour qu'elles soient faciles à manipuler

Formalisons les données pour qu'elles soient faciles à gérer.

Par exemple, convertissez les données de date ou les nombres d'une chaîne en objet datetime ou int. De plus, comme il sera plus facile à l'avenir si les données d'une colonne sont aussi simples que possible, le sexe et l'âge sont divisés en deux colonnes. Il y a plusieurs choses à faire.

Il aurait peut-être été préférable de le faire en même temps que le grattage, mais comme le code de grattage semblait compliqué, j'ai décidé de le faire séparément cette fois.

Voici quelques-uns d'entre eux.

#Extraire les informations d'heure et les combiner avec les informations de date. Faites-en un type datetime
race_df["time"] = race_df["time"].str.replace('Début: (\d\d):(\d\d)(.|\n)*', r'\1 heure\2 minutes')
race_df["date"] = race_df["date"] + race_df["time"]
race_df["date"] = pd.to_datetime(race_df['date'], format='%Y année%m mois%jour j%H heure%M minutes')
#L'heure d'origine n'est pas nécessaire, supprimez-la
race_df.drop(['time'], axis=1, inplace=True)

#Supprimez le R supplémentaire et les blancs / sauts de ligne dans certaines colonnes rondes
race_df['race_round'] = race_df['race_round'].str.strip('R \n')

L'analyse des données

Nous analyserons les données formatées et vérifierons grossièrement le type de distribution dont elles disposent. Lors de la création d'un modèle, il est nécessaire de le former pour que les données ne soient pas biaisées autant que possible, c'est donc également important pour la définition des problèmes du modèle.

En outre, l'analyse des données est importante lorsque l'on considère comment créer des fonctionnalités. Dans le cas de l'apprentissage en profondeur, etc., il semble qu'il ne soit pas nécessaire de s'en tenir à l'ingénierie de la quantité de fonctionnalités, mais lorsque vous effectuez un apprentissage automatique non profond ordinaire tel que le boosting de gradient tel que LightGBM, il est nécessaire de réfléchir attentivement à la quantité de fonctionnalités. il y a.

Même avec Kaggle, si vous pouvez trouver une bonne quantité de fonctionnalités, il semble que la possibilité d'entrer dans les rangs supérieurs augmentera.

Créer des données de train

Après avoir décidé du type de modèle à créer en se référant à l'analyse de données mentionnée précédemment, créons des données de train.

Bien qu'il s'agisse de données d'entrée, c'est à peu près comme suit.

Les cotes de la course que vous souhaitez prédire fluctueront juste avant le match, nous ne les inclurons donc pas dans les données.

Enfin la création de modèles (deep learning)

Tout d'abord, je vais donner un aperçu, cette fois je ferai un apprentissage profond avec keras. Utiliser les données d'un cheval comme entrée

J'en ai fait deux.

Comment décider du modèle

Il faut se demander s'il faut résoudre le problème de classification ou le problème de régression.

Dans le cas du problème de régression, je pense que cela permettra de prédire combien le cheval sera (cela permettra quelque chose comme 1,2) et le temps.

Dans le cas d'un problème de classement, il vous sera demandé de prédire combien de chevaux il y aura (celui-ci est classé par nombres naturels de 1 à 16), s'il sera le premier, s'il sera en tête, etc. ..

Les temps et les vitesses varient énormément en fonction de l'hippodrome et du parcours, il sera donc difficile de ne pas les prévoir séparément. Cette fois, prévoyons simplement «si nous sommes ou non parmi les premiers» comme un problème de classification.

Ce que nous avons fait dans la création de modèles et comment gérer le surapprentissage

J'écrirai sur diverses choses que j'ai essayées lors de la création du modèle.

De plus, même si vous faites un modèle, il est indispensable de concevoir un moyen d'éviter le surapprentissage et de vérifier s'il est sur-appris. Même si vous faites du machine learning et que vous obtenez de bons résultats avec les données disponibles, cela ne signifie pas que le modèle peut prédire d'autres données avec une bonne précision.

Divisez l'ensemble de données pour la formation et les tests

Tout d'abord, des bases. Il est inutile de créer un modèle à moins que vous ne puissiez évaluer s'il est bon ou non.

80% des données collectées et formatées ont été utilisées comme données de formation et 20% ont été utilisées comme données de test. En d'autres termes

--Données d'apprentissage: janvier 2008-23 juillet 2017 --Données d'essai: 23 juillet 2017-novembre 2019

C'est sous la forme de. Ces données de test sont utilisées pour le taux de réponse correct écrit au début.

Au moment de la formation, les données de formation ont été divisées en une pour la formation et une pour la validation.

Régularisation du poids et abandon

La régularisation du poids et les abandons sont quelques-uns des moyens de prévenir le surapprentissage, et les keras les rendent faciles à utiliser.

Ajouter un coût en fonction du poids à la fonction de perte du réseau est la régularisation du poids, et l'abandon consiste à réduire (supprimer) de manière aléatoire la quantité de caractéristiques de la couche pendant l'entraînement.

Nous avons utilisé la régularisation L2 pour la régularisation du poids.

Référence: Connaître le surapprentissage et le manque d'apprentissage | TensorFlow Core


model = tf.keras.Sequential([
        tf.keras.layers.Dense(300, kernel_regularizer=tf.keras.regularizers.l2(0.001), activation=tf.nn.relu, input_dim=df_columns_len), #l2 Couche régularisée
        tf.keras.layers.Dropout(0.2), #Abandonner
        tf.keras.layers.Dense(100, kernel_regularizer=tf.keras.regularizers.l2(0.001), activation=tf.nn.relu), #l2 Couche régularisée
        tf.keras.layers.Dropout(0.2), #Abandonner
        tf.keras.layers.Dense(1, activation=tf.nn.sigmoid) 
    ])

Validation croisée

Une simple validation d'exclusion utilisant seulement une période de temps spécifique peut se révéler surentraînée pour donner de bons résultats pendant cette période.

Vérifions si le modèle est bon avec les données disponibles, car la validation croisée est effectuée dans des compétitions telles que Kaggle.

Le problème est qu'il s'agit de données de séries chronologiques, vous ne pouvez donc pas simplement utiliser KFold pour diviser les données. Lors de la saisie de données de séries chronologiques, si les informations futures sont définies pour s'entraîner et que les informations passées sont validées, le résultat peut être meilleur qu'il ne devrait l'être. En fait, j'ai fait une erreur au début et je me suis entraîné en saisissant des données futures, mais la probabilité de prédiction de double victoire dépassait 70%.

Donc, cette fois, j'ai utilisé la méthode de fractionnement utilisée pour la validation croisée des données de séries temporelles ([TimeSeries Split] de sklearn (https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.TimeSeriesSplit. html)).

En gros, comme le montre la figure ci-dessous, l'ensemble de données est divisé en ajoutant des séries chronologiques et une partie est utilisée comme données de vérification.

プレゼンテーション1のコピー.png

Dans cette figure, vous apprendrez trois fois. Cependant, certaines données d'entraînement seront réduites, donc si le nombre de données est petit, un simple blocage peut être préférable.

tscv = TimeSeriesSplit(n_splits=3)
for train_index, val_index in tscv.split(X_train,Y_train):
    train_data=X_train[train_index]
    train_label=Y_train[train_index]
    val_data=X_train[val_index]
    val_label=Y_train[val_index]
    model = train_model(train_data,train_label,val_data,val_label,target_name)

Réglage des hyper paramètres

Les hyperparamètres dans l'apprentissage automatique sont importants. Par exemple, dans l'apprentissage en profondeur, plus la couche intermédiaire est grande, plus il y a de variables intermédiaires, et moins il y a de données d'entraînement, plus il est facile de surpasser. En revanche, s'il est petit, même si la quantité de données est suffisante, il peut ne pas être assez flexible pour apprendre correctement.

Il y aura beaucoup de controverse sur la façon de le faire. Cela semble varier d'une personne à l'autre.

Cette fois, il y avait une bibliothèque appelée hyperas qui ajuste automatiquement le réglage des paramètres des keras, j'ai donc décidé de l'utiliser. C'était relativement intuitif et facile à comprendre.

Pour une utilisation simple, passez simplement la fonction de préparation des données et la fonction qui renvoie la valeur que vous voulez minimiser en apprenant à ʻoptim.minimize`.

Spécifiez la largeur que vous souhaitez ajuster avec choice pour les valeurs entières et ʻuniform` pour les nombres réels.

Pour plus de détails, consultez ici: https://github.com/maxpumperla/hyperas

import keras
from keras.callbacks import EarlyStopping
from keras.callbacks import CSVLogger
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation

from hyperopt import Trials, STATUS_OK, tpe
from hyperas import optim
from hyperas.distributions import choice, uniform
def prepare_data_is_hukusyo():
    """
Je vais préparer diverses données ici
    """
    return X_train, Y_train, X_test, Y_test

def create_model_is_hukusyo(X_train, Y_train, X_test, Y_test):
    train_size = int(len(Y_train) * 0.8)
    train_data = X_train[0:train_size]
    train_label = Y_train[0:train_size]
    val_data = X_train[train_size:len(Y_train)]
    val_label = Y_train[train_size:len(Y_train)]

    callbacks = []
    callbacks.append(EarlyStopping(monitor='val_loss', patience=2))

    model = Sequential()
    model.add(Dense({{choice([512,1024])}}, kernel_regularizer=keras.regularizers.l2(0.001), activation="relu", input_dim=train_data.shape[1]))
    model.add(Dropout({{uniform(0, 0.3)}}))
    model.add(Dense({{choice([128, 256, 512])}}, kernel_regularizer=keras.regularizers.l2(0.001), activation="relu"))
    model.add(Dropout({{uniform(0, 0.5)}}))

    if {{choice(['three', 'four'])}} == 'three':
        pass
    elif {{choice(['three', 'four'])}} == 'four':
        model.add(Dense(8, kernel_regularizer=keras.regularizers.l2(0.001), activation="relu"))
        model.add(Dropout({{uniform(0, 0.5)}}))

    model.add(Dense(1, activation="sigmoid"))

    model.compile(
        loss='binary_crossentropy',
        optimizer=keras.optimizers.Adam(),
        metrics=['accuracy'])

    history = model.fit(train_data,
        train_label,
        validation_data=(val_data, val_label),
        epochs=30,
        batch_size=256,
        callbacks=callbacks)

    val_loss, val_acc = model.evaluate(X_test, Y_test, verbose=0)
    print('Best validation loss of epoch:', val_loss)
    return {'loss': val_loss, 'status': STATUS_OK, 'model': model}

#Ajuster réellement avec des hyperas
best_run, best_model = optim.minimize(model=create_model_is_hukusyo,
                                     data=prepare_data_is_hukusyo,
                                     algo=tpe.suggest,
                                     max_evals=15,
                                     trials=Trials())

Mélangez le résultat

Vous pourrez peut-être faire des prédictions plus précises en mélangeant les sorties de différents modèles.

En faisant la moyenne de la prédiction de la 1ère place et de la 3ème place et au-dessus de la prédiction, nous avons pu obtenir une valeur légèrement supérieure à la valeur de prédiction d'origine.

Les caractéristiques des chevaux susceptibles d'être classés premiers et les caractéristiques des chevaux susceptibles d'être classés élevés peuvent être légèrement différentes, et l'on pense qu'une prédiction plus précise est possible en mélangeant les deux. Je vais.

Par exemple, il semble que les caractéristiques d'un cheval qui peut être classé 1er mais qui n'en fait pas trop s'il semble échouer au milieu de la course et un cheval qui entre de manière stable dans le top sont légèrement différentes.

résultat

Au final, j'ai réalisé un modèle plus précis que moi, qui est un débutant en courses de chevaux.

Il y a encore plus d'informations qui semblent être importantes dans les courses de chevaux, il semble donc y avoir place à l'amélioration.

Le solde lorsque je continue d'acheter la 1ère place lors d'une victoire est le suivant. Je l'ai tracé correctement en utilisant des pandas.

image.png

Dans la double victoire, c'est devenu comme suit.

image.png

C'est un gros déficit. Ce sera un peu mieux si vous n'achetez que ceux avec des prédictions élevées et non ceux avec des cotes faibles.

Autres conseils

En faisant cette prédiction de courses de chevaux, je laisserai certaines des choses que j'ai essayées qui n'ont rien à voir avec la ligne principale.

Utiliser GCP

Le crédit gratuit GCP était sur le point d'expirer vers la fin du mois de novembre, mon deuxième objectif était donc de le consommer.

Vous pouvez lancer le programme avant d'aller vous coucher et le vérifier lorsque vous vous réveillez le matin.

Soyez prudent si vous utilisez GCP, car l'instance gratuite ne dispose pas de suffisamment de mémoire pour créer du CSV et du deep learning.

Notifier avec LINE Notify

En ce qui concerne GCP, j'avais l'habitude d'envoyer LINE Notify si le programme se terminait ou si une erreur se produisait.

Dès que j'ai terminé, j'ai pu voir les résultats et exécuter le programme suivant, ce qui représentait beaucoup de travail.

Certains à la fin

C'est un divertissement approprié pour les étudiants, donc si vous le connaissez, je pense qu'il y a beaucoup de choses à faire. Si vous faites une erreur, ce sera une expérience d'apprentissage, donc je vous serais reconnaissant de bien vouloir le signaler dans les commentaires ou sur Twitter.

Identifiant Twitter (je ne tweet pas trop): @ 634kami

Code source

Il est publié sur github. Je voulais faire quelque chose qui fonctionne pour le moment, donc ce n'est pas quelque chose que les gens peuvent voir, mais s'il vous plaît ne voyez que ceux qui disent que ça va.

Le code sur Qiita a été partiellement modifié pour le rendre plus facile à lire.

Où vous pouvez vous améliorer / ce que vous voulez faire

D'autres liens auxquels j'ai fait référence ou sont susceptibles d'être

Postscript

J'ai ajouté ce qui suit parce que j'ai fait ce qui suit.

Voici les résultats.

total: 8, random tansyo accuracy:0.125, hukusyo accuracy:0.375
tansyo accuracy: 0.3497536945812808
hukusyo accuracy: 0.7044334975369458

total: 9, random tansyo accuracy:0.1111111111111111, hukusyo accuracy:0.3333333333333333
tansyo accuracy: 0.2693726937269373
hukusyo accuracy: 0.6568265682656826

total: 10, random tansyo accuracy:0.1, hukusyo accuracy:0.3
tansyo accuracy: 0.30563002680965146
hukusyo accuracy: 0.6407506702412868

total: 11, random tansyo accuracy:0.09090909090909091, hukusyo accuracy:0.2727272727272727
tansyo accuracy: 0.2582278481012658
hukusyo accuracy: 0.5468354430379747

total: 12, random tansyo accuracy:0.08333333333333333, hukusyo accuracy:0.25
tansyo accuracy: 0.2600806451612903
hukusyo accuracy: 0.5826612903225806

total: 13, random tansyo accuracy:0.07692307692307693, hukusyo accuracy:0.23076923076923078
tansyo accuracy: 0.2894736842105263
hukusyo accuracy: 0.5855263157894737

total: 14, random tansyo accuracy:0.07142857142857142, hukusyo accuracy:0.21428571428571427
tansyo accuracy: 0.23014586709886548
hukusyo accuracy: 0.5380875202593193

total: 15, random tansyo accuracy:0.06666666666666667, hukusyo accuracy:0.2
tansyo accuracy: 0.2525399129172714
hukusyo accuracy: 0.532656023222061

Dans chaque cas, le taux d'exactitude était meilleur que la méthode de sélection complètement aléatoire.

Recommended Posts

J'ai essayé de prédire les courses de chevaux en faisant tout, de la collecte de données à l'apprentissage en profondeur
[Deep Learning from scratch] J'ai essayé d'expliquer le décrochage
J'ai essayé d'implémenter Perceptron Part 1 [Deep Learning from scratch]
[Deep Learning from scratch] J'ai essayé d'implémenter la couche sigmoïde et la couche Relu
J'ai essayé de classer Oba Hanana et Otani Emiri par apprentissage profond
J'ai essayé l'histoire courante de l'utilisation du Deep Learning pour prédire la moyenne Nikkei
J'ai essayé le deep learning
J'ai essayé d'extraire le dessin au trait de l'image avec Deep Learning
J'ai essayé de prédire la présence ou l'absence de neige par apprentissage automatique.
J'ai essayé de prédire l'évolution de la quantité de neige pendant 2 ans par apprentissage automatique
J'ai essayé de classer Hanana Oba et Emiri Otani par apprentissage profond (partie 2)
J'ai essayé de prédire le match de la J League (analyse des données)
"Deep Learning from scratch" Mémo d'auto-apprentissage (n ° 16) J'ai essayé de créer SimpleConvNet avec Keras
"Deep Learning from scratch" Mémo d'auto-apprentissage (n ° 17) J'ai essayé de créer DeepConvNet avec Keras
[Courses de chevaux] J'ai essayé de quantifier la force du cheval de course
J'ai essayé d'implémenter la détection d'anomalies par apprentissage de structure clairsemée
[Introduction à Pandas] J'ai essayé d'augmenter les données d'échange par interpolation de données ♬
Créez une IA qui identifie le visage de Zuckerberg grâce à l'apprentissage en profondeur ③ (Apprentissage des données)
J'ai essayé d'écrire dans un modèle de langage profondément appris
J'ai essayé d'obtenir rapidement des données d'AS / 400 en utilisant pypyodbc
[Deep Learning from scratch] J'ai essayé d'expliquer la confirmation du gradient d'une manière facile à comprendre.
J'ai essayé de faire d'Othello AI que j'ai appris 7,2 millions de mains par apprentissage profond avec Chainer
J'ai essayé d'implémenter Deep VQE
Utilisation des données ouvertes de Data City Sabae pour prédire la valeur de la jauge de niveau d'eau par apprentissage automatique Partie 2
J'ai essayé d'obtenir une base de données sur les courses de chevaux en utilisant Pandas
J'ai essayé de rendre le deep learning évolutif avec Spark × Keras × Docker
J'ai fait apprendre à RNN la vague de péché et j'ai essayé de prédire
J'ai essayé l'apprentissage en profondeur avec Theano
J'ai essayé d'obtenir rapidement des données d'AS / 400 en utilisant pypyodbc Préparation 1
[Bases de la science des données] J'ai essayé d'enregistrer de csv à mysql avec python
J'ai essayé de mettre en œuvre un apprentissage en profondeur qui n'est pas profond avec uniquement NumPy
J'ai essayé de faire la reconnaissance de caractères manuscrits de Kana Partie 2/3 Création et apprentissage de données
J'ai essayé de classer les nombres de mnist par apprentissage non supervisé [PCA, t-SNE, k-means]
J'ai essayé de récupérer les données de conversation d'ASKfm
Apprentissage amélioré pour apprendre de zéro à profond
Alignement d'image: du SIFT au deep learning
[Python] [Traitement du langage naturel] J'ai essayé le Deep Learning ❷ fait de toutes pièces en japonais ①
[Python] Deep Learning: J'ai essayé d'implémenter Deep Learning (DBN, SDA) sans utiliser de bibliothèque.
Un débutant en apprentissage automatique a essayé de créer un modèle de prédiction de courses de chevaux avec python
J'ai essayé d'automatiser le dépôt de 100 yens des courses de chevaux Rakuten (python / sélénium)
J'ai essayé de traiter et de transformer l'image et d'élargir les données pour l'apprentissage automatique
J'ai essayé de récupérer les données de l'ordinateur portable en le démarrant sur Ubuntu
J'ai essayé d'implémenter Cifar10 avec la bibliothèque SONY Deep Learning NNabla [Nippon Hurray]
J'ai essayé de passer le test G et la qualification E en m'entraînant à partir de 50
J'ai essayé de rendre le deep learning évolutif avec Spark × Keras × Docker 2 Multi-host edition
J'ai essayé de prédire l'année prochaine avec l'IA
J'ai créé une fonction pour récupérer les données de la colonne de base de données par colonne en utilisant sql avec sqlite3 de python [sqlite3, sql, pandas]
J'ai essayé d'obtenir une image en grattant
J'ai essayé de sauvegarder les données avec discorde
J'ai essayé d'obtenir des données CloudWatch avec Python
Comment récupérer des données de courses de chevaux avec Beautiful Soup
J'ai essayé de prédire la survie du Titanic avec PyCaret
J'ai essayé de classer les boules de dragon par adaline
[Keras] J'ai essayé de résoudre le problème de classification des zones de type beignet par apprentissage automatique [Étude]
[Première science des données ⑤] J'ai essayé d'aider mon ami à trouver la première propriété par analyse de données
J'ai essayé de visualiser les données de course du jeu de course (Assetto Corsa) avec Plotly
J'ai essayé d'agréger et de comparer les données de prix unitaires par langue avec Real Gachi by Python