[PYTHON] Prédire les attributs offensifs et défensifs à partir du nom de la carte Yugioh --Yugiou Data Science 3. Machine Learning

introduction

Il s'agit de la série "Yugio DS (Data Science)" qui analyse diverses données de cartes Yugioh en utilisant Python. L'article aura lieu quatre fois au total, et enfin nous mettrons en œuvre un programme qui prédit les attributs offensifs et défensifs des noms de cartes par traitement du langage naturel + apprentissage automatique. De plus, la connaissance de Yugioh par l'auteur s'est arrêtée aux alentours de E ・ HERO. Je suis désolé que les cartes et la science des données soient des amateurs, mais veuillez rester en contact.

No. Le titre de l'article Keyword
0 Obtenir des informations sur la carte de la base de données Yugioh-Yugioh DS 0.Grattage beautifulsoup
1 Visualisez les données de la carte Yugioh avec Python-Yugioh Data Science 1.Édition EDA pandas, seaborn
2 Traitez le nom de la carte Yugioh en langage naturel-Yugioh Data Science 2.Édition PNL wordcloud, word2vec, doc2vec, t-SNE Cet article!
3 Prédire les attributs offensifs et défensifs à partir du nom de la carte Yugioh-Yugioh Data Science 3.Apprentissage automatique lightgbm etc.

Objectif de cet article

Dans Article précédent, le vecteur obtenu en convertissant le nom de la carte avec Doc2Vec est le montant de la fonction, et d'autres éléments de la carte (puissance d'attaque, puissance de défense, attribut, race, niveau). ) Est utilisé comme étiquette, et un modèle qui prédit les attributs offensifs et défensifs à partir du nom de la carte par apprentissage automatique est mis en œuvre. De plus, en utilisant le modèle appris, nous exécuterons une tâche de prédiction qui attribue des attributs offensifs et défensifs au nom de la carte d'origine appropriée. Je voudrais vérifier à quel point le monstre original auquel j'ai pensé a été jugé à la lumière de l'apprentissage automatique.

Explication des prérequis (environnement d'utilisation, données, politique d'analyse)

environnement d'utilisation

Python==3.7.4

Les données

Cet article utilise du code fait à la main extrait de Yugio OCG Card Database comme données d'origine. .. Il s'agit du dernier en juin 2020. De plus, on suppose que les données d'entrée de l'apprentissage automatique utilisent les données d'origine traitées par l'édition NLP. 。

Politique d'analyse

Comme mentionné ci-dessus, seul le nom de la carte (vectorisé) est utilisé comme montant de la fonction cette fois. Il y a 5 étiquettes, puissance d'attaque, puissance de défense, attribut, race et niveau, alors préparez également 5 figurines. Bien qu'il s'agisse d'un type de modèle, l'apprentissage en profondeur n'est pas utilisé en raison des spécifications de la machine utilisée. Pour le moment, utilisez «LightGBM», qui est le plus précis des problèmes d'arbre et peut être appliqué aux problèmes de classification / régression. Avant la mise en œuvre, posez le problème de chaque modèle (modèle de régression / modèle de classification) et faites une hypothèse de bonne précision.

No. Étiquette prédite Problème de réglage hypothèse
1 attribut Classification multi-classes 例えばカード名に「天使」と入ってたら光attributになるなどの傾向はありそうなので、まあまあ精度は高そう
2 Course Classification multi-classes No.1と同様。カード名に「ドラゴン」と入っているものはドラゴン族など、Courseによってはかなり精度が高そう
3 niveau Classification multi-classes シリーズ物のカードだと同じ単語が入っていてもniveauがバラバラになったりするので精度は悪そう。また、ラベル自体のデータ数の偏りが影響しそう
4 Puissance offensive Revenir No.La précision semble être mauvaise pour la même raison que 3
5 Puissance défensive Revenir No.La précision semble être mauvaise pour la même raison que 3

la mise en oeuvre

1. Importation de package

Importez les packages requis.

python


from sklearn.metrics import confusion_matrix, plot_confusion_matrix
from sklearn.metrics import mean_squared_error, r2_score
from gensim.models.doc2vec import Doc2Vec
from gensim.models.doc2vec import TaggedDocument
from sklearn.model_selection import train_test_split

import gensim
import lightgbm as lgb
import matplotlib.pyplot as plt
%matplotlib inline
import MeCab
import numpy as np
import pandas as pd
import pickle
import seaborn as sns
sns.set(font="IPAexGothic")

2. Importation de modèles de données

Importez les données à utiliser et le modèle Doc2Vec qui vectorise le nom de la carte.

python


model_d2v = pickle.load(open('./input/model_d2v.pickle', 'rb'))
X = pickle.load(open('./input/X.pickle', 'rb'))
y = pickle.load(open('./input/y.pickle', 'rb'))

print("shape")
print("X: {}".format(X.shape))
print("y: {}".format(y.shape))
print("----------------")
print("data")
print("y: ")
print(y.head())
shape
X: (6206, 30)
y: (6206, 7)
----------------
data
y: 
   rarity attr  level species  attack  defence  kind
0 Attribut d'obscurité rare 5 Oiseaux et bêtes 1500 2000 Synchro
1 Ténèbres ultra rares 7 Oiseaux et bêtes 2600 2000 Synchro
2 Ténèbres Ultra Rares 12 Oiseaux et Bêtes 3000 2000 Synchro
3 Obscurité normale 2 oiseaux et bêtes 800100 Synchro
4 Ténèbres rares 5 Oiseaux et bêtes 2100 1600-

Le «X» (valeur de la fonction) et le «y» (étiquette) importés sont enregistrés comme suit dans Article précédent. C'est une condition préalable. Le processus pour enregistrer facilement est décrit ci-dessous.

python



#Monstres de trame de données contenant une liste de mots contenus dans le nom de la carte_Créer une liste de mots
#réduction

#Créer un document balisé pour le modèle Doc2Vec
document = [TaggedDocument(words = wordlist, tags = [monsters_wordlist.name[i]]) for i, wordlist in enumerate(monsters_wordlist.wordlist)]

#Apprendre le modèle Doc2Vec
model_d2v = Doc2Vec(documents = document, dm = 0, vector_size=30, epochs=200)

#Vectoriser tous les noms de cartes avec le modèle Doc2Vec
d2v_vecs = np.zeros((monsters_wordlist.name.shape[0],30))
for i, word in enumerate(monsters_wordlist.wordlist):
    d2v_vecs[i] = model_d2v.infer_vector(word)

#Stockez le nom de la carte vectorisée sous X et les données utilisées pour l'étiquette sous y
X = d2v_vecs
y = monsters_wordlist[["rarity", "attr", "level", "species", "attack", "defence"]]

#sauvegarder
with open("./input/model_d2v.pickle", "wb") as f:
    pickle.dump(model_d2v, f)

with open("./input/X.pickle", "wb") as f:
    pickle.dump(X, f)
    
with open("./input/y.pickle", "wb") as f:
    pickle.dump(y, f)

monsters_wordlist est la trame de données suivante. Veuillez vous référer à Article précédent pour la méthode de génération.

image.png

3. Apprentissage

Implémentez un modèle qui forme chacune des cinq étiquettes. Si vous écrivez des hyperparamètres un par un ou si vous les divisez par classification / régression, la quantité de code augmentera, donc par souci de simplicité, implémentez une fonction qui encapsule ces processus. J'ajouterai également un peu sur «LightGBM».

--Il existe deux méthodes d'apprentissage pour LightGBM, ** interface d'origine ** et ** interface Scikit-Learn **, mais cette dernière est adoptée ici. En partie parce que j'y suis habitué, mais parce que le comportement de la méthode predire lors de la classification multi-classes est plus pratique. --La métrique (ʻeval_metric) utilise Multi Logloss pour la classification multiclasse et RMSLE (erreur quadratique moyenne logique) pour la régression. La raison de l'adoption de RMSLE est que la distribution de la puissance offensive et défensive est plus large que la distribution normale (voir 3-2-1 de l'EDA), j'ai donc choisi cela au lieu de RMSE. ――D'autres réglages d'hyper paramètres sont appropriés (utilisation d'un autre modèle réalisé dans le passé). Vous devriez vraiment y réfléchir ... La méthode de réglage des hyperparamètres utilisant ʻOptuna en annexe, est décrite à la fin de l'article.

python


#Données d'entraînement / données de test divisées en deux
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0, test_size=0.2)

#Enveloppez le processus de création et d'apprentissage d'un modèle de classification / régression multi-classes avec une fonction
def fit_model(column, mode='Classifier'):
    if mode == 'Classifier':
        model_lgb = lgb.LGBMClassifier(num_leaves=5,
                                      learning_rate=0.05, n_estimators=720,
                                      max_bin = 55, bagging_fraction = 0.8,
                                      bagging_freq = 5, feature_fraction = 0.2319,
                                      feature_fraction_seed=9, bagging_seed=9,
                                      min_data_in_leaf =6, min_sum_hessian_in_leaf = 11, verbosity=-1)
        model_lgb.fit(X_train, y_train[column], eval_set=[(X_test, y_test[column])], eval_metric='multi_logloss', early_stopping_rounds=10)
        
    elif mode == 'Regressor':
        model_lgb = lgb.LGBMRegressor(num_leaves=5,
                              learning_rate=0.05, n_estimators=720,
                              max_bin = 55, bagging_fraction = 0.8,
                              bagging_freq = 5, feature_fraction = 0.2319,
                              feature_fraction_seed=9, bagging_seed=9,
                              min_data_in_leaf =6, min_sum_hessian_in_leaf = 11, verbosity=-1)
        model_lgb.fit(X_train, y_train[column], eval_set=[(X_test, y_test[column])], eval_metric='rmsle', early_stopping_rounds=10)

    
    return model_lgb

#Créer un modèle pour chaque étiquette
model_attr = fit_model("attr", mode="Classifier")
model_level = fit_model("level", mode="Classifier")
model_species = fit_model("species", mode="Classifier")
model_attack = fit_model("attack", mode="Regressor")
model_defence = fit_model("defence", mode="Regressor")

4. Vérification de l'exactitude

Nous vérifierons l'exactitude des résultats d'apprentissage à l'aide des données de test.

4-1. Taux de réponse correcte (précision) / coefficient de décision (score R2)

En tant qu'indice d'évaluation pour la vérification de l'exactitude, vérifiez le taux de réponse correct (précision) pour les questions de classification et le coefficient de décision (score R2) pour les questions de régression.

python


def get_accuracy(column, model):
    y_pred = model.predict(X_test)
    accuracy = sum(y_test[column] == y_pred) / len(y_test)
    return accuracy

def get_r2score(column, model):
    y_pred = model.predict(X_test)
    r2score = r2_score(y_test[column], y_pred)
    return r2score

accuracy_attr = get_accuracy("attr", model_attr)
print("accuracy_attr: {}".format(accuracy_attr))

accuracy_species = get_accuracy("species", model_species)
print("accuracy_species: {}".format(accuracy_species))

accuracy_level = get_accuracy("level", model_level)
print("accuracy_level: {}".format(accuracy_level))

r2score_attack = get_r2score("attack", model_attack)
print("r2score_attack: {}".format(r2score_attack))

r2score_defence = get_r2score("defence", model_defence)
print("r2score_defence: {}".format(r2score_defence))
accuracy_attr: 0.5515297906602254
accuracy_species: 0.4669887278582931
accuracy_level: 0.3413848631239936
r2score_attack: 0.0804399379391485
r2score_defence: 0.04577024081390113

Tout d'abord, vérifiez le taux de réponse correct «Précision». Compte tenu du taux de réponse correct du modèle qui donne une étiquette complètement aléatoire, il existe 7 types d'étiquettes d'attributs (ʻattr), donc environ ** 0,143 **, et 13 types de niveaux (Level`) vont de 0 à 12. ** 0,077 **, Il y a 25 races («espèces»), ce qui est ** 0,04 **, donc le modèle ci-dessus semble apprendre tel quel. D'un autre côté, dans le cas du niveau, 1925 sur 6206 cartes cibles sont des données biaisées de telle sorte qu'il s'agit du niveau 4, donc même si tous les modèles sont jugés au niveau 4, le taux de réponse correct sera d'environ ** 0,31 **. Je vais. Il s'agit d'une valeur très proche du taux de réponse correct ci-dessus, il est donc nécessaire de confirmer en creusant profondément s'il existe ou non un modèle qui prédit que tous sont de niveau 4.

Vient ensuite le coefficient de décision «Score R2», qui peut être compris comme plus il est proche de 1, plus la précision d'analyse est élevée (la dispersion de l'étiquette peut être expliquée par la formule de prédiction par la quantité de caractéristiques). Puisque la valeur est assez faible en puissance offensive et défensive, on peut dire que le nom de la carte représente à peine la puissance offensive et défensive (non pertinent).

4-2. Matrice de confusion

Pour voir la précision du problème de classification plus en détail, dessinez une matrice de confusion qui mappe les prédictions aux valeurs d'origine.

def make_cm(column, model, normalize="false"):
    labels = y[column].unique()
    y_pred = model.predict(X_test)
    cm = confusion_matrix(y_test[column], y_pred, labels=labels, normalize=normalize)
    cm_labeled = pd.DataFrame(cm, columns=labels, index=labels)
    f, ax = plt.subplots(figsize = (20, 10))
    ax = sns.heatmap(cm_labeled, annot=True, cmap="YlGnBu", fmt=".2f")
    ax.set_ylabel("Actual")
    ax.set_xlabel("Predicted")
    ax.set_title("confusion_matrix: {}".format(column))

make_cm("attr", model_attr, "pred")
plt.savefig('./output/ml4-2-1.png', bbox_inches='tight', pad_inches=0)

make_cm("level", model_level, "pred")
plt.savefig('./output/ml4-2-2.png', bbox_inches='tight', pad_inches=0)

make_cm("level", model_level, "pred")
plt.savefig('./output/ml4-2-3.png', bbox_inches='tight', pad_inches=0)

ml4-2-1.png

ml4-2-2.png

ml4-2-3.png

Les valeurs de la matrice de confusion sont normalisées pour additionner jusqu'à 1 dans le sens des lignes. En d'autres termes, la valeur est la probabilité que ce qui était prévu pour être A soit en réalité A (= taux de précision «Précision»). Par exemple, dans le graphique du premier attribut, on lit qu'environ 58% des attributs d'obscurité prédits sont en fait des attributs d'obscurité.

En regardant les attributs, nous pouvons voir que les attributs du feu et de l'eau peuvent être prédits de manière relativement précise, peut-être parce que le nom de la carte a tendance à inclure directement ces informations. Quant aux races, le taux de compatibilité des reptiles et des dinosaures est également élevé. D'un autre côté, on peut comprendre que la prédiction de la tribu psychique a tendance à être prédite à tort même pour ce qui était en fait une tribu mécanique.

À première vue, il semble qu'il existe des étiquettes qui permettent de prédire le niveau avec précision, mais afin de vérifier le problème (le modèle qui prédit le niveau 4 est terminé), il est nécessaire de vérifier le taux de rappel «Rappel». .. Le rappel est une valeur qui indique le pourcentage de ce qui est réellement étiqueté A qui est correctement prédit comme A. L'image ci-dessous est une matrice de confusion qui montre le rappel en modifiant les paramètres du tracé de niveau, mais il a également été confirmé que la plupart des niveaux étaient prédits à 4.

ml4-2-6.png

Jusqu'à présent, nous avons expliqué des indicateurs déroutants tels que le taux de réponse correct «Précision», le taux de précision «Précision», le taux de rappel «Rappel», mais pour plus de détails, voir [Pour les débutants] Explication des indicateurs d'évaluation des problèmes de classification pour l'apprentissage automatique (taux de réponse correct / (Taux de conformité, taux de rappel, etc.).

5. Prévisions

Implémentez le processus de prédiction des attributs offensifs et défensifs pour les nouveaux noms de cartes qui ne figurent pas dans l'ensemble de données. Le nouveau nom de la carte à saisir est également prétraité (vectorisé) de la même manière que pendant l'apprentissage, et ils sont prédits en appliquant la méthode «prédire» de chaque modèle. La fonction de prétraitement get_vec () effectue le processus d'analyse morphologique de mot → vectorisation à l'aide du modèle doc2vec. C'est fondamentalement le même que le processus de génération de la fonctionnalité X dans l'édition NLP.

python


#Fonction qui pré-traite le nom de la carte
def get_vec(rawtext):
    m = MeCab.Tagger ("-Ochasen -d /usr/local/lib/mecab/dic/mecab-ipadic-neologd/")
    lines = []
    text_list = rawtext.split("・")
    
    for text in text_list:
        keitaiso = []
        m.parse('')
        node = m.parseToNode(text)
        while node:
            #Mettre la morphologie dans le dictionnaire
            tmp = {}
            tmp['surface'] = node.surface
            tmp['base'] = node.feature.split(',')[-3] #Prototype(base)
            tmp['pos'] = node.feature.split(',')[0] #Partie(pos)
            tmp['pos1'] = node.feature.split(',')[1] #Reclassement de mot partiel(pos1)
            
            #BOS représentant le début et la fin d'une phrase/Omettre EOS
            if 'BOS/EOS' not in tmp['pos']:
                keitaiso.append(tmp)
                
            node = node.next
        lines.append(keitaiso)
    
    #Stockez le système de surface pour la nomenclature et la forme originale pour les verbes / adjectifs dans la liste.
    word_list = [] 
    for line in lines:
        for keitaiso in line:
            if (keitaiso['pos'] == 'nom'):
                word_list.append(keitaiso['surface'])
            elif  (keitaiso['pos'] == 'verbe') | (keitaiso['pos'] == 'adjectif') :
                if not keitaiso['base'] == '*' :
                    word_list.append(keitaiso['base'])
                else: 
                    word_list.append(keitaiso['surface'])
#Décommenter si vous incluez la nomenclature, les verbes et les adjectifs
#             else:
#                 word_list.append(keitaiso['surface'])

    model_d2v = pickle.load(open('./input/model_d2v.pickle', 'rb'))
    vec = model_d2v.infer_vector(word_list).reshape(1,-1)

    return vec

#Une fonction qui prédit d'autres informations à partir du nom de la carte à la fois
def predict_cardinfo(name):
    vec=get_vec(name)
    print("attribut:{}".format(model_attr.predict(vec)[0]))
    print("niveau:{}".format(model_level.predict(vec)[0]))
    print("Course:{}".format(model_species.predict(vec)[0]))
    print("Puissance offensive:{}".format(model_attack.predict(vec)[0]))
    print("Puissance défensive:{}".format(model_defence.predict(vec)[0]))

Prédisons en fait différents noms de cartes avec la méthode predict_cardinfo ().

** Dragon blanc aux yeux bleus **

python


predict_cardinfo("Dragon blanc aux yeux bleus")
Attribut: attribut Light
Niveau: 4
Race: Dragon
Puissance d'attaque: 1916.3930197124996
Puissance défensive: 1366.9371594605982

** Dragon blanc aux yeux rouges **

python


predict_cardinfo("Dragon blanc aux yeux rouges")
Attribut: attribut de la Terre
Niveau: 4
Race: guerrier
Puissance d'attaque: 1168.203405707642
Puissance défensive: 1007.5706886946783

** Magicien rouge **

python


predict_cardinfo("Magicien rouge")
Attribut: attribut sombre
Niveau: 4
Race: sorciers
Puissance d'attaque: 1884.3345074514568
Puissance défensive: 1733.53872077943

** Magicien Ultra Super Chaos **

python


predict_cardinfo("Magicien Ultra Super Chaos")
Attribut: attribut sombre
Niveau: 4
Race: sorciers
Puissance d'attaque: 2129.5019817399634
Puissance défensive: 1623.7306977987516

Pour des mots tels que «dragon» et «magicien», nous pouvons prédire «tribu de dragon» et «tribu de sorcière» presque comme prévu. Les puissances offensives et défensives ont tendance à être tirées par les données des monstres de bas niveau et ont des valeurs faibles, mais même ainsi, il semble qu'elles aient tendance à augmenter un peu en utilisant des mots forts tels que «chaos». Quant au niveau, comme le confirme la matrice de confusion, il est prédit quasiment au niveau 4. Cette fonction peut également prédire des noms sans précédent dans lesquels les mots sont utilisés. Je pense qu'il serait intéressant de le prendre du nom de Pikachu ou d'autres jeux.

Annexe. Réglage des hyper paramètres

Bien que l'implémentation soit omise cette fois, il est pratique d'utiliser ʻOptuna lors du réglage des hyper paramètres. ʻOptuna ne semble pas prendre en charge l'interface sciki-learn à partir de juillet 2020, mais un exemple d'implémentation en supposant l'interface d'origine est décrit comme un exemple de référence.

import optuna.integration.lightgbm as lgb_o
def get_best_params(column, mode, metric):
    y_obj = y[column]
    X_trainval, X_test, y_trainval, y_test = train_test_split(X, y_obj, test_size=0.2)
    X_train, X_valid, y_train, y_valid = train_test_split(X_trainval, y_trainval, test_size=0.1)

    #Convertir en un ensemble de données pour LightGBM
    train = lgb_o.Dataset(X_train, y_train)
    val = lgb_o.Dataset(X_valid, y_valid)

    #Recherche d'hyper paramètres&Construction de modèles
    if mode == "regression":
        params = {'objective': '{}'.format(mode),
                  'metric': '{}'.format(metric),
                  'random_seed':0} 
    elif mode == "multiclass":
        params = {'objective': '{}'.format(mode),
          'metric': '{}'.format(metric),
          'num_class': len(y_obj.unique()),
          'random_seed':0} 

    model_o = lgb_o.train(params,
                        train,
                        valid_sets=val,
                        early_stopping_rounds=10,
                        verbose_eval=False)

    y_trainval_pred = model_o.predict(X_trainval,num_iteration=gbm_o.best_iteration)
    y_test_pred = model_o.predict(X_test,num_iteration=gbm_o.best_iteration)

    best_params = model_o.params
    return best_params

best_params_attack = get_best_params("attack", "regression", "rmse")

Résumé

Nous avons implémenté un modèle qui prédit les attributs, la race, le niveau, la puissance offensive et la puissance défensive à partir du nom de la carte Yugioh. Surtout pour les attributs et les races, nous avons pu confirmer la précision des prévisions comme prévu. Pour Todo, l'encapsulation par les fonctions d'apprentissage automatique est un peu difficile, donc la meilleure pratique de conversion Pipeline est de procéder à l'apprentissage. De plus, si vous participez à une compétition comme Kaggle, je pense que vous devriez mettre en œuvre l'évaluation de l'exactitude plus soigneusement. Dans une autre direction, il semble intéressant d'en faire une application web avec Django etc. et de la publier.

Aperçu de la prochaine fois

L'implémentation en tant que data science sera la dernière de cet article, mais quand j'aurai le temps, je pourrai publier un article sur 0. Scraping. Le scraping de données est un sujet problématique, donc je ne vais pas fournir le code complet, juste les conseils de mise en œuvre.

Recommended Posts

Prédire les attributs offensifs et défensifs à partir du nom de la carte Yugioh --Yugiou Data Science 3. Machine Learning
J'ai essayé de traiter et de transformer l'image et d'élargir les données pour l'apprentissage automatique
Machine Learning avec docker (40) avec anaconda (40) "Hands-On Data Science and Python Machine Learning" Par Frank Kane
Étudiez l'apprentissage automatique et l'informatique. Liste des ressources
Visualisez les données de la carte Yugioh avec Python --Yugiou Data Science 1. EDA Edition
Division des données de formation en apprentissage automatique et apprentissage / prédiction / vérification
Prédire le temps objectif d'un marathon complet avec l'apprentissage automatique-③: j'ai essayé de visualiser les données avec Python-
Programmation Python Machine Learning Chapitre 1 donne aux ordinateurs la possibilité d'apprendre à partir du résumé des données
[Apprentissage automatique] Comprendre la SVM à la fois à partir de scikit-learn et des mathématiques
Pip la bibliothèque d'apprentissage automatique à partir d'une extrémité (Ubuntu)
Une méthode concrète pour prédire les courses de chevaux et simuler le taux de récupération par apprentissage automatique
J'ai considéré la méthode d'apprentissage automatique et son langage d'implémentation à partir des informations de balise de Qiita