从多个字符串的 grepl 匹配中返回匹配的字符串,而不是逻辑

Returning the matched string from a grepl match of multiple strings, rather than the logical

目前我正在使用带有 grepl 的嵌套 ifelse 函数来检查与数据框中字符串向量的匹配,例如:

# vector of possible words to match
x <- c("Action", "Adventure", "Animation")

# data
my_text <- c("This one has Animation.", "This has none.", "Here is Adventure.")
my_text <- as.data.frame(my_text)

my_text$new_column <- ifelse (
  grepl("Action", my_text$my_text) == TRUE,
  "Action",
  ifelse (
    grepl("Adventure", my_text$my_text) == TRUE,
    "Adventure",
    ifelse (
      grepl("Animation", my_text$my_text) == TRUE,
      "Animation", NA)))

> my_text$new_column
[1] "Animation" NA          "Adventure"

这对少数元素(例如这里的三个)没问题,但是当可能的匹配项更大(例如 150)时,我如何 return?嵌套的 ifelse 看起来很疯狂。我知道我可以像下面的代码一样一次 grepl 多个东西,但是这个 return 是合乎逻辑的,只告诉我字符串是否匹配,而不是哪个匹配。我想知道匹配的是什么(如果是多个,任何匹配都可以。

x <- c("Action", "Adventure", "Animation")
my_text <- c("This one has Animation.", "This has none.", "Here is Adventure.")
grepl(paste(x, collapse = "|"), my_text)

returns: [1]  TRUE FALSE  TRUE
what i'd like it to return: "Animation" ""(or FALSE) "Adventure"

遵循模式 herebase 解决方案。

x <- c("ActionABC", "AdventureDEF", "AnimationGHI")

regmatches(x, regexpr("(Action|Adventure|Animation)", x))

stringr 有更简单的方法

library(stringr)
str_extract(x, "(Action|Adventure|Animation)")

这样就可以了...

my_text$new_column <- unlist(              
                         apply(            
                             sapply(x, grepl, my_text$my_text),
                             1,
                             function(y) paste("",x[y])))

sapply 生成一个逻辑矩阵,显示 x 项中的哪些项出现在列的每个元素中。然后 apply 逐行运行并将 x 对应于 TRUE 值的所有值粘贴在一起。 (它在开头粘贴了一个""以避免NAs并保持输出的长度与原始数据相同。)如果x中的两个术语匹配一行, 它们将在输出中粘贴在一起。

基于 Benjamin 的基本解决方案,使用 lapply 以便在没有匹配项时您将拥有一个字符 (0) 值。

直接在你的示例代码上使用regmatches,会不会出现如下错误。

    my_text$new_column <-regmatches(x = my_text$my_text, m = regexpr(pattern = paste(x, collapse = "|"), text = my_text$my_text))

    Error in `$<-.data.frame`(`*tmp*`, new_column, value = c("Animation",  : 
  replacement has 2 rows, data has 3

这是因为只有 2 个匹配项,它会尝试在具有 3 行的数据框列中匹配匹配值。

要用特殊值填充不匹配项以便可以直接完成此操作,我们可以使用 lapply.

my_text$new_column <-
lapply(X = my_text$my_text, FUN = function(X){
  regmatches(x = X, m = regexpr(pattern = paste(x, collapse = "|"), text = X))
})

这会将字符 (0) 放在没有匹配项的地方。

Table screenshot

希望对您有所帮助。