r map_df to invoke_map translation

时间:2017-10-06 21:02:30

标签: r function purrr

我想在数据框中的多个列上应用多个函数。我已经研究了如何将一个函数应用于数据框中的所有列,但我很难尝试使用invoke_map来应用函数列表。我玩过quo和enquo,但我没有正确的组合(或者我还在掌握)。

玩具示例设置:

library(tidyverse)
library(RcppRoll)
library(purrr)

ID <- letters[1:26]
var1 <- sample(1:100, 26, replace= T)
var2 <- sample(100:200, 26, replace= T)
temp <- cbind(ID, var1, var2) %>% data.frame()

这适用于一个函数:

roll.var <- function(name) {
  label <- enquo(name)
  map_df(temp[, 2:3], ~ name(.x, 5, fill= NA)) %>%
  rename_all(funs(paste0(., '.', (!!label)))) %>%
  cbind(temp, .)
}

test <- roll.var(roll_sdr)

这是我尝试使用invoke_map将函数列表应用于所选列:

roll.func <- c("roll_sdr", "roll_varr")

invoke_map(roll.var, .x= roll.func)

它返回:名称错误(.x,51,fill = NA):找不到函数“name”

第二个问题是,在第一个例子生成的'test'数据框中,第一个变量命名不正确(var1 .~),而第二个变量命名为我的预期(var2.roll_sdr),可以任何一个告诉我为什么?

非常感谢任何解决方案和/或教育!

编辑:

结合Mike的解释,invoke_map需要一个列表列表,以生成我想要的完整代码:

library(tidyverse)
library(purrr)
library(RcppRoll)
library(plyr)

options(stringsAsFactors= F)

ID <- letters[1:26] %>% data.frame(ID= .)
var1 <- sample(1:100, 26, replace= T) %>% data.frame(var1= .)
var2 <- sample(100:200, 26, replace= T) %>% data.frame(var2= .)
temp <- bind_cols(ID, var1, var2)


roll.func <- list(list(roll_sdr, 'roll_sdr'),
                  list(roll_varr, 'roll_varr'))

roll.var <- function(name, vname) {
  map_df(temp[, 2:3], ~ name(.x, 5, fill= NA)) %>%
    rename_all(funs(paste0(., '.', vname))) %>%
    cbind(temp, .)
}

df <- invoke_map(roll.var, roll.func)
## plyr statrment works much faster than purrr:reduce
df2 <- join_all(df, by= c('ID', 'var1', 'var2'))

是否可以在roll.var函数中添加一个语句,以便不必在roll.func中重复使用vname?以某种方式在函数内部引用名称?我玩过enquo和rlang包,我没想出正确的组合。

roll.func <- list(list(roll_sdr),
                  list(roll_varr))

既可以作为函数调用,也可以将标签附加到变量名。

1 个答案:

答案 0 :(得分:1)

这有两个问题。

第一个问题是构造map_df(temp[, 2:3], ~ name(.x, 5, fill= NA)) - 这不起作用,因为它不知道name指的是什么。在这些类型的情况下,您会发现只传递函数对象更容易,而不是函数的名称 - 也就是说,不要将它放在引号中。

第二个问题是你的构造roll.func不正确。仔细阅读invoke_map的文档 - 该参数必须是一个列表。列表的每个元素必须是一个列表,其元素将作为参数传递给函数。所以,这个简单的例子有效:

library(purrr)

var1 <- sample(1:100, 26, replace= T) %>%  as.numeric
var2 <- sample(100:200, 26, replace= T) %>% as.numeric
temp <- cbind(var1, var2) %>% data.frame()

simple_example <- function(func) map(temp, func)

roll.func <- list(
  list(mean),
  list(sum)
)

invoke_map(simple_example, roll.func)
#> [[1]]
#> [[1]]$var1
#> [1] 53.42308
#> 
#> [[1]]$var2
#> [1] 140.6154
#> 
#> 
#> [[2]]
#> [[2]]$var1
#> [1] 1389
#> 
#> [[2]]$var2
#> [1] 3656

你应该能够根据自己的需要进行调整。