-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[RF] Add RooFit::makeResidHist() and makePullHist() with bin integration #23357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -24,6 +24,7 @@ | |||||||||
| #include <TColor.h> | ||||||||||
|
|
||||||||||
| #include <map> | ||||||||||
| #include <memory> | ||||||||||
| #include <string> | ||||||||||
|
|
||||||||||
| class RooDataHist ; | ||||||||||
|
|
@@ -44,6 +45,7 @@ class RooConstVar ; | |||||||||
| class RooRealVar ; | ||||||||||
| class RooAbsCategory ; | ||||||||||
| class RooNumIntConfig ; | ||||||||||
| class RooHist; | ||||||||||
|
|
||||||||||
| class TH1 ; | ||||||||||
| class TTree ; | ||||||||||
|
|
@@ -472,6 +474,87 @@ RooConstVar& RooConst(double val) ; | |||||||||
| * @} | ||||||||||
| */ | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * \defgroup Residuals Residuals and pulls of binned data vs. a fitted model | ||||||||||
| * | ||||||||||
| * RooFit::makeResidHist() and RooFit::makePullHist() construct per-bin | ||||||||||
| * residual or pull distributions of binned data with respect to a fitted | ||||||||||
| * model. In contrast to RooPlot::residHist() and RooPlot::pullHist(), | ||||||||||
| * which interpolate or average the curve of a plotted pdf, these functions | ||||||||||
| * integrate the model itself exactly over each bin. This avoids the | ||||||||||
| * biased residuals (the "residual wiggle" and inflated \f$\chi^2\f$ values) | ||||||||||
| * that appear when a sharply peaked pdf is compared with binned data. | ||||||||||
| * @{ | ||||||||||
| */ | ||||||||||
|
|
||||||||||
| /// Creates a RooHist with the per-bin residuals `data` - `fitModel`. | ||||||||||
| /// | ||||||||||
| /// For each bin, the model expectation is the model integrated exactly over | ||||||||||
| /// the bin (with RooAbsReal::createIntegral()), normalized to the weight of | ||||||||||
| /// the data inside the normalization range. Unbinned input data is binned | ||||||||||
| /// internally. The supported RooCmdArgs are: | ||||||||||
| /// - `Binning(binning)` / `Binning(nbins)` / `Binning(nbins, xlo, xhi)` : | ||||||||||
| /// the binning used to bin unbinned input data (default: the current | ||||||||||
| /// binning of the observable) | ||||||||||
| /// - `Range(lo, hi)` / `Range("name")` : the range that the model | ||||||||||
| /// expectation is normalized in. Only bins inside this range get points | ||||||||||
|
Comment on lines
+499
to
+500
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
| /// in the result. Range("name") can be passed multiple times for a union | ||||||||||
| /// of named ranges (sidebands). Use it for sideband fits or blinded data, | ||||||||||
| /// so that the model is normalized in the same range as the fitted data. | ||||||||||
| /// - `Normalization(double)` : additional scale factor for the expectation | ||||||||||
| /// (default 1.0). The scale types of Normalization(scale, type) are not | ||||||||||
| /// supported. | ||||||||||
| /// - `DataError(RooAbsData::ErrorType)` : error model used for the point errors, | ||||||||||
| /// one of Poisson, SumW2 or Auto | ||||||||||
| /// (default: Auto, meaning SumW2 for weighted and Poisson for unweighted data) | ||||||||||
| /// - `Name(const char*)`, `Title(const char*)` : name and title of the created RooHist | ||||||||||
| /// | ||||||||||
| /// \note The residuals are computed with respect to `fitModel` itself, not | ||||||||||
| /// with respect to the curve of a plotted pdf. Make sure that the arguments | ||||||||||
| /// are consistent with what is plotted (same normalization and range, same | ||||||||||
| /// error model via DataError()), or the residual/pull histogram will not | ||||||||||
| /// match the displayed data and curve. | ||||||||||
| /// | ||||||||||
| /// \note If the model depends on observables beyond the data's observable | ||||||||||
| /// (e.g. a conditional pdf), they are evaluated at their current values. | ||||||||||
| /// There is no exact equivalent for a projection with ProjWData(). | ||||||||||
| /// | ||||||||||
| /// \note For internal use of RooAbsReal::createIntegral(), a scratch named | ||||||||||
| /// range is left on the model's observable after the call. | ||||||||||
|
Comment on lines
+522
to
+523
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. scratch named range? A range with the name "xxx" is declared? |
||||||||||
| /// | ||||||||||
| /// Only 1-dimensional data is supported, otherwise std::invalid_argument is | ||||||||||
| /// thrown; the same exception is thrown for empty input data, unknown named | ||||||||||
| /// ranges or binnings, or when the model has no support in the normalization | ||||||||||
| /// range. For higher-dimensional fits, project both the data and the | ||||||||||
| /// model onto the observable of interest: | ||||||||||
| /// ~~~{.cpp} | ||||||||||
| /// std::unique_ptr<RooAbsData> projData{data.reduce(RooArgSet{x})}; | ||||||||||
| /// std::unique_ptr<RooAbsPdf> projModel{model.createProjection(RooArgSet{y})}; | ||||||||||
| /// auto pulls = RooFit::makePullHist(*projModel, *projData); | ||||||||||
| /// ~~~ | ||||||||||
| /// For a residual/pull histogram against one component of a composite pdf, | ||||||||||
| /// pass the component pdf itself, scaled by its coefficient: | ||||||||||
| /// ~~~{.cpp} | ||||||||||
| /// auto& background = static_cast<RooAbsPdf&>(*addPdf.pdfList().find("bkg")); | ||||||||||
| /// auto pulls = RooFit::makePullHist(background, data, | ||||||||||
| /// RooFit::Normalization(bkgFraction.getVal())); | ||||||||||
| /// ~~~ | ||||||||||
| std::unique_ptr<RooHist> | ||||||||||
| makeResidHist(RooAbsReal &fitModel, RooAbsData const &data, RooCmdArg const &arg1 = {}, RooCmdArg const &arg2 = {}, | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that these are new functions, would it make sense to declare the cmdArgs as a variadic template, create a vector or list of these, and pass those on to internal funcs? |
||||||||||
| RooCmdArg const &arg3 = {}, RooCmdArg const &arg4 = {}, RooCmdArg const &arg5 = {}, | ||||||||||
| RooCmdArg const &arg6 = {}, RooCmdArg const &arg7 = {}, RooCmdArg const &arg8 = {}); | ||||||||||
|
|
||||||||||
| /// Like makeResidHist(), but the residuals are divided by the corresponding | ||||||||||
| /// data uncertainty, creating a pull distribution. | ||||||||||
| std::unique_ptr<RooHist> | ||||||||||
| makePullHist(RooAbsReal &fitModel, RooAbsData const &data, RooCmdArg const &arg1 = {}, RooCmdArg const &arg2 = {}, | ||||||||||
| RooCmdArg const &arg3 = {}, RooCmdArg const &arg4 = {}, RooCmdArg const &arg5 = {}, | ||||||||||
| RooCmdArg const &arg6 = {}, RooCmdArg const &arg7 = {}, RooCmdArg const &arg8 = {}); | ||||||||||
|
|
||||||||||
| /** | ||||||||||
| * @} | ||||||||||
| */ | ||||||||||
|
|
||||||||||
| namespace Detail { | ||||||||||
|
|
||||||||||
| // Function to pack an arbitrary number of RooCmdArgs into a RooLinkedList. Implementation detail of many high-level RooFit functions. | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -75,6 +75,11 @@ class RooHist : public TGraphAsymmErrors, public RooPlotable { | |
|
|
||
| bool hasIdenticalBinning(const RooHist& other) const ; | ||
|
|
||
| /// Compute residuals with respect to a curve. | ||
| /// \note For residuals/pulls of binned data against a fitted model, the | ||
| /// more accurate RooFit::makeResidHist() and RooFit::makePullHist() are | ||
| /// the recommended interface: they integrate the model itself exactly over | ||
| /// each bin, instead of interpolating the curve. | ||
| RooHist* makeResidHist(const RooCurve& curve,bool normalize=false, bool useAverage=false) const; | ||
| RooHist* makePullHist(const RooCurve& curve, bool useAverage=false) const | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does the above comment also apply to this func? Consider \copydetail if you don't want to repeat it. |
||
| {return makeResidHist(curve,true,useAverage); } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That it's a weight is an implementation detail. Most users probably think of data as counts.