当函数接受多个不同列

时间:2018-01-26 22:52:36

标签: r dplyr

我有一个data.frame,其中包含大量列,其名称遵循模式。如:

df <- data.frame(
  x_1 = c(1, NA, 3), 
  x_2 = c(1, 2, 4), 
  y_1 = c(NA, 2, 1), 
  y_2 = c(5, 6, 7)
)

我想应用mutate_at对每对列执行相同的操作。如:

df %>%
  mutate(
    x = ifelse(is.na(x_1), x_2, x_1), 
    y = ifelse(is.na(y_1), y_2, y_1)
  )

我可以使用mutate_at / mutate_each来做到这一点吗?

此:

df %>%
  mutate_each(vars(x_1, y_1), funs(ifelse(is.na(.), vars(x_2, y_2), .)))

我试过的各种变化都失败了。

问题类似于Using functions of multiple columns in a dplyr mutate_at call,但不同之处在于函数调用的第二个参数不是单个列,而是变量中每列的不同列。

提前致谢。

3 个答案:

答案 0 :(得分:2)

我不知道你是否可以这样做,但这里对问题有不同的看法。如果您发现自己拥有非常广泛的数据(例如,大量具有相似名称的列),并且您希望对它们执行某些操作,那么tidy数据(stata条款长){ {1}}(请参阅此处的文档http://tidyr.tidyverse.org/)。

tidyr::gather

将数据转换为此格式后,使用> df %>% gather() key value 1 x_1 1 2 x_1 NA 3 x_1 3 4 x_2 1 5 x_2 2 6 x_2 4 7 y_1 NA 8 y_1 2 9 y_1 1 10 y_2 5 11 y_2 6 12 y_2 7 组合和重新排列值会更容易,而不是尝试group_by项。例如,您可以使用mutate_at对第一个值进行制作,并使用df %>% gather() %>% mutate(var = substr(key,1,1))以不同方式操纵xy

祝你好运!

答案 1 :(得分:0)

在我看来,目前的答案是:&#34;你不能。&#34;

答案 2 :(得分:0)

古老的问题,但是我同意杰西的观点,您需要稍微整理一下数据。 gather是可行的方法,但是在某种程度上缺乏stats::reshape在其中您可以指定要收集的列组的可能性。所以这是reshape的解决方案:

df %>% 
   reshape(varying   = list(c("x_1", "y_1"), c("x_2", "y_2")), 
           times     = c("x", "y"),
           direction = "long") %>% 
   mutate(x = ifelse(is.na(x_1), x_2, x_1)) %>% 
   reshape(idvar     = "id", 
           timevar   = "time",
           direction = "wide") %>% 
   rename_all(funs(gsub("[a-zA-Z]+(_*)([0-9]*)\\.([a-zA-Z]+)", "\\3\\1\\2", .)))
#   id x_1 x_2 x y_1 y_2 y
# 1  1   1   1 1  NA   5 5
# 2  2  NA   2 2   2   6 2
# 3  3   3   4 3   1   7 1

为了对任意数量的列对执行此操作,可以执行以下操作:

df2 <- setNames(cbind(df, df), c(t(outer(letters[23:26], 1:2, paste, sep = "_"))))
v <- split(names(df2), purrr::map_chr(names(df2), ~ gsub(".*_(.*)", "\\1", .)))
n <- unique(purrr::map_chr(names(df2), ~ gsub("_[0-9]+", "", .) ))
df2 %>% 
    reshape(varying   = v, 
            times     = n,
            direction = "long") %>% 
     mutate(x = ifelse(is.na(!!sym(v[[1]][1])), !!sym(v[[2]][1]), !!sym(v[[1]][1]))) %>% 
     reshape(idvar     = "id", 
             timevar   = "time",
             direction = "wide") %>% 
     rename_all(funs(gsub("[a-zA-Z]+(_*)([0-9]*)\\.([a-zA-Z]+)", "\\3\\1\\2", .)))
#   id w_1 w_2 w x_1 x_2 x y_1 y_2 y z_1 z_2 z
# 1  1   1   1 1  NA   5 5   1   1 1  NA   5 5
# 2  2  NA   2 2   2   6 2  NA   2 2   2   6 2
# 3  3   3   4 3   1   7 1   3   4 3   1   7 1

这假设应该比较的列彼此相邻,并且所有具有可能的NA值的列都位于以_1为后缀的列中,而替换值列则以_2作为后缀。 / p>