Wie erstelle ich mit Pandas Test- und Trainingsmuster aus einem Datenrahmen?


321

Ich habe einen ziemlich großen Datensatz in Form eines Datenrahmens und habe mich gefragt, wie ich den Datenrahmen für Schulungen und Tests in zwei Zufallsstichproben (80% und 20%) aufteilen kann.

Vielen Dank!

Antworten:


344

Ich würde nur Numpys verwenden 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]

Und nur um zu sehen, hat das funktioniert:

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

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

3
Entschuldigung, mein Fehler. Solange mskder dtype ist bool, df[msk], df.iloc[msk]und df.loc[msk]immer das gleiche Ergebnis zurück.
Unutbu

2
Ich denke, Sie sollten verwenden rand, < 0.8um Sinn zu machen, weil es gleichmäßig verteilte Zufallszahlen zwischen 0 und 1 zurückgibt.
R. Max

4
Kann jemand rein in Python Begriffe erklären , was genau in den Zeilen geschieht in[12], in[13], in[14]? Ich möchte den Python-Code selbst hier verstehen
kuatroka

7
Die Antwort mit sklearn von gobrewers14 ist die bessere. Es ist weniger komplex und einfacher zu debuggen. Ich empfehle die Antwort unten.
Also S

2
@kuatroka np.random.rand(len(df))ist ein Größenarray len(df)mit zufällig und gleichmäßig verteilten Float-Werten im Bereich [0, 1]. Das < 0.8wendet den Vergleich elementweise an und speichert das Ergebnis an Ort und Stelle. So werden Werte <0,8 Trueund Wert> = 0,8False
Kentzo

623

scikit learn'strain_test_split ist gut.

from sklearn.model_selection import train_test_split

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

22
Dies wird jedoch numpy Arrays und nicht Pandas Dataframes zurückgeben
Bar

124
Übrigens gibt es jetzt einen Pandas-Datenrahmen zurück (gerade auf Sklearn 0.16.1 getestet)
Julien Marrec

5
Wenn Sie nach KFold suchen, ist es leider etwas komplexer. 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]Das vollständige Beispiel finden Sie hier: quantstart.com/articles/…
ihadanny

12
In neuen Versionen (0.18, möglicherweise früher) importieren Sie from sklearn.model_selection import train_test_splitstattdessen als .
Mark

7
In der neuesten SciKit-Version müssen Sie es jetzt wie folgt nennen:from sklearn.cross_validation import train_test_split
Hufeisen

288

Pandas Zufallsstichprobe wird auch funktionieren

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

Was bedeutet .index / wo befindet sich die Dokumentation für .index auf einem DataFrame? Ich kann es nicht finden
Dmonopol

1
Was macht random_stateArg?
Rishabh Agrahari

1
@RishabhAgrahari mischt zufällig verschiedene Daten, die jedes Mal entsprechend dem frac arg aufgeteilt werden. Wenn Sie die Zufälligkeit steuern möchten, können Sie wie im Beispiel Ihren eigenen Startwert angeben.
MikeL

4
Dies scheint gut zu funktionieren und eine elegantere Lösung zu sein, als sklearn einzuführen. Gibt es einen Grund, warum dies keine besser akzeptierte Antwort sein sollte?
RajV

1
@peer diese Einschränkung kann leicht behoben werden, wenn ein gemischter testSatz gewünscht wird, wie hier gezeigt . stackoverflow.com/questions/29576430/shuffle-dataframe-rows . test=df.drop(train.index).sample(frac=1.0)
Alok Lal

32

Ich würde scikit-learns eigenen training_test_split verwenden und ihn aus dem Index generieren

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
Das cross_validationModul ist jetzt veraltet: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

19

Es gibt viele Möglichkeiten, einen Zug / Test und sogar Validierungsmuster zu erstellen.

Fall 1: klassischer Weg train_test_splitohne Optionen:

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

Fall 2: Fall eines sehr kleinen Datensatzes (<500 Zeilen): Um mit dieser Kreuzvalidierung Ergebnisse für alle Ihre Zeilen zu erhalten. Am Ende haben Sie eine Vorhersage für jede Zeile Ihres verfügbaren Trainingssatzes.

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)

Fall 3a: Unausgeglichene Datensätze zu Klassifizierungszwecken. Nach dem Fall 1 ist hier die äquivalente Lösung:

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)

Fall 3b: Unausgeglichene Datensätze zu Klassifizierungszwecken. Nach dem Fall 2 ist hier die äquivalente Lösung:

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)

Fall 4: Sie müssen einen Zug- / Test- / Validierungssatz für Big Data erstellen, um Hyperparameter abzustimmen (60% Zug, 20% Test und 20% Wert).

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

Sie können den folgenden Code verwenden, um Test- und Trainingsmuster zu erstellen:

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

Die Testgröße kann je nach Prozentsatz der Daten variieren, die Sie in Ihren Test- und Zugdatensatz aufnehmen möchten.


7

Es gibt viele gültige Antworten. Hinzufügen eines weiteren zum Haufen. aus 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

Sie können auch eine geschichtete Unterteilung in Trainings- und Testgruppen in Betracht ziehen. Die gestartete Aufteilung generiert auch zufällig Trainings- und Testsätze, jedoch so, dass die ursprünglichen Klassenanteile erhalten bleiben. Dadurch spiegeln Trainings- und Testsätze die Eigenschaften des Originaldatensatzes besser wider.

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] und df [test_inds] geben Ihnen die Trainings- und Testsätze Ihres ursprünglichen DataFrame df.


Dies ist die bevorzugte Strategie für überwachte Lernaufgaben.
Vincentmajor

Beim Versuch, dies zu verwenden, wird eine Fehlermeldung angezeigt. ValueError: Zuweisungsziel ist in der Zeile "np.random.shuffle (value_inds)" schreibgeschützt
Markus W

4

Wenn Sie Ihre Daten in Bezug auf die Spalte "Etiketten" in Ihrem Datensatz aufteilen müssen, können Sie Folgendes verwenden:

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

und benutze es:

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

Sie können auch random_state übergeben, wenn Sie die geteilte Zufälligkeit steuern oder einen globalen zufälligen Startwert verwenden möchten.


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
Du hast einen kurzen Fehler. Sie sollten die Zielspalte vorher löschen und in train_test_split einfügen. data = data.drop (Spalten = ['Spaltenname'], Achse = 1)
Anton Erjomin

3

Sie können ~ (Tilde-Operator) verwenden, um die mit df.sample () abgetasteten Zeilen auszuschließen, sodass Pandas allein das Abtasten und Filtern von Indizes durchführen können, um zwei Sätze zu erhalten.

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

2

Dies habe ich geschrieben, als ich einen DataFrame teilen musste. Ich habe überlegt, den obigen Ansatz von Andy zu verwenden, aber es hat mir nicht gefallen, dass ich die Größe der Datensätze nicht genau steuern konnte (dh manchmal 79, manchmal 81 usw.).

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

Wählen Sie einfach die Bereichszeile von df wie folgt aus

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

3
Dies würde nur funktionieren, wenn die Daten im Datenrahmen bereits zufällig sortiert sind. Wenn der Datensatz aus mehreren Quellen stammt und an denselben Datenrahmen angehängt wurde, ist es durchaus möglich, einen sehr verzerrten Datensatz für das Training / Testen mit den oben genannten Informationen zu erhalten.
Emil H

1
Sie können den Datenrahmen mischen, bevor Sie ihn teilen. Stackoverflow.com/questions/29576430/shuffle-dataframe-rows
Makio

1
Absolutheit! Wenn Sie hinzufügen, dass dfin Ihrem Code-Snippet gemischt wird (oder werden sollte), wird die Antwort verbessert.
Emil H

2

Es gibt oben viele gute Antworten, daher möchte ich nur ein weiteres Beispiel hinzufügen, falls Sie die genaue Anzahl der Proben für den Zug und die Testsätze nur mithilfe der numpyBibliothek angeben möchten .

# 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

Um sich in mehr als zwei Klassen wie Zug, Test und Validierung aufzuteilen, kann man Folgendes tun:

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]

Dadurch werden ungefähr 70% der Daten in das Training, 15% in den Test und 15% in die Validierung einbezogen.


1
Möglicherweise möchten Sie Ihre Antwort bearbeiten, um "ungefähr" hinzuzufügen. Wenn Sie den Code ausführen, werden Sie feststellen, dass er vom genauen Prozentsatz abweichen kann. zB habe ich es mit 1000 Artikeln versucht und bekam: 700, 141, 159 - also 70%, 14% und 16%.
Stason

2

Sie müssen den Pandas-Datenrahmen in ein Numpy-Array konvertieren und dann das Numpy-Array wieder in einen Datenrahmen konvertieren

 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)

Nur-Code-Antworten sind bei Stapelüberlauf nicht akzeptabel.
VFDan

1

Wenn Sie einen Datenrahmen ein- und zwei Datenrahmen aus haben möchten (keine numpy Arrays), sollte dies den Trick tun:

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

Sie können die Funktion df.as_matrix () verwenden, ein Numpy-Array erstellen und übergeben.

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

Ein bisschen eleganter für meinen Geschmack ist es, eine zufällige Spalte zu erstellen und diese dann aufzuteilen. Auf diese Weise können wir eine Aufteilung erhalten, die unseren Bedürfnissen entspricht und zufällig ist.

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

Ich denke, Sie müssen auch eine Kopie erhalten, kein Stück Datenrahmen, wenn Sie später Spalten hinzufügen möchten.

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

0

Wie wäre es damit? df ist mein Datenrahmen

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

Keine Notwendigkeit, in numpy zu konvertieren. Verwenden Sie einfach einen Pandas df, um den Split durchzuführen, und es wird ein Pandas df zurückgegeben.

from sklearn.model_selection import train_test_split

train, test = train_test_split(df, test_size=0.2)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.