Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ProfileLikelihoodCalculator.cxx
Go to the documentation of this file.
1// @(#)root/roostats:$Id$
2// Author: Kyle Cranmer 28/07/2008
3
4/*************************************************************************
5 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/** \class RooStats::ProfileLikelihoodCalculator
13 \ingroup Roostats
14
15The ProfileLikelihoodCalculator is a concrete implementation of CombinedCalculator
16(the interface class for tools which can produce both a RooStats HypoTestResult
17and ConfInterval). The tool uses the profile likelihood ratio as a test statistic,
18and assumes that Wilks' theorem is valid. Wilks' theorem states that \f$ -2 \cdot \ln(\lambda) \f$
19(profile likelihood ratio) is asymptotically distributed as a \f$ \chi^2 \f$ distribution
20with \f$ N \f$ degrees of freedom. Thus, \f$p\f$-values can be
21constructed, and the profile likelihood ratio can be used to construct a
22LikelihoodInterval. (In the future, this class could be extended to use toy
23Monte Carlo to calibrate the distribution of the test statistic).
24
25Usage: It uses the interface of the CombinedCalculator, so that it can be
26configured by specifying:
27
28 - A model common model (*e.g.* a family of specific models, which includes both
29 the null and alternate)
30 - A data set
31 - A set of parameters of interest. The nuisance parameters will be all other
32 parameters of the model.
33 - A set of parameters which specify the null hypothesis (including values
34 and const/non-const status).
35
36The interface allows one to pass the model, data, and parameters either directly
37or via a ModelConfig class. The alternate hypothesis leaves the parameter free
38to take any value other than those specified by the null hypothesis. There is
39therefore no need to specify the alternate parameters.
40
41After configuring the calculator, one only needs to call GetHypoTest() (which
42will return a HypoTestResult pointer) or GetInterval() (which will return a
43ConfInterval pointer).
44
45This calculator can work with both one-dimensional intervals or multi-
46dimensional ones (contours).
47
48Note that for hypothesis tests, it is often better to use the
49AsymptoticCalculator, which can compute in addition the expected
50\f$p\f$-value using an Asimov data set.
51
52*/
53
55
57
60
61#include "RooFitResult.h"
62#include "RooRealVar.h"
63#include "RooProfileLL.h"
64#include "RooGlobalFunc.h"
65#include "RooMsgService.h"
66
68#include "RooMinimizer.h"
69
70
71using namespace RooFit;
72using namespace RooStats;
73
74
75////////////////////////////////////////////////////////////////////////////////
76/// default constructor
77
79
81 double size, const RooArgSet* nullParams ) :
83 fGlobalFitDone(false)
84{
85 // constructor from pdf and parameters
86 // the pdf must contain eventually the nuisance parameters
87}
88
91 fGlobalFitDone(false)
92{
93 // construct from a ModelConfig. Assume data model.GetPdf() will provide full description of model including
94 // constraint term on the nuisances parameters
95 assert(model.GetPdf() );
96}
97
98
99////////////////////////////////////////////////////////////////////////////////
100/// destructor
101/// cannot delete prod pdf because it will delete all the composing pdf's
102/// if (fOwnPdf) delete fPdf;
103/// fPdf = 0;
104
106
108 // reset and clear fit result
109 // to be called when a new model or data are set in the calculator
110 fFitResult.reset();
111}
112
114 // perform a global fit of the likelihood letting with all parameter of interest and
115 // nuisance parameters
116 // keep the list of fitted parameters
117
118 DoReset();
119 RooAbsPdf * pdf = GetPdf();
121 if (!data || !pdf ) return nullptr;
122
123 // get all non-const parameters
124 std::unique_ptr<RooArgSet> constrainedParams{pdf->getParameters(*data)};
125 if (!constrainedParams) return nullptr;
127
128 const auto& config = GetGlobalRooStatsConfig();
130 RooFit::Offset(config.useLikelihoodOffset) )};
131
132 // check if global fit has been already done
133 if (fFitResult && fGlobalFitDone) {
134 return RooFit::makeOwningPtr(std::move(nll));
135 }
136
137 // calculate MLE
138 oocoutP(nullptr,Minimization) << "ProfileLikelihoodCalcultor::DoGLobalFit - find MLE " << std::endl;
139
140 fFitResult = std::unique_ptr<RooFitResult>{DoMinimizeNLL(nll.get())};
141
142 // print fit result
143 if (fFitResult) {
144 fFitResult->printStream( oocoutI(nullptr,Minimization), fFitResult->defaultPrintContents(nullptr), fFitResult->defaultPrintStyle(nullptr) );
145
146 if (fFitResult->status() != 0) {
147 oocoutW(nullptr,Minimization) << "ProfileLikelihoodCalcultor::DoGlobalFit - Global fit failed - status = " << fFitResult->status() << std::endl;
148 } else {
149 fGlobalFitDone = true;
150 }
151 }
152
153 return RooFit::makeOwningPtr(std::move(nll));
154}
155
157 // Minimizer the given NLL using the default options
158
159 const char * minimType = ""; // empty string to select RooMinimizer default
162 int level = ROOT::Math::MinimizerOptions::DefaultPrintLevel() -1;// RooFit level starts from -1
164 // do global fit and store fit result for further use
165
166 const auto& config = GetGlobalRooStatsConfig();
167
168 RooMinimizer minim(*nll);
169 minim.setStrategy(strategy);
170 minim.setEps(tolerance);
171 minim.setPrintLevel(level);
172 minim.setEvalErrorWall(config.useEvalErrorWall);
173
174 oocoutP(nullptr,Minimization) << "ProfileLikelihoodCalcultor::DoMinimizeNLL - using " << minim.minimizerType()
175 << " / " << minimAlgo << " with strategy " << strategy << std::endl;
176
177 int status = -1;
178 for (int tries = 1, maxtries = 4; tries <= maxtries; ++tries) {
179 status = minim.minimize(minimType,minimAlgo);
180 if (status%1000 == 0) { // ignore errors from Improve
181 break;
182 } else if (tries < maxtries) {
183 oocoutW(nullptr,Minimization) << " ----> Doing a re-scan first" << std::endl;
184 minim.minimize(minimType,"Scan");
185 if (tries == 2) {
186 if (strategy == 0 ) {
187 oocoutW(nullptr,Minimization) << " ----> trying with strategy = 1" << std::endl;
188 minim.setStrategy(1);
189 }
190 else
191 tries++; // skip this trial if strategy is already 1
192 }
193 if (tries == 3) {
194 oocoutW(nullptr,Minimization) << " ----> trying with improve" << std::endl;
195 minimType = "Minuit";
196 minimAlgo = "migradimproved";
197 }
198 }
199 }
200
201 return minim.save();
202}
203
204////////////////////////////////////////////////////////////////////////////////
205/// Main interface to get a RooStats::ConfInterval.
206/// It constructs a profile likelihood ratio, and uses that to construct a RooStats::LikelihoodInterval.
207
209// RooAbsPdf* pdf = fWS->pdf(fPdfName);
210// RooAbsData* data = fWS->data(fDataName);
211 RooAbsPdf * pdf = GetPdf();
213 if (!data || !pdf || fPOI.empty()) return nullptr;
214
215 std::unique_ptr<RooArgSet> constrainedParams{pdf->getParameters(*data)};
217
218
219 /*
220 RooNLLVar* nll = new RooNLLVar("nll","",*pdf,*data, Extended(),Constrain(*constrainedParams));
221 RooProfileLL* profile = new RooProfileLL("pll","",*nll, *fPOI);
222 profile->addOwnedComponents(*nll) ; // to avoid memory leak
223 */
224
225 // do a global fit cloning the data
226 std::unique_ptr<RooAbsReal> nll{DoGlobalFit()};
227 if (!nll) return nullptr;
228
229 if (!fFitResult) {
230 return nullptr;
231 }
232
233 std::unique_ptr<RooAbsReal> profile{nll->createProfile(fPOI)};
234 profile->addOwnedComponents(std::move(nll)) ; // to avoid memory leak
235
236 // t.b.f. " RooProfileLL should keep and provide possibility to query on global minimum
237 // set POI to fit value (this will speed up profileLL calculation of global minimum)
238 const RooArgList & fitParams = fFitResult->floatParsFinal();
239 for (auto *fitPar : static_range_cast<RooRealVar *>(fitParams)) {
240 RooRealVar * par = static_cast<RooRealVar*>(fPOI.find( fitPar->GetName() ));
241 if (par) {
242 par->setVal( fitPar->getVal() );
243 par->setError( fitPar->getError() );
244 }
245 }
246
247 // do this so profile will cache inside the absolute minimum and
248 // minimum values of nuisance parameters
249 // (no need to this here)
250 // profile->getVal();
251 //RooMsgService::instance().setGlobalKillBelow(RooFit::DEBUG) ;
252 // profile->Print();
253
254 TString name = TString("LikelihoodInterval_");// + TString(GetName() );
255
256 // make a list of fPOI with fit result values and pass to LikelihoodInterval class
257 // bestPOI is a cloned list of POI only with their best fit values
258 RooArgSet fitParSet(fitParams);
259 RooArgSet * bestPOI = new RooArgSet();
260 for (auto const *arg : fPOI){
261 RooAbsArg * p = fitParSet.find( arg->GetName() );
262 if (p) bestPOI->addClone(*p);
263 else bestPOI->addClone(*arg);
264 }
265 // fPOI contains the parameter of interest of the PL object
266 // and bestPOI contains a snapshot with the best fit values
267 LikelihoodInterval* interval = new LikelihoodInterval(name, profile.release(), &fPOI, bestPOI);
268 interval->SetConfidenceLevel(1.-fSize);
269 return interval;
270}
271
272////////////////////////////////////////////////////////////////////////////////
273/// Main interface to get a HypoTestResult.
274/// It does two fits:
275/// 1. The first lets the null parameters float, so it's a maximum likelihood estimate.
276/// 2. The second is to the null model (fixing null parameters to their specified values): *e.g.* a conditional maximum likelihood.
277/// Since not all parameters are floating, this likelihood will be lower than the unconditional model.
278///
279/// The ratio of the likelihood obtained from the conditional MLE to the MLE is the profile likelihood ratio.
280/// Wilks' theorem is used to get \f$p\f$-values.
281
283// RooAbsPdf* pdf = fWS->pdf(fPdfName);
284// RooAbsData* data = fWS->data(fDataName);
285 RooAbsPdf * pdf = GetPdf();
287
288
289 if (!data || !pdf) return nullptr;
290
291 if (fNullParams.empty()) return nullptr;
292
293 // make a clone and ordered list since a vector will be associated to keep parameter values
294 // clone the list since first fit will changes the fNullParams values
296 poiList.addClone(fNullParams); // make a clone list
297
298
299 // do a global fit
300 std::unique_ptr<RooAbsReal> nll{DoGlobalFit()};
301 if (!nll) return nullptr;
302
303 if (!fFitResult) {
304 return nullptr;
305 }
306
307 std::unique_ptr<RooArgSet> constrainedParams{pdf->getParameters(*data)};
309
310 double nLLatMLE = fFitResult->minNll();
311 // in case of using offset need to save offset value
312 double nlloffset = RooStats::NLLOffsetMode() == "initial" ? nll->getVal() - nLLatMLE : 0;
313
314 // set POI to given values, set constant, calculate conditional MLE
315 std::vector<double> oldValues(poiList.size() );
316 for (unsigned int i = 0; i < oldValues.size(); ++i) {
317 RooRealVar * mytarget = static_cast<RooRealVar*>(constrainedParams->find(poiList[i].GetName()));
318 if (mytarget) {
319 oldValues[i] = mytarget->getVal();
320 mytarget->setVal( ( static_cast<RooRealVar&>( poiList[i]) ).getVal() );
321 mytarget->setConstant(true);
322 }
323 }
324
325
326
327 // perform the fit only if nuisance parameters are available
328 // get nuisance parameters
329 // nuisance parameters are the non const parameters from the likelihood parameters
331
332 // need to remove the parameter of interest
334
335 // check there are variable parameter in order to do a fit
336 bool existVarParams = false;
337 for (auto const *myarg : static_range_cast<RooRealVar *> (nuisParams)) {
338 if ( !myarg->isConstant() ) {
339 existVarParams = true;
340 break;
341 }
342 }
343
344 double nLLatCondMLE = nLLatMLE;
345 if (existVarParams) {
346 oocoutP(nullptr,Minimization) << "ProfileLikelihoodCalcultor::GetHypoTest - do conditional fit " << std::endl;
347
348 std::unique_ptr<RooFitResult> fit2{DoMinimizeNLL(&*nll)};
349
350 // print fit result
351 if (fit2) {
352 nLLatCondMLE = fit2->minNll();
353 fit2->printStream( oocoutI(nullptr,Minimization), fit2->defaultPrintContents(nullptr), fit2->defaultPrintStyle(nullptr) );
354
355 if (fit2->status() != 0)
356 oocoutW(nullptr,Minimization) << "ProfileLikelihoodCalcultor::GetHypotest - Conditional fit failed - status = " << fit2->status() << std::endl;
357 }
358
359 }
360 else {
361 // get just the likelihood value (no need to do a fit since the likelihood is a constant function)
362 nLLatCondMLE = nll->getVal();
363 // this value contains the offset
364 if (RooStats::NLLOffsetMode() == "initial") nLLatCondMLE -= nlloffset;
365 }
366
367 // Use Wilks' theorem to translate -2 log lambda into a significance/p-value
368 double deltaNLL = std::max( nLLatCondMLE-nLLatMLE, 0.);
369
370 // get number of free parameter of interest
372 int ndf = poiList.size();
373
375
376 // in case of one dimension (1 poi) do the one-sided p-value (need to divide by 2)
377 if (ndf == 1) pvalue = 0.5 * pvalue;
378
379 TString name = TString("ProfileLRHypoTestResult_");// + TString(GetName() );
381
382 // restore previous value of poi
383 for (unsigned int i = 0; i < oldValues.size(); ++i) {
384 RooRealVar * mytarget = static_cast<RooRealVar*>(constrainedParams->find(poiList[i].GetName()));
385 if (mytarget) {
386 mytarget->setVal(oldValues[i] );
387 mytarget->setConstant(false);
388 }
389 }
390
391 return htr;
392
393}
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define oocoutW(o, a)
#define oocoutI(o, a)
#define oocoutP(o, a)
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
char name[80]
Definition TGX11.cxx:142
static const std::string & DefaultMinimizerAlgo()
Common abstract base class for objects that represent a value and a "shape" in RooFit.
Definition RooAbsArg.h:76
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
RooAbsArg * find(const char *name) const
Find object with given name in list.
Abstract base class for binned and unbinned datasets.
Definition RooAbsData.h:55
Abstract interface for all probability density functions.
Definition RooAbsPdf.h:32
RooFit::OwningPtr< RooAbsReal > createNLL(RooAbsData &data, CmdArgs_t const &... cmdArgs)
Construct representation of -log(L) of PDF with given dataset.
Definition RooAbsPdf.h:155
Abstract base class for objects that represent a real value and implements functionality common to al...
Definition RooAbsReal.h:63
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
RooArgSet is a container object that can hold multiple RooAbsArg objects.
Definition RooArgSet.h:24
Wrapper class around ROOT::Math::Minimizer that provides a seamless interface between the minimizer f...
Variable that can be changed from the outside.
Definition RooRealVar.h:37
void setVal(double value) override
Set value of variable to 'value'.
void setError(double value)
Definition RooRealVar.h:61
CombinedCalculator is an interface class for a tools which can produce both RooStats HypoTestResults ...
RooArgSet fNullParams
RooArgSet specifying null parameters for hypothesis test.
RooArgSet fPOI
RooArgSet specifying parameters of interest for interval.
RooArgSet fGlobalObs
RooArgSet specifying the global observables.
double fSize
size of the test (eg. specified rate of Type I error)
RooArgSet fConditionalObs
RooArgSet specifying the conditional observables.
HypoTestResult is a base class for results from hypothesis tests.
LikelihoodInterval is a concrete implementation of the RooStats::ConfInterval interface.
< A class that holds configuration information for a model using a workspace as a store
Definition ModelConfig.h:34
static RooFit::OwningPtr< RooFitResult > DoMinimizeNLL(RooAbsReal *nll)
minimize likelihood
HypoTestResult * GetHypoTest() const override
Return the hypothesis test result obtained from the likelihood ratio of the maximum likelihood value ...
RooFit::OwningPtr< RooAbsReal > DoGlobalFit() const
perform a global fit
bool fGlobalFitDone
flag to control if a global fit has been done
~ProfileLikelihoodCalculator() override
destructor cannot delete prod pdf because it will delete all the composing pdf's if (fOwnPdf) delete ...
void DoReset() const
clear internal fit result
LikelihoodInterval * GetInterval() const override
Return a likelihood interval.
ProfileLikelihoodCalculator()
Default constructor (needed for I/O)
Basic string class.
Definition TString.h:137
RooCmdArg Offset(std::string const &mode)
RooCmdArg Constrain(const RooArgSet &params)
RooCmdArg GlobalObservables(Args_t &&... argsOrArgSet)
RooCmdArg CloneData(bool flag)
RooCmdArg ConditionalObservables(Args_t &&... argsOrArgSet)
Create a RooCmdArg to declare conditional observables.
double chisquared_cdf_c(double x, double r, double x0=0)
Complement of the cumulative distribution function of the distribution with degrees of freedom (upp...
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...
Definition CodegenImpl.h:73
T * OwningPtr
An alias for raw pointers for indicating that the return type of a RooFit function is an owning point...
Definition Config.h:35
OwningPtr< T > makeOwningPtr(std::unique_ptr< T > &&ptr)
Internal helper to turn a std::unique_ptr<T> into an OwningPtr.
Definition Config.h:40
Namespace for the RooStats classes.
Definition CodegenImpl.h:67
void RemoveConstantParameters(RooArgSet *set)
std::string const & NLLOffsetMode()
Test what offsetting mode RooStats should use by default.
RooStatsConfig & GetGlobalRooStatsConfig()
Retrieve the config object which can be used to set flags for things like offsetting the likelihood o...