2010-02-03 6 views

Répondre

122

Il existe certains problèmes lorsque le vecteur logique contient des 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) 

Je pense donc que la sécurité est

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

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

En outre, vous devez faire attention avec la solution "table", dans le cas où il n'y a pas de valeurs TRUE dans le vecteur logique. Supposons z <- c(NA, FALSE, NA) ou simplement z <- c(FALSE, FALSE)

table(z)["TRUE"] # gives you NA for both cases. 
10

Une autre façon est

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

Alors que sum(z) est agréable et courte, pour moi length(z[z==TRUE]) est plus auto expliquer. Bien, je pense avec une tâche simple comme ceci cela ne fait pas vraiment une différence ...

Si c'est un grand vecteur, vous devriez probablement aller avec la solution la plus rapide, qui est sum(z). length(z[z==TRUE]) est environ 10x plus lent et table(z)[TRUE] est environ 200x plus lent que sum(z). Pour résumer, sum(z) est le plus rapide à taper et à exécuter.

71

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

length(which(z)) 

Juste pour fournir effectivement un contexte sur le « qui est plus rapide question », il est toujours plus facile juste pour te 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 

Donc, en utilisant clairement sum est la meilleure approche dans ce cas. Vous pouvez également vérifier les valeurs NA comme Marek l'a suggéré.

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

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

Notez que qui vérifie uniquement TRUE logique, il ne tient pas compte essentiellement des valeurs non logiques.

+0

BTW, il y avait un truc sympa avec un timing en réponse Dirk: http://stackoverflow.com/questions/1748590/revolution-for-r/1748932#1748932 – Marek

6

which est une bonne alternative, en particulier lorsque vous opérez sur des matrices (vérifiez ?which et notez l'argument arr.ind). Mais je suggère que vous restiez avec sum, en raison de na.rm argument qui peut gérer NA dans le 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 en conséquence, mais si vous passez na.rm = TRUE en fonction sum, vous obtiendrez le résultat que vous voulez. Votre question est-elle strictement théorique ou vous avez un problème pratique concernant les vecteurs logiques?

+0

je tentais de qualité d'un jeu-questionnaire. Faire quelque chose comme la somme (youranswer == rightanswer) dans une application. –

+0

Ma réponse est trop longue, j'ai donc posté une nouvelle réponse, car elle diffère de la précédente. – aL3xa

0

J'ai fait quelque chose de similaire il y a quelques semaines. Voici une solution possible, c'est écrit à partir de zéro, donc c'est 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 n'est applicable que pour un questionnaire à choix unique). Alternativement, vous pouvez ajouter un troisième argument qui retournera un vecteur numérique avec un score final, ou un fichier data.frame avec un score incorporé.

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 le faire d'une manière plus élégante avec une fonction * ply. Notez que je ne l'ai pas mis na.rm l'argument ... Est-ce que faire

# 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 data.frame argument, il retournera data.frame modifié. Je vais essayer de réparer celui-ci ... J'espère que ça aide!

+6

One-liner: 'rowSums (t (t (d) == sol), na.rm = TRUE)'. R recycler le vecteur pour comparaison. Si votre 'd' était une matrice avec des cas dans des colonnes, alors il simplifie' rowSums (d == sol, na.rm = TRUE) '. – Marek

0

Je viens d'avoir un problème particulier où je devais compter le nombre de véritables déclarations d'un vecteur logique et cela a fonctionné mieux pour moi ...

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

donc Cela prend un sous-ensemble du gène objet .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. La longueur calcule ensuite le nombre d'entrées trouvées par grep, donnant ainsi le nombre d'entrées VRAIES.

4

Une autre option consiste à utiliser la fonction de résumé. Il donne un résumé des Ts, F et NA.

> summary(hival) 
    Mode FALSE TRUE NA's 
logical 4367  53 2076 
> 
+1

En outre, pour obtenir uniquement les résultats "TRUE" (qui seront affichés sous la forme d'une chaîne, mais qui inclut également "TRUE" en sortie): 'summary (hival) [" TRUE "]'; – michael

Questions connexes