在R中进行计数模式匹配

6
如何高效地计算一个字符串中出现另一个字符串的次数?
以下是我目前的代码。它可以成功地识别一个字符串是否出现在另一个字符串中。但是,我不知道如何将其从一个TRUE/FALSE关系扩展到一个计数关系。
x <- ("Hello my name is Christopher. Some people call me Chris")
y <- ("Chris is an interesting person to be around")
z <- ("Because he plays sports and likes statistics")

lll <- tolower(list(x,y,z))
dict <- tolower(c("Chris", "Hell"))

mmm <- matrix(nrow=length(lll), ncol=length(dict), NA)

for (i in 1:length(lll)) {
for (j in 1:length(dict)) {
    mmm[i,j] <- sum(grepl(dict[j],lll[i]))
}
}
mmm

它的意思是:
       [,1] [,2]
 [1,]    1    1
 [2,]    1    0
 [3,]    0    0

自小写字符串“chris”在lll [1] 中出现两次,我希望mmm [1,1]为2而不是1。
真实示例具有更高的维度...因此,如果代码可以向量化,而不是使用我的暴力循环,那就太好了。
5个回答

8

两个小技巧:

  1. 避免使用双重循环,您不需要它;)
  2. 使用stringr软件包

library(stringr)

dict <- setNames(nm=dict)  # simply for neatness
lapply(dict, str_count, string=lll)
# $chris
# [1] 2 1 0
#
# $hell
# [1] 1 0 0

或者作为矩阵:

#  sapply(dict, str_count, string=lll)
#      chris hell
# [1,]     2    1
# [2,]     1    0
# [3,]     0    0

谢谢@Ricardo。我收到了许多其他很好的答案。如下所述...希望其他SO用户能够权衡解决问题的最有效方法(考虑以下建议)。 - Chris
2
这取决于你对“高效”的定义。看看microbenchmark包。请注意,stringr是语法糖,使处理字符串更容易。自己编码总是会更快。 - Ricardo Saporta
1
话虽如此,效率 = 使用次数 * 代码运行时间 + 程序员时间。计算机的时间相对较便宜。 - Tyler Rinker

4
您也可以这样做:
count.matches <- function(pat, vec) sapply(regmatches(vec, gregexpr(pat, vec)), length)
mapply(count.matches, c('chris', 'hell'), list(lll))
#      chris hell
# [1,]     2    1
# [2,]     1    0
# [3,]     0    0

我也喜欢这个解决方案,因为它不依赖于安装 stringr 库。但是 stringr 中的代码非常简单。非常感谢您提供的解决方案(我希望我能接受两者)!我会让 SO 社区告诉我哪一个更好。 - Chris

2

不要使用 sum(grepl(dict[j],lll[i])),尝试使用 sum(gregexpr(dict[j],lll[i])[[1]] > 0)


现在运行得很好。谢谢你。看起来有多种方法可以解决这个问题。 - Chris

1
llll<-rep(lll,length(dict))
dict1<-rep(dict,each=length(lll))


 do.call(rbind,Map(function(x,y)list(y,sum(gregexpr(y,x)[[1]] > 0)), llll,dict1))
                                                        [,1]    [,2]
hello my name is christopher. some people call me chris "chris" 2   
chris is an interesting person to be around             "chris" 1   
because he plays sports and likes statistics            "chris" 0   
hello my name is christopher. some people call me chris "hell"  1   
chris is an interesting person to be around             "hell"  0   
because he plays sports and likes statistics            "hell"  0  

您可以使用reshape来获得您想要的结果。

1

这使用了qdap包。CRAN版本应该可以正常工作,但您可能需要dev版本

library(qdap)

termco(c(x, y, z), 1:3, c('chris', 'hell'))

##   3 word.count     chris      hell
## 1 1         10 2(20.00%) 1(10.00%)
## 2 2          8 1(12.50%)         0
## 3 3          7         0         0


termco(c(x, y, z), 1:3, c('chris', 'hell'))$raw

##   3 word.count chris hell
## 1 1         10     2    1
## 2 2          8     1    0
## 3 3          7     0    0

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