this is my model from statsforecast import StatsForecast
from statsforecast.models import AutoARIMA
from statsforecast.utils import ConformalIntervals
import numpy as np
import polars as pl

# Polars option to display all rows
pl.Config.set_tbl_rows(None)

# Initialize the models
models = [AutoARIMA(season_length=52)]

# Initialize the StatsForecast model
sf = StatsForecast(models=models, freq='1w', n_jobs=-1)

# Perform cross-validation with a step size of 1 to do an expanding window
crossvalidation_df = sf.cross_validation(df=y_cl4_over_10, h=4, step_size=1, n_windows=5, sort_df=True)

def wmape(y_true, y_pred):
    return np.abs(y_true - y_pred).sum() / np.abs(y_true).sum()

# Calculate the WMAPE for the model
wmape_value = wmape(crossvalidation_df['y'], crossvalidation_df['AutoARIMA'])
print('Average WMAPE: ', round(wmape_value, 4))

# Calculate the errors for the model
errors = crossvalidation_df['y'] - crossvalidation_df['AutoARIMA']

# For an individual forecast
individual_accuracy = 1 - (abs(crossvalidation_df['y'] - crossvalidation_df['AutoARIMA']) / crossvalidation_df['y'])
individual_bias = (crossvalidation_df['AutoARIMA'] / crossvalidation_df['y']) - 1

# Add these calculations as new columns to DataFrame
crossvalidation_df = crossvalidation_df.with_columns([
    individual_accuracy.alias("individual_accuracy"),
    individual_bias.alias("individual_bias")
])

# Print the individual accuracy and bias for each week
for row in crossvalidation_df.to_dicts():
    id = row['unique_id']
    date = row['ds'] 
    accuracy = row['individual_accuracy']
    bias = row['individual_bias']
    print(f"{id}, {date}, Individual Accuracy: {accuracy:.4f}, Individual Bias: {bias:.4f}")

# Filter individual accuracy and individual bias to be within absolute value of 15
filtered_df = crossvalidation_df.filter(
    (crossvalidation_df["individual_accuracy"].abs() <= 5) 
    & (crossvalidation_df["individual_bias"].abs() <= 5)
)

# Calculate errors for the filtered DataFrame
errors_filtered = filtered_df['y'] - filtered_df['AutoARIMA']

# For groups of forecasts
group_accuracy = 1 - (errors_filtered.abs().sum() / filtered_df['y'].sum())
group_bias = (filtered_df['AutoARIMA'].sum() / filtered_df['y'].sum()) - 1

# Print the average group accuracy and group bias over all folds for the ensemble model
print('Average Group Accuracy: ', round(group_accuracy, 4))
print('Average Group Bias: ', round(group_bias, 4))


# Instantiate the ConformalIntervals class
prediction_intervals = ConformalIntervals()

# Generate 24 months forecasts
forecasts_df = sf.forecast(df=y_cl4_over_10, h=52*2, X_df=y_cl4_over_10_forecast, prediction_intervals=prediction_intervals, level=[95], id_col='unique_id', sort_df=True)

# Apply the non-negative constraint to the forecasts of the model
forecasts_df = forecasts_df.with_columns([
    pl.when(pl.col('AutoARIMA') < 0).then(0).otherwise(pl.col('AutoARIMA')).alias('AutoARIMA'),
    pl.when(pl.col('AutoARIMA-lo-95') < 0).then(0).otherwise(pl.col('AutoARIMA-lo-95')).alias('AutoARIMA-lo-95')
])

forecasts_df = forecasts_df.with_columns([
    pl.col("AutoARIMA").round().cast(pl.Int32),
    pl.col("AutoARIMA-lo-95").round().cast(pl.Int32),
    pl.col("AutoARIMA-hi-95").round().cast(pl.Int32)
])

# Split the unique_id concat into the original columns
def split_unique_id(unique_id):
    parts = unique_id.split('_')
    return parts if len(parts) >= 4 else (parts + [None] * (4 - len(parts)))

forecasts_df = (
    forecasts_df
    .with_columns([
        pl.col('unique_id').apply(lambda uid: split_unique_id(uid)[0]).alias('MaterialID'),
        pl.col('unique_id').apply(lambda uid: split_unique_id(uid)[1]).alias('SalesOrg'),
        pl.col('unique_id').apply(lambda uid: split_unique_id(uid)[2]).alias('DistrChan'),
        pl.col('unique_id').apply(lambda uid: split_unique_id(uid)[3]).alias('CL4'),
    ])
    .drop('unique_id')
)

# Rename ‘ds’ to ‘WeekDate’
forecasts_df = forecasts_df.rename({'ds': 'WeekDate'})

# Reorder the columns
forecasts_df = forecasts_df.select([
    "MaterialID",
    "SalesOrg",
    "DistrChan", 
    "CL4",
    "WeekDate",
    "AutoARIMA", 
    "AutoARIMA-lo-95", 
    "AutoARIMA-hi-95"
]) 

# Create an empty list
forecasts_list = []

# Append each row to the list
for row in forecasts_df.to_dicts():
    forecasts_list.append(row)

# Print the list
for forecast in forecasts_list:
    print(forecast), this is the dataset ds	y	unique_id
datetime[μs]	f64	str
2020-11-30 00:00:00	87.0	"12385622_US01_…
2020-11-30 00:00:00	37.0	"12421245_US01_…
2020-11-30 00:00:00	272.0	"11000366_US03_…
2020-11-30 00:00:00	7.0	"11003930_US03_…
2020-11-30 00:00:00	47.0	"11003457_US03_…
 this is the accuraacy and bias ouput, unique_id	ds	cutoff	y	AutoARIMA	individual_accuracy	individual_bias
str	datetime[ns]	datetime[ns]	f32	f32	f32	f32
"10000012_US03_…	2023-01-02 00:00:00	2022-12-19 00:00:00	40.0	61.163826	0.470904	0.529096
"10000012_US03_…	2023-01-23 00:00:00	2022-12-19 00:00:00	40.0	5.802792	0.14507	-0.85493
"10000012_US03_…	2023-05-15 00:00:00	2022-12-19 00:00:00	32.0	46.195965	0.556376	0.443624
"10000012_US03_…	2023-06-05 00:00:00	2022-12-19 00:00:00	24.0	17.629753	0.734573	-0.265427
"10000012_US03_…	2023-01-23 00:00:00	2023-01-02 00:00:00	40.0	21.248421	0.531211	-0.468789, this is the forecast output MaterialID	SalesOrg	DistrChan	CL4	WeekDate	AutoARIMA	AutoARIMA-lo-95	AutoARIMA-hi-95
str	str	str	str	datetime[ns]	i32	i32	i32
"10000012"	"US03"	"10"	"1131030"	2023-11-06 00:00:00	34	18	50
"10000012"	"US03"	"10"	"1131030"	2023-11-13 00:00:00	0	0	7
"10000012"	"US03"	"10"	"1131030"	2023-11-20 00:00:00	30	14	46
"10000012"	"US03"	"10"	"1131030"	2023-11-27 00:00:00	13	0	29
"10000012"	"US03"	"10"	"1131030"	2023-12-04 00:00:00	28	12	44. okay so we need to do a lag forecast in supply chain context, with the first cut off is the first week of 2023, then it will have a 12 weeks out forecast, this is an example from excel forecast start date/modeling date/cutoff date
6
9|
10
11|
121
12 weeks out
1/1/2024 lagO
lag1
1/8/2024
lago
1/15/2024
1/22/2024
1/29/2024
2/5/2024
2/12/2024
2/19/2024
1/1/2024 1/8/2024 1/15/2024 1/22/2024 1/29/2024 2/5/2024 2/12/2024 2/19/2024
lag2
lag1
lago
lag3
lag4
lag2
lag3
lag1
lag2
lago
lag1
lago
lag5
lag4
lag3
lag2
lag1
lago
lag6
lag5
lag4
lag3
lag2
lag1
lago
lag7
lago
lags lag4
lag3
lag? lag1
lago