在 mutate 中使用匿名函数

Jos*_*osh 2 r

我想使用数据帧的一列中的字符串作为搜索字符串,逐行搜索sub数据帧的另一列中的字符串。我想使用 来做到这一点dplyr::mutate。我已经找到了一种使用匿名函数 和 来做到这一点的方法apply,但我觉得apply没有必要,而且我的实现方式一定是出了问题mutate。(是的,我知道这tools::file_path_sans_ext可以给我最终结果而不需要使用 mutate ;我只是想了解如何使用mutate。)

这是我认为应该有效但无效的代码:

files.vec <- dir(
    dir.target, 
    full.names = T, 
    recursive = T, 
    include.dirs = F, 
    no.. = T
)

library(tools)
files.paths.df <- as.data.frame(
    cbind(
        path = files.vec, 
        directory = dirname(files.vec), 
        file = basename(files.vec), 
        extension = file_ext(files.vec)
    )
)

library(tidyr)
library(dplyr)
files.split.df <- files.paths.df %>% 
    mutate(
        no.ext = function(x) {
            sub(paste0(".", x["extension"], "$"), "", x["file"])
        }
    )
| Error in mutate_impl(.data, dots) : 
| Column `no.ext` is of unsupported type function
Run Code Online (Sandbox Code Playgroud)

这是有效的代码,使用apply

files.split.df <- files.paths.df %>% 
    mutate(no.ext = apply(., 1, function(x) {
        sub(paste0(".", x["extension"], "$"), "", x["file"])
    }))
Run Code Online (Sandbox Code Playgroud)

没有 可以做到这一点apply吗?

see*_*e24 6

显然你需要的是一大堆括号。请参阅/sf/answers/2583489261/

在你的情况下,它看起来像:

files.split.df <- files.paths.df %>% 
  mutate(
    no.ext = (function(x) {sub(paste0(".", x["extension"], "$"), "", x["file"])})(.)
  )
Run Code Online (Sandbox Code Playgroud)

因此,如果将整个函数定义放在括号中,您就可以将其视为常规函数并为其提供参数。

新答案

实际上,这根本不是使用 mutate 的正确方法。我首先专注于匿名函数部分,而没有考虑您实际在做什么。您需要的是 sub 的矢量化版本。str_replace所以我从包装中使用stringr。然后你可以只按名称引用列,因为这就是 dplyr 的优点:

library(tidyr)
library(dplyr)
library(stringr)

files.split.df <- files.paths.df %>% 
  mutate(
    no.ext = str_replace(file, paste0(".", extension, "$"), ""))
Run Code Online (Sandbox Code Playgroud)

编辑回复评论

要在没有现有向量化函数的情况下使用用户定义的函数,您可以Vectorize像这样使用:

string_fun <- Vectorize(function(x, y) {sub(paste0(".", x, "$"), "", y)})
files.split.df <- files.paths.df %>% 
  mutate(
    no.ext = string_fun(extension, file))
Run Code Online (Sandbox Code Playgroud)

或者,如果您真的不想命名该函数,我不建议这样做,因为它更难阅读:

files.split.df <- files.paths.df %>% 
  mutate(
    no.ext = (Vectorize(function(x, y) {sub(paste0(".", x, "$"), "", y)}))(extension, file))
Run Code Online (Sandbox Code Playgroud)