33 trackingClass =
false;
35 debugLog.setProceedingText(
"[DEBUG LTSCD]");
36 errorLog.setProceedingText(
"[ERROR LTSCD]");
37 warningLog.setProceedingText(
"[WARNING LTSCD]");
39 if( numDimensions > 0 ){
55 this->totalNumSamples = rhs.totalNumSamples;
56 this->lastClassID = rhs.lastClassID;
57 this->playbackIndex = rhs.playbackIndex;
58 this->trackingClass = rhs.trackingClass;
61 this->data = rhs.data;
62 this->classTracker = rhs.classTracker;
63 this->timeSeriesPositionTracker = rhs.timeSeriesPositionTracker;
75 trackingClass =
false;
78 timeSeriesPositionTracker.clear();
82 if( numDimensions > 0 ){
92 errorLog <<
"setNumDimensions(const UINT numDimensions) - The number of dimensions of the dataset must be greater than zero!" << endl;
100 if( datasetName.find(
" ") == string::npos ){
105 errorLog <<
"setDatasetName(const string datasetName) - The dataset name cannot contain any spaces!" << endl;
116 for(UINT i=0; i<classTracker.size(); i++){
117 if( classTracker[i].classLabel == classLabel ){
118 classTracker[i].className = className;
123 errorLog <<
"setClassNameForCorrespondingClassLabel(const string className,const UINT classLabel) - Failed to find class with label: " << classLabel << endl;
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;
134 bool searchForNewClass =
true;
136 if( classLabel != lastClassID ){
138 timeSeriesPositionTracker[ timeSeriesPositionTracker.size()-1 ].setEndIndex( totalNumSamples-1 );
139 }
else searchForNewClass =
false;
142 if( searchForNewClass ){
143 bool newClass =
true;
145 for(UINT k=0; k<classTracker.size(); k++){
146 if( classTracker[k].classLabel == classLabel ){
148 classTracker[k].counter++;
153 classTracker.push_back( newCounter );
157 trackingClass =
true;
158 lastClassID = classLabel;
160 timeSeriesPositionTracker.push_back( newTracker );
164 data.push_back( labelledSample );
171 if( totalNumSamples > 0 ){
174 UINT classLabel = data[ totalNumSamples-1 ].getClassLabel();
177 data.erase( data.end()-1 );
179 totalNumSamples = (UINT)data.size();
182 for(UINT i=0; i<classTracker.size(); i++){
183 if( classTracker[i].classLabel == classLabel ){
184 classTracker[i].counter--;
190 if( !trackingClass ){
191 UINT endIndex = timeSeriesPositionTracker[ timeSeriesPositionTracker.size()-1 ].getEndIndex();
192 timeSeriesPositionTracker[ timeSeriesPositionTracker.size()-1 ].setEndIndex( endIndex-1 );
202 UINT numExamplesRemoved = 0;
203 UINT numExamplesToRemove = 0;
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);
215 if( numExamplesToRemove > 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;
226 vector< TimeSeriesPositionTracker >::iterator iter = timeSeriesPositionTracker.begin();
228 while( iter != timeSeriesPositionTracker.end() ){
229 if( iter->getClassLabel() == classLabel ){
230 UINT length = iter->getLength();
232 vector< TimeSeriesPositionTracker >::iterator updateIter = iter + 1;
234 while( updateIter != timeSeriesPositionTracker.end() ){
235 updateIter->setStartIndex( updateIter->getStartIndex() - length );
236 updateIter->setEndIndex( updateIter->getEndIndex() - length );
241 iter = timeSeriesPositionTracker.erase( iter );
245 totalNumSamples = (UINT)data.size();
247 return numExamplesRemoved;
251 bool oldClassLabelFound =
false;
252 bool newClassLabelAllReadyExists =
false;
253 UINT indexOfOldClassLabel = 0;
254 UINT indexOfNewClassLabel = 0;
257 for(UINT i=0; i<classTracker.size(); i++){
258 if( classTracker[i].classLabel == oldClassLabel ){
259 indexOfOldClassLabel = i;
260 oldClassLabelFound =
true;
262 if( classTracker[i].classLabel == newClassLabel ){
263 indexOfNewClassLabel = i;
264 newClassLabelAllReadyExists =
true;
269 if( !oldClassLabelFound ){
274 for(UINT i=0; i<totalNumSamples; i++){
275 if( data[i].getClassLabel() == oldClassLabel ){
276 data[i].set(newClassLabel, data[i].getSample());
281 if( newClassLabelAllReadyExists ){
283 classTracker[ indexOfNewClassLabel ].counter += classTracker[ indexOfOldClassLabel ].counter;
286 classTracker.erase( classTracker.begin() + indexOfOldClassLabel );
289 classTracker.push_back(
ClassTracker(newClassLabel,classTracker[ indexOfOldClassLabel ].counter,classTracker[ indexOfOldClassLabel ].className) );
293 for(UINT i=0; i<timeSeriesPositionTracker.size(); i++){
294 if( timeSeriesPositionTracker[i].getClassLabel() == oldClassLabel ){
295 timeSeriesPositionTracker[i].setClassLabel( newClassLabel );
322 return scale(ranges,minTarget,maxTarget);
329 for(UINT i=0; i<totalNumSamples; i++){
331 data[i][j] =
Util::scale(data[i][j],ranges[j].minValue,ranges[j].maxValue,minTarget,maxTarget);
338 if( playbackIndex < totalNumSamples ){
339 this->playbackIndex = playbackIndex;
348 UINT index = playbackIndex++ % totalNumSamples;
349 return data[ index ];
354 for(UINT x=0; x<timeSeriesPositionTracker.size(); x++){
355 if( timeSeriesPositionTracker[x].getClassLabel() == classLabel && timeSeriesPositionTracker[x].getEndIndex() > 0){
357 for(UINT i=timeSeriesPositionTracker[x].getStartIndex(); i<timeSeriesPositionTracker[x].getEndIndex(); i++){
358 timeSeries.
push_back( data[ i ].getSample() );
360 classData.
addSample(classLabel,timeSeries);
367 UINT minClassLabel = 99999;
369 for(UINT i=0; i<classTracker.size(); i++){
370 if( classTracker[i].classLabel < minClassLabel ){
371 minClassLabel = classTracker[i].classLabel;
375 return minClassLabel;
380 UINT maxClassLabel = 0;
382 for(UINT i=0; i<classTracker.size(); i++){
383 if( classTracker[i].classLabel > maxClassLabel ){
384 maxClassLabel = classTracker[i].classLabel;
388 return maxClassLabel;
392 for(UINT k=0; k<classTracker.size(); k++){
393 if( classTracker[k].classLabel == classLabel ){
397 warningLog <<
"getClassLabelIndexValue(const UINT classLabel) - Failed to find class label: " << classLabel <<
" in class tracker!" << endl;
403 for(UINT i=0; i<classTracker.size(); i++){
404 if( classTracker[i].classLabel == classLabel ){
405 return classTracker[i].className;
408 return "CLASS_LABEL_NOT_FOUND";
419 if( totalNumSamples > 0 ){
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]; }
425 else if( data[i][j] > ranges[j].maxValue ){ ranges[j].maxValue = data[i][j]; }
457 file.open(filename.c_str(), std::ios::out);
459 if( !file.is_open() ){
460 errorLog <<
"saveDatasetToFile(const string &filename) - Failed to open file!" << endl;
466 trackingClass =
false;
467 timeSeriesPositionTracker[ timeSeriesPositionTracker.size()-1 ].setEndIndex( totalNumSamples-1 );
470 file <<
"GRT_LABELLED_CONTINUOUS_TIME_SERIES_CLASSIFICATION_FILE_V1.0\n";
472 file <<
"InfoText: " <<
infoText << 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;
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;
495 file <<
"LabelledContinuousTimeSeriesClassificationData:\n";
496 for(UINT i=0; i<totalNumSamples; i++){
497 file << data[i].getClassLabel();
499 file <<
"\t" << data[i][j];
511 file.open(filename.c_str(), std::ios::in);
513 UINT numTrackingPoints = 0;
516 if( !file.is_open() ){
517 errorLog<<
"loadDatasetFromFile(string fileName) - Failed to open file!" << endl;
525 if(word !=
"GRT_LABELLED_CONTINUOUS_TIME_SERIES_CLASSIFICATION_FILE_V1.0"){
527 errorLog<<
"loadDatasetFromFile(string fileName) - Failed to find file header!" << endl;
533 if(word !=
"DatasetName:"){
534 errorLog <<
"loadDatasetFromFile(string filename) - failed to find DatasetName!" << endl;
541 if(word !=
"InfoText:"){
542 errorLog <<
"loadDatasetFromFile(string filename) - failed to find InfoText!" << endl;
550 while( word !=
"NumDimensions:" ){
556 if(word !=
"NumDimensions:"){
557 errorLog<<
"loadDatasetFromFile(string fileName) - Failed to find NumDimensions!" << endl;
565 if(word !=
"TotalNumSamples:"){
566 errorLog<<
"loadDatasetFromFile(string fileName) - Failed to find TotalNumSamples!" << endl;
570 file >> totalNumSamples;
574 if(word !=
"NumberOfClasses:"){
575 errorLog<<
"loadDatasetFromFile(string fileName) - Failed to find NumberOfClasses!" << endl;
582 classTracker.resize(numClasses);
586 if(word !=
"ClassIDsAndCounters:"){
587 errorLog<<
"loadDatasetFromFile(string fileName) - Failed to find ClassIDsAndCounters!" << endl;
592 for(UINT i=0; i<classTracker.size(); i++){
593 file >> classTracker[i].classLabel;
594 file >> classTracker[i].counter;
599 if(word !=
"NumberOfPositionTrackers:"){
600 errorLog<<
"loadDatasetFromFile(string fileName) - Failed to find NumberOfPositionTrackers!" << endl;
604 file >> numTrackingPoints;
605 timeSeriesPositionTracker.resize( numTrackingPoints );
609 if(word !=
"TimeSeriesPositionTrackers:"){
610 errorLog<<
"loadDatasetFromFile(string fileName) - Failed to find TimeSeriesPositionTrackers!" << endl;
615 for(UINT i=0; i<timeSeriesPositionTracker.size(); i++){
622 timeSeriesPositionTracker[i].setTracker(startIndex,endIndex,classLabel);
627 if(word !=
"UseExternalRanges:"){
628 errorLog <<
"loadDatasetFromFile(string filename) - failed to find DatasetName!" << endl;
635 if( useExternalRanges ){
645 if(word !=
"LabelledContinuousTimeSeriesClassificationData:"){
646 errorLog<<
"loadDatasetFromFile(string fileName) - Failed to find LabelledContinuousTimeSeriesClassificationData!" << endl;
655 for(UINT i=0; i<totalNumSamples; i++){
657 vector<double> sample(numDimensions);
664 data[i].set(classLabel,sample);
673 file.open(filename.c_str(), std::ios::out );
675 if( !file.is_open() ){
681 for(UINT i=0; i<data.size(); i++){
682 file << data[i].getClassLabel();
684 file <<
"," << data[i][j];
705 if( !parser.parseCSVFile(filename,
true) ){
706 errorLog <<
"loadDatasetFromCSVFile(const string filename,const UINT classLabelColumnIndex) - Failed to parse CSV file!" << endl;
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;
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;
726 for(UINT i=0; i<parser.getRowSize(); i++){
734 if( n != classLabelColumnIndex ){
742 warningLog <<
"loadDatasetFromCSVFile(const string filename,const UINT classLabelColumnIndex) - Could not add sample " << i <<
" to the dataset!" << endl;
752 cout <<
"DatasetInfo:\t" <<
infoText << endl;
754 cout <<
"Number of Samples:\t" << totalNumSamples << endl;
756 cout <<
"ClassStats:\n";
759 cout <<
"ClassLabel:\t" << classTracker[k].classLabel;
760 cout <<
"\tNumber of Samples:\t" << classTracker[k].counter;
761 cout <<
"\tClassName:\t" << classTracker[k].className << endl;
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;
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;
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;
791 if( startIndex >= endIndex ){
792 warningLog <<
"getSubset(const UINT startIndex,const UINT endIndex) - The startIndex is greater than or equal to the endIndex!" << endl;
802 for(UINT i=startIndex; i<=endIndex; i++){
803 subset.
addSample(data[i].getClassLabel(), data[i].getSample());
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;
836 for(UINT i=0; i<timeSeriesPositionTracker.size(); i++){
837 addSample = includeNullGestures ?
true : timeSeriesPositionTracker[i].getClassLabel() != GRT_DEFAULT_NULL_CLASS_LABEL;
840 for(UINT j=0; j<dataSegment.
getNumRows(); j++){
841 classificationData.
addSample(timeSeriesPositionTracker[i].getClassLabel(), dataSegment.
getRowVector(j) );
846 return classificationData;
852 warningLog <<
"getTimeSeriesData(TimeSeriesPositionTracker trackerInfo) - Invalid tracker indexs!" << endl;
858 UINT M = endIndex > 0 ? trackerInfo.
getLength() : totalNumSamples - startIndex;
862 for(UINT i=0; i<M; i++){
863 for(UINT j=0; j<N; j++){
864 tsData[i][j] = data[ i+startIndex ][j];
874 for(UINT i=0; i<M; i++){
875 for(UINT j=0; j<N; j++){
876 matrixData[i][j] = data[i][j];
883 const UINT K = (UINT)classTracker.size();
884 vector< UINT > classLabels( K );
886 for(UINT i=0; i<K; i++){
887 classLabels[i] = classTracker[i].classLabel;
WarningLog warningLog
Default warning log.
UINT getNumDimensions() const
ClassificationSample getNextSample()
DebugLog debugLog
Default debugging log.
UINT getNumClasses() const
UINT getMinimumClassLabel() const
bool load(const string &filename)
UINT getClassLabelIndexValue(const UINT classLabel) const
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.
bool resetPlaybackIndex(const UINT playbackIndex)
string getClassNameForCorrespondingClassLabel(const UINT classLabel)
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
bool saveDatasetToFile(const string &filename)
UINT getMaximumClassLabel() const
string getDatasetName() const
vector< UINT > getClassLabels() const
TimeSeriesClassificationDataStream(const UINT numDimensions=0, const string datasetName="NOT_SET", const string infoText="")
bool push_back(const std::vector< T > &sample)
static double scale(const double &x, const double &minSource, const double &maxSource, const double &minTarget, const double &maxTarget, const bool constrain=false)
bool setNumDimensions(UINT numDimensions)
UINT getNumSamples() const
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)
string datasetName
The name of the dataset.
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 setNumDimensions(const UINT numDimensions)
bool saveDatasetToCSVFile(const string &filename)
bool enableExternalRangeScaling(const bool useExternalRanges)
bool setDatasetName(const string datasetName)
vector< MinMax > getRanges() const
bool relabelAllSamplesWithClassLabel(const UINT oldClassLabel, const UINT newClassLabel)
string getInfoText() const
MatrixDouble getDataAsMatrixDouble() const
ErrorLog errorLog
Default error log.
unsigned int getNumRows() const
static int stringToInt(const std::string &s)
bool scale(const double minTarget, const double maxTarget)
static bool stringEndsWith(const std::string &str, const std::string &ending)
bool save(const string &filename)
UINT eraseAllSamplesWithClassLabel(const UINT classLabel)
bool setClassNameForCorrespondingClassLabel(const string className, const UINT classLabel)
bool loadDatasetFromFile(const string &filename)
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
UINT getStartIndex() const
bool setInfoText(const string infoText)
virtual ~TimeSeriesClassificationDataStream()
ClassificationData getClassificationData(const bool includeNullGestures=false) const
bool setAllowNullGestureClass(const bool allowNullGestureClass)