43 auto tupleSort = [](std::tuple<Float_t, Float_t, Bool_t> _a, std::tuple<Float_t, Float_t, Bool_t> _b) {
44 return std::get<0>(_a) < std::get<0>(_b);
48 TMVA::ROCCurve::ROCCurve(
const std::vector<std::tuple<Float_t, Float_t, Bool_t>> &mvas)
49 : fLogger(new TMVA::MsgLogger(
"ROCCurve")), fGraph(NULL), fMva(mvas)
56 TMVA::ROCCurve::ROCCurve(
const std::vector<Float_t> &mvaValues,
const std::vector<Bool_t> &mvaTargets,
57 const std::vector<Float_t> &mvaWeights)
58 : fLogger(new TMVA::MsgLogger(
"ROCCurve")), fGraph(NULL)
60 assert(mvaValues.size() == mvaTargets.size());
61 assert(mvaValues.size() == mvaWeights.size());
63 for (UInt_t i = 0; i < mvaValues.size(); i++) {
64 fMva.emplace_back(mvaValues[i], mvaWeights[i], mvaTargets[i]);
67 std::sort(fMva.begin(), fMva.end(), tupleSort);
73 TMVA::ROCCurve::ROCCurve(
const std::vector<Float_t> &mvaValues,
const std::vector<Bool_t> &mvaTargets)
74 : fLogger(new TMVA::MsgLogger(
"ROCCurve")), fGraph(NULL)
76 assert(mvaValues.size() == mvaTargets.size());
78 for (UInt_t i = 0; i < mvaValues.size(); i++) {
79 fMva.emplace_back(mvaValues[i], 1, mvaTargets[i]);
82 std::sort(fMva.begin(), fMva.end(), tupleSort);
88 TMVA::ROCCurve::ROCCurve(
const std::vector<Float_t> &mvaSignal,
const std::vector<Float_t> &mvaBackground)
89 : fLogger(new TMVA::MsgLogger(
"ROCCurve")), fGraph(NULL)
91 for (UInt_t i = 0; i < mvaSignal.size(); i++) {
92 fMva.emplace_back(mvaSignal[i], 1, kTRUE);
95 for (UInt_t i = 0; i < mvaBackground.size(); i++) {
96 fMva.emplace_back(mvaBackground[i], 1, kFALSE);
99 std::sort(fMva.begin(), fMva.end(), tupleSort);
105 TMVA::ROCCurve::ROCCurve(
const std::vector<Float_t> &mvaSignal,
const std::vector<Float_t> &mvaBackground,
106 const std::vector<Float_t> &mvaSignalWeights,
const std::vector<Float_t> &mvaBackgroundWeights)
107 : fLogger(new TMVA::MsgLogger(
"ROCCurve")), fGraph(NULL)
109 assert(mvaSignal.size() == mvaSignalWeights.size());
110 assert(mvaBackground.size() == mvaBackgroundWeights.size());
112 for (UInt_t i = 0; i < mvaSignal.size(); i++) {
113 fMva.emplace_back(mvaSignal[i], mvaSignalWeights[i], kTRUE);
116 for (UInt_t i = 0; i < mvaBackground.size(); i++) {
117 fMva.emplace_back(mvaBackground[i], mvaBackgroundWeights[i], kFALSE);
120 std::sort(fMva.begin(), fMva.end(), tupleSort);
126 TMVA::ROCCurve::~ROCCurve() {
128 if(fGraph)
delete fGraph;
131 TMVA::MsgLogger &TMVA::ROCCurve::Log()
const
134 fLogger =
new TMVA::MsgLogger(
"ROCCurve");
141 std::vector<Double_t> TMVA::ROCCurve::ComputeSpecificity(
const UInt_t num_points)
143 if (num_points <= 2) {
147 std::vector<Double_t> specificity_vector;
148 std::vector<Double_t> true_negatives;
149 specificity_vector.reserve(fMva.size());
150 true_negatives.reserve(fMva.size());
152 Double_t true_negatives_sum = 0.0;
153 for (
auto &ev : fMva) {
155 auto weight = std::get<1>(ev);
156 auto isSignal = std::get<2>(ev);
158 true_negatives_sum += weight * (!isSignal);
159 true_negatives.push_back(true_negatives_sum);
162 specificity_vector.push_back(0.0);
163 Double_t total_background = true_negatives_sum;
164 for (
auto &tn : true_negatives) {
165 Double_t specificity =
166 (total_background <= std::numeric_limits<Double_t>::min()) ? (0.0) : (tn / total_background);
167 specificity_vector.push_back(specificity);
169 specificity_vector.push_back(1.0);
171 return specificity_vector;
177 std::vector<Double_t> TMVA::ROCCurve::ComputeSensitivity(
const UInt_t num_points)
179 if (num_points <= 2) {
183 std::vector<Double_t> sensitivity_vector;
184 std::vector<Double_t> true_positives;
185 sensitivity_vector.reserve(fMva.size());
186 true_positives.reserve(fMva.size());
188 Double_t true_positives_sum = 0.0;
189 for (
auto it = fMva.rbegin(); it != fMva.rend(); ++it) {
191 auto weight = std::get<1>(*it);
192 auto isSignal = std::get<2>(*it);
194 true_positives_sum += weight * (isSignal);
195 true_positives.push_back(true_positives_sum);
197 std::reverse(true_positives.begin(), true_positives.end());
199 sensitivity_vector.push_back(1.0);
200 Double_t total_signal = true_positives_sum;
201 for (
auto &tp : true_positives) {
202 Double_t sensitivity = (total_signal <= std::numeric_limits<Double_t>::min()) ? (0.0) : (tp / total_signal);
203 sensitivity_vector.push_back(sensitivity);
205 sensitivity_vector.push_back(0.0);
207 return sensitivity_vector;
220 Double_t TMVA::ROCCurve::GetEffSForEffB(Double_t effB,
const UInt_t num_points)
222 assert(0.0 <= effB && effB <= 1.0);
224 auto effS_vec = ComputeSensitivity(num_points);
225 auto effB_vec = ComputeSpecificity(num_points);
228 auto complement = [](Double_t x) {
return 1 - x; };
229 std::transform(effB_vec.begin(), effB_vec.end(), effB_vec.begin(), complement);
232 std::reverse(effS_vec.begin(), effS_vec.end());
233 std::reverse(effB_vec.begin(), effB_vec.end());
235 TGraph *graph =
new TGraph(effS_vec.size(), &effB_vec[0], &effS_vec[0]);
238 TSpline1 rocSpline = TSpline1(
"", graph);
239 return rocSpline.Eval(effB);
251 Double_t TMVA::ROCCurve::GetROCIntegral(
const UInt_t num_points)
253 auto sensitivity = ComputeSensitivity(num_points);
254 auto specificity = ComputeSpecificity(num_points);
256 Double_t integral = 0.0;
257 for (UInt_t i = 0; i < sensitivity.size() - 1; i++) {
259 Double_t currFnr = 1 - sensitivity[i];
260 Double_t nextFnr = 1 - sensitivity[i + 1];
262 integral += 0.5 * (nextFnr - currFnr) * (specificity[i] + specificity[i + 1]);
277 TGraph *TMVA::ROCCurve::GetROCCurve(
const UInt_t num_points)
279 if (fGraph !=
nullptr) {
283 auto sensitivity = ComputeSensitivity(num_points);
284 auto specificity = ComputeSpecificity(num_points);
286 fGraph =
new TGraph(sensitivity.size(), &sensitivity[0], &specificity[0]);