CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_3_9_patch3/src/HiggsAnalysis/CombinedLimit/src/JacknifeQuantile.cc

Go to the documentation of this file.
00001 #include "../interface/JacknifeQuantile.h"
00002 #include <cmath>
00003 #include <stdexcept>
00004 #include <iostream>
00005 #include <algorithm>
00006 #include <Math/QuantFuncMathMore.h>
00007 #include <RooAbsData.h>
00008 #include <RooRealVar.h>
00009 
00010 QuantileCalculator::QuantileCalculator()
00011 {
00012 }
00013 
00014 QuantileCalculator::~QuantileCalculator()
00015 {
00016 }
00017 
00018 QuantileCalculator::QuantileCalculator(const std::vector<double> &values, const std::vector<double> &weights)
00019 {
00020    import<double>(values, weights); 
00021 }
00022 
00023 QuantileCalculator::QuantileCalculator(const std::vector<float> &values, const std::vector<float> &weights)
00024 {
00025    import<float>(values, weights); 
00026 }
00027 
00028 QuantileCalculator::QuantileCalculator(const RooAbsData &data, const char *varName, int firstEntry, int lastEntry)
00029 {
00030     if (lastEntry == -1) lastEntry = data.numEntries();
00031     const RooArgSet  *set = data.get();
00032     const RooRealVar *x   = dynamic_cast<const RooRealVar *>(set->find(varName)); 
00033     if (x == 0) {
00034      set->Print("V");
00035      throw std::logic_error("Parameter of interest not in the idataset");
00036     }
00037     sumw_.resize(1, 0.0);
00038     if (firstEntry < lastEntry) {
00039         points_.resize(lastEntry - firstEntry);
00040         for (int i = firstEntry, j = 0; i < lastEntry; ++i, ++j) {
00041             data.get(i); 
00042             points_[j].x = x->getVal(); 
00043             points_[j].w = data.weight();
00044             sumw_[0] += points_[j].w;
00045         }
00046     }
00047 }
00048 
00049 void QuantileCalculator::randomizePoints()
00050 {
00051     std::random_shuffle(points_.begin(), points_.end());
00052 }
00053 
00054 std::pair<double,double> QuantileCalculator::quantileAndError(double quantile, Method method) 
00055 {
00056     if (method == Simple) {
00057         std::sort(points_.begin(), points_.end());
00058         quantiles(quantile, false);
00059         return std::pair<double,double>(quantiles_[0], 0);
00060     } else if (method == Sectioning || method == Jacknife) {
00061         int m = guessPartitions(points_.size(), quantile);
00062         partition(m, (method == Jacknife));
00063         std::sort(points_.begin(), points_.end());
00064         quantiles(quantile, (method == Jacknife));
00065         double avg = 0;
00066         for (int i = 0; i < m; ++i) {
00067             avg += quantiles_[i];
00068         }
00069         avg /= m;
00070         double rms = 0;
00071         for (int i = 0; i < m; ++i) {
00072             rms += (quantiles_[i] - avg)*(quantiles_[i] - avg);
00073         }
00074         rms = sqrt(rms/(m*(m-1)));
00075         double onesigma = ROOT::Math::tdistribution_quantile_c(0.16, m-1);
00076         return std::pair<double,double>(avg, rms * onesigma);
00077     }
00078     return std::pair<double,double>(0,-1);
00079 }
00080 
00081 int QuantileCalculator::guessPartitions(int size, double quantile) 
00082 {
00083     // number of events on the small side of the quantile for m=1
00084     double smallnum = size * std::min(quantile, 1-quantile); 
00085     // now the naive idea is that err(q) ~ 1/sqrt(smallnum/m), while the error from averaging does as ~1/sqrt(m)
00086     // so you want m ~ sqrt(smallnum)
00087     int n = 5; //std::min(std::max(3., sqrt(smallnum)), 5.);
00088     std::cout << "   .....  will split the " << size << " events in " << n << " subsets, smallnum is " << smallnum << std::endl;
00089     return n;
00090 }
00091 
00092 template<typename T>
00093 void QuantileCalculator::import(const std::vector<T> &values, const std::vector<T> &weights) 
00094 {
00095     int n = values.size();
00096     points_.resize(values.size());
00097     sumw_.resize(1); sumw_[0] = 0.0;
00098     for (int i = 0; i < n; ++i) {
00099         points_[i].x = values[i];
00100         points_[i].w = weights.empty() ? 1 : weights[i];
00101         points_[i].set = 0;
00102         sumw_[0] += points_[i].w;
00103     }
00104 }
00105 
00106 
00107 void QuantileCalculator::partition(int m, bool doJacknife) 
00108 {
00109     int n = points_.size();
00110     sumw_.resize(m+1);
00111     std::fill(sumw_.begin(), sumw_.end(), 0.0);
00112     double alpha = double(m)/n;
00113     for (int i = 0, j = 0; i < n; ++i) {
00114         j = floor(i*alpha); 
00115         points_[i].set = j;
00116         sumw_[j] += points_[i].w;
00117     }
00118     if (doJacknife) {
00119         // at this point sumw[j] has the weights of j... 
00120         // now I have to get the weights of everyhing else
00121         // start with all weights
00122         for (int j = 0; j < m; ++j) sumw_[m] += sumw_[j];
00123         // and then subtract
00124         for (int j = 0; j < m; ++j) sumw_[j] = (sumw_[m] - sumw_[j]);
00125     }
00126 }
00127 
00128 void QuantileCalculator::quantiles(double quantile, bool doJacknife) 
00129 {
00130     int m = sumw_.size()-1;
00131     int n = points_.size();
00132     quantiles_.resize(m+1);
00133     for (int j = 0; j <= m; ++j) {
00134         double runningSum = 0;
00135         double threshold  = quantile * sumw_[j];
00136         int ilow = 0, ihigh = n-1;
00137         for (int i = 0; i < n; ++i) {
00138             if ((points_[i].set == j) == doJacknife) continue; // if jacknife, cut away just one piece, otherwise cut away everthing else
00139             //std::cout << "\t\t\t" << points_[i].x << std::endl;;
00140             if (runningSum + points_[i].w <= threshold) { 
00141                 runningSum += points_[i].w;
00142                 ilow = i;
00143             } else {
00144                 ihigh = i;
00145                 break;
00146             }
00147         }
00148         if (runningSum == threshold) { // possible if all unit weights
00149             quantiles_[j] = points_[ilow].x;
00150         } else {
00151             quantiles_[j] = 0.5*(points_[ilow].x + points_[ihigh].x);
00152         }
00153     }
00154     for (int j = 0; j <= m; ++j) {  
00155         //printf("   ... quantile of section %d: %6.3f\n", j, quantiles_[j]);
00156     }
00157     if (doJacknife) {
00158         // now compute the pseudo-values alpha_[j] = m * quantile[m] - (m-1) * quantile[j]
00159         for (int j = 0; j < m; ++j) {
00160             quantiles_[j] = m * quantiles_[m] - (m-1) * quantiles_[j];
00161             printf("   ... jacknife quantile of section %d: %6.3f\n", j, quantiles_[j]);
00162         }
00163     }
00164 }