Coverage for uqmodels/postprocessing/UQ_processing.py: 61%
293 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-05 14:29 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-09-05 14:29 +0000
1####################################################################
2# Ensemble of processing aim to process UQmesures into Intermediate quantity or into final UQ-KPI
4from copy import deepcopy
6import numpy as np
7import scipy
9import uqmodels.utils as ut
10from uqmodels.utils import apply_middledim_reduction, cut
13def check_y_vs_pred_and_UQ_shape(y, pred, UQ=None):
14 """Check if y, pred and UQ have compatible shape
16 Args:
17 y (_type_): _description_
18 pred (_type_): _description_
19 UQ (_type_): _description_
21 Returns:
22 y,pred,UQ : Reshaped if needed
23 """
24 if y.shape != pred.shape:
25 print("warning y shape :", y.shape, "pred shape", pred.shape)
26 if (len(y.shape) == (1 + len(pred.shape))) and (y.shape[-1] == 1):
27 if UQ is not None:
28 UQ = np.expand_dims(UQ, -1)
29 return (y, np.expand_dims(pred, -1), UQ)
31 elif ((len(y.shape) + 1) == (len(pred.shape))) and (pred.shape[-1] == 1):
32 if UQ is not None:
33 UQ = UQ[..., 0]
34 return (y, pred[..., 0], UQ)
35 else:
36 return (y, pred, UQ)
39def check_UQ(UQ, type_UQ, type_UQ_params):
40 """Check if UQ and type_UQ are compatible.
41 Args:
42 UQ (_type_): UQ object
43 type_UQ (_type_): type_UQ specification
44 """
46 if type_UQ in ["res_2var", "2var", "var_A&E"]:
47 if not isinstance(UQ, np.ndarray) and (len(UQ) < 2):
48 raise ValueError(
49 type_UQ + " UQ should contains at least 2 dimension not " + str(len(UQ))
50 )
52 elif type_UQ in ["quantile", "res_quantile"]:
53 len_UQ = len(type_UQ_params["list_alpha"])
54 if UQ.shape[0] != len_UQ:
55 raise ValueError(
56 type_UQ
57 + " UQ should contains len(UQ)=="
58 + len_UQ
59 + " not "
60 + str(len(UQ))
61 )
63 elif type_UQ in ["var", "res_var"]:
64 if not isinstance(UQ, np.ndarray):
65 raise ValueError("type(UQ) shoud be np.ndarray not " + type(UQ))
66 elif type_UQ in ["None"]:
67 pass
68 else:
69 raise ValueError(
70 type_UQ
71 + " not in ['var','res_var', 'res_2var', '2var', 'var_A&E', 'quantile', 'res_quantile']"
72 )
75def get_extremum_var(
76 var, min_cut=0, max_cut=1, var_min=0, var_max=None, factor=1, mode_multidim=True
77):
78 dim = np.arange(len(var.shape))
79 # Mode multivariate
80 if mode_multidim:
81 dim = np.arange(len(var.shape))
82 var_min_ = np.maximum(
83 np.quantile(var, min_cut, axis=dim[:-1]) / factor, var_min
84 )
85 var_max_ = np.quantile(var, max_cut, axis=dim[:-1]) * factor
86 else:
87 var_min_ = np.maximum(np.quantile(var, min_cut) / factor, var_min)
88 var_max_ = np.quantile(var, max_cut) * factor
90 if var_max is not None:
91 var_max_ = np.minimum(var_max_, var_max)
93 return (var_min_, var_max_)
96def get_nominal_disentangled_UQ_ratio(UQ, q_var=1, q_Eratio=2):
97 """Compute nominal_disentangled_UQ_ration form set of data and k_var_e
99 Args:
100 UQ (_type_): _description_
101 k_var_e (_type_): nominal considerate ratio (high-pass filters)
103 Returns:
104 ndUQ_ratio: nominal disentangled_UQ_ratio
105 """
106 if q_Eratio is None:
107 q_Eratio = 2
109 var_a, var_e = UQ
110 var_ratio = var_e / np.power(var_a, q_var)
111 if q_Eratio < 1: # Empirique quantile
112 ndUQ_ratio = np.quantile(var_ratio, 1 - q_Eratio)
113 else: # N-sigma quantile
114 ndUQ_ratio = np.mean(var_ratio) + q_Eratio * np.std(
115 cut(var_ratio, 0.005, 0.995)
116 )
117 return ndUQ_ratio
120def split_var_dUQ(
121 UQ,
122 q_var=1,
123 q_var_e=1,
124 ndUQ_ratio=None,
125 extremum_var_TOT=(None, None),
126 E_cut_in_var_nominal=True,
127 A_res_in_var_atypic=False,
128):
129 """split var_A&E into var_nominal & var_atypique based threshold
131 Args:
132 UQ (_type_): _description_
133 q_var (int, optional): _description_. Defaults to 1.
134 k_var_e (int, optional): _description_. Defaults to 1.
135 q_var_e (int, optional): _description_. Defaults to 1.
136 ndUQ_ratio (int, optional): _description_. Defaults to 0.
137 extremum_var_TOT (tuple, optional): _description_. Defaults to (None, None).
139 Returns:
140 _type_: _description_
141 """
142 if ndUQ_ratio is None:
143 ndUQ_ratio = 0
145 var_a, var_e = UQ
146 ratio_EA = var_e / var_a
147 ratio_EA_res = np.maximum(ratio_EA - ndUQ_ratio, 0)
148 if E_cut_in_var_nominal:
149 var_e_cut = (ratio_EA - ratio_EA_res) * var_a
150 var_a = var_a + var_e_cut
152 var_e = norm_var(
153 var_e * var_a, min_cut=0, max_cut=1, var_min=0, var_max=None, q_var=q_var_e
154 )
156 # Part of high values link to abnormal espitemic unconfidence
157 var_e_res = norm_var(
158 ratio_EA_res * var_a,
159 min_cut=0,
160 max_cut=1,
161 var_min=0,
162 var_max=None,
163 q_var=q_var_e,
164 )
166 var_a = norm_var(var_a, q_var=q_var)
167 # Part of low A_values link to nominal aleatoric uncertainty
168 var_a_cut = ut.threshold(
169 var_a, min_val=extremum_var_TOT[0], max_val=extremum_var_TOT[1]
170 )
172 # Part of low E_values link to nominal epistemic uncertainty (nominal extrapolation cost)
173 var_e_cut = var_e - var_e_res # equal to (ratio_EA - ratio_EA_res) * var_a
175 # Part of high A_values link to abnormal aleatoric uncertainty estimation
176 var_a_res = var_a - var_a_cut
178 if A_res_in_var_atypic:
179 var_e_res = var_e_res + var_a_res
181 return (var_a_cut, var_e_res)
184def get_extremum_var_TOT_and_ndUQ_ratio(
185 UQ,
186 type_UQ,
187 pred=None,
188 y=None,
189 type_UQ_params=None,
190 min_cut=0,
191 max_cut=1,
192 var_min=0,
193 var_max=None,
194 factor=2,
195 q_var=1,
196 q_Eratio=2,
197 mode_multidim=True,
198 E_cut_in_var_nominal=True,
199 A_res_in_var_atypic=False,
200 **kwargs_process_TOT,
201):
202 """Estimate parameters use to seperate from var_A & var_E theirs
203 Respective nominal part (Affected in TOT,ATYPIC) et atypical part
204 using empirical threeshold
206 Args:
207 UQ (_type_): _description_
208 type_UQ (_type_, optional): _description_. Defaults to None.
209 pred (_type_, optional): _description_. Defaults to None.
210 y (_type_, optional): _description_. Defaults to None.
211 type_UQ_params (_type_, optional): _description_. Defaults to None.
212 min_cut (int, optional): _description_. Defaults to 0.
213 max_cut (int, optional): _description_. Defaults to 1.
214 var_min (int, optional): _description_. Defaults to 0.
215 var_max (_type_, optional): _description_. Defaults to None.
216 factor (int, optional): _description_. Defaults to 2.
217 q_var (int, optional): _description_. Defaults to 1.
218 q_Eratio (int, optional): _description_. Defaults to 2.
219 mode_multidim (bool, optional): _description_. Defaults to False.
221 Returns:
222 _type_: _description_
223 """
224 sigma_TOT, sigma_E = process_UQmeasure_to_TOT_and_E_sigma(
225 UQ,
226 type_UQ=type_UQ,
227 pred=None,
228 y=None,
229 type_UQ_params=None,
230 var_min=0,
231 var_max=None,
232 min_cut=0,
233 max_cut=1,
234 extremum_var_TOT=(var_min, var_max),
235 **kwargs_process_TOT,
236 )
237 var_E = np.power(sigma_E, 2)
238 var_TOT = np.power(sigma_TOT, 2)
239 extremum_var_TOT = get_extremum_var(
240 var_TOT,
241 min_cut=min_cut,
242 max_cut=max_cut,
243 var_min=var_min,
244 var_max=var_max,
245 factor=factor,
246 mode_multidim=mode_multidim,
247 )
249 UQ_bis = (var_TOT, var_E)
250 UQ_bis = split_var_dUQ(
251 UQ,
252 q_var=1,
253 q_var_e=1,
254 ndUQ_ratio=None,
255 E_cut_in_var_nominal=E_cut_in_var_nominal,
256 A_res_in_var_atypic=A_res_in_var_atypic,
257 extremum_var_TOT=extremum_var_TOT,
258 )
260 ndUQ_ratio = get_nominal_disentangled_UQ_ratio(UQ_bis, q_var, q_Eratio)
262 return (extremum_var_TOT, ndUQ_ratio)
265def norm_var(var, min_cut=0, max_cut=1, var_min=0, var_max=None, q_var=1, epsilon=1e-8):
266 """variance normalisation
267 Args:
268 var (np.array): variance to normalise
269 min_cut (float): Bottom extremun percentile : [0,1].
270 max_cut (float): Bottom upper percentile: [0,1].
271 var_min (float, optional): minimal variance assumption. Defaults to 0.
272 q_var (float): Power coefficent
274 Returns:
275 var: normalised variance
276 """
277 var = deepcopy(var)
278 var_min, var_max = get_extremum_var(var, min_cut, max_cut, var_min, var_max)
280 var = ut.threshold(var, min_val=var_min + epsilon, max_val=var_max + 2 * epsilon)
281 if q_var != 1:
282 var = np.power(var, q_var)
283 return var
286def renormalise_UQ(UQ, type_UQ, scaler=None, var_min=0, var_max=None):
287 """UQmeasure to normalised
289 Args:
290 UQ (np.array): UQmeasure provided by an UQEstimator
291 type_UQ (_type_): nature of the UQeeasure
292 rescale_val (np.array): rescale variance term (may be obtain by scikilearn Standard normalizer)
293 var_min (float, optional): minimal variance assumption. Defaults to 0.
295 Returns:
296 UQ: normalised UQmeasure
297 """
298 escale_val = 1
299 if scaler is not None:
300 rescale_val = scaler.var_
302 if type_UQ in ["res_var", "var", "var_A&E"]:
303 UQ = UQ * rescale_val
304 if var_min > 0:
305 UQ = np.maximum(UQ, var_min)
306 if var_max is not None:
307 UQ = np.minimum(UQ, var_max)
309 elif type_UQ in ["res_2var", "2var"]:
310 UQ = np.array([UQ[0] * rescale_val, UQ[1] * rescale_val])
311 if var_min > 0:
312 UQ = np.maximum(UQ, var_min)
313 if var_max is not None:
314 UQ = np.minimum(UQ, var_max)
316 elif type_UQ in ["quantile", "res_quantile"]:
317 inv_trans = scaler.inverse_transform
318 UQ = np.array([inv_trans(Q) for Q in UQ])
320 else:
321 print("renormalise_UQ :", type_UQ, "not_covered")
323 return UQ
326def process_UQmeasure_to_sigma(
327 UQ,
328 type_UQ,
329 pred=None,
330 y=None,
331 type_UQ_params=None,
332 var_min=0,
333 var_max=None,
334 min_cut=0,
335 max_cut=1,
336 q_var=1,
337 reduc_filter=None,
338):
339 """Process UQ measure into sigma (sqrt(varirance)) according prediction, UQmeasure and observation.
341 Args:
342 UQ (np.array or list): UQmeasure obtain from UQEstimator
343 type_UQ (_type_): Type UQ that the nature of UQmeasure
344 pred (np.array): prediction provide by a predictor or an UQEstimator
345 y (np.array): Targets/Observation
346 type_UQ_params : additional parameters link to type paradigm (ex : alpha for quantile)
347 min_cut (_type_): Bottom extremun percentile.
348 max_cut (_type_): Bottom upper percentile.
349 q_var (_type_): Power coefficent
350 sigma_min (float, optional): Minimum values of UQ considered.
352 Returns:
353 sigma : standards deviation estimation link to ML-uncertainty
354 """
355 check_UQ(UQ, type_UQ, type_UQ_params)
357 # Case sigma
358 if type_UQ in ["res_var", "var"]:
359 sigma = np.sqrt(
360 norm_var(
361 UQ,
362 min_cut=min_cut,
363 max_cut=max_cut,
364 var_min=var_min,
365 var_max=var_max,
366 q_var=q_var,
367 )
368 )
370 # Case 2 sigma
371 elif type_UQ in ["res_2var", "2var"]:
372 sigma_bot = np.sqrt(
373 norm_var(
374 UQ[0],
375 min_cut=min_cut,
376 max_cut=max_cut,
377 var_min=var_min,
378 var_max=var_max,
379 q_var=q_var,
380 )
381 )
382 sigma_top = np.sqrt(
383 norm_var(
384 UQ[1],
385 min_cut=min_cut,
386 max_cut=max_cut,
387 var_min=var_min,
388 var_max=var_max,
389 q_var=q_var,
390 )
391 )
392 sigma = np.concatenate([sigma_bot[None, :], sigma_top[None, :]])
394 elif type_UQ == "var_A&E":
395 sigma = np.sqrt(
396 norm_var(
397 UQ[0] + UQ[1],
398 min_cut=min_cut,
399 max_cut=max_cut,
400 var_min=var_min,
401 var_max=var_max,
402 q_var=q_var,
403 )
404 )
406 elif type_UQ in ["quantile", "res_quantile"]:
407 print("Warning quantile renormalisation based on gaussian assumption")
408 sigma = []
409 for n, param_alpha in type_UQ_params:
410 current_sigma = scipy.stats.norm.ppf(param_alpha, 0, 1)
411 sigma.append(np.abs((pred - UQ[n])) / current_sigma)
412 var = np.power(np.array(sigma).mean(axis=0), 2)
413 sigma = np.sqrt(norm_var(var, min_cut, max_cut, var_min, q_var=q_var))
415 sigma = apply_middledim_reduction(sigma, reduc_filter)
417 return sigma
420def process_UQmeasure_to_TOT_and_E_sigma(
421 UQ,
422 type_UQ,
423 pred=None,
424 y=None,
425 type_UQ_params=None,
426 var_min=0,
427 var_max=None,
428 min_cut=0,
429 max_cut=1,
430 q_var=1,
431 q_var_e=1,
432 k_var_e=1,
433 q_Eratio=None,
434 ndUQ_ratio=None,
435 extremum_var_TOT=(None, None),
436 reduc_filter=None,
437 roll=0,
438 **kwargs,
439):
440 """Process UQ measure into sigma_tot & sigma_E (sqrt(varirance)) according prediction, UQmeasure and observation.
442 Args:
443 UQ (np.array or list): UQmeasure obtain from UQEstimator
444 type_UQ (_type_): Type UQ that the nature of UQmeasure
445 pred (np.array): prediction provide by a predictor or an UQEstimator
446 y (np.array): Targets/Observation
447 type_UQ_params : additional parameters link to type paradigm (ex : alpha for quantile)
448 min_cut (_type_): Bottom extremun percentile.
449 max_cut (_type_): Bottom upper percentile.
450 q_var (_type_): Power coefficent
451 sigma_min (float, optional): Minimum values of UQ considered.
453 Returns:
454 sigma : standards deviation estimation link to ML-uncertainty
455 """
457 check_UQ(UQ, type_UQ, type_UQ_params)
458 # Case sigma
460 # Naive disentanglement:
461 # - Hypothesis estimation of var_E uppon estimation lead to entangled var_E that include amont of var_A in var_E
462 # - Epistemics contains 'nominal espitemics quantity
464 # Consider a ratio of k_var_e nominal epistemics to swith towarsd E var.
465 if (
466 (ndUQ_ratio is None)
467 & (extremum_var_TOT[0] is None)
468 & (extremum_var_TOT[1] is None)
469 ):
470 # print('Compute ndUQ_ratio from provided data')
471 extremum_var_TOT, ndUQ_ratio = get_extremum_var_TOT_and_ndUQ_ratio(
472 UQ,
473 type_UQ=type_UQ,
474 min_cut=min_cut,
475 max_cut=max_cut,
476 var_min=0,
477 var_max=None,
478 factor=2,
479 q_var=q_var,
480 q_Eratio=q_Eratio,
481 mode_multidim=True,
482 )
484 var_nominal, var_atypic = split_var_dUQ(
485 UQ,
486 q_var=q_var,
487 q_var_e=q_var_e,
488 ndUQ_ratio=ndUQ_ratio,
489 extremum_var_TOT=extremum_var_TOT,
490 )
492 sigma_nominal = np.sqrt(var_nominal)
493 sigma_atypic = k_var_e * np.sqrt(var_atypic)
495 sigma_nominal = apply_middledim_reduction(sigma_nominal, reduc_filter, roll=roll)
497 sigma_atypic = apply_middledim_reduction(sigma_atypic, reduc_filter, roll=roll)
498 return (sigma_nominal, sigma_atypic)
501def process_UQmeasure_to_residu(
502 UQ,
503 type_UQ,
504 pred,
505 y,
506 type_UQ_params=None,
507 d=2,
508 min_cut=0,
509 max_cut=1,
510 q_var=1,
511 var_min=0,
512 var_max=None,
513 with_born=False,
514 k_var_e=0,
515 q_var_e=None,
516 q_Eratio=None,
517 extremum_var_TOT=(None, None),
518 ndUQ_ratio=None,
519 reduc_filter=None,
520 roll=0,
521 debug=False,
522):
523 """Process UQ measure to residu according prediction, UQmeasure and observation.
525 Args:
526 UQ (np.array or list): UQ measure obtain from UQ-estimator
527 type_UQ (_type_): Type UQ that caracterise UQ measre
528 pred (np.array): prediction
529 y (np.array): Targets/Observation
530 type_UQ_params : additional parameters link to type paradigm (ex : alpha for quantile)
531 min_cut (_type_): Bottom extremun percentile.
532 max_cut (_type_): Bottom upper percentile.
533 min_cut (_type_): Bottom extremun percentile.
534 max_cut (_type_): Bottom upper percentile.
535 q_var (_type_): Power coefficent
536 sigma_min (float, optional): Minimum values of UQ considered.
538 Returns:
539 res : residu
540 """
541 check_UQ(UQ, type_UQ, type_UQ_params)
543 if q_var_e is None:
544 q_var_e = q_var
546 if k_var_e is None:
547 k_var_e = 0
549 res_norm = y - pred
551 if type_UQ in ["var", "res_var", "var_A&E"]:
552 if type_UQ in ["var", "res_var"]:
553 sigma = np.sqrt(
554 norm_var(
555 UQ,
556 min_cut=min_cut,
557 max_cut=max_cut,
558 var_min=var_min,
559 var_max=var_max,
560 q_var=q_var,
561 )
562 )
563 E_penalisation = 0
565 elif type_UQ == "var_A&E":
566 sigma, E_penalisation = process_UQmeasure_to_TOT_and_E_sigma(
567 UQ,
568 type_UQ=type_UQ,
569 pred=pred,
570 y=y,
571 min_cut=min_cut,
572 max_cut=max_cut,
573 var_min=var_min,
574 var_max=var_max,
575 q_var=q_var,
576 q_var_e=q_var_e,
577 k_var_e=k_var_e,
578 q_Eratio=q_Eratio,
579 extremum_var_TOT=extremum_var_TOT,
580 ndUQ_ratio=ndUQ_ratio,
581 )
583 if debug:
584 print(
585 "params : q_var_e:",
586 q_var_e,
587 "k_var_e:",
588 k_var_e,
589 "q_Eratio:",
590 q_Eratio,
591 "extremum_var_TOT:",
592 extremum_var_TOT,
593 "ndUQ_ratio:",
594 ndUQ_ratio,
595 )
597 print(
598 "d1",
599 np.mean(np.mean(res_norm, axis=0), axis=0),
600 np.mean(np.mean(E_penalisation, axis=0), axis=0),
601 )
603 sign_res = np.sign(res_norm)
604 # In normalised residu, add epistemic set_off equal to part of epistemic overhang (E/tot > (k_var))
606 sigma = sigma + ut.EPSILON
607 if debug:
608 print(
609 "Start build res raw :",
610 np.abs(res_norm).mean(),
611 "Mean_Escore :",
612 E_penalisation.mean(),
613 "Mean_Sigma :",
614 sigma.mean(),
615 )
617 res_norm = (np.abs(res_norm) + E_penalisation) / (sigma)
618 res_norm = sign_res * np.power(res_norm, d)
620 if with_born:
621 born_bot = (pred + E_penalisation) - (sigma)
622 born_top = (pred - E_penalisation) + (sigma)
624 born_bot = np.minimum(born_bot, pred)
625 born_top = np.maximum(born_top, pred)
627 elif type_UQ in ["2var", "res_2var", "quantile", "res_quantile"]:
628 res_norm = y - pred
629 sign_res = np.sign(res_norm)
630 if type_UQ in ["2var", "res_2var"]:
631 print("Naïf approach mean of 2 sigma")
632 UQ_bot = np.sqrt(norm_var(UQ[0], min_cut, max_cut, var_min, q_var))
633 UQ_top = np.sqrt(norm_var(UQ[1], min_cut, max_cut, var_min, q_var))
634 elif type_UQ == "quantile":
635 UQ_bot = pred - cut(UQ[0], min_cut, max_cut)
636 UQ_top = cut(UQ[1], min_cut, max_cut) - pred
637 elif type_UQ == "res_quantile":
638 UQ_bot = cut(UQ[0], min_cut, max_cut)
639 UQ_top = cut(UQ[1], min_cut, max_cut)
641 reshape_marker = False
642 if len(y.shape) == 1:
643 res_norm = res_norm[:, None]
644 if with_born:
645 born_bot = born_bot[:, None]
646 born_top = born_top[:, None]
648 reshape_marker = True
650 for dim in range(y.shape[1]):
651 mask = res_norm[:, dim] > 0
652 sigma = UQ_bot[mask, dim]
653 E_penalisation = 0
654 res_norm[mask, dim] = (res_norm[mask, dim] + E_penalisation) / (sigma)
656 res_norm = sign_res * np.power(res_norm, d)
658 if with_born:
659 born_bot[mask, dim] = born_bot[mask, dim] + E_penalisation - (sigma)
660 born_top[mask, dim] = born_top[mask, dim] - E_penalisation + (sigma)
662 sigma = np.power(UQ_top[~mask, dim], q_var)
663 res_norm[~mask, dim] = res_norm[~mask, dim] / (sigma)
664 res_norm = np.sign(res_norm) * np.power(res_norm, d)
665 if with_born:
666 born_bot[~mask, dim] = born_bot[~mask, dim] + E_penalisation + (sigma)
667 born_top[~mask, dim] = born_top[~mask, dim] - E_penalisation + (sigma)
669 if reshape_marker:
670 res_norm = res_norm[:, 0]
672 if debug:
673 print("Mid build res norm:", np.abs(res_norm).mean(), reduc_filter, roll)
675 res_norm = apply_middledim_reduction(res_norm, reduc_filter, roll=roll)
677 if debug:
678 print("End build res norm :", np.abs(res_norm).mean())
680 if with_born:
681 return res_norm, (born_bot, born_top)
682 else:
683 return res_norm
686def process_UQmeasure_to_quantile(
687 UQ,
688 type_UQ,
689 pred,
690 y=None,
691 type_UQ_params=None,
692 alpha=0.05,
693 var_min=0,
694 var_max=None,
695 min_cut=0,
696 max_cut=1,
697 q_var=1,
698 reduc_filter=None,
699 roll=0,
700):
701 """Process UQ measure into gaussian_quantile according prediction, UQmeasure and observation
702 and a alpha quantile lvl
704 Args:
705 UQ (np.array or list): UQmeasure obtain from UQEstimator
706 type_UQ (_type_): Type UQ that the nature of UQmeasure
707 pred (np.array): prediction provide by a predictor or an UQEstimator
708 y (np.array): Targets/Observation
709 type_UQ_params : additional parameters link to type paradigm (ex : alpha for quantile)
710 min_cut (_type_): Bottom extremun percentile.
711 max_cut (_type_): Bottom upper percentile.
712 q_var (_type_): Power coefficent
713 sigma_min (float, optional): Minimum values of UQ considered.
715 Returns:
716 gaussian_quantile : alpha quantile lvl based on gaussian assumption
717 """
718 check_UQ(UQ, type_UQ, type_UQ_params)
720 if type_UQ in ["quantile", "res_quantile"]:
721 if type_UQ_params is None:
722 print(
723 "Missing type_UQ_params : cannot manipulate quantile without alpha parameters"
724 )
725 elif alpha in type_UQ_params["list_alpha"]:
726 print("recover quantile")
727 idx = type_UQ_params["list_alpha"].index(alpha)
728 if type_UQ == "quantile":
729 gaussian_quantile = UQ[idx]
731 elif type_UQ == "res_quantile":
732 idx = type_UQ_params["list_alpha"].index(alpha)
733 gaussian_quantile = pred + UQ[idx]
735 elif type_UQ in ["res_2var", "2var"]:
736 sigma = process_UQmeasure_to_sigma(
737 UQ,
738 type_UQ,
739 pred,
740 y,
741 type_UQ_params,
742 var_min=var_min,
743 var_max=var_max,
744 min_cut=min_cut,
745 max_cut=max_cut,
746 q_var=q_var,
747 )
748 y_shape = pred.shape
750 if alpha > 0.5:
751 sigma = sigma[1].reshape(y_shape)
752 else:
753 sigma = sigma[0].reshape(y_shape)
754 gaussian_quantile = pred + scipy.stats.norm.ppf(alpha, 0, sigma)
756 elif type_UQ in ["var_A&E", "res_var", "var"]:
757 sigma = process_UQmeasure_to_sigma(
758 UQ,
759 type_UQ,
760 pred,
761 y,
762 type_UQ_params,
763 var_min=var_min,
764 var_max=var_max,
765 min_cut=min_cut,
766 max_cut=max_cut,
767 q_var=q_var,
768 )
769 gaussian_quantile = pred + scipy.stats.norm.ppf(alpha, 0, sigma)
771 else:
772 raise ValueError(type_UQ + " not covered")
774 gaussian_quantile = apply_middledim_reduction(
775 gaussian_quantile, reduc_filter, roll=roll
776 )
777 return gaussian_quantile
780def process_UQmeasure_to_Epistemicscore(
781 UQ,
782 type_UQ,
783 pred=None,
784 y=None,
785 type_UQ_params=None,
786 var_min=0,
787 var_max=None,
788 min_cut=0,
789 max_cut=1,
790 q_var=1,
791 q_var_e=None,
792 k_var_e=1,
793 mode="relative_likelihood",
794 reduc_filter=None,
795 roll=0,
796 **kwargs,
797):
798 """Process UQ measure to epistemicvalues according UQmeasure
800 Args:
801 UQ (np.array or list): UQ measure obtain from UQ-estimator
802 type_UQ (_type_): Type UQ that caracterise UQ measre
803 pred (np.array): prediction unused
804 y (np.array): Targets/Observation unused
805 type_UQ_params : additional parameters unused
806 Returns:
807 Eval : Epistemic unconfidence score.
808 """
809 check_UQ(UQ, type_UQ, type_UQ_params)
811 if q_var_e is None:
812 q_var_e = q_var
814 var_A = norm_var(
815 UQ[0], min_cut=min_cut, max_cut=max_cut, var_min=var_min, q_var=q_var
816 )
818 var_E = norm_var(
819 UQ[1], min_cut=0, max_cut=1, var_min=0, var_max=var_max, q_var=q_var_e
820 )
822 if type_UQ == "var_A&E":
823 if mode == "relative_likelihood":
824 Eval = np.exp(-0.5 * np.log(1 + (var_A / var_E)))
826 if mode == "relative_variance_part":
827 Eval = np.sqrt(var_E / (var_A + var_E))
829 Eval = np.maximum(Eval - (1 - k_var_e), 0)
831 else:
832 print(
833 "process_UQmeasure_to_Epistemicscore : ",
834 type_UQ,
835 " not covered : only cover var_A&E",
836 )
837 raise ValueError
839 Eval = apply_middledim_reduction(Eval, reduc_filter, roll=roll)
840 return Eval
843def fit_PI(
844 UQ,
845 type_UQ,
846 pred,
847 y=None,
848 list_alpha=[0.025, 0.975],
849 type_UQ_params=None,
850 reduc_filter=None,
851 **kwargs,
852):
853 """Function that estimate PIs parameters according to normal assumption a list of quantile parametrized
854 by list alpha from the UQmeasure
856 Args:
857 pred (_type_): Mean prediction
858 UQ (_type_): UQmeasure
859 type_UQ (_type_): UQmeasure hypothesis
860 list_alpha (list, optional): Quantile values. Defaults to [0.025, 0.975].
861 type_UQ_params (_type_, optional): UQmeasure params. Defaults to None.
862 PIs_params (_type_, optional): PIs_params : May use externally fit_PIs to obtain it.
863 If None, fit_PIs is used internally.
865 Raises:
866 ValueError: type_UQ not covered
868 Returns:
869 list_PIs : List of computed quantiles
870 """
871 PIs_params_ = None
872 return PIs_params_
875def compute_PI(
876 UQ,
877 type_UQ,
878 pred,
879 y=None,
880 type_UQ_params=None,
881 list_alpha=[0.025, 0.975],
882 var_min=0,
883 var_max=None,
884 min_cut=0,
885 max_cut=1,
886 q_var=1,
887 params_=None,
888 reduc_filter=None,
889 **kwargs,
890):
891 """Compute according to normal assumption a list of quantile parametrized by list alpha from the UQmeasre
893 Args:
894 pred (_type_): Mean prediction
895 UQ (_type_): UQmeasure
896 type_UQ (_type_): UQmeasure hypothesis
897 list_alpha (list, optional): Quantile values. Defaults to [0.025, 0.975].
898 type_UQ_params (_type_, optional): UQmeasure params. Defaults to None.
899 params_ (_type_, optional): params : May use externally fit_PIs to obtain it.
900 If None, fit_PIs is used internally.
902 Raises:
903 ValueError: type_UQ not covered
905 Returns:
906 list_PIs : List of computed quantiles
907 params : Params provided or computed
908 """
910 if params_ is None:
911 params_ = fit_PI(
912 UQ,
913 type_UQ,
914 pred,
915 y,
916 list_alpha,
917 type_UQ_params=type_UQ_params,
918 reduc_filter=reduc_filter,
919 )
921 list_PIs = []
922 for alpha in list_alpha:
923 quantile_env = process_UQmeasure_to_quantile(
924 UQ,
925 type_UQ,
926 pred,
927 y=None,
928 type_UQ_params=type_UQ_params,
929 alpha=alpha,
930 var_min=var_min,
931 var_max=var_max,
932 min_cut=min_cut,
933 max_cut=max_cut,
934 q_var=q_var,
935 reduc_filter=reduc_filter,
936 )
938 list_PIs.append(quantile_env)
940 if len(list_PIs) == 1:
941 list_PIs = list_PIs[0]
942 return list_PIs, params_
945def fit_Epistemic_score(
946 UQ,
947 type_UQ,
948 pred=None,
949 y=None,
950 type_UQ_params=None,
951 list_percent=[0.50, 0.80, 0.95, 0.98, 0.995, 1],
952 var_min=0,
953 var_max=None,
954 min_cut=0.1,
955 max_cut=0.97,
956 q_var=1,
957 q_Eratio=3,
958 mode="score",
959 reduc_filter=None,
960 **kwargs,
961):
962 """Function that estimate parameters link to Epistemic_score_normalisation based on quantile lvl
964 Args:
965 pred (_type_): Mean prediction
966 UQ (_type_): UQmeasure
967 type_UQ (_type_): UQmeasure hypothesis
968 list_percent (list, optional): Quantile values to normalise.
969 Defaults to [0.50, 0.80, 0.90, 0.95, 0.975, 0.99, 0.999].
970 type_UQ_params (_type_, optional): UQmeasure params. Defaults to None.
972 returns:
973 params : Params needed by compute_Epistemic_score
974 """
975 if type_UQ != "var_A&E":
976 raise ("type_UQ should be 'var_A&E' not " + type_UQ)
978 extremum_var_TOT, ndUQ_ratio = get_extremum_var_TOT_and_ndUQ_ratio(
979 UQ,
980 type_UQ=type_UQ,
981 min_cut=min_cut,
982 max_cut=max_cut,
983 var_min=var_min,
984 var_max=var_max,
985 factor=2,
986 q_var=q_var,
987 q_Eratio=q_Eratio,
988 mode_multidim=True,
989 )
991 # Do not apply reduc_filter in an intermedaire function.
992 sigma_nominal, sigma_atypique = process_UQmeasure_to_TOT_and_E_sigma(
993 UQ=UQ,
994 type_UQ=type_UQ,
995 pred=pred,
996 y=y,
997 var_min=var_min,
998 var_max=var_max,
999 min_cut=min_cut,
1000 max_cut=max_cut,
1001 q_var=q_var,
1002 type_UQ_params=type_UQ_params,
1003 q_Eratio=q_Eratio,
1004 q_var_e=1,
1005 k_var_e=1,
1006 ndUQ_ratio=ndUQ_ratio,
1007 extremum_var_TOT=extremum_var_TOT,
1008 reduc_filter=None,
1009 )
1010 UQ = np.power(sigma_nominal, 2), np.power(sigma_atypique, 2)
1012 Epistemic_score = process_UQmeasure_to_Epistemicscore(
1013 UQ=UQ,
1014 type_UQ=type_UQ,
1015 pred=pred,
1016 y=y,
1017 var_min=0,
1018 var_max=None,
1019 min_cut=0,
1020 max_cut=1,
1021 q_var=q_var,
1022 type_UQ_params=type_UQ_params,
1023 reduc_filter=reduc_filter,
1024 )
1026 list_q_val = []
1027 for n, i in enumerate(list_percent):
1028 list_q_val.append(np.quantile(Epistemic_score, i, axis=0))
1030 params_ = list_q_val, list_percent, ndUQ_ratio, extremum_var_TOT
1031 return params_
1034def compute_Epistemic_score(
1035 UQ,
1036 type_UQ,
1037 pred=None,
1038 y=None,
1039 type_UQ_params=None,
1040 list_percent=[0.80, 0.90, 0.99, 0.999, 1],
1041 var_min=0,
1042 var_max=None,
1043 min_cut=0,
1044 max_cut=1,
1045 q_var=1,
1046 q_Eratio=3,
1047 mode="levels",
1048 params_=None,
1049 reduc_filter=None,
1050 **kwargs,
1051):
1052 """Function that compute Epistemic_score_lvl from (predictor) & UQEstimor outputs &
1053 fitted parameters provided by fit_Epistemic_score
1055 Args:
1056 pred (_type_): Mean prediction
1057 UQ (_type_): UQmeasure
1058 type_UQ (_type_): UQmeasure hypothesis
1059 list_percent (list, optional): Quantile values. Defaults to [0.025, 0.975].
1060 type_UQ_params (_type_, optional): UQmeasure params. Defaults to None.
1061 params_ (_type_, optional): May use externally fit_Epistemic_score to obtain it. If None, internal called to fit
1063 Returns:
1064 Epistemic_scorelvl : Epistemic_score_lvl : Quantile class values of Epistemic score
1065 params : Parameters provided or computed
1066 """
1067 if type_UQ != "var_A&E":
1068 raise ("type_UQ should be 'var_A&E' not " + type_UQ)
1070 if params_ is None:
1071 params_ = fit_Epistemic_score(
1072 UQ=UQ,
1073 type_UQ=type_UQ,
1074 pred=pred,
1075 y=y,
1076 list_percent=list_percent,
1077 var_min=var_min,
1078 var_max=var_max,
1079 min_cut=min_cut,
1080 max_cut=max_cut,
1081 q_var=q_var,
1082 reduc_filter=None,
1083 **kwargs,
1084 )
1086 list_q_val, list_percent, ndUQ_ratio, extremum_var_TOT = params_
1088 # Do not apply reduc_filter in an intermedaire function.
1089 sigma, sigma_E = process_UQmeasure_to_TOT_and_E_sigma(
1090 UQ=UQ,
1091 type_UQ=type_UQ,
1092 pred=pred,
1093 y=y,
1094 var_min=var_min,
1095 var_max=var_max,
1096 min_cut=min_cut,
1097 max_cut=max_cut,
1098 q_var=q_var,
1099 type_UQ_params=type_UQ_params,
1100 q_Eratio=q_Eratio,
1101 q_var_e=1,
1102 k_var_e=1,
1103 ndUQ_ratio=ndUQ_ratio,
1104 extremum_var_TOT=extremum_var_TOT,
1105 reduc_filter=None,
1106 )
1108 UQ = np.power(sigma, 2), np.power(sigma_E, 2)
1110 Epistemic_score = process_UQmeasure_to_Epistemicscore(
1111 UQ=UQ,
1112 type_UQ=type_UQ,
1113 pred=pred,
1114 y=y,
1115 var_min=0,
1116 var_max=None,
1117 min_cut=0,
1118 max_cut=1,
1119 q_var=q_var,
1120 type_UQ_params=type_UQ_params,
1121 reduc_filter=reduc_filter,
1122 )
1124 Epistemic_scorelvl = np.zeros(Epistemic_score.shape)
1126 if mode == "score":
1127 return Epistemic_score, params_
1129 else:
1130 for q_val in list_q_val:
1131 if len(pred.shape) == 1:
1132 Epistemic_scorelvl += Epistemic_score > q_val
1133 else:
1134 for d in range(Epistemic_scorelvl.shape[1]):
1135 Epistemic_scorelvl[:, d] += Epistemic_score[:, d] > q_val[d]
1136 return Epistemic_scorelvl, params_