GestureRecognitionToolkit  Version: 0.2.0
The Gesture Recognition Toolkit (GRT) is a cross-platform, open-source, c++ machine learning library for real-time gesture recognition.
UnlabelledData.cpp
1 /*
2 GRT MIT License
3 Copyright (c) <2012> <Nicholas Gillian, Media Lab, MIT>
4 
5 Permission is hereby granted, free of charge, to any person obtaining a copy of this software
6 and associated documentation files (the "Software"), to deal in the Software without restriction,
7 including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in all copies or substantial
12 portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
15 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
18 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 */
20 
21 #define GRT_DLL_EXPORTS
22 #include "UnlabelledData.h"
23 
24 GRT_BEGIN_NAMESPACE
25 
26 UnlabelledData::UnlabelledData(const UINT numDimensions,const std::string datasetName,const std::string infoText):debugLog("[DEBUG ULCD]"),errorLog("[ERROR ULCD]"),warningLog("[WARNING ULCD]"){
27  this->datasetName = datasetName;
28  this->numDimensions = numDimensions;
29  this->infoText = infoText;
30  totalNumSamples = 0;
31  crossValidationSetup = false;
32  useExternalRanges = false;
33  if( numDimensions > 0 ) setNumDimensions( numDimensions );
34 }
35 
36 UnlabelledData::UnlabelledData(const UnlabelledData &rhs):debugLog("[DEBUG ULCD]"),errorLog("[ERROR ULCD]"),warningLog("[WARNING ULCD]"){
37  *this = rhs;
38 }
39 
41 
43  if( this != &rhs){
44  this->datasetName = rhs.datasetName;
45  this->infoText = rhs.infoText;
46  this->numDimensions = rhs.numDimensions;
47  this->totalNumSamples = rhs.totalNumSamples;
48  this->kFoldValue = rhs.kFoldValue;
49  this->crossValidationSetup = rhs.crossValidationSetup;
50  this->useExternalRanges = rhs.useExternalRanges;
51  this->externalRanges = rhs.externalRanges;
52  this->data = rhs.data;
53  this->crossValidationIndexs = rhs.crossValidationIndexs;
54  this->debugLog = rhs.debugLog;
55  this->errorLog = rhs.errorLog;
56  this->warningLog = rhs.warningLog;
57  }
58  return *this;
59 }
60 
62  totalNumSamples = 0;
63  data.clear();
64  crossValidationSetup = false;
65  crossValidationIndexs.clear();
66 }
67 
68 bool UnlabelledData::setNumDimensions(const UINT numDimensions){
69 
70  if( numDimensions > 0 ){
71  //Clear any previous training data
72  clear();
73 
74  //Set the dimensionality of the data
75  this->numDimensions = numDimensions;
76 
77  //Clear the external ranges
78  useExternalRanges = false;
79  externalRanges.clear();
80 
81  return true;
82  }
83  return false;
84 }
85 
86 bool UnlabelledData::setDatasetName(const std::string datasetName){
87 
88  //Make sure there are no spaces in the std::string
89  if( datasetName.find(" ") == std::string::npos ){
90  this->datasetName = datasetName;
91  return true;
92  }
93 
94  return false;
95 }
96 
97 bool UnlabelledData::setInfoText(const std::string infoText){
98  this->infoText = infoText;
99  return true;
100 }
101 
103 
104  if( sample.size() != numDimensions ) return false;
105 
106  //The dataset has changed so flag that any previous cross validation setup will now not work
107  crossValidationSetup = false;
108  crossValidationIndexs.clear();
109 
110  data.push_back( sample );
111  totalNumSamples++;
112 
113  return true;
114 }
115 
117 
118  if( totalNumSamples > 0 ){
119 
120  //The dataset has changed so flag that any previous cross validation setup will now not work
121  crossValidationSetup = false;
122  crossValidationIndexs.clear();
123 
124  //If there is only one sample then we just need to clear the buffer
125  if( totalNumSamples == 1 ){
126  data.clear();
127  return true;
128  }
129 
130  data.erase( data.begin()+data.size()-1 );
131 
132  return true;
133 
134  }else return false;
135 
136 }
137 
138 bool UnlabelledData::reserve(const UINT N){
139 
140  data.reserve( N );
141 
142  if( data.capacity() >= N ) return true;
143 
144  return false;
145 }
146 
147 bool UnlabelledData::setExternalRanges(const Vector< MinMax > &externalRanges,const bool useExternalRanges){
148 
149  if( externalRanges.size() != numDimensions ) return false;
150 
151  this->externalRanges = externalRanges;
152  this->useExternalRanges = useExternalRanges;
153 
154  return true;
155 }
156 
157 bool UnlabelledData::enableExternalRangeScaling(const bool useExternalRanges){
158  if( externalRanges.size() == numDimensions ){
159  this->useExternalRanges = useExternalRanges;
160  return true;
161  }
162  return false;
163 }
164 
165 bool UnlabelledData::scale(const Float minTarget,const Float maxTarget){
166  Vector< MinMax > ranges = getRanges();
167  return scale(ranges,minTarget,maxTarget);
168 }
169 
170 bool UnlabelledData::scale(const Vector<MinMax> &ranges,const Float minTarget,const Float maxTarget){
171  if( ranges.size() != numDimensions ) return false;
172 
173  //Scale the training data
174  for(UINT i=0; i<totalNumSamples; i++){
175  for(UINT j=0; j<numDimensions; j++){
176  data[i][j] = Util::scale(data[i][j],ranges[j].minValue,ranges[j].maxValue,minTarget,maxTarget);
177  }
178  }
179 
180  return true;
181 }
182 
183 bool UnlabelledData::save(const std::string &filename) const{
184 
185  //Check if the file should be saved as a csv file
186  if( Util::stringEndsWith( filename, ".csv" ) ){
187  return saveDatasetToCSVFile( filename );
188  }
189 
190  //Otherwise save it as a custom GRT file
191  return saveDatasetToFile( filename );
192 }
193 
194 bool UnlabelledData::load(const std::string &filename){
195 
196  //Check if the file should be loaded as a csv file
197  if( Util::stringEndsWith( filename, ".csv" ) ){
198  return loadDatasetFromCSVFile( filename );
199  }
200 
201  //Otherwise save it as a custom GRT file
202  return loadDatasetFromFile( filename );
203 }
204 
205 bool UnlabelledData::saveDatasetToFile(const std::string &filename) const{
206 
207  std::fstream file;
208  file.open(filename.c_str(), std::ios::out);
209 
210  if( !file.is_open() ){
211  errorLog << "saveDatasetToFile(const std::string &filename) - Failed to open file!" << std::endl;
212  return false;
213  }
214 
215  file << "GRT_UNLABELLED_DATA_FILE_V1.0\n";
216  file << "DatasetName: " << datasetName << std::endl;
217  file << "InfoText: " << infoText << std::endl;
218  file << "NumDimensions: " << numDimensions << std::endl;
219  file << "TotalNumTrainingExamples: " << totalNumSamples << std::endl;
220 
221  file << "UseExternalRanges: " << useExternalRanges << std::endl;
222 
223  if( useExternalRanges ){
224  for(UINT i=0; i<externalRanges.size(); i++){
225  file << externalRanges[i].minValue << "\t" << externalRanges[i].maxValue << std::endl;
226  }
227  }
228 
229  file << "UnlabelledTrainingData:\n";
230 
231  for(UINT i=0; i<totalNumSamples; i++){
232  for(UINT j=0; j<numDimensions; j++){
233  if( j != 0 ) file << "\t";
234  file << data[i][j];
235  }
236  file << std::endl;
237  }
238 
239  file.close();
240  return true;
241 }
242 
243 bool UnlabelledData::loadDatasetFromFile(const std::string &filename){
244 
245  std::fstream file;
246  file.open(filename.c_str(), std::ios::in);
247  clear();
248 
249  if( !file.is_open() ){
250  errorLog << "loadDatasetFromFile(const std::string &filename) - could not open file!" << std::endl;
251  return false;
252  }
253 
254  std::string word;
255 
256  //Check to make sure this is a file with the Training File Format
257  file >> word;
258  if( word != "GRT_UNLABELLED_DATA_FILE_V1.0" && word != "GRT_UNLABELLED_CLASSIFICATION_DATA_FILE_V1.0" ){
259  errorLog << "loadDatasetFromFile(const std::string &filename) - could not find file header!" << std::endl;
260  file.close();
261  return false;
262  }
263 
264  //Get the name of the dataset
265  file >> word;
266  if(word != "DatasetName:"){
267  errorLog << "loadDatasetFromFile(const std::string &filename) - failed to find DatasetName!" << std::endl;
268  file.close();
269  return false;
270  }
271  file >> datasetName;
272 
273  file >> word;
274  if(word != "InfoText:"){
275  errorLog << "loadDatasetFromFile(const std::string &filename) - failed to find InfoText!" << std::endl;
276  file.close();
277  return false;
278  }
279 
280  //Load the info text
281  file >> word;
282  infoText = "";
283  while( word != "NumDimensions:" ){
284  infoText += word + " ";
285  file >> word;
286  }
287 
288  //Get the number of dimensions in the training data
289  if(word != "NumDimensions:"){
290  errorLog << "loadDatasetFromFile(const std::string &filename) - failed to find DatasetName!" << std::endl;
291  file.close();
292  return false;
293  }
294  file >> numDimensions;
295 
296  //Get the total number of training examples in the training data
297  file >> word;
298  if(word != "TotalNumTrainingExamples:"){
299  errorLog << "loadDatasetFromFile(const std::string &filename) - failed to find DatasetName!" << std::endl;
300  file.close();
301  return false;
302  }
303  file >> totalNumSamples;
304 
305  //Check if the dataset should be scaled using external ranges
306  file >> word;
307  if(word != "UseExternalRanges:"){
308  errorLog << "loadDatasetFromFile(const std::string &filename) - failed to find DatasetName!" << std::endl;
309  file.close();
310  return false;
311  }
312  file >> useExternalRanges;
313 
314  //If we are using external ranges then load them
315  if( useExternalRanges ){
316  externalRanges.resize(numDimensions);
317  for(UINT i=0; i<externalRanges.size(); i++){
318  file >> externalRanges[i].minValue;
319  file >> externalRanges[i].maxValue;
320  }
321  }
322 
323  //Get the main training data
324  file >> word;
325  if(word != "UnlabelledTrainingData:"){
326  errorLog << "loadDatasetFromFile(const std::string &filename) - failed to find DatasetName!" << std::endl;
327  file.close();
328  return false;
329  }
330  data.resize( totalNumSamples, VectorFloat(numDimensions) );
331 
332  for(UINT i=0; i<totalNumSamples; i++){
333  for(UINT j=0; j<numDimensions; j++){
334  file >> data[i][j];
335  }
336  }
337 
338  file.close();
339  return true;
340 }
341 
342 
343 bool UnlabelledData::saveDatasetToCSVFile(const std::string &filename) const{
344 
345  std::fstream file;
346  file.open(filename.c_str(), std::ios::out );
347 
348  if( !file.is_open() ){
349  errorLog << "saveDatasetToCSVFile(const std::string &filename) - Failed to open file!" << std::endl;
350  return false;
351  }
352 
353  //Write the data to the CSV file
354  for(UINT i=0; i<totalNumSamples; i++){
355  for(UINT j=0; j<numDimensions; j++){
356  if( j != 0 ) file << ",";
357  file << data[i][j];
358  }
359  file << std::endl;
360  }
361 
362  file.close();
363 
364  return true;
365 }
366 
367 bool UnlabelledData::loadDatasetFromCSVFile(const std::string &filename){
368 
369  std::string value;
370  datasetName = "NOT_SET";
371  infoText = "";
372 
373  //Clear any previous data
374  clear();
375 
376  //Parse the CSV file
377  FileParser parser;
378 
379  if( !parser.parseCSVFile(filename,true) ){
380  errorLog << "loadDatasetFromCSVFile(const std::string &filename) - Failed to parse CSV file!" << std::endl;
381  return false;
382  }
383 
384  if( !parser.getConsistentColumnSize() ){
385  errorLog << "loadDatasetFromCSVFile(const std::string &filename) - The CSV file does not have a consistent number of columns!" << std::endl;
386  return false;
387  }
388 
389  const UINT rows = parser.getRowSize();
390  const UINT cols = parser.getColumnSize();
391 
392  //Setup the labelled classification data
393  numDimensions = cols;
394 
395  //Reserve the data so we do not have to continually resize the memory
396  data.reserve( rows );
397 
398  VectorFloat sample(numDimensions);
399  for(UINT i=0; i<rows; i++){
400 
401  //Get the input vector
402  for(UINT j=0; j<numDimensions; j++){
403  sample[j] = Util::stringToFloat( parser[i][j] );
404  }
405 
406  //Add the labelled sample to the dataset
407  if( !addSample(sample) ){
408  warningLog << "loadDatasetFromCSVFile(const std::string &filename) - Could not add sample " << i << " to the dataset!" << std::endl;
409  }
410  }
411 
412  return true;
413 }
414 
415 UnlabelledData UnlabelledData::partition(const UINT trainingSizePercentage){
416  return split( trainingSizePercentage );
417 }
418 
419 UnlabelledData UnlabelledData::split(const UINT trainingSizePercentage){
420 
421  //Partitions the dataset into a training dataset (which is kept by this instance of the UnlabelledData) and
422  //a testing/validation dataset (which is return as a new instance of the UnlabelledData). The trainingSizePercentage
423  //therefore sets the size of the data which remains in this instance and the remaining percentage of data is then added to
424  //the testing/validation dataset
425 
426  //The dataset has changed so flag that any previous cross validation setup will now not work
427  crossValidationSetup = false;
428  crossValidationIndexs.clear();
429 
430  const UINT numTrainingExamples = (UINT) floor( Float(totalNumSamples) / 100.0 * Float(trainingSizePercentage) );
431 
432  UnlabelledData trainingSet(numDimensions);
433  UnlabelledData testSet(numDimensions);
434  Vector< UINT > indexs( totalNumSamples );
435 
436  //Create the random partion indexs
437  Random random;
438  UINT randomIndex = 0;
439  for(UINT i=0; i<totalNumSamples; i++) indexs[i] = i;
440  for(UINT x=0; x<totalNumSamples; x++){
441  //Pick a random index
442  randomIndex = random.getRandomNumberInt(0,totalNumSamples);
443 
444  //Swap the indexs
445  SWAP( indexs[ x ] , indexs[ randomIndex ] );
446  }
447 
448  trainingSet.reserve( numTrainingExamples );
449  testSet.reserve( totalNumSamples-numTrainingExamples );
450 
451  //Add the data to the training and test sets
452  for(UINT i=0; i<numTrainingExamples; i++){
453  trainingSet.addSample( data[ indexs[i] ] );
454  }
455  for(UINT i=numTrainingExamples; i<totalNumSamples; i++){
456  testSet.addSample( data[ indexs[i] ] );
457  }
458 
459  //Overwrite the training data in this instance with the training data of the trainingSet
460  *this = trainingSet;
461 
462  return testSet;
463 }
464 
465 bool UnlabelledData::merge(const UnlabelledData &unlabelledData){
466 
467  if( unlabelledData.getNumDimensions() != numDimensions ){
468  errorLog << "merge(const UnlabelledData &unlabelledData) - The number of dimensions in the unlabelledData (" << unlabelledData.getNumDimensions() << ") does not match the number of dimensions of this dataset (" << numDimensions << ")" << std::endl;
469  return false;
470  }
471 
472  //The dataset has changed so flag that any previous cross validation setup will now not work
473  crossValidationSetup = false;
474  crossValidationIndexs.clear();
475 
476  reserve( getNumSamples() + unlabelledData.getNumSamples() );
477 
478  //Add the data from the labelledData to this instance
479  for(UINT i=0; i<unlabelledData.getNumSamples(); i++){
480  addSample( unlabelledData[i] );
481  }
482 
483  return true;
484 }
485 
487 
488  crossValidationSetup = false;
489  crossValidationIndexs.clear();
490 
491  //K can not be zero
492  if( K > totalNumSamples ){
493  errorLog << "spiltDataIntoKFolds(const UINT K) - K can not be zero!" << std::endl;
494  return false;
495  }
496 
497  //K can not be larger than the number of examples
498  if( K > totalNumSamples ){
499  errorLog << "spiltDataIntoKFolds(const UINT K) - K can not be larger than the total number of samples in the dataset!" << std::endl;
500  return false;
501  }
502 
503  //Setup the dataset for k-fold cross validation
504  kFoldValue = K;
505  Vector< UINT > indexs( totalNumSamples );
506 
507  //Work out how many samples are in each fold, the last fold might have more samples than the others
508  UINT numSamplesPerFold = (UINT) floor( totalNumSamples/Float(K) );
509 
510  //Add the random indexs to each fold
511  crossValidationIndexs.resize(K);
512 
513  //Create the random partion indexs
514  Random random;
515  UINT randomIndex = 0;
516 
517  //Randomize the order of the data
518  for(UINT i=0; i<totalNumSamples; i++) indexs[i] = i;
519  for(UINT x=0; x<totalNumSamples; x++){
520  //Pick a random index
521  randomIndex = random.getRandomNumberInt(0,totalNumSamples);
522 
523  //Swap the indexs
524  grt_swap( indexs[ x ] , indexs[ randomIndex ] );
525  }
526 
527  UINT counter = 0;
528  UINT foldIndex = 0;
529  for(UINT i=0; i<totalNumSamples; i++){
530  //Add the index to the current fold
531  crossValidationIndexs[ foldIndex ].push_back( indexs[i] );
532 
533  //Move to the next fold if ready
534  if( ++counter == numSamplesPerFold && foldIndex < K-1 ){
535  foldIndex++;
536  counter = 0;
537  }
538  }
539 
540  crossValidationSetup = true;
541  return true;
542 
543 }
544 
546  UnlabelledData trainingData;
547 
548  if( !crossValidationSetup ){
549  errorLog << "getTrainingFoldData(const UINT foldIndex) - Cross Validation has not been setup! You need to call the spiltDataIntoKFolds(UINT K) function first before calling this function!" << std::endl;
550  return trainingData;
551  }
552 
553  if( foldIndex >= kFoldValue ) return trainingData;
554 
555  trainingData.setNumDimensions( numDimensions );
556 
557  //Work out how many samples will be in this fold
558  UINT numSamples = 0;
559  for(UINT k=0; k<kFoldValue; k++){
560  if( k != foldIndex ){
561  numSamples += (UINT)crossValidationIndexs[k].size();
562  }
563  }
564  trainingData.reserve( numSamples );
565 
566  //Add the data to the training set, this will consist of all the data that is NOT in the foldIndex
567  UINT index = 0;
568  for(UINT k=0; k<kFoldValue; k++){
569  if( k != foldIndex ){
570  for(UINT i=0; i<crossValidationIndexs[k].size(); i++){
571 
572  index = crossValidationIndexs[k][i];
573  trainingData.addSample( data[ index ] );
574  }
575  }
576  }
577 
578  return trainingData;
579 }
580 
582  UnlabelledData testData;
583 
584  if( !crossValidationSetup ) return testData;
585 
586  if( foldIndex >= kFoldValue ) return testData;
587 
588  //Add the data to the training
589  testData.setNumDimensions( numDimensions );
590 
591  //Work out how many samples will be in this fold
592  UINT numSamples = (UINT)crossValidationIndexs[ foldIndex ].size();
593 
594  testData.reserve( numSamples );
595 
596  UINT index = 0;
597  for(UINT i=0; i<crossValidationIndexs[ foldIndex ].size(); i++){
598 
599  index = crossValidationIndexs[ foldIndex ][i];
600  testData.addSample( data[ index ] );
601  }
602 
603  return testData;
604 }
605 
607  std::string statsText;
608  statsText += "DatasetName:\t" + datasetName + "\n";
609  statsText += "DatasetInfo:\t" + infoText + "\n";
610  statsText += "Number of Dimensions:\t" + Util::toString( numDimensions ) + "\n";
611  statsText += "Number of Samples:\t" + Util::toString( totalNumSamples ) + "\n";
612 
613  Vector< MinMax > ranges = getRanges();
614 
615  statsText += "Dataset Ranges:\n";
616  for(UINT j=0; j<ranges.size(); j++){
617  statsText += "[" + Util::toString( j+1 ) + "] Min:\t" + Util::toString( ranges[j].minValue ) + "\tMax: " + Util::toString( ranges[j].maxValue ) + "\n";
618  }
619 
620  return statsText;
621 }
622 
624 
625  //If the dataset should be scaled using the external ranges then return the external ranges
626  if( useExternalRanges ) return externalRanges;
627 
628  Vector< MinMax > ranges(numDimensions);
629 
630  //Otherwise return the min and max values for each column in the dataset
631  if( totalNumSamples > 0 ){
632  for(UINT j=0; j<numDimensions; j++){
633  ranges[j].minValue = data[0][0];
634  ranges[j].maxValue = data[0][0];
635  for(UINT i=0; i<totalNumSamples; i++){
636  if( data[i][j] < ranges[j].minValue ){ ranges[j].minValue = data[i][j]; } //Search for the min value
637  else if( data[i][j] > ranges[j].maxValue ){ ranges[j].maxValue = data[i][j]; } //Search for the max value
638  }
639  }
640  }
641  return ranges;
642 }
643 
645  return data;
646 }
647 
649  const UINT rows = getNumSamples();
650  const UINT cols = getNumDimensions();
651  MatrixDouble d(rows,cols);
652 
653  for(UINT i=0; i<rows; i++){
654  for(UINT j=0; j<cols; j++){
655  d[i][j] = data[i][j];
656  }
657  }
658 
659  return d;
660 }
661 
663  const UINT rows = getNumSamples();
664  const UINT cols = getNumDimensions();
665  MatrixFloat d(rows,cols);
666 
667  for(UINT i=0; i<rows; i++){
668  for(UINT j=0; j<cols; j++){
669  d[i][j] = data[i][j];
670  }
671  }
672 
673  return d;
674 }
675 
676 GRT_END_NAMESPACE
677 
bool loadDatasetFromCSVFile(const std::string &filename)
static std::string toString(const int &i)
Definition: Util.cpp:74
bool scale(const Float minTarget, const Float maxTarget)
bool addSample(const VectorFloat &sample)
static Float scale(const Float &x, const Float &minSource, const Float &maxSource, const Float &minTarget, const Float &maxTarget, const bool constrain=false)
Definition: Util.cpp:53
static Float stringToFloat(const std::string &s)
Definition: Util.cpp:133
Definition: Random.h:40
bool load(const std::string &filename)
MatrixFloat getDataAsMatrixFloat() const
UINT getNumDimensions() const
virtual bool resize(const unsigned int size)
Definition: Vector.h:133
bool setExternalRanges(const Vector< MinMax > &externalRanges, const bool useExternalRanges=false)
UnlabelledData split(const UINT partitionPercentage)
UINT getNumSamples() const
UnlabelledData & operator=(const UnlabelledData &rhs)
bool reserve(const UINT N)
Vector< VectorFloat > getData() const
The UnlabelledData class is the main data container for supporting unsupervised learning.
UnlabelledData getTestFoldData(const UINT foldIndex) const
UnlabelledData(const UINT numDimensions=0, const std::string datasetName="NOT_SET", const std::string infoText="")
bool save(const std::string &filename) const
bool saveDatasetToFile(const std::string &filename) const
bool setNumDimensions(const UINT numDimensions)
bool enableExternalRangeScaling(const bool useExternalRanges)
bool setInfoText(const std::string infoText)
bool saveDatasetToCSVFile(const std::string &filename) const
Vector< MinMax > getRanges() const
int getRandomNumberInt(int minRange, int maxRange)
Definition: Random.h:88
static bool stringEndsWith(const std::string &str, const std::string &ending)
Definition: Util.cpp:157
UnlabelledData getTrainingFoldData(const UINT foldIndex) const
MatrixDouble getDataAsMatrixDouble() const
bool merge(const UnlabelledData &unlabelledData)
bool setDatasetName(const std::string datasetName)
bool spiltDataIntoKFolds(const UINT K)
bool loadDatasetFromFile(const std::string &filename)
std::string getStatsAsString() const