在 R 中使用 lmap 将函数应用于列表时出错

Error when applying function to list using lmap in R

我有一个基于 运行 的数据帧列表:

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))

然后我尝试使用 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)

我收到这个错误:

Error in lmap_at(.x, seq_along(.x), .f, ...) : is.list(res) is not TRUE

如果我从列表中提取一个数据帧和 运行 计数函数,它工作正常,所以我知道我在使用 lmap 时做错了什么。由于 lmap 旨在将函数应用于列表和 return 列表,我假设这就是我想在这里使用的。我不知道错误试图告诉我什么。对于我做错了什么以及如何解决它,我将不胜感激。完全有可能有一个愚蠢的错误在盯着我,而我只是没有看到它。

我知道我可以通过将第二个函数的代码放入第一个函数来解决这个问题,但我需要将它分开。而且我还想知道我做错了什么,以后不再重蹈覆辙

在代码中,OP 使用了 lambda 表达式,并没有在列表元素上应用该函数。根据创建的函数,更适合map

a1 <- map(z, count)

或使用 lambda 表达式

a1 <- map(z, ~ count(.x))

关于 lmap,如文档中所述

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).

因此,子集仍然是list。因此,我们可能需要使用 [[ 提取列表元素,因为函数 'count' 正在寻找 data.frame 作为输入而不是 list

a2 <- lmap(z, ~ count(.x[[1]]))

注意 maplmap 的输出结构不同,lmap returns list 作为输出,它是一个list 的 25 个向量,而 map 是 5 tibble 的 list 即如果我们检查 'a1' 的第一个列表元素和 [= 的前五个元素的输出41=],它是相同的,类似 'a1' 的第二个元素和 'a2' 的下五个 (6:10),...

all.equal(unclass(a1[[1]]), a2[1:5], check.attributes = FALSE)
#[1] TRUE