วิธีการแบ่ง / แบ่งชุดข้อมูลลงในชุดข้อมูลการฝึกอบรมและทดสอบสำหรับเช่นการตรวจสอบความถูกต้องข้าม?


101

วิธีที่ดีในการแบ่งอาร์เรย์ NumPy แบบสุ่มเป็นชุดข้อมูลการฝึกอบรมและการทดสอบ / การตรวจสอบความถูกต้องคืออะไร? สิ่งที่คล้ายกับcvpartitionหรือcrossvalindฟังก์ชันใน Matlab

คำตอบ:


128

หากคุณต้องการแบ่งชุดข้อมูลออกเป็นสองส่วนคุณสามารถใช้numpy.random.shuffleหรือnumpy.random.permutationหากคุณต้องการติดตามดัชนี:

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

หรือ

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

มีหลายวิธีที่จะเป็นซ้ำ ๆ พาร์ทิชันชุดข้อมูลเดียวกันสำหรับการตรวจสอบข้าม กลยุทธ์หนึ่งคือการสุ่มตัวอย่างจากชุดข้อมูลโดยทำซ้ำ:

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มีวิธีการตรวจสอบข้ามหลายวิธี (k-fold, leave-n-out, ... ) นอกจากนี้ยังรวมถึงวิธีการ"การสุ่มตัวอย่างแบบแบ่งชั้น"ขั้นสูงที่สร้างพาร์ติชันของข้อมูลที่สมดุลกับคุณลักษณะบางอย่างเช่นเพื่อให้แน่ใจว่ามีตัวอย่างเชิงบวกและเชิงลบในสัดส่วนที่เท่ากันในชุดการฝึกอบรมและการทดสอบ


14
ขอบคุณสำหรับการแก้ปัญหาเหล่านี้ แต่วิธีสุดท้ายที่ใช้ Randint มีโอกาสที่ดีในการให้ดัชนีเดียวกันสำหรับทั้งชุดทดสอบและชุดฝึกหรือไม่?
ggauravr

3
คำตอบที่สองเป็นคำตอบที่ถูกต้องในขณะที่คำตอบที่ 1 และ 3 ไม่ใช่คำตอบ สำหรับวิธีแก้ปัญหาที่ 1 การสลับชุดข้อมูลไม่ใช่ทางเลือกเสมอไปมีหลายกรณีที่คุณต้องรักษาลำดับของอินพุตข้อมูล และอันที่ 3 สามารถสร้างดัชนีเดียวกันสำหรับการทดสอบและการฝึกอบรมได้เป็นอย่างดี (ตามที่ @ggauravr ชี้ให้เห็น)
pedram bashiri

คุณไม่ควรสุ่มตัวอย่างสำหรับชุดการตรวจสอบความถูกต้องข้ามของคุณ แนวคิดทั้งหมดคือชุด CV ของคุณไม่เคยเห็นมาก่อน ชุดการฝึกอบรมและการทดสอบใช้เพื่อให้พอดีกับข้อมูลดังนั้นแน่นอนว่าคุณจะได้รับผลลัพธ์ที่ดีหากรวมไว้ในชุด CV ของคุณ ฉันต้องการโหวตให้คำตอบนี้เพราะวิธีแก้ปัญหาที่ 2 คือสิ่งที่ฉันต้องการ แต่คำตอบนี้มีปัญหา
RubberDuck

55

มีอีกทางเลือกหนึ่งที่เกี่ยวข้องกับการใช้ scikit-learn ตามที่วิกิอธิบายของ scikitคุณสามารถใช้คำแนะนำต่อไปนี้:

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)

วิธีนี้ช่วยให้คุณสามารถซิงค์ป้ายกำกับสำหรับข้อมูลที่คุณพยายามแยกออกเป็นการฝึกอบรมและทดสอบ


1
นี่เป็นคำตอบที่ใช้ได้จริงเนื่องจากการจัดการทั้งชุดรถไฟและป้ายกำกับที่เป็นจริง
chinnychinchin

ส่งคืนรายการไม่ใช่อาร์เรย์
EngrStudent

38

เพียงแค่ทราบ ในกรณีที่คุณต้องการชุดฝึกทดสอบและตรวจสอบความถูกต้องคุณสามารถทำได้:

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)

พารามิเตอร์เหล่านี้จะให้ 70% สำหรับการฝึกอบรมและ 15% สำหรับการทดสอบและชุดวาล หวังว่านี่จะช่วยได้


5
ควรเพิ่มสิ่งนี้ลงในโค้ดของคุณ: from sklearn.cross_validation import train_test_splitเพื่อให้ชัดเจนว่าคุณใช้โมดูลใด
Radix

สิ่งนี้ต้องสุ่มหรือไม่?
liang

นั่นคือเป็นไปได้ไหมที่จะแยกตามคำสั่งของ X และ y?
เลี่ยง

1
@liang ไม่มันไม่จำเป็นต้องสุ่ม คุณสามารถพูดได้ว่าขนาดชุดรถไฟการทดสอบและการตรวจสอบความถูกต้องจะเป็น a, b และ c เปอร์เซ็นต์ของขนาดของชุดข้อมูลทั้งหมด สมมติว่าa=0.7, b=0.15, c=0.15และd = dataset, N=len(dataset)แล้วx_train = dataset[0:int(a*N)], และx_test = dataset[int(a*N):int((a+b)*N)] x_val = dataset[int((a+b)*N):]
offwhitelotus

1
เลิกใช้: stackoverflow.com/a/34844352/4237080ใช้from sklearn.model_selection import train_test_split
briennakh

14

เนื่องจากsklearn.cross_validationโมดูลเลิกใช้งานแล้วคุณสามารถใช้:

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

คุณอาจพิจารณาการแบ่งชั้นเป็นชุดการฝึกอบรมและการทดสอบ การแบ่งเริ่มต้นยังสร้างชุดการฝึกอบรมและการทดสอบแบบสุ่ม แต่ในลักษณะที่รักษาสัดส่วนชั้นเรียนเดิมไว้ ทำให้ชุดการฝึกอบรมและการทดสอบสะท้อนคุณสมบัติของชุดข้อมูลเดิมได้ดีขึ้น

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]

รหัสนี้ส่งออก:

[1 2 3]
[1 2 3]

ขอบคุณ! การตั้งชื่อค่อนข้างทำให้เข้าใจผิดvalue_indsเป็นดัชนีจริง ๆ แต่ผลลัพธ์ไม่ใช่ดัชนี แต่มาสก์เท่านั้น
greenoldman

1

ฉันเขียนฟังก์ชันสำหรับโครงการของฉันเองเพื่อทำสิ่งนี้ (แม้ว่าจะไม่ใช้ 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

หากคุณต้องการสุ่มชิ้นส่วนให้สุ่มรายการก่อนส่งต่อ


0

นี่คือรหัสสำหรับแบ่งข้อมูลออกเป็น n = 5 เท่าในลักษณะแบ่งชั้น

% 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

ขอบคุณ pberkes สำหรับคำตอบของคุณ ฉันเพิ่งแก้ไขเพื่อหลีกเลี่ยง (1) การแทนที่ในขณะที่สุ่มตัวอย่าง (2) อินสแตนซ์ที่ซ้ำกันเกิดขึ้นทั้งในการฝึกอบรมและการทดสอบ:

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

หลังจากอ่านและคำนึงถึงวิธีการต่างๆในการแยกข้อมูลเพื่อฝึกอบรมและทดสอบฉันตัดสินใจที่จะหมดเวลา

ฉันใช้ 4 วิธีที่แตกต่างกัน (ไม่ใช่วิธีการใช้ไลบรารี sklearn ซึ่งฉันแน่ใจว่าจะให้ผลลัพธ์ที่ดีที่สุดเนื่องจากได้รับการออกแบบและทดสอบโค้ดมาเป็นอย่างดี):

  1. สลับอาร์เรย์เมทริกซ์ทั้งหมดจากนั้นแยกข้อมูลเพื่อฝึกอบรมและทดสอบ
  2. สับเปลี่ยนดัชนีแล้วกำหนด x และ y เพื่อแยกข้อมูล
  3. เช่นเดียวกับวิธีที่ 2 แต่เป็นวิธีที่มีประสิทธิภาพมากกว่า
  4. ใช้ดาต้าเฟรมของแพนด้าเพื่อแบ่ง

วิธีที่ 3 ชนะโดยใช้เวลาที่สั้นที่สุดหลังจากนั้นวิธีที่ 1 และวิธีที่ 2 และ 4 พบว่าไม่มีประสิทธิภาพจริงๆ

รหัสสำหรับ 4 วิธีต่างๆที่ฉันตั้งเวลาไว้:

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)

และในบางครั้งเวลาขั้นต่ำในการทำซ้ำ 3 ครั้งจาก 1,000 ลูปคือ:

  • วิธีที่ 1: 0.35883826200006297 วินาที
  • วิธีที่ 2: 1.7157016959999964 วินาที
  • วิธีที่ 3: 1.7876616719995582 วินาที
  • วิธีที่ 4: 0.07562861499991413 วินาที

หวังว่าจะเป็นประโยชน์!


0

เป็นไปได้ว่าคุณไม่เพียง แต่ต้องแยกไปฝึกอบรมและทดสอบเท่านั้น แต่ยังรวมถึงการตรวจสอบความถูกต้องข้ามเพื่อให้แน่ใจว่าแบบจำลองของคุณมีลักษณะทั่วไป ฉันสมมติว่าข้อมูลการฝึกอบรม 70% การตรวจสอบความถูกต้อง 20% และข้อมูลการระงับ / การทดสอบ 10%

ตรวจสอบnp.split :

ถ้า indices_or_sections เป็นอาร์เรย์ 1-D ของจำนวนเต็มที่เรียงลำดับรายการจะระบุตำแหน่งที่แบ่งอาร์เรย์ตามแกน ตัวอย่างเช่น [2, 3] จะให้ผลลัพธ์เป็นแกน = 0

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

แยกเป็นการทดสอบรถไฟและถูกต้อง

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

ฉันทราบดีว่าโซลูชันของฉันไม่ได้ดีที่สุด แต่มีประโยชน์เมื่อคุณต้องการแยกข้อมูลด้วยวิธีง่ายๆโดยเฉพาะอย่างยิ่งเมื่อสอนวิทยาศาสตร์ข้อมูลให้กับมือใหม่!

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

ตามรหัสนี้ข้อมูลจะถูกแบ่งออกเป็นสามส่วน - 1/4 สำหรับส่วนทดสอบอีก 1/4 สำหรับส่วนการตรวจสอบความถูกต้องและ 2/4 สำหรับชุดฝึก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.