source: trunk/yat/utility/PCA.cc @ 715

Last change on this file since 715 was 715, checked in by Jari Häkkinen, 16 years ago

Addresses #170.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 5.9 KB
Line 
1// $Id: PCA.cc 715 2006-12-22 08:42:39Z jari $
2
3/*
4  Copyright (C) The authors contributing to this file.
5
6  This file is part of the yat library, http://lev.thep.lu.se/trac/yat
7
8  The yat library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version.
12
13  The yat library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  02111-1307, USA.
22*/
23
24#include "PCA.h"
25#include "SVD.h"
26
27#include <iostream>
28#include <cmath>
29#include <memory>
30
31namespace theplu {
32namespace yat {
33namespace utility {
34
35
36  PCA::PCA(const utility::matrix& A)
37    : A_(A), process_(false), explained_calc_(false)
38  {
39  }
40
41
42  utility::vector PCA::get_eigenvector(size_t i) const
43  {
44    return utility::vector(eigenvectors_,i);
45  }
46
47
48  double PCA::get_eigenvalue(size_t i) const
49  {
50    return eigenvalues_[i];
51  }
52
53
54  void PCA::process(void)
55  {
56    process_ = true;
57    // Row-center the data matrix
58    utility::matrix A_center( A_.rows(), A_.columns() );
59    this->row_center( A_center );
60
61    // Single value decompose the data matrix
62    std::auto_ptr<SVD> pSVD( new SVD( A_center ) );
63    pSVD->decompose();
64    utility::matrix U = pSVD->U(); 
65    utility::matrix V = pSVD->V();
66
67    // Read the eigenvectors and eigenvalues
68    eigenvectors_ = U;
69    eigenvectors_ .transpose();
70    eigenvalues_ = pSVD->s();
71
72    // T
73    for( size_t i = 0; i < eigenvalues_.size(); ++i )
74      eigenvalues_[ i ] = eigenvalues_[ i ]*eigenvalues_[ i ];
75    eigenvalues_ *= 1.0/A_center.rows();
76
77    // Sort the eigenvectors in order of eigenvalues
78    // Simple (not efficient) algorithm that always
79    // make sure that the i:th element is in its correct
80    // position (N element --> Ordo( N*N ))
81    for ( size_t i = 0; i < eigenvalues_.size(); ++i )
82      for ( size_t j = i + 1; j < eigenvalues_.size(); ++j )
83        if ( eigenvalues_[ j ] > eigenvalues_[ i ] ) {
84          std::swap( eigenvalues_[ i ], eigenvalues_[ j ] ); 
85          eigenvectors_.swap_rows(i,j);
86        }
87  }
88
89
90  void PCA::process_transposed_problem(void)
91  {
92    process_ = true;
93    // Row-center the data matrix
94    utility::matrix A_center( A_.rows(), A_.columns() );
95    this->row_center( A_center );
96
97    // Transform into SVD friendly dimension
98    A_.transpose();
99    A_center.transpose();
100
101    // Single value decompose the data matrix
102    std::auto_ptr<SVD> pSVD( new SVD( A_center ) );
103    pSVD->decompose();
104    utility::matrix U = pSVD->U(); 
105    utility::matrix V = pSVD->V();
106
107    // Read the eigenvectors and eigenvalues
108    eigenvectors_=V;
109    eigenvectors_.transpose();
110    eigenvalues_ = pSVD->s();
111
112    // Transform back when done with SVD!
113    // (used V insted of U now for eigenvectors)
114    A_.transpose();
115    A_center.transpose();
116
117    // T
118    for( size_t i = 0; i < eigenvalues_.size(); ++i )
119      eigenvalues_[ i ] = eigenvalues_[ i ]*eigenvalues_[ i ];
120    eigenvalues_ *= 1.0/A_center.rows();
121
122    // Sort the eigenvectors in order of eigenvalues
123    // Simple (not efficient) algorithm that always
124    // make sure that the i:th element is in its correct
125    // position (N element --> Ordo( N*N ))
126    for ( size_t i = 0; i < eigenvalues_.size(); ++i )
127      for ( size_t j = i + 1; j < eigenvalues_.size(); ++j )
128        if ( eigenvalues_[ j ] > eigenvalues_[ i ] ) {
129          std::swap( eigenvalues_[ i ], eigenvalues_[ j ] ); 
130          eigenvectors_.swap_rows(i,j);
131        }
132  }
133
134
135  // This function will row-center the matrix A_,
136  // that is, A_ = A_ - M, where M is a matrix
137  // with the meanvalues of each row
138  void PCA::row_center(utility::matrix& A_center)
139  {
140    meanvalues_ = utility::vector( A_.rows() );
141    utility::vector A_row_sum(A_.rows());
142    for (size_t i=0; i<A_row_sum.size(); ++i)
143      A_row_sum(i)=utility::vector(A_,i).sum();
144    for( size_t i = 0; i < A_center.rows(); ++i ) {
145      meanvalues_[i] = A_row_sum(i) / static_cast<double>(A_.columns());
146      for( size_t j = 0; j < A_center.columns(); ++j )
147        A_center(i,j) = A_(i,j) - meanvalues_(i);
148    }
149  }
150
151
152  utility::matrix PCA::projection(const utility::matrix& samples ) const
153  {
154    const size_t Ncol = samples.columns();
155    const size_t Nrow = samples.rows();
156    utility::matrix projs( Ncol, Ncol );
157
158    utility::vector temp(samples.rows());
159    for( size_t j = 0; j < Ncol; ++j ) {
160      for (size_t i=0; i<Ncol; ++i )
161        temp(i) = samples(i,j); 
162      utility::vector centered( Nrow );
163      for( size_t i = 0; i < Nrow; ++i ) 
164        centered(i) = temp(i) - meanvalues_(i);
165      utility::vector proj( eigenvectors_ * centered );
166      for( size_t i = 0; i < Ncol; ++i ) 
167        projs(i,j)=proj(i);
168    }
169    return projs;
170  }
171
172
173  utility::matrix
174  PCA::projection_transposed(const utility::matrix& samples) const
175  {
176    const size_t Ncol = samples.columns();
177    const size_t Nrow = samples.rows();
178    utility::matrix projs( Nrow, Ncol );
179
180    utility::vector temp(samples.rows());
181    for( size_t j = 0; j < Ncol; ++j ) {
182      for (size_t i=0; i<Ncol; ++i )
183        temp(i) = samples(i,j); 
184      utility::vector centered( Nrow );
185      for( size_t i = 0; i < Nrow; ++i ) 
186        centered(i)=temp(i)-meanvalues_(i);
187      utility::vector proj( eigenvectors_ * centered );
188      for( size_t i = 0; i < Nrow; ++i ) 
189        projs(i,j)=proj(i);
190    }
191    return projs;
192  }
193
194
195  void PCA::calculate_explained_intensity(void)
196  {
197    size_t DIM = eigenvalues_.size();
198    explained_intensity_ = utility::vector( DIM );
199    double sum = 0;
200    for( size_t i = 0; i < DIM; ++i ) 
201      sum += eigenvalues_[ i ];
202    double exp_sum = 0;
203    for( size_t i = 0; i < DIM; ++i ) {
204      exp_sum += eigenvalues_[ i ];
205      explained_intensity_[ i ] = exp_sum / sum ;
206    }
207  }
208
209
210  double PCA::get_explained_intensity( const size_t& k )
211  {
212    if( !explained_calc_ ) {
213      this->calculate_explained_intensity();
214      explained_calc_ = true;
215    }
216    return explained_intensity_[ k ];
217  }
218
219
220}}} // of namespace utility, yat, and theplu
Note: See TracBrowser for help on using the repository browser.