Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
HypoTestResult.cxx
Go to the documentation of this file.
1// @(#)root/roostats:$Id$
2// Author: Kyle Cranmer, Lorenzo Moneta, Gregory Schott, Wouter Verkerke, Sven Kreiss
3/*************************************************************************
4 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11/*****************************************************************************
12 * Project: RooStats
13 * Package: RooFit/RooStats
14 * @(#)root/roofit/roostats:$Id$
15 * Authors:
16 * Kyle Cranmer, Lorenzo Moneta, Gregory Schott, Wouter Verkerke, Sven Kreiss
17 *
18 *****************************************************************************/
19
20
21/** \class RooStats::HypoTestResult
22 \ingroup Roostats
23
24HypoTestResult is a base class for results from hypothesis tests.
25Any tool inheriting from HypoTestCalculator can return a HypoTestResult.
26As such, it stores a p-value for the null-hypothesis (eg. background-only)
27and an alternate hypothesis (eg. signal+background).
28The p-values can also be transformed into confidence levels
29(\f$CL_{b}\f$, \f$CL_{s+b}\f$) in a trivial way.
30The ratio of the \f$CL_{s+b}\f$ to \f$CL_{b}\f$ is often called
31\f$CL_{s}\f$, and is considered useful, though it is not a probability.
32Finally, the p-value of the null can be transformed into a number of
33equivalent Gaussian sigma using the Significance method.
34
35The p-value of the null for a given test statistic is rigorously defined and
36this is the starting point for the following conventions.
37
38### Conventions used in this class
39
40The p-value for the null and alternate are on the **same side** of the
41observed value of the test statistic. This is the more standard
42convention and avoids confusion when doing inverted tests.
43
44For exclusion, we also want the formula \f$CL_{s} = CL_{s+b} / CL_{b}\f$
45to hold which therefore defines our conventions for \f$CL_{s+b}\f$ and
46\f$CL_{b}\f$. \f$CL_{s}\f$ was specifically invented for exclusion
47and therefore all quantities need be related through the assignments
48as they are for exclusion: \f$CL_{s+b} = p_{s+b}\f$; \f$CL_{b} = p_{b}\f$. This
49is derived by considering the scenarios of a powerful and not powerful
50inverted test, where for the not so powerful test, \f$CL_{s}\f$ must be
51close to one.
52
53For results of Hypothesis tests,
54\f$CL_{s}\f$ has no similar direct interpretation as for exclusion and can
55be larger than one.
56
57*/
58
61#include "RooAbsReal.h"
62
64
65#include <TMath.h>
66
67#include <limits>
68#define NaN numeric_limits<float>::quiet_NaN()
69#define IsNaN(a) TMath::IsNaN(a)
70
72
73using namespace RooStats;
74using std::numeric_limits, std::endl;
75
76////////////////////////////////////////////////////////////////////////////////
77/// Default constructor
78
81 fNullPValue(NaN), fAlternatePValue(NaN),
82 fNullPValueError(0), fAlternatePValueError(0),
83 fTestStatisticData(NaN),
84 fAllTestStatisticsData(nullptr),
85 fNullDistr(nullptr), fAltDistr(nullptr),
86 fNullDetailedOutput(nullptr), fAltDetailedOutput(nullptr),
87 fPValueIsRightTail(true),
88 fBackgroundIsAlt(false)
89{
90}
91
92////////////////////////////////////////////////////////////////////////////////
93/// Alternate constructor
94
95HypoTestResult::HypoTestResult(const char* name, double nullp, double altp) :
97 fNullPValue(nullp), fAlternatePValue(altp),
98 fNullPValueError(0), fAlternatePValueError(0),
99 fTestStatisticData(NaN),
100 fAllTestStatisticsData(nullptr),
101 fNullDistr(nullptr), fAltDistr(nullptr),
102 fNullDetailedOutput(nullptr), fAltDetailedOutput(nullptr),
103 fPValueIsRightTail(true),
104 fBackgroundIsAlt(false)
105{
106}
107
108////////////////////////////////////////////////////////////////////////////////
109/// copy constructor
110
112 TNamed(other),
113 fNullPValue(other.fNullPValue), fAlternatePValue(other.fAlternatePValue),
114 fNullPValueError(other.fNullPValueError), fAlternatePValueError(other.fAlternatePValueError),
115 fTestStatisticData(other.fTestStatisticData),
116 fAllTestStatisticsData(nullptr),
117 fNullDistr(nullptr), fAltDistr(nullptr),
118 fNullDetailedOutput(nullptr), fAltDetailedOutput(nullptr),
119 fPValueIsRightTail( other.GetPValueIsRightTail() ),
120 fBackgroundIsAlt( other.GetBackGroundIsAlt() )
121{
122 this->Append( &other );
123}
124
125////////////////////////////////////////////////////////////////////////////////
126/// Destructor
127
129{
130
131}
132
133////////////////////////////////////////////////////////////////////////////////
134/// assignment operator
135
137 if (this == &other) return *this;
138 SetName(other.GetName());
139 SetTitle(other.GetTitle());
140 fNullPValue = other.fNullPValue;
145
146
147 fAllTestStatisticsData = nullptr;
148 fNullDistr = nullptr;
149 fAltDistr = nullptr;
150 fNullDetailedOutput = nullptr;
151 fAltDetailedOutput = nullptr;
152
153 fFitInfo = nullptr;
154
157
158 this->Append( &other );
159
160 return *this;
161}
162
163////////////////////////////////////////////////////////////////////////////////
164/// Add additional toy-MC experiments to the current results.
165/// Use the data test statistics of the added object if it is not already
166/// set (otherwise, ignore the new one).
167
169 if (fNullDistr) {
170 fNullDistr->Add(other->GetNullDistribution());
171 } else if (other->GetNullDistribution()) {
172 fNullDistr = std::make_unique<SamplingDistribution>(*other->GetNullDistribution());
173 }
174
175 if (fAltDistr) {
176 fAltDistr->Add(other->GetAltDistribution());
177 } else if (other->GetAltDistribution()) {
178 fAltDistr = std::make_unique<SamplingDistribution>(*other->GetAltDistribution());
179 }
180
181 if( fNullDetailedOutput ) {
182 if( other->GetNullDetailedOutput() ) fNullDetailedOutput->append( *other->GetNullDetailedOutput() );
183 }else{
184 if( other->GetNullDetailedOutput() ) fNullDetailedOutput = std::make_unique<RooDataSet>( *other->GetNullDetailedOutput() );
185 }
186
187 if( fAltDetailedOutput ) {
188 if( other->GetAltDetailedOutput() ) fAltDetailedOutput->append( *other->GetAltDetailedOutput() );
189 }else{
190 if( other->GetAltDetailedOutput() ) fAltDetailedOutput = std::make_unique<RooDataSet>( *other->GetAltDetailedOutput() );
191 }
192
193 if( fFitInfo ) {
194 if( other->GetFitInfo() ) fFitInfo->append( *other->GetFitInfo() );
195 }else{
196 if( other->GetFitInfo() ) fFitInfo = std::make_unique<RooDataSet>( *other->GetFitInfo());
197 }
198
199 // if no data is present use the other HypoTestResult's data
201
204}
205
206////////////////////////////////////////////////////////////////////////////////
207
209 fAltDistr.reset(alt);
211}
212
213////////////////////////////////////////////////////////////////////////////////
214
216 fNullDistr.reset(null);
218}
219
220////////////////////////////////////////////////////////////////////////////////
221
223 fTestStatisticData = tsd;
224
227}
228
229////////////////////////////////////////////////////////////////////////////////
230
232 if (tsd) fAllTestStatisticsData.reset(static_cast<const RooArgList*>(tsd->snapshot()));
233
235 RooRealVar* firstTS = static_cast<RooRealVar*>(fAllTestStatisticsData->at(0));
236 if( firstTS ) SetTestStatisticData( firstTS->getVal() );
237 }
238}
239
240////////////////////////////////////////////////////////////////////////////////
241
244
247}
248
249////////////////////////////////////////////////////////////////////////////////
250
252 return !IsNaN(fTestStatisticData);
253}
254
255////////////////////////////////////////////////////////////////////////////////
256
258 // compute error on Null pvalue
259 return fNullPValueError;
260}
261
262////////////////////////////////////////////////////////////////////////////////
263/// compute \f$CL_{b}\f$ error
264/// \f$CL_{b}\f$ = 1 - NullPValue()
265/// must use opposite condition that routine above
266
269}
270
271////////////////////////////////////////////////////////////////////////////////
272
275}
276
277////////////////////////////////////////////////////////////////////////////////
278/// Taylor expansion series approximation for standard deviation (error propagation)
279
282}
283
284////////////////////////////////////////////////////////////////////////////////
285/// Returns an estimate of the error on \f$CL_{s}\f$ through combination of the
286/// errors on \f$CL_{b}\f$ and \f$CL_{s+b}\f$:
287/// \f[
288/// \sigma_{CL_s} = CL_s
289/// \sqrt{\left( \frac{\sigma_{CL_{s+b}}}{CL_{s+b}} \right)^2 + \left( \frac{\sigma_{CL_{b}}}{CL_{b}} \right)^2}
290/// \f]
291
293 if(!fAltDistr || !fNullDistr) return 0.0;
294
295 // unsigned const int n_b = fNullDistr->GetSamplingDistribution().size();
296 // unsigned const int n_sb = fAltDistr->GetSamplingDistribution().size();
297
298 // if CLb() == 0 CLs = -1 so return a -1 error
299 if (CLb() == 0 ) return -1;
300
301 double cl_b_err2 = pow(CLbError(),2);
302 double cl_sb_err2 = pow(CLsplusbError(),2);
303
304 return std::sqrt(cl_sb_err2 + cl_b_err2 * pow(CLs(),2))/CLb();
305}
306
307////////////////////////////////////////////////////////////////////////////////
308/// updates the pvalue if sufficient data is available
309
310void HypoTestResult::UpdatePValue(const SamplingDistribution* distr, double &pvalue, double &perror, bool /*isNull*/) {
311 if(IsNaN(fTestStatisticData)) return;
312 if(!distr) return;
313
314 /* Got to be careful for discrete distributions:
315 * To get the right behaviour for limits, the p-value must
316 * include the value of fTestStatistic both for Alt and Null cases
317 */
319 pvalue = distr->IntegralAndError(perror, fTestStatisticData, RooNumber::infinity(), true,
320 true , true ); // always closed interval [ fTestStatistic, inf ]
321
322 }else{
323 pvalue = distr->IntegralAndError(perror, -RooNumber::infinity(), fTestStatisticData, true,
324 true, true ); // // always closed [ -inf, fTestStatistic ]
325 }
326}
327
328////////////////////////////////////////////////////////////////////////////////
329/// Print out some information about the results
330/// Note: use Alt/Null labels for the hypotheses here as the Null
331/// might be the s+b hypothesis.
332
334{
335 bool fromToys = (fAltDistr || fNullDistr);
336
337 std::cout << std::endl << "Results " << GetName() << ": " << endl;
338 std::cout << " - Null p-value = " << NullPValue();
339 if (fromToys) std::cout << " +/- " << NullPValueError();
340 std::cout << std::endl;
341 std::cout << " - Significance = " << Significance();
342 if (fromToys) std::cout << " +/- " << SignificanceError() << " sigma";
343 std::cout << std::endl;
344 if(fAltDistr)
345 std::cout << " - Number of Alt toys: " << fAltDistr->GetSize() << std::endl;
346 if(fNullDistr)
347 std::cout << " - Number of Null toys: " << fNullDistr->GetSize() << std::endl;
348
349 if (HasTestStatisticData() ) std::cout << " - Test statistic evaluated on data: " << fTestStatisticData << std::endl;
350 std::cout << " - CL_b: " << CLb();
351 if (fromToys) std::cout << " +/- " << CLbError();
352 std::cout << std::endl;
353 std::cout << " - CL_s+b: " << CLsplusb();
354 if (fromToys) std::cout << " +/- " << CLsplusbError();
355 std::cout << std::endl;
356 std::cout << " - CL_s: " << CLs();
357 if (fromToys) std::cout << " +/- " << CLsError();
358 std::cout << std::endl;
359
360 return;
361}
#define NaN
#define IsNaN(a)
#define NaN
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:382
char name[80]
Definition TGX11.cxx:110
RooAbsCollection * snapshot(bool deepCopy=true) const
Take a snap shot of current collection contents.
double getVal(const RooArgSet *normalisationSet=nullptr) const
Evaluate object.
Definition RooAbsReal.h:103
RooArgList is a container object that can hold multiple RooAbsArg objects.
Definition RooArgList.h:22
static constexpr double infinity()
Return internal infinity representation.
Definition RooNumber.h:25
Variable that can be changed from the outside.
Definition RooRealVar.h:37
HypoTestResult is a base class for results from hypothesis tests.
RooDataSet * GetFitInfo() const
std::unique_ptr< RooDataSet > fNullDetailedOutput
void UpdatePValue(const SamplingDistribution *distr, double &pvalue, double &perror, bool pIsRightTail)
updates the pvalue if sufficient data is available
void Print(const Option_t *="") const override
Print out some information about the results Note: use Alt/Null labels for the hypotheses here as the...
double fNullPValue
p-value for the null hypothesis (small number means disfavoured)
bool HasTestStatisticData(void) const
double fAlternatePValueError
error of p-value for the alternate hypothesis (small number means disfavoured)
HypoTestResult & operator=(const HypoTestResult &other)
assignment operator
virtual double CLsplusb() const
Convert AlternatePValue into a "confidence level".
std::unique_ptr< RooDataSet > fAltDetailedOutput
void SetAllTestStatisticsData(const RooArgList *tsd)
double GetTestStatisticData(void) const
virtual void Append(const HypoTestResult *other)
add values from another HypoTestResult
double NullPValueError() const
The error on the Null p-value.
double CLsError() const
The error on the ratio .
RooDataSet * GetNullDetailedOutput(void) const
virtual double Significance() const
familiar name for the Null p-value in terms of 1-sided Gaussian significance
bool GetPValueIsRightTail(void) const
void SetNullDistribution(SamplingDistribution *null)
~HypoTestResult() override
destructor
bool GetBackGroundIsAlt(void) const
HypoTestResult(const char *name=nullptr)
default constructor
double SignificanceError() const
The error on the significance, computed from NullPValueError via error propagation.
virtual double NullPValue() const
Return p-value for null hypothesis.
double CLbError() const
The error on the "confidence level" of the null hypothesis.
void SetTestStatisticData(const double tsd)
double CLsplusbError() const
The error on the "confidence level" of the alternative hypothesis.
double fNullPValueError
error of p-value for the null hypothesis (small number means disfavoured)
double fTestStatisticData
result of the test statistic evaluated on data
void SetAltDistribution(SamplingDistribution *alt)
RooDataSet * GetAltDetailedOutput(void) const
std::unique_ptr< const RooArgList > fAllTestStatisticsData
for the case of multiple test statistics, holds all the results
SamplingDistribution * GetNullDistribution(void) const
std::unique_ptr< RooDataSet > fFitInfo
std::unique_ptr< SamplingDistribution > fAltDistr
virtual double CLs() const
is simply (not a method, but a quantity)
double fAlternatePValue
p-value for the alternate hypothesis (small number means disfavoured)
std::unique_ptr< SamplingDistribution > fNullDistr
virtual double CLb() const
Convert NullPValue into a "confidence level".
SamplingDistribution * GetAltDistribution(void) const
This class simply holds a sampling distribution of some test statistic.
double IntegralAndError(double &error, double low, double high, bool normalize=true, bool lowClosed=true, bool highClosed=false) const
numerical integral in these limits including error estimation
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:164
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:48
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition TNamed.cxx:140
double normal_pdf(double x, double sigma=1, double x0=0)
Probability density function of the normal (Gaussian) distribution.
Namespace for the RooStats classes.
Definition Asimov.h:19