Рубрики
Без рубрики

В режиме онлайн переименования агрегатов Pandas

Имена столбцов по умолчанию могут сосать. Вот быстрый способ улучшить их .. Теги с Python, Pandas, наукой данных.

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

import pandas as pd 
import numpy as np

iris = pd.read_csv('https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv')

iris.groupby('species').agg({
    'sepal_length': np.mean
}).round(2)
сетоса 5.01
вершина 5.94
Вирджина 6.59

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

iris.groupby('species').agg({
    'sepal_length': [np.mean]
}).round(2)
5.01 сетоса
5.94 вершина
6.59 Вирджина

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

Этот подход работает хорошо. Если вы хотите завершить многоиндекс для создания более доступных столбцов, вы можете использовать подход ConcateNation, вдохновленный Этот стек переполняет пост (Обратите внимание, что другие реализации аналогично используют .ravel () ):

df = iris.groupby('species').agg({
    'sepal_length': [np.mean]
}).round(2)
df.columns = ['_'.join(gp) for gp in df.columns.values]
df
сетоса 5.01
вершина 5.94
Вирджина 6.59

Обе эти решения имеют несколько непосредственных проблем:

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

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

Чтобы быть понятным: мы могли бы, очевидно, переименули любую из этих столбцов после возврата DataFrame, но в этом случае я хотел, чтобы решение, где я мог бы установить имена столбцов на лету.

Используя преимущества атрибута __name__

Если вы незнакомы, __name__ Атрибут – это то, что вы или кто-то другой, определяют в Python.

def this_function():
    pass 

print(this_function.__name__)

this_function

Мы можем изменить этот атрибут после его определения:

def this_function():
    pass 

this_function.__name__ = 'that.'

print(this_function.__name__)

это.

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

Возвращаясь к нашему заявлению, давайте рассмотрим следующую ситуацию:

def my_agg(x): 
    return (x/20).sum()

iris.groupby('species').agg({
    'sepal_length': [my_agg],
    'sepal_width': [my_agg]
}).round(2)
8.57 12.52 сетоса
6.92 14.84 вершина
7.44 16.47 Вирджина

Мы могли бы добавить строку, регулируя __name__ my_agg () Прежде чем мы начнем нашу агрегацию. Но что, если мы сможем переименовать функцию, поскольку мы были агрегированы? Подобно тому, как мы можем переименовывать столбцы в операторе SQL, так как мы определяем их.

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

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

def renamer(agg_func,desired_name):
    def return_func(x):
        return agg_func(x)
    return_func.__name__ = desired_name
    return return_func

Мы можем применить эту функцию за пределами нашего применения my_agg сбросить __name__ на лету:

iris.groupby('species').agg({
    'sepal_length': [renamer(my_agg,'Cool Name')],
    'sepal_width': [renamer(my_agg,'Better Name')]
}).round(2)
12.52 8.57 сетоса
14.84 6.92 вершина
16.47 7.44 Вирджина

Реалистичные примеры

Вот идеальный сценарий для использования этого решения:

from numpy import percentile

iris.groupby('species').agg({
    'sepal_length': [renamer(lambda x: percentile(x,25),'25th Percentile')],
    'sepal_width': [renamer(lambda x: percentile(x,75),'75th Percentile')]
}).round(2) 
сетоса 3.68 4.80
вершина 3.00 5.60
Вирджина 3.18 6.22

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

Чтобы сделать этот шаг дальше, мы можем включить имя столбца в строку RENAME и отбросить верхний уровень колонны Multiindex:

from numpy import percentile

df3 = iris.groupby('species').agg({
    'sepal_length': [renamer(lambda x: percentile(x,25),'Length 25th Percentile')],
    'sepal_width': [renamer(lambda x: percentile(x,75),'Width 75th Percentile')]
}).round(2) 

df3.columns = df3.columns.droplevel()

df3
сетоса 3.68 4.80
вершина 3.00 5.60
Вирджина 3.18 6.22

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

Оригинал: “https://dev.to/rpm4real/in-line-renaming-of-pandas-aggregates-3i6n”