パンダを使用して1つのデータフレームからテストとトレーニングサンプルを作成するにはどうすればよいですか?


323

データフレームの形式のかなり大きなデータセットがあり、トレーニングとテストのためにデータフレームを2つのランダムサンプル(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
すみません、私の間違いです。長いほどmskDTYPEでありbooldf[msk]df.iloc[msk]df.loc[msk]常に同じ結果を返します。
unutbu

2
私はあなたが使うべきだと思うrand< 0.8、それは0と1の間で一様に分布する乱数を返すため意味をなさない
R.マックス

4
誰かが正確にラインで何が起こるかPythonの用語で、純粋に説明できin[12]in[13]in[14]?私はここでpythonコード自体を理解したいと思います
kuatroka

7
使用して答えsklearnをからgobrewers14は、より良いものです。複雑さが軽減され、デバッグが容易になります。以下の答えを使用することをお勧めします。
つまり、S

2
@kuatroka np.random.rand(len(df))は、len(df)[0、1]の範囲でランダムかつ均一に分散されたfloat値を持つサイズの配列です。< 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
ただし、これはnumpy配列を返し、Pandas Dataframesは返しません
バー

124
ところで、今はPandas Dataframeを返します(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代わりにインポートします。
マーク

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の意味/ DataFrameの.indexのドキュメントはどこにありますか?見つかりません。
dmonopoly 2017

1
random_statearg は何をしていますか?
Rishabh Agrahari 2017年

1
@RishabhAgrahariは、フラク引数に従って毎回異なるデータ分割をランダムにシャッフルします。ランダム性を制御したい場合は、例のように独自のシードを指定できます。
MikeL 2017年

4
これはうまく機能し、sklearnを導入するよりもエレガントなソリューションのようです。これがよりよく受け入れられる答えにならない理由はありますか?
RajV

1
シャッフル場合@peerその制限は容易に改善されtest、ここで指摘したように組が望まれるstackoverflow.com/questions/29576430/shuffle-dataframe-rowstest=df.drop(train.index).sample(frac=1.0)
Alok Lal

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.
ハリー・

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行)の場合:この相互検証ですべてのラインの結果を取得するため。最後に、使用可能なトレーニングセットの行ごとに1つの予測があります。

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%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

以下のコードを使用して、テストの作成とサンプルのトレーニングを行うことができます。

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

テストのサイズは、テストに入れてデータセットをトレーニングするデータの割合によって異なります。


7

多くの有効な答えがあります。束にもう1つ追加します。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

また、トレーニングとテストセットへの層別分割を検討することもできます。Startified除算では、トレーニングとテストのセットがランダムに生成されますが、元のクラスの比率は維持されます。これにより、トレーニングセットとテストセットが元のデータセットのプロパティをより適切に反映します。

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 2017年

これを使用しようとすると、エラーが発生します。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(columns = ['column_name']、axis = 1)
Anton Erjomin

3

〜(チルド演算子)を使用すると、df.sample()を使用してサンプリングされた行を除外し、パンダのみがインデックスのサンプリングとフィルタリングを処理できるようにして、2つのセットを取得できます。

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
これは、データフレーム内のデータがすでにランダムに並べられている場合にのみ機能します。データセットが複数のソースから派生し、同じデータフレームに追加されている場合、上記を使用してトレーニング/テストのために非常に歪んだデータセットを取得することは十分に可能です。
エミールH

1
あなたはそれが分裂する前にデータフレームをシャッフルすることができますstackoverflow.com/questions/29576430/shuffle-dataframe-rows
牧夫

1
絶対!これをdfコードスニペットに追加すると、シャッフルされます(またはそうする必要があります)と、答えが向上します。
エミールH

2

上記の多くの素晴らしい答えがあるので、numpyライブラリーだけを使用してトレインセットとテストセットの正確なサンプル数を指定する場合は、もう1つ例を追加したいと思います。

# 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

トレーニング、テスト、検証などの3つ以上のクラスに分割するには、次のようにします。

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

あなたが望むのは、1つのデータフレームを入れて2つのデータフレームを出すことです(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

numpyに変換する必要はありません。パンダdfを使用して分割すると、パンダ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は私のデータフレームです

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

最初の行はシャッフルされた範囲を返します(データフレームのサイズに関して)。2番目の行はテストセットの目的の割合を表します。3番目と4番目の行は、割合をシャッフルされた範囲に組み込みます。残りの行は自明です。よろしく。
Elyte D General
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.