vacio - listas en r
Cómo contar valores VERDADEROS en un vector lógico (7)
En R, ¿cuál es la forma más eficiente / idiomática de contar el número de valores TRUE
en un vector lógico? Puedo pensar de dos maneras:
z <- sample(c(TRUE, FALSE), 1000, rep = TRUE)
sum(z)
# [1] 498
table(z)["TRUE"]
# TRUE
# 498
¿Cual prefieres? ¿Hay algo aún mejor?
Acabo de tener un problema particular en el que tuve que contar el número de declaraciones verdaderas de un vector lógico y esto funcionó mejor para mí ...
length(grep(TRUE, (gene.rep.matrix[i,1:6] > 1))) > 5
Entonces esto toma un subconjunto del objeto gene.rep.matrix, y aplica una prueba lógica, devolviendo un vector lógico. Este vector se pone como argumento para grep, que devuelve las ubicaciones de cualquier entrada TRUE. Longitud luego calcula cuántas entradas encuentra grep, dando así el número de entradas VERDADERAS.
Hay algunos problemas cuando el vector lógico contiene valores de NA
.
Ver por ejemplo:
z <- c(TRUE, FALSE, NA)
sum(z) # gives you NA
table(z)["TRUE"] # gives you 1
length(z[z==TRUE]) # f3lix answer, gives you 2 (because NA indexing returns values)
Entonces creo que es seguro
sum(z, na.rm=TRUE) # best way to count TRUE values
(que da 1). Creo que la solución de table
es menos eficiente (mira el código de la función de table
).
Además, debe tener cuidado con la solución de "tabla", en caso de que no haya valores VERDADEROS en el vector lógico. Supongamos que z <- c(NA, FALSE, NA)
o simplemente z <- c(FALSE, FALSE)
table(z)["TRUE"] # gives you NA for both cases.
He estado haciendo algo similar hace unas semanas. Aquí hay una posible solución, está escrita desde cero, por lo que es una especie de versión beta o algo así. Trataré de mejorarlo eliminando bucles del código ...
La idea principal es escribir una función que tomará 2 (o 3) argumentos. El primero es un data.frame
que contiene los datos recopilados del cuestionario, y el segundo es un vector numérico con respuestas correctas (esto solo se aplica al cuestionario de opción única). Alternativamente, puede agregar un tercer argumento que devolverá el vector numérico con puntaje final o data.frame con puntaje incrustado.
fscore <- function(x, sol, output = ''numeric'') {
if (ncol(x) != length(sol)) {
stop(''Number of items differs from length of correct answers!'')
} else {
inc <- matrix(ncol=ncol(x), nrow=nrow(x))
for (i in 1:ncol(x)) {
inc[,i] <- x[,i] == sol[i]
}
if (output == ''numeric'') {
res <- rowSums(inc)
} else if (output == ''data.frame'') {
res <- data.frame(x, result = rowSums(inc))
} else {
stop(''Type not supported!'')
}
}
return(res)
}
Trataré de hacer esto de una manera más elegante con alguna función * ply. Tenga en cuenta que no puse na.rm
argumento ... Haré eso
# create dummy data frame - values from 1 to 5
set.seed(100)
d <- as.data.frame(matrix(round(runif(200,1,5)), 10))
# create solution vector
sol <- round(runif(20, 1, 5))
Ahora aplica una función:
> fscore(d, sol)
[1] 6 4 2 4 4 3 3 6 2 6
Si pasa el argumento data.frame, devolverá data.frame modificado. Trataré de arreglar este ... ¡Espero que ayude!
Otra forma es
> length(z[z==TRUE])
[1] 498
Mientras que sum(z)
es bueno y corto, para mí la length(z[z==TRUE])
es más auto explicativo. Sin embargo, creo que con una tarea simple como esta no hace la diferencia ...
Si es un vector grande, probablemente debería ir con la solución más rápida, que es sum(z)
. length(z[z==TRUE])
es aproximadamente 10 veces más lenta y la table(z)[TRUE]
es aproximadamente 200 veces más lenta que sum(z)
.
En resumen, sum(z)
es el más rápido para escribir y ejecutar.
Otra opción es usar la función de resumen. Da un resumen de los Ts, Fs y NA.
> summary(hival)
Mode FALSE TRUE NA''s
logical 4367 53 2076
>
Otra opción que no se ha mencionado es usar which
:
length(which(z))
Solo para proporcionar un cierto contexto sobre la "pregunta que es más rápida", siempre es más fácil simplemente probarse a sí mismo. Hice el vector mucho más grande para la comparación:
z <- sample(c(TRUE,FALSE),1000000,rep=TRUE)
system.time(sum(z))
user system elapsed
0.03 0.00 0.03
system.time(length(z[z==TRUE]))
user system elapsed
0.75 0.07 0.83
system.time(length(which(z)))
user system elapsed
1.34 0.28 1.64
system.time(table(z)["TRUE"])
user system elapsed
10.62 0.52 11.19
Entonces, usar claramente sum
es el mejor enfoque en este caso. También es posible que desee comprobar los valores de NA
como sugirió Marek.
Solo para agregar una nota con respecto a los valores de NA y la función:
> which(c(T, F, NA, NULL, T, F))
[1] 1 4
> which(!c(T, F, NA, NULL, T, F))
[1] 2 5
Tenga en cuenta que solo verifica el TRUE
lógico, por lo que esencialmente ignora los valores no lógicos.
which
es una buena alternativa, especialmente cuando opera en matrices (verifique ?which
y observe el argumento arr.ind
). Pero sugiero que te na.rm
con la sum
, debido na.rm
argumento na.rm
que puede manejar NA
en el vector lógico. Por ejemplo:
# create dummy variable
set.seed(100)
x <- round(runif(100, 0, 1))
x <- x == 1
# create NA''s
x[seq(1, length(x), 7)] <- NA
Si escribe sum(x)
, obtendrá NA
como resultado, pero si pasa na.rm = TRUE
en la función sum
, obtendrá el resultado que desee.
> sum(x)
[1] NA
> sum(x, na.rm=TRUE)
[1] 43
¿Es su pregunta estrictamente teórica, o tiene algún problema práctico con respecto a los vectores lógicos?