Reputation: 470
I have a list of data frames based on running the following:
library(tidyverse)
candidates <- c("A1", "A2", "A3", "B1", "B2")
votes <- function(aa, ab, ba, bb, can) {
aprob <- c(aa, aa, aa, ab, ab)
bprob <- c(ba, ba, ba, bb, bb)
avotes <- t(replicate(25, (sample(can, replace = FALSE, prob = aprob))))
bvotes <- t(replicate(20, (sample(can, replace = FALSE, prob = bprob))))
avotes <- as_tibble(avotes)
bvotes <- as_tibble(bvotes)
all_votes <- bind_rows(avotes, bvotes)
}
z <- map(1:5, ~ votes(aa = .6, ab = .4, ba = .4, bb = .6, candidates))
I am then trying to apply a function to each data frame in the list using lmap:
count <- function(x) {
all_votes <- x %>%
mutate(rn = row_number()) %>%
pivot_longer(cols = contains("V")) %>%
mutate(name = str_remove_all(name, "V")) %>%
pivot_wider(names_from = value, values_from = name) %>%
select(-rn) %>%
mutate_all(as.integer)
}
a <- lmap(z, ~ count)
And I get this error:
Error in lmap_at(.x, seq_along(.x), .f, ...) : is.list(res) is not TRUE
If I pluck one of the data frames from the list and run the count function it works fine, so I know I'm doing something wrong with lmap. Since lmap is meant to apply a function to a list and return a list I assumed that was what I wanted to use here. I have no idea what the error is trying to tell me. I’d appreciate some help on what I’m doing wrong and how to fix it. Entirely possible there is an stupid mistake staring at me and I'm just not seeing it.
I know I could solve this by putting the code from the second function into the first function but I need to separate it out. And I still want to know what I’m doing wrong so I don’t repeat it in the future.
Upvotes: 1
Views: 281
Reputation: 887541
In the code, OP's used lambda expression, and not applying the function on the list element. Based on the function created, it is more suitable for map
a1 <- map(z, count)
or with lambda expression
a1 <- map(z, ~ count(.x))
Regarding the lmap
, as specified in the documentation
map(), lmap_at() and lmap_if() are similar to map(), map_at() and map_if(), with the difference that they operate exclusively on functions that take and return a list (or data frame). Thus, instead of mapping the elements of a list (as in .x[[i]]), they apply a function .f to each subset of size 1 of that list (as in .x[i]). We call those elements list-elements).
Thus, subset is still a list
. So, we may need to extract the list element with [[
as the function 'count' is looking for a data.frame
as input and not a list
a2 <- lmap(z, ~ count(.x[[1]]))
Note that there is a difference in the structure of output from map
and lmap
as lmap
returns list
as output, it is a list
of 25 vectors, while map
is a list
of 5 tibble i.e. if we check the output of the first list element of 'a1' and the first five elements of 'a2', it is the same, similarly second element of 'a1' and next five (6:10) of 'a2',...
all.equal(unclass(a1[[1]]), a2[1:5], check.attributes = FALSE)
#[1] TRUE
Upvotes: 3