I’ve been measuring my weight almost daily for almost 2 years now; I actually started earlier, but
not as consistently. The goal of this blog post is to get re-acquaiented with time series; I haven’t
had the opportunity to work with time series for a long time now and I have seen that quite a few
packages that deal with time series have been released on CRAN. In this blog post, I will explore
my weight measurements using some functions from the {tsibble} and {tibbletime} packages,
and then do some predictions with the {forecast} package.
First, let’s load the needed packages, read in the data and convert it to a tsibble:
library(&quot;tidyverse&quot;)
library(&quot;readr&quot;)
library(&quot;forecast&quot;)
library(&quot;tsibble&quot;)
library(&quot;tibbletime&quot;)
library(&quot;mice&quot;)
weight % as_tsibble()
## Parsed with column specification:
## cols(
## Date = col_date(format = &quot;&quot;),
## Poids = col_double()
## )
## The `index` is `Date`.
You can read more about {tsibble} here. Here, I use {tsibble} mostly
for the next step, which is using the function fill_na() on the tsibble. fill_na() turns
implicit missing values into explicit missing values. These are implicit missing values:
Date Poids
1 2013-01-01 84.10
2 2013-01-04 85.60
and this is the same view, but with explicit missing values:
Date Poids
1 2013-01-01 84.10
2 2013-01-02 NA
3 2013-01-03 NA
4 2013-01-04 85.60
This is useful to do, because I want to impute the missing values using the {mice} package.
Let’s do this:
weight % fill_na()
imp_weight % mice::complete(&quot;long&quot;)
## ## iter imp variable
## 1 1 Poids
## 1 2 Poids
## 1 3 Poids
## 1 4 Poids
## 1 5 Poids
## 2 1 Poids
## 2 2 Poids
## 2 3 Poids
## 2 4 Poids
## 2 5 Poids
## 3 1 Poids
## 3 2 Poids
## 3 3 Poids
## 3 4 Poids
## 3 5 Poids
## 4 1 Poids
## 4 2 Poids
## 4 3 Poids
## 4 4 Poids
## 4 5 Poids
## 5 1 Poids
## 5 2 Poids
## 5 3 Poids
## 5 4 Poids
## 5 5 Poids
Let’s take a look at imp_weight:
head(imp_weight)
## .imp .id Date Poids
## 1 1 1 2013-10-28 84.1
## 2 1 2 2013-10-29 84.4
## 3 1 3 2013-10-30 83.5
## 4 1 4 2013-10-31 84.1
## 5 1 5 2013-11-01 85.6
## 6 1 6 2013-11-02 85.2
Let’s select the relevant data. I filter from the 11th of July 2016, which is where I started
weighing myself almost every day, to the 31st of May 2018. I want to predict my weight for the
month of June (you might think of the month of June 2018 as the test data, and the rest as training
data):
imp_weight_train % filter(Date __= &quot;2016-07-11&quot;, Date % select(-.id, -.imp) %__% rename(date = Date) %__% rename(weight = Poids)
Let’s take a look at the data:
ggplot(imp_weight_train, aes(date, weight, colour = imputation)) +
geom_line() + theme(legend.position = &quot;bottom&quot;)
This plots gives some info, but it might be better to smooth the lines. This is possible by
computing a rolling mean. For this I will use the rollify() function of the {tibbletime} package:
mean_roll_5 % mutate(predictions = map(predictions, as_tibble)) %__% pull(predictions) I forecast 24 days (I am writing this on the 24th of June), and convert the predictions to tibbles,
and then pull only the predictions tibble:
forecasts
## [[1]]
## # A tibble: 24 x 5
## `Point Forecast` `Lo 80` `Hi 80` `Lo 95` `Hi 95`
## * ## 1 71.5 70.7 72.3 70.2 72.8
## 2 71.5 70.7 72.4 70.3 72.8
## 3 71.5 70.6 72.3 70.1 72.8
## 4 71.5 70.6 72.4 70.1 72.9
## 5 71.4 70.5 72.4 70.0 72.9
## 6 71.5 70.5 72.4 70.0 72.9
## 7 71.4 70.5 72.4 69.9 72.9
## 8 71.4 70.4 72.4 69.9 72.9
## 9 71.4 70.4 72.4 69.9 72.9
## 10 71.4 70.4 72.4 69.8 73.0
## # ... with 14 more rows
## ## [[2]]
## # A tibble: 24 x 5
## `Point Forecast` `Lo 80` `Hi 80` `Lo 95` `Hi 95`
## * ## 1 71.6 70.8 72.3 70.3 72.8
## 2 71.6 70.8 72.5 70.3 72.9
## 3 71.5 70.6 72.4 70.2 72.9
## 4 71.5 70.6 72.5 70.1 72.9
## 5 71.5 70.5 72.5 70.0 73.0
## 6 71.5 70.5 72.5 70.0 73.0
## 7 71.5 70.5 72.5 69.9 73.0
## 8 71.5 70.4 72.5 69.9 73.1
## 9 71.5 70.4 72.5 69.8 73.1
## 10 71.4 70.3 72.6 69.7 73.1
## # ... with 14 more rows
## ## [[3]]
## # A tibble: 24 x 5
## `Point Forecast` `Lo 80` `Hi 80` `Lo 95` `Hi 95`
## * ## 1 71.6 70.8 72.4 70.4 72.8
## 2 71.5 70.7 72.4 70.2 72.8
## 3 71.5 70.6 72.4 70.2 72.9
## 4 71.5 70.6 72.4 70.1 72.9
## 5 71.5 70.5 72.4 70.0 72.9
## 6 71.5 70.5 72.4 70.0 73.0
## 7 71.5 70.5 72.5 69.9 73.0
## 8 71.4 70.4 72.5 69.9 73.0
## 9 71.4 70.4 72.5 69.8 73.0
## 10 71.4 70.4 72.5 69.8 73.1
## # ... with 14 more rows
## ## [[4]]
## # A tibble: 24 x 5
## `Point Forecast` `Lo 80` `Hi 80` `Lo 95` `Hi 95`
## * ## 1 71.5 70.8 72.3 70.3 72.8
## 2 71.5 70.7 72.4 70.3 72.8
## 3 71.5 70.7 72.4 70.2 72.8
## 4 71.5 70.6 72.4 70.1 72.9
## 5 71.5 70.6 72.4 70.1 72.9
## 6 71.5 70.5 72.5 70.0 73.0
## 7 71.5 70.5 72.5 69.9 73.0
## 8 71.5 70.4 72.5 69.9 73.0
## 9 71.4 70.4 72.5 69.8 73.1
## 10 71.4 70.3 72.5 69.8 73.1
## # ... with 14 more rows
## ## [[5]]
## # A tibble: 24 x 5
## `Point Forecast` `Lo 80` `Hi 80` `Lo 95` `Hi 95`
## * ## 1 71.5 70.8 72.3 70.3 72.8
## 2 71.5 70.7 72.4 70.3 72.8
## 3 71.5 70.7 72.4 70.2 72.8
## 4 71.5 70.6 72.4 70.1 72.9
## 5 71.5 70.6 72.4 70.1 72.9
## 6 71.5 70.5 72.4 70.0 73.0
## 7 71.5 70.5 72.5 69.9 73.0
## 8 71.5 70.4 72.5 69.9 73.0
## 9 71.4 70.4 72.5 69.8 73.1
## 10 71.4 70.3 72.5 69.8 73.1
## # ... with 14 more rows
So forecasts is a list of tibble, each containing a forecast. Remember that I have 5 tibbles, because
I imputed the data 5 times. I will merge this list of data sets together into one, but before I need
to add a column that indices the forecasts:
forecasts % bind_rows() %__% select(-c(`Lo 80`, `Hi 80`))
colnames(forecasts) = &quot;2018-06-01&quot;) %__% select(-.id) %__% group_by(Date) %__% summarise(true_weight = mean(Poids)) %__% rename(date = Date)
Let’s take a look at weight_june:
weight_june
## # A tibble: 24 x 2
## date true_weight
## ## 1 2018-06-01 71.8
## 2 2018-06-02 70.8
## 3 2018-06-03 71.2
## 4 2018-06-04 71.4
## 5 2018-06-05 70.9
## 6 2018-06-06 70.8
## 7 2018-06-07 70.5
## 8 2018-06-08 70.1
## 9 2018-06-09 70.3
## 10 2018-06-10 71.0
## # ... with 14 more rows
Let’s repeat weight_june 5 times, and add the index 1 to 5. Why? Because I want to merge the
true data with the forecasts, and having the data in this form makes things easier:
weight_june % bind_rows()
The first line:
modify(list_along(1:5), ~`