GestureRecognitionToolkit  Version: 1.0 Revision: 04-03-15
The Gesture Recognition Toolkit (GRT) is a cross-platform, open-source, c++ machine learning library for real-time gesture recognition.
TimeSeriesClassificationDataStream.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 
22 
23 namespace GRT{
24 
25 //Constructors and Destructors
26 TimeSeriesClassificationDataStream::TimeSeriesClassificationDataStream(const UINT numDimensions,const string datasetName,const string infoText){
27 
28  this->numDimensions= numDimensions;
29  this->datasetName = datasetName;
30  this->infoText = infoText;
31 
32  playbackIndex = 0;
33  trackingClass = false;
34  useExternalRanges = false;
35  debugLog.setProceedingText("[DEBUG LTSCD]");
36  errorLog.setProceedingText("[ERROR LTSCD]");
37  warningLog.setProceedingText("[WARNING LTSCD]");
38 
39  if( numDimensions > 0 ){
40  setNumDimensions(numDimensions);
41  }
42 }
43 
45  *this = rhs;
46 }
47 
49 
51  if( this != &rhs){
52  this->datasetName = rhs.datasetName;
53  this->infoText = rhs.infoText;
54  this->numDimensions = rhs.numDimensions;
55  this->totalNumSamples = rhs.totalNumSamples;
56  this->lastClassID = rhs.lastClassID;
57  this->playbackIndex = rhs.playbackIndex;
58  this->trackingClass = rhs.trackingClass;
60  this->externalRanges = rhs.externalRanges;
61  this->data = rhs.data;
62  this->classTracker = rhs.classTracker;
63  this->timeSeriesPositionTracker = rhs.timeSeriesPositionTracker;
64  this->debugLog = rhs.debugLog;
65  this->warningLog = rhs.warningLog;
66  this->errorLog = rhs.errorLog;
67 
68  }
69  return *this;
70 }
71 
73  totalNumSamples = 0;
74  playbackIndex = 0;
75  trackingClass = false;
76  data.clear();
77  classTracker.clear();
78  timeSeriesPositionTracker.clear();
79 }
80 
82  if( numDimensions > 0 ){
83  //Clear any previous data
84  clear();
85 
86  //Set the dimensionality of the time series data
87  this->numDimensions = numDimensions;
88 
89  return true;
90  }
91 
92  errorLog << "setNumDimensions(const UINT numDimensions) - The number of dimensions of the dataset must be greater than zero!" << endl;
93  return false;
94 }
95 
96 
98 
99  //Make sure there are no spaces in the string
100  if( datasetName.find(" ") == string::npos ){
101  this->datasetName = datasetName;
102  return true;
103  }
104 
105  errorLog << "setDatasetName(const string datasetName) - The dataset name cannot contain any spaces!" << endl;
106  return false;
107 }
108 
110  this->infoText = infoText;
111  return true;
112 }
113 
114 bool TimeSeriesClassificationDataStream::setClassNameForCorrespondingClassLabel(const string className,const UINT classLabel){
115 
116  for(UINT i=0; i<classTracker.size(); i++){
117  if( classTracker[i].classLabel == classLabel ){
118  classTracker[i].className = className;
119  return true;
120  }
121  }
122 
123  errorLog << "setClassNameForCorrespondingClassLabel(const string className,const UINT classLabel) - Failed to find class with label: " << classLabel << endl;
124  return false;
125 }
126 
127 bool TimeSeriesClassificationDataStream::addSample(const UINT classLabel,const VectorDouble &sample){
128 
129  if( numDimensions != sample.size() ){
130  errorLog << "addSample(const UINT classLabel, vector<double> sample) - the size of the new sample (" << sample.size() << ") does not match the number of dimensions of the dataset (" << numDimensions << ")" << endl;
131  return false;
132  }
133 
134  bool searchForNewClass = true;
135  if( trackingClass ){
136  if( classLabel != lastClassID ){
137  //The class ID has changed so update the time series tracker
138  timeSeriesPositionTracker[ timeSeriesPositionTracker.size()-1 ].setEndIndex( totalNumSamples-1 );
139  }else searchForNewClass = false;
140  }
141 
142  if( searchForNewClass ){
143  bool newClass = true;
144  //Search to see if this class has been found before
145  for(UINT k=0; k<classTracker.size(); k++){
146  if( classTracker[k].classLabel == classLabel ){
147  newClass = false;
148  classTracker[k].counter++;
149  }
150  }
151  if( newClass ){
152  ClassTracker newCounter(classLabel,1);
153  classTracker.push_back( newCounter );
154  }
155 
156  //Set the timeSeriesPositionTracker start position
157  trackingClass = true;
158  lastClassID = classLabel;
159  TimeSeriesPositionTracker newTracker(totalNumSamples,0,classLabel);
160  timeSeriesPositionTracker.push_back( newTracker );
161  }
162 
163  ClassificationSample labelledSample(classLabel,sample);
164  data.push_back( labelledSample );
165  totalNumSamples++;
166  return true;
167 }
168 
170 
171  if( totalNumSamples > 0 ){
172 
173  //Find the corresponding class ID for the last training example
174  UINT classLabel = data[ totalNumSamples-1 ].getClassLabel();
175 
176  //Remove the training example from the buffer
177  data.erase( data.end()-1 );
178 
179  totalNumSamples = (UINT)data.size();
180 
181  //Remove the value from the counter
182  for(UINT i=0; i<classTracker.size(); i++){
183  if( classTracker[i].classLabel == classLabel ){
184  classTracker[i].counter--;
185  break;
186  }
187  }
188 
189  //If we are not tracking a class then decrement the end index of the timeseries position tracker
190  if( !trackingClass ){
191  UINT endIndex = timeSeriesPositionTracker[ timeSeriesPositionTracker.size()-1 ].getEndIndex();
192  timeSeriesPositionTracker[ timeSeriesPositionTracker.size()-1 ].setEndIndex( endIndex-1 );
193  }
194 
195  return true;
196 
197  }else return false;
198 
199 }
200 
202  UINT numExamplesRemoved = 0;
203  UINT numExamplesToRemove = 0;
204 
205  //Find out how many training examples we need to remove
206  for(UINT i=0; i<classTracker.size(); i++){
207  if( classTracker[i].classLabel == classLabel ){
208  numExamplesToRemove = classTracker[i].counter;
209  classTracker.erase(classTracker.begin()+i);
210  break; //There should only be one class with this classLabel so break
211  }
212  }
213 
214  //Remove the samples with the matching class ID
215  if( numExamplesToRemove > 0 ){
216  UINT i=0;
217  while( numExamplesRemoved < numExamplesToRemove ){
218  if( data[i].getClassLabel() == classLabel ){
219  data.erase(data.begin()+i);
220  numExamplesRemoved++;
221  }else if( ++i == data.size() ) break;
222  }
223  }
224 
225  //Update the time series position tracker
226  vector< TimeSeriesPositionTracker >::iterator iter = timeSeriesPositionTracker.begin();
227 
228  while( iter != timeSeriesPositionTracker.end() ){
229  if( iter->getClassLabel() == classLabel ){
230  UINT length = iter->getLength();
231  //Update the start and end positions of all the following position trackers
232  vector< TimeSeriesPositionTracker >::iterator updateIter = iter + 1;
233 
234  while( updateIter != timeSeriesPositionTracker.end() ){
235  updateIter->setStartIndex( updateIter->getStartIndex() - length );
236  updateIter->setEndIndex( updateIter->getEndIndex() - length );
237  updateIter++;
238  }
239 
240  //Erase the current position tracker
241  iter = timeSeriesPositionTracker.erase( iter );
242  }else iter++;
243  }
244 
245  totalNumSamples = (UINT)data.size();
246 
247  return numExamplesRemoved;
248 }
249 
250 bool TimeSeriesClassificationDataStream::relabelAllSamplesWithClassLabel(const UINT oldClassLabel,const UINT newClassLabel){
251  bool oldClassLabelFound = false;
252  bool newClassLabelAllReadyExists = false;
253  UINT indexOfOldClassLabel = 0;
254  UINT indexOfNewClassLabel = 0;
255 
256  //Find out how many training examples we need to relabel
257  for(UINT i=0; i<classTracker.size(); i++){
258  if( classTracker[i].classLabel == oldClassLabel ){
259  indexOfOldClassLabel = i;
260  oldClassLabelFound = true;
261  }
262  if( classTracker[i].classLabel == newClassLabel ){
263  indexOfNewClassLabel = i;
264  newClassLabelAllReadyExists = true;
265  }
266  }
267 
268  //If the old class label was not found then we can't do anything
269  if( !oldClassLabelFound ){
270  return false;
271  }
272 
273  //Relabel the old class labels
274  for(UINT i=0; i<totalNumSamples; i++){
275  if( data[i].getClassLabel() == oldClassLabel ){
276  data[i].set(newClassLabel, data[i].getSample());
277  }
278  }
279 
280  //Update the class label counters
281  if( newClassLabelAllReadyExists ){
282  //Add the old sample count to the new sample count
283  classTracker[ indexOfNewClassLabel ].counter += classTracker[ indexOfOldClassLabel ].counter;
284 
285  //Erase the old class tracker
286  classTracker.erase( classTracker.begin() + indexOfOldClassLabel );
287  }else{
288  //Create a new class tracker
289  classTracker.push_back( ClassTracker(newClassLabel,classTracker[ indexOfOldClassLabel ].counter,classTracker[ indexOfOldClassLabel ].className) );
290  }
291 
292  //Update the timeseries position tracker
293  for(UINT i=0; i<timeSeriesPositionTracker.size(); i++){
294  if( timeSeriesPositionTracker[i].getClassLabel() == oldClassLabel ){
295  timeSeriesPositionTracker[i].setClassLabel( newClassLabel );
296  }
297  }
298 
299  return true;
300 }
301 
302 bool TimeSeriesClassificationDataStream::setExternalRanges(const vector< MinMax > &externalRanges, const bool useExternalRanges){
303 
304  if( externalRanges.size() != numDimensions ) return false;
305 
306  this->externalRanges = externalRanges;
307  this->useExternalRanges = useExternalRanges;
308 
309  return true;
310 }
311 
313  if( externalRanges.size() == numDimensions ){
314  this->useExternalRanges = useExternalRanges;
315  return true;
316  }
317  return false;
318 }
319 
320 bool TimeSeriesClassificationDataStream::scale(const double minTarget,const double maxTarget){
321  vector< MinMax > ranges = getRanges();
322  return scale(ranges,minTarget,maxTarget);
323 }
324 
325 bool TimeSeriesClassificationDataStream::scale(const vector<MinMax> &ranges,const double minTarget,const double maxTarget){
326  if( ranges.size() != numDimensions ) return false;
327 
328  //Scale the training data
329  for(UINT i=0; i<totalNumSamples; i++){
330  for(UINT j=0; j<numDimensions; j++){
331  data[i][j] = Util::scale(data[i][j],ranges[j].minValue,ranges[j].maxValue,minTarget,maxTarget);
332  }
333  }
334  return true;
335 }
336 
338  if( playbackIndex < totalNumSamples ){
339  this->playbackIndex = playbackIndex;
340  return true;
341  }
342  return false;
343 }
344 
346  if( totalNumSamples == 0 ) return ClassificationSample();
347 
348  UINT index = playbackIndex++ % totalNumSamples;
349  return data[ index ];
350 }
351 
354  for(UINT x=0; x<timeSeriesPositionTracker.size(); x++){
355  if( timeSeriesPositionTracker[x].getClassLabel() == classLabel && timeSeriesPositionTracker[x].getEndIndex() > 0){
356  Matrix<double> timeSeries;
357  for(UINT i=timeSeriesPositionTracker[x].getStartIndex(); i<timeSeriesPositionTracker[x].getEndIndex(); i++){
358  timeSeries.push_back( data[ i ].getSample() );
359  }
360  classData.addSample(classLabel,timeSeries);
361  }
362  }
363  return classData;
364 }
365 
367  UINT minClassLabel = 99999;
368 
369  for(UINT i=0; i<classTracker.size(); i++){
370  if( classTracker[i].classLabel < minClassLabel ){
371  minClassLabel = classTracker[i].classLabel;
372  }
373  }
374 
375  return minClassLabel;
376 }
377 
378 
380  UINT maxClassLabel = 0;
381 
382  for(UINT i=0; i<classTracker.size(); i++){
383  if( classTracker[i].classLabel > maxClassLabel ){
384  maxClassLabel = classTracker[i].classLabel;
385  }
386  }
387 
388  return maxClassLabel;
389 }
390 
392  for(UINT k=0; k<classTracker.size(); k++){
393  if( classTracker[k].classLabel == classLabel ){
394  return k;
395  }
396  }
397  warningLog << "getClassLabelIndexValue(const UINT classLabel) - Failed to find class label: " << classLabel << " in class tracker!" << endl;
398  return 0;
399 }
400 
402 
403  for(UINT i=0; i<classTracker.size(); i++){
404  if( classTracker[i].classLabel == classLabel ){
405  return classTracker[i].className;
406  }
407  }
408  return "CLASS_LABEL_NOT_FOUND";
409 }
410 
412 
413  vector< MinMax > ranges(numDimensions);
414 
415  //If the dataset should be scaled using the external ranges then return the external ranges
416  if( useExternalRanges ) return externalRanges;
417 
418  //Otherwise return the min and max values for each column in the dataset
419  if( totalNumSamples > 0 ){
420  for(UINT j=0; j<numDimensions; j++){
421  ranges[j].minValue = data[0][0];
422  ranges[j].maxValue = data[0][0];
423  for(UINT i=0; i<totalNumSamples; i++){
424  if( data[i][j] < ranges[j].minValue ){ ranges[j].minValue = data[i][j]; } //Search for the min value
425  else if( data[i][j] > ranges[j].maxValue ){ ranges[j].maxValue = data[i][j]; } //Search for the max value
426  }
427  }
428  }
429  return ranges;
430 }
431 
432 bool TimeSeriesClassificationDataStream::save(const string &filename){
433 
434  //Check if the file should be saved as a csv file
435  if( Util::stringEndsWith( filename, ".csv" ) ){
436  return saveDatasetToCSVFile( filename );
437  }
438 
439  //Otherwise save it as a custom GRT file
440  return saveDatasetToFile( filename );
441 }
442 
443 bool TimeSeriesClassificationDataStream::load(const string &filename){
444 
445  //Check if the file should be loaded as a csv file
446  if( Util::stringEndsWith( filename, ".csv" ) ){
447  return loadDatasetFromCSVFile( filename );
448  }
449 
450  //Otherwise save it as a custom GRT file
451  return loadDatasetFromFile( filename );
452 }
453 
455 
456  std::fstream file;
457  file.open(filename.c_str(), std::ios::out);
458 
459  if( !file.is_open() ){
460  errorLog << "saveDatasetToFile(const string &filename) - Failed to open file!" << endl;
461  return false;
462  }
463 
464  if( trackingClass ){
465  //The class tracker was not stopped so assume the last sample is the end
466  trackingClass = false;
467  timeSeriesPositionTracker[ timeSeriesPositionTracker.size()-1 ].setEndIndex( totalNumSamples-1 );
468  }
469 
470  file << "GRT_LABELLED_CONTINUOUS_TIME_SERIES_CLASSIFICATION_FILE_V1.0\n";
471  file << "DatasetName: " << datasetName << endl;
472  file << "InfoText: " << infoText << endl;
473  file << "NumDimensions: "<<numDimensions<<endl;
474  file << "TotalNumSamples: "<<totalNumSamples<<endl;
475  file << "NumberOfClasses: "<<classTracker.size()<<endl;
476  file << "ClassIDsAndCounters: "<<endl;
477  for(UINT i=0; i<classTracker.size(); i++){
478  file << classTracker[i].classLabel << "\t" << classTracker[i].counter << endl;
479  }
480 
481  file << "NumberOfPositionTrackers: "<<timeSeriesPositionTracker.size()<<endl;
482  file << "TimeSeriesPositionTrackers: "<<endl;
483  for(UINT i=0; i<timeSeriesPositionTracker.size(); i++){
484  file << timeSeriesPositionTracker[i].getClassLabel() << "\t" << timeSeriesPositionTracker[i].getStartIndex() << "\t" << timeSeriesPositionTracker[i].getEndIndex() <<endl;
485  }
486 
487  file << "UseExternalRanges: " << useExternalRanges << endl;
488 
489  if( useExternalRanges ){
490  for(UINT i=0; i<externalRanges.size(); i++){
491  file << externalRanges[i].minValue << "\t" << externalRanges[i].maxValue << endl;
492  }
493  }
494 
495  file << "LabelledContinuousTimeSeriesClassificationData:\n";
496  for(UINT i=0; i<totalNumSamples; i++){
497  file << data[i].getClassLabel();
498  for(UINT j=0; j<numDimensions; j++){
499  file << "\t" << data[i][j];
500  }
501  file << endl;
502  }
503 
504  file.close();
505  return true;
506 }
507 
509 
510  std::fstream file;
511  file.open(filename.c_str(), std::ios::in);
512  UINT numClasses = 0;
513  UINT numTrackingPoints = 0;
514  clear();
515 
516  if( !file.is_open() ){
517  errorLog<< "loadDatasetFromFile(string fileName) - Failed to open file!" << endl;
518  return false;
519  }
520 
521  string word;
522 
523  //Check to make sure this is a file with the Training File Format
524  file >> word;
525  if(word != "GRT_LABELLED_CONTINUOUS_TIME_SERIES_CLASSIFICATION_FILE_V1.0"){
526  file.close();
527  errorLog<< "loadDatasetFromFile(string fileName) - Failed to find file header!" << endl;
528  return false;
529  }
530 
531  //Get the name of the dataset
532  file >> word;
533  if(word != "DatasetName:"){
534  errorLog << "loadDatasetFromFile(string filename) - failed to find DatasetName!" << endl;
535  file.close();
536  return false;
537  }
538  file >> datasetName;
539 
540  file >> word;
541  if(word != "InfoText:"){
542  errorLog << "loadDatasetFromFile(string filename) - failed to find InfoText!" << endl;
543  file.close();
544  return false;
545  }
546 
547  //Load the info text
548  file >> word;
549  infoText = "";
550  while( word != "NumDimensions:" ){
551  infoText += word + " ";
552  file >> word;
553  }
554 
555  //Get the number of dimensions in the training data
556  if(word != "NumDimensions:"){
557  errorLog<< "loadDatasetFromFile(string fileName) - Failed to find NumDimensions!" << endl;
558  file.close();
559  return false;
560  }
561  file >> numDimensions;
562 
563  //Get the total number of training examples in the training data
564  file >> word;
565  if(word != "TotalNumSamples:"){
566  errorLog<< "loadDatasetFromFile(string fileName) - Failed to find TotalNumSamples!" << endl;
567  file.close();
568  return false;
569  }
570  file >> totalNumSamples;
571 
572  //Get the total number of classes in the training data
573  file >> word;
574  if(word != "NumberOfClasses:"){
575  errorLog<< "loadDatasetFromFile(string fileName) - Failed to find NumberOfClasses!" << endl;
576  file.close();
577  return false;
578  }
579  file >> numClasses;
580 
581  //Resize the class counter buffer and load the counters
582  classTracker.resize(numClasses);
583 
584  //Get the total number of classes in the training data
585  file >> word;
586  if(word != "ClassIDsAndCounters:"){
587  errorLog<< "loadDatasetFromFile(string fileName) - Failed to find ClassIDsAndCounters!" << endl;
588  file.close();
589  return false;
590  }
591 
592  for(UINT i=0; i<classTracker.size(); i++){
593  file >> classTracker[i].classLabel;
594  file >> classTracker[i].counter;
595  }
596 
597  //Get the NumberOfPositionTrackers
598  file >> word;
599  if(word != "NumberOfPositionTrackers:"){
600  errorLog<< "loadDatasetFromFile(string fileName) - Failed to find NumberOfPositionTrackers!" << endl;
601  file.close();
602  return false;
603  }
604  file >> numTrackingPoints;
605  timeSeriesPositionTracker.resize( numTrackingPoints );
606 
607  //Get the TimeSeriesPositionTrackers
608  file >> word;
609  if(word != "TimeSeriesPositionTrackers:"){
610  errorLog<< "loadDatasetFromFile(string fileName) - Failed to find TimeSeriesPositionTrackers!" << endl;
611  file.close();
612  return false;
613  }
614 
615  for(UINT i=0; i<timeSeriesPositionTracker.size(); i++){
616  UINT classLabel;
617  UINT startIndex;
618  UINT endIndex;
619  file >> classLabel;
620  file >> startIndex;
621  file >> endIndex;
622  timeSeriesPositionTracker[i].setTracker(startIndex,endIndex,classLabel);
623  }
624 
625  //Check if the dataset should be scaled using external ranges
626  file >> word;
627  if(word != "UseExternalRanges:"){
628  errorLog << "loadDatasetFromFile(string filename) - failed to find DatasetName!" << endl;
629  file.close();
630  return false;
631  }
632  file >> useExternalRanges;
633 
634  //If we are using external ranges then load them
635  if( useExternalRanges ){
636  externalRanges.resize(numDimensions);
637  for(UINT i=0; i<externalRanges.size(); i++){
638  file >> externalRanges[i].minValue;
639  file >> externalRanges[i].maxValue;
640  }
641  }
642 
643  //Get the main time series data
644  file >> word;
645  if(word != "LabelledContinuousTimeSeriesClassificationData:"){
646  errorLog<< "loadDatasetFromFile(string fileName) - Failed to find LabelledContinuousTimeSeriesClassificationData!" << endl;
647  file.close();
648  return false;
649  }
650 
651  //Reset the memory
652  data.resize( totalNumSamples, ClassificationSample() );
653 
654  //Load each sample
655  for(UINT i=0; i<totalNumSamples; i++){
656  UINT classLabel = 0;
657  vector<double> sample(numDimensions);
658 
659  file >> classLabel;
660  for(UINT j=0; j<numDimensions; j++){
661  file >> sample[j];
662  }
663 
664  data[i].set(classLabel,sample);
665  }
666 
667  file.close();
668  return true;
669 }
670 
672  std::fstream file;
673  file.open(filename.c_str(), std::ios::out );
674 
675  if( !file.is_open() ){
676  return false;
677  }
678 
679  //Write the data to the CSV file
680 
681  for(UINT i=0; i<data.size(); i++){
682  file << data[i].getClassLabel();
683  for(UINT j=0; j<numDimensions; j++){
684  file << "," << data[i][j];
685  }
686  file << endl;
687  }
688 
689  file.close();
690 
691  return true;
692 }
693 
694 bool TimeSeriesClassificationDataStream::loadDatasetFromCSVFile(const string &filename,const UINT classLabelColumnIndex){
695 
696  datasetName = "NOT_SET";
697  infoText = "";
698 
699  //Clear any previous data
700  clear();
701 
702  //Parse the CSV file
703  FileParser parser;
704 
705  if( !parser.parseCSVFile(filename,true) ){
706  errorLog << "loadDatasetFromCSVFile(const string filename,const UINT classLabelColumnIndex) - Failed to parse CSV file!" << endl;
707  return false;
708  }
709 
710  if( !parser.getConsistentColumnSize() ){
711  errorLog << "loadDatasetFromCSVFile(const string filename,const UINT classLabelColumnIndex) - The CSV file does not have a consistent number of columns!" << endl;
712  return false;
713  }
714 
715  if( parser.getColumnSize() <= 1 ){
716  errorLog << "loadDatasetFromCSVFile(const string filename,const UINT classLabelColumnIndex) - The CSV file does not have enough columns! It should contain at least two columns!" << endl;
717  return false;
718  }
719 
720  //Set the number of dimensions
721  numDimensions = parser.getColumnSize()-1;
722  UINT classLabel = 0;
723  UINT j = 0;
724  UINT n = 0;
725  VectorDouble sample(numDimensions);
726  for(UINT i=0; i<parser.getRowSize(); i++){
727  //Get the class label
728  classLabel = Util::stringToInt( parser[i][classLabelColumnIndex] );
729 
730  //Get the sample data
731  j=0;
732  n=0;
733  while( j != numDimensions ){
734  if( n != classLabelColumnIndex ){
735  sample[j++] = Util::stringToDouble( parser[i][n] );
736  }
737  n++;
738  }
739 
740  //Add the labelled sample to the dataset
741  if( !addSample(classLabel, sample) ){
742  warningLog << "loadDatasetFromCSVFile(const string filename,const UINT classLabelColumnIndex) - Could not add sample " << i << " to the dataset!" << endl;
743  }
744  }
745 
746  return true;
747 }
748 
750 
751  cout << "DatasetName:\t" << datasetName << endl;
752  cout << "DatasetInfo:\t" << infoText << endl;
753  cout << "Number of Dimensions:\t" << numDimensions << endl;
754  cout << "Number of Samples:\t" << totalNumSamples << endl;
755  cout << "Number of Classes:\t" << getNumClasses() << endl;
756  cout << "ClassStats:\n";
757 
758  for(UINT k=0; k<getNumClasses(); k++){
759  cout << "ClassLabel:\t" << classTracker[k].classLabel;
760  cout << "\tNumber of Samples:\t" << classTracker[k].counter;
761  cout << "\tClassName:\t" << classTracker[k].className << endl;
762  }
763 
764  cout << "TimeSeriesMarkerStats:\n";
765  for(UINT i=0; i<timeSeriesPositionTracker.size(); i++){
766  cout << "ClassLabel: " << timeSeriesPositionTracker[i].getClassLabel();
767  cout << "\tStartIndex: " << timeSeriesPositionTracker[i].getStartIndex();
768  cout << "\tEndIndex: " << timeSeriesPositionTracker[i].getEndIndex();
769  cout << "\tLength: " << timeSeriesPositionTracker[i].getLength() << endl;
770  }
771 
772  vector< MinMax > ranges = getRanges();
773 
774  cout << "Dataset Ranges:\n";
775  for(UINT j=0; j<ranges.size(); j++){
776  cout << "[" << j+1 << "] Min:\t" << ranges[j].minValue << "\tMax: " << ranges[j].maxValue << endl;
777  }
778 
779  return true;
780 }
781 
783 
785 
786  if( endIndex >= totalNumSamples ){
787  warningLog << "getSubset(const UINT startIndex,const UINT endIndex) - The endIndex is greater than or equal to the number of samples in the current dataset!" << endl;
788  return subset;
789  }
790 
791  if( startIndex >= endIndex ){
792  warningLog << "getSubset(const UINT startIndex,const UINT endIndex) - The startIndex is greater than or equal to the endIndex!" << endl;
793  return subset;
794  }
795 
796  //Set the header info
798  subset.setDatasetName( getDatasetName() );
799  subset.setInfoText( getInfoText() );
800 
801  //Add the data
802  for(UINT i=startIndex; i<=endIndex; i++){
803  subset.addSample(data[i].getClassLabel(), data[i].getSample());
804  }
805 
806  return subset;
807 }
808 
810 
812 
814  tsData.setAllowNullGestureClass( includeNullGestures );
815 
816  bool addSample = false;
817  const UINT numTimeseries = (UINT)timeSeriesPositionTracker.size();
818  for(UINT i=0; i<numTimeseries; i++){
819  addSample = includeNullGestures ? true : timeSeriesPositionTracker[i].getClassLabel() != GRT_DEFAULT_NULL_CLASS_LABEL;
820  if( addSample ){
821  tsData.addSample(timeSeriesPositionTracker[i].getClassLabel(), getTimeSeriesData( timeSeriesPositionTracker[i] ) );
822  }
823  }
824 
825  return tsData;
826 }
827 
829 
830  ClassificationData classificationData;
831 
832  classificationData.setNumDimensions( getNumDimensions() );
833  classificationData.setAllowNullGestureClass( includeNullGestures );
834 
835  bool addSample = false;
836  for(UINT i=0; i<timeSeriesPositionTracker.size(); i++){
837  addSample = includeNullGestures ? true : timeSeriesPositionTracker[i].getClassLabel() != GRT_DEFAULT_NULL_CLASS_LABEL;
838  if( addSample ){
839  MatrixDouble dataSegment = getTimeSeriesData( timeSeriesPositionTracker[i] );
840  for(UINT j=0; j<dataSegment.getNumRows(); j++){
841  classificationData.addSample(timeSeriesPositionTracker[i].getClassLabel(), dataSegment.getRowVector(j) );
842  }
843  }
844  }
845 
846  return classificationData;
847 }
848 
850 
851  if( trackerInfo.getStartIndex() >= totalNumSamples || trackerInfo.getEndIndex() > totalNumSamples ){
852  warningLog << "getTimeSeriesData(TimeSeriesPositionTracker trackerInfo) - Invalid tracker indexs!" << endl;
853  return MatrixDouble();
854  }
855 
856  UINT startIndex = trackerInfo.getStartIndex();
857  UINT endIndex = trackerInfo.getEndIndex();
858  UINT M = endIndex > 0 ? trackerInfo.getLength() : totalNumSamples - startIndex;
859  UINT N = getNumDimensions();
860 
861  MatrixDouble tsData(M,N);
862  for(UINT i=0; i<M; i++){
863  for(UINT j=0; j<N; j++){
864  tsData[i][j] = data[ i+startIndex ][j];
865  }
866  }
867  return tsData;
868 }
869 
871  UINT M = getNumSamples();
872  UINT N = getNumDimensions();
873  MatrixDouble matrixData(M,N);
874  for(UINT i=0; i<M; i++){
875  for(UINT j=0; j<N; j++){
876  matrixData[i][j] = data[i][j];
877  }
878  }
879  return matrixData;
880 }
881 
883  const UINT K = (UINT)classTracker.size();
884  vector< UINT > classLabels( K );
885 
886  for(UINT i=0; i<K; i++){
887  classLabels[i] = classTracker[i].classLabel;
888  }
889 
890  return classLabels;
891 }
892 
893 } //End of namespace GRT
894 
The TimeSeriesClassificationDataStream is the main data structure for recording, labeling, managing, saving, and loading datasets that can be used to test the continuous classification abilities of the GRT supervised temporal learning algorithms.
TimeSeriesClassificationDataStream getSubset(const UINT startIndex, const UINT endIndex) const
bool setAllowNullGestureClass(bool allowNullGestureClass)
vector< MinMax > externalRanges
A vector containing a set of externalRanges set by the user.
MatrixDouble getTimeSeriesData(const TimeSeriesPositionTracker &trackerInfo) const
TimeSeriesClassificationDataStream(const UINT numDimensions=0, const string datasetName="NOT_SET", const string infoText="")
Definition: AdaBoost.cpp:25
bool push_back(const std::vector< T > &sample)
Definition: Matrix.h:390
static double scale(const double &x, const double &minSource, const double &maxSource, const double &minTarget, const double &maxTarget, const bool constrain=false)
Definition: Util.cpp:44
bool setNumDimensions(UINT numDimensions)
bool setExternalRanges(const vector< MinMax > &externalRanges, const bool useExternalRanges=false)
bool setNumDimensions(const UINT numDimensions)
TimeSeriesClassificationData getTimeSeriesClassificationData(const bool includeNullGestures=false) const
bool addSample(const UINT classLabel, const MatrixDouble &trainingSample)
TimeSeriesClassificationData getAllTrainingExamplesWithClassLabel(const UINT classLabel) const
static double stringToDouble(const std::string &s)
Definition: Util.cpp:124
bool useExternalRanges
A flag to show if the dataset should be scaled using the externalRanges values.
UINT numDimensions
The number of dimensions in the dataset.
TimeSeriesClassificationDataStream & operator=(const TimeSeriesClassificationDataStream &rhs)
bool enableExternalRangeScaling(const bool useExternalRanges)
bool relabelAllSamplesWithClassLabel(const UINT oldClassLabel, const UINT newClassLabel)
unsigned int getNumRows() const
Definition: Matrix.h:531
static int stringToInt(const std::string &s)
Definition: Util.cpp:117
bool scale(const double minTarget, const double maxTarget)
static bool stringEndsWith(const std::string &str, const std::string &ending)
Definition: Util.cpp:141
bool setClassNameForCorrespondingClassLabel(const string className, const UINT classLabel)
bool addSample(const UINT classLabel, const VectorDouble &trainingSample)
bool addSample(UINT classLabel, const VectorDouble &sample)
string infoText
Some infoText about the dataset.
bool loadDatasetFromCSVFile(const string &filename, const UINT classLabelColumnIndex=0)
std::vector< T > getRowVector(const unsigned int r) const
Definition: Matrix.h:173
ClassificationData getClassificationData(const bool includeNullGestures=false) const
bool setAllowNullGestureClass(const bool allowNullGestureClass)