Jak liczyć wartości TRUE w wektorze logicznym


160

Jaki jest najbardziej efektywny / idiomatyczny sposób obliczania liczby TRUEwartości w wektorze logicznym w języku R ? Przychodzą mi do głowy dwa sposoby:

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

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

Który wolisz? Czy jest coś jeszcze lepszego?

Odpowiedzi:


174

Istnieją pewne problemy, gdy wektor logiczny zawiera NAwartości.
Zobacz na przykład:

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)

Myślę więc, że najbezpieczniej jest użyć na.rm = TRUE:

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

(co daje 1). Myślę, że to tablerozwiązanie jest mniej wydajne (spójrz na kod tablefunkcji).

Należy również zachować ostrożność przy rozwiązaniu „tabelowym”, na wypadek gdyby w wektorze logicznym nie było wartości TRUE. Załóżmy z <- c(NA, FALSE, NA)lub po prostu z <- c(FALSE, FALSE), a następnie table(z)["TRUE"]podaje NAdla obu przypadków.


table(c(FALSE))["TRUE"]daje NA, a nie 0.
Yossi Farjoun

@YossiFarjoun Tak, i to jest w mojej odpowiedzi. Oto przykłady, dlaczego to nie zadziała. Moje rozwiązanie tosum(z, na.rm = TRUE)
Marek

84

Inną opcją, o której nie wspomniano, jest użycie which:

length(which(z))

Aby rzeczywiście podać kontekst na pytanie „które jest szybsze”, zawsze najłatwiej jest po prostu sprawdzić siebie. Zrobiłem wektor znacznie większy dla porównania:

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 

Dlatego sumw tym przypadku najlepszym podejściem jest użycie . Możesz także chcieć sprawdzić NAwartości, jak zasugerował Marek.

Wystarczy dodać uwagę dotyczącą wartości NA i whichfunkcji:

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

Zwróć uwagę, że sprawdza tylko logikę TRUE, więc zasadniczo ignoruje wartości nielogiczne.


Przy okazji, była niezła sztuczka z synchronizacją w odpowiedzi Dirka: stackoverflow.com/questions/1748590/revolution-for-r/…
Marek

12

Innym sposobem jest

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

Chociaż sum(z) jest ładne i krótkie, dla mnie length(z[z==TRUE])jest bardziej zrozumiałe. Chociaż myślę, że w przypadku prostego zadania takiego jak to nie ma to większego znaczenia ...

Jeśli jest to duży wektor, prawdopodobnie powinieneś wybrać najszybsze rozwiązanie, czyli sum(z). length(z[z==TRUE])jest około 10x wolniejszy i table(z)[TRUE]około 200x wolniejszy niż sum(z).

Podsumowując, sum(z)jest najszybszy do wpisania i wykonania.


6

whichjest dobrą alternatywą, zwłaszcza gdy operujesz na macierzach (sprawdź ?whichi zwróć uwagę na arr.indargument). Ale proponuję, żebyś się trzymał sum, ponieważ na.rmargument, który może obsłużyć NAw wektorze logicznym. Na przykład:

# 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

Jeśli wpiszesz sum(x)dostaniesz NAwyniku, ale jeśli przejdzie na.rm = TRUEw sumfunkcję, otrzymasz wynik, który chcesz.

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

Czy twoje pytanie jest stricte teoretyczne, czy też masz jakiś praktyczny problem dotyczący wektorów logicznych?


Próbowałem ocenić quiz. Wykonanie czegoś takiego jak suma (youranswer == rightanswer) w zgłoszeniu.
Jyotirmoy Bhattacharya

Moja odpowiedź jest po prostu za długa, więc zamieściłem nową odpowiedź, ponieważ różni się od poprzedniej.
aL3xa

6

Inną opcją jest użycie funkcji podsumowującej. Zawiera podsumowanie Ts, F i NA.

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

1
Ponadto, aby otrzymać tylko wyniki „PRAWDA” (które zostaną wyprowadzone jako łańcuch, ale zawierają również wyniki „PRAWDA”) summary(hival)["TRUE"]:;
michael

0

Robiłem coś podobnego kilka tygodni temu. Oto możliwe rozwiązanie, zostało napisane od zera, więc jest to wersja beta lub coś w tym rodzaju. Spróbuję to poprawić, usuwając pętle z kodu ...

Głównym pomysłem jest napisanie funkcji, która będzie pobierać 2 (lub 3) argumenty. Pierwsza to, data.framektóra przechowuje dane zebrane z kwestionariusza, a druga to wektor numeryczny z poprawnymi odpowiedziami (dotyczy to tylko kwestionariusza jednokrotnego wyboru). Alternatywnie możesz dodać trzeci argument, który zwróci wektor numeryczny z wynikiem końcowym lub data.frame z osadzonym wynikiem.

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

Postaram się zrobić to w bardziej elegancki sposób z jakąś funkcją * ply. Zauważ, że nie na.rmargumentowałem ... Zrobię to

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

Teraz zastosuj funkcję:

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

Jeśli przekażesz argument data.frame, zwróci on zmodyfikowany data.frame. Spróbuję to naprawić ... Mam nadzieję, że to pomoże!


6
One-liner: rowSums(t(t(d)==sol), na.rm=TRUE). Wektor recyklingu R. dla porównania. Jeśli macie dmacierz z przypadkami w kolumnach, to upraszcza się do rowSums(d==sol, na.rm=TRUE).
Marek

0

Właśnie miałem szczególny problem, w którym musiałem policzyć liczbę prawdziwych stwierdzeń z wektora logicznego i to działało najlepiej dla mnie ...

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

Więc to bierze podzbiór obiektu gene.rep.matrix i stosuje test logiczny, zwracając wektor logiczny. Ten wektor jest wstawiany jako argument dla grep, który zwraca lokalizacje wszystkich wpisów TRUE. Length następnie oblicza liczbę wpisów znalezionych przez grep, podając w ten sposób liczbę PRAWDA.


0

Istnieje również pakiet o nazwie, bitktóry jest specjalnie zaprojektowany do szybkich operacji logicznych. Jest to szczególnie przydatne, jeśli masz duże wektory lub musisz wykonać wiele operacji logicznych.

z <- sample(c(TRUE, FALSE), 1e8, rep = TRUE)

system.time({
  sum(z) # 0.170s
})

system.time({
  bit::sum.bit(z) # 0.021s, ~10x improvement in speed
})
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.