Example #1
0
def test_prophet_hyperparameter_grid_exception():
    """Tests prophet_hyperparameter_grid exceptions"""
    # unknown argument
    with pytest.raises(ValueError, match=r"Unexpected key\(s\) found"):
        model_components = ModelComponentsParam(
            seasonality={"unknown_seasonality": ["additive"]})
        template = ProphetTemplate()
        template.config = template.apply_forecast_config_defaults()
        template.config.model_components_param = model_components
        template.get_hyperparameter_grid()

    # regressor must be specified under `add_regressor_dict`, not directly
    with pytest.raises(ValueError, match=r"Unexpected key\(s\) found"):
        model_components = ModelComponentsParam(
            regressors={
                "regressor1": {
                    "prior_scale": 10,
                    "standardize": True,
                    "mode": "additive"
                },
                "regressor2": {
                    "prior_scale": 15,
                    "standardize": False,
                    "mode": "additive"
                },
                "regressor3": {}
            })
        template = ProphetTemplate()
        template.config = template.apply_forecast_config_defaults()
        template.config.model_components_param = model_components
        template.get_hyperparameter_grid()
Example #2
0
def test_prophet_hyperparameter_grid_seasonality_growth(default_holidays):
    """Tests get_hyperparameter_grid for basic seasonality, growth and other default params"""
    seasonality = {"yearly_seasonality": [True], "weekly_seasonality": [False]}
    growth = {"growth_term": ["linear"]}
    model_components = ModelComponentsParam(seasonality=seasonality,
                                            growth=growth)
    template = ProphetTemplate()
    template.config = template.apply_forecast_config_defaults()
    template.config.model_components_param = model_components
    hyperparameter_grid = template.get_hyperparameter_grid()
    # Expected Values
    expected_holidays = default_holidays
    expected_grid = {
        "estimator__growth": ["linear"],
        "estimator__seasonality_mode": ["additive"],
        "estimator__seasonality_prior_scale": [10.0],
        "estimator__yearly_seasonality": [True],
        "estimator__weekly_seasonality": [False],
        "estimator__daily_seasonality": ["auto"],
        "estimator__add_seasonality_dict": [None],
        "estimator__holidays": [expected_holidays],
        "estimator__holidays_prior_scale": [10.0],
        "estimator__changepoint_prior_scale": [0.05],
        "estimator__changepoints": [None],
        "estimator__n_changepoints": [25],
        "estimator__changepoint_range": [0.8],
        "estimator__mcmc_samples": [0],
        "estimator__uncertainty_samples": [1000],
        "estimator__add_regressor_dict": [None]
    }
    # Assertions
    assert_equal(actual=hyperparameter_grid, expected=expected_grid)
Example #3
0
def test_prophet_hyperparameter_grid_default():
    """Tests get_hyperparameter_grid and apply_prophet_model_components_defaults"""
    template = ProphetTemplate()
    template.config = template.apply_forecast_config_defaults()
    # both model_components, time_properties are None
    hyperparameter_grid = template.get_hyperparameter_grid()
    expected_holidays = template.get_prophet_holidays(year_list=list(
        range(2015 - 1, 2030 + 2)),
                                                      countries="auto",
                                                      lower_window=-2,
                                                      upper_window=2)
    expected_grid = {
        "estimator__growth": ["linear"],
        "estimator__seasonality_mode": ["additive"],
        "estimator__seasonality_prior_scale": [10.0],
        "estimator__yearly_seasonality": ["auto"],
        "estimator__weekly_seasonality": ["auto"],
        "estimator__daily_seasonality": ["auto"],
        "estimator__add_seasonality_dict": [None],
        "estimator__holidays": [expected_holidays],
        "estimator__holidays_prior_scale": [10.0],
        "estimator__changepoint_prior_scale": [0.05],
        "estimator__changepoints": [None],
        "estimator__n_changepoints": [25],
        "estimator__changepoint_range": [0.8],
        "estimator__mcmc_samples": [0],
        "estimator__uncertainty_samples": [1000],
        "estimator__add_regressor_dict": [None]
    }
    assert_equal(actual=hyperparameter_grid, expected=expected_grid)
Example #4
0
def test_prophet_hyperparameter_grid_events():
    """Tests get_prophet_hyperparameter_grid for selected Countries" holidays"""
    # holiday params
    start_year = 2018
    end_year = 2022
    holiday_pre_num_days = [1]
    holiday_post_num_days = [1]
    holiday_lookup_countries = ["UnitedStates", "China", "India"]
    holidays_prior_scale = [5.0, 10.0, 15.0]
    events = {
        "holiday_lookup_countries": holiday_lookup_countries,
        "holiday_pre_num_days": holiday_pre_num_days,
        "holiday_post_num_days": holiday_post_num_days,
        "start_year": start_year,
        "end_year": end_year,
        "holidays_prior_scale": holidays_prior_scale
    }
    model_components = ModelComponentsParam(events=events)
    template = ProphetTemplate()
    template.config = template.apply_forecast_config_defaults()
    template.config.model_components_param = model_components
    hyperparameter_grid = template.get_hyperparameter_grid()

    # Expected Values
    # Holidays df, based on given holidays params
    expected_holidays = template.get_prophet_holidays(
        year_list=list(range(start_year - 1, end_year + 2)),
        countries=holiday_lookup_countries,
        lower_window=-holiday_pre_num_days[0],
        upper_window=holiday_post_num_days[0])

    expected_grid = {
        "estimator__growth": ["linear"],
        "estimator__seasonality_mode": ["additive"],
        "estimator__seasonality_prior_scale": [10.0],
        "estimator__yearly_seasonality": ["auto"],
        "estimator__weekly_seasonality": ["auto"],
        "estimator__daily_seasonality": ["auto"],
        "estimator__add_seasonality_dict": [None],
        "estimator__holidays": [expected_holidays],
        "estimator__holidays_prior_scale": [5.0, 10.0, 15.0],
        "estimator__changepoint_prior_scale": [0.05],
        "estimator__changepoints": [None],
        "estimator__n_changepoints": [25],
        "estimator__changepoint_range": [0.8],
        "estimator__mcmc_samples": [0],
        "estimator__uncertainty_samples": [1000],
        "estimator__add_regressor_dict": [None]
    }
    # Assertions
    assert_equal(actual=hyperparameter_grid, expected=expected_grid)
Example #5
0
def test_hyperparameter_override(default_holidays):
    """Tests the hyperparameter_override functionality.
    Use hyperparameter_override to override parameters and
    create multiple sets of grids.
    """
    model_components = ModelComponentsParam(
        seasonality={
            "yearly_seasonality": [True, False],
            "weekly_seasonality": False,
        },
        hyperparameter_override=[{
            "input__response__null__max_frac": 0.1,
            "estimator__yearly_seasonality": True,
            "estimator__growth": ["logistic"],
        }, {}])
    template = ProphetTemplate()
    template.config = template.apply_forecast_config_defaults()
    template.config.model_components_param = model_components
    hyperparameter_grid = template.get_hyperparameter_grid()
    expected_grid = {
        "estimator__growth": ["linear"],
        "estimator__seasonality_mode": ["additive"],
        "estimator__seasonality_prior_scale": [10.0],
        "estimator__yearly_seasonality": [True, False],
        "estimator__weekly_seasonality": [False],
        "estimator__daily_seasonality": ["auto"],
        "estimator__add_seasonality_dict": [None],
        "estimator__holidays": [default_holidays],
        "estimator__holidays_prior_scale": [10.0],
        "estimator__changepoint_prior_scale": [0.05],
        "estimator__changepoints": [None],
        "estimator__n_changepoints": [25],
        "estimator__changepoint_range": [0.8],
        "estimator__mcmc_samples": [0],
        "estimator__uncertainty_samples": [1000],
        "estimator__add_regressor_dict": [None]
    }
    updated_grid = expected_grid.copy()
    updated_grid["input__response__null__max_frac"] = [0.1]
    updated_grid["estimator__yearly_seasonality"] = [True]
    updated_grid["estimator__growth"] = ["logistic"]
    assert_equal(hyperparameter_grid, [updated_grid, expected_grid])
Example #6
0
def test_prophet_hyperparameter_grid_auto_list(default_holidays):
    """Tests `get_prophet_hyperparameter_grid` automatic list conversion
    via `dictionaries_values_to_lists`. Holidays are tested separately
    because they are not directly passed to ProphetEstimator."""
    growth = {"growth_term": "linear"}
    seasonality = {
        "seasonality_mode": "multiplicative",
        "seasonality_prior_scale": 10.0,
        "yearly_seasonality": False,
        "weekly_seasonality": False,
        "daily_seasonality": True,
        "add_seasonality_dict": {
            "yearly": {
                "period": 365.25,
                "fourier_order": 20,
                "prior_scale": 20.0
            },
            "quarterly": {
                "period": 365.25 / 4,
                "fourier_order": 15
            },
            "weekly": {
                "period": 7,
                "fourier_order": 35,
                "prior_scale": 30.0
            }
        }
    }

    changepoints = {
        "changepoint_prior_scale": 0.05,
        "changepoints": ["2018-10-11", "2018-11-11", "2019-01-17"],
        "n_changepoints": 25,
        "changepoint_range": 0.8
    }
    uncertainty = {"mcmc_samples": 0, "uncertainty_samples": 1000}
    regressors = {
        "add_regressor_dict": {
            "reg_col1": {
                "prior_scale": 10.0,
                "standardize": False,
                "mode": "additive"
            },
            "reg_col2": {
                "prior_scale": 20.0,
                "standardize": True,
                "mode": "multiplicative"
            }
        }
    }
    model_components = ModelComponentsParam(growth=growth,
                                            seasonality=seasonality,
                                            changepoints=changepoints,
                                            regressors=regressors,
                                            uncertainty=uncertainty)
    template = ProphetTemplate()
    template.config = template.apply_forecast_config_defaults()
    template.config.model_components_param = model_components
    hyperparameter_grid = template.get_hyperparameter_grid()

    # Expected Values
    expected_grid = {
        "estimator__growth": ["linear"],
        "estimator__seasonality_mode": ["multiplicative"],
        "estimator__seasonality_prior_scale": [10.0],
        "estimator__yearly_seasonality": [False],
        "estimator__weekly_seasonality": [False],
        "estimator__daily_seasonality": [True],
        "estimator__add_seasonality_dict":
        [seasonality["add_seasonality_dict"]],
        "estimator__holidays": [default_holidays],
        "estimator__holidays_prior_scale": [10.0],
        "estimator__changepoint_prior_scale": [0.05],
        "estimator__changepoints": [["2018-10-11", "2018-11-11",
                                     "2019-01-17"]],
        "estimator__n_changepoints": [25],
        "estimator__changepoint_range": [0.8],
        "estimator__mcmc_samples": [0],
        "estimator__uncertainty_samples": [1000],
        "estimator__add_regressor_dict": [{
            "reg_col1": {
                "prior_scale": 10.0,
                "standardize": False,
                "mode": "additive"
            },
            "reg_col2": {
                "prior_scale": 20.0,
                "standardize": True,
                "mode": "multiplicative"
            }
        }]
    }
    assert_equal(actual=hyperparameter_grid, expected=expected_grid)
Example #7
0
def test_prophet_hyperparameter_grid_changepoints_uncertainty_custom(
        default_holidays):
    """Tests get_prophet_hyperparameter_grid for selected
    changepoints, regressor, and uncertainty"""
    changepoints = {
        "changepoint_prior_scale": [0.05, 1.0, 5.0, 10.0, 15.0],
        "changepoints": [None, ["2018-10-11", "2018-11-11", "2019-01-17"]],
        "n_changepoints": [25, 50, 100],
        "changepoint_range": [0.8, 0.9]
    }
    uncertainty = {
        "mcmc_samples": [0, 1000],
        "uncertainty_samples": [1000, 2000]
    }
    regressors = {
        "add_regressor_dict": [{
            "reg_col1": {
                "prior_scale": 10.0,
                "standardize": False,
                "mode": "additive"
            },
            "reg_col2": {
                "prior_scale": 20.0,
                "standardize": True,
                "mode": "multiplicative"
            }
        }, {
            "reg_col1": {
                "prior_scale": 20.0,
                "standardize": True,
                "mode": "additive"
            },
            "reg_col2": {
                "prior_scale": 40.0,
                "standardize": False,
                "mode": "multiplicative"
            }
        }]
    }
    model_components = ModelComponentsParam(changepoints=changepoints,
                                            regressors=regressors,
                                            uncertainty=uncertainty)
    template = ProphetTemplate()
    template.config = template.apply_forecast_config_defaults()
    template.config.model_components_param = model_components
    hyperparameter_grid = template.get_hyperparameter_grid()

    # Expected Values
    expected_holidays = default_holidays
    expected_grid = {
        "estimator__growth": ["linear"],
        "estimator__seasonality_mode": ["additive"],
        "estimator__seasonality_prior_scale": [10.0],
        "estimator__yearly_seasonality": ["auto"],
        "estimator__weekly_seasonality": ["auto"],
        "estimator__daily_seasonality": ["auto"],
        "estimator__add_seasonality_dict": [None],
        "estimator__holidays": [expected_holidays],
        "estimator__holidays_prior_scale": [10.0],
        "estimator__changepoint_prior_scale": [0.05, 1.0, 5.0, 10.0, 15.0],
        "estimator__changepoints":
        [None, ["2018-10-11", "2018-11-11", "2019-01-17"]],
        "estimator__n_changepoints": [25, 50, 100],
        "estimator__changepoint_range": [0.8, 0.9],
        "estimator__mcmc_samples": [0, 1000],
        "estimator__uncertainty_samples": [1000, 2000],
        "estimator__add_regressor_dict": [{
            "reg_col1": {
                "prior_scale": 10.0,
                "standardize": False,
                "mode": "additive"
            },
            "reg_col2": {
                "prior_scale": 20.0,
                "standardize": True,
                "mode": "multiplicative"
            }
        }, {
            "reg_col1": {
                "prior_scale": 20.0,
                "standardize": True,
                "mode": "additive"
            },
            "reg_col2": {
                "prior_scale": 40.0,
                "standardize": False,
                "mode": "multiplicative"
            }
        }]
    }
    assert_equal(actual=hyperparameter_grid, expected=expected_grid)
Example #8
0
def test_prophet_hyperparameter_grid_custom_seasonality(default_holidays):
    """Tests get_prophet_hyperparameter_grid for custom seasonality params, other params being defaults"""
    seasonality = {
        "seasonality_mode": ["additive", "multiplicative"],
        "seasonality_prior_scale": [5.0, 10.0, 15.0],
        "yearly_seasonality": [True, False],
        "weekly_seasonality": [True, False],
        "daily_seasonality": [True, False],
        "add_seasonality_dict": [{
            "yearly": {
                "period": 365.25,
                "fourier_order": 20,
                "prior_scale": 20.0
            },
            "quarterly": {
                "period": 365.25 / 4,
                "fourier_order": 15
            },
            "weekly": {
                "period": 7,
                "fourier_order": 35,
                "prior_scale": 30.0
            }
        }, {
            "yearly": {
                "period": 365.25,
                "fourier_order": 10,
                "prior_scale": 20.0
            },
            "quarterly": {
                "period": 365.25 / 4,
                "fourier_order": 3
            },
            "weekly": {
                "period": 7,
                "fourier_order": 5,
                "prior_scale": 20.0
            }
        }, {
            "yearly": {
                "period": 365.25,
                "fourier_order": 10,
                "prior_scale": 30.0
            },
            "quarterly": {
                "period": 365.25 / 4,
                "fourier_order": 5
            },
            "weekly": {
                "period": 7,
                "fourier_order": 15,
                "prior_scale": 20.0
            }
        }, {
            "yearly": {
                "period": 365.25,
                "fourier_order": 15,
                "prior_scale": 20.0
            },
            "quarterly": {
                "period": 365.25 / 4,
                "fourier_order": 10
            },
            "weekly": {
                "period": 7,
                "fourier_order": 25,
                "prior_scale": 20.0
            }
        }]
    }
    model_components = ModelComponentsParam(seasonality=seasonality)
    template = ProphetTemplate()
    template.config = template.apply_forecast_config_defaults()
    template.config.model_components_param = model_components
    hyperparameter_grid = template.get_hyperparameter_grid()

    # Expected Values
    expected_holidays = default_holidays
    expected_grid = {
        "estimator__growth": ["linear"],
        "estimator__seasonality_mode": ["additive", "multiplicative"],
        "estimator__seasonality_prior_scale": [5.0, 10.0, 15.0],
        "estimator__yearly_seasonality": [True, False],
        "estimator__weekly_seasonality": [True, False],
        "estimator__daily_seasonality": [True, False],
        "estimator__add_seasonality_dict": [{
            "yearly": {
                "period": 365.25,
                "fourier_order": 20,
                "prior_scale": 20.0
            },
            "quarterly": {
                "period": 365.25 / 4,
                "fourier_order": 15
            },
            "weekly": {
                "period": 7,
                "fourier_order": 35,
                "prior_scale": 30.0
            }
        }, {
            "yearly": {
                "period": 365.25,
                "fourier_order": 10,
                "prior_scale": 20.0
            },
            "quarterly": {
                "period": 365.25 / 4,
                "fourier_order": 3
            },
            "weekly": {
                "period": 7,
                "fourier_order": 5,
                "prior_scale": 20.0
            }
        }, {
            "yearly": {
                "period": 365.25,
                "fourier_order": 10,
                "prior_scale": 30.0
            },
            "quarterly": {
                "period": 365.25 / 4,
                "fourier_order": 5
            },
            "weekly": {
                "period": 7,
                "fourier_order": 15,
                "prior_scale": 20.0
            }
        }, {
            "yearly": {
                "period": 365.25,
                "fourier_order": 15,
                "prior_scale": 20.0
            },
            "quarterly": {
                "period": 365.25 / 4,
                "fourier_order": 10
            },
            "weekly": {
                "period": 7,
                "fourier_order": 25,
                "prior_scale": 20.0
            }
        }],
        "estimator__holidays": [expected_holidays],
        "estimator__holidays_prior_scale": [10.0],
        "estimator__changepoint_prior_scale": [0.05],
        "estimator__changepoints": [None],
        "estimator__n_changepoints": [25],
        "estimator__changepoint_range": [0.8],
        "estimator__mcmc_samples": [0],
        "estimator__uncertainty_samples": [1000],
        "estimator__add_regressor_dict": [None]
    }
    # Assertions
    assert_equal(actual=hyperparameter_grid, expected=expected_grid)
Example #9
0
def test_prophet_hyperparameter_grid_warn():
    """Tests get_prophet_hyperparameter_grid warnings"""
    # holiday params
    start_year = 2018
    end_year = 2022
    holiday_pre_num_days = [1, 2, 3, 4]
    holiday_post_num_days = [1, 2, 3, 4]
    holiday_lookup_countries = [["UnitedStates"],
                                ["UnitedStates", "China", "India"]]
    holidays_prior_scale = [5.0, 10.0, 15.0]
    events = {
        "holiday_lookup_countries": holiday_lookup_countries,
        "holiday_pre_num_days": holiday_pre_num_days,
        "holiday_post_num_days": holiday_post_num_days,
        "start_year": start_year,
        "end_year": end_year,
        "holidays_prior_scale": holidays_prior_scale
    }
    model_components = ModelComponentsParam(events=events)
    with pytest.warns(Warning) as record:
        template = ProphetTemplate()
        template.config = template.apply_forecast_config_defaults()
        template.config.model_components_param = model_components
        template.get_hyperparameter_grid()
        assert f"`events['holiday_pre_num_days']` list has more than 1 element. "\
               f"We currently support only 1 element. "\
               f"Using 1." in record[0].message.args[0]
        assert f"`events['holiday_post_num_days']` list has more than 1 element. " \
               f"We currently support only 1 element. " \
               f"Using 1." in record[1].message.args[0]
        # Extra spaces for holidays to align with actual warning in the function, because of an extra tab.
        assert f"`events['holiday_lookup_countries']` contains multiple options. "\
               f"We currently support only 1 option. Using ['UnitedStates']." in record[2].message.args[0]

    # other invalid holiday_lookup_countries
    with pytest.warns(Warning) as record:
        events["holiday_pre_num_days"] = [1]
        events["holiday_post_num_days"] = [0]
        events["holiday_lookup_countries"] = ["auto", None]
        model_components = ModelComponentsParam(events=events)
        template = ProphetTemplate()
        template.config = template.apply_forecast_config_defaults()
        template.config.model_components_param = model_components
        template.get_hyperparameter_grid()
        assert f"`events['holiday_lookup_countries']` contains multiple options. " \
               f"We currently support only 1 option. Using auto." in record[0].message.args[0]

    # no warning if only one list of holiday_lookup_countries is provided
    with pytest.warns(None):
        events["holiday_pre_num_days"] = [1]
        events["holiday_post_num_days"] = [0]
        events["holiday_lookup_countries"] = [[
            "UnitedStates", "China", "UnitedKingdom", "India"
        ]]
        template = ProphetTemplate()
        template.config = template.apply_forecast_config_defaults()
        template.config.model_components_param = ModelComponentsParam(
            events=events)
        hyp1 = template.get_hyperparameter_grid()

        events["holiday_lookup_countries"] = [
            "UnitedStates", "China", "UnitedKingdom", "India"
        ]
        template = ProphetTemplate()
        template.config = template.apply_forecast_config_defaults()
        template.config.model_components_param = ModelComponentsParam(
            events=events)
        hyp2 = template.get_hyperparameter_grid()
        assert_equal(hyp1, hyp2)
Example #10
0
def test_get_regressor_cols():
    """Tests get_regressor_names"""
    # `add_regressor_dict` is a list of dict
    template = ProphetTemplate()
    model_components = ModelComponentsParam(
        regressors={
            "add_regressor_dict": [{
                "regressor1": {
                    "prior_scale": 10,
                    "standardize": True,
                    "mode": "additive"
                },
                "regressor2": {
                    "prior_scale": 15,
                    "standardize": False,
                    "mode": "additive"
                },
                "regressor3": {}
            }, None, {
                "regressor1": {
                    "prior_scale": 10,
                    "standardize": True,
                    "mode": "additive"
                },
                "regressor4": {
                    "prior_scale": 15,
                    "standardize": False,
                    "mode": "additive"
                },
                "regressor5": {}
            }]
        })
    template.config = ForecastConfig(model_components_param=model_components)
    assert set(template.get_regressor_cols()) == {
        "regressor1", "regressor2", "regressor3", "regressor4", "regressor5"
    }

    # `add_regressor_dict` is a single dict
    model_components = ModelComponentsParam(
        regressors={
            "add_regressor_dict": {
                "regressor1": {
                    "prior_scale": 10,
                    "standardize": True,
                    "mode": "additive"
                },
                "regressor2": {
                    "prior_scale": 15,
                    "standardize": False,
                    "mode": "additive"
                },
                "regressor3": {}
            }
        })
    template.config = ForecastConfig(model_components_param=model_components)
    assert set(template.get_regressor_cols()) == {
        "regressor1", "regressor2", "regressor3"
    }

    # no regressors
    model_components = ModelComponentsParam()
    template.config = ForecastConfig(model_components_param=model_components)
    assert template.get_regressor_cols() is None

    model_components = ModelComponentsParam(regressors={})
    template.config = ForecastConfig(model_components_param=model_components)
    assert template.get_regressor_cols() is None

    model_components = ModelComponentsParam(
        regressors={"add_regressor_dict": []})
    template.config = ForecastConfig(model_components_param=model_components)
    assert template.get_regressor_cols() is None

    model_components = ModelComponentsParam(
        regressors={"add_regressor_dict": [{}, None]})
    template.config = ForecastConfig(model_components_param=model_components)
    assert template.get_regressor_cols() is None