Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
jmoralez committed Jan 18, 2024
2 parents 004bb5a + 63822d7 commit 4e143dc
Show file tree
Hide file tree
Showing 21 changed files with 1,298 additions and 186 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/build-docs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ jobs:
publish_dir: ./_docs
user_name: github-actions[bot]
user_email: 41898282+github-actions[bot]@users.noreply.github.com
- name: Trigger mintlify workflow
if: github.event_name == 'push'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.DOCS_WORKFLOW_TOKEN }}
script: |
await github.rest.actions.createWorkflowDispatch({
owner: 'nixtla',
repo: 'docs',
workflow_id: 'mintlify-action.yml',
ref: 'main',
});
- name: Deploy to Github Pages
if: github.event_name == 'push'
uses: peaceiris/actions-gh-pages@v3
Expand Down
2 changes: 1 addition & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ dependencies:
- polars
- ray<2.8
- triad==0.9.1
- utilsforecast>=0.0.21
- utilsforecast>=0.0.24
- xgboost_ray
2 changes: 1 addition & 1 deletion local_environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ dependencies:
- datasetsforecast
- nbdev
- polars
- utilsforecast>=0.0.21
- utilsforecast>=0.0.24
2 changes: 1 addition & 1 deletion mlforecast/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
__version__ = "0.11.2"
__version__ = "0.11.5"
__all__ = ['MLForecast']
from mlforecast.forecast import MLForecast
20 changes: 19 additions & 1 deletion mlforecast/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
'mlforecast/core.py'),
'mlforecast.core.TimeSeries._get_raw_predictions': ( 'core.html#timeseries._get_raw_predictions',
'mlforecast/core.py'),
'mlforecast.core.TimeSeries._has_ga_target_tfms': ( 'core.html#timeseries._has_ga_target_tfms',
'mlforecast/core.py'),
'mlforecast.core.TimeSeries._predict_multi': ('core.html#timeseries._predict_multi', 'mlforecast/core.py'),
'mlforecast.core.TimeSeries._predict_recursive': ( 'core.html#timeseries._predict_recursive',
'mlforecast/core.py'),
Expand Down Expand Up @@ -194,6 +196,8 @@
'mlforecast/grouped_array.py'),
'mlforecast.grouped_array.GroupedArray.take_from_groups': ( 'grouped_array.html#groupedarray.take_from_groups',
'mlforecast/grouped_array.py'),
'mlforecast.grouped_array.GroupedArray.update_difference': ( 'grouped_array.html#groupedarray.update_difference',
'mlforecast/grouped_array.py'),
'mlforecast.grouped_array._append_one': ( 'grouped_array.html#_append_one',
'mlforecast/grouped_array.py'),
'mlforecast.grouped_array._append_several': ( 'grouped_array.html#_append_several',
Expand All @@ -208,7 +212,9 @@
'mlforecast.grouped_array._restore_fitted_difference': ( 'grouped_array.html#_restore_fitted_difference',
'mlforecast/grouped_array.py'),
'mlforecast.grouped_array._transform_series': ( 'grouped_array.html#_transform_series',
'mlforecast/grouped_array.py')},
'mlforecast/grouped_array.py'),
'mlforecast.grouped_array._update_difference': ( 'grouped_array.html#_update_difference',
'mlforecast/grouped_array.py')},
'mlforecast.lag_transforms': { 'mlforecast.lag_transforms.BaseLagTransform': ( 'lag_transforms.html#baselagtransform',
'mlforecast/lag_transforms.py'),
'mlforecast.lag_transforms.BaseLagTransform.transform': ( 'lag_transforms.html#baselagtransform.transform',
Expand Down Expand Up @@ -315,14 +321,20 @@
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseGroupedArrayTargetTransform.inverse_transform_fitted': ( 'target_transforms.html#basegroupedarraytargettransform.inverse_transform_fitted',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseGroupedArrayTargetTransform.update': ( 'target_transforms.html#basegroupedarraytargettransform.update',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseLocalScaler': ( 'target_transforms.html#baselocalscaler',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseLocalScaler._is_utils_tfm': ( 'target_transforms.html#baselocalscaler._is_utils_tfm',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseLocalScaler.fit_transform': ( 'target_transforms.html#baselocalscaler.fit_transform',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseLocalScaler.inverse_transform': ( 'target_transforms.html#baselocalscaler.inverse_transform',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseLocalScaler.inverse_transform_fitted': ( 'target_transforms.html#baselocalscaler.inverse_transform_fitted',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseLocalScaler.update': ( 'target_transforms.html#baselocalscaler.update',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseTargetTransform': ( 'target_transforms.html#basetargettransform',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseTargetTransform.fit_transform': ( 'target_transforms.html#basetargettransform.fit_transform',
Expand All @@ -331,6 +343,8 @@
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseTargetTransform.set_column_names': ( 'target_transforms.html#basetargettransform.set_column_names',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.BaseTargetTransform.update': ( 'target_transforms.html#basetargettransform.update',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.Differences': ( 'target_transforms.html#differences',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.Differences.__init__': ( 'target_transforms.html#differences.__init__',
Expand All @@ -341,6 +355,8 @@
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.Differences.inverse_transform_fitted': ( 'target_transforms.html#differences.inverse_transform_fitted',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.Differences.update': ( 'target_transforms.html#differences.update',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.GlobalSklearnTransformer': ( 'target_transforms.html#globalsklearntransformer',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.GlobalSklearnTransformer.__init__': ( 'target_transforms.html#globalsklearntransformer.__init__',
Expand All @@ -349,6 +365,8 @@
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.GlobalSklearnTransformer.inverse_transform': ( 'target_transforms.html#globalsklearntransformer.inverse_transform',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.GlobalSklearnTransformer.update': ( 'target_transforms.html#globalsklearntransformer.update',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.LocalBoxCox': ( 'target_transforms.html#localboxcox',
'mlforecast/target_transforms.py'),
'mlforecast.target_transforms.LocalBoxCox.__init__': ( 'target_transforms.html#localboxcox.__init__',
Expand Down
2 changes: 2 additions & 0 deletions mlforecast/compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
# %% ../nbs/compat.ipynb 1
try:
import coreforecast.lag_transforms as core_tfms
import coreforecast.scalers as core_scalers
from coreforecast.grouped_array import GroupedArray as CoreGroupedArray

from mlforecast.lag_transforms import BaseLagTransform, Lag

CORE_INSTALLED = True
except ImportError:
core_tfms = None
core_scalers = None
CoreGroupedArray = None

class BaseLagTransform:
Expand Down
81 changes: 56 additions & 25 deletions mlforecast/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ def _get_predictions(self) -> DataFrame:
return df

def _predict_setup(self) -> None:
self._ga = copy.copy(self.ga)
self.ga = copy.copy(self._ga)
if isinstance(self.last_dates, pl_Series):
self.curr_dates = self.last_dates.clone()
else:
Expand Down Expand Up @@ -657,6 +657,12 @@ def _predict_multi(
result = ufp.assign_columns(result, name, raw_preds)
return result

def _has_ga_target_tfms(self):
return any(
isinstance(tfm, BaseGroupedArrayTargetTransform)
for tfm in self.target_transforms
)

def predict(
self,
models: Dict[str, Union[BaseEstimator, List[BaseEstimator]]],
Expand Down Expand Up @@ -723,26 +729,30 @@ def predict(
raise ValueError(msg)
drop_cols = [self.id_col, self.time_col, "_start", "_end"]
X_df = ufp.sort(X_df, [self.id_col, self.time_col]).drop(columns=drop_cols)
if getattr(self, "max_horizon", None) is None:
preds = self._predict_recursive(
models=models,
horizon=horizon,
before_predict_callback=before_predict_callback,
after_predict_callback=after_predict_callback,
X_df=X_df,
)
else:
preds = self._predict_multi(
models=models,
horizon=horizon,
before_predict_callback=before_predict_callback,
X_df=X_df,
)
# backup original series. the ga attribute gets modified
# and is copied from _ga at the start of each model's predict
self._ga = copy.copy(self.ga)
try:
if getattr(self, "max_horizon", None) is None:
preds = self._predict_recursive(
models=models,
horizon=horizon,
before_predict_callback=before_predict_callback,
after_predict_callback=after_predict_callback,
X_df=X_df,
)
else:
preds = self._predict_multi(
models=models,
horizon=horizon,
before_predict_callback=before_predict_callback,
X_df=X_df,
)
finally:
self.ga = self._ga
del self._ga
if self.target_transforms is not None:
if any(
isinstance(tfm, BaseGroupedArrayTargetTransform)
for tfm in self.target_transforms
):
if self._has_ga_target_tfms():
model_cols = [
c for c in preds.columns if c not in (self.id_col, self.time_col)
]
Expand All @@ -751,14 +761,15 @@ def predict(
if isinstance(tfm, BaseGroupedArrayTargetTransform):
tfm.idxs = self._idxs
for col in model_cols:
ga = GroupedArray(preds[col].to_numpy(), indptr)
ga = GroupedArray(
preds[col].to_numpy().astype(self.ga.data.dtype), indptr
)
ga = tfm.inverse_transform(ga)
preds = ufp.assign_columns(preds, col, ga.data)
tfm.idxs = None
else:
preds = tfm.inverse_transform(preds)
self.ga = self._ga
del self._uids, self._idxs, self._static_features, self._ga
del self._uids, self._idxs, self._static_features
return preds

def save(self, path: Union[str, Path]) -> None:
Expand All @@ -778,11 +789,17 @@ def update(self, df: DataFrame) -> None:
if isinstance(uids, pd.Index):
uids = pd.Series(uids)
uids, new_ids = ufp.match_if_categorical(uids, df[self.id_col])
df = ufp.copy_if_pandas(df, deep=False)
df = ufp.assign_columns(df, self.id_col, new_ids)
df = ufp.sort(df, by=[self.id_col, self.time_col])
values = df[self.target_col].to_numpy()
values = values.astype(self.ga.data.dtype, copy=False)
id_counts = ufp.counts_by_id(df, self.id_col)
sizes = ufp.join(uids, id_counts, on=self.id_col, how="outer")
try:
sizes = ufp.join(uids, id_counts, on=self.id_col, how="outer_coalesce")
except (KeyError, ValueError):
# pandas raises key error, polars before coalesce raises value error
sizes = ufp.join(uids, id_counts, on=self.id_col, how="outer")
sizes = ufp.fill_null(sizes, {"counts": 0})
sizes = ufp.sort(sizes, by=self.id_col)
new_groups = ~ufp.is_in(sizes[self.id_col], uids)
Expand All @@ -794,9 +811,12 @@ def update(self, df: DataFrame) -> None:
last_dates = ufp.sort(last_dates, by=self.id_col)
self.last_dates = ufp.cast(last_dates[self.time_col], self.last_dates.dtype)
self.uids = ufp.sort(sizes[self.id_col])
if isinstance(self.uids, pd.Series):
if isinstance(df, pd.DataFrame):
self.uids = pd.Index(self.uids)
self.last_dates = pd.Index(self.last_dates)
if new_groups.any():
if self.target_transforms is not None:
raise ValueError("Can not update target_transforms with new series.")
new_ids = ufp.filter_with_mask(sizes[self.id_col], new_groups)
new_ids_df = ufp.filter_with_mask(df, ufp.is_in(df[self.id_col], new_ids))
new_ids_counts = ufp.counts_by_id(new_ids_df, self.id_col)
Expand All @@ -808,6 +828,17 @@ def update(self, df: DataFrame) -> None:
[self.static_features_, new_statics]
)
self.static_features_ = ufp.sort(self.static_features_, self.id_col)
if self.target_transforms is not None:
if self._has_ga_target_tfms():
indptr = np.append(0, id_counts["counts"]).cumsum()
for tfm in self.target_transforms:
if isinstance(tfm, BaseGroupedArrayTargetTransform):
ga = GroupedArray(values, indptr)
ga = tfm.update(ga)
df = ufp.assign_columns(df, self.target_col, ga.data)
else:
df = tfm.update(df)
values = df[self.target_col].to_numpy()
self.ga = self.ga.append_several(
new_sizes=sizes["counts"].to_numpy().astype(np.int32),
new_values=values,
Expand Down
Loading

0 comments on commit 4e143dc

Please sign in to comment.