Likelihood and minimization: Parameter uncertainties for weighted unbinned ML fits
Parameter uncertainties for weighted unbinned ML fits
Based on example from https://arxiv.org/abs/1911.01303
This example compares different approaches to determining parameter uncertainties in weighted unbinned maximum likelihood fits. Performing a weighted unbinned maximum likelihood fits can be useful to account for acceptance effects and to statistically subtract background events using the sPlot formalism. It is however well known that the inverse Hessian matrix does not yield parameter uncertainties with correct coverage in the presence of event weights. Three approaches to the determination of parameter uncertainties are compared in this example:
- Using the inverse weighted Hessian matrix [SumW2Error(false)]
- Using the expression [SumW2Error(true)]
\[ V_{ij} = H_{ik}^{-1} C_{kl} H_{lj}^{-1}
\]
where H is the weighted Hessian matrix and C is the Hessian matrix with squared weights
- The asymptotically correct approach (for details please see https://arxiv.org/abs/1911.01303) [Asymptotic(true)]
\[ V_{ij} = H_{ik}^{-1} D_{kl} H_{lj}^{-1}
\]
where H is the weighted Hessian matrix and D is given by
\[ D_{kl} = \sum_{e=1}^{N} w_e^2 \frac{\partial \log(P)}{\partial \lambda_k}\frac{\partial \log(P)}{\partial
\lambda_l}
\]
with the event weight \(w_e\).
The example performs the fit of a second order polynomial in the angle cos(theta) [-1,1] to a weighted data set. The polynomial is given by
\[ P = \frac{ 1 + c_0 \cdot \cos(\theta) + c_1 \cdot \cos(\theta) \cdot \cos(\theta) }{\mathrm{Norm}}
\]
The two coefficients \( c_0 \) and \( c_1 \) and their uncertainties are to be determined in the fit.
The per-event weight is used to correct for an acceptance effect, two different acceptance models can be studied:
- acceptancemodel==1: eff = \( 0.3 + 0.7 \cdot \cos(\theta) \cdot \cos(\theta) \)
- acceptancemodel==2: eff = \( 1.0 - 0.7 \cdot \cos(\theta) \cdot \cos(\theta) \) The data is generated to be flat before the acceptance effect.
The performance of the different approaches to determine parameter uncertainties is compared using the pull distributions from a large number of pseudoexperiments. The pull is defined as \( (\lambda_i -
\lambda_{gen})/\sigma(\lambda_i) \), where \( \lambda_i \) is the fitted parameter and \( \sigma(\lambda_i) \) its uncertainty for pseudoexperiment number i. If the fit is unbiased and the parameter uncertainties are estimated correctly, the pull distribution should be a Gaussian centered around zero with a width of one.
void rf611_weightedfits(int acceptancemodel = 2)
{
gStyle->SetPaintTextFormat(
".1f");
gStyle->SetTitleSize(0.05,
"XY");
gStyle->SetLabelSize(0.05,
"XY");
gStyle->SetTitleOffset(0.9,
"XY");
gStyle->SetPadLeftMargin(0.125);
gStyle->SetPadBottomMargin(0.125);
gStyle->SetPadTopMargin(0.075);
gStyle->SetPadRightMargin(0.075);
gStyle->SetHistLineWidth(2.0);
TH1 *haccepted =
new TH1D(
"haccepted",
"Generated events;cos(#theta);#events", 40, -1.0, 1.0);
TH1 *hweighted =
new TH1D(
"hweighted",
"Generated events;cos(#theta);#events", 40, -1.0, 1.0);
std::array<TH1 *, 3> hc0pull;
std::array<TH1 *, 3> hc1pull;
std::array<TH1 *, 3> hntotpull;
std::array<std::string, 3> methodLabels{"Inverse weighted Hessian matrix [SumW2Error(false)]",
"Hessian matrix with squared weights [SumW2Error(true)]",
"Asymptotically correct approach [Asymptotic(true)]"};
auto makePullXLabel = [](std::string const &pLabel) {
return "Pull (" + pLabel + "^{fit}-" + pLabel + "^{gen})/#sigma(" + pLabel + ")";
};
for (std::size_t i = 0; i < 3; ++i) {
std::string const &iLabel = std::to_string(i);
std::string hc0XLabel = methodLabels[i] + ";" + makePullXLabel("c_{0}") + ";";
std::string hc1XLabel = methodLabels[i] + ";" + makePullXLabel("c_{1}") + ";";
std::string hntotXLabel = methodLabels[i] + ";" + makePullXLabel("N_{tot}") + ";";
hc0pull[i] =
new TH1D((
"hc0pull" + iLabel).c_str(), hc0XLabel.c_str(), 20, -5.0, 5.0);
hc1pull[i] =
new TH1D((
"hc1pull" + iLabel).c_str(), hc1XLabel.c_str(), 20, -5.0, 5.0);
hntotpull[i] =
new TH1D((
"hntotpull" + iLabel).c_str(), hntotXLabel.c_str(), 20, -5.0, 5.0);
}
constexpr std::size_t ntoys = 500;
constexpr std::size_t nstats = 500;
constexpr double c0gen = 0.0;
constexpr double c1gen = 0.0;
std::cout << "Running " << ntoys * 3 << " toy fits ..." << std::endl;
for (std::size_t i = 0; i < ntoys; i++) {
RooRealVar costheta(
"costheta",
"costheta", -1.0, 1.0);
RooRealVar weight(
"weight",
"weight", 0.0, 1000.0);
RooRealVar c0(
"c0",
"0th-order coefficient", c0gen, -1.0, 1.0);
RooRealVar c1(
"c1",
"1st-order coefficient", c1gen, -1.0, 1.0);
c0.setError(0.01);
double ngen = nstats;
if (acceptancemodel == 1)
ngen *= 2.0 / (23.0 / 15.0);
else
ngen *= 2.0 / (16.0 / 15.0);
RooRealVar ntot(
"ntot",
"ntot", ngen, 0.0, 2.0 * ngen);
RooExtendPdf extended(
"extended",
"extended pdf", pol, ntot);
int npoisson = rnd->
Poisson(nstats);
for (std::size_t j = 0; j < npoisson; j++) {
bool finished = false;
while (!finished) {
costheta = 2.0 * rnd->
Rndm() - 1.0;
double eff = 1.0;
if (acceptancemodel == 1)
eff = 1.0 - 0.7 * costheta.getVal() * costheta.getVal();
else
eff = 0.3 + 0.7 * costheta.getVal() * costheta.getVal();
weight = 1.0 / eff;
if (10.0 * rnd->
Rndm() < eff * pol.getVal())
finished = true;
}
haccepted->
Fill(costheta.getVal());
hweighted->
Fill(costheta.getVal(), weight.getVal());
data.add({costheta, weight}, weight.getVal());
}
auto fillPulls = [&](std::size_t i) {
hc0pull[i]->Fill((c0.getVal() - c0gen) / c0.getError());
hc1pull[i]->Fill((
c1.getVal() - c1gen) /
c1.getError());
hntotpull[i]->Fill((ntot.getVal() - ngen) / ntot.getError());
};
fillPulls(0);
fillPulls(1);
fillPulls(2);
}
std::cout << "... done." << std::endl;
haccepted->
Draw(
"same hist");
leg->AddEntry(haccepted,
"Accepted");
leg->AddEntry(hweighted,
"Weighted");
std::vector<TH1 *> pullHistos{hc0pull[0], hc0pull[1], hc0pull[2], hc1pull[0], hc1pull[1],
hc1pull[2], hntotpull[0], hntotpull[1], hntotpull[2]};
for (std::size_t i = 0; i < pullHistos.size(); ++i) {
pullHistos[i]->Fit("gaus");
pullHistos[i]->Draw("ep");
}
}
Container class to hold unbinned data.
RooExtendPdf is a wrapper around an existing PDF that adds a parameteric extended likelihood term to ...
static RooMsgService & instance()
Return reference to singleton instance.
RooPolynomial implements a polynomial p.d.f of the form.
Variable that can be changed from the outside.
virtual void SetLineColor(Color_t lcolor)
Set the line color.
TVirtualPad * cd(Int_t subpadnumber=0) override
Set current canvas & pad.
void Update() override
Update canvas pad buffers.
1-D histogram with a double per channel (see TH1 documentation)
TH1 is the base class of all histogram classes in ROOT.
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
void Draw(Option_t *option="") override
Draw this histogram with options.
virtual void SetMinimum(Double_t minimum=-1111)
void Divide(Int_t nx=1, Int_t ny=1, Float_t xmargin=0.01, Float_t ymargin=0.01, Int_t color=0) override
Automatic pad generation by division.
Random number generator class based on M.
Double_t Rndm() override
Machine independent random number generator.
void SetSeed(ULong_t seed=0) override
Set the random generator sequence.
virtual ULong64_t Poisson(Double_t mean)
Generates a random integer N according to a Poisson law.
RooCmdArg WeightVar(const char *name="weight", bool reinterpretAsWeight=false)
RooCmdArg AsymptoticError(bool flag)
RooCmdArg SumW2Error(bool flag)
RooCmdArg PrintLevel(Int_t code)
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Running 1500 toy fits ...
... done.
****************************************
Minimizer is Minuit2 / Migrad
Chi2 = 12.2745
NDf = 12
Edm = 3.84566e-06
NCalls = 53
Constant = 82.0512 +/- 4.52865
Mean = -0.042844 +/- 0.0572716
Sigma = 1.19191 +/- 0.0392558 (limited)
****************************************
Minimizer is Minuit2 / Migrad
Chi2 = 8.83881
NDf = 9
Edm = 6.19877e-08
NCalls = 53
Constant = 104.798 +/- 5.86613
Mean = -0.0132039 +/- 0.0432773
Sigma = 0.938314 +/- 0.0320986 (limited)
****************************************
Minimizer is Minuit2 / Migrad
Chi2 = 7.28099
NDf = 10
Edm = 6.30801e-07
NCalls = 53
Constant = 103.063 +/- 5.55774
Mean = -0.0233563 +/- 0.0435444
Sigma = 0.954358 +/- 0.0285394 (limited)
****************************************
Minimizer is Minuit2 / Migrad
Chi2 = 23.1247
NDf = 14
Edm = 2.27317e-06
NCalls = 53
Constant = 69.5383 +/- 3.95119
Mean = -0.160071 +/- 0.0652133
Sigma = 1.37036 +/- 0.0473756 (limited)
****************************************
Minimizer is Minuit2 / Migrad
Chi2 = 7.18474
NDf = 15
Edm = 9.01145e-06
NCalls = 61
Constant = 51.3838 +/- 3.49309
Mean = -0.985792 +/- 0.0760226
Sigma = 1.36366 +/- 0.0605719 (limited)
****************************************
Minimizer is Minuit2 / Migrad
Chi2 = 11.9456
NDf = 11
Edm = 4.88766e-08
NCalls = 61
Constant = 94.7614 +/- 5.45747
Mean = -0.0978895 +/- 0.0483575
Sigma = 1.03309 +/- 0.0382346 (limited)
****************************************
Minimizer is Minuit2 / Migrad
Chi2 = 20.9563
NDf = 16
Edm = 8.77656e-06
NCalls = 53
Constant = 69.8331 +/- 3.99247
Mean = -0.0767062 +/- 0.0640105
Sigma = 1.36919 +/- 0.0474577 (limited)
****************************************
Minimizer is Minuit2 / Migrad
Chi2 = 8.84994
NDf = 10
Edm = 1.85865e-06
NCalls = 53
Constant = 101.665 +/- 5.77203
Mean = -0.0558063 +/- 0.0444665
Sigma = 0.96468 +/- 0.0336688 (limited)
****************************************
Minimizer is Minuit2 / Migrad
Chi2 = 9.73174
NDf = 10
Edm = 1.95484e-06
NCalls = 53
Constant = 99.7164 +/- 5.69932
Mean = -0.0653755 +/- 0.0459247
Sigma = 0.982023 +/- 0.0349408 (limited)
- Date
- November 2019
- Author
- Christoph Langenbruch
Definition in file rf611_weightedfits.C.