Grup K-fold dengan stratifikasi target
Saya memiliki pd.DataFrame
pd.DataFrame({
'person': ['a', 'b', 'c', 'aa', 'bb', 'cc', 'aaa', 'bbb', 'ccc'],
'group': [10, 10, 10, 20, 20, 20, 30, 30, 30],
'target': [1, 2, 2, 3, 2, 3, 1, 2, 3]
})
Saya ingin membagi df menjadi train dan menguji kelompok beberapa kali (K-Fold), jadi train and test berisi contoh-contoh dari subset kelompok yang saling eksklusif . Misalnya, jika tes berisi contoh dari grup [10, 20] tes harus berisi contoh hanya dari grup [30]. Saya juga ingin menjaga stratifikasi berdasarkan target. Jadi distribusi target juga dipertimbangkan untuk pembuatan himpunan bagian grup. Bagaimana itu mungkin? Tidak menemukan apa pun di scikit-learn yang dapat membantu.
Dalam praktiknya saya memiliki df dengan sekitar 500k baris, 2.5k orang yang berbeda, 30 grup dan mengikuti distribusi target
Jawaban
Untuk menggunakan kedua grup dan stratifikasi, tampaknya Anda harus menulis kode Anda sendiri. Perhatikan bahwa Anda pasti akan kehilangan sampel dalam pelatihan dan / atau set pengujian (kecuali jika Anda beruntung).
Salah satu cara untuk mencapainya adalah dengan:
- lakukan pemisahan Anda dengan grup (Anda dapat menggunakan metode GroupKFold dari
sklearn) - periksa distribusi target dalam set pelatihan / pengujian.
- menghapus target secara acak dalam pelatihan atau pengujian yang ditetapkan untuk menyeimbangkan distribusi.
Catatan : Ada kemungkinan bahwa grup menghilang menggunakan algoritme semacam itu. Anda mungkin memilih untuk tidak menghapus target secara acak saat menyeimbangkan set pelatihan / pengujian.
Berikut ini contoh kode
import pandas as pd
import numpy as np
from sklearn.model_selection import GroupKFold
df = pd.DataFrame({
'person': ['a', 'b', 'c', 'aa', 'bb', 'cc', 'aaa', 'bbb', 'ccc'],
'group': [10, 10, 20, 20, 20, 20, 20, 30, 30],
'target': [1, 2, 2, 3, 2, 3, 1, 2, 3]
})
X = df['person']
y = df['target']
groups = df['group'].values
group_kfold = GroupKFold(n_splits=3)
group_kfold.get_n_splits(X, y, groups)
# First split by groups
for train_index, test_index in group_kfold.split(X, y, groups):
print("Groups split: TRAIN:", train_index, "TEST:", test_index)
y_train_grouped, y_test_grouped = y[train_index], y[test_index]
final_train_index = []
final_test_index = []
# Then balance the distributions for each target
for target in df['target'].unique():
target_train_index = y_train_grouped[y_train_grouped == target].index.tolist()
target_test_index = y_test_grouped[y_test_grouped == target].index.tolist()
n_training = len(target_train_index)
n_testing = len(target_test_index)
print("Target:" + str(target) + " - n_training:" + str(n_training) + " - n_testing:" + str(n_testing) +
" | target_train_index:" + str(target_train_index) + " - target_test_index:" + str(target_test_index))
# Shuffle to remove randomly
np.random.shuffle(target_train_index)
np.random.shuffle(target_test_index)
# Check if we need to remove samples from training or testing set
if n_training > n_testing:
while n_training > n_testing:
target_train_index.pop(0)
n_training = len(target_train_index)
if n_training < n_testing:
while n_training < n_testing:
target_test_index.pop(0)
n_testing = len(target_test_index)
# Append new indexes to global train/test indexes
final_train_index.append(target_train_index)
final_test_index.append(target_test_index)
# Flatten for readability
final_train_index = [item for sublist in final_train_index for item in sublist]
final_test_index = [item for sublist in final_test_index for item in sublist]
print("FINAL split: TRAIN:", final_train_index," TEST:", final_test_index, "\n")
EDIT
Menggunakan bertingkat cross-validasi tampaknya tidak menjadi wajib (lihat link di bawah), sehingga Anda mungkin mempertimbangkan kembali menggunakannya.
Tautan ini mungkin berguna bagi Anda:
- Mengapa menggunakan validasi silang bertingkat? Mengapa ini tidak merusak manfaat terkait varians?
- Memahami validasi silang bertingkat
- Sebuah studi tentang validasi silang dan bootstrap untuk estimasi akurasi dan pemilihan model
Mengenai over / undersampling, menurut saya sulit untuk menjawab tanpa detail lebih lanjut tentang distribusi data dan seberapa tidak seimbang kelas Anda.