def test_custom_seasonality(self): holidays = pd.DataFrame({ 'ds': pd.to_datetime(['2017-01-02']), 'holiday': ['special_day'], 'prior_scale': [4.], }) m = Prophet(holidays=holidays) m.add_seasonality(name='monthly', period=30, fourier_order=5, prior_scale=2.) self.assertEqual( m.seasonalities['monthly'], { 'period': 30, 'fourier_order': 5, 'prior_scale': 2., 'mode': 'additive', 'condition_name': None }, ) with self.assertRaises(ValueError): m.add_seasonality(name='special_day', period=30, fourier_order=5) with self.assertRaises(ValueError): m.add_seasonality(name='trend', period=30, fourier_order=5) m.add_seasonality(name='weekly', period=30, fourier_order=5) # Test fourier order <= 0 m = Prophet() with self.assertRaises(ValueError): m.add_seasonality(name='weekly', period=7, fourier_order=0) with self.assertRaises(ValueError): m.add_seasonality(name='weekly', period=7, fourier_order=-1) # Test priors m = Prophet(holidays=holidays, yearly_seasonality=False, seasonality_mode='multiplicative') m.add_seasonality(name='monthly', period=30, fourier_order=5, prior_scale=2., mode='additive') m.fit(DATA.copy()) self.assertEqual(m.seasonalities['monthly']['mode'], 'additive') self.assertEqual(m.seasonalities['weekly']['mode'], 'multiplicative') seasonal_features, prior_scales, component_cols, modes = ( m.make_all_seasonality_features(m.history)) self.assertEqual(sum(component_cols['monthly']), 10) self.assertEqual(sum(component_cols['special_day']), 1) self.assertEqual(sum(component_cols['weekly']), 6) self.assertEqual(sum(component_cols['additive_terms']), 10) self.assertEqual(sum(component_cols['multiplicative_terms']), 7) if seasonal_features.columns[0] == 'monthly_delim_1': true = [2.] * 10 + [10.] * 6 + [4.] self.assertEqual(sum(component_cols['monthly'][:10]), 10) self.assertEqual(sum(component_cols['weekly'][10:16]), 6) else: true = [10.] * 6 + [2.] * 10 + [4.] self.assertEqual(sum(component_cols['weekly'][:6]), 6) self.assertEqual(sum(component_cols['monthly'][6:16]), 10) self.assertEqual(prior_scales, true)
def test_logistic_floor(self): m = Prophet(growth='logistic') N = DATA.shape[0] history = DATA.head(N // 2).copy() history['floor'] = 10. history['cap'] = 80. future = DATA.tail(N // 2).copy() future['cap'] = 80. future['floor'] = 10. m.fit(history, algorithm='Newton') self.assertTrue(m.logistic_floor) self.assertTrue('floor' in m.history) self.assertAlmostEqual(m.history['y_scaled'][0], 1.) self.assertEqual(m.fit_kwargs, {'algorithm': 'Newton'}) fcst1 = m.predict(future) m2 = Prophet(growth='logistic') history2 = history.copy() history2['y'] += 10. history2['floor'] += 10. history2['cap'] += 10. future['cap'] += 10. future['floor'] += 10. m2.fit(history2, algorithm='Newton') self.assertAlmostEqual(m2.history['y_scaled'][0], 1.)
def main(): path_example = "../examples" """example 1""" df = read_dataframe(path_examples=path_example, data_idx=4) model, future, forecasted = forecast( df, periods=1096, showflag=True) # uncertainty intervals seem way too wide df.loc[(df['ds'] > '2010-01-01') & (df['ds'] < '2011-01-01'), 'y'] = None model_removed = Prophet().fit(df) fig = model_removed.plot( model_removed.predict(future) ) # model with missing data. prediction of whole data with future. fig.set_figheight(18) fig.set_figwidth(9) plt.title('prediction (model with missing data)') plt.show() """example 2""" df2 = read_dataframe(path_examples=path_example, data_idx=5) model2, future2, forecasted2 = forecast( df2, periods=1096, showflag=True) # extreme outlieres in June 2015 mess up estimate. df2.loc[(df2['ds'] > '2015-06-01') & (df2['ds'] < '2015-06-30'), 'y'] = None model2_removed = Prophet().fit(df2) # Same approach as previous example fig = model2_removed.plot(model2_removed.predict(future2)) fig.set_figheight(18) fig.set_figwidth(9) plt.title('prediction2 (model with missing data)') plt.show()
def test_set_seasonality_mode(self): # Setting attribute m = Prophet() self.assertEqual(m.seasonality_mode, 'additive') m = Prophet(seasonality_mode='multiplicative') self.assertEqual(m.seasonality_mode, 'multiplicative') with self.assertRaises(ValueError): Prophet(seasonality_mode='batman')
def test_fit_predict_constant_history(self): N = DATA.shape[0] train = DATA.head(N // 2).copy() train['y'] = 20 future = pd.DataFrame({'ds': DATA['ds'].tail(N // 2)}) m = Prophet() m.fit(train) fcst = m.predict(future) self.assertEqual(fcst['yhat'].values[-1], 20) train['y'] = 0 future = pd.DataFrame({'ds': DATA['ds'].tail(N // 2)}) m = Prophet() m.fit(train) fcst = m.predict(future) self.assertEqual(fcst['yhat'].values[-1], 0)
def fit_prophet(dtf_train, dtf_test, lst_exog=None, model=None, freq="D", conf=0.95, figsize=(15,10)): ## setup prophet if model is None: model = Prophet(growth="linear", changepoints=None, n_changepoints=25, seasonality_mode="multiplicative", yearly_seasonality="auto", weekly_seasonality="auto", daily_seasonality="auto", holidays=None, interval_width=conf) if lst_exog != None: for regressor in lst_exog: model.add_regressor(regressor) ## train model.fit(dtf_train) ## test dtf_prophet = model.make_future_dataframe(periods=len(dtf_test)+10, freq=freq, include_history=True) if model.growth == "logistic": dtf_prophet["cap"] = dtf_train["cap"].unique()[0] if lst_exog != None: dtf_prophet = dtf_prophet.merge(dtf_train[["ds"]+lst_exog], how="left") dtf_prophet.iloc[-len(dtf_test):][lst_exog] = dtf_test[lst_exog].values dtf_prophet = model.predict(dtf_prophet) dtf_train = dtf_train.merge(dtf_prophet[["ds","yhat"]], how="left").rename( columns={'yhat':'model', 'y':'ts'}).set_index("ds") dtf_test = dtf_test.merge(dtf_prophet[["ds","yhat","yhat_lower","yhat_upper"]], how="left").rename( columns={'yhat':'forecast', 'y':'ts', 'yhat_lower':'lower', 'yhat_upper':'upper'}).set_index("ds") ## evaluate dtf = dtf_train.append(dtf_test) dtf = utils_evaluate_ts_model(dtf, conf=conf, figsize=figsize, title="Prophet") return dtf, model
def _prophet_fit_and_predict( # pylint: disable=too-many-arguments df: DataFrame, confidence_interval: float, yearly_seasonality: Union[bool, str, int], weekly_seasonality: Union[bool, str, int], daily_seasonality: Union[bool, str, int], periods: int, freq: str, ) -> DataFrame: """ Fit a prophet model and return a DataFrame with predicted results. """ try: prophet_logger = logging.getLogger("prophet.plot") prophet_logger.setLevel(logging.CRITICAL) from prophet import Prophet # pylint: disable=import-error prophet_logger.setLevel(logging.NOTSET) except ModuleNotFoundError: raise QueryObjectValidationError(_("`prophet` package not installed")) model = Prophet( interval_width=confidence_interval, yearly_seasonality=yearly_seasonality, weekly_seasonality=weekly_seasonality, daily_seasonality=daily_seasonality, ) if df["ds"].dt.tz: df["ds"] = df["ds"].dt.tz_convert(None) model.fit(df) future = model.make_future_dataframe(periods=periods, freq=freq) forecast = model.predict(future)[[ "ds", "yhat", "yhat_lower", "yhat_upper" ]] return forecast.join(df.set_index("ds"), on="ds").set_index(["ds"])
def _run_prophet(self, data: ProphetDataEntry, params: dict) -> np.ndarray: """ Construct and run a :class:`Prophet` model on the given :class:`ProphetDataEntry` and return the resulting array of samples. """ prophet = self.init_model(Prophet(**params)) # Register dynamic features as regressors to the model for i in range(len(data.feat_dynamic_real)): prophet.add_regressor(feat_name(i)) prophet.fit(data.prophet_training_data) future_df = prophet.make_future_dataframe( periods=self.prediction_length, freq=self.freq, include_history=False, ) # Add dynamic features in the prediction range for i, feature in enumerate(data.feat_dynamic_real): future_df[feat_name(i)] = feature[data.train_length:] prophet_result = prophet.predictive_samples(future_df) return prophet_result["yhat"].T
def forecast(self, forecast_horizon: int = 96): super().forecast(forecast_horizon) print("Running Prophet forecast for Currency-pair: {} using forecast horizon: {}", self.currency_pair.upper(), forecast_horizon) print("Dataset: ", self.currency_pair.upper()) print(self.training_data.head(5)) print(".....\t.........\t...") print(self.training_data.tail(5)) # model = Prophet(interval_width=0.99, mcmc_samples=60) model = Prophet(interval_width=0.99) model.fit(self.training_data) future = model.make_future_dataframe(periods=forecast_horizon) future.tail() _forecast = model.predict(future) last_n = _forecast.tail(forecast_horizon) last_n.to_csv(f"output/{self.currency_pair}__{self.model_name.lower()}__{forecast_horizon}__forecasts.csv") # last_n = _forecast[["ds", "yhat", "yhat_lower", "yhat_upper"]].tail(n) print(last_n) self.forecasts = last_n["yhat"] self.forecasts_upper = last_n["yhat_upper"] self.forecasts_lower = last_n["yhat_lower"] self.errors = [(abs(upper - lower) / 2) for upper, lower in zip(self.forecasts_upper, self.forecasts_lower)] self.forecasts_raw = last_n
def predict(ticker, start_date): today = datetime.date.today() end_date = today.strftime("%Y-%m-%d") data = yf.download(ticker, start_date, end_date) df_forecast = data.copy() df_forecast.reset_index(inplace=True) df_forecast["ds"] = df_forecast["Date"] df_forecast["y"] = df_forecast["Adj Close"] df_forecast = df_forecast[["ds", "y"]] df_forecast model = Prophet() model.fit(df_forecast) future = pd.to_datetime(end_date) + pd.DateOffset(days=7) future_date = future.strftime("%Y-%m-%d") dates = pd.date_range(start=end_date, end=future_date) df_pred = pd.DataFrame({"ds": dates}) forecast = model.predict(df_pred) prediction_list = forecast.tail(7).to_dict("records") output = {} for data in prediction_list: date = data["ds"].strftime("%Y-%m-%d") output[date] = data["trend"] return output
def predict_in_france(data, country, vaccination_metric, future_days, plot=True): df = data[(data['country'] == country)] df = df[['date', vaccination_metric]] df.columns = ['ds', 'y'] model = Prophet(interval_width=0.95) model.fit(df) layout = dict( title= 'Prediction : Nombre de personnes vaccinées par cent dans les 60 prochains jours (jusqu' "'" 'au 28/06/21)', xaxis=dict(title='Dates'), yaxis=dict(title='Pourcentage')) future = model.make_future_dataframe(periods=future_days) forecast = model.predict(future) if plot: fig = plot_plotly(model, forecast) fig.layout = layout fig.write_html("analyse/Prediction_France.html") else: return forecast
def _estimate_weekly_pattern(self, time, energy_per_day, daily_masks): epd = energy_per_day.copy() for i in range(daily_masks.shape[0]): if daily_masks[i] < 1: epd[i] = np.nan daily_times = [i*self.vpd for i in range(daily_masks.shape[0])] try: time_index = pd.to_datetime( time.take(daily_times), format='%Y-%m-%d %H:%M:%S') except ValueError: time_index = pd.to_datetime( time.take(daily_times), format='%d-%b-%Y %H:%M:%S') time_index.reset_index(drop=True, inplace=True) daily_data = pd.concat([time_index, pd.Series( epd)], keys=['ds', 'y'], axis=1) prophet_model = Prophet(weekly_seasonality=True, yearly_seasonality=True) if daily_data.count()['y'] > 1: prophet_model.fit(daily_data) # `future` starts with the first day of the time series. # This allows us to select the corresponding pattern value # for day `i` by accessing `weekly[i % 7]`. future = prophet_model.make_future_dataframe(periods=0) forecast = prophet_model.predict(future) return forecast.get('weekly').head(7) return pd.Series(np.zeros(7))
def __init__(self, demand: float = 20, var_per_day: float = 0.1, var_per_season: float = 0.1) -> None: self.__var_per_day = var_per_day self.__var_per_season = var_per_season self.__mean_demand = demand self.__pt = Prophet(seasonality_mode="multiplicative") self.__periods = 12 * 20 self.data_demand = None
def make_forecast(df, len_forecast: int, time_series_label: str): """ Function for making time series forecasting with Prophet library :param df: dataframe to process :param len_forecast: forecast length :param time_series_label: name of time series to process :return predicted_values: forecast :return model_name: name of the model (always 'AutoTS') """ df['ds'] = df['datetime'] df['y'] = df[time_series_label] prophet_model = Prophet() prophet_model.fit(df) future = prophet_model.make_future_dataframe(periods=len_forecast, include_history=False) forecast = prophet_model.predict(future) predicted_values = np.array(forecast['yhat']) model_name = 'Prophet' return predicted_values, model_name
def test_fit_changepoint_not_in_history(self): train = DATA[(DATA['ds'] < '2013-01-01') | (DATA['ds'] > '2014-01-01')] future = pd.DataFrame({'ds': DATA['ds']}) prophet = Prophet(changepoints=['2013-06-06']) forecaster = prophet forecaster.fit(train) forecaster.predict(future)
def predict_trend(self): object_type = 'PyTrends.trend_ratio' # Pull and prep data conn = sqlite3.connect("db.sqlite3") df = pd.read_sql_query( "select date as ds, btc_usd, buy_bitcoin, trend_ratio from crypto_track_pytrends;", conn) df['y'] = df['trend_ratio'] df['ds'] = pd.to_datetime(df['ds'], errors='coerce') # Get prior 'y' value to fill in nan df['y-1'] = df.y.shift(1) df['y_nan'] = df.y.isna() df.y.fillna(df['y-1'], inplace=True) df.drop(['y-1'], axis=1, inplace=True) # Instantiate a Prophet object future_trend = Prophet(df, 'Trend Ratio') # Change default attributes as analyzed in Trend Prediction.ipynb notebook. future_trend.weekly_seasonality = True future_trend.training_years = 6 future_trend.changepoint_prior_scale = 0.05 future, train, model = future_trend.predict(self.prediction_days) # Create predictions and load table. return_message = self.dbload_prophet(df=future, object_type=object_type) return return_message
def test_prophet_trend_onnx(self): df = self._get_data() m = Prophet() m.fit(df) future = m.make_future_dataframe(periods=365) future_np = (future.values - np.datetime64("1970-01-01T00:00:00.000000000")).astype( np.int64) / 1000000000 # Convert with Hummingbird. hb_model = hummingbird.ml.convert(m, "onnx", future_np) # Predictions. prophet_trend = m.predict(future)["trend"] hb_trend = hb_model.predict(future_np) import onnx onnx.save(hb_model.model, "prophet.onnx") np.testing.assert_allclose(prophet_trend, hb_trend, rtol=1e-06, atol=1e-06)
def get_prophet_forecast(df, country="ALL", save_model=True): df_ts = df.copy() if country == "ALL" else df[df['country'] == country].copy() if len(df_ts) <= 180: return None df_month = df_ts.groupby('inv_month').sum().reset_index() df_ts['inv_date'] = pd.to_datetime(df_ts['inv_date']) df_ts.rename(columns={'inv_date': 'ds', 'value': 'y'}, inplace=True) m = Prophet(yearly_seasonality=20) m.fit(df_ts) if save_model: with open(fr'models\{country}_model.json', 'w') as fout: json.dump(model_to_json(m), fout) # Save model future = m.make_future_dataframe(periods=180, freq='D') forecast = m.predict(future) forecast['inv_month'] = forecast['ds'].apply( lambda v: date(v.year, v.month, 1).isoformat()) monthly_forecast = forecast[['inv_month', 'yhat' ]].groupby('inv_month').sum().reset_index() df_forecast = pd.merge(monthly_forecast, df_month, on='inv_month', how='left') return df_forecast
def test_check_single_cutoff_forecast_func_calls(self): m = Prophet() m.fit(self.__df) mock_predict = pd.DataFrame({ 'ds': pd.date_range(start='2012-09-17', periods=3), 'yhat': np.arange(16, 19), 'yhat_lower': np.arange(15, 18), 'yhat_upper': np.arange(17, 20), 'y': np.arange(16.5, 19.5), 'cutoff': [datetime.date(2012, 9, 15)] * 3 }) # cross validation with 3 and 7 forecasts for args, forecasts in ((['4 days', '10 days', '115 days'], 3), (['4 days', '4 days', '115 days'], 7)): with patch( 'prophet.diagnostics.single_cutoff_forecast') as mock_func: mock_func.return_value = mock_predict df_cv = diagnostics.cross_validation(m, *args) # check single forecast function called expected number of times self.assertEqual(diagnostics.single_cutoff_forecast.call_count, forecasts)
def test_cross_validation_extra_regressors(self): df = self.__df.copy() df['extra'] = range(df.shape[0]) df['is_conditional_week'] = np.arange(df.shape[0]) // 7 % 2 m = Prophet() m.add_seasonality(name='monthly', period=30.5, fourier_order=5) m.add_seasonality(name='conditional_weekly', period=7, fourier_order=3, prior_scale=2., condition_name='is_conditional_week') m.add_regressor('extra') m.fit(df) df_cv = diagnostics.cross_validation(m, horizon='4 days', period='4 days', initial='135 days') self.assertEqual(len(np.unique(df_cv['cutoff'])), 2) period = pd.Timedelta('4 days') dc = df_cv['cutoff'].diff() dc = dc[dc > pd.Timedelta(0)].min() self.assertTrue(dc >= period) self.assertTrue((df_cv['cutoff'] < df_cv['ds']).all()) df_merged = pd.merge(df_cv, self.__df, 'left', on='ds') self.assertAlmostEqual( np.sum((df_merged['y_x'] - df_merged['y_y'])**2), 0.0)
def get_forecast(df, month, country="ALL"): df_ts = df.copy() if country=="ALL" else df[df['country']==country].copy() if len(df_ts) <= 180: return None actual = df_ts[df_ts['inv_month'] == month.isoformat()]['value'].sum() df_ts = df_ts[['inv_month', 'inv_date', 'value']].groupby(['inv_month', 'inv_date']).sum().reset_index() df_train = df_ts[df_ts['inv_month'] < month.isoformat()] df_train['inv_date'] = pd.to_datetime(df_train['inv_date']) df_train.rename(columns={'inv_date':'ds', 'value':'y'}, inplace=True) m = Prophet(yearly_seasonality=20) m.fit(df_train) future = m.make_future_dataframe(periods=60, freq='D') df_forecast = m.predict(future) df_forecast['inv_month'] = df_forecast['ds'].apply(lambda v: date(v.year, v.month, 1).isoformat()) forecast = df_forecast[df_forecast['inv_month'] == month.isoformat()]['yhat'].sum() exp_model = SimpleExpSmoothing(df_ts[['inv_month', 'inv_date', 'value']].set_index(['inv_month', 'inv_date'])).fit(smoothing_level=0.2, optimized=False) exp_forecast = forecast_df = sum(exp_model.forecast(30)) return actual, forecast, exp_forecast
def train(self, metric_data=None, prediction_duration=15): """Train the Prophet model and store the predictions in predicted_df.""" prediction_freq = "1MIN" # convert incoming metric to Metric Object if metric_data: # because the rolling_data_window_size is set, this df should not bloat self.metric += Metric(metric_data) # Don't really need to store the model, as prophet models are not retrainable # But storing it as an example for other models that can be retrained self.model = Prophet(daily_seasonality=True, weekly_seasonality=True, yearly_seasonality=True) _LOGGER.info("training data range: %s - %s", self.metric.start_time, self.metric.end_time) # _LOGGER.info("training data end time: %s", self.metric.end_time) _LOGGER.debug("begin training") self.model.fit(self.metric.metric_values) future = self.model.make_future_dataframe( periods=int(prediction_duration), freq=prediction_freq, include_history=False, ) forecast = self.model.predict(future) forecast["timestamp"] = forecast["ds"] forecast = forecast[["timestamp", "yhat", "yhat_lower", "yhat_upper"]] forecast = forecast.set_index("timestamp") self.predicted_df = forecast _LOGGER.debug(forecast)
def generate_forecast(df: pd.DataFrame, length: int) -> pd.DataFrame: """Takes in a training set (data - value) and a length to return a forecast DataFrame""" model = Prophet(interval_width=0.50) model.fit(df) return model.predict(model.make_future_dataframe(periods=length))
def test_fit_predict_no_changepoints_mcmc(self): N = DATA.shape[0] train = DATA.head(N // 2) future = DATA.tail(N // 2) forecaster = Prophet(n_changepoints=0, mcmc_samples=100) forecaster.fit(train) forecaster.predict(future)
def test_fit_predict_no_seasons(self): N = DATA.shape[0] train = DATA.head(N // 2) future = DATA.tail(N // 2) forecaster = Prophet(weekly_seasonality=False, yearly_seasonality=False) forecaster.fit(train) forecaster.predict(future)
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Train the Prophet model on each time tick. df = dataframe[['time', 'close']] \ .rename(columns={'time': 'ds', 'close': 'y'}) self.model = Prophet(interval_width=0.95, daily_seasonality=True) self.model.fit(df) return dataframe
def test_subdaily_holidays(self): holidays = pd.DataFrame({ 'ds': pd.to_datetime(['2017-01-02']), 'holiday': ['special_day'], }) m = Prophet(holidays=holidays) m.fit(DATA2) fcst = m.predict() self.assertEqual(sum(fcst['special_day'] == 0), 575)
def fit(df, args): m = Prophet(changepoint_prior_scale=args.changepoint_prior_scale, interval_width=args.interval_width, mcmc_samples=args.mcmc_samples) m.add_country_holidays(country_name='US') # m.add_regressor('low', prior_scale=0.5, mode='multiplicative') ? print(f'Model is trained on {len(df)} data') m.fit(df) return m
def test_auto_weekly_seasonality(self): # Should be enabled N = 15 train = DATA.head(N) m = Prophet() self.assertEqual(m.weekly_seasonality, 'auto') m.fit(train) self.assertIn('weekly', m.seasonalities) self.assertEqual( m.seasonalities['weekly'], { 'period': 7, 'fourier_order': 3, 'prior_scale': 10., 'mode': 'additive', 'condition_name': None }, ) # Should be disabled due to too short history N = 9 train = DATA.head(N) m = Prophet() m.fit(train) self.assertNotIn('weekly', m.seasonalities) m = Prophet(weekly_seasonality=True) m.fit(train) self.assertIn('weekly', m.seasonalities) # Should be False due to weekly spacing train = DATA.iloc[::7, :] m = Prophet() m.fit(train) self.assertNotIn('weekly', m.seasonalities) m = Prophet(weekly_seasonality=2, seasonality_prior_scale=3.) m.fit(DATA) self.assertEqual( m.seasonalities['weekly'], { 'period': 7, 'fourier_order': 2, 'prior_scale': 3., 'mode': 'additive', 'condition_name': None }, )
def test_fit_with_holidays(self): holidays = pd.DataFrame({ 'ds': pd.to_datetime(['2012-06-06', '2013-06-06']), 'holiday': ['seans-bday'] * 2, 'lower_window': [0] * 2, 'upper_window': [1] * 2, }) model = Prophet(holidays=holidays, uncertainty_samples=0) model.fit(DATA).predict()