R dplyr使用自定义函数对多个列进行突变以创建新列

时间:2019-02-05 18:36:47

标签: r dataframe dplyr mutate

我想使用自定义函数使用dplyr::mutate在data.frame中创建新列,该自变量是data.frame列名称的向量,但是我得到以下输出:

customFun <- function(col.vec) {
  paste0(gsub("\\s", "_", col.vec), collapse = "-")
}

df <- data.frame(A = c("x 1", "x", "x w"), B = c("E", "D", "2 w"), stringsAsFactors = FALSE)

df %>%
   mutate(C = customFun(c(A, B)))
    A   B                 C
1 x 1   E x_1-x-x_w-E-D-2_w
2   x   D x_1-x-x_w-E-D-2_w
3 x w 2 w x_1-x-x_w-E-D-2_w

代替:

data.table::data.table(df)[, C := customFun(c(A, B)), by = .(A, B)]
     A   B       C
1: x 1   E   x_1-E
2:   x   D     x-D
3: x w 2 w x_w-2_w

可以通过多种方式实现,但是我仅对dplyr解决方案感兴趣。谢谢您的帮助。

3 个答案:

答案 0 :(得分:2)

我们可以使用maplift_dl。我们首先在每个map上使用col.vec(注意,由于c展平了任何矢量元素,而list却没有,所以我使用了列表而不是向量作为输入),并应用了{{1 }}。然后,列表输出被馈送到gsub中。由于paste使用paste,因此我们可以使用...将其输入域从purrr::lift_dl提升为...类型:

list

或以library(dplyr) library(purrr) customFun <- function(col.vec) { map(col.vec, ~gsub("\\s", "_", .x)) %>% lift_dl(paste, sep = "-")() } df %>% mutate(C = customFun(list(A, B))) 作为输入:

...

输出:

customFun <- function(...) {
  col.vec <- list(...)
  map(col.vec, ~gsub("\\s", "_", .x)) %>%
    lift_dl(paste, sep = "-")()
}

df %>%
  mutate(C = customFun(A, B))

答案 1 :(得分:1)

为什么在您的by=.(..)解决方案中使用data.table?如果您有两行具有完全相似的值,那么这些行将合为一体。您需要修改customFun。这样是不正确的:

library(tidyverse)
customFun = function(data) invoke(paste, data.frame(gsub('\\s+', '_', as.matrix(data))), sep='-')

df %>% 
    mutate(c = customFun(.))

    A   B       C
1 x 1   E   x_1-E
2   x   D     x-D
3 x w 2 w x_w-2_w

您可以将调用替换为do.call甚至是lift等。

您的功能未完全满足您的要求。阅读上面的评论

答案 2 :(得分:0)

只需在rowwise之前添加mutate,以便paste中仅使用行的A和B值,而不是 all的向量行。

library(dplyr)

df %>%
  rowwise() %>%
  mutate(C = customFun(c(A, B)))
#> Source: local data frame [3 x 3]
#> Groups: <by row>
#> 
#> # A tibble: 3 x 3
#>   A     B     C      
#>   <chr> <chr> <chr>  
#> 1 x 1   E     x_1-E  
#> 2 x     D     x-D    
#> 3 x w   2 w   x_w-2_w

reprex package(v0.2.1)于2019-02-05创建