Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/amazon-s3/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Pandas GroupBy-如何使行达到累计总和的百分比?_Python_Pandas_Group By_Sum_Percentage - Fatal编程技术网

Python Pandas GroupBy-如何使行达到累计总和的百分比?

Python Pandas GroupBy-如何使行达到累计总和的百分比?,python,pandas,group-by,sum,percentage,Python,Pandas,Group By,Sum,Percentage,我有一个未订购的数据帧: df A B Moves 0 E1 E2 10 1 E1 E3 20 2 E1 E4 15 3 E2 E1 9 4 E2 E3 8 5 E2 E4 7 6 E3 E1 30 7 E3 E2 32 8 E3 E4 40 9 E4 E1 5 10 E4 E2 20 11 E4 E3 3

我有一个未订购的数据帧:

df
     A   B  Moves
0   E1  E2     10
1   E1  E3     20
2   E1  E4     15
3   E2  E1      9
4   E2  E3      8
5   E2  E4      7
6   E3  E1     30
7   E3  E2     32
8   E3  E4     40
9   E4  E1      5
10  E4  E2     20
11  E4  E3      3
我想返回行
B
,直到它们的累计总和达到
A
B
的每一组
Moves
的总
移动量的最低百分比(其中我首先取最高值)

一旦达到%阈值,我就停止获取行(累积和)。该过程必须是“贪婪”的,因为如果一行超过所需的百分比,它就包括该行

如果总数的最低百分比为50%,那么我想首先返回:

所需输出

     A   B  Moves
    E1  E3     20
    E1  E4     15
    E2  E1      9
    E2  E3      8
    E3  E4     40
    E3  E2     32
    E4  E2     20
然后,我想使用
df.groupby(…).apply(list)
从中提取每个分组的行名称

我所尝试的:

我可以使用问题中的
cumsum
和问题中的

df.groupby(by=['A','B']).sum().groupby(level=[0]).cumsum()[::-1]

       Moves
A  B        
E4 E3     28
   E2     25
   E1      5
E3 E4    102
   E2     62
   E1     30
E2 E4     24
   E3     17
   E1      9
E1 E4     45
   E3     30
   E2     10
我可以分别返回每组的总移动量(总和):

df.groupby(by="A").sum()

    Moves
A        
E1     45
E2     24
E3    102
E4     28
从“问题”和“问题I”中,可以将每一行作为该类别总和的百分比返回:

df.groupby(by=["A"])["Moves"].apply(lambda x: 100 * x / float(x.sum()))

0     22.222222
1     44.444444
2     33.333333
3     37.500000
4     33.333333
5     29.166667
6     29.411765
7     31.372549
8     39.215686
9     17.857143
10    71.428571
11    10.714286
什么不起作用

但是,如果我将它们结合起来,它将计算整个行的百分比:

df.groupby(by=["A", "B"])["Moves"].agg({"Total_Moves":sum}).sort_values("Total_Moves", ascending=False).apply(lambda x: 100 * x / float(x.sum()))

       Total_Moves
A  B              
E3 E4    20.100503
   E2    16.080402
   E1    15.075377
E1 E3    10.050251
E4 E2    10.050251
E1 E4     7.537688
   E2     5.025126
E2 E1     4.522613
   E3     4.020101
   E4     3.517588
E4 E1     2.512563
   E3     1.507538
这将评估整个数据帧中的百分比,而不是单个组中的百分比

我就是想不出如何把这些拼凑起来,得到我的输出


非常感谢您的帮助。

您可以使用
groupby。通过自定义函数应用

def select(group, pct=50):
    # print(group)
    moves = group['Moves'].sort_values(ascending=False)
    cumsum = moves.cumsum() / moves.sum()
    # print(cumsum)
    # `cumsum` is the cumulative contribution of the sorted moves
    idx = len(cumsum[cumsum < pct/100]) + 1
    # print(idx)
    # `idx` is the first index of the move which has a cumulative sum of `pct` or higher
    idx = moves.index[:idx]  
    # print(idx)
    # here, `idx` is the Index of all the moves in with a cumulative contribution of `pct` or higher
    # print(group.loc[idx])
    return group.loc[idx].set_index(['B'], drop=True)['Moves']
    # return a Series of Moves with column `B` as index of the items which have index `idx`
编辑
我在代码中添加了一些注释。为了更清楚地说明它的作用,我还添加了中间变量的print语句(注释)。如果您取消对它们的注释,那么打印第一个组时不要感到惊讶

您可以使用带有自定义函数的
groupby.apply

def select(group, pct=50):
    # print(group)
    moves = group['Moves'].sort_values(ascending=False)
    cumsum = moves.cumsum() / moves.sum()
    # print(cumsum)
    # `cumsum` is the cumulative contribution of the sorted moves
    idx = len(cumsum[cumsum < pct/100]) + 1
    # print(idx)
    # `idx` is the first index of the move which has a cumulative sum of `pct` or higher
    idx = moves.index[:idx]  
    # print(idx)
    # here, `idx` is the Index of all the moves in with a cumulative contribution of `pct` or higher
    # print(group.loc[idx])
    return group.loc[idx].set_index(['B'], drop=True)['Moves']
    # return a Series of Moves with column `B` as index of the items which have index `idx`
编辑
我在代码中添加了一些注释。为了更清楚地说明它的作用,我还添加了中间变量的print语句(注释)。如果您取消注释它们,第一组内容被打印出来也不要感到惊讶

谢谢Maarten。完美-这适用于我上面的示例和我的真实数据集。感谢添加评论。感谢Maarten。完美-这适用于我上面的示例和我的真实数据集。感谢添加评论。
df.groupby('A').apply(select)
        Moves
A   B   
E1  E3  20
    E4  15
E2  E1  9
    E3  8
E3  E4  40
    E2  32
E4  E2  20