Назначить, сопоставить, запросить и разнести; самые горячие методы в городе
Введение
Независимо от того, являетесь ли вы специалистом по данным, инженером данных, аналитиком данных или экспертом по машинному обучению, вам придется работать с табличными данными. Если вы пользователь Python, для работы с табличными данными вам подойдет библиотека Pandas 🐼. Из-за того, что табличные данные вездесущи, Pandas, вероятно, является одной из наиболее часто используемых библиотек среди всех нас, занимающихся данными.
Pandas предлагает многофункциональный API для преобразования данных и извлечения ценной информации. К сожалению, многие люди, в том числе и я из прошлого, не используют в полной мере все предоставляемые им функции. Это часто приводит к громоздкому, чрезмерно сложному и низкопроизводительному коду Pandas 😔.
Я хочу внести свой вклад в это и помочь вам повысить уровень ваших знаний о Pandas, чтобы ваш будущий код был более приятным для чтения и более производительным 💪! С этой целью в этом посте я познакомлю вас с четырьмя различными функциями Pandas, а именно assign, map, query,
и exlpode
. Осваивая их, мы делаем шаг в правильном направлении, учитывая ясность и производительность!
Вы готовы? Давайте начнем!
Фантастическая четверка
Прежде чем мы рассмотрим конкретную функциональность Pandas, нам сначала нужны данные для работы. В следующих примерах я использую знаменитый набор данных Iris. Если вы не хотите устанавливать специальную библиотеку только для получения данных, просто введите data = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')
, и все будет хорошо.
Напоследок, прежде чем мы начнем, большинство следующих примеров могут не иметь большого смысла с точки зрения содержания, но проясняют особенности каждой функции.
Все готово? Давайте начнем!
Назначать
Первый метод, который мы рассмотрим, — это метод assign
. Этот метод позволяет добавлять столбцы в DataFrame. Код лучше всего объясняется с помощью кода, поэтому вот пример
Что мы здесь делали? Это довольно легко! Мы создали два новых столбца, используя assign
, передав имена этих столбцов в качестве аргументов ключевого слова в функцию и назначив им значения, которые должны содержать результирующие столбцы. Как видите, для назначения фактических значений у вас есть три разных варианта.
- Вы можете использовать скалярное значение, которое устанавливает для всех записей нового столбца это значение.
- Вы можете использовать массив или серию, что приведет к тому, что этот массив будет использоваться в качестве значений столбца. Этот массив должен иметь ту же длину, что и DataFrame, для которого вызывается метод assign.
- Вы можете использовать функцию или, в более общем случае, вызываемый, который принимает DataFrame в качестве единственного входа и возвращает скаляр или ряд. Когда серия возвращается, она должна иметь ту же длину, что и входной кадр данных.
Что хорошо в этой опции, так это то, что входной DataFrame для вызываемого объекта является тем, для которого был вызван метод assign. Что это означает и почему это аккуратно? Так, например, если вы сначала выполняетеgroupby
с агрегатами, а затем вызываетеassign
, вы можете использовать агрегаты в своей функции для вычисления значений нового столбца. Это то, что вы также видите в примере кода. Для меня это действительно компактно, но при этом выразительно.
Как показывает пример, можно создать несколько столбцов одним вызовом assign. Поэтому вам просто нужно передать несколько аргументов ключевого слова; по одному для каждого создаваемого столбца. Что здорово, так это то, что более поздние назначения могут использовать ранее созданные или измененные столбцы. В качестве простого примера вы можете запустить df.assign(x_axis=np.random.rand(len(df)), y_axis=lambda in_: in_.x_axis ** 2)
, где второе назначение использует столбец, созданный в первом.
Наконец, я хочу упомянуть небольшой трюк, который позволяет вам создавать столбцы, у которых нет правильных имен переменных Python. Для этого вам нужно создать словарь с именами столбцов в качестве ключей и операциями присваивания в качестве значений и передать этот распакованный словарь в метод assign 😵 . Это звучит сложнее, чем есть на самом деле. Чтобы было понятнее, давайте закончим этот абзац примером, в котором мы создаем два новых столбца с недопустимыми именами переменных Python df.assign(**{'X-Axis': np.random.rand(len(df)), 'Y-Axis': lambda in_: in_['X-Axis'] ** 2})
.
карта
Еще одна удобная функция, которую можно вызывать для объектов серии Pandas, — это функция map
. С помощью map
вы можете заменить каждое значение в серии другим значением. Вот простой пример, где я провел пробную проверку, используя вызов функции assign 😃
В этом коде мы используем map
, чтобы условно установить записи столбца to_big_to_small
в две разные строки. Кроме того, мы используем map
, чтобы добавить новый столбец inverted_name
, содержащий инвертированное название каждого вида. Конечно, этот пример не очень полезен с точки зрения содержания, хотя он иллюстрирует два варианта того, как вы можете вызвать map
.
- Вы передаете тип коллекции, такой как словарь или серия, в функцию карты. Что произойдет, так это то, что значения вашей серии будут использоваться в качестве ключей для поиска соответствующих значений из данной коллекции. Любое значение, не являющееся частью коллекции, будет сопоставлено с
NaN
илиNone
. Чтобы сделать это немного менее сухим, я даю вам другую игрушку examplepd.Series(range(3)).map({1:'medium', 2:'high'})
. Когда вы выполняете это, это приводит к серии с записями[NaN, 'medium', 'high']
. - Вы передаете функцию или вызываемый объект
map
, который принимает скаляр в качестве входных данных и возвращает скалярное значение. Когда вы это сделаете, эта функция будет применяться поэлементно к каждой записи вашей серии, используя каждое значение в качестве входного аргумента. Это то, что вы видите в строке 6, где мы инвертируем названия видов цветов.
В качестве рекомендации: не используйте этот подход для выполнения каких-либо математических операций. Это можно сделать гораздо эффективнее, если применить его непосредственно к серии, так как затем используется векторизация NumPy сзади.
Наконец, если вы хотите выполнять поэлементные операции со всем DataFrame вместо Series, вы можете использовать функцию applymap
, которая ведет себя так же, как map
.
Запрос
После того, как мы рассмотрели функции для работы с контейнерами данных, давайте посмотрим, как мы можем извлекать данные из DataFrames. Одной из полезных функций для извлечения строк является функция query
. Конечно, мы начнем с некоторого кода
Что мы здесь делали? Мы выбрали подмножество всех строк, используя выражение логического фильтра, которое мы передали в query
. Выражение фильтра — это строка, которая может содержать различные логические сравнения, такие как >,<,>=,<=,!=,==,
и другие, для сравнения столбцов вашего DataFrame. Затем query
функция оценивает это выражение и возвращает все строки, в которых выражение оценивается как True
.
В выражении вы ссылаетесь на столбцы, используя их имена. Чтобы сослаться на имена столбцов, которые не являются допустимыми именами переменных Python, вы должны окружить их обратными кавычками, что вы можете увидеть в строке 6.
Если вы хотите сослаться на какую-либо переменную из внешней области, вы можете сделать это, добавив к их имени префикс @, как вы можете видеть для переменной length_th
.
Важно отметить, что вы можете выполнять те же действия с помощью операций индексирования. Однако при использовании query
результирующий код становится менее подробным и более приятным для чтения.
Взорваться
Последняя функция, которую мы рассмотрим в этом посте, — explode
, очевидно, с самым драматичным названием 💣. Чем хороша эта функция? Функция explode
полезна, когда записи столбца имеют вид списка. В частности, это позволяет вам создавать новую строку для каждой записи этих списков. При этом будут реплицированы все остальные записи строки, а также индекс. Вы вызываете его, передавая имя столбца, содержащего спископодобные объекты. Как всегда, давайте воспользуемся примером, чтобы сделать это более осязаемым.
В данном примере мы сначала создаем DataFrame с 3 строками. Записи столбца a
изначально представляют собой списки длин 1, 2 и 4 соответственно. После развертывания DataFrame в столбце a
результирующий DataFrame имеет размер 1+2+4 = 7. Я могу порекомендовать скопировать пример и поиграть с ним.
Теперь вы можете понять, почему эта функция называется взорваться; при его использовании размер вашего DataFrame может резко увеличиться. Если отойти от примера с маленькой игрушкой, предположим, что у вас есть DataFrame с 500_000 строк и есть столбец, содержащий списки из 100 записей. Когда вы вызываете взрыв для этого столбца, вы получаете 50_000_000 строк. Это может быть проблемой. Поэтому мой совет: Используйте его с осторожностью!
Важно знать, что разнесение не меняет тип данных столбца, к которому оно применяется. Поскольку Pandas хранит спископодобные значения с типом объекта, это означает, что после разнесения столбца он по-прежнему будет иметь тип объекта. Если вы хотите изменить это, вы должны сделать это явно, используя метод astype
. Это то, что вы также видите в примере кода.
Заворачивать
В этом посте мы рассмотрели четыре различные функции Pandas для работы с DataFrames и Series. Когда вы начнете использовать эти функции, ваш будущий код будет более элегантным, читабельным и эффективным. Поверьте мне. И если вы действительно хотите, вы также можете использовать эти функции, чтобы произвести впечатление на своих коллег, просматривающих ваш код 😎.
Спасибо, что подписались на этот пост. Как всегда, не стесняйтесь обращаться ко мне или подписываться на меня для вопросов, комментариев или предложений либо здесь, на среде, либо через LinkedIn.