140 votes

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

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 individuelle.

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 de caractères (par exemple c(2,1,0)).

La seule approche alambiquée que j'ai réussi à mettre en place est :

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

0voto

bacnqn Points 1

L'expression suivante fait le travail et fonctionne également pour les symboles, pas seulement les lettres.

L'expression fonctionne comme suit :

1 : il utilise lapply sur les colonnes du dataframe q.data pour itérer sur les lignes de la colonne 2 ("lapply(q.data[,2],"),

2 : il applique à chaque ligne de la colonne 2 une fonction "function(x){sum('a' == strsplit(as.character(x), '')[[1]])}". La fonction prend chaque valeur de ligne de la colonne 2 (x), la convertit en caractère (au cas où il s'agirait d'un facteur par exemple), et effectue la division de la chaîne sur chaque caractère ("strsplit(as.character(x), '')"). Comme résultat, nous avons un vecteur avec chaque caractère de la valeur de la chaîne pour chaque ligne de la colonne 2.

3 : Chaque valeur du vecteur est comparée au caractère que l'on souhaite compter, dans ce cas "a" (" 'a' == "). Cette opération retournera un vecteur de valeurs Vrai et Faux "c(Vrai,Faux,Vrai,....)", étant Vrai lorsque la valeur du vecteur correspond au caractère désiré à compter.

4 : Le nombre total de fois où le caractère "a" apparaît dans la ligne est calculé comme la somme de toutes les valeurs "Vrai" dans le vecteur "sum(....)".

5 : Ensuite, on applique la fonction "unlist" pour décompresser le résultat de la fonction "lapply" et l'affecter à une nouvelle colonne dans le dataframe ("q.data$number.of.a<-unlist(....")

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

0voto

iago Points 1663

Une autre réponse de base de R, pas aussi bonne que celles de @IRTFM et @Finn (ou que celles qui utilisent stringi / stringr ), mais meilleur que les autres :

sapply(strsplit(q.data$string, split=""), function(x) sum(x %in% "a"))

q.data<-data.frame(number=1:3, string=c("greatgreat", "magic", "not"))
q.data<-q.data[rep(1:NROW(q.data), 3000),]
library(rbenchmark)
library(stringr)
library(stringi)

benchmark( Dason = {str_count(q.data$string, "a") },
           Tim = {sapply(q.data$string, function(x, letter = "a"){sum(unlist(strsplit(x, split = "")) == letter) }) },
           DWin = {nchar(q.data$string) -nchar( gsub("a", "", q.data$string, fixed=TRUE))}, 
           Markus = {stringi::stri_count(q.data$string, fixed = "a")},
           Finn={nchar(gsub("[^a]", "", q.data$string))},
           tmmfmnk={lengths(lapply(q.data$string, grepRaw, pattern = "a", all = TRUE, fixed = TRUE))},
           Josh1 = {sapply(regmatches(q.data$string, gregexpr("g",q.data$string )), length)}, 
           Josh2 = {lengths(regmatches(q.data$string, gregexpr("g",q.data$string )))}, 
           Iago = {sapply(strsplit(q.data$string, split=""), function(x) sum(x %in% "a"))}, 
           replications =100, order = "elapsed")

     test replications elapsed relative user.self sys.self user.child sys.child
4  Markus          100   0.076    1.000     0.076    0.000          0         0
3    DWin          100   0.277    3.645     0.277    0.000          0         0
1   Dason          100   0.290    3.816     0.291    0.000          0         0
5    Finn          100   1.057   13.908     1.057    0.000          0         0
9    Iago          100   3.214   42.289     3.215    0.000          0         0
2     Tim          100   6.000   78.947     6.002    0.000          0         0
6 tmmfmnk          100   6.345   83.487     5.760    0.003          0         0
8   Josh2          100  12.542  165.026    12.545    0.000          0         0
7   Josh1          100  13.288  174.842    13.268    0.028          0         0

-1voto

Le moyen le plus simple et le plus propre, à mon avis, 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`

-2voto

Amarjeet Points 468
s <- "aababacababaaathhhhhslsls jsjsjjsaa ghhaalll"
p <- "a"
s2 <- gsub(p,"",s)
numOcc <- nchar(s) - nchar(s2)

Ce n'est peut-être pas le plus efficace, mais il répond à mes besoins.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X