From 1d55986c74ab38251c89f8a124102747946561aa Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Fri, 7 Oct 2022 15:14:32 +0200 Subject: [PATCH 1/4] Alternative implementation of the scatter index --- fmskill/metrics.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/fmskill/metrics.py b/fmskill/metrics.py index 71ed8268b..f8c0e57e8 100644 --- a/fmskill/metrics.py +++ b/fmskill/metrics.py @@ -410,6 +410,26 @@ def si(obs: np.ndarray, model: np.ndarray) -> float: def scatter_index(obs: np.ndarray, model: np.ndarray) -> float: """Scatter index (SI) + Which is the same as the unbiased-RMSE normalized by the mean of the observations. + + .. math:: + \\sqrt {\frac{1}{n} \\sum_{i=1}^n \\left( (model_i - \\overline {model}) - (obs_i - \\overline {obs}) \\right)^2 + {\frac{1}{n} \\sum_{i=1}^n obs_i^2}} + + Range: [0, 100]; Best: 0 + """ + assert obs.size == model.size + if len(obs) == 0: + return np.nan + + residual = obs.ravel() - model.ravel() + residual = residual - residual.mean() # unbiased + return np.sqrt(np.mean(residual**2)) / np.mean(obs.ravel()) + + +def scatter_index2(obs: np.ndarray, model: np.ndarray) -> float: + """Alternative formulation of the scatter index (SI) + .. math:: \\sqrt {\\frac{\\sum_{i=1}^n \\left( (model_i - \\overline {model}) - (obs_i - \\overline {obs}) \\right)^2} {\\sum_{i=1}^n obs_i^2}} From 7a472f8243d7abc0230abe8ac50910907b7421b8 Mon Sep 17 00:00:00 2001 From: Jesper Sandvig Mariegaard <34088801+jsmariegaard@users.noreply.github.com> Date: Wed, 12 Oct 2022 10:30:41 +0200 Subject: [PATCH 2/4] normalize with abs mean --- fmskill/metrics.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fmskill/metrics.py b/fmskill/metrics.py index f8c0e57e8..58ebf2bf2 100644 --- a/fmskill/metrics.py +++ b/fmskill/metrics.py @@ -410,13 +410,13 @@ def si(obs: np.ndarray, model: np.ndarray) -> float: def scatter_index(obs: np.ndarray, model: np.ndarray) -> float: """Scatter index (SI) - Which is the same as the unbiased-RMSE normalized by the mean of the observations. + Which is the same as the unbiased-RMSE normalized by the absolute mean of the observations. .. math:: - \\sqrt {\frac{1}{n} \\sum_{i=1}^n \\left( (model_i - \\overline {model}) - (obs_i - \\overline {obs}) \\right)^2 - {\frac{1}{n} \\sum_{i=1}^n obs_i^2}} + \\frac{ \\sqrt{ \\frac{1}{n} \\sum_{i=1}^n \\left( (model_i - \\overline {model}) - (obs_i - \\overline {obs}) \\right)^2} } + {\\frac{1}{n} \\sum_{i=1}^n | obs_i | } - Range: [0, 100]; Best: 0 + Range: [0, \\infty); Best: 0 """ assert obs.size == model.size if len(obs) == 0: @@ -424,7 +424,7 @@ def scatter_index(obs: np.ndarray, model: np.ndarray) -> float: residual = obs.ravel() - model.ravel() residual = residual - residual.mean() # unbiased - return np.sqrt(np.mean(residual**2)) / np.mean(obs.ravel()) + return np.sqrt(np.mean(residual**2)) / np.mean(np.abs(obs.ravel())) def scatter_index2(obs: np.ndarray, model: np.ndarray) -> float: From caa1acf1f3df8e87098edc51260d3b33265f1423 Mon Sep 17 00:00:00 2001 From: caichac-dhi <97288080+caichac-dhi@users.noreply.github.com> Date: Wed, 12 Oct 2022 15:05:45 +0200 Subject: [PATCH 3/4] changed_SI_test --- tests/test_multimodelcompare.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_multimodelcompare.py b/tests/test_multimodelcompare.py index efed980c4..cb5193459 100644 --- a/tests/test_multimodelcompare.py +++ b/tests/test_multimodelcompare.py @@ -118,7 +118,7 @@ def test_mm_skill_obs(cc): assert s.loc["SW_2"].bias == s2.loc["SW_2"].bias df = cc.mean_skill(model=0, observation=[0, "c2"]).df - assert pytest.approx(df.si[0]) == 0.10358979 + assert pytest.approx(df.si[0]) == 0.11113215 def test_mm_skill_missing_obs(cc, o1): From 5aa326a64b7a14981db88d90af7fed4d25d57088 Mon Sep 17 00:00:00 2001 From: caichac-dhi <97288080+caichac-dhi@users.noreply.github.com> Date: Wed, 12 Oct 2022 15:14:48 +0200 Subject: [PATCH 4/4] fixed docstring --- fmskill/metrics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmskill/metrics.py b/fmskill/metrics.py index 58ebf2bf2..33386b91d 100644 --- a/fmskill/metrics.py +++ b/fmskill/metrics.py @@ -42,7 +42,7 @@ >>> mef(obs, mod) 0.9231099877688299 >>> si(obs, mod) -0.7294663886165093 +0.8715019052958266 >>> spearmanr(obs, mod) 0.5 >>> cc(obs, mod)