Pandas, более быстрый способ суммирования подгруппированных итогов данных в объединенный df в виде отдельных столбцов

#python #pandas #merge #pandas-groupby

#python #pandas #слияние #pandas-groupby

Вопрос:

У меня есть данные, которые я сгруппировал по двум столбцам и подвел промежуточный итог. Я использовал .loc для разделения дочерней группы и pd.merge для добавления каждой в виде столбца с итогами для родительской группы. Это не было безумным количеством ввода, поскольку дочерних групп было не так много, но я надеюсь найти более эффективный способ для будущих проектов. Мой код довольно простой, и у меня есть привычка делать все долго, но мне кажется, что для больших наборов данных должен быть более простой способ.

 import pandas as pd
data = {"Company":["a","b","c","b","a","c","a","a","b"], "Product":[3,2,2,1,4,4,3,2,1], "Qty":[2,4,8,1,8,3,6,4,5]}

#Create df and group by first two columns               
df = pd.DataFrame(data)
        
grouped_prod_df=df.groupby(["Company","Product"])
        
qty_sum= grouped_prod_df.sum()    
qty_sum_df =pd.DataFrame(qty_sum.reset_index())

# find total qtys of each product
product_1 = qty_sum_df.loc[qty_sum_df["Product"] == 1]
product_2 = qty_sum_df.loc[qty_sum_df["Product"] == 2] 
product_3 = qty_sum_df.loc[qty_sum_df["Product"] == 3]
product_4 = qty_sum_df.loc[qty_sum_df["Product"] == 4]        

product_1_df = pd.DataFrame(product_1)
product_1_df = product_1_df[["Company","Qty"]]
product_1_df = product_1_df.rename(columns={"Qty":"Product_1"})

product_2_df= pd.DataFrame(product_2)
product_2_df = product_2_df[["Company","Qty"]]
product_2_df = product_2_df.rename(columns={"Qty":"Product_2"})

product_3_df= pd.DataFrame(product_3)
product_3_df = product_3_df[["Company","Qty"]]
product_3_df = product_3_df.rename(columns={"Qty":"Product_3"})

product_4_df= pd.DataFrame(product_4)
product_4_df = product_4_df[["Company","Qty"]]
product_4_df = product_4_df.rename(columns={"Qty":"Product_4"})

#sum company grand totals    
company_df = df[["Company","Qty"]]
grouped_company_df=company_df.groupby(["Company"])
company_sum= grouped_company_df.sum()
company_sum_df = pd.DataFrame(company_sum)

#merge product totals in column next to grand total with product as column header and repeat for
#other columns
       
all_prod = pd.merge(company_sum_df, product_1_df, on="Company", how="left")
all_prod = pd.merge(all_prod, product_2_df, on="Company", how="left")
all_prod = pd.merge(all_prod, product_3_df, on="Company", how="left")
all_prod = pd.merge(all_prod, product_4_df, on="Company", how="left")

all_prod
 

РЕДАКТИРОВАТЬ: пытался сделать свой код более общим и в итоге не работал, но я исправил и протестировал его сейчас. Вывод должен быть следующим с количеством, показывающим общее количество всех продуктов по компаниям.

 Company Qty Product_1   Product_2   Product_3 Product_4
0   a   20  NaN 4   8.0 8.0
1   b   10  6.0 4   NaN NaN
2   c   11  NaN 8   NaN 3.0 
 

Любая помощь приветствуется.

Комментарии:

1. ваш общий код требует исправлений (возвращает ряд ошибок). Пожалуйста, опубликуйте ожидаемый результат, и мы сможем работать оттуда.

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

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

Ответ №1:

На самом простом уровне вам нужно только сделать:

 (
    df.groupby(["Company","Product"])
      .sum()
      .unstack(level='Product')['Qty']
      .assign(Qty=lambda df: df.sum(axis='columns'))
)
 

И это даст вам:

 Product    1    2    3    4   Qty
Company                          
a        NaN  4.0  8.0  8.0  20.0
b        6.0  4.0  NaN  NaN  10.0
c        NaN  8.0  NaN  3.0  11.0
 

Если имена столбцов действительно должны совпадать, вы можете переименовать их:

 (
    df.groupby(["Company","Product"])
      .sum()
      .unstack(level='Product')['Qty']
      .rename(columns=lambda c: f"Product_{c}")
      .assign(Qty=lambda df: df.sum(axis='columns'))
      .rename_axis(None, axis='columns')
)
 

И это дает вам:

          Product_1  Product_2  Product_3  Product_4   Qty
Company                                                  
a              NaN        4.0        8.0        8.0  20.0
b              6.0        4.0        NaN        NaN  10.0
c              NaN        8.0        NaN        3.0  11.0
 

Комментарии:

1. Спасибо! Это было именно то, что я искал.