линейная интерполяция пропущенных значений во временных рядах

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

df <- data.frame(date = as.Date(c("2015-10-05","2015-10-08","2015-10-09",
                                  "2015-10-12","2015-10-14")),       
                 value = c(8,3,9,NA,5))

      date value
2015-10-05     8
2015-10-08     3
2015-10-09     9
2015-10-12    NA
2015-10-14     5

      date value approx
2015-10-05     8      8
2015-10-06    NA   6.33
2015-10-07    NA   4.67
2015-10-08     3      3
2015-10-09     9      9
2015-10-10    NA   8.20
2015-10-11    NA   7.40
2015-10-12    NA   6.60
2015-10-13    NA   5.80
2015-10-14     5      5

Есть четкое решение с dplyr и approx? (Мне не нравится мой 10-строчный for код цикла.)


person ckluss    schedule 17.10.2015    source источник


Ответы (4)


Вот один способ. Я создал фрейм данных с последовательностью дат, используя первую и последнюю дату. Используя full_join() в пакете dplyr, я объединил фрейм данных и mydf. Затем я использовал na.approx() в пакете zoo для обработки интерполяции в части mutate().

mydf <- data.frame(date = as.Date(c("2015-10-05","2015-10-08","2015-10-09",
                                    "2015-10-12","2015-10-14")),       
                   value = c(8,3,9,NA,5))

library(dplyr)
library(zoo)

data.frame(date = seq(mydf$date[1], mydf$date[nrow(mydf)], by = 1)) %>%
full_join(mydf, by = "date") %>%
mutate(approx = na.approx(value))

#         date value   approx
#1  2015-10-05     8 8.000000
#2  2015-10-06    NA 6.333333
#3  2015-10-07    NA 4.666667
#4  2015-10-08     3 3.000000
#5  2015-10-09     9 9.000000
#6  2015-10-10    NA 8.200000
#7  2015-10-11    NA 7.400000
#8  2015-10-12    NA 6.600000
#9  2015-10-13    NA 5.800000
#10 2015-10-14     5 5.000000
person jazzurro    schedule 17.10.2015

Вот несколько решений.

1) zoo Преобразуйте фрейм данных в серию zoo и используйте na.approx с xout= последовательных дат, чтобы получить окончательную серию

library(zoo)
z <- read.zoo(mydf)
zz <- na.approx(z, xout = seq(start(z), end(z), "day"))

давая:

> zz
2015-10-05 2015-10-06 2015-10-07 2015-10-08 2015-10-09 2015-10-10 2015-10-11 
  8.000000   6.333333   4.666667   3.000000   9.000000   8.200000   7.400000 
2015-10-12 2015-10-13 2015-10-14 
  6.600000   5.800000   5.000000 

Возможно, будет удобнее оставить его в форме зоопарка, чтобы вы могли использовать все возможности зоопарка, но если вам это нужно в форме фрейма данных, просто используйте

DF <- fortify.zoo(zz)

1a) zoo / magrittr. Вышесказанное можно также выразить как трубопровод magrittr:

library(magrittr)
df %>% read.zoo %>% na.approx(xout = seq(start(.), end(.), "day")) %>% fortify.zoo

(или опустите часть fortify.zoo, если хотите, чтобы результат был зоопарком).

2) base R. Мы можем сделать то же самое и без таких пакетов:

n <- nrow(mydf)
with(mydf, data.frame(approx(date, value, xout = seq(date[1], date[n], "day"))))
person G. Grothendieck    schedule 17.10.2015

Я думаю, ваш код выглядел бы намного яснее и проще, если бы вы использовали пакет Forecast.

library(forecast)
x <- zoo(df$value,df$date)
x <- as.ts(x)
x <- na.interp(x)
print(x)
person Acoustesh    schedule 30.10.2015

Еще одно красивое и короткое решение (с использованием imputeTS):

library(imputeTS)
x <- zoo(df$value,df$date)
x <- na.interpolation(x, option = "linear")
print(x)
person Steffen Moritz    schedule 11.11.2016
comment
Я только начал использовать этот пакет, и он делает такие вещи намного проще! - person Andrew Brēza; 21.07.2017