Coverage for uqmodels / postprocessing / UQ_processing.py: 80%
295 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-09 08:15 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-09 08:15 +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 epsilon=10e-10
523):
524 """Process UQ measure to residu according prediction, UQmeasure and observation.
526 Args:
527 UQ (np.array or list): UQ measure obtain from UQ-estimator
528 type_UQ (_type_): Type UQ that caracterise UQ measre
529 pred (np.array): prediction
530 y (np.array): Targets/Observation
531 type_UQ_params : additional parameters link to type paradigm (ex : alpha for quantile)
532 min_cut (_type_): Bottom extremun percentile.
533 max_cut (_type_): Bottom upper percentile.
534 min_cut (_type_): Bottom extremun percentile.
535 max_cut (_type_): Bottom upper percentile.
536 q_var (_type_): Power coefficent
537 sigma_min (float, optional): Minimum values of UQ considered.
539 Returns:
540 res : residu
541 """
542 check_UQ(UQ, type_UQ, type_UQ_params)
544 if q_var_e is None:
545 q_var_e = q_var
547 if k_var_e is None:
548 k_var_e = 0
550 res_norm = y - pred
552 if type_UQ in ["var", "res_var", "var_A&E"]:
553 if type_UQ in ["var", "res_var"]:
554 sigma = np.sqrt(
555 norm_var(
556 UQ,
557 min_cut=min_cut,
558 max_cut=max_cut,
559 var_min=var_min,
560 var_max=var_max,
561 q_var=q_var,
562 )
563 )
564 E_penalisation = 0
566 elif type_UQ == "var_A&E":
567 sigma, E_penalisation = process_UQmeasure_to_TOT_and_E_sigma(
568 UQ,
569 type_UQ=type_UQ,
570 pred=pred,
571 y=y,
572 min_cut=min_cut,
573 max_cut=max_cut,
574 var_min=var_min,
575 var_max=var_max,
576 q_var=q_var,
577 q_var_e=q_var_e,
578 k_var_e=k_var_e,
579 q_Eratio=q_Eratio,
580 extremum_var_TOT=extremum_var_TOT,
581 ndUQ_ratio=ndUQ_ratio,
582 )
584 if debug:
585 print(
586 "params : q_var_e:",
587 q_var_e,
588 "k_var_e:",
589 k_var_e,
590 "q_Eratio:",
591 q_Eratio,
592 "extremum_var_TOT:",
593 extremum_var_TOT,
594 "ndUQ_ratio:",
595 ndUQ_ratio,
596 )
598 print(
599 "d1",
600 np.mean(np.mean(res_norm, axis=0), axis=0),
601 np.mean(np.mean(E_penalisation, axis=0), axis=0),
602 )
604 sign_res = np.sign(res_norm)
605 # In normalised residu, add epistemic set_off equal to part of epistemic overhang (E/tot > (k_var))
607 sigma = sigma + ut.EPSILON
608 if debug:
609 print(
610 "Start build res raw :",
611 np.abs(res_norm).mean(),
612 "Mean_Escore :",
613 E_penalisation.mean(),
614 "Mean_Sigma :",
615 sigma.mean(),
616 )
618 res_norm = (np.abs(res_norm) + E_penalisation) / (sigma)
619 res_norm = sign_res * np.power(res_norm, d)
621 if with_born:
622 born_bot = (pred + E_penalisation) - (sigma)
623 born_top = (pred - E_penalisation) + (sigma)
625 born_bot = np.minimum(born_bot, pred)
626 born_top = np.maximum(born_top, pred)
628 elif type_UQ in ["2var", "res_2var", "quantile", "res_quantile"]:
629 res_norm = y - pred
630 sign_res = np.sign(res_norm)
631 if type_UQ in ["2var", "res_2var"]:
632 print("Naïf approach mean of 2 sigma")
633 UQ_bot = np.sqrt(norm_var(UQ[0], min_cut, max_cut, var_min, q_var))
634 UQ_top = np.sqrt(norm_var(UQ[1], min_cut, max_cut, var_min, q_var))
635 elif type_UQ == "quantile":
636 UQ_bot = pred - cut(UQ[0], min_cut, max_cut)
637 UQ_top = cut(UQ[1], min_cut, max_cut) - pred
638 elif type_UQ == "res_quantile":
639 UQ_bot = cut(UQ[0], min_cut, max_cut)
640 UQ_top = cut(UQ[1], min_cut, max_cut)
642 if with_born:
643 born_bot = pred
644 born_top = pred
646 reshape_marker = False
647 if len(y.shape) == 1:
648 res_norm = res_norm[:, None]
649 reshape_marker = True
650 if with_born:
651 born_bot = pred[:, None]
652 born_top = pred[:, None]
654 for dim in range(y.shape[1]):
655 mask = res_norm[:, dim] > 0
656 sigma = UQ_bot[mask, dim]
657 E_penalisation = 0
658 res_norm[mask, dim] = (res_norm[mask, dim] + E_penalisation) / (sigma)
660 res_norm = sign_res * np.power(res_norm, d)
662 if with_born:
663 born_bot[mask, dim] = pred + E_penalisation - (sigma)
664 born_top[mask, dim] = pred - E_penalisation + (sigma)
666 sigma = np.power(UQ_top[~mask, dim], q_var)
667 res_norm[~mask, dim] = res_norm[~mask, dim] / (sigma + epsilon)
668 res_norm = np.sign(res_norm) * np.power(res_norm, d)
669 if with_born:
670 born_bot[~mask, dim] = pred + E_penalisation + (sigma)
671 born_top[~mask, dim] = pred - E_penalisation + (sigma)
673 if reshape_marker:
674 res_norm = res_norm[:, 0]
676 if debug:
677 print("Mid build res norm:", np.abs(res_norm).mean(), reduc_filter, roll)
679 res_norm = apply_middledim_reduction(res_norm, reduc_filter, roll=roll)
681 if debug:
682 print("End build res norm :", np.abs(res_norm).mean())
684 if with_born:
685 return res_norm, (born_bot, born_top)
686 else:
687 return res_norm
690def process_UQmeasure_to_quantile(
691 UQ,
692 type_UQ,
693 pred,
694 y=None,
695 type_UQ_params=None,
696 alpha=0.05,
697 var_min=0,
698 var_max=None,
699 min_cut=0,
700 max_cut=1,
701 q_var=1,
702 reduc_filter=None,
703 roll=0,
704):
705 """Process UQ measure into gaussian_quantile according prediction, UQmeasure and observation
706 and a alpha quantile lvl
708 Args:
709 UQ (np.array or list): UQmeasure obtain from UQEstimator
710 type_UQ (_type_): Type UQ that the nature of UQmeasure
711 pred (np.array): prediction provide by a predictor or an UQEstimator
712 y (np.array): Targets/Observation
713 type_UQ_params : additional parameters link to type paradigm (ex : alpha for quantile)
714 min_cut (_type_): Bottom extremun percentile.
715 max_cut (_type_): Bottom upper percentile.
716 q_var (_type_): Power coefficent
717 sigma_min (float, optional): Minimum values of UQ considered.
719 Returns:
720 gaussian_quantile : alpha quantile lvl based on gaussian assumption
721 """
722 check_UQ(UQ, type_UQ, type_UQ_params)
724 if type_UQ in ["quantile", "res_quantile"]:
725 if type_UQ_params is None:
726 print(
727 "Missing type_UQ_params : cannot manipulate quantile without alpha parameters"
728 )
729 elif alpha in type_UQ_params["list_alpha"]:
730 print("recover quantile")
731 idx = type_UQ_params["list_alpha"].index(alpha)
732 if type_UQ == "quantile":
733 gaussian_quantile = UQ[idx]
735 elif type_UQ == "res_quantile":
736 idx = type_UQ_params["list_alpha"].index(alpha)
737 gaussian_quantile = pred + UQ[idx]
739 elif type_UQ in ["res_2var", "2var"]:
740 sigma = process_UQmeasure_to_sigma(
741 UQ,
742 type_UQ,
743 pred,
744 y,
745 type_UQ_params,
746 var_min=var_min,
747 var_max=var_max,
748 min_cut=min_cut,
749 max_cut=max_cut,
750 q_var=q_var,
751 )
752 y_shape = pred.shape
754 if alpha > 0.5:
755 sigma = sigma[1].reshape(y_shape)
756 else:
757 sigma = sigma[0].reshape(y_shape)
758 gaussian_quantile = pred + scipy.stats.norm.ppf(alpha, 0, sigma)
760 elif type_UQ in ["var_A&E", "res_var", "var"]:
761 sigma = process_UQmeasure_to_sigma(
762 UQ,
763 type_UQ,
764 pred,
765 y,
766 type_UQ_params,
767 var_min=var_min,
768 var_max=var_max,
769 min_cut=min_cut,
770 max_cut=max_cut,
771 q_var=q_var,
772 )
773 gaussian_quantile = pred + scipy.stats.norm.ppf(alpha, 0, sigma)
775 else:
776 raise ValueError(type_UQ + " not covered")
778 gaussian_quantile = apply_middledim_reduction(
779 gaussian_quantile, reduc_filter, roll=roll
780 )
781 return gaussian_quantile
784def process_UQmeasure_to_Epistemicscore(
785 UQ,
786 type_UQ,
787 pred=None,
788 y=None,
789 type_UQ_params=None,
790 var_min=0,
791 var_max=None,
792 min_cut=0,
793 max_cut=1,
794 q_var=1,
795 q_var_e=None,
796 k_var_e=1,
797 mode="relative_likelihood",
798 reduc_filter=None,
799 roll=0,
800 **kwargs,
801):
802 """Process UQ measure to epistemicvalues according UQmeasure
804 Args:
805 UQ (np.array or list): UQ measure obtain from UQ-estimator
806 type_UQ (_type_): Type UQ that caracterise UQ measre
807 pred (np.array): prediction unused
808 y (np.array): Targets/Observation unused
809 type_UQ_params : additional parameters unused
810 Returns:
811 Eval : Epistemic unconfidence score.
812 """
813 check_UQ(UQ, type_UQ, type_UQ_params)
815 if q_var_e is None:
816 q_var_e = q_var
818 var_A = norm_var(
819 UQ[0], min_cut=min_cut, max_cut=max_cut, var_min=var_min, q_var=q_var
820 )
822 var_E = norm_var(
823 UQ[1], min_cut=0, max_cut=1, var_min=0, var_max=var_max, q_var=q_var_e
824 )
826 if type_UQ == "var_A&E":
827 if mode == "relative_likelihood":
828 Eval = np.exp(-0.5 * np.log(1 + (var_A / var_E)))
830 if mode == "relative_variance_part":
831 Eval = np.sqrt(var_E / (var_A + var_E))
833 Eval = np.maximum(Eval - (1 - k_var_e), 0)
835 else:
836 print(
837 "process_UQmeasure_to_Epistemicscore : ",
838 type_UQ,
839 " not covered : only cover var_A&E",
840 )
841 raise ValueError
843 Eval = apply_middledim_reduction(Eval, reduc_filter, roll=roll)
844 return Eval
847def fit_PI(
848 UQ,
849 type_UQ,
850 pred,
851 y=None,
852 list_alpha=[0.025, 0.975],
853 type_UQ_params=None,
854 reduc_filter=None,
855 **kwargs,
856):
857 """Function that estimate PIs parameters according to normal assumption a list of quantile parametrized
858 by list alpha from the UQmeasure
860 Args:
861 pred (_type_): Mean prediction
862 UQ (_type_): UQmeasure
863 type_UQ (_type_): UQmeasure hypothesis
864 list_alpha (list, optional): Quantile values. Defaults to [0.025, 0.975].
865 type_UQ_params (_type_, optional): UQmeasure params. Defaults to None.
866 PIs_params (_type_, optional): PIs_params : May use externally fit_PIs to obtain it.
867 If None, fit_PIs is used internally.
869 Raises:
870 ValueError: type_UQ not covered
872 Returns:
873 list_PIs : List of computed quantiles
874 """
875 PIs_params_ = None
876 return PIs_params_
879def compute_PI(
880 UQ,
881 type_UQ,
882 pred,
883 y=None,
884 type_UQ_params=None,
885 list_alpha=[0.025, 0.975],
886 var_min=0,
887 var_max=None,
888 min_cut=0,
889 max_cut=1,
890 q_var=1,
891 params_=None,
892 reduc_filter=None,
893 **kwargs,
894):
895 """Compute according to normal assumption a list of quantile parametrized by list alpha from the UQmeasre
897 Args:
898 pred (_type_): Mean prediction
899 UQ (_type_): UQmeasure
900 type_UQ (_type_): UQmeasure hypothesis
901 list_alpha (list, optional): Quantile values. Defaults to [0.025, 0.975].
902 type_UQ_params (_type_, optional): UQmeasure params. Defaults to None.
903 params_ (_type_, optional): params : May use externally fit_PIs to obtain it.
904 If None, fit_PIs is used internally.
906 Raises:
907 ValueError: type_UQ not covered
909 Returns:
910 list_PIs : List of computed quantiles
911 params : Params provided or computed
912 """
914 if params_ is None:
915 params_ = fit_PI(
916 UQ,
917 type_UQ,
918 pred,
919 y,
920 list_alpha,
921 type_UQ_params=type_UQ_params,
922 reduc_filter=reduc_filter,
923 )
925 list_PIs = []
926 for alpha in list_alpha:
927 quantile_env = process_UQmeasure_to_quantile(
928 UQ,
929 type_UQ,
930 pred,
931 y=None,
932 type_UQ_params=type_UQ_params,
933 alpha=alpha,
934 var_min=var_min,
935 var_max=var_max,
936 min_cut=min_cut,
937 max_cut=max_cut,
938 q_var=q_var,
939 reduc_filter=reduc_filter,
940 )
942 list_PIs.append(quantile_env)
944 if len(list_PIs) == 1:
945 list_PIs = list_PIs[0]
946 return list_PIs, params_
949def fit_Epistemic_score(
950 UQ,
951 type_UQ,
952 pred=None,
953 y=None,
954 type_UQ_params=None,
955 list_percent=[0.50, 0.80, 0.95, 0.98, 0.995, 1],
956 var_min=0,
957 var_max=None,
958 min_cut=0.1,
959 max_cut=0.97,
960 q_var=1,
961 q_Eratio=3,
962 mode="score",
963 reduc_filter=None,
964 **kwargs,
965):
966 """Function that estimate parameters link to Epistemic_score_normalisation based on quantile lvl
968 Args:
969 pred (_type_): Mean prediction
970 UQ (_type_): UQmeasure
971 type_UQ (_type_): UQmeasure hypothesis
972 list_percent (list, optional): Quantile values to normalise.
973 Defaults to [0.50, 0.80, 0.90, 0.95, 0.975, 0.99, 0.999].
974 type_UQ_params (_type_, optional): UQmeasure params. Defaults to None.
976 returns:
977 params : Params needed by compute_Epistemic_score
978 """
979 if type_UQ != "var_A&E":
980 raise ("type_UQ should be 'var_A&E' not " + type_UQ)
982 extremum_var_TOT, ndUQ_ratio = get_extremum_var_TOT_and_ndUQ_ratio(
983 UQ,
984 type_UQ=type_UQ,
985 min_cut=min_cut,
986 max_cut=max_cut,
987 var_min=var_min,
988 var_max=var_max,
989 factor=2,
990 q_var=q_var,
991 q_Eratio=q_Eratio,
992 mode_multidim=True,
993 )
995 # Do not apply reduc_filter in an intermedaire function.
996 sigma_nominal, sigma_atypique = process_UQmeasure_to_TOT_and_E_sigma(
997 UQ=UQ,
998 type_UQ=type_UQ,
999 pred=pred,
1000 y=y,
1001 var_min=var_min,
1002 var_max=var_max,
1003 min_cut=min_cut,
1004 max_cut=max_cut,
1005 q_var=q_var,
1006 type_UQ_params=type_UQ_params,
1007 q_Eratio=q_Eratio,
1008 q_var_e=1,
1009 k_var_e=1,
1010 ndUQ_ratio=ndUQ_ratio,
1011 extremum_var_TOT=extremum_var_TOT,
1012 reduc_filter=None,
1013 )
1014 UQ = np.power(sigma_nominal, 2), np.power(sigma_atypique, 2)
1016 Epistemic_score = process_UQmeasure_to_Epistemicscore(
1017 UQ=UQ,
1018 type_UQ=type_UQ,
1019 pred=pred,
1020 y=y,
1021 var_min=0,
1022 var_max=None,
1023 min_cut=0,
1024 max_cut=1,
1025 q_var=q_var,
1026 type_UQ_params=type_UQ_params,
1027 reduc_filter=reduc_filter,
1028 )
1030 list_q_val = []
1031 for n, i in enumerate(list_percent):
1032 list_q_val.append(np.quantile(Epistemic_score, i, axis=0))
1034 params_ = list_q_val, list_percent, ndUQ_ratio, extremum_var_TOT
1035 return params_
1038def compute_Epistemic_score(
1039 UQ,
1040 type_UQ,
1041 pred=None,
1042 y=None,
1043 type_UQ_params=None,
1044 list_percent=[0.80, 0.90, 0.99, 0.999, 1],
1045 var_min=0,
1046 var_max=None,
1047 min_cut=0,
1048 max_cut=1,
1049 q_var=1,
1050 q_Eratio=3,
1051 mode="levels",
1052 params_=None,
1053 reduc_filter=None,
1054 **kwargs,
1055):
1056 """Function that compute Epistemic_score_lvl from (predictor) & UQEstimor outputs &
1057 fitted parameters provided by fit_Epistemic_score
1059 Args:
1060 pred (_type_): Mean prediction
1061 UQ (_type_): UQmeasure
1062 type_UQ (_type_): UQmeasure hypothesis
1063 list_percent (list, optional): Quantile values. Defaults to [0.025, 0.975].
1064 type_UQ_params (_type_, optional): UQmeasure params. Defaults to None.
1065 params_ (_type_, optional): May use externally fit_Epistemic_score to obtain it. If None, internal called to fit
1067 Returns:
1068 Epistemic_scorelvl : Epistemic_score_lvl : Quantile class values of Epistemic score
1069 params : Parameters provided or computed
1070 """
1071 if type_UQ != "var_A&E":
1072 raise ("type_UQ should be 'var_A&E' not " + type_UQ)
1074 if params_ is None:
1075 params_ = fit_Epistemic_score(
1076 UQ=UQ,
1077 type_UQ=type_UQ,
1078 pred=pred,
1079 y=y,
1080 list_percent=list_percent,
1081 var_min=var_min,
1082 var_max=var_max,
1083 min_cut=min_cut,
1084 max_cut=max_cut,
1085 q_var=q_var,
1086 reduc_filter=None,
1087 **kwargs,
1088 )
1090 list_q_val, list_percent, ndUQ_ratio, extremum_var_TOT = params_
1092 # Do not apply reduc_filter in an intermedaire function.
1093 sigma, sigma_E = process_UQmeasure_to_TOT_and_E_sigma(
1094 UQ=UQ,
1095 type_UQ=type_UQ,
1096 pred=pred,
1097 y=y,
1098 var_min=var_min,
1099 var_max=var_max,
1100 min_cut=min_cut,
1101 max_cut=max_cut,
1102 q_var=q_var,
1103 type_UQ_params=type_UQ_params,
1104 q_Eratio=q_Eratio,
1105 q_var_e=1,
1106 k_var_e=1,
1107 ndUQ_ratio=ndUQ_ratio,
1108 extremum_var_TOT=extremum_var_TOT,
1109 reduc_filter=None,
1110 )
1112 UQ = np.power(sigma, 2), np.power(sigma_E, 2)
1114 Epistemic_score = process_UQmeasure_to_Epistemicscore(
1115 UQ=UQ,
1116 type_UQ=type_UQ,
1117 pred=pred,
1118 y=y,
1119 var_min=0,
1120 var_max=None,
1121 min_cut=0,
1122 max_cut=1,
1123 q_var=q_var,
1124 type_UQ_params=type_UQ_params,
1125 reduc_filter=reduc_filter,
1126 )
1128 Epistemic_scorelvl = np.zeros(Epistemic_score.shape)
1130 if mode == "score":
1131 return Epistemic_score, params_
1133 else:
1134 for q_val in list_q_val:
1135 if len(pred.shape) == 1:
1136 Epistemic_scorelvl += Epistemic_score > q_val
1137 else:
1138 for d in range(Epistemic_scorelvl.shape[1]):
1139 Epistemic_scorelvl[:, d] += Epistemic_score[:, d] > q_val[d]
1140 return Epistemic_scorelvl, params_