【问题标题】:pandas GroupBy aggregate only one columnpandas GroupBy 只聚合一列
【发布时间】:2017-07-02 04:52:59
【问题描述】:

我有一个如下形式的 DataFrame:

>>> sales = pd.DataFrame({'seller_id':list('AAAABBBB'),'buyer_id':list('CCDECDEF'),\
                          'amount':np.random.randint(10,20,size=(8,))})
>>> sales = sales[['seller_id','buyer_id','amount']]
>>> sales
  seller_id buyer_id  amount
0         A        C      18
1         A        C      15
2         A        D      11
3         A        E      12
4         B        C      16
5         B        D      18
6         B        E      16
7         B        F      19

现在我想做的是为每个卖家计算其最大买家在总销售额中所占的份额。我有执行此操作的代码,但我必须不断重置索引并再次分组,这很浪费。一定有更好的方法。我想要一个解决方案,我可以一次聚合一列并将其他列分组。 这是我当前的代码:

>>> gr2 = sales.groupby(['buyer_id','seller_id'])
>>> seller_buyer_level = gr2['amount'].sum() # sum over different purchases
>>> seller_buyer_level_reset = seller_buyer_level.reset_index('buyer_id')
>>> gr3 = seller_buyer_level_reset.groupby(seller_buyer_level_reset.index)
>>> result = gr3['amount'].max() / gr3['amount'].sum()

>>> result
seller_id
A    0.589286
B    0.275362

我简化了一点。实际上,我也有一个时间段列,因此我想在卖方和时间段级别执行此操作,这就是为什么在 gr3 中我按多索引分组(在此示例中,它显示为单个索引) . 我认为会有一个解决方案,而不是减少和重新组合,我只能从组中聚合一个索引,而将其他索引分组,但在文档或在线中找不到它。有什么想法吗?

【问题讨论】:

    标签: python pandas group-by


    【解决方案1】:

    这是一个单行,但它也重置了一次索引:

    sales.groupby(['seller_id','buyer_id']).sum().\
        reset_index(level=1).groupby(level=0).\
        apply(lambda x: x.amount.max()/x.amount.sum())
    #seller_id
    #A    0.509091
    #B    0.316667
    #dtype: float64
    

    【讨论】:

    • 谢谢!我想问题是 groupby(level=0) 是否很快,因为它是索引。如果是,那么这是一个完美的答案。
    • 我为您的原始解决方案和我的解决方案计时。你的速度快 30%。所以,我想,我的不值得。
    • 我也计时了。我认为只有“应用”行会减慢它的速度。
    【解决方案2】:

    我会使用pivot_table 执行此操作,然后进行广播(请参阅What does the term "broadcasting" mean in Pandas documentation?)。

    首先,使用索引中的seller_id 和列中的buyer_id 对数据进行透视:

    sales_pivot = sales.pivot_table(index='seller_id', columns='buyer_id', values='amount', aggfunc='sum')
    

    然后,将每行中的值除以所述行的总和:

    result = sales_pivot.div(sales_pivot.sum(axis=1), axis=0)
    

    最后,您可以致电result.max(axis=1) 查看每个卖家的最高份额。

    【讨论】:

    • 谢谢!但这会创建一个大小为 n_buyers * n_sellers 的表,它可能在这个玩具示例中有效,但在我的真实数据集中永远无法放入内存中。
    猜你喜欢
    • 2021-11-01
    • 2019-10-12
    • 2017-07-20
    • 2017-06-07
    • 2019-12-22
    • 2018-03-01
    • 2014-11-23
    • 2020-11-05
    • 1970-01-01
    相关资源
    最近更新 更多