使用fbprophet指定cutoffs做交叉验证时触发ValueError报错
问题:Prophet交叉验证触发
ValueError: Dataframe has no rows. 问题背景
时间序列数据范围为2017-01-01至2022-07-01,已完成fbprophet模型的创建与拟合。使用cross_validation函数指定cutoffs(生成月度时间点从2021-01-01到2022-06-01),尝试查看最近7个月的交叉验证结果时触发报错。
执行代码
df_cv2 = cross_validation(model=m, cutoffs=cutoffs, horizon='30 days')
完整报错栈
ValueError Traceback (most recent call last) <ipython-input-323-75c1d39c86f3> in <module> ----> 1 df_cv2 = cross_validation(model=m, cutoffs=cutoffs, horizon='30 days') C:\ProgramData\Anaconda3\lib\site-packages\prophet\diagnostics.py in cross_validation(model, horizon, period, initial, parallel, cutoffs, disable_tqdm) 197 198 else: ---> 199 predicts = [ 200 single_cutoff_forecast(df, model, cutoff, horizon, predict_columns) 201 for cutoff in (tqdm(cutoffs) if not disable_tqdm else cutoffs) C:\ProgramData\Anaconda3\lib\site-packages\prophet\diagnostics.py in <listcomp>(.0) 198 else: 199 predicts = [ ---> 200 single_cutoff_forecast(df, model, cutoff, horizon, predict_columns) 201 for cutoff in (tqdm(cutoffs) if not disable_tqdm else cutoffs) 202 ] C:\ProgramData\Anaconda3\lib\site-packages\prophet\diagnostics.py in single_cutoff_forecast(df, model, cutoff, horizon, predict_columns) 251 for props in m.seasonalities.values() 252 if props['condition_name'] is not None]) ---> 253 yhat = m.predict(df[index_predicted][columns]) 254 # Merge yhat(predicts), y(df, original data) and cutoff 255 C:\ProgramData\Anaconda3\lib\site-packages\prophet\forecaster.py in predict(self, df) 1202 else: 1203 if df.shape[0] == 0: -> 1204 raise ValueError('Dataframe has no rows.') 1205 df = self.setup_dataframe(df.copy()) 1206 ValueError: Dataframe has no rows.
数据框样例
y ds 0 -1.0 2017-01-01 978 2.0 2017-02-01 1582 0.0 2017-03-01 2237 0.0 2017-04-01 2902 0.0 2017-05-01
cutoff生成代码与结果
cutoffs = pd.date_range(start='2021-01-01', end='2022-06-01', freq='1MS')
生成的cutoffs:
DatetimeIndex(['2021-01-01', '2021-02-01', '2021-03-01', '2021-04-01', '2021-05-01', '2021-06-01', '2021-07-01', '2021-08-01', '2021-09-01', '2021-10-01', '2021-11-01', '2021-12-01', '2022-01-01', '2022-02-01', '2022-03-01', '2022-04-01', '2022-05-01', '2022-06-01'], dtype='datetime64[ns]', freq='MS')
报错原因分析
- 时间范围超出边界:原始数据截止到2022-07-01,当cutoff为2022-06-01时,
horizon='30 days'要求预测到2022-07-01之后的时间点,但原始数据中没有该范围内的观测值,导致生成的预测用Dataframe为空。 - 时间粒度不匹配:数据是月度频率(每月一条记录),但horizon使用了
30 days,可能出现时间点不匹配的情况,找不到对应日期的观测数据。
解决方法
方法1:调整cutoffs的结束时间
将cutoffs的结束时间提前,确保cutoff加上horizon不超过数据的最大时间:
cutoffs = pd.date_range(start='2021-01-01', end='2022-05-01', freq='1MS')
方法2:匹配时间粒度设置horizon
因为数据是月度的,将horizon改为月度单位,避免时间点匹配问题:
df_cv2 = cross_validation(model=m, cutoffs=cutoffs, horizon='1 month')
方法3:自动过滤无效cutoffs
提前筛选出那些cutoff + horizon不超过数据最大时间的有效cutoffs:
max_ds = df['ds'].max() horizon = '30 days' valid_cutoffs = [cutoff for cutoff in cutoffs if cutoff + pd.Timedelta(horizon) <= max_ds] df_cv2 = cross_validation(model=m, cutoffs=valid_cutoffs, horizon=horizon)
内容的提问来源于stack exchange,提问作者Mohamed Najb
相关产品推荐
相关产品推荐

