Saya memiliki kerangka data panda dan saya ingin membaginya menjadi 3 set terpisah. Saya tahu bahwa menggunakan train_test_split from sklearn.cross_validation
, seseorang dapat membagi data dalam dua set (melatih dan menguji). Namun, saya tidak dapat menemukan solusi apa pun tentang membagi data menjadi tiga set. Lebih disukai, saya ingin memiliki indeks dari data asli.
Saya tahu bahwa solusinya adalah menggunakan train_test_split
dua kali dan entah bagaimana menyesuaikan indeks. Tetapi apakah ada cara yang lebih standar / built-in untuk membagi data menjadi 3 set, bukan 2?
Jawaban:
Solusi numpy. Kami akan mengocok seluruh dataset terlebih dahulu (
df.sample(frac=1, random_state=42)
) dan kemudian membagi kumpulan data kami menjadi beberapa bagian berikut:In [305]: train, validate, test = \ np.split(df.sample(frac=1, random_state=42), [int(.6*len(df)), int(.8*len(df))]) In [306]: train Out[306]: A B C D E 0 0.046919 0.792216 0.206294 0.440346 0.038960 2 0.301010 0.625697 0.604724 0.936968 0.870064 1 0.642237 0.690403 0.813658 0.525379 0.396053 9 0.488484 0.389640 0.599637 0.122919 0.106505 8 0.842717 0.793315 0.554084 0.100361 0.367465 7 0.185214 0.603661 0.217677 0.281780 0.938540 In [307]: validate Out[307]: A B C D E 5 0.806176 0.008896 0.362878 0.058903 0.026328 6 0.145777 0.485765 0.589272 0.806329 0.703479 In [308]: test Out[308]: A B C D E 4 0.521640 0.332210 0.370177 0.859169 0.401087 3 0.333348 0.964011 0.083498 0.670386 0.169619
[int(.6*len(df)), int(.8*len(df))]
- adalahindices_or_sections
larik untuk numpy.split () .Berikut ini demo kecil untuk
np.split()
penggunaan - mari kita pisahkan larik 20-elemen menjadi beberapa bagian berikut: 80%, 10%, 10%:In [45]: a = np.arange(1, 21) In [46]: a Out[46]: array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]) In [47]: np.split(a, [int(.8 * len(a)), int(.9 * len(a))]) Out[47]: [array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]), array([17, 18]), array([19, 20])]
sumber
frac=1
menginstruksikansample()
fungsi untuk mengembalikan semua (100%
atau fraksi =1.0
) barisnp.random.seed(any_number)
sebelum garis pemisah untuk mendapatkan hasil yang sama dengan setiap proses. Kedua, membuat rasio yang tidak sama sepertitrain:test:val::50:40:10
digunakan[int(.5*len(dfn)), int(.9*len(dfn))]
. Di sini elemen pertama menunjukkan ukuran untuktrain
(0,5%), elemen kedua menunjukkan ukuran untukval
(1-0,9 = 0,1%) dan perbedaan antara keduanya menunjukkan ukuran untuktest
(0,9-0,5 = 0,4%). Koreksi saya jika saya salah :)catatan:
Fungsi ditulis untuk menangani penyemaian pembuatan set acak. Anda tidak boleh mengandalkan pemisahan set yang tidak mengacak set.
import numpy as np import pandas as pd def train_validate_test_split(df, train_percent=.6, validate_percent=.2, seed=None): np.random.seed(seed) perm = np.random.permutation(df.index) m = len(df.index) train_end = int(train_percent * m) validate_end = int(validate_percent * m) + train_end train = df.iloc[perm[:train_end]] validate = df.iloc[perm[train_end:validate_end]] test = df.iloc[perm[validate_end:]] return train, validate, test
Demonstrasi
np.random.seed([3,1415]) df = pd.DataFrame(np.random.rand(10, 5), columns=list('ABCDE')) df
sumber
Namun, salah satu pendekatan untuk membagi dataset ke dalam
train
,test
,cv
dengan0.6
,0.2
,0.2
akan menggunakantrain_test_split
metode dua kali.from sklearn.model_selection import train_test_split x, x_test, y, y_test = train_test_split(xtrain,labels,test_size=0.2,train_size=0.8) x_train, x_cv, y_train, y_cv = train_test_split(x,y,test_size = 0.25,train_size =0.75)
sumber
np.split()
. Selain itu, tidak memerlukan ketergantungan tambahan padasklearn
.Berikut adalah fungsi Python yang membagi dataframe Pandas menjadi train, validasi, dan menguji dataframe dengan pengambilan sampel bertingkat. Ia melakukan pemisahan ini dengan memanggil fungsi scikit-learn
train_test_split()
dua kali.import pandas as pd from sklearn.model_selection import train_test_split def split_stratified_into_train_val_test(df_input, stratify_colname='y', frac_train=0.6, frac_val=0.15, frac_test=0.25, random_state=None): ''' Splits a Pandas dataframe into three subsets (train, val, and test) following fractional ratios provided by the user, where each subset is stratified by the values in a specific column (that is, each subset has the same relative frequency of the values in the column). It performs this splitting by running train_test_split() twice. Parameters ---------- df_input : Pandas dataframe Input dataframe to be split. stratify_colname : str The name of the column that will be used for stratification. Usually this column would be for the label. frac_train : float frac_val : float frac_test : float The ratios with which the dataframe will be split into train, val, and test data. The values should be expressed as float fractions and should sum to 1.0. random_state : int, None, or RandomStateInstance Value to be passed to train_test_split(). Returns ------- df_train, df_val, df_test : Dataframes containing the three splits. ''' if frac_train + frac_val + frac_test != 1.0: raise ValueError('fractions %f, %f, %f do not add up to 1.0' % \ (frac_train, frac_val, frac_test)) if stratify_colname not in df_input.columns: raise ValueError('%s is not a column in the dataframe' % (stratify_colname)) X = df_input # Contains all columns. y = df_input[[stratify_colname]] # Dataframe of just the column on which to stratify. # Split original dataframe into train and temp dataframes. df_train, df_temp, y_train, y_temp = train_test_split(X, y, stratify=y, test_size=(1.0 - frac_train), random_state=random_state) # Split the temp dataframe into val and test dataframes. relative_frac_test = frac_test / (frac_val + frac_test) df_val, df_test, y_val, y_test = train_test_split(df_temp, y_temp, stratify=y_temp, test_size=relative_frac_test, random_state=random_state) assert len(df_input) == len(df_train) + len(df_val) + len(df_test) return df_train, df_val, df_test
Di bawah ini adalah contoh kerja lengkap.
Pertimbangkan kumpulan data yang memiliki label tempat Anda ingin melakukan stratifikasi. Label ini memiliki distribusinya sendiri di kumpulan data asli, misalnya 75%
foo
, 15%,bar
dan 10%baz
. Sekarang mari kita pisahkan kumpulan data menjadi train, validation, dan test menjadi beberapa subset menggunakan rasio 60/20/20, di mana setiap pemisahan mempertahankan distribusi label yang sama. Lihat ilustrasi di bawah ini:Berikut contoh datasetnya:
df = pd.DataFrame( { 'A': list(range(0, 100)), 'B': list(range(100, 0, -1)), 'label': ['foo'] * 75 + ['bar'] * 15 + ['baz'] * 10 } ) df.head() # A B label # 0 0 100 foo # 1 1 99 foo # 2 2 98 foo # 3 3 97 foo # 4 4 96 foo df.shape # (100, 3) df.label.value_counts() # foo 75 # bar 15 # baz 10 # Name: label, dtype: int64
Sekarang, mari panggil
split_stratified_into_train_val_test()
fungsi dari atas untuk melatih, memvalidasi, dan menguji kerangka data mengikuti rasio 60/20/20.df_train, df_val, df_test = \ split_stratified_into_train_val_test(df, stratify_colname='label', frac_train=0.60, frac_val=0.20, frac_test=0.20)
Tiga kerangka data
df_train
,,df_val
dandf_test
berisi semua baris asli tetapi ukurannya akan mengikuti rasio di atas.df_train.shape #(60, 3) df_val.shape #(20, 3) df_test.shape #(20, 3)
Selanjutnya masing-masing dari ketiga pemisahan tersebut akan memiliki distribusi label yang sama yaitu 75%
foo
, 15%bar
dan 10%baz
.df_train.label.value_counts() # foo 45 # bar 9 # baz 6 # Name: label, dtype: int64 df_val.label.value_counts() # foo 15 # bar 3 # baz 2 # Name: label, dtype: int64 df_test.label.value_counts() # foo 15 # bar 3 # baz 2 # Name: label, dtype: int64
sumber
Sangat nyaman digunakan
train_test_split
tanpa melakukan pengindeksan ulang setelah membagi ke beberapa set dan tidak menulis beberapa kode tambahan. Jawaban terbaik di atas tidak menyebutkan bahwa dengan memisahkan dua kali menggunakantrain_test_split
tidak mengubah ukuran partisi tidak akan memberikan partisi yang dimaksudkan pada awalnya:Kemudian porsi validasi dan set pengujian di x_remain berubah dan dapat dihitung sebagai
new_test_size = np.around(test_size / (val_size + test_size), 2) # To preserve (new_test_size + new_val_size) = 1.0 new_val_size = 1.0 - new_test_size x_val, x_test = train_test_split(x_remain, test_size=new_test_size)
Dalam kesempatan ini semua partisi awal disimpan.
sumber
Dalam kasus supervised learning, Anda mungkin ingin membagi X dan y (di mana X adalah masukan Anda dan y adalah keluaran kebenaran dasar). Anda hanya perlu memperhatikan mengocok X dan y dengan cara yang sama sebelum memisahkan.
Di sini, baik X dan y berada dalam kerangka data yang sama, jadi kami mengocoknya, memisahkannya, dan menerapkan pemisahan untuk masing-masing (seperti dalam jawaban yang dipilih), atau X dan y berada dalam dua kerangka data yang berbeda, jadi kami mengacak X, menyusun ulang y dengan cara yang sama seperti X yang dikocok dan menerapkan pemisahan ke masing-masing.
# 1st case: df contains X and y (where y is the "target" column of df) df_shuffled = df.sample(frac=1) X_shuffled = df_shuffled.drop("target", axis = 1) y_shuffled = df_shuffled["target"] # 2nd case: X and y are two separated dataframes X_shuffled = X.sample(frac=1) y_shuffled = y[X_shuffled.index] # We do the split as in the chosen answer X_train, X_validation, X_test = np.split(X_shuffled, [int(0.6*len(X)),int(0.8*len(X))]) y_train, y_validation, y_test = np.split(y_shuffled, [int(0.6*len(X)),int(0.8*len(X))])
sumber