Logo ROOT   6.08/07
Reference Guide
TPrincipal.cxx
Go to the documentation of this file.
1 // @(#)root/hist:$Id$
2 // Author: Christian Holm Christensen 1/8/2000
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TPrincipal
13  \ingroup Hist
14 Principal Components Analysis (PCA)
15 
16 The current implementation is based on the LINTRA package from CERNLIB
17 by R. Brun, H. Hansroul, and J. Kubler.
18 The class has been implemented by Christian Holm Christensen in August 2000.
19 
20 ## Introduction
21 
22 In many applications of various fields of research, the treatment of
23 large amounts of data requires powerful techniques capable of rapid
24 data reduction and analysis. Usually, the quantities most
25 conveniently measured by the experimentalist, are not necessarily the
26 most significant for classification and analysis of the data. It is
27 then useful to have a way of selecting an optimal set of variables
28 necessary for the recognition process and reducing the dimensionality
29 of the problem, resulting in an easier classification procedure.
30 
31 This paper describes the implementation of one such method of
32 feature selection, namely the principal components analysis. This
33 multidimensional technique is well known in the field of pattern
34 recognition and and its use in Particle Physics has been documented
35 elsewhere (cf. H. Wind, <I>Function Parameterization</I>, CERN
36 72-21).
37 
38 ## Overview
39 Suppose we have prototypes which are trajectories of particles,
40 passing through a spectrometer. If one measures the passage of the
41 particle at say 8 fixed planes, the trajectory is described by an
42 8-component vector:
43 \f[
44  \mathbf{x} = \left(x_0, x_1, \ldots, x_7\right)
45 \f]
46 in 8-dimensional pattern space.
47 
48 One proceeds by generating a a representative tracks sample and
49 building up the covariance matrix \f$\mathsf{C}\f$. Its eigenvectors and
50 eigenvalues are computed by standard methods, and thus a new basis is
51 obtained for the original 8-dimensional space the expansion of the
52 prototypes,
53 \f[
54  \mathbf{x}_m = \sum^7_{i=0} a_{m_i} \mathbf{e}_i
55  \quad
56  \mbox{where}
57  \quad
58  a_{m_i} = \mathbf{x}^T\bullet\mathbf{e}_i
59 \f]
60 allows the study of the behavior of the coefficients \f$a_{m_i}\f$ for all
61 the tracks of the sample. The eigenvectors which are insignificant for
62 the trajectory description in the expansion will have their
63 corresponding coefficients \f$a_{m_i}\f$ close to zero for all the
64 prototypes.
65 
66 On one hand, a reduction of the dimensionality is then obtained by
67 omitting these least significant vectors in the subsequent analysis.
68 
69 On the other hand, in the analysis of real data, these least
70 significant variables(?) can be used for the pattern
71 recognition problem of extracting the valid combinations of
72 coordinates describing a true trajectory from the set of all possible
73 wrong combinations.
74 
75 The program described here performs this principal components analysis
76 on a sample of data provided by the user. It computes the covariance
77 matrix, its eigenvalues ands corresponding eigenvectors and exhibits
78 the behavior of the principal components \f$a_{m_i}\f$, thus providing
79 to the user all the means of understanding their data.
80 
81 ## Principal Components Method
82 Let's consider a sample of \f$M\f$ prototypes each being characterized by
83 \f$P\f$ variables \f$x_0, x_1, \ldots, x_{P-1}\f$. Each prototype is a point, or a
84 column vector, in a \f$P\f$-dimensional *Pattern space*.
85 \f[
86  \mathbf{x} = \left[\begin{array}{c}
87  x_0\\x_1\\\vdots\\x_{P-1}\end{array}\right]\,,
88 \f]
89 where each \f$x_n\f$ represents the particular value associated with the
90 \f$n\f$-dimension.
91 
92 Those \f$P\f$ variables are the quantities accessible to the
93 experimentalist, but are not necessarily the most significant for the
94 classification purpose.
95 
96 The *Principal Components Method* consists of applying a
97 *linear* transformation to the original variables. This
98 transformation is described by an orthogonal matrix and is equivalent
99 to a rotation of the original pattern space into a new set of
100 coordinate vectors, which hopefully provide easier feature
101 identification and dimensionality reduction.
102 
103 Let's define the covariance matrix:
104 \f[
105  \mathsf{C} = \left\langle\mathbf{y}\mathbf{y}^T\right\rangle
106  \quad\mbox{where}\quad
107  \mathbf{y} = \mathbf{x} - \left\langle\mathbf{x}\right\rangle\,,
108 \f]
109 and the brackets indicate mean value over the sample of \f$M\f$
110 prototypes.
111 
112 This matrix \f$\mathsf{C}\f$ is real, positive definite, symmetric, and will
113 have all its eigenvalues greater then zero. It will now be show that
114 among the family of all the complete orthonormal bases of the pattern
115 space, the base formed by the eigenvectors of the covariance matrix
116 and belonging to the largest eigenvalues, corresponds to the most
117 significant features of the description of the original prototypes.
118 
119 let the prototypes be expanded on into a set of \f$N\f$ basis vectors
120 \f$\mathbf{e}_n, n=0,\ldots,N,N+1, \ldots, P-1\f$
121 \f[
122  \mathbf{y}_i = \sum^N_{i=0} a_{i_n} \mathbf{e}_n,
123  \quad
124  i = 1, \ldots, M,
125  \quad
126  N < P-1
127 \f]
128 The `best' feature coordinates \f$\mathbf{e}_n\f$, spanning a *feature
129 space*, will be obtained by minimizing the error due to this
130 truncated expansion, i.e.,
131 \f[
132  \min\left(E_N\right) =
133  \min\left[\left\langle\left(\mathbf{y}_i - \sum^N_{i=0} a_{i_n} \mathbf{e}_n\right)^2\right\rangle\right]
134 \f]
135 with the conditions:
136 \f[
137  \mathbf{e}_k\bullet\mathbf{e}_j = \delta_{jk} =
138  \left\{\begin{array}{rcl}
139  1 & \mbox{for} & k = j\\
140  0 & \mbox{for} & k \neq j
141  \end{array}\right.
142 \f]
143 Multiplying (3) by \f$\mathbf{e}^T_n\f$ using (5),
144 we get
145 \f[
146  a_{i_n} = \mathbf{y}_i^T\bullet\mathbf{e}_n\,,
147 \f]
148 so the error becomes
149 \f{eqnarray*}{
150  E_N &=&
151  \left\langle\left[\sum_{n=N+1}^{P-1} a_{i_n}\mathbf{e}_n\right]^2\right\rangle\nonumber\\
152  &=&
153  \left\langle\left[\sum_{n=N+1}^{P-1} \mathbf{y}_i^T\bullet\mathbf{e}_n\mathbf{e}_n\right]^2\right\rangle\nonumber\\
154  &=&
155  \left\langle\sum_{n=N+1}^{P-1} \mathbf{e}_n^T\mathbf{y}_i\mathbf{y}_i^T\mathbf{e}_n\right\rangle\nonumber\\
156  &=&
157  \sum_{n=N+1}^{P-1} \mathbf{e}_n^T\mathsf{C}\mathbf{e}_n
158 \f}
159 The minimization of the sum in (7) is obtained when each
160 term \f$\mathbf{e}_n^\mathsf{C}\mathbf{e}_n\f$ is minimum, since \f$\mathsf{C}\f$ is
161 positive definite. By the method of Lagrange multipliers, and the
162 condition (5), we get
163 \f[
164  E_N = \sum^{P-1}_{n=N+1} \left(\mathbf{e}_n^T\mathsf{C}\mathbf{e}_n -
165  l_n\mathbf{e}_n^T\bullet\mathbf{e}_n + l_n\right)
166 \f]
167 The minimum condition \f$\frac{dE_N}{d\mathbf{e}^T_n} = 0\f$ leads to the
168 equation
169 \f[
170  \mathsf{C}\mathbf{e}_n = l_n\mathbf{e}_n\,,
171 \f]
172 which shows that \f$\mathbf{e}_n\f$ is an eigenvector of the covariance
173 matrix \f$\mathsf{C}\f$ with eigenvalue \f$l_n\f$. The estimated minimum error is
174 then given by
175 \f[
176  E_N \sim \sum^{P-1}_{n=N+1} \mathbf{e}_n^T\bullet l_n\mathbf{e}_n
177  = \sum^{P-1}_{n=N+1} l_n\,,
178 \f]
179 where \f$l_n,\,n=N+1,\ldots,P\f$ \f$l_n,\,n=N+1,\ldots,P-1\f$ are the eigenvalues associated with the
180 omitted eigenvectors in the expansion (3). Thus, by choosing
181 the \f$N\f$ largest eigenvalues, and their associated eigenvectors, the
182 error \f$E_N\f$ is minimized.
183 
184 The transformation matrix to go from the pattern space to the feature
185 space consists of the ordered eigenvectors \f$\mathbf{e}_1,\ldots,\mathbf{e}_P\f$
186 \f$\mathbf{e}_0,\ldots,\mathbf{e}_{P-1}\f$ for its columns
187 \f[
188  \mathsf{T} = \left[
189  \begin{array}{cccc}
190  \mathbf{e}_0 &
191  \mathbf{e}_1 &
192  \vdots &
193  \mathbf{e}_{P-1}
194  \end{array}\right]
195  = \left[
196  \begin{array}{cccc}
197  \mathbf{e}_{0_0} & \mathbf{e}_{1_0} & \cdots & \mathbf{e}_{{P-1}_0}\\
198  \mathbf{e}_{0_1} & \mathbf{e}_{1_1} & \cdots & \mathbf{e}_{{P-1}_1}\\
199  \vdots & \vdots & \ddots & \vdots \\
200  \mathbf{e}_{0_{P-1}} & \mathbf{e}_{1_{P-1}} & \cdots & \mathbf{e}_{{P-1}_{P-1}}\\
201  \end{array}\right]
202 \f]
203 This is an orthogonal transformation, or rotation, of the pattern
204 space and feature selection results in ignoring certain coordinates
205 in the transformed space.
206 
207 Christian Holm August 2000, CERN
208 */
209 
210 #include "TPrincipal.h"
211 
212 #include "TVectorD.h"
213 #include "TMatrixD.h"
214 #include "TMatrixDSymEigen.h"
215 #include "TMath.h"
216 #include "TList.h"
217 #include "TH2.h"
218 #include "TDatime.h"
219 #include "TBrowser.h"
220 #include "TROOT.h"
221 #include "Riostream.h"
222 
223 
225 
226 ////////////////////////////////////////////////////////////////////////////////
227 /// Empty constructor. Do not use.
228 
230  : fMeanValues(0),
231  fSigmas(0),
232  fCovarianceMatrix(1,1),
233  fEigenVectors(1,1),
234  fEigenValues(0),
235  fOffDiagonal(0),
236  fStoreData(kFALSE)
237 {
238  fTrace = 0;
239  fHistograms = 0;
242  fNumberOfVariables = 0;
243 }
244 
245 ////////////////////////////////////////////////////////////////////////////////
246 /// Constructor. Argument is number of variables in the sample of data
247 /// Options are:
248 /// - N Normalize the covariance matrix (default)
249 /// - D Store input data (default)
250 ///
251 /// The created object is named "principal" by default.
252 
254  : fMeanValues(nVariables),
255  fSigmas(nVariables),
256  fCovarianceMatrix(nVariables,nVariables),
257  fEigenVectors(nVariables,nVariables),
258  fEigenValues(nVariables),
259  fOffDiagonal(nVariables),
261 {
262  if (nVariables <= 1) {
263  Error("TPrincipal", "You can't be serious - nVariables == 1!!!");
264  return;
265  }
266 
267  SetName("principal");
268 
269  fTrace = 0;
270  fHistograms = 0;
273  fNumberOfVariables = nVariables;
274  while (strlen(opt) > 0) {
275  switch(*opt++) {
276  case 'N':
277  case 'n':
279  break;
280  case 'D':
281  case 'd':
282  fStoreData = kTRUE;
283  break;
284  default:
285  break;
286  }
287  }
288 
289  if (!fMeanValues.IsValid())
290  Error("TPrincipal","Couldn't create vector mean values");
291  if (!fSigmas.IsValid())
292  Error("TPrincipal","Couldn't create vector sigmas");
293  if (!fCovarianceMatrix.IsValid())
294  Error("TPrincipal","Couldn't create covariance matrix");
295  if (!fEigenVectors.IsValid())
296  Error("TPrincipal","Couldn't create eigenvector matrix");
297  if (!fEigenValues.IsValid())
298  Error("TPrincipal","Couldn't create eigenvalue vector");
299  if (!fOffDiagonal.IsValid())
300  Error("TPrincipal","Couldn't create offdiagonal vector");
301  if (fStoreData) {
302  fUserData.ResizeTo(nVariables*1000);
303  fUserData.Zero();
304  if (!fUserData.IsValid())
305  Error("TPrincipal","Couldn't create user data vector");
306  }
307 }
308 
309 ////////////////////////////////////////////////////////////////////////////////
310 /// Copy constructor.
311 
313  TNamed(pr),
317  fSigmas(pr.fSigmas),
322  fUserData(pr.fUserData),
323  fTrace(pr.fTrace),
327 {
328 }
329 
330 ////////////////////////////////////////////////////////////////////////////////
331 /// Assignment operator.
332 
334 {
335  if(this!=&pr) {
336  TNamed::operator=(pr);
340  fSigmas=pr.fSigmas;
345  fUserData=pr.fUserData;
346  fTrace=pr.fTrace;
350  }
351  return *this;
352 }
353 
354 ////////////////////////////////////////////////////////////////////////////////
355 /// Destructor.
356 
358 {
359  if (fHistograms) {
360  fHistograms->Delete();
361  delete fHistograms;
362  }
363 }
364 
365 ////////////////////////////////////////////////////////////////////////////////
366 /// Add a data point and update the covariance matrix. The input
367 /// array must be <TT>fNumberOfVariables</TT> long.
368 ///
369 ///
370 /// The Covariance matrix and mean values of the input data is calculated
371 /// on the fly by the following equations:
372 ///
373 /// \f[
374 /// \left<x_i\right>^{(0)} = x_{i0}
375 /// \f]
376 ///
377 ///
378 /// \f[
379 /// \left<x_i\right>^{(n)} = \left<x_i\right>^{(n-1)}
380 /// + \frac1n \left(x_{in} - \left<x_i\right>^{(n-1)}\right)
381 /// \f]
382 ///
383 /// \f[
384 /// C_{ij}^{(0)} = 0
385 /// \f]
386 ///
387 ///
388 ///
389 /// \f[
390 /// C_{ij}^{(n)} = C_{ij}^{(n-1)}
391 /// + \frac1{n-1}\left[\left(x_{in} - \left<x_i\right>^{(n)}\right)
392 /// \left(x_{jn} - \left<x_j\right>^{(n)}\right)\right]
393 /// - \frac1n C_{ij}^{(n-1)}
394 /// \f]
395 ///
396 /// since this is a really fast method, with no rounding errors (please
397 /// refer to CERN 72-21 pp. 54-106).
398 ///
399 ///
400 /// The data is stored internally in a <TT>TVectorD</TT>, in the following
401 /// way:
402 ///
403 /// \f[
404 /// \mathbf{x} = \left[\left(x_{0_0},\ldots,x_{{P-1}_0}\right),\ldots,
405 /// \left(x_{0_i},\ldots,x_{{P-1}_i}\right), \ldots\right]
406 /// \f]
407 ///
408 /// With \f$P\f$ as defined in the class description.
409 
411 {
412  if (!p)
413  return;
414 
415  // Increment the data point counter
416  Int_t i,j;
417  if (++fNumberOfDataPoints == 1) {
418  for (i = 0; i < fNumberOfVariables; i++)
419  fMeanValues(i) = p[i];
420  }
421  else {
422 
423  Double_t cor = 1 - 1./Double_t(fNumberOfDataPoints);
424  for (i = 0; i < fNumberOfVariables; i++) {
425 
426  fMeanValues(i) *= cor;
428  Double_t t1 = (p[i] - fMeanValues(i)) / (fNumberOfDataPoints - 1);
429 
430  // Setting Matrix (lower triangle) elements
431  for (j = 0; j < i + 1; j++) {
432  fCovarianceMatrix(i,j) *= cor;
433  fCovarianceMatrix(i,j) += t1 * (p[j] - fMeanValues(j));
434  }
435  }
436  }
437 
438  // Store data point in internal vector
439  // If the vector isn't big enough to hold the new data, then
440  // expand the vector by half it's size.
441  if (!fStoreData)
442  return;
443  Int_t size = fUserData.GetNrows();
445  fUserData.ResizeTo(size + size/2);
446 
447  for (i = 0; i < fNumberOfVariables; i++) {
448  j = (fNumberOfDataPoints-1) * fNumberOfVariables + i;
449  fUserData(j) = p[i];
450  }
451 
452 }
453 
454 ////////////////////////////////////////////////////////////////////////////////
455 /// Browse the TPrincipal object in the TBrowser.
456 
458 {
459  if (fHistograms) {
460  TIter next(fHistograms);
461  TH1* h = 0;
462  while ((h = (TH1*)next()))
463  b->Add(h,h->GetName());
464  }
465 
466  if (fStoreData)
467  b->Add(&fUserData,"User Data");
468  b->Add(&fCovarianceMatrix,"Covariance Matrix");
469  b->Add(&fMeanValues,"Mean value vector");
470  b->Add(&fSigmas,"Sigma value vector");
471  b->Add(&fEigenValues,"Eigenvalue vector");
472  b->Add(&fEigenVectors,"Eigenvector Matrix");
473 
474 }
475 
476 ////////////////////////////////////////////////////////////////////////////////
477 /// Clear the data in Object. Notice, that's not possible to change
478 /// the dimension of the original data.
479 
481 {
482  if (fHistograms) {
483  fHistograms->Delete(opt);
484  }
485 
487  fTrace = 0;
490  fEigenValues.Zero();
491  fMeanValues.Zero();
492  fSigmas.Zero();
493  fOffDiagonal.Zero();
494 
495  if (fStoreData) {
497  fUserData.Zero();
498  }
499 }
500 
501 ////////////////////////////////////////////////////////////////////////////////
502 /// Return a row of the user supplied data.
503 /// If row is out of bounds, 0 is returned.
504 /// It's up to the user to delete the returned array.
505 /// Row 0 is the first row;
506 
508 {
509  if (row >= fNumberOfDataPoints)
510  return 0;
511 
512  if (!fStoreData)
513  return 0;
514 
515  Int_t index = row * fNumberOfVariables;
516  return &fUserData(index);
517 }
518 
519 
520 ////////////////////////////////////////////////////////////////////////////////
521 /// Generates the file `<filename>`, with `.C` appended if it does
522 /// argument doesn't end in .cxx or .C.
523 ///
524 /// The file contains the implementation of two functions
525 /// ~~~ {.cpp}
526 /// void X2P(Double_t *x, Double *p)
527 /// void P2X(Double_t *p, Double *x, Int_t nTest)
528 /// ~~~
529 /// which does the same as `TPrincipal::X2P` and `TPrincipal::P2X`
530 /// respectively. Please refer to these methods.
531 ///
532 /// Further, the static variables:
533 /// ~~~ {.cpp}
534 /// Int_t gNVariables
535 /// Double_t gEigenValues[]
536 /// Double_t gEigenVectors[]
537 /// Double_t gMeanValues[]
538 /// Double_t gSigmaValues[]
539 /// ~~~
540 /// are initialized. The only ROOT header file needed is Rtypes.h
541 ///
542 /// See TPrincipal::MakeRealCode for a list of options
543 
544 void TPrincipal::MakeCode(const char *filename, Option_t *opt)
545 {
546  TString outName(filename);
547  if (!outName.EndsWith(".C") && !outName.EndsWith(".cxx"))
548  outName += ".C";
549 
550  MakeRealCode(outName.Data(),"",opt);
551 }
552 
553 ////////////////////////////////////////////////////////////////////////////////
554 /// Make histograms of the result of the analysis.
555 /// The option string say which histograms to create
556 /// - X Histogram original data
557 /// - P Histogram principal components corresponding to
558 /// original data
559 /// - D Histogram the difference between the original data
560 /// and the projection of principal unto a lower
561 /// dimensional subspace (2D histograms)
562 /// - E Histogram the eigenvalues
563 /// - S Histogram the square of the residues
564 /// (see `TPrincipal::SumOfSquareResiduals`)
565 /// The histograms will be named `<name>_<type><number>`, where `<name>`
566 /// is the first argument, `<type>` is one of X,P,D,E,S, and `<number>`
567 /// is the variable.
568 
569 void TPrincipal::MakeHistograms(const char *name, Option_t *opt)
570 {
571  Bool_t makeX = kFALSE;
572  Bool_t makeD = kFALSE;
573  Bool_t makeP = kFALSE;
574  Bool_t makeE = kFALSE;
575  Bool_t makeS = kFALSE;
576 
577  Int_t len = strlen(opt);
578  Int_t i,j,k;
579  for (i = 0; i < len; i++) {
580  switch (opt[i]) {
581  case 'X':
582  case 'x':
583  if (fStoreData)
584  makeX = kTRUE;
585  break;
586  case 'd':
587  case 'D':
588  if (fStoreData)
589  makeD = kTRUE;
590  break;
591  case 'P':
592  case 'p':
593  if (fStoreData)
594  makeP = kTRUE;
595  break;
596  case 'E':
597  case 'e':
598  makeE = kTRUE;
599  break;
600  case 's':
601  case 'S':
602  if (fStoreData)
603  makeS = kTRUE;
604  break;
605  default:
606  Warning("MakeHistograms","Unknown option: %c",opt[i]);
607  }
608  }
609 
610  // If no option was given, then exit gracefully
611  if (!makeX && !makeD && !makeP && !makeE && !makeS)
612  return;
613 
614  // If the list of histograms doesn't exist, create it.
615  if (!fHistograms)
616  fHistograms = new TList;
617 
618  // Don't create the histograms if they are already in the TList.
619  if (makeX && fHistograms->FindObject(Form("%s_x000",name)))
620  makeX = kFALSE;
621  if (makeD && fHistograms->FindObject(Form("%s_d000",name)))
622  makeD = kFALSE;
623  if (makeP && fHistograms->FindObject(Form("%s_p000",name)))
624  makeP = kFALSE;
625  if (makeE && fHistograms->FindObject(Form("%s_e",name)))
626  makeE = kFALSE;
627  if (makeS && fHistograms->FindObject(Form("%s_s",name)))
628  makeS = kFALSE;
629 
630  TH1F **hX = 0;
631  TH2F **hD = 0;
632  TH1F **hP = 0;
633  TH1F *hE = 0;
634  TH1F *hS = 0;
635 
636  // Initialize the arrays of histograms needed
637  if (makeX)
638  hX = new TH1F * [fNumberOfVariables];
639 
640  if (makeD)
641  hD = new TH2F * [fNumberOfVariables];
642 
643  if (makeP)
644  hP = new TH1F * [fNumberOfVariables];
645 
646  if (makeE){
647  hE = new TH1F(Form("%s_e",name), "Eigenvalues of Covariance matrix",
649  hE->SetXTitle("Eigenvalue");
650  fHistograms->Add(hE);
651  }
652 
653  if (makeS) {
654  hS = new TH1F(Form("%s_s",name),"E_{N}",
656  hS->SetXTitle("N");
657  hS->SetYTitle("#sum_{i=1}^{M} (x_{i} - x'_{N,i})^{2}");
658  fHistograms->Add(hS);
659  }
660 
661  // Initialize sub elements of the histogram arrays
662  for (i = 0; i < fNumberOfVariables; i++) {
663  if (makeX) {
664  // We allow 4 sigma spread in the original data in our
665  // histogram.
666  Double_t xlowb = fMeanValues(i) - 4 * fSigmas(i);
667  Double_t xhighb = fMeanValues(i) + 4 * fSigmas(i);
668  Int_t xbins = fNumberOfDataPoints/100;
669  hX[i] = new TH1F(Form("%s_x%03d", name, i),
670  Form("Pattern space, variable %d", i),
671  xbins,xlowb,xhighb);
672  hX[i]->SetXTitle(Form("x_{%d}",i));
673  fHistograms->Add(hX[i]);
674  }
675 
676  if(makeD) {
677  // The upper limit below is arbitrary!!!
678  Double_t dlowb = 0;
679  Double_t dhighb = 20;
680  Int_t dbins = fNumberOfDataPoints/100;
681  hD[i] = new TH2F(Form("%s_d%03d", name, i),
682  Form("Distance from pattern to "
683  "feature space, variable %d", i),
684  dbins,dlowb,dhighb,
685  fNumberOfVariables-1,
686  1,
687  fNumberOfVariables);
688  hD[i]->SetXTitle(Form("|x_{%d} - x'_{%d,N}|/#sigma_{%d}",i,i,i));
689  hD[i]->SetYTitle("N");
690  fHistograms->Add(hD[i]);
691  }
692 
693  if(makeP) {
694  // For some reason, the trace of the none-scaled matrix
695  // (see TPrincipal::MakeNormalised) should enter here. Taken
696  // from LINTRA code.
698  Double_t plowb = -10 * TMath::Sqrt(et);
699  Double_t phighb = -plowb;
700  Int_t pbins = 100;
701  hP[i] = new TH1F(Form("%s_p%03d", name, i),
702  Form("Feature space, variable %d", i),
703  pbins,plowb,phighb);
704  hP[i]->SetXTitle(Form("p_{%d}",i));
705  fHistograms->Add(hP[i]);
706  }
707 
708  if (makeE)
709  // The Eigenvector histogram is easy
710  hE->Fill(i,fEigenValues(i));
711 
712  }
713  if (!makeX && !makeP && !makeD && !makeS)
714  return;
715 
716  Double_t *x = 0;
719  for (i = 0; i < fNumberOfDataPoints; i++) {
720 
721  // Zero arrays
722  for (j = 0; j < fNumberOfVariables; j++)
723  p[j] = d[j] = 0;
724 
725  // update the original data histogram
726  x = (Double_t*)(GetRow(i));
727  R__ASSERT(x);
728 
729  if (makeP||makeD||makeS)
730  // calculate the corresponding principal component
731  X2P(x,p);
732 
733  if (makeD || makeS) {
734  // Calculate the difference between the original data, and the
735  // same project onto principal components, and then to a lower
736  // dimensional sub-space
737  for (j = fNumberOfVariables; j > 0; j--) {
738  P2X(p,d,j);
739 
740  for (k = 0; k < fNumberOfVariables; k++) {
741  // We use the absolute value of the difference!
742  d[k] = x[k] - d[k];
743 
744  if (makeS)
745  hS->Fill(j,d[k]*d[k]);
746 
747  if (makeD) {
748  d[k] = TMath::Abs(d[k]) / (fIsNormalised ? fSigmas(k) : 1);
749  (hD[k])->Fill(d[k],j);
750  }
751  }
752  }
753  }
754 
755  if (makeX||makeP) {
756  // If we are asked to make any of these histograms, we have to
757  // go here
758  for (j = 0; j < fNumberOfVariables; j++) {
759  if (makeX)
760  (hX[j])->Fill(x[j]);
761 
762  if (makeP)
763  (hP[j])->Fill(p[j]);
764  }
765  }
766  }
767  // Clean up
768  if (hX)
769  delete [] hX;
770  if (hD)
771  delete [] hD;
772  if (hP)
773  delete [] hP;
774  if (d)
775  delete [] d;
776  if (p)
777  delete [] p;
778 
779  // Normalize the residues
780  if (makeS)
781  hS->Scale(Double_t(1.)/fNumberOfDataPoints);
782 }
783 
784 ////////////////////////////////////////////////////////////////////////////////
785 /// Normalize the covariance matrix
786 
788 {
789  Int_t i,j;
790  for (i = 0; i < fNumberOfVariables; i++) {
792  if (fIsNormalised)
793  for (j = 0; j <= i; j++)
794  fCovarianceMatrix(i,j) /= (fSigmas(i) * fSigmas(j));
795 
796  fTrace += fCovarianceMatrix(i,i);
797  }
798 
799  // Fill remaining parts of matrix, and scale.
800  for (i = 0; i < fNumberOfVariables; i++)
801  for (j = 0; j <= i; j++) {
802  fCovarianceMatrix(i,j) /= fTrace;
804  }
805 
806 }
807 
808 ////////////////////////////////////////////////////////////////////////////////
809 /// Generate the file <classname>PCA.cxx which contains the
810 /// implementation of two methods:
811 /// ~~~ {.cpp}
812 /// void <classname>::X2P(Double_t *x, Double *p)
813 /// void <classname>::P2X(Double_t *p, Double *x, Int_t nTest)
814 /// ~~~
815 /// which does the same as TPrincipal::X2P and TPrincipal::P2X
816 /// respectively. Please refer to these methods.
817 ///
818 /// Further, the public static members:
819 /// ~~~ {.cpp}
820 /// Int_t <classname>::fgNVariables
821 /// Double_t <classname>::fgEigenValues[]
822 /// Double_t <classname>::fgEigenVectors[]
823 /// Double_t <classname>::fgMeanValues[]
824 /// Double_t <classname>::fgSigmaValues[]
825 /// ~~~
826 /// are initialized, and assumed to exist. The class declaration is
827 /// assumed to be in <classname>.h and assumed to be provided by the
828 /// user.
829 ///
830 /// See TPrincipal::MakeRealCode for a list of options
831 ///
832 /// The minimal class definition is:
833 /// ~~~ {.cpp}
834 /// class <classname> {
835 /// public:
836 /// static Int_t fgNVariables;
837 /// static Double_t fgEigenVectors[];
838 /// static Double_t fgEigenValues[];
839 /// static Double_t fgMeanValues[];
840 /// static Double_t fgSigmaValues[];
841 ///
842 /// void X2P(Double_t *x, Double_t *p);
843 /// void P2X(Double_t *p, Double_t *x, Int_t nTest);
844 /// };
845 /// ~~~
846 /// Whether the methods <classname>::X2P and <classname>::P2X should
847 /// be static or not, is up to the user.
848 
849 void TPrincipal::MakeMethods(const char *classname, Option_t *opt)
850 {
851 
852  MakeRealCode(Form("%sPCA.cxx", classname), classname, opt);
853 }
854 
855 
856 ////////////////////////////////////////////////////////////////////////////////
857 /// Perform the principal components analysis.
858 /// This is done in several stages in the TMatrix::EigenVectors method:
859 /// - Transform the covariance matrix into a tridiagonal matrix.
860 /// - Find the eigenvalues and vectors of the tridiagonal matrix.
861 
863 {
864  // Normalize covariance matrix
865  MakeNormalised();
866 
868  TMatrixDSymEigen eigen(sym);
869  fEigenVectors = eigen.GetEigenVectors();
870  fEigenValues = eigen.GetEigenValues();
871  //make sure that eigenvalues are positive
872  for (Int_t i = 0; i < fNumberOfVariables; i++) {
873  if (fEigenValues[i] < 0) fEigenValues[i] = -fEigenValues[i];
874  }
875 }
876 
877 ////////////////////////////////////////////////////////////////////////////////
878 /// This is the method that actually generates the code for the
879 /// transformations to and from feature space and pattern space
880 /// It's called by TPrincipal::MakeCode and TPrincipal::MakeMethods.
881 ///
882 /// The options are: NONE so far
883 
884 void TPrincipal::MakeRealCode(const char *filename, const char *classname,
885  Option_t *)
886 {
887  Bool_t isMethod = (classname[0] == '\0' ? kFALSE : kTRUE);
888  const char *prefix = (isMethod ? Form("%s::", classname) : "");
889  const char *cv_qual = (isMethod ? "" : "static ");
890 
891  std::ofstream outFile(filename,std::ios::out|std::ios::trunc);
892  if (!outFile) {
893  Error("MakeRealCode","couldn't open output file '%s'",filename);
894  return;
895  }
896 
897  std::cout << "Writing on file \"" << filename << "\" ... " << std::flush;
898  //
899  // Write header of file
900  //
901  // Emacs mode line ;-)
902  outFile << "// -*- mode: c++ -*-" << std::endl;
903  // Info about creator
904  outFile << "// " << std::endl
905  << "// File " << filename
906  << " generated by TPrincipal::MakeCode" << std::endl;
907  // Time stamp
908  TDatime date;
909  outFile << "// on " << date.AsString() << std::endl;
910  // ROOT version info
911  outFile << "// ROOT version " << gROOT->GetVersion()
912  << std::endl << "//" << std::endl;
913  // General information on the code
914  outFile << "// This file contains the functions " << std::endl
915  << "//" << std::endl
916  << "// void " << prefix
917  << "X2P(Double_t *x, Double_t *p); " << std::endl
918  << "// void " << prefix
919  << "P2X(Double_t *p, Double_t *x, Int_t nTest);"
920  << std::endl << "//" << std::endl
921  << "// The first for transforming original data x in " << std::endl
922  << "// pattern space, to principal components p in " << std::endl
923  << "// feature space. The second function is for the" << std::endl
924  << "// inverse transformation, but using only nTest" << std::endl
925  << "// of the principal components in the expansion" << std::endl
926  << "// " << std::endl
927  << "// See TPrincipal class documentation for more "
928  << "information " << std::endl << "// " << std::endl;
929  // Header files
930  outFile << "#ifndef __CINT__" << std::endl;
931  if (isMethod)
932  // If these are methods, we need the class header
933  outFile << "#include \"" << classname << ".h\"" << std::endl;
934  else
935  // otherwise, we need the typedefs of Int_t and Double_t
936  outFile << "#include <Rtypes.h> // needed for Double_t etc" << std::endl;
937  // Finish the preprocessor block
938  outFile << "#endif" << std::endl << std::endl;
939 
940  //
941  // Now for the data
942  //
943  // We make the Eigenvector matrix, Eigenvalue vector, Sigma vector,
944  // and Mean value vector static, since all are needed in both
945  // functions. Also ,the number of variables are stored in a static
946  // variable.
947  outFile << "//" << std::endl
948  << "// Static data variables" << std::endl
949  << "//" << std::endl;
950  outFile << cv_qual << "Int_t " << prefix << "gNVariables = "
951  << fNumberOfVariables << ";" << std::endl;
952 
953  // Assign the values to the Eigenvector matrix. The elements are
954  // stored row-wise, that is element
955  // M[i][j] = e[i * nVariables + j]
956  // where i and j are zero-based.
957  outFile << std::endl << "// Assignment of eigenvector matrix." << std::endl
958  << "// Elements are stored row-wise, that is" << std::endl
959  << "// M[i][j] = e[i * nVariables + j] " << std::endl
960  << "// where i and j are zero-based" << std::endl;
961  outFile << cv_qual << "Double_t " << prefix
962  << "gEigenVectors[] = {" << std::flush;
963  Int_t i,j;
964  for (i = 0; i < fNumberOfVariables; i++) {
965  for (j = 0; j < fNumberOfVariables; j++) {
966  Int_t index = i * fNumberOfVariables + j;
967  outFile << (index != 0 ? "," : "" ) << std::endl
968  << " " << fEigenVectors(i,j) << std::flush;
969  }
970  }
971  outFile << "};" << std::endl << std::endl;
972 
973  // Assignment to eigenvalue vector. Zero-based.
974  outFile << "// Assignment to eigen value vector. Zero-based." << std::endl;
975  outFile << cv_qual << "Double_t " << prefix
976  << "gEigenValues[] = {" << std::flush;
977  for (i = 0; i < fNumberOfVariables; i++)
978  outFile << (i != 0 ? "," : "") << std::endl
979  << " " << fEigenValues(i) << std::flush;
980  outFile << std::endl << "};" << std::endl << std::endl;
981 
982  // Assignment to mean Values vector. Zero-based.
983  outFile << "// Assignment to mean value vector. Zero-based." << std::endl;
984  outFile << cv_qual << "Double_t " << prefix
985  << "gMeanValues[] = {" << std::flush;
986  for (i = 0; i < fNumberOfVariables; i++)
987  outFile << (i != 0 ? "," : "") << std::endl
988  << " " << fMeanValues(i) << std::flush;
989  outFile << std::endl << "};" << std::endl << std::endl;
990 
991  // Assignment to mean Values vector. Zero-based.
992  outFile << "// Assignment to sigma value vector. Zero-based." << std::endl;
993  outFile << cv_qual << "Double_t " << prefix
994  << "gSigmaValues[] = {" << std::flush;
995  for (i = 0; i < fNumberOfVariables; i++)
996  outFile << (i != 0 ? "," : "") << std::endl
997  << " " << (fIsNormalised ? fSigmas(i) : 1) << std::flush;
998  // << " " << fSigmas(i) << std::flush;
999  outFile << std::endl << "};" << std::endl << std::endl;
1000 
1001  //
1002  // Finally we reach the functions themselves
1003  //
1004  // First: void x2p(Double_t *x, Double_t *p);
1005  //
1006  outFile << "// " << std::endl
1007  << "// The "
1008  << (isMethod ? "method " : "function ")
1009  << " void " << prefix
1010  << "X2P(Double_t *x, Double_t *p)"
1011  << std::endl << "// " << std::endl;
1012  outFile << "void " << prefix
1013  << "X2P(Double_t *x, Double_t *p) {" << std::endl
1014  << " for (Int_t i = 0; i < gNVariables; i++) {" << std::endl
1015  << " p[i] = 0;" << std::endl
1016  << " for (Int_t j = 0; j < gNVariables; j++)" << std::endl
1017  << " p[i] += (x[j] - gMeanValues[j]) " << std::endl
1018  << " * gEigenVectors[j * gNVariables + i] "
1019  << "/ gSigmaValues[j];" << std::endl << std::endl << " }"
1020  << std::endl << "}" << std::endl << std::endl;
1021  //
1022  // Now: void p2x(Double_t *p, Double_t *x, Int_t nTest);
1023  //
1024  outFile << "// " << std::endl << "// The "
1025  << (isMethod ? "method " : "function ")
1026  << " void " << prefix
1027  << "P2X(Double_t *p, Double_t *x, Int_t nTest)"
1028  << std::endl << "// " << std::endl;
1029  outFile << "void " << prefix
1030  << "P2X(Double_t *p, Double_t *x, Int_t nTest) {" << std::endl
1031  << " for (Int_t i = 0; i < gNVariables; i++) {" << std::endl
1032  << " x[i] = gMeanValues[i];" << std::endl
1033  << " for (Int_t j = 0; j < nTest; j++)" << std::endl
1034  << " x[i] += p[j] * gSigmaValues[i] " << std::endl
1035  << " * gEigenVectors[i * gNVariables + j];" << std::endl
1036  << " }" << std::endl << "}" << std::endl << std::endl;
1037 
1038  // EOF
1039  outFile << "// EOF for " << filename << std::endl;
1040 
1041  // Close the file
1042  outFile.close();
1043 
1044  std::cout << "done" << std::endl;
1045 }
1046 
1047 ////////////////////////////////////////////////////////////////////////////////
1048 /// Calculate x as a function of nTest of the most significant
1049 /// principal components p, and return it in x.
1050 /// It's the users responsibility to make sure that both x and p are
1051 /// of the right size (i.e., memory must be allocated for x).
1052 
1053 void TPrincipal::P2X(const Double_t *p, Double_t *x, Int_t nTest)
1054 {
1055  for (Int_t i = 0; i < fNumberOfVariables; i++){
1056  x[i] = fMeanValues(i);
1057  for (Int_t j = 0; j < nTest; j++)
1058  x[i] += p[j] * (fIsNormalised ? fSigmas(i) : 1)
1059  * fEigenVectors(i,j);
1060  }
1061 
1062 }
1063 
1064 ////////////////////////////////////////////////////////////////////////////////
1065 /// Print the statistics
1066 /// Options are
1067 /// - M Print mean values of original data
1068 /// - S Print sigma values of original data
1069 /// - E Print eigenvalues of covariance matrix
1070 /// - V Print eigenvectors of covariance matrix
1071 /// Default is MSE
1072 
1073 void TPrincipal::Print(Option_t *opt) const
1074 {
1075  Bool_t printV = kFALSE;
1076  Bool_t printM = kFALSE;
1077  Bool_t printS = kFALSE;
1078  Bool_t printE = kFALSE;
1079 
1080  Int_t len = strlen(opt);
1081  for (Int_t i = 0; i < len; i++) {
1082  switch (opt[i]) {
1083  case 'V':
1084  case 'v':
1085  printV = kTRUE;
1086  break;
1087  case 'M':
1088  case 'm':
1089  printM = kTRUE;
1090  break;
1091  case 'S':
1092  case 's':
1093  printS = kTRUE;
1094  break;
1095  case 'E':
1096  case 'e':
1097  printE = kTRUE;
1098  break;
1099  default:
1100  Warning("Print", "Unknown option '%c'",opt[i]);
1101  break;
1102  }
1103  }
1104 
1105  if (printM||printS||printE) {
1106  std::cout << " Variable # " << std::flush;
1107  if (printM)
1108  std::cout << "| Mean Value " << std::flush;
1109  if (printS)
1110  std::cout << "| Sigma " << std::flush;
1111  if (printE)
1112  std::cout << "| Eigenvalue" << std::flush;
1113  std::cout << std::endl;
1114 
1115  std::cout << "-------------" << std::flush;
1116  if (printM)
1117  std::cout << "+------------" << std::flush;
1118  if (printS)
1119  std::cout << "+------------" << std::flush;
1120  if (printE)
1121  std::cout << "+------------" << std::flush;
1122  std::cout << std::endl;
1123 
1124  for (Int_t i = 0; i < fNumberOfVariables; i++) {
1125  std::cout << std::setw(12) << i << " " << std::flush;
1126  if (printM)
1127  std::cout << "| " << std::setw(10) << std::setprecision(4)
1128  << fMeanValues(i) << " " << std::flush;
1129  if (printS)
1130  std::cout << "| " << std::setw(10) << std::setprecision(4)
1131  << fSigmas(i) << " " << std::flush;
1132  if (printE)
1133  std::cout << "| " << std::setw(10) << std::setprecision(4)
1134  << fEigenValues(i) << " " << std::flush;
1135  std::cout << std::endl;
1136  }
1137  std::cout << std::endl;
1138  }
1139 
1140  if(printV) {
1141  for (Int_t i = 0; i < fNumberOfVariables; i++) {
1142  std::cout << "Eigenvector # " << i << std::flush;
1143  TVectorD v(fNumberOfVariables);
1145  v.Print();
1146  }
1147  }
1148 }
1149 
1150 ////////////////////////////////////////////////////////////////////////////////
1151 /// Calculates the sum of the square residuals, that is
1152 ///
1153 /// \f[
1154 /// E_N = \sum_{i=0}^{P-1} \left(x_i - x^\prime_i\right)^2
1155 /// \f]
1156 ///
1157 /// where \f$x^\prime_i = \sum_{j=i}^N p_i e_{n_j}\f$
1158 /// is the \f$i^{\mbox{th}}\f$ component of the principal vector, corresponding to
1159 /// \f$x_i\f$, the original data; I.e., the square distance to the space
1160 /// spanned by \f$N\f$ eigenvectors.
1161 
1163 {
1164 
1165  if (!x)
1166  return;
1167 
1168  Double_t p[100];
1169  Double_t xp[100];
1170 
1171  X2P(x,p);
1172  for (Int_t i = fNumberOfVariables-1; i >= 0; i--) {
1173  P2X(p,xp,i);
1174  for (Int_t j = 0; j < fNumberOfVariables; j++) {
1175  s[i] += (x[j] - xp[j])*(x[j] - xp[j]);
1176  }
1177  }
1178 }
1179 
1180 ////////////////////////////////////////////////////////////////////////////////
1181 /// Test the PCA, bye calculating the sum square of residuals
1182 /// (see method SumOfSquareResiduals), and display the histogram
1183 
1185 {
1186  MakeHistograms("pca","S");
1187 
1188  if (!fStoreData)
1189  return;
1190 
1191  TH1 *pca_s = 0;
1192  if (fHistograms) pca_s = (TH1*)fHistograms->FindObject("pca_s");
1193  if (!pca_s) {
1194  Warning("Test", "Couldn't get histogram of square residuals");
1195  return;
1196  }
1197 
1198  pca_s->Draw();
1199 }
1200 
1201 ////////////////////////////////////////////////////////////////////////////////
1202 /// Calculate the principal components from the original data vector
1203 /// x, and return it in p.
1204 ///
1205 /// It's the users responsibility to make sure that both x and p are
1206 /// of the right size (i.e., memory must be allocated for p).
1207 
1209 {
1210  for (Int_t i = 0; i < fNumberOfVariables; i++){
1211  p[i] = 0;
1212  for (Int_t j = 0; j < fNumberOfVariables; j++)
1213  p[i] += (x[j] - fMeanValues(j)) * fEigenVectors(j,i) /
1214  (fIsNormalised ? fSigmas(j) : 1);
1215  }
1216 
1217 }
void Add(TObject *obj, const char *name=0, Int_t check=-1)
Add object with name to browser.
Definition: TBrowser.cxx:261
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:51
virtual void Scale(Double_t c1=1, Option_t *option="")
Multiply this histogram by a constant c1.
Definition: TH1.cxx:5936
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
Definition: TH1.cxx:3125
Principal Components Analysis (PCA)
Definition: TPrincipal.h:28
TVectorT< Element > & ResizeTo(Int_t lwb, Int_t upb)
Resize the vector to [lwb:upb] .
Definition: TVectorT.cxx:292
virtual void Browse(TBrowser *b)
Browse the TPrincipal object in the TBrowser.
Definition: TPrincipal.cxx:457
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:405
Bool_t fIsNormalised
Definition: TPrincipal.h:49
TMatrixTSym< Element > & Use(Int_t row_lwb, Int_t row_upb, Element *data)
virtual ~TPrincipal()
Destructor.
Definition: TPrincipal.cxx:357
void MakeRealCode(const char *filename, const char *prefix, Option_t *option="")
This is the method that actually generates the code for the transformations to and from feature space...
Definition: TPrincipal.cxx:884
TMatrixD fEigenVectors
Definition: TPrincipal.h:38
virtual void Print(Option_t *opt="MSE") const
Print the statistics Options are.
TList * fHistograms
Definition: TPrincipal.h:47
virtual TMatrixTBase< Element > & Zero()
Set matrix elements to zero.
virtual void P2X(const Double_t *p, Double_t *x, Int_t nTest)
Calculate x as a function of nTest of the most significant principal components p, and return it in x.
const char Option_t
Definition: RtypesCore.h:62
virtual const Element * GetMatrixArray() const
Definition: TMatrixT.h:223
virtual void SetName(const char *name)
Set the name of the TNamed.
Definition: TNamed.cxx:131
THist< 1, float, THistStatContent, THistStatUncertainty > TH1F
Definition: THist.hxx:302
TH1 * h
Definition: legend2.C:5
TVectorD fMeanValues
Definition: TPrincipal.h:34
#define R__ASSERT(e)
Definition: TError.h:98
#define gROOT
Definition: TROOT.h:364
Basic string class.
Definition: TString.h:137
tomato 1-D histogram with a float per channel (see TH1 documentation)}
Definition: TH1.h:575
Int_t GetNrows() const
Definition: TVectorT.h:81
TMatrixTColumn_const< Double_t > TMatrixDColumn_const
virtual void SumOfSquareResiduals(const Double_t *x, Double_t *s)
Calculates the sum of the square residuals, that is.
int Int_t
Definition: RtypesCore.h:41
virtual void SetYTitle(const char *title)
Definition: TH1.h:414
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kFALSE
Definition: Rtypes.h:92
void MakeNormalised()
Normalize the covariance matrix.
Definition: TPrincipal.cxx:787
void Test(Option_t *option="")
Test the PCA, bye calculating the sum square of residuals (see method SumOfSquareResiduals), and display the histogram.
void Print(Option_t *option="") const
Print the vector as a list of elements.
Definition: TVectorT.cxx:1361
TLatex * t1
Definition: textangle.C:20
Short_t Abs(Short_t d)
Definition: TMathBase.h:110
Int_t fNumberOfVariables
Definition: TPrincipal.h:32
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:497
TMatrixDSymEigen.
Double_t x[n]
Definition: legend1.C:17
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:33
virtual void MakeMethods(const char *classname="PCA", Option_t *option="")
Generate the file <classname>PCA.cxx which contains the implementation of two methods: void <classnam...
Definition: TPrincipal.cxx:849
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition: TString.cxx:2221
Double_t fTrace
Definition: TPrincipal.h:45
virtual void MakeHistograms(const char *name="pca", Option_t *option="epsdx")
Make histograms of the result of the analysis.
Definition: TPrincipal.cxx:569
virtual void X2P(const Double_t *x, Double_t *p)
Calculate the principal components from the original data vector x, and return it in p...
A doubly linked list.
Definition: TList.h:47
Using a TBrowser one can browse all ROOT objects.
Definition: TBrowser.h:41
TNamed & operator=(const TNamed &rhs)
TNamed assignment operator.
Definition: TNamed.cxx:42
TVectorD fUserData
Definition: TPrincipal.h:43
virtual void AddRow(const Double_t *x)
Add a data point and update the covariance matrix.
Definition: TPrincipal.cxx:410
virtual void Draw(Option_t *option="")
Draw this histogram with options.
Definition: TH1.cxx:2851
SVector< double, 2 > v
Definition: Dict.h:5
tomato 2-D histogram with a float per channel (see TH1 documentation)}
Definition: TH2.h:255
TVectorT< Element > & Zero()
Set vector elements to zero.
Definition: TVectorT.cxx:451
Bool_t IsValid() const
Definition: TVectorT.h:89
TVectorD fEigenValues
Definition: TPrincipal.h:39
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:925
char * Form(const char *fmt,...)
virtual void MakePrincipals()
Perform the principal components analysis.
Definition: TPrincipal.cxx:862
Int_t fNumberOfDataPoints
Definition: TPrincipal.h:31
const TMatrixD & GetEigenVectors() const
virtual void Clear(Option_t *option="")
Clear the data in Object.
Definition: TPrincipal.cxx:480
Bool_t fStoreData
Definition: TPrincipal.h:50
Int_t GetNrows() const
Definition: TMatrixTBase.h:134
const TVectorD & GetEigenValues() const
const Double_t * GetRow(Int_t row)
Return a row of the user supplied data.
Definition: TPrincipal.cxx:507
#define ClassImp(name)
Definition: Rtypes.h:279
double Double_t
Definition: RtypesCore.h:55
TPrincipal & operator=(const TPrincipal &)
Assignment operator.
Definition: TPrincipal.cxx:333
The TH1 histogram class.
Definition: TH1.h:80
const char * AsString() const
Return the date & time as a string (ctime() format).
Definition: TDatime.cxx:101
virtual void SetXTitle(const char *title)
Definition: TH1.h:413
TVectorD fOffDiagonal
Definition: TPrincipal.h:41
virtual void Add(TObject *obj)
Definition: TList.h:81
you should not use this method at all Int_t Int_t Double_t Double_t Double_t Int_t Double_t Double_t Double_t Double_t b
Definition: TRolke.cxx:630
virtual void MakeCode(const char *filename="pca", Option_t *option="")
Generates the file <filename>, with .C appended if it does argument doesn&#39;t end in ...
Definition: TPrincipal.cxx:544
Double_t Sqrt(Double_t x)
Definition: TMath.h:464
const Bool_t kTRUE
Definition: Rtypes.h:91
THist< 2, float, THistStatContent, THistStatUncertainty > TH2F
Definition: THist.hxx:308
#define sym(otri1, otri2)
Definition: triangle.c:932
char name[80]
Definition: TGX11.cxx:109
TMatrixD fCovarianceMatrix
Definition: TPrincipal.h:36
TVectorD fSigmas
Definition: TPrincipal.h:35
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:911
Bool_t IsValid() const
Definition: TMatrixTBase.h:157
TPrincipal()
Empty constructor. Do not use.
Definition: TPrincipal.cxx:229
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition: TDatime.h:39
const char * Data() const
Definition: TString.h:349