@@ -515,7 +515,7 @@ def binned_1D_fit(hist: dict, param: dict, fitfunc: dict, techno: dict, par_fixe
515
515
### [Chi2 loss function]
516
516
def chi2_loss (par ):
517
517
518
- total = 0
518
+ tot = 0
519
519
520
520
# Over histograms
521
521
for key in counts .keys ():
@@ -529,14 +529,14 @@ def chi2_loss(par):
529
529
530
530
residual = (y_pred [fmask ] - counts [key ][rmask ][fmask ]) / errors [key ][rmask ][fmask ]
531
531
532
- total += np .sum (residual ** 2 )
532
+ tot += np .sum (residual ** 2 )
533
533
534
- return total
534
+ return tot
535
535
536
536
### [Huber loss function]
537
537
def huber_loss (par ):
538
538
539
- total = 0
539
+ tot = 0
540
540
delta = techno ['huber_delta' ]
541
541
542
542
# Over histograms
@@ -552,14 +552,15 @@ def huber_loss(par):
552
552
T = huber_lossfunc (y_true = counts [key ][rmask ][fmask ], y_pred = y_pred [fmask ],
553
553
sigma = errors [key ][rmask ][fmask ], delta = delta )
554
554
555
- total += T
555
+ tot += T
556
556
557
- return total
557
+ return tot
558
558
559
- ### [Poissonian negative log-likelihood loss function]
559
+ ### [Poissonian negative delta log-likelihood loss function]
560
560
def poiss_nll_loss (par ):
561
561
562
- total = 0
562
+ EPS = 1e-9
563
+ nll = 0
563
564
564
565
# Over histograms
565
566
for key in counts .keys ():
@@ -571,16 +572,27 @@ def poiss_nll_loss(par):
571
572
# ** Note use x=cbins[range_mask] here, due to trapz integral in fitfunc ! **
572
573
y_pred = fitfunc [key ](cbins [key ][rmask ], par , par_fixed )
573
574
574
- valid = (y_pred > 0 ) & fmask
575
+ valid = (y_pred > 0 )
575
576
if np .sum (valid ) == 0 : return 1e9
576
577
577
- T1 = counts [key ][rmask ][valid ] * np .log (y_pred [valid ])
578
- T2 = y_pred [valid ]
579
-
580
- total += (- 1 )* (np .sum (T1 ) - np .sum (T2 ))
581
-
582
- return total
583
-
578
+ y_pred [~ valid ] = EPS
579
+
580
+ # Bohm-Zech scale transform for weighted events (https://arxiv.org/abs/1309.1287)
581
+ # https://scikit-hep.org/iminuit/notebooks/weighted_histograms.html
582
+ s = counts [key ][rmask ][fmask ] / (errors [key ][rmask ][fmask ]** 2 ) # Per bin
583
+
584
+ n = counts [key ][rmask ][fmask ] # Observed
585
+ mu = y_pred [fmask ] # Predicted
586
+
587
+ # Factor 2 x taken into account by setting `errordef = iminuit.Minuit.LIKELIHOOD`
588
+
589
+ # Delta log-likelihood with Bohm-Zech scale
590
+ nll += np .sum ( s * (n * (np .log (n ) - np .log (mu )) - (n - mu )) )
591
+
592
+ # Simple log-likelihood (NB. x -1)
593
+ #nll += (-1) * np.sum(n * np.log(mu) - mu)
594
+
595
+ return nll
584
596
585
597
# --------------------------------------------------------------------
586
598
loss_type = techno ['loss_type' ]
@@ -739,9 +751,11 @@ def optimizer_execute(trials, loss, param, techno):
739
751
m1 .fixed [k ] = param ['fixed' ][k ]
740
752
# --------------------------------------------------------------------
741
753
742
- if techno ['loss_type' ] == 'nll' :
754
+ if 'nll' in techno ['loss_type' ]:
755
+ cprint ('Setting errordef "LIKELIHOOD" ' , 'yellow' )
743
756
m1 .errordef = iminuit .Minuit .LIKELIHOOD
744
757
else :
758
+ cprint ('Setting errordef "LEAST_SQUARES" ' , 'yellow' )
745
759
m1 .errordef = iminuit .Minuit .LEAST_SQUARES
746
760
747
761
# Set parameter bounds
0 commit comments