web-dev-qa-db-fra.com

Comment diviser/partitionner un jeu de données en jeux de données d'apprentissage et de test pour, par exemple, une validation croisée?

Quel est le bon moyen de diviser un tableau NumPy de manière aléatoire en un ensemble de données d'apprentissage et de test/validation? Quelque chose de semblable aux fonctions cvpartition ou crossvalind dans Matlab.

78
erik

Si vous souhaitez fractionner le jeu de données une fois en deux moitiés, vous pouvez utiliser numpy.random.shuffle ou numpy.random.permutation si vous devez suivre les index:

import numpy
# x is your dataset
x = numpy.random.Rand(100, 5)
numpy.random.shuffle(x)
training, test = x[:80,:], x[80:,:]

ou

import numpy
# x is your dataset
x = numpy.random.Rand(100, 5)
indices = numpy.random.permutation(x.shape[0])
training_idx, test_idx = indices[:80], indices[80:]
training, test = x[training_idx,:], x[test_idx,:]

Il existe de nombreuses manières de partitionner plusieurs fois le même jeu de données pour une validation croisée . Une stratégie consiste à rééchantillonner à partir du jeu de données, avec répétition:

import numpy
# x is your dataset
x = numpy.random.Rand(100, 5)
training_idx = numpy.random.randint(x.shape[0], size=80)
test_idx = numpy.random.randint(x.shape[0], size=20)
training, test = x[training_idx,:], x[test_idx,:]

Enfin, sklearn contient plusieurs méthodes de validation croisée (k-fold, leave-n-out, ...). Il inclut également des méthodes "d'échantillonnage stratifié" plus avancées qui créent une partition des données équilibrée par rapport à certaines caractéristiques, par exemple pour s'assurer que la formation contient la même quantité d'exemples positifs et négatifs. ensemble d'essai.

89
pberkes

Une autre option consiste simplement à utiliser scikit-learn. Comme décrit dans le wiki de scikit , vous pouvez simplement utiliser les instructions suivantes:

from sklearn.model_selection import train_test_split

data, labels = np.arange(10).reshape((5, 2)), range(5)

data_train, data_test, labels_train, labels_test = train_test_split(data, labels, test_size=0.20, random_state=42)

De cette façon, vous pouvez synchroniser les étiquettes des données que vous essayez de scinder en formations et tests.

40
Paulo Malvar

Juste une note. Si vous souhaitez former, tester et valider des ensembles, vous pouvez le faire:

from sklearn.cross_validation import train_test_split

X = get_my_X()
y = get_my_y()
x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
x_test, x_val, y_test, y_val = train_test_split(x_test, y_test, test_size=0.5)

Ces paramètres donneront 70% à la formation, et 15% chacun pour tester et valider des ensembles. J'espère que cela t'aides. 

31
offwhitelotus

Le module sklearn.cross_validation étant obsolète, vous pouvez utiliser:

import numpy as np
from sklearn.model_selection import train_test_split
X, y = np.arange(10).reshape((5, 2)), range(5)

X_trn, X_tst, y_trn, y_tst = train_test_split(X, y, test_size=0.2, random_state=42)
9
M. Mashaye

Vous pouvez également envisager une division stratifiée en un ensemble d’entraînement et d’essai. La division Startified génère également des ensembles d’entraînement et de test de manière aléatoire, mais de manière à préserver les proportions de classe originales. Cela permet aux ensembles de formation et de test de mieux refléter les propriétés du jeu de données d'origine.

import numpy as np  

def get_train_test_inds(y,train_proportion=0.7):
    '''Generates indices, making random stratified split into training set and testing sets
    with proportions train_proportion and (1-train_proportion) of initial sample.
    y is any iterable indicating classes of each observation in the sample.
    Initial proportions of classes inside training and 
    testing sets are preserved (stratified sampling).
    '''

    y=np.array(y)
    train_inds = np.zeros(len(y),dtype=bool)
    test_inds = np.zeros(len(y),dtype=bool)
    values = np.unique(y)
    for value in values:
        value_inds = np.nonzero(y==value)[0]
        np.random.shuffle(value_inds)
        n = int(train_proportion*len(value_inds))

        train_inds[value_inds[:n]]=True
        test_inds[value_inds[n:]]=True

    return train_inds,test_inds

y = np.array([1,1,2,2,3,3])
train_inds,test_inds = get_train_test_inds(y,train_proportion=0.5)
print y[train_inds]
print y[test_inds]

Ce code affiche:

[1 2 3]
[1 2 3]
4
Apogentus

Merci pberkes pour ta réponse. Je viens de le modifier pour éviter (1) le remplacement lors de l'échantillonnage (2) des instances dupliquées se sont produites à la fois lors de la formation et des tests:

training_idx = np.random.choice(X.shape[0], int(np.round(X.shape[0] * 0.8)),replace=False)
training_idx = np.random.permutation(np.arange(X.shape[0]))[:np.round(X.shape[0] * 0.8)]
    test_idx = np.setdiff1d( np.arange(0,X.shape[0]), training_idx)
0
Zahran

J'ai écrit une fonction pour mon propre projet pour le faire (il n'utilise pas numpy, cependant):

def partition(seq, chunks):
    """Splits the sequence into equal sized chunks and them as a list"""
    result = []
    for i in range(chunks):
        chunk = []
        for element in seq[i:len(seq):chunks]:
            chunk.append(element)
        result.append(chunk)
    return result

Si vous voulez que les morceaux soient randomisés, il suffit de mélanger la liste avant de la transmettre.

0
Colin

Voici un code pour fractionner les données en n = 5 plis de manière stratifiée

% X = data array
% y = Class_label
from sklearn.cross_validation import StratifiedKFold
skf = StratifiedKFold(y, n_folds=5)
for train_index, test_index in skf:
    print("TRAIN:", train_index, "TEST:", test_index)
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
0
prashanth

Après avoir lu un peu et pris en compte les nombreuses (nombreuses ..) façons de diviser les données pour former et tester, j'ai décidé de le faire!

J'ai utilisé 4 méthodes différentes (aucune d'entre elles n'utilise la bibliothèque Sklearn, ce qui, j'en suis sûr, donnera les meilleurs résultats, car il s'agit d'un code bien conçu et testé):

  1. mélanger toute la matrice arr puis diviser les données pour former et tester
  2. mélanger les indices, puis attribuez-lui x et y pour diviser les données
  3. identique à la méthode 2, mais de manière plus efficace
  4. utiliser des données de pandas pour scinder

la méthode 3 a gagné de loin avec le temps le plus court, après cette méthode 1, et les méthodes 2 et 4 se sont révélées vraiment inefficaces.

Le code pour les 4 méthodes différentes que j'ai chronométrées:

import numpy as np
arr = np.random.Rand(100, 3)
X = arr[:,:2]
Y = arr[:,2]
spl = 0.7
N = len(arr)
sample = int(spl*N)

#%% Method 1:  shuffle the whole matrix arr and then split
np.random.shuffle(arr)
x_train, x_test, y_train, y_test = X[:sample,:], X[sample:, :], Y[:sample, ], Y[sample:,]

#%% Method 2: shuffle the indecies and then shuffle and apply to X and Y
train_idx = np.random.choice(N, sample)
Xtrain = X[train_idx]
Ytrain = Y[train_idx]

test_idx = [idx for idx in range(N) if idx not in train_idx]
Xtest = X[test_idx]
Ytest = Y[test_idx]

#%% Method 3: shuffle indicies without a for loop
idx = np.random.permutation(arr.shape[0])  # can also use random.shuffle
train_idx, test_idx = idx[:sample], idx[sample:]
x_train, x_test, y_train, y_test = X[train_idx,:], X[test_idx,:], Y[train_idx,], Y[test_idx,]

#%% Method 4: using pandas dataframe to split
import pandas as pd
df = pd.read_csv(file_path, header=None) # Some csv file (I used some file with 3 columns)

train = df.sample(frac=0.7, random_state=200)
test = df.drop(train.index)

Et pour les temps, le temps minimum pour exécuter sur 3 répétitions de 1000 boucles est:

  • Méthode 1: 0,35883826200006297 secondes
  • Méthode 2: 1.7157016959999964 secondes
  • Méthode 3: 1,7876616719995582 secondes
  • Méthode 4: 0,0756286149999141413 secondes

J'espère que c'est utile!

0
rotem