Москва,2017
УДК 004.438Python:004.6
ББК 32.973.22
Р28
Рашка С.
Р28 Python и машинное обучение / пер. с англ. А. В. Логунова. - М.: ДМК Пресс,
2017. - 418 с.: ил.
ISBN 978-5-97060-409-0
Книга предоставит вам доступ в мир прогнозной аналитики и продемонстрирует, по
чему Python является одним из лидирующих языков науки о данных. Охватывая широкий
круг мощных библиотек Python, в том числе scikit-learn, Theano и Keras, предлаrая руко
водство и советы по всем вопросам, начиная с анализа мнений и заканчивая нейронными
сетями, книга ответит на большинство ваших вопросов по машинному обучению.
Издание предназначено для специалистов по анализу данных, находящихся в поисках
более широкого и практического понимания принципов машинного обучения.
УДК 004.438Python:004.6
ББК 32.973.22
Copyright ©Packt PuЫishing 201.5. First puЬlished in the English language under the title 'Python
Machine Leaгning - (9781783555130)'
Все пра ва защищен ы . Любая часть этой I<ниги н е может быть воспроизведена в I<aI<oй бы
то ни было форме и I<аI<ими бы то ни было средствами без письмешюго разреше 1шя владельцев
авторс1шх прав.
Применение регуляри зованных методов для регре ссии." " .. ".""""" .."... " .................. " .. 277
Превращение линейной регрессионной модели в криволинейную -
поли номиальная регрессия ................................................................................... .... .................. 278
Моделирование нелинейных связей в наборе данных Housing """""."""""""""" 280
Обработка нелинейных связей при помощи случайных лесов"""""""".""""""" . 283
Регрессия на основе дерева решений."""" " ." """ " """" """""""""""."" "" """"""" 283
Регрессия на основе случайного леса" """"""" ". """"".".""""".""""""".""""""". 285
Резюме " ... " ....... """ .............................. " .." ........... " ................. " ............ " .. " .... " ............................ " .. 287
Приложение А ........................... ".. "......................... "...................................... "...".... "."." ... ". 380
Оценка моделей ........" .... " ............. """ .. " ......... " ..... "" .................................................. " .... " ..".. " ..
380
Что такое переобучение? ........ " .. "" ....."........."" ......." ... " ....................... " ...... " ......"." .. ".. " ..
380
Как оценивать модель?"" ....." .... "" .... " ......." ... ""." .. " ... "" .............. " ................""."." ..".. ".. 381
Сценарий 1. Элементарно обучить простую модель""""""""""""""""" """"" " 381
Сценарий 2. Натренировать модель и выполнить тонкую настройку
(оптимизировать гиперпараметры) " ......." ............................" ................... "." ...... " .... 382
Сценарий 3. Построить разные модели и сравнить разные алгоритмы
(например, SVM против логистической регрессии против случайных
лесов и т. д. ) """"""""""""""""""""""""""""""""""".""".""""""."""""".""""""""" 383
Перекрестная проверка. Оценка качества оценщика""""""""""""""""""""""""". 384
Перекрестная проверка с исключением по одному""""""""""""""""""""."""""". 386
Пример стратифицированной k-блочной перекрестной проверки"" " """"""" " ". 387
Расширенный пример вложенной перекрестной проверки""" " """"""". "" "" " """ 387
А. Вложенная кросс-валидация : быстрая версия""""""""""""""""".""""."""" 388
Б. Вложенная кросс - валидация: ручной подход с распечаткой
модельных параметров ................ " .... " .......................... " ...................................... " .." ..... 388
В. Регулярная k-блочная кросс-валидация для оптимизации модели
на полном наборе тренировочных данных"" " """""".""""""""""""""."""""""" 389
График проверочной (валидационной) кривой""""""""""""""" " """"""""."""""" 389
Настройка типового конвейера и сеточного поиска."""" """""""""" "" """ " """"" " 391
Машинное обучение .................... """" .... " ..." .... "."""" ..... " ........." ....... " ..... "" .............. "."." .. " .. 393
В чем разница между классификатором и моделью?""""""""" " """"""""" "" """". 393
В чем разница между функцией стоимости и функцией потерь?""""""""""""". 394
Обеспечение персистентности моделей scikit-learn на ocнoвeJSON " """" " """" . 395
н
аверное, не стоит и говорить, что машинное обучение стало одной из самых за
хватывающих технологий современности. Такие крупные компании, как Google,
Facebook, Apple, Amazon, IBM, и еще многие другие небезосновательно вкладывают
значительный капитал в разработку методов и программных приложений в обла
сти машинного обучения. Хотя может показаться, что термин «машинное обучение»
сегодня уже набил оскомину, совершенно очевидно, что весь этот ажиотаж не яв
ляется результатом рекламной шумихи. Эта захватывающая область исследования
открывает путь к новым возможностям и стала неотъемлемой частью нашей по
вседневной жизни. Разговоры с речевым ассистентом по смартфону, предоставление
рекомендаций относительно подходящего продукта для клиентов, предотвращение
актов мошенничества с кредитными картами, фильтрация спама из входящих со
общений электронной почты, обнаружение и диагностирование внутренних заболе
ваний - и этот список можно продолжать.
Если вы хотите стать практиком в области машинного обучения, более основа
тельным решателем задач или, возможно, даже обдумываете карьеру в научно - ис
следовательской области, связанной с машинным обучением, то эта книга для вас!
Однако новичка теоретические идеи, лежащие в основании машинного обучения,
нередко могут подавлять своей сложностью . И все же многие из опубликованных
в последние годы практических изданий способны помочь вам приступить к работе
с машинным обучением на основе реализации мощных алгоритмов обучения. По
моему мнению, использование практических примеров программного кода служит
ковая система по полным текстам научных публикаций всех форматов и дисциплин. Про
ект работает с ноября 2004 r. - Прш.t. перев .
16 Введение
данными подхода.
Условные обозначения
В этой книге вы найдете ряд текстовых стилей, которые выделяют различные виды
информации. Вот некоторые примеры этих стилей и объяснение их значения.
Кодовые слова в тексте, имена таблиц баз данных, папок, файлов, расширения
файлов, пути, ввод данных пользователем и дескрипторы социальной сети Twitter
показаны следующим образом: «И уже установленные пакеты могут быть обновле
ны при помощи флага --upgrade».
Отзывы читателей 19
с
D
dtype : iпt64
Отзывы читателей
Отзывы наших читателей всегда приветствуются. Сообщите нам, что вы думаете об
этой книге - что вам понравилось, а что нет. Обратная связь с читателя ми для нас
очень важна, поскольку она помогает нам форм ировать названия книг, из которых
вы действительно получите максимум полезного.
Отзыв по общим вопросам можно отправить по адресу feedback@packtpub.com,
упомянув заголовок книги в теме вашего электронного сообщения.
20 Введение
Служба поддержки
Теперь, когда вы являетесь довольным владельцем книги издательства «Packt», мы
предложим вам ряд возможностей с целью помочь вам получать максимум от своей
покупки.
Опечатки
Вопросы
Если у вас есть вопрос по каким-либо аспектам этой книги, то вы можете связаться
с нами по электронному адресу questions@packtpub.com, и мы приложим все уси
лия, чтобы решить ваш вопрос.
Комментарий переводчика
Весь материал книги приведен в соответствие с последними действующими версия
ми библиотек (время перевода книги - октябрь-ноябрь 2016 г.), дополнен свежей
информацией и протестирован в среде Windows 10 и Fedora 24. При тестировании
исходного кода за основу взят Python версии 3.5.2.
Большинство содержащихся в книге технических терминов и аббревиатур для
удобства кратко определено в сносках, а для некоторых терминов в силу отсутствия
единой терминологии приведены соответствующие варианты наименований или
пояснения. Книга дополнена ~глоссарием основных терминов и сокращений». В при
ложении к книге особое внимание уделено оценке качества машиннообучаемых мо
делей .
На веб-сайте Github имеется веб-страница книги, где содержатся обновляемые
исходные коды прилагаемых к книге программ, много дополнительных материалов
либо как 1vl1i: рiрЗ install scipy-0 .18. l - cp35 - cp35m-win_amd64 - any. whl
рiрЗ i nstall jupyter
рiрЗ install theano
рiрЗ install keras
р i рЗ instal l nltk
р i рЗ install seaborn
р i рЗ install flask
рiрЗ install pyprind
рiрЗ install wtforms
факультатиш10:
рiрЗ i nsta l l mlxtend
рiрЗ install pyqtS
рiрЗ install spyder
И чтобы обновить:
Во всех вышеперечисленных случаях речь идет о версии Spydeг для Python 3 (на
момент инсталляции это был Python 3.5.2).
Установка среды Spydeг в Windows:
рiрЗ install spyder
Глава 1
Наделение компьютеров
способностью обучаться на данных
п
о моему убеждению, машинное обучение как область практической деятельно
СJИ и как сфера научных исследований алгоритмов, извлекающих смысл из дан
ных, является самой захватывающей отраслью всей информатики! В наш век пере
избытка данных при помощи самообучающихся алгоритмов мы можем превратить
эти данные в знание. Благодаря тому что за последние несколько лет были разра
ботаны многочисленные мощные библиотеки с открытым исходным кодом, вероят
но, никогда еще не появлялся столь подходящий момент для того, чтобы ворваться
в область машинного обучения и научиться использовать мощные алгоритмы, по
зволяющие обнаруживать в данных повторяющиеся образы и делать прогнозы о бу
дущих событиях.
В этой главе мы узнаем об общих принципах машинного обучения и его типах.
Вместе с вводным курсом в соответствующую терминологию мы заложим основу
для того, чтобы успешно использовать методы машинного обучения для решения
практических задач .
Обучение с подкреплением
1
Класс - это множество всех объектов с данным значением метки. - Пршt. перев.
Под образцом, или экземпляром (sample), здесь и далее по тексту подразумевается совокуп
2
о о 1
1
о 1
о + 1
1
00 1
+
о 1
+ +
1
о
1
Х2 • о 1
о о 1
1
+ +
+ ++
1
о 1
о 1
о 1
1
+ + +
о 1
1
+ + +
Xi
1
SAT Math - тест по математике для будущих бакалавров ( http://test-sat. ru/sat-math/). -
Прим. перев.
Три типа лtашинного обучепия 29
1
Геометрически пересечение (intercept) - это точка, в которой линия регрессии пересекает
ось У. В формуле линейной регрессии пересечение - это свободный коэффициент, кото
рому равна з ависимая переменная, если предиктор, или независимая переменная, равен
Среда
Вознагражд ение
Состояние
А1 ....
~
,.. ~
,..
:-- Действие
.
Агент
при помощи трех - или двухмерных точечных графиков или гистограмм. Рисунок
ниже показывает пример использования нелинейного снижения размерности для
сжатия трехмерного швейцарского рулета (Swiss гoll) в новое двумерное подпро
странство признаков:
32 Наделение ко11тыотеров способностью обучаться на данных
Чашелистик
Признаки
/ Метки классов
(цели)
(атрибуты, данные измерений, размерности)
1
Ирисы Фишера (Iгis) - набор данных для задачи классификации, на примере которого Ро
нальд Фишер в 1936 году продемонстрировал разработанный им метод дискриминантного
анализа . Для каждого экземпляра измерялись четыре характеристики/признака (в сантиме
трах): длина чашелистика (sepal length), ширина чашелистика (sepal width); длина лепестка
(petal length), ширина лепестка (petal width). Этот набор данных уже стал классическим
и часто используется в литературе для иллюстрации работы различных статистических ал
горитмов (см. https://ru.wikipedia.org/wiki/Иpиcы_ Фишepa). - Пршt. перев.
Дорожная карта для построения сuсте.м .машииного обучения 33
В остальной части этой книги мы будем использовать надстрочный индекс (i) для обо
с+ значения i-й тренировочного образца и подстрочный индекс j для обозначения j-й раз
мерности тренировочного набора данных.
Мы используем заглавные (прописные) буквы, набранные жирным шрифтом, для обо
1
значения векторов (х Е R"x ) и строчные буквы, набранные жирным шрифтом, для обо
значения матриц соответственно (Х Е R"x'") . Для обозначения в векторе или матрице
отдельных элементов мы пишем буквы курсивом, соответственно х<") или х~~
Например, x:so обозначает первое измерение 150-го образца цветков, длину чашелис
тика. Таким образом, каждая строка в этой матрице признаков представляет один эк
земпляр цветка и может быть записана как четырехмерный вектор-строка :J-i> Е JR 1x
4
,
X(I)
)
х<2>
)
x<1so)
)
[
у(!) ]
денная ниже схема показывает типичную диаграмму потока операций при исполь
зовании машинного обучения в прогнозном моделировании, которое мы обсудим
в последующих подразделах:
Выделение
и масштабирование признаков
Отбор признаков
Снижение размерности
Взятие выборок
1м;ки1----1
Алгоритм
.----' - ---. :• .......
Окончательная ..._._ --1
Тренировочный Новые данные
•-------·
-
1
--------------.i
1
1
.... -""!!''!!!1'-•-"'
1
:
1
1
Отбор модели
Перекрестная проверка
Метрики качества
Гиперпараметрическая
оптимизация
Исходные (необработанные) данные редко поступают в том виде и в той форме, ко
торые необходимы для оптимальной работы алгоритма обучения. Поэтому предобра
ботка данных является одним из самых важных этапов в любом приложении с ис
пользованием машинного обучения. Если в качестве примера взять набор данных
цветков ириса из предыдущего раздела, то исходные данные можно представить как
Д. Вульперт (1996) показал, что попытки найти алгоритм обучения без смещений беспо
1
лезны. Кроме того, он продемонстрировал, что в свободном от шума сценарии, где функция
потерь эквивалентна коэффициенту ошибочной классификации, если вы интересуетесь
ошибкой вне тренировочного набора, то между алгоритмами обучения нет никаких апри
орных различий . См . http://www.no-free-lunch .org/. - Прим. перев .
Иными словами, когда у вас в руках молоток, все задачи кажутся гвоздями.
- Пршt. перев.
В машинном обучении точность (precision) является мерой статистической изменчивости
3
После того как мы отобрали модель, подогнанную под тренировочный набор дан
ных, мы можем воспользоваться тестовым набором данных и оценить, насколько
хорошо она работает на этих ранее не встречавшихся ей данных, чтобы вычислить
ошибку обобщения . Если мы удовлетворены качеством модели, то теперь мы можем
использовать ее для прогнозирования новых будущих данных. Важно отметить, что
параметры для таких ранее упомянутых процедур, как масштабирование признаков
и снижение размерности, получают исключительно из тренировочного набора дан
ных, и те же самые параметры позже применяют повторно для трансформирования
тестового набора данных, а также любых новых образцов данных - в противном
случае измеренное на тестовых данных качество модели может оказаться сверхоп
тимистичной.
1
Перекрестная проверка, валидация (cross validation, CV) - это метод подтверждения ра
ботоспособности моделей, который используется для оценки того, насколько точно про
гнозная модель будет работать на практике . Задача перекрестной проверки - выделить
из тренировочного набора данных подмножество данных, которое будет использоваться
с целью « протестировать » модель на этапе ее тренировки (так называемый перекрестно
проверочный набор), с тем чтобы ограничить такие проблемы , как переобучение, и дать
представление о том, как модель будет обобщаться на независимый набор данных (т . е . ра
нее не встречавшихся данных, например из реальной задачи). - Прим . перев.
Использовапие Python длл .маши1111ого обучеиия 37
данными, делая работу с табличными данными еще более удобной. В помощь на
шей познавательной деятельности, а также в целях визуализации количественных
данных, что порой бывает чрезвычайно полезно делать для интуитивного пони
мания материала, мы будем пользоваться полностью настраиваемой библиотекой
matplotlib.
Номера версий основных пакетов Python, которые использовались при написа
нии этой книги , упомянуты ниже . Удостоверьтесь, что номера версий ваших уста
новленных пакетов идентичны приведенным в списке или выше, чтобы примеры
программ гарантированно выполнялись корректно:
Hello world
3.0 ......-----...~-~--.....------..-~~--.......
2 .5
2.0
1..5
$ cd ~/code/python-machine-learning-book
$ jupyter notebook
: QI ;- « /
t - - -
code / ch01
D ..
О D images
1/;' ch01 .ipynb
О D README.md
Резюме
В этой главе мы провели широкомасштабную разведку обширной области информа
тики - машинного обучения и ознакомились с общей картиной и ее главными кон
цепциями, которые мы собираемся разобрать в следующих главах более подробно.
Мы узнали, что обучение с учителем состоит из двух важных подобластей: задач
классификации и регрессии. В отличие от модели классификации, которая позво
ляет распределять (категоризировать) объекты по известным классам, мы можем
применять регрессию с целью предсказания непрерывных результатов для целевых
После того как мы охватим все важные концепции типичного конвейера машин
ного обучения 1, в главе 8 <.<Применение алгоритмов машинного обучения в анализе мне
ний» займемся реализацией модели, предназначенной для прогнозирования эмоций
в тексте, в главе 9 <.<Встраивание алгоритма машинного обучения в веб-приложение»
мы встроим ее в веб-приложение, чтобы поделиться им с миром . Затем в главе 10
<.<Прогнозирование непрерывных целевых величин на основе регрессионного анализа»
мы воспользуемся алгоритмами машинного обучения для регрессионного анализа,
которые позволят прогнозировать непрерывные выходные переменные, и в главе 11
<.<Работа с немаркированными данными - кластерный анализ» мы применим алго
ритмы кластеризации, которые позволят находить в данных скрытые структуры.
' В информатике конвейер представляет собой набор элементов обработки данных, соеди
ненных последовательно, где выход одного элемента является входом следующего. Эле
менты конвейера часто выполняются параллельно по принципу квантования по времени . -
Прим . перев.
Глава2
Тренировка алгоритмов
машинного обучения
для задачи классификации
в методами
этой главе мы воспользуемся двумя первыми алгоритмически описанными
машинного обучения, применяемыми для классификации данных,
персептроном и адаптивными линейными нейронами. Мы начнем с пошаговой реа
лизации персептрона на языке Python и его тренировки для решения задачи клас
сификации различных видов цветков из набора данных Ирисов Фишера (lгis). Это
позволит нам понять принцип работы алгоритмов машинного обучения при реше
нии задачи классификации и каким образом их можно эффективно реализовывать
на Python. Затем мы перейдем к обсуждению азов оптимизации с использованием
адаптивных линейных нейронов, которые заложат основу для использования более
мощных классификаторов на основе библиотеки машинного обучения scikit-learn
в следующей г.лаве З «Обзор 1(,Jlассификаторов с использованием библиотеки scikit-
learn».
В этой главе мы затронем следующие темы:
Qf> формирование интуитивного понимания алгоритмов машинного обучения;
~ использование библиотек pandas, NumPy и matplotlib для чтения, обработки
и визуализации данных;
Аксон
Более формально эту проблему можно изложить как задачу бинарной классифи
кации, где для простоты мы обозначим наши два класса как 1 (положительный класс)
и - 1 (отрицательный класс). Затем можно определить передаточную функцию, или
функцию активации ф(z), которая принимает линейную комбинацию определенных
входных значений, или входной вектор х, и соответствующий весовой вектор w, где
z- это так называемый чистый вход (от англ. net input) (z = w1x 1 + ". + w";x,,,):
Персептрон еще часто называют пороговым сумматором. Правило, или процесс, обучения -
это применяемый многократно метод (математическая формула) обновления весов и узла
смещения модели, который улучшает ее эффективность. - При.м. перев.
После обучения персептрон готов работать в одном из двух режимов: распознавания либо
обобщения. - Прим. перев .
44 IjJенировка алгориmJ.юв J.tашинного обучения для задачи классификации
Теперь если активация отдельно взятого образца x<i), т. е. выход из ф(z), превы
шает заданный пороге, то мы распознаем класс 1, в противном случае - класс -1.
В алгоритме персептрона функция активации ф(-) - это простая едu1tИЧ1tая стуnе1t
чатая фу1tкцuя, которую иногда также называют стуnе1tчатой фу1tкцией Хевисайда
(или функцией единичного скачка):
ф(z)={1, еслиz~О
-1, иначе
Например' 123]х[~] =
[ tx 4+2 х5 3х6 =
+ 32.
14
3 2]т
[1 3 5]·
[5 6
=
2 4 6
ф(wтх) =О
ф(wrx)
ф(w х) <о
1
\ ф(и/х):::: о
о
1 о
о + +
о
00 +
Х2
о о + +
WTX о о + +
-1
00
о + ++
о + +++
о +
Х1
w1 := w1 + ЛwJ"
где ri - это темп обучения (константа между О.О и 1.0), y<iJ_ истинная метка класса
i-го тренировочного образца и y(i) - идентифицированная метка класса. Важно от
метить, что все веса в весовом векторе обновляются одновременно, т. е. мы не вы
числяем ·[/> повторно до тех пор, пока все веса Лw1 не будут обновлены. Конкретно
для двумерного набора данных мы запишем обновление следующим образом:
о
Оо 1
1
+ о о о • о
+ о о
Х2
о о 1
1 •
+
+ Х2 о ... + Х2 о •++
•• +
Оо 1
1
• • Оо
о +
• + ... о
о
О 1'
, +
• о + • о о
Х1 Х1 Х1
.......,-'!+!"'!!'!'• Выход
входа
Если вы еще незнакомы с научными библиотеками Python или же вам требуется осве
с+ жить свои з нания, пожалуйста, обратитесь к следующим ресурсам:
Библиотека NumPy: http://wiki . scipy. org[Тentative_NumPy_Tutorial
Библиотека Pandas: http://pandas . pydata . org/pandas-docs/staЫe/ tutorials.html
Библиотека Matplotlib: http://matplotlib.org/users/beginner. html
Кроме того, для того чтобы лучше отслеживать приводимые примеры, рекомендуется
скачать блокноты Jupyter с веб-сайта Packt. По поводу общих сведений о записных
книжках Jupyter посетите http://jupyter.org/ или обратитесь к документации по IPython
http://ipython . readthedocs.io/en/staЫe/. Исходные коды примеров, блокноты Jupyter и до
полнительную информацию можно также получить на странице книги на Github https://
github.com/rasbt/python-machine-learning-book.
import numpy as np
class Perceptron(object):
"""класс ификатор на основе персептрона.
Параметры
eta : float
Темп обучения (между О.О и 1 .0 )
n iter : int
Проходы по тренировочному набору данных.
Атрибуты
w : 1 - мерный массив
Весовые коэффициенты после подгонки.
errors список
def fit(self, Х, у) :
"""Выполнить подгонку модели под тренировочные данные .
Параметры
Реализация алгоритлtа обучеиия персептроиа 11а Python 49
Возвращает
self : object
self . w = np . ze r os (l + X. shape[l] )
self . errors = []
de f net_input(self , Х ):
' " Рассчитать
1
чистый вход
11 11 11 11
Вместо того чтобы для вычисления скалярного произведения двух массивов а и Ь ис
с+ пользовать библ иотеку NumPy, применяя для этого
a.dot(b) или np.dot(a, Ь), это вычис
ление можно выполнить на чистом в виде
sum([i*j, for i, j in zip( a, Ь)]. Однако
Python
преимущество использования библиотеки NumPy над классическими структурами
цикла for на Python заключается в том, что ее арифметические операции векторизо
ваны . Векторизация означает, что элементарная арифметическая операция автомати
чески применяется ко всем элементам в массиве. Формулируя наши арифметические
операции в виде последовательности инструкций на массиве вместо выполнения серии
операций для каждого элемента по одному, мы можем лучше использовать наши со
временные процессорные архитектуры с поддержкой ОКМД (SIMD), т. е. одиночного
потока команд, множественного потока данных (single instruction, multiple data). Кро
ме того, в библиотеке NшnPy используются высокооптимизированные динамические
библиотеки линейной алгебры, такие как библиотека основных подпрограмм линейной
алгебры BLAS (Basic Linear Algebra Subprograms) и пакет линейной алгебры LAPACK
(Linear Algebra Package), написанные на С или Fortran. Наконец, библиотека NurnPy
также поз воля ет писать исходный код в более компактном и интуитивном виде, исполь
зуя основы линейной алгебры, такие как скалярные произведения векторов и матриц.
»>
i mport pandas as pd
url = ' https : //archive.ics . uci . edu/ml/machine - learning-dataЬases/iris/iris . data'
df = pd . read_csv(url , header=None)
df. tail ()
о 1 2 3 4
145 6.7 3.0 5.2 2.3 Iris-v i гginica
• • • щети нистый 1
5 1х хх ра з ноцветны й х
х хх хххх
х хх х~х ххх х
х ххх хх
х !! !! ~ х х х
х
!! х я
х х х
х х
• •
••
• ···==·····=·
• •
О'-----"-----'----~---~---~---~---~
4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5
длина чашелистика [см]
~ 2.5
~
-&
~ 2.0. - - - ·
~
"";;
С1
.g 1.5
s:
3
С1
"'~ 1.0
5
Q
~ 0.5
'7'
1 10
Эпохи
Реализация ал2оритма обучеиил персептроиа па Python 53
создаем пару матричных массивов xxl и хх2 , используя для этого функцию mesh-
grid библиотеки NumPy 1• Учитывая, что мы натренировали наш персептронный
классификатор на двупризнаковых размерностях, мы должны сгладить матричные
массивы и создать матрицу с тем же самым числом столбцов, что и у тренировочно
го подмножества цветков ириса, в результате чего можно применить метод predict
и идентифицировать метки классов Z для соответствующих точек матрицы . После
преобразования формы идентифицированных меток классов Z в матрицу с такими
же размерностями, что и у xxl и хх2 , можно начертить контурный график, исполь
зуя для этого функцию contourf библиотеки matplotlib, которая ставит в соответ
ствие разным областям решения разный цвет по каждому идентифицированному
классу в матричном массиве:
plot_decision_regions(X, у, classifier=ppn)
рlt . хlаЬеl('дпина чашелистика [см]')
pl t . ylaЬel ( 'длина лепестка [см] ' )
plt . legend(loc='upper left')
plt. show()
•
•···==·1•··=·
• :•
4
длина чашелистика [см]
с+
Несмотря на то что персептрон полностью р аспределил цветки ириса на два класса, схо
димость представляет для персептрона одну из самых больших проблем. Фрэнк Розен
блатт математически доказал, что правило обучения персептрона сходится , только если
два класса могут быть разделены линейной гиперплоскостью. Однако если полностью
разделить классы такой линейной границей решения невозможно, то без установления
максимального числа эпох веса никогда не прекратят обновляться.
Выход
1
Член полусуммы - добавлен просто для удобства; как мы убедимся в после-
2
дующих абзацах, он упростит получение градиента. В отличие от единичной сту
пенчатой функции, основное преимущество этой непрерывной линейной функции
активации состоит в том, что функция стоимости становится дифференцируемой.
Еще одно хорошее свойство этой функции стоимости - в том, что она выпуклая;
следовательно, мы можем использовать простой и одновременно мощный алгоритм
оптимизации - алгоритм градиентного спуска для нахождения весов, которые мини
мизируют нашу функцию стоимости для решения задачи классификации образцов
в наборе данных цветков ириса
1
•
Как проиллюстрировано на нижеследующем рисунке, мы можем описать лежа
щую в основе градиентного спуска идею как спуск вниз по склону холма, пока не
,/---------
'\ 1
w := w + Лw.
Здесь изменение веса Лw определяется как отрицательный градиент, помножен
ный на темп обучения 11:
Лw = - 11V](w).
owj owj 2 i
= L(y<i) _ф(z(i»)(-x)i))
=-L:(y<i) _ф(z(i»)x)i).
i
cl ass AdalineGD(object) :
"'"'Классификатор на основе ADALINE (ADAptive Llnear NEuron ).
Параметры
eta : float
Темп обучения ( между О .О и 1 . 0)
n iter : int
58 Тренировка алгоритмов .машинного обучения для задачи классификации
Атрибуты
w_ : 1 - мерный массив
Веса после подгонки .
errors список
def fi t( self , Х , у ):
""" Выполнить подгонку под т ренир о в о чные д анные .
Параметры
Возвращает
self : объект
def predict(self , Х ):
11111
' В е рнуть метку класса посл е е дин ичного скачка """
re t ur n np . where (s el f . ac tivat ion(X) >= О . О , 1, - 1)
Вместо того чтобы обновлять веса после выполнения оценки каждого отдельного
тренировочного образца, как в персептроне, мы вычисляем градиент на основе всего
тренировочного набора данных, используя self.eta * errors.sum() для веса в нулевой
позиции и self.eta * X.T.dot(errors) для весов от 1 пот , где X.T.dot(errors) - это мат-
Адаптивные линейные нейроны и сходшюсть обучения 59
Темп обучения ТJ и число э пох n_iter - это так наз ы ваемые гиперпарw.tетры алгорит
с+ мов о,ручен ия ADALIN E и персептрона . В главе 4 .-.Создание хороших тренир овочных
наборов - предобработка даииых'-> мы рассмотрим различные методы автоматического
нахождения значений различ ных гиперпараметров, которые п риводят к оптимальному
качеству модели классиф икац ии данных .
4Z
40'-----'~---'-~--'-~-'-~.1..----'~-'-~-'----"
1 4 10
Эпохи Эпохи
Исходный вес
~
Глобальный минимум
СТОИМОСТИ Jmin(w)
w w
х. -µ.
X J'.=-J _ _
J
•
cr j
Здесь x j - это вектор, состоящий из значения j-го признака из всех трени р овоч
ных образцов п.
Стандартизацию можно легко получить при помощи методов mean и std библио
теки NumPy:
X_std = np.copy(X)
X_std[: , 0] (Х[ : ,0] - X[:,0].mean()) / X[ : ,0] . std()
X_std[ :, l] = (Х[ :, 1] - X[ : ,l].mean()) / X[ :, l] . std()
•=i •• 1. •l 1 - 1•
•1 • ·-
-z
-z -1 о
40
""
о
\О
:s::
3
о
><
:;; 30
":s::
:т
...:g,
С(
~ 20
"'::Е
:о:
б'
10
O'--~~-'-~~-i.~~~"--~~-'-~~--'~~~..._~~-'-~~--'
о 4 10 12 14 16
Эпохи
нять переоценку всего тренировочного набора данных каждый раз, когда мы делаем
один шаг к глобальному минимуму.
Популярной альтернативой алгоритму пакетного градиентного спуска является
стохастический градuе1tт1lый спуск, иногда также именуемый итератив1tьtМ, или
динамическим (онлайновым), градиентным спуском. Вместо обновления весов, ос
новываясь на сумме накопленных ошибок по всем образцам x<i):
С!
тического градиентного спуска. В методе fit мы теперь будем обновлять веса после
каждого тренировочного образца. Кроме того, мы реализуем дополнительный метод
частичной подгонки partial_fit, который повторно не инициализирует веса, чтобы
учесть динамическое обучение . Для того чтобы удостовериться, что наш алгоритм
сходился после тренировки, мы вычислим стоимость как усредненную стоимость
class AdalineSGD(object):
""" Классификатор на основе ADALINE (ADAptive Linear Neuron).
Параметры
eta : float
Темп обучения (между О . О и 1 . 0)
n iter : int
Пр охо ды по тренировочному набору данных.
Атрибуты
errors : list/cпиcoк
Число случаев ошибочной классификации в каждой эпохе.
shuffie : bool (по умолчанию: True)
Перемешивает тренировочные данные в каждой эпохе, если True,
для предотвращения зацикливания .
Пар аметры
Возвращает
self : объект
r = пp . raпdom.permutatioп(leп(y))
returп X[r], y[r]
sel f . w = пp . zeros(l + m)
self.w iпitialized = True
plt. show ()
I 40
::! 1
.&
:;: 1i
~
~ 30
~
~
g
ш
о
l
ю
20
~ 1 "s
••..•:i·1•···· •
-1 ~
~ 10
-1
о
-2 -1 о 10 12 14 16
длин а чашелистика {стандартмзоаан н аА) Эпохи
Как видно, средняя стоимость довольно быстро уходит вниз, а окончательная гра
ница решения после 15 эпох выглядит аналогично пакетному градиентному спуску.
Если нашу модель нужно обновить, например в сценарии динамического обучения
с потоковой передачей данных, то мы можем просто вызывать метод partial_fit на
индивидуальных образцах, к примеру ada.partial_fit(X_std[O, :], у[О]).
Резю~1е 67
Резюме
В этой главе мы получили хорошее представление об основных принципах работы
линейных классификаторов, используемых в обучении с учителем. После реализа
ции персептрона мы познакомились с методами эффективной тренировки адаптив
ных линейных нейронов (ADALINE) векторизованной версией метода градиентного
спуска и с динамическим обучением методом стохастического градиентного спуска.
Научившись реализовывать простые классификаторы на Python, теперь мы готовы
перейти к следующей главе, где воспользуемся библиотекой машинного обучения
scikit-l eaгn языка Python для доступа к более продвинутым и мощным стандартным
машиннообучаемым классификаторам, которые обычно используются в научных
кругах и в информационной отрасли.
ГлаваЗ
Обзор классификаторов
с использованием библиотеки
scikit-learn
в
этой главе мы пройдемся по массиву популярных и мощных алгоритмов машин
ного обучения, которые обычно используются в научных кругах и в информаци
онной отрасли . По мере ознакомления с различиями между несколькими алгорит
мами обучения с учителем для решения задачи классификации мы также получим
интуитивное представление об их индивидуальных достоинствах и недостатках .
Кроме того, мы сделаем наши первые шаги в работе с библиотекой scikit-learn, кото
рая предлагает пользователю удобный интерфейс для эффективного и продуктив
ного использования этих алгоритмов .
Поскол ьку принятый в книге подход состоит в посте пенном накоплении зна
ний в области машинного обучения, в этой главе мы в основном сосредоточимся
на основных принципах работы разных алгоритмов и в дальнейшем в целях более
детального обсуждения будем пересматривать такие темы, как, например, отбор
и предобработка признаков, качественной метрики и тонкая настройка гиперпара
метров.
>»
y_pred = ppn . predict(X_test_std)
print('Чиcлo ошибочно классифицированных образцов : %d ' % (y_tes t ! = y_pred) .sum())
Число ошибочно классифицированных обра зцов: 4
>»
from sklearn.metrics import accuracy_score
%. 2f ' % accuracy_score(y_test , y_pred))
print( ' Bepнocть:
Верность: 0 .91
Здесь у_test - это истинные метки классов, y_pred - метки классов, которые мы
идентифицировали ранее .
Отметим, что в этой главе мы оцениваем качество наших моделей, основываясь на те
с+ стовом наборе. В главе 5 «Сжатие данных путе.м снижения раз.мерности;, вы узнаете
о полезных методах, включая графический анализ, такой как кривые обучения, чтобы
обнаруживать и предотвращать переобучение. Термин «переобучение;, означает, что
модель хорошо захватывает повторяющиеся образы (закономерности, паттерны) в тре
нировочных данных, но ей не удается хорошо обобщаться на ранее не встречавшиеся ей
данные.
• • 11 о
Х Хх 1
ооо 2
ООО тестовый набор
-2
-2 -1
дпина лепестка [ста ндартизова нн ая]
Класс Percept ron, а также другие функции и классы библиотеки scikit-learn имеют до
с+ полнительные параметры, которые мы для ясности пропускаем. Дополнительную ин
формацию об этих параметрах можно прочесть, воспользовав ш ись функцией Python
help (например, help(Perceptron)) или просмотрев превосходную онлайн-документацию
по библиотеке scikit-learn на http://sc i ki t-lea rn . org/staЫe/.
Здесь р(у = 1~) - это условная вероятность, что отдельно взятый образец принад
лежит классу 1 при наличии его признаков х.
Далее нас на самом деле интересует предсказание вероятности, что определенный
образец принадлежит отдельно взятому классу, т. е. обратная форма функции логит.
Ее также называют логистической функцией, иногда просто сокращенно сиг.моидой,
или сигмоидальной функцией, из-за ее характерной формы в виде латинской буквы S.
1
ф(z)=-- .
1+ e- z
def sigmoid ( z) :
return 1 . 0 / (1.0 + np.exp (-z))
z = np.arange(-7 , 7, 0.1 )
phi_ z = sigmoid (z)
plt . plot(z , phi_ z)
plt.axvline(O.O, color= ' k ')
plt.axhspan(O . O, 1.0, facecolo r='l. 0 ', alpha=l.0 , ls= ' dotted ')
plt . axhline (y=0.5 , ls= ' dotted ', color= ' k ')
plt. yticks ( [О. О , О . 5, 1 . О ] )
plt.ylim (- 0 . 1, 1 . 1)
plt. xl abel ( ' z ' )
pl t . yl abel( ' $\ ph i (z) $ ' )
plt. show ()
1.0
,,...._
~0.5
о. о
-8 -6 -4 -2 4 8
z
в главе
2 «Тренировка алгоритмов машинного обучения для задачи классификации~ .
В ADALINE мы в качестве функции активации использовали тождественное ото
бражение ф(z) = z. В логистической регрессии эта функция активации просто стано
вится сигмоидальной функцией, которую мы определили ранее, как проиллюстри
ровано на следующем рисунке:
ч и стого
входа
А { 1, еслиz ~ О.О
у =
О, иначе
циента есть отдельно взятое заболевание при наличии определенных симптомов; вот
почему логистическая регрессия имеет широкую популярность в сфере медицины.
Моделирование вероятностей 1СJ1ассов логистической регрессии 77
1
Правдоподобие (likelilюod), или функция правдоподобия, - это совместное распределение
образца из параметрического распределения , рассматриваемое как функция параметра.
При этом используется совместная функция плотности (в случае образца из непрерывного
распределения) либо совместная вероятность (в случае образца из дискретного распреде
ления) , вычисленные для значений выборочных данных . - Прим . перев.
Во избежание проблемы арифметического переполнения снизу (приводящего к исчезнове
2
нию разрядов) при работе с числами с плавающей точкой, находящимися слишком близко
к нулю, пользуются свойствами логарифмов: logab= и exp(log[(x) = х]), кото
loga + logb
рые позволяют произведение р 1 * ". * р 11 представить в виде эквивалентной суммы логариф
мов: exp(log(p 1) + ". + log(p 11 ) . - Прш.t . перев.
3
Градиентный (наискорейший) подъем (gradient ascent) - алгоритм градиентного подъема,
инкрементный алгоритм оптимизации, или поиска оптимального решения, где приближе
ние к локальному максимуму функции идет шагами, пропорциональными величине гради
ента этой функции в текущей точке. - Прим . перев .
' Речь о методе под названием «оценка максимального правдоподобия». Это метод оценива
ния неизвестного параметра путем максимизации функции вероятности, в результате кото
рой приобретаются значения параметров модели, которые делают данные «ближе» к реаль
ным. - Прим . перев.
78 Обзор 1СЛассификаторов с исполъзование.м библиотеки scikit-leam
5
j(w), если у= 1
j(w), если у= О
4 1
1
з
,,-._
~
:::::;
2
• •11 о
ххх
"'
""'
""'"'
ооо 2
о
Q.
ООо
~
....
"'Q.
"'
с:[
"'"
з.
"'t
"'
с:
"'"'
""'"'
Q.
3"'
-1
.}j:
-2
-2 -1
длина лепестка [стандартиз и рованная]
80 Обзор классифшсаторов с исполъзование.м библиотеки scikit-leam
Глядя на прив еде нный выше пример исходного кода, который использовался для
тренировки модели LogisticRegression, вам, наверное, теперь интересно, что это за за
гадочный параметр С. Мы разберемся в нем через пару секунд, а пока в следующем
подразделе сначала кратко остановимися на понятии переобучения и регуляризации.
В свою очередь, мы можем предсказывать вероятность принадлежности образцов
классам при помощи метода predict_proba. Например, можно предсказать вероятно
сти первого образ ца ириса щетинистого:
8
-l(w)= ( у--(1-у)
1 1 ) -ф(z).
8
owj ф(z) 1-ф(z) owj
8
Теперь можно в наше первое уравнение повторно подставить -ф(z) = ф(z)(1 - ф(z))
8z
и получить следующее:
w := w + лw.
Лw = 11Vl(w).
Поскольку максимизация логарифмического правдоподобия эквивалентна ми
нимизации определенной ранее функции стоимости], мы можем записать правило
обновления на основе градиентного спуска следующим образом:
w := w + Лw, Лw := - 11V](w).
Таким образом, оно эквивалентно правилу на основе градиентного спуска в ада
лине из главы 2 «Тренировка алгоритмов машинного обучения для задачи классифи
кацuu'i>.
Х2 \ Х2 ~ Х2
\
\ о о,/ о:
о, + о /+ ~
""+
о '.+ + о•
+ ~ +
о +~\+ ' + " +
о +'t ...+ ~''+ + +
о о ... о~---ь-"
Переобучение Х1 Хоро ш и й ком про ми с Х1 Недообуч ен ие Х1
( в ысо кое сме ще н ие) ( вы со кая ди сперси я)
С = _!.
л
weights , pararns = [] , []
for с in np . arange (- 5, 5 ) :
lr = Logistic Regression (C=lO**c , randorn_sta t e=O )
lr .fit(X_train_s t d , y_ train )
weigh t s . append (lr . coef_ [l] )
pararns . appe nd (lO**c )
weights = np . array (weights )
plt . plot (pararns , we i ghts [ :, О] , lаЬ еl= ' дл и на лепес тка ' )
plt.plot (pa r arns , weight s[ :, 1] , l i ne st yl e=' -- ', l аЬ еl= ' шири н а л е пе стк а ' )
plt . ylabel ( ' вeco в o й коэффициент ' )
plt . xlabel ( ' С ' )
plt . l egend (loc= ' upper left ')
plt . xscale ( ' log ' )
plt . show ()
Учитывая, что метки классов в наборе данных iris в библ иоте ке scikit-learn равны {О, 1, 2} ,
1
этот класс должен быть 2-м в наборе отсортированных в восходящем порядке данных, обо
з н а чая метку кла сса 1. - Прим . перев .
84 Обзор классификаторов с использованием библиотеки scikit-leam
длина лепестка
ширина лепестка
....
:z:
"':'§-
!""
С>
>S
С>
"'8 '
~ -1 '
''
''
-2
Параметр С
с+
Поскольку всестороннее освещение отдельных алгоритмов классификации выходит за
рамки этой книги. настоятельно рекомендуем читателям, которые хотят узнать о логис
тической регрессии больше. обратиться к книге доктора Скотта Менарда "догистиче
ская регрессия: от вводного курса до продвинутых концепций и приложений;, (Dr. Scott
Menard, Logistic Regression: From Introductory to Advanced Concepts and Applications)
издательства "sage;, .
Зазор
\
Х2 1. Х2
\ 1
\ 1
'' \ !f. + + Граница решения
'' ~ и/х= О
+ ++
1\
о ~· , « Положительная »
о "•' \\ « Отрицательная » --- гиперплоскость
W0 + u/xpos = 1; (1 )
W0 + W тХпсg = -1. (2)
Если вычесть два линейных уравнения (1 ) и (2) друг из друга, то получим:
т
=> w (xpos - хпсg) = 2.
Можно выполнить его нормализацию по длине (величине ) вектора w, которая
определяется следующим образом:
WT ( xpos - Xneg ) 2
llwll l wl'
Тогда левую часть предыдущего уравнения можно интерпретировать как расстоя
ние между положительной и отрицательной гиперплоскостями, т. е. ту самую мар
жу, которую мы хотим максимизировать.
Теперь целевая функция SVM сводится к максимизации этого зазаора путем мак-
2
симизации lwll с учетом ограничения, что образцы классифицированы правильно.
Эти два уравнения, в сущности, говорят о том, что все отрицательные образцы
должны попасть на одну сторону от отрицательной гиперплоскости, тогда как все
положительные образцы должны остаться за положительной гиперплоскостью. Это
можно записать более сжато следующим образом:
!+
~ 1 tl + +
+
+
ol
о l
"'""___v......................1 _,,,о,__......-• xl
1
'-----.---.........,..........,.........,...х1
Большая велич и на па рам етра С Малая вел ич и на пара м етра С
Изучив ключевые идеи, лежащие в основе линейного метода SVM, теперь натре
нируем модель SVM для классификации различных цветков в нашем наборе дан
ных цветков ириса:
••• о
ххх
о:'
"' ооо 2
"'"'"'
"'
о
CL
~
,_
s:
CL
:&
:r
"'
~
"'""t;
....
...
с
"'"'"'s: -1
CL
s:
3
-2
-z -1
длин а л еп естка [ста нда ртизирова н н ая]
88 Обзор 1'/lассификаторов с использованием библиотеки scikit-leam
с+
Логистическая регрессия в сопоставлении с методом опорных векторов
В практических задачах классификации линейная логистическая регрессия и линейные
методы опорных векторов часто приводят к очень похожим результатам. Логистическая
регрессия пытается максимизировать условные вероятности тренировочных данных ,
что делает ее более подверженной выбросам, чем методы опорных векторов (SVM). Ме
тоды SVM главным образом сосредоточены на точках, ближайших к границе решения
(опорных векторах). С другой стороны, преимущество логистической регрессии состоит
в том, что это более простая модель, которую проще реализовать. Кроме того , модели
логистической регрессии можно легко обновлять, что выглядит привлекательным при
работе с потоковой передачей данных. '
plt.scatter(X_xor[y_xor==l , О] , X_xor[y_xor==l , 1] ,
с= 'Ь', marker= ' x ', label= ' l ' )
plt.scatter(X_xor[y_xor==- 1, 0] , X_xor[y_xor==- 1, 1],
c= ' r ', marker= ' s ', label= '- 1 ')
plt . ylim (- 3 . 0)
pl t . legend ()
plt . show ()
После выполнения приведенного выше исходного кода у нас будет набор данных
XOR со случайным шумом, как показано на нижеследующем рисунке:
х
х
•
х
х
х х
~
~
х8
•
х
""' • • •
• • ••
)\.., :х
rl'
хХ х )f')!x
х
х х ~ .~r1'8 °JJ •
• •
• • •
~х х хх ~
х
8
х х х 3~
':18
,_,.
х
•х х
••• • •
• r•
'f!c х хх х х
•• • х
1118
• . . , 1 •• " ~ хх х
• "-..; •11 ~ ~.,,,х !Е х
-1
-z
•
. ".-. . • • • •
il
•
х
"
• ~
х х.
х
х
х
х
•
х
-з~~~~~~~~~~~~~~~~~---~~~~~~~~~
-3 -2 -1
Это дает нам возможность разделить эти два показанных на графике класса ли
нейной гиперплоскостью, которая становится нелинейной границей решения, если
ее спроецировать назад на исходное пространство признаков:
1.5 , - - - - - - - - - - - - - ,
1.0
. . ..
.,. . t :• •. . .
2.0
1.5
o.s
..
·"' .. . . ' .. ~-.
1•
1.0
~=· ."i.~. ~:-:4
о.о
: .. -.·1·· ~
·'с...
: :ь~
. '· ...
.;
:·: ф
0.5
23
-o.s "
:: " .
. ............ "11".\
·11·•
..
••
,,,. . о.о
-1.0
• • • "
" ..
• • • • •• 1 • • •
- 1 ~1·'-=
, ,--,_1~
.о---=-0-=-
.• -7'0.0,---0=".s----,1"'"
.o--,'1.s
z . 1.0 1.5 -1 .т- l.О- . z
2 1
х
1
1. s.-------------~
1.0 .. ..
o.s
. ·:· . t :· •. . : 1
..
,. ·' •i
о.о :
".. :·:.
- 0.5
•"' .
- 1.0
.. ."........
~:
.. .
1
- -.:1.s - 1.0 -o.s о.о o.s 1.0 i.s
Х1
x(i) x(j)2)
k(x(i>,x(j)) == ехр
[ 2~2 •
-1
-2
-3
-3 -2 -1
92 Обзор классификаторов с использованием библиотеки scikit-leam
••• о
..."'
:i:
:i:
ххх
ооо
1
2
"'"'
о ООо
С>.
;!;
....""
С>.
"'
с<
:i:
~
"'><
~
i::::
"'
.}j:
с;
-1
"'
:i:
""
С>.
""3
-2
-2 -1 о
дл и на лепестка [стандартизированная]
Теперь на итоговом графике можно увидеть, что граница решения вокруг классов
О и 1 намного компактнее относительно большой величины параметра у:
••• о
х хх 1
~
х
х
"'"'
о
с.
ооо 2
ООО тестовый набор
8mJ 0 0>
0oo
О
00
ООО
~
о оо о
0 0
....s
~
о
о
"'
~
"'
..."'t;
с
"'
с:
-1
"
"'s
х
с.
s
3
-2
-2 -1
дл и на лепестка [стандартизи рова н ная]
Хотя эта модель очень хорошо подогнана под тренировочный набор данных, т. е.
хорошо им соответствует, такой классификатор, скорее всего, будет иметь высокую
ошибку обобщения на ранее не наблюдавшихся данных, а это, в свою очередь, сви
детельствует о том, что оптимизация параметра у играет одинаково важную роль
в управлении переобучения.
Дождливо
Пасмурно
Да
Остаться дома
Для того чтобы расщепить узлы в самых информативных признаках, нам нужно опре
делить целевую функцию, которую мы хотим оптимизировать алгоритмом обучения
на основе дерева. Здесь наша целевая функция состоит в максимизации прироста ин
формации при каждом расщеплении, которую мы определяем следующим образом:
т N.
IG(Dp,f)=I(Dp)- I - I(D1)·1
j=t NP
Здесь p(ilt) - это доля образцов, которая принадлежит классу i для отдельно взя
того узла t. Следовательно, энтропия равна О, если все образцы в узле принадлежат
одному и тому же классу, и энтропия максимальна, если у нас равномерное рас
i=i i=i
i=i
Мера неоднородности, или мера Джини (Gini impurity), - это вероятность, что случайный
1
образец будет классифицирован правильно, если произвольно выбрать метку согласно рас
пределению в ветви дерева. Не следует путать с коэффициентом Джини в статистике, где
он представляет собой показатель степени расслоения общества по отношению к какому
либо признаку. - Прим. перев.
2
Речь идет о вероятностной мере неопределенности Шеннона (или информационной энтро
пии). Данная формула означает, что прирост информации равен утраченной неопределен
ности. - Прщt. перев.
96 Обзор 1СЛассификаторов с использование.м библиоте~сu scikit-leam
Iit) = 1 - max{p(ilt)}.
А в
3
А: lн(Dлевый)=1-4=0.25;
3
А: lн(Dправьrй)=1-4=0.25;
4 4
A:IGн =0.5- 0.25- 0.25=0.25;
8 8
4 1
В: lн(Dлевый)=1-в=3;
В: lн(Dправый)=1-1=0;
6 1
В: IGн =0.5- х -0=0.25.
8 3
Однако_мера неоднородности Джини предпочтет расщепление в сценарии
в( IGн = 0.16) над сценарием A(IGE = 0.125), который действительно более однороден:
lc(Dp)=1-(0.5 2 +О.5 2 )=0.5;
А Iс(D,"ы,)=1-[Ш +Ш'Н=0375;
А: Ic (D,,~"") =1-[Ш' +Ш' н =0375;
4 4
A:IGc =0.5--0.375--0.375=0.125;
8 8
Обучение на основе деревьев peuurnuй 97
цщ~">=1-[Ю +Ш'Н=о4,
2
В: Iс(Dправый)=1-(1 +0 )=0;
2
6 - -
В: IGc =0.S- 0.4-0=0.16.
8
Аналогичным образом энтропийный критерий будет отдавать предпочтение сце
нарию B(IG11 = 0.31) перед сценарием A(IG11 = 0.19):
I н(DР) = -(O.Slog 2(0.5)+0.5log 2 (0.5)) = 1;
6
В: IGн =1- 0.92-0=0.31.
8
Для более наглядного сравнения трех разных критериев неоднородности, которые
мы обсудили выше , построим график индексов неоднородности для вероятностного
диапазона [О, 1] для класса 1. Отметим, что мы также добавим масштабированную
версию энтропии (энтропия/2) , чтобы уч есть , что мера неоднородности Джини яв
ляется промежуточной между энтропией и ошибкой классификации. Соответству
ющий исходный код выглядит следующим образом:
def entropy ( р ) :
return - p*np. log2 (р) - (1 - р) *np . log 2 ( (1 - р ))
def error ( р) :
return 1 - np . max([p , 1 - р] )
х = np . arange ( О . О , 1 . О , О . О 1)
[ ' Ыасk ', ' lightgray', 'red ' , ' green ' , ' cyan']):
line = ax.pl ot (x , i, label=lab, linestyle=ls, lw=2, color=c)
ax.legend(loc='upper center ', bbox_to_anchor=(0 . 5, 1.15) ,
ncol=З , fancybox=True, shadow=False)
ax.axhline(y=0 . 5, linewidth=l , color= ' k', linestyle= ' - - ')
ax.axhline(y=l.0 , linewidth=l, color= ' k ' , linestyle= ' -- ' )
plt.ylim ( [O , 1.1])
plt . xlabel ('p(i= l ) ')
рlt.уlаЬеl( ' Индекс неоднородности')
plt . show ()
1.0
0.8
s:
t:;
~
g. 0.6
~
"'~
:с
~ 0.4
- - - - - - ------
,;
--
- - ... .....-·.,..-·.. - --.......- ,- - - - - - - - - -
',
:s::
:с
; ' '
,, ''
;
0.2 ,, '
'
,' '
Деревья решений могут создавать сложные границы решения путем деления про
странства признаков на прямоугольники. Однако мы должны быть осторожными,
поскольку чем глубже дерево решений, тем сложнее становится граница решения,
что может легко закончиться переобучением. Теперь, используя scikit - leaш, натре
нируем дерево решений с максимальной глубиной 3, применив в качестве крите
рия неоднородности энтропию. Хотя для целей визуализации может понадобиться
шкалирование признаков, отметим, что масштабирование признаков не является
необходимой составной частью алгоритмов деревьев решений . Соответствующий
исходный код выглядит следующим образом:
Обучение на основе деревьев реuиний 99
3.0 ••• о
ххх 1
2.5 ооо 2
ООО тестов ы й набор
'"i' 2.0
~
"'
...""t:; 1.5
...
с
"'"'
х 1.0
"'
Q.
:s:
3 0.5
о. о
-0.5
о 4
длина леп естка [см ]
3.0 ••• о
ххх 1
2.5 ооо 2
ООо тестовы й набор
~ 2.0
~
\:!
...t; 1.5
...
с
с;
"' 1.0
:z:
s:
"'"
s:
.JI:
3
0.5
о.о
-0.5
4
дл ин а л е п естка [см]
k ближайших соседей - aлгopumJot ленивого обучения 103
с+
Параметрические модели в сопоставлении с непараметрическими
Алгоритмы машинного обучения можно сгруппировать в параметрические и непара
метрические модели. Используя параметрические модели, мы выполняем оценивание
параметров из тренировочного набора данных, чтобы извлечь функцию, которая сможет
классифицировать новые точки данных, больше не требуя исходного тренировочного
набора данных. Типичными примерами параметрических моделей являются персептрон,
логистическая регрессия и линейный метод опорных векторов (SVM). Напротив, непа
раметрические модели не могут быть охарактеризованы фиксированным набором па
раметров, и число параметров в них растет вместе с тренировочными данными. Двумя
примерами непараметрических моделей, которые мы видели до сих пор, являются клас
сификатор на основе дерева решений/случайного леса и ядерный метод SVM.
Модель k ближайших соседей (KNN) принадлежит подкатеrории непараметрических
моделе й , которая описывается как обучение на примерах (или по прецедентам , in-
stance-based). Модели, в основе которых лежит обучение на примерах, характеризуются
запоминанием тренировочного набора данных, и ленивое обучение является особым
случаем обучения на примерах, которое связано с отсутствующей (нулевой) стоимо
стыо во время процесса обучения.
lx +
lx ...
3 х h.
Предсказать
Задав пять соседей в модели KNN для этого набора данных, мы получаем относи
тельно гладкую границу решения, как показано на нижеследующем рисунке:
k ближайuшх соседей - Шlгopum.At ленивого обучения 105
а:
..
ххх
" о
1
"'~
:z: ооо 2
"'
о
с:>.
;:;
"',_
с:>.
;]!:
:z:
"'
~
"'
"
t;
"'"'
"'
""' -1
х
"'
с:>.
"'3
-2
-2 -1
длина лепестка [стандартизированная]
тая евклидова мера расстояния. При этом если мы используем евклидову меру рас
стояния, также важно данные стандартизировать, благодаря чему каждый признак
вносит в расстояние одинаковый вклад. Расстояние Минковского (' minkowski' ),
которое мы использовали в приведенном выше примере, является простым обоб
щением евклидова расстояния и расстояния городских кварталов (манхэттенского ),
которое можно записать следующим образом:
Проклятие размерности
с+ Важно упомянуть, что модель KNN очень восприимчива к переобучению из-за явления
проклятия размерности , когда пространство признаков становится все более разрежен
ным для растущего числа размерностей тренировочного набора данных фиксированно-
106 Обзор 1СЛассификаторов с использованиеJ.t библиотеки scikit-leam
Резюме
В этой главе вы узнали о разнообразных алгоритмах машинного обучения, которые
используются для решения линейных и нелинейных задач . Мы убедились, что де
ревья решений особенно привлекательны, в случае если интерпретируемости моде
ли уделено должное внимание. Логистическая регрессия - это не только полезная
модель для динамического ( онлайнового) обучения методом стохастического гра
диентного спуска, она позволяет также прогнозировать вероятность отдельно взя
к
ачество данных и объем полезной информации, которую они содержат, являют
ся ключевыми факторами, которые определяют, как хорошо алгоритм машинно
го обучения сможет обучиться . Следовательно, крайне важно сначала набор данных
обязательно проверить и подвергнуть предварительной обработке и только потом
подавать его на вход обучаемого алгоритма. В этой главе мы обсудим ключевые ме
тоды предобработки данных, которые помогут создавать хорошие машиннообучае
мые модели .
>»
import pandas as pd
from io import StringIO
А в с D
о 1.0 2.0 3.0 4.0
1 5.0 6.0 NaN 8.0
2 10.0 11.0 12.0 NaN
При помощи приведен н ого выше исходного кода мы считали данные в формате
CSV в таблицу данных DataFram e библиотеки pandas, используя для этого функцию
read_csv, при этом отметим, что две пустые ячейки были заменены на NaN. Функция
StringlO в прив еденном выше примере использовалась просто в ц елях иллюстрации .
Она позволяет считывать строковое значение, присвоенное переменной csv_data ,
в объект DataFrame библиотеки pandas так, как будто это обычный СSV-файл на
нашем же стком диске .
>»
df. i s null () . sum()
А О
в о
с
D 1
dt ype : i nt6 4
Один из самых простых способов реш ения проблемы пропущенных данных состо
ит в том, чтобы просто удалить соответствующие признаки (столбцы) или образцы
(строки) из набора данных полностью; строки с пропущенными значениями можно
легко отбросить при помощи метода dropna :
>»
df. dropna ()
А в с D
о 1.0 2.0 3.0 4.0
Точно так же можно отбросить столбцы, которые в любой строке имеют, по край
ней мере, одно значение NaN; это делается путем установки параметра оси ax is в 1:
>»
df.dropna (ax is=l)
А в
о 1.0 2.0
1 5.0 6.0
2 10.0 11.0
А в с D
о 1.0 2.0 3.0 4.0
1 5.0 6.0 NaN 8.0
2 10.0 11.0 12.0 NaN
# отбросить строки, если в них менее 4 значений нe - NaN
df.dropna(thresh=4 )
А в с D
о 1.0 2.0 3.0 4.0
#отбросить строки , если в оп ределе нных столбцах (здесь ' С') имеется NaN
df.dropna(subset=[ 'C' ] )
А в с D
о 1.0 2.0 3.0 4.0
2 10.0 11.0 12.0 NaN
»>
from sklearn . preprocessi ng import I mput er
i mr = Impu t er(missing_values=' Na N', strategy='mean', a xi s =O )
i mr = imr.fit( df )
i mpu t ed_da t a = imr . transfo r m(d f. va l ues)
imputed_da t a
array ( [ [ 1. , 2 ., 3 ., 4 . ] '
[ 5. ' 6 .' 7 . 5, 8 . ] '
[ 10. , 11 ., 12 ., 6 . ]] )
Здесь каждое з нач е ние NaN заменено на соответствующее среднее значение, кото
рое вычисляется отдельно для каждого признакового столбца. Если поменять значе
ние оси axis=O на axis=l, то будет вычислено среднее строки. Другими значениями
параметра strategy может быть median либо most_frequent, где в последнем случае
пропущенные з нач ения меняются на самые частотные значения. Это удобно при
импутации значений категориальных признаков.
Тренировочные Тестовые
данные данные
Модель
est.transform (X_train )
Трансформированные Трансформированные
тренировочные данные тестовые данные
тода predict можно использовать для выполнения прогнозов о новых образцах дан
ных, как проиллюстрировано на нижеследующем рисунке:
Тренировочные Тренировочные
данные метки
est.fit(X_train, y_train)
Модель
est.predict(X_test)
Идентифициро
ванные метки
112 Создание хороших тренировочных наборов - предобработка данных
например XL = L+ 1= М + 2.
>»
size_mapping # словарь соответствий
'XL': 3 ,
'L' : 2,
'М' : 1)
df[ ' размер ' ] df [ 'размер'] . map(size_mapping)
df
Обработка категориальных дттых 113
сваиваем отдельно взятой строковой метке. Поэтому можно просто нумеровать мет
ки классов, начиная с О:
>»
impor t nurnpy as np
class_mapping {labe l:idx for idx,label in
enurnerate(np.unique(df[ ' мeткa ' ] )) )
class_mapping
{ ' класс 1 ' : О, 'класс2 ' : 1)
>»
df [ ' метка ' ) df[ ' метка ' ] . rnap(class_rnapping)
df
»>
from s kl earn.preprocessing impo r t LabelEncoder
class_l e = LabelE ncoder()
у= class _l e.fi t _ transform( d f [ 'мeткa' ) .values)
у
array( [0, 1, 0) )
»>
class_l e. i nverse_ trans f orm( y)
arra y ( [ ' классl', 'класс2' , 'классl' ] , dtype=object)
»>
Х = df[ [ 'цвет ' , ' раз м ер ', 'цeнa' J ).values
color_ le = LabelEncoder()
Х [ :, 0) = color_ le.fit_ transform(X [ :, 0] )
х
array( [[ l , 1, 10.1 ) ,
[2, 2, 13 . 5),
[0 , 3, 15.3 ) ), dtype=ob j ect)
обучения теперь предположит, что зеленый больше синего, а красный больше зелеио
zо. Хотя это допущение является неправильным, алгоритм все равно способен про
извести полезные результаты. Однако эти результаты не будут оптимальными.
Общее обходное решение этой проблемы состоит в использовании метода, кото
рый наз ывается прямым кодированием . В основе этого подхода лежит идея, кото
1
рая состоит в том, чтобы в столбце номинального признака создавать новый фиктив
ный признак для каждого уникального знач ения. В данном случае признак «цвет »
можно преобразовать в три новых признака: синий, зеленый и красный. Затем
можно использовать двоичные значения для указания отдельно взятого цвета об
разца; например, синий образец может быть закодирована как синий=l, зеленый=О,
красный = О. Для выполнения этого преобразования можно воспользоваться классом
OneHotEncoder, который реализован в модуле scikit-learn.preprocessing:
>»
from sklearn . prep rocessing i mpo rt OneHotEncoder
ohe = OneHotEncoder (cat egorical_f eat ur es=[O] )
ohe . fit_ transform ( Х ) . toarray ()
array( [[ О . , 1. , О . , 1. , 10 . 1] ,
[о . / о. ' 1. ' 2 . / 13 . 5] ,
[ 1 .• о . ' о . ' 3 . / 15 . 3]] )
»>
pd . get dummies (d f [ [ ' це на ', 'цве т ', 'разме р ' ]] )
1 13.5 2 о 1 о
2 15.3 3 о о 1
Прямое кодирование (oп e- hot eпcodiпg) - двоичный код фи ксированной длины , содержа
1
щий только одну 1. При обратном кодировании имеется только один О. Длина кода опреде
л я ется коли<1 еством кодируе мых приз наков, или объектов. - Прим . перев.
116 Создание хороших тренировочных наборов - предобработка данных
Набор данных сортов вин Wine - это еще один общедоступный набор данных,
предлагаемый репозиторием машинного обучения UCI ( https://archive.i cs.uci. edu/ml/
dat aset s/Wine); он состоит из 178 образцов белых вин с 13 признаками, описываю
щими их различные химические свойства .
Пользуясь библиотекой pandas, мы прочитаем набор данных вин непосредствен
но из репозитория машинного обучения UCI:
»>
url = ' https://archive.ics . uci.edu/ml/machinelearning-databases/wine/wine.data '
df_wine = pd.read_csv(url, header=None)
df wine . columns [ 'Метка класса', 'Алкоголь' ,
'Яблочная кислота', ' Зола ' ,
< Щелочность золы> , <Магний>,
<Всего фе н ола>, <Флаваноиды >,
<Фенолы нефлаваноидные> , <Проантоцианины> ,
"'"
Q ~ QJ
:3 ~ ~
~
=
5 Q
"' =
Q
= =
..Q
t ..... к
~
=
:.:
..Q
t
о:
Q
:3
~
~ =
"'Q:='= Q
=
м
~ ~
-
"'"' =
~
!:"'
..Q
о:
Q
....
~
~
Q
~ '=
~
QJ
-6'
Q
"'=
-@="'=
§
!;:
=
=
"'
="'
:.:Q
о
ci- а
= ""' "'
QJ
§
"'=
е
Q Q"'
Q
::; о: "'
= ~i
Q
"'а
QJ N\O
о: Q
~
QJ -6' !::
с"'
е
QJ
::?J"'
QJ
\О Q. Q.
"' =
о
::?J
1 14.23
t:i::
1.71
м
2.43 =
15.6 127
~
2.80 3.06
е~
0.28 2.29 5.64
о
1.04
о~
3.92 1065
1 1 13.20 1.78 2.14 11.2 100 2.65 2.76 0.26 1.28 4.38 1.05 3.40 1050
2 1 13.16 2.36 2.67 18.6 101 2.80 3.24 0.30 2.81 5.68 1.03 3.17 1185
3 1 14.37 1.95 2.50 16.8 113 3.85 3.49 0.24 2.18 7.80 0.86 3.45 1480
4 1 13.24 2.59 2.87 21.0 118 2.80 2.69 0.39 1.82 4.32 1.04 2.93 735
(+ Следует учесть, что когда мы делим набор данных на тренировочный и тестовый набо
ры данных, то мы лишаемся части ценной информации, из которой алгоритм обучения
мог бы извлечь выгоду. Поэтому мы не выделяем слишком много информации для тес
тового набора. Однако чем меньше тестовый набор, тем менее точной является оценка
ошибки обобщения. Деление набора данных на тренировочный и тестовый наборы на
прямую касается уравновешивания этого компромисса . На практике обычно использу
ются пропорции разделения 60:40, 70:30 или 80:20, в зависимости от размера исходного
набора данных. Однако для крупных наборов данных разделение на тренировочный
и тестовый наборы в пропорциях 90:10 или 99:1 также распространено и приемлемо.
Вместо того чтобы после тренировки и оценки модели отбросить выделенные тестовые
данные, неплохо для настройки оптимального качества также переобучить классифика
тор на всем наборе данных.
Здесь x<i) - это отдельно взятый образец, x 111 ;n - наименьшее значение в признако
вом столбце и х""'' - соответственно наибольшее значение.
Процедура минимаксного масштабирования реализована в библиотеке scikit-
leaш и может быть применена следующим образом:
L2:JJwll~ = I:wJ.
j=1
Построим график контуров выпуклой функции стоимости для двух весовых коэф
фициентов w1 и w2• Здесь мы рассмотрим функцию стоимости с извлечением весов
в виде суммы квадратичных ошибок (SSE), которую мы использовали для ADALINE
в главе 2 «Тренировка алгоритмов машинного обучения для задачи Ю1ассификации~, по
скольку она симметрична и проще для изображения на графике, чем функция стои
мости логистической регрессии; хотя к последней применимы те же самые принци
пы. Напомним, что наша задача состоит в том, чтобы найти комбинацию весовых
коэффициентов, которые минимизируют функцию стоимости для тренировочных
данных, как показано на нижеследующем рисунке (точка посередине эллипсов):
Минимизировать
--------- стоимость
------ -------
Отбор содержательных признаков 121
Миним и зировать
/ / ,/- ---------:~-
! 1
r ,
\ \
\ \
//
_,.../·
---------~-------<----~---";----~-- ~
--
Ми н имизировать
стоимость + ш тра ф
(w1 =О)
'' \ ''
'
'' ''
' т
\
JJwll1= l:lwjl
j=1 llwll2 =~t, wj
Отбор содержательных признаков 123
»>
lr = LogisticRegression (penalty= 'll', С=О.1)
>»
lr.intercept_
array([ - 0.38379237 , - 0.1580855 , - 0.70047966])
1
Функции в виде у = f(x ) могут содержать две и более точек пересечения оси Х, а некото
рые двухмерные математические отношения, такие как круги, эллипсы и гиперболы, могут
иметь более одной точки пересечения оси У. Точки пересечения оси Х функций, если они
есть, часто труднее локализовать, чем точку пересечения оси У, т . к. нахождение последней
закл ючается всего лишь в оценке функции при х = О. - Прим. перев.
124 Создапие хороших трепuровочпых паборов - предобработка даппых
Отмечаем для себя, что весовые векторы разрежены, т. е. имеют всего несколько
ненулевых записей. В результате L1-регуляризации, которая служит в качестве ме
тода отбора признаков, мы только что натренировали модель, устойчивую к потен
циально нерелевантным (лишним) признакам в этом наборе данных.
Наконец, построим график траекторий регуляризации , т. е. весовых коэффициен
тов, разных призна ков для разных сил регуляризации:
Чтобы учесть постоянное смещение (Ьias unit), единицы должны быть заменены на нули
1
(как в главе 2). При этом отметим, что scikit-learn хранит смещение и веса раздельно, и по
т
этому лучше записать так: w1x 1 + ... + rш";хт + Ь = LXjlШ1 + Ь = w x+ Ь. - Прим. перев.
1
j=O
Отбор содержательных признтсов 125
Алкоголь
Яблочная кислота
Зола
Щелочность золы
Магний
Всего фенола
Флаванонды
"" -10
Фенолы нефлаван о идные
Q
"
~ -15
Проантоцианины
Интенсивность цвета
-20 Оттенок
OD280_0D315 разбавленных вин
-25 Пролин
10·! 104 1Q·J 10-1 10-1 100 101 101 101 10~ 101
Параметр С
вательный прямой отбор (sequential forward selection, SFS), метод отбора « плюс 1 минус r»
(plus-1 minus-г selection), двунаправленный (Ьidiгectional search) и плавающий поиск (floating
searcl1) . См., например: http://research.cs.tamu.edu/prism/lectures/pr/pr_lll.pdf. - ПpUJ11 . перев.
126 Создание хороших тренировочных наборов - предобработка данных
Жадные алгоритмы на каждом шаге комбинаторной задачи поиска делают локально оп
с+ тимальный выбор и обычно производят субоптимальное решение задачи, в отличие от
алгоритмов исчерпывающего поиска, которые оценивают все возможные комбинации
и гарантированно находят оптимальное решение. Однако на практике исчерпывающий
поиск часто в вычислительном плане не выполним, тогда как жадные алгоритмы допус
ство признаков не будет содержать нужное число признаков. Для определения того,
какой признак удалять на каждом шаге, нам нужно определить критериальную
функцию], которую мы хотим минимизировать. Вычисленный данной функцией
критерий может быть просто разницей в качестве классификатора после и до уда
ления отдельно взятого признака. Тогда удаляемый на каждом шаге признак можно
просто определить как признак, который максимизирует этот критерий; или в более
интуитивных терминах на каждом шаге мы устраняем признак, который вызывает
наименьшую потерю качества после удаления. Основываясь на предыдущем опре
делении алгоритма SBS, его можно в общих чертах обрисовать в 4 простых шагах:
1. Инициализировать алгоритм, назначив k = d, где d- это размерность полно
признакового пространства.
class SBS():
def init (self, estimator , k_features,
scoring=accuracy_score,
test_size=0.25, random_state=l):
self . scoring = scoring
self.estimator = clone(estimator)
self.k- f eatures = k- features
self.test- size = test - size
self.random state random state
def fit(self, Х , у) :
Х train, X_ test, у train, y_test
Отбор содержателы1ых nрUЗ11аков 127
dim = X_train.shape[l]
self.indices = tuple(range(dim))
self.subsets = [self.indices_]
score = self. _calc_score(X_train, y_train ,
X_test , y_test , self .indices
self.scores [score]
best = np.argmax(scores)
self.indices_ = subsets[best]
self.subsets_ .append(self.indices
dim - = 1
self.scores .append(scores[best])
self.k score self.scores [- 1]
return self
Несмотря на то что наша реализация SBS и так уже разделяет набор данных внут
ри функции fit на тестовый и тренировочный наборы данных, мы все же подали на
вход алгоритма тренировочный набор данных X_train. Метод fit класса SBS затем
создаст новые тренировочные подмножества для тестирования (валидации) и трени
ровки. По этой причине этот тестовый набор также называется проверочным (вали
дационным) набором данных. Этот подход необходим для того, чтобы не дать на
шему исходному тестовому набору стать составной частыо тренировочиы:х даиных.
Напомним, что наш алгоритм SBS на каждом шаге накапливает оценки в подмно
жестве лучших признаков, поэтому перейдем к более захватывающей части нашей
реализации и построим график верности классификации классификатора KNN, ко
торый был вычислен на перекрестно-проверочном наборе данных. Соответствую
щий исходный код выглядит следующим образом:
plt.grid()
plt. show ()
1.10
1.05 .. .. . . .. . .... ;
1.00
0.95
. ..
.. . . .... ... ... . . . .. . . . . .. . .. . ... ..... .. .
...t; .. ..
о
0.90 ... . ·: . .. .. . .. . . . . .:· . . . . . . . ... . . . . . . .. . .. . -. .. .. ...... .. ·; .. . ... . . . .. .
..
~ ~
..
0.80 .. . .. . .. ...;....... . .. . .. :. . .
0.75
0.70
о 4 10 12 14
Число признаков
Отбор содержательных приз11тсов 129
»>
kS = list(sbs.subsets_[8 ] )
print(df_wine.columns[l: ] [k5])
Indех( [ ' Алкоголь ', ' Яблочная кислота ', ' Щелочность золы 1
, 'Оттенок', 'Пролин'],
dtype = ' object ')
>»
knn.fit (X_train_std, y_train)
При меньшем, чем наполовину, числе исходных признаков из набора данных сор
тов вин верность предсказания на тестовом наборе улучшилась почти на 2%. Кроме
того, мы уменьшили переобучение, которую можно определить по малому разрыву
между верностью на тестовом наборе ( -96.3%) и верностью на тренировочном на-
боре ( -96.0%).
Алrторитмы отбора признаков в библиотеке scikit-leam
с+ Библиотека scikit-learn располагает многими другими алгоритмами отбора признаков.
Они включают в себя рекурсивный алгоритм обратного устранения признаков на осно
ве весовых коэффициентов признаков, методы отбора признаков по важности на основе
деревьев и одномерные статистические методы. Всестороннее обсуждение различных
методов отбора признаков выходит за рамки этой книги. Впрочем, хороший сводный
обзор с показательными примерами можно найти на http://scikit-learn.org/staЫe/modules/
feature_selection.html.
130 Создание хороших тренировочных наборов - предобработка данных
>»
from sklearn . ensemЫe import RandomForestClassifier
feat_labels = df_wine . columns[l:]
forest = RandomForestClassifie r (n_estimators=lOOO O,
random_state=O,
n_ j obs=-1)
forest .fit(X_ train, y_train )
importances = forest.feature importances
indices = np . argsort(importances) ( ::-1 ]
for f in range(X_ train . shape[l]):
print ("%2d) %- *s %f " % (f + 1, 30 ,
feat_labels[indices[f]] ,
importances[indices[f]]))
1) Интенсивность цвета 0 . 182483
2) Проли н 0 . 158610
3) Флаваноиды 0 . 150948
4) 00280 00315 разбавленных вин 0.131987
5) Алкоголь 0 . 106589
6) Оттенок 0 . 078243
7) Всего фенола 0.060718
8) Щелочность золы 0 . 032033
9) Яблочная кислота 0.025400
10) Проан тоцианины 0 . 022351
11) Магний 0.022078
12) Фенолы нефлаваноидные 0 . 014645
13) Зола 0 . 013916
plt.title('Baжнocти признаков')
plt . bar(range(X_ train.shape[l]), importances[indices],
color= ' lightЫue ', align= 'center ' )
plt . xticks(range(X_ train . shape [l]) ,
Определение ва:ж:ности признаков при по.мощи случайных лесов 131
Важности признаков
0.20 .---...---,----т----т--r---т---.---.----т---,...-.-.,.---,--....,...---.
0.15
0.10
0.05
....... ~
:;; ж ..а
"' ... :;; :;;
""'1=:s: "'
:;;
...
:s:
'°
о
"'=t
"' "'
"[
:s:
"' "'
е ж
"'
о
ж "'
о
о
5
ж
"'"'т
е
~
о
;: ...
"
;:
=t
о
....
ж
~
"'::z:б ~ a:i о ;:;
~
... "'"'
о
"'
о
С>.
"'
-е-
....
"' 3" "" с= "'
:i:
::с
:s:
С>.
"'
,..,
"' :;;
а
о :i:
о,
С>
&"'
00
N
о
о
ности, тогда как информация о другом признаке ( или признаках) может оказаться
не захваченной полностью. С другой стороны, нам не нужно беспокоиться по этому
поводу, если нас интересует только предсказательная способность модели, а не ин
терпретация важностей признаков. В заключение этого раздела о важностях при
знаков и случайных лесах стоит упомянуть, что в библиотеке scikit -leaгn также реа
лизован метод transform, который отбирает признаки, основываясь на определенном
пользователями пороге после подгонки модели, который очень часто применяется
в случае, если мы хотим использовать RandomForestC lassifier в качестве селектора
признаков и промежуточного звена в конвейере библиотеки scikit- leaгn; это позво
ляет соединять разные шаги предобработки с оценщиком, как мы убедимся в главе 6
«Изучение наиболее успешных методов оценки модели и тоюсой 1-tастройки гиперпа -
132 Создание хороших тренировочных наборов - предобработка данных
раметров». К примеру, можно установить порог в 0.15 для сведения набора данных
к 3 наиболее важным признакам - интенсивность цвета, пролин и флавоноиды, ис
пользуя для этого нижеследующий исходный код:
>»
Х selected = forest.transform(X_ train, threshold=0.15)
X_selected.shape
(124, 3)
Резюме
Мы начали эту главу с того, что рассмотрели часто используемые методы, которые
обеспечив ают правильную обработку пропущенных данных. Прежде чем передать
данные на вход алго ритма машинного обучения, мы также должны удостоверить
ся, что категориальные переменные имеют правильную кодировку, и мы увидели,
Сжатие данных
путем снижения размерности
в
zлаве 4 «Создание хороших тренировочных наборов - предобработка даюtЪL"С»
вы узнали о разных подходах к решению задачи снижения размерности набора
данных на основе различных методов отбора признаков. Помимо методики отбора
признаков, альтернативным подходом к решению этой задачи является методика
выделения призиаков . В этой главе вы узнаете о трех основополагающих методах,
которые помогут резюмировать информационное содержание набора данных путем
преобразования его в новое подпространство признаков более низкой размерности,
чем исходное. В машинном обучении методы сжатия данных представляют собой
важную тему; они помогают накапливать и анализировать увеличивающиеся объ
емы данных, производимые и собираемые в нашу современную технологическую
эпоху. В этой главе мы охватим следующие темы:
r1r анализ главных компонент для сжатия данных без учителя;
rr линейный дискриминантный анализ как метод снижения размерности с учи
телем для максимизации разделимости классов;
РС2
)(
)(
)(
Прежде чем рассмотреть алгоритм РСА для снижения размерности более подроб
но, сведем этот подход к нескольким простым шагам:
import pandas as pd
url = ' ht tp s : //archive .ics . uci . edu/ ml/machi ne l ea r nin g-databases/ wi ne/ wi ne . da t a '
df_wine = pd . read_csv (url , heade r=None )
LV = Лv.
>»
i mpor t nump y as np
cov_mat = np . cov (X_t r ain_s t d .T)
e igen_vals , eigen_vecs = np.li nal g. eig (cov_mat)
р rin t ( ' \nСоб с тв е нные з нач е ния \n %s' % e i ge n_va ls)
Собственные з начения
опред еляется как его евклидова норма (или евклидова длина), т . е. как квадратный корень
из суммы квадратов элементов вектора: l xll=~xl +х~ + ... +х~. - Прим. перев.
Собственная пара матрицы - это вещественное число Л. и вектор z матрицы А, если они
2
с+
Хотя функция numpy.linalg. elg предназначена для разложения несимметричных ква
дратных матриц, вы можете обнаружить, что в определенных случаях она возвращает
комплексные собственные значения.
Родственная функция numpy.linalg.elgh реализована для разложения эрмитовых (само
сопряженных) матриц, которые представляют собой численно более стабильный под
ход для работы с симметричными матрицами, такими как ковариационная матрица;
функция numpy.linalg .eigh всегда возвращает веществе нные собственные з начения.
Учитывая, что мы хотим снизить размерность нашего набора данных путем его
сжатия в новое подпространство признаков, мы отберем лишь подмножество соб
ственных векторов (главных компонент), которые содержат б6льшую часть ин
формации (дисперсии) . Поскольку собственные значения определяют величину
собственных векторов, нам нужно отсортировать собственные значения в порядке
убывания величины векторов; нас интересуют верхние k собственных векторов, ос
новываясь на значениях соответствующих им собствен ных значений. Но прежде
чем собрать эти k наиболее информативных собственных векторов, построим гра
фик долей объясненной дисперсии собственных значений.
Доля объясненной дисперсии собственного значения Л; - это просто частное соб
ственного значения \ и полной суммы собственных значений:
Л, j
d
"""
L..J j=1 JЛ,
Тогда при помощи функции cumsum библиотеки NumPy можно вычислить ку
мулятивную сумму объясненных дисперсий, которую затем можно отобразить на
графике, воспользовавшись функцией step библиотеки matplotlib:
1.2 ....----.-----.-----.-----.-----т-----.-------.
s
s
~ 0.8
5
~
•S
о
:z:
:z: 0.6
"'...,:z:
о:
..Е:
о
о: 0.4
с:
о
c:t
0.2
8 10 12 14
Главные ко м поненты
Преобразование признаков
eigen_pairs = [ (np.abs(eigen_vals[i]),eigen_vecs[: , i ] )
for i in range(len(eigen_vals))]
eigen_pairs.sort(reverse=True)
»>
w = np .h s t ack ( (eige n_pai rs [О] [1] [ :, np. newa xis] ,
eige n_pa i rs [1] [1] [ : , np.newa xi s] ))
print ( ' Матрица W: \ n ' , w)
Матрица W:
[[ 0 . 1466981 1 0 . 50417079]
[- 0 . 24224554 0 . 24216889 ]
[- 0 . 02993442 0 . 28698484 ]
[- 0 . 25519002 - 0 . 06468718 ]
[ 0 . 12079772 0 . 22995385 ]
( 0 . 38934455 0 . 09363991]
[ 0 . 42326486 0 . 01088622 ]
(- 0.30634956 0 . 018 70216]
[ 0.30572219 0 . 03040352 ]
(- 0 . 09869191 0.54527081]
[ 0 . 30032535 - 0.27924322]
[ 0 . 36821154 - 0 . 174365 ]
[ 0 . 29259713 0 . 36315461]]
x' = xW.
»>
X_train_std[O] . dot (w)
array([ 2.59891628 , 0 . 00484089] )
Х' =XW.
X_train_pca = X_t ra i n_std . dot (w)
Как видно на итоговом графике, данные более разбросаны вдоль оси Х - первая
главная компонента, чем вдоль второй главной компоненты (ось У), что согласуется
с графиком долей объясненной дисперсии, который мы построили в предыдущем
подразделе. Вместе с тем интуитивно можно отм етить, что линейный классифика
тор , вероятно, смо жет хорошо разделить классы:
140 Сжатие данных путем снижения разАtерности
"....
• •
• ,& •
11
••""
• •• •
"•: .
·-·'
.... "..,..
N
u
а.
-1
• • х
х
х х
• х
х
х ххх
•
. ""
• ••••• •
х х
~
х
ххх 2 х
-4
••• з
-5
-6 -4 -2 4 6
РС 1
z = Z. reshape(xxl . shape)
plt . contourf(x xl, хх2, Z, alpha=0.4 , crnap=crnap)
plt.xlirn(xxl.rnin(), xxl.rnax())
plt . ylirn(xx2.rnin(), xx2.rnax())
""
u
Q.
•••••••••1.• ,,,.•
..., ".
о
о
-1 00
ое о 0
о
-2 ••• •1 •• ••
ххх 2
о %f о
•
-3
ооо 3
о о
•
-4 -2 о 4
РС 1
N
u
сь
Q.
()
-1
о о
о
• •.:~.
••
о
-2
о
о о
•
••• • ••
-3 ххх 2
о
-4 ооо 3
-4 -z о 4
РС 1
>»
рса = PCA (n_compo ne nt s=Non e)
X_ t rain_pca = pca . fi t _ t ra nsform (X_t r a in_std)
pca . explained_variance_ra t io_
a rray ( [ О. 37329648 , О . 18818 92 6, О .1 08 96791, О . 0772 4389 ,
0 . 064785 95 ,
о . 04592014 ' о. 03986936 , о. 025 21914 ' о . 022 58 181, о . 01830924 ,
0 . 01635336 , 0.01284 271 , 0.00642076] )
Сжатие дттых с учителеJ.t путем линейного диС11.ршtинантн.ого анализа 143
Следующий ниже рисунок резюмирует идею LDA для двуклассовой задачи. Об
разцы из класса 1 показаны крестиками, соответственно, образцы из класса 2 -
окружностями:
144 Сжатие данных путем снижения раз.мерности
)(
х
)( • •• •
..
х
~ х ~
х
~
••• tt• • •
х
"
),(
~ х )(
)()( х
х х
)((
•• • \t
)(
Хх • • ••
х
•
Как показано на оси Х (LD 1), линейный дискриминант хорошо разделяет два
нормально распределенных класса. Несмотря на то что приведенный в качестве
примера линейный дискриминант на оси У (LD 2) захватывает довольно много дис
персии в наборе данных, он не может быть хорошим линейным дискриминантом,
поскольку не захватывает какой-либо информации о различении классов .
Одно из допущений в LDA состоит в том, что данные нормально распределены.
Кроме того, мы также допускаем, что классы имеют идентичные ковариационные
матрицы и что признаки статистически независимы друг от друга. Однако даже если
одно или несколько допущений слегка нарушается, то метод LDA для снижения
размерности может все еще работать относительно хорошо (R. О. Duda, Р. Е. Hart
and D. G. Stork. Pattern Classification («Классификация образов»). 2°d Edition. New
York, 2001).
Прежде чем в следующих подразделах мы рассмотрим внутреннее устройство
LDA, сначала резюмируем ключевые шаги алгоритма LDA:
1. Стандартизировать d-мерный набор данных (d - это число признаков).
2. Для каждого класса вычислить d-мерный вектор средних.
3. Создать матрицу разброса между классами S8 и матрицу разброса внутри
классов Siv·
4. Вычислить собственные векторы и соответствующие собственные значения
матрицы sv) s в .
5. Выбрать k собственных векторов, которые соответствуют k самым большим
собственным значениям для построения dхk- матрицы преобразования W;
собственные векторы являются столбцами этой матрицы.
6. Спроецировать образцы на новое подпространство признаков при помощи
матрицы преобразования W.
мы до определе нной степе ни эти допущения нарушаем , то LDA смож ет относ ительно
хорошо продолжить выполняться в задачах снижения размерности и класс ификации
(R. О. Duda, Р. Е. Hart and D. G. Stork. Pattem Classification ( <~ Классификация образов~) .
2"d Edition. New York, 2001).
Учитывая, что в разделе РСА в начале этой главы мы уже стандартизировали призна
ки набора данных сортов вин , мы можем пропустить первый шаг и сразу перейти к вы
числению векторов средних значений, которые мы будем использовать для построения
матриц разброса соответственно внутри классов и между классами. Каждый вектор
средних т; хранит среднее значение признака µ'" относительно образцов класса i:
1 с
mi =-Ixm.
n; xeD;
[
µi,amroro.ль
т. = µi,яблочная кислота
iE {1, 2, 3}.
1 :
µi,пролин
>»
np . set_printoptions (precision=4 )
mean _ vecs = [ ]
for label in range (l , 4 ) :
mean_vecs . append(np. mean(
X_train_ std[y_ train==l abel] , a xi s=O ))
print (' BC %s : %s\n ' %(label , me an_vecs[labe l - 1] ))
S; = L: <х - т; )(х - т; )т .
XEDi
146 Сжатие данных путем снижения раз.мерности
>»
d = 13 # число признаков
S W = np . zeros ( (d, d))
for label ,mv in zip(range(l,4), mean_vecs):
class_scatter = np .z eros((d , d))
for row in X_train [y_ train == label ] :
row, mv = row.reshape(d, 1) , mv.reshape(d, 1)
class_scatter += (row-mv) . dot((row -mv) .Т)
s w += class scatter
рrint( ' Внутриклассовая матрица разброса: %sx%s ' % (S_W.shape[O ] , S_W.shape[l ] ))
Внутриклассовая матрица разброса : 13х13
>»
рrint('Распределение меток классов: %s ' % np.bincount(y_ train) [l: ] )
Распределение меток классов: (40 49 35]
1 1 с т
L; = N- Sw = N- ~)x-mi)(x-mi) .
1 1 xeD;
»>
d = 13 # число признаков
S W = np .zeros((d , d))
for label , mv in zip(range(l, 4) , mean_vecs):
class_scatter = np.cov(X_ train_std[y_train==label] .Т)
S- W += class - scatter
рrint('Масштабированная внутриклассовая матрица разброса: %sx%s'
% (S_W.shape [O] , S_W .shape [l]))
Масштабированная внутриклассовая матрица разброса: lЗхlЗ
Sв = 'L,,p;(mi-m)(mi-m)т.
i=1
»>
mean_overall = np . mean(X_train_std, axis=O)
d = 13 # число признаков
S В = np . zeros ( (d, d))
for i,mean_vec in enumerate(mean_vecs) :
Сжатие дттых с учителеАt nymeAt линейного дисхршtинантного анализа 147
Оставшиеся шаги алгоритма LDA аналогичны шагам алгоритма РСА. Однако вмес
то выполнения разложения по собственным значениям на ковариационной матри це
мы решаем обобщенную задачу на собственные значения матрицы Sµ}Sв:
eigen_vals , eigen_vecs = \
np . linalg . eig (np . linalg . i nv (S_W) .do t (S_B) )
»>
eigen_pairs [ (np.abs (eigen_val s [i] ) , e igen_ve c s[ : , i] )
for i i n ra nge (l en( eigen_vals )) ]
eigen_pa i rs sorted (eigen_pairs ,
ke y=lambda k: k[O] , re verse=True )
рrint( ' Собственные значения в убывающем порядке : \n ' )
for eigen_val in e i gen_pairs :
print (eigen_val[O] )
452 . 721581245
156 . 43636122
8 . 11327596465е - 14
2 . 78687384543е - 14
2 . 7868738454Зе - 14
2 . 27622032758е - 14
2.27622032758е - 14
1 . 97162599817е - 14
1 . 32484714652е - 14
1 . 32484714652е-14
1.03791501611е - 14
5 . 94140664834е - 15
2.12636975748е - 16
tot = sum(eigen_vals.real)
discr = [(i / tot) for i in sorted(eigen_vals.real, reverse=True)]
cum_discr = np.cumsum(discr)
plt.bar(range(l, 14) , discr , alpha=0.5, align='center',
lаЬеl= ' индивидуальная "дискриминабель ност ь"')
1.0
' 0.8
6
С>
..."'
] 0.6
"'"'s: кумулятивная "дискриминабельность"
:Е
s: - индивидуальная "дискриминабельность"
~ 0.4
.~
"'а
с.: 0.2
о.о
I __________ _
4 6 10 12 14
Линейные дискриминанты
Матрица W:
( ( 0 . 0662 - 0.3797]
[- 0 . 0386 - 0 . 2206]
( 0 . 0217 - 0 . 3816]
(- 0 . 184 0 . 3018]
( 0 . 0034 0 . 0141]
[- 0.2326 0.0234]
[ 0.774 7 0.1869]
( 0 . 08 11 0.0696]
[- 0 . 0875 0 . 1796]
(- 0 . 185 - 0 . 284 ]
[ 0 . 066 0 . 2349}
0 . 3805 0.073 ]
0 . 3285 - 0 . 5971]]
Х' = XW.
Х train lda = X_train_std.do t( w)
colors = [ ' r ' , ' Ь ' , ' g ' ]
markers = [ s 1
' х ',
1
, ' о' ]
for 1, с , т in zip(np . unique (y_ train), colors , markers ):
plt . scatter (X_train_lda [y_train==l, 0]* (- 1) ,
X_ train_ lda[y_t rain==l , 1]* (- 1) ,
с=с , labe l= l , ma rker=m)
plt. xlabel ( 'L D 1 ' )
plt.ylabel (' LD 2 ')
plt.legend (loc= ' lower right ')
plt. show ()
Как видно на получ ив шемся графике , т еп ерь в новом подпространстве призн аков
три класса вин линейно разделимы:
"... .
• •
• ."• •
·-
1
-r.·•·
•. J. .•
• • l\t ••
• • ~•
.:.
•
,,,. • 8
Мх
х
• •
х
х х
-1 хХ "х Х
х
мхх )!( .;<х
х х *~ ~~х
-2 )1( .;'-
х х xjfc х
••• 1
-3 ххх 2
-4
х
••• з
-3 -2 -1
LO 1
150 Сжатие данных путем снижения разАtерностu
lr = LogisticRegression ()
lr = lr .fit (X_t rain_lda , y_ t rain )
plo t _decision_ regions (X_t r a in_lda , y_train, class i fie r=l r)
pl t . xlabel ( 'LD l ')
plt . yl abe l ( ' LD 2 ' )
pl t .legend(loc= ' lower lef t ' )
plt. show ()
• ••
4
....,....1\.
"..
о
о0 о
о о ..9.
8 'g
о
N
g
••
• • '11
•• •.. О
§о
(i)
оО О
(:)
0
о
-2
-4
ххх
ооо
-6
-6 -4 -2 4
lD 1
)(
х х ,"' )( )(
х ,"'
.
х х х ", х
...
х х
х х х
"," • )(
..
)( х / ".,,, ,.."!"' ~ - . . . .... ,
х х х / •
• ••
. ......
"\
х х
", /'
•• •
х х
~
,,,""" \ : х
х / •• )(
'\ '
)(
/)(
... " ..,, __ ..,.,,.,, "'
,,, •
/'
• х
)( х
'----------------+Х1
т
Х = [х 11 х2 ] ;
!Ф
z = [ xf ,~2х1 х2 ,х~ У.
Другими словами, посредством ядерного РСА мы выполняем нелинейное отобра
жение, которое преобразует данные в пространство более высокой размерности,
и используем стандартный РСА в этом более высокоразмерном пространстве для
проецирования данных назад в пространство более низкой размерности, где образ
цы могут быть разделены линейным классификатором (при условии, что образцы
могут быть разделены во входном пространстве по плотности). Однако оборотной
стороной этого подхода является то, что он в вычислительном плане очень затратен,
и поэтому мы используем ядерный трюк. При помощи ядерного трюка можно вы
числить подобие между двумя векторами признаков высокой размерности в исход
ном пространстве признаков.
1~ (i) (i)
ajk =- L/xj -µj)(xk -µk).
п i=1
L=.!.. i:x(i)x(i)T_
п i=1
LV =AV
1
=>-ф(Х)ф(Х/ а=Ла
п
1
=>-Ка=Ла.
п
К= ф(Х)ф(Х)r.
Другими словами, после ядерного РСА мы получаем образцы, которые уже спрое
цированы на соответствующие компоненты, вместо того чтобы строить матрицу
преобраз ования, как при подходе на основе стандартного РСА. В сущности, ядер
ная функция (или просто ядро) может пониматься как функция, которая вычисляет
скалярное произведение между двумя векторами - меру подобия.
Наиболее распространены следующие ядра:
"11"" полиномиальное ядро :
"11"" радиальная базисная функция (РБФ, гadial basis function, RBF), или гауссо
во ядро, которую мы будем использовать в последующих примерах в следую
щем подразделе:
Использоваиие ядериого .Atemoдa аиализа главиых ко.Аmо11е11т 155
Резюмируя все, что мы обсудили до сих пор, можно определить следующие три
шага для реализации ядерного РСА с РБФ в качестве ядра.
1. Вычислить матрицу ядра (матрицу подобия) k, где нам нужно вычислить сле
дующее:
Параметры
n_components : int
Число возвращаемых главных компонент
Возвращает
Х_рс np.column_stack((eigvecs[:, - i]
for i in range(l, n_components + 1)))
return Х_рс
Использование ядерного .метода анализа главиых ко.мпоиеит 157
Оборотная сторона использования ядерного РСА с РБФ в качестве ядра для сни
же ния р азмерности состоит в том, что нам нужно априорно определить параметр у.
1.0
••••••••••••
•••• ••••
• •• •• д
д
д • •• д
0.5
•• •• •• ••
.д
•
••
д •
•
•\)
••
.
д
д
•
••
.•
•
•
•
о.о
• •• • •••
•• ••
•• ••
••••• •••
••
-0.5 ••••••••••••
-1 .5 -1.0 -0.5 о. о 0.5 1.0 1.5 2.0 2.5
0.8
•
{ !.\
0.6
0.4
0.2
=
\J )
N ;; 'PPl! tt""'" ...
u о.о
"'-
-0.2
-0.4
-0.6
-0.8
••
-2.0 -1.5 -1 .0 -0.5 о. о 0.5 1.0 1.5 2.0 -2.0 -1 .5 -1 .0 -0.5 о.о 0.5 1.0 1.5 2.0
РС1 РС1
Напомним, что РСА это метод машинного обучения без учителя, и, в отличие от
с+
- LDA,
в нем информация о метках классов для максимизации дисперсии не используется.
В данном случае треугольные и круглые символы были добавлены для целей визуали
за ции , просто чтобы обозначить степень разделения.
Теперь видно, что эти два класса (круги и треугольники) хорошо линейно разде
лены, и поэтому преобразованные данные стали тренировочным набором, который
подходит для передачи на вход линейных классификаторов:
0.20
0.15
0.10
0.05
с:: 0.00 ан а
Q.
- 0.05
-0.10
-0.15
-0.20
-0.2 -0.2 -0.1 -О. О О.О О.О 0.1 0.2 0.2 -0.2 -0.2 -0.1 - О. О О. О О.О 0.1 0.2 0.2
РС1 РС1
1.5 .-------.------.------т-----....------т------.
1.0
0.5
о. о
-0.5
- 1.0
scikit_pca = PCA(n_components=2)
X_spca = scikit_pca.fit_transform(X)
fig, ах= plt.subplots(nrows=l , ncol s=2 , figsize=(7 , 3))
ax[O] . scat te r(X_spca[y==O , О] , X_spca[y==O , 1] ,
color= ' red ' , marker= • л • , alpha=0.5)
ах [О] . scatter(X_spca[y==l, 0] , X_spca[ y==l, 1] ,
color= ' Ьlue ' , marker= ' o' , alpha=0.5)
ax [l] .scatter(X_spca[y==O , О] , np.zeros(( 500 , 1)) +0 . 02 ,
color= ' red ', marker='л ' , alpha=0.5)
ax[l ] .scatter(X_spca[y==l , О] , np.zeros((S00,1))-0.02 ,
color= 'Ьlue ' , marker='o', alpha=0.5)
ах [О] .set_xlabe l( ' PCl ' )
ах[О] .set_ylabel( ' PC2')
ax [l] .set_ ylim ( [- 1, 1])
ax[l] .set_yticks( [] )
ах [ 1] . set _xlabel ( 'PCl')
plt. show ()
1.5
1.0
0.5
"'
u
Q.
О. О
-0.5
-1.0
-1.5
-1.5 -1.0 -0.5 О.О 0.5 1.0 1.5 -1.5 -1 .0 -0.5 о. о 0.5 1.0 1.5
РС 1 РС1
При услов и и, что им еется подходя щее значение для у , посмотрим , будем ли мы
удачливее с реал изацией ядерного РСА на основе РБФ :
И сно ва ядерный РСА на основе РБФ спроец иро вал данн ые на н о в ое под про
с транство , где эти дв а класса ст ановятся л ин ейно раздели мым и:
0.08
~•·
0.06
0.04
N
u
Q.
0.02
0.00
-0.02
-0.04
-0.06
- ,.
.,_". .
'- ··
,,:~~~i
-0.08
-0.06 -0.04 -0.02 0.00 0.02 0.04 О. Об 0.08 -0.06 -0.04 -0.02 0.00 0.02 0.04 0.06 0.08
РС1 РС1
162 Сжатие данных путем снижения ра:шерности
ф(х'/v.
= ''f/i)k(x',x<;»т .
j
Ка= Ал.
Параметры
gamma: float
Настроечный параметр я дра РБФ
n_components : int
Чис л о возвращаемых главных компонент
Во зв ращает
lamЬdas : список
Собственные значения
N = K. shape[OJ
one_n np.ones ( (N, N)) / N
К= К - one_n . dot (K) - K. dot (one_n) + one_n.dot (K) . dot (one_n)
Х , у= make_moons(n_samples=lOO , random_state=l23 )
al phas, lambdas =rbf ke r nel_pca (X, gamma =lS , n_components=l)
новой точкой данных х', и наша задача состоит в том, чтобы спроецировать ее на
это новое подпространство:
>»
х new Х [25] # новая точка данных
х леw
»>
x_reproj project_x (x_new , Х , # проецирование "н овой" точки данных
gamma=lS, alphas=alphas, lambdas=lambdas)
x_ reproj
array( [ 0.07877284])
0.015
исходная проекция точки Х[25]
0.010
0.005
* перепроецированная точка Х[25]
О.ООО llM•MMMMMMMMMAA
••• ~
-0.005
-0.010
-0.015
-0.20 -0.15 -0.10 -0.05 0.00 0.05 0.10 0.15 0.20
0.4
... """
••
.........••
0.2 "
...."li ··"
"" д •
•
••
о
д" " д
• •• ••
""
д
" ••
N
О. О
u
Q_
" •
•••
д
"" ••
д д "" •• •
••
-0.2
"" ""
-0.4
.
""•
".""" ... ""
"
••
.........
• •о
Резюме
В этой главе вы узнали о трех разных основополагающих методах снижения раз
мерности, применяемых для выделения признаков: стандартном методе РСА, LDA
и ядерном методе РСА. Используя РСА, мы спроецировали данные на подпростран
ство более низкой размерности для максимизации дисперсии вдоль ортогональных
осей признаков, при этом игнорируя метки классов. Метод LDA, в отличие от РСА,
применяется для снижения размерности с учителем, т. е. в нем при попытке макси
гиперпараметров
в
предыдущих главах вы узнали о ключевых алгоритмах машинного обучения
для выполнения классификации и о методах приведения данных в приемлемый
вид перед подачей их на вход этих алгоритмов. Теперь пора узнать об успешно за
рекомендовавших себя на практике методах создания хороших машиннообучаемых
моделей посредством тонкой настройки алгоритмов и о методах оценки качества
моделей! В этой главе мы узнаем, как:
<:r извлекать объективные оценки качества моделей;
<:r диагностировать типичные проблемы алгоритмов машинного обучения;
<:r выполнять тонкую настройку машиннообучаемых моделей;
cr оценивать прогнозные модели при помощи различных метрик оценки ка
чества .
impo rt pandas as pd
url = ' ht t ps://archive . ics.uci.edu/ml/machi nelearning- da t abases/breas t- cancer -
wis cons in /wdbc . da t a '
df = pd . read_csv (url , header=None)
>»
le .t ransform( [ ' М ', 'В' ] )
array ( [1, 0] )
вой шкале. Поэтому прежде чем мы сможем подать столбцы набора данных BCW
на вход линейного классификатора, такого как классификатор на основе логистиче
ской регрессии, нам нужно их стандартизировать. Кроме того, мы предположим, что
нам нужно, используя анализ главных компонент (РСА), который мы представили
в главе 5 %Сжатие данных путем снижения размер1юсти», применяемый для вы
деления признаков с целью снижения размерности, сжать данные с исходных 30
размерностей в более низкое двухмерное подпространство. Вместо раздельного вы
полнения шагов по подгонке и преобразованию тренировочного и тестового набо
ров данных мы можем расположить объекты StandardScaler, РСА и LogisticRegression
друг за другом в конвейере:
»>
fr om sklearn.preprocessing import StandardScaler
f rom s kl earn.decomposition import РСА
f rom sklearn.linear_model import LogisticRegression
f rom s klearn.pipeline import Pipeline
pipe_ lr Pipeline([('scl' , StandardScaler()),
('рса', PCA(n_ components=2)),
('clf ' , LogisticRegression(random_state= l )) ] )
pi pe_l r.fit(X_ train, y_train)
p ri nt( ' Bepнocть на т ес т овом наборе: % . Зf' % pipe_ lr.score(X_ test, y_test))
Верность на т е стовом наборе: 0 . 947
Метки классов
0 pipeline.fit 0 pipeline.pгedict
КОНВЕЙЕР
Масштабирование
Алгоритм обучения
pгedict
Прогнозная модель Метки классов
Иными словами, для каждого блока двум наборам одинакового размера, dO и d1, случайно
1
наз начаются точки данных (обычно это делается путем перемешивания массива данных
и его разбивки на две части). Затем мы тренируем на dO и тестируем на d1, после чего тре
нируем на d 1 и тестируем на dO. - Прим. перев.
172 Изучение наиболее успешных методов оцен'/СИ .моделей и тотсой настрой1."И
Исходны й набор
;_ щ D!!CS:
.-------------------...····················-·······...-----------,
Трен и ровочны й набор Проверочны й набор Тестовы й набор
"
1 -я итерация 1 ] .. 1' J_ ~
1 1, 1~ - 1.
GE1
2-я итерация J
1 J~ 1." 1 ~ ~Е2
1
••
10
Е = -~)-
10
3-я итерация J
i=I '
QЕз
1
J 1
•••
'"
174 Изучение наиболее успешных .методов оценки .моделей и тонкой настройJСU
»>
import numpy as np
fr om sklearn. mode l _ sele c tion import StratifiedKFold
kf old = StratifiedKFo l d (y= y_ train,
n_folds=lO ,
random_ state=l)
scores []
»>
from sklearn.model_selection import cross_val_score
scores ; cross_val_score(estimator;pipe_lr ,
X;X_ train ,
y;y_train ,
cv;lO ,
n _j obs;l)
рrint( ' Оценки перекрестно -пр оверочной верности: %s ' % scores )
Оценки перекрестно - проверочной верности: [ 0 . 89130435 0 . 97826087 0 . 97826087
0 . 91304348 0.93478261 о . 97777778
0 . 93333333 0 . 95555556 0 . 97777778
0 . 95555556]
рrint( 'Пе рекрестно-проверочная верность : %. 3f +/ - %.3f ' %
(np.mean(scores) , np . std(scores)))
Перекрестно - проверочная верность : 0.950 +/ - 0 . 029
Если модель для данного тренировочного набора данных слишком сложна, напри
мер в этой модели имеется слишком много степеней свободы либо параметров, то
она демонстрирует тенденцию к переобучению под тренировочные данные и недо
статочно хорошо обобщается на ранее не встречавшиеся данные . Нередко сократить
степень переобучения помогает аккумулирование большего количества тренировоч
ных образцов. Однако на практике эта работа часто может оказаться очень затратной
или просто невыполнимой. Построив график модельных верностей на тренировоч
ном и проверочном ( валидационном) наборах как функций размера тренировочно
го набора, можно легко установить, страдает ли модель от высокой дисперсии или
высокого смещения и поможет ли аккумулирование большего количества данных
решить эту проблему. Но прежде чем мы приступим к обсуждению того, как постро
ить график кривых обучения в библиотеке sckit-learn, обсудим эти две распростра
ненные модельные проблемы, вкратце рассмотрев следующую ниже иллюстрацию:
Отладка алгоритrшов при по~ющи кривой обучения и проверочной кривой 177
Хороший компромисс
«смещение-дисперсия»
,... ... - Верность на тренировочном ' ......."" ........ "."....."......."""."."".""""..""""::.":.".~ ".~".~ .";:i:i."~"
наборе
_,,
- Проверочная верность t
о
:i::
а.
-·-· Требуемая верность ф
CD
1.00 .----.------.----т---....----т----.----.---.....----.
~
. . .
: ~;.. t·,.-•· ·-· ::i"."e;:: -
:: :
.
,8 z~
: _"...;:-•-::_.._...;:•
: .
8,
. . .
.
~ -
.. . ·
.~ 8
.
,,.8
_;...•--•--11:-
1 :
:' /
• -:- •' .: .
: .:: .: : .
.: .
:...... : : : . ' :
0.95 ····· w;·--· ....." .. "" .. "" .. --··:·""----:· ·· " -- ·":-- ·--· ·--·:··· ·" .. " :"".".
.. .. .
.Q
.
~
.. ~
..
~
>=
проверочная точность
~
о
а. 0.90
Q}
CD
0.85
Принцип работы метода поиска по сетке параметров довольно прост, это парадигма
исчерпывающего поиска «путем грубой силы», где мы задаем список значений для
различных гиперпараметров, и компьютер оценивает качество модели для их каж
1
Оптимизационный поиск по сетке параметров, или сеточный поиск (grid seaгch) - это по
просту исчерпывающий поиск в заданном вручную подмножестве rиперпараметрическо
rо пространства с целью нахождения оптимальной комбинации гиперпараметров. - Прим.
перев.
182 Изучение наиболее успешных методов оценки моделей и тонкой настройки
»>
from s kl earn.mode l selection import GridSearchCV
from sklear n . svm import SVC
pipe_svc = Pipeline( [ ( ' scl ', StandardScaler()),
('clf', SVC(random_state=l)) ] )
param_ range = [0 . 000 1, 0.001 , 0 . 01, 0.1, 1.0, 10 . О, 100 . 0, 1000 .0 ]
param_grid [( 'clf_ C': param_ range,
'clf kernel ' : [ ' linear' ] ) ,
( 'clf_C': param_ range,
'c l f_ gamma': param_ range,
' clf_ kernel': [ ' rЬf' ] }]
gs Gri dSearchCV(est i mator=pipe_svc,
param_grid=param_grid ,
scoring= ' accuracy ',
cv= lO,
n_ jobs=-1)
gs = gs.fit (X_train, y_ train)
print(gs.best_score_ ) #перекрестно- п роверочная верность
0.978021978022
print(gs . best_params_ ) #наилучшие параметры
( 'clf_ C': 0 .1, 'clf_ kernel': 'linear'}
»>
clf = gs.best_est i mator_
clf . fit(X_ train, y_train)
print('Bepнocть на тестовом наборе: % .Зf' % clf.score(X_test , y_test))
Верность на тестовом наборе: 0.965
статистики (например, среднего или медианы), полученное с помощью большого числа об
разцов, отобранных из конкретной генеральной совокупности. - Прим. перев.
Тонкая настройка .маuщннообучаелtъ~~ люделей л1етодол1 сеточного поиска 183
нации параметров. Более подробно и с большим количеством примеров эта тема рассма
тривается на http://s c ikit- l earn. o rg/staЫe/ m odu l es/gr i d_se a rc h . html#ra n d om iz e d- pa ra m eter
optimization.
,_
1", . ,._,·"""" :ь д=- ==1= 0д,е ""'""I .ос=> '" "' " ' ·""~"""""'J Внешний ци кл
Трен ировать
;-;:>!•.o:;;f.'!.'P.'\."'::·.'i'••• параметра ми
Внутренний цикл
Перекрес~:н о
Тренировочн ый блок п ровероч ны и бл ок
} Настрои ть п а ра м етры
184 Изучение наиболее успешных .методов оценки .моделей и тонкой настройки
>»
gs GridSearc hCV (estimator;pipe_svc ,
param_grid;param_grid ,
scoring; ' accu ra cy ',
cv;2 ,
n_j obs;- 1)
scores; cross_val_score(gs , X_train, y_train, scoring; ' accuracy ', cv;5)
рr i nt( ' Перекрестно-nроверочная верность: % .Зf +/ - % . Зf ' % (
np.mean(scores), np . std(scores)))
Пере крестно - проверочная верность: 0.96 5 +/ - 0.025
»>
from sklearn . tree import DecisionTreeClassifier
gs ; GridSearchCV(
estimator;DecisionTreeClassifier (random_ state;O) ,
param_grid;[
{ ' max_depth ': [1, 2, 3, 4, 5, 6, 7, None] )] ,
scoring= ' accuracy ',
cv;5)
scores cross_val score(gs ,
X_train ,
y_ train ,
scoring; ' accuracy ',
cv;2)
рr in t( ' Перекрестно - проверочная верность: % .Зf +/ - % .Зf ' %
np . mean(scores), np.std(scores)))
Пере крес тно - проверочная верность: 0 . 921 +/ - 0 . 029
Спрогнозированный класс
р N
Исти н но Л ожно
Р положительные отр и цательные
(ТР) (FN)
Фа ктический класс
Ложно- Истинно
N положительные отр и цательные
(FP) (TN)
Хотя эти метрики можно легко вычислить вручную путем сравнения истинных
и предсказанных меток классов, библиотека scikit-leaгn предлагает вспомогатель
ную функцию confusion_matrix, которую можно использовать следующим образом:
»>
from sklearn.metrics import confusion_mat rix
pipe_svc .fit( X_ train , y_train )
y_pred = pipe_svc.predict (X_test)
confmat = confusion_matrix (y_true =y_test , y_pred=y_pred)
print(confmat)
[ [ 71 1]
[ 2 40]]
После выполнения приведенного выше исходного кода был получен массив, кото
рый предоставляет информацию о различных типах ошибок, сделанных классифи
катором на тестовом наборе данных, которые можно проиллюстрировать, изобразив
матрицу несоотв етствий из предыдущего рисунка при помощи функции matshow
библиотеки matplotlib:
fig , ах= plt . subplots(figsize= (2.5 , 2 . 5))
ax . matshow (confmat , cmap=plt.cm.Blues , alpha=0 . 3)
for i in range(confmat . shape [O] ):
for j in range(confmat . shape[l] ):
ax.text(x=j , y=i ,
s=confmat[i , j ] ,
va= ' center ', ha= ' center ' )
рlt.хlаЬеl (' распознанная метка ' )
plt . ylabel ('истинная метка ')
plt . show ()
1
Для справки: tгue positives (ТР)- истинно положительные исходы, true negatives (ТN) -
истинно отрицательные исходы, false positives (FP) - ложноположительные исходы и false
negatives (FN) - ложноотрицательные исходы. - Пpu..llt . перев.
186 Изучение наиболее успешных методов оцен1СU моделей и тоmсой настройкu
о 71
"'"':i;:~
"'"'
:х:
:х:
:s:
t:;
х
40
предсказанная метка
ERR= FP+FN
FP+FN +ТР+ТN
В этом случае верность прогноза можно вычислить непосредственно из ошибки:
TP+TN
АСС 1-ERR.
FP+FN +ТР+ТN
Метрики оценки качества «доля истинно положительных исходов,,-, (tгue positive
rate, TPR) и «доля ложноположительных исходов» (false positive rate, FPR) осо
бенно полезны для задач с несбалансированными классами :
1
ТР
PRE
TP+FP'
REC=TPR= ТР = ТР
Р FN+TP
На практике часто комбинация точности и полноты используется в так называе
мой метрике F1:
Fi= 2 PRExREC .
PRE+REC
Все эти оценочные метрики реализованы в scikit-leaш и могут быть импортирова
ны из модуля sklearn .metrics, как показано в следующем ниже фрагменте:
»>
from sklearn.metrics impor t precision_score
from sklearn.metrics import recall_score, fl score
рrint( ' Точность: % . Зf ' % precision_score(
y_ true=y_test , y_pred=y_pred))
Точность : 0.976
рrint('Полнота: % .Зf' % recall_score(
y_true=y_test, y_pred=y_pred))
Полнота: 0 . 952
print( ' Meтpикa Fl: % .Зf ' % fl_score(
y_true=y_test , y_pred=y_pred))
Метрика Fl : 0 . 964
используя для этого параметр scoring. Полный список разных значений, которые
принимаются этим параметром, можно найти на http://scikit- leam.org/staЫe/modules/
model_evaluation .html.
Напомним, что положительный класс в библиотеке scikit-leaш - это класс, кото
рый маркирован как класс 1. Если мы хотим указать другую положuтелъную мет
ку, то мы можем создать наш собственный регистратор оценок (scorer), воспользо-
188 Изучение наиболее успешных .методов оцен1СU J.tаделей и тонкой настройки
с+
Аналогично RОС - кривым можно вычислить кривые точности-полноты для различных
вероятностных порогов классификатора. Функция для построения графика кривых точ
ности-полноты также реализована в scikit-learn и задокументирована на веб-странице
http://scikit-learn.org/staЫe/modules/generated/sklearn.metrics . precision_recall_curve . html .
random_ state=O ,
C=l00 . 0))])
Х _ train2= Х _ train [ : , [ 4, 14] ]
cv = StratifiedKFold (y_ train,
n_folds=З ,
random_ state=l)
fig = plt.figure(figsize=(7, 5))
mean tpr = О . О
mean_fpr = np.linspace(O , 1, 100)
all_tpr = []
График RОС-криво й
1.0
0.8
><
:;;
...
х
~ 0.6
ilE
с:>
а
с:
о
х
х
t:s: 0.4
"' RОС·бло к1 (площадь= 0.69)
~ RОС·блок 2 (площадь= 0.78)
0.2 RОС·блок 3 (площадь= 0.76)
/
случайное гадание
средняя ROC (площадь= 0.75)
о. о идеальная работоспособность
»>
pi pe_lr = pipe_lr.fit (X_train2, y_train)
y_pred2 = pipe_lr.predict(X_test[: , [4 , 14]])
from sklearn.metrics import roc_auc_score
from sklearn.metrics import accuracy_score
print( ' ROC AUC : % .Зf ' % roc_auc_score(
y_true=y_test , y_score=y_pred2))
ROC AUC: 0 . 662
print( ' Bep нocть : % . Зf ' % accuracy_score(
y_true=y_test , y_pred=y_pred2))
Верность: 0.711
единичную точку отсечения на кривой ROC, А. П. Брэдли показал, что площадь под
RОС-кривой и метрики верности в основном друг с другом согласуются (А. Р. Brad-
ley, «The Use of the Area Under the ROC Curve in the Evaluatioв of Machine Learniвg
Algoгithms», Pattern гecogвition, 30 (7):1145-1159, 1997 («Использование площади под
кривой ROC при оценке алгоритмов машинного обучения»)).
Резюме
В начале этой главы мы обсудили, как соединять в цепочку различные методы пре
образования и классификаторы в виде удобных модельных конвейеров, которые
помогли нам эффективнее тренировать и тестировать машиннообучаемые модели.
Затем мы использовали эти конвейеры для выполнения одного из ключевых мето
дов отбора и оценивания модели - k- блочную перекрестную проверку. Используя
k- блочную перекрестную проверку, мы построили график с кривой обучения и про
верочной (валидационной) кривой для диагностирования типичных проблем алго
ритмов обучения, таких как переобучение и недообучение. Затем, используя опти
мизационный поиск по сетке параметров, мы выполнили тонкую настройку модели .
Мы завершили эту главу рассмотрением матрицы несоответствий и всевозможных
метрик оценки качества, которые могут быть полезными для дальнейшей оптими
зации модели для конкретной практической задачи. Теперь мы достаточно хорошо
оснащены ключевыми методами, чтобы успешно строить модели машинного обуче
ния с учителем для классификации данных.
В следующей главе мы рассмотрим ансамблевые методы, т. е. методы, которые по
зволяют комбинировать две и более моделей и алгоритмов классификации данных
для дальнейшего повышения предсказательной способности системы машинного
обучения.
Глава 7
Объединение моделей
для методов ансамблевого обучения
в
предыдущей главе мы сосредоточились на наиболее успешных практических
методах тонкой настройки и оценки разных моделей классификации данных.
В этой главе, опираясь на эти методы, мы разберем методы построения наборов
классификаторов, которые нередко могут давать более хорошую предсказательную
способность, чем любой из ее индивидуальных членов. Вы узнаете о том, как:
c:r выполнять прогнозы на основе мажоритарного голосования;
c:r сократить переобучение путем извлечения случайных комбинаций из трени
ровочного набора с повторами;
c:r строить мощные модели из слабых учеников, которые обучаются на своих
ошибках.
1
Мода (пюdе) - значение во множестве наблюдений, которое встречается наиболее часто,
т. е. з начение признака, имеющее наибольшую частоту в статистическом ряду распределе
ния . - Прим. перев.
194 Обьедине11ие J.t0делей для J.tетодов ансамблевого обучения
•••••••••• Единогласие
••••
т разных классификаторов ( Ct> ... , Ст).
О О О Плюрализм
\[
Тренировочный на~ор
i :: i
11
"'
о:
у
ф
Классификационные модели
'---
с! С2 ... c"lm
1:1
Q)
::i:
::i:
~
i i ! i
Прогнозы Р1 Р2 Р,,,
"-....,......- ......__ • • • ,.__,.
! i ! !
Окончательный прогноз
Обучение при по.мощи анса.J1tблей 195
если "''fy/x) ~О
иначе
Для иллюстрации того, почему ансамблевые методы могут работать лучше инди
видуальных классификаторов, взятых в отдельности, применим простые принципы
из комбинаторики. Пусть в следующем ниже примере все п базовых классифика
торов для задачи двухклассовой классификации имеют одинаковую частоту появ
ления ошибок Е. Кроме того, примем, что классификаторы независимы и частоты
ошибок не коррелированы. При таких допущениях можно выразить вероятность по
явления ошибки ансамбля из базовых классификаторов просто как функцию массы
вероятности биномиального распределения :
1
P(y~k)= f(
k=6
11
\ o.25k(1 - 0.25) 11-k = 0.034.
k/
Как видно, частота ошибок ансамбля (0.034) намного ниже частоты ошибок каж
дого индивидуального классификатора (0.25), в случае если все допущения соблю
дены. Отметим, что в этом упрощенном примере разделение 50 на 50 на равное чис
ло классификаторов п трактуется как ошибка, поскольку верно лишь в половине
случаев. Чтобы сравнить такой идеализированный ансамблевый классификатор
с базовым классификатором на диапазоне разных базовых частот ошибок, реализу
ем функцию массы вероятности на Python:
1
Функция массы вероятности (probability mass function, PMF) дает относительную вероят
ность того , что случайная дискретная величина в точности равна некоторому значению. Би
номинальное распределение - распределение количества «успехов~> в последовательности
»>
from scipy.mis c import соmЬ
impo r t math
def ensemЬle_ error (n _ classifier , error) :
k star t = int(math . ceil(n_classifier / 2.0)) #int для совместим. с Python 2.7
probs = [comb (n _ classifier , k) *
error**k *
(l - error)**(n_classifier - k)
for k in range(k_start , n classifier + 1) ]
return sum(probs)
ensemЬle _ error (n_ classifier=ll, error=O. 25)
0.034327507 01 904 2969
import numpy as np
error_ range = np.arange(O.O , 1.01, 0.01)
ens_ errors = [ ensemЬle _ error (n _ classifier=l 1, error=error)
for error in error_ range]
import matplotlib . pyplot as plt
pl t.plot(error_ range , ens_errors,
lаЬеl='Ансамблевая ошибка',
linewidth=2)
plt.plot(error_range, error_range,
linestyle=' --', lаЬеl= 'Ба зовая ошибка ',
linewi dth=2)
рlt.хlаЬеl('Базовая ошибка ')
рlt.уlаЬеl('Базовая/ансамблевая ошибка ')
plt.legend(loc= ' upper left')
plt. grid ()
plt.show()
1.0 .------.-------г-----.-----::;_.,----..,..
Ансамблевая ошибка
,
Базовая ошибка
0.8 ._...~~~~~~~~~-- .... .. ... . .
,,
\:1
\О
s:
3
о
::; 0.6
"'
"'
.а
"'
~
~ 0.4
,,
::;
"'~
"' :.,,,"
,
0.2 " " .... . ... """
,,
,,
0.2 0.4 0.6 0.8 1.0
Базовая ошибка
= argm~x[0.2x io + 0.2хio+О.6х4]=1.
1
у= mode{O, О, 1, 1, 1} = 1.
Для перевода принципа взвешенного мажоритарного голосования в исходный
код на
Python можно воспользоваться вспомогательными функциями библиотеки
NumPy argmax и Ьincount:
>»
import numpy as np
np.argmax(np.bincount( [O, О, 1] , weights=[0.2 , 0.2, 0.6]))
1
'f)=argm~x
1
'2:w1pii.
j=1
Параметры
def fit(self , Х , у ):
"" " Выполни ть подгонку классификаторов.
Пара метры
Возвращает
self : объек т
self.laЫenc = LabelEncoder()
self . laЫenc_ . fit(y)
self.classes = self . laЫen c . classes
self.classifiers = [}
for clf in self . classifiers:
fitted_clf = clone (clf) .fit (Х ,
self . laЫenc .trans form (y))
self. classifiers_. append (fitted_clf)
return self
Для лучшего понимания отдельных частей в исходный код было добавлено много
комментариев. Но прежде чем мы реализуем оставшиеся методы, сделаем неболь
шой перерыв и обсудим фрагмент исходного кода, который на первый взгляд может
показаться озадачивающим . Мы исп ользовали родительские классы BaseEstimator
и ClassifierMixin, чтобы бесплатно получить немного базовой функциональности,
включая методы get_params и set_params для установки и возврата значений пара
метров классификатора, и соответственно метод score для вычисления оценки точ
ности прогнозирования . Кроме того, отметим, что мы импортировали модуль six,
чтобы сделать ансамблевый мажоритарный классификатор MajorityVoteClassifier со
вместимым с Pytl10n 2. 7.
Реализация простого 1(Лассифика тора с 1о1ажоритарны.м голосование1оt 201
Параметры
Возвращает
def predict_proba(self, Х) :
Спрогнозировать вероятности классов для Х .
111111
Параметры
Возвращает
avg_proba массивоnодобный ,
202 Обьедuне1tие 11юделей для 11tетодов ансаJ1tблевого обучения
probas = np.asarray([clf.predict_proba(X)
for clf in self.classifiers ])
avg_proba = np.average(probas ,
axis=O, weights=self.weights)
return avg_proba
Отметим, что для вычислений оценки площади под RОС- кривой библио
с+
(ROC AUC)
те ка scikit-learn использует метод predict_proba (если он применим). В гл аве З ~ обзор
классификаторов с исполъзование.лt библиотеки scikit-lean1 ~ мы увидели , как вычисля
ются ве роятности классов в логистических регрессионных моделях. В деревьях реше
ний в ероятности вычисляются из частотного ве ктора , создаваемого для каждого узла
во время тренировки. Ве ктор аккумулирует значения частоты каждой м етки класса , вы
числяе мой из распределения меток классов в этом узл е. Затем частоты нормализуют
ся (нормируются) так , чтобы в сумме составлять 1. В алгоритме k бл ижайши х соседе й
метки классов k ближайших соседей агрегируются аналогичным образом, в результате
ч е го воз вращаются нормированные частоты меток классов . Несмотря на то ч то воз вра
щ аемые классификаторами на основе дерева реш е ний и k ближайши х соседей нормиро
в анные вероятности могут выглядеть похожими на в е роятности, полученные из логи
стич ес кой ре грессионной модели, мы должны осоз н авать, что они все - та ки выводятся
н е и з функций масс вероятносте й.
>»
from sklearn . model_ selection i mpor t cros s_val_s core
from sklearn . li near_model i mport Logi s t ic Regression
from sklearn . tree import Dec is i onTreeCl a ss ifier
from sklearn. neighbors import KNeighborsClassifier
from sklearn . pi peline i mport Pipeline
i mport numpy as np
clfl ; Logisti cRegres s ion(p enalty; ' l2 ' ,
С;О . 001 ,
ra ndom_state;O )
clf2 DecisionTreeCl a ssifier (max_ depth;l ,
cr"i t erion; ' en t ropy ' ,
random_ stat e;O )
clfЗ KNeighborsClassifier (n_neighbors; l ,
р ;2 ,
»>
mv_clf = MajorityVoteClassifier(classifiers= [pipel, clf2, рiреЗ])
clf_labels += [ 'М ажоритарное голосование' ]
a l l _clf = [pipel, clf2 , рiреЗ, mv_clf]
for clf, label in zip(all_clf , clf_labels) :
scores = cros s_val_s core(est i mator=clf,
X=X_train,
y=y_ train,
cv=lO,
scoring='roc_auc')
print("ROC AUC: %0 .2 f (+/ - %0.2f) [% s)"
% (scores. mean (), scores . std (), label))
ROC AUC: 0 . 92 (+/ - 0 .20) [Логистическа я регрессия ]
ROC AUC : 0 . 92 (+/ - 0.15 ) [Дерево решений)
ROC AUC: 0 . 93 (+/ - 0.10) [К ближайших соседей]
ROC AUC: 0 .97 (+/ - о .10) [ Мажоритарное голосование ]
Оценка и тонкая настройка ансамблевого 1СJ1ассификатора 205
for clf, label , clr , ls in zip(all_ clf , clf_ labels , colors, linestyles):
# принимая , что метка положительного класса равна 1
y_pred = clf .fit (X_ train ,
y_ train) .predict_proba(X_ test) [:, 1]
fpr, tpr, thresholds = roc_curve(y_ true=y_ test,
y_score=y_pred)
roc_auc = auc(x=fpr, y=tpr)
plt.plot(fpr, tpr,
color=clr,
linestyle=ls,
labe l =' %s (auc %0.2f)' % (label, roc_auc))
plt.legend(loc= ' lower right ' )
plt.plot ( [0 , 1] , [О , 1] ,
linestyle=' - -',
color= ' gray ',
linewidth=2)
plt.xlim( [- 0.1, 1.1 ] )
plt . yl im([ - 0 . 1, 1.1 ] )
plt.grid()
plt . xlabel('Дoля ложноположительных ' )
plt.ylabel( ' Дoля истинно положительных ' )
plt . show ()
1.0 """
''" /j:~:, :_.;:~~-+~:.:~.:-~ -.~<~~ -~ :-.:.-:· -~ ~-; ~-.,,:
>< 0.8 ....... .'. !. :::. . . .. ~. . . . . . . . . . . . . ;<tt. . ...•. . ...
:;;
:z: "'
..о
"'
а:
'}
1
а •/
.,._ ;
;
Лоrистическая регрессия(auc =0.92)
~ 0.2 ~" ;'
Дерево решений (auc =0.89)
;
1 ; К ближайших соседей (auc =0.86)
о.о 1- . • . . • . ~ .~ Мажоритарное голосование (auc = 0.95)
; ;
о.о 0.2 0.4 0.6 0.8 1.0
Доля ложн оположи тельных
С учетом того, что для примеров классификации мы отобрали всего два признака,
будет интересно увидеть, на что фактически похожа область решения ансамблевого
классификатора. Несмотря на то что перед подгонкой модели нет необходимости
стандартизировать тренировочные признаки, потому что наши конвейеры логис
тической регрессии и k ближайших соседей автоматически об этом позаботятся,
в целях визуализации мы выполним стандартизацию тренировочного набора, в ре
зультате чего области решений дерева решений будут в той же самой шкале. Соот
ветствующий исходный код выглядит следующим образом:
sc = StandardScaler()
X_train_std = sc . fit_transform(X_train)
from itertools import product
х min X_train_std[:, 0) .min () - l
х max X_train_std[ : , О] .max() + l
y_min X_tr ain_std[ :, 1 ) .min() - l
y_max X_ train_std [ :, 1] . max() + 1
хх, уу = np.meshgrid(np.arange(x_min , x_max , 0 .1),
np.arange(y_min , y_max , 0 . 1))
f, axarr plt.subplots(nrows=2, ncols=2 ,
sharex= col ', 1
s=50 )
axarr[idx[O], idx[l]] . set title(tt)
plt . text(-3.5 , - 4.5 ,
s= ' Шири на чашелистика [станд артизованная ] ' ,
ha= ' center ' , va= ' center ', fon tsize=l2)
plt.text( - 10.5 , 4. 5,
s= ' Длина лепестка [стан дар тизованн ая ] ',
";<
"'::z:::z:
"'"'
о
с.
-1
s:
,_"'s: -2
с.
"'::z:
с:[
-3
"'
..12. К бл ижа й ш их со седе й М а жоритарное голосован и е
"'
t""
"'<::
"'
о:;
"'::z:s:
~
-1
-2
-з
-з -2 -1 о -з -2 -1
1
Одноуровневое дерево решений, также именуемое пенько;11 решения (decision stшnp ), пред
ставляет собой дерево с одним внутренним узлом (корнем), который непосредственно под
ключе н к терминальным узлам (своим листьям). Пене к ре шения выполняет прогноз, ис
ходя из значения всего одного входного объекта. - Прим. перев.
208 Объединение .моделей для .методов анса.11tблевого обучения
Перед тем как вы узнаете, как выполнять тонкую настройку отдельных парамет
ров классификатора для ансамблевой классификации, вызовем метод get_params,
чтобы получить общее представление о том, каким образом обращаться к отдель
ным параметрам внутри объекта для поиска по сетке параметров GridSearch:
>»
mv_clf.get_params()
»>
for params , mean_score , scores in grid . grid_scores_ :
print (" %0.3f+/ - %0.2f %r"
% (mean_score, scores . std() / 2 , params))
0 . 967 +/ - 0 . 05 ( 'pipeline - l _ clf_C': 0.00 1, ' deci siontreeclassifier
max_ depth ' : 1}
0.967 +/ - 0.05 { ' pipe li ne - 1 clf С ' : 0.1 , ' decisiontreeclassifier_max_
depth ' : 1 }
1.000 + /-0.ОО { ' pipeline- 1 clf С ' : 100.0, ' decisiontreeclassifie r
max_dept h ': 1)
0 . 967 +/ -0 . 05 { 'pipe line - 1 clf С ' : 0.001 , ' decisiontreeclassifier
max_dept h': 2)
0 . 967 +/ - 0 . 05 { ' pipeline- 1 clf С ' : 0 .1 , ' decisio ntre eclassifier_max_
depth ' : 2)
1 . 000 +/ - 0 . 00 { ' pipeline- 1 clf С ' : 100 . 0 , 'decisi ontreeclassifier
max _ depth ' : 2 )
с+
Подход на основе мажоритарного голосования, который мы реализовали в этом разделе,
иногда также упоминается как многоярусное обобщение (stacking). Однако алгоритм
многоярусного обобщения чаще используется в сочетании с лоrистической регрессион
ной моделью, которая прогнозирует окончательную метку класса, используя в качестве
входа прогнозы индивидуальных классификаторов ансамбля, как более подробно опи
сано Дэвидом Х. Уолпертом в: D. Н. Wolpert, «Stacked generalization», Neural networks,
5(2):241 -259, 1992 («Многоярусное обобщение . Нейронные сети»).
210 Обьедuненuе Аt0делей для методов ансшtблевого обучения
Бутстрап-выборки 1 т) 1
1
~1 .. .
1~
! 1 / :::I:
о
tD
о:
... у
ф
! ! ! !
'
Прогнозы Р2
~ \......../ ~'
! ! ! !
Окончательны й прогноз
Затем переведем метки классов в двоичный формат и разделим набор данных со
ответственно на тренировочный ( 60%) и тестовый ( 40%) наборы:
»>
from sklearn.metrics import accuracy_score
tree = tree . fit (X_ tra in , y_ train)
y_train_pred = tree.predict(X_ train)
y_test_pred = tree.predict(X_test)
tree_ train = accuracy_score(y_train , y_train_pred)
tree test = accuracy score(y test, у test pred)
print('Bep нocть дере;а решен~й на тр~ниро;очном/тестовом наборах %. 3f/ %.3f '
% (tree_train, tree_test))
Верность дерева решений на тренировочном/тестовом наборах 1.000/0.833