Як створити тестові та тренувальні зразки з одного фрейму даних з пандами?


322

У мене досить великий набір даних у вигляді фрейму даних, і мені було цікаво, як мені вдасться розділити кадр даних на два випадкові вибірки (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, є кращою. Це менш складний і простіший налагодження. Рекомендую скористатися відповіддю нижче.
Тож S

2
@kuatroka np.random.rand(len(df))- це масив розмірів len(df)з випадковими і рівномірно розподіленими значеннями поплавків у діапазоні [0, 1]. < 0.8Застосовується порівняння поелементно і зберігає результат на місці. Таким чином, значення <0,8 стають, Trueа значення> = 0,8 стаютьFalse
Кенцо

623

scikit learn'strain_test_split - хороший.

from sklearn.model_selection import train_test_split

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

22
Це поверне nummy масиви, а не Pandas Dataframes, однак
Bar

124
Btw, він повертає дану рамку Pandas зараз (щойно перевірена на Sklearn 0.16.1)
Жульєн Маррек

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натомість.
Марк

7
У найновішій версії SciKit його тепер потрібно назвати так:from sklearn.cross_validation import train_test_split
підкова

289

Випадкова вибірка панди також буде працювати

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

Що означає .index / де документація для .index на DataFrame? Я не можу його знайти.
dmonopoly

1
що робить random_stateаргумент?
Рішабх Аграхарі

1
@RishabhAgrahari випадковим чином переміщує різні розділені дані щоразу відповідно до аргументу frac. Якщо ви хочете контролювати випадковість, ви можете вказати власне насіння, як у прикладі.
MikeL

4
Це, здається, працює добре і елегантніше рішення, ніж залучення склеарну. Чи є причина, чому це не має бути краще прийнятої відповіді?
RajV

1
@peer, що обмеження легко виправити, якщо потрібен перетасований testнабір, як зазначено тут stackoverflow.com/questions/29576430/shuffle-dataframe-row . test=df.drop(train.index).sample(frac=1.0)
Алок Лал

32

Я би використовував scikit-learn власний training_test_split і генерував його з індексу

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.
Гаррі

19

Існує багато способів створити зразки поїздів / тестів і навіть перевірку валідації.

Випадок 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 import 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

Якщо вам потрібно розділити свої дані стосовно стовпця міток у вашому наборі даних, ви можете скористатися цим:

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 (столбцы = ['ім'я_ колонки'], вісь = 1)
Антон Ержомін

3

Ви можете використовувати ~ (tilde operator), щоб виключити рядки, відібрані за допомогою df.sample (), дозволяючи пандам самостійно обробляти вибірки та фільтрувати індекси, щоб отримати два набори.

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

2

Це я написав, коли мені потрібно було розділити DataFrame. Я розглядав можливість використання підходу Енді вище, але мені не сподобалося, що я не міг точно контролювати розмір наборів даних (тобто, це було б іноді 79, іноді 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
Це буде працювати лише в тому випадку, якщо дані в кадрі даних вже упорядковані випадковим чином. Якщо набір даних походить з верхніх джерел і додається до одного і того ж фрейму даних, то цілком можливо отримати набір даних із сильним перекосом для навчання / тестування, використовуючи вищезазначене.
Еміль Н

1
Ви можете перетасувати dataframe , перш ніж розділити його stackoverflow.com/questions/29576430/shuffle-dataframe-rows
Makio

1
Абсолютність! Якщо ви додасте, що dfу вашому фрагменті коду перетасовано (або має бути), це відповідь покращить.
Еміль Н

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
Ви можете відредагувати свою відповідь, щоб додати "приблизно", якщо запустити код, ви побачите, що він може бути зовсім від точного відсотка. Наприклад, я спробував це на 1000 предметах і отримав: 700, 141, 159 - так 70%, 14% і 16%.
стасон

2

вам потрібно перетворити фрейм даних панд в numpy масив, а потім перетворити numpy масив назад в кадр даних

 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)

Відповіді, що стосуються лише коду, неприйнятні для переповнення стека.
VFDan

1

Якщо ви бажаєте мати один кадр даних та два фрейми даних (а не нумерові масиви), це має зробити:

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-масив та передати його.

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

0

Я думаю, вам також потрібно отримати копію, а не фрагмент фрейму даних, якщо ви хочете додати стовпці пізніше.

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

0

Як щодо цього? df - мій кадр даних

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

Не потрібно перетворюватися на numpy. Просто використовуйте pandas df, щоб зробити спліт, і він поверне pandas df.

from sklearn.model_selection import train_test_split

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

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

Хоча цей код може відповісти на питання, надаючи додатковий контекст щодо того, як та / або чому він вирішує проблему, покращить довгострокове значення відповіді.
шаунакде

Перший рядок повертає перетасований діапазон (щодо розміру фрейму даних). Другий рядок представляє бажану частку тестового набору. Третя і четверта рядки включають дробу в перетасований діапазон. Лінії відпочинку повинні бути зрозумілими . Поваги.
Еліте Д Генерал
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.