基于另一列的每个值的列值总和,然后除以总数

Posted

技术标签:

【中文标题】基于另一列的每个值的列值总和,然后除以总数【英文标题】:Sum values of a column for each value based on another column and divide it by total 【发布时间】:2019-11-23 09:24:27 【问题描述】:

今天我又一次在 python 和数据分析方面苦苦挣扎。

我得到了一个如下所示的数据框:

    name         totdmgdealt
0   Warwick      96980.0
1   Nami         25995.0
2   Draven       171568.0
3   Fiora        113721.0
4   Viktor       185302.0
5   Skarner      148791.0
6   Galio        130692.0
7   Ahri         145731.0
8   Jinx         182680.0
9   VelKoz       85785.0
10  Ziggs        46790.0
11  Cassiopeia   62444.0
12  Yasuo        117896.0
13  Warwick      129156.0
14  Evelynn      179252.0
15  Caitlyn      163342.0
16  Wukong       122919.0
17  Syndra       146754.0
18  Karma        35766.0
19  Warwick      117790.0
20  Draven       74879.0
21  Janna        11242.0
22  Lux          66424.0
23  Amumu        87826.0
24  Vayne        76085.0
25  Ahri         93334.0
..
..
..

这是一个数据框,其中包括一个英雄在一场比赛中的总伤害。 现在我想对这些信息进行分组,这样我就可以看到总体上哪个英雄造成的伤害最大。 我尝试了 groupby('name') 但它根本不起作用。 我已经完成了一些关于 groupby 和 summing values 的线程,但我没有解决我的具体问题。

每个英雄造成的伤害也应该显示为总伤害的百分比。

我正在寻找这样的输出:

    name     totdmgdealt  percentage
0   Warwick  2378798098     2.1  %
1   Nami     2837491074     2.3  %
2   Draven   1231451224     ..
3   Fiora    1287301724     ..
4   Viktor   1239808504     ..
5   Skarner  1487911234     ..
6   Galio    1306921234     ..

【问题讨论】:

添加你尝试过的代码 【参考方案1】:

我们可以按名称分组并得到sum,然后我们将每个值除以.div 的总数,然后将其乘以100 并使用.mul,最后将其四舍五入到小数点后.round

total = df['totdmgdealt'].sum()

summed = df.groupby('name', sort=False)['totdmgdealt'].sum().reset_index()

summed['percentage'] = summed.groupby('name', sort=False)['totdmgdealt']\
                             .sum()\
                             .div(total)\
                             .mul(100)\
                             .round(1).values
          name  totdmgdealt  percentage
0      Warwick     343926.0        12.2
1         Nami      25995.0         0.9
2       Draven     246447.0         8.7
3        Fiora     113721.0         4.0
4       Viktor     185302.0         6.6
5      Skarner     148791.0         5.3
6        Galio     130692.0         4.6
7         Ahri     239065.0         8.5
8         Jinx     182680.0         6.5
9       VelKoz      85785.0         3.0
10       Ziggs      46790.0         1.7
11  Cassiopeia      62444.0         2.2
12       Yasuo     117896.0         4.2
13     Evelynn     179252.0         6.4
14     Caitlyn     163342.0         5.8
15      Wukong     122919.0         4.4
16      Syndra     146754.0         5.2
17       Karma      35766.0         1.3
18       Janna      11242.0         0.4
19         Lux      66424.0         2.4
20       Amumu      87826.0         3.1
21       Vayne      76085.0         2.7

【讨论】:

感谢您的回答。我需要提一下,列名对于每个名称都有多次出现。我想将每个名称的这些值相加,然后将一个名称的总伤害除以总伤害。 您能否编辑您的答案并将其包含在您的示例数据框中? @FloatingGoat 我刚刚更新了我的帖子。带有名称和 totdmgdealt 的数据框是 1.784.592 行大。 更新了答案,只有矢量化方法,没有使用.apply。这应该对 180 万行与您在速度方面接受@FloatingGoat 的答案产生很大影响 @FloatingGoat 是的,肯定应该有,因为.apply 逐行进行,而“本机”(即矢量化)方法可以并行化这项工作。我去申请格式。【参考方案2】:

您可以使用sum() 获取总伤害,并使用apply 计算每行的相关百分比,如下所示:

import pandas as pd
from io import StringIO

df = pd.read_csv(StringIO("""
    name         totdmgdealt
0   Warwick      96980.0
1   Nami         25995.0
2   Draven       171568.0
3   Fiora        113721.0
4   Viktor       185302.0
5   Skarner      148791.0
6   Galio        130692.0
7   Ahri         145731.0
8   Jinx         182680.0
9   VelKoz       85785.0
10  Ziggs        46790.0
11  Cassiopeia   62444.0
12  Yasuo        117896.0
13  Warwick      129156.0
14  Evelynn      179252.0
15  Caitlyn      163342.0
16  Wukong       122919.0
17  Syndra       146754.0
18  Karma        35766.0
19  Warwick      117790.0
20  Draven       74879.0
21  Janna        11242.0
22  Lux          66424.0
23  Amumu        87826.0
24  Vayne        76085.0
25  Ahri         93334.0"""), sep=r"\s+")

summed_df = df.groupby('name')['totdmgdealt'].agg(['sum']).rename(columns="sum": "totdmgdealt").reset_index()
summed_df['percentage'] = summed_df.apply(
    lambda x: ":.2f%".format(x['totdmgdealt'] / summed_df['totdmgdealt'].sum() * 100), axis=1)
print(summed_df)

输出:

          name  totdmgdealt percentage
0         Ahri     239065.0      8.48%
1        Amumu      87826.0      3.12%
2      Caitlyn     163342.0      5.79%
3   Cassiopeia      62444.0      2.21%
4       Draven     246447.0      8.74%
5      Evelynn     179252.0      6.36%
6        Fiora     113721.0      4.03%
7        Galio     130692.0      4.64%
8        Janna      11242.0      0.40%
9         Jinx     182680.0      6.48%
10       Karma      35766.0      1.27%
11         Lux      66424.0      2.36%
12        Nami      25995.0      0.92%
13     Skarner     148791.0      5.28%
14      Syndra     146754.0      5.21%
15       Vayne      76085.0      2.70%
16      VelKoz      85785.0      3.04%
17      Viktor     185302.0      6.57%
18     Warwick     343926.0     12.20%
19      Wukong     122919.0      4.36%
20       Yasuo     117896.0      4.18%
21       Ziggs      46790.0      1.66%

【讨论】:

注意:如果您打算稍后将此值用于计算(而不仅仅是显示),最好将其保持为浮点数,不带% 符号。 感谢您的回答。我需要提一下,列名对于每个名称都有多次出现。我想将每个名称的这些值相加,然后将一个名称的总伤害除以总伤害。 @FloatingGoat,好的,我编辑了我的答案,首先创建了一个求和的 df,然后将我的解决方案应用于它。 @FloatingGoat 编辑了我的输出和示例以使用您的新扩展示例 有没有办法不将名称作为索引值?【参考方案3】:

也许你可以试试这个: 我尝试使用我的示例数据来实现相同的目标,并尝试在您的 Jupyter Notebook 中运行以下代码:


import pandas as pd
name=['abhit','mawa','vaibhav','dharam','sid','abhit','vaibhav','sid','mawa','lakshya']
totdmgdealt=[24,45,80,22,89,55,89,51,93,85]
name=pd.Series(name,name='name')               #converting into series 
totdmgdealt=pd.Series(totdmgdealt,name='totdmgdealt')  #converting into series
data=pd.concat([name,totdmgdealt],axis=1)
data=pd.DataFrame(data)                      #converting into Dataframe 
final=data.pivot_table(values="totdmgdealt",columns="name",aggfunc="sum").transpose()  #actual aggregating method
total=data['totdmgdealt'].sum()            #calculating total for calculating percentage
def calPer(row,total):                     #actual Function for Percentage
    return ((row/total)*100).round(2)
total=final['totdmgdealt'].sum()
final['Percentage']=calPer(final['totdmgdealt'],total)  #assigning the function to the column
final

样本数据:

    name    totdmgdealt
0   abhit   24
1   mawa    45
2   vaibhav 80
3   dharam  22
4   sid     89
5   abhit   55
6   vaibhav 89
7   sid     51
8   mawa    93
9   lakshya 85

输出:

        totdmgdealt     Percentage
name        
abhit     79               12.48
dharam    22               3.48
lakshya   85               13.43
mawa      138              21.80
sid       140              22.12
vaibhav   169              26.70

理解并运行代码,只需将数据集替换为 Yours。也许这会有所帮助。

【讨论】:

以上是关于基于另一列的每个值的列值总和,然后除以总数的主要内容,如果未能解决你的问题,请参考以下文章

基于 DataFrame 中另一列的列的滚动总和

对最后一小时分组中的列值求和,然后将所有 5 的总和作为另一列中的总和

基于R中其他列的列值总和[重复]

如何将一列的列值组合到 MySQL 中的另一列中?

求和列名称来自另一列的值的列

laravel 基于另一列值的唯一验证规则