Определить множества NA в векторе - PullRequest
0 голосов
/ 19 февраля 2019

Допустим, у меня есть вектор x:

x <- c(NA, NA, 1, 2, NA, NA, 3, 4)

Как мне определить наборы NA внутри этого вектора, т. Е.

na_set <- c(1, 1, 0, 0, 2, 2, 0, 0)

Моя конечная цель состоит в том, чтобыиспользуйте его с каналом на фрейме данных, используя dplyr.Так что, если есть функция, совместимая с dplyr, это еще лучше.

Спасибо!

Ответы [ 3 ]

0 голосов
/ 19 февраля 2019

Вычислить кодировку длины серии is.na (x) и заменить значения порядковыми номерами или 0. Затем инвертировать обратно.

r <- rle(is.na(x))
r$values <- cumsum(r$values) * r$values
inverse.rle(r)
## [1] 1 1 0 0 2 2 0 0
0 голосов
/ 19 февраля 2019

Если точный ранг наборов не имеет значения, вы можете использовать удобную функцию rleid() из data.table:

rleid(x) * is.na(x)

[1] 1 1 0 0 4 4 0 0

Для сравнения скорости:

library(microbenchmark)

x <- rep(x, 1e5)
microbenchmark(
 IceCreamToucan = cumsum(diff(is.na(c(1, x))) == 1)*is.na(x),
 tmfmnk = rleid(x) * is.na(x),
 G._Grothendieck = {r <- rle(is.na(x))
 r$values <- cumsum(r$values) * r$values
 inverse.rle(r)},
 times = 5
)

Unit: milliseconds
            expr       min       lq     mean   median       uq      max neval cld
  IceCreamToucan 48.607317 52.49508 66.64196 74.63182 76.81896 80.65662     5   b
          tmfmnk  9.952486 12.58168 20.22834 14.38625 16.23961 47.98166     5  a 
 G._Grothendieck 53.533149 57.48818 59.12514 59.73295 62.14772 62.72371     5   b
0 голосов
/ 19 февраля 2019

Вы можете взять diff из is.na(x).Это будет 1 IFF элемент TRUE, а предыдущий элемент FALSE.После применения == 1 у вас есть логический вектор, который TRUE для NA -групп начинается.Затем вы можете взять cumsum, чтобы определить, в какую NA -группу вы входите, и умножить на is.na(x), чтобы установить ne non- NA s в 0.

cumsum(diff(is.na(c(1, x))) == 1)*is.na(x)
#[1] 1 1 0 0 2 2 0 0

Отображаются промежуточные результаты:

a <- is.na(c(1, x))
a
#[1] FALSE  TRUE  TRUE FALSE FALSE  TRUE  TRUE FALSE FALSE
b <- diff(a) == 1
b
#[1]  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE
d <- cumsum(b)
d
#[1] 1 1 1 1 2 2 2 2

Мне было интересно, поэтому я сделал тест.Я не думаю, что результаты имеют значение практически, хотя, разница в миллисекундах даже для length(x) из 1e7.

x <- c(NA,NA, 1,2,NA,NA, 3,4)
x <- sample(x, 1e7, T)

f_rleid <- function(x){
  nax <- is.na(x)
  r <- rleid(x)*nax
  r[nax] <- rleid(r[nax])
  r
}

f_rle <- function(x){
  r <- rle(is.na(x))
  r$values <- cumsum(r$values) * r$values
  inverse.rle(r)
}

f_diffna <- function(x){
  nax <- is.na(x)
  cumsum(c(as.integer(nax[1]), diff(nax)) == 1L)*nax
}

all.equal(f_rleid(x), f_rle(x))
# [1] TRUE
all.equal(f_rleid(x), f_diffna(x))
# [1] TRUE

microbenchmark::microbenchmark(f_rleid(x), f_rle(x),f_diffna(x))

# Unit: milliseconds
#         expr      min       lq     mean   median       uq      max neval
#   f_rleid(x) 421.9483 437.3314 469.3564 446.5081 511.9315 582.5812   100
#     f_rle(x) 451.3790 519.5278 560.8057 572.4148 591.7632 697.2100   100
#  f_diffna(x) 248.3631 267.5462 315.6224 291.5910 362.8829 459.6873   100
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...