Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RSampler.cxx
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cmath>
5#include <random>
6#include <stdexcept>
7#include <utility>
8
10
12
13RSampler::~RSampler() = default;
14
15RSampler::RSampler(std::vector<RFlat2DMatrix> &datasets, const std::string &sampleType, float sampleRatio,
16 bool replacement, bool shuffle, std::size_t setSeed)
17 : fDatasets(datasets),
18 fSampleType(sampleType),
19 fSampleRatio(sampleRatio),
20 fReplacement(replacement),
21 fShuffle(shuffle),
22 fSetSeed(setSeed)
23{
24 fTensorOperators = std::make_unique<RFlat2DMatrixOperators>(fShuffle, fSetSeed);
25
26 // setup the sampler for the datasets
28}
29
30//////////////////////////////////////////////////////////////////////////
31/// \brief Calculate fNumEntries and major/minor variables
33{
34 if (fSampleType == "undersampling") {
36 } else if (fSampleType == "oversampling") {
38 }
39}
40
41//////////////////////////////////////////////////////////////////////////
42/// \brief Collection of sampling types
43/// \param[in] SampledTensor Tensor with all the sampled entries
44void RSampler::Sampler(RFlat2DMatrix &SampledTensor)
45{
46 if (fSampleType == "undersampling") {
47 RandomUndersampler(SampledTensor);
48 } else if (fSampleType == "oversampling") {
49 RandomOversampler(SampledTensor);
50 }
51}
52
53//////////////////////////////////////////////////////////////////////////
54/// \brief Calculate fNumEntries and major/minor variables for the random undersampler
56{
57 if (fDatasets[0].GetRows() > fDatasets[1].GetRows()) {
58 fMajor = 0;
59 fMinor = 1;
60 } else {
61 fMajor = 1;
62 fMinor = 0;
63 }
64
65 fNumMajor = fDatasets[fMajor].GetRows();
66 fNumMinor = fDatasets[fMinor].GetRows();
67 fNumResampledMajor = static_cast<std::size_t>(fNumMinor / fSampleRatio);
69 auto minRatio = std::to_string(std::round(double(fNumMinor) / double(fNumMajor) * 100.0) / 100.0);
70 minRatio.erase(minRatio.find('.') + 3);
71 throw std::invalid_argument(
72 "The sampling_ratio is too low: not enough entries in the majority class to sample from.\n"
73 "Choose sampling_ratio > " +
74 minRatio + " or set replacement to True.");
75 }
77}
78
79//////////////////////////////////////////////////////////////////////////
80/// \brief Calculate fNumEntries and major/minor variables for the random oversampler
82{
83 if (fDatasets[0].GetRows() > fDatasets[1].GetRows()) {
84 fMajor = 0;
85 fMinor = 1;
86 } else {
87 fMajor = 1;
88 fMinor = 0;
89 }
90
91 fNumMajor = fDatasets[fMajor].GetRows();
92 fNumMinor = fDatasets[fMinor].GetRows();
93 fNumResampledMinor = static_cast<std::size_t>(fSampleRatio * fNumMajor);
95}
96
97//////////////////////////////////////////////////////////////////////////
98/// \brief Undersample entries randomly from the majority dataset
99/// \param[in] SampledTensor Tensor with all the sampled entries
101{
102 if (fReplacement) {
104 }
105
106 else {
108 }
109
110 std::size_t cols = fDatasets[0].GetCols();
111 RFlat2DMatrix SampledTensor(fNumEntries, cols);
112 RFlat2DMatrix UndersampledMajorTensor(fNumResampledMajor, cols);
113
114 std::size_t index = 0;
115 for (std::size_t i = 0; i < fNumResampledMajor; i++) {
116 std::copy(fDatasets[fMajor].GetData() + fSamples[i] * cols,
117 fDatasets[fMajor].GetData() + (fSamples[i] + 1) * cols,
118 UndersampledMajorTensor.GetData() + index * cols);
119 index++;
120 }
121
122 fTensorOperators->ConcatenateTensors(SampledTensor, {UndersampledMajorTensor, fDatasets[fMinor]});
123 if (fShuffle) {
124 fTensorOperators->ShuffleTensor(ShuffledTensor, SampledTensor);
125 } else {
126 ShuffledTensor = std::move(SampledTensor);
127 }
128}
129
130//////////////////////////////////////////////////////////////////////////
131/// \brief Oversample entries randomly from the minority dataset
132/// \param[in] SampledTensor Tensor with all the sampled entries
134{
136
137 std::size_t cols = fDatasets[0].GetCols();
138 RFlat2DMatrix SampledTensor(fNumEntries, cols);
139 RFlat2DMatrix OversampledMinorTensor(fNumResampledMinor, cols);
140
141 std::size_t index = 0;
142 for (std::size_t i = 0; i < fNumResampledMinor; i++) {
143 std::copy(fDatasets[fMinor].GetData() + fSamples[i] * cols,
144 fDatasets[fMinor].GetData() + (fSamples[i] + 1) * cols,
145 OversampledMinorTensor.GetData() + index * cols);
146 index++;
147 }
148
149 fTensorOperators->ConcatenateTensors(SampledTensor, {OversampledMinorTensor, fDatasets[fMajor]});
150 if (fShuffle) {
151 fTensorOperators->ShuffleTensor(ShuffledTensor, SampledTensor);
152 } else {
153 ShuffledTensor = std::move(SampledTensor);
154 }
155}
156
157//////////////////////////////////////////////////////////////////////////
158/// \brief Add indices with replacement to fSamples
159/// \param[in] n_samples Number of indices to sample
160/// \param[in] max Max index of the sample distribution
161void RSampler::SampleWithReplacement(std::size_t n_samples, std::size_t max)
162{
163 std::uniform_int_distribution<> dist(0, max - 1);
164 fSamples.clear();
165 fSamples.reserve(n_samples);
166 for (std::size_t i = 0; i < n_samples; ++i) {
167 std::size_t sample;
168 if (fShuffle) {
169 std::random_device rd;
170 std::mt19937 g;
171
172 if (fSetSeed == 0) {
173 g.seed(rd());
174 } else {
175 g.seed(fSetSeed);
176 }
177
178 sample = dist(g);
179 }
180
181 else {
182 sample = i % max;
183 }
184 fSamples.push_back(sample);
185 }
186}
187
188//////////////////////////////////////////////////////////////////////////
189/// \brief Add indices without replacement to fSamples
190/// \param[in] n_samples Number of indices to sample
191/// \param[in] max Max index of the sample distribution
192void RSampler::SampleWithoutReplacement(std::size_t n_samples, std::size_t max)
193{
194 std::vector<std::size_t> UniqueSamples;
195 UniqueSamples.reserve(max);
196 fSamples.clear();
197 fSamples.reserve(n_samples);
198
199 for (std::size_t i = 0; i < max; ++i)
200 UniqueSamples.push_back(i);
201
202 if (fShuffle) {
203 std::random_device rd;
204 std::mt19937 g;
205
206 if (fSetSeed == 0) {
207 g.seed(rd());
208 } else {
209 g.seed(fSetSeed);
210 }
211 std::shuffle(UniqueSamples.begin(), UniqueSamples.end(), g);
212 }
213
214 for (std::size_t i = 0; i < n_samples; ++i) {
215 fSamples.push_back(UniqueSamples[i]);
216 }
217}
218
219} // namespace ROOT::Experimental::Internal::ML
#define g(i)
Definition RSha256.hxx:105
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t index
void SampleWithoutReplacement(std::size_t n_samples, std::size_t max)
Add indices without replacement to fSamples.
Definition RSampler.cxx:192
void SetupRandomUndersampler()
Calculate fNumEntries and major/minor variables for the random undersampler.
Definition RSampler.cxx:55
void RandomOversampler(RFlat2DMatrix &ShuffledTensor)
Oversample entries randomly from the minority dataset.
Definition RSampler.cxx:133
void SampleWithReplacement(std::size_t n_samples, std::size_t max)
Add indices with replacement to fSamples.
Definition RSampler.cxx:161
void SetupRandomOversampler()
Calculate fNumEntries and major/minor variables for the random oversampler.
Definition RSampler.cxx:81
void SetupSampler()
Calculate fNumEntries and major/minor variables.
Definition RSampler.cxx:32
std::vector< std::size_t > fSamples
Definition RSampler.hxx:49
std::unique_ptr< RFlat2DMatrixOperators > fTensorOperators
Definition RSampler.hxx:51
RSampler(std::vector< RFlat2DMatrix > &datasets, const std::string &sampleType, float sampleRatio, bool replacement=false, bool shuffle=true, std::size_t setSeed=0)
Definition RSampler.cxx:15
void RandomUndersampler(RFlat2DMatrix &ShuffledTensor)
Undersample entries randomly from the majority dataset.
Definition RSampler.cxx:100
std::vector< RFlat2DMatrix > & fDatasets
Definition RSampler.hxx:34
void Sampler(RFlat2DMatrix &SampledTensor)
Collection of sampling types.
Definition RSampler.cxx:44
Wrapper around ROOT::RVec<float> representing a 2D matrix.