28 DTW::DTW(
bool useScaling,
bool useNullRejection,Float nullRejectionCoeff,UINT rejectionMode,
bool constrainWarpingPath,Float radius,
bool offsetUsingFirstSample,
bool useSmoothing,UINT smoothingFactor,Float nullRejectionLikelihoodThreshold)
30 this->useScaling=useScaling;
31 this->useNullRejection = useNullRejection;
32 this->nullRejectionCoeff = nullRejectionCoeff;
33 this->nullRejectionLikelihoodThreshold = nullRejectionLikelihoodThreshold;
34 this->rejectionMode = rejectionMode;
35 this->constrainWarpingPath = constrainWarpingPath;
36 this->radius = radius;
37 this->offsetUsingFirstSample = offsetUsingFirstSample;
38 this->useSmoothing = useSmoothing;
39 this->smoothingFactor = smoothingFactor;
41 supportsNullRejection =
true;
43 useZNormalisation=
false;
45 trimTrainingData =
false;
47 zNormConstrainThreshold=0.2;
49 maximumTrimPercentage = 90;
52 distanceMethod=EUCLIDEAN_DIST;
54 averageTemplateLength =0;
57 classifierType = classType;
58 classifierMode = TIMESERIES_CLASSIFIER_MODE;
59 debugLog.setProceedingText(
"[DEBUG NDDTW]");
60 errorLog.setProceedingText(
"[ERROR NDDTW]");
61 trainingLog.setProceedingText(
"[TRAINING NDDTW]");
62 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;
106 if( classifier == NULL )
return false;
110 DTW *ptr = (
DTW*)classifier;
111 this->templatesBuffer = ptr->templatesBuffer;
112 this->distanceMatrices = ptr->distanceMatrices;
113 this->warpPaths = ptr->warpPaths;
114 this->continuousInputDataBuffer = ptr->continuousInputDataBuffer;
115 this->numTemplates = ptr->numTemplates;
116 this->useSmoothing = ptr->useSmoothing;
117 this->useZNormalisation = ptr->useZNormalisation;
118 this->constrainZNorm = ptr->constrainZNorm;
119 this->constrainWarpingPath = ptr->constrainWarpingPath;
120 this->trimTrainingData = ptr->trimTrainingData;
121 this->zNormConstrainThreshold = ptr->zNormConstrainThreshold;
122 this->radius = ptr->radius;
123 this->offsetUsingFirstSample = ptr->offsetUsingFirstSample;
124 this->trimThreshold = ptr->trimThreshold;
125 this->maximumTrimPercentage = ptr->maximumTrimPercentage;
126 this->smoothingFactor = ptr->smoothingFactor;
127 this->distanceMethod = ptr->distanceMethod;
128 this->rejectionMode = ptr->rejectionMode;
129 this->nullRejectionLikelihoodThreshold = ptr->nullRejectionLikelihoodThreshold;
130 this->averageTemplateLength = ptr->averageTemplateLength;
144 templatesBuffer.clear();
147 continuousInputDataBuffer.
clear();
149 if( trimTrainingData ){
155 if( timeSeriesTrimmer.
trimTimeSeries( labelledTrainingData[i] ) ){
156 tempData.
addSample(labelledTrainingData[i].getClassLabel(), labelledTrainingData[i].getData());
158 trainingLog <<
"Removing training sample " << i <<
" from the dataset as it could not be trimmed!" << std::endl;
162 labelledTrainingData = tempData;
166 errorLog <<
"train_(TimeSeriesClassificationData &labelledTrainingData) - Can't train model as there are no samples in training data!" << std::endl;
174 templatesBuffer.
resize( numClasses );
175 classLabels.
resize( numClasses );
176 nullRejectionThresholds.
resize( numClasses );
177 averageTemplateLength = 0;
184 if( useScaling ) scaleData( trainingData );
185 if( useZNormalisation ) znormData( trainingData );
188 for(UINT k=0; k<numTemplates; k++){
196 templatesBuffer[k].classLabel = classLabel;
199 classLabels[k] = classLabel;
201 trainingLog <<
"Training Template: " << k <<
" Class: " << classLabel << std::endl;
204 if( numExamples < 1 ){
205 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;
209 if( numExamples == 1 && useNullRejection ){
210 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;
214 if( numExamples == 1 ){
216 nullRejectionThresholds[k] = 0.0;
219 if( !train_NDDTW(classData,templatesBuffer[k],bestIndex) ){
220 errorLog <<
"train_(LabelledTimeSeriesClassificationData &labelledTrainingData) - Failed to train template for class with label: " << classLabel << std::endl;
226 int trainingMethod = 0;
227 if(useSmoothing) trainingMethod = 1;
229 switch (trainingMethod) {
231 templatesBuffer[k].timeSeries = classData[bestIndex].getData();
235 smoothData(classData[ bestIndex ].getData(),smoothingFactor,templatesBuffer[k].timeSeries);
238 errorLog <<
"Can not train model: Unknown training method " << std::endl;
243 if( offsetUsingFirstSample ){
244 offsetTimeseries( templatesBuffer[k].timeSeries );
248 averageTemplateLength += templatesBuffer[k].averageTemplateLength;
253 averageTemplateLength = averageTemplateLength/numTemplates;
259 continuousInputDataBuffer.
clear();
260 continuousInputDataBuffer.
resize(averageTemplateLength,
VectorFloat(numInputDimensions,0));
262 classDistances.
resize(numTemplates,0);
263 predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
274 MatrixFloat distanceResults(numExamples,numExamples);
275 dtwTemplate.averageTemplateLength = 0;
277 for(UINT m=0; m<numExamples; m++){
281 dtwTemplate.averageTemplateLength += trainingData[m].getLength();
284 if( useSmoothing ) smoothData(trainingData[m].getData(),smoothingFactor,templateA);
285 else templateA = trainingData[m].getData();
287 if( offsetUsingFirstSample ){
288 offsetTimeseries(templateA);
291 for(UINT n=0; n<numExamples; n++){
294 if( useSmoothing ) smoothData(trainingData[n].getData(),smoothingFactor,templateB);
295 else templateB = trainingData[n].getData();
297 if( offsetUsingFirstSample ){
298 offsetTimeseries(templateB);
304 Float dist = computeDistance(templateA,templateB,distanceMatrix,warpPath);
306 trainingLog <<
"Template: " << m <<
" Timeseries: " << n <<
" Dist: " << dist << std::endl;
309 distanceResults[m][n] = dist;
311 }
else distanceResults[m][n] = 0;
315 for(UINT m=0; m<numExamples; m++) results[m]/=(numExamples-1);
318 Float bestAverage = results[0];
319 for(UINT m=1; m<numExamples; m++){
320 if( results[m] < bestAverage ){
321 bestAverage = results[m];
326 if( numExamples > 2 ){
329 dtwTemplate.trainingMu = results[bestIndex];
330 dtwTemplate.trainingSigma = 0.0;
332 for(UINT n=0; n<numExamples; n++){
334 dtwTemplate.trainingSigma += SQR( distanceResults[ bestIndex ][n] - dtwTemplate.trainingMu );
337 dtwTemplate.trainingSigma = sqrt( dtwTemplate.trainingSigma / Float(numExamples-2) );
339 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;
340 dtwTemplate.trainingMu = 0.0;
341 dtwTemplate.trainingSigma = 0.0;
345 dtwTemplate.averageTemplateLength = (UINT) (dtwTemplate.averageTemplateLength/Float(numExamples));
347 trainingLog <<
"AverageTemplateLength: " << dtwTemplate.averageTemplateLength << std::endl;
357 errorLog <<
"predict_(MatrixFloat &inputTimeSeries) - The DTW templates have not been trained!" << std::endl;
361 if( classLikelihoods.size() != numTemplates ) classLikelihoods.
resize(numTemplates);
362 if( classDistances.size() != numTemplates ) classDistances.
resize(numTemplates);
364 predictedClassLabel = 0;
366 for(UINT k=0; k<classLikelihoods.size(); k++){
367 classLikelihoods[k] = 0;
371 if( numInputDimensions != inputTimeSeries.
getNumCols() ){
372 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;
381 scaleData(*timeSeriesPtr,processedTimeSeries);
382 timeSeriesPtr = &processedTimeSeries;
386 if( useZNormalisation ){
387 znormData(*timeSeriesPtr,processedTimeSeries);
388 timeSeriesPtr = &processedTimeSeries;
393 smoothData(*timeSeriesPtr,smoothingFactor,tempMatrix);
394 timeSeriesPtr = &tempMatrix;
398 if( offsetUsingFirstSample ){
399 offsetTimeseries( *timeSeriesPtr );
404 if( distanceMatrices.size() != numTemplates ) distanceMatrices.
resize( numTemplates );
405 if( warpPaths.size() != numTemplates ) warpPaths.
resize( numTemplates );
408 for(UINT k=0; k<numTemplates; k++){
410 classDistances[k] = computeDistance(templatesBuffer[k].timeSeries,*timeSeriesPtr,distanceMatrices[k],warpPaths[k]);
412 if(classDistances[k] > 1e-9)
414 classLikelihoods[k] = 1.0 / classDistances[k];
418 classLikelihoods[k] = 1e9;
421 sum += classLikelihoods[k];
425 UINT closestTemplateIndex = 0;
426 bestDistance = classDistances[0];
427 for(UINT k=1; k<numTemplates; k++){
428 if( classDistances[k] < bestDistance ){
429 bestDistance = classDistances[k];
430 closestTemplateIndex = k;
435 UINT maxLikelihoodIndex = 0;
438 for(UINT k=0; k<numTemplates; k++){
439 classLikelihoods[k] /= sum;
440 if( classLikelihoods[k] > maxLikelihood ){
441 maxLikelihood = classLikelihoods[k];
442 maxLikelihoodIndex = k;
447 if( useNullRejection ){
449 switch( rejectionMode ){
450 case TEMPLATE_THRESHOLDS:
451 if( bestDistance <= nullRejectionThresholds[ closestTemplateIndex ] ) predictedClassLabel = templatesBuffer[ closestTemplateIndex ].classLabel;
452 else predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
454 case CLASS_LIKELIHOODS:
455 if( maxLikelihood >= nullRejectionLikelihoodThreshold) predictedClassLabel = templatesBuffer[ maxLikelihoodIndex ].classLabel;
456 else predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
458 case THRESHOLDS_AND_LIKELIHOODS:
459 if( bestDistance <= nullRejectionThresholds[ closestTemplateIndex ] && maxLikelihood >= nullRejectionLikelihoodThreshold)
460 predictedClassLabel = templatesBuffer[ closestTemplateIndex ].classLabel;
461 else predictedClassLabel = GRT_DEFAULT_NULL_CLASS_LABEL;
464 errorLog <<
"predict_(MatrixFloat &timeSeries) - Unknown RejectionMode!" << std::endl;
469 }
else predictedClassLabel = templatesBuffer[ closestTemplateIndex ].classLabel;
477 errorLog <<
"predict_(VectorFloat &inputVector) - The model has not been trained!" << std::endl;
480 predictedClassLabel = 0;
483 std::fill(classDistances.begin(),classDistances.end(),0);
485 if( numInputDimensions != inputVector.size() ){
486 errorLog <<
"predict_(VectorFloat &inputVector) - The number of features in the model " << numInputDimensions <<
" does not match that of the input Vector " << inputVector.size() << std::endl;
491 continuousInputDataBuffer.
push_back( inputVector );
499 const UINT M = continuousInputDataBuffer.
getSize();
500 const UINT N = numInputDimensions;
502 for(UINT i=0; i<M; i++){
503 for(UINT j=0; j<N; j++){
504 predictionTimeSeries[i][j] = continuousInputDataBuffer[i][j];
509 return predict( predictionTimeSeries );
514 continuousInputDataBuffer.
clear();
516 continuousInputDataBuffer.
resize(averageTemplateLength,
VectorFloat(numInputDimensions,0));
528 templatesBuffer.clear();
529 distanceMatrices.clear();
531 continuousInputDataBuffer.
clear();
538 if(!trained)
return false;
541 nullRejectionThresholds.
resize(numTemplates);
543 for(UINT k=0; k<numTemplates; k++){
545 nullRejectionThresholds[k] = templatesBuffer[k].trainingMu + (templatesBuffer[k].trainingSigma * nullRejectionCoeff);
553 if( newTemplates.size() == templatesBuffer.size() ){
554 templatesBuffer = newTemplates;
556 classLabels.
resize( templatesBuffer.size() );
557 for(UINT i=0; i<templatesBuffer.size(); i++){
558 classLabels[i] = templatesBuffer[i].classLabel;
573 Float totalDist,v,normFactor = 0.;
577 distanceMatrix.
resize(M, N);
580 switch (distanceMethod) {
581 case (ABSOLUTE_DIST):
584 distanceMatrix[i][j] = 0.0;
586 distanceMatrix[i][j] += fabs(timeSeriesA[i][k]-timeSeriesB[j][k]);
591 case (EUCLIDEAN_DIST):
595 distanceMatrix[i][j] = 0.0;
597 distanceMatrix[i][j] += SQR( timeSeriesA[i][k]-timeSeriesB[j][k] );
599 distanceMatrix[i][j] = sqrt( distanceMatrix[i][j] );
603 case (NORM_ABSOLUTE_DIST):
606 distanceMatrix[i][j] = 0.0;
608 distanceMatrix[i][j] += fabs(timeSeriesA[i][k]-timeSeriesB[j][k]);
610 distanceMatrix[i][j]/=N;
615 errorLog<<
"ERROR: Unknown distance method: "<<distanceMethod<< std::endl;
621 Float distance = sqrt( d(M-1,N-1,distanceMatrix,M,N) );
623 if( grt_isinf(distance) || grt_isnan(distance) ){
624 warningLog <<
"DTW computeDistance(...) - Distance Matrix Values are INF!" << std::endl;
633 distanceMatrix[i][j] = fabs( distanceMatrix[i][j] );
640 totalDist = distanceMatrix[i][j];
641 warpPath.push_back(
IndexDist(i,j,distanceMatrix[i][j]) );
646 if( i==0 && j==0 )
break;
654 if( distanceMatrix[i-1][j] < v ){ v = distanceMatrix[i-1][j]; index = 1; }
655 if( distanceMatrix[i][j-1] < v ){ v = distanceMatrix[i][j-1]; index = 2; }
656 if( distanceMatrix[i-1][j-1] <= v ){ index = 3; }
669 warningLog <<
"DTW computeDistance(...) - Could not compute a warping path for the input matrix! Dist: " << distanceMatrix[i-1][j] <<
" i: " << i <<
" j: " << j << std::endl;
676 totalDist += distanceMatrix[i][j];
677 warpPath.push_back(
IndexDist(i,j,distanceMatrix[i][j]) );
680 return totalDist/normFactor;
683 Float DTW::d(
int m,
int n,
MatrixFloat &distanceMatrix,
const int M,
const int N){
689 if( grt_isnan( distanceMatrix[m][n] ) ){
693 if( constrainWarpingPath ){
694 Float r = ceil( grt_min(M,N)*radius );
696 if( fabs( n-((N-1)/((M-1)/Float(m))) ) > r ){
697 if( n-((N-1)/((M-1)/Float(m))) > 0 ){
698 for(
int i=0; i<m; i++){
699 for(
int j=n; j<N; j++){
700 distanceMatrix[i][j] = NAN;
704 for(
int i=m; i<M; i++){
705 for(
int j=0; j<n; j++){
706 distanceMatrix[i][j] = NAN;
716 if( distanceMatrix[m][n] < 0 ){
717 dist = fabs( distanceMatrix[m][n] );
725 if( m == 0 && n == 0 ){
726 dist = distanceMatrix[0][0];
727 distanceMatrix[0][0] = -distanceMatrix[0][0];
734 Float contribDist = d(m,n-1,distanceMatrix,M,N);
736 dist = distanceMatrix[m][n] + contribDist;
738 distanceMatrix[m][n] = -dist;
744 Float contribDist = d(m-1,n,distanceMatrix,M,N);
746 dist = distanceMatrix[m][n] + contribDist;
748 distanceMatrix[m][n] = -dist;
752 Float contribDist1 = d(m-1,n-1,distanceMatrix,M,N);
753 Float contribDist2 = d(m-1,n,distanceMatrix,M,N);
754 Float contribDist3 = d(m,n-1,distanceMatrix,M,N);
757 if( contribDist1 < minValue ){ minValue = contribDist1; index = 1; }
758 if( contribDist2 < minValue ){ minValue = contribDist2; index = 2; }
759 if( contribDist3 < minValue ){ minValue = contribDist3; index = 3; }
763 dist = distanceMatrix[m][n] + minValue;
766 dist = distanceMatrix[m][n] + minValue;
769 dist = distanceMatrix[m][n] + minValue;
776 distanceMatrix[m][n] = -dist;
785 inline Float DTW::MIN_(Float a,Float b, Float c){
799 scaleData( trainingData[i].getData(), trainingData[i].getData() );
814 for(UINT i=0; i<R; i++)
815 for(UINT j=0; j<C; j++)
816 scaledData[i][j] = grt_scale(data[i][j],ranges[j].minValue,ranges[j].maxValue,0.0,1.0);
823 znormData( trainingData[i].getData(), trainingData[i].getData() );
837 for(UINT j=0; j<C; j++){
842 for(UINT i=0; i<R; i++) mean += data[i][j];
846 for(UINT i=0; i<R; i++)
847 stdDev += grt_sqr(data[i][j]-mean);
848 stdDev = grt_sqrt( stdDev / (R - 1.0) );
850 if(constrainZNorm && stdDev < 0.01){
852 for(UINT i=0; i<R; i++)
853 normData[i][j] = (data[i][j] - mean);
856 for(UINT i=0; i<R; i++)
857 normData[i][j] = (data[i][j] - mean) / stdDev;
864 const UINT M = (UINT)data.size();
865 const UINT N = (UINT) floor(Float(M)/Float(smoothFactor));
867 for(UINT i=0; i<N; i++) resultsData[i]=0.0;
869 if(smoothFactor==1 || M<smoothFactor){
874 for(UINT i=0; i<N; i++){
876 UINT index = i*smoothFactor;
877 for(UINT x=0; x<smoothFactor; x++){
878 mean += data[index+x];
880 resultsData[i] = mean/smoothFactor;
883 if(M%smoothFactor!=0.0){
885 for(UINT i=N*smoothFactor; i<M; i++) mean += data[i];
886 mean/=M-(N*smoothFactor);
889 for(UINT i=0; i<N; i++) tempVector[i] = resultsData[i];
890 tempVector[N] = mean;
891 resultsData = tempVector;
900 const UINT N = (UINT) floor(Float(M)/Float(smoothFactor));
903 if(smoothFactor==1 || M<smoothFactor){
908 for(UINT i=0; i<N; i++){
909 for(UINT j=0; j<C; j++){
911 int index = i*smoothFactor;
912 for(UINT x=0; x<smoothFactor; x++){
913 mean += data[index+x][j];
915 resultsData[i][j] = mean/smoothFactor;
920 if(M%smoothFactor!=0.0){
922 for(UINT j=0; j<C; j++){
923 for(UINT i=N*smoothFactor; i<M; i++) mean[j] += data[i][j];
924 mean[j]/=M-(N*smoothFactor);
930 for(UINT i=0; i<N; i++)
931 for(UINT j=0; j<C; j++)
932 tempMatrix[i][j] = resultsData[i][j];
934 for(UINT j=0; j<C; j++) tempMatrix[N][j] = mean[j];
935 resultsData = tempMatrix;
945 errorLog <<
"saveModelToFile( string fileName ) - Could not open file to save data" << std::endl;
949 file <<
"GRT_DTW_Model_File_V2.0" << std::endl;
953 errorLog <<
"saveModelToFile(fstream &file) - Failed to save classifier base settings to file!" << std::endl;
957 file <<
"DistanceMethod: ";
958 switch(distanceMethod){
960 file <<ABSOLUTE_DIST<< std::endl;
962 case(EUCLIDEAN_DIST):
963 file <<EUCLIDEAN_DIST<< std::endl;
966 file <<ABSOLUTE_DIST<< std::endl;
969 file <<
"UseSmoothing: "<<useSmoothing<< std::endl;
970 file <<
"SmoothingFactor: "<<smoothingFactor<< std::endl;
971 file <<
"UseZNormalisation: "<<useZNormalisation<< std::endl;
972 file <<
"OffsetUsingFirstSample: " << offsetUsingFirstSample << std::endl;
973 file <<
"ConstrainWarpingPath: " << constrainWarpingPath << std::endl;
974 file <<
"Radius: " << radius << std::endl;
975 file <<
"RejectionMode: " << rejectionMode<< std::endl;
978 file <<
"NumberOfTemplates: " << numTemplates << std::endl;
979 file <<
"OverallAverageTemplateLength: " << averageTemplateLength << std::endl;
981 for(UINT i=0; i<numTemplates; i++){
982 file <<
"***************TEMPLATE***************" << std::endl;
983 file <<
"Template: " << i+1 << std::endl;
984 file <<
"ClassLabel: " << templatesBuffer[i].classLabel << std::endl;
985 file <<
"TimeSeriesLength: " << templatesBuffer[i].timeSeries.getNumRows() << std::endl;
986 file <<
"TemplateThreshold: " << nullRejectionThresholds[i] << std::endl;
987 file <<
"TrainingMu: " << templatesBuffer[i].trainingMu << std::endl;
988 file <<
"TrainingSigma: " << templatesBuffer[i].trainingSigma << std::endl;
989 file <<
"AverageTemplateLength: " << templatesBuffer[i].averageTemplateLength << std::endl;
990 file <<
"TimeSeries: " << std::endl;
991 for(UINT k=0; k<templatesBuffer[i].timeSeries.getNumRows(); k++){
992 for(UINT j=0; j<templatesBuffer[i].timeSeries.getNumCols(); j++){
993 file << templatesBuffer[i].timeSeries[k][j] <<
"\t";
1006 UINT timeSeriesLength;
1011 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to open file!" << std::endl;
1018 if( word ==
"GRT_DTW_Model_File_V1.0" ){
1019 return loadLegacyModelFromFile( file );
1023 if(word !=
"GRT_DTW_Model_File_V2.0"){
1024 errorLog <<
"loadDTWModelFromFile( string fileName ) - Unknown file header!" << std::endl;
1030 errorLog <<
"loadModelFromFile(string filename) - Failed to load base settings from file!" << std::endl;
1036 if(word !=
"DistanceMethod:"){
1037 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find DistanceMethod!" << std::endl;
1040 file >> distanceMethod;
1044 if(word !=
"UseSmoothing:"){
1045 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseSmoothing!" << std::endl;
1048 file >> useSmoothing;
1052 if(word !=
"SmoothingFactor:"){
1053 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find SmoothingFactor!" << std::endl;
1056 file >> smoothingFactor;
1060 if(word !=
"UseZNormalisation:"){
1061 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseZNormalisation!" << std::endl;
1064 file >> useZNormalisation;
1068 if(word !=
"OffsetUsingFirstSample:"){
1069 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find OffsetUsingFirstSample!" << std::endl;
1072 file >> offsetUsingFirstSample;
1076 if(word !=
"ConstrainWarpingPath:"){
1077 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find ConstrainWarpingPath!" << std::endl;
1080 file >> constrainWarpingPath;
1084 if(word !=
"Radius:"){
1085 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find Radius!" << std::endl;
1092 if(word !=
"RejectionMode:"){
1093 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find RejectionMode!" << std::endl;
1096 file >> rejectionMode;
1102 if(word !=
"NumberOfTemplates:"){
1103 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find NumberOfTemplates!" << std::endl;
1106 file >> numTemplates;
1110 if(word !=
"OverallAverageTemplateLength:"){
1111 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find OverallAverageTemplateLength!" << std::endl;
1114 file >> averageTemplateLength;
1117 templatesBuffer.
resize(numTemplates);
1118 classLabels.
resize(numTemplates);
1119 nullRejectionThresholds.
resize(numTemplates);
1122 for(UINT i=0; i<numTemplates; i++){
1125 if( word !=
"***************TEMPLATE***************" ){
1127 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find template header!" << std::endl;
1133 if(word !=
"Template:"){
1135 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find Template Number!" << std::endl;
1143 errorLog <<
"loadDTWModelFromFile( string fileName ) - Invalid Template Number: " << ts << std::endl;
1149 if(word !=
"ClassLabel:"){
1151 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find ClassLabel!" << std::endl;
1154 file >> templatesBuffer[i].classLabel;
1155 classLabels[i] = templatesBuffer[i].classLabel;
1159 if(word !=
"TimeSeriesLength:"){
1161 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TimeSeriesLength!" << std::endl;
1164 file >> timeSeriesLength;
1167 templatesBuffer[i].timeSeries.
resize(timeSeriesLength,numInputDimensions);
1171 if(word !=
"TemplateThreshold:"){
1173 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TemplateThreshold!" << std::endl;
1176 file >> nullRejectionThresholds[i];
1180 if(word !=
"TrainingMu:"){
1182 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TrainingMu!" << std::endl;
1185 file >> templatesBuffer[i].trainingMu;
1189 if(word !=
"TrainingSigma:"){
1191 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TrainingSigma!" << std::endl;
1194 file >> templatesBuffer[i].trainingSigma;
1198 if(word !=
"AverageTemplateLength:"){
1200 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find AverageTemplateLength!" << std::endl;
1203 file >> templatesBuffer[i].averageTemplateLength;
1207 if(word !=
"TimeSeries:"){
1209 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find template timeseries!" << std::endl;
1212 for(UINT k=0; k<timeSeriesLength; k++)
1213 for(UINT j=0; j<numInputDimensions; j++)
1214 file >> templatesBuffer[i].timeSeries[k][j];
1218 continuousInputDataBuffer.
clear();
1219 continuousInputDataBuffer.
resize(averageTemplateLength,
VectorFloat(numInputDimensions,0));
1221 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
1223 classDistances.
resize(numClasses,DEFAULT_NULL_DISTANCE_VALUE);
1229 if( rejectionMode == TEMPLATE_THRESHOLDS || rejectionMode == CLASS_LIKELIHOODS || rejectionMode == THRESHOLDS_AND_LIKELIHOODS ){
1230 this->rejectionMode = rejectionMode;
1238 this->nullRejectionLikelihoodThreshold = nullRejectionLikelihoodThreshold;
1243 this->offsetUsingFirstSample = offsetUsingFirstSample;
1248 this->constrainWarpingPath = constrain;
1253 this->radius = radius;
1258 this->useZNormalisation = useZNormalisation;
1259 this->constrainZNorm = constrainZNorm;
1265 if( trimThreshold < 0 || trimThreshold > 1 ){
1266 warningLog <<
"Failed to set trimTrainingData. The trimThreshold must be in the range of [0 1]" << std::endl;
1269 if( maximumTrimPercentage < 0 || maximumTrimPercentage > 100 ){
1270 warningLog <<
"Failed to set trimTrainingData. The maximumTrimPercentage must be a valid percentage in the range of [0 100]" << std::endl;
1274 this->trimTrainingData = trimTrainingData;
1275 this->trimThreshold = trimThreshold;
1276 this->maximumTrimPercentage = maximumTrimPercentage;
1280 void DTW::offsetTimeseries(
MatrixFloat ×eries){
1282 for(UINT i=0; i<timeseries.
getNumRows(); i++){
1283 for(UINT j=0; j<timeseries.
getNumCols(); j++){
1284 timeseries[i][j] -= firstRow[j];
1289 bool DTW::loadLegacyModelFromFile( std::fstream &file ){
1292 UINT timeSeriesLength;
1297 if(word !=
"NumberOfDimensions:"){
1298 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find NumberOfDimensions!" << std::endl;
1301 file >> numInputDimensions;
1305 if(word !=
"NumberOfClasses:"){
1306 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find NumberOfClasses!" << std::endl;
1313 if(word !=
"NumberOfTemplates:"){
1314 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find NumberOfTemplates!" << std::endl;
1317 file >> numTemplates;
1321 if(word !=
"DistanceMethod:"){
1322 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find DistanceMethod!" << std::endl;
1325 file >> distanceMethod;
1329 if(word !=
"UseNullRejection:"){
1330 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseNullRejection!" << std::endl;
1333 file >> useNullRejection;
1337 if(word !=
"UseSmoothing:"){
1338 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseSmoothing!" << std::endl;
1341 file >> useSmoothing;
1345 if(word !=
"SmoothingFactor:"){
1346 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find SmoothingFactor!" << std::endl;
1349 file >> smoothingFactor;
1353 if(word !=
"UseScaling:"){
1354 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseScaling!" << std::endl;
1361 if(word !=
"UseZNormalisation:"){
1362 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find UseZNormalisation!" << std::endl;
1365 file >> useZNormalisation;
1369 if(word !=
"OffsetUsingFirstSample:"){
1370 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find OffsetUsingFirstSample!" << std::endl;
1373 file >> offsetUsingFirstSample;
1377 if(word !=
"ConstrainWarpingPath:"){
1378 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find ConstrainWarpingPath!" << std::endl;
1381 file >> constrainWarpingPath;
1385 if(word !=
"Radius:"){
1386 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find Radius!" << std::endl;
1393 if(word !=
"RejectionMode:"){
1394 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find RejectionMode!" << std::endl;
1397 file >> rejectionMode;
1401 if(word !=
"NullRejectionCoeff:"){
1402 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find NullRejectionCoeff!" << std::endl;
1405 file >> nullRejectionCoeff;
1409 if(word !=
"OverallAverageTemplateLength:"){
1410 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find OverallAverageTemplateLength!" << std::endl;
1413 file >> averageTemplateLength;
1416 templatesBuffer.
resize(numTemplates);
1417 classLabels.
resize(numTemplates);
1418 nullRejectionThresholds.
resize(numTemplates);
1421 for(UINT i=0; i<numTemplates; i++){
1424 while(word !=
"Template:"){
1433 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find Invalid Template Number!" << std::endl;
1439 if(word !=
"ClassLabel:"){
1442 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find ClassLabel!" << std::endl;
1445 file >> templatesBuffer[i].classLabel;
1446 classLabels[i] = templatesBuffer[i].classLabel;
1450 if(word !=
"TimeSeriesLength:"){
1453 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TimeSeriesLength!" << std::endl;
1456 file >> timeSeriesLength;
1459 templatesBuffer[i].timeSeries.
resize(timeSeriesLength,numInputDimensions);
1463 if(word !=
"TemplateThreshold:"){
1466 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TemplateThreshold!" << std::endl;
1469 file >> nullRejectionThresholds[i];
1473 if(word !=
"TrainingMu:"){
1476 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TrainingMu!" << std::endl;
1479 file >> templatesBuffer[i].trainingMu;
1483 if(word !=
"TrainingSigma:"){
1486 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find TrainingSigma!" << std::endl;
1489 file >> templatesBuffer[i].trainingSigma;
1493 if(word !=
"AverageTemplateLength:"){
1496 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find AverageTemplateLength!" << std::endl;
1499 file >> templatesBuffer[i].averageTemplateLength;
1503 if(word !=
"TimeSeries:"){
1506 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find template timeseries!" << std::endl;
1509 for(UINT k=0; k<timeSeriesLength; k++)
1510 for(UINT j=0; j<numInputDimensions; j++)
1511 file >> templatesBuffer[i].timeSeries[k][j];
1515 if(word !=
"***************************"){
1518 numInputDimensions=0;
1520 errorLog <<
"loadDTWModelFromFile( string fileName ) - Failed to find template footer!" << std::endl;
1526 continuousInputDataBuffer.
clear();
1527 continuousInputDataBuffer.
resize(averageTemplateLength,
VectorFloat(numInputDimensions,0));
1529 bestDistance = DEFAULT_NULL_DISTANCE_VALUE;
1531 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 loadModelFromFile(std::fstream &file)
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
unsigned int getSize() const
bool resize(const unsigned int newBufferSize)
virtual bool saveModelToFile(std::fstream &file) const