Группировка разных столбцов с разной агрегацией с cumsum с другим набором данных

У меня есть фрейм данных, отсортированный по дате и времени как: df1:

ID    Date     A_sum  A_count   B_sum   B_count  A_last  B_last  
abc   01/jan    26       2        25       2       0      0
xyz   01/jan    54       3        45       3       4      6

df2:

ID     Date     Time      A         B
abc   02/jan     11       10        10 
abc   02/jan     12       14        13
xyz   02/jan      1       26        24
xyz   02/jan      2       18        15
xyz   02/jan      3       20        16

Я хочу добавить эти два dfs к идентификатору и хочу обновить df2 в качестве вывода как:

ID    Date     A_sum             A_count    B_sum   B_count  A_last  B_last  
abc   02/jan  50 #26+10+14        4 #2+2     48       4      14      13
xyz   02/jan  118 #54+26+18+20    6 #3+3    100       6      20      16

Таким образом, он берет предыдущее значение столбцов из df1 и добавляет его в df2


person naina    schedule 07.06.2021    source источник
comment
Дата не важна?   -  person crayxt    schedule 07.06.2021
comment
нет это не так...   -  person naina    schedule 07.06.2021


Ответы (5)


Вы можете использовать .groupby() и < em> _2 _, чтобы преобразовать df2 в тот же макет, что и df1, а затем добавить результат в df1, за которым следует еще один раунд groupby() и агрегирование, как показано ниже:

df3 = (df2.groupby(['ID', 'Date'], as_index=False, sort=False)
          .agg(A_sum=('A', 'sum'), A_count=('A', 'count'), 
               B_sum=('B', 'sum'), B_count=('A', 'count'), 
               A_last=('A', 'last'), B_last=('B', 'last'))
      )

df_out = (df1.append(df3)
             .groupby('ID', as_index=False)
             .agg({'Date': 'last', 
                   'A_sum': 'sum', 'A_count': 'sum', 
                   'B_sum': 'sum', 'B_count': 'sum', 
                   'A_last': 'last', 'B_last': 'last'})
         )

Результат:

print(df_out)


    ID    Date  A_sum  A_count  B_sum  B_count  A_last  B_last
0  abc  02/jan     50        4     48        4      14      13
1  xyz  02/jan    118        6    100        6      20      16
person SeaBean    schedule 07.06.2021
comment
У меня 40 столбцов, и это дает синтаксическую ошибку, поскольку я использовал для i в столбцах: df3 = (df2.groupby (['ID', 'Date'], as_index = False) .agg (i + '_ Num' = (i, 'sum'), i + '_ denom' = (i, 'count'), i + '_ last' = (i, 'last')) final = (df1.append (df3) .groupby ('ID', as_index = False). ) .agg ({i + '_ Num': 'sum', i + '_ denom': 'sum', i + '_ Last': 'last'}))) - person naina; 07.06.2021
comment
я имя столбца - person naina; 07.06.2021
comment
@naina Если вы хотите использовать его в цикле для всех столбцов, тогда вы не можете использовать этот синтаксис. Поскольку для именованной агрегации это имя переменной слева от = вместо строки. Кроме того, тогда вы получите дискретные результаты агрегирования, которые будет сложно использовать. - person SeaBean; 07.06.2021
comment
@naina В этом случае вам может потребоваться вернуться к решению определения столбцов один за другим, как и другое решение. Извините, у меня сейчас срочные дела. Возможно, вам придется попросить помощи у другого автора решения, как изменить его / ее решение в соответствии с вашими потребностями. - person SeaBean; 07.06.2021

Слегка длинный путь

>>> import pandas as pd
>>> from io import StringIO
>>>
>>> df1 = pd.read_csv(StringIO("""ID    Date     A_sum  A_count   B_sum   B_count  A_last  B_last
... abc   01/jan    26       2        25       2       0      0
... xyz   01/jan    54       3        45       3       4      6"""), sep="\s+")
>>>
>>>
>>> df2 = pd.read_csv(StringIO("""ID     Date     Time      A         B
... abc   02/jan     11       10        10
... abc   02/jan     12       14        13
... xyz   02/jan      1       26        24
... xyz   02/jan      2       18        15
... xyz   02/jan      3       20        16"""), sep="\s+")
>>>
>>>
>>>
>>> df2["A_sum"]   = df2.groupby("ID")["A"].transform("sum")
>>> df2["A_count"] = df2.groupby("ID")["A"].transform("count")
>>> df2["A_last"]  = df2.groupby("ID")["A"].transform("last")
>>>
>>> df2["B_sum"]   = df2.groupby("ID")["B"].transform("sum")
>>> df2["B_count"] = df2.groupby("ID")["B"].transform("count")
>>> df2["B_last"]  = df2.groupby("ID")["B"].transform("last")
>>>
>>> del df2["Time"]
>>> del df2["A"]
>>> del df2["B"]
>>>
>>> df2 = df2.groupby("ID").apply(lambda x: x.iloc[-1])
>>>
>>> df3 = pd.concat([df1, df2])
>>>
>>> df3.groupby('ID').agg({"Date": 'last', 'A_sum': 'sum', 'B_sum' : 'sum', 'A_count': 'sum', 'B_count': 'sum', 'A_last': 'last', 'B_last': 'last'})
       Date  A_sum  B_sum  A_count  B_count  A_last  B_last
ID
abc  02/jan     50     48        4        4      14      13
xyz  02/jan    118    100        6        6      20      16
person crayxt    schedule 07.06.2021

Вы можете объединить оба df, а затем использовать groupby:

cols = df1.columns
df1 = df1[['ID','Date','A_sum', 'B_sum']]
df2 = df2.drop('Time', 1)
df1.columns = df2.columns
merged_df  = pd.concat([df1, df2]).groupby(['ID']).agg({'A' : [sum , 'count', 'last'], 'B' : [sum , 'count', 'last'], 'Date': 'last'})
merged_df.columns = merged_df.columns.map('_'.join)

ВЫХОД:

     A_sum  A_count  A_last  B_sum  B_count  B_last Date_last
ID                                                           
abc     50        3      14     48        3      13    02/jan
xyz    118        4      20    100        4      16    02/jan
person Nk03    schedule 07.06.2021
comment
A_count должно быть 2 + 2 = 4,3 + 3 = 6 - person naina; 07.06.2021

Использовать:

#https://stackoverflow.com/a/67800033/2901002
cols = ['A','B']

df11 = df2.groupby(['ID','Date'])[cols].agg(['sum','count'])
df11.columns = df11.columns.map(lambda x: f'{x[0]}_{x[1]}')

df22 = df2.groupby(['ID','Date'])[cols].last().add_suffix('_last')

df3 = pd.concat([df11, df22], axis=1).reset_index(level=1)
print (df3)
       Date  A_sum  A_count  B_sum  B_count  A_last  B_last
ID                                                         
abc  02/jan     24        2     23        2      14      13
xyz  02/jan     64        3     55        3      20      16

Отфильтровать только столбцы из df1 для суммы:

df33 = df1.filter(regex='ID|_sum|count').set_index('ID')
print (df33)
     A_sum  A_count  B_sum  B_count
ID                                 
abc     26        2     25        2
xyz     54        3     45        3

Объединитесь вместе, sum и при необходимости назначьте отсутствующий date:

df = pd.concat([df3, df33]).sum(level=0).astype(int).assign(Date = df3['Date']).set_index('Date', append=True).reset_index()
print (df)
    ID    Date  A_sum  A_count  B_sum  B_count  A_last  B_last
0  abc  02/jan     50        4     48        4      14      13
1  xyz  02/jan    118        6    100        6      20      16
person jezrael    schedule 07.06.2021
comment
я не могу понять эту строку .. df33 = df1.filter (regex = 'ID | _sum | count'). set_index ('ID') фактические имена: A_Num, A_denom, B_Num, B_denom - person naina; 07.06.2021
comment
@naina - фильтрует только все столбцы с _sum, _count или ID susbtrings - person jezrael; 07.06.2021
comment
@naina - Потому что только эти столбцы важны для суммирования df3 - person jezrael; 07.06.2021
comment
df33 = df2.filter (regex = 'ID | _Num | _denom'). set_index ('ID') будет использовать мой код, верно? - person naina; 07.06.2021
comment
@naina - да, именно так. - person jezrael; 07.06.2021
comment
столбцы sum и count не выводятся - person naina; 07.06.2021
comment
Я не могу получить сумму и подсчитать столбцы в выводе. Он просто возвращает столбцы _Last - person naina; 08.06.2021
comment
@naina - прости, встреча. Итак, df33 = df1.filter(regex='ID|_sum|count').set_index('ID') у вас не работает? есть разные названия столбцов, подобные упомянутым в вопросе? - person jezrael; 08.06.2021
comment
Нет df = pd.concat ([df3, df33]). Sum (level = 0) .astype (int) .assign (Date = df3 ['Date']). Set_index ('Date', append = True) .reset_index () это не работает .. я отправил тебе мой код в сообщении - person naina; 08.06.2021
comment
@naina - Что такое ошибка? - person jezrael; 08.06.2021
comment
ошибки не возникает ... последняя строка кода дает только столбцы, заканчивающиеся на _Last вместе с ID и DATE - person naina; 08.06.2021
comment
@naina - Если использовать pd.concat([df3, df33]).sum(level=0), то ожидается выход? следующий код для столбца appedn date - person jezrael; 08.06.2021
comment
но все же в конце идут только id, дата и столбцы последнего значения - person naina; 08.06.2021
comment
@naina - Хорошо, значит print (df33) вернуть ID и все count и все sum столбцы? - person jezrael; 08.06.2021
comment
они идут ... если я jz concat df3, df33, тогда я также получаю все столбцы, но поскольку у меня есть постановка задачи о добавлении суммы и подсчета, этого не происходит - person naina; 08.06.2021

person    schedule
comment
Если это пояснение к вашему вопросу, отредактируйте сам вопрос и добавьте его туда. Если это решение, пожалуйста, четко укажите это здесь. - person joanis; 07.06.2021
comment
Воспользуйтесь ссылкой редактирования вашего вопроса, чтобы добавить дополнительную информацию. Кнопку «Ответить» следует использовать только для полных ответов на вопрос. - Из отзыва - person Bradley Mackey; 07.06.2021