Як порахувати ІСТИЧНІ значення в логічному векторі


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"]дає НА, а не 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/…
Marek

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) у програмі.
Jyotirmoy Bhattacharya

Моя відповідь занадто довга, тому я опублікував нову відповідь, оскільки вона відрізняється від попередньої.
aL3xa

6

Інший варіант - використовувати підсумкову функцію. У ньому подано звіт про ЦЗ, ФС та НС.

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

1
Далі, щоб отримати лише результати "TRUE" (які будуть виводитись як рядок, але також включати "TRUE" у висновку) 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 переробляти вектор для порівняння Якщо у вас dбула матриця зі справами в стовпцях, тоді її спрощується до rowSums(d==sol, na.rm=TRUE).
Марек

0

У мене щойно була особлива проблема, коли мені довелося порахувати кількість правдивих тверджень з логічного вектора, і це найкраще працювало для мене ...

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

Отже, це займає підмножину об'єкта gene.rep.matrix і застосовує логічний тест, повертаючи логічний вектор. Цей вектор ставиться як аргумент grep, який повертає місця будь-яких істинних записів. Далі довжина обчислює кількість записів греп-значень, надаючи таким чином кількість істинних записів.


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.