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

1#################################################################### 

2# Ensemble of processing aim to process UQmesures into Intermediate quantity or into final UQ-KPI 

3 

4from copy import deepcopy 

5 

6import numpy as np 

7import scipy 

8 

9import uqmodels.utils as ut 

10from uqmodels.utils import apply_middledim_reduction, cut 

11 

12 

13def check_y_vs_pred_and_UQ_shape(y, pred, UQ=None): 

14 """Check if y, pred and UQ have compatible shape 

15 

16 Args: 

17 y (_type_): _description_ 

18 pred (_type_): _description_ 

19 UQ (_type_): _description_ 

20 

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) 

30 

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) 

37 

38 

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 """ 

45 

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 ) 

51 

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 ) 

62 

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 ) 

73 

74 

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 

89 

90 if var_max is not None: 

91 var_max_ = np.minimum(var_max_, var_max) 

92 

93 return (var_min_, var_max_) 

94 

95 

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 

98 

99 Args: 

100 UQ (_type_): _description_ 

101 k_var_e (_type_): nominal considerate ratio (high-pass filters) 

102 

103 Returns: 

104 ndUQ_ratio: nominal disentangled_UQ_ratio 

105 """ 

106 if q_Eratio is None: 

107 q_Eratio = 2 

108 

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 

118 

119 

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 

130 

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). 

138 

139 Returns: 

140 _type_: _description_ 

141 """ 

142 if ndUQ_ratio is None: 

143 ndUQ_ratio = 0 

144 

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 

151 

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 ) 

155 

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 ) 

165 

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 ) 

171 

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 

174 

175 # Part of high A_values link to abnormal aleatoric uncertainty estimation 

176 var_a_res = var_a - var_a_cut 

177 

178 if A_res_in_var_atypic: 

179 var_e_res = var_e_res + var_a_res 

180 

181 return (var_a_cut, var_e_res) 

182 

183 

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 

205 

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. 

220 

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 ) 

248 

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 ) 

259 

260 ndUQ_ratio = get_nominal_disentangled_UQ_ratio(UQ_bis, q_var, q_Eratio) 

261 

262 return (extremum_var_TOT, ndUQ_ratio) 

263 

264 

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 

273 

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) 

279 

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 

284 

285 

286def renormalise_UQ(UQ, type_UQ, scaler=None, var_min=0, var_max=None): 

287 """UQmeasure to normalised 

288 

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. 

294 

295 Returns: 

296 UQ: normalised UQmeasure 

297 """ 

298 escale_val = 1 

299 if scaler is not None: 

300 rescale_val = scaler.var_ 

301 

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) 

308 

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) 

315 

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]) 

319 

320 else: 

321 print("renormalise_UQ :", type_UQ, "not_covered") 

322 

323 return UQ 

324 

325 

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. 

340 

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. 

351 

352 Returns: 

353 sigma : standards deviation estimation link to ML-uncertainty 

354 """ 

355 check_UQ(UQ, type_UQ, type_UQ_params) 

356 

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 ) 

369 

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, :]]) 

393 

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 ) 

405 

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)) 

414 

415 sigma = apply_middledim_reduction(sigma, reduc_filter) 

416 

417 return sigma 

418 

419 

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. 

441 

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. 

452 

453 Returns: 

454 sigma : standards deviation estimation link to ML-uncertainty 

455 """ 

456 

457 check_UQ(UQ, type_UQ, type_UQ_params) 

458 # Case sigma 

459 

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 

463 

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 ) 

483 

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 ) 

491 

492 sigma_nominal = np.sqrt(var_nominal) 

493 sigma_atypic = k_var_e * np.sqrt(var_atypic) 

494 

495 sigma_nominal = apply_middledim_reduction(sigma_nominal, reduc_filter, roll=roll) 

496 

497 sigma_atypic = apply_middledim_reduction(sigma_atypic, reduc_filter, roll=roll) 

498 return (sigma_nominal, sigma_atypic) 

499 

500 

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. 

524 

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. 

537 

538 Returns: 

539 res : residu 

540 """ 

541 check_UQ(UQ, type_UQ, type_UQ_params) 

542 

543 if q_var_e is None: 

544 q_var_e = q_var 

545 

546 if k_var_e is None: 

547 k_var_e = 0 

548 

549 res_norm = y - pred 

550 

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 

564 

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 ) 

582 

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 ) 

596 

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 ) 

602 

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)) 

605 

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 ) 

616 

617 res_norm = (np.abs(res_norm) + E_penalisation) / (sigma) 

618 res_norm = sign_res * np.power(res_norm, d) 

619 

620 if with_born: 

621 born_bot = (pred + E_penalisation) - (sigma) 

622 born_top = (pred - E_penalisation) + (sigma) 

623 

624 born_bot = np.minimum(born_bot, pred) 

625 born_top = np.maximum(born_top, pred) 

626 

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) 

640 

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] 

647 

648 reshape_marker = True 

649 

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) 

655 

656 res_norm = sign_res * np.power(res_norm, d) 

657 

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) 

661 

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) 

668 

669 if reshape_marker: 

670 res_norm = res_norm[:, 0] 

671 

672 if debug: 

673 print("Mid build res norm:", np.abs(res_norm).mean(), reduc_filter, roll) 

674 

675 res_norm = apply_middledim_reduction(res_norm, reduc_filter, roll=roll) 

676 

677 if debug: 

678 print("End build res norm :", np.abs(res_norm).mean()) 

679 

680 if with_born: 

681 return res_norm, (born_bot, born_top) 

682 else: 

683 return res_norm 

684 

685 

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 

703 

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. 

714 

715 Returns: 

716 gaussian_quantile : alpha quantile lvl based on gaussian assumption 

717 """ 

718 check_UQ(UQ, type_UQ, type_UQ_params) 

719 

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] 

730 

731 elif type_UQ == "res_quantile": 

732 idx = type_UQ_params["list_alpha"].index(alpha) 

733 gaussian_quantile = pred + UQ[idx] 

734 

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 

749 

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) 

755 

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) 

770 

771 else: 

772 raise ValueError(type_UQ + " not covered") 

773 

774 gaussian_quantile = apply_middledim_reduction( 

775 gaussian_quantile, reduc_filter, roll=roll 

776 ) 

777 return gaussian_quantile 

778 

779 

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 

799 

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) 

810 

811 if q_var_e is None: 

812 q_var_e = q_var 

813 

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 ) 

817 

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 ) 

821 

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))) 

825 

826 if mode == "relative_variance_part": 

827 Eval = np.sqrt(var_E / (var_A + var_E)) 

828 

829 Eval = np.maximum(Eval - (1 - k_var_e), 0) 

830 

831 else: 

832 print( 

833 "process_UQmeasure_to_Epistemicscore : ", 

834 type_UQ, 

835 " not covered : only cover var_A&E", 

836 ) 

837 raise ValueError 

838 

839 Eval = apply_middledim_reduction(Eval, reduc_filter, roll=roll) 

840 return Eval 

841 

842 

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 

855 

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. 

864 

865 Raises: 

866 ValueError: type_UQ not covered 

867 

868 Returns: 

869 list_PIs : List of computed quantiles 

870 """ 

871 PIs_params_ = None 

872 return PIs_params_ 

873 

874 

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 

892 

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. 

901 

902 Raises: 

903 ValueError: type_UQ not covered 

904 

905 Returns: 

906 list_PIs : List of computed quantiles 

907 params : Params provided or computed 

908 """ 

909 

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 ) 

920 

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 ) 

937 

938 list_PIs.append(quantile_env) 

939 

940 if len(list_PIs) == 1: 

941 list_PIs = list_PIs[0] 

942 return list_PIs, params_ 

943 

944 

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 

963 

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. 

971 

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) 

977 

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 ) 

990 

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) 

1011 

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 ) 

1025 

1026 list_q_val = [] 

1027 for n, i in enumerate(list_percent): 

1028 list_q_val.append(np.quantile(Epistemic_score, i, axis=0)) 

1029 

1030 params_ = list_q_val, list_percent, ndUQ_ratio, extremum_var_TOT 

1031 return params_ 

1032 

1033 

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 

1054 

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 

1062 

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) 

1069 

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 ) 

1085 

1086 list_q_val, list_percent, ndUQ_ratio, extremum_var_TOT = params_ 

1087 

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 ) 

1107 

1108 UQ = np.power(sigma, 2), np.power(sigma_E, 2) 

1109 

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 ) 

1123 

1124 Epistemic_scorelvl = np.zeros(Epistemic_score.shape) 

1125 

1126 if mode == "score": 

1127 return Epistemic_score, params_ 

1128 

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_