Множественные группировки и групповые агрегации с использованием Python Pandas

У меня есть набор данных, который очень похож на данные ниже.

  1. Я хотел бы создать две группы, используя значения в столбце sku.

    группа1 - новые и

    группа2 - старая

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

данные:

     rack   sku    used    free     total   date
     a      old     1       4       5       11/1/2020
     b      old     1       4       5       11/1/2020
     c      old     1       4       5       11/1/2020
     d      new     2       1       3       11/1/2020
     e      new     2       1       3       11/1/2020
     f      old     1       1       2       11/1/2020
     g      old     1       1       2       11/1/2020
     e      new     2       2       4       11/1/2020
     d      new     2       2       4       11/1/2020

Желаемый результат

        used    free    total   date

        2       1.5     3.5     11/1/2020
        2       1.5     3.5     11/1/2020
        5       14      19      11/1/2020

Мы получаем этот результат выше, потому что:

group1- new имеет две группы: d и e Среднее значение используемого d равно 2, среднее значение свободного d равно 1,5, а среднее значение общего d равно 3,5.

Среднее значение используемого е равно 2, среднее значение свободного е равно 1,5, а среднее значение общего количества е равно 3,5.

group2- old просто берет сумму из которых используется 5, бесплатно 14 и всего 19.

Вот как выглядят данные после группировки:

id  group   used    free    total   date
d   new     2       1       3       11/1/2020
d   new     2       2       4       11/1/2020
e   new     2       1       3       11/1/2020
e   new     2       2       4       11/1/2020
a   old     1       4       5       11/1/2020
b   old     1       4       5       11/1/2020
c   old     1       4       5       11/1/2020
f   old     1       1       2       11/1/2020
g   old     1       1       2       11/1/2020

Вот что я делаю:

    new = df[df.sku.str.contains('|'.df(['new']), na = False)]

    old = df[df.sku.str.contains('|'.df(['old']), na = False)] 

set = jdf.groupby('rack').agg({'used': 'mean', 'free': 'mean', 
                                           'total': 'mean'}).sum().to_frame().T

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

Привет, я обновил пост. group1 новые должны быть сгруппированы по стойкам, а затем нужно взять среднее значение для всех 3 столбцов (используется, свободен, всего)

Lynn 10.12.2020 08:21

Как проходит обработка date ?

jezrael 10.12.2020 08:23

Интересно, можно ли указать дату?

Lynn 10.12.2020 08:24

хм, можно использовать .groupby(['rack', 'date']) ?

jezrael 10.12.2020 08:26
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
75
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете фильтровать по условиям с помощью Series.isin для совпадения нескольких sku и для старых несовпадающих значений с помощью ~ для инвертированной маски:

mask = df.sku.isin(['new','foo','foo1','foo3'])
new = df[mask]

old = df[~mask] 

Затем агрегируйте mean и для всех остальных значений используйте sum только для числовых столбцов:

df = (new.groupby('rack').mean()
         .append(old.select_dtypes(np.number).sum().to_frame('old').T)
         .rename_axis('col')
         .reset_index())

print (df)
   col  backup  free  total
0    d     2.0   1.5    3.5
1    e     2.0   1.5    3.5
2  old     5.0  14.0   19.0

Если возможно группировка по rack и date решению немного изменена - для старых значений используется первое значение date:

mask = df.sku.isin(['new','foo','foo1','foo3'])
new = df[mask]

old = df[~mask] 

df = (new.groupby(['rack', 'date']).mean()
         .append(old.select_dtypes(np.number).sum().to_frame(('old', old['date'].iat[0])).T)
         .reset_index())

print (df)
  rack       date  backup  free  total
0    d  11/1/2020     2.0   1.5    3.5
1    e  11/1/2020     2.0   1.5    3.5
2  old  11/1/2020     5.0  14.0   19.0

хорошо, спасибо @jezrael - мне интересно, могу ли я исключить столбец d, e, old?

Lynn 10.12.2020 08:23

@Lynnette - конечно, добавь .rename_axis('col').reset_index()

jezrael 10.12.2020 08:24

Привет @jezrael, что, если мне нужно отфильтровать несколько строк, а не только «новые», могу ли я сделать: mask = df.sku == «новые», «foo», «foo1», «foo3» ??

Lynn 10.12.2020 08:26

@Lynnette - Используй mask = df.sku.isin(['new','foo','foo1','foo3'])

jezrael 10.12.2020 08:27

хорошо, большое спасибо за помощь - сейчас попробую

Lynn 10.12.2020 08:28

могу ли я использовать это, если столбец СОДЕРЖИТ: df.sku.str.contains(['new','foo', 'foo1', 'foo4'])????

Lynn 10.12.2020 08:40

@Lynnette - тестирует подстроки, так что нужно df.sku.str.contains('|'.join(['new','foo', 'foo1', 'foo4']))

jezrael 10.12.2020 08:41

@Lynnette - Если нет таких подстрок, как new1, new2, foo569, то проверьте, работает ли isin хорошо

jezrael 10.12.2020 08:42

Привет @jezrael, он говорит: ValueError: невозможно маскировать небулевым массивом, содержащим значения NA / NaN, могу ли я использовать isna ??

Lynn 10.12.2020 08:47

@Линнет - тогда df.sku.str.contains('|'.join(['new','foo', 'foo1', 'foo4']), na=False)

jezrael 10.12.2020 08:47

Вы можете сначала groupby по 'sku'. Затем вы можете получить целевую группу с помощью get_group, снова groupby и подсчитать итог. Например, среднее значение для 'new':

g = df.groupby('sku')
g.get_group('new').groupby('rack').mean()

Выход:

      used  free  total
rack                   
d      2.0   1.5    3.5
e      2.0   1.5    3.5

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

# Define last group for suming
last_grp = 'old'
# Calculate the mean by rack to all groups but last one
out = df.query('sku!=@last_grp').groupby(['sku','rack']).mean()
# Add sum from last group to df
out.loc[(last_grp, ''),:] = df.query('sku==@last_grp').select_dtypes(np.number).sum()
# Add date back to df (if more than one date, it'll be concatenated with comma)
out['date'] = ','.join(df.date.unique())

Выход:

          used  free  total       date
sku rack                              
new d      2.0   1.5    3.5  11/1/2020
    e      2.0   1.5    3.5  11/1/2020
old        5.0  14.0   19.0  11/1/2020

Примечание. Если вы не хотите суммировать все группы, вам нужно заменить df.query('sku!=@last_grp') на df[df.sku.isin(target_grps)], где target_grps означает ваши целевые группы (например, «новый», «foo», «foo2»).

Привет @Caina, что, если у меня есть несколько строк для фильтрации - скажем, «new», «foo1», «foo2»?

Lynn 10.12.2020 08:33

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

Cainã Max Couto-Silva 10.12.2020 08:37

Привет @Lynnette, кажется, у тебя уже есть очень хороший ответ. Я пишу этот комментарий только для того, чтобы заметить, что я также обновил ответ с помощью масштабируемого подхода. Лучший!

Cainã Max Couto-Silva 10.12.2020 09:18

Другие вопросы по теме