2010-02-03 9 views
117

In R, was ist der effizienteste/idiomatische Weg, um die Anzahl der TRUE Werte in einem logischen Vektor zu zählen? Ich kann mir zwei Möglichkeiten vorstellen:Wie TRUE-Werte in einem logischen Vektor zählen

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

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

Welche bevorzugen Sie? Gibt es etwas noch Besseres?

Antwort

122

Es gibt einige Probleme, wenn der logische Vektor NA Werte enthält.
Siehe zum Beispiel:

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) 

Ich denke also sicher ist

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

(das gibt 1). Ich denke, dass table Lösung weniger effizient ist (siehe Code der table Funktion).

Auch sollten Sie vorsichtig mit der "Tabelle" -Lösung sein, falls keine TRUE-Werte im logischen Vektor vorhanden sind. Angenommen z <- c(NA, FALSE, NA) oder einfach z <- c(FALSE, FALSE)

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

Ein anderer Weg ist

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

Während sum(z) schön kurz ist, für mich length(z[z==TRUE]) erklären, mehr Selbst ist. Obwohl ich denke, mit einer einfachen Aufgabe wie dieser macht es keinen wirklichen Unterschied ...

Wenn es ein großer Vektor ist, sollten Sie wahrscheinlich mit der schnellsten Lösung gehen, die sum(z) ist. length(z[z==TRUE]) ist etwa 10x langsamer und table(z)[TRUE] ist etwa 200x langsamer als sum(z).

Zusammenfassend ist sum(z) der schnellste zu tippen und auszuführen.

71

Eine weitere Option, die which erwähnt wird nicht zu benutzen ist: tatsächlich etwas Kontext

length(which(z)) 

einfach zur Verfügung zu stellen auf dem „die schnellere Frage ist“, es ist immer am einfachsten nur um dich selbst zu testen. Ich machte den Vektor viel größer zum Vergleich:

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 

So klar mit sum der beste Ansatz ist in diesem Fall. Sie können auch nach NA Werten suchen, wie Marek vorgeschlagen hat.

einfach eine Anmerkung in Bezug auf NA-Werten und die which Funktion hinzuzufügen:

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

Beachten Sie, dass die nur prüfen, ob logische TRUE, so dass es im Wesentlichen nicht-logische Werte ignoriert.

+0

BTW, war es ein schöner Trick mit dem Timing in Dirk Antwort: http://stackoverflow.com/questions/1748590/revolution-for-r/1748932#1748932 – Marek

6

which ist eine gute Alternative, besonders wenn Sie mit Matrizen arbeiten Aber ich schlage vor, dass Sie mit sum bleiben, wegen na.rm Argument, das im logischen Vektor behandeln kann. Zum Beispiel:

# 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 

Wenn Sie in sum(x) geben werden Sie NA als Ergebnis erhalten, aber wenn Sie na.rm = TRUE in sum Funktion übergeben, werden Sie das Ergebnis erhalten, die Sie wollen.

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

Ist Ihre Frage streng theoretisch, oder Sie haben einige praktische Problem in Bezug auf logische Vektoren?

+0

Ich war ein Quiz Klasse versuchen. Etwas wie sum (youranswer == rightanswer) innerhalb eines Antrags tun. –

+0

Meine Antwort ist einfach zu lang, so gab ich eine neue Antwort, da sie von früheren unterscheidet. – aL3xa

0

Ich habe vor ein paar Wochen etwas ähnliches getan. Hier ist eine mögliche Lösung, es wurde von Grund auf neu geschrieben, also ist es eine Art Beta-Release oder so ähnlich. Ich werde versuchen, es zu verbessern, indem Schleifen von Code ...

Die Hauptidee zu schreiben, ist eine Funktion zu entfernen, die 2 (oder 3) Argumente nehmen. Die erste ist eine data.frame, die die Daten aus dem Fragebogen enthält, und die zweite ist ein numerischer Vektor mit korrekten Antworten (dies gilt nur für Single-Choice-Fragebogen). Alternativ können Sie ein drittes Argument hinzufügen, das den numerischen Vektor mit dem Endergebnis oder data.frame mit eingebettetem Ergebnis zurückgibt.

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

Ich werde versuchen, dies auf eine elegantere Weise mit etwas * ply-Funktion zu tun. Beachten Sie, dass ich nicht na.rm Argument habe setzen ... Mach ich, dass

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

nun eine Funktion anwenden:

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

Wenn Sie data.frame Argument übergeben, wird es geändert data.frame zurück. Ich werde versuchen, dieses zu beheben ... Hoffe es hilft!

+6

Einzeiler: 'rowSums (t (t (d) == sol), na.rm = TRUE)'. R recycle-Vektor zum Vergleich. Wenn Ihr 'd' waren Matrix mit Fällen, in Spalten dann seine Vereinfacht zu 'rowSums (d == sol, na.rm = TRUE)'. – Marek

0

Ich hatte gerade ein besonderes Problem, wenn ich die Anzahl der wahren Aussagen von einem logischen Vektor zählen musste, und dies war für mich am besten ...

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

So Dies dauert eine Teilmenge des Gens .rep.matrix-Objekt und wendet einen logischen Test an und gibt einen logischen Vektor zurück. Dieser Vektor wird als Argument an grep übergeben, das die Positionen aller TRUE-Einträge zurückgibt. Length berechnet dann, wie viele Einträge grep findet und gibt dabei die Anzahl der TRUE-Einträge an.

4

Eine weitere Option ist die Verwendung der Zusammenfassungsfunktion. Es gibt eine Zusammenfassung der Ts, Fs und NAs.

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

Ferner erhält nur die "TRUE" Ergebnisse (die Ausgabe als String sein, aber auch "TRUE" in der Ausgabe): 'Zusammenfassung (hival) [ "TRUE"]'; – michael

Verwandte Themen