Aufteilen von Zug- / Test- / Validierungssätzen in Sklearn

59

Wie könnte ich mit Sklearn eine Datenmatrix und den entsprechenden Beschriftungsvektor zufällig in einen X_train, X_test, X_val, y_train, y_test, y_val aufteilen? Soweit ich weiß, sklearn.cross_validation.train_test_splitist nur in der Lage, in zwei, nicht in drei zu spalten ...

Hendrik
quelle

Antworten:

81

Sie könnten nur sklearn.model_selection.train_test_splitzweimal verwenden. Zuerst in Training aufteilen, testen und dann wieder in Validierung und Training aufteilen. Etwas wie das:

 X_train, X_test, y_train, y_test 
    = train_test_split(X, y, test_size=0.2, random_state=1)

 X_train, X_val, y_train, y_val 
    = train_test_split(X_train, y_train, test_size=0.2, random_state=1)
hh32
quelle
1
Ja, das funktioniert natürlich, aber ich habe mir etwas eleganteres erhofft;) Egal, ich akzeptiere diese Antwort.
Hendrik
1
Ich wollte hinzufügen, dass, wenn Sie den Validierungssatz verwenden möchten, um nach den besten Hyperparametern
skd 06.06.18
12
Wie hoch ist der endgültige Zug-, Test- und Validierungsanteil in diesem Beispiel? Denn im zweiten train_test_split Fall machen Sie dies über den vorherigen 80/20 Split. Ihr Wert beträgt also 20% von 80%. Die aufgeteilten Proportionen sind auf diese Weise nicht sehr einfach.
Monica Heddneck
1
Ich stimme @Monica Heddneck zu, dass die 64% -Zug-, 16% -Validierungs- und 20% -Test-Aufteilung klarer sein könnten. Es ist eine lästige Schlussfolgerung, die Sie mit dieser Lösung ziehen müssen.
Perry,
32

Es gibt eine großartige Antwort auf diese Frage auf SO , die Numpy und Pandas verwendet.

Der Befehl (siehe die Antwort für die Diskussion):

train, validate, test = np.split(df.sample(frac=1), [int(.6*len(df)), int(.8*len(df))])

Erzeugt eine Aufteilung von 60%, 20%, 20% für Schulungs-, Validierungs- und Testsätze.

0_0
quelle
2
Ich kann die .6Bedeutung von 60% sehen ... aber was bedeutet das .8?
Tom Hale
1
@TomHale np.splitteilt sich auf 60% der Länge des gemischten Arrays auf, dann auf 80% der Länge (das sind zusätzliche 20% der Daten), sodass 20% der Daten übrig bleiben. Dies liegt an der Definition der Funktion. Sie können testen / spielen mit x = np.arange(10.0)np.split(x, [ int(len(x)*0.6), int(len(x)*0.8)])
:,
3

In den meisten Fällen teilen Sie Ihre Daten nicht einmal auf, sondern in einem ersten Schritt in einem Trainings- und Testset. Anschließend führen Sie eine Parametersuche durch, die komplexere Aufteilungen wie die Kreuzvalidierung mit einem "Split-K-Fold" - oder "Leave-One-Out (LOO)" -Algorithmus enthält.

JLT
quelle
3

Sie können train_test_splitzweimal verwenden. Ich denke, das ist sehr einfach.

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=1)
X_train, X_val, y_train, y_val = train_test_split(
    X_train, y_train, test_size=0.25, random_state=1)

Auf diese Weise wird train, val, testwird Set 60%, 20%, 20% des Datensatzes sind.

David Jung
quelle
2

Die beste obige Antwort erwähnt nicht, dass durch zweimaliges Trennen train_test_splitohne Änderung der Partitionsgrößen die ursprünglich vorgesehene Partition nicht erhalten wird:

x_train, x_remain = train_test_split(x, test_size=(val_size + test_size))

Dann ändert sich der Teil der Validierungs- und Testmengen in x_remain und kann als gezählt werden

new_test_size = np.around(test_size / (val_size + test_size), 2)
# To preserve (new_test_size + new_val_size) = 1.0 
new_val_size = 1.0 - new_test_size

x_val, x_test = train_test_split(x_remain, test_size=new_test_size)

In diesem Fall werden alle anfänglichen Partitionen gespeichert.

A. Metov
quelle
1

Hier ist ein anderer Ansatz (unter der Annahme einer gleichmäßigen Dreifachaufteilung):

# randomly shuffle the dataframe
df = df.reindex(np.random.permutation(df.index))

# how many records is one-third of the entire dataframe
third = int(len(df) / 3)

# Training set (the top third from the entire dataframe)
train = df[:third]

# Testing set (top half of the remainder two third of the dataframe)
test = df[third:][:third]

# Validation set (bottom one third)
valid = df[-third:]

Dies kann präziser formuliert werden, ich habe es jedoch zu Erklärungszwecken ausführlich gehalten.

Vishal
quelle
0

Vorausgesetzt train_frac=0.8, diese Funktion erzeugt eine Aufteilung von 80% / 10% / 10%:

import sklearn

def data_split(examples, labels, train_frac, random_state=None):
    ''' https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html
    param data:       Data to be split
    param train_frac: Ratio of train set to whole dataset

    Randomly split dataset, based on these ratios:
        'train': train_frac
        'valid': (1-train_frac) / 2
        'test':  (1-train_frac) / 2

    Eg: passing train_frac=0.8 gives a 80% / 10% / 10% split
    '''

    assert train_frac >= 0 and train_frac <= 1, "Invalid training set fraction"

    X_train, X_tmp, Y_train, Y_tmp = sklearn.model_selection.train_test_split(
                                        examples, labels, train_size=train_frac, random_state=random_state)

    X_val, X_test, Y_val, Y_test   = sklearn.model_selection.train_test_split(
                                        X_tmp, Y_tmp, train_size=0.5, random_state=random_state)

    return X_train, X_val, X_test,  Y_train, Y_val, Y_test
Tom Hale
quelle
0

Hinzufügen zu @ hh32s Antwort unter Berücksichtigung vordefinierter Proportionen wie (75, 15, 10):

train_ratio = 0.75
validation_ratio = 0.15
test_ratio = 0.10

# train is now 75% of the entire data set
# the _junk suffix means that we drop that variable completely
x_train, x_test, y_train, y_test = train_test_split(dataX, dataY, test_size=1 - train_ratio)

# test is now 10% of the initial data set
# validation is now 15% of the initial data set
x_val, x_test, y_val, y_test = train_test_split(x_test, y_test, test_size=test_ratio/(test_ratio + validation_ratio)) 

print(x_train, x_val, x_test)
Andrei Florea
quelle
0

Erweiterung der Antwort von @ hh32 mit beibehaltenen Verhältnissen.

# Defines ratios, w.r.t. whole dataset.
ratio_train = 0.8
ratio_val = 0.1
ratio_test = 0.1

# Produces test split.
x_remaining, x_test, y_remaining, y_test = train_test_split(
    x, y, test_size=test_ratio)

# Adjusts val ratio, w.r.t. remaining dataset.
ratio_remaining = 1 - ratio_test
ratio_val_adjusted = ratio_val / ratio_remaining

# Produces train and val splits.
x_train, x_val, y_train, y_val = train_test_split(
    x_remaining, y_remaining, test_size=ratio_val_adjusted)

Da der verbleibende Datensatz nach der ersten Aufteilung reduziert wird, müssen neue Verhältnisse in Bezug auf den reduzierten Datensatz berechnet werden, indem die folgende Gleichung gelöst wird:

RremeinichnichnGRnew=ROld

Jorge Barrios
quelle