Skip to content

check_forecaster_methods_call_check_is_fitted

yohou.testing.check_forecaster_methods_call_check_is_fitted(forecaster, y, X_actual=None, forecasting_horizon=3)

Check all forecaster methods (except fit) raise NotFittedError when unfitted.

Validates that predict()/predict_interval(), observe(), rewind(), and observe_predict()/observe_predict_interval() methods all check fitted state and raise NotFittedError before operating on an unfitted forecaster.

For class-probability forecasters, predict() is the prediction method exercised (they also expose predict_class_proba(), which delegates through the same fitted-state guard).

Parameters

Name Type Description Default
forecaster BaseForecaster

Unfitted forecaster instance

required
y DataFrame

Training/test target data with "time" column

required
X_actual DataFrame

Training/test features with "time" column

None
forecasting_horizon int

Number of steps ahead to forecast

3

Raises

Type Description
AssertionError

If any method fails to raise NotFittedError when called on unfitted forecaster

Source Code

Source code in src/yohou/testing/forecaster.py
def check_forecaster_methods_call_check_is_fitted(
    forecaster,
    y: pl.DataFrame,
    X_actual: pl.DataFrame | None = None,
    forecasting_horizon: int = 3,
) -> None:
    """Check all forecaster methods (except fit) raise NotFittedError when unfitted.

    Validates that predict()/predict_interval(), observe(), rewind(), and
    observe_predict()/observe_predict_interval() methods all check fitted state
    and raise NotFittedError before operating on an unfitted forecaster.

    For class-probability forecasters, predict() is the prediction method
    exercised (they also expose predict_class_proba(), which delegates through
    the same fitted-state guard).

    Parameters
    ----------
    forecaster : BaseForecaster
        Unfitted forecaster instance
    y : pl.DataFrame
        Training/test target data with "time" column
    X_actual : pl.DataFrame, optional
        Training/test features with "time" column
    forecasting_horizon : int, default=3
        Number of steps ahead to forecast

    Raises
    ------
    AssertionError
        If any method fails to raise NotFittedError when called on unfitted forecaster

    """
    forecaster_clone = clone(forecaster)

    # Length-safe slice so observe()/rewind() receive a non-empty frame even on short y.
    stride = max(1, len(y) // 10)
    y_slice = y[:stride]
    X_actual_slice = X_actual[:stride] if X_actual is not None else None

    # Determine if this is an interval forecaster. Only interval forecasters
    # expose predict_interval(); point and class-proba forecasters do not.
    is_interval = hasattr(forecaster_clone, "predict_interval")

    # Test that predict() or predict_interval() raises NotFittedError when unfitted
    try:
        if is_interval:
            forecaster_clone.predict_interval(
                forecasting_horizon=forecasting_horizon,
                coverage_rates=[0.9],
            )
            method_name = "predict_interval"
        else:
            forecaster_clone.predict(forecasting_horizon=forecasting_horizon)
            method_name = "predict"
        raise AssertionError(
            f"{forecaster_clone.__class__.__name__}.{method_name}() must raise NotFittedError when called on unfitted forecaster"
        )
    except NotFittedError:
        pass  # Expected

    # Test that observe() raises NotFittedError when unfitted
    try:
        forecaster_clone.observe(y_slice, X_actual_slice)
        raise AssertionError(
            f"{forecaster_clone.__class__.__name__}.observe() must raise NotFittedError when called on unfitted forecaster"
        )
    except NotFittedError:
        pass  # Expected

    # Test that rewind() raises NotFittedError when unfitted
    try:
        forecaster_clone.rewind(y_slice, X_actual_slice)
        raise AssertionError(
            f"{forecaster_clone.__class__.__name__}.rewind() must raise NotFittedError when called on unfitted forecaster"
        )
    except NotFittedError:
        pass  # Expected

    # Test that observe_predict() or observe_predict_interval() raises NotFittedError when unfitted
    try:
        if is_interval:
            forecaster_clone.observe_predict_interval(y_slice, X_actual_slice, coverage_rates=[0.9])
            method_name = "observe_predict_interval"
        else:
            forecaster_clone.observe_predict(y_slice, X_actual_slice)
            method_name = "observe_predict"
        raise AssertionError(
            f"{forecaster_clone.__class__.__name__}.{method_name}() must raise NotFittedError when called on unfitted forecaster"
        )
    except NotFittedError:
        pass  # Expected