web-dev-qa-db-fra.com

Comment compter les valeurs TRUE dans un vecteur logique

Dans R, quel est le moyen le plus efficace/idiomatique de compter le nombre de valeurs TRUE dans un vecteur logique? Je peux penser de deux manières:

z <- sample(c(TRUE, FALSE), 1000, rep = TRUE)
sum(z)
# [1] 498

table(z)["TRUE"]
# TRUE 
#  498 

Lequel préfères-tu? Y a-t-il encore mieux?

147

Il existe certains problèmes lorsque le vecteur logique contient les valeurs NA.
Voir par exemple:

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)

Donc, je pense que le plus sûr est d'utiliser na.rm = TRUE:

sum(z, na.rm = TRUE) # best way to count TRUE values

(ce qui donne 1). Je pense que la solution table est moins efficace (regardez le code de la fonction table.).

De plus, vous devriez faire attention avec la solution "table", au cas où il n'y aurait pas de valeur TRUE dans le vecteur logique. Supposons que z <- c(NA, FALSE, NA) ou simplement z <- c(FALSE, FALSE), puis table(z)["TRUE"] vous donne NA dans les deux cas.

158
Marek

Une autre option qui n’a pas été mentionnée est d’utiliser which:

length(which(z))

Juste pour fournir un contexte à la question "qui est plus rapide", il est toujours plus facile de se tester. J'ai fait le vecteur beaucoup plus grand pour la comparaison:

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 

Si clairement utiliser sum est la meilleure approche dans ce cas. Vous pouvez également vouloir vérifier les valeurs de NA comme suggéré par Marek.

Juste pour ajouter une note concernant les valeurs NA et la fonction which:

> which(c(T, F, NA, NULL, T, F))
[1] 1 4
> which(!c(T, F, NA, NULL, T, F))
[1] 2 5

Notez ce qui ne vérifie que la logique TRUE, donc il ignore essentiellement les valeurs non logiques.

83
Shane

Une autre façon est

> length(z[z==TRUE])
[1] 498

Alors que sum(z) est agréable et court, pour moi length(z[z==TRUE]) est plus explicite. Cependant, je pense qu'avec une tâche aussi simple, cela ne fait pas vraiment la différence ...

S'il s'agit d'un grand vecteur, vous devriez probablement utiliser la solution la plus rapide, sum(z). length(z[z==TRUE]) est environ 10x plus lent et table(z)[TRUE] est environ 200x plus lent que sum(z).

En résumé, sum(z) est le plus rapide à taper et à exécuter.

11
f3lix

Une autre option consiste à utiliser la fonction de résumé. Il résume les Ts, les F et les NA.

> summary(hival)
   Mode   FALSE    TRUE    NA's 
logical    4367      53    2076 
> 
6
ramrad

which est une bonne alternative, en particulier lorsque vous utilisez des matrices (vérifiez ?which et notez l'argument arr.ind.). Mais je vous suggère de vous en tenir à sum, en raison de l'argument de na.rm pouvant gérer les NA en vecteur logique. Par exemple:

# 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 vous tapez sum(x), vous obtiendrez NA, mais si vous passez na.rm = TRUE à la fonction sum, vous obtiendrez le résultat souhaité.

> sum(x)
[1] NA
> sum(x, na.rm=TRUE)
[1] 43

Votre question est-elle strictement théorique ou avez-vous un problème pratique concernant les vecteurs logiques?

6
aL3xa

J'ai fait quelque chose de similaire il y a quelques semaines. Voici une solution possible, écrite à partir de rien, donc une sorte de version bêta ou quelque chose comme ça. Je vais essayer de l'améliorer en supprimant les boucles du code ...

L'idée principale est d'écrire une fonction qui prendra 2 (ou 3) arguments. Le premier est un data.frame qui contient les données recueillies à partir du questionnaire, et le second est un vecteur numérique avec des réponses correctes (ceci ne s'applique que pour le questionnaire à choix unique). Vous pouvez également ajouter un troisième argument renvoyant un vecteur numérique avec le score final ou data.frame avec un score intégré.

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)
}

Je vais essayer de faire cela d'une manière plus élégante avec une fonction * ply. Notez que je n'ai pas mis l'argument na.rm ... le fera

# 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))

Maintenant, appliquez une fonction:

> fscore(d, sol)
 [1] 6 4 2 4 4 3 3 6 2 6

Si vous passez l'argument data.frame, il retournera data.frame modifié. Je vais essayer de réparer celui-ci ... J'espère que ça aide!

0
aL3xa

Je viens d'avoir un problème particulier où je devais compter le nombre d'énoncés vrais à partir d'un vecteur logique et cela fonctionnait mieux pour moi ...

length(grep(TRUE, (gene.rep.matrix[i,1:6] > 1))) > 5

Donc, cela prend un sous-ensemble de l'objet gene.rep.matrix et applique un test logique, renvoyant un vecteur logique. Ce vecteur est mis en argument de grep, qui renvoie les emplacements de toutes les entrées TRUE. Longueur calcule ensuite le nombre d'entrées trouvées par grep, donnant ainsi le nombre d'entrées VRAIES.

0
A_Skelton73