diff --git a/src/modelskill/metrics.py b/src/modelskill/metrics.py index 5d0652666..6ea0838d6 100644 --- a/src/modelskill/metrics.py +++ b/src/modelskill/metrics.py @@ -251,6 +251,9 @@ def nash_sutcliffe_efficiency(obs: ArrayLike, model: ArrayLike) -> Any: Nash, J. E.; Sutcliffe, J. V. (1970). "River flow forecasting through conceptual models part I — A discussion of principles". Journal of Hydrology. 10 (3): 282–290. """ + # np.sum on a pandas Series skips NaN, so convert to get NaN like the other metrics + obs = np.asarray(obs) + model = np.asarray(model) assert obs.size == model.size if len(obs) == 0: @@ -331,6 +334,9 @@ def r2(obs: ArrayLike, model: ArrayLike) -> Any: >>> r2(obs,model) np.float64(0.6379999999999998) """ + # np.sum on a pandas Series skips NaN, so convert to get NaN like the other metrics + obs = np.asarray(obs) + model = np.asarray(model) assert obs.size == model.size if len(obs) == 0: return np.nan diff --git a/tests/test_metrics.py b/tests/test_metrics.py index 26bc58579..89a675042 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -74,6 +74,19 @@ def test_kge_climatology_model(): assert mtr.kling_gupta_efficiency(obs, mod) == pytest.approx(-0.41, abs=1e-2) +@pytest.mark.parametrize("metric", [mtr.nse, mtr.r2]) +@pytest.mark.parametrize( + "model", [[1.0, 2.0, np.nan, np.nan], [np.nan, np.nan, np.nan, np.nan]] +) +def test_nse_r2_nan_in_model_series(metric: Callable, model: list) -> None: + # pandas Series must give the same result as NumPy arrays (NaN), not 1.0 + obs = pd.Series([1.0, 2.0, 3.0, 4.0]) + mod = pd.Series(model) + + assert np.isnan(metric(obs.to_numpy(), mod.to_numpy())) + assert np.isnan(metric(obs, mod)) + + def test_nse_suboptimal(): obs = np.array([1.0, 0.5, 0]) mod = np.array([1.0, 0.0, 0.5])