使用Python的多个分组和groupby聚合

使用Python的多个分组和groupby聚合,python,pandas,numpy,Python,Pandas,Numpy,我有一个看起来与下面数据非常相似的数据集 我想使用sku列中的值创建两个组 第1组-新& 第2组-旧 在group1-new中,我想按机架分组,取每个分组机架的平均值,并对group1-old中的所有内容求和 数据: 期望的结果 used free total date 2 1.5 3.5 11/1/2020 2 1.5 3.5 11/1/2020 5

我有一个看起来与下面数据非常相似的数据集

  • 我想使用sku列中的值创建两个组

    第1组-新&

    第2组-旧

  • 在group1-new中,我想按机架分组,取每个分组机架的平均值,并对group1-old中的所有内容求和

  • 数据:

    期望的结果

            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
    
    我们得到上述结果是因为

    第1组-新建有两组:de 使用d的平均值为2,无d的平均值为1.5,总计d的平均值为3.5

    使用e的平均值为2,无e的平均值为1.5,总计e的平均值为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
    
    我只是不知道如何把这些放在一起创建新的数据帧。
    非常感谢您的建议。

    您可以通过条件筛选多个
    sku
    的匹配值,并通过
    ~
    的反向掩码筛选旧的所有不匹配值:

    mask = df.sku.isin(['new','foo','foo1','foo3'])
    new = df[mask]
    
    old = df[~mask] 
    
    然后聚合
    平均值
    ,对于所有其他值,仅对数值列使用
    总和

    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
    
    如果可能,按
    机架
    日期
    分组解决方案有点变化-对于旧值,首先使用
    日期
    值:

    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
    

    对于多个
    sku
    的匹配,您可以根据条件进行过滤;对于反转遮罩的
    ~
    的匹配,您可以根据条件过滤旧的所有不匹配值:

    mask = df.sku.isin(['new','foo','foo1','foo3'])
    new = df[mask]
    
    old = df[~mask] 
    
    然后聚合
    平均值
    ,对于所有其他值,仅对数值列使用
    总和

    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
    
    如果可能,按
    机架
    日期
    分组解决方案有点变化-对于旧值,首先使用
    日期
    值:

    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
    

    您可以首先通过
    '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
    
              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
    

    您可以首先通过
    '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
    
              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
    

    除最后一组(即总和)外,所有组均采用机架平均值的方法:

    #定义消费的最后一组
    last_grp=‘old’
    #计算除最后一组外所有组的机架平均值
    out=df.query('sku!=@last_grp').groupby(['sku','rack']).mean()
    #将最后一组的总和添加到df
    out.loc[(last\u grp',,:]=df.query('sku==@last\u grp')。选择数据类型(np.number).sum()
    #将日期添加回df(如果有多个日期,将用逗号连接)
    out['date']=','.join(df.date.unique())
    
    输出:

          used  free  total
    rack                   
    d      2.0   1.5    3.5
    e      2.0   1.5    3.5
    
              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\u grp')
    替换为
    df[df.sku.isin(target\u grps)]
    ,其中
    target\u grps
    代表您的目标组(例如“new”、“foo”、“foo2”)。

    将机架平均值用于除最后一组以外的所有组(金额如下):

    #定义消费的最后一组
    last_grp=‘old’
    #计算除最后一组外所有组的机架平均值
    out=df.query('sku!=@last_grp').groupby(['sku','rack']).mean()
    #将最后一组的总和添加到df
    out.loc[(last\u grp',,:]=df.query('sku==@last\u grp')。选择数据类型(np.number).sum()
    #将日期添加回df(如果有多个日期,将用逗号连接)
    out['date']=','.join(df.date.unique())
    
    输出:

          used  free  total
    rack                   
    d      2.0   1.5    3.5
    e      2.0   1.5    3.5
    
              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\u grp')
    替换为
    df[df.sku.isin(target\u grps)]
    其中
    target\u grps
    代表您的目标组(例如“新”、“foo”、“foo2”).

    Hi我更新了帖子。group1 new应该按机架分组,然后对所有3列(已用、免费、总计)进行平均。处理
    日期的方式如何?我想知道是否可以包括日期?嗯,是否可以使用
    。groupby(['rack',date']))
    ?您好,我更新了帖子。group1 new应该按机架分组,然后对所有3列(已用、免费、总计)进行平均处理
    日期是如何处理的
    ?我想知道是否可以包括日期?嗯,是否可能使用
    。groupby(['rack',date'])
    ?@Lynnette-当然,添加
    。重命名轴('col')。重置索引()
    @Lynnette-it测试子字符串,所以需要
    df.sku.str.contains('.|'.join(['new','foo','foo1','foo3'])
    @Lynnette-如果不是像
    new1
    new2
    foo569
    这样的子字符串,则通过
    isin
    工作进行测试well@Lynnette-然后
    df.sku.str.contains('|'.join(['new','foo','foo1','foo4']),na=False)
    @Lynnette-当然,添加
    。重命名轴('col')。重置索引()
    @Lynnette-it测试子字符串,所以需要
    df.sku.str.contains('.|'.join(['new','foo','foo1','foo3'])
    @Lynnette-如果不是像
    new1
    new2
    foo569
    这样的子字符串,则通过
    isin
    工作进行测试well@Lynnette-then
    df.sku.str.contains('|'.join(['new','foo','foo1','foo4']),na=False)
    Hi@Caina,如果我有多个字符串要过滤怎么办?比如“new”、“foo1”、“foo2”?可能你需要在组中循环(最后一个除外,你想取和),并将它们连接起来。嗨@Lynnette,你似乎已经有了一个非常好的答案。我写这篇评论只是为了注意到我已经用一种可扩展的方法更新了答案。最好!谢谢你的帮助。嗨@Caina,如果我有多个字符串要过滤呢?比如“new”、“foo1”、“f”