ฉันจะสร้างตัวอย่างการทดสอบและฝึกอบรมตัวอย่างจากดาต้าเฟรมที่มีแพนด้าได้อย่างไร


323

ฉันมีชุดข้อมูลที่มีขนาดใหญ่พอสมควรในรูปแบบของ dataframe และฉันสงสัยว่าฉันจะสามารถแยก dataframe ออกเป็นสองตัวอย่างแบบสุ่ม (80% และ 20%) สำหรับการฝึกอบรมและการทดสอบได้อย่างไร

ขอบคุณ!

คำตอบ:


346

ฉันแค่จะใช้ของ numpy randn:

In [11]: df = pd.DataFrame(np.random.randn(100, 2))

In [12]: msk = np.random.rand(len(df)) < 0.8

In [13]: train = df[msk]

In [14]: test = df[~msk]

และเพื่อที่จะเห็นสิ่งนี้ได้ผล:

In [15]: len(test)
Out[15]: 21

In [16]: len(train)
Out[16]: 79

3
ขอโทษที่ฉันทำผิด ตราบใดที่mskเป็นของ dtype bool, df[msk], df.iloc[msk]และdf.loc[msk]มักจะกลับผลเดียวกัน
unutbu

2
ฉันคิดว่าคุณควรจะใช้randเพื่อ< 0.8ทำให้ความรู้สึกเพราะมันส่งกลับกระจายอย่างสม่ำเสมอตัวเลขสุ่มระหว่าง 0 และ 1
อาร์แม็กซ์

4
คนที่สามารถอธิบายได้อย่างหมดจดในแง่หลามว่าสิ่งที่เกิดขึ้นในสายin[12], in[13], in[14]? ฉันต้องการเข้าใจโค้ดไพ ธ อนเองที่นี่
kuatroka

7
คำตอบที่ใช้sklearnจากgobrewers14เป็นคำตอบที่ดีกว่า มันซับซ้อนน้อยกว่าและง่ายต่อการตรวจแก้จุดบกพร่อง ฉันแนะนำให้ใช้คำตอบด้านล่าง
ดังนั้น

2
@kuatroka np.random.rand(len(df))เป็นอาร์เรย์ขนาดที่len(df)มีค่าทศนิยมแบบสุ่มและกระจายแบบสม่ำเสมอในช่วง [0, 1] < 0.8ใช้การเปรียบเทียบองค์ประกอบที่ชาญฉลาดและร้านค้าผลในสถานที่ ดังนั้นค่า <0.8 กลายเป็นTrueและค่า> = 0.8 กลายเป็นFalse
Kentzo

623

scikit learntrain_test_splitคืออันที่ดี

from sklearn.model_selection import train_test_split

train, test = train_test_split(df, test_size=0.2)

22
สิ่งนี้จะส่งคืนอาร์เรย์ที่มีจำนวนมากและไม่ใช่ Pandas Dataframes
Bar

124
Btw มันจะคืนค่าดาต้าดาต้าของ Pandas ทันที (เพิ่งทดสอบ Sklearn 0.16.1)
Julien Marrec

5
หากคุณกำลังมองหา KFold มันซับซ้อนกว่าเล็กน้อยเศร้า kf = KFold(n, n_folds=folds) for train_index, test_index in kf: X_train, X_test = X.ix[train_index], X.ix[test_index]ดูตัวอย่างทั้งหมดได้ที่นี่: quantstart.com/articles/…
ihadanny

12
ในเวอร์ชันใหม่ (0.18 อาจจะเร็วกว่า) นำเข้าfrom sklearn.model_selection import train_test_splitแทน
Mark

7
ใน SciKit เวอร์ชั่นใหม่ล่าสุดคุณต้องเรียกมันตอนนี้ว่า:from sklearn.cross_validation import train_test_split
horseshoe

289

ตัวอย่างแบบสุ่มของนุ่นก็จะได้ผลเช่นกัน

train=df.sample(frac=0.8,random_state=200) #random state is a seed value
test=df.drop(train.index)

. index หมายถึงอะไร / อยู่ที่ไหนเอกสารสำหรับ. ดัชนีใน DataFrame? ฉันหามันไม่เจอ
dmonopoly

1
สิ่งที่เป็นrandom_stateหาเรื่องทำ?
Rishabh Agrahari

1
@RishabhAgrahari สุ่มสับข้อมูลที่แตกต่างกันทุกครั้งตาม ARC frac หากคุณต้องการควบคุมการสุ่มคุณสามารถระบุเมล็ดพันธุ์ของคุณเองเช่นในตัวอย่าง
MikeL

4
ดูเหมือนว่าจะทำงานได้ดีและเป็นทางออกที่หรูหรากว่าการนำเข้าสู่ความสับสน มีเหตุผลหรือไม่ที่ทำไมนี่จึงไม่ใช่คำตอบที่ดีกว่า?
RajV

1
@peer ข้อ จำกัด ที่แก้ได้ง่ายถ้าสับtestชุดเป็นที่ต้องการเป็นแหลมออกจากที่นี่stackoverflow.com/questions/29576430/shuffle-dataframe-rows test=df.drop(train.index).sample(frac=1.0)
Alok Lal

32

ฉันจะใช้ training_test_split ของ scikit-learn และสร้างมันจากดัชนี

from sklearn.model_selection import train_test_split


y = df.pop('output')
X = df

X_train,X_test,y_train,y_test = train_test_split(X.index,y,test_size=0.2)
X.iloc[X_train] # return dataframe train

3
cross_validationโมดูลจะเลิกตอนนี้:DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.
แฮร์รี่

20

มีหลายวิธีในการสร้างรถไฟ / ทดสอบและแม้กระทั่งตัวอย่างการตรวจสอบ

กรณีที่ 1: วิธีคลาสสิคtrain_test_splitโดยไม่มีตัวเลือกใด ๆ :

from sklearn.model_selection import train_test_split
train, test = train_test_split(df, test_size=0.3)

กรณีที่ 2: กรณีของชุดข้อมูลขนาดเล็กมาก (<500 แถว): เพื่อรับผลลัพธ์สำหรับทุกบรรทัดของคุณด้วยการตรวจสอบความถูกต้องไขว้นี้ ในตอนท้ายคุณจะมีการคาดการณ์หนึ่งครั้งสำหรับแต่ละบรรทัดของชุดการฝึกอบรมที่คุณมี

from sklearn.model_selection import KFold
kf = KFold(n_splits=10, random_state=0)
y_hat_all = []
for train_index, test_index in kf.split(X, y):
    reg = RandomForestRegressor(n_estimators=50, random_state=0)
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
    clf = reg.fit(X_train, y_train)
    y_hat = clf.predict(X_test)
    y_hat_all.append(y_hat)

กรณีที่ 3a: ชุดข้อมูลที่ไม่สมดุลเพื่อจุดประสงค์ในการจัดหมวดหมู่ ตามกรณีที่ 1 นี่คือทางออกที่เทียบเท่า:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, test_size=0.3)

กรณีที่ 3b: ชุดข้อมูลที่ไม่สมดุลเพื่อจุดประสงค์ในการจัดหมวดหมู่ ตามกรณีที่ 2 นี่คือทางออกที่เทียบเท่า:

from sklearn.model_selection import StratifiedKFold
kf = StratifiedKFold(n_splits=10, random_state=0)
y_hat_all = []
for train_index, test_index in kf.split(X, y):
    reg = RandomForestRegressor(n_estimators=50, random_state=0)
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
    clf = reg.fit(X_train, y_train)
    y_hat = clf.predict(X_test)
    y_hat_all.append(y_hat)

กรณีที่ 4: คุณต้องสร้างชุดรถไฟ / ทดสอบ / การตรวจสอบความถูกต้องของข้อมูลขนาดใหญ่เพื่อปรับแต่งพารามิเตอร์ไฮเปอร์ (รถไฟ 60% การทดสอบ 20% และ 20% วาล)

from sklearn.model_selection import train_test_split
X_train, X_test_val, y_train, y_test_val = train_test_split(X, y, test_size=0.6)
X_test, X_val, y_test, y_val = train_test_split(X_test_val, y_test_val, stratify=y, test_size=0.5)

13

คุณสามารถใช้โค้ดด้านล่างเพื่อสร้างตัวอย่างทดสอบและฝึกอบรม:

from sklearn.model_selection import train_test_split
trainingSet, testSet = train_test_split(df, test_size=0.2)

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


7

มีคำตอบที่ถูกต้องมากมาย เพิ่มอีกหนึ่งในพวง จาก sklearn.cross_validation นำเข้า train_test_split

#gets a random 80% of the entire set
X_train = X.sample(frac=0.8, random_state=1)
#gets the left out portion of the dataset
X_test = X.loc[~df_model.index.isin(X_train.index)]

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

df [train_inds] และ df [test_inds] ให้ชุดฝึกอบรมและทดสอบของ DataFrame ต้นฉบับของคุณ df


นี่เป็นกลยุทธ์ที่ดีกว่าสำหรับงานการเรียนรู้แบบมีผู้สอน
vincentmajor

เมื่อพยายามใช้สิ่งนี้ฉันได้รับข้อผิดพลาด ValueError: ปลายทางที่ได้รับมอบหมายเป็นแบบอ่านอย่างเดียวในบรรทัด "np.random.shuffle (value_inds)"
Markus W

4

หากคุณต้องการแบ่งข้อมูลของคุณตามคอลัมน์ lables ในชุดข้อมูลของคุณคุณสามารถใช้สิ่งนี้:

def split_to_train_test(df, label_column, train_frac=0.8):
    train_df, test_df = pd.DataFrame(), pd.DataFrame()
    labels = df[label_column].unique()
    for lbl in labels:
        lbl_df = df[df[label_column] == lbl]
        lbl_train_df = lbl_df.sample(frac=train_frac)
        lbl_test_df = lbl_df.drop(lbl_train_df.index)
        print '\n%s:\n---------\ntotal:%d\ntrain_df:%d\ntest_df:%d' % (lbl, len(lbl_df), len(lbl_train_df), len(lbl_test_df))
        train_df = train_df.append(lbl_train_df)
        test_df = test_df.append(lbl_test_df)

    return train_df, test_df

และใช้มัน:

train, test = split_to_train_test(data, 'class', 0.7)

นอกจากนี้คุณยังสามารถส่ง random_state หากคุณต้องการควบคุมการแยกแบบสุ่มหรือใช้เมล็ดพันธุ์แบบสุ่มทั่วโลก


3
import pandas as pd

from sklearn.model_selection import train_test_split

datafile_name = 'path_to_data_file'

data = pd.read_csv(datafile_name)

target_attribute = data['column_name']

X_train, X_test, y_train, y_test = train_test_split(data, target_attribute, test_size=0.8)

2
คุณมีข้อผิดพลาดสั้น ๆ คุณควรวางคอลัมน์เป้าหมายไว้ก่อนแล้ววางลงใน train_test_split data = data.drop (คอลัมน์ = ['column_name'], แกน = 1)
Anton Erjomin

3

คุณสามารถใช้ ~ (โอเปอเรเตอร์ tilde) เพื่อยกเว้นแถวที่สุ่มตัวอย่างโดยใช้ df.sample () เพื่อให้หมีแพนด้าจัดการการสุ่มตัวอย่างและการกรองดัชนีเพียงอย่างเดียวเพื่อรับสองชุด

train_df = df.sample(frac=0.8, random_state=100)
test_df = df[~df.index.isin(train_df.index)]

2

นี่คือสิ่งที่ฉันเขียนเมื่อฉันต้องการแยก DataFrame ฉันพิจารณาว่าใช้วิธีของ Andy ด้านบน แต่ไม่ชอบว่าฉันไม่สามารถควบคุมขนาดของชุดข้อมูลได้อย่างแน่นอน (เช่นบางครั้งอาจเป็น 79, 81 หรือ 81 ฯลฯ )

def make_sets(data_df, test_portion):
    import random as rnd

    tot_ix = range(len(data_df))
    test_ix = sort(rnd.sample(tot_ix, int(test_portion * len(data_df))))
    train_ix = list(set(tot_ix) ^ set(test_ix))

    test_df = data_df.ix[test_ix]
    train_df = data_df.ix[train_ix]

    return train_df, test_df


train_df, test_df = make_sets(data_df, 0.2)
test_df.head()

2

เพียงเลือกช่วงแถวจาก df เช่นนี้

row_count = df.shape[0]
split_point = int(row_count*1/5)
test_data, train_data = df[:split_point], df[split_point:]

3
สิ่งนี้จะใช้ได้ก็ต่อเมื่อข้อมูลใน dataframe ถูกสุ่มสั่งแล้ว หากชุดข้อมูลนั้นได้มาจากแหล่ง ultiple และผนวกเข้ากับ dataframe เดียวกันก็เป็นไปได้ที่จะได้รับชุดข้อมูลที่เบ้อย่างมากสำหรับการฝึกอบรม / ทดสอบโดยใช้ข้อมูลด้านบน
Emil H

1
ท่านสามารถสุ่ม dataframe ก่อนที่จะแยกมันstackoverflow.com/questions/29576430/shuffle-dataframe-rows
มะคิโอะ

1
Absolutelty! หากคุณเพิ่มdfเข้าไปในข้อมูลโค้ดของคุณคือการสับ (หรือควร) มันจะปรับปรุงคำตอบ
Emil H

2

มีคำตอบที่ดีมากมายหลายข้อด้านบนดังนั้นฉันแค่ต้องการเพิ่มอีกตัวอย่างหนึ่งในกรณีที่คุณต้องการระบุจำนวนตัวอย่างที่แน่นอนสำหรับชุดรถไฟและชุดทดสอบโดยใช้เพียงnumpyห้องสมุด

# set the random seed for the reproducibility
np.random.seed(17)

# e.g. number of samples for the training set is 1000
n_train = 1000

# shuffle the indexes
shuffled_indexes = np.arange(len(data_df))
np.random.shuffle(shuffled_indexes)

# use 'n_train' samples for training and the rest for testing
train_ids = shuffled_indexes[:n_train]
test_ids = shuffled_indexes[n_train:]

train_data = data_df.iloc[train_ids]
train_labels = labels_df.iloc[train_ids]

test_data = data_df.iloc[test_ids]
test_labels = data_df.iloc[test_ids]

2

หากต้องการแบ่งออกเป็นสองคลาสมากกว่าเช่นรถไฟการทดสอบและการตรวจสอบความถูกต้องสามารถทำได้:

probs = np.random.rand(len(df))
training_mask = probs < 0.7
test_mask = (probs>=0.7) & (probs < 0.85)
validatoin_mask = probs >= 0.85


df_training = df[training_mask]
df_test = df[test_mask]
df_validation = df[validatoin_mask]

สิ่งนี้จะใส่ข้อมูลประมาณ 70% ในการฝึกอบรม 15% ในการทดสอบและ 15% ในการตรวจสอบ


1
คุณอาจต้องการแก้ไขคำตอบของคุณเพื่อเพิ่ม "โดยประมาณ" หากคุณเรียกใช้รหัสคุณจะเห็นว่าสามารถลบออกได้จากเปอร์เซ็นต์ที่แน่นอน เช่นฉันลองกับ 1,000 รายการและได้รับ: 700, 141, 159 - ดังนั้น 70%, 14% และ 16%
stason

2

คุณต้องแปลง p ดาสดาต้าฟารมเป็นอาเรย์นันตี้แล้วแปลงอาร์มินัมกลับสู่ดาตาแฟรม

 import pandas as pd
df=pd.read_csv('/content/drive/My Drive/snippet.csv', sep='\t')
from sklearn.model_selection import train_test_split

train, test = train_test_split(df, test_size=0.2)
train1=pd.DataFrame(train)
test1=pd.DataFrame(test)
train1.to_csv('/content/drive/My Drive/train.csv',sep="\t",header=None, encoding='utf-8', index = False)
test1.to_csv('/content/drive/My Drive/test.csv',sep="\t",header=None, encoding='utf-8', index = False)

คำตอบที่ไม่ใช้รหัสเท่านั้นไม่สามารถยอมรับได้ใน Stack Overflow
VFDan

1

หากความปรารถนาของคุณคือมีหนึ่งดาต้าไฟล์ในและสองดาต้าเฟรมออกมา (ไม่ใช่อาร์เรย์ numpy) สิ่งนี้ควรทำเคล็ดลับ:

def split_data(df, train_perc = 0.8):

   df['train'] = np.random.rand(len(df)) < train_perc

   train = df[df.train == 1]

   test = df[df.train == 0]

   split_data ={'train': train, 'test': test}

   return split_data

1

คุณสามารถใช้ประโยชน์จากฟังก์ชั่น df.as_matrix () และสร้าง Numpy-array และส่งผ่านมันได้

Y = df.pop()
X = df.as_matrix()
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size = 0.2)
model.fit(x_train, y_train)
model.test(x_test)

1

อีกเล็กน้อยที่หรูหราสำหรับรสนิยมของฉันคือการสร้างคอลัมน์แบบสุ่มแล้วแยกตามมันด้วยวิธีนี้เราจะได้รับการแบ่งที่จะเหมาะกับความต้องการของเราและจะสุ่ม

def split_df(df, p=[0.8, 0.2]):
import numpy as np
df["rand"]=np.random.choice(len(p), len(df), p=p)
r = [df[df["rand"]==val] for val in df["rand"].unique()]
return r

1

ไม่จำเป็นต้องเปลี่ยนเป็นคนอ้วน เพียงใช้ pandas df ทำการแยกและมันจะคืน pandas df

from sklearn.model_selection import train_test_split

train, test = train_test_split(df, test_size=0.2)

0

ฉันคิดว่าคุณต้องได้รับสำเนาไม่ใช่ชิ้นส่วนของดาต้าเฟรมถ้าคุณต้องการเพิ่มคอลัมน์ในภายหลัง

msk = np.random.rand(len(df)) < 0.8
train, test = df[msk].copy(deep = True), df[~msk].copy(deep = True)

0

แล้วเรื่องนี้ล่ะ df คือ dataframe ของฉัน

total_size=len(df)

train_size=math.floor(0.66*total_size) (2/3 part of my dataset)

#training dataset
train=df.head(train_size)
#test dataset
test=df.tail(len(df) -train_size)

0
shuffle = np.random.permutation(len(df))
test_size = int(len(df) * 0.2)
test_aux = shuffle[:test_size]
train_aux = shuffle[test_size:]
TRAIN_DF =df.iloc[train_aux]
TEST_DF = df.iloc[test_aux]

2
นี่จะเป็นคำตอบที่ดีกว่าถ้าคุณอธิบายว่ารหัสที่คุณให้ไว้ตอบคำถามอย่างไร
pppery

ในขณะที่รหัสนี้อาจตอบคำถามให้บริบทเพิ่มเติมเกี่ยวกับวิธีการและ / หรือทำไมมันแก้ปัญหาจะปรับปรุงค่าระยะยาวของคำตอบ
Shaunakde

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