取消引用字符串作为管道中的变量

时间:2018-07-31 13:46:52

标签: r dplyr

我想从数据框中删除重复的行,仅适用于特定的列。可以通过distinct来获得:

data <- tibble(a = c(1, 1, 2, 2), b = c(3, 3, 3, 4), z = c(5,4,5,5))
filtered_data <- data %>% distinct(a, b, .keep_all = T)
dim(filtered_data)  
# [1] 3 3

(几乎)这是我需要的。但是,我的问题是我需要与distinct一起使用的列名会更改。因此,我有一个字符串gen,其中包含我想与distinct函数一起使用的列的名称。他们需要被取消报价才能在管道中有用。我发现了使用as.name()eval(parse())的建议。但是,这给了我不同的结果:

gen <- c("a", "b")
filtered_data <- data %>% distinct(eval(parse(text = gen)), .keep_all = T)
dim(filtered_data)  
# [1] 2 4

eval似乎在过滤数据的次数上做得很有趣。 (并且,添加了一个额外的列。不过,我可以忍受...)那么,如何获得类似的结果,就像我曾经使用过a,b一样,而是使用了变量?

其他信息 我实际上是通过读取数据帧的列名来获得gen的:gen <- colnames(data)[1:2]。如果我有办法将gen转换为c(a, b),那么@gymbrane建议的解决方案将是完美的。关键是要避免对列名进行硬编码。我尝试了类似gen <- noquotes(gen)的操作,该操作在下面建议的rm_dup_rows函数中没有给出错误,但是确实给出了不同的结果,给出了与我开始时相同的重复过滤... < / p>

固定 我想我可以使用了。这可能很简单,我不确定结果是否需要执行每个步骤,但是似乎可以通过将下面@gymbrane提供的功能与ensymquos结合使用,在forloop中运行添加到GlobalEnv 中的列表中(编辑:不需要GlobalEnv):

unquote_string <- function(string) {
  out <- list()
  i <- 1
  for (s in string) {
    t <- ensym(s)
    out[i] <-dplyr::quos(!!t)
    i <- i+1
  }
return(out)
}
gen_quo <- unquote_string(gen)
filtered_data <- rm_dup_rows(data, gen_quo)
dim(filtered_data)
# [1] 3 3 

1 个答案:

答案 0 :(得分:1)

如何创建函数并使用quosures。也许您正在寻找类似这样的东西...

rm_dup_rows <- function(data, ...){
  vars = dplyr::quos(...)
  data %>% distinct(!!! vars, .keep_all = T)
}

我相信这会返回您的要求

rm_dup_rows(data = data, a, b)

# A tibble: 3 x 3
  a     b     z
<dbl> <dbl> <dbl>
    1     3     5
    2     3     5
    2     4     5


rm_dup_rows(data, b, z)
# A tibble: 3 x 3
a     b     z
<dbl> <dbl> <dbl>
    1     3     5
    1     3     4
    2     4     5

其他

您可以稍微修改rm_dup_rows并用quos构造和向量。像这样...

rm_dup_rows <- function(data, vars){
  data %>% distinct(!!! vars, .keep_all = T)
}

# quos your column name vector
gen <- quos(a,z)

rm_dup_rows(data, gen)
# A tibble: 3 x 3
  a     b     z
 <dbl> <dbl> <dbl>
   1     3     5
   1     3     4
   2     3     5