pandas 中的split-apply-combine process,特别是aggregation,是解决此问题的最佳方式。首先我会解释这个过程是如何手动工作的,然后我会展示 pandas 是如何在一行中完成的。
手动拆分-应用-合并
拆分
首先,将DataFrame分成同一个Sector的组。这涉及获取扇区列表并确定哪些行属于它(就像代码的前两行一样)。此代码贯穿 DataFrame 并构建一个字典,其中键为 Sectors 和对应于它的 sectors_df 的行索引列表。
sectors_index = {}
for ix, row in sectors_df.iterrows():
if row['Sector'] not in sectors_index:
sectors_index[row['Sector']] = [ix]
else:
sectors_index[row['Sector']].append(ix)
申请
在每个组上运行相同的函数,在本例中对 Current Value 求和并计算其百分比份额。也就是说,对于每个扇区,从 DataFrame 中获取相应的行并在代码的下一行中运行计算。我会将结果存储为字典字典:{'Sector1': {'value_in_sect': 1234.56, 'pct_in_sect': 11.11}, 'Sector2': ... },原因稍后会很明显:
sector_total_value = {}
total_value = sectors_df['Current Value'].sum()
for sector, row_indices in sectors_index.items():
sector_df = sectors_df.loc[row_indices]
current_value = sector_df['Current Value'].sum()
sector_total_value[sector] = {'value_in_sect': round(current_value, 2),
'pct_in_sect': round(current_value/total_value * 100, 2)
}
(有关四舍五入的说明见脚注 1)
合并
最后,将函数结果收集到一个新的DataFrame中,其中索引为Sector。 pandas 可以轻松地将这个嵌套的字典结构转换成DataFrame:
sector_total_value_df = pd.DataFrame.from_dict(sector_total_value, orient='index')
使用groupby 拆分应用组合
pandas 使用groupby 方法使这个过程变得非常简单。
拆分
groupby 方法将 DataFrame 按一列或多列(甚至另一个系列)分成组:
grouped_by_sector = sectors_df.groupby('Sector')
grouped_by_sector 类似于我们之前构建的索引,但可以更轻松地操作组,如下面的步骤所示。
申请
要计算每组中的总值,请选择要汇总的列或列,将agg 或aggregate 方法与您要应用的函数一起使用:
sector_total_value = grouped_by_sector['Current Value'].agg(value_in_sect=sum)
合并
已经完成了! apply 步骤已经创建了一个 DataFrame,其中索引是 Sector(groupby 列),value_in_sect 列中的值是 sum 操作的结果。
我省略了 pct_in_sect 部分,因为 a) 事后更容易完成:
sector_total_value_df['pct_in_sect'] = round(sector_total_value_df['value_in_sect'] / total_value * 100, 2)
sector_total_value_df['value_in_sect'] = round(sector_total_value_df['value_in_sect'], 2)
和b)它超出了这个答案的范围。
大部分内容都可以在一行中轻松完成(参见脚注 2 以了解百分比和四舍五入):
sector_total_value_df = sectors_df.groupby('Sector')['Current Value'].agg(value_in_sect=sum)
对于子行业,还有一个额外的考虑因素,那就是分组应该由行业和子行业完成,而不仅仅是子行业,这样,例如来自公用事业/天然气和能源/天然气的行t 合并。
subsector_total_value_df = sectors_df.groupby(['Sector', 'Sub Sector'])['Current Value'].agg(value_in_sect=sum)
这会生成一个带有 MultiIndex 的 DataFrame,它具有“Sector”和“Sub Sector”级别,以及“value_in_sect”列。对于最后一个魔法,可以很容易地计算出 Sector 中的百分比:
subsector_total_value_df['pct_within_sect'] = round(subsector_total_value_df['value_in_sect'] / sector_total_value_df['value_in_sect'] * 100, 2)
之所以有效,是因为在划分期间匹配了“扇区”索引级别。
脚注 1. 这与您的代码略有不同,因为我选择使用未四舍五入的总值计算百分比,以最大限度地减少百分比误差。但理想情况下,舍入仅在显示时进行。
脚注 2. 这个单行生成所需的结果,包括百分比和四舍五入:
sector_total_value_df = sectors_df.groupby('Sector')['Current Value'].agg(
value_in_sect = lambda c: round(sum(c), 2),
pct_in_sect = lambda c: round(sum(c)/sectors_df['Current Value'].sum() * 100, 2),
)