web-dev-qa-db-fra.com

Comment calculer le nombre d'occurrences d'un caractère donné dans chaque ligne d'une colonne de chaînes?

J'ai un data.frame dans lequel certaines variables contiennent une chaîne de texte. Je souhaite compter le nombre d'occurrences d'un caractère donné dans chaque chaîne.

Exemple:

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

Je souhaite créer une nouvelle colonne pour q.data avec le nombre d'occurrences de "a" dans la chaîne (c'est-à-dire c (2,1,0)).

La seule approche compliquée que j'ai gérée est la suivante:

string.counter<-function(strings, pattern){  
  counts<-NULL
  for(i in 1:length(strings)){
    counts[i]<-length(attr(gregexpr(pattern,strings[i])[[1]], "match.length")[attr(gregexpr(pattern,strings[i])[[1]], "match.length")>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
77

Le paquet stringr fournit la fonction str_count qui semble faire ce qui vous intéresse

# 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
102
Dason

Si vous ne voulez pas quitter la base R, voici une possibilité assez succincte et expressive:

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

Notez que je force la variable facteur à caractère, avant de passer à nchar. Les fonctions regex semblent le faire en interne.

Voici des résultats de référence (avec une taille de test augmentée à 3000 lignes)

 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
11
42-
sum(charToRaw("abc.d.aa") == charToRaw('.'))

est une bonne option.

5
Zhang Tao

Je suis sûr que quelqu'un peut faire mieux, mais cela fonctionne:

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

ou dans une fonction:

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

Le paquetage stringi fournit les fonctions stri_count et stri_count_fixed qui sont très rapides.

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

repère

Comparé à l'approche la plus rapide de la réponse de @ 42 ' et au fonction équivalente du paquet stringr pour un vecteur de 30 000 éléments.

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)

data

q.data <- data.frame(number=1:3, string=c("greatgreat", "magic", "not"), stringsAsFactors = FALSE)
test.data <- q.data[rep(1:NROW(q.data), 10000),]

enter image description here

1
markus

Le moyen le plus simple et le plus propre IMHO est:

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`
0
Giovanni Campagnoli

Je compte les personnages de la même manière que Amarjeet. Cependant, je préfère le faire en une seule ligne.

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

La question ci-dessous a été déplacée ici, mais il semble que cette page ne réponde pas directement à la question de Farah El. Comment trouver le numéro 1 sur 101 dans R

Donc, je vais écrire une réponse ici, juste au cas où.

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

https://stackoverflow.com/users/8931457/farah-el

0
Yoshiaki

Une variante de https://stackoverflow.com/a/12430764/589165 est

> nchar(gsub("[^a]", "", q.data$string))
[1] 2 1 0
0
Finn Årup Nielsen
s <- "aababacababaaathhhhhslsls jsjsjjsaa ghhaalll"
p <- "a"
s2 <- gsub(p,"",s)
numOcc <- nchar(s) - nchar(s2)

Peut ne pas être l'efficace mais résoudre mon objectif.  

0
Amarjeet

Vous pouvez simplement utiliser la division de chaîne

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

Ce qui vous donnera 1, 3, 1, 0. Vous pouvez également utiliser la division de chaîne avec des expressions régulières et des mots entiers. 

0
Benbob