Skip to content

Commit

Permalink
Merge branch 'isolate-numba' of https://github.com/fkiraly/tsbootstrap
Browse files Browse the repository at this point in the history
…into isolate-numba
  • Loading branch information
fkiraly committed Jan 19, 2024
2 parents 7b7890a + c5d7987 commit a3ad707
Show file tree
Hide file tree
Showing 18 changed files with 247 additions and 4,737 deletions.
30 changes: 15 additions & 15 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
name: CI

on:
push:
paths:
- 'src/**'
- 'tests/**'
- '.github/workflows/CI.yml'
- 'pyproject.toml'
- 'poetry.lock'
- 'docs/**'
# push:
# paths:
# - 'src/**'
# - 'tests/**'
# - '.github/workflows/CI.yml'
# - 'pyproject.toml'
# - 'poetry.lock'
# - 'docs/**'
pull_request:
branches:
- main
Expand Down Expand Up @@ -178,13 +178,13 @@ jobs:
# fail_ci_if_error: true
# verbose: true

commitlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: wagoid/commitlint-github-action@v4
# commitlint:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v3
# with:
# fetch-depth: 0
# - uses: wagoid/commitlint-github-action@v4


docs:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,6 @@ README_template.md

# scratch file
scratch*

# poetry.lock
poetry.lock
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
<a href="https://pypi.org/project/tsbootstrap/">
<img src="https://img.shields.io/pypi/pyversions/tsbootstrap?color=5D6D7E&logo=python" alt="pypi-python-version" />
</a>
<a href="https://pypi.org/project/tsbootstrap/">
<img src="https://img.shields.io/pypi/dt/tsbootstrap?color=5D6D7E" alt="pypi-downloads" />
<a href="https://pepy.tech/project/tsbootstrap">
<img src="https://static.pepy.tech/badge/tsbootstrap" alt="Downloads"/>
</a>
<img src="https://img.shields.io/github/license/eli64s/readme-ai?color=5D6D7E" alt="github-license" />
</a>
Expand Down Expand Up @@ -140,7 +140,6 @@ The `tsbootstrap` package contains various modules that handle tasks such as boo
| [.codeclimate.yml](https://github.com/astrogilda/tsbootstrap/blob/main/.codeclimate.yml) | Configuration for Code Climate quality checks. |
| [.gitignore](https://github.com/astrogilda/tsbootstrap/blob/main/.gitignore) | Specifies files and folders to be ignored by Git. |
| [.pre-commit-config.yaml](https://github.com/astrogilda/tsbootstrap/blob/main/.pre-commit-config.yaml) | Configuration for pre-commit hooks. |
| [poetry.lock](https://github.com/astrogilda/tsbootstrap/blob/main/poetry.lock) | Lock file generated by Poetry, pinning exact package versions. |
| [poetry.toml](https://github.com/astrogilda/tsbootstrap/blob/main/poetry.toml) | Configuration file for Poetry package management. |
| [tsbootstrap_logo.png](https://github.com/astrogilda/tsbootstrap/blob/main/tsbootstrap_logo.png) | Project logo image. |

Expand Down
4,486 changes: 0 additions & 4,486 deletions poetry.lock

This file was deleted.

28 changes: 12 additions & 16 deletions src/tsbootstrap/base_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def bootstrap(
self,
X: np.ndarray,
return_indices: bool = False,
exog: np.ndarray | None = None,
y: np.ndarray | None = None,
test_ratio: float = None,
) -> Iterator[np.ndarray] | Iterator[tuple[list[np.ndarray], np.ndarray]]:
"""Generate indices to split data into training and test set.
Expand All @@ -56,7 +56,7 @@ def bootstrap(
If True, a second output is retured, integer locations of
index references for the bootstrap sample, in reference to original indices.
Indexed values do are not necessarily identical with bootstrapped values.
exog : array-like of shape (n_timepoints, n_features_exog), default=None
y : array-like of shape (n_timepoints, n_features_exog), default=None
Exogenous time series to use in bootstrapping.
test_ratio : float, default=0.2
The ratio of test samples to total samples.
Expand Down Expand Up @@ -92,14 +92,14 @@ def bootstrap(

X_train, X_test = time_series_split(X, test_ratio=test_ratio)

if exog is not None:
self._check_input(exog)
exog_train, _ = time_series_split(exog, test_ratio=test_ratio)
if y is not None:
self._check_input(y)
exog_train, _ = time_series_split(y, test_ratio=test_ratio)
else:
exog_train = None

tuple_iter = self._generate_samples(
X=X_train, return_indices=return_indices, exog=exog_train
X=X_train, return_indices=return_indices, y=exog_train
)

yield from tuple_iter
Expand All @@ -108,7 +108,7 @@ def _generate_samples(
self,
X: np.ndarray,
return_indices: bool = False,
exog: np.ndarray | None = None,
y: np.ndarray | None = None,
) -> Iterator[np.ndarray] | Iterator[tuple[list[np.ndarray], np.ndarray]]:
"""Generates bootstrapped samples directly.
Expand All @@ -124,9 +124,7 @@ def _generate_samples(
"""
for _ in range(self.config.n_bootstraps):
indices, data = self._generate_samples_single_bootstrap(
X=X, exog=exog
)
indices, data = self._generate_samples_single_bootstrap(X=X, y=y)
data = np.concatenate(data, axis=0)
if return_indices:
yield indices, data # type: ignore
Expand All @@ -135,7 +133,7 @@ def _generate_samples(

@abstractmethod
def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
"""Generates list of bootstrapped indices and samples for a single bootstrap iteration.
Expand Down Expand Up @@ -216,9 +214,7 @@ def __init__(
self.X_fitted = None
self.coefs = None

def _fit_model(
self, X: np.ndarray, exog: np.ndarray | None = None
) -> None:
def _fit_model(self, X: np.ndarray, y: np.ndarray | None = None) -> None:
"""Fits the model to the data and stores the residuals."""
if (
self.resids is None
Expand All @@ -232,7 +228,7 @@ def _fit_model(
save_models=self.config.save_models,
**self.config.model_params,
)
self.fit_model = fit_obj.fit(X=X, exog=exog).model
self.fit_model = fit_obj.fit(X=X, y=y).model
self.X_fitted = fit_obj.get_fitted_X()
self.resids = fit_obj.get_residuals()
self.order = fit_obj.get_order()
Expand Down Expand Up @@ -534,7 +530,7 @@ def _fit_resids_model(self, X: np.ndarray) -> None:
save_models=self.config.save_resids_models,
**self.config.resids_model_params,
)
resids_fit_model = resids_fit_obj.fit(X, exog=None).model
resids_fit_model = resids_fit_obj.fit(X, y=None).model
resids_order = resids_fit_obj.get_order()
resids_coefs = resids_fit_obj.get_coefs()
self.resids_fit_model = resids_fit_model
Expand Down
8 changes: 4 additions & 4 deletions src/tsbootstrap/block_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def _generate_blocks(self, X: np.ndarray) -> list[np.ndarray]:
return blocks

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
"""
Generate a single bootstrap sample.
Expand Down Expand Up @@ -174,7 +174,7 @@ def __init__(self, config: BaseBlockBootstrapConfig, **kwargs):
](config=config)

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
"""
Generate a single bootstrap sample using either the base BlockBootstrap method or the specified bootstrap_type.
Expand All @@ -194,7 +194,7 @@ def _generate_samples_single_bootstrap(
(
block_indices,
block_data,
) = super()._generate_samples_single_bootstrap(X=X, exog=exog)
) = super()._generate_samples_single_bootstrap(X=X, y=y)
else:
# Generate samples using the specified bootstrap_type
if hasattr(
Expand All @@ -204,7 +204,7 @@ def _generate_samples_single_bootstrap(
block_indices,
block_data,
) = self.bootstrap_instance._generate_samples_single_bootstrap(
X=X, exog=exog
X=X, y=y
)
else:
raise NotImplementedError(
Expand Down
36 changes: 18 additions & 18 deletions src/tsbootstrap/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ def __init__(self, config: BaseResidualBootstrapConfig):
super().__init__(config)

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
self._fit_model(X=X, exog=exog)
self._fit_model(X=X, y=y)

# Resample residuals
resampled_indices = generate_random_indices(
Expand Down Expand Up @@ -105,10 +105,10 @@ def __init__(
self.block_bootstrap = BaseBlockBootstrap(config=block_config)

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
# Fit the model and store residuals, fitted values, etc.
BaseResidualBootstrap._fit_model(self, X=X, exog=exog)
BaseResidualBootstrap._fit_model(self, X=X, y=y)

# Generate blocks of residuals
(
Expand Down Expand Up @@ -144,10 +144,10 @@ class WholeMarkovBootstrap(BaseMarkovBootstrap):
"""

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
# Fit the model and store residuals, fitted values, etc.
self._fit_model(X=X, exog=exog)
self._fit_model(X=X, y=y)

# Fit HMM to residuals, just once.
random_seed = self.config.rng.integers(0, 1000)
Expand Down Expand Up @@ -217,10 +217,10 @@ def __init__(
self.block_bootstrap = BaseBlockBootstrap(config=block_config)

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
# Fit the model and store residuals, fitted values, etc.
super()._fit_model(X=X, exog=exog)
super()._fit_model(X=X, y=y)

# Generate blocks of residuals
(
Expand Down Expand Up @@ -279,7 +279,7 @@ class WholeStatisticPreservingBootstrap(BaseStatisticPreservingBootstrap):
"""

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
if self.statistic_X is None:
self.statistic_X = self._calculate_statistic(X=X)
Expand Down Expand Up @@ -338,7 +338,7 @@ def __init__(
self.block_bootstrap = BaseBlockBootstrap(config=block_config)

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
if self.statistic_X is None:
self.statistic_X = super()._calculate_statistic(X=X)
Expand Down Expand Up @@ -385,10 +385,10 @@ class WholeDistributionBootstrap(BaseDistributionBootstrap):
"""

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
# Fit the model and residuals
self._fit_model(X=X, exog=exog)
self._fit_model(X=X, y=y)
# Fit the specified distribution to the residuals
if not self.config.refit:
if self.resids_dist is None or self.resids_dist_params == ():
Expand Down Expand Up @@ -474,10 +474,10 @@ def __init__(
self.block_bootstrap = BaseBlockBootstrap(config=block_config)

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
# Fit the model and residuals
super()._fit_model(X=X, exog=exog)
super()._fit_model(X=X, y=y)
(
block_indices,
block_data,
Expand Down Expand Up @@ -538,9 +538,9 @@ class WholeSieveBootstrap(BaseSieveBootstrap):
"""

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
self._fit_model(X=X, exog=exog)
self._fit_model(X=X, y=y)
self._fit_resids_model(X=self.resids)

ts_simulator = TimeSeriesSimulator(
Expand Down Expand Up @@ -593,10 +593,10 @@ def __init__(
self.block_bootstrap = BaseBlockBootstrap(config=block_config)

def _generate_samples_single_bootstrap(
self, X: np.ndarray, exog: np.ndarray | None = None
self, X: np.ndarray, y: np.ndarray | None = None
) -> tuple[list[np.ndarray], list[np.ndarray]]:
# Fit the model and residuals
super()._fit_model(X=X, exog=exog)
super()._fit_model(X=X, y=y)
super()._fit_resids_model(X=self.resids)

ts_simulator = TimeSeriesSimulator(
Expand Down
22 changes: 11 additions & 11 deletions src/tsbootstrap/ranklags.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def __init__(
X: np.ndarray,
model_type: ModelTypes,
max_lag: Integral = 10,
exog: np.ndarray | None = None,
y: np.ndarray | None = None,
save_models: bool = False,
) -> None:
"""
Expand All @@ -57,15 +57,15 @@ def __init__(
The type of model to fit. One of 'ar', 'arima', 'sarima', 'var', 'arch'.
max_lag : int, optional, default=10
Maximum lag to consider.
exog : np.ndarray, optional, default=None
y : np.ndarray, optional, default=None
Exogenous variables to include in the model.
save_models : bool, optional, default=False
Whether to save the models.
"""
self.X = X
self.max_lag = max_lag
self.model_type = model_type
self.exog = exog
self.y = y
self.save_models = save_models
self.models = []

Expand Down Expand Up @@ -146,7 +146,7 @@ def model_type(self, value: ModelTypes) -> None:
self._model_type = value.lower()

@property
def exog(self) -> np.ndarray | None:
def y(self) -> np.ndarray | None:
"""
Exogenous variables to include in the model.
Expand All @@ -155,21 +155,21 @@ def exog(self) -> np.ndarray | None:
np.ndarray
Exogenous variables to include in the model.
"""
return self._exog
return self._y

@exog.setter
def exog(self, value: np.ndarray | None) -> None:
@y.setter
def y(self, value: np.ndarray | None) -> None:
"""
Set the exogenous variables to include in the model.
Parameters
----------
exog : np.ndarray
y : np.ndarray
Exogenous variables to include in the model.
"""
if value is not None and not isinstance(value, np.ndarray):
raise TypeError("exog must be a numpy array.")
self._exog = value
raise TypeError("y must be a numpy array.")
self._y = value

def rank_lags_by_aic_bic(self) -> tuple[np.ndarray, np.ndarray]:
"""
Expand All @@ -188,7 +188,7 @@ def rank_lags_by_aic_bic(self) -> tuple[np.ndarray, np.ndarray]:
for lag in range(1, self.max_lag + 1):
try:
fit_obj = TSFit(order=lag, model_type=self.model_type)
model = fit_obj.fit(X=self.X, exog=self.exog).model
model = fit_obj.fit(X=self.X, y=self.y).model
except Exception as e:
# raise RuntimeError(f"An error occurred during fitting: {e}")
print(f"{e}")
Expand Down
Loading

0 comments on commit a3ad707

Please sign in to comment.