【问题标题】:%like% with multiple patterns in r%like% 在 r 中有多种模式
【发布时间】:2020-05-22 19:20:19
【问题描述】:

是否可以在嵌套 ifelse 中使用 %like% 的多个模式?如果没有,还有什么替代方案?

fruits<-c("apple", "pineapple", "grape", "avocado","banana")

color <-c("red","yellow","purple", "green","yellow")

mydata = data.frame(fruits=fruits,color=color ) 


mydata %>%
  mutate(group = ifelse(fruits %like% c("%pple%","%vocado%"), "group 1",
                           ifelse(fruits %like% c("%anana%","%grape%"), "group 2", "group 3")))

当我尝试上面的代码时,我收到以下错误:

Warning messages:
1: In grep(pattern, levels(vector)) :
  argument 'pattern' has length > 1 and only the first element will be used
2: In grep(pattern, levels(vector)) :
  argument 'pattern' has length > 1 and only the first element will be used

感谢任何指导。谢谢!

【问题讨论】:

  • 不确定您使用的是哪个包,但如果您使用的是DescTools 版本的%like%,它们还有%like any% 功能。但是,如果您使用的是 data.tableTmisc 软件包版本,我看不到等效版本。
  • 你在使用data.table::%like%吗?您使用的那些模式不是正则表达式,它们更像是 SQL 风格。
  • 请告诉我们您使用的是什么版本的%like%。如果不确定,请将?"%like%" 放在控制台中,然后查看弹出的文档页面的左上角,以查看 {braces} 中的包名称

标签: r if-statement dplyr


【解决方案1】:

您可以在模式上sapply 并进行行求和以找到您需要的内容。

注意事项:

  • 我在这里将您的 SQL 式模式转换为正则表达式。
  • 使用dplyr 时,最好使用它的if_else,因为这个版本可以更好地防范不同的类输出(以及与基ifelse 相关的一些其他问题)。
  • 由于%like% 只是like 函数的中缀运算符(至少在data.table 中),为了清楚起见,我在这里使用后者(前缀版本)。
sapply(c(".*apple.*", ".*vocado.*"), like, vector = fruits)
#      .*apple.* .*vocado.*
# [1,]      TRUE      FALSE
# [2,]      TRUE      FALSE
# [3,]     FALSE      FALSE
# [4,]     FALSE       TRUE
# [5,]     FALSE      FALSE
rowSums(sapply(c(".*apple.*", ".*vocado.*"), like, vector = fruits)) > 0
# [1]  TRUE  TRUE FALSE  TRUE FALSE

这就是我们需要的,logical 的向量。我会为此创建一个辅助函数。

mylike <- function(x, ptns) rowSums(sapply(ptns, like, vector = x)) > 0
mylike(fruits, c(".*apple.*", ".*vocado.*"))
# [1]  TRUE  TRUE FALSE  TRUE FALSE
mydata %>%
  mutate(
    group = if_else(mylike(fruits, c(".*apple.*", ".*vocado.*")), "group 1",
                    if_else(mylike(fruits, c(".*anana.*",".*grape.*")), "group 2", "group 3"))
  )
#      fruits  color   group
# 1     apple    red group 1
# 2 pineapple yellow group 1
# 3     grape purple group 2
# 4   avocado  green group 1
# 5    banana yellow group 2

但是,当我看到嵌套的ifelse/if_else 时,我建议使用case_when,因为它更具可读性,尤其是当条件数量增加时。

mydata %>%
  mutate(
    group = case_when(
      mylike(fruits, c(".*apple.*", ".*vocado.*")) ~ "group 1",
      mylike(fruits, c(".*anana.*",".*grape.*"))   ~ "group 2",
      TRUE                                         ~ "group 3"
    )
  )
#      fruits  color   group
# 1     apple    red group 1
# 2 pineapple yellow group 1
# 3     grape purple group 2
# 4   avocado  green group 1
# 5    banana yellow group 2

如果您已经有一组 SQL 模式并且不想将它们全部转换为正则表达式,这里有一个基于 https://codereview.stackexchange.com/a/36864/42300 的快速帮助函数:

# https://codereview.stackexchange.com/a/36864/42300
sql2regex <- function(ptn) {
  paste0(
    "^",
    gsub("_", ".",
         gsub("(?<!\\[)%(?!\\])", ".*", ptn, perl = TRUE)),
    "$")
}

它尽量不转换[%],这是一种“逃避”百分比并使用其字面量的方法(参考:http://www.sqlserver.info/syntax/sql-server-like-with-percent-literal/)。然而,即使[% 可能看起来不完整,它也没有正确转换为^[.*$,而是仍然是^[%$,这将失败。同样,这只是一个快速破解助手功能。

mydata %>%
  mutate(
    group = case_when(
      mylike(fruits, sql2regex(c("%pple%","%vocado%"))) ~ "group 1",
      mylike(fruits, sql2regex(c("%anana%","%grape%"))) ~ "group 2",
      TRUE ~ "group 3"
    )
  )
#      fruits  color   group
# 1     apple    red group 1
# 2 pineapple yellow group 1
# 3     grape purple group 2
# 4   avocado  green group 1
# 5    banana yellow group 2

【讨论】:

    【解决方案2】:

    data.tablelike() 函数及其 %like%%ilike%%flike% 运算符版本仅接受单个模式参数,但您可以在正则表达式中使用 alternation .交替用竖线表示:

    library(data.table)
    library(dplyr)
    mydata %>%
      mutate(group = ifelse(fruits %ilike% "apple|avocado", "group 1",
                            ifelse(fruits %ilike% "banana|grape", "group 2", "group 3")))
    
         fruits  color   group
    1     apple    red group 1
    2 pineapple yellow group 1
    3     grape purple group 2
    4   avocado  green group 1
    5    banana yellow group 2
    

    所以,group 1 匹配任何出现appleavocado 的字符串任何地方。因此,不需要% 来表示任意字符的任意数量。

    请注意,%ilike% 已被使用,而不是 %like%%ilike% 是一个新的便利函数,用于不区分大小写的模式匹配,它随 data.table v1.12.4 提供(自 2019 年 10 月 3 日起在 CRAN 上)。

    %ilike% 也将匹配单词Apple(带有大写字母A)。

    当然,case_when()r2evans 建议的嵌套 ifelse() 的一个很好的替代方案:

    mydata %>%
      mutate(group = case_when(fruits %ilike% "apple|avocado" ~ "group 1",
                               fruits %ilike% "banana|grape" ~ "group 2", 
                               TRUE ~ "group 3"))
    

    【讨论】:

    • “交替”方法对我很有用,但我发现这种表示法/语法根本不允许任何空白空格! “apple|avocado”可以正常工作,但“apple|avocado”不行!对我来说似乎有点奇怪,R 通常会接受这个,有什么好的理由吗?
    • @JimMaas,正则表达式的世界有自己的(有时很简洁)规则。所以。 "apple | avocado" 需要在 apple 之后有一个尾随空格,以及在 avocado 之前有一个前导空格。
    猜你喜欢
    • 1970-01-01
    • 2014-12-01
    • 2015-07-27
    • 2020-09-05
    • 2019-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多