Назначить, сопоставить, запросить и разнести; самые горячие методы в городе

Введение

Независимо от того, являетесь ли вы специалистом по данным, инженером данных, аналитиком данных или экспертом по машинному обучению, вам придется работать с табличными данными. Если вы пользователь 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, передав имена этих столбцов в качестве аргументов ключевого слова в функцию и назначив им значения, которые должны содержать результирующие столбцы. Как видите, для назначения фактических значений у вас есть три разных варианта.

  1. Вы можете использовать скалярное значение, которое устанавливает для всех записей нового столбца это значение.
  2. Вы можете использовать массив или серию, что приведет к тому, что этот массив будет использоваться в качестве значений столбца. Этот массив должен иметь ту же длину, что и DataFrame, для которого вызывается метод assign.
  3. Вы можете использовать функцию или, в более общем случае, вызываемый, который принимает 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.

  1. Вы передаете тип коллекции, такой как словарь или серия, в функцию карты. Что произойдет, так это то, что значения вашей серии будут использоваться в качестве ключей для поиска соответствующих значений из данной коллекции. Любое значение, не являющееся частью коллекции, будет сопоставлено с NaN или None. Чтобы сделать это немного менее сухим, я даю вам другую игрушку examplepd.Series(range(3)).map({1:'medium', 2:'high'}) . Когда вы выполняете это, это приводит к серии с записями [NaN, 'medium', 'high'] .
  2. Вы передаете функцию или вызываемый объект 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.