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

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 epsilon=10e-10 

523): 

524 """Process UQ measure to residu according prediction, UQmeasure and observation. 

525 

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. 

538 

539 Returns: 

540 res : residu 

541 """ 

542 check_UQ(UQ, type_UQ, type_UQ_params) 

543 

544 if q_var_e is None: 

545 q_var_e = q_var 

546 

547 if k_var_e is None: 

548 k_var_e = 0 

549 

550 res_norm = y - pred 

551 

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 

565 

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 ) 

583 

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 ) 

597 

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 ) 

603 

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

606 

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 ) 

617 

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

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

620 

621 if with_born: 

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

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

624 

625 born_bot = np.minimum(born_bot, pred) 

626 born_top = np.maximum(born_top, pred) 

627 

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) 

641 

642 if with_born: 

643 born_bot = pred 

644 born_top = pred 

645 

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] 

653 

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) 

659 

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

661 

662 if with_born: 

663 born_bot[mask, dim] = pred + E_penalisation - (sigma) 

664 born_top[mask, dim] = pred - E_penalisation + (sigma) 

665 

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) 

672 

673 if reshape_marker: 

674 res_norm = res_norm[:, 0] 

675 

676 if debug: 

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

678 

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

680 

681 if debug: 

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

683 

684 if with_born: 

685 return res_norm, (born_bot, born_top) 

686 else: 

687 return res_norm 

688 

689 

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 

707 

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. 

718 

719 Returns: 

720 gaussian_quantile : alpha quantile lvl based on gaussian assumption 

721 """ 

722 check_UQ(UQ, type_UQ, type_UQ_params) 

723 

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] 

734 

735 elif type_UQ == "res_quantile": 

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

737 gaussian_quantile = pred + UQ[idx] 

738 

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 

753 

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) 

759 

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) 

774 

775 else: 

776 raise ValueError(type_UQ + " not covered") 

777 

778 gaussian_quantile = apply_middledim_reduction( 

779 gaussian_quantile, reduc_filter, roll=roll 

780 ) 

781 return gaussian_quantile 

782 

783 

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 

803 

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) 

814 

815 if q_var_e is None: 

816 q_var_e = q_var 

817 

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 ) 

821 

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 ) 

825 

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

829 

830 if mode == "relative_variance_part": 

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

832 

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

834 

835 else: 

836 print( 

837 "process_UQmeasure_to_Epistemicscore : ", 

838 type_UQ, 

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

840 ) 

841 raise ValueError 

842 

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

844 return Eval 

845 

846 

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 

859 

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. 

868 

869 Raises: 

870 ValueError: type_UQ not covered 

871 

872 Returns: 

873 list_PIs : List of computed quantiles 

874 """ 

875 PIs_params_ = None 

876 return PIs_params_ 

877 

878 

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 

896 

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. 

905 

906 Raises: 

907 ValueError: type_UQ not covered 

908 

909 Returns: 

910 list_PIs : List of computed quantiles 

911 params : Params provided or computed 

912 """ 

913 

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 ) 

924 

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 ) 

941 

942 list_PIs.append(quantile_env) 

943 

944 if len(list_PIs) == 1: 

945 list_PIs = list_PIs[0] 

946 return list_PIs, params_ 

947 

948 

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 

967 

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. 

975 

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) 

981 

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 ) 

994 

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) 

1015 

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 ) 

1029 

1030 list_q_val = [] 

1031 for n, i in enumerate(list_percent): 

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

1033 

1034 params_ = list_q_val, list_percent, ndUQ_ratio, extremum_var_TOT 

1035 return params_ 

1036 

1037 

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 

1058 

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 

1066 

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) 

1073 

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 ) 

1089 

1090 list_q_val, list_percent, ndUQ_ratio, extremum_var_TOT = params_ 

1091 

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 ) 

1111 

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

1113 

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 ) 

1127 

1128 Epistemic_scorelvl = np.zeros(Epistemic_score.shape) 

1129 

1130 if mode == "score": 

1131 return Epistemic_score, params_ 

1132 

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_