Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RSampler.cxx
Go to the documentation of this file.
1#include "RSampler.hxx"
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(const RFlat2DMatrix &dataset, std::vector<std::vector<std::size_t>> &rows,
16 const std::string &sampleType, float sampleRatio, bool replacement, bool shuffle,
17 std::size_t setSeed)
18 : fDataset(dataset),
19 fRows(rows),
20 fSampleType(sampleType),
21 fSampleRatio(sampleRatio),
22 fReplacement(replacement),
23 fShuffle(shuffle),
24 fSetSeed(setSeed)
25{
26 fTensorOperators = std::make_unique<RFlat2DMatrixOperators>(fShuffle, fSetSeed);
27
28 // setup the sampler for the datasets
30}
31
32//////////////////////////////////////////////////////////////////////////
33/// \brief Calculate fNumEntries and major/minor variables
35{
36 if (fSampleType == "undersampling") {
38 } else if (fSampleType == "oversampling") {
40 }
41}
42
43//////////////////////////////////////////////////////////////////////////
44/// \brief Collection of sampling types
45/// \param[in] SampledTensor Tensor with all the sampled entries
46void RSampler::Sampler(RFlat2DMatrix &SampledTensor)
47{
48 if (fSampleType == "undersampling") {
49 RandomUndersampler(SampledTensor);
50 } else if (fSampleType == "oversampling") {
51 RandomOversampler(SampledTensor);
52 }
53}
54
55//////////////////////////////////////////////////////////////////////////
56/// \brief Calculate fNumEntries and major/minor variables for the random undersampler
58{
59 if (fRows[0].size() > fRows[1].size()) {
60 fMajor = 0;
61 fMinor = 1;
62 } else {
63 fMajor = 1;
64 fMinor = 0;
65 }
66
67 fNumMajor = fRows[fMajor].size();
68 fNumMinor = fRows[fMinor].size();
69 fNumResampledMajor = static_cast<std::size_t>(fNumMinor / fSampleRatio);
71 auto minRatio = std::to_string(std::round(double(fNumMinor) / double(fNumMajor) * 100.0) / 100.0);
72 minRatio.erase(minRatio.find('.') + 3);
73 throw std::invalid_argument(
74 "The sampling_ratio is too low: not enough entries in the majority class to sample from.\n"
75 "Choose sampling_ratio > " +
76 minRatio + " or set replacement to True.");
77 }
79}
80
81//////////////////////////////////////////////////////////////////////////
82/// \brief Calculate fNumEntries and major/minor variables for the random oversampler
84{
85 if (fRows[0].size() > fRows[1].size()) {
86 fMajor = 0;
87 fMinor = 1;
88 } else {
89 fMajor = 1;
90 fMinor = 0;
91 }
92
93 fNumMajor = fRows[fMajor].size();
94 fNumMinor = fRows[fMinor].size();
95 fNumResampledMinor = static_cast<std::size_t>(fSampleRatio * fNumMajor);
97}
98
99//////////////////////////////////////////////////////////////////////////
100/// \brief Undersample entries randomly from the majority dataset
101/// \param[in] SampledTensor Tensor with all the sampled entries
114
115//////////////////////////////////////////////////////////////////////////
116/// \brief Oversample entries randomly from the minority dataset
117/// \param[in] SampledTensor Tensor with all the sampled entries
124
125//////////////////////////////////////////////////////////////////////////
126/// \brief Fill the sampled entries: the resampled entries followed by all the other ones, in shuffled order
127/// \param[in] ShuffledTensor Tensor with all the sampled entries
128/// \param[in] ResampledRows Rows of the class the entries in fSamples are taken from
129/// \param[in] numResampled Number of resampled entries
130/// \param[in] OtherRows Rows of the class whose entries are all taken
131void RSampler::GatherSamples(RFlat2DMatrix &ShuffledTensor, const std::vector<std::size_t> &ResampledRows,
132 std::size_t numResampled, const std::vector<std::size_t> &OtherRows)
133{
134 std::size_t cols = fDataset.GetCols();
135 const auto permutation = fTensorOperators->MakePermutation(fNumEntries);
136
137 // read the entries straight from the datasets, instead of concatenating and shuffling copies of them
138 ShuffledTensor.Resize(fNumEntries, cols);
139 float *out = ShuffledTensor.GetData();
140 for (std::size_t i = 0; i < fNumEntries; i++) {
141 const std::size_t entry = permutation.empty() ? i : permutation[i];
142 const std::size_t row = entry < numResampled ? ResampledRows[fSamples[entry]] : OtherRows[entry - numResampled];
143 out = std::copy_n(fDataset.GetData() + row * cols, cols, out);
144 }
145}
146
147//////////////////////////////////////////////////////////////////////////
148/// \brief Add indices with replacement to fSamples
149/// \param[in] n_samples Number of indices to sample
150/// \param[in] max Max index of the sample distribution
151void RSampler::SampleWithReplacement(std::size_t n_samples, std::size_t max)
152{
153 std::uniform_int_distribution<> dist(0, max - 1);
154 // a single generator for all the samples: seeding one per sample was slow, and with a fixed seed it drew the same
155 // sample every time
156 std::random_device rd;
157 std::mt19937 g;
158
159 if (fSetSeed == 0) {
160 g.seed(rd());
161 } else {
162 g.seed(fSetSeed);
163 }
164
165 fSamples.clear();
166 fSamples.reserve(n_samples);
167 for (std::size_t i = 0; i < n_samples; ++i) {
168 std::size_t sample;
169 if (fShuffle) {
170 sample = dist(g);
171 }
172
173 else {
174 sample = i % max;
175 }
176 fSamples.push_back(sample);
177 }
178}
179
180//////////////////////////////////////////////////////////////////////////
181/// \brief Add indices without replacement to fSamples
182/// \param[in] n_samples Number of indices to sample
183/// \param[in] max Max index of the sample distribution
184void RSampler::SampleWithoutReplacement(std::size_t n_samples, std::size_t max)
185{
186 std::vector<std::size_t> UniqueSamples;
187 UniqueSamples.reserve(max);
188 fSamples.clear();
189 fSamples.reserve(n_samples);
190
191 for (std::size_t i = 0; i < max; ++i)
192 UniqueSamples.push_back(i);
193
194 if (fShuffle) {
195 std::random_device rd;
196 std::mt19937 g;
197
198 if (fSetSeed == 0) {
199 g.seed(rd());
200 } else {
201 g.seed(fSetSeed);
202 }
203 std::shuffle(UniqueSamples.begin(), UniqueSamples.end(), g);
204 }
205
206 for (std::size_t i = 0; i < n_samples; ++i) {
207 fSamples.push_back(UniqueSamples[i]);
208 }
209}
210
211} // namespace ROOT::Experimental::Internal::ML
#define g(i)
Definition RSha256.hxx:105
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
void SampleWithoutReplacement(std::size_t n_samples, std::size_t max)
Add indices without replacement to fSamples.
Definition RSampler.cxx:184
void SetupRandomUndersampler()
Calculate fNumEntries and major/minor variables for the random undersampler.
Definition RSampler.cxx:57
void GatherSamples(RFlat2DMatrix &ShuffledTensor, const std::vector< std::size_t > &ResampledRows, std::size_t numResampled, const std::vector< std::size_t > &OtherRows)
Fill the sampled entries: the resampled entries followed by all the other ones, in shuffled order.
Definition RSampler.cxx:131
void RandomOversampler(RFlat2DMatrix &ShuffledTensor)
Oversample entries randomly from the minority dataset.
Definition RSampler.cxx:118
std::vector< std::vector< std::size_t > > & fRows
Definition RSampler.hxx:36
void SampleWithReplacement(std::size_t n_samples, std::size_t max)
Add indices with replacement to fSamples.
Definition RSampler.cxx:151
void SetupRandomOversampler()
Calculate fNumEntries and major/minor variables for the random oversampler.
Definition RSampler.cxx:83
void SetupSampler()
Calculate fNumEntries and major/minor variables.
Definition RSampler.cxx:34
std::vector< std::size_t > fSamples
Definition RSampler.hxx:51
std::unique_ptr< RFlat2DMatrixOperators > fTensorOperators
Definition RSampler.hxx:53
void RandomUndersampler(RFlat2DMatrix &ShuffledTensor)
Undersample entries randomly from the majority dataset.
Definition RSampler.cxx:102
RSampler(const RFlat2DMatrix &dataset, std::vector< std::vector< std::size_t > > &rows, const std::string &sampleType, float sampleRatio, bool replacement=false, bool shuffle=true, std::size_t setSeed=0)
Definition RSampler.cxx:15
void Sampler(RFlat2DMatrix &SampledTensor)
Collection of sampling types.
Definition RSampler.cxx:46
Wrapper around ROOT::RVec<float> representing a 2D matrix.
void Resize(std::size_t rows, std::size_t cols)