【问题标题】:R dplyr mutate multiple columns using custom function to create new columnR dplyr 使用自定义函数改变多个列以创建新列
【发布时间】:2019-02-05 18:36:46
【问题描述】:

我想使用 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 解决方案感兴趣。感谢您的帮助。

【问题讨论】:

  • Mutate 只能返回一个与数据长度相同或长度为 1 的向量。到目前为止,您的自定义函数还没有做到这一点。我猜你没有做你期望做的事情,例如,你到底在粘贴什么?你有一个长向量,你用 sep 粘贴什么?试试with(head(iris),customFun(c(Species, Petal.Length, Petal.Width))),你会发现这不是你想要的。 c(Species, Petal.Length, Petal.Width) 已经是一个向量,所以技术上不能粘贴到另一个不存在的东西上
  • 对不起,伙计们,我提供了不好的例子 - 我更新了我的问题,现在可以了。
  • 即使使用data.tables,如果你有两个相似的行,你会被折叠成一个。你的 customFunc 不对
  • 你需要做类似df%&gt;%mutate(C = invoke(paste,data.frame(gsub('\\s+','_',as.matrix(.))),sep='-'))的事情

标签: r dataframe dplyr


【解决方案1】:

我们可以使用maplift_dl。我们首先在每个col.vec 上使用map(注意我使用列表而不是向量作为输入,因为c 会展平任何向量元素,而列表不会)并应用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))

输出:

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

【讨论】:

    【解决方案2】:

    只需在mutate 之前添加rowwise,这样paste 中只使用每个 行的A 和B 值,而不是所有 行的向量。

    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 年 2 月 5 日创建

    【讨论】:

      【解决方案3】:

      为什么在您的data.table 解决方案中使用by=.(..)?如果您有两行具有完全相同的值,那么它们将被折叠成一行。您需要修改您的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 等。

      您的功能并未完全按照您的意愿行事。阅读上面的评论

      【讨论】:

        猜你喜欢
        • 2023-01-29
        • 1970-01-01
        • 2020-07-05
        • 1970-01-01
        • 2020-11-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-22
        相关资源
        最近更新 更多