File size: 2,499 Bytes
5c0af90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
"""
inference.py — SARIMAX Groundwater Level Forecasting
=====================================================
Usage
-----
    from inference import load_model, forecast
    model = load_model()
    predictions, conf_int = forecast(model, steps=12, exog_future=X_future)
"""

import json
import joblib
import numpy as np
import pandas as pd
from pathlib import Path

MODEL_PATH  = Path(__file__).parent / "sarimax_model.pkl"
CONFIG_PATH = Path(__file__).parent / "model_config.json"


def load_model():
    """Load the fitted SARIMAX model."""
    return joblib.load(MODEL_PATH)


def load_config():
    """Load model configuration and metrics."""
    with open(CONFIG_PATH) as f:
        return json.load(f)


def forecast(model, steps: int, exog_future: pd.DataFrame):
    """
    Generate a forecast.

    Parameters
    ----------
    model       : fitted SARIMAX result (from load_model)
    steps       : number of months ahead to forecast
    exog_future : DataFrame with columns [temperature, precipitation, wind_speed]
                  Must have a DatetimeIndex with freq='MS' and exactly `steps` rows.

    Returns
    -------
    predictions : pd.Series  — point forecasts
    conf_int    : pd.DataFrame — 95% confidence interval
    """
    cfg           = load_config()
    required_cols = cfg['exog_cols']

    missing = [c for c in required_cols if c not in exog_future.columns]
    if missing:
        raise ValueError(f"exog_future is missing columns: {missing}")
    if len(exog_future) != steps:
        raise ValueError(f"exog_future must have {steps} rows, got {len(exog_future)}")

    fc          = model.get_forecast(steps=steps, exog=exog_future[required_cols])
    predictions = fc.predicted_mean
    conf_int    = fc.conf_int()
    return predictions, conf_int


if __name__ == "__main__":
    model = load_model()
    cfg   = load_config()
    print(f"Model loaded: SARIMAX{cfg['order']}x{cfg['seasonal_order']}")
    print(f"Test RMSE: {cfg['test_metrics']['RMSE']}")

    # Dummy forecast — replace with real future met data
    idx   = pd.date_range(start="2024-01-01", periods=12, freq="MS")
    X_fut = pd.DataFrame({
        "temperature"  : np.random.uniform(3, 15, 12),
        "precipitation": np.random.uniform(20, 120, 12),
        "wind_speed"   : np.random.uniform(10, 25, 12),
    }, index=idx)

    preds, ci = forecast(model, steps=12, exog_future=X_fut)
    print(pd.DataFrame({"predicted": preds, "lower": ci.iloc[:,0], "upper": ci.iloc[:,1]}))