Bir veri kümesini eğitime ve örneğin çapraz doğrulama için test veri kümelerine nasıl bölünür / bölümlenir?


101

NumPy dizisini rastgele olarak eğitim ve test / doğrulama veri kümesine bölmenin iyi bir yolu nedir? Matlab'daki cvpartitionveya crossvalindişlevlerine benzer bir şey .

Yanıtlar:


128

Veri kümesini ikiye bölmek isterseniz, kullanabilirsiniz numpy.random.shuffleveya numpy.random.permutationendeksleri takip etmeniz gerekiyorsa:

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

veya

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

Çapraz doğrulama için aynı veri kümesini tekrar tekrar bölümlemenin birçok yolu vardır . Bir strateji, veri kümesinden tekrar ederek yeniden örneklemektir:

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

Son olarak, sklearn birkaç çapraz doğrulama yöntemi içerir (k-katlama, dışarıda bırakma, ...). Aynı zamanda, örneğin eğitim ve test setinde aynı oranda olumlu ve olumsuz örneklerin bulunduğundan emin olmak için, verilerin bazı özelliklere göre dengelenmiş bir bölümünü oluşturan daha gelişmiş "tabakalı örnekleme" yöntemlerini içerir.


14
bu çözümler için teşekkürler. Ancak, randint kullanan son yöntemin hem test hem de eğitim setleri için aynı indeksleri verme şansı yüksek değil mi?
ggauravr

3
İkinci çözüm geçerli bir cevaptır, 1. ve 3. olanlar ise değildir. Birinci çözüm için, veri kümesini karıştırmak her zaman bir seçenek değildir, veri girişlerinin sırasını korumanız gereken birçok durum vardır. Ve üçüncüsü, test ve eğitim için aynı indeksleri çok iyi üretebilir (@ggauravr tarafından belirtildiği gibi).
pedram bashiri

Sen gerektiğini değil Çapraz doğrulama kümesi için yeniden örneklemek. Tüm fikir, CV setinin algo tarafından daha önce hiç görülmemiş olmasıdır. Eğitim ve test setleri verilere uymak için kullanılır, bu nedenle CV setinize bunları eklerseniz elbette iyi sonuçlar alırsınız. Bu yanıtı yükseltmek istiyorum çünkü 2. çözüm ihtiyacım olan şeydi, ancak bu yanıtın sorunları var.
RubberDuck

56

Scikit-learn'ü kullanmayı gerektiren başka bir seçenek daha var. As scikit wiki anlatılmaktadır , sadece aşağıdaki yönergeler kullanabilirsiniz:

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)

Bu şekilde, eğitime ve teste ayırmaya çalıştığınız verilerin etiketlerini senkronize tutabilirsiniz.


1
Bu, hem tren setinin hem de etiketlerin gerçekçi kullanımı nedeniyle çok pratik bir cevaptır.
chinnychinchin

Bir dizi değil, bir liste döndürür.
EngrStudent

38

Sadece bir not. Eğitim, test VE doğrulama kümeleri istiyorsanız, bunu yapabilirsiniz:

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)

Bu parametreler eğitime% 70 ve test ve değer setlerine% 15 verecektir. Bu yardımcı olur umarım.


5
muhtemelen bunu kodunuza eklemelisiniz: from sklearn.cross_validation import train_test_splithangi modülü kullandığınızı netleştirmek için
Radix

Bunun rastgele olması gerekiyor mu?
liang

Yani X ve y'nin verilen sırasına göre bölmek mümkün müdür?
liang

1
@liang hayır rastgele olmak zorunda değil. tren, test ve doğrulama kümesi boyutlarının toplam veri kümesinin boyutunun a, b ve c yüzdesi olacağını söyleyebilirsiniz. diyelim ki a=0.7, b=0.15, c=0.15, ve d = dataset, N=len(dataset)daha sonra x_train = dataset[0:int(a*N)], x_test = dataset[int(a*N):int((a+b)*N)]ve x_val = dataset[int((a+b)*N):].
offwhitelotus

1
Kullanımdan kaldırıldı: stackoverflow.com/a/34844352/4237080 , kullanımfrom sklearn.model_selection import train_test_split
briennakh

14

Gibi sklearn.cross_validationmodül kaldırıldı, şunları kullanabilirsiniz:

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)

5

Ayrıca, eğitim ve test seti olarak kademeli bölünmeyi de düşünebilirsiniz. Başlatılan bölüm aynı zamanda rastgele eğitim ve test seti oluşturur, ancak orijinal sınıf oranları korunacak şekilde. Bu, eğitim ve test setlerinin orijinal veri setinin özelliklerini daha iyi yansıtmasını sağlar.

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]

Bu kodun çıktısı:

[1 2 3]
[1 2 3]

Teşekkür ederim! Adlandırma biraz yanıltıcıdır, value_indsgerçekten indekslerdir, ancak çıktılar indeksler değildir, sadece maskelerdir.
greenoldman

1

Bunu yapmak için kendi projem için bir işlev yazdım (yine de numpy kullanmıyor):

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

Parçaların rastgele hale getirilmesini istiyorsanız, listeyi iletmeden önce karıştırın.


0

Verileri tabakalı bir şekilde n = 5 kata bölmek için bir kod.

% 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

Cevabınız için teşekkürler pberkes. Hem eğitimde hem de testte (2) yinelenen örnekleme sırasında (1) değiştirmeyi önlemek için değiştirdim:

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

Biraz okuma yaptıktan ve eğitmek ve test etmek için verileri bölmenin (birçok ..) farklı yolunu hesaba kattıktan sonra, zaman ayırmaya karar verdim!

4 farklı yöntem kullandım (bunların hiçbiri en iyi sonuçları vereceğinden emin olduğum kütüphane sklearn'ı kullanmıyor, iyi tasarlanmış ve test edilmiş bir kod olduğu için):

  1. tüm matrisi karıştırın ve ardından eğitmek ve test etmek için verileri bölün
  2. endeksleri karıştırın ve ardından verileri bölmek için x ve y atayın
  3. yöntem 2 ile aynı, ancak daha verimli bir şekilde
  4. pandalar veri çerçevesini kullanarak

Yöntem 3, en kısa sürede açık farkla kazandı, bundan sonra yöntem 1 ve yöntem 2 ve 4'ün gerçekten verimsiz olduğu keşfedildi.

Zamanladığım 4 farklı yöntemin kodu:

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)

Ve zamanlar için, 1000 döngünün 3 tekrardan gerçekleştirilmesi için minimum süre:

  • Yöntem 1: 0,35883826200006297 saniye
  • Yöntem 2: 1.7157016959999964 saniye
  • Yöntem 3: 1.7876616719995582 saniye
  • Yöntem 4: 0,07562861499991413 saniye

Umarım yardımcı olur!


0

Muhtemelen sadece eğitim ve teste ayrılmanız gerekmeyecek, aynı zamanda modelinizin genelleştiğinden emin olmak için çapraz doğrulamaya da ihtiyaç duyacaksınız. Burada% 70 eğitim verisi,% 20 doğrulama ve% 10 erteleme / test verisi varsayıyorum.

Check out np.split :

İndices_or_sections, sıralı tam sayılardan oluşan 1 boyutlu bir diziyse, girişler, dizinin eksen boyunca nerede bölündüğünü belirtir. Örneğin, [2, 3], eksen = 0 için sonuçlanır

ary [: 2] ary [2: 3] ary [3:]

t, v, h = np.split(df.sample(frac=1, random_state=1), [int(0.7*len(df)), int(0.9*len(df))]) 

0

Tren testine bölün ve geçerli

x =np.expand_dims(np.arange(100), -1)


print(x)

indices = np.random.permutation(x.shape[0])

training_idx, test_idx, val_idx = indices[:int(x.shape[0]*.9)], indices[int(x.shape[0]*.9):int(x.shape[0]*.95)],  indices[int(x.shape[0]*.9):int(x.shape[0]*.95)]


training, test, val = x[training_idx,:], x[test_idx,:], x[val_idx,:]

print(training, test, val)

0

Çözümümün en iyisi olmadığının farkındayım, ancak verileri basit bir şekilde bölmek istediğinizde, özellikle de yeni başlayanlara veri bilimini öğretirken işe yarıyor!

def simple_split(descriptors, targets):
    testX_indices = [i for i in range(descriptors.shape[0]) if i % 4 == 0]
    validX_indices = [i for i in range(descriptors.shape[0]) if i % 4 == 1]
    trainX_indices = [i for i in range(descriptors.shape[0]) if i % 4 >= 2]

    TrainX = descriptors[trainX_indices, :]
    ValidX = descriptors[validX_indices, :]
    TestX = descriptors[testX_indices, :]

    TrainY = targets[trainX_indices]
    ValidY = targets[validX_indices]
    TestY = targets[testX_indices]

    return TrainX, ValidX, TestX, TrainY, ValidY, TestY

Bu koda göre, veriler üç bölüme ayrılacaktır - test bölümü için 1/4, doğrulama bölümü için başka bir 1/4 ve eğitim seti için 2/4.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.