En tant que pratique de la prédiction d'apprentissage automatique des données de séries chronologiques, j'ai essayé la prédiction Janken de Sazae avec LightGBM.
C'est l'un des algorithmes d'apprentissage automatique et utilise un boost de gradient basé sur l'arbre de décision. Il s'agit d'une méthode d'apprentissage automatique de haut niveau utilisée par de nombreux joueurs de premier plan lors des récentes compétitions Kaggle.
Une introduction approfondie à LightGBM https://www.codexa.net/lightgbm-beginner/
Nous avons emprunté des données au "Sazae-san Janken Institute", qui enregistre tous les Janken depuis le début de Janken en 1991 jusqu'à nos jours. Je suis surpris que j'enregistre depuis l'ère de la communication PC avant Internet. En plus des enregistrements, nous analysons sous différents angles le prochain mouvement.
Site officiel de l'Institut Sazae-san Janken http://park11.wakwak.com/~hkn/
Selon l'analyse du "Sazae-san Janken Institute", il y avait une méthode pour prédire le prochain mouvement des deux derniers mouvements, et une méthode pour prédire que le mouvement qui n'a pas été sorti depuis le plus longtemps est le prochain mouvement. De plus, il est facile de s'étouffer lors de la première diffusion de la saison (janvier, avril, juillet, octobre) et de l'épisode spécial.
Tout d'abord, nous avons créé un modèle de base les utilisant comme quantités d'entités, et vérifié quelle quantité d'entités était efficace tout en augmentant ou en diminuant la quantité d'entités.
En conséquence, les fonctionnalités finalement sélectionnées sont les suivantes. ・ Résultats des 3 dernières fois (si vous incluez les 4 dernières fois, la précision diminuera) ・ Que ce soit la première saison ・ Que ce soit un moment spécial ・ Si la dernière fois est la première de la saison (ceci n'est que pour la dernière fois. Si vous incluez jusqu'à 2 fois, la précision diminuera) ・ Si la dernière fois était un moment spécial (ce n'est que pour la dernière fois. Si vous incluez jusqu'à 2 fois, la précision diminuera)
Selon "Sazae-san Janken Institute", le responsable de la société de production décide de la main en fonction de l'humeur. À ce moment-là, il est très probable que le prochain mouvement soit pris afin de ne pas le porter en référence au passé plusieurs fois de Janken. Par conséquent, je pense qu'il est logique d'utiliser les résultats d'au plus 3 fois plus de fonctionnalités de décalage que la quantité de fonctionnalités. De plus, il y avait une méthode en laboratoire pour prédire que le mouvement qui n'apparaissait pas le plus longtemps était le prochain mouvement, mais quand j'ai regardé cela comme une quantité de caractéristiques, la précision n'a pas tellement changé, donc je l'ai exclue.
Nous avons fait l'apprentissage final et les tests avec LightGBM comme ces fonctionnalités. ・ Données d'apprentissage: 1196 fois du 1er décembre 1991 au 9 août 2015 ・ Données de vérification: 194 fois du 16 août 2015 au 14 juillet 2019 ・ Données de test: 50 fois du 21 juillet 2019 au 5 juillet 2020
En conséquence, le ** taux de précision (précision) des données de test était de 65,3% **. De plus, lorsque le taux de gain a été calculé (gagnant / (gagnant + perdant)) en utilisant le même indice que le site, en prenant la stratégie de gagner le coup avec la probabilité la plus élevée parmi les prédictions, le taux de gain était de 84,2% **. J'ai fait.
Enfin, je vais mettre le code.
import pandas as pd
import lightgbm as lgb
import numpy as np
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
#Janken2.Au moment de csv, un certain traitement était terminé.
sazae = pd.read_csv('Janken2.csv')
sazae.drop(labels=['cnt','date'], axis=1, inplace=True)
sazae.year = sazae.year - 1990
sazae.season = sazae.season.fillna(0)
sazae.special = sazae.special.fillna(0)
sazae['janken_lag_1'] = sazae['janken'].shift(1)
sazae['janken_lag_2'] = sazae['janken'].shift(2)
sazae['janken_lag_3'] = sazae['janken'].shift(3)
sazae['season_lag'] = sazae['season'].shift(1)
sazae['special_lag'] = sazae['special'].shift(1)
sazae = sazae[3:]
sazae = sazae.astype({'special_lag':int,'season_lag':int,'janken': int, 'special': int, 'season': int, 'janken_lag_1':int, 'janken_lag_2':int, 'janken_lag_3':int})
sazae[(sazae['janken_lag_1']==0) & (sazae['janken_lag_2']==1)& (sazae['janken_lag_3']==0)]
X, y = sazae[['special','season','janken_lag_1','janken_lag_2','janken_lag_3','season_lag','special_lag']], sazae[['janken']]
cat = ['season','janken_lag_1','janken_lag_2','janken_lag_3','season_lag','special_lag', 'special']
X_train, y_train = X[(X.index >= 0) & (X.index < 1200)], y[(y.index >= 0) & (y.index < 1200)]
X_valid, y_valid = X[(X.index >= 1200) & (X.index < 1394)], y[(y.index >= 1200) & (y.index < 1394)]
X_test, y_test = X[(X.index >= 1394)], y[(y.index >= 1394)]
#Définir les données utilisées pour l'apprentissage
lgb_train = lgb.Dataset(X_train, y_train, categorical_feature=cat)
lgb_eval = lgb.Dataset(X_valid, y_valid, reference=lgb_train, categorical_feature=cat)
# LightGBM parameters
params = {
'task': 'train',
'boosting_type': 'gbdt',
'objective': 'multiclass', #Objectif:Classification multi-classes
'num_class': 3, #Nombre de cours: 3
'metric': {'multi_error'}, #Index d'évaluation:Taux d'erreur(= 1-Taux de réponse correct)
}
#Apprentissage de modèle
model = lgb.train(params,
train_set=lgb_train, #Désignation des données d'entraînement
valid_sets=lgb_eval, #Spécification des données de vérification
#Apprenez jusqu'à 1000 tours
num_boost_round=2000,
#Arrêtez d'apprendre si les performances ne s'améliorent pas après 10 tours
early_stopping_rounds=100
)
#Prédiction des données de test((Probabilité de prédiction de chaque classe[Goo(0)Probabilité de prédiction,Choki(1)のProbabilité de prédiction,Par(2)のProbabilité de prédiction]rends le))
y_pred_prob = model.predict(X_test)
y_pred = np.argmax(y_pred_prob, axis=1)
accuracy = accuracy_score(y_test, y_pred)
print(accuracy)
win = 0
lose = 0
draw = 0
janken = (y_pred + 2) % 3
print(janken)
for (test, j) in zip(y_test.values, janken):
if test == j:
draw += 1
elif (test+2)%3 == j:
win += 1
elif (test+1)%3 == j:
lose += 1
print(win,draw,lose)
print(win/(win+lose))
test2 = pd.DataFrame(index=[], columns=X_test.columns)
print(test2)
#[Périodes spéciales,Première fois de la saison,Dernière main,Mains deux fois avant,Main il y a trois fois,Si la dernière fois est la première fois de la saison,前回がPériodes spécialesかどうか]Spécifier
test2.loc[0] = [0,0,1,0,2,1,0] #2020/7/12
test2 = test2.astype({'special_lag':int,'season_lag':int, 'special': int, 'season': int, 'janken_lag_1':int, 'janken_lag_2':int, 'janken_lag_3':int})
result = model.predict(test2)
#[Probabilité Goo, probabilité choki, probabilité par]
print(result)
・ Le code est un peu compliqué, je vais donc l'organiser. ・ CV (validation croisée) ・ Réglage des paramètres