Commit e049ca0f authored by Thibault Hallouin's avatar Thibault Hallouin
Browse files

add new deterministic metric CONT_TBL

1 merge request!1release v0.1.0.0
Pipeline #44821 passed with stage
in 4 minutes and 12 seconds
Showing with 293 additions and 33 deletions
+293 -33
157.,19.,15.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
157.,19.,15.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
157.,19.,15.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
157.,19.,15.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,19.,14.,120.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,21.,14.,118.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,21.,14.,118.
200.,15.,8.,88.
220.,21.,6.,64.
nan,nan,nan,nan
158.,21.,14.,118.
200.,16.,8.,87.
221.,21.,5.,64.
nan,nan,nan,nan
...@@ -8,12 +8,19 @@ import evalhyd ...@@ -8,12 +8,19 @@ import evalhyd
_prd = numpy.genfromtxt("./data/q_prd.csv", delimiter=',')[:, :] _prd = numpy.genfromtxt("./data/q_prd.csv", delimiter=',')[:, :]
_obs = numpy.genfromtxt("./data/q_obs.csv", delimiter=',')[numpy.newaxis, :] _obs = numpy.genfromtxt("./data/q_obs.csv", delimiter=',')[numpy.newaxis, :]
_thr = numpy.repeat(
numpy.array([[690, 534, 445, numpy.nan]]), repeats=_prd.shape[0], axis=0
)
_events = "high"
# list all available deterministic metrics # list all available deterministic metrics
_all_metrics = ( _all_metrics = (
# errors-based # errors-based
'MAE', 'MARE', 'MSE', 'RMSE', 'MAE', 'MARE', 'MSE', 'RMSE',
# efficiencies-based # efficiencies-based
'NSE', 'KGE', 'KGE_D', 'KGEPRIME', 'KGEPRIME_D', 'NSE', 'KGE', 'KGE_D', 'KGEPRIME', 'KGEPRIME_D',
# contingency table-based
'CONT_TBL'
) )
# list all available deterministic diagnostics # list all available deterministic diagnostics
...@@ -30,12 +37,18 @@ class TestMetrics(unittest.TestCase): ...@@ -30,12 +37,18 @@ class TestMetrics(unittest.TestCase):
[:, numpy.newaxis, numpy.newaxis] [:, numpy.newaxis, numpy.newaxis]
) for metric in _all_metrics ) for metric in _all_metrics
} }
# /!\ stacked-up thresholds in CSV file for CONT_TBL
# because 5D metric so need to reshape array
expected['CONT_TBL'] = (
expected['CONT_TBL'].reshape(expected['NSE'].shape + (4, 4))
)
def test_metrics_2d(self): def test_metrics_2d(self):
for metric in self.expected.keys(): for metric in self.expected.keys():
with self.subTest(metric=metric): with self.subTest(metric=metric):
numpy.testing.assert_almost_equal( numpy.testing.assert_almost_equal(
evalhyd.evald(_obs, _prd, [metric])[0], evalhyd.evald(_obs, _prd, [metric],
q_thr=_thr, events=_events)[0],
self.expected[metric] self.expected[metric]
) )
...@@ -43,7 +56,8 @@ class TestMetrics(unittest.TestCase): ...@@ -43,7 +56,8 @@ class TestMetrics(unittest.TestCase):
for metric in self.expected.keys(): for metric in self.expected.keys():
with self.subTest(metric=metric): with self.subTest(metric=metric):
numpy.testing.assert_almost_equal( numpy.testing.assert_almost_equal(
evalhyd.evald(_obs[0], _prd[0], [metric])[0], evalhyd.evald(_obs[0], _prd[0], [metric],
q_thr=_thr[0], events=_events)[0],
[self.expected[metric][0]] [self.expected[metric][0]]
) )
...@@ -51,31 +65,48 @@ class TestMetrics(unittest.TestCase): ...@@ -51,31 +65,48 @@ class TestMetrics(unittest.TestCase):
class TestTransform(unittest.TestCase): class TestTransform(unittest.TestCase):
def test_transform_sqrt(self): def test_transform_sqrt(self):
numpy.testing.assert_almost_equal( for metric in _all_metrics:
evalhyd.evald(_obs, _prd, ["NSE"], transform="sqrt")[0], with self.subTest(metric=metric):
evalhyd.evald(_obs ** 0.5, _prd ** 0.5, ["NSE"])[0] numpy.testing.assert_almost_equal(
) evalhyd.evald(_obs, _prd, ["NSE"], transform="sqrt",
q_thr=_thr, events=_events)[0],
evalhyd.evald(_obs ** 0.5, _prd ** 0.5, ["NSE"],
q_thr=_thr ** 0.5, events=_events)[0]
)
def test_transform_inv(self): def test_transform_inv(self):
eps = 0.01 * numpy.mean(_obs) eps = 0.01 * numpy.mean(_obs)
numpy.testing.assert_almost_equal( for metric in _all_metrics:
evalhyd.evald(_obs, _prd, ["NSE"], transform="inv")[0], with self.subTest(metric=metric):
evalhyd.evald(1 / (_obs + eps), 1 / (_prd + eps), ["NSE"])[0] numpy.testing.assert_almost_equal(
) evalhyd.evald(_obs, _prd, ["NSE"], transform="inv",
q_thr=_thr, events=_events)[0],
evalhyd.evald(1 / (_obs + eps), 1 / (_prd + eps), ["NSE"],
q_thr=1 / (_thr + eps), events=_events)[0]
)
def test_transform_log(self): def test_transform_log(self):
eps = 0.01 * numpy.mean(_obs) eps = 0.01 * numpy.mean(_obs)
numpy.testing.assert_almost_equal( for metric in _all_metrics:
evalhyd.evald(_obs, _prd, ["NSE"], transform="log")[0], with self.subTest(metric=metric):
evalhyd.evald(numpy.log(_obs + eps), numpy.log(_prd + eps), numpy.testing.assert_almost_equal(
["NSE"])[0] evalhyd.evald(_obs, _prd, ["NSE"], transform="log",
) q_thr=_thr, events=_events)[0],
evalhyd.evald(numpy.log(_obs + eps), numpy.log(_prd + eps),
["NSE"],
q_thr=numpy.log(_thr + eps), events=_events)[0]
)
def test_transform_pow(self): def test_transform_pow(self):
numpy.testing.assert_almost_equal( for metric in _all_metrics:
evalhyd.evald(_obs, _prd, ["NSE"], transform="pow", exponent=0.3)[0], with self.subTest(metric=metric):
evalhyd.evald(_obs ** 0.3, _prd ** 0.3, ["NSE"])[0] numpy.testing.assert_almost_equal(
) evalhyd.evald(_obs, _prd, ["NSE"],
q_thr=_thr, events=_events,
transform="pow", exponent=0.3)[0],
evalhyd.evald(_obs ** 0.3, _prd ** 0.3, ["NSE"],
q_thr=_thr ** 0.3, events=_events)[0]
)
class TestMasking(unittest.TestCase): class TestMasking(unittest.TestCase):
...@@ -90,8 +121,10 @@ class TestMasking(unittest.TestCase): ...@@ -90,8 +121,10 @@ class TestMasking(unittest.TestCase):
prd = _prd[..., 99:].copy() prd = _prd[..., 99:].copy()
numpy.testing.assert_almost_equal( numpy.testing.assert_almost_equal(
evalhyd.evald(_obs, _prd, ["NSE"], t_msk=msk)[0], evalhyd.evald(_obs, _prd, ["NSE"],
evalhyd.evald(obs, prd, ["NSE"])[0] q_thr=_thr, events=_events, t_msk=msk)[0],
evalhyd.evald(obs, prd, ["NSE"],
q_thr=_thr, events=_events)[0]
) )
def test_conditions(self): def test_conditions(self):
...@@ -106,8 +139,10 @@ class TestMasking(unittest.TestCase): ...@@ -106,8 +139,10 @@ class TestMasking(unittest.TestCase):
prd = _prd[..., msk].copy() prd = _prd[..., msk].copy()
numpy.testing.assert_almost_equal( numpy.testing.assert_almost_equal(
evalhyd.evald(_obs, _prd, ["NSE"], m_cdt=cdt)[0], evalhyd.evald(_obs, _prd, ["NSE"],
evalhyd.evald(obs, prd, ["NSE"])[0] q_thr=_thr, events=_events, m_cdt=cdt)[0],
evalhyd.evald(obs, prd, ["NSE"],
q_thr=_thr, events=_events)[0]
) )
with self.subTest(conditions="observed streamflow statistics"): with self.subTest(conditions="observed streamflow statistics"):
...@@ -121,8 +156,10 @@ class TestMasking(unittest.TestCase): ...@@ -121,8 +156,10 @@ class TestMasking(unittest.TestCase):
prd = _prd[..., msk].copy() prd = _prd[..., msk].copy()
numpy.testing.assert_almost_equal( numpy.testing.assert_almost_equal(
evalhyd.evald(_obs, _prd, ["NSE"], m_cdt=cdt)[0], evalhyd.evald(_obs, _prd, ["NSE"],
evalhyd.evald(obs, prd, ["NSE"])[0] q_thr=_thr, events=_events, m_cdt=cdt)[0],
evalhyd.evald(obs, prd, ["NSE"],
q_thr=_thr, events=_events)[0]
) )
with self.subTest(conditions="time indices"): with self.subTest(conditions="time indices"):
...@@ -138,15 +175,17 @@ class TestMasking(unittest.TestCase): ...@@ -138,15 +175,17 @@ class TestMasking(unittest.TestCase):
prd = _prd[..., 20:].copy() prd = _prd[..., 20:].copy()
numpy.testing.assert_almost_equal( numpy.testing.assert_almost_equal(
evalhyd.evald(_obs, _prd, ["NSE"], m_cdt=cdt)[0], evalhyd.evald(_obs, _prd, ["NSE"],
evalhyd.evald(obs, prd, ["NSE"])[0] q_thr=_thr, events=_events, m_cdt=cdt)[0],
evalhyd.evald(obs, prd, ["NSE"],
q_thr=_thr, events=_events)[0]
) )
class TestMissingData(unittest.TestCase): class TestMissingData(unittest.TestCase):
def test_nan(self): def test_nan(self):
for metric in ('RMSE', 'NSE', 'KGE', 'KGEPRIME'): for metric in _all_metrics:
obs = numpy.array( obs = numpy.array(
[[4.7, numpy.nan, 5.5, 2.7, 4.1]] [[4.7, numpy.nan, 5.5, 2.7, 4.1]]
) )
...@@ -155,9 +194,16 @@ class TestMissingData(unittest.TestCase): ...@@ -155,9 +194,16 @@ class TestMissingData(unittest.TestCase):
[numpy.nan, 4.2, 4.7, 4.3, 3.3], [numpy.nan, 4.2, 4.7, 4.3, 3.3],
[5.3, 5.2, 5.7, numpy.nan, 3.9]] [5.3, 5.2, 5.7, numpy.nan, 3.9]]
) )
thr = numpy.array(
[[4., 5.],
[4., 5.],
[4., 5.]]
)
events = "low"
with self.subTest(metric=metric): with self.subTest(metric=metric):
res = evalhyd.evald(obs, prd, [metric])[0] res = evalhyd.evald(obs, prd, [metric],
q_thr=thr, events=events)[0]
for i in range(prd.shape[0]): for i in range(prd.shape[0]):
msk = ~numpy.isnan(obs[0]) & ~numpy.isnan(prd[i]) msk = ~numpy.isnan(obs[0]) & ~numpy.isnan(prd[i])
...@@ -169,7 +215,8 @@ class TestMissingData(unittest.TestCase): ...@@ -169,7 +215,8 @@ class TestMissingData(unittest.TestCase):
evalhyd.evald( evalhyd.evald(
obs[:, msk], obs[:, msk],
prd[i, msk][numpy.newaxis], prd[i, msk][numpy.newaxis],
[metric] [metric],
q_thr=thr[i, :][numpy.newaxis], events=events
)[0] )[0]
) )
...@@ -190,21 +237,30 @@ class TestUncertainty(unittest.TestCase): ...@@ -190,21 +237,30 @@ class TestUncertainty(unittest.TestCase):
obs_3yrs = numpy.hstack((obs_1yr,) * 3) obs_3yrs = numpy.hstack((obs_1yr,) * 3)
prd_3yrs = numpy.hstack((prd_1yr,) * 3) prd_3yrs = numpy.hstack((prd_1yr,) * 3)
for metric in ('RMSE', 'NSE', 'KGE', 'KGEPRIME'): thr = numpy.repeat(
numpy.array([[690, 534, 445, numpy.nan]]),
repeats=prd_1yr.shape[0], axis=0
)
events = "low"
for metric in _all_metrics:
with self.subTest(metric=metric): with self.subTest(metric=metric):
numpy.testing.assert_almost_equal( numpy.testing.assert_almost_equal(
# bootstrap with only one year of data # bootstrap with only one year of data
# (compare last sample only to have matching dimensions) # (compare last sample only to have matching dimensions)
evalhyd.evald( evalhyd.evald(
obs_1yr, prd_1yr, [metric], obs_1yr, prd_1yr, [metric],
q_thr=thr,
events=events,
bootstrap={ bootstrap={
"n_samples": 10, "len_sample": 3, "summary": 0 "n_samples": 10, "len_sample": 3, "summary": 0
}, },
dts=dts_1yr dts=dts_1yr
)[0][..., [0]], )[0][:, :, [0]],
# repeat year of data three times to correspond to a # repeat year of data three times to correspond to a
# bootstrap sample of length 3 # bootstrap sample of length 3
evalhyd.evald(obs_3yrs, prd_3yrs, [metric])[0] evalhyd.evald(obs_3yrs, prd_3yrs, [metric],
q_thr=thr, events=events)[0]
) )
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment