R dplyr具有多个具有相同词干名称的列

时间:2018-02-14 00:22:07

标签: r dplyr mutate

我有一些数据列,只要相应的列为> 0,我就需要设置为NA。

我可以使用mutate和两列的名称来完成此操作,但我想要一个范围版本,我从第一列的名称创建相应列的名称

(x<-data.frame(x1=(1:4),map.x1=c(0,0,7,0),x2=c(2,2,2,2),map.x2=c(0,7,0,0)))

mutate(x, x1=ifelse(map.x1>0, NA, x1))

mutate_at(x, vars(starts_with("x")), function(v) { 
  m.name <- paste0("map.", deparse(substitute(v)))
  ifelse(get(m.name)>0, NA, v)
  )
}

我可以看到ifelse()不满意,因为它希望第一个参数成为一个对象,并且我已经给出了一个表达式。

我找不到办法。我甚至想知道是否有某种方法可以避免函数(v)并在paste0()或get()中使用(。)

我也在考虑重塑,所以我可以做一个变异。这里的最佳做法是什么?

2 个答案:

答案 0 :(得分:1)

这是获得所需输出的一种方法。无需编写自定义函数。重塑文件就足够了。

library(tibble)
library(dplyr)
library(stats)

# creating dataframe with proper names
x <-
  tibble::as_data_frame(cbind(
    x_1 = c(1:4),
    map.x_1 = c(0, 0, 7, 0),
    x_2 = c(2, 2, 2, 2),
    map.x_2 = c(0, 7, 0, 0)
  )) %>%
  tibble::rownames_to_column(df = ., var = 'id')

# converting to long format
x_long <- stats::reshape(
  as.data.frame(x),
  timevar = "level",
  varying = dput(as.character(as.vector(names(
    x[, base::grep("^x|^map", names(x))]
  )))),
  direction = "long",
  idvar = c("id"),
  sep = "_"
)
#> c("x_1", "map.x_1", "x_2", "map.x_2")

# converting the dataframe based on condition
x_long %>%
  group_by(.data = ., level) %>%
  dplyr::mutate(.data = .,
                x = base::ifelse(test = map.x > 0,
                                 yes = NA,
                                 no = x))
#> # A tibble: 8 x 4
#> # Groups:   level [2]
#>   id    level     x map.x
#>   <chr> <dbl> <dbl> <dbl>
#> 1 1      1.00  1.00  0   
#> 2 2      1.00  2.00  0   
#> 3 3      1.00 NA     7.00
#> 4 4      1.00  4.00  0   
#> 5 1      2.00  2.00  0   
#> 6 2      2.00 NA     7.00
#> 7 3      2.00  2.00  0   
#> 8 4      2.00  2.00  0

reprex package创建于2018-02-14(v0.1.1.9000)。

答案 1 :(得分:1)

这是一种无需重塑数据的解决方案。

library(dplyr)
library(rlang)

custom_mutate <- function(df, v){
  v <- enquo(v)
  map.v <- paste0("map.", quo_name(v))

  df %>%
    mutate(UQE(v) := ifelse((!!sym(map.v)) > 0, NA, (!!v))) %>% 
    pull(UQE(v))
}

mutate_at(x, vars(starts_with("x")), funs(custom_mutate(df = x, v = .)))

#   x1 map.x1 x2 map.x2
# 1  1      0  2      0
# 2  2      0 NA      7
# 3 NA      7  2      0
# 4  4      0  2      0

mutate_at调用中的函数仅应用于列,而不应用于整个数据帧。因此,您必须明确告诉函数在哪里查找map.x1列 要从您使用的列中获取名称,首先需要使用enquo转换v中的quosure。然后,您可以使用quo_name构建map. - 名称。在以下mutate调用中,您必须告诉dplyrv是一个结果(因此UQE缠绕它,这与{{1}类似在!! - FALSE语句的一部分前面。} 对于ifelse列,您必须使用map.x1 - 包中的sym - 函数来获取裸名称(不带引号),然后再次使用rlang来说明!!将此作为列名称。

我试图解释我的解决方案,而不是技术方面。有关如何使用dplyr进行编程的详细说明,请参见此处:Programming with dplyr