45
45
0.637783218973691
46
46
>>> lin_slope(obs, mod)
47
47
0.4724896836313617
48
+ >>> willmott(obs, mod)
49
+ 0.7484604452865941
48
50
>>> hit_ratio(obs, mod, a=0.5)
49
51
0.6666666666666666
50
52
"""
@@ -59,13 +61,26 @@ def bias(obs, model) -> float:
59
61
.. math::
60
62
bias=\\ frac{1}{n}\\ sum_{i=1}^n (model_i - obs_i)
61
63
62
- Range: -infinity to infinity ; Best: 0. 0
64
+ Range: :math:`(- \\ infty, \\ infty)` ; Best: 0
63
65
"""
64
66
65
67
assert obs .size == model .size
66
68
return np .mean (model .ravel () - obs .ravel ())
67
69
68
70
71
+ def max_error (obs , model ) -> float :
72
+ """Max (absolute) error
73
+
74
+ .. math::
75
+ max_error = max(|model_i - obs_i|)
76
+
77
+ Range: :math:`[0, \\ infty)`; Best: 0
78
+ """
79
+
80
+ assert obs .size == model .size
81
+ return np .max (np .abs (model .ravel () - obs .ravel ()))
82
+
83
+
69
84
def mae (obs : np .ndarray , model : np .ndarray , weights : np .ndarray = None ) -> float :
70
85
"""alias for mean_absolute_error"""
71
86
assert obs .size == model .size
@@ -80,7 +95,7 @@ def mean_absolute_error(
80
95
.. math::
81
96
MAE=\\ frac{1}{n}\\ sum_{i=1}^n|model_i - obs_i|
82
97
83
- Range: 0.0 to infinity ; Best: 0. 0
98
+ Range: :math:`[0, \\ infty)` ; Best: 0
84
99
"""
85
100
assert obs .size == model .size
86
101
@@ -100,7 +115,7 @@ def mean_absolute_percentage_error(obs: np.ndarray, model: np.ndarray) -> float:
100
115
.. math::
101
116
MAPE=\\ frac{1}{n}\\ sum_{i=1}^n\\ frac{|model_i - obs_i|}{obs_i}*100
102
117
103
- Range: 0.0 to infinity ; Best: 0. 0
118
+ Range: :math:`[0, \\ infty)` ; Best: 0
104
119
"""
105
120
106
121
assert obs .size == model .size
@@ -125,7 +140,7 @@ def urmse(obs: np.ndarray, model: np.ndarray, weights: np.ndarray = None) -> flo
125
140
126
141
uRMSE = \\ sqrt{\\ frac{1}{n} \\ sum_{i=1}^n res_{u,i}^2}
127
142
128
- Range: 0.0 to infinity ; Best: 0. 0
143
+ Range: :math:`[0, \\ infty)` ; Best: 0
129
144
130
145
See Also
131
146
--------
@@ -165,7 +180,7 @@ def root_mean_squared_error(
165
180
166
181
uRMSE=\\ sqrt{\\ frac{1}{n} \\ sum_{i=1}^n res_{u,i}^2}
167
182
168
- Range: 0.0 to infinity ; Best: 0. 0
183
+ Range: :math:`[0, \\ infty)` ; Best: 0
169
184
170
185
"""
171
186
assert obs .size == model .size
@@ -191,7 +206,7 @@ def nash_sutcliffe_efficiency(obs: np.ndarray, model: np.ndarray) -> float:
191
206
NSE = 1 - \\ frac {\\ sum _{i=1}^{n}\\ left(model_{i} - obs_{i}\\ right)^{2}}
192
207
{\\ sum_{i=1}^{n}\\ left(obs_{i} - {\\ overline{obs}}\\ right)^{2}}
193
208
194
- Range: -infinity to 1.0 ; Best: 1.0
209
+ Range: :math:`(- \\ infty, 1]` ; Best: 1
195
210
196
211
Note
197
212
----
@@ -214,16 +229,16 @@ def nash_sutcliffe_efficiency(obs: np.ndarray, model: np.ndarray) -> float:
214
229
215
230
216
231
def r2 (obs : np .ndarray , model : np .ndarray ) -> float :
217
- """Coefficient of determination (R2) - pronounced 'R-squared'
232
+ """Coefficient of determination (R2)
218
233
219
- The proportion of the variation in the dependent variable that is predictable from the independent variable(s), e.g . the proportion of explained variance.
234
+ Pronounced 'R-squared'; the proportion of the variation in the dependent variable that is predictable from the independent variable(s), i.e . the proportion of explained variance.
220
235
221
236
.. math::
222
237
223
238
R^2 = 1 - \\ frac{\\ sum_{i=1}^n (model_i - obs_i)^2}
224
239
{\\ sum_{i=1}^n (obs_i - \\ overline {obs})^2}
225
240
226
- Range: -infinity to 1.0 ; Best: 1.0
241
+ Range: :math:`(- \\ infty, 1]` ; Best: 1
227
242
228
243
Note
229
244
----
@@ -262,7 +277,7 @@ def model_efficiency_factor(obs: np.ndarray, model: np.ndarray) -> float:
262
277
MEF = \\ frac{RMSE}{STDEV}=\\ frac{\\ sqrt{\\ frac{1}{n} \\ sum_{i=1}^n(model_i - obs_i)^2}}
263
278
{\\ sqrt{\\ frac{1}{n} \\ sum_{i=1}^n(obs_i - \\ overline{obs})^2}}=\\ sqrt{1-NSE}
264
279
265
- Range: 0.0 to infinity ; Best: 0. 0
280
+ Range: :math:`[0, \\ infty)` ; Best: 0
266
281
267
282
See Also
268
283
--------
@@ -288,11 +303,11 @@ def corrcoef(obs, model, weights=None) -> float:
288
303
{\\ sqrt{\\ sum_{i=1}^n (model_i - \\ overline{model})^2}
289
304
\\ sqrt{\\ sum_{i=1}^n (obs_i - \\ overline{obs})^2} }
290
305
291
- Range: -1.0 to 1.0 ; Best: 1.0
306
+ Range: [-1, 1] ; Best: 1
292
307
293
308
See Also
294
309
--------
295
- numpy .corrcoef
310
+ np .corrcoef
296
311
"""
297
312
assert obs .size == model .size
298
313
if len (obs ) <= 1 :
@@ -321,7 +336,7 @@ def spearmanr(obs: np.ndarray, model: np.ndarray) -> float:
321
336
{\\ sqrt{\\ sum_{i=1}^n (rmodel_i - \\ overline{rmodel})^2}
322
337
\\ sqrt{\\ sum_{i=1}^n (robs_i - \\ overline{robs})^2} }
323
338
324
- Range: -1.0 to 1.0 ; Best: 1.0
339
+ Range: [-1, 1] ; Best: 1
325
340
326
341
Examples
327
342
--------
@@ -353,7 +368,7 @@ def scatter_index(obs: np.ndarray, model: np.ndarray) -> float:
353
368
\\ sqrt {\\ frac{\\ sum_{i=1}^n \\ left( (model_i - \\ overline {model}) - (obs_i - \\ overline {obs}) \\ right)^2}
354
369
{\\ sum_{i=1}^n obs_i^2}}
355
370
356
- Range: 0.0 to 100.0 ; Best: 0. 0
371
+ Range: [0, 100] ; Best: 0
357
372
"""
358
373
assert obs .size == model .size
359
374
if len (obs ) == 0 :
@@ -365,19 +380,54 @@ def scatter_index(obs: np.ndarray, model: np.ndarray) -> float:
365
380
)
366
381
367
382
383
+ def willmott (obs : np .ndarray , model : np .ndarray ) -> float :
384
+ """willmott's Index of Agreement
385
+
386
+ A scaled representation of the predictive accuracy of the model against observations. A value of 1 indicates a perfect match, and 0 indicates no agreement at all.
387
+
388
+ .. math::
389
+
390
+ willmott = 1 - \\ frac{\\ frac{1}{n} \\ sum_{i=1}^n(model_i - obs_i)^2}
391
+ {\\ frac{1}{n} \\ sum_{i=1}^n(|model_i - \\ overline{obs}| + |obs_i - \\ overline{obs}|)^2}
392
+
393
+ Range: [0, 1]; Best: 1
394
+
395
+ Examples
396
+ --------
397
+ >>> obs = np.array([1.0, 1.1, 1.2, 1.3, 1.4, 1.4, 1.3])
398
+ >>> model = np.array([1.02, 1.16, 1.3, 1.38, 1.49, 1.45, 1.32])
399
+ >>> willmott(obs, model)
400
+ 0.9501403174479723
401
+
402
+ References
403
+ ----------
404
+ Willmott, C. J. 1981. "On the validation of models". Physical Geography, 2, 184–194.
405
+ """
406
+
407
+ assert obs .size == model .size
408
+ if len (obs ) == 0 :
409
+ return np .nan
410
+
411
+ residual = model .ravel () - obs .ravel ()
412
+ nominator = np .sum (residual ** 2 )
413
+ denominator = np .sum ((np .abs (model - obs .mean ()) + np .abs (obs - obs .mean ())) ** 2 )
414
+
415
+ return 1 - nominator / denominator
416
+
417
+
368
418
def hit_ratio (obs : np .ndarray , model : np .ndarray , a = 0.1 ) -> float :
369
419
"""Fraction within obs ± acceptable deviation
370
420
371
421
.. math::
372
422
373
423
HR = \\ frac{1}{n}\\ sum_{i=1}^n I_{|(model_i - obs_i)|} < a
374
424
375
- Range: 0.0 to 1.0 ; Best: 1.0
425
+ Range: [0, 1] ; Best: 1
376
426
377
427
Examples
378
428
--------
379
- >>> obs = np.array([1.0,1.1,1.2,1.3,1.4, 1.4, 1.3])
380
- >>> model = np.array([1.02, 1.16, 1.3 , 1.38, 1.49, 1.45, 1.32])
429
+ >>> obs = np.array([1.0, 1.1, 1.2, 1.3, 1.4, 1.4, 1.3])
430
+ >>> model = np.array([1.02, 1.16, 1.3, 1.38, 1.49, 1.45, 1.32])
381
431
>>> hit_ratio(obs, model, a=0.05)
382
432
0.2857142857142857
383
433
>>> hit_ratio(obs, model, a=0.1)
@@ -397,7 +447,7 @@ def lin_slope(obs: np.ndarray, model: np.ndarray, reg_method="ols") -> float:
397
447
slope = \\ frac{\\ sum_{i=1}^n (model_i - \\ overline {model})(obs_i - \\ overline {obs})}
398
448
{\\ sum_{i=1}^n (obs_i - \\ overline {obs})^2}
399
449
400
- Range: -infinity to infinity ; Best: 1.0
450
+ Range: :math:`(- \\ infty, \\ infty )` ; Best: 1
401
451
"""
402
452
return _linear_regression (obs , model , reg_method )[0 ]
403
453
0 commit comments