Книга «Python для сложных задач: наука о данных. 2-е межд. изд. »

image Привет, Хаброжители!

Python — первоклассный инструмент, и в первую очередь благодаря наличию множества библиотек для хранения, анализа и обработки данных. Отдельные части стека Python описываются во многих источниках, но только в новом издании «Python для сложных задач» вы найдете подробное описание IPython, NumPy, pandas, Matplotlib, Scikit-Learn и др.

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

Для кого предназначена эта книга
«Как именно следует изучать Python?» — один из наиболее часто задаваемых мне вопросов студентами Вашингтонского университета и на различных технологических конференциях и встречах. Задают его заинтересованные в технологиях студенты, разработчики или исследователи, часто уже со значительным опытом написания кода и использования вычислительного и цифрового инструментария. Большинству из них не нужен язык программирования Python в чистом виде, они хотели бы изучать его, чтобы применять в качестве инструмента для решения задач, требующих вычислений с обработкой больших объемов данных. Несмотря на большое разнообразие видеороликов, статей в блогах и учебных пособий, ориентированных на эту аудиторию, вы не найдете в Интернете единственного хорошего ответа на данный вопрос, именно поэтому я взялся за эту книгу.

Эта книга не планировалась как введение в язык Python или в программирование вообще. Я предполагаю, что читатель знаком с языком Python и знает, как определять функции, присваивать значения переменным, вызывать методы объектов, управлять потоком выполнения программы и решать другие простейшие задачи. Она должна помочь пользователям языка Python научиться применять инструменты исследования данных, имеющиеся в языке Python, — библиотеки, упоминающиеся в следующем разделе, и сопутствующие инструменты — для эффективного хранения и анализа данных и извлечения из них полезной информации.

Общая структура книги
Каждая часть книги посвящена конкретному пакету или инструменту, составляющему существенную часть инструментария Python для исследования данных, и разбита на более короткие независимые главы, обсуждающие отдельные понятия.
  • Jupyter: за пределами обычного Python (часть I) — знакомит с IPython и Jupyter. Эти пакеты образуют вычислительное окружение, в котором работают многие исследователи данных, использующие Python.
  • Введение в NumPy (часть II) — представляет библиотеку NumPy, в состав которой входит объект ndarray для эффективного хранения и работы с плотными массивами данных в Python.
  • Манипуляции над данными с помощью пакета Pandas (часть III) — представляет библиотеку Pandas, в состав которой входит объект DataFrame для эффективного хранения и работы с маркированными/табличными данными в Python.
  • Визуализация с помощью библиотеки Matplotlib (часть IV) — представляет библиотеку Matplotlib, реализующую богатые возможности для разнообразной гибкой визуализации данных в Python.
  • Машинное обучение (часть V) — представляет библиотеку Scikit-Learn, включающую эффективные реализации на Python многих важных и широко известных алгоритмов машинного обучения.
Мир PyData гораздо шире представленных пакетов, и он растет день ото дня. С учетом этого я использую каждую возможность в книге, чтобы упомянуть другие интересные работы, проекты и пакеты, расширяющие пределы возможностей языка Python. Тем не менее пакеты, перечисленные выше, являются основой для применения языка программирования Python в исследовании данных. Я полагаю, что они сохранят свое значение и при росте окружающей их экосистемы.


Сводные таблицы


Мы уже видели, какие возможности по исследованию отношений в наборе данных предоставляет абстракция groupby. Сводная таблица (pivot table) — схожая операция, часто встречающаяся в электронных таблицах и других программах, работающих с табличными данными. Сводная таблица получает на входе простые данные в виде столбцов и группирует записи в двумерную таблицу, обеспечивающую многомерное представление данных. Различие между сводными таблицами и операцией groupby иногда неочевидно. Лично мне помогает представлять сводные таблицы как многомерную версию агрегирующей функции groupby. То есть вы выполняете операцию «разбить, применить, объединить», но как разбиение, так и объединение происходят не на одномерном индексе, а на двумерной координатной сетке.

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


В качестве примера в этой главе мы используем базу данных пассажиров парохода «Титаник», доступную в пакете Seaborn:

image


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

Сводные таблицы «вручную»


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

image


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

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

image


Эти результаты дают нам еще более полное представление о том, как пол и класс повлияли на выживаемость, но код начинает выглядеть несколько запутанным. Каждый шаг этого конвейера выглядит вполне осмысленным в свете ранее рассмотренных инструментов, но такая длинная строка кода не особенно удобна для чтения или использования. Двумерная операция groupby встречается настолько часто, что в библиотеку Pandas был включен удобный метод pivot_table, позволяющий более кратко описать данную разновидность многомерного агрегирования.

Синтаксис сводных таблиц


Вот код, эквивалентный вышеприведенной операции, использующий метод pivot_table объекта DataFrame:

image


Такая запись несравненно удобнее для чтения, чем подход с groupby, при том же результате. Как и следовало ожидать от трансатлантического круиза начала XX века, судьба благоприятствовала женщинам, путешествовавшим первым классом. Женщины из первого класса выжили практически все (привет, Роуз!), из мужчин, путешествовавших третьим классом, выжила только десятая часть (извини, Джек!).

Многоуровневые сводные таблицы


Группировку в сводных таблицах, как и при операции groupby, можно задавать на нескольких уровнях и со множеством параметров. Например, интересно взглянуть на возраст в качестве третьего измерения. Разобьем данные на интервалы по возрасту с помощью функции pd.cut:

image


Ту же стратегию можно применить при работе со столбцами. Добавим сюда информацию о стоимости билета, воспользовавшись функцией pd.qcut для автоматического вычисления квантилей:

image


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

Дополнительные параметры сводных таблиц


Полная сигнатура метода DataFrame.pivot_table выглядит следующим образом:

# сигнатура в версии Pandas 1.3.5
DataFrame.pivot_table(data, values=None, index=None, columns=None,
                      aggfunc='mean', fill_value=None, margins=False,
                      dropna=True, margins_name='All', observed=False,
                      sort=True)


Мы уже видели примеры первых трех аргументов, в данном подразделе рассмотрим остальные. Параметры fill_value и dropna определяют, как обрабатывать отсутствующие значения, и интуитивно понятны, примеры их использования мы приводить не будем.

Именованный аргумент aggfunc задает тип агрегирования — по умолчанию среднее значение. Как и в groupby, агрегирующая функция может задаваться строкой с одним из обычных вариантов ('sum', 'mean', 'count', 'min', 'max' и т. д.) или именем функции, реализующей агрегирование (np.sum, min, sum и т. п.). Кроме того, агрегирование можно задать в виде словаря, отображающего столбец в любой из вышеперечисленных вариантов:

image


Обратите внимание, что, задав аргумент aggfunc, мы опустили аргумент values, так как в этом случае он определяется автоматически.

Иногда бывает полезно вычислять итоги по каждой группе. Это можно сделать, передав аргумент margins:

image


Такие итоги автоматически дают нам информацию о выживаемости вне зависимости от класса, коэффициенте выживаемости по классу вне зависимости от пола и общем коэффициенте выживаемости 38%. Метки для этих итогов можно задать с помощью аргумента margins_name, по умолчанию имеющего значение «All».

Пример: данные о рождаемости


В качестве еще одного примера взглянем на находящиеся в открытом доступе данные о рождаемости в США (https://oreil.ly/2NWnk), предоставляемые центрами по контролю заболеваний (Centers for Disease Control, CDC). Этот набор данных довольно широко исследовался Эндрю Гелманом и его группой (см., например, сообщение в блоге oreil.ly/5EqEp):

image


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

image


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

image


Сразу же видим, что в каждом десятилетии мальчиков рождается больше, чем девочек. Воспользуемся встроенными средствами построения графиков в библиотеке Pandas для визуализации общего количества новорожденных в зависимости от года, как показано на рис. 21.1 (см. обсуждение построения графиков с помощью библиотеки Matplotlib в части IV):

image


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

Хотя это, возможно, и не имеет отношения к сводным таблицам, но в библиотеке Pandas есть еще несколько интересных инструментов, позволяющих извлечь дополнительную информацию из этого набора данных. Для начала немного почистим данные, удалив аномальные значения, возникшие из-за неправильно набранных дат (например, 31 июня) или отсутствующих значений (например, 99 июня). Простой способ убрать их все сразу — отсечь аномальные значения. Мы сделаем это с помощью надежного алгоритма сигма-отсечения (sigma-clipping):

image


В последней строке вычисляется грубая оценка среднего значения по выборке, где 0,74 — межквартильный размах гауссова распределения (узнать больше об операциях сигма-отсечения можно в книге, которую я написал совместно с Желько Ивечичем, Эндрю Дж. Конолли и Александром Греем: Statistics, Data Mining and Machine Learning in Astronomy: A Practical Python Guide for the Analysis of Survey Data (Princeton University Press, 2014)).

Теперь можно воспользоваться методом query (обсуждается в главе 24) для фильтрации строк, в которых количество новорожденных выходит за пределы этих значений:

image


Далее установим целочисленный тип для столбца day. Ранее он был строчным, потому что некоторые столбцы в наборе данных содержат значение 'null':

image


Наконец, создадим индекс для даты, объединив день, месяц и год (см. главу 23). Это даст нам возможность быстро вычислять день недели для каждой строки:

image


С помощью следующего кода построим график дней рождения в зависимости от дня недели за несколько десятилетий (рис. 21.2):

image


Очевидно, что в выходные дни число рождений меньше, чем в будни! Обратите внимание, что 1990-е и 2000-е годы отсутствуют на графике, потому что начиная с 1989 года данные CDC содержат только месяц рождения.

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

image


Результат представляет собой мультииндекс по месяцам и дням. Чтобы упростить построение графика, преобразуем месяцы и дни в даты, связав их с фиктивным годом (обязательно выбирайте високосный год, чтобы корректно обработать 29 февраля!):

image


Сфокусировавшись на дне и месяце, мы получаем временной ряд, отражающий среднее количество новорожденных в зависимости от дня года. Исходя из этого, можно с помощью метода plot построить график (рис. 21.3). В нем, как видите, обнаруживаются некоторые любопытные тренды.

image


В частности, удивительным выглядит резкое падение количества рождений в государственные праздники США (например, День независимости, День труда, День благодарения, Рождество, Новый год). Хотя оно отражает скорее тенденции, относящиеся к заранее запланированным/искусственным родам, а не глубокое психосоматическое влияние на естественные роды. Дальнейшее обсуждение данной тенденции, ее анализ и ссылки на эту тему вы найдете в статье (https://oreil.ly/ugVHI) в блоге Эндрю Гелмана. Мы вернемся к этому графику в главе 32, где используем инструменты из библиотеки Matplotlib для добавления меток на график.

Рассматривая этот краткий пример, вы могли заметить, что многие из представленных инструментов Python и Pandas можно комбинировать между собой и использовать, чтобы почерпнуть полезную информацию из наборов данных. В следующих главах мы увидим более сложные манипуляции с данными!

Векторизованные операции над строками


Одна из сильных сторон языка Python — относительная простота работы со строковыми данными. Библиотека Pandas тоже вносит свою лепту и предоставляет набор векторизованных операций над строками, широко используемых для очистки данных, необходимой при работе с реальными данными. В этой главе мы перечислим некоторые строковые операции, реализованные в библиотеке Pandas, а затем рассмотрим их применение для частичной очистки очень зашумленного набора данных рецептов, собранных в Интернете.

Знакомство со строковыми операциями в библиотеке Pandas


В предыдущих главах мы видели, как библиотеки NumPy и Pandas обобщают арифметические операции, позволяя легко и быстро выполнять одну и ту же операцию над множеством элементов массива. Например:

image


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

image


Для работы с некоторыми данными этого достаточно, но если в наборе могут отсутствовать какие-то значения, то приходится добавлять дополнительные проверки:

image


Такой подход не только влечет за собой написание лишнего кода, но и чреват ошибками.

Библиотека Pandas включает средства и для поддержки векторизованных строковых операций, и для корректной обработки отсутствующих значений в виде атрибута str объектов Series и объектов Index со строками. Так, например, создав объект Series с такими данными, вы сможете вызвать один-единственный метод str.capitalize для преобразования строчных букв в заглавные, который будет игнорировать любые отсутствующие значения:

image


Таблица строковых методов в библиотеке Pandas


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

image


Методы, аналогичные строковым методам языка Python


Практически для всех встроенных строковых методов Python в библиотеке Pandas имеются векторизованные эквиваленты. Вот список методов атрибута str в библиотеке Pandas, дублирующих строковые методы языка Python:

image


Обратите внимание, что они возвращают разные значения. Некоторые, например lower, возвращают ряды строк:

image


Другие — числовые значения:

image


Третьи — булевы значения:

image


А четвертые — списки и другие составные значения для каждого элемента:

image


Далее мы рассмотрим приемы работы с подобными объектами типа «ряды списков».

Методы, использующие регулярные выражения


Помимо перечисленных выше, есть несколько методов, принимающих регулярные выражения, проверяющих содержимое всех строковых элементов и следующих некоторым соглашениям по API встроенного модуля re языка Python (табл. 22.1).

image


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

image


Или, например, найти все имена, начинающиеся и заканчивающиеся согласным звуком, воспользовавшись символами регулярных выражений «начало строки» (^) и «конец строки» ($):

image


Такой сжатый синтаксис применения регулярных выражений для обработки записей в объектах Series и DataFrame открывает массу возможностей для анализа и очистки данных.

Об авторе

Джейк Вандер Плас — инженер-программист в Google Research, работает над инструментами для исследований с привлечением больших объемов данных. Джейк создает и разрабатывает инструменты на Python для выполнения научных вычислений, в том числе такие пакеты, как Scikit-Learn, SciPy, AstroPy, Altair, JAX и многие другие. Участвует в жизни обширного сообщества специалистов по обработке данных, разрабатывая и представляя доклады и учебные пособия по темам научных вычислений на различных конференциях в мире науки о данных.


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

» Оглавление
» Отрывок

По факту оплаты бумажной версии книги на e-mail высылается электронная книга.
Для Хаброжителей скидка 25% по купону — Python

© Habrahabr.ru