rapply to nested list of data frames in R
Update June 2020:
You can now also use rrapply
in the rrapply
-package, (an extended version of base rapply
). Setting classes = "data.frame"
applies the f
function to data.frame objects as a whole (instead of recursing into the individual columns):
library(rrapply)
L <- list(a = BOD, b = BOD)
## apply f to data.frames
rrapply(L, f = colSums, classes = "data.frame")
#> $a
#> Time demand
#> 22 89
#>
#> $b
#> Time demand
#> 22 89
## apply f to individual columns of data.frames
rrapply(L, f = function(x, .xname) if(.xname == "demand") scale(x) else x)
#> $a
#> Time demand
#> 1 1 -1.4108974
#> 2 2 -0.9789900
#> 3 3 0.8998070
#> 4 4 0.2519460
#> 5 5 0.1655645
#> 6 7 1.0725699
#>
#> $b
#> Time demand
#> 1 1 -1.4108974
#> 2 2 -0.9789900
#> 3 3 0.8998070
#> 4 4 0.2519460
#> 5 5 0.1655645
#> 6 7 1.0725699
1. wrap in proto
When creating your list structure try wrapping the data frames in proto objects:
library(proto)
L <- list(a = proto(DF = BOD), b = proto(DF = BOD))
rapply(L, f = function(.) colSums(.$DF), how = "replace")
giving:
$a
Time demand
22 89
$b
Time demand
22 89
Wrap the result of your function in a proto object too if you want to further rapply
it;
f <- function(.) proto(result = colSums(.$DF))
out <- rapply(L, f = f, how = "replace")
str(out)
giving:
List of 2
$ a:proto object
.. $ result: Named num [1:2] 22 89
.. ..- attr(*, "names")= chr [1:2] "Time" "demand"
$ b:proto object
.. $ result: Named num [1:2] 22 89
.. ..- attr(*, "names")= chr [1:2] "Time" "demand"
2. write your own rapply alternative
recurse <- function (L, f) {
if (inherits(L, "data.frame")) f(L)
else lapply(L, recurse, f)
}
L <- list(a = BOD, b = BOD)
recurse(L, colSums)
This gives:
$a
Time demand
22 89
$b
Time demand
22 89
ADDED: second approach