如何将 purrr 与 dplyr 一起使用来过滤列表元素并将列表导出到 Excel

How to use purrr with dplyr to filter list elements and export lists into Excel

我对在 R 中使用列表还很陌生,有一个快速问题也涉及使用 purrr。下面以太小的样本数据框为例。

Client1 <- c("John","Chris","Yutaro","Dean","Andy")
Animals <- c("Cat","Cat","Dog","Rat","Bird")
Living <- c("House","Condo","Condo","Apartment","House")
Data1 <- data.frame(Client1,Animals,Living)

Client1 <- c("John","Chris","Yutaro","Dean","Andy")  
Animals2 <- c("Cat","Dog","Dog","Rat","Cat")
Living2 <- c("House","Apartment","Apartment","Family","Apartment")
Data2 <- data.frame(Client1,Animals2,Living2)

如果您可以包括如何立即重命名列表元素而不是使用下面的两行,则奖励:

names(Data1)[1:3] <- c("Client","Animals","Living")
names(Data2)[1:3] <- c("Client","Animals","Living")

接下来,如果我想按 Animals 过滤每个数据框,然后使用以下两行代码将每个数据框导出到 Excel 电子表格中:

Data1 %>% filter(Animals=="Cat") %>% write.csv(.,file="Data1.csv")
Data2 %>% filter(Animals=="Cat") %>% write.csv(.,file="Data2.csv")

但是,为了提高效率,我可以将两个数据帧连接到一个 list 中,并使用 purrr 同时过滤每个数据帧。

DataList <- list(Data1,Data2)
DataList %>% map(~filter(.,Animals=="Cat"))

对于上面的代码,我将为每只动物使用多行 ~filter 行,所以不确定是否有更有效的方法可以避免在仍然使用 purrr 的同时编写许多不同的代码行dplyr

此外,如何将 write.csvpurrr 一起使用。我可以将列表导出到一个电子表格中,但我不确定如何分解列表以使其正确导出。此外,我可以将每个列表元素导出到单独的电子表格中。很高兴看到针对这两种情况的解决方案。

如果我正确理解你的问题,你想为两个数据框的每个 Animals 编写一个单独的文件:

DataList <- list(Data1, Data2)

library(purrr)


a <- DataList %>% map(., function(x) { 
        colnames(x) <- c("Client","Animals","Living")
        x
}) %>% map(., function(x) { 
        split(x, x$Animals)
}) %>% flatten(.)

names(a) <- paste0("Data", (1:length(a)))


lapply(1:length(a), function(x) write.csv(a[[x]], 
                                            file = paste0(names(a[x]), ".csv"),
                                            row.names = FALSE))

我们首先转储 DataList 中的两个数据框,然后用第一个 map 重命名两个数据框的列,然后 split 两个数据框用 Animals,最后是 flatten 嵌套列表。

我希望我能在不破坏链条的情况下做到这一点,但我找不到其他方法。

从这里开始,我们首先重命名列表的元素,然后使用lapply 遍历列表中的所有元素并对每个元素应用write.csv

您提到了 Excel - 您可以轻松地将 write.csv 替换为用于从 R

写入 excel 文件的任何函数

这是一个选项,涉及在重新拆分之前将两个数据集绑定在一起。

library(purrr)
library(dplyr)

DataList %>%
    map(~setNames(.x, c("Client","Animals","Living"))) %>%
    setNames(c("Data1", "Data2")) %>%
    bind_rows(.id = "id") %>%
    split(list(.$id, .$Animals), drop = TRUE) %>%
    map(~select(.x, -id) %>% 
               write.csv(file = paste0(unique(.x$id), unique(.x$Animals), ".csv"),
                                row.names = FALSE))

第一行 map 显示如何通过 setNames.

一次重命名列表中所有数据集的列
DataList %>%
    map(~setNames(.x, c("Client","Animals","Living")))

然后我通过 setNames 在列表中设置数据集的名称。通过 dplyr 的 bind_rows 将数据集堆叠在一起形成一个 data.frame 时,这些名称将添加为新列 id

setNames(c("Data1", "Data2")) %>%
bind_rows(.id = "id")

最后一步是将组合的 data.frame 拆分为 idAnimal,然后再将每个拆分写入单独的 csv 文件。从数据集中提取信息以按数据集和动物命名各个文件(这是命名 DataList 的元素的原因)。在写入文件之前,我通过 select 删除了 id 变量,因为它可能与您的需求无关。

split(list(.$id, .$Animals), drop = TRUE) %>%
map(~select(.x, -id) %>% 
            write.csv(file = paste0(unique(.x$id), unique(.x$Animals), ".csv"),
                                row.names = FALSE))

无需将它们放入一个文件中即可完成所有这些操作 data.frame,但我在最后命名文件时遇到了麻烦。