CEBL  2.1
NN.cpp
Go to the documentation of this file.
1 #include "QDA.hpp"
2 
3 using namespace cppR;
4 using namespace ublas;
5 using namespace std;
6 
7 namespace CEBL {
8 
10  void QDA::train(const EEGTrainingData& data) {
11 
12  bool debug = false;
13 
14  //X is nsamples by nfeatures
15  ublas::matrix<double> X = t(data.collapse());
16  if(debug)
17  cout << "Starting QDA Training\n"
18  << "X = matrix[" << X.size1() << "," << X.size2() << "]\n";
19 
20  ublas::vector<int> Y = data.getTargets();
21 
22  classes = unique(Y);
23  int nClasses = classes.size();
24  int nSamples = nrow(X);
25  int nFeatures = ncol(X);
26  covariances.resize(nClasses);
27  covariancesInv.resize(nClasses);
28  for (int k = 0; k < nClasses; k++) {
29  //allow for inturruption here
30  this->inturruptionPoint();
31 
32  covariances[k] = createMatrix(0,nFeatures,nFeatures);
33  covariancesInv[k] = createMatrix(0,nFeatures,nFeatures);
34  }
35  covariancesDet = createVector(0,nClasses);
36 
37  priors = rep(0, nClasses);
38 
39  means = createMatrix(0, nClasses, nFeatures);
40  if(debug)
41  cout << "Classes: " << classes << endl << flush;
42 
43  for(int k=0; k< nClasses; k++) {
44  //allow for inturruption here
45  this->inturruptionPoint();
46 
47  // Select samples (X rows) corresponding to targets
48  // (Y) of particular class
49  std::vector<bool> mask = createMask(classes[k], Y);
50  ublas::matrix<double> Z(count(k,classes), nFeatures);
51  Z = rowMask(X, mask);
52  // Does this work instead? ublas::matrix<double> Z = rowMask(X, mask);
53 
54  int nSamplesThisClass = nrow(Z);
55 
56  // Priors are proportion of sample from each class
57  priors[k] = double(nSamplesThisClass) / nSamples;
58 
59  // Class means
60  row(means,k) = colMeans(Z);
61 
62  //R Code: x.c[mask,] <- x[mask,] - matrix( clsf$means[k,], N.k, p, byrow=TRUE);
63  matrix<double> temp = createMatrix(ublas::vector<double>(row(means,k)),
64  nSamplesThisClass, nFeatures, true);
65  matrix<double> Zc = Z - temp;
66 
67  //allow for inturruption here
68  this->inturruptionPoint();
69 
70  covariances[k] = prod(t(Zc), Zc) / nSamplesThisClass;
71  covariancesInv[k] = solve(covariances[k]);
72  covariancesDet[k] = det(covariances[k]);
73 
74  //CHECK RANK
75  // if(rank(c) < nrow(c)) {
76  // cout << "Rank is too small. Inflating covariance matrix\n";
77  // c = c * .9 + diag(.1, nrow(c));
78  // }
79 
80  }
81  trained = true;
82  }
83 
85  ublas::vector<int> QDA::use(const ublas::matrix<double> & data)
86  {
87  if(data.size1() == 0)
88  {
89  cerr << "QDA use error: 0 size data matrix given.\n";
90  ublas::vector<int> ret;
91  return ret;
92  }
93 
94  ublas::matrix<double> X = data;
95  X = t(X);
96 
97  //ublas::vector<int> Y = data.getMatrixClassVector();
98  int nClasses = classes.size();
99  int nSamples = nrow(X);
100  int nFeatures = ncol(X);
101 
102  ublas::matrix<double> disc_functions(nSamples,nClasses);
103 
104  //create discriminate function for each class
105  for(int k=0; k< nClasses; k++)
106  {
107  matrix<double> temp = createMatrix(ublas::vector<double>(row(means,k)),
108  nSamples, nFeatures, true);
109  ublas::matrix<double> Xc = X - temp; //Xc is X - mu_k
110  double scalarpart = -0.5 * log(covariancesDet[k]) + log(priors[k]);
111  ublas::matrix<double> a = prod( Xc,covariancesInv[k]);
112  ublas::matrix<double> sa = compProd(a,Xc);
113  ublas::vector<double> vectorpart = -0.5 * rowSums(sa);
114  for(unsigned int vi=0; vi<vectorpart.size(); vi++)
115  disc_functions(vi,k) = vectorpart[vi] + scalarpart;
116 
117  }
118  //for each column of deltas find max
119  ublas::vector<int> predicted_classes;
120  predicted_classes.resize(nSamples);
121 
122  for(int j=0; j<nrow(disc_functions); j++)
123  {
124  ublas::vector<double> disc_functionsRow = row(disc_functions,j);
125  predicted_classes[j] = classes[whichMax(disc_functionsRow)];
126  }
127 
128  //----------------------------------------------------------------------
129  //compute probabilities for each class
130  if(compute_probs)
131  {
132  // get vector of maximum for each row in disc functions
133  ublas::vector<double> max_disc =
134  cppR::rowApply<double>(disc_functions,&cppR::max<double>);
135 
136  // create a matrix of the same size as disc functions whose
137  // columns are max_disc
138  matrix<double> max_discs =
139  createMatrix(max_disc,disc_functions.size1(),disc_functions.size2());
140 
141  //take the exponent of the disc functions subtracted from their max
142  matrix<double> probabilities =
143  apply(matrix<double>(disc_functions - max_discs), exp);
144 
145  //get rowsums from probabilities
146  ublas::vector<double> sum_p = cppR::rowSums(probabilities);
147 
148  //divide probabilities by rowsums
149  matrix<double> sum_p_rep =
150  createMatrix(sum_p,probabilities.size1(),probabilities.size2());
151  probabilities = compDiv(probabilities, sum_p_rep);
152 
153  //copy to probabilities member variable
154  this->probabilities.resize(probabilities.size1());
155  for(unsigned i=0;i<probabilities.size1();i++)
156  this->probabilities[i] =
157  asStdVector(ublas::vector<double>(row(probabilities,i)));
158 
159  }
160 
161  //----------------------------------------------------------------------
162  //return predicted classes
163  return predicted_classes;
164  }
165 
166 
167 
169  map<string, SerializedObject> QDA::save() const
170  {
171  map<string, SerializedObject> ret;
172  ret["trained"] = serialize(trained);
173  ret["priors"] = serialize(priors);
174  ret["means"] = serialize(means);
175  ret["covariances"] = serialize(covariances);
176  ret["covariancesInv"] = serialize(covariancesInv);
177  ret["covariancesDet"] = serialize(covariancesDet);
178  ret["classes"] = serialize(classes);
179  return ret;
180  }
181 
183  void QDA::load(map<string, SerializedObject> objects)
184  {
185  deserialize(objects["trained"],trained);
186  deserialize(objects["priors"],priors);
187  deserialize(objects["means"],means);
188  deserialize(objects["covariances"],covariances);
189  deserialize(objects["covariancesInv"],covariancesInv);
190  deserialize(objects["covariancesDet"],covariancesDet);
191  deserialize(objects["classes"],classes);
192  }
193 
194 
195 
197  std::map<std::string, CEBL::Param> QDA::getParamsList()
198  {
199  std::map<std::string, CEBL::Param> params;
200  CEBL::Param probs("Compute Probabilities",
201  "Should QDA compute probabilities when you use the classifier?",
202  compute_probs);
203  params["probs"] = probs;
204 
205  return params;
206  }
207 
209  void QDA::setParamsList( std::map<std::string, CEBL::Param> &p)
210  {
211  compute_probs = bool((*(p.begin())).getBool());
212  }
213 }
214 
215 
216 
217 /*************************************************************/
218 //DYNAMIC LOADING
219 
221 {
222  return new CEBL::QDA;
223 }
224 
225 extern "C" void ObjectDestroy(CEBL::Classifier* p)
226 {
227  delete p;
228 }