Train / Test / Validation Set Fractionnement dans Sklearn

59

Comment pourrais-je scinder au hasard une matrice de données et le vecteur d'étiquette correspondant en un X_train, X_test, X_val, y_train, y_test, y_val avec Sklearn? Autant que je sache, sklearn.cross_validation.train_test_splitn'est capable que de se scinder en deux, pas en trois ...

Hendrik
la source

Réponses:

81

Vous pouvez simplement utiliser sklearn.model_selection.train_test_splitdeux fois. D'abord, diviser pour former, tester, puis diviser à nouveau le train en validation et former. Quelque chose comme ça:

 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
la source
1
Oui, cela fonctionne bien sûr, mais j'espérais quelque chose de plus élégant;) Laisse tomber, j'accepte cette réponse.
Hendrik
1
Je voulais ajouter que si vous souhaitez utiliser l'ensemble de validation pour rechercher les meilleurs hyper-paramètres que vous pouvez faire ce qui suit après la scission: gist.github.com/albertotb/1bad123363b186267e3aeaa26610b54b
SKD
12
Alors, quelle est la proportion finale de train, d’essai, de validation dans cet exemple? Parce que sur la seconde train_test_split , vous faites cela par rapport au précédent partage 80/20. Donc, votre val est de 20% à 80%. Les proportions divisées ne sont pas très simples de cette façon.
Monica Heddneck
1
Je conviens avec @Monica Heddneck que les 64% de formation de train, 16% de validation et 20% de test splt pourraient être plus clairs. C'est une inférence ennuyeuse que vous devez faire avec cette solution.
Perry le
33

Il y a une excellente réponse à cette question sur SO qui utilise numpy et pandas.

La commande (voir la réponse à la discussion):

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

produit une répartition de 60%, 20% et 20% pour les ensembles de formation, de validation et de test.

0_0
la source
2
Je peux voir la .6signification de 60% ... mais qu'est-ce que cela .8signifie?
Tom Hale
1
@TomHale np.splitdivisera à 60% de la longueur du tableau mélangé, puis à 80% de la longueur (ce qui représente 20% supplémentaires des données), laissant ainsi 20% restants des données. Cela est dû à la définition de la fonction. Vous pouvez tester / jouer avec x = np.arange(10.0)np.split(x, [ int(len(x)*0.6), int(len(x)*0.8)])
:,
3

La plupart du temps, vous ne vous séparerez pas une fois, mais dans un premier temps, vous diviserez vos données dans un ensemble de formation et de test. Par la suite, vous effectuerez une recherche de paramètres intégrant des découpages plus complexes, tels que la validation croisée avec un algorithme 'split k-fold' ou 'leave-one-out (LOO)'.

JLT
la source
3

Vous pouvez utiliser train_test_splitdeux fois. Je pense que c'est très simple.

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)

De cette façon, train, val, testensemble sera de 60%, 20%, 20% de l'ensemble de données respectivement.

David Jung
la source
2

La meilleure réponse ci-dessus ne mentionne pas qu'en séparant deux fois en utilisant une train_test_splittaille de partition ne changeant pas, on ne donnera pas la partition initialement prévue:

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

Ensuite, la partie des ensembles de validation et de test dans la modification x_remain peut être comptée comme

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)

A cette occasion, toutes les partitions initiales sont enregistrées.

A. Ametov
la source
1

Voici une autre approche (en supposant une séparation égale à trois):

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

Cela peut être plus concis, mais je l’ai gardé prolixe à des fins d’explication.

Vishal
la source
0

Étant donné que train_frac=0.8cette fonction crée un partage de 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
la source
0

Ajoutant à la réponse de @ hh32 , tout en respectant les proportions prédéfinies telles que (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
la source
0

Extension de la réponse de @ hh32 avec des ratios préservés.

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

Étant donné que le jeu de données restant est réduit après la première scission, de nouveaux ratios par rapport au jeu de données réduit doivent être calculés en résolvant l'équation suivante:

RremainingRnew=Rold

Jorge Barrios
la source