КулЛиб - Классная библиотека! Скачать книги бесплатно 

Прагматичный ИИ. Машинное обучение и облачные технологии [Ноа Гифт] (pdf) читать онлайн

Книга в формате pdf! Изображения и текст могут не отображаться!


 [Настройки текста]  [Cбросить фильтры]
Машинное обучение

и облачные технологии

Прагматичный

ной

гисрт

~nnтt:Pfj

Pragmatic AI
An lntroduction to
Cloud-Based Machine
Learning

Noah Gift

./т Addison-Wesley
DuЬai

Boston • Columbus • New York • San Franctsco • Amsterdam • Саре Town
• London • Madrid • Milan • Munich • Paris • Montreal • Toronto • Delhi • Mexico Oty
SЗо Paulo • Sydney • Hong Kong • Seoul • Singapore • Taipei • Tokyo

ДЛЯ

ПРОФЕССИОНАЛОВ

Прагматичный ИИ
Машинное обучение
и облачные технологии

Ной ГиФт

Санкт-Петербург • Москва • Екатеринбург • Воронеж
Нижний Новгород • Ростов-на-Дону

Самара • Минск

2019

ББК
УДК

32.813+32.973.23-018
004.89+004.45

Г51

Гифт Ной
Г51

Прагматичный ИИ. Машинное обучение и облачные технологии.
тер,

2019. -

304 с.: ил. -

-

СПб.: Пи­

(Серия «Для профессионалов»).

ISBN 978-5-4461-1061-2
Искусственный интелле1П

-

это мощный инструмент в руках современного архите1ПОра,

разработчика и аналитика.
Облачные технологии

-

ващ путь к укрощению искусственного интеллекта.

Тщательно изучив эту незаменимую книгу от Ноя Гифта, легендарного эксперта по языку

Python,

вы легко научитесь писаrь облачные приложения с использованием средств искусствен­

ного интелле1Па и машинного обучения, решаrь реалистичные задачи из таких востребованных
и а!Пуальных областей, как спортивный маркетинг, управление прое1Пами, ценообразование,
сделки с недвижимостью.

Все примеры разобраны на языке

Python,





сфере современных стремительных вы­

числений.

16+ (В соответствии с Федеральным законом от 29 декабря 201 О г. № 436-ФЗ.)
ББК
УДК

32.813+32.973.23-018
004.89+004.45

Права на издание получены по соглашению с Реагsоп Educatioп lпс. Все права защищены. Никакая часть
данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения
владельцев авторских прав.

Информация, содержащаяся в данной книге, получена из источников, рассматриваемых издательством как
надежные. Тем не менее, имея в виду возможные человеческие или технические ошибки, издательство не
может гарантировать абсолютную точность и полноту приводимых сведений и не несет ответственности за
возможные ошибки, связанные с использованием книги. Издательство не несет ответственности за доступ­
ность материалов, ссылки на которые вы можете найти в этой книге. На момент подготовки книги к изданию
все ссылки на интернет-ресурсы были действующими.

ISBN 978-0134863863 англ.
ISBN 978-5-4461-1061-2

© 2019

Реагsоп Educatioп,

lnc.

©Перевод на русский язык ООО Издательство «Питер»,

2019

©Издание на русском языке, оформление ООО Издательство «Питер»,

2019
©Серия «Для профессионалов»,

2019

Краткое содержание
Предисловие ......................................................................................................... 14

Благодарности ......... "."""" ...................... " .... " ..................... " ........................... "19
Об авторе" ....... " .. " .... ""."."" ........ " .. " ............... " .. " ................ " .. " ..................... 23

Часrь

1.

Введение в прагматичный ИИ

1. Что такое ИИ """.""""."".""."""""""""."""""."."""".""."""""."". 26
Гпава 2. ИИ и инструменты машинного обучения""."""""""""""."""""""""" 55

Гпава

Гпава 3. Спартанский жизненный цикл ИИ .". ""."" ".""""" ""."". ".""." """. "". 82
Часrь
Гпава

4.

11.

ИИ в облаке

Разработка ИИ в облачной среде с помощью облачной

платформы
Гпава

Google"."""""" ... " ..... " .. " ............ " ..... " ...... " ...... " ........ "." ...... " ..... 100
5. Разработка ИИ в облачной среде с помощью веб-сервисов Amazon .""119

Часrь
Гпава

6.

111. Создание

реальных приложений ИИ с нуля

Прогноз популярности в соцсетях в НБА""".".""."".".""."".".".""".144

Гпава 7. Создание интеллектуального бота Slack в AWS.""""."""""""".""." .. 188
Гпава

8.

Извлечение полезной информации об управлении проектами

из учетной записи GitНuЬ-организации """."""""""""""""."""""""""""""". 206

9. Динамическая оптимизация виртуальных узлов ЕС2 в AWS """. ""."". 232
Гпава 10. Недвижимость "" .. "" "."" ""." .. ".""""" "". " .. """ ""."" """". "."".. 254
Г11ава 11. Промышленная эксплуатация ИИ для пользовательского контента"" 270

Гпава

Приложения

Припожение А. Аппаратные ускорители для ИИ."""".""""""."."""""""""". 298
Припожение Б. Выбор размера кластера ". ""." """" "" ." "" ." "" "" .""" """"" 300

Оглавление

Предисловие ............................................................••...........•...........•................... 14
Кому стоит прочитать эту книгу ............................•.....•...........•.•..........•..•.•....•..• 14

Сrруктура издания .................•...................................................................•....... 15

........•...........•.............••...•...••....•..•.•••.•...•.•.•.......•••...•.................. 17
Условные обозначения ............................•.............................•.........•........••....... 18
Примеры кода

Благодарности ......••.•...................••........•..................•........•....•....••..........•..•......•"19
Об авторе .....•..................................................................... " ..•...................•...•..... 23

Часть
Г11ава

1.

Введение в прагматичный ИИ

1. Что такое ИИ ......... "."" .. " .. " ........ """ "" ...•.. " ..•• " ..•..•• " •. "" """" .•.......• 26

Функциональное введение в Pythoп ..........•...........•.............•.•..••.......••........••.•... 27
Процедурные операторы ..............•.................•.....•.....••..•....••...•.......•....•...• 28

Вывод результатов." .. " .. " ... "."" .. """" ...... " .... ""." ... " .. ""."" .• " ........... " .. 28
Создание и использование переменных

." .. " ........•. " ... " .. " ..... " ......• "" .. " •.• 28

Множественные процедурные операторы .. " ....•.•........ " ..• " .•. " ....... " ..•• " ..... 29

.. " .. "" .....• "" .•...• ". " ... " ... " ...•....•...............•...•.....•.. " .... " ". 29
Склеивание строк ...................................................•................................... 29
Сложные операторы .... """."."""" ... " .. " .... " ...•.... " ... ".""." .. "" ...... ""." .... 29
Строки и форматирование строк ..... " ......... ". " ..•.......•..........••..... " .... " •• " .•. 30

Сложение чисел

Сложение и вычитание чисел."."""." ... " .... """"""""."""""" .. " ..•. """.". 33
Умножение десятичных чисел

.. "." "" "" "" ..• ".""" ... """ •..•. " ... ". " ... """"" 33
Использование показательных функций •. " •. """ .• """"""" .• """"""""""". 33

6

Оглавление

Преобразование между различными числовыми типами данных

"." ......... " 34
Округление ................................................................................................ 34
структуры данных ...................................................................................... 34
Словари

..................................................................................................... 35
....................................................................................................... 36
Функции ..................................................................................................... 36
Списки

Использование управляющих конструкций
Циклы
Циклы

........................................................ 45
for ................................................................................................... 45
while ................................................................................................ 46

Операторы

if/else ....................................................................................... 47
Промежуточные вопросы ............................................................................ 49
Резюме .............................................................................................................. 52
Глава

2.

ИИ и инструменты машинного обучения

... " .......... " ..................... " ........ 55

Экосистема исследования данных языка
блокнот

Язык

Python: IPython, Pandas, NumPy,
Jupiter, Sklearn ...................................................................................... 56

R, RStudio, Shiny

и

ggplot ....... " ................. " ............... " .... """ .... ". " ........... 57
Электронные таблицы: Excel и Google Sheets .. "" .... " ............... " .................... " .. 58
Разработка облачных приложений ИИ с помощью веб-сервисов Amazon ........... 58
Интеграция разработки и эксплуатации на AWS ........ " .... " ............... " ............... 59
Непрерывная поставка ......... " ............. " ...... " .................... " .. " .... " ............. 59
Создание среды разработки ПО для

AWS ..... " " ...................... " .. "."" ......... 60

Настройки проекта Pythoп для

AWS" ......................... " .. " ..... " .................... 63
Jupiter "." ............ " ........ " ............................ " .. "." 67
Интеграция утилит командной строки"." ................................................... 70
Интеграция AWS CodePipeline ........... " ........... " ... " ......... " ..... " ..... " ............. 74
Основные настройки Docker для исследования данных .... " ............................. ". 79
Другие сервисы сборки: Jenkins, CircleCI и Travis ............................................. "80
Резюме .............................................................................................................. 80
Интеграция с блокнотом

Глава

3.

Спартанский жизненный цикл ИИ

.. " ........ "" " .... " .............. " ................•. 82

Прагматическая петля обратной связи при промышленной эксплуатации ...... "" 83
AWS SageMaker ........... " .. " ...... " ............ " .. " ................... " ........ " .......... ". " .... "." 87

Петля обратной связи AWS Glue ........ " ...... "" " ..... " ... ". " ..... "" " ..... "" ............... 89
AWS Batch ...................................................................... " ................................. 93
Петли обратной связи на основе
Резюме

Docker ........... " ...................... " ........ " ... " ..... ". 95
.............................................................................................................. 97

7

Оглавление

Часrь

11.

ИИ в обпаке

Гпава 4. Разработка ИИ в облачной среде с помощью облачной

Google " ............................................................................................ 100
Обзор GCP ............. " ..... " .... ""." .. "".""." ... "" ..... " ........ ""." .. " .... "." ... " ...... ".101
Colaboratory ".". " .. "" " .... " .. "". " ... "" " ... " .... "" ....... " ....... ". ". ".""." .. "."" .. "". 102
Datalab .. " ... ". " ...... " .. " ....... " .. "" ... "" ........ " ..... ". " ..... " ... "." .. " " .. "." "" .. " .... " 105
Расширяем возможности Datalab с помощью Docker и реестра
контейнеров Google"." ... "."" .... "."." ....... "." .... " .. ""." .. "" .. " .. ".".".""."105
Запуск полнофункциональных машин с помощью Datalab ."""""""" .. "".106
BigQuery """"" .. ". ". "." ". "." ... " .. "". """ " .. " .. " ". " .. ". ". "". ". ""." ." .. "" •..... " .. 108
Облачные сервисы ИИ компании Google ... " ............ " .. " ... "" .. " .... "" .. "" ..... " ... 111
Тензорные процессоры Google и TensorFlow ..... " ... " .. "" .... "."" ..... "" .... " ...... "115
Резюме ............... "." ....... " .. " ....... " ................... """." .. " .. " ..... " .................. " ... 118

платформы

Гпава

5.

Разработка ИИ в облачной среде с помощью веб-сервисов

Amazon .• ". 119

Создание решений дополненной и виртуальной реальностей

AWS ................... " ... ". " ... " .... " .... " ....... " ......... " •..... " ....................... 122
Компьютерное зрение: создание конвейеров AR/VR
с помощью EFS и Flask". """. " .. """"" "" ... " .. "" " .... "" .... "." ....... "" ." ...... 122
Создание конвейера инженерии данных с помощью EFS, Flask
и Pandas. " .. ". " ........... " .........•..• " ....... " .. " ........ ". "" ........ "." .... " .. " ........ " 125
Резюме .... " ..... " ..... " .... ""." ... """"."."." .. "" ..... "." .... " .. """""."."."" ........ " .. 141

на основе

Часrь

111. Соэдание реальных приложений ИИ с нуля

Гпава 6. Прогноз популярности в соцсетях в НБА"."""" .. """""""""""".""""144

." ... "." .. "" .. "".".""." .... " .. "." ..... "."" ..... " .. """" ... " .. " ... "145
..... " .. "" ... "." .. "".""." ... " ... "" ...... "" .. " .. " ... "" .. "" .. ""." ...•. 145
Получение данных из труднодоступнь1х источников """ "" ". """. "."""" .. """. 168
Получение данных о просмотрах страниц «Википедии» спортсменов"" ... 168
Получение данных о вовлеченности в Twitter спортсменов""."""" .. """"173

Постановка задачи

Сбор данных

Изучаем данные об игроках НБА "".""""."""""""."""" .. ""."""""""""176
Машинное обучение без учителя для данных об игроках НБА
Построение фасетного графика по игрокам НБА на

". """ "" ... ""."" 181
языке R"""""""."""182

Собираем все воедино: команды, игроков, социальный авторитет

и рекламные отчисления"".""" ... ".""""" .. "."""."" ........ " .. """ ....... "" ..

183
Дальнейшие прагматичные шаги и учебные материалы "" """ "" """ "" "" """ 187
Резюме ...... " .. "."""" .. "" ... ""."."" .•.. ""." .• " .... "."." ... " .. " ... ""."" .. " ... "." .. ""187

8

Оглавление

Гпава

7. Создание интеллектуального бота Slack в AWS ...................... " ............ 188

Создание бота ...... " ... " .. " ......... " ..... " .. " ..... """" .. """." .. " .... "".""" ... " .. "."".188

Преобразование библиотеки в утилиту командной строки"""."""""""""""" 189
Выводим бот на новый уровень с помощью сервиса AWS Step Fuпctioпs".""".191

Настройка учетных данных IAM .. " ... "" ..... " .. "." .. " .. """."""""."." .. " .. " .... " ... 193

Завершение создания пошаговой функции "" ." ." """" ". ""." "" "." ..... " .. """" 203
Резюме." ........ " .. " ......... " .. " ..... " .. " ... "" ..... """." .. "" .. """ ... " ... "."".""""""" 205
Гпава

8.

Извлечение полезной информации об управлении проектами

из учетной записи GitНuЬ-организации """"" .. """""""""""""""""""""""."" 206
Обзор проблем, возникающих при управлении программными проектами""". 206

Создание исходного каркаса проекта исследования данных"""""""""."""". 209
Сбор и преобразование данных .. " ..... " ..... " .. ".""" .. """." ..... "." .. """ .. " .. " ..... 211

Обработка GitНuЬ-организации в целом""""""""""""""""""""""""""" .. ". 213
Формирование предметно-ориентированной статистики""." .. " ..... "".""." .. " .. 214
Подключение проекта по исследованию данных к интерфейсу

командной строки ..... " .. " ..... " .. "."" ... " .. " .. " .. "" ... "."""""."." ..... " .. " .. ".""" .. 216
Исследование GitНuЬ-организаций с помощью блокнота Jupiter.""""""""." ... 218

Изучаем метаданные файлов проекта CPython "" ".""" """ """"" ""." "" """" 221
Изучаем файлы, удаленные из проекта CPython """"""""""""""""""""""" 225
Развертывание проекта в каталоге пакетов Python""""""""""" .. """"""""" 228
Резюме ... " ... " ......... " .. " ....... " .......... " .. " .. "."." .. " .... ""." .. ".""".".""."."""" .. 231
Гпава

9. Динамическая оптимизация виртуальных узлов ЕС2 в AWS """""""". 232

Выполнение заданий на платформе AWS""""""""""""."""""""""""""""" 232
Спотовые виртуальные узлы . """"" """ "." "" ""."" ""." """"" .". "" """" 232
Теория спотовых виртуальных узлов и история цен на них""".""""""". 233
Создание утилиты и блокнота для сравнения цен на спотовые

виртуальные узлы на основе машинного обучения""""""""""""""""". 236
Написание модуля запуска спотового виртуального узла " .. """""""""". 243
Написание более сложного модуля запуска для спотового

виртуального узла ...... "

....... " ..... " .. " ......... "." .. " ........ " .. """." .. " ... """"" 250

Резюме."." .. " ........ " .... " ........ " ............ " .. "." ... "."."" ... "" .. " ... "."""""." .. """ 252
Гпава

10.

Недвижимость

" .......... " ......... " .. "." .. " .. " .... " .. "." .. " ... "."" .... " ... "". 254

Исследование цен на недвижимость в США."""""" .. """"""".""""""""""". 254
Интерактивная визуализация данных в Python """"".""""""""."""""""""" 257

Кластеризация по порядку размера и цене""""""""""""""""""""""""""" 260
Резюме ... " ... " ............. "." ......... " .. " .......... "" .... ""."" ... " .. "."" .. " .. "" .... " .. " .. " 269

9

Оглавление

Глава

11.

Промышленная эксплуатация ИИ для пользовательского контента .. "

Получившее премию

Netflix

270

решение не было внедрено в промышленную

эксплуатацию ........................ "

......... " .. " ....... " .... "" .............. " ............. "."." ... 271

Ключевые понятия рекомендательных систем"""".""."""" .. """"."""""".". 272
Использование фреймворка Surprise в языке Pythoп """ ". ".""" "" "" """"""" 273
Облачные решения для создания рекомендательных систем""."""."""".""" 276
Проблемы, возникающие на практике при работе с рекомендациями." ... """" 277

Облачный NLP и анализ тональности высказываний"""""""""""""""""."". 282

NLP на платформе Azure.""""."""" .. """"""."""""""".""""""""." .. "" 283
NLP на платформе GCP."" "" "" "."."".""""""". """. """ "" "" "" ." """"" 286
Изучаем API сущностей . "" ""."" .. """. """"". """ ".""" """ "". "". """" ". 287
Бессерверный конвейер ИИ промышленного уровня для NLP
на платформе AWS ............. " ........ " .. " .. " ..... " ..... " .. " ... "" .. "." ............. " ... 290
Резюме ...... " .. " ..... "

................. " ..... "." .. " ..... " ................... " ................. " ......... 295

Приложения

Приложение А. Аппаратные ускорители для ИИ""""""""""."""""""." ... """ 298
Приложение&. Выбор размера кластера.""."""".""""" .. """".""."""""".". 300

Отзывы

Фантастическое дополнение к списку литературы, предназначенной для фанатов
новых технологий! Столько всего можно сказать про эту книгу! Ной Гифт создал
действительно практическое руководство для всех, кто имеет дело с коммерческим
применением машинного обучения. Она не только рассказывает, как использовать

машинное обучение для больших наборов данных, но и дает читателю представление
о внутренних взаимосвязях данной технологии. Книга позволит множеству команд
разработчиков и исследователей данных с первых дней наладить эффективную раз­
работку и поддержку самых сложных проектов.

Нивас Дурайрадж

(Nivas Durairaj),
AWS
(сертифицированный архитектор решений AWS уровня Professiona/)
специалист по технической поддержке,

Прекрасная книга для тех, кто хотел бы заглянуть глубже в технологии создания

конвейеров и утилит машинного обучения промышленного уровня, которые действи­
тельно помогли бы командам ваших исследователей данных, инженеров-аналитиков
и специалистов по интеграции разработки и эксплуатации в сфере обработки данных.
Даже опытные разработчики нередко впустую тратят время и силы на определенные
задачи. Часто книги по разработке ПО и университетские курсы даже не упоминают
о важных для перехода к промышленной эксплуатации шагах. У Ноя есть настоящий
дар находить прагматичные подходы к развертыванию программного обеспечения,
существенно ускоряющие процесс разработки и поставки ПО. Благодаря его со­
средоточенности и энтузиазму становится возможным быстрое создание поистине

уникальных программных решений.

Ключ к созданию пригодных для промышленной эксплуатации конвейеров машинного
- автоматизация. Чтобы создать подходящую для промышленной эксплуа­
тации систему, необходимо автоматизировать и масштабировать задачи и шаги,

обучения

выполняемые инженерами вручную во время фазы исследования или создания

11

Отзывы

прототипа. В этой книге можно найти множество полезных и интересных упражнений,
которые помогут разработчикам на языке Python автоматизировать свои конвейеры
и перенести их в облако.

В настоящее время я работаю с большими данными, конвейерами машинного об­
учения, Python, AWS, облачными сервисами Google и Azure в онлайн-риелторском
агентстве Roofstock.com. Размер нашей базы данных, предназначенной для ана­
литической обработки, приближается к 500 млн строк. В этой книге я нашел для
себя множество практических советов и упражнений, значительно повысивших мою
личную производительность. Рекомендую!

Майкл Вирлин

(Michael Vierling),
Roofstock

ведущий инженер, компания

Эта юtига посвящается моим родным и близким, которые
всегда рядом в трудную минуту: моей жене Леа Гифт; моей
маме Шари Гифт; моему сыну Лиаму Гифту и моему учителю

доктору Джозефу Богену

Предисловие
Около

20 лет назад я работал в компании Caltech в Пасадене и мечтал,

что когда-нибудь буду ежедневно работать с ИИ (искусственным интел­
лектом). Тогда, в начале 2000-х, для мечтаний об ИИ было не самое под­
ходящее время. Несмотря на это, я достиг желаемого, и эта книга подводит

- ИИ и научной фантастикой. Мне очень
Caltech бок о бок с крупнейшими специалистами по ИИ,

итоги увлечения всей моей жизни

повезло работать в

и, вне всякого сомнения, этот опыт сыграл свою роль при написании данной
книги.

Помимо ИИ, меня всегда неудержимо притягивали автоматизация и прак­

тичность. Книга, которую вы держите в руках, охватывает и эти темы тоже.
Как закаленный, опытный менеджер, постоянно поставляющий программные

продукты и выживающий среди ужасных, чудовищных, никудышных техно­
логий, я стал очень практичным человеком. То, что не развернуто в промыш­

ленной эксплуатации,

- не в счет. Не автоматизировано - значит не работает.

Надеюсь, что эта книга вдохновит вас разделить мою точку зрения.

Кому стоит прочитать эту книгу
Эта книга предназначена для всех, кого интересуют ИИ, машинное обуче­
ние, облачные вычисления, а также любое сочетание данных тем. Как про­
граммисты, так и не-программисты найдут тут для себя крупицы полезной
информации. Многие студенты, с которыми я пересекался на семинарах

14

Предисловие

в

NASA, PayPal и в Калифорнийском университете в Дэвисе, смогли усво­

ить эти мои идеи даже при очень ограниченном опыте программирования

или вообще без такового. В данной книге активно используется

Python -

один из лучших языков для новичков в программировании.

В то же время здесь рассматривается множество таких продвинутых тем,

как использование платформ облачных вычислений (например,
и

Azure),

AWS, GCP

а также программирование машинного обучения и ИИ. Продви­

нутые технологи, свободно владеющие

Python, облачными вычислениями

и машинным обучением, тоже найдут для себя много полезных идей, кото­
рые смогут сразу применить в своей текущей работе.

Структура издания
Данная книга разбита на три части: часть 1 «Введение в прагматичный ИИ»;
часть

11

«ИИ в облаке» и часть

111

«Создание реальных приложений ИИ

с нуля». В части

1 главы 1-3 являются

О Глава

такое ИИ» включает обзор целей книги и очень краткое

1 «Что

руководство по

вводными.

Python, содержащее ровно столько информации, сколько
Python в этой книге.

нужно пользователю для понимания кода
О Глава

2 «ИИ

и инструменты машинного обучения» охватывает жизнен­

ный цикл систем сборки, использование командной строки и блокнотов

Jupiter в рамках проекта по

исследованию данных.

О Глава 3 «Спартанский жизненный цикл ИИ» показывает петлю обратной
связи при прагматической эксплуатации проектов. Здесь описываются

такие утилиты и фреймворки, как

Docker, SageMaker из

А WS, а также

тензорные процессоры, предназначенные для использования с библио­

текой
В части

TensorFlow (TensorFlow, Processing Units, TPU).

11

главы

4

и

5

рассматривают А WS и облачную инфраструктуру

Google.
О Глава

4

«Разработка ИИ в облачной среде с помощью облачной плат­

формы

Google» описывает облачную платформу Google (Google Cloud
Platform, GCP) и некоторые из предлагаемых ею уникальных, удобных

для разработчика возможностей. В ней охвачены такие сервисы, как

TPU, Colaboratory и Datalab.
15

Предисловие

[]

5 «Разработка ИИ в облачной среде с помощью веб-сервисов
Amazon» углубляется в вопросы последовательности выполняемых при
работе с А WS действий, например использования спотовых виртуальных
узлов, CodePipeline, Boto и тестирования программ на его основе, а также
Глава

включает высокоуровневый обзор сервисов.
В части 111главы6-11 охватывают прикладные приложения ИИ с примерами.

[]

Глава

«Прогноз популярности в соцсетях в НБА» основана на моей

6

работе в стартапе, нескольких статьях и докладе на конференции

Strata.

Охвачены такие темы, как «Что определяет стоимость команды?», «Рас­

тет ли число фанатов на играх в результате побед команды?», «Коррели­
рует ли зарплата игрока с его деятельностью в соцсетях?».

[]

Глава

7 «Создание

интеллектуального бота

Slack в А WS»

рассказывает

о создании бессерверного чат-бота для скрапинга веб-сайтов и отправки

информации обратно на

[]

Slack.

Глава 8 «Извлечение полезной информации об управлении проектами
из учетной записи GitНuЬ-организации» исследует распространенный
источник поведенческих данных - метаданные GitHub. Для поиска бес­

ценных поведенческих данных мы воспользуемся библиотекой
блокнотамиjuруtеr и утилитой командной строки click.

[]

Глава

9

Pandas,

«динамическая оптимизация виртуальных узлов ЕС2 в АWS»

демонстрирует возможности выбора оптимальной цены с помощью при­
емов машинного обучения на основе сигналов А WS.

[]

10 «Недвижимость»

посвящена изучению цен на дома- местных

и в масштабах всей страны

- с помощью машинного обучения и интер­

Глава

активных графиков.

[]

Глава

11

«Промышленная эксплуатация ИИ для пользовательского кон­

тента» рассказывает о применении ИИ для работы с пользовательским
контентом. Рассматриваются такие вопросы, как анализ тональности

высказываний и рекомендательные системы.
Приложение А «Аппаратные ускорители для ИИ» описывает аппаратные

ускорители, специально рассчитанные на работу с ИИ. В качестве примера
аппаратного ускорителя для ИИ можно привести

TPU от компании Google.

Приложение Б «Выбор размера кластера» рассматривает этот процесс ско­
рее как искусство, а не как точную науку, несмотря на наличие некоторых

методик, делающих его более прозрачным.

16

Предисловие

Примеры кода
Каждую главу этой книги сопровождает блокнот или набор блокнотов

Jupiter. Они были разработаны на протяжении нескольких последних лет
и представляют собой результат написания статей, а также проведения
семинаров и курсов.

Все исходные коды книги можно найти в виде блокнотов
здесь: https://github.com/noahgift/pragmaticai.

Jupiter

Многие примеры также включают сборочные файлы, подобные следующему:

setup:
-m venv

pythonЗ

~/.pragai

install:
pip install -r requirements.txt
test:
cd chapter7; py.test --nbval-lax notebooks/*.ipynb
lint:
pylint
lint-warnings:
pylint

--disaЬle=W,R,C *.ру

--disaЬle=R,C *.ру

Сборочные файлы

-

прекрасный способ организации проекта по исследо­

ванию данных на языке

Python или R. Особенно они удобны для настройки

среды, линтинга исходного кода, выполнения тестов и развертывания кода.

Кроме того, устранить целый класс проблем позволяют изолированные

среды, такие как

virtualenv.

Поразительно, сколько моих студентов сталки­

вались с одной и той же проблемой: установили какой-то пакет для одного

интерпретатора

Python, а использовали другой

интерпретатор. Или не могли

заставить программу работать из-за конфликта двух пакетов.

В целом решение этой проблемы

-

применять для каждого проекта вирту­

альную среду и всегда выбирать именно ее при работе с соответствующим
проектом. Использование при планировании проекта лишь малой толики

времени значительно предотвращает будущие проблемы. Применение

сборочных файлов, линтинг, тесты в блокнотах

SaaS -

Jupiter, система сборки

рекомендуемые практики, заслуживающие всяческого одобрения

и распространения.

17

Предисловие

Условные обозначения
В этой книге используются следующие типографские обозначения.
Участки кода внутри текста, названия объектов, классов, методов, имена
папок и файлов, расширения файлов, пути и пользовательский ввод вы­

глядят так: ~теперь можно преобразовать возвращаемые оценки в объект

DataFrame библиотеки Pandas для

разведочного анализа данных\).

Код, начинающийся со строк вида In [2], обозначает выводимые в консоль
результаты работы программы на языке

Python.

Зачастую схоже с сопрово­

ждающими книгу примерами в блокнотахjuрitсr, доступными на
Блок кода выглядит так:
#Переменные

среды приложения

REGION = "us-east-1"
АРР = "nlp-api"
NLP_TABLE = "nlp-taЬle"
Веб-адреса выделены таким шрифтом:

https://github.com.

Новые термины и ключевые слова выделяются курсивом.

GitHub.

Благодарности
Я благодарен Лоре Левин

предоставившей мне возмож­

(Laura Lewin),

ность опубликовать эту книгу в издательстве

Pearson,

как и всем осталь­

ным членам команды издательства: Малобике Чакраборти (MaloЬika

Chakraborty)

и Шери Реплин

(Sheri Replin).

Также я хотел бы поблаго­

дарить технических рецензентов: Чао-Сюаня Шена

(Chao-Hsuan Shen)

(https://www.linkedin.com/in/lucashsuan/), Кеннеди Бермана (Kennedy Behrman)
(https://www.linkedin.com/in/kennedybehrman/) и Гая Эрнеста (Guy Ernest) (https://
www.linkedin.com/in/guyemest/) из компании Amazon. Они сыграли важную роль
в доведении этой книги до ума.

В целом я хотел бы поблагодарить

Именно во время работы там,

Caltech.

в далеко не лучшие для этой технологии времена, я заинтересовался ИИ.

Я помню, как один профессор из

Caltech

говорил мне, что ИИ

-

пустая

трата времени, но я все равно хотел этим заниматься. Я поставил себе целью
к 40-летию начать писать серьезные ИИ-программы и свободно владеть
несколькими языками программирования

-

и достиг этого. Меня всегда

очень мотивировало, когда мне запрещали делать что-то, так что спасибо,
профессор!
Я также встретил там несколько весьма влиятельных людей, включая док­

тора Джозефа Богена

Ooseph Bogen), нейрофизиолога и эксперта в области

теорий сознания. Мы обсуждали за обедами нейронные сети, истоки со­
знания, математический анализ и работу доктора в лаборатории Кристофа

19

Благодарности

Коха (Christof Koch). Слишком мало сказать, что он повлиял на мою жизнь,
и я горжусь тем, что сегодня работаю над нейронными сетями, в частности,
благодаря этим беседам за обедом
Я повстречал в

Caltech

18 лет назад.

и других людей, с которыми не общался так тесно,

но которые все же повлияли на меня: доктора Дэвида Балтимора

(David
Baltimore), на которого я работал, доктора Дэвида Гудстайна (David
Goodstein), на которого я тоже работал, доктора Фэй-Фэй Ли (Fei-Fei Li)
и доктора Тайтуса Брауна (Titus Brown), который «подсадил~ меня на
Python.
Спорт всегда играл большую роль в моей жизни. Какое-то время я всерьез

занимался баскетболом, трекинговыми гонками и даже алтимат-фрисби.
В Калифорнийском политехническом в Сан-Луис-Обиспо я познакомился

(Sheldon Blockburger), олимпийским десяти­
меня бегать дистанцию 8 по 200 м менее чем за 27 с

с Шелдоном Блокбаргером
борцем, который учил
и дистанцию

300

м до тех пор, пока меня не начинало тошнить. Я до сих

пор помню, как он говорил: «Менее процента населения достаточно дис­
циплинированы для этого упражнения~. Такая тренировка внутренней
дисциплины сыграла колоссальную роль в моем становлении как разра­

ботчика ПО.
Я всегда крутился возле спортсменов мирового класса, меня притягивали

в них энергетика, оптимизм и желание побеждать. В последние несколько
лет я, тренируясь в

Empower

в Сан-Франциско, Калифорния, открыл для

(Brazilianjiu-jitsu, BJJ). В значительной мере
благодаря тамошним тренерам - Тареку Азиму (Tareq Azim), Йосефу Азиму
(Yossef Azim) и Джошу Макдональду (Josh McDonald) - я стал мыслить

себя бразильское джиу-джитсу

как боец. В частности, меня вдохновлял Джош Макдональд, спортсмен
мирового класса в нескольких видах спорта, его тренировки сыграли ко­

лоссальную роль в том, что я дописал данную книгу. Я очень рекомендую

этот спортзал и этих тренеров всем техническим специалистам в Области
залива Сан-Франциско.
Перечисленные первоначальные контакты привели меня к знакомству

с множеством других людей из мира боевых искусств, например из школы

NorCal Fight Alliance (Санта-Роза), управляемой Дэйвом
Терреллом (Dave Terrell). Я тренировался с Дэйвом Терреллом, Джейкобом
Хардгроувом (Jacob Hardgrove), Коллином Хартом (Collin Hart), Джасти­
ном Соммером (J ustin Sommer) и другими, и все они бескорыстно делились

боевых искусств

20

Благодарности

своими знаниями и размышлениями о боевых искусствах. Ничего в моей
жизни пока что не может сравниться с тем, как 110-килограммовый облада­
тель черного пояса снова и снова выжимал из меня все соки, день за днем.

Знание, что я способен выдержать это, сильно помогло мне перенести все
тяготы написания данной книги. Мне очень повезло тренироваться в этом

спортзале, и я рекомендую его всем техническим специалистам в Области
залива.

И последняя благодарность из сферы

BJJ -

Академии джиу-джитсу Мауи

в городе Хаику на острове Мауи (на Гавайях), вдохновлявшей меня при на­

писании этой книги. Я взял паузу в прошлом году, чтобы решить для себя,
чем мне хотелось бы заниматься дальше, и тренировался с профессором

Луисом Эредиа

(Luis Heredia)

и Джоэлем Буэ

Uoel Bouhey).

Они оба ве­

ликолепные учителя, и этот опыт очень помог мне при написании данной
книги.

Спасибо Заку Стоуну

(Zak Stone), менеджеру по продуктам TensorFlow,
TPU и помощь с облачной платформой
Google. Спасибо также Гаю Эрнесту (Guy Ernest) из компании Aшazon за
советы по сервисам AWS. Спасибо Полу Шили (Paul Shealy) из Microsoft
за советы по облачным решениям Azure.

за возможность раннего доступа к

Еще одна организация, которую я хотел бы поблагодарить,

-

Калифор­

нийский университет в Дэвисе. Я получил диплом магистра в области
бизнес-аналитики, и это оказало большое влияние на мою жизнь. Мне
повезло встретить таких замечательных профессоров, как доктор Дэвид

Вудрафф

(David Woodruff),

Python для

который разрешил мне программировать на

курса оптимизации и помог с обладающей большими возмож­

ностями библиотекой Руошо. Я должен также поблагодарить профессора
Диксона Луи

Хемана

(Dickson Louie) - замечательного наставника и доктора
Бхаргаву (Heшant Bhargava), предоставившего мне возможность

преподавать машинное обучение в Калифорнийском университете в Дэ­

висе. Доктор Норм Мэтлофф (Norш

Matloff)

также бескорыстно помогал

мне совершенствоваться в машинном обучении и статистике, за что я ему

очень благодарен. Я также благодарен студентам моего курса ВАХ-452,
опробовавшим часть материалов данной книги, и персоналу

Расселл (Ашу

MSBA1: Эми
Russell) и Шачи Говил (Shachi Govil). Хочу сказать спасибо

Магистерская программа в области естественных наук по бизнес-аналитике

(Master

of Science in Business Analytics ). - Здесь и далее прu;неч. пер.

21

Благодарности

и еще одному другу - Марио Искьердо (Mario Izquierdo, https://github.com/
marioizquierdo) - великолепному разработчику, разбрасывавшемуся прекрас­
ными идеями по поводу развертывания систем на практике.

И наконец, я хотел бы поблагодарить нескольких друзей из эпохи моей

работы в стартапе: Джерри Кастро Qeгry

Castro, https://www.linkedin.com/in/jeny-

castro-4bbЬ631/) и Кеннеди Бермана (https://www.linkedin.com/in/kennedyЬehrman/)

-

удивительно надежных, трудолюбивых и безотказных. Значительная часть
материалов для этой книги была создана, когда мы работали бок о бок
в окопах стартапа, который в итоге потерпел крах. Именно подобный опыт
раскрывает подлинный характер человека, и для меня было честью работать
вместе с ними и быть их другом.

Об авторе
Ной Гифт

(Noah Gift) -

преподаватель и консультант в магистратуре

Калифорнийского университета в Дэвисе в программе

MSBA.

Преподает

выпускникам машинное обучение и проводит консультации по машинно­
му обучению и облачным архитектурам для студентов и преподаватель­
ского состава. Ему принадлежит около

100 технических публикаций, в том

числе две книги, по различным темам: от облачного машинного обучения

до интеграции разработки и эксплуатации

(DevOps).

Он

-

сертифици­

рованный архитектор решений А WS и сертифицированный специалист

в области машинного обучения А WS, помогавший в свое время создавать
систему сертификации А WS по машинному обучению. У него также есть
диплом магистра в области бизнес-аналитики Калифорнийского универ­
ситета в Дэвисе, а также диплом магистра естественных наук в области
компьютерных информационных систем от Калифорнийского универси­

тета в Лос-Анджелесе и диплом бакалавра естественных наук в области
диетологии от Калифорнийского политехнического университета, Сан­

Луис-Обиспо.
В профессиональном отношении у Ноя почти

рования на

Foundation.

Python,

20

лет опыта программи­

он является коллегиальным членом

Python Software

Он работал, в частности, на должностях технического ди­

ректора, генерального директора, технического директора-консультанта

и архитектора облачных решений. Свой опыт он получил в множестве

разнообразных компаний, включая АБС,

Caltech, Sony Imageworks, Disney
23

Об авторе

Feature Animation, Weta Digital, АТ& Т, Turner Studios и Linden Lab.

В по­

следние десять лет он отвечал за вывод на глобальный рынок множества
новых продуктов в различных компаниях, принесших миллионы долларов

прибыли. В настоящее время он консультирует в стартапах и других ком­
паниях по вопросам машинного обучения, облачной архитектуры и в ка­

честве основателя компании

Pragmatic AI Labs дает

консультации уровня

технического директора.

Узнать больше о Ное вы можете, подписавшись на него на

GitHub по адресу

https://github.com/noahgift/, посетив сайт его компании Pragmatic AI Labs https://
paiml.com, его личный сайт http://noahgift.com или связавшись с ним на Linkedln
https://www.linkedin.com/in/noahgift/.

Часть

1

Введение

в прагматичный ИИ

Что такое ИИ

Не путайте процесс с результатом .

Джон Вуден

Uohn Wooden)

Если вы взяли в руки данную книгу, то, вероятно, вас интересует прагма­

тичный ИИ . Книг, курсов и вебинаров по современным методам машинного
и глубокого обучения вполне достаточно. Не хватает лишь информации
о том, как довести проект до состояния, при котором появляется принци­

пиальная возможность использования всех продвинутых методов. Именно

для этого предназначена книга

-

чтобы сократить разрыв между теорией

и практической реализацией связанных с искусственным интеллектом
проектов.

Во многих случаях обучить свою модель невозможно по причине простой
нехватки времени, ресурсов и навыков для реализации. Всегда есть лучшее
решение, чем двигаться по заведомо провальному пути. А практикующие

прагматичный ИИ всегда используют оптимальную для ситуации методику.
В некоторых случаях это может означать вызов программного интерфейса

приложения

(application prograrnrning interface, АР!) с предварительно об­

ученным методом. Еще одна прагматичная методика ИИ состоит в создании
намеренно менее эффективной модели для упрощения понимания и раз­

вертывания в промышленной эксплуатации.

В 2009 г. Netflix объявил знаменитый конкурс, предложив приз $1 млн команде

разработчиков, которая сможет повысить точность рекомендаций компании
на 1О %. Конкурс был очень увлекательным и опередил свое время в отноше­

нии науки о данных. Не многие знают, однако, что победивший алгоритм так

и не был реализован вследствие потенциально больших затрат на разработку

26

Глава

и внедрение

1.

Что такое ИИ

(https://www.wired.com/2012/04/netflix-prize-costs/). Вместо него были

использованы некоторые алгоритмы команды, достигшей улучшения резуль­

татов «ЛИШЬ» на

8,43 %. Это прекрасное подтверждение того, что подлинная
- практичность, а вовсе не идеальный результат.

цель многих задач ИИ

Данная книга уделяет основное вниманиетому, как оказаться той самой
командой со второго места, чье решение на самом деле попадет в промыш­

ленную эксплуатацию. Это связующая нить всей книги, чья цель

-

перевод

кода в промышленную эксплуатацию, а не получение им формального титу­
ла «лучшее решение», которое никогда не станет программным продуктом.

Функциональное введение в

Python

Python - потрясающий язык программирования, способный на множество
различных вещей. Есть мнение, что Python ни в чем не демонстрирует
исключительных результатов, но достаточно хорош в абсолютном боль­
шинстве приложений. Подлинная сильная сторона этого языка

намеренное отсутствие сложности.

Python

-

пред­

допускает также программи­

рование в множестве разных стилей. Его вполне можно использовать для

выполнения операторов в процедурном стиле, построчно. Но можно также

и в качестве сложного объектно-ориентированного языка программирова­

ния, обладающего такими продвинутыми возможностями, как метаклассы
и множественное наследование.

При изучении языка

Python,

особенно в контексте науки о данных, на не­

которых его частях можно не заострять внимания. Можно даже сказать, что

многие его составные части, особенно некоторые объектно-ориентированные

возможности, никогда не используются при написании блокнотовJuрitеr.
Вместо этого имеет смысл использовать альтернативный подход с упором

на функции. Данный раздел вкратце познакомит вас с языком
торый можно рассматривать как новый

Python, ко­

Microsoft Excel.

Один из недавних моих аспирантов сказал мне, что до моего курса машин­

ного обучения его беспокоил сложный вид соответствующего кода. Но по­
сле нескольких месяцев работы с языком

Python и блокнотами Jupiter он
Python для решения задач

почувствовал уверенность при использовании

науки о данных. Я убежден, исходя из виденного мной во время преподава­

ния, что любой пользователь

Excel может научиться использовать блокноты

J upiter на Python.
27

Часть

1 •

Введение в прагматичный ИИ

Стоит отметить, что в развертывании кода в промышленной эксплуатации

Jupiter

может играть роль механизма доставки, а может и не играть. В по­

следнее время стали очень популярны новые фреймворки, вроде

Databricks,
SageMaker и Datalab, создающие возможности введения в промышленную
эксплуатацию с помощью jupiter, но чаще всего Jupiter используется для
выполнения различных экспериментов.

Процедурные операторы
Для работы со следующими примерами у вас должен быть установлен

Python
адресу

версии не ниже 3.6. Скачать последнюю версию Python можно по
https://www.python.org/downloads/. Процедурные операторы фактически

представляют собой операторы, допускающие построчное выполнение.
Ниже перечислены типы выполняемых процедурных операторов.

О

Блокнот Jupiter.

О Командная оболочка
О Интерпретатор
о Сценарии

IPython.

Python.

Python.

Вывод результатов
Вывод результатов в

Python очень прост.

Функция

print получает входные

данные и выводит их в консоль:

In [1]: print{"Hello world")
Hello world

Создание и использование переменных
Переменные создаются путем присваивания. В следующем примере пере­
менной присваивается значение, после чего она выводится в консоль по­

средством объединения двух операторов через точку с запятой. Стиль
с подобным использованием точек с запятой можно часто встретить в блок­
нотах j uрitеr, но в коде и библиотеках, предназначенных для промышлен­
ной эксплуатации, на него обычно смотрят с неодобрением.

In [2]:
armbar
28

variaЫe

= "armbar";

print(variaЫe)

Глава

1.

Что такое ИИ

Множественные процедурные операторы
Полное решение задачи может представлять собой обычный процедур­
ный код, показанный ниже. Такой стиль уместен в блокнотах

Jupiter,

но редко встречается в коде, предназначенном для промышленной экс­
плуатации.

In

[З]:

attack_one = "kimura"
attack_two = "arm triangle"
print("In Brazilian jiu-jitsu а common attack is
print("Another common attack is а:", attack_two)

In Brazilian jiu-jitsu а common attack is
Another common attack is а: arm triangle

а:

а:",

attack_one)

kimura

Сложение чисел
Python можно использовать и в качестве калькулятора. Прекрасный способ
привыкнуть к языку - начать использовать его вместо Microsoft Excel или
приложения-калькулятора.

In [4]: 1+1
Out[4]: 2

Склеивание строк
Можно складывать и строки:

In

[б]:

Out[б]:

"arm" + "bar"
'armbar'

Сложные операторы
Можно создавать и более сложные операторы

данных вроде переменной

bel t,

-

с использованием структур

представляющей собой список:

In [7]: belts = ["white", "Ыuе", "purple", "brown", "Ыасk"]
.... for belt in belts:
if "Ыасk" in belt:
print("The belt I want to earn is:", belt)
else:
print("This is not the belt I want to end up with:", belt)
29

Часть

1 • Введение в прагматичный ИИ

....
This is not the
This is not the
This is not the
This is not the
The belt I want

belt I want
belt I want
belt I want
belt I want
to earn is:

to
to
to
to

end
end
end
end

up
up
up
up

with: white
with: Ыuе
with: purple
with: brown

Ыасk

Строки и форматирование строк
Строки

(strings) -

последовательности символов. Они часто форматиру­

ются программно. Практически все программы на языке

Python применяют

строки для отправки сообщений пользователям. Однако важно хорошо
представлять себе несколько базовых понятий.
О Строки можно создавать с помощью одинарных, двойных и тройных/
двойных кавычек.

О Строки можно форматировать.

О Строки могут находиться в нескольких кодировках, включая

Unicode.

О Существует множество методов работы со строками. В редакторе или
командной оболочке

IPython

можно увидеть список этих методов, вы­

деленных с помощью автозаполнения табуляцией.

In [8]: basic_string =
In [9]: basic_string.
encode()
capitalize()
istitle()
islower()
isalpha()
endswith()
casefold()
isupper()
isnumeric()
isdecimal()
expandtabs()
center()
join()
isprintaЫe()
isdigit()
find()
count()
ljust()
isidentifier() isspace()

format()
lower()
format_map()
lstrip()
index()
maketrans ()
isalnum()
parti tion ()

>

Простейший тип строки
Простейший тип строки

-

переменная, которой присвоено значение в виде

фразы в кавычках. Кавычки могут быть тройными, двойными или одинар­
ными.

In [10]: basic_string = "Brazilian jiu-jitsu"
30

Глава

1.

Что такое ИИ

Разбиение строк
Строку можно превратить в список, разбив ее по пробелам или другим
символам:

In [11]: #Разбиение по пробелам (по
.... basic_string.split()
Out[ll]: ['Brazilian', 'jiu-jitsu']

умолчанию)

In [12): #Разбиение по дефисам
.... string_with_hyphen = "Brazilian-jiu-jitsu"
.... string_with_hyphen.split("-")
Out[12]: ['Brazilian', 'jiu-jitsu']
Все заглавные буквы
В

Python есть множество удобных встроенных функций для преобразова­

ния строк. Вот так, например, можно преобразовать все символы в строке
в верхний регистр:

In [13): basic_string.upper()
'BRAZILIAN JIU JITSU'

Out[lЗ):

Срезы строк
Строки можно разрезать на части, указывая на длину:

In [14]:
....
Out [ 14] :
In [15):
....
Out[15):

#Получить первые два символа строки

basic_string[:2]
' Br'
#Получить длину строки

len(basic_string)
19

Склеивание строк
Строки можно склеивать путем конкатенации или присваивания строки

переменной с последующим прибавлением к ней строк. Такой стиль при­

емлем и интуитивно понятен для блокнотов Jupiteг, но из соображений
производительности лучше использовать в коде для промышленной экс­

плуатации f-строки.

In [16): basic_string +" is my favorite Martial Art"
'Brazilian jiu-jitsu is my favorite Martial Art'

Out[lб):

31

Часrь

1 •

Введение в прагматичный ИИ

Сложное форматирование строк
Один из лучших способов форматирования строк в современном

Python 3 -

использование f-строк:
~ Iп

[17]: f'I love

practiciпg

my favorite Martial Art,

{basic_striпg}'

Out[17]: 'I love
Braziliaп

practiciпg

my favorite Martial Art,

jiu-jitsu'

Для обертывания строк можно использовать

тройные кавычки
Иногда может понадобиться взять фрагмент текста и присвоить его пере­
менной. Проще всего сделать это в

Python

с помощью заключения фразы

в тройные кавычки:
Iп

[18]:

fllllll

This phrase is multiple seпteпces loпg.
The phrase сап Ье formatted like simpler seпteпces,
for example, I сап still talk about my favorite
Martial Art {basic_striпg}
Out[18]: '\пThis phrase is multiple seпteпces loпg.\пThe phrase
сап Ье formatted like simpler seпteпces,\пfor example,
I сап still talk about
my favorite Martial Art Braziliaп jiu-jitsu\п'
Разрывы строк можно удалить с помощью метода

Replace

Вышеприведенная длинная строка содержала символы разрывов строки
символы \п, которые можно удалить с помощью метода

Iп

[19]:

replace:

f"''"

This phrase is multiple seпteпces loпg.
The phrase сап Ье formatted like simpler seпteпces,
for example, I сап still talk about my favorite
Martial Art {basic_striпg}
''''".replace(''\n'', "'')
Out[19]: 'This phrase is multiple seпteпces loпg. The phrase сап Ье
formatted like simpler seпteпces, for example, I сап still talk about
my favorite Martial Art Braziliaп jiu-jitsu'

32

-

Глава

1.

Что такое ИИ

Числа и арифметические операции
В

Python есть встроенный калькулятор. Он способен выполнять множество

простых и сложных арифметических операций без всяких дополнительных
библиотек.

Сложение и вычитание чисел
Язык

Python

также демонстрирует гибкость в форматировании фраз на

основе f-строк:

In [20]: steps = (1+1)-1
... : print(f"Two Steps Forward:
Two Steps Forward:

One Step Back = {steps}")

One Step Back = 1

Умножение десятичных чисел
В язык

Python также

встроена поддержка десятичных чисел, что упрощает

решение арифметических задач:

In [21]:
body_fat_percentage = 0.10
weight = 200
fat_total = body_fat_percentage * weight
print(f"I weight 200lbs, and {fat_total}lbs of that is fat")
I weight 200lbs, and 20.0lbs of that is fat

Использование показательных функций
С помощью библиотеки

math можно легко вычислить, например, 2 в третьей

степени:

In [22]: import math
.... math.pow(2,З)
Out[22]: 8.0
Другой сnособ:

>» 2**3
8

33

Часrь

1 • Введение в прагматичный ИИ

Преобразование между различными числовыми
типами данных
В

Python существует множество форм чисел.

Вот две наиболее распростра­

ненные:

целые числа;

D

D числа с плавающей запятой.

In [23]: number = 100
.... num_type = type(number).~name~
.... print(f"{number} is type [{num_type}]")
100 is type [int]
In [24]: number = float(100)
.... num_type = type(number).~name~
.... print(f"{number} is type [{num_type}]")
100.0 is type [float]

Округление
Десятичное число с большим количеством знаков можно округлить, напри­
мер, до двух знаков после запятой:

In [26]: too_many_decimals = 1.912345897
.... round(too_many_decimals, 2)
Out[26]: 1.91
Структуры данных
В

Python есть несколько часто используемых базовых структур данных:

D

списки;

D

словари.

Словари и списки

- основные «рабочие лошадки» языка Python, но в нем

есть и другие структуры данных, например кортежи, счетчики и т. д., также

заслуживающие изучения.

34

Глава

1.

Что такое ИИ

Словари
Словари, как и сам

Python, отлично подходят для решения множества за­

дач. В следующем примере в словарь помещается список атакующих при­

емов бразильского джиу-джитсу. Ключом является прием, а значением

-

половина тела, к которой он применяется:
Iп

[27):

submissioпs

= {"armbar": "upper_body",
"arm_triaпgle": "upper_body",
"heel_hook": "lower_body",
"kпee_bar": "lower_body"}

Распространенный паттерн работы со словарями
с помощью метода

i tems.

- итерация по словарю

В следующем примере в консоль выводятся ключ

и значение:

Iп

[28): for
....

submissioп,

body_part

iп submissioпs.items():

priпt(f"The {submissioп}
оп

is

ап

attack \

the {body_part}")

The armbar is ап attack оп the upper_body
The arm_triaпgle is ап attack оп the upper_body
The heel_hook is ап attack оп the lower_body
The kпee_bar is ап attack оп the lower_body
Словари можно также использовать для фильтрации. В нижеприведенном

примере выводятся только болевые приемы

половину тела
Iп

[29):

( subrnission attack) на верхнюю

(upper body):

are upper_body submissioп attacks\
jiu-jitsu:")
.... for submissioп, body_part iп submissions.items():
....
if body_part == "upper _body":
... .
print(submission)
priпt{f"These

iп Braziliaп

These are upper_body
armbar

submissioп

attacks in Brazilian jiu-jitsu:

arm_triaпgle

Можно также выбирать ключи и значения словарей:
Iп

[30):
....

priпt(f"These

priпt(f"These

are keys: {submissioпs.keys()}")
are values: {submissioпs.values()}")

35

Часть

1 •

Введение в прагматичный ИИ

These are keys: dict_keys(['armbar', 'arm_triangle',
'heel_hook', 'knee_bar'])
These are values: dict_values(['upper_body', 'upper_body',
'lower_body', 'lower_body'])

Списки
Списки часто используются в языке

Python.

Они дают возможность реа­

лизации последовательных коллекций. Списки могут включать в качестве
элементов словари, точно так же, как и словари могут включать списки.

In [31) : list_of_bjj_posi tions = [ "mount", "full-guard",
"half-guard", "turtle",
"side-control", "rear-mount",
"knee-on-belly", "north-south",
"open-guard"]

....

In [32): for position in list_of _bjj_positions:
if "guard" in position:
....
print(position)
....
full-guard
half-guard
open-guard
Можно выбирать элементы списков посредством срезов:

In [35): print(f'First position: {list_of_bjj_positions[:l)}')
print(f'Last position: {list_of_bjj_positions[-1:)}')
print(f'First three positions:\
{list_of_bjj_positions[0:3]}')
First position: ['mount']
Last position: ['open-guard']
First three positions: ['mount', 'full-guard', 'half-guard']
Функции
Функции

-

стандартные блоки программирования при исследовании

данных на языке

Python,

а равно и способ создания логичных, удобных

в тестировании структур. На протяжении десятилетий велись споры о том,

36

Глава

какой стиль программирования на языке

Python лучше -

1.

Что такое ИИ

функциональный

или объектно-ориентированный. В этом разделе вы не найдете ответа на
данный вопрос, но увидите, почему полезно знать основы работы с функ­
циями в

Python.

Написание функций
Важнейший навык для программиста на языке

Python - умение писать

функции. Владение основными навыками работы с функциями означает
возможность использования практически всего, что предлагает язык.

Простая функция
Простейшие функции лишь возвращают значение:

In [1]: def favorite_martial_art():
....
return "bjj"
In [2]: favorite_martial_art()
Out[2]: "bjj"
Документирование функций
Снабдить функцию документацией никогда не будет лишним. В блокнотах

Jupiteг и

IPython для просмотра docstгing достаточно обратиться к функции

по имени с добавлением после объекта символа ?, как показано ниже:

In [2]: favorite_martial_art_with_docstring?
Signature: favorite_martial_art_with_docstring()
Docstring: This function returns the name of my favorite martial art
File:
-/src/functional_intro_to_python/
Туре:
function
Описания dосstгing-функций можно вывести в консоль, обратившись
к атрибуту

_doc_:

In [4]: favorite_martial_art_with_docstring._doc_
Out[4]: 'This function returns the name of my favorite martial art'
Аргументы функций: позиционные, именованные
Наиболее полезны те функции, в которые можно передавать аргументы.
В приведенной ниже функции обрабатываются новые значения для аргумента

37

Часть

times.

1 • Введение в прагматичный ИИ
Аргумент этой функции ~позиционный~, неименованный. Позици­

онные аргументы обрабатываются в порядке их создания:

In [5]: def practice(times):
print(f"I like to practice {times} times
....
In [6]: practice(2)
I like to practice 2 times

а

day

In [7]: practice(З)
I like to practice з times

а

day

а

day")

Позиционные аргументы: обрабатываются по порядку. Позиционные
аргументы функций обрабатываются в порядке их описания. Поэтому их
можно легко создавать и легко же перепутать.

In [9]: def practice(times, technique, duration):
print(f"I like to practice {technique},\
....
{times} times а day, for {duration} minutes")
In [10]: practice(З, "leg locks", 45)
I like to practice leg locks, 3 times

а

day, for 45 minutes

Именованные аргументы: обрабатываются по юuочу или значению, могут
иметь значения по умолчанию. Одно из удобных свойств именованных
аргументов

-

возможность задавать значения по умолчанию и указывать

явным образом только те из них, которые нужно изменить.

In [12]: def practice(times=2, technique="kimura", duration=б0):
print(f"I like to practice {technique},\
{times} times а day, for {duration} minutes")
In [13]: practice()
I like to practice kimura, 2 times а day, for 60 minutes
In [14]: practice(duration=90)
I like to practice kimura, 2 times а day, for 90 minutes

**kwargs

и

*args.

Синтаксисы

**kwargs

или

*args

позволяют передавать

в функции динамические аргументы. Однако применять эти виды син­
таксиса следует осмотрительно, поскольку они затрудняют понимание

кода. При использовании там, где это целесообразно, они предоставляют
широкие возможности.

38

Глава

1.

Что такое ИИ

In [15]: def attack_techniques(**kwargs):
"""Принимает произвольное число именованных аргументов"""

for name, attack in kwargs.items():
print(f"This is an attack I would like\
to practice: {attack}")
In [16]: attack_techniques(arm_attack="kimura",
leg_attack="straight_ankle_lock",
....
neck_attack="arm_triangle")

....

This is an attack I would like to practice: kimura
This is an attack I would like to practice: straight_ankle_lock
This is an attack I would like to practice: arm_triangle
Передача функции словаря именова1П1ых арrумеmов. Синтаксис

**kwargs

можно использовать для передачи всех аргументов сразу:

In [19]: attacks = {"arm_attack":"kimura",
"leg_attack":"straight_ankle_lock",
....
"neck_attack":"arm_triangle"}
....
In [20]: attack_techniques(**attacks)
This is an attack I would like to practice: kimura
This is an attack I would like to practice: straight_ankle_lock
This is an attack I would like to practice: arm_triangle
Передача фуккций в качестве аргументов. Объектно-ориентированное

программирование

-

популярный способ программирования, но не един­

ственный возможный в

Python.

В качестве вспомогательного стиля для

организации конкурентности и исследования данных вполне подходит

функциональное программирование.

В следующем примере благодаря передаче функции в качестве аргумента
появляется возможность использования ее внутри другой функции:

In [21]: def attack_location(technique):
"""Возвращает место применения приема"""

attacks = {"kimura": "arm_attack",
"straight_ankle_lock":"leg_attack",
"arm_triangle":"neck_attack"}
if technique in attacks:
return attacks[technique]

39

Часть

1 •

Введение в прагматичный ИИ

return "Unknown"
In [22): attack_location("kimura")
Out[22]: 'arm_attack'
In [24): attack_location("bear hug")
Out[24]: 'Unknown'
In [25): def multiple_attacks(attack_location_function):
"""Принимает на входе функцию распределения
....

приемов

по категориям и возвращает место применения приема"""

["rear_naked_choke",
new_attacks_list
"americaпa", "kimura"]
for attack in new_attacks_list:
attack_location = attack_location_function(attack)
print(f"The location of attack {attack} \
is {attack_location}")
Iп [26): multiple_attacks(attack_location)
The location of attack rear_naked_choke is Unknown
The location of attack americana is Unknown
The location of attack kimura is arm_attack

Замыкания и каррирование функций. Замыкания ( closures) - функции,
содержащие другие функции. В языке Python их часто применяют для от­
слеживания состояния. В приведенном ниже примере внешняя функция

attack_counter отслеживает число атакующих приемов. Внутренняя функ­
ция attack_filter использует ключевое слово nonlocal языка Python 3 для
изменения значения переменной во внешней функции.

Такой подход носит название каррирования функций

(functional currying)

и позволяет создавать на основе общих функций специализированные.
Как показано ниже, подобные функции могут лечь в основу простой компью­
терной игры или подсчета статистики поединка в смешанных единоборствах:

In [1]: def attack_counter():
"""Подсчитывает количество атак на конкретную половину
тела''''"

lower_body_couпter

=0

=0
def attack_filter(attack):
upper_body_couпter

40

Глава

1.

Что такое ИИ

nonlocal lower_body_counter
nonlocal upper_body_counter
attacks = {"kimura": "upper_body",
"straight_ankle_lock":"lower_body",
"arm_triangle":"upper_body",
"keylock": "upper_body",
"knee_bar": "lower_body"}
if attack in attacks:
i f attacks[attack] == "upper_body":
upper_body_counter +=1
i f attacks[attack] == "lower_body":
lower_body_counter +=1
print(f"Upper Body Attacks {upper_body_counter},\
Lower Body Attacks {lower_body_counter}")
return attack_filter
In [2]: fight = attack_counter()
In [З]: fight("kimura")
Upper Body Attacks 1, Lower Body Attacks 0
In (4): fight{"knee_bar")
Upper Body Attacks 1, Lower Body Attacks 1
In [5]: fight{"keylock")
Upper Body Attacks 2, Lower Body Attacks 1
Функции, использующие ключевое слово
ное вычисление

-

yield

(генераторы). Отложен­

удобный стиль программирования, одним из примеров

которого являются генераторы. Генераторы выдают значение в нужный
момент времени.

Нижеприведенный пример возвращает бесконечную случайную последо­
вательность атакующих приемов. Отложенность здесь заключается в том,

что, хотя количество значений бесконечно, возвращаются они только при
вызове функции.

In [6]: def lazy_return_random_attacks():
"""Каждый раз возвращает атакующие nриемы"""

import random
attacks = {"kimura": "upper_body",
"straight_ankle_lock":"lower_body",
"arm_triangle":"upper_body",

41

Часть

1 •

Введение в прагматичный ИИ

"keylock": "upper_body",
"knee_bar": "lower_body"}
while True:
random_attack = random.choices(list(attacks.keys()))
yield random_attack
In [7]: attack = lazy_return_random_attacks()
In [8]: next(attack)
Out[8): ['straight_ankle_lock')
In [9): attacks = {"kimura": "upper_body",
"straight_ankle_lock":"lower_body",
"arm_triangle":"upper_body",
"keylock": "upper_body",
"knee_bar": "lower_body"}
In [10): for

in range(10):
print(next(attack))

['keylock']
[ 'arm_triangle']
[ 'arm_triangle']
['arm_triangle']
[ 'knee_bar' ]
['arm_triangle']
[ 'knee_bar' ]
['kimura']
['arm_triangle']
['kimura'
Декораторы: функции, служащие адаптерами для других функций.

Еще одна полезная возможность

Python -

синтаксис декоратора, позво­

ляющий обернуть одну функцию в другую. В нижеприведенном примере

написан декоратор, добавляющий к каждому вызову функции паузу слу­
чайной длины. В сочетании с вышеописанным ~бесконечным» генератором
атакующих приемов он генерирует паузы случайной длины между вызовами
функций.

In [12): def randomized_speed_attack_decorator(function):
"""Вносит элемент случайности в скорость атак"""

42

Глава

:
:
:
:
:
:
:
:
:
:

1.

Что такое ИИ

import time
import random
def wrapper_func(*args, **kwargs):
sleep_time = random.randint(0,З)
print(f"Attacking after {sleep_time} seconds")
time.sleep(sleep_time)
return function(*args, **kwargs)
return wrapper_func

In [13) : @randomized_speed_attack_decorator
: def lazy_return_random_attacks():
"""Каждый раз возвращает атакующие приемы"""
:
import random
:
attacks = {"kimura": "upper_body",
"straight_ankle_lock":"lower_body",
:
"arm_triangle":"upper_body",
:
"keylock": "upper_body",
:
"knee_bar": "lower_body"}
:
while True:
:
random_attack = random.choices(list(attacks.keys()))
:
yield random_attack
:
:

in range(10):
In [14) : for
print(next(lazy_return_random_attacks()))
:
:

Attacking after 1 seconds
['knee_bar']
Attacking after 0 seconds
['arm_triangle']
Attacking after 2 seconds
['knee_bar']

apply в библиотеке Pandas. Последний мой урок
- использование их для обработки объектов DataFrame
библиотеки Pandas. Один из базовых принципов Pandas - применение
операции apply к столбцу вместо организации итераций по всем значениям.
Использование метода
на тему функций

Этот пример демонстрирует округление всех чисел до целых:

In [1]: import pandas as pd
.... iris = pd.read_csv('https://raw.githubusercontent.com/mwasko m/
seaborn-data/master/iris.csv')
43

Часть

1 •

Введение в прагматичный ИИ

iris. head()
Out[l]:
sepal_length
5.1
0
4.9
1
4.7
2
4.6
3
5.0
4

sepal_width
3.5
3.0
3.2
3.1
3.6

petal_length petal_width species
0.2 setosa
1.4
0.2 setosa
1.4
0.2 setosa
1.3
0.2 setosa
1.5
0.2 setosa
1.4

In [2]: iris['rounded_sepal_length'] =\
iris[['sepal_length']].apply(pd.Series.round)
.... iris.head()

....

Out[2]:
sepal_length
5.1
0
4.9
1
4.7
2
4.6
3
5.0
4

sepal_width
3.5
3.0
3.2
3.1
3.6

petal_length petal_width species
0.2 setosa
1.4
0.2 setosa
1.4
0.2 setosa
1.3
1.5
0.2 setosa
0.2 setosa
1.4

\

rounded_sepal_length
5.0
5.0
1
5.0
2
5.0
3
5.0
4

0

Мы воспользовались встроенной функцией, но можно было написать и при­
менить к столбцу и свою, пользовательскую. В приведенном далее примере
числа умножаются на

100. Другой

способ сделать это

-

преобразовать данные, после чего записать их обратно. В

организовать цикл,

Pandas гораздо про­

ще и понятнее будет применить взамен этого пользовательскую функцию.

In [3]: def multiply_by_100(x):
"""Умножает на 100"""
return х*100
....
.... iris['100x_sepal_length'] =\
iris[['sepal_length']].apply(multiply_by_100)
.... iris.head()

0

44

rounded_sepal_length
5.0

100x_sepal_length
510.0

Глава

5.0
5.0
5.0
5.0

1

2
3
4

1.

Что такое ИИ

490.0
470.0
460.0
500.0

Использование управляющих конструкций
В этом разделе описываются основные управляющие конструкции языка

В обычном

Python основным компонентом управляющих кон­
for. Стоит отметить, однако, что циклы for редко
используются с библиотекой Pandas и то, что отлично работает в Python,
плохо вписывается в парадигму Pandas. Некоторые примеры:
Python.

струкций является цикл

о

циклы

for;

о

циклы

while;

о

операторы

о

Try /Except;

о

выражения-генераторы;

о

списковое включение;

о

сопоставление с шаблоном.

if/else;

Всем программам нужно как-то управлять последовательностью выпол­

нения. В этом разделе описаны некоторые из методов такого управления.

Циклы
Цикл

for

for -

одна из важнейших управляющих конструкций языка

Один из часто используемых паттернов

-

применение функции

Python.
range для

генерации диапазона значений с последующим проходом по ним в цикле:

In [4]: res = range(З)
... : print(list(res))
[0, 1, 2]

In [5]: for 1 in range(З):
....
print(i)
0
1

2

45

Часть

Введение в прагматичный ИИ

1 •

Цикл for по ~писку. Еще один распространенный паттерн - проход в цикле
по списку:

In [ б]: martial_arts = ["Sambo", "Muay Thai", "BJJ"]
for martial_art in martial_arts:
print(f"{martial_art} has influenced\
modern mixed martial arts")
Sambo has influenced modern mixed martial arts
Muay Thai has influenced modern mixed martial arts
BJJ has influenced modern mixed martial arts

Циклы
Циклы

while

while

часто используются в качестве способа выполнения цикла

вплоть до момента, когда выполнится некое условие. Их часто применяют

для создания бесконечных циклов. В следующем примере цикл

while

ис­

пользуется, чтобы отфильтровать один из двух типов атакующих приемов,
возвращаемых функцией:

In [7]: def attacks():
list_of_attacks = ["lower_body", "lower_body",
"upper_body"]
print(f"There are а total of {len(list_of_attacks)}\
attacks coming!")
for attack in list_of_attacks:
yield attack
attack = attacks()
count = 0
while next(attack) == "lower_body":
count +=1
print(f"crossing legs to prevent attack #{count}")
else:
count +=1
print(f"This is not а lower body attack, \
I will cross my arms for #{count}")
There are а total of З attacks coming!
crossing legs to prevent attack #1
crossing legs to prevent attack #2
This is not а lower body attack, I will cross my arms for #3

46

Глава

Операторы

1.

Что такое ИИ

if/else

Ипользование операторов

if/else - распространенный способ ветвления

логики программы. В следующем примере для выбора одной из веток
применяется

if/elif. Если
else:

ни одна из веток не подходит, выполняется

последний оператор
Iп

[8]: def

recommeпded_attack(positioп):
"""Рекомендует атакующий прием в зависимости от позы
противника"""

if

positioп

== "full_guard":

priпt(f"Try ап

elif

positioп

kimura attack")

priпt(f"Try а

elif

positioп

armbar attack")

== "half_guard":
==

"full_mouпt":

priпt(f"Try ап

arm

triaпgle")

else:
priпt(f"You're оп

there is
Iп

Try

[9]:
ап

your

оwп,

по suggestioп

for

\
ап

attack")

recommeпded_attack("full_guard")

armbar attack

Iп [10]: recommeпded_attack("z_guard")
You're оп your оwп, there is по suggestioп for

ап

attack

Выражения-генераторы
Выражения-генераторы расширяют идею ключевого слова

yield

за счет

отложенных вычислений последовательностей. Преимущество выраже­
ний-генераторов состоит в том, что ничего не вычисляется и не помещает­

ся в оперативную память до момента фактического вычисления. Именно
поэтому в нижеприведенном примере можно оперировать генерируемой

бесконечной последовательностью случайно выбранных атак.
В этом конвейере генераторов атака в нижнем регистре, например,

triaпgle" преобразуется в
черкивания:
Iп

[11]: def

"ARM_TRIANGLE",
"ARM TRIANGLE ".

"arm_

а затем удаляется символ под­

lazy_returп_raпdom_attacks():
"""Каждый

import

раз возвращает атакующие приемы"""

raпdom

47

Часrь

1 •

Введение в прагматичный ИИ

{"kimura": "upper_body",

attacks

"straight_aпkle_lock":"lower_body",
"arm_triaпgle":"upper_body",

"keylock": "upper_body",
"kпee_bar": "lower_body"}
while True:
raпdom_attack

yield

=

raпdom.choices(list(attacks.keys()))

raпdom_attack

#Переводит все атаки в верхний регистр

upper_case_attacks = \
(attack.pop().upper() for attack

iп

\

lazy_returп_raпdom_attacks())
Iп [12]: пext(upper_case_attacks)
Out[12]: 'ARM_TRIANGLE'

Iп

[13]:

##Конвейер генераторов: одно выражение связывается в цепочку

##

со следующим

#Переводит все атаки в верхний регистр

upper_case_attacks =\
(attack.pop().upper() for attack
lazy_returп_raпdom_attacks())
#Удаляет символ

подчеркивания

remove_uпderscore

=\

(attack.split("_") for attack
upper_case_attacks)

iп\

#Создает новую фразу

пew_attack_phrase

("

=\

".joiп(phrase)

for phrase

remove_uпderscore)

Iп [19]: пext(пew_attack_phrase)
Out[19]: 'STRAIGHT ANKLE LOCK'

Iп

[20]: for
....

KIMURA

48

пumber iп raпge(10):
priпt(пext(пew_attack_phrase))

iп\

iп\

Глава

1.

Что такое ИИ

KEYLOCK
STRAIGHT ANKLE LOCK

Списковое включение
Списковое включение синтаксически напоминает выражения-генераторы,
но, в отличие от них, вычисляется в памяти. Кроме того, оно реализовано
в виде оптимизированного кода на языке С, часто значительно превыша­

ющего по производительности обычный цикл

for:

In [21]: martial_arts = [ "Sambo", "Muay Thai", "BJJ"]
new_phrases = [f"Mixed Martial Arts is influenced Ьу \
{martial_art}" for martial_art in martial_arts]
In [22]: print(new_phrases)
['Mixed Martial Arts is influenced Ьу Sambo', \
'Mixed Martial Arts is influenced Ьу Muay Thai', \
'Mixed Martial Arts is influenced Ьу BJJ']

Промежуточные вопросы
После обсуждения всех этих базовых вещей важно разобраться не про­
сто в том, как написать код, а в том, как написать код, удобный для со­
провождения. Один из способов

-

создать библиотеку; другой

-

ис­

пользовать уже готовый код путем установки сторонней библиотеки.

Вообще говоря, основная идея

-

минимизировать сложность путем

разбиения.

Написание библиотеки на языке

Python

Достаточно скоро после начала создания вашего проекта вам понадобится

писать библиотеки. Основное, что нужно знать: в репозитории есть ката­
лог

funclib,

внутри которого находится файл

_init_.py.

Для создания

библиотеки необходимо поместить в этот каталог модуль с какой-либо
функцией внутри него.
Создаем файл:

touch

funcliЬ/funcmod.py

49

Часть

Введение в прагматичный ИИ

1 •

Помещаем в этот файл функцию:
"""Простой модуль"""

def

list_of_belts_iп_bjj():
"""Возвращает список поясов бразильского джиу-джитсу"""

belts

=

returп

["white",
belts

"Ыuе",

"purple",

"browп",

"Ыасk"]

Импорт библиотеки
В Jupiter, если библиотека находится в каталоге на уровень выше, можно доба­
вить для импорта его в системный путь посредством команды

sys. path. аррепd.

После этого можно импортировать модуль с помощью пространства имен

ранее созданного каталога/файла/функции:

[23): import

Iп

from

sys;sys.path.appeпd("

fuпclib

import

.. ")

fuпcmod

Iп [24): fuпcmod.list_of_belts_iп_bjj()
Out[24): [ 'white', 'Ыuе', 'purple', 'browп',

'Ыасk']

Усrановка других библиотек
с помощью команды

pip install

pip iпstall.
conda (https://coпda.io/docs/
user-guide/tasks/maпage-pkgs.html) может служить альтернативой и заменой pip.
Если вы используете conda, то сможете использовать и pip, поскольку среда
conda является заменой virtualenv, но также может и напрямую устанавли­
У становить другие библиотеки можно с помощью команды

Отмечу, что система управления пакетами

вать пакеты.

Для установки пакета

pip

pandas выполните следующую команду:

iпstall paпdas

В качестве альтернативного варианта пакеты можно установить с помощью
файла requiremeпts. txt:

>

са requiremeпts.txt

pyliпt

pytest
pytest-cov

50

Глава

1.

Что такое ИИ

click
jupyter
пbval

> pip

iпstall

-r

requiremeпts.txt

Вот пример использования небольшой библиотеки в блокноте J upiter. Стоит
отметить важный нюанс: создать в блокноте

Jupiter

гигантскую паутину

процедурного кода очень легко. А проще всего избежать этого, создавая
библиотеки с последующим их тестированием и импортированием.
"""Простой модуль'""'

import
def

paпdas

as pd

list_of_belts_iп_bjj():

"""Возвращает список поясов бразильского джиу-джитсу"""

belts

=

returп

def

["white",
belts

"Ыuе",

"purple",

"browп",

"Ыасk"]

couпt_belts():
"""Использует библиотеку Paпdas для подсчета числа поясов"""

belts = list_of_belts_iп_bjj()
df = pd.DataFrame(belts)
res = df.couпt()
couпt = res.values.tolist(}[0]
returп couпt

Iп

[25]: from

Iп

[26]:

fuпclib.fuпcmod

import

couпt_belts

priпt(couпt_belts(})

5

Классы
В блокнотахJuрitеr можно итеративно использовать Юiассы и взаимодей­

ствовать с ними. Простейший тип

IOiacca представляет собой просто наи­

менование, как показано ниже:

class Competitor: pass

51

Часть

1 •

Введение в прагматичный ИИ

Экземпляры этого класса могут представлять собой различные объекты:

In [27]: class Competitor: pass
In [28]:
conor = Competitor()
conor.name = "Conor McGregor"
conor.age = 29
conor.weight = 155
In [29]: nate = Competitor()
nate.name = "Nate Diaz"
nate.age = 30
nate.weight = 170
In [30]: def print_competitor_age(object):
"""Выводит статистику no возрасту

спортсменов"""

print(f"{object.name} is {object.age} years old")
....
In [31]: print_competitor_age(nate)
Nate Diaz is 30 years old
In [32]:
... : print_competitor_age(conor)
Conor McGregor is 29 years old
Различия классов и функций
Ключевые различия классов и функций:

О функции гораздо легче обсуждать;
О состояние функций (обычно) существует лишь внутри функции, а со­
стояние класса может сохраняться и за ее пределами;

О классы предлагают более высокий уровень абстракции за счет повы­
шения сложности.

Резюме
Эта глава подготавливает почву для всей остальной книги. Она началась

с краткого руководства по

Зарплата
Оплата в соответствии
с игровыми
результатами

I
Посещаемость игр
Локальная вовлеченность
и готовность платить

Рис.

6.1.

Источники данных о социальном авторитете в НБА

Это приводит к интересному соображению по поводу способа сбора данных.
Зачастую проще всего собрать их вручную, то есть скачать с сайта и очистить

в

Excel, блокноте Jupiter или RStudio. Это вполне разумный начальный

подход к задаче исследования данных. Однако если сбор данных из одного
источника и их очистка занимают несколько часов, то лучше написать код

146

Глава

6.

Прогноз популярности в соцсетях в НБА

для решения такой задачи. Жестких правил тут нет, но опытные исследо­
ватели знают, как постепенно продвигаться в решении задачи, не застопо­

риваясь по пути.

Первые исrочники данных
Вместо того чтобы начинать с непростого источника данных вроде офици­

ального веб-сайта НБА, активно мешающего скачивать с него данные, мы
начнем с относительно удобного источника. Наш первый источник данных
по баскетболу вы можете скачать непосредственно из проекта

GitHub
для этой книги (https://github.com/noahgift/pragmaticai) или с сайта Basketball
Reference (https://www.ЬasketЬall-reference.com/leagues/NBA_2017_per_game.html).
Для машинного обучения на практике недостаточно выбора правильной
модели для очищенных данных, нужно еще и знать, как настроить локаль­
ную среду.

Для запуска кода необходимо выполнить несколько шагов.

1. Создать виртуальную среду (на основе Python 3.6).

2. У становить несколько пакетов, которые понадобятся нам в этой главе:
Pandas, Jupiter.
3. Запустить все это с помощью сборочного файла.
В листинге 6.1 приведена команда, создающая виртуальную среду для
Python 3.6 и устанавливающая пакеты, перечисленные в файле requirements. txt в листинге 6.2. Эти действия можно выполнить за один раз с по­
мощью следующей однострочной команды:

make setup
Лисrинг

&& install

6.1.

Содержимое сборочного файла

setup:
pythonЗ

-m venv

~/.pragaiб

install:
pip install -r requirements.txt
Лисrинг

6.2.

Содержимое файла

requirements.txt

pytest
nbval

147

Часть

III • Создание реальных приложений ИИ с нуля

ipython
requests
python-twitter
pandas
pylint
sensiЫe

jupyter
matplotlib
seaborn
statsmodels
sklearn
wikipedia
spacy
ggplot

Удобный прием при работе с виртуальными средами Pythoп

создание псевдонима в файле

.bashrc

или

.zshrc,

-

который за одну

операцию автоматически делает активной нужную среду и переходит
в соответствующий каталог. Обычно я делаю это с помощью
следующего фрагмента кода:

alias

pragaiбtop="cd -/src/pragai/chapterб\

&& source -/.

Pragaiб /Ьin/activate"

Для работы над проектом из данной главы просто наберите в ко­
мандной строке pragaiбtop, и вы попадете в каталог с кодом нужного
проекта и запустите виртуальную среду. Вся мощь псевдонимов

командной оболочки в действии . Есть и другие утилиты для этой
цели, например

pipenv,

имеет смысл взглянуть и на них.

Для просмотра данных запустите блокнот

jupyter notebook.

с помощью команды

Jupiter

При этом запустится браузер, где вы сможете просма­

тривать существующие блокноты или создавать новые. Если вы заглянете
в исходный код проекта

GitHub для этой

главы, то найдете файл

basketball_

reference. ipynb.
Он представляет собой простой, типа

«Hello, world!~. блокнот с загружен­
Jupiter или, в случае

ными в него данными. Загрузка данных в блокнот
языка

R, RStudio -

обычно наиболее удобный способ первоначальной

проверки и просмотра набора данных. Листинг

6.3

демонстрирует также,

как просмотреть данные из обыч11ой командной оболочки
нительно кjupiteг или вместо него.

148

IPython допол­

Глава

Листинг

6.3.

6.

Изучение данных с сайта

Прогноз популярности в соцсетях в НБА

Basketball Reference

из блокнота

Jupiter

import pandas as pd
nba = pd.read_csv("data/nba_2017 _br.csv")
nba.describe()
Еще один способ убедиться в работоспособности блокнотов
использовать плагин

test

nbval для pytest.

Jupiter -

Вы можете добавить команду

сборочного файла для запуска всех блокнотов следующим

образом:

make test
В следующем фрагменте кода показано, как это будет выглядеть
в сборочном файле:

test:
py.test --nbval notebooks/*.ipynb
Загрузка СSV-файла в Pandas не представляет сложности, если в нем при­
сутствуют названия столбцов, а длина строк одинакова. При работе с под­
готовленными наборами данные почти всегда оказываются в подходящей

для загрузки форме. На практике же дела обычно обстоят сложнее и при­
вести данные в подходящую форму

-

непростая задача, как мы увидим

далее в этой главе.
Рисунок

6.2

демонстрирует результаты выполнения команды

в блокнотеjuрitеr. Функция

describe
describe объектов DataFrame библиотеки Pandas

возвращает описательную статистику, включая число столбцов (в нашем
случае

27)

и медиану (50-й процентиль) для каждого столбца. На этой

стадии не помешает поэкспериментировать с созданным блокнотомjuрitеr
и посмотреть, какая еще информация доступна. Однако в данных отсутству­

ет единый показатель для оценки игровых результатов в обороне и атаке .
Для его получения нам нужно будет объединить наш набор данных с дру­
гими источниками из

ESPN

и НБА, в результате чего сложность проекта

возрастет с простого использования данных до их поиска с последующим

преобразованием. Разумным будет воспользоваться утилитой скрапинга,

например

Scrapy, но в данной ситуации можно применить более простой
и узкоспециализированный метод. Например, эайдя на сайты ESPN и НБА,
скопировать данные оттуда и вставить их в Ехсе\ . Затем можно будет вруч­
ную очистить данные и сохранить их в файле CSV. Для небольшого набора

149

Часrь

III •

Создание реальных приложений ИИ с нуля

данных такой способ часто требует меньше времени, чем написание сценария
для выполнения тех же задач .

8

::; Ьosketь.ILrefereno•

8

х

.=:,

е

С ~host:8886/;;-o tebo~ks/no1"'e=boo
==ks=/Ьa=sk=et=ba=-ll_-,-.=,=.,.=n=ce=.i-py=
= n=b::-======~=:;--10--.-~-.. - - j

;::: JUpyter ЬasketЬall_reterence-........
Fie

Edit

View

Се1

lnsert

:rn ( 1 ) :

Шport

In ( 3) :

nьа

In ( 3):

nЬa.clescribe()

Кеmв1

"

logout

j PythonЗ

Help

О

pand4s as pd

• pd.read_csv( " . . /dat a/nba_201 7_br.csv • )

Outl 3 ):
Rlt

Age

о

GS

МР

.,,...,

Ш.000000

486.000000

Ш.000000

488.000000

Ш.000000

243.500000

28.•05350

53.781893

25.308642

19.ЮJ:!О&

Э. 120185

6.913992

•ld

t40.q>toring_team_vaJuation_nьa -

т.....

In 11111

Outt 13 J:

fR8 Uytbon.cor. . d.1•pl~ iaiport. di1play. lmlL
d1spl&JC!"l'КL( ".contaiмr ~ widtЬ.1100' lir.portant;

.i:иaьorn.u:189rid.t&1%Gt'1d

t

at

0 •11 1,З Ь19 8>

...... . •

--··
МoмttQuo1 ..... f'f\IOlw 1

--·

~(-Тlм'41< ·

• ••



11

••


• •





••


• • •


•• •

S.•-6"" ·
S...AМ-S.-S ·

_.,..
w................. .

1~ ! ~
6.6.



11

,._.......7&.1·

Рис.

G U :

Oocl8

ltl[0.025 0.975]

Warnings:
[1] Standard Errors assume that the covariance matrix of the errors
is correctly specified.
TOTAL_MILLIONS (общая посе­
0,05)
посещаемости. Равный 0,282 (то есть 28 %)

Судя по результатам регрессии, переменная

щаемость в миллионах) статистически значима (значение Р меньше
для предсказания изменений

коэффициент детерминации (R-квадрат) демонстрирует, насколько хорошо

произведен подбор параметров, то есть насколько прямая регрессии соот­
ветствует данным.

Чтобы выяснить, в какой степени эта модель может предсказывать зна­
чения, построим дополнительные графики и проведем дополнительную

диагностику. В пакете

Seaborn

есть встроенная и очень удобная функция

residplot, предназначенная для построения графиков остаточных погрешно­
6.7. Идеальный вариант: случайно

стей. Ее использование показано на рис.

157

Часть

Создание реальных приложений ИИ с нуля

III •

распределенные остаточные погрешности; наличие на графике каких-либо

паттернов может свидетельствовать о проблемах с моделью. Данный пример
отнюдь не похож на равномерно случайное распределение:

In [88): sns.residplot(y="VALUE_MILLIONS", x="TOTAL_MILLIONS",
. ... data=attendance_valuation_df)
Out[88]:
I n (20):
Out(20J:

1

ans.reaidplot(y• 'VALUВ_МILLIONS' ,



• •

1500



1000





500

о

x• ''I'OТAL_МILLIONS ' ,








...•........ "1" .. "".~·;" .."..."."""."""""""" ........ "." ..

• •• ••• ••

-500

0.60

0.65

о

10

о

75

••
• ••
0.80

о

85

0.90

lOTAl_МIWONS

Рис.

6.7.

Посещаемость матчей команд НБА и график остаточных погрешностей
стоимости команд

Для оценки точности предсказания с применением машинного обучения

часто используют среднеквадратическую погрешность

error, RMSE) .

Сделать это с помощью пакета

(root шеаn squared
StatsModels можно следу­

ющим образом:

In [92): import statsmodels
rmse = statsmodels . tools.eval_measures.rmse(
attendance_valuation_predictions_df["predicted"),
attendance_valuation_predict
ions_df [ "VALUE_MILLIONS"])
rmse
Out[92): 591.33219017442696
Чем меньше

RMSE,

тем лучше предсказание. Для повышения точности

предсказания необходимо найти способ снизить

158

RMSE.

Кроме того, боль-

Глава

6.

Прогноз популярности в соцсетях в НБА

ший набор данных, такой, чтобы можно было разделить его на обучающую
и контрольную последовательности, позволяет повысить точность и снизить

вероятность переобучения. Следующий этап диагностики

-

построение

графика предсказанных линейной регрессией значений относительно на­

стоящих. На рис.

6.8

показаны результаты выполнения функции

lmplot

для предсказанных и настоящих значений, из которых очевидно, что мо­
дель предсказывает значения не так уж хорошо. Однако для начала и это

неплохо, именно так часто модели машинного обучения и создаются

-

посредством обнаружения корреляций и/или статистически значимых
взаимосвязей, а затем

-

принятия решения о том, что имеет смысл собрать

дополнительные данные.

:: exploring_team_vaJuetion_nЬa х ~'-'~,.,_.,---=се,-.,---__._

8

е

r.. ,;.)

С CD localhost:8888/notebooks/note~oks/exploring_team_valuation_nba.ipynb
1

;::: JUpyter exploring_team_valuation_nba Flle

Edit

View

lnsert

Cell

Кernel

Неlр

In ( 186):

sns .lm.plot(x• н predicted "

OUtt 186 ]:


>

#Меняем легенды

>

р

FALSE)

+

guides(color = guide_legend(title = "Salary Millions")) +
guides(size = guide_legend(
title = "Wikipedia Daily Pageviews" ))+
+
scale_color_gradientn(colours = rainbow(З))
+
geom_text(aes(x = ELO, у = VALUE_MILLIONS, label=ifelse(
>
VALUE_MILLIONS>1200,as.character{TEAM),' ')),hjust= . 35,vjust=l)
+
+

В итоге получаем аккуратный фасетный график (рис.

6.12).

Основные

обнаруженные метки представляют собой разл ичия между известностью,
зарплатой и игровыми результатами. «Лучшие из лучших;,.

-

в кластере

с Леброном Лжеймсом и Расселом Вестбруком, но они различаются также
и самыми высокими зарплатами.

г

-

....

-- _
......

J-,.Нafll!ro

.
.. ....·...-~
•" t ,

.

.,.,,...,. ......

...,.,,...._

;,

.
. : .." . ..
"


Рис.

о

••

; ~· :

'

....,.._.

· · ~Gotlltft

"


1!.

WINS АТТNВIЛАSU: ТО Pl.AY'EA (WINS_ftPМ)

а

6.12. Фасетный график, построенный с помощью библиотеки ggplot, для игроков
2016-2017 гг. на основе кластеризации методом k-ближайших соседей

НБА за

Собираем все воедино: команды, игроков,
социальный авторитет и рекламные отчисления
После сбора всех данных мы може м попробовать несколько новых инте­
ресных графиков. Объеди11ив дан11ые о рекламных отчислениях, командах
и игроках, можно создать несколько потрясающих графиков. Во-нервых,

183

Часть П1



Создание реальных приложений ИИ с нуля

показать данные о рекламных отчислениях на карте интенсивности кор­

реляции (рис.

6.13):

In (150]: nba_players_with_salary_wiki_twitter_df.to_csv(
" .. /data/nba_2017_players_social_with_clusters.csv")
In [151]: endorsements = pd.read_csv(
" .. /data/nba_2017_endorsement_full_stats.csv")
In [152]: plt.subplots(figsize={20,15))
.... ах= plt.axes()
.... ax.set_title{"NBA Player Endorsement, \
Social Power, On-Court Performance, \
Team Valuation Correlation Heatmap: 2016-2017
.... Season")
.... corr = endorsements.corr()
.... sns.heatmap(corr,
xticklabels=corr.columns.values,
yticklabels=corr.columns.values, cmap="copper")
Out[152]:

Далее, на рис.

6.14, в графике особенностей

продемонстрирована вся сово­

купность проделанной работы. Код для построения этого графика имеет
следующий вид:

In (153]: from matplotlib.colors import LogNorm
plt.subplots(figsize={20,15))
pd.set_option('display.float_format', lambda х:
norm = LogNorm()
ах = plt.axes()
grid = endorsements.select_dtypes([np.number])
ax.set_title{"NBA Player Endorsement,\
Social Power, On-Court Performance,\
Team Valuation Heatmap: 2016-2017 Season")
sns.heatmap(grid,annot=True,
yticklabels=endorsements["PLAYER"],fmt='g',
cmap="Accent", cbar=False, norm=norm)
Out[153]:

% х)

Глава

6.

Прогноз популярности в соцсетях в НБА

'

r=· 1
1

1

1

1

1

--- -"

---

1

!i 1

--

185

Часть

186

III •

Создание реальных приложений ИИ с нуля

Глава

6.

Прогноз популярности в соцсетях в НБА

Обратите внимание, что важную роль в обеспечении удобочитаемости графи­
ка особенностей играет преобразование цветов в LogNorm. Благодаря этому
относительные изменения приводят к созданию границ между ячейками.

Дальнейшие прагматичные шаги
и учебные материалы
Одна из основных причин написания этой книги

-

желание продемонстри­

ровать создание завершенных работоспособных решений, пригодных для
развертывания в промышленной эксплуатации. Чтобы сделать из блокнота
подобное решение, нужно изучить некоторые из приведенных в других гла­

вах решений, где обсуждаются методы подготовки проектов для промыш­
ленной эксплуатации, например создания

НБА или

API

API

прогноза стоимости команд

для отображения социального авторитета суперзвезд НБА.

До презентации на получение инвестиций в фонде У

Comblnator (УС)

вас

может отделять всего несколько строк кода.

Кроме того, существует возможность ветвления блокнота

www.kaggle.com/noahgift/social-power-nba)

Kaggle (https://

в качестве исходной точки для дальней­

ших исследований. Наконец, вы можете найти видео и слайды по данному
вопросу на сайте конференции по данным

Strata-2018

в Сан-Хосе: https://

conferences.oreilly.com/strata/strata-ca/public/schedule/detail/63606.

Резюме
В этой главе мы рассмотрели реальную практическую задачу машинного

обучения, начав с постановки вопросов и перейдя затем к методикам сбора
данных из всего Интернета. Многие из меньших наборов данных были
скопированы с сайтов, не препятствующих сбору данных. Для больших ис­
точников данных - «Википедии» и Twitter - потребовался иной подход,
скорее программный.

Далее мы изучили данные методами как статистики, так и машинного

обучения без учителя и визуализации данных.

7

Создание
интеллектуального

бота

Slack в AWS

Победителем становится тот, кто способен
двигаться вперед, несмотря на боль.

Роджер Баннистер

( Roger Banister)
Люди давно мечтают создать «искусственную жизнь» . Чаще всего пока

это возможно путем создания ботов. Боты становятся все более неотъем­
лемой частью нашей повседневной жизни, особенно после появления Siгi
от компании

Apple

и

Alexa от Amazon.

В этой главе мы раскроем все тайны

создания ботов.

Создание бота
Для создания бота мы воспользуемся библиотекой

Slack для

языка

Python

(https://github.com/slackapi/python-slackclient). Для начала работы со Slack необ­
ходимо сгенерировать идентификационный маркер. В целом имеет смысл

при работе с подобными маркерами экспортировать переменную среды .
Я часто делаю это в viгtualenv, получая, таким образом, автоматически до­
ступ к ней при выполнении в текущей среде. Для этого необходимо немного
«взломать» утилиту viгtualenv, отредактировав сценарий
При экспорте переменной

Slack

activate.

в сценарии-/ .env/bin/activate он будет

иметь нижеприведенный вид.
И просто для информации, если вы хотите идти в ногу с последними новин­
ками, рекомендуется использовать появившуюся на рынке новую, офици-

188

Глава

7.

Создание интеллектуального бота

Python для управления

альную утилиту

средой

Slack

в

AWS

- pipenv (https://github.com/

pypa/pipenv):
OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/Ьin:$PATH"

export РАТН
SLACK_API_TOKEN=
export SLACK_API_TOKEN
Для проверки того, задано ли значение переменной среды, удобно исполь­
зовать команду

printenv

операционных систем

OS

Х и

Linux.

После этого

для проверки отправки сообщения можно воспользоваться следующим
коротким сценарием:

import os
from slackclient import SlackClient
slack_token = os.environ["SLACK_API_TOKEN"]
sc = SlackClient(slack_token)
sc.api_call(
"chat.postMessage",
channel="#general",
text="Hello from my bot! :tada:"
Стоит также отметить, что утилита

pipenv -

рекомендуемое решение,

объединяющее в одном компоненте возможности утилит

pip и virtualenv.

Она стала новым стандартом, так что имеет смысл взглянуть на нее с точки
зрения управления пакетами.

Преобразование библиотеки в утилиту
v

команднои строки
Как и в других примерах из этой книги, удачной идеей будет преобразовать
наш код в утилиту командной строки, чтобы облегчить проверку новых
идей. Стоит отметить, что многие разработчики-новички часто отдают
предпочтение не утилитам командной строки, а другим решениям, на­

пример, просто работают в блокнотах

Jupiter.

Сыграю ненадолго роль

адвоката дьявола и задам вопрос, который вполне может возникнуть учи­
тателей: «А зачем нам утилиты командной строки в проекте, основанном на

189

Часть

III •

Создание реальных приложений ИИ с нуля

блокнотахJuрitеr? Разве смысл блокнотовjuрitеr состоит не в том, чтобы
сделать ненужными командную оболочку и командную строку?» Добавле­
ние утилиты командной строки в проект хорошо тем, что позволяет быстро
пробовать различные варианты входных данных. Блоки кода блокнотов

Jupiter

не принимают входные данные, в некотором смысле это сценарии

с жестко «зашитыми» данными.

Множество утилит командной строки на платформах как

GCP,

так и А WS

существует не случайно: они обеспечивают гибкость и возможности, недоступ­
ные для графических интерфейсов. Замечательный сборник эссе на эту тему

фантаста Нила Стивенсона

(Neal Stephenson) называется «В начале ... была
«GUI приводят к значительным

командная строка». В нем Стивенсон говорит:

дополнительным накладным расходам на каждый, даже самый маленький

компонент программного обеспечения, которые полностью меняют среду
программирования». Он заканчивает сборник словами:

«... жизнь -

штука

очень тяжелая и сложная; никакой интерфейс это не изменит; и всякий, кто
считает иначе,

-

простофиля ... » Достаточно жестко, но мой опыт подсказыва­

ет, что и достаточно правдиво. Жизнь с командной строкой становится лучше.

Попробуйте ее

- и вы не захотите возвращаться обратно к GUI.

Для этого мы воспользуемся пакетом click, как показано ниже. Отправка со­
общений с помощью нового интерфейса оказывается очень простым делом .

. /clibot.py send --message "from cli"
sending message from cli to #general
Рисунок

7.1

демонстрирует значения по умолчанию, а также настраиваемое

сообщение от утилиты

cli.

#!/usr/bin/env python
import os
import click
from slackclient import SlackClient
SLACK_TOKEN = os.environ["SLACK_API_TOKEN"]
def send_message(channel="#general",
message="Hello from my bot!"):
"""Отnравить сообщение на

канал"""

slack_client = SlackClient(SLACK_TOKEN)
res = slack_client.api_call(

190

Глава

7.

Создание интеллектуального бота

Slack

в

AWS

"chat.postMessage",
channel=channel,
text=message
return res
@click.group()
@click.version_option("0.1")
def cli():
Утилита командной строки для слабаков

@cli.command("send")
@click.option("--message", default="Hello from my bot!",
help="text of message")
@click.option("--channel", default="#general",
help="general channel")
def send(channel, message):
click . echo(f"sending message {message} to {channel}")
send_message(channel, message=message)
if

name_
cli()

_main_' ·

Today
Slack API Tester АРР 2'29 РМ
Hello from my Ьо~
from cll

@@I

1 + 1 Message #general

Рис.

7.1. Утилита

командной строки бота

Slack

Выводим бот на новый уровень с помощью
сервиса

AWS Step Functions

Посл е создан ия канало в свя з и для отп равки сообщени й в

Slack

мож­

но у с ове рш енств ова ть н а ш код, а и ме нн о: за пус кать е го по р ас пи с анию

и и спол ьзовать дл я каких -л ибо пол ез ных действ ий . Серви с пошаговых
функций

AWS (AWS Step Functions) замечательно подходит для этой
Slack научится производить скрапинr

цели. В следующем раздел е наш бот

191

Часть

Создание реальных приложений ИИ с нуля

III •

спортивных страниц

игроков НБА, извлекать их места рождения,

Yahoo!

а затем отправлять эти данные в
Рисунок

7.2 демонстрирует

Slack.

готовую пошаговую функцию в действии. Пер­

вый шаг состоит в извлечении

пользовании библиотеки

URL профилей игроков НБА, а второй- вис­
Beautiful Soup для поиска места рождения каждого

из игроков. По завершении выполнения пошаговой функции результаты

будут отправлены обратно в

--

Slack.

start20
DSucceм

.._

~~~~~~~~~~~~~~

8F818d

D~

Dtnp,._.

• Exeoullon Detaila

" Step Detall•

...
(

,,..JJtpcwts.'f8/'IOO.conVn~5$Y: "8etl ---·
°httpl:/Щlorta.yahoo.~18&1": "AIМnl",

___
___
____
_
___

"httpl;:Нlporta.yWI00.~70....-: "ANon",

"tlape://890tta.yehoo.o:w№~12/":"08kl8nd",

~J/tport8.yehoo.comh1~12/": "AЬ'on",

~/l90ttl.)'8hoo.~15/":"Uol.8'tv.non",
~llpotta.)'81hoo.~17r:"'Нoulton",

_,
.,.,..}

_.,,.,...,_,.,

"httpa:/lsportl.yahoo~o47~"'МoЬh·,

8httpt1/'lportl.)'81hoo.~11r: "м.nt.1",

...,.,_
,.._.. ..

"htlpL//8portl.yehoo.~71f: "Вedfotcr",

"httpa:/llporta.)'81'1oo.comln~: -Vaounde",
"https:/fspOOl.yehoo oomh'IЬWpllly8tll'5007r: -chlc8go",
'"long ~· •

.,.,..

,.........,,."

"hCtpt1'8pofta.)'llhoo.corМ\~439W":

°t'lttpl.://aportl.)'8hoo.corrV'l'IЬ8/plly8tl/462.V: ~181'18PQll'

)

Рис.

7.2.

Начальный конвейер утилиты командной строки бота

Slack

Для координации отдельных частей работы внутри пошаговой функции
можно применить А WS
lamЬda/)

Lambda

и

Chalice. Lambda (https://aws.amazon.com/
позволяет пользователю выполнять функции в А WS, а фреймворк

Chalice (http://chalice.readthedocs.io/en/latest/) дает возможность создания бес­
Python. Вот некоторые предварительные

серверных приложений на языке
требования:

О у пользователя должна быть учетная запись А WS;
О пользователю необходимы учетные данные для использования

О у роли

API;

Lambda (создаваемой Chalice) должна быть политика с приви­
легиями, необходимыми для вызова соответствующих сервисов А WS,
например SЗ.

192

Глава

7.

Создание интеллектуального бота

Настройка учетных данных

Slack

в

AWS

IAM

Подробные инструкции по настройке учетных данных А WS можно найти
по адресу http://ЬotoЗ.readthedocs.io/en/latest/guide/configuration.html. Информацию

об экспорте переменных А WS в операционных системах
можно найти здесь:

set-up-creds.html.

Windows и Linux
https://docs.aws.amazon.com/amazonswf/latest/awsrbflowguide/

Существует множество способов настройки учетных дан­

ных, но пользователи

virtualenv

могут поместить учетные данные А WS

в локальную виртуальную среду, в сценарий

/bin/activate:

#Добавляем ключи AWS
AWS_DEFAULT_REGION=us-east-1
AWS_ACCESS_KEY_ID=XXXXXXXX
AWS_SESSION_TOKEN=xxxxxxxx
#Экспортируем ключи

export AWS_DEFAULT_REGION
export AWS_ACCESS_KEY_ID
export AWS_DEFAULT_REGION
Работа с

Chalice.

У

Chalice есть утилита командной строки с множеством

доступных команд:

Usage: chalice [OPTIONS]

СОММАND

[ARGS] ...

Options:
Show the version and exit.
--version
The project directory. Defaults to CWD
--project-dir ТЕХТ
--debug / --no-debug Print debug logs to stderr.
Show this message and exit.
--help
Commands:
delete
deploy
gen-policy
generate-pipeline Generate
generate-sdk
local
logs
new-project
package
url

а

cloudformation template for

а

...

193

Часrь

III •

Создание реальных приложений ИИ с нуля

Код внутри шаблона арр.ру можно заменить на функции сервиса

Lambda.
Chalice удобно то, что он дает возможность создавать, помимо веб­
сервисов, «автономные» функции Lambda. Благодаря этой функциональ­
ности можно создать несколько функций Lambda, связать их с пошаговой
В А WS

функцией и свести воедино, как кубики «Лего».
Например, можно легко создать запускаемую по расписанию функцию

Lambda,

которая будет выполнять какие-либо действия:

@app.schedule(Rate(l, uпit=Rate.MINUTES))
def every_miпute(eveпt):
'"'"Событие,

запланированное для ежеминутного выполнения"""

#Отправка сообщения боту

Slack

Для налаживания взаимодействия с ботом для веб-скрапинга необходимо

создать несколько функций. В начале файла находятся импорты и объявлено
некоторое количество переменных:

import loggiпg
import csv
from io import

StriпgIO

import ЬоtоЗ
from bs4 import BeautifulSoup
import requests
from chalice import (Chalice, Rate)
APP_NAME = 'scrape-yahoo'
арр = Chalice(app_пame=APP_NAME)
app.log.setlevel(loggiпg.DEBUG)

Боту может понадобиться хранить часть данных в SЗ. Следующая функция
использует

def

Boto для сохранения результатов

create_sЗ_file(data,

csv_buffer =

в СSV-файле:

пame="birthplaces.csv"):

StriпgIO()

file with {data} for
writer = csv.writer(csv_buffer)
for key, value iп data.items():
writer.writerow([key,value])
sЗ = botoЗ.resource('sЗ')
app.log.iпfo(f"Creatiпg

194

паmе")

Глава

res =

7.

Создание интеллектуального бота

Slack

в

AWS

sЗ.Bucket('aiwebscrapiпg').\

Body=csv_buffer.getvalue())

put_object(Key=пame,

res

returп

Функция fetch_page использует библиотеку

Beautiful Soup (https://www.crum-

my.com/software/ВeautifulSoup) для синтаксического разбора НТМL-страницы,

расположенной в соответствии с
ект

def

URL статистики

НБА, и возвращает объ­

soup:
fetch_page(url="https://sports.yahoo.com/пba/stats/"):
"""Извлекает

URL Yahoo"""

#Скачивает страницу и преобразует ее в объект

Beautiful Soup
urls from {url}")
res = requests.get(url)
soup = BeautifulSoup(res.coпteпt, 'html.parser')
returп soup

#

библиотеки

app.log.iпfo(f"Fetchiпg

Функции

get_player _liпks

и

fetch_player _urls

получают ссылки на

URL

профилей игроков:

def

get_player_liпks(soup):
"""Получает ссылки из

URL

Находит все
строки

игроков

на странице в тегах

'а'

и фильтрует их в поисках

'пba/players'

= []

пba_player_urls

for

URL

liпk iп soup.fiпd_all('a'):
liпk_url

=

liпk.get('href')

#Отбрасываем неподходящие

if

liпk_url:

if

"пba/players"

iп liпk_url:

priпt(liпk_url)
пba_player_urls.appeпd(liпk_url)
returп пba_player_urls

def fetch_player_urls():
"""Возвращает URL игроков"""
soup = fetch_page()

195

Часть

III •

Создание реальных приложений ИИ с нуля

urls = get_player_links(soup)
return urls
Далее в функции

find_birthplaces мы извлекаем с расположенных по этим
URL страниц места рождения игроков:

def find_birthplaces(urls):
"""Получаем места рождения со страниц профилей игроков
на

NBA

Yahoo"""

birthplaces = {}
for url in urls:
profile = requests.get(url)
profile_url = BeautifulSoup(profile.content, 'html.parser')
lines = profile_url.text
res2 = lines.split(",")
key _line = []
for line in res2:
if "Birth" in line:
#print(line)
key_line.append(line)
try:
Ыrth_place = key_line[0].split(":")[-1].strip()
app.log.info(f"Ыrth_place:

{Ыrth_place}")

except IndexError:
app.log.info(f"skipping {url}")
continue
Ыrthplaces[url]

= Ыrth_place

app.log.info(Ыrth_place)

return

Ыrthplaces

Теперь мы перейдем к функциям
ворка

Chalice

Chalice.

Обратите внимание: для фрейм­

необходимо, чтобы был создан путь по умолчанию:

#Их можно вызвать с

помощью НТТР-запросов

@app.route('/'}
def index():
"""Корневой

URL"""

app.log.info(f"/ Route: for {APP_NAME}")
return {'app_name': APP_NAME}
Следующая функция
НТТР

196

Lamoda представляет собой

URL с написанной

ранее функцией:

маршрут, связывающий

Глава

7.

Создание интеллектуального бота

Slack

в

AWS

@app.route('/player_urls')
def player_urls():
"""Извлекает URL игроков"""
app.log.info(f"/player_urls Route: for {APP_NAME}")
urls = fetch_player_urls()
return {"nba_player_urls": urls}
Следующие функции

Lambda -

автономные, их можно вызвать внутри

пошаговой функции:
#Это автономная функция Lambda
@app.lambda_function()
def return_player_urls(event, context):
"""Автономная функция Lambda, возвращающая URL

игроков'""'

app.log.info(f"standalone lambda 'return_players_urls'\
{АРР_NАМЕ} with {event} and {context}")
urls = fetch_player_urls()
return {"urls": urls}
#Это автономная функция Lambda
@app.lambda_function()
def birthplace_from_urls(event, context):
"""Находит места

рождения игроков"""

app.log.info(f"standalone lambda 'birthplace_from_urls'\
{АРР_NАМЕ} with {event} and {context}")
payload = event["urls"]
birthplaces = find_birthplaces(payload)
return birthplaces
#Это автономная функция

Lambda

@app.lambda_function()
def create_sз_file_from_json(event, context):
"""Создает файл SЗ на основе данных в формате

JSON"""

app.log.info(f"Creating sЗ file with event data {event}\
and context {context}")
print(type(event))
res = create_sЗ_file(data=event)
app.log.info(f"response of putting file: {res}")
return True

197

Часть Ш



Создание реальных приложений ИИ с нуля

Если запустить получившееся приложение

Chalice локально,

будут выве­

дены следующие результаты:

-+

scrape-yahoo git:(master) 1 chalice local
Serving on 127.0.0.1:8000
scrape-yahoo - INFO - / Route: for scrape-yahoo
127.0.0.1 - - [12/Dec/2017 03:25:42] "GЕТ / НТТР/1.1" 200 127.0.0.1 - - [12/Dec/2017 03:25:42] "GЕТ /favicon.ico"
scrape-yahoo - INFO - / Route: for scrape-yahoo
127.0.0.1 - - [12/Dec/2017 03:25:45] "GET / НТТР/1.1" 200 127.0.0.1 - - [12/Dec/2017 03:25:45] "GET /favicon.ico"
scrape-yahoo - INFO - /player_urls Route: for scrape-yahoo
scrape-yahoo - INFO - https://sports.yahoo.com/nba/stats/
https://sports.yahoo.com/nba/players/4563/
https://sports.yahoo.com/nba/players/5185/
https://sports.yahoo.com/nba/players/3704/
https://sports.yahoo.com/nba/players/5012/
https://sports.yahoo.com/nba/players/4612/
https://sports.yahoo.com/nba/players/5015/
https://sports.yahoo.com/nba/players/4497/
https://sports.yahoo.com/nba/players/4720/
https://sports.yahoo.com/nba/players/3818/
https://sports.yahoo.com/nba/players/5432/
https://sports.yahoo.com/nba/players/5471/
https://sports.yahoo.com/nba/players/4244/
https://sports.yahoo.com/nba/players/5464/
https://sports.yahoo.com/nba/players/5294/
https://sports.yahoo.com/nba/players/5336/
https://sports.yahoo.com/nba/players/4390/
https://sports.yahoo.com/nba/players/4563/
https://sports.yahoo.com/nba/players/3704/
https://sports.yahoo.com/nba/players/5600/
https://sports.yahoo.com/nba/players/4624/
127.0.0.1
[12/Dec/2017 03:25:53] "GET /player_urls"
127.0.0.1 - - [12/Dec/2017 03:25:53] "GET /favicon.ico"
Для развертывания приложения выполните команду

-+

chalice deploy:

scrape-yahoo git:(master) 1 chalice deploy
Creating role: scrape-yahoo-dev
Creating deployment package.
Creating lambda function: scrape-yahoo-dev
Initiating first time deployment.
Deploying to API Gateway stage: api
https://bt98uzslcc.execute-api.us-east-1.amazonaws.co m/api/
198

Глава

7.

Создание интеллектуального бота

Slack

в

AWS

Благодаря интерфейсу командной строки для НТТР

jakubroztocil/httpie) мы вызываем маршрут
ступные в /api/player _urls ссылки:

НТТР из

(https://github.com/
AWS и извлекаем до­

-+ scrape-yahoo git:(master)

~ http \
https://.amazonaws.com/api/player_urls
НТТР/1.1 200 ОК
Connection: keep-alive
Content-Length: 941
Content-Type: application/json
Date: Tue, 12 Dec 2017 11:48:41 GMT
Via: 1.1 ba90f9bd20de9ac04075a8309c165aЫ.cloudfront.net (CloudFront)
X-Amz-Cf-Id: ViZswjo4UeHYwrc9e-5vМVTDhV_Ic0dhVIG0BrDdtYqd5KWcAuZKKQ==
X-Amzn-Trace-Id: sampled=0;root=l-5a2fc217-07cc12d50a4d38a59a688f5c
X-Cache: Miss from cloudfront
x-amzn-Requestid: 64f24fcd-df32-lle7-a81a-2b511652b4f6

{

"nba_player_urls": [
"https://sports.yahoo.com/nba/players/4563/",
"https://sports.yahoo.com/nba/players/5185/",
"https://sports.yahoo.com/nba/players/3704/",
"https://sports.yahoo.com/nba/players/5012/",
"https://sports.yahoo.com/nba/players/4612/",
"https://sports.yahoo.com/nba/players/5015/",
"https://sports.yahoo.com/nba/players/4497/",
"https://sports.yahoo.com/nba/players/4720/",
"https://sports.yahoo.com/nba/players/3818/",
"https://sports.yahoo.com/nba/players/5432/",
"https://sports.yahoo.com/nba/players/5471/",
"https://sports.yahoo.com/nba/players/4244/",
"https://sports.yahoo.com/nba/players/5464/",
"https://sports.yahoo.com/nba/players/5294/",
"https://sports.yahoo.com/nba/players/5336/",
"https://sports.yahoo.com/nba/players/4390/",
"https://sports.yahoo.com/nba/players/4563/",
"https://sports.yahoo.com/nba/players/3704/",
"https://sports.yahoo.com/nba/players/5600/",
"https://sports.yahoo.com/nba/players/4624/"
}
Еще один удобный способ работы с функциями
ный их вызов с помощью пакета

click

Lambda - непосредствен­
Boto языка Python.

и библиотеки

199

Часть П1



Создание реальных приложений ИИ с нуля

Мы можем создать новую утилиту командной строки с названием

wscli.py

(сокращение от 'le 1eb-scraping command-line interface - «интерфейс командной
строки для веб-скрапинга» ). В первой части кода мы настраиваем журна­
лирование и импортируем библиотеки:

#!/usr/bin/env python
import logging
import json
import ЬоtоЗ
import click
from pythonjsonlogger import jsonlogger
#Инициализация журналирования

log = logging.getLogger(~name~)
log.setLevel(logging.INFO)
LOGHANDLER = logging.StreamHandler()
FORMМATTER = jsonlogger.JsonFormatter()
LOGHANDLER.setFormatter(FORММATTER)

log.addHandler(LOGHANDLER)
Следующие три функции предназначены для подключения к функции

Lambda через invoke_lambda:
###Вызовы API Boto Lambda
def lambda_connection(region_name="us-east-1"):
"""Создаем подключение к Lambda"""

lambda_conn = botoЗ.client("lambda", region_name=region_name)
extra_msg = {"region_name": region_name, "aws_service": "lambda"}
log.info("instantiate lambda client", extra=extra_msg)
return lambda_conn
def parse_lambda_result(response):
"""Получаем результаты из ответа библиотеки

Boto

в формате

body = response['Payload']
json_result = body.read()
lambda_return_value = json.loads(json_result)
return lambda_return_value
def invoke_lambda(func_name, lambda_conn, payload=None,
invocation_type="RequestResponse"):
200

JSON"""

Глава

"""Вызываем функцию

7.

Создание интеллектуального бота

Slack в AWS

Lambda"""

extra_msg = {"function_name": func_name, "aws_service": "lambda",
"payload":payload}
log.info("Calling lambda function", extra=extra_msg)
i f not payload:
payload = json.dumps({"payload":"None"})
response = lambda_conn.invoke(FunctionName=func_name,
InvocationType=invocation_type,
Payload=payload
log.info(response, extra=extra_msg)
lambda_return_value = parse_lambda_result(response)
return lambda_return_value
invoke_lambda с помощью пакета Python для создания
Click. Обратите внимание, что мы задали значение
по умолчанию для опции - -func, при котором используется развернутая
нами ранее функция Lambda:
Обертываем функцию

утилит командной строки

@click.group()
@click.version_option("l.0")
def cli():
"""Вспомогательная утилита командной строки для веб-скраnинга'"'"

@cli.command("lambda")
@click. option (" - -func",
default="scrape-yahoo-dev-return_player_urls",
help="name of execution")
@click.option("--payload", default='{"cli":"invoke"}',
help="name of payload")
def call_lambda(func, payload):
"""Вызывает функцию Lambda
./wscli.py lambda
click.echo(click.style("Lambda Function invoked from cli:",
bg='Ьlue', fg='white'))
conn = lambda_connection()
lambda_return_value = invoke_lambda(func_name=func,
lambda_conn=conn,
payload=payload)
201

Часть

III •

Создание реальных приложений ИИ с нуля

formatted_json = json.dumps(lambda_return_value,
sort_keys=True, indent=4)
click.echo(click.style(
"Lambda Return Value Below:", bg='Ьlue', fg='white'))
click.echo(click.style(formatted_json,fg="red"))
if _name_
cli()

"_main_

11

:

Выводимые этой утилитой результаты аналогичны вызову НТГР-интерфейса:

1 ./wscli.py lambda \
--func=scrape-yahoo-dev-birthplace_from_urls\
--payload '{"url":["https://sports.yahoo.com/nba/players/4624/" ,\
"https://sports.yahoo.com/nba/players/5185/"]}'
Lambda Function invoked from cli:
{"message": "instantiate lambda client",
"region_name": "us-east-1", "aws_service": "lambda"}
{"message": "Calling lambda function",
"function_name": "scrape-yahoo-dev-Ыrthplace_from_urls",
"aws_service": "lambda", "payload":
"{\"url\":[\"https://sports.yahoo.com/nba/players/462 4/\",
\"https://sports.yahoo.com/nba/players/5185/\"]}"}
{"message": null, "ResponseMetadata":
{"Requestid": "a6049115-df59-lle7-935d-bЫde9c0649d",
"HTTPStatusCode": 200, "HTTPHeaders":
{"date": "Tue, 12 Dec 2017 16:29:43 GMT", "content-type":
"application/json", "content-length": "118", "connection":
"keep-alive", "x-amzn-requestid":
~

"a6049115-df59-lle7-935d-bЫde9c0649d",

"x-amzn-remapped-content-length": "0", "x-amz-executed-version":
"$LATEST", "x-amzn-trace-id":
"root=l-5a3003f2-2583679b2456022568ed0682;sampled=0"},
"RetryAttempts": 0}, "StatusCode": 200,
"ExecutedVersion": "$LATEST", "Payload":
"",
"function_name": "scrape-yahoo-dev-Ыrthplace_from_urls",
"aws_service": "lambda", "payload":
"{\"url\":[\"https://sports.yahoo.com/nba/players/462 4/\",
\"https://sports.yahoo.com/nba/players/5185/\"]}"}
Lambda Return Value Below:
{

"https://sports.yahoo.com/nba/players/4624/": "Indianapolis",
"https://sports.yahoo.com/nba/players/5185/": "Athens"
}

202

Глава

7.

Создание интеллектуального бота

Slack

в

AWS

Завершение создания пошаговой функции
Последний этап создания пошаговой функции, как описывается в докумен­
тации от А WS (https://docs.aws.amazon.com/step-functions/latest/dg/tutorial-creatingactivity-state-machine.html), - создание с помощью веб-интерфейса структуры
конечного автомата в формате нотации объектов JavaScript QavaScript
Object Notation, JSON). Следующий код демонстрирует этот конвейер,
начиная от исходных функций Lambda для скрапинга Yahoo!, сохранения
данных в файле SЗ и, наконец, отправки содержимого в Slack:

{

"Comment": "Fetch Player Urls",
"StartAt": "FetchUrls",
"States": {
"FetchUrls": {
"Туре": "Task",
"Resource": \
"arn:aws:lambda:us-east-1:561744971673:\
function:scrape-yahoo-dev-return_player_urls",
"Next": "FetchBirthplaces"
},
"FetchBirthplaces": {
"Туре": "Task",
"Resource": \
"arn:aws:lambda:us-east-1:561744971673:\
function:scrape-yahoo-dev-Ыrthplace_from_urls",

"Next": "WriteToS3"
},
"WriteToS3": {
"Туре": "Task",
"Resource": "arn:aws:lambda:us-east-1:\
561744971673:function:scrape-yahoo-dev-create_s3_file_from_json",
"Next": "SendToSlack"
},
"SendToSlack": {
"Туре": "Task",
"Resource": "arn:aws:lambda:us-east-1:561744971673:\
function:send_message",
"Next": "Finish"
},
"Finish": {
"Туре": "Pass",

203

Часть

III • Создание реальных приложений ИИ с нуля

"Result": "Finished",
"End": true
}
}
}
На рис .

7.2 было

показано выполнение первой части этого конвейера. Чрез­

вычайно полезна возможность видеть промежуточные результаты работы
конечного автомата. Кроме того, возможность мониторинга в режиме реаль­

ного времени каждой части конечного автомата очень удобна для отладки.

Рисунок

7.3 демонстрирует

полный конвейер с добавлением шагов записи

в SЗ-файл и отправки содержимого в
запускать эту утилиту скрапинга

-

Slack.

Осталось только решить, как

через определенный интервал времени

или в ответ на какое-либо событие.

Visual Workflow

FetchBirthplaces

SendToStack

Рис.

204

7.3.

Окончательный конвейер утилиты командной строки бота

Slack

Глава

7.

Создание интеллектуального бота

Slack

в

AWS

Резюме
В этой главе вы познакомились с множеством потрясающих концепций

построения приложений ИИ. В ней были созданы бот

Slack и утилита веб­
скрапинга, соединенные затем с помощью бессерверных сервисов от А WS.
В такой начальный каркас можно добавить еще много всего - например,
LаmЬdа-функцию обработки написанных на естественных языках текстов
для чтения веб-страниц и получения их краткого содержимого или алго­
ритм кластеризации без учителя, который бы кластеризовал новых игроков
НБА по произвольным атрибутам.

Извлечение полезной
информации об управлении
"'
проектами из учетнои

записи GitНuЬ-организации

Искусство джиу-джитсу совершенно.

Ответственность за ошибки лежит
на людях.

Рuксон Грейсu

( Rickson Gracie)
Эта глава посвящена двум интереснейшим задачам: использованию науки

о данных для изучения вопросов управления проектами по разработке про­

граммного обеспечения и публикации утилит для исследования данных
в каталоге пакетов

Python (Python Package Index).

Наука о данных как науч­

ная дисциплина стремительно развивается, множество статей посвящается
тонкостям использования того или иного алгоритма, но лишь немногие по­

священы вопросам сбора данных, создания структуры проекта и в конечном

счете публикации программного обеспечения в каталоге пакетов Python.
В этой главе вы найдете четкое практическое руководство по решению обеих
задач . Исходный код можно найти на

GitHub: https://github.com/noahgift/devml.

Обзор проблем, возникающих при управлении
программными проектами
Несмотря на то что индустрия программного обеспечения существует уже
несколько десятилетий, ее до сих пор беспокоят проблемы задержки по­
ставки и низкого качества. Есть и другие проблемы, связанные с оценкой
производительности команд и отдельных разработчиков. Зачастую пред­
приятия

206

-

разработчики ПО находятся на переднем крае прогресса в сфере

Глава

8.

Извлечение полезной информации об управлении проектами

трудовых отношений. В настоящее время в этой отрасли промышленности

наблюдается тенденция к использованию фрилансеров или работающих по
договору команд сотрудников в качестве вспомогательной или замещающей

рабочей силы на некоторых этапах разработки программного обеспечения.
В результате этого возникает очевидная задача оценки компанией способ­
ностей этих сотрудников.

Далее, достаточно мотивированных разработчиков-профессионалов инте­
ресуют пути совершенствования своих навыков. Что могут перенять они

у лучших разработчиков мира? К счастью, последние генерируют свое­
образные ~журналы поведения>.>, благодаря которым можно попытаться
ответить на эти вопросы. Каждая фиксация изменений кода в репозитории

разработчиком подает определенный сигнал.
Хорошему разработчику достаточно лишь нескольких минут обсуждения
метаданных исходного кода, чтобы сказать: ~л, сущая бессмыслица, я могу

обойти эту систему». Можно взглянуть на профиль разработчика на GitHub
и увидеть нечто поистине впечатляющее, например 3000 фиксаций изменений
в год, то есть примерно десять в день ежедневно. Но если посмотреть внима­

тельнее, может оказаться, что это всего лишь результаты работы автоматизи­

рованного сценария. Последний был создан разработчиком для обеспечения
видимости активной работы в профиле или же просто ~Фиктивных» фиксаций
изменений, добавляющих на самом деле всего лишь строку в файл README.
Контраргументом к вышеприведенному могла бы быть фраза, которую
можно услышать по поводу экзаменов по математике: ~да тут можно

просто сжульничать, ничего сложного». При оценке работы студента или
сотрудника всегда можно сжульничать, но это не значит, что всем нужно

автоматически ставить пять по алгебре или что стоит отказаться от экза­

менов и тестов вообще. С точки зрения настоящего исследователя данных,

подобное только делает задачу более интересной. Необходимо учитывать
способы исключения фиктивных данных и шума, чтобы точно оценить
производительность команд и отдельных разработчиков.
Исследовательские вопросы. Вот неполный список вопросов, который

имеет смысл обдумать.
О Каковы отличительные признаки хорошего разработчика программного
обеспечения?
О Каковы отличительные признаки неопытного или плохого разработчика
программного обеспечения?

207

Часть 1П

• Создание реальных приложений ИИ с нуля

1:1 Каковы отличительные признаки хорошей команды разработчиков про­
граммного обеспечения?

1:1 Существуют ли признаки, сигнализирующие о сбойном программном
обеспечении?

1:1 Может ли управляющий программным проектом на основе какого-либо
поступившего сигнала немедленно «развернуть проблемный проект на

180 градусов»?
1:1

Существует ли наглядная разница между проектами с открытым и за­

крытым исходным кодом?

1:1 Существуют ли признаки, сигнализирующие о том, что разработчик
жульничает?

1:1

Какие признаки, независимо от языка программирования, указывают на

хорошего разработчика?

1:1

Какие признаки сигнализируют о состоянии проекта на конкретном

языке программирования?

1:1 Как можно сравнить проделываемую лучшими разработчиками работу,
если все репозитории находятся в полном беспорядке? Ведь при этом
так легко все «скрыть».

1:1 Как найти разработчиков в своей компании и на GitHub, похожих на
ваших лучших разработчиков?

1:1

Есть ли в вашей компании «шелуха», то есть люди, на которых не стоит

полагаться? Один из способов выяснить это

-

узнать, фиксирует ли кон­

кретный разработчик изменения регулярно с понедельника по пятницу?
Найденные мной в последние несколько лет исследования утверждают,

что плохие разработчики часто фиксируют изменения с большими и/или
частыми перерывами. Лучшие разработчики
с 10-20-летним опытом

80-90 % времени

-

-

скажем, разработчики

часто фиксируют изменения в коде примерно

с понедельника по пятницу (даже если занимаются

обучением кого-либо или консультационной поддержкой).

1:1 Есть ли проблемы с новым менеджером проектов, директором или руко­
водителем компании, который сводит к нулю производительность раз­

работчиков, заставляя их проводить бесконечные часы на совещаниях?

1:1 Есть ли у вас в компании «плохой» гениальный разработчик? Кто-то
генерирующий ненадежный код с исключительной плодотворностью?

208

Глава

8.

Извлечение полезной информации об управлении проектами

Создание исходного каркаса проекта
исследования данных
При разработке нового программного решения в сфере науки о данных
часто забывают про исходную структуру проекта. Для начала рекоменду­
ется создать макет, который бы способствовал работе в целом и обеспечил
высококачественную логическую схему проекта. Существует несколько
вариантов организации структуры проекта, из которых мы покажем лишь

один. В листинге

8.1

приведен точный результат выполнения команды

ls,

а ниже дано описание назначения каждого из элементов.

1:1 Каталог . circleci. В нем находятся требуемые для сборки проекта (с по­
мощью SааS-сервиса сборки

CircleCI) настройки. Существует множество

аналогичных сервисов на основе программного обеспечения с открытым
исходным кодом. Можно также воспользоваться утилитой с открытым

исходным кодом, например Jenkins.

1:1 •gi tignore. Очень важно пропускать файлы, не являющиеся частью про­
екта. Про это часто забывают.

1:1 CODE_OF _CONDUCТ. md.

Никогда не помешает включить в проект информа­

цию о том, как, по вашему мнению, должны вести себя участники его

разработки.

1:1

CONTRIBUТING. МD. Явные инструкции по включению дополнений в проект

очень важны для привлечения помощников, чтобы не отпугнуть потен­
циально ценных участников проекта.

1:1 LICENSE. Наличие лицензии, например MIT или BSD, не помешает.
В некоторых случаях в отсутствие у вас лицензии компании не смогут
вносить вклад в ваш проект.

1:1 Сборочный файл (Makefile). Часто используемый стандарт сборки про­
ектов, существующий уже десятки лет. Это отличный инструмент для

тестирования, развертывания и настройки среды разработки.

1:1 Файл READМE. md. Хороший файл README. md должен отвечать на основные
вопросы о проекте, например: как пользователю собрать проект и что он

собой представляет. Кроме того, часто бывает полезно включить в него
метки, демонстрирующие его качество, например пройденные сборки

-

[![CircleCI] (https://circleci.com/gh/noahgift/devml.svg?style=svg )]
https://circleci.com/gh/noahgift/devml).

(см.

209

Часть

III • Создание реальных приложений ИИ с нуля

Q Утилита командной строки. В данном примере есть утилита команд­

ной строки

dml.

Интерфейс командной строки очень удобен как для

изучения возможностей библиотеки, так и в качестве интерфейса для
тестирования.

Q Каталог для библиотеки с файлом

_ini t_. ру.

В корневом каталоге про­

екта необходимо создать каталог для библиотеки с файлом

_init_. ру

в качестве признака переносимости проекта. В данном примере библио­

тека называется

devml.

Q Каталог
и

ext. Подходящее место, например, для файлов config. j son
config.yml. Лучше всего размещать не являющиеся кодом части про­

екта там, где на них можно будет централизованно ссылаться. Может
понадобиться также подкаталог data для создания локальных, усеченных
примеров.

Q Каталог

notebooks. Специальный каталог для блокнотовjuрitеr, пред­

назначенный для централизации разработки связанного с блокнотами
кода. Кроме того, такой каталог упрощает настройку автоматического

тестирования блокнотов.

Q Файл

requirements. txt.

Содержит список необходимых для проекта

пакетов.

Q Файл

setup.py. Этот файл конфигурации задает способ развертывания
пакета Python. Его можно использовать для развертывания пакета в ка­
талоге пакетов Python.

Q Каталог tests. Каталог для размещения тестов.
Лисrинг

8.1.

Структура проекта

( .devml) ~ devml git:(master) ~ ls -la
3 noahgift staff
drwxr-xr-x
96 Oct 14 15:22 .circleci
1 noahgift staff 1241 Oct 21 13:38 .gitignore
-rw-r--r-3216 Oct 15 11:44 CODE_OF_CONDUCT.md
1 noahgift staff
-rw-r--r-357 Oct 15 11:44 CONTRIBUTING.md
1 noahgift staff
-rw-r--r-1 noahgift staff 1066 Oct 14 14:10 LICENSE
-rw-r--r-464 Oct 21 14:17 Makefile
1 noahgift staff
-rw-r--r-1 noahgift staff 13015 Oct 21 19:59 README.md
-rw-r--r--rwxr-xr-x
1 noahgift staff 9326 Oct 21 11:53 dml
128 Oct 20 15:20 ext
drwxr-xr-x 4 noahgift staff
7 noahgift staff
drwxr-xr-x
224 Oct 22 11:25 notebooks
1 noahgift staff
117 Oct 18 19:16 requirements.txt
-rw-r--r-1197 Oct 21 14:07 setup.py
1 noahgift staff
-rw-r--r-drwxr-xr-x 12 noahgift staff
384 Oct 18 10:46 tests
210

Глава

8.

Извлечение полезной информации об управлении проектами

Сбор и преобразование данных
Как обычно, самая сложная часть задачи состоит в поиске способа сбора
данных и преобразования их в нечто удобное для наших целей. Эта подзада­
ча состоит из нескольких частей. Первая: получение данных из отдельного

репозитория и создание на их основе объекта DataFrame библиотеки
Для этого мы создадим в каталоге

devml

Pandas.

новый модуль под названием

mkdata. ру, предназначенный для преобразования
Git в объект DataFrame библиотеки Pandas.

метаданных репозитория

Выбранный фрагмент этого модуля вы можете найти здесь:

https://github.com/
noahgift/devml/Ьlob/master/devml/mkdata.py. Функция log_to_dict принимает на
входе путь к извлеченному на диск содержимому репозитория Git и пре­
образует результаты выполнения команды Git:
def log_to_dict(path):
"""Преобразует журнал

Git

в словарь языка

Python"""

os.chdir(path) #Переходим в другой каталог для обработки
repo_name = generate_repo_name()
р = Popen(GIT_LOG_CМD, shell=True, stdout=PIPE)
(git_log, _) = p.communicate()
try:
git_log = git_log.decode('utf8').\
strip('\n\xle').split("\xle")
except UnicodeDecodeError:
log.exception("utf8 encoding is incorrect,
trying IS0-8859-1")
git_log = git_log.decode('IS0-8859-1').\
strip('\n\xle').split("\xle")

журнала

Git

git_log = [row.strip().split("\xlf") for row in git_log]
git_log = [dict(list(zip(GIT_COММIT_FIELDS, row)))\
for row in git_log]
for dictionary in git_log:
dictionary["repo"]=repo_name
repo_msg = "Found %s Messages For Repo: %s" %\
(len(git_log), repo_name)
log.info(repo_msg)
return git_log
В следующих двух функциях вышеприведенной функции передается путь

на диске. Обратите внимание, что журналы хранятся в виде элементов

211

Часть Ш



Создание реальных приложений ИИ с нуля

списка, который затем используется для создания объекта

в

DataFrame

Pandas:

def create_org_df(path):
"'"'Возвращает объект

DataFrame Pandas

для GitНuЬ-организации"""

original_cwd = os.getcwd()
logs = create_org_logs(path)
org_df = pd.DataFrame.from_dict(logs)
#Преобразует дату [Git] в тип datetime [библиотеки Pandas]
datetime_converted_df = convert_datetime(org_df)
#Добавляем индекс для даты

converted_df = date_index(datetime_converted_df)
new_cwd = os.getcwd()
cd_msg = "Changing back to original cwd: %s from %s" %\
(original_cwd, new_cwd)
log.info(cd_msg)
os.chdir(original_cwd)
return converted_df
def create_org_logs(path):
"""Проходим по всем путям текущего рабочего каталога,

формируя

словари на основе журналов"""

comЫned_log

= []

for sdir in subdirs(path):
repo_msg = "Processing Repo: %s" % sdir
log.info(repo_msg)
comЫned_log += log_to_dict(sdir)
log_entry_msg = "Found а total log entries: %s" %\
len(comЫned_log)

log.info(log_entry_msg)
return comЫned_log
Код в действии выглядит следующим образом при запуске без сбора данных
в объект

DataFrame:

In [5]: res = create_org_logs("/Users/noahgift/src/flask")
2017-10-22 17:36:02,380 - devml.mkdata - INFO - Found repo:\
/Users/noahgift/src/flask/flask
In [11): res[0)
Out[ll]:
{'author_email': 'rgerganov@gmail.com',
'author_name': 'Radoslav Gerganov',
'date': 'Fri Oct 13 04:53:50 2017',
212

Глава

8.

Извлечение полезной информации об управлении проектами

'id':'9291ead32e2fc8Ы3cef82518бc968944e9ff344',
'message': 'Fix typo in logging.rst {#2492)',
'repo': b'flask'}
Вторая часть кода

-

создание объекта

DataFrame -

имеет такой вид:

res = create_org_df{"/Users/noahgift/src/flask")
In [14): res.describe{)
Out[14]:
commits
9552.0
count
1.0
mean
0.0
std
1.0
min
1.0
25%
1.0
50%
1.0
75%
1.0
max
Если не вдаваться в подробности, то именно так и выглядит паттерн для
получения специализированных данных из сторонних источников, например

журналов

Git. Чтобы узнать больше подробностей,

не помешает взглянуть

на полный исходный код.

Обработка GitНuЬ-организации в целом
Естественный следующий этап после написания кода для преобразования

Git-репозиториев на диске в объекты

DataFrame - сбор данных из не­

скольких репозиториев сразу, то есть целой GitНuЬ-организации. Одна
из главных проблем с анализом одного отдельного репозитория

-

то, что

в контексте компании он представляет собой лишь обрывок информации.
Один из способов решения этой проблемы

-

обратиться к

API GitHub

и извлечь репозитории программным путем. Полный исходный код данного
решения приведен на https://github.com/noahgift/devml/Ьlob/master/devml/fetch_repo.py.

Вот его избранные фрагменты:

def clone_org_repos(oath_token, org, dest, branch="master"):
"""Клонируем все репозитории GitНuЬ-организаций и возвращаем
экземпляры

репозиториев

if not validate_checkout_root(dest):

213

Часrь

III •

Создание реальных приложений ИИ с нуля

return False
repo_instances = []
repos = org_repo_names(oath_token, org)
count = 0
for name, url in list(repos.items()):
count += 1
log_msg = "Cloning Repo # %s REPO NAME: %s , URL: %s " %\
(count, name, url)
log.info(log_msg)
try:
repo = clone_remote_repo(name, url, dest, branch=branch)
repo_instances.append(repo)
except GitCommandError:
log.exception("NO МАSТЕR BRANCH ... SKIPPING")
return repo_instances
Основную работу берут на себя пакеты

PyGithub и gitpython. После запуска
API и клонирует их. С помощью
создать единый объект DataFrame.

программа в цикле находит все репозитории из

вышеприведенного кода можно затем

Формирование предметно-ориентированной
статистики
Все вышеприведенное было сделано с одной целью: исследовать собранные
данные и сформировать предметно-ориентированную статистику. Для этого
мы создадим файл

stats.py, полное его содержимое вы можете найти здесь:

https://github.com/noahgift/devml/Ьlob/master/devml/stats.py.

Основная часть данного файла

определяет по записям

- функция author _unique_active_days. Она
DataFrame число дней, когда разработчик вел актив­

ную деятельность. Это уникальная предметно-ориентированная статистика,

редко упоминаемая в обсуждении статистики репозиториев исходного кода.
Ниже показана основная функция:

def author_unique_active_days(df, sort_by="active_days"):
'"'"Объект DataFrame с уникальными днями активности,
отсортировано no именам разработчика в порядке убывания
author_name unique_days
46 Armin Ronacher 271

214

Глава

260

8.

Извлечение полезной информации об управлении проектами

Markus Unterwaditzer

145

author_list = []
count_list = []
duration_active_list = []
ad = author_active_days(df)
for author in ad.index:
author_list.append(author)
vals = ad.loc[author]
vals.dropna(inplace=True)
vals.drop_duplicates(inplace=True)
vals.sort_values(axis=0,inplace=True)
vals.reset_index(drop=True, inplace=True)
count_list.append(vals.count())
duration_active_list.append(vals[len(vals)-1]-vals[0] )
df_author_ud = Dataframe()
df_author_ud("author_name"] = author_list
df_author_ud["active_days"] = count_list
df_author_ud["active_duration"] = duration_active_list
df_author_ud["active_ratio"] = \
round(df_author_ud["active_days"]/\
df_author_ud["active_duration"].dt.days, 2)
df_author_ud = df_author_ud.iloc[l:] #первая строка
df_author_ud = df_author_ud.sort_values(\
by=sort_by, ascending=False)
return df_author_ud
При вызове из оболочки

IPython она возвращает следующие результаты:

In (18]: from devml.stats import author_unique_active_days
In (19]: active_days = author_unique_active_days(df)
In (20]: active_days.head()
Out[20]:
author_name active_days active_duration
2490 days
Armin Ronacher
241
46
1672 days
71
260 Markus Unterwaditzer
710 days
David Lord
58
119
47
785 days
Ron DuPlain
352
19
435 days
Daniel Neuhauser
107
В этой статистике вы можете видеть коэффициент

active_ratio
0.10
0.04
0.08
0.06
0.04

- active_ratio, -

от­

ражающий часть времени от начала работы над проектом и до конца, когда

215

Часть 1П

Создание реальных приложений ИИ с нуля



соответствующий разработчик активно фиксировал изменения кода. В по­

добных показателях интересно, в частности, то, что они отражают степень
вовлеченности в проект и можно провести интересные параллели между

лучшими разработчиками открытого исходного кода. В следующем раз­
деле мы подключим эти базовые компоненты к утилите командной строки
и сравним два различных проекта с открытым исходным кодом с помощью
созданного нами кода.

Подключение проекта по исследованию

данных к интерфейсу командной строки
В первой половине данной главы мы создали компоненты, необходимые
для начала анализа. В этом разделе мы подключим их к гибкой утилите

командной строки, использующей фреймворк
для пакета

dml.

dml

Click.

Полный исходный код

можно найти здесь: https://github.com/noahgift/devml/Ьlob/master/

Отдельные существенные его фрагменты показаны ниже.

Сначала импортируем библиотеку и фреймворк

Click:

#!/usr/bin/env python
import os
import click
from
from
from
from
from
from
from

devml
devml
devml
devml
devml
devml
devml

import
import
import
import
import
import
import

state
fetch_repo
- version mkdata
stats
org_stats
post_processing

Затем подключаем к утилите вышеприведенный код, для чего требуется
лишь несколько его строк:

@gstats.command("activity")
@click.option("--path", default=CHECKOUT_DIR, help="path to org")
@click.option("--sort", default="active_days",
help="can sort Ьу: active_days, active_ratio, active_duration")

216

Глава

8.

Извлечение полезной информации об управлении проектами

def activity(path, sort):
"""Создает статистику активности
Пример запускается после извлечения данных из хранилища:

pythoп

dml.py gstats activity --path\

/Users/пoah/src/wulio/checkout

org_df = mkdata.create_org_df(path)
activity_couпts = stats.author_uпique_active_days(\
org_df, sort_by=sort)
click.echo(activity_couпts)

Использование этой утилиты из командной строки выглядит следующим

образом:

# Коэффициент активности разработчиков Linux
dml gstats activity --path /Users/noahgift/src/linux\
--sort active_days
active_days
author_name
1677
Takashi Iwai
1460
Eric Dumazet
1428
David S. Miller
1329
Johannes Berg
1281
Linus Torvalds
1249
Al Viro
1227
Mauro Carvalho Chehab
1198
Mark Brown
1158
Dan Carpenter
1141
Russell King
1040
Axel Lin
1036
Alex Deucher
#Коэффициент

146
301
128
47
132
375

активности

active_duration
4590 days
4504 days
4513 days
4328 days
4565 days
4562 days
4464 days
4187 days
3972 days
4602 days
2720 days
3497 days

разработчиков

active_ratio
0.370000
0.320000
0.320000
0.310000
0.280000
0.270000
0.270000
0.290000
0.290000
0.250000
0.380000
0.300000

CPython

author_name active_days active_duration
9673 days
2256
Guido van Rossum
5635 days
1361
Raymond Hettinger
5335 days
1239
Fred Drake
3494 days
1234
Benjamin Peterson
4091 days
1080
Georg Brandl
2818 days
980
Victor Stinner

active_ratio
0.230000
0.240000
0.230000
0.350000
0.260000
0.350000

217

Часть

III •

Создание реальных приложений ИИ с нуля

235
Martin v. Lowis
36
Antoine Pitrou
362
Tim Peters
164
Jack Jansen
24 Andrew М. Kuchling
Serhiy Storchaka
330
44
Barry Warsaw
52
Brett Cannon
262
Neal Norwitz

958
883
869
800
743
720
696
681
559

5266
3376
5060
4998
4632
1759
8485
5278
2573

days
days
days
days
days
days
days
days
days

0.180000
0.260000
0.170000
0.160000
0.160000
0.410000
0.080000
0.130000
0.220000

Согласно этой статистике, вероятность того, что создатель языка
Гвидо ван Россума будет работать в заданный день, равна
дателя операционной системы

Linux

23 %,

Python

а для соз­

Линуса Торвальдса она равна

28 %.

В подобной статистике интересно то, что она отражает поведение разработ­
чиков за длительный период времени. В случае проекта

CPython многие из

разработчиков трудятся еще и полный рабочий день, что еще невероятнее.
Интересно было бы также посмотреть историю разработчиков компании

(объединив для этого все доступные репозитории ). Я обратил внимание, что
в некоторых случаях весьма опытные разработчики при полной занятости
выдают код с коэффициентом активности около

85 %.

Исследование GitНuЬ-организаций
с помощью блокнота Jupiter
Проект
зитория

Pallets на GitHub.
-

В числе проблем изучения лишь одного репо­

то, что это всего часть данных. Ранее созданный код дает нам

возможность клонировать и изучать GitНuЬ-организацию в целом. Среди

популярных GitНuЬ-организаций можно выделить проект

Pallets (https://

github.com/pallets). В его состав входит множество популярных проектов,
например Click и Flask. Блокнот Jupiter для этого нашего исследования
можно найти здесь: https://github.com/noahgift/devml/Ьlob/master/notebooks/github_

data_exploration.ipynb.
Для зaпycкajupiter наберите в командной строке команду
Затем импортируйте нужные библиотеки:

In [ 3] : import sys;sys.path.append(" .. ")

import pandas as pd
from pandas import DataFrame
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

218

jupyter notebook.

Глава

8.

Извлечение полезной информации об управлении проектами

%matplotlib inline
from IPython.core.display import display, HTML
display(HTML(".container {\
width:100% !important; }"))
Далее воспользуемся следующим кодом для скачивания GitНuЬ-организации:

In [4]: from devml import (mkdata, stats, state, fetch_repo, ts)
In [5]: dest, token, org = state.get_project_metadata(\
" .. /project/config.json")
In

(б]:

....

fetch_repo.clone_org_repos(token, org,
dest, branch="master")

Out[б]:

[]

После скачивания кода на диск можно его преобразовать в объект
библиотеки

DataFrame

Pandas:

In (7]: df = mkdata.create_org_df(path="/tmp/checkout")
In (9]: df.describe()
Out[9]:
commits
8315.0
count
1.0
mean
0.0
std
1.0
min
1.0
25%
1.0
50%
75%
1.0
1.0
max

219

Часть

III •

Создание реальных приложений ИИ с нуля

И подсчитать количество дней, в которые разработчики вели активную
деятельность:

In [10]: df_author_ud = stats.author_unique_active_days(df)
In [11]: df_author_ud . head(10)
Out[ll]:
author_name active_days active_duration
Armin Ronacher
86
941
3817 days
499 Markus Unterwaditzer
238
1767 days
Oavid Lord
216
94
710 days
Ron DuPlain
663
56
854 days
297
Georg Brandl
41
1337 days
Daniel Neuhauser
196
435 days
36
169
Christopher Grebs
27
1515 days
Ronny Pfannschmidt
665
23
2913 days
Keyan Pishdadian
448
21
882 days
Simon Sapin
712
21
793 days
Наконец , с помощью функции

active_ratio
0.25
0.13
0.13
0.07
0.03
0.08
0.02
0.01
0.02
0.03

sns. barplot можно превратить эти данные
Seaborn, как показано на рис. 8.1, с де­

в столбчатый график из библиотеки

сятью разработчиками , внесшими основной вклад в GitНuЬ-организацию ,
по дням их активности в рамках проекта , то есть дням, когда они действи­

тельно фиксировали изменения кода . И неудивительно, что основные

авторы большинства проектов демонстрируют втрое большую активность,
чем большинство других участников.

In (9):

anв.barplot(y~ · author_name " ,

x= " active_dayв " ,

Out(9J:

Ron OuPl11n
Кenntth

Rtitz

01n1et Neuhauser
Georg Brandl
Oan1tl Ntuhauser
Key1n Pl$hdadian

ChnStophtr Grebs
F-~--,,.-~--,~~--.~~---,-~~-т-'

200

Рис.

220

8.1.

600

800

1000

SеаЬогn-диаграмма дней активности

Глава

8.

Извлечение полезной информации об управлении проектами

Вероятно, некоторые из подобных наблюдений можно экстраполиро­
вать и на проекты с закрытым исходным кодом из репозиториев GitНuЬ­
организации. Дни активности

-

удобный показатель вовлеченности, кото­

рый можно включить в множество метрик для оценивания эффективности

работы команд разработчиков и проектов.

Изучаем метаданные файлов
проекта

CPython

Следующий блокнот

jupiter,

который мы обсудим, будет связан с иссле­

дованием метаданных проекта

CPython.

Его можно найти здесь:

https://

github.com/noahgift/devml/Ьlob/master/notebooks/repo_file_exploration.ipynb. А проект

https://github.com/python/cpython; этот репозиторий используется
для разработки языка Python.

CPython -

тут:

Одна из возможных метрик

кода

(relative churn);

-

относительный пересмотр (редактирование)

прочитать о нем подробнее можно в статье, опубли­

кованной исследовательским подразделением компании «Майкрософт»:

https://www.microsoft.com/en-us/ resea rch/wp-content/ uploads/2016/02/icseOSchurn. pdf.
Эта статья утверждает, что «повышение относительного коэффициента

пересмотра кода сопровождается повышением концентрации ошибок
в системе». Из данного утверждения можно сделать вывод о том, что на

основе слишком большого числа изменений файла можно прогнозировать
наличие в нем ошибок.
В этом новом блокноте мы опять импортируем необходимые для дальней­
шего исследования модули:

In [1]: import sys;sys.path.append(" .. ")
.... import pandas as pd
.... from pandas import DataFrame
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
%matplotlib inline
from IPython.core.display import display, HTML
display(HTML(".container \
{ width:100% !important; }"))
221

Часть Ш



Создание реальных приложений ИИ с нуля

Далее генерируем метрики относительного пересмотра кода:

In [2]: from devml.post_processing import (
git_churn_df, file_len, git_populate_file_metadata)
In [3]: df = git_churn_df(path="/Users/noahgift/src/cpython")
2017-10-23 06:51:00,256 - devml.post_processing - INFO Running churn cmd: [git log --name-only
--pretty=format:] at path [/Users/noahgift/src/cpython]
In [4): df.head()
Out[4]:
files
0
b'LiЬ/test/test_struct.py'
1
Ь' LiЬ/test/test_zipimport. ру'
2
b'Misc/NEWS.d/next/Core'
b'and'
3
4 b'Builtins/2017-10-13-20-01-47.bpo-31781.cXE9S ...

churn_count
178
78
351
351
1

Теперь можно воспользоваться несколькими фильтрами из библиотеки

Pandas для поиска наиболее часто редактируемых файлов с расширением,
Python. Результат приведен на рис. 8.2.

соответствующим языку

На рисунке можно, в частности, заметить, что тесты подвергаются актив­

ному пересмотру кода. Это стоит исследовать подробнее. Означает ли дан­
ный факт, что сами тесты тоже содержат ошибки? У нас может получиться
весьма захватывающее исследование. Кроме того, существует несколько

модулей

Python с исключительно высоким относительным коэффициентом
string. ру: https://github.com/python/cpython/

пересмотра кода, например модуль

Ыob/master/Lib/string.py. Если просмотреть исходный код этого файла, можно
отметить, что он очень сложен для своего размера и содержит метаклассы.

Возможно, именно сложность повышает его предрасположенность к ошиб­
кам. Похоже, что имеет смысл продолжить исследование этого модуля по­
средством науки о данных.

Далее можно сформировать описательную статистику и взглянуть на меди­
анные значения для этого проекта. Статистика показывает, в частности, что

за пару десятков лет существования проекта и более

100 ООО фиксаций из­
менений в его коде медианный файл насчитывает около 146 строк и менялся
пять раз, а его относительный коэффициент пересмотра кода равен 10 %.

222

Глава

8.

Извлечение полезной информации об управлении проектами

In [ 22): python_files_df = metadata_df[metadata_df .extension &• • .ру")
line_python ~ python_files_df [ python_files_df. line_count> 40)
line_python .sort_val ues(by•"relative_churn" , ascending•Palse) . head( 15)
Out[22] :

files

chum_count llne_count extension relatlve_Chum

15

b'UЫtesVregrtest. py'

627

50.О

.ру

12.54

196

b'LlbltesVtest_datetlme.py'

165

57.О

.fY'j

2.89

197

b' UЬ/io.py'

165

99.О

.ру

1.67

430

b'UbltesVtest_sundty.py'

91

56.0

.ру

1.62

289

b'UЫtesVtesL_all_.fY'/'

126

109.0

.ру

1.17

1120

b'UЬ/tesVtest__usef'Strlng.py'

40

44.0

.ру

0.91

827

b'UЫemalV_lnlt_.py·

52

62.О

.ру

0.84

85

b'UbltesVtest_support.py'

262

461.О

.fY'I

0.57

1006

b'UЫtesVtest_select.py'

44

82.О

.ру

0.54

.ру

0.53

1474

b'UЬЛiЬ2to3/fixes/fix.Jtertools_lmports.py'

30

57.О

348

b'Doclconf.py'

106

206.О

.ру

0.51

222

b'UЫstrlng.py'

151

305.0

.ру

0.50

604

b'UЬltesVtest_normallzation.py'

53

106.О

.ру

0.49

592

b'UЬ/tesиtest_fcntl.py'

68

152.О

.ру

0.45

602

b'LIЬ/tesVtest_winsound.py'

67

146.О

.ру

0.45

Рис.

8.2.

Наиболее часто редактируемые файлы с расширением .ру
в проекте

CPython

Следовательно, оптимально будет создавать маленькие файлы и менять их
лишь несколько раз за годы их существования :

ln [16): metadata_df.median()
Out[16):
5.0
churn_count
146.0
line_count
0.1
relative_churn
dtype: float64
Если сгенерировать SеаЬоm-график относительного пересмотра кода, то
эти паттерны станут еще более ясными:

ln [18): import matplotlib . pyplot as plt
plt.figure(figsize=(10,10))
python_files_df =\
metadata_df[metadata_df . extension
line_python =\

". ру"]

223

Часть

Создание реальных приложений ИИ с нуля

III •

python_files_df[python_files_df.line_count> 40)
line_python_sorted =\
line_python.sort_values(by="relative_churn",
ascending=False).head(lS)
sns.barplot(
y="files", x="relative_churn",data=line_python_sorted)
plt.title('Top 15 CPython Absolute and Relative Churn')
plt.show()
На рис.

8.3

модуль

regrtest. ру

выделяется числом своих изменений,

и опять же вполне понят110, почему он менялся так часто. Хотя файл и не­

велик, обычно тестирование регрессии представляет собой весьма непростую
задачу . Он вполне может оказаться критическим участком кода, который
заслуживает пристального внимания: https://github.com/python/cpython/Ьlob/

master/Lib/test/regrtest.py.
Тор

15 CPython Absolute and Relative Chum

llUЬ/ltstlregrtest. py'

ltUЬ/test/lest_dat~me . py'

i:::::::;:::::::::--

Ь'UЬl!t5t/t­
т-

..•,,. .. -·

Elton Olмd • • •• •



"
1

. ""~Вosh ~ . •

• .(

i

о-

.,,_

.,,_

с:

i

i

:'!:О •

о ~~ и-·· · • ·

"'
i-

......


~

-



1
"'
i-

о-

i

х

•i

о-



т~ :

m
i
!

·••.

о-

KevinOt.rnnl 8

"""
Рис. Б.1. кластеризация сезона НБА

300

f



о

... ...


200

-

1=
'°"

"
о

Приложение Б. Выбор размера кластера

Существуют, однако, некоторые способы, которые могут помочь в выборе
scikit-learn приведено не­

числа кластеров. В документации по библиотеке

сколько хороших примеров оценки эффективности кластеризации

(http://

scikit-learn.org/staЬle/modules/clustering.html#clustering-performance-evaluation ). Два по­
пулярных метода для этого

-

метод «локтя» и метод анализа силуэтов.

Именно с них рекомендуется начать, если похоже, что распределение по
кластерам можно улучшить.

НойГифт

Праrматичный ИИ. Машинное обучение
и облачные технолоrии
Перевел с английского И. Пальти

Заведующая редакцией

Ю. Сергиенко

Руководитель проекrа

О. Сивченко

Ведущий редакrор

Н. Гринчик

Литераrурный редакrор

Е. Рафалюк-Бузовская

Художественный редакrор
Коррекrор

В. Мостипан
Е. Павлович

Верстка

Г Блинов

Изrотовлено в России. Изготовитель: ООО «Прогресс книга>>.

Место нахождения и фактический адрес:
Б. Самnсониевский

Дата изrотовления:
Налоговая льгота

12.2018.
-

194044, Россия, г. Санкт-Петербург,
np., д. 29А, nом. 52. Тел.: +78127037373.

Наименование: книжная продукция. Срок годности: не ограничен.

общероссийский классификатор продукции ОК

034-2014, 58.11.12 -

Книги печатные профессиональные, технические и научные.
Импортер в Беларусь: ООО «ПИТЕР М»,
Подписано в печать

220020, РБ,

г. Минск, ул. Тимирязева, д.

18.12.18. Формат 70х 100/16. Бумага офсетная.

Усл. п. л.

121/3, к. 214, тел./факс: 208 80 01.

24,510.

Тираж

1000.

Заказ

Отпечатано в АО «Первая Образцовая типографию>. Филиал «Чеховский Печатный Двор»

142300, Московская область, г. Чехов, ул. Полиграфистов, 1
Сайт: www.chpd.ru, E-mail: sales@chpd.ru
тел: 8(499) 270-73-59

308.

nзaATl!nьcкnlt аом

PAnnтEP®

~

WWW.PITER.COM

ИЗДАТЕЛЬСКИЙ ДОМ «ПИТЕР» преД11аrает

профессиональную, популярную и детскую развивающую литературу
Заказать книrи оптом можно в наших представительствах
РОССИЯ

санкт-Петербурr: м. «Выборгская», Б. сампсониевский пр., д. 29а
тел.jфакс: (812) 703-73-83, 703-73-72; e-mail: sales@piteг.com

Москва: м. «Электрозаводская», Семеновская наб., д. 2/1, стр.
тел.jфакс: (495) 234-38-15; e-mail: sales@msk.piter.com
Воронеж: тел.:

1, 6 этаж

8 951 861-72-70; e-mail: hitsenko@piter.com

Екатеринбурr: ул. Толедова, д. 43а; тел.jфакс:

(343) 378-98-41, 378-98-42;
e-mail: office@ekat.piter.com; skype: ekat.manager2

Нижний Новrород: тел.:
тел.jфакс:

8 930 712-75-13; e-mail: yashny@yandex.ru; skype: yashny1

Ростов-на-Дону: ул. Ульяновская, д. 26
(863) 269-91-22, 269-91-30; e-mail: piter-ug@rostov.piter.com

Самара: ул. Молодогвардейская, д. 33а, офис 223
тел.jфакс: (846) 277-89-79, 277-89-66; e-mail: pitvolga@mail.гu,
pitvolga@samaгa-ttk. гu
БЕЛА РУСЬ

163; тел.jфакс: +37 517 208-80-01, 208-81-25;
e-mail: og@minsk.piter.com

Минск: ул. Розы Люксембург, д.

Иэgательаий gом «Питер» приглашает к сотруgничеству авторов:

тел/факс: (812) 703-73-72, (495)
Поgробная информация зgесь:

234-38-15; e-mail: ivanovaa@piter.com
http:j/www.piter.com/page/avtoru

Иэgателе.ский gом «Питер» nриглоwоет к сотруgничеству зарубежных

торговых партнеров или посреgников, имеющих вьrхоg на зарубежный
рынок: тел/факс: (812) 703-73-73; e-mail: sales@piter.com

3окаэ книг gл11 вузов и библиотек:
тел/факс: (812) 703-73-73, gоб. 6243;
Заказ книг по почте: на сайте

e-mail: uchebnik@piter.com

www.piter.com;

тел.:

(812) 703-73-74, gоб. 6216;

e-mail: books@piter.com
Вопросы по проgаже электронных книг: тел.:
кuznetsov@piter.com

e-mail:

(812) 703-73-74, gоб. 6217;

пзDАт~пьскпn Dом

t>йnnTEP®

~

WWW.PITER.COM

ВАША УНИКАЛЬНАЯ КНИГА
Хотите изgать свою книгу? Она станет иgеальным поgарком gля партнеров
и gрузей, отличным инструментом gля проgвижения вашего бренgа, презентом
gля памятных событий! Мы сможем осуществить ваши любые, gаже самые
смелые и сложные, иgеи и проекты.

МЫ ПРЕДЛАГАЕМ:
• издать вашу книгу
• издание книги для использования в маркетинговых активностях
• книги как корпоративные подарки
• рекламу в книгах
• издание корпоративной библиотеки
Почему наgо выбрать именно нас:
Изgательству «Питер» более 20 лет. Наш опыт - гарантия высокого качества.
Мы npegлazaeм:

• услуги по обработке и доработке вашего текста
• современный дизайн от профессионалов
• высокий уровень полиграфического исполнения
• продажу вашей книги во всех книжных магазинах страны
Обеспечим проgвюкение вашей книги:

• рекламой в профильных СМИ и местах продаж
• рецензиями в ведущих книжных изданиях
• интернет-подцержкой рекламной кампании
Мы имеем собственную сеть gистрибуции по всей России, а также на Украине
и в Беларуси. Сотруgничаем с крупнейшими книжными магазинами.

Изgательство «Питер» является постоянным участником многих конференций
и семинаров, которые преgоставляют широкую возможность реализации книг.

Мы обязательно прослеgим, чтобы ваша книга постоянно имелась в наличии
в магазинах и была выложена на самых виgных местах.
Обеспечим инgивиgуальный пogxog к кажgому клиенту, эксклюзивный gизайн,
любой тираж.
Кроме того, преgлагаем вам выпустить электронную книгу. Мы разместим

ее в крупнейших интернет-магазинах. Книга буgет сверстана в формате ePub
или PDF - самых популярных и наgежных форматах на сегоgняшний gень.
Свяжитесь с нами прямо сейчас:
санкт-Петербург -Анна Титова, (812) 703-73-73, titova@piter.com
Москва - Сергей Клебанов, (495) 234-38-15, k/ebaпov@piter.com

Облачные технологии

-

ваш путь к укрощению

«Это краткое руководство

-

то самое недостающее звено,

искусственного интеллекта.

объединяющее безграничные
возможности искусственного

Тщательно изучив эту незаменимую книгу от Ноя

Гифта, легендарного эксперта по языку

интеллекта и те нетривиальные

Python,

задачи, которые необходимо

вы легко научитесь писать облачные приложения

решать для развертывания

реальных проектов . Понятная

с использованием средств искусственного интел­

и практичная, эта книга станет

лекта и машинного обучения, решать реалистич­

вашим ключом к настоящему

ные задачи из таких востребованных и актуальных

Pythoп и алгоритмам ИИ».

областей, как спортивный маркетинг, управление

Кристофер Бруссо, основатель
и генеральный директор корпора­

проектами, ценообразование, сделки с недвижи­

тивной платформы ИИ

мостью .

Все примеры разобраны на языке


Python,
1 в сфере современных стремительных

Surface Owl

«Фантастическое дополнение

к списку обязательной литера­

вычислений.

туры для фанатов новых техно­

Прагматичный подход+ амбициозные задачи
искусственный интеллект.

=

логий! Столько всего можно
сказать про эту книгу! Ной

Гифт создал по-настоящему
практичное руководство для
всех, кто имеет дело с коммер­

ческим применением машин­

НОЙ ГИФТ. Преподаватель и консультант по программе
Maпagemeпt

MSBA

в аспирантуре Калифорнийского

университета в Дэвисе . На протяжении карьеры занимал

должности СТО, главного менеджера, СТО-консультанта,

архитектора облачных решений. Основатель компании

Pragmatic AI Labs,

занимается консультированием

стартапов и других компаний по вопросам машинного

обучения и облачных архитектур. Член Pythoп Software
Fouпdatioп (сфера ответственности

-

автор книг по машинному обучению и

машинное обучение),

DevOps.

ного обучения. Она не только
рассказывает, как использовать

машинное обучение для боль­
ших наборов данных, но и дает
читателю представление о внут­

ренних взаимосвязях этой тех­
нологии. Книга позволит мно­

жеству команд разработчиков
и исследователей данных
с первых дней наладить эффек­

тивную разработку и поддерж­
ку самых сложных проектов ».

Ни вас Дурайрадж, специалист
по технической поддержке,

AWS

(сертифицирова нный архитектор
решений

AWS уровня

Professioпal)

--~nnTEP®
заказкниг:

тел.:(81 2) 703-73-74
Ьooks@piter.com

О instagram .com/piterЬooks

V

ISBN: 978-5-4461-1061-2

~

~ youtube.com/ТhePiterBooks

WWW.PITER.COM

каталог книг и интернет-магазин

@ vkcom/piterbooks

ф faceЬook.com/piterbooks

111111111111111111111111

9 785446 110612