Заменить значения в векторе на основе предыдущего и следующего правильного значения? - PullRequest
3 голосов
/ 12 марта 2019

Если у меня есть такой вектор, как

x = c(1, 2, -1, -2, 5, 6, 7, -1, -2, -3, 8, 9)

, я бы хотел для каждого отрицательного значения смотреть в будущее и подсчитывать, сколько отрицательных значений впереди, включая текущее значение.Таким образом, результат будет выглядеть следующим образом:

y = c(0, 0, 2, 1, 0, 0, 0, 3, 2, 1, 0, 0)

Моя конечная цель - использовать эти результаты для создания замещающих значений для отрицательных значений, основанных на среднем значении ближайших положительных значений.В этом случае я хочу, чтобы результат был:

result = {1,2,(2+5)/2,(2+5)/2,5,6,7,(7+8)/2,(7+8)/2,(7+8)/2,8,9}

Теперь я могу сделать это, используя mutate и lead с разными смещениями, но должен быть более простой способ?

Ответы [ 5 ]

6 голосов
/ 12 марта 2019

Вот еще один способ, вдохновленный ответом @ Хашаа:

approx(replace(x, x < 0, NA), xout = seq_along(x), 
  method = "constant", f = 0.5, rule = 2)$y
# [1] 1.0 2.0 3.5 3.5 5.0 6.0 7.0 7.5 7.5 7.5 8.0 9.0

Как это работает в псевдокоде. Пусть X = replace (x, x <0, NA).</p>

X = 1  2 NA NA  5  6  7 NA NA NA  8  9

Мы интерполируем функцию X (i), где i принимает значения в xout = 1..12, используя данные

  {[i, X(i)] : X(i) not NA, i = 1..12} 
= {[i, X(i)] : i = 1, 2, 5, 6, 7, 11, 12}

Поскольку у нас уже есть данные по X(i) если это не NA, нам нужно только заполнить интервалы NA, то есть i = 3, 4, 8, 9, 10.

  • method = "постоянная" заполняет каждуюинтервал NA, i = 3-4 и i = 8-10, с одним значением, рассчитанным на основе двух ближайших наблюдений
  • f = 0,5 взвешивает два наблюдения одинаково
  • rule = 2 заполняет пропущенные интервалы в начале или конце вектора на основе ближайшего наблюдения (не применимо для этого примера)

Для полной документации см. ?approx.

(Спасибо @thothal за разъяснения и исправления в комментариях.)

2 голосов
/ 12 марта 2019

1) na.locf0 Замените отрицательные значения на NA, а затем используйте na.locf0 как вперед, так и назад, взяв среднее из двух.

library(zoo)

x.na <- replace(x, x < 0, NA)
(na.locf0(x.na) + na.locf0(x.na, fromLast = TRUE)) / 2
## [1] 1.0 2.0 3.5 3.5 5.0 6.0 7.0 7.5 7.5 7.5 8.0 9.0

2) cummax / cummin Если неотрицательные числа являются неубывающими, как в выборочных данных вопроса, тогда это будет работать, используя только базу R. Мы берем cummax вперед и cummin назад и усредняем два (кромеобратный проход заменяем отрицательными значениями на Inf).

( cummax(x) +  rev(cummin(rev(replace(x, x < 0, Inf)))) ) / 2
## [1] 1.0 2.0 3.5 3.5 5.0 6.0 7.0 7.5 7.5 7.5 8.0 9.0
0 голосов
/ 12 марта 2019

Чтобы добавить чистый базовый раствор:

rl <- rle(x < 0)
unlist(mapply(rl$length, rl$values, FUN = function(l, v) if (v) seq(l, 1) else rep(0, l)))
# [1] 0 0 2 1 0 0 0 3 2 1 0 0
0 голосов
/ 12 марта 2019

Вместо того чтобы найти количество последовательных отрицательных целых чисел, я попытался достичь вашей конечной цели.Он пытается найти серию отрицательных чисел, заменить ее соседним средним положительных чисел и двигаться вперед.Я добавил комментарии для лучшего понимания, надеюсь, это поможет.Ура!

x = c(1, 2, -1, -2, 5, 6, 7, -1, -2, -3, 8, 9)
i <- 1 #iterator
while (i < length(x)){
    if (x[i]>0 & x[i+1]<0){  #check for the 1st negative number
        temp <- i+1
        while (x[temp]<0){  #check for all consectuive negative numbers  
            temp <- temp + 1
        }
        mean <- (x[temp] + x[i])/2  #find mean of the nearest positive numbers
        i <- i + 1
        while (i<temp){   #replacing all negative with the mean
            x[i] = mean
            i = i + 1
        }
    }
    i = i+1
}
print(x)
0 голосов
/ 12 марта 2019
ave(x, with(rle(sign(x)), rep(seq_along(values), lengths)),
    FUN = function(x) rev(seq_along(x)) * (x < 0))
# [1] 0 0 2 1 0 0 0 3 2 1 0 0

Если вы просто хотите заменить значения

indsn = which(x < 0)
indsp = which(x > 0)
replace(x = x,
        list = x < 0,
        values = sapply(indsn, function(n){
            i = indsp[tail(which(indsp < n), 1)]
            j = indsp[head(which(indsp > n), 1)]
            mean(x[c(i, j)])
        }))
# [1] 1.0 2.0 3.5 3.5 5.0 6.0 7.0 7.5 7.5 7.5 8.0 9.0
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...