¿Cómo calcular el número de ocurrencias de un personaje dado en cada fila de una columna de cadenas?

Tengo un data.frame en el que ciertas variables contienen una cadena de texto. Deseo contar el número de ocurrencias de un personaje dado en cada cadena individual.

Ejemplo:

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

Deseo crear una nueva columna para q.data con el número de ocurrencia de “a” en cadena (es decir, c (2,1,0)).

El único enfoque complicado que he logrado es:

 string.counter<-function(strings, pattern){ counts<-NULL for(i in 1:length(strings)){ counts[i]0]) } return(counts) } string.counter(strings=q.data$string, pattern="a") number string number.of.a 1 1 greatgreat 2 2 2 magic 1 3 3 not 0 

El paquete stringr proporciona la función str_count que parece hacer lo que le interesa

 # 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 

Si no quiere abandonar la base R, aquí hay una posibilidad bastante breve y expresiva:

 x <- q.data$string lengths(regmatches(x, gregexpr("g", x))) # [1] 2 1 0 
 nchar(as.character(q.data$string)) -nchar( gsub("a", "", q.data$string)) [1] 2 1 0 

Fíjate que forzaré la variable factor a carácter, antes de pasar a nchar. Las funciones de expresiones regulares parecen hacer eso internamente.

Aquí hay resultados de referencia (con un tamaño ampliado de la prueba a 3000 filas)

  q.data<-q.data[rep(1:NROW(q.data), 1000),] str(q.data) 'data.frame': 3000 obs. of 3 variables: $ number : int 1 2 3 1 2 3 1 2 3 1 ... $ string : Factor w/ 3 levels "greatgreat","magic",..: 1 2 3 1 2 3 1 2 3 1 ... $ number.of.a: int 2 1 0 2 1 0 2 1 0 2 ... benchmark( Dason = { q.data$number.of.a <- str_count(as.character(q.data$string), "a") }, Tim = {resT <- sapply(as.character(q.data$string), function(x, letter = "a"){ sum(unlist(strsplit(x, split = "")) == letter) }) }, DWin = {resW <- nchar(as.character(q.data$string)) -nchar( gsub("a", "", q.data$string))}, Josh = {x <- sapply(regmatches(q.data$string, gregexpr("g",q.data$string )), length)}, replications=100) #----------------------- test replications elapsed relative user.self sys.self user.child sys.child 1 Dason 100 4.173 9.959427 2.985 1.204 0 0 3 DWin 100 0.419 1.000000 0.417 0.003 0 0 4 Josh 100 18.635 44.474940 17.883 0.827 0 0 2 Tim 100 3.705 8.842482 3.646 0.072 0 0 
 sum(charToRaw("abc.d.aa") == charToRaw('.')) 

es una buena opción.

Estoy seguro de que alguien puede hacerlo mejor, pero esto funciona:

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

o en una función:

 countLetter <- function(charvec, letter){ sapply(charvec, function(x, letter){ sum(unlist(strsplit(x, split = "")) == letter) }, letter = letter) } countLetter(as.character(q.data$string),"a") 
 s <- "aababacababaaathhhhhslsls jsjsjjsaa ghhaalll" p <- "a" s2 <- gsub(p,"",s) numOcc <- nchar(s) - nchar(s2) 

Puede que no sea el eficiente pero resuelva mi propósito.

Cuento personajes de la misma manera que Amarjeet. Sin embargo, prefiero hacerlo en una sola línea.

 HowManySpaces<-nchar(DF$string)-nchar(gsub(" ","",DF$string)) # count spaces in DF$string 

La manera más fácil y más limpia en mi humilde opinión es:

 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`