R中的部分动物字符串匹配

Posted

技术标签:

【中文标题】R中的部分动物字符串匹配【英文标题】:Partial animal string matching in R 【发布时间】:2014-05-21 20:57:18 【问题描述】:

我有一个数据框,

d<-data.frame(name=c("brown cat", "blue cat", "big lion", "tall tiger",
                     "black panther", "short cat", "red bird",
                     "short bird stuffed", "big eagle", "bad sparrow",
                     "dog fish", "head dog", "brown yorkie",
                     "lab short bulldog"), label=1:14)

我想搜索name 列,如果这些词 出现“cat”、“lion”、“tiger”和“panther”,我想将字符串feline分配给新列和对应行species

如果出现"bird", "eagle", and "sparrow"字样,我想将字符串avian分配给新列和对应行species

如果出现单词“dog”、“yorkie”和“bulldog”,我想将字符串canine分配给新列和对应行species

理想情况下,我会将其存储在一个列表或类似的东西中,我可以保留在脚本的开头,因为随着物种的新变种出现在名称类别中,很容易访问更新符合条件的 felineaviancanine

这个问题在这里几乎得到了回答 (How to create new column in dataframe based on partial string matching other column in R),但它没有解决这个问题中存在的多个名称扭曲。

【问题讨论】:

【参考方案1】:

可能有比这更优雅的解决方案,但您可以使用 grep| 来指定替代匹配项。

d[grep("cat|lion|tiger|panther", d$name), "species"] <- "feline"
d[grep("bird|eagle|sparrow", d$name), "species"] <- "avian"
d[grep("dog|yorkie", d$name), "species"] <- "canine"

我假设您的意思是“鸟类”,而忽略了“斗牛犬”,因为它包含“狗”。

您可能希望将 ignore.case = TRUE 添加到 grep。

输出:

#                 name label species
#1           brown cat     1  feline
#2            blue cat     2  feline
#3            big lion     3  feline
#4          tall tiger     4  feline
#5       black panther     5  feline
#6           short cat     6  feline
#7            red bird     7   avian
#8  short bird stuffed     8   avian
#9           big eagle     9   avian
#10        bad sparrow    10   avian
#11           dog fish    11  canine
#12           head dog    12  canine
#13       brown yorkie    13  canine
#14  lab short bulldog    14  canine

【讨论】:

【参考方案2】:

这样做的一种优雅的方式(我说优雅是因为,虽然这是我所知道的最优雅的方式,但它不是很好)是这样的:

#Define the regexes at the beginning of the code
regexes <- list(c("(cat|lion|tiger|panther)","feline"),
                c("(bird|eagle|sparrow)","avian"),
                c("(dog|yorkie|bulldog)","canine"))

....


#Create a vector, the same length as the df
output_vector <- character(nrow(d))

#For each regex..
for(i in seq_along(regexes))

    #Grep through d$name, and when you find matches, insert the relevant 'tag' into
    #The output vector
    output_vector[grepl(x = d$name, pattern = regexes[[i]][1])] <- regexes[[i]][2]

 

#Insert that now-filled output vector into the dataframe
d$species <- output_vector

这种方法的优点是多方面的

    整个过程只需要修改一次数据框,提高了循环的速度(数据框没有就地修改;修改一个数据框3次,本质上是重新标记和重新创建 3 次)。 通过提前指定向量的长度,因为我们知道它将是什么,您可以通过确保输出向量在创建后不再需要分配更多内存来进一步提高速度。 因为它是一个循环,而不是重复的手动调用,所以向“正则表达式”对象添加更多行和类别不需要进一步修改代码。它会像现在一样运行。

唯一的缺点 - 我认为这适用于您可能获得的大多数解决方案,如果某物匹配多个模式,则它匹配的列表中的最后一个模式将是它的“物种”标签。

【讨论】:

关于是否可以有多个匹配项的要点。 @Brocolli-Rob:如果您的数据集中可能出现这种情况,那么为每个物种设置一个 TRUE/FALSE 列可能是一种更好的方法。【参考方案3】:

另一种方法是创建查找表并将按索引与grepmatch 组合匹配

d<-data.frame(name=c("brown cat", "blue cat", "big lion", "tall tiger",
                     "black panther", "short cat", "red bird",
                     "short bird stuffed", "big eagle", "bad sparrow",
                     "dog fish", "head dog", "brown yorkie",
                     "lab short bulldog"), label=1:14)

avian <- c("bird", "eagle", "sparrow")
canine <- c("dog", "yorkie", "bulldog")
feline <-  c("cat", "lion", "tiger", "panther")

lu <- stack(tibble::lst(avian, canine, feline))
lu2 <- stack(sapply(lu$values, grep, x = d$name, ignore.case = TRUE))
lu2$ind <- as.character(lu$ind[match(as.character(lu2$ind), lu$values)])

d$species <- d$name
d$species[lu2$values] <- as.character(lu2$ind)

d
#>                  name label species
#> 1           brown cat     1  feline
#> 2            blue cat     2  feline
#> 3            big lion     3  feline
#> 4          tall tiger     4  feline
#> 5       black panther     5  feline
#> 6           short cat     6  feline
#> 7            red bird     7   avian
#> 8  short bird stuffed     8   avian
#> 9           big eagle     9   avian
#> 10        bad sparrow    10   avian
#> 11           dog fish    11  canine
#> 12           head dog    12  canine
#> 13       brown yorkie    13  canine
#> 14  lab short bulldog    14  canine

由reprex package (v2.0.1) 于 2021 年 11 月 13 日创建

【讨论】:

以上是关于R中的部分动物字符串匹配的主要内容,如果未能解决你的问题,请参考以下文章

是否有一个 R 函数来匹配基于具有部分相似性的字符串的数据框列?

R:使用 for 循环将因子的级别部分匹配到字符串? [复制]

在R中根据部分字符串的匹配度来查找值。

R中的正则表达式:匹配所有内容,但不匹配“某些字符串”[重复]

字符串匹配---KMP算法

python怎么做让正则只匹配输出url中的域名?