【问题标题】:Quosure with in a nested function嵌套函数中的 Quosure
【发布时间】:2019-04-07 01:43:28
【问题描述】:

我正在努力编写一个使用 fun1 的函数 fun2...并且不断出错。我在下面写了一个简化的例子。这是我第一次处理“整洁的评估”,不确定其中的来龙去脉。

示例数据框:

d1 = data.frame(
  ID = c("A", "A", "A", "B", "B", "C", "C", "C", "C"),
  EXPR = c(2, 8, 3, 5, 7, 20, 1, 5, 4)
)

d2 = data.frame(
  ID = c("A", "B", "C"),
  NUM = c(22, 50, 31)
)

第一个函数

fun1 <- function(
  df1 = "df 1", 
  df2 = "df 2",
  t1 = "threshold 1",
  expr_col = "expr column", 
  id_col = "sample column - must be present in df1 and df2") {

  # dataframes
  df <- df1
  db <- df2

  # quosure
  enquo_id <- enquo(id_col)
  enquo_expr <- enquo(expr_col)

  # classify
  df <- df %>% 
    mutate(threshold = t1) %>% 
    mutate(class = ifelse(!!enquo_expr > t1, "positive", "negative")) %>% 
    mutate(class = factor(class, levels = c("positive", "negative")))

  # calculate sample data
  df.sum <- df %>% 
    group_by(!!enquo_id, class) %>% 
    summarise(count = n()) %>% 
    complete(class, fill = list(count = 0)) %>% 
    mutate(total = sum(count), freq = count/total)

  # merge dataframes
  df.sum <- left_join(df.sum, db, by = quo_name(enquo_id))

  # return
  return(df.sum)
}

如果我对此进行测试,我会得到一个数据帧作为回报,正如预期的那样

test <- fun1(df1 = d1, df2 = d2, t1 = 3, expr_col = EXPR, id_col = ID)

第二个功能 现在有了 fun2,我尝试在 for 循环中使用 fun1 来从 ti 迭代到 seq 向量的 tf:

fun2 <- function(
  df1 = "df 1", 
  df2 = "df 2",
  expr_col = "expr column", 
  id_col = "sample column - must be present in df1 and df2",
  ti = "initial value",
  tf = "final value",
  res = "resolution") {

  # define variables for fun1
  var1 <- enquo(d1)
  var2 <- enquo(d2)
  var3 <- enquo(t1)
  var4 <- enquo(EXPR)
  var5 <- enquo(ID)

  # get sequence of values
  seq <- seq(from = ti, to = tf, by = res)

  # open list
  t.list <- list()

  # Loop ----
  for (i in seq_along(seq)){
    t1 <- seq[i]
    t.list[[i]] <- fun1(df1 = var1,
                        df2 = var2,
                        t1 = var3,
                        expr_col = var4,
                        id_col = var5)
  }
  df.out <- plyr::ldply(t.list, rbind)

  ### Return ---
  return(df.out)
}

但是如果我运行这个

test <- fun2(df1 = d1, df2 = d2, expr_col = EXPR, id_col = ID, ti = 1, tf = 10, res = 1)

我收到一条错误消息

Error in (function (x)  : object 'EXPR' not found

我尝试了各种方法......我有点卡在这里。我想我没有正确使用 enquo() 。我可以通过不使用 varX 并将每个元素的实际适当名称直接放在 fun1 参数中来使其工作,但对我来说,这样做的重点是,是使其“generalisable”,因此仅在 fun2 中指定参数,然后将其传递给 fun1

任何帮助将不胜感激。

【问题讨论】:

  • 传递EXPR 并期望它工作意味着EXPR 可以在全局环境中找到(从您提供的代码来看,它不是)。也许您的意思是引用名为EXPR 的数据框列?或者你的意思是 attach() 一个数据框?
  • EXPR 这里是数据框的列名d1...但实际上,我的代码似乎没有解决问题...
  • 当您将EXPR 传递给fun2() 时,您将其作为对象EXPR 传递,而不是数据框列。难道你的意思是d1$EXPR
  • 您没有在fun2() 中使用您的参数名称。例如,您的参数名称是expr_col,但您使用EXPRid_colID 的问题相同。我想你想要,例如,var4 &lt;- enquo(expr_col)。您需要在 fun2() (expr_col = !! var4)) 中取消引用函数中使用的所有变量名称。您的数据集和常量(参数 df1df2ti)可能可以直接使用,例如 @987654348 @(虽然我对你在 for 循环中使用 t1ti 感到有些困惑)。

标签: r dplyr quosure


【解决方案1】:

非常感谢您的回答 aosmith。我现在使用以下代码进行排序:

fun2 <- function(
  df1 = "df 1", 
  df2 = "df 2",
  expr_col = "expr column", 
  id_col = "sample column - must be present in df1 and df2",
  ti = "initial value",
  tf = "final value",
  res = "resolution") {

  # define variables for fun1
  var4 <- enquo(expr_col)
  var5 <- enquo(id_col)

  # get sequence of values
  seq <- seq(from = ti, to = tf, by = res)

  # open list
  t.list <- list()

  ### Loop --------------------------------------------------------------
  for (i in seq_along(seq)){
    t1 <- seq[i]
    t.list[[i]] <- fun1(df1 = df1,
                        df2 = df2,
                        t1 = t1,
                        expr_col = !!var4,
                        id_col = !!var5)
  }
  df.out <- plyr::ldply(t.list, rbind)

  ### Return ---
  return(df.out)
}

# TEST FUN2
test <- fun2(df1 = d1, df2 = d2, expr_col = EXPR, id_col = ID, ti = 1, tf = 10, res = 1)

【讨论】:

  • 我不确定这将如何工作,您实际上是在没有 qusiquotation 上下文的情况下取消引用,例如,您在 dplyr 环境之外取消引用,如 f1
猜你喜欢
  • 1970-01-01
  • 2011-02-06
  • 2016-12-23
  • 2015-05-24
  • 2010-12-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多