Заполнить NA на границе вектора в r - PullRequest
4 голосов
/ 10 ноября 2019

У меня есть вектор, содержащий NA на границе

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

Я хочу, чтобы результат был:

c(-3, -1, 1,-1, 1, 0, -1, 2, 5, 8)

Другими словами, я хочу заполнить как внутренние, так и граничные NAс линейной интерполяцией (может быть, я не могу назвать это « inter -polation», так как NA находятся на границах).

Я попробовал функцию в пакете "zoo", na.fill (x,"extension"), но вывод границы - это не то, что мне нужно, он просто повторяет крайнее левое или крайнее правое значение, отличное от NA:

na.fill(x,"extend")

, а вывод -

[1] -1 -1  1 -1  1  0 -1  2  2  2

Iтакже проверил другие функции для заполнения NA, такие как na.approx (), na.locf () и т. д., но ни одна из них не работает.

na.spline работает, но выходные данные граничных NA приводят к чрезвычайно большим изменениям.

na.spline(x)

Выходные данные:

 [1] -15.9475983  -1.0000000   1.0000000  -1.0000000   1.0000000   0.3400655  -1.0000000   2.0000000
 [9]  13.1441048  35.9323144

Граничные точкислишком большой. Может кто-нибудь мне помочь? Заранее спасибо!

Ответы [ 4 ]

6 голосов
/ 10 ноября 2019

Вы можете использовать na.spline() из библиотеки zoo:

na.spline(x)

[1] 0.0 0.5 1.0 1.5 2.0 2.5

Данные для исходного вопроса:

x <- c(0, NA, 1, NA, 2, NA)
2 голосов
/ 10 ноября 2019

Вот один из способов сделать это:

Сначала мы выполним линейное приближение, которое оставит нас со всеми хвостами NA -с слева и справа:

x <- na.approx(x, method = "constant", f = 0.5,na.rm = F)

Теперь давайте найдем не-NA-вектор и связанные с ним крайние левые и правые члены приращения арифметической прогрессии:

x_c <- x[!is.na(x)]
left <- x_c[1] - x_c[2]
right <- x_c[length(x_c)] - x_c[length(x_c) - 1]

Теперь пришло время заполнить левый и правый NA -ы числами, полученными арифметикойпрогрессия:

ind_x<- which(!is.na(x))
big_M <- 100

x[(ind_x[length(ind_x)]):length(x)] <- seq(x[ind_x[length(ind_x)]],
                                           sign(right) * big_M,
                                           right)[1:(length(x) - ind_x[length(ind_x)] + 1)]
x[ind_x[1]:1] <- seq(x[ind_x[1]],sign(left) * big_M,left)[1:ind_x[1]]
y <- x

, где big_M - определяемое пользователем большое число, которое не будет превышено арифметической прогрессией, учитывая базовые данные.

Ввод - вывод:

x <- c(NA, -1, 1,-1, 1, NA, -1, 2, NA, NA)
> y
 [1] -3 -1  1 -1  1  0 -1  2  5  8

x <- c(NA,NA,NA, -1, 1,-1, 1, NA, -1, 2, NA, NA,NA)
> y
 [1] -7 -5 -3 -1  1 -1  1  0 -1  2  5  8 11

x <- c(NA,NA,NA, 5,1, 1,-1, 1, NA, -1, 2, NA, NA,NA)
> y
 [1] 17 13  9  5  1  1 -1  1  0 -1  2  5  8 11
2 голосов
/ 10 ноября 2019

Учитывая данные и ожидаемый результат после редактирования вопроса, я полагаю, что следующая функция делает это. Он заполняет внутреннюю область NA с approxfun, а затем обрабатывает крайности один за другим.

na.extrapol <- function(y){
  x <- seq_along(y)
  f <- approxfun(x[!is.na(y)], y[!is.na(y)])
  y[is.na(y)] <- f(x[is.na(y)])
  r <- rle(is.na(y))
  if(r$values[1]){
    Y <- y[r$lengths[1] + 1:2]
    X <- seq_len(r$lengths[1])
    y[rev(X)] <- Y[1] - diff(Y)*X
  }
  n <- length(r$lengths)
  if(r$values[n]){
    s <- sum(r$lengths[-n])
    Y <- y[s - 1:0]
    X <- seq_len(r$lengths[n])
    y[s + X] <- Y[2] + diff(Y)*X
  }
  y
}

x <- c(NA, -1, 1,-1, 1, NA, -1, 2, NA, NA)
na.extrapol(x)
#[1] -3 -1  1 -1  1  0 -1  2  5  8

x2 <- c(NA, NA, -1, 1,-1, 1, NA, -1, 2, NA, NA)
na.extrapol(x2)
#[1] -5 -3 -1  1 -1  1  0 -1  2  5  8
0 голосов
/ 11 ноября 2019

Помимо рассмотрения Hmisc::approxExtrap, другой вариант заключается в использовании lm, но он, скорее всего, будет медленнее, чем другие варианты здесь

x <- c(NA, -1, 1,-1, 1, NA, -1, 2, NA, NA)
DF <- data.frame(i=seq_along(x), x)
cc <- DF[complete.cases(DF),]
DF$x <- approx(cc$i, cc$x, DF$i)$y
hh <- head(cc, 2L)
tt <- tail(cc, 2L)
DF$x[DF$i < hh$i[1L]] <- predict(lm(x ~ i, hh), DF[DF$i < hh$i[1L], "i", drop=FALSE])
DF$x[DF$i > tt$i[2L]] <- predict(lm(x ~ i, tt), DF[DF$i > tt$i[2L], "i", drop=FALSE])
DF

output:

    i  x
1   1 -3
2   2 -1
3   3  1
4   4 -1
5   5  1
6   6  0
7   7 -1
8   8  2
9   9  5
10 10  8
...