J'ai un vecteur de nombres:
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,
453,435,324,34,456,56,567,65,34,435)
Comment puis-je faire compter le nombre de fois où une valeur x apparaît dans le vecteur?
J'ai un vecteur de nombres:
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,
453,435,324,34,456,56,567,65,34,435)
Comment puis-je faire compter le nombre de fois où une valeur x apparaît dans le vecteur?
Réponses:
Vous pouvez simplement utiliser table()
:
> a <- table(numbers)
> a
numbers
4 5 23 34 43 54 56 65 67 324 435 453 456 567 657
2 1 2 2 1 1 2 1 2 1 3 1 1 1 1
Ensuite, vous pouvez le sous-définir:
> a[names(a)==435]
435
3
Ou convertissez-le en un data.frame si vous êtes plus à l'aise avec cela:
> as.data.frame(table(numbers))
numbers Freq
1 4 2
2 5 1
3 23 2
4 34 2
...
a["435"]
tête a[names(a)==435]
?
Le moyen le plus direct est sum(numbers == x)
.
numbers == x
crée un vecteur logique qui est VRAI à chaque emplacement où x se produit, et lors de l' sum
ing, le vecteur logique est contraint en numérique qui convertit VRAI en 1 et FAUX en 0.
Toutefois, notez que pour les nombres à virgule flottante , il est préférable d'utiliser quelque chose comme: sum(abs(numbers - x) < 1e-6)
.
x
dans les données plutôt qu'une valeur connue spécifique de x
. Pour être juste, c'était sur cela que portait la question initiale. Comme je l'ai dit dans ma réponse ci-dessous, "Je trouve qu'il est rare que je veuille connaître la fréquence d'une valeur et pas toutes les valeurs ..."
Je ferais probablement quelque chose comme ça
length(which(numbers==x))
Mais vraiment, une meilleure façon est
table(numbers)
table(numbers)
va faire beaucoup plus de travail que la solution la plus simple sum(numbers==x)
, car elle va aussi comprendre le nombre de tous les autres nombres de la liste.
Il y a aussi count(numbers)
du plyr
package. Beaucoup plus pratique qu'à table
mon avis.
Ma solution préférée utilise rle
, qui renverra une valeur (l'étiquette, x
dans votre exemple) et une longueur, qui représente le nombre de fois où cette valeur est apparue en séquence.
En combinant rle
avec sort
, vous avez un moyen extrêmement rapide de compter le nombre de fois qu'une valeur est apparue. Cela peut être utile pour des problèmes plus complexes.
Exemple:
> numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,453,435,324,34,456,56,567,65,34,435)
> a <- rle(sort(numbers))
> a
Run Length Encoding
lengths: int [1:15] 2 1 2 2 1 1 2 1 2 1 ...
values : num [1:15] 4 5 23 34 43 54 56 65 67 324 ...
Si la valeur souhaitée n'apparaît pas ou si vous devez la stocker pour plus tard, faites a
un data.frame
.
> b <- data.frame(number=a$values, n=a$lengths)
> b
values n
1 4 2
2 5 1
3 23 2
4 34 2
5 43 1
6 54 1
7 56 2
8 65 1
9 67 2
10 324 1
11 435 3
12 453 1
13 456 1
14 567 1
15 657 1
Je trouve qu'il est rare que je veuille connaître la fréquence d'une valeur et pas toutes les valeurs, et rle semble être le moyen le plus rapide pour obtenir le comptage et les stocker toutes.
c(rep('A', 3), rep('G', 4), 'A', rep('G', 2), rep('C', 10))
reviendrait values = c('A','G','A','G','C')
et lengths=c(3, 4, 1, 2, 10)
qui est parfois utile.
table
c'est plus rapide when the vector is long
(j'ai essayé 100000) mais légèrement plus long quand il est plus court (j'ai essayé 1000)
Il y a une fonction standard dans R pour cela
tabulate(numbers)
tabulate
est que vous ne pouvez pas gérer les nombres nuls et négatifs.
tabulate
. Note: sort
semble être nécessaire pour son utilisation correcte en général: tabulate(sort(numbers))
.
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435 453,435,324,34,456,56,567,65,34,435)
> length(grep(435, numbers))
[1] 3
> length(which(435 == numbers))
[1] 3
> require(plyr)
> df = count(numbers)
> df[df$x == 435, ]
x freq
11 435 3
> sum(435 == numbers)
[1] 3
> sum(grepl(435, numbers))
[1] 3
> sum(435 == numbers)
[1] 3
> tabulate(numbers)[435]
[1] 3
> table(numbers)['435']
435
3
> length(subset(numbers, numbers=='435'))
[1] 3
Si vous souhaitez compter le nombre d'apparitions ultérieurement, vous pouvez utiliser la sapply
fonction:
index<-sapply(1:length(numbers),function(x)sum(numbers[1:x]==numbers[x]))
cbind(numbers, index)
Production:
numbers index
[1,] 4 1
[2,] 23 1
[3,] 4 2
[4,] 23 2
[5,] 5 1
[6,] 43 1
[7,] 54 1
[8,] 56 1
[9,] 657 1
[10,] 67 1
[11,] 67 2
[12,] 435 1
[13,] 453 1
[14,] 435 2
[15,] 324 1
[16,] 34 1
[17,] 456 1
[18,] 56 2
[19,] 567 1
[20,] 65 1
[21,] 34 2
[22,] 435 3
Vous pouvez changer le nombre en ce que vous souhaitez dans la ligne suivante
length(which(numbers == 4))
Une autre façon que je trouve pratique est:
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,453,435,324,34,456,56,567,65,34,435)
(s<-summary (as.factor(numbers)))
Cela convertit l'ensemble de données en facteur, puis summary () nous donne les totaux de contrôle (décompte des valeurs uniques).
La sortie est:
4 5 23 34 43 54 56 65 67 324 435 453 456 567 657
2 1 2 2 1 1 2 1 2 1 3 1 1 1 1
Cela peut être stocké en tant que trame de données si vous préférez.
as.data.frame (cbind (Number = noms (s), Freq = s), stringsAsFactors = F, row.names = 1: longueur (s))
ici row.names a été utilisé pour renommer les noms de ligne. sans utiliser row.names, les noms de colonne en s sont utilisés comme noms de ligne dans la nouvelle trame de données
La sortie est:
Number Freq
1 4 2
2 5 1
3 23 2
4 34 2
5 43 1
6 54 1
7 56 2
8 65 1
9 67 2
10 324 1
11 435 3
12 453 1
13 456 1
14 567 1
15 657 1
En utilisant le tableau mais sans comparer avec names
:
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435)
x <- 67
numbertable <- table(numbers)
numbertable[as.character(x)]
#67
# 2
table
est utile lorsque vous utilisez plusieurs fois le nombre d'éléments différents. Si vous n'avez besoin que d'un seul comptage, utilisezsum(numbers == x)
Il existe différentes façons de compter un élément spécifique
library(plyr)
numbers =c(4,23,4,23,5,43,54,56,657,67,67,435,453,435,7,65,34,435)
print(length(which(numbers==435)))
#Sum counts number of TRUE's in a vector
print(sum(numbers==435))
print(sum(c(TRUE, FALSE, TRUE)))
#count is present in plyr library
#o/p of count is a DataFrame, freq is 1 of the columns of data frame
print(count(numbers[numbers==435]))
print(count(numbers[numbers==435])[['freq']])
Une méthode qui est relativement rapide sur les vecteurs longs et qui donne une sortie pratique est à utiliser lengths(split(numbers, numbers))
(notez le S à la fin de lengths
):
# Make some integer vectors of different sizes
set.seed(123)
x <- sample.int(1e3, 1e4, replace = TRUE)
xl <- sample.int(1e3, 1e6, replace = TRUE)
xxl <-sample.int(1e3, 1e7, replace = TRUE)
# Number of times each value appears in x:
a <- lengths(split(x,x))
# Number of times the value 64 appears:
a["64"]
#~ 64
#~ 15
# Occurences of the first 10 values
a[1:10]
#~ 1 2 3 4 5 6 7 8 9 10
#~ 13 12 6 14 12 5 13 14 11 14
La sortie est simplement un vecteur nommé.
La vitesse semble comparable à celle rle
proposée par JBecker et même un peu plus rapide sur de très longs vecteurs. Voici une microbenchmark dans R 3.6.2 avec certaines des fonctions proposées:
library(microbenchmark)
f1 <- function(vec) lengths(split(vec,vec))
f2 <- function(vec) table(vec)
f3 <- function(vec) rle(sort(vec))
f4 <- function(vec) plyr::count(vec)
microbenchmark(split = f1(x),
table = f2(x),
rle = f3(x),
plyr = f4(x))
#~ Unit: microseconds
#~ expr min lq mean median uq max neval cld
#~ split 402.024 423.2445 492.3400 446.7695 484.3560 2970.107 100 b
#~ table 1234.888 1290.0150 1378.8902 1333.2445 1382.2005 3203.332 100 d
#~ rle 227.685 238.3845 264.2269 245.7935 279.5435 378.514 100 a
#~ plyr 758.866 793.0020 866.9325 843.2290 894.5620 2346.407 100 c
microbenchmark(split = f1(xl),
table = f2(xl),
rle = f3(xl),
plyr = f4(xl))
#~ Unit: milliseconds
#~ expr min lq mean median uq max neval cld
#~ split 21.96075 22.42355 26.39247 23.24847 24.60674 82.88853 100 ab
#~ table 100.30543 104.05397 111.62963 105.54308 110.28732 168.27695 100 c
#~ rle 19.07365 20.64686 23.71367 21.30467 23.22815 78.67523 100 a
#~ plyr 24.33968 25.21049 29.71205 26.50363 27.75960 92.02273 100 b
microbenchmark(split = f1(xxl),
table = f2(xxl),
rle = f3(xxl),
plyr = f4(xxl))
#~ Unit: milliseconds
#~ expr min lq mean median uq max neval cld
#~ split 296.4496 310.9702 342.6766 332.5098 374.6485 421.1348 100 a
#~ table 1151.4551 1239.9688 1283.8998 1288.0994 1323.1833 1385.3040 100 d
#~ rle 399.9442 430.8396 464.2605 471.4376 483.2439 555.9278 100 c
#~ plyr 350.0607 373.1603 414.3596 425.1436 437.8395 506.0169 100 b
Surtout, la seule fonction qui compte également le nombre de valeurs manquantes NA
est plyr::count
. Ceux-ci peuvent également être obtenus séparément en utilisantsum(is.na(vec))
Il s'agit d'une solution très rapide pour les vecteurs atomiques unidimensionnels. Il repose sur match()
, il est donc compatible avec NA
:
x <- c("a", NA, "a", "c", "a", "b", NA, "c")
fn <- function(x) {
u <- unique.default(x)
out <- list(x = u, freq = .Internal(tabulate(match(x, u), length(u))))
class(out) <- "data.frame"
attr(out, "row.names") <- seq_along(u)
out
}
fn(x)
#> x freq
#> 1 a 3
#> 2 <NA> 2
#> 3 c 2
#> 4 b 1
Vous pouvez également modifier l'algorithme pour qu'il ne s'exécute pas unique()
.
fn2 <- function(x) {
y <- match(x, x)
out <- list(x = x, freq = .Internal(tabulate(y, length(x)))[y])
class(out) <- "data.frame"
attr(out, "row.names") <- seq_along(x)
out
}
fn2(x)
#> x freq
#> 1 a 3
#> 2 <NA> 2
#> 3 a 3
#> 4 c 2
#> 5 a 3
#> 6 b 1
#> 7 <NA> 2
#> 8 c 2
Dans les cas où cette sortie est souhaitable, vous n'en avez probablement même pas besoin pour renvoyer le vecteur d'origine, et la deuxième colonne est probablement tout ce dont vous avez besoin. Vous pouvez obtenir cela en une seule ligne avec le tuyau:
match(x, x) %>% `[`(tabulate(.), .)
#> [1] 3 2 3 2 3 1 2 2
Cela peut être fait avec outer
pour obtenir une métrique des égalités suivie rowSums
d'une signification évidente.
Afin d'avoir les numbers
nombres et dans le même ensemble de données, un data.frame est d'abord créé. Cette étape n'est pas nécessaire si vous souhaitez une entrée et une sortie distinctes.
df <- data.frame(No = numbers)
df$count <- rowSums(outer(df$No, df$No, FUN = `==`))