webentwicklung-frage-antwort-db.com.de

So teilen Sie die Daten eines ausgewogenen Trainingssatzes und eines Testsets auf sklearn

Ich benutze sklearn für Multi-Klassifizierungsaufgaben. Ich muss alldata in train_set und test_set aufteilen. Ich möchte zufällig die gleiche Probennummer aus jeder Klasse nehmen . Eigentlich amüsiere ich diese Funktion

X_train, X_test, y_train, y_test = cross_validation.train_test_split(Data, Target, test_size=0.3, random_state=0)

aber es gibt einen unausgeglichenen Datensatz! Irgendein Vorschlag.

16
Jeanne

Sie können StratifiedShuffleSplit verwenden, um Datensätze zu erstellen, die denselben Prozentsatz der Klassen wie der ursprüngliche haben:

import numpy as np
from sklearn.cross_validation import StratifiedShuffleSplit
X = np.array([[1, 3], [3, 7], [2, 4], [4, 8]])
y = np.array([0, 1, 0, 1])
stratSplit = StratifiedShuffleSplit(y, 1, test_size=0.5,random_state=42)
StratifiedShuffleSplit(y, n_iter=1, test_size=0.5)
for train_idx,test_idx in stratSplit:
    X_train=X[train_idx]
    y_train=y[train_idx]
print(X_train)
print(y_train)
//[[3 7]
// [2 4]]
//[1 0]
13

Obwohl Christians Vorschlag korrekt ist, sollten Sie mit train_test_split unter Verwendung des Parameters stratify stratifizierte Ergebnisse erhalten.

Sie könnten also folgendes tun:

X_train, X_test, y_train, y_test = cross_validation.train_test_split(Data, Target, test_size=0.3, random_state=0, stratify=Target)

Der Trick hier ist, dass ab Version 0.17 in sklearn beginnt.

Aus der Dokumentation zum Parameter stratify:

stratify: Array-like oder None (Standardeinstellung ist None) Wenn nicht None, werden die Daten in einer geschichteten Form aufgeteilt, wobei dies als Beschriftungsarray verwendet wird. Neu in Version 0.17: Schichtung von Spalten

13
Guiem Bosch

Wenn die Klassen nicht ausbalanciert sind, Sie jedoch möchten, dass die Teilung ausgeglichen ist, hilft Stratifizierung nicht. Es scheint keine Methode zu geben, um in sklearn ein ausgewogenes Sampling durchzuführen, aber es ist ziemlich einfach, grundlegende Zahlen zu verwenden, zum Beispiel kann eine Funktion wie diese Ihnen helfen:

def split_balanced(data, target, test_size=0.2):

    classes = np.unique(target)
    # can give test_size as fraction of input data size of number of samples
    if test_size<1:
        n_test = np.round(len(target)*test_size)
    else:
        n_test = test_size
    n_train = max(0,len(target)-n_test)
    n_train_per_class = max(1,int(np.floor(n_train/len(classes))))
    n_test_per_class = max(1,int(np.floor(n_test/len(classes))))

    ixs = []
    for cl in classes:
        if (n_train_per_class+n_test_per_class) > np.sum(target==cl):
            # if data has too few samples for this class, do upsampling
            # split the data to training and testing before sampling so data points won't be
            #  shared among training and test data
            splitix = int(np.ceil(n_train_per_class/(n_train_per_class+n_test_per_class)*np.sum(target==cl)))
            ixs.append(np.r_[np.random.choice(np.nonzero(target==cl)[0][:splitix], n_train_per_class),
                np.random.choice(np.nonzero(target==cl)[0][splitix:], n_test_per_class)])
        else:
            ixs.append(np.random.choice(np.nonzero(target==cl)[0], n_train_per_class+n_test_per_class,
                replace=False))

    # take same num of samples from all classes
    ix_train = np.concatenate([x[:n_train_per_class] for x in ixs])
    ix_test = np.concatenate([x[n_train_per_class:(n_train_per_class+n_test_per_class)] for x in ixs])

    X_train = data[ix_train,:]
    X_test = data[ix_test,:]
    y_train = target[ix_train]
    y_test = target[ix_test]

    return X_train, X_test, y_train, y_test

Wenn Sie dies verwenden und mehr Punkte pro Klasse als in den Eingabedaten abtasten, werden diese upsampled (Probe mit Ersetzung). Infolgedessen erscheinen einige Datenpunkte mehrmals und dies kann sich auf die Genauigkeitsmessungen usw. auswirken. Wenn eine Klasse nur einen Datenpunkt hat, tritt ein Fehler auf. Sie können die Anzahl der Punkte pro Klasse beispielsweise mit np.unique(target, return_counts=True) überprüfen.

2
antike

Dies ist meine Implementierung, die ich verwende, um Zug-/Testdatenindizes zu erhalten

def get_safe_balanced_split(target, trainSize=0.8, getTestIndexes=True, shuffle=False, seed=None):
    classes, counts = np.unique(target, return_counts=True)
    nPerClass = float(len(target))*float(trainSize)/float(len(classes))
    if nPerClass > np.min(counts):
        print("Insufficient data to produce a balanced training data split.")
        print("Classes found %s"%classes)
        print("Classes count %s"%counts)
        ts = float(trainSize*np.min(counts)*len(classes)) / float(len(target))
        print("trainSize is reset from %s to %s"%(trainSize, ts))
        trainSize = ts
        nPerClass = float(len(target))*float(trainSize)/float(len(classes))
    # get number of classes
    nPerClass = int(nPerClass)
    print("Data splitting on %i classes and returning %i per class"%(len(classes),nPerClass ))
    # get indexes
    trainIndexes = []
    for c in classes:
        if seed is not None:
            np.random.seed(seed)
        cIdxs = np.where(target==c)[0]
        cIdxs = np.random.choice(cIdxs, nPerClass, replace=False)
        trainIndexes.extend(cIdxs)
    # get test indexes
    testIndexes = None
    if getTestIndexes:
        testIndexes = list(set(range(len(target))) - set(trainIndexes))
    # shuffle
    if shuffle:
        trainIndexes = random.shuffle(trainIndexes)
        if testIndexes is not None:
            testIndexes = random.shuffle(testIndexes)
    # return indexes
    return trainIndexes, testIndexes
0
Cobry