Skip to content

Commit 385288d

Browse files
authored
0.3.7
2 parents 2cf9af2 + 3294903 commit 385288d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1097
-7404
lines changed

TODO.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,17 @@
1515
* Forecasts are desired for the future immediately following the most recent data.
1616

1717
# Latest
18-
* back_forecast for forecast on training data
19-
* Mosaic ensembles can now be used beyond training forecast_length and for shorter lengths too
20-
* best_model_name, best_model_params, and best_model_transformation_params AutoTS attributes now available
21-
* mean, median, and ffill NaN now handle fully NaN series by returning 0.
22-
* fixed bug that was causing mosaic generalization to fail if ffill/bfill handled all missing values
23-
* STLFilter and HPFilter and convolution_filter Transformers added
18+
* bug fix in fake_date imputation
19+
* bug fix in Round
20+
* make SinTrend fail if it fails on all series (may revert this)
21+
* load_linear and load_sine artificial datasets
22+
* new NVAR model based on https://github.com/quantinfo/ng-rc-paper-code/
23+
* tuning retrieve_regressor to allow it to better work with multioutput and univariate
24+
* expand GluonTS models included
25+
* GluonTS now works on univariate inputs
26+
* GluonTS now works with regressors
27+
* fixed bug where model_count wrong for mosaic ensembles
28+
* fixed bug in VECM that meant it didn't couldn't utilize future_regressor
2429

2530
# Errors:
2631
DynamicFactor holidays Exceptions 'numpy.ndarray' object has no attribute 'values'

autots/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
load_weekly,
1212
load_weekdays,
1313
load_live_daily,
14+
load_linear,
1415
)
1516

1617
from autots.evaluator.auto_ts import AutoTS
@@ -19,7 +20,7 @@
1920
from autots.tools.regressor import create_lagged_regressor
2021
from autots.evaluator.auto_model import model_forecast
2122

22-
__version__ = '0.3.6'
23+
__version__ = '0.3.7'
2324

2425
TransformTS = GeneralTransformer
2526

@@ -31,6 +32,7 @@
3132
'load_weekly',
3233
'load_weekdays',
3334
'load_live_daily',
35+
'load_linear',
3436
'AutoTS',
3537
'TransformTS',
3638
'GeneralTransformer',

autots/datasets/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
load_weekly,
1111
load_weekdays,
1212
load_zeroes,
13+
load_linear,
14+
load_sine,
1315
)
1416

1517
__all__ = [
@@ -21,4 +23,6 @@
2123
'load_weekdays',
2224
'load_live_daily',
2325
'load_zeroes',
26+
'load_linear',
27+
'load_sine',
2428
]

autots/datasets/_base.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,47 @@ def load_zeroes(long=False, shape=None, start_date: str = "2021-01-01"):
391391
id_vars=['datetime'], var_name='series_id', value_name='value'
392392
)
393393
return df_long
394+
395+
396+
def load_linear(long=False, shape=None, start_date: str = "2021-01-01"):
397+
"""Create a dataset of just zeroes for testing edge case."""
398+
if shape is None:
399+
shape = (500, 5)
400+
df_wide = pd.DataFrame(
401+
np.ones(shape), index=pd.date_range(start_date, periods=shape[0], freq="D")
402+
)
403+
df_wide = (df_wide * list(range(0, shape[1]))).cumsum()
404+
if not long:
405+
return df_wide
406+
else:
407+
df_wide.index.name = "datetime"
408+
df_long = df_wide.reset_index(drop=False).melt(
409+
id_vars=['datetime'], var_name='series_id', value_name='value'
410+
)
411+
return df_long
412+
413+
414+
def load_sine(long=False, shape=None, start_date: str = "2021-01-01"):
415+
"""Create a dataset of just zeroes for testing edge case."""
416+
if shape is None:
417+
shape = (500, 5)
418+
df_wide = pd.DataFrame(
419+
np.ones(shape),
420+
index=pd.date_range(start_date, periods=shape[0], freq="D"),
421+
columns=range(shape[1]),
422+
)
423+
X = pd.to_numeric(df_wide.index, errors='coerce', downcast='integer').values
424+
425+
def sin_func(a, X):
426+
return a * np.sin(1 * X) + a
427+
428+
for column in df_wide.columns:
429+
df_wide[column] = sin_func(column, X)
430+
if not long:
431+
return df_wide
432+
else:
433+
df_wide.index.name = "datetime"
434+
df_long = df_wide.reset_index(drop=False).melt(
435+
id_vars=['datetime'], var_name='series_id', value_name='value'
436+
)
437+
return df_long

autots/evaluator/auto_model.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
SeasonalNaive,
3131
ZeroesNaive,
3232
Motif,
33+
NVAR,
3334
)
3435
from autots.models.statsmodels import (
3536
GLS,
@@ -425,6 +426,15 @@ def ModelMonster(
425426
**parameters,
426427
)
427428
return model
429+
elif model == 'NVAR':
430+
model = NVAR(
431+
frequency=frequency,
432+
prediction_interval=prediction_interval,
433+
random_seed=random_seed,
434+
verbose=verbose,
435+
**parameters,
436+
)
437+
return model
428438
else:
429439
raise AttributeError(
430440
("Model String '{}' not a recognized model type").format(model)
@@ -987,6 +997,7 @@ def TemplateWizard(
987997
# template = unpack_ensemble_models(template, template_cols, keep_ensemble = False)
988998

989999
for index, row in template.iterrows():
1000+
template_start_time = datetime.datetime.now()
9901001
try:
9911002
model_str = row['Model']
9921003
parameter_dict = json.loads(row['ModelParameters'])
@@ -1065,11 +1076,6 @@ def TemplateWizard(
10651076
df_forecast.model_parameters,
10661077
df_forecast.transformation_parameters,
10671078
)
1068-
total_runtime = (
1069-
df_forecast.fit_runtime
1070-
+ df_forecast.predict_runtime # noqa W503
1071-
+ df_forecast.transformation_runtime # noqa W503
1072-
)
10731079
result = pd.DataFrame(
10741080
{
10751081
'ID': model_id,
@@ -1081,7 +1087,7 @@ def TemplateWizard(
10811087
'TransformationRuntime': df_forecast.transformation_runtime,
10821088
'FitRuntime': df_forecast.fit_runtime,
10831089
'PredictRuntime': df_forecast.predict_runtime,
1084-
'TotalRuntime': total_runtime,
1090+
'TotalRuntime': datetime.datetime.now() - template_start_time,
10851091
'Ensemble': ensemble_input,
10861092
'Exceptions': np.nan,
10871093
'Runs': 1,
@@ -1147,6 +1153,7 @@ def TemplateWizard(
11471153

11481154
except KeyboardInterrupt:
11491155
if model_interrupt:
1156+
fit_runtime = datetime.datetime.now() - template_start_time
11501157
result = pd.DataFrame(
11511158
{
11521159
'ID': create_model_id(
@@ -1157,9 +1164,9 @@ def TemplateWizard(
11571164
'TransformationParameters': json.dumps(transformation_dict),
11581165
'Ensemble': ensemble_input,
11591166
'TransformationRuntime': datetime.timedelta(0),
1160-
'FitRuntime': datetime.timedelta(0),
1167+
'FitRuntime': fit_runtime,
11611168
'PredictRuntime': datetime.timedelta(0),
1162-
'TotalRuntime': datetime.timedelta(0),
1169+
'TotalRuntime': fit_runtime,
11631170
'Exceptions': "KeyboardInterrupt by user",
11641171
'Runs': 1,
11651172
'Generation': current_generation,
@@ -1194,7 +1201,7 @@ def TemplateWizard(
11941201
(repr(e)), template_result.model_count, model_str
11951202
)
11961203
)
1197-
1204+
fit_runtime = datetime.datetime.now() - template_start_time
11981205
result = pd.DataFrame(
11991206
{
12001207
'ID': create_model_id(
@@ -1205,9 +1212,9 @@ def TemplateWizard(
12051212
'TransformationParameters': json.dumps(transformation_dict),
12061213
'Ensemble': ensemble_input,
12071214
'TransformationRuntime': datetime.timedelta(0),
1208-
'FitRuntime': datetime.timedelta(0),
1215+
'FitRuntime': fit_runtime,
12091216
'PredictRuntime': datetime.timedelta(0),
1210-
'TotalRuntime': datetime.timedelta(0),
1217+
'TotalRuntime': fit_runtime,
12111218
'Exceptions': repr(e),
12121219
'Runs': 1,
12131220
'Generation': current_generation,

autots/evaluator/auto_ts.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -880,8 +880,8 @@ def fit(
880880
min_allowed_train_percent=self.min_allowed_train_percent,
881881
verbose=self.verbose,
882882
)
883-
self.validation_train_indexes.append(val_df_train)
884-
self.validation_test_indexes.append(val_df_test)
883+
self.validation_train_indexes.append(val_df_train.index)
884+
self.validation_test_indexes.append(val_df_test.index)
885885
if self.verbose >= 2:
886886
print(f'Validation index is {val_df_train.index}')
887887

@@ -901,7 +901,7 @@ def fit(
901901
if self.introduce_na or (self.introduce_na is None and self._nan_tail):
902902
nan_frac = val_df_train.shape[1] / num_validations
903903
val_df_train.iloc[
904-
-1, int(nan_frac * y) : int(nan_frac * (y + 1))
904+
-2:, int(nan_frac * y) : int(nan_frac * (y + 1))
905905
] = np.nan
906906

907907
# run validation template on current slice

autots/evaluator/metrics.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ def SPL(A, F, df_train, quantile):
5656
"""Scaled pinball loss."""
5757
# scaler = df_train.tail(1000).diff().abs().mean(axis=0)
5858
# scaler = np.abs(np.diff(df_train[-1000:], axis=0)).mean(axis=0)
59-
scaler = np.nanmean(np.abs(np.diff(df_train[-1000:], axis=0)), axis=0)
59+
with warnings.catch_warnings():
60+
warnings.simplefilter("ignore", category=RuntimeWarning)
61+
scaler = np.nanmean(np.abs(np.diff(df_train[-1000:], axis=0)), axis=0)
6062
# need to handle zeroes to prevent div 0 errors.
6163
# this will tend to make that series irrelevant to the overall evaluation
6264
fill_val = np.nanmax(scaler)

0 commit comments

Comments
 (0)