r语言 - 将 purrr::walk2() 应用于管道末端的数据帧



我有一个 R 数据框,其中包含一列数据框,我想将每个数据框打印到一个文件中:

df0 <- tibble(x = 1:3, y = rnorm(3))
df1 <- tibble(x = 1:3, y = rnorm(3))
df2 <- tibble(x = 1:3, y = rnorm(3))
animalFrames <- tibble(animals = c('sheep', 'cow', 'horse'),
                       frames = list(df0, df1, df2))

我可以用一个 for 循环来做到这一点:

for (i in 1:dim(animalFrames)[1]){
    write.csv(animalFrames[i,2][[1]], file = paste0('test_', animalFrames[i,1], '.csv'))
}

或者使用 purrrwalk2函数:

walk2(animalFrames$animals, animalFrames$frames,  ~write.csv(.y, file
= paste0('test_', .x, '.csv')))

有没有办法把这个步行功能放在magrittr管的末端?

我在想这样的事情:

animalFrames %>% do({walk2(.$animals, .$frames, ~write.csv(.y, file = paste0('test_', .x, '.csv')))})

但这给了我一个错误:

Error: Result must be a data frame, not character
Traceback:
1. animalFrames %>% do({
 .     walk2(.$animals, .$frames, ~write.csv(.y, file = paste0("test_", 
 .         .x, ".csv")))
 . })
2. withVisible(eval(quote(`_fseq`(`_lhs`)), env, env))
3. eval(quote(`_fseq`(`_lhs`)), env, env)
4. eval(quote(`_fseq`(`_lhs`)), env, env)
5. `_fseq`(`_lhs`)
6. freduce(value, `_function_list`)
7. withVisible(function_list[[k]](value))
8. function_list[[k]](value)
9. do(., {
 .     walk2(.$animals, .$frames, ~write.csv(.y, file = paste0("test_", 
 .         .x, ".csv")))
 . })
10. do.data.frame(., {
  .     walk2(.$animals, .$frames, ~write.csv(.y, file = paste0("test_", 
  .         .x, ".csv")))
  . })
11. bad("Result must be a data frame, not {fmt_classes(out)}")
12. glubort(NULL, ..., .envir = parent.frame())
13. .abort(text)

大概是因为write.csv()正在返回数据帧,而do()不处理这些或其他东西。

真的没有编码要求我必须在管道的末端放置 walk(事实上,我总是可以在管道周围工作(,但似乎我缺少一些基本的东西,这困扰着我。有什么建议吗?

我认为你根本不需要do。以下两者都对我有用。我认为第一个与您的减去do相同,第二个利用magrittr方便的%$%运算符将列名暴露给walk2并避免.$。请注意,如果这是在管道的末尾,那么使用walk2还是map2并不重要,因为您不在乎此步骤之后返回的内容。

注意:出于习惯,我也把paste0write.csv换成了tidyverse等价物,但它们很容易放回去。

library(tidyverse)
df0 <- tibble(x = 1:3, y = rnorm(3))
df1 <- tibble(x = 1:3, y = rnorm(3))
df2 <- tibble(x = 1:3, y = rnorm(3))
animalFrames <- tibble(animals = c('sheep', 'cow', 'horse'),
                       frames = list(df0, df1, df2))
animalFrames %>%
  walk2(
    .x = .$animals,
    .y = .$frames,
    .f = ~ write_csv(.y, str_c("test_", .x, ".csv"))
  )
library(magrittr)
#> 
#> Attaching package: 'magrittr'
#> The following object is masked from 'package:purrr':
#> 
#>     set_names
#> The following object is masked from 'package:tidyr':
#> 
#>     extract
animalFrames %$%
  walk2(
    .x = animals,
    .y = frames,
    .f = ~ write_csv(.y, str_c("test_", .x, ".csv"))
  )

创建于 2018-03-13 由 reprex 软件包 (v0.2.0(.

使用 purrr::p walk((

与Calum You给出的精彩答案非常相似,但更短,(在我看来(稍微优雅一些。

pwalk()并行遍历许多列表元素。它主要用于在两个以上的向量上执行walk()。但是因为 tibble 是一个命名的列列表,我们可以将整个 tibble 传递给 pwalk(),每列都成为一个参数,传递给 .f 进行并行评估。

最短的解决方案使用基于列位置的~表示法,但您也可以编写一个函数来接受与列同名的参数:

## using column locations (`~` notation) ---------------------
animalFrames |> 
  pwalk(
    .f = ~ write.csv(.y, file = paste0("test_", .x, ".csv"))
  )
## using column names & custom function ----------------------
## (longer, more robust, perhaps more readable) --------------
save_file <- function(animals, frames){
  write.csv(frames, file = paste0("test_", animals, ".csv"))
}
animalFrames |> pwalk(save_file)

创建于 2022-10-11 由 reprex 软件包 (v2.0.1(

最新更新