it-swarm.com.de

Wie kann ein Datensatz in Trainings- und Testdatensätze aufgeteilt/unterteilt werden, um beispielsweise eine Kreuzvalidierung durchzuführen?

Wie kann ein NumPy-Array nach dem Zufallsprinzip in Datensätze für Training und Test/Validierung aufgeteilt werden? Etwas ähnlich wie die cvpartition- oder crossvalind-Funktionen in Matlab.

78
erik

Wenn Sie den Datensatz einmal in zwei Hälften teilen möchten, können Sie numpy.random.shuffle oder numpy.random.permutation verwenden, wenn Sie die Indizes nachverfolgen müssen:

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

oder

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

Es gibt viele Möglichkeiten, denselben Datensatz wiederholt für die Kreuzvalidierung zu partitionieren . Eine Strategie besteht darin, aus der Datenmenge eine erneute Abtastung durchzuführen, mit Wiederholung:

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

Sklearn enthält mehrere Kreuzvalidierungsmethoden (k-fach, Leave-n-out, ...). Es enthält auch fortgeschrittenere "stratifizierte Stichprobenverfahren" , mit denen eine Partition der Daten erstellt wird, die in Bezug auf einige Merkmale abgeglichen ist, z. B. um sicherzustellen, dass im Training der gleiche Anteil an positiven und negativen Beispielen vorhanden ist Testsatz.

89
pberkes

Es gibt noch eine weitere Option, die nur Scikit-Learn beinhaltet. Wie das Wiki von scikit beschreibt, können Sie einfach die folgenden Anweisungen verwenden:

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)

Auf diese Weise können Sie die Bezeichnungen für die Daten, die Sie in Training und Test aufteilen möchten, synchron halten.

40
Paulo Malvar

Nur eine Notiz. Wenn Sie Schulungs-, Test- und Validierungssätze benötigen, können Sie Folgendes tun:

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)

Diese Parameter geben 70% für das Training und jeweils 15% für Test- und Val-Sets. Hoffe das hilft. 

31
offwhitelotus

Da das sklearn.cross_validation-Modul veraltet war, können Sie Folgendes verwenden:

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

Sie können auch eine stratifizierte Einteilung in Schulungs- und Testset in Betracht ziehen. Startified Division generiert auch Trainings- und Test-Sets nach dem Zufallsprinzip, jedoch so, dass die ursprünglichen Klassenverhältnisse erhalten bleiben. Dadurch können Schulungs- und Testsätze die Eigenschaften des ursprünglichen Datensatzes besser widerspiegeln.

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]

Dieser Code gibt aus:

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

Danke pberkes für deine Antwort. Ich habe es gerade modifiziert, um zu vermeiden, dass (1) während der Probenahme (2) doppelte Instanzen sowohl während des Trainings als auch beim Testen ersetzt werden:

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

Ich habe dazu eine Funktion für mein eigenes Projekt geschrieben (es wird jedoch kein numpy verwendet):

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

Wenn Sie möchten, dass die Chunks randomisiert werden, mischen Sie einfach die Liste, bevor Sie sie übergeben.

0
Colin

Hier ist ein Code zum Aufteilen der Daten in n = 5-fach geschichtet

% 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

Nachdem ich ein wenig gelesen und die (vielen ..) verschiedenen Arten der Aufteilung der zu trainierenden und zu testenden Daten berücksichtigt hatte, entschied ich mich für timeit!

Ich habe 4 verschiedene Methoden verwendet (von denen keine die Bibliothek sklearn verwenden, von der ich sicher bin, dass sie die besten Ergebnisse liefert, da es sich um gut gestalteten und getesteten Code handelt):

  1. mische den gesamten Matrix-Arr und teile dann die Daten auf, um zu trainieren und zu testen
  2. mische die Indizes und weise sie dann x und y zu, um die Daten zu teilen
  3. wie Methode 2, aber effizienter
  4. verwenden von Pandas-Datenrahmen zum Teilen

methode 3 gewann mit Abstand die kürzeste Zeit nach Methode 1, und Methode 2 und 4 stellten fest, dass sie wirklich ineffizient waren.

Der Code für die 4 verschiedenen Methoden, die ich zeitlich festgelegt habe:

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)

Die Mindestzeit für die Ausführung von 3 Wiederholungen von 1000 Schleifen beträgt:

  • Methode 1: 0,35883826200006297 Sekunden
  • Methode 2: 1,7157016959999964 Sekunden
  • Methode 3: 1.7876616719995582 Sekunden
  • Methode 4: 0,07562861499991413 Sekunden

Ich hoffe das ist hilfreich!

0
rotem