多时间序列Prophet预测多进程报错及百分比差异计算可行性咨询
问题解决与优化方案
一、修复DataFrame constructor not properly called!错误
你遇到的错误核心是传入Prophet的predict方法的DataFrame格式不符合要求,同时代码里的全局变量forecast在多进程场景下会引发逻辑混乱,具体修复如下:
1. 正确构造预测用的日期DataFrame
Prophet要求输入的预测数据集必须包含名为ds的日期列,你当前直接把单个日期传入pd.DataFrame()的方式是错误的,需要改为:
# 构造单个日期的DataFrame,指定列名为'ds' target_date = prevmonth + timedelta future_date = pd.DataFrame({'ds': [target_date]})
如果需要生成到目标日期的序列再筛选,也可以用make_future_dataframe后过滤:
# 先生成未来序列,再筛选目标日期 future = m.make_future_dataframe(periods=180) # 生成6个月左右的序列 future_date = future[future['ds'] == target_date]
2. 移除全局变量forecast
多进程中每个子进程拥有独立内存空间,全局变量无法在进程间共享且会导致逻辑冲突,直接在函数内部定义forecast即可,同时补充数据不足时的默认返回值:
def train_and_forecast(group): prevmonth = datetime.date(2021, 9, 1) timedelta = relativedelta(months=6) m = Prophet(weekly_seasonality=False, yearly_seasonality=False, changepoint_range=0.8, changepoint_prior_scale=0.8) # 初始化默认返回值,避免group行数不足时出错 default_forecast = pd.DataFrame(columns=['ds', 'ticker', 'yhat', 'yhat_upper', 'yhat_lower']) if group.shape[0] > 2: m.fit(group) target_date = prevmonth + timedelta # 正确构造预测日期DataFrame future_date = pd.DataFrame({'ds': [target_date]}) forecast = m.predict(future_date)[['ds', 'yhat', 'yhat_lower', 'yhat_upper']] forecast['ticker'] = group['ticker'].iloc[0] return forecast[['ds', 'ticker', 'yhat', 'yhat_upper', 'yhat_lower']], m # 数据不足时返回空结构 return default_forecast, None
二、多进程实现分组日期百分比差异计算
针对你计算间隔1个月、2个月等日期间百分比差异的需求,可以基于多进程并行处理每个分组,以下是完整优化后的代码:
1. 定义差异计算函数
先编写计算单组数据不同间隔日期差异的函数:
def calculate_period_diff(group, intervals=[1,2,6]): # 确保日期列是datetime类型并排序 group['ds'] = pd.to_datetime(group['ds']) group = group.set_index('ds').sort_index() diff_results = [] ticker = group['ticker'].iloc[0] for months in intervals: # 移位获取间隔months个月的历史数据 shifted = group['y'].shift(months, freq='M') # 计算百分比差异:(当前值-过去值)/过去值 *100 pct_diff = ((group['y'] - shifted) / shifted).dropna() # 取该间隔的平均差异 avg_pct_diff = pct_diff.mean() diff_results.append({ 'ticker': ticker, 'interval_months': months, 'avg_pct_diff': avg_pct_diff }) return pd.DataFrame(diff_results)
2. 多进程并行执行
基于multiprocessing.Pool并行处理所有分组,结合tqdm显示进度:
import time from multiprocessing import Pool, cpu_count from tqdm import tqdm import pandas as pd from dateutil.relativedelta import relativedelta import datetime if __name__ == '__main__': # 假设你的分组数据已经存在于groups_by_ticker和ticker_list中 series = [groups_by_ticker.get_group(ticker) for ticker in ticker_list] start_time = time.time() # 创建进程池,建议用cpu_count()-1避免占满系统资源 with Pool(cpu_count()-1) as p: # 并行计算每个分组的差异 diff_results = list(tqdm(p.imap(calculate_period_diff, series), total=len(series))) # 合并所有结果 final_diff_df = pd.concat(diff_results, ignore_index=True) testtime = time.time() - start_time print(f"多进程计算耗时: {testtime:.2f}秒") print(final_diff_df.head())
三、关键注意事项
- 必须加
if __name__ == '__main__'::Windows系统下多进程需要这个入口,避免子进程重复执行主代码;Linux/macOS加上更兼容。 - 避免全局变量:所有进程间传递的数据都通过函数参数和返回值处理,不要依赖全局变量。
- 数据预处理:确保每个分组的日期列是
datetime类型且已排序,否则移位计算会出错。 - 进程数设置:建议用
cpu_count()-1,留出一个核心给系统进程,避免机器卡顿。
内容的提问来源于stack exchange,提问作者Александр Лепендин
相关产品推荐
相关产品推荐

