2011-10-05 8 views
9

Mi manca qualcosa di ovvio qui? Sembra che la funzione inversa di which manchi dalla base R (googling e anche una ricerca su SO per "R inversa che" restituisce una miriade di collegamenti non correlati)?Inversa del quale

Beh, non che io non possa scriverne uno, ma solo per alleviare la mia frustrazione per il fatto che manchi e come una sfida di flessione dei muscoli R: come andresti a scriverne uno?

Ciò di cui abbiamo bisogno è una funzione come:

invwhich<-function(indices, totlength) 

che restituisce un vettore logica di lunghezza totlength dove ogni elemento in indices è TRUE e il resto è FALSE.

Ci sono molti modi per ottenere questo risultato (alcuni dei quali sono molto bassi), quindi spiegate perché la vostra soluzione è "migliore". Oneliner qualcuno?

Se si prende in considerazione alcuni degli altri parametri di which (arr.ind ??), che è, ovviamente, ancora meglio ...

+0

io non sono sicuro che questo è l'inverso del ' which'. È come dire che fare una torta è l'inverso di mangiarne uno. Non è possibile avere un inverso perché 'which' fornisce solo indici di un vettore e non è possibile conoscere la lunghezza del vettore dal risultato. Pertanto, nessuna funzione 'invwhich' in R. – John

risposta

7

soluzione One-liner:

invwhich <- function(indices, totlength) is.element(seq_len(totlength), indices) 

invwhich(c(2,5), 10) 
[1] FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE 
+0

+1 per oneliner.Un po 'alla mia sorpresa, le prestazioni non sono poi così buone (anche se diventano evidenti solo per i grandi vettori e molte ripetizioni). –

+2

Dimostra piuttosto efficacemente che le one-liner non sono sempre la soluzione "migliore". – Andrie

+1

'is.element' è identico a'% in% 'quindi l'alternativa è' seq_len (totlength)% in% indici'. – Marek

5

la mia soluzione (per ora): MODIFICA come da suggerimento di @ Marek.

invwhich<-function(indices, outlength, useNames = TRUE) 
{ 
    rv<-logical(outlength) 
    #rv<-rep(FALSE, outlength) #see Marek's comment 
    if(length(indices) > 0) 
    { 
     rv[indices]<-TRUE 
     if(useNames) names(rv)[indices]<-names(indices) 
    } 
    return(rv) 
} 

Svolge molto bene (a quanto pare meglio di @ oneliner di Andrie) e, in quanto possibile, rappresenta usenames. Ma è possibile renderlo un oneliner?

prestazioni WRT, ho semplicemente usare:

someindices<-sample(1000000, 500000, replace=FALSE) 
system.time(replicate(100, tmp<-invwhich(someindices, 1000000))) 

come misurazione delle prestazioni molto lo-fi.

+1

Puoi accelerarlo di 5x sostituendo 'rep (FALSE, outlength)' a 'logical (outlength)'. – Marek

+0

Oppure sostituire 'rep' di' rep.int'. – Marek

+0

Questo sarebbe l'oneliner: 'invwhich <- function (i, len) '[<-' (logical (len), i, T)'. O con useNames (ma chi ne avrà bisogno?): 'Invwhich <- function (i, len, useNames = TRUE) setNames ('[<-' (logico (len), i, T), if (useNames) nomi (i) else NULL) ' –

1

Un'altra variante, per fare un oneliner:

lWhich <- function(indices, totlength, vec = vector(length = totlength)){vec[indices] <- TRUE; return(vec)} 

Preferirei nomi diversi, per brevità:

lWhich <- function(ix, len, vec = vector(length = len)){vec[ix] <- TRUE; return(vec)} 

Oppure, utilizzando il pacchetto bit:

lWhichBit <- function(ix, len){return(as.logical(bitwhich(len, x = ix, poslength = length(ix))))} 

Sorprendentemente, sembra lento. Risulta che il codice utilizza rep in alcuni posti. :(

Questo è un lavoro per Rcpp o compile :)

+0

Utilizzo di"; " equivale a non avere un oneliner ... Comunque, ti rimborserò un +1 per lo sforzo (e se avrò il tempo, farò qualche profilazione e ti faccio sapere come è andata) –

+0

Ah sì, è vero ; non vola su di te :) Era tardi, cosa posso dire ... Ho provato a fare un incarico all'interno del ritorno, ma è stato complicato. – Iterator

0

versione Overkill a lavorare con tutti i tipi di indici:!

#' Logical which 
#' 
#' Inverse of \link[base]{which}. 
#' Converts an array of any indices to a logical index array. 
#' 
#' Either \code{nms} or \code{len} has to be specified. 
#' 
#' @param idx  Numeric or character indices. 
#' @param nms  Array of names or a sequence. 
#'     Required if \code{idx} is a character array 
#' @param len  Length of output array. 
#'     Alternative to \code{nms} if \code{idx} is numeric 
#' @param useNames Use the names of nms or idx 
#' 
#' @examples 
#' all(lWhich(2, len = 3) == c(F, T, F)) 
#' all(lWhich(c('a', 'c'), letters[1:3]) == c(T, F, T)) 
#' 
#' @export 
lWhich <- function(idx, nms = seq_len(len), len = length(nms), useNames = TRUE) { 
    rv <- logical(len) 
    if (is.character(nms)) # we need names here so that rv[idx] works 
     names(rv) <- nms 

    if (useNames && !is.null(names(idx))) 
     names(rv)[idx] <- names(idx) 

    rv[idx] <- TRUE 

    if (!useNames) # if we don’t want names, we’ll remove them again 
     names(rv) <- NULL 
    rv 
} 
0
setdiff(1:total_length, indices) 
+2

Questo non è il significato di "inverso" usato qui. La domanda è di passare da un vettore di numeri a un vettore di valori vero/falso, cioè, che cosa "fa", ma nella direzione opposta. –