Hi, I noticed that by() returns an object of class 'by', regardless of what its argument 'simplify' is. ?by says that it always returns a list if simplify=FALSE, yet by.data.frame shows: ---<--------------------cut here---------------start------------------->--- function (data, INDICES, FUN, ..., simplify = TRUE) { if (!is.list(INDICES)) { IND <- vector("list", 1L) IND[[1L]] <- INDICES names(IND) <- deparse(substitute(INDICES))[1L] } else IND <- INDICES FUNx <- function(x) FUN(data[x, , drop = FALSE], ...) nd <- nrow(data) ans <- eval(substitute(tapply(1L:nd, IND, FUNx, simplify = simplify)), data) attr(ans, "call") <- match.call() class(ans) <- "by" ans } <environment: namespace:base> ---<--------------------cut here---------------end--------------------->--- One could force a list by wrapping it around an lapply(by.object, "["), but this is not possible if the object contains S4 objects. How does one force a list in those cases? Cheers, -- Seb
It returns a list with athe class attribut set to "by", just use: x <- by(.....) unclass(x) Uwe Ligges On 14.09.2010 00:11, Seb wrote:> Hi, > > I noticed that by() returns an object of class 'by', regardless of what > its argument 'simplify' is. ?by says that it always returns a list if > simplify=FALSE, yet by.data.frame shows: > > ---<--------------------cut here---------------start------------------->--- > function (data, INDICES, FUN, ..., simplify = TRUE) > { > if (!is.list(INDICES)) { > IND<- vector("list", 1L) > IND[[1L]]<- INDICES > names(IND)<- deparse(substitute(INDICES))[1L] > } > else IND<- INDICES > FUNx<- function(x) FUN(data[x, , drop = FALSE], ...) > nd<- nrow(data) > ans<- eval(substitute(tapply(1L:nd, IND, FUNx, simplify = simplify)), > data) > attr(ans, "call")<- match.call() > class(ans)<- "by" > ans > } > <environment: namespace:base> > ---<--------------------cut here---------------end--------------------->--- > > One could force a list by wrapping it around an lapply(by.object, "["), > but this is not possible if the object contains S4 objects. How does > one force a list in those cases? > > > Cheers, >
On Sep 15, 2010, at 10:55 , Uwe Ligges wrote:> > > On 14.09.2010 20:50, Seb wrote: >> On Tue, 14 Sep 2010 12:02:04 +0200, >> Uwe Ligges<ligges at statistik.tu-dortmund.de> wrote: >> >>> It returns a list with athe class attribut set to "by", just use: x<- >>> by(.....) unclass(x) >> >> Thanks Uwe, however, that still returns an array when using the >> data.frame method for by(): >> >> R> class(unclass(with(warpbreaks, by(warpbreaks[, 1:2], tension, summary)))) >> [1] "array" >> >> It seems as if the only way to really ensure a list: >> >> R> class(lapply(unclass(with(warpbreaks, by(warpbreaks[, 1:2], tension, summary))), function(x) x)) >> [1] "list" >> >> but it seems like a waste to call another function just to do this. >> >> > > Then you could still do > > x <- by(.....) > attributes(x) <- NULL >Or just use c() instead of unclass(). (The root cause is that even with simplify=FALSE, tapply() will always create an array, in this case a 1d array with dim=3. The _contents_ of the array will be a list, though.) Notice that in the relevant cases, what you get really _is_ a list, and both walks and quacks like one. E.g.> L <- with(warpbreaks, by(warpbreaks[, 1], tension, mean, simplify=FALSE)) > is.list(L)[1] TRUE> L$M[1] 26.38889 -- Peter Dalgaard Center for Statistics, Copenhagen Business School Solbjerg Plads 3, 2000 Frederiksberg, Denmark Phone: (+45)38153501 Email: pd.mes at cbs.dk Priv: PDalgd at gmail.com