forum.alglib.net http://forum.alglib.net/ |
|
PCA when M >> N http://forum.alglib.net/viewtopic.php?f=2&t=893 |
Page 1 of 1 |
Author: | santhu [ Wed Jul 24, 2013 4:52 pm ] |
Post subject: | PCA when M >> N |
Hello all, I have a matrix A of size M X N where M is greater than N. [Typical sizes are M = 15,000 while N =20]. We want to apply PCA on this matrix where variables are more than observations.[ I am aware that the results are not completely reliable but in our experiments with R, they made some sense]. In R when such a scenario is presented, the eigen values would mostly be a vector of N and eigen values are N X N. But in alglib, though the code uses QR-decomposition and bidagional reduction to find the N eigen values, the memory allocation happens for M X M matrix. We are running out of memory because of this. [As far as I have debugged]. Is there any way we can solve this problem without creating these huge matrices which would not be useful at all. Thanks Santhosh |
Author: | snowflake [ Sat Jul 27, 2013 10:18 pm ] |
Post subject: | Re: PCA when M >> N |
this is hard due to the fact that the needed underlying covariance matrix has MxM size when M is larger than N i hope that there is a solution, as i'm dealing with this problem right now too i use it for an Active Shape Model, where one dataset in 3D is concatenated in 1 vector in the format xxxyyyzzz, so a relatively normal object with 3000 points gets a 9000 dimensional vector and it crashes with alglib 3.7.0. Sergey mentioned a workaround for windows here http://bugs.alglib.net/view.php?id=439 |
Author: | santhu [ Sat Jul 27, 2013 10:29 pm ] |
Post subject: | Re: PCA when M >> N |
Actually I was able to do this myself. The solution is pretty simple. Instead of depending upon the existing module pcabuildbasis, do the PCA yourself using svd. Decompose the matrix A[MXN) using SVD. http://www.alglib.net/translator/man/manual.cpp.html#unit_svd The number of significant[non-zero] principal components would always be min(M,N) which would be a part of w. You need to divide them by 1/sqrt(min(M,N)-1). For the eigen vectors, they would be either in U or V. I have written the code but do not have it right now. I could post that on monday. :-) |
Author: | snowflake [ Sun Jul 28, 2013 2:03 am ] |
Post subject: | Re: PCA when M >> N |
yeah, that would be nice :) @ Sergey There seems to be a bug in linalg.cpp. Some or all methods allocate a "ae_matrix _a" object and copy the ingoing source matrix "a" into it, but never use it. As for my tests, i got 650 MB continous memory and with a copy of this the program crashes under 32 bit. Works fine with smaller data so this is only memory limitation. malloc returns null pointer for a second object of that size. |
Author: | santhu [ Mon Jul 29, 2013 3:12 pm ] |
Post subject: | Re: PCA when M >> N |
Hey snowflake, Here is the code that does PCA for huge matrices .. The results match R well ... // The method inputs a matrix whose coloumns represent variables and rows represent observations. // set transpose to be true if it isnt so. // Do keep in mind that only the number of Principal components and Principal values would be limited by the min(numRows, numColoums). // please be aware that dataMatrix would be changed in this process. It would be centered, scaled. // #eigen values : is the min(nrow, ncol) // the rotation matrix should be of size : #numVariables( ncol or nrow if transposed)) X min(ncol, nrow) // retx = x * rotation. [ according to the transpose] int numPcs; alglib::real_2d_array ptInput; int nrow, ncol; if(transpose){ if(center){ centerRows(x,numRows,stride); } if(scale){ scaleRows(x,numRows, stride); } }else{ if(center){ centerColumns(x,numRows,stride); } if(scale){ scaleColumns(x,numRows, stride); } } ptInput.setcontent(numRows, stride, x); nrow = numRows; ncol = stride; numPcs = nrow <ncol? nrow : ncol; real_1d_array w; real_2d_array u,vt; alglib::rmatrixsvd(ptInput,nrow,ncol,1,1,1,w,u,vt); double denom = sqrt(ncol-1); for(int i=0; i< numPcs; i++){ eigV[i] = w[i]/denom; } int count = 0; if(transpose){ for(int i=0; i< nrow; i++){ for(int j=0; j< numPcs ; j++) { rotation[count] = u[i][j]; count++; } } } else{ for(int i=0; i< ncol; i++){ for(int j=0; j< numPcs ; j++) { rotation[count] = vt[j][i]; count++; } } } if(transpose){ // the rotation matrix is nrow X numPcs. for(int i =0; i< ncol ; i++){ for(int j=0; j< numPcs ; j++){ double sum =0; for(int k =0; k< nrow ; k++){ sum += x[ k*ncol + i] * rotation[k*numPcs + j]; } retx[i*numPcs + j] = sum; } } }else{ // the rotation matrix is of size ncol X numPcs. for(int i=0; i< nrow; i++){ for(int j=0; j<numPcs ; j++){ double sum=0; for(int k=0; k < ncol ; k++){ sum += x[i*ncol + k]*rotation[ k*ncol + j]; } retx[i*numPcs + j] = sum; } } } Utillity functions which center and scale the matrix are : static void centerColumns(double *a, int numRows, int stride){ for(int i=0; i< stride ; i++) { double colMean = 0; for(int j = 0; j< numRows ; j++) { colMean += a[j*stride + i]; } colMean = colMean/numRows; for(int j = 0; j< numRows ; j++) { a[j*stride + i] -= colMean; } } } static void scaleColumns(double *a, int numRows, int stride){ for(int i=0; i< stride ; i++) { double std = 0; for(int j = 0; j< numRows ; j++) { std += a[j*stride + i]*a[j*stride + i]; } std = sqrt(std/(numRows-1)); for(int j = 0; j< numRows ; j++) { a[j*stride + i] /= std; } } } static void centerRows(double *a, int numRows, int stride){ for(int i=0; i< numRows ; i++) { double rowMean = 0; for(int j = 0; j< stride ; j++) { rowMean += a[i*stride + j]; } rowMean = rowMean/stride; for(int j = 0; j< stride ; j++) { a[i*stride + j] -= rowMean; } } } static void scaleRows(double *a, int numRows, int stride){ for(int i=0; i< numRows ; i++) { double std = 0; for(int j = 0; j< stride ; j++) { std += a[i*stride + j]*a[i*stride + j]; } std = sqrt(std/(stride-1)); for(int j = 0; j< stride ; j++) { a[i*stride + j] /= std; } } } |
Author: | snowflake [ Mon Jul 29, 2013 8:36 pm ] |
Post subject: | Re: PCA when M >> N |
Hi santhu, thanks for the code :) here is a thing i wonder about: Why are you centering / scaling over all values ? It should be according too single rows / cols depending on transposition. You are centering / scaling over all elements of data, but it should be 2 separate values for x and y. And the rmatrixsvd routine isn't rectangular, as far as i found out. In the original pcabuildbasis routine the matrix grows to a square max(cols, rows) matrix, depending which one is bigger. Seems the focus was too far for full U and VT matrix, but not for the minimized versions as with uneeded and vtneeded equal 1 as in your code. Is your code working, so that you get right sized matrices back ? I changed both, pcabuildbasis and rmatrixsvd to get what i want. Do you have a max size you could proceed with your svd version ? My changes are crashing somewhere between 9000x3 and 9000x6 matrices on 32 bit. My alglib version is 3.7.0. |
Author: | santhu [ Mon Jul 29, 2013 8:44 pm ] |
Post subject: | Re: PCA when M >> N |
Hi Snowflake, The centering and scaling is per a single row or column depending upon transposition. I checked my code against R and it works perfectly well. My matrixes were 40,000 X 24 and there was no crash at all. :-) Hope it helps, Santhu |
Author: | snowflake [ Sun Aug 04, 2013 12:23 am ] |
Post subject: | Re: PCA when M >> N |
Hi santhu, yeah, i should have ckecked it better, now i see that your scaling / centering is right ;) i'm still working on the rmatrixsvd routine and i'm still not sure if it's right. are you developing under 64 bit or 32 bit ? thanks for your help :) |
Author: | yiuin [ Thu May 15, 2014 5:36 pm ] |
Post subject: | Re: PCA when M >> N |
My PCA looks like this, it doesn't use NVARS*NVARS memory, much less so if you have a massive number of dimensions, it will be much lighter. Note you should prescale/demean. Xr is the reduced output, odim is the number of output dimensions. Its a pretty direct translation of the description on wikipedia =). It would be nice if this was an option in alglib, since it is wayyyy more efficient if you don't care about the basis vectors. (Edit ... and I'm posting in a dead thread) Code: void pca(const alglib::real_2d_array& X, alglib::real_2d_array& Xr, int odim) { alglib::real_2d_array U; alglib::real_2d_array VT; alglib::real_1d_array W; const double VARTHRESH = 1E-12; std::cout << "svd: " << X.rows() << "x" << X.cols() << "..."; alglib::rmatrixsvd(X, X.rows(), X.cols(), 1, 0, 2, W, U, VT); std::cout << " done" << endl; std::cout << "odims = " << odim << "..."; Xr.setlength(X.rows(), odim); for(int rr=0; rr<X.rows(); rr++) { for(int cc=0; cc<odim; cc++) { Xr(rr,cc) = U(rr, cc)*W[cc]; } } std::cout << " Done" << endl; } |
Page 1 of 1 | All times are UTC |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |