Как считать ИСТИННЫЕ значения в логическом векторе


160

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

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

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

Какой ты предпочитаешь? Есть ли что-нибудь еще лучше?

Ответы:


174

Есть некоторые проблемы, когда логический вектор содержит 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для обоих случаев.


table(c(FALSE))["TRUE"]дает NA, а не 0.
Йосси Фарджун

@YossiFarjoun Да, и это в моем ответе. Это примеры, почему это не сработает. Мое решениеsum(z, na.rm = TRUE)
Марек

84

Другой вариант, который не был упомянут, это использовать 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, поэтому он по существу игнорирует нелогические значения.


Кстати, в ответе Дирка был хороший трюк с выбором времени: stackoverflow.com/questions/1748590/revolution-for-r/…
Марек

12

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

> 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

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

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


Я пытался оценить викторину. Делать что-то вроде суммы (youranswer == rightanswer) в заявке.
Джотирмой Бхаттачарья

Мой ответ слишком длинный, поэтому я отправил новый ответ, поскольку он отличается от предыдущего.
aL3xa

6

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

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

1
Далее, чтобы получить только результаты «ИСТИНА» (которые будут выводиться в виде строки, но также будут содержать «ИСТИНА» в выводе) summary(hival)["TRUE"]:;
Майкл

0

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

Основная идея - написать функцию, которая будет принимать 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. Я постараюсь исправить это ... Надеюсь, это поможет!


6
Однострочник: rowSums(t(t(d)==sol), na.rm=TRUE). R recycle вектор для сравнения. Если вы dбыли матрица со случаями в столбцах, то это упрощает до rowSums(d==sol, na.rm=TRUE).
Марек

0

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

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

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


0

Также есть пакет, bitкоторый специально разработан для быстрых логических операций. Это особенно полезно, если у вас большие векторы или вам нужно много логических операций.

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
})
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.