[PYTHON] Mémorandum sur la validation

J'oublierai trop la validation du modèle, voici donc un minimum de choses à retenir. Dans cet article, je vais aborder les principales méthodes de validation telles que la méthode d'exclusion et la validation croisée, ainsi que le traitement des données de séries chronologiques. Références: [Kaggle book](https://www.amazon.co.jp/Kaggle%E3%81%A7%E5%8B%9D%E3%81%A4%E3%83%87%E3%83% BC% E3% 82% BF% E5% 88% 86% E6% 9E% 90% E3% 81% AE% E6% 8A% 80% E8% A1% 93-% E9% 96% 80% E8% 84% 87 -% E5% A4% A7% E8% BC% 94 / dp / 4297108437 / ref = sr_1_1_sspa? __Mk_ja_JP =% E3% 82% AB% E3% 82% BF% E3% 82% AB% E3% 83% 8A & mots-clés = Kaggle % E3% 81% A7% E5% 8B% 9D% E3% 81% A4% E3% 83% 87% E3% 83% BC% E3% 82% BF% E5% 88% 86% E6% 9E% 90% E3 % 81% AE% E6% 8A% 80% E8% A1% 93 & qid = 1583042364 & sr = 8-1-SPONS & psc = 1 & APLS = ZW5jcnlwdGVkUXVhbGlmaWVyPUExTkhDNkExUTRFMzQ2JmVuY3J5cHRlZElkPUEwMzc3MjMyMzFUQ0g5SERIQ1BDSiZlbmNyeXB0ZWRBZElkPUFMT0hMWThLWFhJNDUmd2lkZ2V0TmFtZT1zcF9hdGYmYWN0aW9uPWNsaWNrUmVkaXJlY3QmZG9Ob3RMb2dDbGljaz10cnVl)

1. Préparation

1-1. Environnement

Le code de l'article a été confirmé pour fonctionner sur Windows-10, Python 3.7.3.

import platform

print(platform.platform())
print(platform.python_version())

1-2. Ensemble de données

Lisez les ensembles de données de régression et de classification binaire à partir de sklearn.datasets.

from sklearn import datasets
import numpy as np
import pandas as pd

#Ensemble de données pour la régression
boston = datasets.load_boston()
boston_X = pd.DataFrame(boston.data, columns=boston.feature_names)
boston_y = pd.Series(boston.target)

#Jeu de données de classification binar
cancer = datasets.load_breast_cancer()
cancer_X = pd.DataFrame(cancer.data, columns=cancer.feature_names)
cancer_y = pd.Series(cancer.target)

2. méthode hold-out

C'est la méthode la plus simple et la plus directe. Gardez-en quelques-uns pour validation et entraînez le modèle avec le reste. J'entends souvent "Divisons-le en 7: 3", mais quand on y pense, cela dépend de la quantité de données, donc il n'y a pas de ratio fixe. Les données de validation ne peuvent pas être utilisées pour l'apprentissage, donc si la quantité de données est petite, la validation croisée, etc., qui sera décrite plus tard, doit être envisagée, et inversement, si elle est énorme, la méthode d'exclusion doit être utilisée. Fondamentalement, mélangez et divisez les données. Cependant, il n'est pas mélangé lorsqu'il s'agit de données de séries chronologiques. En effet, il existe un risque d'apprendre (de fuir) des informations futures si elles sont mélangées tout en essayant de prédire l'avenir à partir d'informations passées. J'ai eu une erreur avec ça une fois. Vous trouverez ci-dessous le code qui divise les données en 3: 1 et les évalue avec un facteur de décision. En passant, les indices d'évaluation tels que le coefficient de détermination sont résumés dans ici avant.

from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split

tr_x, va_x, tr_y, va_y = train_test_split(boston_X, boston_y, test_size=0.25, random_state=2020, shuffle=True)
slr = LinearRegression()
slr.fit(tr_x, tr_y)
va_pred = slr.predict(va_x)
score = r2_score(va_y, va_pred)
print(score)

0.732147337324218

3. Validation croisée

Une méthode pour répéter plusieurs fois la méthode d'exclusion précédente. L'image est Rocket Empitsu. Après avoir évalué le modèle dans un bloc, l'étape suivante consiste à ajouter ce bloc aux données d'apprentissage, à l'évaluer dans un autre bloc, et ainsi de suite, et à répéter pour le nombre de blocs. Étant donné que les données de validation ne peuvent pas être utilisées pour l'apprentissage de la méthode d'exclusion, la validation croisée est souvent sélectionnée lorsque la quantité de données est faible. Lorsque le nombre de blocs = le nombre de plis augmente, les données d'apprentissage augmentent, mais le temps de calcul augmente également. Cela dépend également de la quantité de données, mais environ 4 ou 5 sont courants. Lors de l'évaluation de la précision (performance de généralisation) du modèle, regardez le score moyen de chaque pli ou calculez à nouveau le score avec les valeurs prédites de tous les plis. KFold.png Vous trouverez ci-dessous le code de validation croisée. Ce n'est pas aussi simple que la méthode hold-out, alors oubliez-le.

from sklearn.metrics import mean_absolute_error
from sklearn.model_selection import KFold

i = 0
scores = []
kf = KFold(n_splits=4, shuffle=True, random_state=2020)
for tr_idx, va_idx in kf.split(boston_X):
    i += 1
    tr_x, va_x = boston_X.iloc[tr_idx], boston_X.iloc[va_idx]
    tr_y, va_y = boston_y.iloc[tr_idx], boston_y.iloc[va_idx]
    slr = LinearRegression()
    slr.fit(tr_x, tr_y)
    va_pred = slr.predict(va_x)
    score = mean_absolute_error(va_y, va_pred)
    print('fold{}: {:.2f}'.format(i, score))
    scores.append(score)

print(np.mean(scores))

fold1: 3.34 fold2: 3.39 fold3: 3.89 fold4: 3.02 3.4098095699116184

La validation est maintenant terminée, mais il y a autant de modèles que de plis. Il doit être assemblé d'une manière ou d'une autre.

--Faites la moyenne de chaque modèle de pli.

Peu importe celui que vous utilisez, mais en pratique, vous devez enregistrer et exploiter le modèle créé dans ce dernier. 4. stratified k-fold C'est la méthode utilisée pour les tâches de classification. Par exemple, dans la tâche de classification comme négatif ou positif, s'il y a extrêmement peu de positifs, il peut arriver qu'il n'y ait pas de positif dans les données de validation après avoir divisé les données au hasard. Par conséquent, il y a une motivation pour effectuer un échantillonnage stratifié de sorte que la proportion de classes contenues dans chaque pli soit égale. Au contraire, si le ratio est équilibré, il n'y a pas grand chose à craindre. StratifiedKFold.png

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import log_loss
from sklearn.model_selection import StratifiedKFold

# hold-Également possible avec la méthode out
# tr_x, va_x, tr_y, va_y = train_test_split(cancer_X, cancer_y, test_size=0.25, random_state=2020, shuffle=True, stratify=cancer_y)

i = 0
scores = []
kf = StratifiedKFold(n_splits=4, shuffle=True, random_state=2020)
for tr_idx, va_idx in kf.split(cancer_X, cancer_y):
    i += 1
    tr_x, va_x = cancer_X.iloc[tr_idx], cancer_X.iloc[va_idx]
    tr_y, va_y = cancer_y.iloc[tr_idx], cancer_y.iloc[va_idx]
    lr = LogisticRegression(solver='liblinear')
    lr.fit(tr_x, tr_y)
    va_pred = lr.predict_proba(va_x)[:, 1]
    score = log_loss(va_y, va_pred)
    print('fold{}: {:.2f}'.format(i, score))
    scores.append(score)

print(np.mean(scores))

fold1: 0.11 fold2: 0.17 fold3: 0.09 fold4: 0.07 0.11030074372001544

5. Autre validation

A part ça, je ne l'ai pas utilisé, mais il y a quelque chose comme ça, donc je vais juste prendre note de la méthode. 5-1. group k-fold Une méthode de division des données par des variables qui représentent des groupes. Par exemple, dans le cas d'une tâche telle que l'apprentissage de l'historique des achats de chaque client et la notation de nouveaux clients, nous ne voulons pas que le même client coexiste dans les données de formation et les données de validation. En effet, on considère que certaines des réponses sont mélangées avec les données de formation (fuite). Par conséquent, lorsque vous souhaitez diviser les données à l'aide de l'ID client, effectuez le groupe k-fold. Vous pouvez utiliser une classe appelée GroupKFold. Cependant, il n'y a pas de fonction de mélange et d'ensemencement aléatoire. GroupKFold.png 5-2. leave-one-out (LOO) Je n'ai jamais utilisé cela non plus. Il y a extrêmement peu de données, et je veux augmenter le nombre de N autant que possible → Cela semble être une méthode radicale pour augmenter le nombre de plis par le nombre d'enregistrements. Tout ce que vous avez à faire est de spécifier le nombre d'enregistrements dans n_splits avec KFold, mais il existe également une classe dédiée appelée LeaveOneOut.

6. Validation des données de séries chronologiques

L'élément le plus important de cet article est peut-être que les techniques dont nous avons parlé jusqu'à présent ne doivent pas être utilisées directement pour les données de séries chronologiques. L'ancien / le nouveau est une information en soi, vous devez donc être conscient de la série chronologique lors de l'apprentissage ou de l'évaluation.

6-1. Ensemble de données

Étant donné que sklearn.datasets ne dispose pas des données de séries chronologiques appropriées, nous utiliserons les données [Question pratique] Prévisions de la demande pour le déjeuner de SIGNATE.

import matplotlib.pyplot as plt
%matplotlib inline

#Lecture des données
train = pd.read_csv('./train.csv')

#Exclure les anciennes données avec des tendances différentes
train.index = pd.to_datetime(train['datetime'])
train = train['2014-05-01':].copy()

#terrain
train['y'].plot(figsize=(15, 3))
plt.show()

#Création de fonctionnalités
train = train.reset_index(drop=True)
train['days'] = train.index
train['fun'] = train['remarks'].apply(lambda x: 1 if x == 'Menu amusant' else 0)
train['curry'] = train['name'].apply(lambda x: 1 if x.find('curry') >= 0 else 0)
train_X = train[['days', 'fun', 'curry']].copy()
train_y = train['y'].copy()

lunch1.png

Au fond, le nombre de ventes est en baisse (corrélation négative avec le nombre de jours), mais il est dopé lors des menus populaires (menu fun, curry). Jusqu'où pouvons-nous prédire avec une simple régression linéaire?

from sklearn.metrics import mean_squared_error

slr = LinearRegression()
slr.fit(train_X, train_y)
train['pred'] = slr.predict(train_X)
rmse = np.sqrt(mean_squared_error(train['y'], train['pred']))

print(rmse)
train.plot(y=['y', 'pred'], figsize=(15, 3))
plt.show()

10.548692191381326 lunch2.png

C'est assez bizarre, mais j'ai une idée approximative. Je reviendrai sur le sujet de la validation, avec un fort désir de voir la relation entre les résidus et d'autres quantités de caractéristiques.

6-2. Validation croisée des données de séries chronologiques

La méthode la plus simple est probablement la méthode non aléatoire. False doit être spécifié dans l'argument shuffle de la fonction train_test_split. En apprenant avec d'anciennes données et en évaluant avec de nouvelles données, même les données de séries chronologiques peuvent être validées sans problème. Cependant, il est toujours inutile de ne pas utiliser les données pour la formation qui reflètent très probablement les tendances les plus récentes ou les plus récentes. Par conséquent, si les performances de généralisation peuvent être confirmées, elles seront souvent réapprises avec toutes les données. Même ainsi, il y aura toujours des plaintes quant à savoir si la précision sera améliorée pour d'autres périodes, ou simplement la quantité de données est insuffisante, c'est-à-dire le désir d'utiliser les données plus efficacement. Par conséquent, une méthode appelée TimeSeries Split apparaît. L'idée elle-même est simple, bref, c'est une méthode de validation croisée par ordre chronologique. TimeSeriesSplit.png Cependant, même avec cela, je ne suis toujours pas satisfait du fait que les dernières données ne peuvent pas être utilisées et que la longueur des données d'entraînement diffère pour chaque pli. Mais il vaut mieux l'utiliser.

from sklearn.model_selection import TimeSeriesSplit

i = 0
scores = []
tss = TimeSeriesSplit(n_splits=4)
for tr_idx, va_idx in tss.split(train_X):
    i += 1
    tr_x, va_x = train_X.iloc[tr_idx], train_X.iloc[va_idx]
    tr_y, va_y = train_y.iloc[tr_idx], train_y.iloc[va_idx]
    slr = LinearRegression()
    slr.fit(tr_x, tr_y)
    va_pred = slr.predict(va_x)
    score = np.sqrt(mean_squared_error(va_y, va_pred))
    print('fold{}: {:.2f}'.format(i, score))
    scores.append(score)

print(np.mean(scores))

fold1: 20.29 fold2: 9.21 fold3: 15.05 fold4: 9.68 13.557202833084698

C'est un résultat difficile à juger. Il est intéressant de noter que la précision ne s'améliore pas à mesure que la quantité de données d'entraînement augmente. Il y a encore de la place pour l'expérimentation, mais cela dépasse le cadre de cet article et se termine ici.

Ainsi, la validation des données chronologiques est difficile à tirer des conclusions claires. En particulier, lorsqu'un changement de tendance se produit le plus récemment, il est exact que les données de validation ne peuvent pas être expliquées par les données d'apprentissage, mais on peut plutôt dire que le modèle doit être formé par les données de validation. Dans le système de contrôle, il est possible de surveiller la précision avec RMSE ou quelque chose, revenir à la commande existante lorsque le seuil est dépassé, réapprendre lorsque le nombre requis de données est accumulé et redémarrer la commande. Alternativement, l'idée peut être de continuer à mettre à jour le modèle avec l'apprentissage en ligne. Qu'en est-il du système de prévision de la demande? Puisqu'il n'est pas toujours nécessaire de prédire une certaine période comme une compétition, un modèle ARIMA qui considère l'autocorrélation à court terme peut être efficace. Je voudrais demander à l'équipe de prévision de la demande la prochaine fois.

Recommended Posts

Mémorandum sur la validation
Un mémorandum sur Nan.
fonction de mémorandum python pour débutant
Un mémorandum sur le simulacre de Python
À propos de LangID
À propos de CAGR
Mémorandum / mémo sur le site de programmation d'apprentissage / de programmation
mémorandum Linux
mémorandum jinja2
À propos de virtiofs
À propos de python-apt
À propos de l'autorisation
À propos de sklearn.preprocessing.Imputer
À propos de Gunicorn
Mémorandum Python
Mémorandum Django
À propos de requirements.txt
À propos des paramètres régionaux
Mémorandum de commandement
Mémorandum Python 2
Mémorandum sur les paramètres de régression et de classification binomiale
À propos de l'axe = 0, axe = 1
mémorandum complot
Mémorandum Slackbot (1)
Mémorandum des débutants en python
mémorandum de multitraitement
Mémorandum MetaTrader5
Mémorandum sur le QueryDict de Django
Mémorandum ShellScript
mémorandum pip
Mémorandum Python
À propos de numpy
À propos de pip
mémorandum pydoc
Mémorandum de Pandas
mémorandum python
À propos de numpy.newaxis
À propos d'Endian
Mémorandum de commandement
Mémorandum de base Python Partie 3-A propos de l'orientation des objets-
À propos de Linux
À propos de l'importation
Mémorandum Python
mémorandum pandas
À propos de Linux
Mémorandum Python
À propos de Linux
À propos de cv2.imread
À propos de _ et __
À propos de wxPython
Un mémorandum sur la bibliothèque de wrapper Python tesseract