Стратифікований поїзд / тест-спліт у науковому дослідженні


88

Мені потрібно розділити свої дані на навчальний набір (75%) та набір тестів (25%). На даний момент я роблю це за допомогою коду нижче:

X, Xt, userInfo, userInfo_train = sklearn.cross_validation.train_test_split(X, userInfo)   

Однак я хотів би розшарувати свій навчальний набір даних. Як це зробити? Я досліджував StratifiedKFoldметод, але не дозволяв мені конкретизувати розподіл 75% / 25% і лише стратифікувати набір навчальних даних.

Відповіді:


154

[оновлення для 0.17]

Див. Документи sklearn.model_selection.train_test_split:

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.25)

[/ оновлення для 0,17]

Існує запит тягнути тут . Але ви можете просто робити train, test = next(iter(StratifiedKFold(...))) і використовувати поїзд і тестувати індекси, якщо хочете.


1
@AndreasMueller Чи існує простий спосіб стратифікації даних регресії?
Йорданія

3
@ Йорданія в scikit-learn нічого не реалізовано. Я не знаю стандартного способу. Ми могли б використовувати процентилі.
Андреас Мюллер,

@AndreasMueller Ви коли-небудь бачили поведінку, коли цей метод значно повільніший, ніж StratifiedShuffleSplit? Я використовував набір даних MNIST.
snymkpr

@activatedgeek, що здається дуже дивним, оскільки train_test_split (... stratify =) просто викликає StratifiedShuffleSplit і бере перший спліт. Не соромтеся відкривати випуск на трекері з відтворюваним прикладом.
Андреас Мюллер,

@AndreasMueller Я насправді не відкривав проблему, тому що у мене є сильне відчуття, що я роблю щось не так (хоча це лише 2 рядки). Але якщо я все ще можу відтворити його сьогодні кілька разів, я зроблю це!
snymkpr

29

TL; DR: Використовуйте StratifiedShuffleSplit зtest_size=0.25

Scikit-learn пропонує два модулі для розшарованого розщеплення:

  1. StratifiedKFold : Цей модуль корисний як оператор прямої перехресної перевірки в k-кратному форматі: оскільки в ньому буде встановлено набори n_foldsнавчання / тестування, щоб класи були однаково збалансовані в обох.

Ось якийсь код (безпосередньо з наведеної вище документації)

>>> skf = cross_validation.StratifiedKFold(y, n_folds=2) #2-fold cross validation
>>> len(skf)
2
>>> for train_index, test_index in skf:
...    print("TRAIN:", train_index, "TEST:", test_index)
...    X_train, X_test = X[train_index], X[test_index]
...    y_train, y_test = y[train_index], y[test_index]
...    #fit and predict with X_train/test. Use accuracy metrics to check validation performance
  1. StratifiedShuffleSplit : Цей модуль створює єдиний навчально-тестувальний набір, що має однаково збалансовані (стратифіковані) класи. По суті, це те, що ви хочете від n_iter=1. Ви можете вказати розмір тесту тут, як і вtrain_test_split

Код:

>>> sss = StratifiedShuffleSplit(y, n_iter=1, test_size=0.5, random_state=0)
>>> len(sss)
1
>>> for train_index, test_index in sss:
...    print("TRAIN:", train_index, "TEST:", test_index)
...    X_train, X_test = X[train_index], X[test_index]
...    y_train, y_test = y[train_index], y[test_index]
>>> # fit and predict with your classifier using the above X/y train/test

5
Зверніть увагу, що станом на 0.18.x, n_iterмає бути n_splitsдля StratifiedShuffleSplit - і що для нього є дещо інший API: scikit-learn.org/stable/modules/generated/…
lollercoaster

2
Якщо yце серія Pandas, використовуйтеy.iloc[train_index], y.iloc[test_index]
Owlright

1
@Owlright Я спробував використовувати фрейм даних pandas, і індекси, які повертає StratifiedShuffleSplit, не є індексами в фреймі даних. dataframe index: 2,3,5 the first split in sss:[(array([2, 1]), array([0]))]:(
Мегна Натрадж

2
@tangy чому це цикл for? хіба це не так, що коли рядок X_train, X_test = X[train_index], X[test_index]викликається, він замінює X_trainі X_test? Чому тоді не просто сингл next(sss)?
Bartek Wójcik,

13

Ось приклад для даних безперервної роботи / регресії (до вирішення цієї проблеми на GitHub ).

min = np.amin(y)
max = np.amax(y)

# 5 bins may be too few for larger datasets.
bins     = np.linspace(start=min, stop=max, num=5)
y_binned = np.digitize(y, bins, right=True)

X_train, X_test, y_train, y_test = train_test_split(
    X, 
    y, 
    stratify=y_binned
)
  • Де startmin та stopmax від вашої безперервної цілі.
  • Якщо ви не встановите значення, right=Trueце більш-менш зробить ваше максимальне значення окремим контейнером, і ваше розділення завжди буде невдалим, оскільки в цьому додатковому контейнері буде занадто мало зразків.

12

Ви можете просто зробити це train_test_split()методом, доступним у Scikit learn:

from sklearn.model_selection import train_test_split 
train, test = train_test_split(X, test_size=0.25, stratify=X['YOUR_COLUMN_LABEL']) 

Я також підготував короткий GitHub Gist, який показує, як stratifyпрацює параметр:

https://gist.github.com/SHi-ON/63839f3a3647051a180cb03af0f7d0d9


6

На додаток до прийнятої відповіді @Andreas Mueller, просто хочу додати, що як @tangy згадано вище:

StratifiedShuffleSplit найбільш нагадує train_test_split ( stratify = y) з доданими функціями:

  1. стратифікувати за замовчуванням
  2. вказуючи n_splits , він неодноразово розділяє дані

0
#train_size is 1 - tst_size - vld_size
tst_size=0.15
vld_size=0.15

X_train_test, X_valid, y_train_test, y_valid = train_test_split(df.drop(y, axis=1), df.y, test_size = vld_size, random_state=13903) 

X_train_test_V=pd.DataFrame(X_train_test)
X_valid=pd.DataFrame(X_valid)

X_train, X_test, y_train, y_test = train_test_split(X_train_test, y_train_test, test_size=tst_size, random_state=13903)

0

Оновлення відповіді @tangy зверху до поточної версії scikit-learn: 0.23.2 ( документація StratifiedShuffleSplit ).

from sklearn.model_selection import StratifiedShuffleSplit

n_splits = 1  # We only want a single split in this case
sss = StratifiedShuffleSplit(n_splits=n_splits, test_size=0.25, random_state=0)

for train_index, test_index in sss.split(X, y):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y[train_index], y[test_index]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.