2010-02-03 13 views

risposta

122

Ci sono alcuni problemi quando il vettore logico contiene valori NA.
Vedere per esempio:

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) 

Quindi penso cassaforte è

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

(che dà 1). Penso che la soluzione table sia meno efficiente (guarda il codice della funzione table).

Inoltre, si deve fare attenzione con la soluzione "tabella", nel caso in cui non ci siano valori VERO nel vettore logico. Supponiamo z <- c(NA, FALSE, NA) o semplicemente z <- c(FALSE, FALSE)

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

Un altro modo è

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

Mentre sum(z) è bello e breve, per me length(z[z==TRUE]) è più auto spiegare. Tuttavia, penso che con un semplice compito come questo non fa davvero la differenza ...

Se si tratta di un vettore di grandi dimensioni, probabilmente si dovrebbe andare con la soluzione più veloce, che è sum(z). length(z[z==TRUE]) è circa 10 volte più lento e table(z)[TRUE] è circa 200x più lento di sum(z).

Riassumendo, sum(z) è il più veloce da digitare e da eseguire.

71

Un'altra opzione che non è stato menzionato è quello di utilizzare which:

length(which(z)) 

solo per fornire effettivamente qualche contesto sul "che è questione più veloce", è sempre più facile solo per metterti alla prova. Ho fatto il vettore molto più grande per il confronto:

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 

Quindi, chiaramente usando sum è l'approccio migliore in questo caso. Potresti anche voler controllare i valori NA come suggerito da Marek.

Giusto per aggiungere una nota per quanto riguarda i valori di NA e la funzione which:

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

Nota ciò che controlla solo per logica TRUE, quindi ignora essenzialmente valori non-logici.

+0

A proposito, c'era un bel trucco con temporizzazione in Dirk risposta: http://stackoverflow.com/questions/1748590/revolution-for-r/1748932#1748932 – Marek

6

which è una buona alternativa, soprattutto quando si opera su matrici (controllare ?which e notare l'argomento arr.ind). Ma suggerisco di attenersi allo sum, a causa dell'argomento na.rm in grado di gestire il vettore logico NA. Per esempio:

# 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 

Se si digita sum(x) si otterrà NA come risultato, ma se si passa na.rm = TRUE in sum funzione, si otterrà il risultato che si desidera.

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

La tua domanda è strettamente teorica oppure hai qualche problema pratico relativo ai vettori logici?

+0

stavo cercando di grado un quiz. Fare qualcosa come somma (youranswer == rightanswer) all'interno di una domanda. –

+0

La mia risposta è troppo lunga, quindi ho inviato una nuova risposta, poiché differisce da quella precedente. – aL3xa

0

Ho fatto qualcosa di simile qualche settimana fa. Ecco una possibile soluzione, è scritta da zero, quindi è una sorta di beta-release o qualcosa del genere. Proverò a migliorarlo rimuovendo i loop dal codice ...

L'idea principale è scrivere una funzione che richiederà 2 (o 3) argomenti. Il primo è uno data.frame che contiene i dati raccolti dal questionario e il secondo è un vettore numerico con risposte corrette (applicabile solo per il questionario a scelta singola). In alternativa, è possibile aggiungere un terzo argomento che restituirà un vettore numerico con punteggio finale o data.frame con punteggio incorporato.

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

Cercherò di farlo in un modo più elegante con alcune funzioni * ply. Si noti che non ho messo na.rm argomento ... lo farà

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

Ora applicare una funzione:

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

Se si passa data.frame argomento, tornerà data.frame modificato. Proverò a sistemare questo ... Spero che aiuti!

+6

One-liner: 'rowSum (t (t (d) == sol), na.rm = TRUE)'. R ricicla il vettore per il confronto. Se il tuo 'd' era matrice con casi in colonne, allora si semplifica in' rowSums (d == sol, na.rm = TRUE) '. – Marek

0

Ho appena avuto un problema particolare in cui ho dovuto contare il numero di affermazioni vere da un vettore logico e questo ha funzionato meglio per me ...

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

Quindi questo richiede un sottoinsieme del gene .rep.matrix object e applica un test logico, restituendo un vettore logico. Questo vettore è messo come argomento per grep, che restituisce le posizioni di tutte le voci VERO. La lunghezza calcola quindi il numero di voci trovate da grep, fornendo così il numero di voci VERO.

4

Un'altra opzione è utilizzare la funzione di riepilogo. Fornisce un riassunto di Ts, Fs e NAs.

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

Inoltre, per ottenere solo i risultati "VERO" (che verrà emesso come una stringa, ma include anche "TRUE" nell'output): 'summary (hival) [" TRUE "]'; – michael

Problemi correlati