Как считать ИСТИННЫЕ значения в логическом векторе - PullRequest
145 голосов
/ 03 февраля 2010

В R, какой самый эффективный / идиоматический способ подсчета количества TRUE значений в логическом векторе? Я могу придумать два пути:

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

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

Что вы предпочитаете? Что-нибудь еще лучше?

Ответы [ 7 ]

156 голосов
/ 03 февраля 2010

Существуют некоторые проблемы, когда логический вектор содержит NA значений.
См. Например:

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)

Поэтому я думаю, что наиболее безопасным является использование na.rm = TRUE:

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

(что дает 1). Я думаю, что решение table менее эффективно (посмотрите на код функции table).

Кроме того, вы должны быть осторожны с решением «таблица», если в логическом векторе нет значений ИСТИНА. Предположим, что z <- c(NA, FALSE, NA) или просто z <- c(FALSE, FALSE), тогда table(z)["TRUE"] даст вам NA для обоих случаев.

81 голосов
/ 03 февраля 2010

Другой вариант, который не был упомянут, - это использовать which:

length(which(z))

Просто для того, чтобы на самом деле предоставить некоторый контекст для «вопроса, который быстрее», всегда проще всего проверить себя.Я сделал для сравнения вектор намного больше:

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 

Так что использование sum в данном случае - лучший подход.Вы также можете проверить значения NA, как предложил Марек.

Просто добавьте примечание, касающееся значений NA и функции which:

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

Обратите внимание, что проверяет толькодля логического TRUE, поэтому он по существу игнорирует нелогические значения.

11 голосов
/ 03 февраля 2010

Другой способ -

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

Хотя sum(z) приятно и коротко, для меня length(z[z==TRUE]) более самоочевидно. Хотя, я думаю, что с такой простой задачей это не имеет большого значения ...

Если это большой вектор, вам, вероятно, следует выбрать самое быстрое решение, а именно sum(z). length(z[z==TRUE]) примерно в 10 раз медленнее, а table(z)[TRUE] примерно в 200 раз медленнее, чем sum(z).

Подводя итог, sum(z) является самым быстрым для ввода и выполнения.

6 голосов
/ 05 февраля 2010

which - хорошая альтернатива, особенно когда вы работаете с матрицами (отметьте ?which и обратите внимание на аргумент arr.ind). Но я предлагаю придерживаться sum из-за аргумента na.rm, который может обрабатывать NA в логическом векторе. Например:

# 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

Если вы введете sum(x), вы получите NA в результате, но если вы передадите na.rm = TRUE в функции sum, вы получите желаемый результат.

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

Ваш вопрос носит чисто теоретический характер, или у вас есть практическая проблема с логическими векторами?

5 голосов
/ 10 мая 2015

Другой вариант - использовать функцию сводки. Это дает краткое изложение Ts, Fs и NA.

> summary(hival)
   Mode   FALSE    TRUE    NA's 
logical    4367      53    2076 
> 
0 голосов
/ 09 мая 2014

У меня только что была особая проблема, когда мне приходилось подсчитывать количество истинных утверждений по логическому вектору, и это работало лучше всего для меня ...

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

Итак, он берет подмножество объекта gene.rep.matrix и применяет логический тест, возвращая логический вектор. Этот вектор помещается в качестве аргумента в grep, который возвращает расположение любых ИСТИННЫХ записей. Затем Length вычисляет, сколько записей находит grep, и, таким образом, дает количество TRUE записей.

0 голосов
/ 05 февраля 2010

Я делал нечто похожее несколько недель назад. Вот возможное решение, оно написано с нуля, так что это своего рода бета-релиз или что-то в этом роде. Я постараюсь улучшить его, удалив из кода циклы ...

Основная идея - написать функцию, которая будет принимать 2 (или 3) аргумента. Первый - data.frame, который содержит данные, собранные из вопросника, а второй - числовой вектор с правильными ответами (это применимо только для вопросника с одним выбором). Кроме того, вы можете добавить третий аргумент, который будет возвращать числовой вектор с окончательной оценкой, или data.frame со встроенной оценкой.

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

Я попытаюсь сделать это более элегантно с помощью некоторой функции * ply. Обратите внимание, что я не поставил na.rm аргумент ... Сделаю это

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

Теперь примените функцию:

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

Если вы передадите аргумент data.frame, он вернет измененный data.frame. Я постараюсь исправить это ... Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...