Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
RDatasetLoader.cxx
Go to the documentation of this file.
1#include "RDatasetLoader.hxx"
2
3#include "ROOT/RDFHelpers.hxx"
4
6
7RDatasetLoader::RDatasetLoader(const std::vector<ROOT::RDF::RNode> &rdfs, const float validationSplit,
8 const std::vector<std::string> &cols, const std::vector<std::size_t> &vecSizes,
9 const float vecPadding, bool shuffle, const std::size_t setSeed)
10 : fValidationSplit(validationSplit),
11 fVecSizes(vecSizes),
12 fVecPadding(vecPadding),
13 f_rdfs(rdfs),
14 fCols(cols),
15 fSetSeed(setSeed),
16 fShuffle(shuffle)
17{
18 fTensorOperators = std::make_unique<RFlat2DMatrixOperators>(fShuffle, fSetSeed);
19 fNumCols = fCols.size();
20 fSumVecSizes = std::accumulate(fVecSizes.begin(), fVecSizes.end(), 0);
21
23}
24
25//////////////////////////////////////////////////////////////////////////
26/// \brief Number of entries to reserve for each dataframe
27/// \param[in] rdfs Dataframes to load
28/// \return Number of entries of each dataframe, an upper bound for a filtered dataframe
29std::vector<std::size_t> RDatasetLoader::CountEntries(std::vector<ROOT::RDF::RNode> &rdfs)
30{
31 // size the buffer from the cluster metadata, Count() is only the fallback for sources without it. With filters
32 // this is an upper bound: the memory reserved for the entries that don't pass them is never touched
33 std::vector<std::size_t> NumEntries(rdfs.size(), 0);
34 std::vector<ROOT::RDF::RResultPtr<ULong64_t>> Counts;
35 for (std::size_t i = 0; i < rdfs.size(); i++) {
36 try {
37 for (const auto &cluster : ROOT::Internal::RDF::GetDatasetGlobalClusterBoundaries(rdfs[i])) {
38 NumEntries[i] += cluster.second - cluster.first;
39 }
40 } catch (const std::runtime_error &) {
41 // GetDatasetGlobalClusterBoundaries() throws when the RDataFrame has no cluster
42 // metadata to query (a source other than TTree/RNTuple or no data source at all).
43 // Those paths fall back to Count() below.
44 }
45 if (NumEntries[i] == 0) {
46 Counts.push_back(rdfs[i].Count());
47 }
48 }
49
50 // the dataframes without cluster metadata are counted together
51 if (!Counts.empty()) {
52 ROOT::RDF::RunGraphs({Counts.begin(), Counts.end()});
53 }
54 for (std::size_t i = 0, c = 0; i < rdfs.size(); i++) {
55 if (NumEntries[i] == 0) {
56 NumEntries[i] = static_cast<std::size_t>(*Counts[c++]);
57 }
58 }
59
60 return NumEntries;
61}
62
63//////////////////////////////////////////////////////////////////////////
64/// \brief Load all the entries of an individual dataframe at the end of the dataset
65/// \param[in] rdf Dataframe to load
66/// \param[in] NumEntries Number of entries of the dataframe, an upper bound for a filtered dataframe
67void RDatasetLoader::LoadDataframe(ROOT::RDF::RNode &rdf, std::size_t NumEntries)
68{
69 const bool NotFiltered = rdf.GetFilterNames().empty();
70 const std::size_t firstRow = fDataset.GetRows();
71
72 // a single event loop, the filters only let the passing entries through
74 if (!NotFiltered) {
75 NumEntries = fDataset.GetSize() / fNumDatasetCols - firstRow;
76 }
77 fDataset.Resize(firstRow + NumEntries, fNumDatasetCols);
78}
79
80//////////////////////////////////////////////////////////////////////////
81/// \brief Split the rows of the dataset from \p firstRow on into training and validation rows
82/// \param[in] firstRow First row of the dataframe in the dataset
83/// \param[in] TrainingRows Rows of the training set, appended to
84/// \param[in] ValidationRows Rows of the validation set, appended to
85void RDatasetLoader::SplitRows(std::size_t firstRow, std::vector<std::size_t> &TrainingRows,
86 std::vector<std::size_t> &ValidationRows)
87{
88 // number of training and validation entries after the split
89 std::size_t NumEntries = fDataset.GetRows() - firstRow;
90 std::size_t NumValidationEntries = static_cast<std::size_t>(fValidationSplit * NumEntries);
91 std::size_t NumTrainingEntries = NumEntries - NumValidationEntries;
92
93 // the sets refer to the rows of the dataset in shuffled order, instead of copying them
94 const auto permutation = fTensorOperators->MakePermutation(NumEntries);
95 TrainingRows.reserve(TrainingRows.size() + NumTrainingEntries);
96 ValidationRows.reserve(ValidationRows.size() + NumValidationEntries);
97 for (std::size_t i = 0; i < NumEntries; i++) {
98 const std::size_t row = firstRow + (permutation.empty() ? i : permutation[i]);
99 (i < NumTrainingEntries ? TrainingRows : ValidationRows).push_back(row);
100 }
101}
102
103//////////////////////////////////////////////////////////////////////////
104/// \brief Load the dataframes into a single dataset and split it in training and validation rows
105/// \param[in] concatenate Whether to concatenate the rows of all the dataframes into a single set
106void RDatasetLoader::SplitDatasets(bool concatenate)
107{
108 // reserve the dataset for all the dataframes and let their values be appended to it
109 const std::vector<std::size_t> NumEntries = CountEntries(f_rdfs);
110 fDataset.Reserve(std::accumulate(NumEntries.begin(), NumEntries.end(), std::size_t{0}), fNumDatasetCols);
111
112 const std::size_t numSets = concatenate ? 1 : f_rdfs.size();
113 fTrainingRows.resize(numSets);
114 fValidationRows.resize(numSets);
115 for (std::size_t i = 0; i < f_rdfs.size(); i++) {
116 const std::size_t firstRow = fDataset.GetRows();
117 LoadDataframe(f_rdfs[i], NumEntries[i]);
118 SplitRows(firstRow, fTrainingRows[concatenate ? 0 : i], fValidationRows[concatenate ? 0 : i]);
119 }
120
123 for (std::size_t i = 0; i < numSets; i++) {
126 }
127}
128
129} // namespace ROOT::Experimental::Internal::ML
#define c(i)
Definition RSha256.hxx:101
std::vector< std::size_t > CountEntries(std::vector< ROOT::RDF::RNode > &rdfs)
Number of entries to reserve for each dataframe.
void SplitRows(std::size_t firstRow, std::vector< std::size_t > &TrainingRows, std::vector< std::size_t > &ValidationRows)
Split the rows of the dataset from firstRow on into training and validation rows.
std::unique_ptr< RFlat2DMatrixOperators > fTensorOperators
void SplitDatasets(bool concatenate)
Load the dataframes into a single dataset and split it in training and validation rows.
std::vector< std::vector< std::size_t > > fTrainingRows
void LoadDataframe(ROOT::RDF::RNode &rdf, std::size_t NumEntries)
Load all the entries of an individual dataframe at the end of the dataset.
RDatasetLoader(const std::vector< ROOT::RDF::RNode > &rdfs, const float validationSplit, const std::vector< std::string > &cols, const std::vector< std::size_t > &vecSizes={}, const float vecPadding=0.0, bool shuffle=true, const std::size_t setSeed=0)
std::vector< std::vector< std::size_t > > fValidationRows
The public interface to the RDataFrame federation of classes.
std::vector< std::string > GetFilterNames()
Returns the names of the filters created.
void LoadCustomValues(ROOT::RDF::RNode &node, const std::vector< std::string > &cols, const std::vector< std::size_t > &vecSizes, float vecPadding, ROOT::RVecF &dest)
std::vector< std::pair< std::uint64_t, std::uint64_t > > GetDatasetGlobalClusterBoundaries(const RNode &node)
Retrieve the cluster boundaries for each cluster in the dataset, across files, with a global offset.
unsigned int RunGraphs(std::vector< RResultHandle > handles)
Run the event loops of multiple RDataFrames concurrently.
void Resize(std::size_t rows, std::size_t cols)
void Reserve(std::size_t rows, std::size_t cols)