<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/timings-of-a-grouped-rank-filter-task/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://www.win-vector.com/blog/2018/08/timings-of-a-grouped-rank-filter-task/"> R â€“ Win-Vector Blog</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<h1>Introduction</h1>
<p><a rel="nofollow" href="https://github.com/WinVector/rqdatatable/blob/master/extras/GroupedRankFilter2.md" target="_blank">This note</a> shares an experiment comparing the performance of a number of data processing systems available in <a rel="nofollow" href="https://www.r-project.org/" target="_blank"><code>R</code></a>. Our notional or example problem is finding the top ranking item per group (group defined by three string columns, and order defined by a single numeric column). This is a common and often needed task.</p>
<p><span></span></p>
<p>
<h1>Comparisons</h1>
<p>First let’s compare three methods on the same grouped ranking problem.</p>
<ul>
<li>&quot;Base-<code>R</code>&quot; (term defined as <code>R</code> plus just core packages, earlier results <a rel="nofollow" href="http://www.win-vector.com/blog/2018/01/base-r-can-be-fast/" target="_blank">here</a>). We are using <code>base::order()</code> with the option &quot;<code>method = &quot;auto&quot;</code>&quot; (as described <a rel="nofollow" href="http://www.win-vector.com/blog/2018/08/r-tip-use-radix-sort/" target="_blank">here</a>).</li>
<li><a rel="nofollow" href="https://cran.r-project.org/package=dplyr" target="_blank"><code>dplyr</code></a>.</li>
<li>The seemingly silly idea of using <a rel="nofollow" href="https://cran.r-project.org/package=reticulate" target="_blank"><code>reticulate</code></a> to ship the data to <code>Python</code>, and then using <a rel="nofollow" href="https://pandas.pydata.org/" target="_blank"><code>Pandas</code></a> to do the work, and finally bring the result back to <code>R</code>.</li>
</ul>
<p>We will plot the run-times (in seconds) of these three solutions to the same task as a function of the number of rows in the problem. For all tasks shorter run-times (being lower on the graph) is better. Since we are plotting a large range of values (1 through 100,000,000 rows) we will present the data as a &quot;log-log&quot; plot.</p>
<p><img border="0" src="https://i0.wp.com/www.win-vector.com/blog/wp-content/uploads/2018/08/present2-1-1.png?resize=660%2C440" alt="Present2 1" width="450" title="present2-1.png" data-recalc-dims="1"></p>
<p>Notice <code>dplyr</code> is slower (higher up on the graph) than base <code>R</code> for all problem scales tested (1 row through 100,000,000 rows). Height differences on a <code>log-y</code> scaled graph such as this represent ratios of run-times and we can see the ratio of <code>dplyr</code> to base-<code>R</code> runtime is large (often over 40 to 1).</p>
<p>Also notice by the time we get the problem size up to 5,000 rows even sending the data to <code>Python</code> and back for <code>Pandas</code> processing is faster than <code>dplyr</code>.</p>
<p>Note: in this article &quot;<code>pandas</code> timing&quot; means the time it would take an <code>R</code> process to use <code>Pandas</code> for data manipulation. This includes the extra overhead of moving the data from <code>R</code> to <code>Python</code>/<code>Pandas</code> and back. This is always going to be slower than <code>Pandas</code> itself as it includes extra overhead. We are <em>not</em> saying <code>R</code> users should round trip their data through <code>Python</code> and (as we will discuss later) these performance numbers alone are not a reason for <code>R</code> users to switch to <code>Python</code>. It <em>does</em> indicate that clients may not always be well-served by a pure-<code>dplyr</code> or pure-<code>tidyverse</code> approach. As an <code>R</code> advocate, I like <code>R</code> to have its best fair chance in the market, regardless of loyalty or dis-loyalty to any one set of packages.</p>
<p>All runs were performed on an Amazon EC2 <code>r4.8xlarge</code> (244 GiB RAM) 64-bit Ubuntu Server 16.04 LTS (HVM), SSD Volume Type – ami-ba602bc2. We used R 3.4.4, with all packages current as of 8-20-2018 (the date of the experiment).</p>
<p>We are not testing <a rel="nofollow" href="https://cran.r-project.org/package=dtplyr" target="_blank"><code>dtplyr</code></a> for the simple reason it did not work with the <code>dplyr</code> pipeline as written. We demonstrate this issue below.</p>
<div>
<pre><code>ds &lt;-<span> </span><span>mk_data</span>(<span>3</span>)

dplyr_pipeline &lt;-<span> </span>. <span>%>%</span>
<span> </span><span>group_by</span>(col_a, col_b, col_c) <span>%>%</span><span> </span>
<span> </span><span>arrange</span>(col_x) <span>%>%</span><span> </span>
<span> </span><span>filter</span>(<span>row_number</span>() <span>==</span><span> </span><span>1</span>) <span>%>%</span>
<span> </span><span>ungroup</span>() <span>%>%</span>
<span> </span><span>arrange</span>(col_a, col_b, col_c, col_x)

ds <span>%>%</span><span> </span>
<span> </span>dplyr_pipeline</code></pre>
</div>
<pre><code>## # A tibble: 3 x 4
##   col_a col_b col_c col_x
##   </code></pre>