[PYTHON] Méthode de mise en œuvre spécifique pour ajouter les données de performances passées des chevaux à la quantité de fonctionnalités d'apprentissage automatique

Objectif

Prédisez les courses de chevaux avec l'apprentissage automatique et visez un taux de récupération de 100%.

Que faire cette fois

La dernière fois, j'ai créé un modèle d'apprentissage automatique qui prédit les chevaux qui seront dans le top 3 avec LightGBM. Cette fois, j'aimerais ajouter "performances passées des chevaux" comme quantité de caractéristiques, mais quand j'essaye de le faire, le grattage et le traitement des données sont assez difficiles. Donc, je voudrais résumer quel type de code doit être écrit et implémenté </ font>. スクリーンショット 2020-07-09 18.13.19.png

Code source

Tout d'abord, retrouvez les résultats passés de tous les chevaux en course en 2019 sur netkeiba.com. Sur netkeiba.com, horse_id est donné pour chaque cheval et l'URL de la page des résultats passés est 「https://db.netkeiba.com/horse/(horse_id)」 Puisqu'elle a la structure, la fonction scrape_race_results créée dans Article précédent est traitée pour gratter le horse_id nécessaire (ainsi que l'identifiant du cavalier).

import time
from tqdm.notebook import tqdm
import requests
from bs4 import BeautifulSoup
import re
import pandas as pd

def scrape_race_results(race_id_list, pre_race_results={}):
    race_results = pre_race_results
    for race_id in tqdm(race_id_list):
        if race_id in race_results.keys():
            continue
        try:
            url = "https://db.netkeiba.com/race/" + race_id
            df = pd.read_html(url)[0]

            # horse_id et jockey_Identifiant de raclage
            html = requests.get(url)
            html.encoding = "EUC-JP"
            soup = BeautifulSoup(html.text, "html.parser")
            # horse_id
            horse_id_list = []
            horse_a_list = soup.find("table", attrs={"summary": "Résultat de la course"}).find_all(
                "a", attrs={"href": re.compile("^/horse")}
            )
            for a in horse_a_list:
                horse_id = re.findall(r"\d+", a["href"])
                #Il est en majuscule car il provoque un bogue lors de l'utilisation de la barre oblique inverse dans qiita.
                horse_id_list.append(horse_id[0])
            # jockey_id
            jockey_id_list = []
            jockey_a_list = soup.find("table", attrs={"summary": "Résultat de la course"}).find_all(
                "a", attrs={"href": re.compile("^/jockey")}
            )
            for a in jockey_a_list:
                jockey_id = re.findall(r"\d+", a["href"])
                jockey_id_list.append(jockey_id[0])

            df["horse_id"] = horse_id_list
            df["jockey_id"] = jockey_id_list
            race_results[race_id] = df
            time.sleep(1)
        except IndexError:
            continue
        except Exception as e:
            print(e)
            break
    return race_results

Convertissez en type DataFrame en référence à l'article précédent. Cela vous donnera une liste des horse_ids dont vous avez besoin.

results = scrape_race_results(race_id_list)
results = pd.concat([results[key] for key in results])
horse_id_list = results['horse_id'].unique()

Ceci est utilisé pour récupérer les données de performances passées.

def scrape_horse_results(horse_id_list, pre_horse_id=[]):
    horse_results = {}
    for horse_id in tqdm(horse_id_list):
        if horse_id in pre_horse_id:
            continue
        try:
            url = 'https://db.netkeiba.com/horse/' + horse_id
            df = pd.read_html(url)[3]
            if df.columns[0]=='Historique des récompenses':
                df = pd.read_html(url)[4]
            horse_results[horse_id] = df
            time.sleep(1)
        except IndexError:
            continue
        except Exception as e:
            import traceback
            traceback.print_exc()
            print(e)
            break
        except:
            break
    return horse_results

Cela prend beaucoup de temps, mais après le scraping, faites-en à nouveau un type DataFrame et enregistrez-le dans un fichier pickle.

horse_results = scrape_horse_results(horse_id_list)
for key in horse_results:
    horse_results[key].index = [key] * len(horse_results[key])
df = pd.concat([horse_results[key] for key in horse_results])
df.to_pickle('horse_results.pickle')

Ensuite, créez une classe appelée HorseResults et implémentez une fonction qui fusionne l'ordre d'arrivée et la moyenne des prix.

class HorseResults:
    def __init__(self, horse_results):
        self.horse_results = horse_results[['Date', 'Ordre d'arrivée', 'Prix']]
        self.preprocessing()
        
    def preprocessing(self):
        df = self.horse_results.copy()

        #Supprimer les éléments contenant des chaînes de caractères non numériques dans l'ordre d'arrivée
        df['Ordre d'arrivée'] = pd.to_numeric(df['Ordre d'arrivée'], errors='coerce')
        df.dropna(subset=['Ordre d'arrivée'], inplace=True)
        df['Ordre d'arrivée'] = df['Ordre d'arrivée'].astype(int)

        df["date"] = pd.to_datetime(df["Date"])
        df.drop(['Date'], axis=1, inplace=True)
        
        #Remplissez le prix NaN avec 0
        df['Prix'].fillna(0, inplace=True)
    
        self.horse_results = df
        
    def average(self, horse_id_list, date, n_samples='all'):
        target_df = self.horse_results.loc[horse_id_list]
        
        #Spécifiez le nombre d'exécutions dans le passé
        if n_samples == 'all':
            filtered_df = target_df[target_df['date'] < date]
        elif n_samples > 0:
            filtered_df = target_df[target_df['date'] < date].\
                sort_values('date', ascending=False).groupby(level=0).head(n_samples)
        else:
            raise Exception('n_samples must be >0')
            
        average = filtered_df.groupby(level=0)[['Ordre d'arrivée', 'Prix']].mean()
        return average.rename(columns={'Ordre d'arrivée':'Ordre d'arrivée_{}R'.format(n_samples), 'Prix':'Prix_{}R'.format(n_samples)})
    
    def merge(self, results, date, n_samples='all'):
        df = results[results['date']==date]
        horse_id_list = df['horse_id']
        merged_df = df.merge(self.average(horse_id_list, date, n_samples), left_on='horse_id',
                             right_index=True, how='left')
        return merged_df
    
    def merge_all(self, results, n_samples='all'):
        date_list = results['date'].unique()
        merged_df = pd.concat([self.merge(results, date, n_samples) for date in tqdm(date_list)])
        return merged_df

Avec cela, par exemple, si vous souhaitez ajouter les résultats des 5 dernières courses à la quantité de caractéristiques, vous pouvez implémenter comme suit.

hr = HorseResults(horse_results)
results_5R = hr.merge_all(results_p, n_samples=5)

Vous pouvez maintenant voir que l'ordre d'arrivée et la moyenne des 5 dernières courses de prix ont été ajoutés aux deux colonnes les plus à droite. スクリーンショット 2020-07-09 18.41.01.png

Les détails sont expliqués dans la vidéo ↓ Analyse de données / apprentissage automatique à partir de la prédiction des courses de chevaux スクリーンショット 2020-07-11 15.00.29.png

Recommended Posts

Méthode de mise en œuvre spécifique pour ajouter les données de performances passées des chevaux à la quantité de fonctionnalités d'apprentissage automatique
Comment collecter des données d'apprentissage automatique
Méthode de voisinage #k d'apprentissage automatique et sa mise en œuvre et divers
Introduction à l'apprentissage automatique
Essayez d'évaluer les performances du modèle d'apprentissage automatique / de régression
Introduction à l'apprentissage automatique avec scikit-learn - De l'acquisition de données à l'optimisation des paramètres
Vérification des performances du prétraitement des données pour l'apprentissage automatique (données numériques) (partie 2)
Utilisation d'icrawler plus simple pour la collecte de données d'apprentissage automatique
Essayez d'évaluer les performances du modèle d'apprentissage automatique / de classification
Les débutants en apprentissage automatique tentent de contacter Naive Bayes (2) - Mise en œuvre
Vérification des performances du prétraitement des données pour l'apprentissage automatique (données numériques) (partie 1)
Ensemble de données pour l'apprentissage automatique
Une introduction à l'apprentissage automatique
Super introduction à l'apprentissage automatique
[Apprentissage automatique] Vérifiez les performances du classificateur à l'aide de données de caractères manuscrites
Méthode Newton pour l'apprentissage automatique (de 1 variable à plusieurs variables)