Tengo un vector de números:
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,
453,435,324,34,456,56,567,65,34,435)
¿Cómo puedo hacer que R cuente la cantidad de veces que aparece un valor x en el vector?
Tengo un vector de números:
numbers <- c(4,23,4,23,5,43,54,56,657,67,67,435,
453,435,324,34,456,56,567,65,34,435)
¿Cómo puedo hacer que R cuente la cantidad de veces que aparece un valor x en el vector?
Respuestas:
Solo puedes usar 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
Entonces puedes subconjuntarlo:
> a[names(a)==435]
435
3
O conviértalo en un data.frame si se siente más cómodo trabajando con eso:
> as.data.frame(table(numbers))
numbers Freq
1 4 2
2 5 1
3 23 2
4 34 2
...
a["435"]
lugar de a[names(a)==435]
?
La forma más directa es sum(numbers == x)
.
numbers == x
crea un vector lógico que es VERDADERO en cada ubicación en la que x ocurre, y cuando se sum
ing, el vector lógico se convierte en numérico, lo que convierte VERDADERO en 1 y FALSO en 0.
Sin embargo, tenga en cuenta que los números de coma flotante que es mejor usar algo como: sum(abs(numbers - x) < 1e-6)
.
x
los datos en lugar de un valor conocido específico de x
. Para ser justos, de eso se trataba la pregunta original. Como dije en mi respuesta a continuación, "Encuentro que es raro que quiera saber la frecuencia de un valor y no todos los valores ..."
Probablemente haría algo como esto
length(which(numbers==x))
Pero realmente, una mejor manera es
table(numbers)
table(numbers)
va a hacer mucho más trabajo que la solución más fácil sum(numbers==x)
, porque también va a calcular los recuentos de todos los otros números en la lista.
Mi solución preferida usa rle
, que devolverá un valor (la etiqueta, x
en su ejemplo) y una longitud, que representa cuántas veces ese valor apareció en secuencia.
Al combinar rle
con sort
, tiene una forma extremadamente rápida de contar la cantidad de veces que apareció cualquier valor. Esto puede ser útil con problemas más complejos.
Ejemplo:
> 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 el valor que desea no aparece, o necesita almacenar ese valor para más adelante, haga 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
Creo que es raro que quiera saber la frecuencia de un valor y no todos los valores, y rle parece ser la forma más rápida de contarlos y almacenarlos todos.
c(rep('A', 3), rep('G', 4), 'A', rep('G', 2), rep('C', 10))
volvería values = c('A','G','A','G','C')
y lengths=c(3, 4, 1, 2, 10)
que a veces es útil.
table
es más rápido when the vector is long
(intenté con 100000) pero un poco más largo cuando fue más corto (intenté con 1000)
Hay una función estándar en R para eso
tabulate(numbers)
tabulate
es que no puedes lidiar con números cero y negativos.
tabulate
. Nota: sort
parece ser necesario para su correcto uso en general: 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 desea contar el número de apariciones posteriormente, puede utilizar la sapply
función:
index<-sapply(1:length(numbers),function(x)sum(numbers[1:x]==numbers[x]))
cbind(numbers, index)
Salida:
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
Puede cambiar el número a lo que desee en la siguiente línea
length(which(numbers == 4))
Una forma más que encuentro conveniente es:
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)))
Esto convierte el conjunto de datos en factor, y luego summary () nos da los totales de control (recuentos de los valores únicos).
Salida es:
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
Esto se puede almacenar como marco de datos si se prefiere.
as.data.frame (cbind (Number = names (s), Freq = s), stringsAsFactors = F, row.names = 1: length (s))
aquí row.names se ha utilizado para renombrar nombres de fila. sin usar row.names, los nombres de columna en s se usan como nombres de fila en el nuevo marco de datos
Salida es:
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
Usando la tabla pero sin comparar con 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
es útil cuando usa los recuentos de diferentes elementos varias veces. Si solo necesita un recuento, usesum(numbers == x)
Hay diferentes formas de contar elementos específicos.
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']])
Un método que es relativamente rápido en vectores largos y proporciona una salida conveniente es usar lengths(split(numbers, numbers))
(tenga en cuenta la S al final 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 salida es simplemente un vector con nombre.
La velocidad parece comparable a la rle
propuesta por JBecker e incluso un poco más rápida en vectores muy largos. Aquí hay un microbenchmark en R 3.6.2 con algunas de las funciones propuestas:
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
Es importante destacar que la única función que también cuenta el número de valores faltantes NA
es plyr::count
. Estos también se pueden obtener por separado usandosum(is.na(vec))
Esta es una solución muy rápida para vectores atómicos unidimensionales. Se basa match()
, por lo que es compatible con 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
También puede ajustar el algoritmo para que no se ejecute 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
En los casos en que ese resultado es deseable, probablemente ni siquiera lo necesite para volver a devolver el vector original, y la segunda columna es probablemente todo lo que necesita. Puede obtener eso en una línea con la tubería:
match(x, x) %>% `[`(tabulate(.), .)
#> [1] 3 2 3 2 3 1 2 2
Esto se puede hacer outer
para obtener una metrix de igualdades seguida de rowSums
un significado obvio.
Para tener los recuentos y numbers
en el mismo conjunto de datos, primero se crea un data.frame. Este paso no es necesario si desea entradas y salidas separadas.
df <- data.frame(No = numbers)
df$count <- rowSums(outer(df$No, df$No, FUN = `==`))