Train / Test / Validation Set Divisione in Sklearn


59

Come potrei dividere casualmente una matrice di dati e il corrispondente vettore di etichetta in X_train, X_test, X_val, y_train, y_test, y_val con Sklearn? Per quanto ne so, sklearn.cross_validation.train_test_splitè solo in grado di dividersi in due, non in tre ...

Risposte:


81

Potresti usare solo sklearn.model_selection.train_test_splitdue volte. Prima di dividere per allenarsi, testare e poi dividere nuovamente il treno in convalida e treno. Qualcosa come questo:

 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)

1
Sì, questo funziona ovviamente, ma speravo in qualcosa di più elegante;) Non importa, accetto questa risposta.
Hendrik,

1
Volevo aggiungere che, se si desidera utilizzare il set di validazione per cercare i migliori iper-parametri che è possibile effettuare le seguenti operazioni dopo la scissione: gist.github.com/albertotb/1bad123363b186267e3aeaa26610b54b
SKD

12
Quindi qual è il treno finale, il test, la proporzione di validazione in questo esempio? Perché nel secondo train_test_split , lo stai facendo nella precedente divisione 80/20. Quindi il tuo valore è del 20% dell'80%. Le proporzioni divise non sono molto semplici in questo modo.
Monica Heddneck,

1
Concordo con @Monica Heddneck sul fatto che il 64% di treni, il 16% di convalida e il 20% di test splt potrebbero essere più chiari. È un'inferenza fastidiosa che devi fare con questa soluzione.
Perry, il

33

C'è un'ottima risposta a questa domanda su SO che usa intorpidimento e panda.

Il comando (vedi la risposta per la discussione):

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

produce una divisione del 60%, 20%, 20% per training, validazione e set di test.


2
Posso vedere il .6significato del 60% ... ma cosa .8significa?
Tom Hale,

1
@TomHale np.splitsi dividerà al 60% della lunghezza dell'array mischiato, quindi all'80% della lunghezza (che rappresenta un ulteriore 20% dei dati), lasciando così un restante 20% dei dati. Ciò è dovuto alla definizione della funzione. Puoi provare / giocare con x = np.arange(10.0)np.split(x, [ int(len(x)*0.6), int(len(x)*0.8)])
:,

3

Molto spesso ti ritroverai a non dividerlo una volta, ma in una prima fase dividerai i tuoi dati in un set di training e test. Successivamente eseguirai una ricerca di parametri che incorpora suddivisioni più complesse come la convalida incrociata con un algoritmo 'split k-fold' o 'leave-one-out (LOO)'.


3

Puoi usarlo train_test_splitdue volte. Penso che questo sia molto semplice.

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)

In questo modo, train, val, testinsieme sarà 60%, 20%, 20% del set di dati, rispettivamente.


2

La migliore risposta sopra non menziona il fatto che separando due volte usando train_test_splitnon cambiando le dimensioni della partizione non darà partizione inizialmente prevista:

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

Quindi la parte di convalida e set di test nella modifica x_remain può essere conteggiata come

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 questa occasione vengono salvate tutte le partizioni iniziali.


1

Ecco un altro approccio (presuppone una divisione a tre vie uguale):

# 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:]

Questo può essere reso più conciso, ma l'ho tenuto dettagliato per scopi esplicativi.


0

Dato train_frac=0.8, questa funzione crea una divisione dell'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

0

Aggiungendo alla risposta di @hh32 , nel rispetto di eventuali proporzioni predefinite come (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)

0

Estensione della risposta di @hh32 con rapporti conservati.

# 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)

Poiché il set di dati rimanente viene ridotto dopo la prima divisione, i nuovi rapporti rispetto al set di dati ridotto devono essere calcolati risolvendo l'equazione:

RremainingRnew=Rold

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.