[R] sapply behavior

Gabor Grothendieck ggrothendieck at myway.com
Tue Sep 28 03:14:58 CEST 2004


Elizabeth Purdom <epurdom <at> stanford.edu> writes:

: 
: Hi,
: 
: I use sapply very frequently, but I have recently noticed a behavior of 
: sapply which I don't understand and have never seen before. Basically, 
: sapply returns what looks like a matrix,  says it a matrix, and appears to 
: let me do matrix things (like transpose). But it is also a list and behaves 
: like a list when I subset it, not a vector (so I can't sort a row for 
: instance). I don't know where this is coming from so as to avoid it, nor 
: how to handle the beast that sapply is returning. I double checked my old 
: version of R and apparently this same thing happens in 1.8.0, though I 
: never experienced it. I had a hard time reproducing it, and I don't know 
: what's setting it off, but the code below seems to do it for me. (I'm using 
: R on Windows XP, either 1.8.0 or 1.9.1)
: 
: Thanks for any help,
: Elizabeth Purdom
: 
: 
:  > temp2<-matrix(sample(1:6,6,replace=F),byrow=F,nrow=6,ncol=4)
:  > colnames(temp2)<-paste("A",as.character(1:4),sep="")
:  > temp2<-as.data.frame(temp2)
:  > 
: newtemp2<-sapply((1:6),function(x){xmat<-temp2[temp2[,1]==x,,drop=F];return
(xmat[1,])})
:  > print(newtemp2) #looks like matrix
:     [,1] [,2] [,3] [,4] [,5] [,6]
: A1 1    2    3    4    5    6
: A2 1    2    3    4    5    6
: A3 1    2    3    4    5    6
: A4 1    2    3    4    5    6
:  > is.matrix(newtemp2) #says it's matrix
: [1] TRUE
:  > class(newtemp2)
: [1] "matrix"
:  > is.list(newtemp2) #but also list
: [1] TRUE
:  > newtemp2[,1] #can't subset and get a vector back; same thing happens for 
: rows.
: $A1
: [1] 1
: 
: $A2
: [1] 1
: 
: $A3
: [1] 1
: 
: $A4
: [1] 1
: #other things about it:
:  > names(newtemp2)
: NULL
:  > dimnames(newtemp2)
: [[1]]
: [1] "A1" "A2" "A3" "A4"
: 
: [[2]]
: NULL
:  > dim(newtemp2)
: [1] 4 6
:  > length(newtemp2)
: [1] 24


The problem is that your function is returning a one row data frame
and when sapply tries to simplify the resulting list of 6 data frames 
that gives a list with dimensions rather what you were expecting
which is a vector with dimensions.

Let us call the original anonymous function in your post (i.e. the one
passed to sapply there), f.  We can modify it to produce f2 which is like
f except that we wrap the return expression in c() to turn it into a
vector:

  f2 <- function(x){xmat<-temp2[temp2[,1]==x,,drop=F];return(c(xmat[1,]))}
  sapply(1:6, f2)

If you really do want to return a one row data frame then
use rbind to bind the data frames together rather than sapply:

   do.call("rbind", lapply(1:6, f))




More information about the R-help mailing list