Mark Orr
2013-Mar-27 21:39 UTC
[R] Passing arguments between apply and l(s)apply functions vs. nested for loop
Hi R community,
I have a question concerning passing arguments between apply and lapply? Or
maybe, once my problem is explained, the question is really about how to best
transform my nested for loops into list/matrix operations; I am just beginning
this transformation away from nested for loops, so I beg of you to have some
lenience regarding my ignorance.
Part I:
I used a set of nested for loops for a computation, which works as fine as it is
slow--very slow. My needs are on the order of about 20000 iterations; in nested
loop format this is millions of calculations. To give you a sense of what
I'm trying to do, it may help to first see the nested for loop (this code is
run-able via copy-and-paste):
#START CODE SNIPPET
#LIST AND VECTOR
rm(list=ls())
l <- list(1:3,2:3,4:10,7:9)
v <- 1:3
#USED IN j loop to catch values
catch.mat <- matrix(NA,nrow=length(v),ncol=length(l))
#LOOPS
for (i in 1:length(v)){
for (j in 1:length(l)) {
catch.mat[i,j] <- sum(l[[j]]==i)
}
}
#SIMPLY APPLY OVER catch.mat
catch.all <- apply(catch.mat,1,sum)
catch.mat
catch.all
#END CODE SNIPPET
This does exactly what I want, < catch.all> provides the number of
elements in < l > for which each element of < v > is a member, given
the constraint that within each element in < l > the sub-elements are
unique.
Part II:
However, for my data set it takes about 3 days to run. So, I stumbled onto list
and matrix operations (apply family of functions) and have been working to
coerce my code above into an apply-like format. Here is my best example (of
several failings of different sorts), after trying for several hours and reading
much on the web and in some books:
#THIS CODE SNIPPET IS PASTE-ABLE AFTER RUNNING FIRST SNIPPET ABOVE
#SIMPLE TEST TO SHOW THAT apply is passing elements from mat.1 to f.1
f.1 <- function(x){
i <- x
print(x)
print(i)
}
mat.1 <- matrix(1:2318,nrow=1,ncol=2318)
apply(mat.1,1,f.1)
#THAT GAVE EXPECTED RESULTS
#THEN I ADD A NEW FUNCTION
f.2 <- function(x,l=l){
i <- x
rm(x)
return(sum(lapply(l,function(x) sum(x==i))))
}
mat.1 <- matrix(1:2318,nrow=1,ncol=2318)
apply(mat.1,1,f.2)
#BUT GET ERROR
#> apply(mat.1,1,f.2)
#Error in lapply(l, function(x) sum(x == i)) :
# promise already under evaluation: recursive default argument reference or
earlier problems?
#BUT I KNOW THAT the lapply in f.2 works
sapply(l,function(x) sum(x==2))
sum(sapply(l,function(x) sum(x==2)))
#END CODE SNIPPET
I Am totally stuck, as I really don't understand the internals of R or S
well enough to get a sense of what is the root of this problem in my code.
I would appreciate some guidance by example, not by reference. I don't
think further reading of existing texts, unless extremely basic, is going to
help me.
Thanks,
Mark Orr
----------------------------------------------------
Mark G. Orr, Ph.D.
Epidemiology Merit Fellow
Assoc. Research Scientist
Columbia Univ.-Mailman Sch. Public Health
Department of Epidemiology
722 W. 168th St., RM 528
New York, NY
T: 212-305-3815
F: 212-342-5168
mo2259@columbia.edu
http://chbdlab.org/
[[alternative HTML version deleted]]
Charles Berry
2013-Mar-28 03:55 UTC
[R] Passing arguments between apply and l(s)apply functions vs. nested for loop
Mark Orr <mo2259 <at> columbia.edu> writes:> > Hi R community, > I have a question concerning passing arguments between apply and lapply?[snip]> > #START CODE SNIPPET > > #LIST AND VECTOR > rm(list=ls()) > l <- list(1:3,2:3,4:10,7:9) > v <- 1:3 > > #USED IN j loop to catch values > catch.mat <- matrix(NA,nrow=length(v),ncol=length(l)) > > #LOOPS > for (i in 1:length(v)){ > for (j in 1:length(l)) { > catch.mat[i,j] <- sum(l[[j]]==i) > } > } > > #SIMPLY APPLY OVER catch.mat > catch.all <- apply(catch.mat,1,sum) > > catch.mat > catch.all >Given the constraint you state about uniqueness,> table(factor(unlist(l),v))1 2 3 1 2 2 gives the same answer as catch.all --- up to names which you can remove with unname(table(factor(unlist(l),v))) [deleted]> > #THEN I ADD A NEW FUNCTION > f.2 <- function(x,l=l){ > i <- x > rm(x) > return(sum(lapply(l,function(x) sum(x==i)))) > } > > mat.1 <- matrix(1:2318,nrow=1,ncol=2318) > apply(mat.1,1,f.2) > > #BUT GET ERROR > #> apply(mat.1,1,f.2) > #Error in lapply(l, function(x) sum(x == i)) : > # promise already under evaluation: recursive default argument reference orearlier problems? Always helps to ponder the error message --- 'recursive default argument'. Here is an example: foo <- function(x=x) x> foo() ## here it comes again!Error in foo() : promise already under evaluation: recursive default argument reference or earlier problems?> foo(1) # this works[1] 1>The default is what you use when the argument is not given in the call. And x=x confuses the evaluator. You can avoid confusion by choosing a different name like this:> foo <- function(xx=x) xx > x <- 3 > foo()[1] 3>[rest deleted] HTH,