Вот способ использования na.approx
из пакета zoo
и apply
с MARGIN = 1
(так что это, вероятно, не очень эффективно, но сделайте свою работу).
library(zoo)
df1 <- as.data.frame(t(apply(dat, 1, na.approx, method = "constant", f = .5, na.rm = FALSE)))
В результате
df1
# V1 V2 V3 V4 V5
#A NA 0.1 0.2 0.25 0.3
#B 0.1 0.2 0.2 0.30 0.2
#C NA NA NA NA 0.3
#E NA NA 0.1 0.20 0.1
Заменить NA
s и переименовать столбцы.
df1[is.na(df1)] <- 0
names(df1) <- names(dat)
df1
# Date_1 Date_2 Date_3 Date_4 Date_5
#A 0.0 0.1 0.2 0.25 0.3
#B 0.1 0.2 0.2 0.30 0.2
#C 0.0 0.0 0.0 0.00 0.3
#E 0.0 0.0 0.1 0.20 0.1
Объяснение
Учитывая вектор
x <- c(0.1, NA, NA, 0.3, 0.2)
na.approx(x)
возвращает x
с линейными интерполированными значениями
#[1] 0.1000000 0.1666667 0.2333333 0.3000000 0.2000000
Но OP запросил постоянные значения, поэтому нам нужен аргумент method = "constant"
из функции approx
.
na.approx(x, method = "constant")
# [1] 0.1 0.1 0.1 0.3 0.2
Но это все-таки не то, что запрашивал OP, потому что он переносит последнее наблюдение вперед, в то время как вы хотите получить среднее значение для ближайших не NA
значений. Поэтому нам нужен аргумент f
(также из approx
)
na.approx(x, method = "constant", f = .5)
# [1] 0.1 0.2 0.2 0.3 0.2 # looks good
С ?approx
f: для method = "constant" число от 0 до 1 включительно, указывающее на компромисс между пошаговыми функциями слева и справа. Если y0 и y1 являются значениями слева и справа от точки, то значение равно y0, если f == 0, y1, если f == 1, и y0 * (1-f) + y1 * f для промежуточных значений. Таким образом, результат является непрерывным справа для f == 0 и непрерывным слева для f == 1, даже для не конечных значений y.
Наконец, если мы не хотим заменять NA
s в начале и конце каждой строки, нам нужно na.rm = FALSE
.
С ?na.approx
na.rm: логично. Если результат (сплайновой) интерполяции все еще приводит к NA, должны ли они быть удалены?
Данные
dat <- structure(list(Date_1 = c(NA, 0.1, NA, NA), Date_2 = c(0.1, NA,
NA, NA), Date_3 = c(0.2, NA, NA, 0.1), Date_4 = c(NA, 0.3, NA,
0.2), Date_5 = c(0.3, 0.2, 0.3, 0.1)), .Names = c("Date_1", "Date_2",
"Date_3", "Date_4", "Date_5"), class = "data.frame", row.names = c("A",
"B", "C", "E"))
EDIT
Если в последнем столбце есть NA
s, мы можем заменить их на последние не-1066 * s перед тем, как применить na.approx
, как показано выше.
dat$Date_6[is.na(dat$Date_6)] <- dat[cbind(1:nrow(dat),
max.col(!is.na(dat), ties.method = "last"))][is.na(dat$Date_6)]