21 #define GRT_DLL_EXPORTS
29 DTW::DTW(
bool useScaling,
bool useNullRejection,Float nullRejectionCoeff,UINT rejectionMode,
bool constrainWarpingPath,Float radius,
bool offsetUsingFirstSample,
bool useSmoothing,UINT smoothingFactor,Float nullRejectionLikelihoodThreshold){
31 this->useScaling=useScaling;
32 this->useNullRejection = useNullRejection;
33 this->nullRejectionCoeff = nullRejectionCoeff;
34 this->nullRejectionLikelihoodThreshold = nullRejectionLikelihoodThreshold;
35 this->rejectionMode = rejectionMode;
36 this->constrainWarpingPath = constrainWarpingPath;
37 this->radius = radius;
38 this->offsetUsingFirstSample = offsetUsingFirstSample;
39 this->useSmoothing = useSmoothing;
40 this->smoothingFactor = smoothingFactor;
42 supportsNullRejection =
true;
44 useZNormalisation=
false;
46 trimTrainingData =
false;
48 zNormConstrainThreshold=0.2;
50 maximumTrimPercentage = 90;
53 distanceMethod=EUCLIDEAN_DIST;
55 averageTemplateLength =0;
58 classifierType = classType;
59 classifierMode = TIMESERIES_CLASSIFIER_MODE;
60 debugLog.setProceedingText(
"[DEBUG NDDTW]");
61 errorLog.setProceedingText(
"[ERROR NDDTW]");
62 trainingLog.setProceedingText(
"[TRAINING NDDTW]");
63 warningLog.setProceedingText(
"[WARNING NDDTW]");
77 this->templatesBuffer = rhs.templatesBuffer;
78 this->distanceMatrices = rhs.distanceMatrices;
79 this->warpPaths = rhs.warpPaths;
80 this->continuousInputDataBuffer = rhs.continuousInputDataBuffer;
81 this->numTemplates = rhs.numTemplates;
82 this->useSmoothing = rhs.useSmoothing;
83 this->useZNormalisation = rhs.useZNormalisation;
84 this->constrainZNorm = rhs.constrainZNorm;
85 this->constrainWarpingPath = rhs.constrainWarpingPath;
86 this->trimTrainingData = rhs.trimTrainingData;
87 this->zNormConstrainThreshold = rhs.zNormConstrainThreshold;
88 this->radius = rhs.radius;
89 this->offsetUsingFirstSample = rhs.offsetUsingFirstSample;
90 this->trimThreshold = rhs.trimThreshold;
91 this->maximumTrimPercentage = rhs.maximumTrimPercentage;
92 this->smoothingFactor = rhs.smoothingFactor;
93 this->distanceMethod = rhs.distanceMethod;
94 this->rejectionMode = rhs.rejectionMode;
95 this->nullRejectionLikelihoodThreshold = rhs.nullRejectionLikelihoodThreshold;
96 this->averageTemplateLength = rhs.averageTemplateLength;
107 if( classifier == NULL )
return false;
111 DTW *ptr = (
DTW*)classifier;
112 this->templatesBuffer = ptr->templatesBuffer;
113 this->distanceMatrices = ptr->distanceMatrices;
114 this->warpPaths = ptr->warpPaths;
115 this->continuousInputDataBuffer = ptr->continuousInputDataBuffer;
116 this->numTemplates = ptr->numTemplates;
117 this->useSmoothing = ptr->useSmoothing;
118 this->useZNormalisation = ptr->useZNormalisation;
119 this->constrainZNorm = ptr->constrainZNorm;
120 this->constrainWarpingPath = ptr->constrainWarpingPath;
121 this->trimTrainingData = ptr->trimTrainingData;
122 this->zNormConstrainThreshold = ptr->zNormConstrainThreshold;
123 this->radius = ptr->radius;
124 this->offsetUsingFirstSample = ptr->offsetUsingFirstSample;
125 this->trimThreshold = ptr->trimThreshold;
126 this->maximumTrimPercentage = ptr->maximumTrimPercentage;
127 this->smoothingFactor = ptr->smoothingFactor;
128 this->distanceMethod = ptr->distanceMethod;
129 this->rejectionMode = ptr->rejectionMode;
130 this->nullRejectionLikelihoodThreshold = ptr->nullRejectionLikelihoodThreshold;
131 this->averageTemplateLength = ptr->averageTemplateLength;
146 templatesBuffer.clear();
149 continuousInputDataBuffer.
clear();
151 if( trimTrainingData ){
158 tempData.
addSample(data[i].getClassLabel(), data[i].getData());
160 trainingLog <<
"Removing training sample " << i <<
" from the dataset as it could not be trimmed!" << std::endl;
168 errorLog <<
"train_(TimeSeriesClassificationData &trainingData) - Can't train model as there are no samples in training data!" << std::endl;
176 templatesBuffer.
resize( numClasses );
177 classLabels.
resize( numClasses );
178 nullRejectionThresholds.
resize( numClasses );
179 averageTemplateLength = 0;
186 if( useScaling ) scaleData( trainingData );
187 if( useZNormalisation ) znormData( trainingData );
190 for(UINT k=0; k<numTemplates; k++){
198 templatesBuffer[k].classLabel = classLabel;
201 classLabels[k] = classLabel;
203 trainingLog <<
"Training Template: " << k <<
" Class: " << classLabel << std::endl;
206 if( numExamples < 1 ){
207 errorLog <<
"train_(TimeSeriesClassificationData &labelledTrainingData) - Can not train model: Num of Example is < 1! Class: " << classLabel <<
". Turn off null rejection if you want to use DTW with only 1 training sample per class." << std::endl;
211 if( numExamples == 1 && useNullRejection ){
212 errorLog <<
"train_(TimeSeriesClassificationData &labelledTrainingData) - Can not train model as there is only 1 example in class: " << classLabel <<
". Turn off null rejection if you want to use DTW with only 1 training sample per class." << std::endl;
216 if( numExamples == 1 ){
218 nullRejectionThresholds[k] = 0.0;
221 if( !train_NDDTW(classData,templatesBuffer[k],bestIndex) ){
222 errorLog <<
"train_(LabelledTimeSeriesClassificationData &labelledTrainingData) - Failed to train template for class with label: " << classLabel << std::endl;
228 int trainingMethod = 0;
229 if(useSmoothing) trainingMethod = 1;
231 switch (trainingMethod) {
233 templatesBuffer[k].timeSeries = classData[bestIndex].getData();
237 smoothData(classData[ bestIndex ].getData(),smoothingFactor,templatesBuffer[k].timeSeries);
240 errorLog <<
"Can not train model: Unknown training method " << std::endl;
245 if( offsetUsingFirstSample ){
246 offsetTimeseries( templatesBuffer[k].timeSeries );
250 averageTemplateLength += templatesBuffer[k].averageTemplateLength;
255 averageTemplateLength = averageTemplateLength/numTemplates;
261 continuousInputDataBuffer.
clear();
262 continuousInputDataBuffer.
resize(averageTemplateLength,
VectorFloat(numInputDimensions,0));
264 classDistances.
resize(numTemplates,0);
265 predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
276 MatrixFloat distanceResults(numExamples,numExamples);
277 dtwTemplate.averageTemplateLength = 0;
279 for(UINT m=0; m<numExamples; m++){
283 dtwTemplate.averageTemplateLength += trainingData[m].getLength();
286 if( useSmoothing ) smoothData(trainingData[m].getData(),smoothingFactor,templateA);
287 else templateA = trainingData[m].getData();
289 if( offsetUsingFirstSample ){
290 offsetTimeseries(templateA);
293 for(UINT n=0; n<numExamples; n++){
296 if( useSmoothing ) smoothData(trainingData[n].getData(),smoothingFactor,templateB);
297 else templateB = trainingData[n].getData();
299 if( offsetUsingFirstSample ){
300 offsetTimeseries(templateB);
306 Float dist = computeDistance(templateA,templateB,distanceMatrix,warpPath);
308 trainingLog <<
"Template: " << m <<
" Timeseries: " << n <<
" Dist: " << dist << std::endl;
311 distanceResults[m][n] = dist;
313 }
else distanceResults[m][n] = 0;
317 for(UINT m=0; m<numExamples; m++) results[m]/=(numExamples-1);
320 Float bestAverage = results[0];
321 for(UINT m=1; m<numExamples; m++){
322 if( results[m] < bestAverage ){
323 bestAverage = results[m];
328 if( numExamples > 2 ){
330 dtwTemplate.trainingMu = results[bestIndex];
331 dtwTemplate.trainingSigma = 0.0;
333 for(UINT n=0; n<numExamples; n++){
335 dtwTemplate.trainingSigma += SQR( distanceResults[ bestIndex ][n] - dtwTemplate.trainingMu );
338 dtwTemplate.trainingSigma = sqrt( dtwTemplate.trainingSigma / Float(numExamples-2) );
340 warningLog <<
"_train_NDDTW(TimeSeriesClassificationData &trainingData,DTWTemplate &dtwTemplate,UINT &bestIndex - There are not enough examples to compute the trainingMu and trainingSigma for the template for class " << dtwTemplate.classLabel << std::endl;
341 dtwTemplate.trainingMu = 0.0;
342 dtwTemplate.trainingSigma = 0.0;
346 dtwTemplate.averageTemplateLength = (UINT) (dtwTemplate.averageTemplateLength/Float(numExamples));
348 trainingLog <<
"AverageTemplateLength: " << dtwTemplate.averageTemplateLength << std::endl;
358 errorLog <<
"predict_(MatrixFloat &inputTimeSeries) - The DTW templates have not been trained!" << std::endl;
362 if( classLikelihoods.size() != numTemplates ) classLikelihoods.
resize(numTemplates);
363 if( classDistances.size() != numTemplates ) classDistances.
resize(numTemplates);
365 predictedClassLabel = 0;
367 for(UINT k=0; k<classLikelihoods.size(); k++){
368 classLikelihoods[k] = 0;
372 if( numInputDimensions != inputTimeSeries.
getNumCols() ){
373 errorLog <<
"predict_(MatrixFloat &inputTimeSeries) - The number of features in the model (" << numInputDimensions <<
") do not match that of the input time series (" << inputTimeSeries.
getNumCols() <<
")" << std::endl;
382 scaleData(*timeSeriesPtr,processedTimeSeries);
383 timeSeriesPtr = &processedTimeSeries;
387 if( useZNormalisation ){
388 znormData(*timeSeriesPtr,processedTimeSeries);
389 timeSeriesPtr = &processedTimeSeries;
394 smoothData(*timeSeriesPtr,smoothingFactor,tempMatrix);
395 timeSeriesPtr = &tempMatrix;
399 if( offsetUsingFirstSample ){
400 offsetTimeseries( *timeSeriesPtr );
405 if( distanceMatrices.size() != numTemplates ) distanceMatrices.
resize( numTemplates );
406 if( warpPaths.size() != numTemplates ) warpPaths.
resize( numTemplates );
409 for(UINT k=0; k<numTemplates; k++){
411 classDistances[k] = computeDistance(templatesBuffer[k].timeSeries,*timeSeriesPtr,distanceMatrices[k],warpPaths[k]);
413 if(classDistances[k] > 1e-8)
415 classLikelihoods[k] = 1.0 / classDistances[k];
419 classLikelihoods[k] = 1e8;
422 sum += classLikelihoods[k];
426 UINT closestTemplateIndex = 0;
427 bestDistance = classDistances[0];
428 for(UINT k=1; k<numTemplates; k++){
429 if( classDistances[k] < bestDistance ){
430 bestDistance = classDistances[k];
431 closestTemplateIndex = k;
436 UINT maxLikelihoodIndex = 0;
439 for(UINT k=0; k<numTemplates; k++){
440 classLikelihoods[k] /= sum;
441 if( classLikelihoods[k] > maxLikelihood ){
442 maxLikelihood = classLikelihoods[k];
443 maxLikelihoodIndex = k;
448 if( useNullRejection ){
450 switch( rejectionMode ){
451 case TEMPLATE_THRESHOLDS:
452 if( bestDistance <= nullRejectionThresholds[ closestTemplateIndex ] ) predictedClassLabel = templatesBuffer[ closestTemplateIndex ].classLabel;
453 else predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
455 case CLASS_LIKELIHOODS:
456 if( maxLikelihood >= nullRejectionLikelihoodThreshold) predictedClassLabel = templatesBuffer[ maxLikelihoodIndex ].classLabel;
457 else predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
459 case THRESHOLDS_AND_LIKELIHOODS:
460 if( bestDistance <= nullRejectionThresholds[ closestTemplateIndex ] && maxLikelihood >= nullRejectionLikelihoodThreshold)
461 predictedClassLabel = templatesBuffer[ closestTemplateIndex ].classLabel;
462 else predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
465 errorLog <<
"predict_(MatrixFloat &timeSeries) - Unknown RejectionMode!" << std::endl;
470 }
else predictedClassLabel = templatesBuffer[ closestTemplateIndex ].classLabel;
478 errorLog <<
"predict_(VectorFloat &inputVector) - The model has not been trained!" << std::endl;
481 predictedClassLabel = 0;
484 std::fill(classDistances.begin(),classDistances.end(),0);
486 if( numInputDimensions != inputVector.size() ){
487 errorLog <<
"predict_(VectorFloat &inputVector) - The number of features in the model " << numInputDimensions <<
" does not match that of the input Vector " << inputVector.size() << std::endl;
492 continuousInputDataBuffer.
push_back( inputVector );
500 const UINT M = continuousInputDataBuffer.
getSize();
501 const UINT N = numInputDimensions;
503 for(UINT i=0; i<M; i++){
504 for(UINT j=0; j<N; j++){
505 predictionTimeSeries[i][j] = continuousInputDataBuffer[i][j];
510 return predict( predictionTimeSeries );
515 continuousInputDataBuffer.
clear();
517 continuousInputDataBuffer.
resize(averageTemplateLength,
VectorFloat(numInputDimensions,0));
529 templatesBuffer.clear();
530 distanceMatrices.clear();
532 continuousInputDataBuffer.
clear();
539 if(!trained)
return false;
542 nullRejectionThresholds.
resize(numTemplates);
544 for(UINT k=0; k<numTemplates; k++){
546 nullRejectionThresholds[k] = templatesBuffer[k].trainingMu + (templatesBuffer[k].trainingSigma * nullRejectionCoeff);
554 if( newTemplates.size() == templatesBuffer.size() ){
555 templatesBuffer = newTemplates;
557 classLabels.
resize( templatesBuffer.size() );
558 for(UINT i=0; i<templatesBuffer.size(); i++){
559 classLabels[i] = templatesBuffer[i].classLabel;
574 Float totalDist,v,normFactor = 0.;
578 distanceMatrix.
resize(M, N);
581 switch (distanceMethod) {
582 case (ABSOLUTE_DIST):
585 distanceMatrix[i][j] = 0.0;
587 distanceMatrix[i][j] += fabs(timeSeriesA[i][k]-timeSeriesB[j][k]);
592 case (EUCLIDEAN_DIST):
596 distanceMatrix[i][j] = 0.0;
598 distanceMatrix[i][j] += SQR( timeSeriesA[i][k]-timeSeriesB[j][k] );
600 distanceMatrix[i][j] = sqrt( distanceMatrix[i][j] );
604 case (NORM_ABSOLUTE_DIST):
607 distanceMatrix[i][j] = 0.0;
609 distanceMatrix[i][j] += fabs(timeSeriesA[i][k]-timeSeriesB[j][k]);
611 distanceMatrix[i][j]/=N;
616 errorLog<<
"ERROR: Unknown distance method: "<<distanceMethod<< std::endl;
622 Float distance = sqrt( d(M-1,N-1,distanceMatrix,M,N) );
624 if( grt_isinf(distance) || grt_isnan(distance) ){
625 warningLog <<
"DTW computeDistance(...) - Distance Matrix Values are INF!" << std::endl;
634 distanceMatrix[i][j] = fabs( distanceMatrix[i][j] );
641 totalDist = distanceMatrix[i][j];
642 warpPath.push_back(
IndexDist(i,j,distanceMatrix[i][j]) );
647 if( i==0 && j==0 )
break;
655 if( distanceMatrix[i-1][j] < v ){ v = distanceMatrix[i-1][j]; index = 1; }
656 if( distanceMatrix[i][j-1] < v ){ v = distanceMatrix[i][j-1]; index = 2; }
657 if( distanceMatrix[i-1][j-1] <= v ){ index = 3; }
670 warningLog <<
"DTW computeDistance(...) - Could not compute a warping path for the input matrix! Dist: " << distanceMatrix[i-1][j] <<
" i: " << i <<
" j: " << j << std::endl;
677 totalDist += distanceMatrix[i][j];
678 warpPath.push_back(
IndexDist(i,j,distanceMatrix[i][j]) );
681 return totalDist/normFactor;
684 Float DTW::d(
int m,
int n,
MatrixFloat &distanceMatrix,
const int M,
const int N){
690 if( grt_isnan( distanceMatrix[m][n] ) ){
694 if( constrainWarpingPath ){
695 Float r = ceil( grt_min(M,N)*radius );
697 if( fabs( n-((N-1)/((M-1)/Float(m))) ) > r ){
698 if( n-((N-1)/((M-1)/Float(m))) > 0 ){
699 for(
int i=0; i<m; i++){
700 for(
int j=n; j<N; j++){
701 distanceMatrix[i][j] = NAN;
705 for(
int i=m; i<M; i++){
706 for(
int j=0; j<n; j++){
707 distanceMatrix[i][j] = NAN;
717 if( distanceMatrix[m][n] < 0 ){
718 dist = fabs( distanceMatrix[m][n] );
726 if( m == 0 && n == 0 ){
727 dist = distanceMatrix[0][0];
728 distanceMatrix[0][0] = -distanceMatrix[0][0];
735 Float contribDist = d(m,n-1,distanceMatrix,M,N);
737 dist = distanceMatrix[m][n] + contribDist;
739 distanceMatrix[m][n] = -dist;
745 Float contribDist = d(m-1,n,distanceMatrix,M,N);
747 dist = distanceMatrix[m][n] + contribDist;
749 distanceMatrix[m][n] = -dist;
753 Float contribDist1 = d(m-1,n-1,distanceMatrix,M,N);
754 Float contribDist2 = d(m-1,n,distanceMatrix,M,N);
755 Float contribDist3 = d(m,n-1,distanceMatrix,M,N);
758 if( contribDist1 < minValue ){ minValue = contribDist1; index = 1; }
759 if( contribDist2 < minValue ){ minValue = contribDist2; index = 2; }
760 if( contribDist3 < minValue ){ minValue = contribDist3; index = 3; }
764 dist = distanceMatrix[m][n] + minValue;
767 dist = distanceMatrix[m][n] + minValue;
770 dist = distanceMatrix[m][n] + minValue;
777 distanceMatrix[m][n] = -dist;
786 inline Float DTW::MIN_(Float a,Float b, Float c){
800 scaleData( trainingData[i].getData(), trainingData[i].getData() );
815 for(UINT i=0; i<R; i++)
816 for(UINT j=0; j<C; j++)
817 scaledData[i][j] = grt_scale(data[i][j],ranges[j].minValue,ranges[j].maxValue,0.0,1.0);
824 znormData( trainingData[i].getData(), trainingData[i].getData() );
838 for(UINT j=0; j<C; j++){
843 for(UINT i=0; i<R; i++) mean += data[i][j];
847 for(UINT i=0; i<R; i++)
848 stdDev += grt_sqr(data[i][j]-mean);
849 stdDev = grt_sqrt( stdDev / (R - 1.0) );
851 if(constrainZNorm && stdDev < 0.01){
853 for(UINT i=0; i<R; i++)
854 normData[i][j] = (data[i][j] - mean);
857 for(UINT i=0; i<R; i++)
858 normData[i][j] = (data[i][j] - mean) / stdDev;
865 const UINT M = (UINT)data.size();
866 const UINT N = (UINT) floor(Float(M)/Float(smoothFactor));
868 for(UINT i=0; i<N; i++) resultsData[i]=0.0;
870 if(smoothFactor==1 || M<smoothFactor){
875 for(UINT i=0; i<N; i++){
877 UINT index = i*smoothFactor;
878 for(UINT x=0; x<smoothFactor; x++){
879 mean += data[index+x];
881 resultsData[i] = mean/smoothFactor;
884 if(M%smoothFactor!=0.0){
886 for(UINT i=N*smoothFactor; i<M; i++) mean += data[i];
887 mean/=M-(N*smoothFactor);
890 for(UINT i=0; i<N; i++) tempVector[i] = resultsData[i];
891 tempVector[N] = mean;
892 resultsData = tempVector;
901 const UINT N = (UINT) floor(Float(M)/Float(smoothFactor));
904 if(smoothFactor==1 || M<smoothFactor){
909 for(UINT i=0; i<N; i++){
910 for(UINT j=0; j<C; j++){
912 int index = i*smoothFactor;
913 for(UINT x=0; x<smoothFactor; x++){
914 mean += data[index+x][j];
916 resultsData[i][j] = mean/smoothFactor;
921 if(M%smoothFactor!=0.0){
923 for(UINT j=0; j<C; j++){
924 for(UINT i=N*smoothFactor; i<M; i++) mean[j] += data[i][j];
925 mean[j]/=M-(N*smoothFactor);
931 for(UINT i=0; i<N; i++)
932 for(UINT j=0; j<C; j++)
933 tempMatrix[i][j] = resultsData[i][j];
935 for(UINT j=0; j<C; j++) tempMatrix[N][j] = mean[j];
936 resultsData = tempMatrix;
946 errorLog <<
"save( string fileName ) - Could not open file to save data" << std::endl;
950 file <<
"GRT_DTW_Model_File_V2.0" << std::endl;
954 errorLog <<
"save(fstream &file) - Failed to save classifier base settings to file!" << std::endl;
958 file <<
"DistanceMethod: ";
959 switch(distanceMethod){
961 file <<ABSOLUTE_DIST<< std::endl;
963 case(EUCLIDEAN_DIST):
964 file <<EUCLIDEAN_DIST<< std::endl;
967 file <<ABSOLUTE_DIST<< std::endl;
970 file <<
"UseSmoothing: "<<useSmoothing<< std::endl;
971 file <<
"SmoothingFactor: "<<smoothingFactor<< std::endl;
972 file <<
"UseZNormalisation: "<<useZNormalisation<< std::endl;
973 file <<
"OffsetUsingFirstSample: " << offsetUsingFirstSample << std::endl;
974 file <<
"ConstrainWarpingPath: " << constrainWarpingPath << std::endl;
975 file <<
"Radius: " << radius << std::endl;
976 file <<
"RejectionMode: " << rejectionMode<< std::endl;
979 file <<
"NumberOfTemplates: " << numTemplates << std::endl;
980 file <<
"OverallAverageTemplateLength: " << averageTemplateLength << std::endl;
982 for(UINT i=0; i<numTemplates; i++){
983 file <<
"***************TEMPLATE***************" << std::endl;
984 file <<
"Template: " << i+1 << std::endl;
985 file <<
"ClassLabel: " << templatesBuffer[i].classLabel << std::endl;
986 file <<
"TimeSeriesLength: " << templatesBuffer[i].timeSeries.getNumRows() << std::endl;
987 file <<
"TemplateThreshold: " << nullRejectionThresholds[i] << std::endl;
988 file <<
"TrainingMu: " << templatesBuffer[i].trainingMu << std::endl;
989 file <<
"TrainingSigma: " << templatesBuffer[i].trainingSigma << std::endl;
990 file <<
"AverageTemplateLength: " << templatesBuffer[i].averageTemplateLength << std::endl;
991 file <<
"TimeSeries: " << std::endl;
992 for(UINT k=0; k<templatesBuffer[i].timeSeries.getNumRows(); k++){
993 for(UINT j=0; j<templatesBuffer[i].timeSeries.getNumCols(); j++){
994 file << templatesBuffer[i].timeSeries[k][j] <<
"\t";
1007 UINT timeSeriesLength;
1012 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to open file!" << std::endl;
1019 if( word ==
"GRT_DTW_Model_File_V1.0" ){
1020 return loadLegacyModelFromFile( file );
1024 if(word !=
"GRT_DTW_Model_File_V2.0"){
1025 errorLog <<
"loadDTWModelFromFile( string fileName ) - Unknown file header!" << std::endl;
1031 errorLog <<
"load(string filename) - Failed to load base settings from file!" << std::endl;
1037 if(word !=
"DistanceMethod:"){
1038 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find DistanceMethod!" << std::endl;
1041 file >> distanceMethod;
1045 if(word !=
"UseSmoothing:"){
1046 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseSmoothing!" << std::endl;
1049 file >> useSmoothing;
1053 if(word !=
"SmoothingFactor:"){
1054 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find SmoothingFactor!" << std::endl;
1057 file >> smoothingFactor;
1061 if(word !=
"UseZNormalisation:"){
1062 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseZNormalisation!" << std::endl;
1065 file >> useZNormalisation;
1069 if(word !=
"OffsetUsingFirstSample:"){
1070 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find OffsetUsingFirstSample!" << std::endl;
1073 file >> offsetUsingFirstSample;
1077 if(word !=
"ConstrainWarpingPath:"){
1078 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find ConstrainWarpingPath!" << std::endl;
1081 file >> constrainWarpingPath;
1085 if(word !=
"Radius:"){
1086 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find Radius!" << std::endl;
1093 if(word !=
"RejectionMode:"){
1094 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find RejectionMode!" << std::endl;
1097 file >> rejectionMode;
1103 if(word !=
"NumberOfTemplates:"){
1104 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find NumberOfTemplates!" << std::endl;
1107 file >> numTemplates;
1111 if(word !=
"OverallAverageTemplateLength:"){
1112 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find OverallAverageTemplateLength!" << std::endl;
1115 file >> averageTemplateLength;
1118 templatesBuffer.
resize(numTemplates);
1119 classLabels.
resize(numTemplates);
1120 nullRejectionThresholds.
resize(numTemplates);
1123 for(UINT i=0; i<numTemplates; i++){
1126 if( word !=
"***************TEMPLATE***************" ){
1128 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find template header!" << std::endl;
1134 if(word !=
"Template:"){
1136 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find Template Number!" << std::endl;
1144 errorLog <<
"loadDTWModelFromFile( string fileName ) - Invalid Template Number: " << ts << std::endl;
1150 if(word !=
"ClassLabel:"){
1152 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find ClassLabel!" << std::endl;
1155 file >> templatesBuffer[i].classLabel;
1156 classLabels[i] = templatesBuffer[i].classLabel;
1160 if(word !=
"TimeSeriesLength:"){
1162 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TimeSeriesLength!" << std::endl;
1165 file >> timeSeriesLength;
1168 templatesBuffer[i].timeSeries.
resize(timeSeriesLength,numInputDimensions);
1172 if(word !=
"TemplateThreshold:"){
1174 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TemplateThreshold!" << std::endl;
1177 file >> nullRejectionThresholds[i];
1181 if(word !=
"TrainingMu:"){
1183 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TrainingMu!" << std::endl;
1186 file >> templatesBuffer[i].trainingMu;
1190 if(word !=
"TrainingSigma:"){
1192 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TrainingSigma!" << std::endl;
1195 file >> templatesBuffer[i].trainingSigma;
1199 if(word !=
"AverageTemplateLength:"){
1201 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find AverageTemplateLength!" << std::endl;
1204 file >> templatesBuffer[i].averageTemplateLength;
1208 if(word !=
"TimeSeries:"){
1210 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find template timeseries!" << std::endl;
1213 for(UINT k=0; k<timeSeriesLength; k++)
1214 for(UINT j=0; j<numInputDimensions; j++)
1215 file >> templatesBuffer[i].timeSeries[k][j];
1219 continuousInputDataBuffer.
clear();
1220 continuousInputDataBuffer.
resize(averageTemplateLength,
VectorFloat(numInputDimensions,0));
1222 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
1224 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
1230 if( rejectionMode == TEMPLATE_THRESHOLDS || rejectionMode == CLASS_LIKELIHOODS || rejectionMode == THRESHOLDS_AND_LIKELIHOODS ){
1231 this->rejectionMode = rejectionMode;
1239 this->nullRejectionLikelihoodThreshold = nullRejectionLikelihoodThreshold;
1244 this->offsetUsingFirstSample = offsetUsingFirstSample;
1249 this->constrainWarpingPath = constrain;
1254 this->radius = radius;
1259 this->useZNormalisation = useZNormalisation;
1260 this->constrainZNorm = constrainZNorm;
1266 if( trimThreshold < 0 || trimThreshold > 1 ){
1267 warningLog <<
"Failed to set trimTrainingData. The trimThreshold must be in the range of [0 1]" << std::endl;
1270 if( maximumTrimPercentage < 0 || maximumTrimPercentage > 100 ){
1271 warningLog <<
"Failed to set trimTrainingData. The maximumTrimPercentage must be a valid percentage in the range of [0 100]" << std::endl;
1275 this->trimTrainingData = trimTrainingData;
1276 this->trimThreshold = trimThreshold;
1277 this->maximumTrimPercentage = maximumTrimPercentage;
1281 void DTW::offsetTimeseries(
MatrixFloat ×eries){
1283 for(UINT i=0; i<timeseries.
getNumRows(); i++){
1284 for(UINT j=0; j<timeseries.
getNumCols(); j++){
1285 timeseries[i][j] -= firstRow[j];
1290 bool DTW::loadLegacyModelFromFile( std::fstream &file ){
1293 UINT timeSeriesLength;
1298 if(word !=
"NumberOfDimensions:"){
1299 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find NumberOfDimensions!" << std::endl;
1302 file >> numInputDimensions;
1306 if(word !=
"NumberOfClasses:"){
1307 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find NumberOfClasses!" << std::endl;
1314 if(word !=
"NumberOfTemplates:"){
1315 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find NumberOfTemplates!" << std::endl;
1318 file >> numTemplates;
1322 if(word !=
"DistanceMethod:"){
1323 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find DistanceMethod!" << std::endl;
1326 file >> distanceMethod;
1330 if(word !=
"UseNullRejection:"){
1331 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseNullRejection!" << std::endl;
1334 file >> useNullRejection;
1338 if(word !=
"UseSmoothing:"){
1339 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseSmoothing!" << std::endl;
1342 file >> useSmoothing;
1346 if(word !=
"SmoothingFactor:"){
1347 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find SmoothingFactor!" << std::endl;
1350 file >> smoothingFactor;
1354 if(word !=
"UseScaling:"){
1355 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseScaling!" << std::endl;
1362 if(word !=
"UseZNormalisation:"){
1363 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseZNormalisation!" << std::endl;
1366 file >> useZNormalisation;
1370 if(word !=
"OffsetUsingFirstSample:"){
1371 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find OffsetUsingFirstSample!" << std::endl;
1374 file >> offsetUsingFirstSample;
1378 if(word !=
"ConstrainWarpingPath:"){
1379 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find ConstrainWarpingPath!" << std::endl;
1382 file >> constrainWarpingPath;
1386 if(word !=
"Radius:"){
1387 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find Radius!" << std::endl;
1394 if(word !=
"RejectionMode:"){
1395 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find RejectionMode!" << std::endl;
1398 file >> rejectionMode;
1402 if(word !=
"NullRejectionCoeff:"){
1403 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find NullRejectionCoeff!" << std::endl;
1406 file >> nullRejectionCoeff;
1410 if(word !=
"OverallAverageTemplateLength:"){
1411 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find OverallAverageTemplateLength!" << std::endl;
1414 file >> averageTemplateLength;
1417 templatesBuffer.
resize(numTemplates);
1418 classLabels.
resize(numTemplates);
1419 nullRejectionThresholds.
resize(numTemplates);
1422 for(UINT i=0; i<numTemplates; i++){
1425 while(word !=
"Template:"){
1434 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find Invalid Template Number!" << std::endl;
1440 if(word !=
"ClassLabel:"){
1443 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find ClassLabel!" << std::endl;
1446 file >> templatesBuffer[i].classLabel;
1447 classLabels[i] = templatesBuffer[i].classLabel;
1451 if(word !=
"TimeSeriesLength:"){
1454 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TimeSeriesLength!" << std::endl;
1457 file >> timeSeriesLength;
1460 templatesBuffer[i].timeSeries.
resize(timeSeriesLength,numInputDimensions);
1464 if(word !=
"TemplateThreshold:"){
1467 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TemplateThreshold!" << std::endl;
1470 file >> nullRejectionThresholds[i];
1474 if(word !=
"TrainingMu:"){
1477 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TrainingMu!" << std::endl;
1480 file >> templatesBuffer[i].trainingMu;
1484 if(word !=
"TrainingSigma:"){
1487 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TrainingSigma!" << std::endl;
1490 file >> templatesBuffer[i].trainingSigma;
1494 if(word !=
"AverageTemplateLength:"){
1497 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find AverageTemplateLength!" << std::endl;
1500 file >> templatesBuffer[i].averageTemplateLength;
1504 if(word !=
"TimeSeries:"){
1507 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find template timeseries!" << std::endl;
1510 for(UINT k=0; k<timeSeriesLength; k++)
1511 for(UINT j=0; j<numInputDimensions; j++)
1512 file >> templatesBuffer[i].timeSeries[k][j];
1516 if(word !=
"***************************"){
1519 numInputDimensions=0;
1521 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find template footer!" << std::endl;
1527 continuousInputDataBuffer.
clear();
1528 continuousInputDataBuffer.
resize(averageTemplateLength,
VectorFloat(numInputDimensions,0));
1530 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
1532 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
virtual bool predict_(VectorFloat &inputVector)
bool saveBaseSettingsToFile(std::fstream &file) const
bool push_back(const T &value)
virtual bool predict(VectorFloat inputVector)
#define DEFAULT_NULL_LIKELIHOOD_VALUE
virtual bool save(std::fstream &file) const
std::string getClassifierType() const
bool setRejectionMode(UINT rejectionMode)
bool setNumDimensions(const UINT numDimensions)
virtual bool train_(TimeSeriesClassificationData &trainingData)
virtual bool resize(const unsigned int size)
bool enableTrimTrainingData(bool trimTrainingData, Float trimThreshold, Float maximumTrimPercentage)
bool setContrainWarpingPath(bool constrain)
bool enableZNormalization(bool useZNormalization, bool constrainZNorm=true)
bool setWarpingRadius(Float radius)
DTW & operator=(const DTW &rhs)
Vector< MinMax > getRanges() const
bool setModels(Vector< DTWTemplate > newTemplates)
Vector< ClassTracker > getClassTracker() const
unsigned int getNumValuesInBuffer() const
bool copyBaseVariables(const Classifier *classifier)
bool loadBaseSettingsFromFile(std::fstream &file)
bool setNullRejectionThreshold(Float nullRejectionLikelihoodThreshold)
This class implements Dynamic Time Warping. Dynamic Time Warping (DTW) is a powerful classifier that ...
unsigned int getNumRows() const
unsigned int getNumCols() const
bool addSample(const UINT classLabel, const MatrixFloat &trainingSample)
virtual bool recomputeNullRejectionThresholds()
VectorFloat getRow(const unsigned int r) const
TimeSeriesClassificationData getClassData(const UINT classLabel) const
UINT getNumDimensions() const
DTW(bool useScaling=false, bool useNullRejection=false, Float nullRejectionCoeff=3.0, UINT rejectionMode=DTW::TEMPLATE_THRESHOLDS, bool dtwConstrain=true, Float radius=0.2, bool offsetUsingFirstSample=false, bool useSmoothing=false, UINT smoothingFactor=5, Float nullRejectionLikelihoodThreshold=0.99)
virtual bool deepCopyFrom(const Classifier *classifier)
virtual bool resize(const unsigned int r, const unsigned int c)
UINT getNumClasses() const
bool trimTimeSeries(TimeSeriesClassificationSample &timeSeries)
bool setOffsetTimeseriesUsingFirstSample(bool offsetUsingFirstSample)
UINT getNumSamples() const
virtual bool load(std::fstream &file)
unsigned int getSize() const
bool resize(const unsigned int newBufferSize)