ra4_stats  0341147a0dc35f80f4e12c6003afb76a38e2ed6e
one_bin_test_statistic.py
Go to the documentation of this file.
1 #! /usr/bin/env python
2 
3 import argparse
4 import math
5 import numpy
6 import ROOT
7 ROOT.gROOT.SetBatch(True)
8 
9 def LogPoissonLike(N, mu):
10  return numpy.nan_to_num(numpy.subtract(numpy.multiply(N, numpy.log(mu)), mu))
11 
12 def GetQs(mu, s, b, obs):
13  muhat_uncapped = numpy.divide(numpy.subtract(obs,b), s)
14  muhat_low_cap = numpy.maximum(muhat_uncapped, 0.)
15  muhat_high_cap = numpy.minimum(muhat_uncapped, mu)
16  muhat_capped = numpy.maximum(muhat_high_cap, 0.)
17  top = LogPoissonLike(obs, b+s*mu)
18  bot_standard = LogPoissonLike(obs, b)
19  bot_uncapped = LogPoissonLike(obs, obs)
20  bot_low_cap = LogPoissonLike(obs, numpy.add(b, numpy.multiply(s, muhat_low_cap)))
21  bot_high_cap = LogPoissonLike(obs, numpy.add(b, numpy.multiply(s, muhat_high_cap)))
22  bot_capped = LogPoissonLike(obs, numpy.add(b, numpy.multiply(s, muhat_capped)))
23  return (obs,
24  numpy.multiply(-2., numpy.subtract(top, bot_standard)),
25  numpy.multiply(-2., numpy.subtract(top, bot_uncapped)),
26  numpy.multiply(-2., numpy.subtract(top, bot_low_cap)),
27  numpy.multiply(-2., numpy.subtract(top, bot_high_cap)),
28  numpy.multiply(-2., numpy.subtract(top, bot_capped)))
29 
30 def Style(h, color, style):
31  h.SetLineColor(color)
32  h.SetLineStyle(style)
33  h.SetLineWidth(4)
34 
35 def GetName(i):
36  if i == 0: return "raw_num"
37  elif i == 1: return "standard"
38  elif i == 2: return "no_cap"
39  elif i == 3: return "low_cap"
40  elif i == 4: return "high_cap"
41  elif i == 5: return "both_capped"
42  else: return "UNKNOWN"
43 
44 def GetXmax(i, background, signal):
45  if i == 0:
46  r = background + signal
47  return math.ceil(r+5.*math.sqrt(r))
48  else:
49  return 2*ROOT.RooStats.NumberCountingUtils.BinomialWithTauExpZ(signal, background, 10000.)**2 + 4
50 
51 def GetXmin(i, background, signal):
52  if i == 0: return max(0., math.floor(background-5.*math.sqrt(background)))
53  elif i == 1: return -GetXmax(i, background, signal)
54  else: return 0.
55 
56 def PlotQ(i, q_0_bonly, q_0_splusb, q_1_bonly, q_1_splusb, background, signal):
57  nbins = 100
58  xmax = GetXmax(i, background, signal)
59  xmin = GetXmin(i, background, signal)
60  h_0_bonly = ROOT.TH1D("q_0_bonly", ";q;Toys", nbins, xmin, xmax)
61  h_0_splusb = ROOT.TH1D("q_0_splusb", ";q;Toys", nbins, xmin, xmax)
62  h_1_bonly = ROOT.TH1D("q_1_bonly", ";q;Toys", nbins, xmin, xmax)
63  h_1_splusb = ROOT.TH1D("q_1_splusb", ";q;Toys", nbins, xmin, xmax)
64 
65  for q in q_0_bonly: h_0_bonly.Fill(q)
66  for q in q_0_splusb: h_0_splusb.Fill(q)
67  for q in q_1_bonly: h_1_bonly.Fill(q)
68  for q in q_1_splusb: h_1_splusb.Fill(q)
69 
70  Style(h_0_bonly, ROOT.kBlack, 1)
71  Style(h_0_splusb, ROOT.kBlack, 2)
72  Style(h_1_bonly, ROOT.kRed, 1)
73  Style(h_1_splusb, ROOT.kRed, 2)
74 
75  h_dumb = ROOT.TH1D("q", ";q;Toys", 1, xmin, xmax)
76  h_dumb.SetMinimum(1.)
77  h_dumb.SetMaximum(len(q_0_bonly))
78  h_dumb.SetStats(False)
79  h_dumb.GetYaxis().SetTitleOffset(1.25)
80 
81  l = ROOT.TLegend(0.1, 0.915, 0.9, 0.995)
82  l.SetNColumns(4)
83  l.SetBorderSize(0)
84  l.AddEntry(h_0_bonly, "q_{0}^{B}", "l")
85  l.AddEntry(h_0_splusb, "q_{0}^{S+B}", "l")
86  l.AddEntry(h_1_bonly, "q_{1}^{B}", "l")
87  l.AddEntry(h_1_splusb, "q_{1}^{S+B}", "l")
88 
89  c = ROOT.TCanvas()
90  c.SetMargin(0.1, 0.05, 0.1, 0.1)
91  c.SetLogy()
92  h_dumb.Draw("hist")
93  h_0_bonly.Draw("hist same")
94  h_1_bonly.Draw("hist same")
95  h_0_splusb.Draw("hist same")
96  h_1_splusb.Draw("hist same")
97  l.Draw()
98 
99  c.Print("plots/one_bin_test_stat_q_"+GetName(i)+"_b_"+str(background)+"_s_"+str(signal)+"_toys_"+str(len(q_0_bonly))+".pdf")
100 
101 def PlotQVsN(i, n, q_0, q_1, background, signal):
102  h_0 = ROOT.TH1D("", ";N_{obs};q(N_{obs})", len(n)-1, n)
103  h_1 = ROOT.TH1D("", ";N_{obs};q(N_{obs})", len(n)-1, n)
104  for bin in range(1, len(n)+1):
105  h_0.SetBinContent(bin, q_0[bin-1])
106  h_1.SetBinContent(bin, q_1[bin-1])
107  h_0.SetBinError(bin, 0.)
108  h_1.SetBinError(bin, 0.)
109 
110  Style(h_0, ROOT.kBlack, 1)
111  Style(h_1, ROOT.kRed, 1)
112  h_0.SetStats(False)
113  h_1.SetStats(False)
114 
115  q_min = min(h_0.GetBinContent(h_0.GetMinimumBin()),
116  h_1.GetBinContent(h_1.GetMinimumBin()))
117  q_max = max(h_0.GetBinContent(h_0.GetMaximumBin()),
118  h_1.GetBinContent(h_1.GetMaximumBin()))
119  h_0.SetMinimum(q_min)
120  h_0.SetMaximum(q_max)
121  h_1.SetMinimum(q_min)
122  h_1.SetMaximum(q_max)
123 
124  c = ROOT.TCanvas()
125 
126  h_0.Draw("hist l")
127  h_1.Draw("hist l same")
128 
129  l = ROOT.TLegend(0.1, 0.915, 0.9, 0.995)
130  l.SetNColumns(2)
131  l.SetBorderSize(0)
132  l.AddEntry(h_0, "q_{0}", "l")
133  l.AddEntry(h_1, "q_{1}", "l")
134  l.Draw("same")
135 
136  c.Print("plots/one_bin_test_stat_q_vs_n_"+GetName(i)+"_b_"+str(background)+"_s_"+str(signal)+".pdf")
137 
138 def ScanSigStrength(i, mu, q_bonly, q_splusb, background, signal):
139  nbins = 100
140  xmax = GetXmax(i, background, signal)
141  xmin = GetXmin(i, background, signal)
142  h_bonly = ROOT.TH1D("", ";q_{"+str(mu)+"};Toys", nbins, xmin, xmax)
143  h_splusb = ROOT.TH1D("", ";q_{"+str(mu)+"};Toys", nbins, xmin, xmax)
144 
145  for q in q_bonly: h_bonly.Fill(q)
146  for q in q_splusb: h_splusb.Fill(q)
147 
148  Style(h_bonly, ROOT.kBlack, 1)
149  Style(h_splusb, ROOT.kBlack, 2)
150 
151  h_dumb = ROOT.TH1D("", ";q_{"+str(mu)+"};Toys", 1, xmin, xmax)
152  h_dumb.SetMinimum(1.)
153  h_dumb.SetMaximum(len(q_bonly))
154  h_dumb.SetStats(False)
155  h_dumb.GetYaxis().SetTitleOffset(1.25)
156  h_dumb.SetFillStyle(0)
157  h_dumb.SetFillColor(0)
158  h_dumb.SetLineStyle(0)
159  h_dumb.SetLineColor(0)
160  h_dumb.SetLineWidth(0)
161  h_dumb.SetMarkerStyle(0)
162  h_dumb.SetMarkerColor(0)
163  h_dumb.SetMarkerSize(0)
164 
165  q_example = GetQs(mu, signal, background, background)[i]
166  clb = numpy.mean(numpy.greater_equal(q_bonly, q_example))
167  clsb = numpy.mean(numpy.greater_equal(q_splusb, q_example))
168  if i == 0 or i == 1:
169  clb = numpy.mean(numpy.less_equal(q_bonly, q_example))
170  clsb = numpy.mean(numpy.less_equal(q_splusb, q_example))
171  cls = clsb/clb
172 
173  line = ROOT.TLine(q_example, 1., q_example, len(q_bonly))
174  line.SetLineColor(ROOT.kGreen)
175  line.SetLineStyle(1)
176  line.SetLineWidth(4)
177 
178  c = ROOT.TCanvas()
179  c.SetMargin(0.1, 0.05, 0.1, 0.2)
180  c.SetLogy()
181 
182  h_dumb.Draw("hist")
183  h_bonly.Draw("hist same")
184  h_splusb.Draw("hist same")
185  line.Draw("same")
186 
187  l = ROOT.TLegend(0.1, 0.83, 0.9, 0.995)
188  l.SetNColumns(2)
189  l.SetBorderSize(0)
190  l.SetTextSize(0.05)
191  l.AddEntry(h_dumb, "r="+str(round(mu,3)), "l")
192  if i!=0:
193  l.AddEntry(h_splusb, "q_{"+str(round(mu,3))+"}^{rS+B} (CL_{S+B}="+str(round(clsb,3))+")", "l")
194  else:
195  l.AddEntry(h_splusb, "N^{rS+B} (CL_{S+B}="+str(round(clsb,3))+")", "l")
196  l.AddEntry(h_dumb, "CL_{S}="+str(round(cls,3)), "l")
197  if i!=0:
198  l.AddEntry(h_bonly, "q_{"+str(round(mu,3))+"}^{B} (CL_{B}="+str(round(clb,3))+")", "l")
199  else:
200  l.AddEntry(h_bonly, "N^{B} (CL_{B}="+str(round(clb,3))+")", "l")
201  l.Draw()
202 
203  c.Print("plots/one_bin_test_stat_cls_scan_"+GetName(i)+"_mu_"+str(mu)+"_b_"+str(background)+"_s_"+str(signal)+"_toys_"+str(len(q_bonly))+".pdf")
204 
205 def OneBinTestStatistic(background, signal, num_toys):
206  backgrounds = numpy.random.poisson(background, num_toys)
207  splusb = numpy.random.poisson(signal+background, num_toys)
208 
209  q_0_bonly = GetQs(0., signal, background, backgrounds)
210  q_0_splusb = GetQs(0., signal, background, splusb)
211  q_1_bonly = GetQs(1., signal, background, backgrounds)
212  q_1_splusb = GetQs(1., signal, background, splusb)
213  q_2_bonly = GetQs(2., signal, background, backgrounds)
214  q_2_splusb = GetQs(2., signal, background, splusb)
215  q_3_bonly = GetQs(3., signal, background, backgrounds)
216  q_3_splusb = GetQs(3., signal, background, splusb)
217 
218  nmin = GetXmin(0, background, signal)
219  nmax = GetXmax(0, background, signal)
220  n = numpy.linspace(nmin, nmax, 100)
221 
222  q_0 = GetQs(0., signal, background, n)
223  q_1 = GetQs(1., signal, background, n)
224 
225  for i in range(0, 6):
226  PlotQ(i, q_0_bonly[i], q_0_splusb[i], q_1_bonly[i], q_1_splusb[i], background, signal)
227  PlotQVsN(i, n, q_0[i], q_1[i], background, signal)
228  for mu in [0., 0.25, 0.5, 0.654511, 0.75, 1.]:
229  obs = backgrounds
230  if mu == 1.: obs = splusb
231  elif mu != 0.: obs = numpy.random.poisson(background+mu*signal, num_toys)
232  q_bonly = GetQs(mu, signal, background, backgrounds)
233  q_splusb = GetQs(mu, signal, background, obs)
234  for i in range(0, 6):
235  ScanSigStrength(i, mu, q_bonly[i], q_splusb[i], background, signal)
236 
237 if __name__ == "__main__":
238  parser = argparse.ArgumentParser(description="Plots distributions of test statistics for a single bin counting experiment",
239  formatter_class=argparse.ArgumentDefaultsHelpFormatter)
240  parser.add_argument("background", type=float, help="True background rate")
241  parser.add_argument("signal", type=float, help="True signal rate")
242  parser.add_argument("--num_toys", type=int, default=100000, help="Number of toys to throw when plotting distributions.")
243  args = parser.parse_args()
244 
245  OneBinTestStatistic(args.background, args.signal, args.num_toys)
def OneBinTestStatistic(background, signal, num_toys)
def ScanSigStrength(i, mu, q_bonly, q_splusb, background, signal)
def PlotQ(i, q_0_bonly, q_0_splusb, q_1_bonly, q_1_splusb, background, signal)
def Style(h, color, style)
def GetXmin(i, background, signal)
def GetXmax(i, background, signal)
def PlotQVsN(i, n, q_0, q_1, background, signal)