Bagaimana cara membagi / mempartisi set data menjadi set data pelatihan dan pengujian, misalnya, validasi silang?


99

Apa cara yang baik untuk membagi array NumPy secara acak menjadi set data pelatihan dan pengujian / validasi? Sesuatu yang mirip dengan cvpartitionatau crossvalindfungsi di Matlab.

Jawaban:


125

Jika Anda ingin membagi kumpulan data satu kali menjadi dua bagian, Anda dapat menggunakan numpy.random.shuffle, atau numpy.random.permutationjika Anda perlu melacak indeks:

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

atau

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

Ada banyak cara untuk mempartisi berulang kali kumpulan data yang sama untuk validasi silang . Salah satu strateginya adalah mengambil sampel kembali dari kumpulan data, dengan pengulangan:

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

Terakhir, sklearn berisi beberapa metode validasi silang (k-fold, leave-n-out, ...). Ini juga mencakup metode "pengambilan sampel bertingkat" yang lebih canggih yang membuat partisi data yang seimbang sehubungan dengan beberapa fitur, misalnya untuk memastikan bahwa ada proporsi yang sama dari contoh positif dan negatif dalam set pelatihan dan pengujian.


13
terima kasih atas solusi ini. Tapi, bukankah metode terakhir, menggunakan randint, memiliki peluang bagus untuk memberikan indeks yang sama untuk set pengujian dan pelatihan?
ggauravr

3
Solusi kedua adalah jawaban yang valid sedangkan yang pertama dan ketiga tidak. Untuk solusi pertama, mengacak dataset tidak selalu menjadi pilihan, ada banyak kasus di mana Anda harus menjaga urutan input data. Dan yang ketiga bisa menghasilkan indeks yang sama untuk tes dan pelatihan (seperti yang ditunjukkan oleh @ggauravr).
pedram bashiri

Anda tidak boleh mengambil sampel ulang untuk set validasi silang Anda. Keseluruhan idenya adalah bahwa kumpulan CV belum pernah dilihat oleh algo Anda sebelumnya. Set pelatihan dan tes digunakan untuk menyesuaikan data, jadi tentu saja Anda akan mendapatkan hasil yang baik jika Anda memasukkannya ke dalam set CV Anda. Saya ingin meningkatkan jawaban ini karena solusi ke-2 adalah yang saya butuhkan, tetapi jawaban ini bermasalah.
RubberDuck

55

Ada opsi lain yang hanya memerlukan penggunaan scikit-learn. Seperti yang dijelaskan oleh scikit's wiki , Anda cukup menggunakan instruksi berikut:

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)

Dengan cara ini Anda dapat tetap menyinkronkan label untuk data yang Anda coba bagi menjadi pelatihan dan pengujian.


1
Ini adalah jawaban yang sangat praktis, karena penanganan yang realistis dari set dan label kereta.
chinnychinchin

38

Hanya sebuah catatan. Jika Anda ingin melatih, menguji, DAN set validasi, Anda dapat melakukan ini:

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)

Parameter ini akan memberikan 70% untuk pelatihan, dan 15% masing-masing untuk pengujian dan set val. Semoga ini membantu.


5
mungkin harus menambahkan ini ke kode Anda: from sklearn.cross_validation import train_test_splituntuk memperjelas modul apa yang Anda gunakan
Radix

Apakah ini harus acak?
liang

Yaitu, apakah mungkin untuk membagi menurut urutan yang diberikan X dan y?
liang

1
@liang tidak tidak harus acak. Anda bisa mengatakan ukuran set train, test, dan validasi adalah a, b, dan c persen dari ukuran total dataset. katakanlah a=0.7, b=0.15, c=0.15, dan d = dataset, N=len(dataset), kemudian x_train = dataset[0:int(a*N)], x_test = dataset[int(a*N):int((a+b)*N)], dan x_val = dataset[int((a+b)*N):].
offwhitelotus

1
Tidak digunakan lagi: stackoverflow.com/a/34844352/4237080 , gunakanfrom sklearn.model_selection import train_test_split
briennakh

14

Karena sklearn.cross_validationmodul sudah tidak digunakan lagi, Anda dapat menggunakan:

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

Anda juga dapat mempertimbangkan pembagian bertingkat menjadi set pelatihan dan pengujian. Pembagian yang dimulai juga menghasilkan pelatihan dan pengujian yang ditetapkan secara acak tetapi sedemikian rupa sehingga proporsi kelas asli dipertahankan. Ini membuat set pelatihan dan pengujian lebih mencerminkan properti dari set data asli.

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]

Kode ini menghasilkan:

[1 2 3]
[1 2 3]

Terima kasih! Penamaannya agak menyesatkan, value_indssebenarnya adalah indeks, tetapi hasilnya bukan indeks, hanya topeng.
greenoldman

1

Saya menulis fungsi untuk proyek saya sendiri untuk melakukan ini (meskipun tidak menggunakan numpy):

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

Jika Anda ingin potongannya diacak, cukup kocok daftarnya sebelum meneruskannya.


0

Berikut adalah kode untuk membagi data menjadi n = 5 kali lipat secara bertingkat

% 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

Terima kasih pberkes atas jawaban Anda. Saya baru saja memodifikasinya untuk menghindari (1) penggantian saat pengambilan sampel (2) contoh duplikat terjadi di pelatihan dan pengujian:

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

Setelah melakukan beberapa pembacaan dan mempertimbangkan (banyak ..) cara yang berbeda dalam membagi data untuk dilatih dan diuji, saya memutuskan untuk melakukannya!

Saya menggunakan 4 metode berbeda (tidak ada yang menggunakan library sklearn, yang saya yakin akan memberikan hasil terbaik, memberikan kode yang dirancang dan diuji dengan baik):

  1. mengocok seluruh matriks arr dan kemudian membagi data untuk dilatih dan diuji
  2. mengocok indeks dan kemudian menetapkannya x dan y untuk memisahkan data
  3. sama seperti metode 2, tetapi dengan cara yang lebih efisien untuk melakukannya
  4. menggunakan pandas dataframe untuk memisahkan

Metode 3 menang sejauh ini dengan waktu tersingkat, setelah itu metode 1, dan metode 2 dan 4 ditemukan sangat tidak efisien.

Kode untuk 4 metode berbeda yang saya hitung:

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)

Dan untuk waktu, waktu minimum untuk mengeksekusi dari 3 pengulangan 1000 loop adalah:

  • Metode 1: 0,35883826200006297 detik
  • Metode 2: 1.7157016959999964 detik
  • Metode 3: 1.7876616719995582 detik
  • Metode 4: 0,07562861499991413 detik

Saya harap itu membantu!


0

Kemungkinan Anda tidak hanya perlu membagi menjadi train and test, tetapi juga validasi silang untuk memastikan model Anda digeneralisasi. Di sini saya mengasumsikan 70% data pelatihan, 20% validasi, dan 10% data pisahan / uji.

Lihat np.split :

Jika indices_or_sections adalah larik 1-D dari bilangan bulat yang diurutkan, entri menunjukkan di mana sepanjang sumbu larik dipisahkan. Misalnya, [2, 3] akan, untuk sumbu = 0, menghasilkan

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

Bagi menjadi tes kereta dan valid

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)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.