I have a matrix for which each row has 12 elements that represent the xyz coordinates of 4 points. So each row of M is (x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4). Some points have NA as z values. I want another matrix to be the same as M but with the coordinates of those points with z=NA placed last. For ezample if z1=NA then the new matrix row should be (x2,y2,z2,x3,y3,z3,x4,y4,z4,x1,y1,z1) I've tried writing a function that does the job for each row and then apply to the matrix Put.NaN.last<-function(p) { Index<-c(which(!is.na(p[c(3,6,9,12)]))*3,which(is.na(p[c(3,6,9,12)]))*3) p<-c(p[Index[1]-2],p[Index[1]-1],p[Index[1]], p[Index[2]-2],p[Index[2]-1],p[Index[2]], p[Index[3]-2],p[Index[3]-1],p[Index[3]], p[Index[4]-2],p[Index[4]-1],p[Index[4]]) return(p) } A<-matrix(1:36,ncol=12) A[c(7,9,17,36)]<-NA A<-t(apply(A,1,Put.NaN.last)) but it is awfully slow. Any suggestions on how to do this faster? Thanks Angel [[alternative HTML version deleted]]
Have you considered "?order"? Spencer Graves Angel wrote:> I have a matrix for which each row has 12 elements that represent the xyz coordinates of 4 points. > So each row of M is (x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4). Some points have NA as z values. > I want another matrix to be the same as M but with the coordinates of those points with z=NA placed last. > For ezample if z1=NA then the new matrix row should be (x2,y2,z2,x3,y3,z3,x4,y4,z4,x1,y1,z1) > I've tried writing a function that does the job for each row and then apply to the matrix > > Put.NaN.last<-function(p) { > Index<-c(which(!is.na(p[c(3,6,9,12)]))*3,which(is.na(p[c(3,6,9,12)]))*3) > p<-c(p[Index[1]-2],p[Index[1]-1],p[Index[1]], > p[Index[2]-2],p[Index[2]-1],p[Index[2]], > p[Index[3]-2],p[Index[3]-1],p[Index[3]], > p[Index[4]-2],p[Index[4]-1],p[Index[4]]) > return(p) > } > A<-matrix(1:36,ncol=12) > A[c(7,9,17,36)]<-NA > A<-t(apply(A,1,Put.NaN.last)) > > but it is awfully slow. > Any suggestions on how to do this faster? > Thanks > Angel > > [[alternative HTML version deleted]] > > ______________________________________________ > R-help at stat.math.ethz.ch mailing list > https://www.stat.math.ethz.ch/mailman/listinfo/r-help
Thanks to Gabor and others I've found the solution to my problem, but there are some issues with order, sort and apply that I post in another thread. Here are two solutions to my problem: # Example matrix: A<-matrix(rnorm(10000*12),nrow=10000,ncol=12) A[rbind(c(100,3),c(90,9),c(40,6))]<-NA # Solution given by GaborGrothendieck system.time({A.a<-t(apply(A,1,function(x){x<-matrix(x,nr=3);x[,order(colSums (is.na(x))>0)]}))}) # A function I wrote with various suggestions (Petr Pikal, Duncan Murdoch, Ted Harding) Put.NaN.last<-function(A) { # First creates a matrix where the points with NA z have also NA # x and y A.o<-A A.o[,1:3]<-A.o[,1:3]*A[,3]/A[,3] A.o[,4:6]<-A.o[,4:6]*A[,6]/A[,6] A.o[,7:9]<-A.o[,7:9]*A[,9]/A[,9] A.o[,10:12]<-A.o[,10:12]*A[,12]/A[,12] # Transposes both matrix as I want to order each row (by column) and R is # by default "column-major order" A<-t(A) A.o<-t(A.o) # Now makes another matrix Ind with same dim as A but # where the integer part of each element indicates the row (original A columns) # and the second decimal indicates the column (original A row, i.e A is now transposed) serie<-rep(1:4,each=3)/10 serie<-rep(serie,ncol(A)) Ind<-rep(1:ncol(A),each=nrow(A)) Ind<-Ind+serie # Adds 0.5 to the elements where A.o is NA so they will be larger # than any in the row Ind[which(is.na(A.o))]<-Ind[which(is.na(A.o))]+0.5 # Finally order A according to the Ind # this avoids having to use apply A.o[,]<-A[order(Ind)] A.o<-t(A.o) A<-t(A) return(A.o) } system.time({A.put<-Put.NaN.last(A)}) # As you see calling with my function is much faster than the apply # I've decided to post another thread to try to understand what is going on here # Thanks to all that helped # Angel