Regex 如何计算字符串列的每一行中给定字符的出现次数?

Regex 如何计算字符串列的每一行中给定字符的出现次数?,regex,r,dataframe,Regex,R,Dataframe,我有一个data.frame,其中某些变量包含一个文本字符串。我希望计算每个字符串中给定字符的出现次数 例如: q.data<-data.frame(number=1:3, string=c("greatgreat", "magic", "not")) q.data我相信有人可以做得更好,但这是可行的: sapply(as.character(q.data$string), function(x, letter = "a"){ sum(unlist(strsplit(x, split

我有一个data.frame,其中某些变量包含一个文本字符串。我希望计算每个字符串中给定字符的出现次数

例如:

q.data<-data.frame(number=1:3, string=c("greatgreat", "magic", "not"))

q.data我相信有人可以做得更好,但这是可行的:

sapply(as.character(q.data$string), function(x, letter = "a"){
  sum(unlist(strsplit(x, split = "")) == letter)
})
greatgreat      magic        not 
     2          1          0 
或在函数中:

countLetter <- function(charvec, letter){
  sapply(charvec, function(x, letter){
    sum(unlist(strsplit(x, split = "")) == letter)
  }, letter = letter)
}
countLetter(as.character(q.data$string),"a")

countLetterstringr软件包提供了
str\u count
函数,它似乎做了您感兴趣的事情

# Load your example data
q.data<-data.frame(number=1:3, string=c("greatgreat", "magic", "not"), stringsAsFactors = F)
library(stringr)

# Count the number of 'a's in each element of string
q.data$number.of.a <- str_count(q.data$string, "a")
q.data
#  number     string number.of.a
#1      1 greatgreat           2
#2      2      magic           1
#3      3        not           0
#加载示例数据

q、 data如果你不想离开R基,这里有一个相当简洁和表达的可能性:

x <- q.data$string
lengths(regmatches(x, gregexpr("a", x)))
# [1] 2 1 0
x
注意,在传递到nchar之前,我将因子变量强制为character。regex函数似乎在内部实现了这一点

下面是基准测试结果(测试的规模放大到3000行)


q.data
s另一个好的选择,使用charToRaw:


IMHO最简单、最干净的方法是:

q.data$number.of.a <- lengths(gregexpr('a', q.data$string))

#  number     string number.of.a`
#1      1 greatgreat           2`
#2      2      magic           1`
#3      3        not           0`

q.data$number.of.a您可以使用字符串除法

require(roperators)
my_strings <- c('apple', banana', 'pear', 'melon')
my_strings %s/% 'a'
require(索具)

my_stringsstringi
包提供了非常快速的函数
stri_count
stri_count\u fixed

stringi::stri_count(q.data$string, fixed = "a")
# [1] 2 1 0
基准

与从和到的最快方法相比,对于具有30000个元素的向量

library(microbenchmark)

benchmark <- microbenchmark(
  stringi = stringi::stri_count(test.data$string, fixed = "a"),
  baseR = nchar(test.data$string) - nchar(gsub("a", "", test.data$string, fixed = TRUE)),
  stringr = str_count(test.data$string, "a")
)

autoplot(benchmark)
库(微基准)

benchmark下面的问题已经移到这里,但这一页似乎没有直接回答Farah El的问题。

所以,我会在这里写一个答案,以防万一

library(magrittr)
n %>% # n is a number you'd like to inspect
  as.character() %>%
  str_count(pattern = "1")
is的一种变体


另一个
base R
选项可以是:

lengths(lapply(q.data$string, grepRaw, pattern = "a", all = TRUE, fixed = TRUE))

[1] 2 1 0

下一个表达式起作用,它也适用于符号,而不仅仅是字母

该表达式的作用如下:

1:它在数据帧q.data的列上使用lappy来迭代第2列的行(“lappy(q.data[,2],”)

2:它适用于第2列的每一行,即函数“function(x){sum('a'==strsplit(as.character(x),'')[[1]])}”。 该函数获取第2(x)列的每一行值,转换为字符(例如,如果它是一个因子),并对每个字符进行字符串拆分(“strsplit(as.character(x),“”)”)。因此,对于第2列的每一行,字符串值的每个字符都有一个向量

3:将向量的每个向量值与要计数的所需字符进行比较,在本例中为“a”(“'a'==”)。当向量中的值与要计数的所需字符匹配时,此操作将返回真值和假值向量“c(真、假、真……)”

4:将字符“a”在行中出现的总次数计算为向量“sum(..)”中所有“True”值的总和


5:然后应用“unlist”函数来解压缩“lappy”函数的结果,并将其分配给数据帧中的一个新列("q、 data$number.of.aOK——也许只有在您将
regmatches
gregexpr
一起使用了几次之后,您才会感觉到它的表现力,但该组合足够强大,我认为它值得一插。
regmatches
相对较新。它是在2.14中引入的。我认为您不需要regmatches位。函数gregexpr返回一个列表,其中包含x的每个元素的匹配出现次数的索引。@savagent——您介意分享用于计算每个字符串中匹配次数的代码吗?对不起,我忘记了-1。它只在每行至少有一个匹配项sapply(gregexpr(“g”,q.data$string),length)时起作用。我似乎在第一个…和第二个…(试图对所有这些进行基准测试)中遇到错误。您的速度要快得多,尽管它确实需要as.character()围绕主要论点来解决所提出的问题。@DWin-没错,但在定义数据帧时,我通过添加
stringsAsFactors=FALSE
避免了这个问题。很抱歉,我不清楚。我实际上是在回复tim riffe,告诉他他的函数在所提出的问题上出现了错误。他可能使用了你的重新定义是的,我在我的comp上也说过,
stringsAsFactors=TRUE
,但没有提到在一个factor中搜索字符串将起作用,即str_计数(d$factor_列,'a'))但并非如此,这是答案中最快的解决方案,但通过将可选的
fixed=TRUE
传递到
gsub
,在基准测试中提高了约30%。也有需要
fixed=TRUE
的情况(即,当您要计数的字符可以解释为regex断言时,例如
)。这是如何完成的?对我来说,
长度(gregexpr('a',q.data$string))
返回
2 1 1
,而不是
2 1 0
。如果你能详细说明它的作用,你的答案会更好,尤其是对新用户来说,因为它不是一个简单的表达方式。感谢@Khaine775的评论,并对文章缺乏描述表示歉意。我已经编辑了这篇文章,并添加了一些评论,以便更好地理解描述它是如何工作的。
require(roperators)
my_strings <- c('apple', banana', 'pear', 'melon')
my_strings %s/% 'a'
stringi::stri_count(q.data$string, fixed = "a")
# [1] 2 1 0
library(microbenchmark)

benchmark <- microbenchmark(
  stringi = stringi::stri_count(test.data$string, fixed = "a"),
  baseR = nchar(test.data$string) - nchar(gsub("a", "", test.data$string, fixed = TRUE)),
  stringr = str_count(test.data$string, "a")
)

autoplot(benchmark)
q.data <- data.frame(number=1:3, string=c("greatgreat", "magic", "not"), stringsAsFactors = FALSE)
test.data <- q.data[rep(1:NROW(q.data), 10000),]
library(magrittr)
n %>% # n is a number you'd like to inspect
  as.character() %>%
  str_count(pattern = "1")
> nchar(gsub("[^a]", "", q.data$string))
[1] 2 1 0
lengths(lapply(q.data$string, grepRaw, pattern = "a", all = TRUE, fixed = TRUE))

[1] 2 1 0
q.data$number.of.a<-unlist(lapply(q.data[,2],function(x){sum('a' == strsplit(as.character(x), '')[[1]])}))

>q.data

#  number     string     number.of.a
#1   greatgreat         2
#2      magic           1
#3      not             0