<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/tidy-time-series-analysis-part-2-rolling-functions/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.business-science.io/timeseries-analysis/2017/07/23/tidy-timeseries-analysis-pt-2.html"> business-science.io - Articles</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>In the second part in a series on <strong>Tidy Time Series Analysis</strong>, we’ll again use <code>tidyquant</code> to investigate CRAN downloads this time focusing on <strong>Rolling Functions</strong>. If you haven’t checked out the previous post on <a rel="nofollow" href="http://www.business-science.io/timeseries-analysis/2017/07/02/tidy-timeseries-analysis.html" target="_blank">period apply functions</a>, you may want to review it to get up to speed. Both <code>zoo</code> and <code>TTR</code> have a number of “roll” and “run” functions, respectively, that are integrated with <code>tidyquant</code>. In this post, we’ll focus on the <code>rollapply</code> function from <code>zoo</code> because of its flexibility with <strong>applying custom functions across rolling windows</strong>. If you like what you read, please <a rel="nofollow" href="http://www.business-science.io/timeseries-analysis/2017/07/23/tidy-timeseries-analysis-pt-2.html#social" target="_blank">follow us on social media</a> to stay up on the latest <a rel="nofollow" href="http://www.business-science.io/timeseries-analysis/2017/07/23/tidy-timeseries-analysis-pt-2.html#contact" target="_blank">Business Science</a> news, events and information! As always, we are interested in both expanding our <em>network of data scientists</em> and seeking <em>new clients interested in applying data science to business and finance</em>.</p>
<p>An example of the visualization we can create using the <code>rollapply</code> function with <code>tq_mutate()</code>:</p>
<p><img alt="tidyverse Bollinger Bands" src="https://i0.wp.com/www.business-science.io/assets/tidy-timeseries-part2.png?w=456" data-recalc-dims="1"></p>
<h1>Libraries Needed</h1>
<p>We’ll primarily be using two libraries today.</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>tidyquant</span><span>)</span><span> </span><span># Loads tidyverse, tidyquant, financial pkgs, xts/zoo
</span><span>library</span><span>(</span><span>cranlogs</span><span>)</span><span> </span><span>#</span><span> </span><span>For</span><span> </span><span>inspecting</span><span> </span><span>package</span><span> </span><span>downloads</span><span> </span><span>over</span><span> </span><span>time</span></code></pre>
</figure>
<h1>CRAN tidyverse Downloads</h1>
<p>We’ll be using the same “tidyverse” dataset as the last post. The script below gets the package downloads for the first half of 2017. The data is very <strong>noisy</strong>, meaning it’s difficult to identify trends. We’ll see how rolling functions can help shortly.</p>
<figure>
<pre><code data-lang="r"><span># tidyverse packages (see my laptop stickers from last post) ;)
</span><span>pkgs</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>
</span><span>&quot;tidyr&quot;</span><span>,</span><span> </span><span>&quot;lubridate&quot;</span><span>,</span><span> </span><span>&quot;dplyr&quot;</span><span>,</span><span> </span><span>&quot;broom&quot;</span><span>,</span><span> </span><span>&quot;tidyquant&quot;</span><span>,</span><span> </span><span>&quot;ggplot2&quot;</span><span>,</span><span> </span><span>&quot;purrr&quot;</span><span>,</span><span> </span><span>&quot;stringr&quot;</span><span>,</span><span> </span><span>&quot;knitr&quot;</span><span>
</span><span>)</span><span>
</span><span># Get the downloads for the individual packages
</span><span>tidyverse_downloads</span><span> </span><span>&lt;-</span><span> </span><span>cran_downloads</span><span>(</span><span>
</span><span>packages</span><span> </span><span>=</span><span> </span><span>pkgs</span><span>,</span><span> </span><span>from</span><span> </span><span>=</span><span> </span><span>&quot;2017-01-01&quot;</span><span>,</span><span> </span><span>to</span><span> </span><span>=</span><span> </span><span>&quot;2017-06-30&quot;</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>tibble</span><span>::</span><span>as_tibble</span><span>()</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>package</span><span>)</span><span>
</span><span># Visualize the package downloads
</span><span>tidyverse_downloads</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>date</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>count</span><span>,</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>package</span><span>))</span><span> </span><span>+</span><span>
</span><span># Data
</span><span> </span><span>geom_point</span><span>(</span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.5</span><span>)</span><span> </span><span>+</span><span>
</span><span>facet_wrap</span><span>(</span><span>~</span><span> </span><span>package</span><span>,</span><span> </span><span>ncol</span><span> </span><span>=</span><span> </span><span>3</span><span>,</span><span> </span><span>scale</span><span> </span><span>=</span><span> </span><span>&quot;free_y&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span># Aesthetics
</span><span> </span><span>labs</span><span>(</span><span>title</span><span> </span><span>=</span><span> </span><span>&quot;tidyverse packages: Daily downloads&quot;</span><span>,</span><span> </span><span>x</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>,</span><span>
</span><span>subtitle</span><span> </span><span>=</span><span> </span><span>&quot;2017-01-01 through 2017-06-30&quot;</span><span>,</span><span>
</span><span>caption</span><span> </span><span>=</span><span> </span><span>&quot;Downloads data courtesy of cranlogs package&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>scale_color_tq</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme_tq</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme</span><span>(</span><span>legend.position</span><span>=</span><span>&quot;none&quot;</span><span>)</span></code></pre>
</figure>
<p><img alt="plot of chunk unnamed-chunk-2" src="https://i0.wp.com/www.business-science.io/figure/source/2017-7-23-tidy-timeseries-analysis-pt-2/unnamed-chunk-2-1.png?w=456" data-recalc-dims="1"></p>
<h1>Rolling Window Calculations</h1>
<p>What are <em>rolling window calculations</em>, and why do we care? In time series analysis, nothing is static. A correlation may exist for a subset of time or an average may vary from one day to the next. Rolling calculations simply apply functions to a fixed width subset of this data (aka a window), indexing one observation each calculation. There are a few common reasons you may want to use a rolling calculation in time series analysis:</p>
<ul>
<li>Measuring the central tendency over time (<code>mean</code>, <code>median</code>)</li>
<li>Measuring the volatility over time (<code>sd</code>, <code>var</code>)</li>
<li>Detecting changes in trend (fast vs slow moving averages)</li>
<li>Measuring a relationship between two time series over time (<code>cor</code>, <code>cov</code>)</li>
</ul>
<p>The most common example of a rolling window calculation is a <a rel="nofollow" href="https://en.wikipedia.org/wiki/Moving_average" target="_blank"><em>moving average</em></a>. Here’s a nice illustration of a 3-month rolling window calculation from <a rel="nofollow" href="http://chandoo.org/wp/2009/04/28/calculate-moving-average/" target="_blank">Chandoo.org</a>.</p>
<p><img alt="Sample Moving Average Calculation" src="https://i2.wp.com/assets.chandoo.org/img/n/calculate-moving-average.png?w=456" data-recalc-dims="1"></p>
<p><center><em>Source: <a rel="nofollow" href="http://chandoo.org/wp/2009/04/28/calculate-moving-average/" target="_blank">Chandoo.org</a></em></center></p>
<p></p>
<p>A <em>moving average</em> allows us to visualize how an average changes over time, which is very useful in <strong>cutting through the noise to detect a trend</strong> in a time series dataset. Further, by varying the window (the number of observations included in the rolling calculation), we can <strong>vary the sensitivity of the window calculation</strong>. This is useful in comparing fast and slow moving averages (shown later).</p>
<p>Combining a <em>rolling mean</em> with a <em>rolling standard deviation</em> can help <strong>detect regions of abnormal volatility and consolidation</strong>. This is the concept behind <em>Bollinger Bands</em> in the financial industry. The bands can be useful in detecting breakouts in trend for many time series, not just financial.</p>
<h1>Time Series Functions</h1>
<p>The <code>xts</code>, <code>zoo</code>, and <code>TTR</code> packages have some great functions that enable working with time series. Today, we’ll take a look at the <strong>Rolling or Running Functions</strong> from the <code>zoo</code> and <code>TTR</code> packages. The roll apply functions are helper functions that enable the application of <em>other functions</em> across a rolling window. What “other functions” can be supplied? Any function that returns a numeric vector such as scalars (<code>mean</code>, <code>median</code>, <code>sd</code>, <code>min</code>, <code>max</code>, etc) or vectors (<code>quantile</code>, <code>summary</code>, and custom functions). The rolling (or running) functions are in the format <code>roll[apply or fun name]</code> for <code>zoo</code> or <code>run[Fun]</code> for <code>TTR</code>. You can see which functions are integrated into <code>tidyquant</code> package below:</p>
<figure>
<pre><code data-lang="r"><span># &quot;roll&quot; functions from zoo
</span><span>tq_mutate_fun_options</span><span>()</span><span>$</span><span>zoo</span><span> </span><span>%>%</span><span>
</span><span>stringr</span><span>::</span><span>str_subset</span><span>(</span><span>&quot;^roll&quot;</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">##  [1] &quot;rollapply&quot;          &quot;rollapplyr&quot;         &quot;rollmax&quot;           
##  [4] &quot;rollmax.default&quot;    &quot;rollmaxr&quot;           &quot;rollmean&quot;          
##  [7] &quot;rollmean.default&quot;   &quot;rollmeanr&quot;          &quot;rollmedian&quot;        
## [10] &quot;rollmedian.default&quot; &quot;rollmedianr&quot;        &quot;rollsum&quot;           
## [13] &quot;rollsum.default&quot;    &quot;rollsumr&quot;</code></pre>
</figure>
<figure>
<pre><code data-lang="r"><span># &quot;run&quot; functions from TTR
</span><span>tq_mutate_fun_options</span><span>()</span><span>$</span><span>TTR</span><span> </span><span>%>%</span><span>
</span><span>stringr</span><span>::</span><span>str_subset</span><span>(</span><span>&quot;^run&quot;</span><span>)</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">##  [1] &quot;runCor&quot;         &quot;runCov&quot;         &quot;runMAD&quot;        
##  [4] &quot;runMax&quot;         &quot;runMean&quot;        &quot;runMedian&quot;     
##  [7] &quot;runMin&quot;         &quot;runPercentRank&quot; &quot;runSD&quot;         
## [10] &quot;runSum&quot;         &quot;runVar&quot;</code></pre>
</figure>
<p>We’ll investigate the <code>rollapply</code> function from the <code>zoo</code> package because it allows us to use <em>custom functions</em> that we create!</p>
<h1>Tidy Implementation of Time Series Functions</h1>
<p>We’ll be using the <code>tq_mutate()</code> function to apply time series functions in a “tidy” way. The <code>tq_mutate()</code> function always adds columns to the existing data frame (rather than returning a new data frame like <code>tq_transmute()</code>). It’s well suited for tasks that result in column-wise dimension changes (not row-wise such as periodicity changes, use <code>tq_transmute</code> for those!). It comes with a bunch of integrated financial and time series package integrations. We can see which apply functions will work by investigating the list of available functions returned by <code>tq_mutate_fun_options()</code>.</p>
<figure>
<pre><code data-lang="r"><span># Condensed function options... lot's of 'em
</span><span>tq_mutate_fun_options</span><span>()</span><span> </span><span>%>%</span><span>
</span><span>str</span><span>()</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## List of 5
##  $ zoo                 : chr [1:14] &quot;rollapply&quot; &quot;rollapplyr&quot; &quot;rollmax&quot; &quot;rollmax.default&quot; ...
##  $ xts                 : chr [1:27] &quot;apply.daily&quot; &quot;apply.monthly&quot; &quot;apply.quarterly&quot; &quot;apply.weekly&quot; ...
##  $ quantmod            : chr [1:25] &quot;allReturns&quot; &quot;annualReturn&quot; &quot;ClCl&quot; &quot;dailyReturn&quot; ...
##  $ TTR                 : chr [1:61] &quot;adjRatios&quot; &quot;ADX&quot; &quot;ALMA&quot; &quot;aroon&quot; ...
##  $ PerformanceAnalytics: chr [1:7] &quot;Return.annualized&quot; &quot;Return.annualized.excess&quot; &quot;Return.clean&quot; &quot;Return.cumulative&quot; ...</code></pre>
</figure>
<h1>Tidy Application of Rolling Functions</h1>
<p>As we saw in the tidyverse daily download graph above, it can be difficult to understand <em>changes in trends</em> just by visualizing the data. We can use <strong>rolling functions to better understand how trends are changing over time</strong>.</p>
<h2>Rolling Mean: Inspecting Fast and Slow Moving Averages</h2>
<p>Suppose we’d like to investigate if significant changes in trend are taking place among the package downloads such that future downloads are likely to continue to increase, decrease or stay the same. One way to do this is to use moving averages. Rather than try to sift through the noise, we can <strong>use a combination of a fast and slow moving average to detect momentum</strong>.</p>
<p>We’ll create a fast moving average with <code>width = 30</code> days (just enough to detrend the data) and a slow moving average with <code>width = 90</code> days (slow window = 3X fast window). To do this we apply two calls to <code>tq_mutate()</code>, the first for the 30 day (fast) and the second for the 90 day (slow) moving average. There are three groups of arguments we need to supply:</p>
<ol>
<li><code>tq_mutate</code> args: These <code>select</code> the column to apply the mutation to (“count”) and the mutation function (<code>mutate_fun</code>) to apply (<code>rollapply</code> from <code>zoo</code>).</li>
<li><code>rollapply</code> args: These set the <code>width</code>, <code>align = &quot;right&quot;</code> (aligns with end of data frame), and the <code>FUN</code> we wish to apply (<code>mean</code> in this case).</li>
<li><code>FUN</code> args: These are arguments that get passed to the function. In this case we want to set <code>na.rm = TRUE</code> so <code>NA</code> values are skipped if present.</li>
</ol>
<p>I add an additional <code>tq_mutate</code> arg, <code>col_rename</code>, at the end to rename the column. This is my preference, but it can be placed with the other <code>tq_mutate</code> args above.</p>
<figure>
<pre><code data-lang="r"><span># Rolling mean
</span><span>tidyverse_downloads_rollmean</span><span> </span><span>&lt;-</span><span> </span><span>tidyverse_downloads</span><span> </span><span>%>%</span><span>
</span><span>tq_mutate</span><span>(</span><span>
</span><span># tq_mutate args
</span><span> </span><span>select</span><span> </span><span>=</span><span> </span><span>count</span><span>,</span><span>
</span><span>mutate_fun</span><span> </span><span>=</span><span> </span><span>rollapply</span><span>,</span><span> </span><span># rollapply args
</span><span> </span><span>width</span><span> </span><span>=</span><span> </span><span>30</span><span>,</span><span>
</span><span>align</span><span> </span><span>=</span><span> </span><span>&quot;right&quot;</span><span>,</span><span>
</span><span>FUN</span><span> </span><span>=</span><span> </span><span>mean</span><span>,</span><span>
</span><span># mean args
</span><span> </span><span>na.rm</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>,</span><span>
</span><span># tq_mutate args
</span><span> </span><span>col_rename</span><span> </span><span>=</span><span> </span><span>&quot;mean_30&quot;</span><span>
</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>tq_mutate</span><span>(</span><span>
</span><span># tq_mutate args
</span><span> </span><span>select</span><span> </span><span>=</span><span> </span><span>count</span><span>,</span><span>
</span><span>mutate_fun</span><span> </span><span>=</span><span> </span><span>rollapply</span><span>,</span><span>
</span><span># rollapply args
</span><span> </span><span>width</span><span> </span><span>=</span><span> </span><span>90</span><span>,</span><span>
</span><span>align</span><span> </span><span>=</span><span> </span><span>&quot;right&quot;</span><span>,</span><span>
</span><span>FUN</span><span> </span><span>=</span><span> </span><span>mean</span><span>,</span><span>
</span><span># mean args
</span><span> </span><span>na.rm</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>,</span><span>
</span><span># tq_mutate args
</span><span> </span><span>col_rename</span><span> </span><span>=</span><span> </span><span>&quot;mean_90&quot;</span><span>
</span><span>)</span><span>
</span><span># ggplot
</span><span>tidyverse_downloads_rollmean</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>date</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>count</span><span>,</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>package</span><span>))</span><span> </span><span>+</span><span>
</span><span># Data
</span><span> </span><span>geom_point</span><span>(</span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.1</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>aes</span><span>(</span><span>y</span><span> </span><span>=</span><span> </span><span>mean_30</span><span>),</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>palette_light</span><span>()[[</span><span>1</span><span>]],</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>1</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>aes</span><span>(</span><span>y</span><span> </span><span>=</span><span> </span><span>mean_90</span><span>),</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>palette_light</span><span>()[[</span><span>2</span><span>]],</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>1</span><span>)</span><span> </span><span>+</span><span>
</span><span>facet_wrap</span><span>(</span><span>~</span><span> </span><span>package</span><span>,</span><span> </span><span>ncol</span><span> </span><span>=</span><span> </span><span>3</span><span>,</span><span> </span><span>scale</span><span> </span><span>=</span><span> </span><span>&quot;free_y&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span># Aesthetics
</span><span> </span><span>labs</span><span>(</span><span>title</span><span> </span><span>=</span><span> </span><span>&quot;tidyverse packages: Daily Downloads&quot;</span><span>,</span><span> </span><span>x</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>,</span><span>
</span><span>subtitle</span><span> </span><span>=</span><span> </span><span>&quot;30 and 90 Day Moving Average&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>scale_color_tq</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme_tq</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme</span><span>(</span><span>legend.position</span><span>=</span><span>&quot;none&quot;</span><span>)</span></code></pre>
</figure>
<p><img alt="plot of chunk unnamed-chunk-5" src="https://i2.wp.com/www.business-science.io/figure/source/2017-7-23-tidy-timeseries-analysis-pt-2/unnamed-chunk-5-1.png?w=456" data-recalc-dims="1"></p>
<p>The output is a little difficult to see. We’ll need to zoom in a little more to detect momentum. Let’s drop the “count” data from the plots and inspect just the moving averages. What we are looking for are points where the fast trend is above (has momentum) or below (is slowing) the slow trend. In addition, we want to inspect for cross-over, which indicates shifts in trend.</p>
<figure>
<pre><code data-lang="r"><span>tidyverse_downloads_rollmean</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>date</span><span>,</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>package</span><span>))</span><span> </span><span>+</span><span>
</span><span># Data
</span><span> </span><span># geom_point(alpha = 0.5) + # Drop &quot;count&quot; from plots
</span><span> </span><span>geom_line</span><span>(</span><span>aes</span><span>(</span><span>y</span><span> </span><span>=</span><span> </span><span>mean_30</span><span>),</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>palette_light</span><span>()[[</span><span>1</span><span>]],</span><span> </span><span>linetype</span><span> </span><span>=</span><span> </span><span>1</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>1</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_line</span><span>(</span><span>aes</span><span>(</span><span>y</span><span> </span><span>=</span><span> </span><span>mean_90</span><span>),</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>palette_light</span><span>()[[</span><span>2</span><span>]],</span><span> </span><span>linetype</span><span> </span><span>=</span><span> </span><span>1</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>1</span><span>)</span><span> </span><span>+</span><span>
</span><span>facet_wrap</span><span>(</span><span>~</span><span> </span><span>package</span><span>,</span><span> </span><span>ncol</span><span> </span><span>=</span><span> </span><span>3</span><span>,</span><span> </span><span>scale</span><span> </span><span>=</span><span> </span><span>&quot;free_y&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span># Aesthetics
</span><span> </span><span>labs</span><span>(</span><span>title</span><span> </span><span>=</span><span> </span><span>&quot;tidyverse packages: Daily downloads&quot;</span><span>,</span><span> </span><span>x</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>,</span><span>
</span><span>subtitle</span><span> </span><span>=</span><span> </span><span>&quot;Zoomed In: 30 and 90 Day Moving Average&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>scale_color_tq</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme_tq</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme</span><span>(</span><span>legend.position</span><span>=</span><span>&quot;none&quot;</span><span>)</span></code></pre>
</figure>
<p><img alt="plot of chunk unnamed-chunk-6" src="https://i1.wp.com/www.business-science.io/figure/source/2017-7-23-tidy-timeseries-analysis-pt-2/unnamed-chunk-6-1.png?w=456" data-recalc-dims="1"></p>
<p>We can see that several packages have strong upward momentum (<code>purrr</code> and <code>lubridate</code>). Others such as <code>dplyr</code>, <code>knitr</code> and <code>tidyr</code> seem to be cycling in a range. Others such as <code>ggplot2</code> and <code>stringr</code> have short term downward trends (keep in mind these packages are getting the most downloads of the bunch). The last point is this is only a six month window of data. The long term trends may be much different than short term, but we’ll leave that for another day.</p>
<h2>Rolling Custom Functions: Useful for multiple statistics</h2>
<p>You may find in your analytic endeavors that you want more than one statistic. Well you’re in luck with custom functions! In this example, we’ll create a custom function, <code>custom_stat_fun_2()</code>, that returns four statistics:</p>
<ul>
<li>mean</li>
<li>standard deviation</li>
<li>95% confidence interval (mean +/- 2SD)</li>
</ul>
<p>The custom function can then be applied in the same way that <code>mean</code> was applied.</p>
<figure>
<pre><code data-lang="r"><span># Custom function to return mean, sd, 95% conf interval
</span><span>custom_stat_fun_2</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>x</span><span>,</span><span> </span><span>na.rm</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span> </span><span>{</span><span>
</span><span># x = numeric vector
</span><span> </span><span># na.rm = boolean, whether or not to remove NA's
</span><span> </span><span>m</span><span> </span><span>&lt;-</span><span> </span><span>mean</span><span>(</span><span>x</span><span>,</span><span> </span><span>na.rm</span><span> </span><span>=</span><span> </span><span>na.rm</span><span>)</span><span>
</span><span>s</span><span> </span><span>&lt;-</span><span> </span><span>sd</span><span>(</span><span>x</span><span>,</span><span> </span><span>na.rm</span><span> </span><span>=</span><span> </span><span>na.rm</span><span>)</span><span>
</span><span>hi</span><span> </span><span>&lt;-</span><span> </span><span>m</span><span> </span><span>+</span><span> </span><span>2</span><span>*</span><span>s</span><span>
</span><span>lo</span><span> </span><span>&lt;-</span><span> </span><span>m</span><span> </span><span>-</span><span> </span><span>2</span><span>*</span><span>s</span><span>
</span><span>ret</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>mean</span><span> </span><span>=</span><span> </span><span>m</span><span>,</span><span> </span><span>stdev</span><span> </span><span>=</span><span> </span><span>s</span><span>,</span><span> </span><span>hi.95</span><span> </span><span>=</span><span> </span><span>hi</span><span>,</span><span> </span><span>lo.95</span><span> </span><span>=</span><span> </span><span>lo</span><span>)</span><span> </span><span>return</span><span>(</span><span>ret</span><span>)</span><span>
</span><span>}</span></code></pre>
</figure>
<p>Now for the fun part: <strong>performing the “tidy” rollapply</strong>. Let’s apply the <code>custom_stat_fun_2()</code> to groups using <code>tq_mutate()</code> and the rolling function <code>rollapply()</code>. The process is almost identical to the process of applying <code>mean()</code> with the main exception that we need to set <code>by.column = FALSE</code> to prevent a “length of dimnames [2]” error. The output returned is a “tidy” data frame with <strong>each statistic in its own column</strong>.</p>
<figure>
<pre><code data-lang="r"><span># Roll apply using custom stat function
</span><span>tidyverse_downloads_rollstats</span><span> </span><span>&lt;-</span><span> </span><span>tidyverse_downloads</span><span> </span><span>%>%</span><span>
</span><span>tq_mutate</span><span>(</span><span>
</span><span>select</span><span> </span><span>=</span><span> </span><span>count</span><span>,</span><span>
</span><span>mutate_fun</span><span> </span><span>=</span><span> </span><span>rollapply</span><span>,</span><span> </span><span># rollapply args
</span><span> </span><span>width</span><span> </span><span>=</span><span> </span><span>30</span><span>,</span><span>
</span><span>align</span><span> </span><span>=</span><span> </span><span>&quot;right&quot;</span><span>,</span><span>
</span><span>by.column</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>,</span><span>
</span><span>FUN</span><span> </span><span>=</span><span> </span><span>custom_stat_fun_2</span><span>,</span><span>
</span><span># FUN args
</span><span> </span><span>na.rm</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>
</span><span>)</span><span>
</span><span>tidyverse_downloads_rollstats</span></code></pre>
</figure>
<figure>
<pre><code data-lang="text">## # A tibble: 1,629 x 7
## # Groups:   package [9]
##    package       date count  mean stdev hi.95 lo.95
##      </code></pre></figure>