我想删除数据框中的重复行,仅针对特定列.这可以通过以下方式获得:
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]. @gymbrane建议的解决方案是完美的,如果我有办法将gen转换为c(a,b).重点是避免对列名进行硬编码.我试过像gen< – noquotes(gen)这样的东西,它没有在下面建议的rm_dup_rows函数中给出错误,但它确实给出了不同的结果,给出了与我开始时相同的重复过滤… 固定
我想我搞定了.它可能是不优雅的,我不确定结果是否每一步都是必要的,但它似乎通过将下面的@gymbrane提供的函数与for循环中的ensym和quos相结合,同时添加到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
最佳答案 如何创建一个功能并使用
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