Как создать векторную последовательность вдоль элементов nonNA - PullRequest
0 голосов
/ 08 октября 2018

В R, учитывая вектор с некоторыми элементами как NA, как я могу рассчитывать, пропуская NA?Например:

let <- letters[1:10]
let[c(2,3,7,9)] <- NA

Как бы получить вектор?

1,NA,NA,2,3,4,NA,5,NA,6

Ответы [ 4 ]

0 голосов
/ 08 октября 2018

Это даст результат, который вы ищете, но не эффективен

let <- letters[1:10]
let[c(2,3,7,9)] <- NA

j = 0
for (i in 1:length(let)) {
  if(is.na(let[i]) == FALSE){
    j = j + 1
    let[i] <- j
    }
}
0 голосов
/ 08 октября 2018

Другой вариант, используя seq_along

let[!is.na(let)] <- seq_along(let[!is.na(let)])
as.numeric(let)
# [1]  1 NA NA  2  3  4 NA  5 NA  6

эталон

library(microbenchmark)

n <- 1e7
let_long <- seq_len(n)
set.seed(1)
let_long[sample(seq_len(n), size = 1e6)] <- NA

benchmark <- microbenchmark(
  Karolis = Karolis(let_long),
  Markus = Markus(let_long),
  Snoram = Snoram(let_long),
  Alexandra = Alexandra(let_long),
  Frank = Frank(let_long) # see comment under Snoram's answer
)

Чтобы получить приведенную ниже диаграмму, введите autoplot(benchmark).

enter image description here

#Unit: milliseconds
#      expr       min        lq      mean    median        uq       max neval
#   Karolis 1042.0708 1216.6241 1314.9765 1290.3428 1374.7090 1807.4604   100
#    Markus  210.3860  259.9957  310.0776  293.8244  363.4317  488.2171   100
#    Snoram  714.4514  938.5760 1033.6168 1029.8205 1104.5614 1546.3733   100
# Alexandra 4317.5206 4470.2634 4665.9004 4603.6446 4771.5768 6495.3595   100
#     Frank  103.3624  126.2842  166.7555  159.3568  190.5186  290.0422   100

Функции, сравниваемые до настоящего времени.

Karolis <- function(x) {
  match(seq_along(x), which(!is.na(x)))
}

Markus <- function(x) {
  x[!is.na(x)] <- seq_along(x[!is.na(x)])
  as.numeric(x)
}

Snoram <- function(x) {
  ifelse(is.na(x), NA, cumsum(!is.na(x)))
}

Alexandra <- function(x) {
  j = 0
  for (i in 1:length(x)) {
    if(is.na(x[i]) == FALSE){
      j = j + 1
      x[i] <- j
    }
  }
  as.numeric(x)
}

Frank <- function(x) {
  replace(cumsum(!is.na(x)), is.na(x), NA)
}
0 голосов
/ 08 октября 2018

Другие опции включают в себя:

Использование ifelse() и cumsum()

ifelse(is.na(let), NA, cumsum(!is.na(let)))
#[1]  1 NA NA  2  3  4 NA  5 NA  6
0 голосов
/ 08 октября 2018

Один из способов - сопоставить все индексы let с не-индексами:

> match(seq_along(let), which(!is.na(let)))
 [1]  1 NA NA  2  3  4 NA  5 NA  6
...