Skip to content

Commit 19f0a23

Browse files
authored
Merge pull request #463 from unit8co/develop
Release 0.11.0
2 parents 9715c9f + 5aff483 commit 19f0a23

20 files changed

+313
-204
lines changed

.github/scripts/libomp-Linux.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exit 0

.github/scripts/libomp-macOS.sh

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
brew install libomp wget
2+
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/fb8323f2b170bd4ae97e1bac9bf3e2983af3fdb0/Formula/libomp.rb
3+
brew unlink libomp
4+
brew install libomp.rb

.github/workflows/develop.yml

+6-2
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,18 @@ jobs:
4040
run: |
4141
./gradlew installPipLatest
4242
43-
- name: "5. Attach cache for pip"
43+
- name: "5. Install libomp (for LightGBM)"
44+
run: |
45+
./.github/scripts/libomp-${{ runner.os }}.sh
46+
47+
- name: "6. Attach cache for pip"
4448
uses: actions/cache@v1
4549
id: cache
4650
with:
4751
path: ~/.cache/pip
4852
key: tests-${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('requirements-latest.txt') }}
4953

50-
- name: "6. Tests"
54+
- name: "7. Tests"
5155
run: |
5256
./gradlew "test_${{matrix.flavour}}"
5357

.github/workflows/merge.yml

+6-2
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,18 @@ jobs:
4141
run: |
4242
./gradlew installPipLatest
4343
44-
- name: "5. Attach cache for pip"
44+
- name: "5. Install libomp (for LightGBM)"
45+
run: |
46+
./.github/scripts/libomp-${{ runner.os }}.sh
47+
48+
- name: "6. Attach cache for pip"
4549
uses: actions/cache@v1
4650
id: cache
4751
with:
4852
path: ~/.cache/pip
4953
key: tests-${{ runner.os }}-${{ matrix.python-version }}-pip-${{ hashFiles('requirements-latest.txt') }}
5054

51-
- name: "6. Tests"
55+
- name: "7. Tests"
5256
run: |
5357
./gradlew "test_${{matrix.flavour}}"
5458

CHANGELOG.md

+20-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,27 @@
44
Darts is still in an early development phase and we cannot always guarantee backwards compatibility. Changes that may **break code which uses a previous release of Darts** are marked with a "🔴".
55

66
## [Unreleased](https://github.com/unit8co/darts/tree/develop)
7-
[Full Changelog](https://github.com/unit8co/darts/compare/0.10.1...develop)
7+
[Full Changelog](https://github.com/unit8co/darts/compare/0.11.0...develop)
88

9-
## [0.10.1](https://github.com/unit8co/darts/tree/0.10.0) (2021-08-19)
9+
## [0.11.0](https://github.com/unit8co/darts/tree/0.11.0) (2021-09-04)
10+
### For users of the library:
11+
12+
**Added:**
13+
- New model: `LightGBMModel` is a new regression model. Regression models allow to predict future values
14+
of the target, given arbitrary lags of the target as well as past and/or future covariates. `RegressionModel`
15+
already works with any scikit-learn regression model, and now `LightGBMModel` does the same with LightGBM.
16+
If you want to activate LightGBM support in Darts, please read the detailed install notes on
17+
the [README](https://github.com/unit8co/darts/blob/master/README.md) carefully.
18+
- Added stride support to gridsearch
19+
20+
**Fixed:**
21+
- A bug which was causing issues when training on a GPU with a validation set
22+
- Some issues with custom-provided RNN modules in `RNNModel`.
23+
- Properly handle `kwargs` in the `fit` function of `RegressionModel`s.
24+
- Fixed an issue which was causing problems with latest versions of Matplotlib.
25+
- An issue causing errors in the FFT notebook
26+
27+
## [0.10.1](https://github.com/unit8co/darts/tree/0.10.1) (2021-08-19)
1028
### For users of the library:
1129

1230
**Fixed:**

README.md

+53-25
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ on multiple time series, and some of the models offer probabilistic forecasts.
3333
* [Using Past and Future Covariates](https://medium.com/unit8-machine-learning-publication/time-series-forecasting-using-past-and-future-external-data-with-darts-1f0539585993)
3434
* [Temporal Convolutional Networks and Forecasting](https://medium.com/unit8-machine-learning-publication/temporal-convolutional-networks-and-forecasting-5ce1b6e97ce4)
3535

36-
## Install
36+
## Quick Install
3737

3838
We recommend to first setup a clean Python environment for your project with at least Python 3.7 using your favorite tool ([conda](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html "conda-env"), [venv](https://docs.python.org/3/library/venv.html), [virtualenv](https://virtualenv.pypa.io/en/latest/) with or without [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/)).
3939

@@ -123,35 +123,44 @@ inferences of the underlying states/values.
123123
Here's a breakdown of the forecasting models currently implemented in Darts. We are constantly working
124124
on bringing more models and features.
125125

126-
Model | Univariate | Multivariate | Probabilistic | Multiple-series training | Past-observed covariates support | Future-known covariates support
127-
--- | --- | --- | --- | --- | --- | ---
128-
`ARIMA` | x | | x | | |
129-
`VARIMA` | x | x | | | |
130-
`AutoARIMA` | x | | | | |
131-
`ExponentialSmoothing` | x | | x | | |
132-
`Theta` and `FourTheta` | x | | | | |
133-
`Prophet` | x | | | | |
134-
`FFT` (Fast Fourier Transform) | x | | | | |
135-
`RegressionModel` (incl `RandomForest` and `LinearRegressionModel`) | x | x | | x | x | x
136-
`RNNModel` (incl. LSTM and GRU); equivalent to DeepAR in its probabilistic version | x | x | x | x | | x
137-
`BlockRNNModel` (incl. LSTM and GRU) | x | x | | x | x |
138-
`NBEATSModel` | x | x | | x | x |
139-
`TCNModel` | x | x | x | x | x |
140-
`TransformerModel` | x | x | | x | x |
141-
Naive Baselines | x | | | | |
142-
143-
## Contribute
126+
Model | Univariate | Multivariate | Probabilistic | Multiple-series training | Past-observed covariates support | Future-known covariates support | Reference
127+
--- | --- | --- | --- | --- | --- | --- | ---
128+
`ARIMA` | x | | x | | | |
129+
`VARIMA` | x | x | | | | |
130+
`AutoARIMA` | x | | | | | |
131+
`ExponentialSmoothing` | x | | x | | | |
132+
`Theta` and `FourTheta` | x | | | | | | [Theta](https://robjhyndman.com/papers/Theta.pdf) & [4 Theta](https://github.com/Mcompetitions/M4-methods/blob/master/4Theta%20method.R)
133+
`Prophet` | x | | | | | | [Prophet repo](https://github.com/facebook/prophet)
134+
`FFT` (Fast Fourier Transform) | x | | | | | |
135+
`RegressionModel` (incl `RandomForest`, `LinearRegressionModel` and `LightGBMModel`) | x | x | | x | x | x |
136+
`RNNModel` (incl. LSTM and GRU); equivalent to DeepAR in its probabilistic version | x | x | x | x | | x | [DeepAR paper](https://arxiv.org/abs/1704.04110)
137+
`BlockRNNModel` (incl. LSTM and GRU) | x | x | | x | x | |
138+
`NBEATSModel` | x | x | | x | x | | [N-BEATS paper](https://arxiv.org/abs/1905.10437)
139+
`TCNModel` | x | x | x | x | x | | [TCN paper](https://arxiv.org/abs/1803.01271), [DeepTCN paper](https://arxiv.org/abs/1906.04397), [blog post](https://medium.com/unit8-machine-learning-publication/temporal-convolutional-networks-and-forecasting-5ce1b6e97ce4)
140+
`TransformerModel` | x | x | | x | x | |
141+
Naive Baselines | x | | | | | |
142+
143+
144+
## Community & Contact
145+
146+
Anyone is welcome to join our [Discord server](https://discord.gg/Um3jBTYFsA) to
147+
ask questions, make proposals, discuss use-cases, and more. If you spot a bug or
148+
or have a feature request, Github issues are also welcome.
149+
150+
If what you want to tell us is not suitable for Discord or Github,
151+
feel free to send us an email at <a href="mailto:[email protected]">[email protected]</a> for
152+
darts related matters or <a href="mailto:[email protected]">[email protected]</a> for any other
153+
inquiries.
154+
155+
### Contribute
144156

145157
The development is ongoing, and there are many new features that we want to add.
146-
We welcome pull requests and issues on GitHub.
158+
We welcome pull requests and issues on Github.
147159

148-
Before working on a contribution (a new feature or a fix), [**check our contribution guidelines**](CONTRIBUTE.md).
160+
Before working on a contribution (a new feature or a fix),
161+
[**check our contribution guidelines**](CONTRIBUTE.md).
149162

150163

151-
## Contact Us
152-
153-
If what you want to tell us is not a suitable github issue, feel free to send us an email at <a href="mailto:[email protected]">[email protected]</a> for darts related matters or <a href="mailto:[email protected]">[email protected]</a> for any other inquiries.
154-
155164
## Installation Guide
156165

157166
Some of the models depend on `prophet` and `torch`, which have non-Python dependencies.
@@ -191,6 +200,25 @@ we also maintain the `u8darts` package, which provides the following alternate l
191200
* Install core + Facebook Prophet: `pip install 'u8darts[prophet]'`
192201
* Install core + AutoARIMA: `pip install 'u8darts[pmdarima]'`
193202

203+
### Enabling Support for LightGBM
204+
205+
To enable support for LightGBM in Darts, please follow the
206+
[installation instructions](https://lightgbm.readthedocs.io/en/latest/Installation-Guide.html) for your OS.
207+
208+
#### MacOS Issues with LightGBM
209+
At the time of writing, there is an issue with ``libomp`` 12.0.1 that results in
210+
[segmentation fault on Mac OS Big Sur](https://github.com/microsoft/LightGBM/issues/4229).
211+
Here's the procedure to downgrade the ``libomp`` library (from the
212+
[original Github issue](https://github.com/microsoft/LightGBM/issues/4229#issue-867528353)):
213+
* [Install brew](https://brew.sh/) if you don't already have it.
214+
* Install `wget` if you don't already have it : `brew install wget`.
215+
* Run the commands below:
216+
```
217+
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/fb8323f2b170bd4ae97e1bac9bf3e2983af3fdb0/Formula/libomp.rb
218+
brew unlink libomp
219+
brew install libomp.rb
220+
```
221+
194222

195223
### Running the examples only, without installing:
196224

darts/dataprocessing/dtw/_plot.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def plot_alignment(self,
155155

156156
x_coords[0::3] = x_coords1
157157
x_coords[1::3] = x_coords2
158-
x_coords[2::3] = np.nan
158+
x_coords[2::3] = np.datetime64("NaT")
159159

160160
y_coords[0::3] = y_coords1
161161
y_coords[1::3] = y_coords2

darts/models/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@
4040
from .random_forest import RandomForest
4141
from .regression_model import RegressionModel
4242

43+
try:
44+
from .gradient_boosted_model import LightGBMModel
45+
except:
46+
logger.warning("Support for LightGBM not available. To enable LightGBM support in Darts, follow the detailed "
47+
"install instructions for LightGBM in the README: "
48+
"https://github.com/unit8co/darts/blob/master/README.md")
49+
4350
# Ensembling
4451
from .ensemble_model import EnsembleModel
4552
from .baselines import NaiveEnsembleModel

darts/models/fft.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from .forecasting_model import ForecastingModel
1212
from ..timeseries import TimeSeries
1313
from ..logging import get_logger
14+
from ..utils.missing_values import fill_missing_values
1415

1516
logger = get_logger(__name__)
1617

@@ -195,8 +196,7 @@ def __init__(self,
195196
This model performs forecasting on a TimeSeries instance using FFT, subsequent frequency filtering
196197
(controlled by the `nr_freqs_to_keep` argument) and inverse FFT, combined with the option to detrend
197198
the data (controlled by the `trend` argument) and to crop the training sequence to full seasonal periods
198-
(controlled by the `required_matches` argument).
199-
Please note that the training sequence must not contain any NaN values for the model to produce useful output.
199+
Note that if the training series contains any NaNs (missing values), these will be filled using `darts.utils.missing_values.fill_missing_values()`.
200200
201201
Examples:
202202
@@ -234,6 +234,7 @@ def __str__(self):
234234
return 'FFT(nr_freqs_to_keep=' + str(self.nr_freqs_to_keep) + ', trend=' + str(self.trend) + ')'
235235

236236
def fit(self, series: TimeSeries):
237+
series = fill_missing_values(series)
237238
super().fit(series)
238239
series = self.training_series
239240

darts/models/forecasting_model.py

+4
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ def gridsearch(model_class,
438438
past_covariates: Optional[TimeSeries] = None,
439439
future_covariates: Optional[TimeSeries] = None,
440440
forecast_horizon: Optional[int] = None,
441+
stride: int = 1,
441442
start: Union[pd.Timestamp, float, int] = 0.5,
442443
last_points_only: bool = False,
443444
val_series: Optional[TimeSeries] = None,
@@ -498,6 +499,8 @@ def gridsearch(model_class,
498499
An optional future-known covariate series. This applies only if the model supports future covariates.
499500
forecast_horizon
500501
The integer value of the forecasting horizon used in expanding window mode.
502+
stride
503+
The number of time steps between two consecutive predictions. Only used in expanding window mode.
501504
start
502505
The `int`, `float` or `pandas.Timestamp` that represents the starting point in the time index
503506
of `training_series` from which predictions will be made to evaluate the model.
@@ -568,6 +571,7 @@ def _evaluate_combination(param_combination):
568571
num_samples=1,
569572
start=start,
570573
forecast_horizon=forecast_horizon,
574+
stride=stride,
571575
metric=metric,
572576
reduction=reduction,
573577
last_points_only=last_points_only)
+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"""
2+
LightGBM Model
3+
--------------
4+
5+
This is a LightGBM implementation of Gradient Boosted Trees algorightm.
6+
7+
To enable LightGBM support in Darts, follow the detailed install instructions for LightGBM in the README:
8+
https://github.com/unit8co/darts/blob/master/README.md
9+
"""
10+
11+
from ..logging import get_logger
12+
from typing import Union, Optional, Sequence, List, Tuple
13+
from .regression_model import RegressionModel
14+
from ..timeseries import TimeSeries
15+
import lightgbm as lgb
16+
17+
logger = get_logger(__name__)
18+
19+
20+
class LightGBMModel(RegressionModel):
21+
def __init__(self,
22+
lags: Union[int, list] = None,
23+
lags_past_covariates: Union[int, List[int]] = None,
24+
lags_future_covariates: Union[Tuple[int, int], List[int]] = None,
25+
**kwargs):
26+
""" Light Gradient Boosted Model
27+
28+
Parameters
29+
----------
30+
lags
31+
Lagged target values used to predict the next time step. If an integer is given the last `lags` past lags
32+
are used (from -1 backward). Otherwise a list of integers with lags is required (each lag must be < 0).
33+
lags_past_covariates
34+
Number of lagged past_covariates values used to predict the next time step. If an integer is given the last
35+
`lags_past_covariates` past lags are used (inclusive, starting from lag -1). Otherwise a list of integers
36+
with lags < 0 is required.
37+
lags_future_covariates
38+
Number of lagged future_covariates values used to predict the next time step. If an tuple (past, future) is
39+
given the last `past` lags in the past are used (inclusive, starting from lag -1) along with the first
40+
`future` future lags (starting from 0 - the prediction time - up to `future - 1` included). Otherwise a list
41+
of integers with lags is required.
42+
**kwargs
43+
Additional keyword arguments passed to `lightgbm.LGBRegressor`.
44+
"""
45+
self.kwargs = kwargs
46+
47+
super().__init__(
48+
lags=lags,
49+
lags_past_covariates=lags_past_covariates,
50+
lags_future_covariates=lags_future_covariates,
51+
model=lgb.LGBMRegressor(
52+
**kwargs
53+
)
54+
)
55+
56+
def __str__(self):
57+
return 'LGBModel(lags={}, lags_past={}, lags_future={})'.format(
58+
self.lags, self.lags_past_covariates, self.lags_future_covariates
59+
)
60+
61+
def fit(self,
62+
series: Union[TimeSeries, Sequence[TimeSeries]],
63+
past_covariates: Optional[Union[TimeSeries, Sequence[TimeSeries]]] = None,
64+
future_covariates: Optional[Union[TimeSeries, Sequence[TimeSeries]]] = None,
65+
eval_series: Optional[Union[TimeSeries, Sequence[TimeSeries]]] = None,
66+
eval_past_covariates: Optional[Union[TimeSeries, Sequence[TimeSeries]]] = None,
67+
eval_future_covariates: Optional[Union[TimeSeries, Sequence[TimeSeries]]] = None,
68+
max_samples_per_ts: Optional[int] = None,
69+
**kwargs) -> None:
70+
"""
71+
Fits/trains the model using the provided list of features time series and the target time series.
72+
Parameters
73+
----------
74+
series : Union[TimeSeries, Sequence[TimeSeries]]
75+
TimeSeries or Sequence[TimeSeries] object containing the target values.
76+
past_covariates : Union[TimeSeries, Sequence[TimeSeries]]
77+
Optionally, a series or sequence of series specifying past-observed covariates
78+
future_covariates : Union[TimeSeries, Sequence[TimeSeries]]
79+
Optionally, a series or sequence of series specifying future-known covariates
80+
eval_series : Union[TimeSeries, Sequence[TimeSeries]]
81+
TimeSeries or Sequence[TimeSeries] object containing the target values for evaluation dataset
82+
eval_past_covariates : Union[TimeSeries, Sequence[TimeSeries]]
83+
Optionally, a series or sequence of series specifying past-observed covariates for evaluation dataset
84+
eval_future_covariates : Union[TimeSeries, Sequence[TimeSeries]]
85+
Optionally, a series or sequence of series specifying future-known covariates for evaluation dataset
86+
max_samples_per_ts : int
87+
This is an upper bound on the number of tuples that can be produced
88+
per time series. It can be used in order to have an upper bound on the total size of the dataset and
89+
ensure proper sampling. If `None`, it will read all of the individual time series in advance (at dataset
90+
creation) to know their sizes, which might be expensive on big datasets.
91+
If some series turn out to have a length that would allow more than `max_samples_per_ts`, only the
92+
most recent `max_samples_per_ts` samples will be considered.
93+
"""
94+
95+
if eval_series is not None:
96+
97+
kwargs['eval_set'] = self._create_lagged_data(
98+
target_series=eval_series,
99+
past_covariates=eval_past_covariates,
100+
future_covariates=eval_future_covariates,
101+
max_samples_per_ts=max_samples_per_ts
102+
)
103+
104+
super().fit(series=series,
105+
past_covariates=past_covariates,
106+
future_covariates=future_covariates,
107+
max_samples_per_ts=max_samples_per_ts,
108+
**kwargs)

darts/models/regression_model.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ def fit(
358358

359359
self.input_dim = series_dim + covariates_dim
360360

361-
self._fit_model(series, past_covariates, future_covariates, max_samples_per_ts)
361+
self._fit_model(series, past_covariates, future_covariates, max_samples_per_ts, **kwargs)
362362

363363
def _get_prediction_data(
364364
self,

darts/models/rnn_model.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def __init__(self,
138138
model
139139
Either a string specifying the RNN module type ("RNN", "LSTM" or "GRU"),
140140
or a PyTorch module with the same specifications as
141-
`darts.models.rnn_model.RNNModule`.
141+
`darts.models.rnn_model._RNNModule`.
142142
input_chunk_length
143143
Number of past time steps that are fed to the forecasting module at prediction time.
144144
hidden_dim
@@ -234,7 +234,12 @@ def _create_model(self, train_sample: Tuple[torch.Tensor]) -> torch.nn.Module:
234234
dropout=self.dropout,
235235
num_layers=self.n_rnn_layers)
236236
else:
237-
model = self.rnn_type_or_module
237+
model = self.rnn_type_or_module(name='custom_module',
238+
input_size=input_dim,
239+
target_size=target_size,
240+
hidden_dim=self.hidden_dim,
241+
dropout=self.dropout,
242+
num_layers=self.n_rnn_layers)
238243
return model
239244

240245
def _build_train_dataset(self,

0 commit comments

Comments
 (0)