Skip to content

Commit

Permalink
Backports v0.14.1 (#3055)
Browse files Browse the repository at this point in the history
* Refactor tests for `ev.aggregations` (#3038)

* Fix edge cases in metric computation (#3037)

* Add plt.show() to README (#3043)

* Rotbaum: Add item-id to forecast. (#3049)

* Fix mypy checks (#3052)

---------

Co-authored-by: Jasper <schjaspe@amazon.de>
  • Loading branch information
lostella and Jasper authored Nov 14, 2023
1 parent 380bf89 commit 536465d
Show file tree
Hide file tree
Showing 8 changed files with 191 additions and 69 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ plt.plot(df["1954":], color="black")
for forecast in forecasts:
forecast.plot()
plt.legend(["True values"], loc="upper left", fontsize="xx-large")
plt.show()
```

![[train-test]](https://ts.gluon.ai/static/README/forecasts.png)
Expand Down
13 changes: 8 additions & 5 deletions src/gluonts/ev/aggregations.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class Sum(Aggregation):
def step(self, values: np.ndarray) -> None:
assert self.axis is None or isinstance(self.axis, tuple)

summed_values = np.ma.sum(values, axis=self.axis)
summed_values = np.nansum(values, axis=self.axis)

if self.axis is None or 0 in self.axis:
if self.partial_result is None:
Expand All @@ -66,9 +66,11 @@ def get(self) -> np.ndarray:
assert self.axis is None or isinstance(self.axis, tuple)

if self.axis is None or 0 in self.axis:
return np.ma.copy(self.partial_result)
assert isinstance(self.partial_result, np.ndarray)
return np.copy(self.partial_result)

return np.ma.concatenate(self.partial_result)
assert isinstance(self.partial_result, list)
return np.concatenate(self.partial_result)


@dataclass
Expand Down Expand Up @@ -107,7 +109,7 @@ def step(self, values: np.ndarray) -> None:
if self.partial_result is None:
self.partial_result = []

mean_values = np.ma.mean(values, axis=self.axis)
mean_values = np.nanmean(values, axis=self.axis)
assert isinstance(self.partial_result, list)
self.partial_result.append(mean_values)

Expand All @@ -118,4 +120,5 @@ def get(self) -> np.ndarray:
assert isinstance(self.partial_result, np.ndarray)
return self.partial_result / self.n

return np.ma.concatenate(self.partial_result)
assert isinstance(self.partial_result, list)
return np.concatenate(self.partial_result)
8 changes: 4 additions & 4 deletions src/gluonts/ev/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ def mean(**quantile_losses: np.ndarray) -> np.ndarray:
[quantile_loss for quantile_loss in quantile_losses.values()],
axis=0,
)
return np.ma.mean(stacked_quantile_losses, axis=0)
return np.mean(stacked_quantile_losses, axis=0)

def __call__(self, axis: Optional[int] = None) -> DerivedMetric:
return DerivedMetric(
Expand All @@ -515,7 +515,7 @@ def mean(**quantile_losses: np.ndarray) -> np.ndarray:
[quantile_loss for quantile_loss in quantile_losses.values()],
axis=0,
)
return np.ma.mean(stacked_quantile_losses, axis=0)
return np.mean(stacked_quantile_losses, axis=0)

def __call__(self, axis: Optional[int] = None) -> DerivedMetric:
return DerivedMetric(
Expand All @@ -538,7 +538,7 @@ def mean(**quantile_losses: np.ndarray) -> np.ndarray:
[quantile_loss for quantile_loss in quantile_losses.values()],
axis=0,
)
return np.ma.mean(stacked_quantile_losses, axis=0)
return np.mean(stacked_quantile_losses, axis=0)

def __call__(self, axis: Optional[int] = None) -> DerivedMetric:
return DerivedMetric(
Expand All @@ -565,7 +565,7 @@ def mean(
[np.abs(coverages[f"coverage[{q}]"] - q) for q in quantile_levels],
axis=0,
)
return np.ma.mean(intermediate_result, axis=0)
return np.mean(intermediate_result, axis=0)

def __call__(self, axis: Optional[int] = None) -> DerivedMetric:
return DerivedMetric(
Expand Down
4 changes: 3 additions & 1 deletion src/gluonts/ext/rotbaum/_predictor.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@ def __init__(
featurized_data: List,
start_date: pd.Period,
prediction_length: int,
item_id: Optional[str] = None,
):
self.models = models
self.featurized_data = featurized_data
self.start_date = start_date
self.prediction_length = prediction_length
self.item_id = None
self.item_id = item_id
self.lead_time = None

def quantile(self, q: float) -> np.ndarray: # type: ignore
Expand Down Expand Up @@ -336,6 +337,7 @@ def predict( # type: ignore
[featurized_data],
start_date=forecast_start(ts),
prediction_length=self.prediction_length,
item_id=ts.get("item_id"),
)

def explain(
Expand Down
2 changes: 1 addition & 1 deletion src/gluonts/model/evaluation.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def evaluate_forecasts(
)
if index0 is not None:
index0_repeated = np.take(index0, indices=index_arrays[0], axis=0)
index_arrays = (*zip(*index0_repeated), *index_arrays[1:])
index_arrays = (*zip(*index0_repeated), *index_arrays[1:]) # type: ignore
index = pd.MultiIndex.from_arrays(index_arrays)

flattened_metrics = valmap(np.ravel, metrics_values)
Expand Down
4 changes: 2 additions & 2 deletions src/gluonts/mx/model/deepstate/issm.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# express or implied. See the License for the specific language governing
# permissions and limitations under the License.

from typing import List, Tuple
from typing import List, Sequence, Tuple

from pandas.tseries.frequencies import to_offset

Expand All @@ -31,7 +31,7 @@
)


def _make_block_diagonal(blocks: List[Tensor]) -> Tensor:
def _make_block_diagonal(blocks: Sequence[Tensor]) -> Tensor:
assert (
len(blocks) > 0
), "You need at least one tensor to make a block-diagonal tensor"
Expand Down
145 changes: 90 additions & 55 deletions test/ev/test_aggregations.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,84 +18,119 @@
from gluonts.ev.aggregations import Mean, Sum
from gluonts.itertools import power_set

VALUE_STREAM = [
[
np.full((3, 5), np.nan),
np.full((3, 5), np.nan),
np.full((3, 5), np.nan),
],
[
np.array([[0, np.nan], [0, 0]]),
np.array([[0, 5], [-5, np.nan]]),
],
[
np.full(shape=(3, 3), fill_value=1),
np.full(shape=(1, 3), fill_value=4),
],
]

SUM_RES_AXIS_NONE = [
0,
0,
21,
]

SUM_RES_AXIS_0 = [
np.zeros(5),
np.array([-5, 5]),
np.array([7, 7, 7]),
]
SUM_RES_AXIS_1 = [
np.zeros(9),
np.array([0, 0, 5, -5]),
np.array([3, 3, 3, 12]),
]


MEAN_RES_AXIS_NONE = [
np.nan,
0,
1.75,
]

MEAN_RES_AXIS_0 = [
np.full(5, np.nan),
np.array([-1.25, 2.5]),
np.array([1.75, 1.75, 1.75]),
]
MEAN_RES_AXIS_1 = [
np.full(9, np.nan),
np.array([0, 0, 2.5, -5]),
np.array([1, 1, 1, 4]),
]


@pytest.mark.parametrize(
"value_stream, res_axis_none, res_axis_0, res_axis_1",
zip(VALUE_STREAM, SUM_RES_AXIS_NONE, SUM_RES_AXIS_0, SUM_RES_AXIS_1),
[
(
[
np.full((3, 5), 0.0),
np.full((3, 5), 0.0),
np.full((3, 5), 0.0),
],
0.0,
np.zeros(5),
np.zeros(9),
),
(
np.ma.masked_invalid(
[
np.full((3, 5), np.nan),
np.full((3, 5), np.nan),
np.full((3, 5), np.nan),
]
),
0,
np.zeros(5),
np.zeros(9),
),
(
np.ma.masked_invalid(
[
np.array([[0, np.nan], [0, 0]]),
np.array([[0, 5], [-5, np.nan]]),
]
),
0,
np.array([-5, 5]),
np.array([0, 0, 5, -5]),
),
(
[
np.full(shape=(3, 3), fill_value=1),
np.full(shape=(1, 3), fill_value=4),
],
21,
np.array([7, 7, 7]),
np.array([3, 3, 3, 12]),
),
],
)
def test_Sum(value_stream, res_axis_none, res_axis_0, res_axis_1):
for axis, expected_result in zip(
[None, 0, 1], [res_axis_none, res_axis_0, res_axis_1]
):
sum = Sum(axis=axis)
for values in value_stream:
sum.step(np.ma.masked_invalid(values))
sum.step(values)

np.testing.assert_almost_equal(sum.get(), expected_result)


@pytest.mark.parametrize(
"value_stream, res_axis_none, res_axis_0, res_axis_1",
zip(VALUE_STREAM, MEAN_RES_AXIS_NONE, MEAN_RES_AXIS_0, MEAN_RES_AXIS_1),
[
(
[
np.full((3, 5), 0.0),
np.full((3, 5), 0.0),
np.full((3, 5), 0.0),
],
0.0,
np.zeros(5),
np.zeros(9),
),
(
np.ma.masked_invalid(
[
np.full((3, 5), np.nan),
np.full((3, 5), np.nan),
np.full((3, 5), np.nan),
]
),
np.nan,
np.full(5, np.nan),
np.full(9, np.nan),
),
(
np.ma.masked_invalid(
[
np.array([[0, np.nan], [0, 0]]),
np.array([[0, 5], [-5, np.nan]]),
]
),
0,
np.array([-1.25, 2.5]),
np.array([0, 0, 2.5, -5]),
),
(
[
np.full(shape=(3, 3), fill_value=1),
np.full(shape=(1, 3), fill_value=4),
],
1.75,
np.array([1.75, 1.75, 1.75]),
np.array([1, 1, 1, 4]),
),
],
)
def test_Mean(value_stream, res_axis_none, res_axis_0, res_axis_1):
for axis, expected_result in zip(
[None, 0, 1], [res_axis_none, res_axis_0, res_axis_1]
):
mean = Mean(axis=axis)
for values in value_stream:
mean.step(np.ma.masked_invalid(values))
mean.step(values)

np.testing.assert_almost_equal(mean.get(), expected_result)

Expand Down
Loading

0 comments on commit 536465d

Please sign in to comment.