<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/forecasting-my-weight-with-r/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.brodrigues.co/blog/2018-06-24-fun_ts/"> Econometrics and Free Software</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>I’ve been measuring my weight almost daily for almost 2 years now; I actually started earlier, but<br>
not as consistently. The goal of this blog post is to get re-acquaiented with time series; I haven’t<br>
had the opportunity to work with time series for a long time now and I have seen that quite a few<br>
packages that deal with time series have been released on CRAN. In this blog post, I will explore<br>
my weight measurements using some functions from the <code>{tsibble}</code> and <code>{tibbletime}</code> packages,<br>
and then do some predictions with the <code>{forecast}</code> package.</p>
<p>First, let’s load the needed packages, read in the data and convert it to a <code>tsibble</code>:</p>
<pre><code>library(&quot;tidyverse&quot;)
library(&quot;readr&quot;)
library(&quot;forecast&quot;)
library(&quot;tsibble&quot;)
library(&quot;tibbletime&quot;)
library(&quot;mice&quot;)</code></pre>
<pre><code>weight &lt;- read_csv(&quot;https://gist.githubusercontent.com/b-rodrigues/ea60679135f8dbed448ccf66a216811f/raw/18b469f3b0720f76ce5ee2715d0f9574b615f170/gistfile1.txt&quot;) %>% 
    as_tsibble()</code></pre>
<pre><code>## Parsed with column specification:
## cols(
##   Date = col_date(format = &quot;&quot;),
##   Poids = col_double()
## )</code></pre>
<pre><code>## The `index` is `Date`.</code></pre>
<p>You can read more about <code>{tsibble}</code> <a rel="nofollow" href="https://pkg.earo.me/tsibble/" target="_blank">here</a>. Here, I use <code>{tsibble}</code> mostly<br>
for the next step, which is using the function <code>fill_na()</code> on the tsibble. <code>fill_na()</code> turns<br>
implicit missing values into explicit missing values. These are implicit missing values:</p>
<pre><code>          Date Poids
1   2013-01-01 84.10
2   2013-01-04 85.60</code></pre>
<p>and this is the same view, but with explicit missing values:</p>
<pre><code>          Date Poids
1   2013-01-01 84.10
2   2013-01-02 NA
3   2013-01-03 NA
4   2013-01-04 85.60</code></pre>
<p>This is useful to do, because I want to impute the missing values using the <code>{mice}</code> package.<br>
Let’s do this:</p>
<pre><code>weight &lt;- weight %>% 
    fill_na()

imp_weight &lt;- mice(data = weight) %>% 
    mice::complete(&quot;long&quot;)</code></pre>
<pre><code>## 
##  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</code></pre>
<p>Let’s take a look at <code>imp_weight</code>:</p>
<pre><code>head(imp_weight)</code></pre>
<pre><code>##   .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</code></pre>
<p>Let’s select the relevant data. I filter from the 11th of July 2016, which is where I started<br>
weighing myself almost every day, to the 31st of May 2018. I want to predict my weight for the<br>
month of June (you might think of the month of June 2018 as the test data, and the rest as training<br>
data):</p>
<pre><code>imp_weight_train &lt;- imp_weight %>% 
    filter(Date >= &quot;2016-07-11&quot;, Date &lt;= &quot;2018-05-31&quot;)</code></pre>
<p>In the next lines, I create a column called <code>imputation</code> which is simply the same as the column<br>
<code>.imp</code> but of character class, remove unneeded columns and rename some other columns (“Poids” is<br>
French for weight):</p>
<pre><code>imp_weight_train &lt;- imp_weight_train %>% 
    mutate(imputation = as.character(.imp)) %>% 
    select(-.id, -.imp) %>% 
    rename(date = Date) %>% 
    rename(weight = Poids)</code></pre>
<p>Let’s take a look at the data:</p>
<pre><code>ggplot(imp_weight_train, aes(date, weight, colour = imputation)) +
    geom_line() + 
    theme(legend.position = &quot;bottom&quot;)</code></pre>
<p><img src="https://i2.wp.com/www.brodrigues.co/blog/2018-06-24-fun_ts/blog/2018-06-24-fun_ts_files/figure-html/unnamed-chunk-8-1.png?w=450" data-recalc-dims="1"></p>
<p>This plots gives some info, but it might be better to smooth the lines. This is possible by<br>
computing a rolling mean. For this I will use the <code>rollify()</code> function of the <code>{tibbletime}</code> package:</p>
<pre><code>mean_roll_5 &lt;- rollify(mean, window = 5)
mean_roll_10 &lt;- rollify(mean, window = 10)</code></pre>
<p><code>rollify()</code> can be seen as an adverb, pretty much like <code>purrr::safely()</code>; <code>rollify()</code> is a higher<br>
order function that literally rollifies a function, in this case <code>mean()</code> which means that<br>
rollifying the mean creates a function that returns the rolling mean. The <code>window</code> argument lets<br>
you decide how smooth you want the curve to be: the higher the smoother. However, you will lose<br>
some observations. Let’s use this functions to add the rolling means to the data frame:</p>
<pre><code>imp_weight_train &lt;- imp_weight_train %>% 
    group_by(imputation) %>% 
    mutate(roll_5 = mean_roll_5(weight),
           roll_10 = mean_roll_10(weight))</code></pre>
<p>Now, let’s plot these new curves:</p>
<pre><code>ggplot(imp_weight_train, aes(date, roll_5, colour = imputation)) +
    geom_line() + 
    theme(legend.position = &quot;bottom&quot;)</code></pre>
<pre><code>## Warning: Removed 20 rows containing missing values (geom_path).</code></pre>
<p><img src="https://i2.wp.com/www.brodrigues.co/blog/2018-06-24-fun_ts/blog/2018-06-24-fun_ts_files/figure-html/unnamed-chunk-11-1.png?w=450" data-recalc-dims="1"></p>
<pre><code>ggplot(imp_weight_train, aes(date, roll_10, colour = imputation)) +
    geom_line() + 
    theme(legend.position = &quot;bottom&quot;)</code></pre>
<pre><code>## Warning: Removed 45 rows containing missing values (geom_path).</code></pre>
<p><img src="https://i0.wp.com/www.brodrigues.co/blog/2018-06-24-fun_ts/blog/2018-06-24-fun_ts_files/figure-html/unnamed-chunk-11-2.png?w=450" data-recalc-dims="1"></p>
<p>That’s easier to read, isn’t it?</p>
<p>Now, I will use the <code>auto.arima()</code> function to train a model on the data to forecast my weight for<br>
the month of June. However, my data, <code>imp_weight_train</code> is a list of datasets. <code>auto.arima()</code> does<br>
not take a data frame as an argument, much less so a list of datasets. I’ll create a wrapper around<br>
<code>auto.arima()</code> that works on a dataset, and then map it to the list of datasets:</p>
<pre><code>auto.arima.df &lt;- function(data, y, ...){

    y &lt;- enquo(y)

    yts &lt;- data %>% 
        pull(!!y) %>% 
        as.ts()

    auto.arima(yts, ...)
}</code></pre>
<p><code>auto.arima.df()</code> takes a data frame as argument, and then <code>y</code>, which is the column that contains the<br>
univariate time series. This column then gets pulled out of the data frame, converted to a time<br>
series object with <code>as.ts()</code>, and then passed down to <code>auto.arima()</code>. I can now use this function<br>
on my list of data sets. The first step is to nest the data:</p>
<pre><code>nested_data &lt;- imp_weight_train %>% 
    group_by(imputation) %>% 
    nest() </code></pre>
<p>Let’s take a look at <code>nested_data</code>:</p>
<pre><code>nested_data</code></pre>
<pre><code>## # A tibble: 5 x 2
##   imputation data              
##   </code></pre>