Conjunto de entrenamiento / prueba / validación División en Sklearn

59

¿Cómo podría dividir aleatoriamente una matriz de datos y el vector de etiqueta correspondiente en un X_train, X_test, X_val, y_train, y_test, y_val con Sklearn? Que yo sepa, sklearn.cross_validation.train_test_splitsolo es capaz de dividirse en dos, no en tres ...

Hendrik
fuente

Respuestas:

81

Podrías usar solo sklearn.model_selection.train_test_splitdos veces. Primero dividir para entrenar, probar y luego dividir el tren nuevamente en validación y entrenar. Algo como esto:

 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
fuente
1
Sí, esto funciona, por supuesto, pero esperaba algo más elegante;) No importa, acepto esta respuesta.
Hendrik
1
Quería agregar que si desea utilizar el conjunto de validación para buscar los mejores hiperparámetros
skd
12
Entonces, ¿cuál es la proporción final de tren, prueba y validación en este ejemplo? Porque en el segundo train_test_split , estás haciendo esto durante la división 80/20 anterior. Entonces su valor es 20% de 80%. Las proporciones divididas no son muy sencillas de esta manera.
Monica Heddneck
1
Estoy de acuerdo con @Monica Heddneck en que el 64% del tren, el 16% de validación y el 20% de prueba splt podrían ser más claros. Es una inferencia molesta que debes hacer con esta solución.
Perry
33

Hay una gran respuesta a esta pregunta sobre SO que usa numpy y pandas.

El comando (ver la respuesta para la discusión):

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

produce una división del 60%, 20%, 20% para conjuntos de entrenamiento, validación y prueba.

0_0
fuente
2
Puedo ver el .6significado 60% ... pero ¿qué .8significa?
Tom Hale
1
@TomHale np.splitse dividirá al 60% de la longitud de la matriz aleatoria, luego al 80% de la longitud (que es un 20% adicional de datos), dejando así un 20% restante de los datos. Esto se debe a la definición de la función. Puedes probar / jugar con:, x = np.arange(10.0)seguido denp.split(x, [ int(len(x)*0.6), int(len(x)*0.8)])
0_0
3

En la mayoría de los casos, no se dividirá una vez, pero en un primer paso dividirá sus datos en un conjunto de entrenamiento y prueba. Posteriormente, realizará una búsqueda de parámetros que incorpore divisiones más complejas, como la validación cruzada con un algoritmo de 'división de plegado en k' o 'omisión de una salida (LOO)'.

JLT
fuente
3

Puedes usar train_test_splitdos veces. Creo que esto es más sencillo.

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 esta manera, train, val, testconjunto será 60%, 20%, 20% del conjunto de datos, respectivamente.

David Jung
fuente
2

La mejor respuesta anterior no menciona que separarse dos veces usando train_test_splitno cambiar los tamaños de partición no dará la partición inicialmente prevista:

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

Luego, la parte de los conjuntos de validación y prueba en x_remain cambia y podría contarse como

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)

En esta ocasión, todas las particiones iniciales se guardan.

A.Ametov
fuente
1

Aquí hay otro enfoque (supone una división tripartita igual):

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

Esto puede hacerse más conciso, pero lo mantuve detallado para fines de explicación.

Vishal
fuente
0

Dado train_frac=0.8, esta función crea una división del 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
fuente
0

Agregando a la respuesta de @ hh32 , respetando las proporciones predefinidas como (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
fuente
0

Extensión de la respuesta de @ hh32 con relaciones preservadas.

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

Como el conjunto de datos restante se reduce después de la primera división, se deben calcular nuevas relaciones con respecto al conjunto de datos reducido resolviendo la ecuación:

RremainingRnew=Rold

Jorge Barrios
fuente