Python金融模型中如何自动将DataFrame多列合并为单一时间序列?
问题说明
我用Python构建了一个金融模型,可输入y个场景(含基准场景)下x年的销售额与利润数据。年度数据按场景存入首个DataFrame(比如x=5且起始年为2022时,基准场景销售额列会包含2022-2026年的数据)。之后我用月度权重生成月度分阶段销售预测,存入新DataFrame,每个年份对应一列(如Base sales 2022、Base sales 2023等)。我需要把这些列合并为单一时间序列(如2022年1月至2026年12月的基准销售额序列),用于图表制作与分析。
我之前用手动添加列名的方式实现过,但这种方法没法适配可变的场景数与年份数,所以尝试自动化处理但没找到可行方案。我没分享主模型代码,而是写了一个示例模型(如下),但代码没法正常运行:虽然输出了创建listA0、listA1、listA2的语句,但这些列表并未实际创建(调用时提示NameError),且输出是多行而非单行。需要解决方案。
示例代码
# 创建场景列表并记录数量 Scenlist=["Bad","Very bad","Terrible"] Scen_number=3 # 创建评估年份列表并计算年份数量 Years=[2020,2021,2022] Totyrs=len(Years) # 创建dprofit数据集,示例中所有列都填充[10,10] dprofit=pd.DataFrame() a=0 b=0 # 创建格式为"Bad profit 2020"、"Bad profit 2021"的列名 while a<Scen_number: while b<Totyrs: dprofit[Scenlist[a]+" profit "+str(Years[b])]=[10,10] b=b+1 b=0 a=a+1 # 打印生成的表格 print(dprofit) # 创建新数据集dprofit2,用于将每个场景的年度列合并为完整时间序列 dprofit2=pd.DataFrame() # 尝试生成代码语句,将dprofit的列合并为listA0、listA1、listA2 a=0 b=0 Totyrs=len(Years) while a<Scen_number: while b<Totyrs: if b==0: print(f"listA{a}=dprofit['{Scenlist[a]} profit {Years[b]}']") else: print(f"+dprofit['{Scenlist[a]} profit {Years[b]}']") b=b+1 b=0 a=a+1 print(listA0) # 调用print(listA0)会报错:NameError: name 'listA0' is not defined. Did you mean: 'list'?
解决方案
原代码核心问题
- 你只是打印了赋值语句的字符串,并没有实际执行这些代码来创建列表,自然会触发
NameError。 - 循环输出的是多行拼接代码,无法直接作为可执行语句运行。
正确实现方式
不需要通过生成字符串代码的方式,直接用pandas的内置方法就能高效完成场景列的合并,同时适配任意数量的场景和年份:
方法1:用字典存储各场景的合并序列
import pandas as pd # 初始化场景和年份(和原代码一致) Scenlist=["Bad","Very bad","Terrible"] Years=[2020,2021,2022] # 构建示例dprofit(优化原循环写法) dprofit = pd.DataFrame() for scen in Scenlist: for year in Years: dprofit[f"{scen} profit {year}"] = [10,10] # 为每个场景合并年度列,存储到字典中 scen_series = {} for scen in Scenlist: # 筛选当前场景的所有年度列 scen_cols = [col for col in dprofit.columns if col.startswith(f"{scen} profit")] # 按年份顺序合并列,转为单一序列 merged_series = pd.concat([dprofit[col] for col in scen_cols], ignore_index=True) scen_series[scen] = merged_series # 调用示例:获取Bad场景的合并序列 print(scen_series["Bad"])
方法2:直接构建带时间索引的完整时间序列(适配月度数据场景)
如果你的实际需求是生成月度时间序列,可以直接构造日期索引,把年度数据按权重拆分后合并:
import pandas as pd import numpy as np # 示例月度权重(假设每年12个月,权重均等) monthly_weights = np.ones(12)/12 # 初始化场景和年份 Scenlist=["Bad","Very bad","Terrible"] Years=[2020,2021,2022] # 构建示例年度利润数据(每个场景每年的年度值) annual_profit = pd.DataFrame({ f"{scen} profit {year}": [100] for scen in Scenlist for year in Years }) # 生成完整月度时间索引 date_index = pd.date_range(start=f"{Years[0]}-01-01", end=f"{Years[-1]}-12-31", freq="MS") # 为每个场景生成月度序列 dprofit_monthly = pd.DataFrame(index=date_index) for scen in Scenlist: # 提取当前场景的所有年度列 scen_annual_cols = [col for col in annual_profit.columns if col.startswith(f"{scen} profit")] # 按年份顺序拆分年度值为月度数据 monthly_data = [] for year in Years: annual_value = annual_profit[f"{scen} profit {year}"].iloc[0] monthly_data.extend(annual_value * monthly_weights) # 添加到结果数据集 dprofit_monthly[f"{scen} profit monthly"] = monthly_data # 查看结果 print(dprofit_monthly)
关键优化点
- 用**列表推导式+
pd.concat**替代手动拼接,适配任意数量的场景和年份 - 避免动态生成代码字符串的危险操作,直接通过pandas API实现逻辑
- 若需处理月度数据,直接构造时间索引,确保序列的时间连续性
内容的提问来源于stack exchange,提问作者James Kelly
相关产品推荐
相关产品推荐

