2017-02-14 44 views
0

我有以下形式的数据帧:大熊猫的GroupBy聚集只有一列

>>> 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中我按多索引进行分组(在本例中,它显示为单个索引) 。 我认为会有一个解决方案,而不是减少和重组,我将能够聚集只有一个索引出组,但其他人分组,但无法在文档或在线找到它。有任何想法吗?

回答

0

这里是一个一行,但它一旦复位指数,太:

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 
+0

谢谢!我想问题是,如果groupby(level = 0)很快就是因为它是索引。如果是,那么这是一个完美的答案。 – ErnestScribbler

+0

我定时你的原始解决方案和我的。你的速度提高了30%。所以,我猜,我的不值得。 – DyZ

+0

我也计时了。我认为这只是“减速”的“适用”线。 – ErnestScribbler

0

我会用这个和pivot_table然后做广播(见What does the term "broadcasting" mean in Pandas documentation?)。

首先,与索引seller_idbuyer_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)查看每位卖家的最高份额。

+0

谢谢!但是,这会创建一个大小为n_buyers * n_sellers的表格,这可能适用于这个玩具示例,但在我的真实数据集中永远不会适应内存。 – ErnestScribbler