[PYTHON] Memorandum über die Validierung

Ich werde zu viel über die Modellvalidierung vergessen, daher hier ein Minimum an Dingen, an die man sich erinnern sollte. In diesem Artikel werde ich auf die wichtigsten Validierungsmethoden wie Hold-out-Methode und Kreuzvalidierung sowie den Umgang mit Zeitreihendaten eingehen. Referenzen: [Kaggle-Buch](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 & Schlüsselwörter = 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 & sPLA = ZW5jcnlwdGVkUXVhbGlmaWVyPUExTkhDNkExUTRFMzQ2JmVuY3J5cHRlZElkPUEwMzc3MjMyMzFUQ0g5SERIQ1BDSiZlbmNyeXB0ZWRBZElkPUFMT0hMWThLWFhJNDUmd2lkZ2V0TmFtZT1zcF9hdGYmYWN0aW9uPWNsaWNrUmVkaXJlY3QmZG9Ob3RMb2dDbGljaz10cnVl)

1. Vorbereitung

1-1. Umgebung

Es wurde bestätigt, dass der Code im Artikel unter Windows-10, Python 3.7.3 funktioniert.

import platform

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

1-2. Datensatz

Lesen Sie Regressions- und binäre Klassifizierungsdatensätze aus sklearn.datasets.

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

#Datensatz für die Regression
boston = datasets.load_boston()
boston_X = pd.DataFrame(boston.data, columns=boston.feature_names)
boston_y = pd.Series(boston.target)

#Binar-Klassifizierungsdatensatz
cancer = datasets.load_breast_cancer()
cancer_X = pd.DataFrame(cancer.data, columns=cancer.feature_names)
cancer_y = pd.Series(cancer.target)

2. Hold-out-Methode

Dies ist die einfachste und einfachste Methode. Speichern Sie einige zur Validierung und trainieren Sie das Modell mit dem Rest. Ich höre oft "Teilen wir es in 7: 3", aber wenn Sie darüber nachdenken, hängt es von der Datenmenge ab, sodass es kein festes Verhältnis gibt. Validierungsdaten können nicht zum Lernen verwendet werden. Wenn also die Datenmenge gering ist, sollte eine Kreuzvalidierung usw. in Betracht gezogen werden, die später beschrieben wird. Umgekehrt sollte die Hold-out-Methode verwendet werden, wenn sie sehr groß ist. Grundsätzlich mischen und teilen Sie die Daten. Zeitreihendaten werden jedoch nicht gemischt. Dies liegt daran, dass das Risiko besteht, zukünftige Informationen zu lernen (zu verlieren), wenn diese gemischt werden, während versucht wird, die Zukunft anhand vergangener Informationen vorherzusagen. Ich hatte einmal einen Fehler damit. Unten finden Sie den Code, der die Daten in 3: 1 unterteilt und mit einem Entscheidungsfaktor bewertet. Übrigens sind die Bewertungsindizes wie der Bestimmungskoeffizient zuvor in hier zusammengefasst.

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. Kreuzvalidierung

Eine Methode zum mehrmaligen Wiederholen der vorherigen Hold-out-Methode. Das Bild ist Rocket Empitsu. Nach der Auswertung des Modells in einem Block besteht der nächste Schritt darin, diesen Block zu den Trainingsdaten hinzuzufügen, in einem anderen Block auszuwerten usw. und die Anzahl der Blöcke zu wiederholen. Da Validierungsdaten nicht für das Training in der Hold-out-Methode verwendet werden können, wird die Kreuzvalidierung häufig ausgewählt, wenn die Datenmenge gering ist. Wenn die Anzahl der Blöcke = die Anzahl der Falten zunimmt, nehmen die Trainingsdaten zu, aber auch die Berechnungszeit. Dies hängt auch von der Datenmenge ab, aber ungefähr 4 oder 5 sind üblich. Betrachten Sie bei der Bewertung der Genauigkeit (Generalisierungsleistung) des Modells entweder die durchschnittliche Punktzahl jeder Falte oder berechnen Sie die Punktzahl erneut mit den vorhergesagten Werten aller Falten. KFold.png Unten finden Sie den Kreuzvalidierungscode. Es ist nicht so einfach wie die Hold-Out-Methode, also vergiss es.

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

Die Validierung ist jetzt abgeschlossen, es gibt jedoch so viele Modelle wie Falten. Es muss irgendwie zusammengesetzt werden.

--Machen Sie den Durchschnitt jedes Falzmodells.

Es spielt keine Rolle, welches Sie verwenden, aber in der Praxis sollten Sie das in letzterem erstellte Modell speichern und betreiben. 4. stratified k-fold Dies ist die Methode für Klassifizierungsaufgaben. Zum Beispiel kann es bei der Aufgabe, als negativ oder positiv zu klassifizieren, bei extrem wenigen positiven Ergebnissen vorkommen, dass die Validierungsdaten nach zufälliger Aufteilung der Daten keine positiven enthalten. Daher besteht eine Motivation, eine geschichtete Stichprobe durchzuführen, damit der Anteil der in jeder Falte enthaltenen Klassen gleich ist. Im Gegenteil, wenn das Verhältnis ausgeglichen ist, gibt es nicht viel zu befürchten. StratifiedKFold.png

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

# hold-Auch mit der out-Methode möglich
# 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. Andere Validierung

Davon abgesehen habe ich es nicht benutzt, aber es gibt so etwas, also werde ich nur die Methode aufschreiben. 5-1. group k-fold Eine Methode zum Teilen von Daten durch Variablen, die Gruppen darstellen. Zum Beispiel möchten wir bei einer Aufgabe wie dem Lernen der Kaufhistorie jedes Kunden und dem Bewerten neuer Kunden nicht, dass derselbe Kunde in den Trainingsdaten und Validierungsdaten koexistiert. Dies liegt daran, dass davon ausgegangen wird, dass die Antwort teilweise mit den Trainingsdaten gemischt ist (Leck). Wenn Sie die Daten anhand der Kunden-ID teilen möchten, führen Sie daher die Gruppe k-fach aus. Sie können eine Klasse namens "GroupKFold" verwenden. Es gibt jedoch keine Shuffle- und Random-Seeding-Funktion. GroupKFold.png 5-2. leave-one-out (LOO) Ich habe das auch nie benutzt. Es gibt extrem wenig Daten, und ich möchte die Anzahl von N so weit wie möglich erhöhen. → Es scheint eine radikale Methode zu sein, die Anzahl der Falten um die Anzahl der Datensätze zu erhöhen. Sie müssen lediglich die Anzahl der Datensätze in n_splits mit KFold angeben. Es gibt jedoch auch eine dedizierte Klasse namens "LeaveOneOut".

6. Validierung von Zeitreihendaten

Das vielleicht Wichtigste in diesem Artikel ist, dass die Techniken, mit denen wir uns bisher befasst haben, nicht direkt für Zeitreihendaten verwendet werden sollten. Da Alt / Neu Information für sich ist, müssen Sie beim Lernen und Bewerten die Zeitreihen kennen.

6-1. Datensatz

Da sklearn.datasets nicht über die richtigen Zeitreihendaten verfügt, werden wir die Daten von SIGNATE ([Übungsfrage] Lunch Demand Forecast](https://signate.jp/competitions/24) verwenden.

import matplotlib.pyplot as plt
%matplotlib inline

#Daten gelesen
train = pd.read_csv('./train.csv')

#Schließen Sie alte Daten mit unterschiedlichen Trends aus
train.index = pd.to_datetime(train['datetime'])
train = train['2014-05-01':].copy()

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

#Feature-Erstellung
train = train.reset_index(drop=True)
train['days'] = train.index
train['fun'] = train['remarks'].apply(lambda x: 1 if x == 'Spaßmenü' 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

Grundsätzlich ist die Anzahl der Verkäufe rückläufig (negative Korrelation mit der Anzahl der Tage), sie wird jedoch bei beliebten Menüs (unterhaltsames Menü, Curry) erhöht. Wie weit können wir mit einer einfachen linearen Regression vorhersagen?

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

Es ist ziemlich falsch, aber ich habe eine ungefähre Vorstellung. Ich werde auf das Thema Validierung zurückkommen, mit dem starken Wunsch, die Beziehung zwischen den Residuen und anderen Merkmalsgrößen zu sehen.

6-2 Kreuzvalidierung von Zeitreihendaten

Am einfachsten ist wahrscheinlich die Nicht-Shuffle-Hold-Out-Methode. False sollte im Argument shuffle der Funktion train_test_split angegeben werden. Durch Lernen mit alten Daten und Auswerten mit neuen Daten können auch Zeitreihendaten problemlos validiert werden. Es ist jedoch immer noch eine Verschwendung, die Daten, die die neuesten oder neuesten Trends am besten widerspiegeln, nicht für Schulungen zu verwenden. Wenn die Generalisierungsleistung bestätigt werden kann, wird sie daher häufig mit allen Daten neu gelernt. Trotzdem wird es immer noch Beschwerden darüber geben, ob die Genauigkeit für andere Zeiträume verbessert wird oder einfach die Datenmenge nicht ausreicht, dh der Wunsch, die Daten effizienter zu nutzen. Daher wird eine Methode namens TimeSeries Split angezeigt. Die Idee selbst ist einfach, kurz gesagt, es handelt sich um eine Methode zur Kreuzvalidierung in chronologischer Reihenfolge. TimeSeriesSplit.png Trotzdem bin ich immer noch unzufrieden mit der Tatsache, dass die neuesten Daten nicht verwendet werden können und dass die Länge der Trainingsdaten für jede Falte unterschiedlich ist. Aber es ist besser, es zu benutzen.

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

Es ist ein Ergebnis, das schwer zu beurteilen ist. Es ist interessant, dass sich die Genauigkeit mit zunehmender Menge an Trainingsdaten nicht verbessert. Es gibt noch Raum zum Experimentieren, aber es geht über den Rahmen dieses Artikels hinaus und endet hier.

Die Validierung von Zeitreihendaten ist daher schwierig, eindeutige Schlussfolgerungen zu ziehen. Insbesondere wenn sich der Trend in letzter Zeit ändert, ist es richtig, dass die Trainingsdaten die Validierungsdaten nicht erklären können, sondern dass das Modell unter Verwendung der Validierungsdaten trainiert werden sollte. Im Steuerungssystem ist es möglich, die Genauigkeit mit RMSE oder etwas anderem zu überwachen, zur vorhandenen Steuerung zurückzukehren, wenn der Schwellenwert überschritten wird, neu zu lernen, wenn die erforderliche Anzahl von Daten akkumuliert ist, und die Steuerung neu zu starten. Alternativ könnte die Idee sein, das Modell mit Online-Lernen ständig zu aktualisieren. Was ist mit dem Bedarfsprognosesystem? Da es nicht immer notwendig ist, einen bestimmten Zeitraum wie einen Wettbewerb vorherzusagen, kann ein ARIMA-Modell, das eine kurzfristige Autokorrelation berücksichtigt, effektiv sein. Ich möchte das nächste Mal das Nachfrageprognoseteam fragen.

Recommended Posts

Memorandum über die Validierung
Ein Memorandum über Nan.
Python-Anfänger-Memorandum-Funktion
Ein Memorandum über den Python-Mock
Über LangID
Über CAGR
Memorandum / Memo über Programmieren Lern- / Wettbewerbsprogrammierungsseite
Linux Memorandum
jinja2 Memorandum
Über Tugenden
Über Python-Apt
Über die Erlaubnis
Über sklearn.preprocessing.Imputer
Über Gunicorn
Python-Memorandum
Django Memorandum
Informationen zu den Anforderungen.txt
Über das Gebietsschema
Befehlsmemorandum
Python-Memorandum 2
Memorandum über Metriken für Regression und Binomialklassifikation
Über Achse = 0, Achse = 1
Plotly Memorandum
Slackbot-Memorandum (1)
Memorandum von Python-Anfängern
Multiprocessing Memorandum
Memorandum MetaTrader5
Memorandum zu Djangos QueryDict
ShellScript-Memorandum
Pip Memorandum
Python-Memorandum
Über Numpy
Über pip
Pydoc Memorandum
Memorandum of Pandas
Python Memorandum
Über numpy.newaxis
Über Endian
Befehlsmemorandum
Python Basic Memorandum Teil 3 - Informationen zur Objektorientierung
Über Linux
Über den Import
Python-Memorandum
Pandas Memorandum
Über Linux
Python-Memorandum
Über Linux
Über cv2.imread
Über _ und __
Über wxPython
Ein Memorandum über die Python-Tesseract-Wrapper-Bibliothek