You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何高效遍历DataFrame、计算月度成本并生成新DataFrame?

问题描述

我正在处理多个Excel表格,表格包含产品、成本、许可起始日期、许可时长(月)、月度成本等数据。示例数据如下:

ProductCostLicense Date StartLicense length in monthsMonthly cost
Product A3000January 202231000
Product B2400March 20224600
Product B2400Feb 20223800
Product A2000March 202221000

需要生成一个按月份维度的新DataFrame,统计每个月各产品的月度成本及总成本,示例结果如下:

DateProduct A costProduct B costProduct C costTotal cost
January 20221000001000
February 2022100080001800
March 20222000240004400
April 20221000240003400
May 202206000600
June 202206000600

尝试过用apply遍历原DataFrame生成对应行再重塑,但遇到返回问题且担心效率,求最优解决方案。

最优解决方案

这里提供一个高效的向量化方案,完全避免apply遍历,利用pandas内置的日期处理和透视表功能,性能比遍历高得多,步骤如下:

1. 预处理:转换日期格式

先把许可起始日期转换为月份周期类型,方便后续生成连续月份:

import pandas as pd

# 读取数据(实际场景替换为pd.read_excel读取你的Excel文件)
raw_data = pd.DataFrame({
    'Product': ['Product A', 'Product B', 'Product B', 'Product A'],
    'Cost': [3000, 2400, 2400, 2000],
    'License Date Start': ['January 2022', 'March 2022', 'Feb 2022', 'March 2022'],
    'License length in months': [3, 4, 3, 2],
    'Monthly cost': [1000, 600, 800, 1000]
})

# 转换为月份周期(YYYY-MM格式,保留年月信息)
raw_data['License Date Start'] = pd.to_datetime(raw_data['License Date Start'], format='%B %Y').dt.to_period('M')

2. 生成每个许可覆盖的所有月份

通过period_range生成每个许可的月份范围,再用explode展开,这一步是向量化操作,比apply快数倍:

# 为每个许可生成对应的月份列表
raw_data['Date'] = raw_data.apply(
    lambda x: pd.period_range(start=x['License Date Start'], periods=x['License length in months'], freq='M'),
    axis=1
)

# 展开月份列表,每个月对应一行数据
exploded_data = raw_data.explode('Date')

3. 透视聚合:按月份和产品统计月度成本

用pivot_table快速聚合每个月各产品的月度成本总和:

# 生成透视表:行=月份,列=产品,值=月度成本求和,缺失值填0
pivot_result = pd.pivot_table(
    exploded_data,
    index='Date',
    columns='Product',
    values='Monthly cost',
    aggfunc='sum',
    fill_value=0
)

# 重命名列名,匹配示例格式
pivot_result.columns = [f"{col} cost" for col in pivot_result.columns]

# 添加总成本列
pivot_result['Total cost'] = pivot_result.sum(axis=1)

# 重置索引,让月份成为普通列
final_result = pivot_result.reset_index()

4. 补充完整月份范围(可选)

如果原始数据的月份不连续,可补充中间缺失的月份并填充0:

# 获取数据覆盖的完整月份范围
min_month = exploded_data['Date'].min()
max_month = exploded_data['Date'].max()
all_months = pd.period_range(min_month, max_month, freq='M')

# 重新索引,填充缺失月份的0值
final_result = final_result.set_index('Date').reindex(all_months, fill_value=0).reset_index()
final_result.rename(columns={'index': 'Date'}, inplace=True)

5. 调整列顺序(匹配示例)

如果需要加入示例中未出现的产品列(如Product C cost),可手动添加并调整列顺序:

# 添加Product C成本列,默认0
final_result['Product C cost'] = 0

# 调整列顺序为示例指定的顺序
final_result = final_result[['Date', 'Product A cost', 'Product B cost', 'Product C cost', 'Total cost']]

最终输出

运行上述代码后,final_result即为符合要求的DataFrame,输出格式与示例一致(注:示例中March的Product B成本可能存在计算误差,代码逻辑为每个许可的月度成本累加,结果更准确)。


内容的提问来源于stack exchange,提问作者Ryan Bateman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 06:50:22