Pandas:基于其他行数据创建新列及性能优化咨询
优化时间序列加权计算的性能方案
我来帮你解决这个时间序列计算的性能问题,你的核心痛点是逐行循环太慢,而且因为日期缺失没法直接用shift生成前N个月的对应数据列,下面给你具体的实现方法和优化思路:
一、生成前N个月对应数据列的方法
因为日期不连续,shift确实没法直接用,但我们可以先给每个日期计算出往前N个月的调整后日期(周末自动转上周五),再通过日期匹配把对应的value映射过来,就能生成value-1、value-2、value-3这类列。
具体代码实现:
import pandas as pd import numpy as np # 先确保date列是datetime类型(如果还不是的话) ds['date'] = pd.to_datetime(ds['date']) # 定义函数:计算往前n个月的日期,自动把周末调整为上周五 def get_adjusted_date(base_date, months_back): target_date = base_date - pd.DateOffset(months=months_back) # 周日(dayofweek=6)减2天,周六(dayofweek=5)减1天,统一转到周五 if target_date.dayofweek == 6: return target_date - pd.DateOffset(days=2) elif target_date.dayofweek == 5: return target_date - pd.DateOffset(days=1) else: return target_date # 为每个需要回溯的月份生成调整后的目标日期列 for n in [1, 2, 3]: ds[f'target_date_{n}'] = ds['date'].apply(lambda x: get_adjusted_date(x, n)) # 把原始数据的date和value做成快速查询的映射(用Series比字典更灵活) value_lookup = ds.set_index('date')['value'] # 映射生成对应的value列,缺失日期会自动填充NaN for n in [1, 2, 3]: ds[f'value-{n}'] = ds[f'target_date_{n}'].map(value_lookup.get) # 清理临时的目标日期列(可选) ds = ds.drop(columns=[f'target_date_{n}' for n in [1, 2, 3]])
这样生成的value-1、value-2、value-3就完全符合你的需求,而且比循环查询快得多。
二、整体性能优化:直接向量化计算outval
其实你甚至不需要生成中间列,可以直接用向量化操作一次性计算outval,这会比逐行循环快几个数量级,尤其是数据量大的时候:
weight_vector = np.array([1, 2, 3]) value_lookup = ds.set_index('date')['value'] # 第一步:生成所有行对应的调整后目标日期矩阵 target_dates = ds['date'].apply( lambda x: [get_adjusted_date(x, n) for n in weight_vector] ).tolist() target_dates_df = pd.DataFrame(target_dates, index=ds.index) # 第二步:批量匹配对应的value值 vals_df = target_dates_df.applymap(lambda dt: value_lookup.get(dt, np.nan)) # 第三步:加权求和,只要有一个值缺失就返回NaN(和你原来的逻辑一致) ds['outval'] = (vals_df * weight_vector).sum(axis=1, skipna=False)
为什么这个方法更快?
你原来的itertuples循环是逐行遍历,每次都要做ds.loc[ds['date'].isin(d_vals)]的全表查询,属于O(n²)的时间复杂度,数据量上去后会非常慢。而上面的方法是先建立日期到value的O(1)查询映射,再批量处理所有行,时间复杂度是O(n),性能提升非常明显。
如果你的数据里有重复日期,记得先去重(比如取每日的均值或最新值),确保value_lookup的索引是唯一的,这样映射结果才准确。
内容的提问来源于stack exchange,提问作者stavrop
相关产品推荐
相关产品推荐

