Обратная из которых - PullRequest
       56

Обратная из которых

11 голосов
/ 05 октября 2011

Я что-то упускаю здесь очевидное?Похоже, что обратная функция which отсутствует в базе R (поиск в Google и даже поиск SO для "R inverse, который" возвращает множество несвязанных ссылок)?

Ну, не то, что я не могунапиши один, но только для того, чтобы облегчить мое разочарование по поводу его отсутствия и проблемы сгибания мышц R: как бы ты это написал?

Нам нужна такая функция, как:

invwhich<-function(indices, totlength)

, который возвращает логический вектор длины totlength, где каждый элемент в indices равен TRUE, а остальные - FALSE.

Там должно быть много способов сделать это (некоторые из которых являются очень низко висящими фруктами), так что спорьте, почему ваше решение «лучшее».Кто-нибудь еще?

Если он учитывает некоторые другие параметры which (arr.ind ??), это, очевидно, даже лучше ...

Ответы [ 5 ]

10 голосов
/ 05 октября 2011

Однострочное решение:

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
5 голосов
/ 05 октября 2011

Мое собственное решение (пока): РЕДАКТИРОВАТЬ согласно предложению @ 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)
}

Он работает очень хорошо (по-видимому, лучше, чем oneliner @ Andrie) и, насколько это возможно, учитывает useNames. Но возможно ли превратить это в единый лайнер?

по производительности, я просто использую:

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

в качестве очень эффективного измерения производительности.

1 голос
/ 28 октября 2011

Другой вариант, чтобы сделать вкладыш:

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

Я бы предпочел разные имена, для краткости:

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

Или, используя пакет bit:

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

Удивительно, но это кажется медленным. Оказывается, что код использует rep в некоторых местах. (

Это работа для Rcpp или compile! :)

0 голосов
/ 13 марта 2017
setdiff(1:total_length, indices)
0 голосов
/ 29 июня 2015

Overkill версия, работающая со всеми видами индексов:

#' 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
}
...