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.
PrincipalComponentAnalysis.cpp
Go to the documentation of this file.
1 
27 
28 namespace GRT{
29 
31  trained = false;
32  normData = false;
33  numInputDimensions = 0;
34  numPrincipalComponents = 0;
35  maxVariance = 0;
36 
37  classType = "PrincipalComponentAnalysis";
38  errorLog.setProceedingText("[ERROR PrincipalComponentAnalysis]");
39  warningLog.setProceedingText("[WARNING PrincipalComponentAnalysis]");
40 }
41 
43 
44 }
45 
46 bool PrincipalComponentAnalysis::computeFeatureVector(const MatrixDouble &data,double maxVariance,bool normData){
47  trained = false;
48  this->maxVariance = maxVariance;
49  this->normData = normData;
50  return computeFeatureVector_(data,MAX_VARIANCE);
51 }
52 
53 bool PrincipalComponentAnalysis::computeFeatureVector(const MatrixDouble &data,UINT numPrincipalComponents,bool normData){
54  trained = false;
55  if( numPrincipalComponents > data.getNumCols() ){
56  errorLog << "computeFeatureVector(const MatrixDouble &data,UINT numPrincipalComponents,bool normData) - The number of principal components (";
57  errorLog << numPrincipalComponents << ") is greater than the number of columns in your data (" << data.getNumCols() << ")" << endl;
58  return false;
59  }
60  this->numPrincipalComponents = numPrincipalComponents;
61  this->normData = normData;
62  return computeFeatureVector_(data,MAX_NUM_PCS);
63 }
64 
65 bool PrincipalComponentAnalysis::computeFeatureVector_(const MatrixDouble &data,const UINT analysisMode){
66 
67  trained = false;
68  const UINT M = data.getNumRows();
69  const UINT N = data.getNumCols();
70  this->numInputDimensions = N;
71 
72  MatrixDouble msData( M, N );
73 
74  //Compute the mean and standard deviation of the input data
75  mean = data.getMean();
76  stdDev = data.getStdDev();
77 
78  if( normData ){
79  //Normalize the data
80  for(UINT i=0; i<M; i++)
81  for(UINT j=0; j<N; j++)
82  msData[i][j] = (data[i][j]-mean[j]) / stdDev[j];
83 
84  }else{
85  //Mean Subtract Data
86  for(UINT i=0; i<M; i++)
87  for(UINT j=0; j<N; j++)
88  msData[i][j] = data[i][j] - mean[j];
89  }
90 
91  //Get the covariance matrix
92  MatrixDouble cov = msData.getCovarianceMatrix();
93 
94  //Use Eigen Value Decomposition to find eigenvectors of the covariance matrix
95  EigenvalueDecomposition eig;
96 
97  if( !eig.decompose( cov ) ){
98  mean.clear();
99  stdDev.clear();
100  componentWeights.clear();
101  sortedEigenvalues.clear();
102  eigenvectors.clear();
103  errorLog << "computeFeatureVector(const MatrixDouble &data,UINT analysisMode) - Failed to decompose input matrix!" << endl;
104  return false;
105  }
106 
107  //Get the eigenvectors and eigenvalues
108  eigenvectors = eig.getEigenvectors();
109  eigenvalues = eig.getRealEigenvalues();
110 
111  //Any eigenvalues less than 0 are not worth anything so set to 0
112  for(UINT i=0; i<eigenvalues.size(); i++){
113  if( eigenvalues[i] < 0 )
114  eigenvalues[i] = 0;
115  }
116 
117  //Sort the eigenvalues and compute the component weights
118  double sum = 0;
119  UINT componentIndex = 0;
120  sortedEigenvalues.clear();
121  componentWeights.resize(N,0);
122 
123  while( true ){
124  double maxValue = 0;
125  UINT index = 0;
126  for(UINT i=0; i<eigenvalues.size(); i++){
127  if( eigenvalues[i] > maxValue ){
128  maxValue = eigenvalues[i];
129  index = i;
130  }
131  }
132  if( maxValue == 0 || componentIndex >= eigenvalues.size() ){
133  break;
134  }
135  sortedEigenvalues.push_back( IndexedDouble(index,maxValue) );
136  componentWeights[ componentIndex++ ] = eigenvalues[ index ];
137  sum += eigenvalues[ index ];
138  eigenvalues[ index ] = 0; //Set the maxValue to zero so it won't be used again
139  }
140 
141  double cumulativeVariance = 0;
142  switch( analysisMode ){
143  case MAX_VARIANCE:
144  //Normalize the component weights and workout how many components we need to use to reach the maxVariance
145  numPrincipalComponents = 0;
146  for(UINT k=0; k<N; k++){
147  componentWeights[k] /= sum;
148  cumulativeVariance += componentWeights[k];
149  if( cumulativeVariance >= maxVariance && numPrincipalComponents==0 ){
150  numPrincipalComponents = k+1;
151  }
152  }
153  break;
154  case MAX_NUM_PCS:
155  //Normalize the component weights and compute the maxVariance
156  maxVariance = 0;
157  for(UINT k=0; k<N; k++){
158  componentWeights[k] /= sum;
159  if( k < numPrincipalComponents ){
160  maxVariance += componentWeights[k];
161  }
162  }
163  break;
164  default:
165  errorLog << "computeFeatureVector(const MatrixDouble &data,UINT analysisMode) - Unknown analysis mode!" << endl;
166  break;
167  }
168 
169  //Get the raw eigenvalues (encase the user asks for these later)
170  eigenvalues = eig.getRealEigenvalues();
171 
172  //Flag that the features have been computed
173  trained = true;
174 
175  return true;
176 }
177 
179 
180  if( !trained ){
181  warningLog << "project(const MatrixDouble &data,MatrixDouble &prjData) - The PrincipalComponentAnalysis module has not been trained!" << endl;
182  return false;
183  }
184  if( data.getNumCols() != numInputDimensions ){
185  warningLog << "project(const MatrixDouble &data,MatrixDouble &prjData) - The number of columns in the input vector (" << data.getNumCols() << ") does not match the number of input dimensions (" << numInputDimensions << ")!" << endl;
186  return false;
187  }
188 
189  MatrixDouble msData( data );
190  prjData.resize(data.getNumRows(),numPrincipalComponents);
191 
192  if( normData ){
193  //Mean subtract the data
194  for(UINT i=0; i<data.getNumRows(); i++)
195  for(UINT j=0; j<numInputDimensions; j++)
196  msData[i][j] = (msData[i][j]-mean[j])/stdDev[j];
197  }else{
198  //Mean subtract the data
199  for(UINT i=0; i<data.getNumRows(); i++)
200  for(UINT j=0; j<numInputDimensions; j++)
201  msData[i][j] -= mean[j];
202  }
203 
204  //Projected Data
205  for(UINT row=0; row<msData.getNumRows(); row++){//For each row in the final data
206  for(UINT i=0; i<numPrincipalComponents; i++){//For each PC
207  prjData[row][i]=0;
208  for(UINT j=0; j<data.getNumCols(); j++)//For each feature
209  prjData[row][i] += msData[row][j] * eigenvectors[j][sortedEigenvalues[i].index];
210  }
211  }
212 
213  return true;
214 }
215 
216 bool PrincipalComponentAnalysis::project(const VectorDouble &data,VectorDouble &prjData){
217 
218  const unsigned int N = (unsigned int)data.size();
219 
220  if( !trained ){
221  warningLog << "project(const VectorDouble &data,VectorDouble &prjData) - The PrincipalComponentAnalysis module has not been trained!" << endl;
222  return false;
223  }
224  if( N != numInputDimensions ){
225  warningLog << "project(const VectorDouble &data,VectorDouble &prjData) - The size of the input vector (" << N << ") does not match the number of input dimensions (" << numInputDimensions << ")!" << endl;
226  return false;
227  }
228 
229  VectorDouble msData = data;
230 
231  if( normData ){
232  //Mean subtract the data
233  for(UINT j=0; j<numInputDimensions; j++)
234  msData[j] = (msData[j]-mean[j])/stdDev[j];
235  }else{
236  //Mean subtract the data
237  for(UINT j=0; j<numInputDimensions; j++)
238  msData[j] -= mean[j];
239  }
240 
241  //Projected Data
242  prjData.resize( numPrincipalComponents );
243  for(UINT i=0; i<numPrincipalComponents; i++){//For each PC
244  prjData[i]=0;
245  for(UINT j=0; j<N; j++)//For each feature
246  prjData[i] += msData[j] * eigenvectors[j][sortedEigenvalues[i].index];
247  }
248 
249  return true;
250 }
251 
252 bool PrincipalComponentAnalysis::print(string title) const{
253 
254  if( title != "" ){
255  cout << title << endl;
256  }
257  if( !trained ){
258  cout << "Not Trained!\n";
259  return false;
260  }
261  cout << "NumInputDimensions: " << numInputDimensions << " NumPrincipalComponents: " << numPrincipalComponents << endl;
262  cout << "ComponentWeights: ";
263  for(UINT k=0; k<componentWeights.size(); k++){
264  cout << "\t" << componentWeights[k];
265  }
266  cout << endl;
267  cout << "SortedEigenValues: ";
268  for(UINT k=0; k<sortedEigenvalues.size(); k++){
269  cout << "\t" << sortedEigenvalues[k].value;
270  }
271  cout << endl;
272  eigenvectors.print("Eigenvectors:");
273 
274  return true;
275 }
276 
278  return eigenvectors;
279 }
280 
281 }//End of namespace GRT
Definition: AdaBoost.cpp:25
unsigned int getNumCols() const
Definition: Matrix.h:538
VectorDouble getStdDev() const
virtual bool print(string title="") const
void clear()
Definition: Matrix.h:511
bool computeFeatureVector(const MatrixDouble &data, double maxVariance=0.95, bool normData=false)
MatrixDouble getCovarianceMatrix() const
unsigned int getNumRows() const
Definition: Matrix.h:531
This class runs the Principal Component Analysis (PCA) algorithm, a dimensionality reduction algorith...
VectorDouble getMean() const
bool project(const MatrixDouble &data, MatrixDouble &prjData)
virtual bool resize(const unsigned int r, const unsigned int c)
Definition: Matrix.h:234
bool print(const string title="") const