【问题标题】:r map_df to invoke_map translationr map_df 到 invoke_map 的翻译
【发布时间】:2018-03-18 17:46:51
【问题描述】:

我想在数据框中的多个列上应用多个函数。我已经研究出如何将一个函数应用于数据框中的所有列,但我很难尝试使用 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,填充=NA):找不到函数“名称”

第二个问题是,在第一个示例生成的“测试”数据框中,第一个变量的名称不正确(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 函数中添加一条语句,这样 vname 就不必在 roll.func 中重复?在函数内部以某种方式引用名称一次?我玩过 enquo 和 rlang 包,但我没有想出正确的组合。

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

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

【问题讨论】:

    标签: r function purrr


    【解决方案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
    

    你应该能够适应它来做你需要的。

    【讨论】:

    • 谢谢-我确实错过了必须将列表列表传递给 invoke_map 函数。不过,我仍然对命名功能有疑问。目前,通过将标签作为参数添加到函数来解决(即 list(list(roll_sdr, 'roll_sdr'), list(roll_varr, 'roll_varr'))
    • 您能更具体地说明您要完成的工作吗?您想对一个数据框的所有列应用 N 个函数并返回 N 个数据框,还是一个数据框?
    • 现在通过将列表传递给它可以很好地工作。命名部分将是一个不错的奖励。我在原始帖子的末尾添加了一个编辑以反映这一点。
    猜你喜欢
    • 1970-01-01
    • 2022-01-18
    • 2016-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多