Pandas DataFrame动态添加列:计算各国年度GDP占比的实现问题
问题描述
我手头有这样一个Pandas DataFrame:
Date Country GDP 0 2011 United States 345.0 1 2012 United States 0.0 2 2013 United States 457.0 3 2014 United States 577.0 4 2015 United States 0.0 5 2016 United States 657.0 6 2011 UK 35.0 7 2012 UK 64.0 8 2013 UK 54.0 9 2014 UK 67.0 10 2015 UK 687.0 11 2016 UK 0.0 12 2011 China 34.0 13 2012 China 54.0 14 2013 China 678.0 15 2014 China 355.0 16 2015 China 5678.0 17 2016 China 345.0
我想给它加一列perc,用来计算每个国家当年的GDP在三个国家当年总GDP中的占比。
最开始我写了嵌套循环的代码:
import pandas as pd countrylist=['United States','UK','China'] for country in countrylist: for year in range (2011,2016): df['perc']=(df['GDP'][(df['Country']==country) & (df['Date']==year)]).astype(float)/df['GDP'][df['Date']==year].sum() print (df['perc'])
结果发现每次循环都会把之前的perc值覆盖掉,最后只有最后一次循环的结果保留,大部分行都是NaN。后来我试了指定位置赋值:
df['perc'][([(df['Country']==country) & (df['Date']==year)])]=(df['GDP'][(df['Country']==country) & (df['Date']==year)]).astype(float)/df['GDP'][df['Date']==year].sum()
也没起作用,想请教怎么才能得到如下的理想结果:
Date Country GDP perc 0 2011 United States 345.0 0.81 1 2012 United States 0.0 0.0 2 2013 United States 457.0 0.23 3 2014 United States 577.0 xx 4 2015 United States 0.0 xx 5 2016 United States 657.0 xx 6 2011 UK 35.0 xx 7 2012 UK 64.0 xx 8 2013 UK 54.0 xx 9 2014 UK 67.0 xx 10 2015 UK 687.0 xx 11 2016 UK 0.0 xx 12 2011 China 34.0 xx 13 2012 China 54.0 xx 14 2013 China 678.0 xx 15 2014 China 355.0 xx 16 2015 China 5678.0 xx 17 2016 China 345.0 xx
解决方案
你踩了Pandas新手常见的坑:用嵌套循环逐行赋值不仅效率低,还容易因为覆盖整列数据导致结果丢失。其实用Pandas的分组功能就能一行搞定,完全不需要循环。
推荐方法:groupby + transform
groupby('Date')会把数据按年份分组,transform('sum')会计算每个年份的GDP总和,并且把这个总和广播回该年份的每一行,这样直接用每行的GDP除以对应年份的总和就能得到占比:
import pandas as pd # 先构造你的DataFrame(如果还没创建的话) data = [ [2011, 'United States', 345.0], [2012, 'United States', 0.0], [2013, 'United States', 457.0], [2014, 'United States', 577.0], [2015, 'United States', 0.0], [2016, 'United States', 657.0], [2011, 'UK', 35.0], [2012, 'UK', 64.0], [2013, 'UK', 54.0], [2014, 'UK', 67.0], [2015, 'UK', 687.0], [2016, 'UK', 0.0], [2011, 'China', 34.0], [2012, 'China', 54.0], [2013, 'China', 678.0], [2014, 'China', 355.0], [2015, 'China', 5678.0], [2016, 'China', 345.0] ] df = pd.DataFrame(data, columns=['Date', 'Country', 'GDP']) # 计算占比并新增列 df['perc'] = df['GDP'] / df.groupby('Date')['GDP'].transform('sum') # 可选:保留两位小数让结果更整洁 df['perc'] = df['perc'].round(2) print(df)
为什么你的原代码失效?
- 整列覆盖问题:你每次循环直接给
df['perc']赋值,会把整列替换成当前循环的结果——只有符合country和year条件的行有值,其他行都是NaN,所以循环结束后只剩最后一次循环的有效数据。 - 赋值语法错误:你尝试的位置赋值写法有问题,正确的修改应该用
.loc来避免SettingWithCopyWarning,但即使改对了,嵌套循环的效率也远不如Pandas原生的分组运算。
运行结果示例
以2011年为例,总GDP是345+35+34=414,美国的占比是345/414≈0.83,英国是35/414≈0.08,中国是34/414≈0.08,和你理想结果里的0.81(手动近似值)接近。运行代码后,所有年份的占比都会正确计算,不会出现NaN覆盖的问题。
内容的提问来源于stack exchange,提问作者Chelseajcole
相关产品推荐
相关产品推荐

