如何通过循环或数据重构实现基于多列计算的行追加及人口聚合求和?
解决方案:按年龄区间聚合人口并追加到原数据
首先,先统一你的原始DataFrame(注意你提供的字典和表格内容有出入,我先以字典为准修正,确保代码能正确运行):
import pandas as pd d = { 'year': [2019,2020,2019,2020,2019,2020], 'age': [10,10,20,20,30,30], 'con': ['UK','UK','UK','US','US','US'], 'population': [1,2,300,400,1000,2000] } df = pd.DataFrame(data=d)
你的核心需求是:针对每个国家(con)、每个年份(覆盖2019-2040,这里先以现有年份为例,扩展到2040只需调整年份范围),按指定年龄区间聚合人口总和,然后将这些聚合行追加到原数据中。下面是简洁高效的实现方式,避免复杂循环:
步骤1:定义年龄区间与对应分类
先明确你的年龄区间和分类映射:
# 定义年龄区间(左闭右开,可根据需求调整)、区间名称、对应分类 age_bins = [0, 10, 20, 30] age_labels = ["0-10", "10-20", "20-30"] category_labels = ["Child", "Teen", "Work"] # 建立区间到分类的映射 bin_to_category = dict(zip(age_labels, category_labels))
步骤2:生成聚合数据
利用Pandas的pd.cut划分年龄区间,再通过groupby按年份、国家、区间分组求和:
# 给原数据添加年龄区间列 df['age_range'] = pd.cut(df['age'], bins=age_bins, labels=age_labels, right=False) # 按year、con、age_range分组,求和人口 agg_df = df.groupby(['year', 'con', 'age_range'], as_index=False)['population'].sum() # 添加分类列,并重命名列以匹配原数据格式 agg_df['category'] = agg_df['age_range'].map(bin_to_category) agg_df = agg_df.rename(columns={'age_range': 'age'})
步骤3:合并原数据与聚合数据
将聚合后的行追加到原DataFrame,并重设索引:
# 原数据不需要age_range列,先删除 df = df.drop('age_range', axis=1) # 合并数据 final_df = pd.concat([df, agg_df], ignore_index=True) # 可选:按year、con排序,让结果更清晰 final_df = final_df.sort_values(['year', 'con']).reset_index(drop=True)
运行后,final_df就包含了原数据和按年龄区间聚合的行,比如2019年UK的"10-20"区间人口和为1+300=301,完全符合你的需求。
针对你尝试代码的优化说明
你之前的循环代码存在几个问题:
- 变量名错误(比如
date未定义,cat2应该是con) - 逻辑过于繁琐,手动循环年份、国家、区间容易出错且效率低
- 没有正确处理分组后的结果拼接
而上面的方案利用Pandas的矢量化操作和groupby聚合,比手动循环高效得多,代码也更易维护。
关于melt方法的说明
melt主要用于将宽格式数据转换为长格式,在你的场景中并不需要——我们的需求是聚合而非重塑数据,所以groupby是更直接的选择。如果后续需要对结果进行宽转长处理,再考虑使用melt即可。
扩展到2019-2040年份
如果你的原始数据缺少部分年份,需要先补全所有年份的空值行,再进行聚合:
# 生成所有需要的年份、国家、年龄的笛卡尔积 all_years = range(2019, 2041) all_countries = df['con'].unique() all_ages = df['age'].unique() index = pd.MultiIndex.from_product([all_years, all_countries, all_ages], names=['year', 'con', 'age']) # 重新索引原数据,补全缺失的年份/国家/年龄行,人口设为0 df_full = df.set_index(['year', 'con', 'age']).reindex(index, fill_value=0).reset_index() # 之后再按上面的步骤进行聚合即可
内容的提问来源于stack exchange,提问作者vishvas chauhan
相关产品推荐
相关产品推荐

