在R中进行部分动物字符串匹配

16

我有一个数据框:

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"和"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) 差不多被回答了,但它没有解决这个问题中存在的多个名称匹配的情况。

3个回答

26

可能有比这更优雅的解决方案,但您可以使用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"

我假设你是指"鸟类",并省略了"斗牛犬",因为它包含"狗"。

你可能想在grep中添加ignore.case = TRUE

输出:

#                 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

这种方法的优点有几个:
  1. 整个过程中只需修改一次数据框,这增加了循环的速度(数据框没有就地修改;要修改数据框3次,实际上相当于重新标记和创建它3次)。
  2. 通过预先指定向量的长度,由于我们知道它将是什么,您可以通过确保输出向量在创建后永远不需要分配更多内存来进一步提高速度。
  3. 因为它是一个循环,而不是重复的手动调用,所以向'regexes'对象添加更多行和类别不需要进一步修改代码。 它将像现在一样运行。
唯一的缺点 - 这适用于我认为您可能会得到的大多数解决方案 - 是如果某些内容与多个模式匹配,则其“物种”标签将是它匹配列表中的最后一个模式。

关于是否可能存在多个匹配项的好点子。@Brocolli-Rob:如果您的数据集中可能出现这种情况,为每个物种设置一个TRUE/FALSE列可能是更好的方法。 - ping

1
另一种方法是创建查找表,然后使用索引与 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日创建


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接