加速时间序列自举:优化DataFrame列函数应用速度
时间序列自举样本的函数应用速度优化方案
问题背景
对时间序列执行IID自举生成大量样本后,使用df.apply(func)逐列计算指标的速度成为瓶颈,尤其是样本量超过10000时。部分待应用函数支持DataFrame批量输入,但仍有大量函数仅支持单Series输入,需要针对性优化。
优化方案
1. 优先利用函数的批量处理能力(支持DataFrame输入的场景)
如果目标函数支持直接接收DataFrame作为输入(如示例中的qs.stats.adjusted_sortino),完全不需要使用apply,直接传入整个自举样本DataFrame即可,底层会用向量化逻辑处理,速度远超逐列循环:
# 替代原df_func = df_results.apply(func) df_func = func(df_results)
2. 并行处理(仅支持单Series输入的场景)
对于不支持批量处理的函数,用多进程/多线程并行处理每一列,充分利用多核CPU资源。以下是基于concurrent.futures的实现:
import concurrent.futures def process_column(col_series): return func(col_series) # 使用进程池并行处理所有列(CPU密集型场景首选) with concurrent.futures.ProcessPoolExecutor() as executor: results = list(executor.map(process_column, [df_results[col] for col in df_results.columns])) # 转换为结果Series df_func = pd.Series(results, index=df_results.columns)
注:若函数为IO密集型,可改用
ThreadPoolExecutor。
3. 自举阶段直接计算指标,避免生成大DataFrame(内存+速度双重优化)
原代码先生成包含所有自举样本的大DataFrame再处理,会占用大量内存且增加后续步骤。可以在自举循环中直接计算指标,跳过样本存储环节:
def BootstrapIDD_with_metric(series: pd.Series = None, n_samples: int = 1000, func=None): nobs = len(series) bsidd = IIDBootstrap(series) metric_results = [] row_range = range(0, nobs) for pos_data in bsidd.bootstrap(reps=n_samples): new_sample = pos_data[0][0] new_sample.index = row_range # 直接计算当前样本的指标,存入结果列表 metric_results.append(func(new_sample)) # 生成结果Series string_name = series.name index = [string_name + '_path_' + str(x) for x in range(1, n_samples + 1)] return pd.Series(metric_results, index=index) # 调用时直接传入目标函数 df_func = BootstrapIDD_with_metric(ret_bench, n_samples=10000, func=func)
该方案大幅减少内存占用(无需存储上万列的DataFrame),同时避免后续apply的循环开销,是最优的端到端优化方案。
内容的提问来源于stack exchange,提问作者msh855
相关产品推荐
相关产品推荐

