[БЕЗ_ЗВУКА] В этом видео мы научимся делать разбиение набора данных на подвыборки. С помощью модуля Sklearn.cross_validation мы научимся делать разовые разбиения данных на обучение и тест, а также рассмотрим несколько часто встречающихся стратегий кросс-валидации. По приведенной ниже ссылке доступна документация этого модуля. Мы начнем с того, что импортируем нужные нам модули — это модуль datasets, с которым мы познакомились на предыдущем уроке, и модуль cross_validation. Также нам понадобится библиотека numpy. Теперь давайте загрузим стандартный dataset, снова воспользуемся dataset-ом ирисы Фишера. Теперь предположим, что мы хотим решить задачу классификации. Для этого нам нужно разбить данные на обучение и тест, чтобы впоследствии обучить модель на обучающей выборке и оценить ее качество на тесте. Для этого cross_validation предоставляет нам очень удобную функцию под названием train_test_split. Она позволяет нам построить разовое разбиение данных на обучение и тест. В качестве аргумента функция принимает набор данных, которые мы хотим разбить, набор меток классов, и также ей можно указать соотношение, в котором мы хотим разбивать данные. В данном случае я хочу отправить 30 % объектов в тестовую выборку и все остальные — в обучающую. Давайте это сделаем и посмотрим, что же мы получим в результате. В результате мы получили 4 объекта, train_data и test_data — это части нашей выборки для обучения и для теста, непосредственное описание объектов, и train_labels и test_labels — это метки объектов из обучающей и тестовой выборки соответственно. Теперь давайте убедимся, что наша выборка действительно разбита в заданном соотношении. Мы просто оценим, какую долю тестовая выборка составляет от всех данных. Да, действительно, видим, что 0,3 — так, как мы указали. Теперь давайте выведем размер обучающей тестовой выборки в объектах. Для этого можно оценить размер train_data или test_data и также можно оценить размер train_labels или test_labels. Понятно, что размеры должны получиться одинаковые. Да, действительно, мы видим, что соотношение вот такое, как мы хотели: 105 объектов для обучения и 45 объектов для тестирования. Ну теперь давайте выведем часть нашей обучающей и тестовой выборки и посмотрим, как они выглядят. Ну действительно, это все то же самое, это выглядит ровно так же, как наши исходные данные, просто это некоторая подвыборка из них. Ну и мы можем вывести полностью список лейблов на обучении и на тесте и убедиться, что, действительно, это те же самые лейблы (метки от 0 до 2), и в обучении и в тесте присутствуют объекты всех классов. Довольно удобно. Эта функция позволяет строить разовое разбиение на обучение и тест. Часто это полезно, если мы просто хотим оценить качество нашей модели в одной точке. Если же мы хотим получить более строгую оценку, нам нужно пользоваться кросс-валидацией. Давайте начнем с простого. Первая стратегия кросс-валидации, которую мы рассмотрим, называется KFold. Напоминаю, что в случае KFold мы разбиваем нашу выборку на K групп, при этом каждая из групп 1 раз участвует в тестировании и (K − 1) раз участвует в обучении. Для того чтобы получить такую кросс-валидацию, нам нужно использовать функцию KFold. В качестве аргументов она принимает на вход количество объектов, которое мы хотим разбивать, и количество фолдов, которое нам нужно. В отличие от функции train_test_split, функция KFold не строит нам разбиение исходных данных. Она возвращает нам пару индексов: индексы из обучения и индексы из тестов, с помощью которых мы далее можем самостоятельно разбить нашу выборку. Вот давайте применим эту функцию в случае, когда мы хотим разбить 10 объектов на 5 фолдов, и посмотрим, как выглядят наши индексы. Вот мы видим наши разбиения. Каждый фолд получился размером 2 объекта, и поэтому обучающая выборка состоит каждый раз из 8 объектов, тестовая — из 2-х. Кстати, мы видим, что наши объекты разбиты по порядку. Если посмотреть на тестовую выборку, то мы видим, что каждый раз у нас индексы расположены в исходном порядке. Не всегда это удобно, в качестве примера можете вспомнить dataset ирисы Фишера, в котором наши объекты были исходно отсортированы по метке класса. В данном случае может получиться не очень хорошая ситуация, когда у нас в обучении или в тесте присутствуют представители не всех классов. Чтобы такого избежать, нам нужно указать параметр shuffle и сказать, что он должен быть равен True, то есть мы хотим сделать shuffle с нашей выборкой, хотим перемешать элементы. Вот давайте посмотрим, как будут выглядеть индексы. В данном случае мы построили разбиение на 2 фолда, чтобы было немножечко покороче, и видим, что в данном случае объекты уже расположены не по порядку. Но при этом если мы вызовем эту функцию еще раз или еще раз, мы получаем каждый раз разные разбиения. Не всегда это удобно. Если мы хотим, чтобы результат работы нашей функции был детерминированным, то нам нужно указать параметр random_state, зафиксировать какое именно случайное разбиение мы будем использовать. Вот давайте его укажем и посмотрим. Получили некоторое разбиение, повторные запуски этой функции приводят к таким же разбиениям. Часто это удобно, если мы хотим, чтобы результаты нашей работы были воспроизводимы. Следующая стратегия кросс-валидации, которую мы рассмотрим, называется StratifiedKFold. Она очень похожа на предыдущую, но есть существенное отличие. В данном случае мы сохраняем соотношение классов в обучающих и тестовых подвыборках. Для того чтобы запустить такую функцию, нам нужно передать ей не только количество объектов, но и непосредственно метки классов на объектах, так как разбиение происходит с учетом меток. Поэтому давайте создадим набор меток классов. В данном случае мы создадим список из 10 элементов, первые 5 элементов будут равны 0, последние 5 элементов будут равны 1. Таким образом мы получили задачу бинарной классификации. И передадим этот список меток в нашу функцию. Скажем, что мы хотим сделать разбиение на 2 фолда, также укажем параметр shuffle = True и random_state. Вот давайте посмотрим. Для начала выведем наши метки, а потом индексы. Вот видим, что метки получились такие, как мы хотели, и давайте убедимся, что у нас соотношение объектов в обучающих и тестовых выборках также 50 на 50, как и в исходных метках. Ну вот видим, что объекты с индексом 3 и 4 имеют метку 0, объекты с индексом 8 и 9 имеют метку 1. Соответственно, соотношение правильное. Для примера давайте создадим другой список меток, где метки уже будут идти через одну (0 1 0 1) и посмотрим, как изменятся наши индексы. Функцию запускаем практически с такими же параметрами. Вот видим, что, да, действительно, индексы другие, и видим, что вот наш индекс 1 и 5 — это объекты с меткой 1, индексы 2 и 8 — объекты с меткой 0, то есть соотношение опять правильное, все так, как мы хотели. Следующая интересная стратегия — это ShuffleSplit. Она позволяет строить так называемые случайные перестановки. Таким образом мы можем получить очень много выборок, при этом мы можем специфицировать размер обучающей выборки, и у нас нет никаких ограничений на то, сколько раз каждый объект должен появиться в обучении или в тесте. Каждый раз мы действуем с возвращением, то есть мы получаем одно разбиение и дальше можем строить другое независимо от предыдущего. В качестве аргументов функции нужно указать количество наших объектов, сколько итераций мы хотим и размер тестовой выборки. Вот давайте разобъем данные в соотношении: 80 % — обучение и 20 % — тест, и посмотрим, как будут выглядеть наши выборки. Ну вот мы построили 10 итераций. Невооруженным взглядом видно, что у нас нет никаких ограничений на то, сколько раз объект должен встретиться в обучении или в тесте. Вот, в частности, мы видим, что объект с меткой 0 сразу несколько раз попадает в тест, разбиение действительно случайное. Но shuffle_split также можно стратифицировать. Для этого нужно использовать функцию StratifiedShuffleSplit, и в этом случае мы тоже будем получать выборки, которые имеют исходное соотношение классов. Опять же, для этого нам придется передать target и целевую метку в функцию. И давайте посмотрим, как это выглядит. Сделаем поменьше итераций, сделаем 4 и убедимся, что все правильно. Вот, действительно, каждый раз мы видим, что в тесте есть один объект нулевого класса, один объект первого класса, таким образом, очевидно, что и в обучении у нас также получилась сбалансированная выборка. И последняя стратегия, на которую мы сегодня посмотрим, называется LeaveOneOut. Наверняка вы помните, что это стратегия, которая позволяет оставить каждый объект в тесте 1 раз. Таким образом, тестовая выборка всегда состоит из одного объекта, и каждый объект из нашего набора данных 1 раз присутствует в тесте. Это очень удобная стратегия кросс-валидации, которую хорошо использовать в случае, когда мы имеем небольшую выборку данных. Давайте посмотрим, как это выглядит. Все очень просто. Функции достаточно передать только количество объектов, и легко проверить, что мы получили правильное разбиение. Каждый объект 1 раз присутствует в тестовой выборке. Конечно же, это не единственные стратегии, которыми можно пользоваться. Все остальные вы можете посмотреть в документации по предоставленной ниже ссылке. А мы с вами на этом заканчиваем изучение модуля cross-validation. Мы научились строить разовые разбиения данных с помощью функции train_test_split, а также рассмотрели наиболее популярные стратегии кросс-валидации. В следующем уроке мы перейдем к построению моделей и рассмотрим модуль Linear Models. Мы будем строить линейные модели классификации.