Pandas扩展DataFrame计算占比:优化低效循环实现方案需求
Pandas高效计算分组占比优化方案
问题说明
现有两个DataFrame:
源数据(df_source)
| Location | Total Values | Total Values 2 |
|---|---|---|
| Location 1 | 100 | 300 |
| Location 2 | 200 | 400 |
占比规则(df_fractions)
| Ident | Fraction |
|---|---|
| Frac A | 0.25 |
| Frac B | 0.75 |
需要生成新的DataFrame,将每个Location与所有占比标识组合,计算对应数值,目标结构如下:
| Location | Total Values | Total Values 2 |
|---|---|---|
| Location 1 A | 25 | 75 |
| Location 1 B | 75 | 225 |
| Location 2 A | 50 | 100 |
| Location 2 B | 150 | 300 |
当前使用逐行循环的方式实现,代码如下,但数据量大时效率极低:
ccalculated = [] for _, row in df_source.iterrows(): for ident in df_fractions: new_row = row.copy() scaling_factor = df_fractions[df_fractions.loc[:, "Ident"] == "Frac A"] for values in ValueCols: new_row[values] = np.multiply(new_row["Total Values"], scaling_factor) calculated.append(new_row)
优化方案:用Pandas向量化操作替代循环
Pandas的核心优势是向量化运算,避免逐行循环能大幅提升效率,具体步骤如下:
步骤1:生成Location与占比规则的全组合(交叉连接)
通过添加临时键实现两个DataFrame的笛卡尔积,得到所有Location和Ident的组合:
# 添加临时键用于交叉连接 df_source['tmp_key'] = 1 df_fractions['tmp_key'] = 1 # 交叉连接得到所有组合 merged_df = df_source.merge(df_fractions, on='tmp_key').drop('tmp_key', axis=1)
步骤2:计算各数值列的占比结果
直接对数值列做向量化乘法,避免逐元素循环:
# 计算占比后的值 merged_df['Total Values'] = merged_df['Total Values'] * merged_df['Fraction'] merged_df['Total Values 2'] = merged_df['Total Values 2'] * merged_df['Fraction']
步骤3:整理Location列并清理冗余列
把原Location和Ident拼接成新的Location名称,然后删除不需要的列:
# 拼接Location和Ident(提取Ident中的字母部分) merged_df['Location'] = merged_df['Location'] + ' ' + merged_df['Ident'].str.replace('Frac ', '') # 删除冗余列 result_df = merged_df.drop(['Ident', 'Fraction'], axis=1)
完整代码
import pandas as pd # 示例数据初始化 df_source = pd.DataFrame({ 'Location': ['Location 1', 'Location 2'], 'Total Values': [100, 200], 'Total Values 2': [300, 400] }) df_fractions = pd.DataFrame({ 'Ident': ['Frac A', 'Frac B'], 'Fraction': [0.25, 0.75] }) # 交叉连接生成全组合 df_source['tmp_key'] = 1 df_fractions['tmp_key'] = 1 merged_df = df_source.merge(df_fractions, on='tmp_key').drop('tmp_key', axis=1) # 批量计算占比数值 merged_df[['Total Values', 'Total Values 2']] *= merged_df['Fraction'].values[:, None] # 整理Location列格式 merged_df['Location'] = merged_df['Location'] + ' ' + merged_df['Ident'].str[-1] # 清理冗余列并重置索引 result_df = merged_df.drop(['Ident', 'Fraction'], axis=1).reset_index(drop=True) print(result_df)
运行后输出的result_df就是目标结构,且完全基于向量化操作,数据量越大,效率提升越明显。
效率提升原因
- 避免了
iterrows()逐行循环的Python层面开销,Pandas向量化操作基于底层C实现,速度远快于原生循环 - 交叉连接和列运算均为批量处理,减少了内存拷贝和循环迭代的损耗
内容的提问来源于stack exchange,提问作者Fscir
相关产品推荐
相关产品推荐

