Come posso creare test e addestrare campioni da un frame di dati con i panda?


324

Ho un set di dati abbastanza grande sotto forma di un frame di dati e mi chiedevo come avrei potuto dividere il frame di dati in due campioni casuali (80% e 20%) per addestramento e test.

Grazie!

Risposte:


347

Vorrei solo usare 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]

E solo per vedere che ha funzionato:

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

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

3
Scusa, errore mio. Finché mskè di DTYPE bool, df[msk], df.iloc[msk]e df.loc[msk]tornare sempre lo stesso risultato.
unutbu,

2
Penso che dovresti usare randper < 0.8avere un senso perché restituisce numeri casuali distribuiti uniformemente tra 0 e 1.
R. Max

4
Qualcuno può spiegare in termini puramente pitone che cosa succede esattamente in linee in[12], in[13], in[14]? Voglio capire il codice python stesso qui
kuatroka,

7
La risposta che utilizza sklearn da gobrewers14 è la migliore. È meno complesso e più facile da eseguire il debug. Raccomando di usare la risposta qui sotto.
Quindi,

2
@kuatroka np.random.rand(len(df))è un array di dimensioni len(df)con valori float distribuiti in modo casuale e uniforme nell'intervallo [0, 1]. L' < 0.8vale il confronto elemento-saggio e memorizza il risultato in luogo. Quindi i valori <0,8 diventano Truee valore> = 0,8 diventanoFalse
Kentzo il

624

scikit learn'strain_test_split è buono.

from sklearn.model_selection import train_test_split

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

22
Ciò restituirà array intorpiditi e non Pandas Dataframes
Bar

124
A proposito, ora restituisce un Pandas Dataframe (appena testato su Sklearn 0.16.1)
Julien Marrec

5
Se stai cercando KFold, è purtroppo un po 'più complesso. 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]guarda l'esempio completo qui: quantstart.com/articles/…
ihadanny,

12
Nelle nuove versioni (0.18, forse precedente), importare come from sklearn.model_selection import train_test_splitinvece.
Segna il

7
Nella versione più recente di SciKit è necessario chiamarlo ora come:from sklearn.cross_validation import train_test_split
ferro di cavallo

290

Anche il campione casuale di Panda funzionerà

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

Cosa significa .index / dove si trova la documentazione per .index su un DataFrame? Non riesco a trovarlo
Dmonopoli

1
cosa sta random_statefacendo arg?
Rishabh Agrahari,

1
@RishabhAgrahari mescola casualmente dati diversi suddivisi ogni volta secondo il frac arg. Se vuoi controllare la casualità puoi dichiarare il tuo seme, come nell'esempio.
MikeL,

4
Questo sembra funzionare bene e una soluzione più elegante che portare sklearn. C'è un motivo per cui questa non dovrebbe essere una risposta meglio accettata?
RajV,

1
@peer che la limitazione è facilmente risolta se testsi desidera un set mischiato come indicato qui stackoverflow.com/questions/29576430/shuffle-dataframe-rows . test=df.drop(train.index).sample(frac=1.0)
Alok Lal,

32

Vorrei usare il training_test_split di scikit-learn e generarlo dall'indice

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
Il cross_validationmodulo è ora obsoleto: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.
Harry,

20

Esistono molti modi per creare un treno / test e persino campioni di validazione.

Caso 1: modo classico train_test_splitsenza opzioni:

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

Caso 2: caso di set di dati molto piccoli (<500 righe): per ottenere risultati per tutte le linee con questa convalida incrociata. Alla fine, avrai una previsione per ogni linea del tuo set di allenamento disponibile.

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)

Caso 3a: set di dati non bilanciati ai fini della classificazione. Di seguito al caso 1, ecco la soluzione equivalente:

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)

Caso 3b: set di dati non bilanciati ai fini della classificazione. Di seguito al caso 2, ecco la soluzione equivalente:

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)

Caso 4: è necessario creare un treno / test / set di validazione su big data per ottimizzare gli iperparametri (60% di treno, 20% di test e 20% di val).

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

È possibile utilizzare il codice seguente per creare campioni di prova e di addestramento:

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

Le dimensioni del test possono variare in base alla percentuale di dati che si desidera inserire nel set di dati del test e del training.


7

Ci sono molte risposte valide. Aggiungerne uno in più al gruppo. da 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

Puoi anche considerare la divisione stratificata in set di addestramento e test. La divisione Starificata genera anche addestramento e test impostati casualmente ma in modo tale da preservare le proporzioni di classe originali. In questo modo i set di training e test riflettono meglio le proprietà del set di dati originale.

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] e df [test_inds] offrono i set di addestramento e test del DataFrame df originale.


Questa è la strategia preferibile per compiti di apprendimento supervisionato.
vincentmajor,

Quando provo ad usare questo sto ricevendo un errore. ValueError: la destinazione del compito è di sola lettura nella riga "np.random.shuffle (value_inds)"
Markus W

4

Se hai bisogno di dividere i tuoi dati rispetto alla colonna lables nel tuo set di dati puoi usare questo:

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

e usalo:

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

puoi anche passare random_state se vuoi controllare la casualità divisa o usare un seme casuale globale.


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
Hai un breve errore. Dovresti eliminare la colonna di destinazione prima, inserirla in train_test_split. data = data.drop (colonne = ['nome_colonna'], asse = 1)
Anton Erjomin

3

Puoi usare ~ (operatore tilde) per escludere le righe campionate usando df.sample (), lasciando che solo i panda gestiscano il campionamento e il filtraggio degli indici, per ottenere due set.

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

2

Questo è quello che ho scritto quando avevo bisogno di dividere un DataFrame. Ho preso in considerazione l'utilizzo dell'approccio di Andy sopra, ma non mi è piaciuto non poter controllare esattamente la dimensione dei set di dati (cioè, a volte sarebbe 79, a volte 81, ecc.).

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

Basta selezionare la riga di intervallo da df in questo modo

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

3
Funzionerebbe solo se i dati nel dataframe sono già ordinati casualmente. Se il set di dati è derivato da più fonti ed è stato aggiunto allo stesso frame di dati, è possibile ottenere un set di dati molto distorto per la formazione / test utilizzando quanto sopra.
Emil H,

1
È possibile mischiare dataframe prima della divisione che stackoverflow.com/questions/29576430/shuffle-dataframe-rows~~V~~singular~~3rd
Makio

1
Absolutelty! Se aggiungi che lo dfsnippet di codice è (o dovrebbe essere) mischiato, migliorerà la risposta.
Emil H,

2

Ci sono molte ottime risposte sopra, quindi voglio solo aggiungere un altro esempio nel caso in cui si desideri specificare il numero esatto di campioni per il treno e i set di test utilizzando solo la numpylibreria.

# 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

Per dividere in più di due classi come treno, test e validazione, si può fare:

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]

Questo metterà circa il 70% dei dati in formazione, il 15% in prova e il 15% in validazione.


1
Potresti voler modificare la tua risposta per aggiungere "approssimativamente", se esegui il codice vedrai che può essere abbastanza diverso dalla percentuale esatta. ad esempio, l'ho provato su 1000 articoli e ho ottenuto: 700, 141, 159, quindi 70%, 14% e 16%.
Stason,

2

è necessario convertire i frame di dati Panda in array numpy e quindi convertire l'array numpy in frame di dati

 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)

Le risposte di solo codice non sono accettabili su Stack Overflow.
VFDan

1

Se il tuo desiderio è quello di avere un frame di dati in entrata e due di frame di dati in uscita (non array intorpiditi), questo dovrebbe fare il trucco:

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

È possibile utilizzare la funzione df.as_matrix () e creare Numpy-array e passarlo.

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

Un po 'più elegante per i miei gusti è quello di creare una colonna casuale e quindi dividerla, in questo modo possiamo ottenere una divisione che soddisfi le nostre esigenze e sarà casuale.

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
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
Questa sarebbe una risposta migliore se spiegassi come il codice che hai fornito risponde alla domanda.
pppery

Sebbene questo codice possa rispondere alla domanda, fornire un contesto aggiuntivo riguardo a come e / o perché risolve il problema migliorerebbe il valore a lungo termine della risposta.
Shaunakde,

la prima riga restituisce un intervallo mischiato (rispetto alla dimensione del frame di dati). La seconda riga rappresenta la frazione desiderata del set di test. La terza e la quarta riga incorporano la frazione nell'intervallo mischiato. Le restanti linee devono essere autoesplicative .Saluti.
Elyte D Generale,

1

Non è necessario convertire in numpy. Basta usare un panda df per fare la divisione e restituirà un panda df.

from sklearn.model_selection import train_test_split

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

E se vuoi dividere x da y

X_train, X_test, y_train, y_test = train_test_split(df[list_of_x_cols], df[y_col],test_size=0.2)

0

Penso che sia necessario anche ottenere una copia, non una porzione di frame di dati, se si desidera aggiungere colonne in un secondo momento.

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

0

Cosa ne pensi di questo? df è il mio frame di dati

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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.