Groupby 和 Value Counting 类别

Groupby and Value Counting categories

我有一个数据框,其中每一行代表产品销售。这些链接到订单号(可以有多个产品),每个都有价格和颜色。我需要按订单号对这些进行分组,并获得一个列来计算该订单行的每种产品类型。

df = pd.DataFrame({'Product': ['X','X','Y','X','Y','W','W','Z','W','X'],
                   'Order #': ['01','01','02','03','03','03','04','05','05','05'],
                   'Price': [100,100,650,50,700,3000,2500,10,2500,150],
                   'Color': ['RED','BLUE','RED','RED','BLUE','GREEN','RED','BLUE','BLUE','GREEN']})

'regular' 使用计数的分组表达式不是我要找的。

# Aggregate 
ag_func = {'Product Quant.': pd.NamedAgg(column='Product', aggfunc='count'),
           'Total Price': pd.NamedAgg(column='Price', aggfunc='sum'),
           'Color Quant.': pd.NamedAgg(column='Color', aggfunc='count')}

# Test
test = df.groupby(pd.Grouper(key='Order #')).agg(**ag_func).reset_index()

我可以通过对每个类别(产品/颜色)使用 get_dummies 然后使用 sum 聚合函数来解决这个问题。这对于较小的数据集来说很好,但在我的真实世界中有几十个类别,并且新的集合一起出现在不同的类别中......

这是我想出的'solution'

# Dummy 
df_dummy = pd.get_dummies(df, prefix='Type', prefix_sep=': ', columns=['Product', 'Color'])

ag_func2 = {'Product Quant.': pd.NamedAgg(column='Order #', aggfunc='count'),
            'W total': pd.NamedAgg(column='Type: W', aggfunc='sum'),
            'X total': pd.NamedAgg(column='Type: X', aggfunc='sum'),
            'Y total': pd.NamedAgg(column='Type: Y', aggfunc='sum'),
            'Z total': pd.NamedAgg(column='Type: Z', aggfunc='sum'),
            'Total Price': pd.NamedAgg(column='Price', aggfunc='sum'),
            'Color BLUE': pd.NamedAgg(column='Type: BLUE', aggfunc='sum'),
            'Color GREEN': pd.NamedAgg(column='Type: GREEN', aggfunc='sum'),
            'Color RED': pd.NamedAgg(column='Type: RED', aggfunc='sum')}

solution = df_dummy.groupby(pd.Grouper(key='Order #')).agg(**ag_func2).reset_index()

注意第 1 行的 2 个 X 产品和第 5 行的 2 个蓝色产品。这种行为是我所需要的,但这对于在多个数据集上重复使用来说太复杂了。我尝试使用 pivot_tables 但没有成功。

我是否应该只定义一个函数来遍历分类列,虚拟化这些列,然后使用虚拟变量的总和聚合按一组列分组?

谢谢

IIUC 你的问题是为所有创建的假人输入所有 pd.NamedAgg,也许你可以单独进行操作。先创建组对象,然后concat对不同的列进行不同的操作

gr = df.groupby('Order #')
res = pd.concat([
    # equivalent to count the orders
    gr.size().to_frame(name='Product Quant.'),
    # equivalent to dummy then sum the dummy product columns
    gr['Product'].value_counts().unstack(fill_value=0).add_suffix(' Total'),
    # sum the price to get the total
    gr['Price'].sum().to_frame(name='Total Price'),
    # equivalent to sum the dummy color columns
    gr['Color'].value_counts().unstack(fill_value=0).add_prefix('Color ')
], axis=1)

print(res)
         Product Quant.  W Total  X Total  Y Total  Z Total  Total Price  \
Order #                                                                    
01                    2        0        2        0        0          200   
02                    1        0        0        1        0          650   
03                    3        1        1        1        0         3750   
04                    1        1        0        0        0         2500   
05                    3        1        1        0        1         2660   

         Color BLUE  Color GREEN  Color RED  
Order #                                      
01                1            0          1  
02                0            0          1  
03                1            1          1  
04                0            0          1  
05                2            1          0  

所以基本上在这种情况下,groupby.value_counts.unstack 等同于 get_dummies.groupby.sum

为了进一步使用,而不是

df.groupby('Order #')['Product'].value_counts().unstack(fill_value=0)

您可以执行 pivot_table 以获得相同的结果:

df.pivot_table(index='Order #', columns='Product', aggfunc='size', fill_value=0)