Logo ROOT  
Reference Guide
rf403_weightedevts.py File Reference

Namespaces

namespace  rf403_weightedevts
 

Detailed Description

View in nbviewer Open in SWAN

'DATA AND CATEGORIES' RooFit tutorial macro #403

Using weights in unbinned datasets

from __future__ import print_function
import ROOT
# Create observable and unweighted dataset
# -------------------------------------------
# Declare observable
x = ROOT.RooRealVar("x", "x", -10, 10)
x.setBins(40)
# Construction a uniform pdf
p0 = ROOT.RooPolynomial("px", "px", x)
# Sample 1000 events from pdf
data = p0.generate({x}, 1000)
# Calculate weight and make dataset weighted
# --------------------------------------------------
# Construct formula to calculate (fake) weight for events
wFunc = ROOT.RooFormulaVar("w", "event weight", "(x*x+10)", [x])
# Add column with variable w to previously generated dataset
w = data.addColumn(wFunc)
# Dataset d is now a dataset with two observable (x,w) with 1000 entries
data.Print()
# Instruct dataset wdata in interpret w as event weight rather than as
# observable
wdata = ROOT.RooDataSet(data.GetName(), data.GetTitle(), data, data.get(), "", w.GetName())
# Dataset d is now a dataset with one observable (x) with 1000 entries and
# a sum of weights of ~430K
wdata.Print()
# Unbinned ML fit to weighted data
# ---------------------------------------------------------------
# Construction quadratic polynomial pdf for fitting
a0 = ROOT.RooRealVar("a0", "a0", 1)
a1 = ROOT.RooRealVar("a1", "a1", 0, -1, 1)
a2 = ROOT.RooRealVar("a2", "a2", 1, 0, 10)
p2 = ROOT.RooPolynomial("p2", "p2", x, [a0, a1, a2], 0)
# Fit quadratic polynomial to weighted data
# NOTE: A plain Maximum likelihood fit to weighted data does in general
# NOT result in correct error estimates, individual
# event weights represent Poisson statistics themselves.
#
# Fit with 'wrong' errors
r_ml_wgt = p2.fitTo(wdata, Save=True)
# A first order correction to estimated parameter errors in an
# (unbinned) ML fit can be obtained by calculating the
# covariance matrix as
#
# V' = V C-1 V
#
# where V is the covariance matrix calculated from a fit
# to -logL = - sum [ w_i log f(x_i) ] and C is the covariance
# matrix calculated from -logL' = -sum [ w_i^2 log f(x_i) ]
# (i.e. the weights are applied squared)
#
# A fit in self mode can be performed as follows:
r_ml_wgt_corr = p2.fitTo(wdata, Save=True, SumW2Error=True)
# Plot weighted data and fit result
# ---------------------------------------------------------------
# Construct plot frame
frame = x.frame(ROOT.RooFit.Title("Unbinned ML fit, chi^2 fit to weighted data"))
# Plot data using sum-of-weights-squared error rather than Poisson errors
wdata.plotOn(frame, ROOT.RooFit.DataError(ROOT.RooAbsData.SumW2))
# Overlay result of 2nd order polynomial fit to weighted data
p2.plotOn(frame)
# ML fit of pdf to equivalent unweighted dataset
# ---------------------------------------------------------------------
# Construct a pdf with the same shape as p0 after weighting
genPdf = ROOT.RooGenericPdf("genPdf", "x*x+10", [x])
# Sample a dataset with the same number of events as data
data2 = genPdf.generate({x}, 1000)
# Sample a dataset with the same number of weights as data
data3 = genPdf.generate({x}, 43000)
# Fit the 2nd order polynomial to both unweighted datasets and save the
# results for comparison
r_ml_unw10 = p2.fitTo(data2, Save=True)
r_ml_unw43 = p2.fitTo(data3, Save=True)
# Chis2 fit of pdf to binned weighted dataset
# ---------------------------------------------------------------------------
# Construct binned clone of unbinned weighted dataset
binnedData = wdata.binnedClone()
binnedData.Print("v")
# Perform chi2 fit to binned weighted dataset using sum-of-weights errors
#
# NB: Within the usual approximations of a chi2 fit, chi2 fit to weighted
# data using sum-of-weights-squared errors does give correct error
# estimates
chi2 = ROOT.RooChi2Var("chi2", "chi2", p2, binnedData, ROOT.RooFit.DataError(ROOT.RooAbsData.SumW2))
m = ROOT.RooMinimizer(chi2)
m.migrad()
m.hesse()
# Plot chi^2 fit result on frame as well
r_chi2_wgt = m.save()
p2.plotOn(frame, LineStyle="--", LineColor="r")
# Compare fit results of chi2, L fits to (un)weighted data
# ------------------------------------------------------------
# Note that ML fit on 1Kevt of weighted data is closer to result of ML fit on 43Kevt of unweighted data
# than to 1Kevt of unweighted data, the reference chi^2 fit with SumW2 error gives a result closer to
# that of an unbinned ML fit to 1Kevt of unweighted data.
print("==> ML Fit results on 1K unweighted events")
r_ml_unw10.Print()
print("==> ML Fit results on 43K unweighted events")
r_ml_unw43.Print()
print("==> ML Fit results on 1K weighted events with a summed weight of 43K")
r_ml_wgt.Print()
print("==> Corrected ML Fit results on 1K weighted events with a summed weight of 43K")
r_ml_wgt_corr.Print()
print("==> Chi2 Fit results on 1K weighted events with a summed weight of 43K")
r_chi2_wgt.Print()
c = ROOT.TCanvas("rf403_weightedevts", "rf403_weightedevts", 600, 600)
ROOT.gPad.SetLeftMargin(0.15)
frame.GetYaxis().SetTitleOffset(1.8)
frame.Draw()
c.SaveAs("rf403_weightedevts.png")
Date
February 2018
Author
Clemens Lange

Definition in file rf403_weightedevts.py.