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