<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/writing-better-r-functions-part-three-april-13-2018/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://ibecav.github.io/betterfunctions3/"> Chuck Powell</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><a rel="nofollow" href="https://ibecav.github.io/betterfunctions2/" target="_blank">In my last post</a> I worked<br>
on two functions that took pairs of variables from a dataset and<br>
produced some nice useful <code>ggplot</code> plots from them. We started with the<br>
simplest case, plotting counts of how two variables cross-tabulate. Then<br>
we worked our way up to being able to automate the process of plotting<br>
lots of pairings of variables from the same dataframe. We added a<br>
<strong>feature</strong> to change the plot type and tested for general<br>
functionality. To be honest I thought I was in great shape until I went<br>
and started trying the function on a much larger dataset. Performance<br>
was <strong>terrible</strong> I had made a couple of mistakes at least. Today I’ll<br>
fix those problems and combine our two functions into one function.</p>
<blockquote>
<p><strong>I’m going to output all the plots in a smaller size for the benefit<br>
of you the readers. I’m doing that via RMarkdown and it won’t happen<br>
automatically for you if you download and use the code. I’ll be using<br>
, fig.width=4.5, fig.height=2</strong></p>
</blockquote>
<h2>Background and catch-up</h2>
<p>Some quick setup. In a few paragraphs I’ll add lines to the function so<br>
you don’t have to run the setup code, but for now…</p>
<div>
<div>
<pre><code><span>library</span><span>(</span><span>dplyr</span><span>)</span><span>
</span><span>library</span><span>(</span><span>ggplot2</span><span>)</span><span>
</span><span>library</span><span>(</span><span>microbenchmark</span><span>)</span><span>
</span><span>theme_set</span><span>(</span><span>theme_bw</span><span>())</span><span> </span><span># set theme to my personal preference</span><span>
</span></code></pre>
</div>
</div>
<p>We originally started with a simple task using <code>dplyr</code> and <code>ggplot2</code> in<br>
the console. Take two of the <code>mtcars</code> variables, in this case <code>am</code> and<br>
<code>cyl</code>, and conduct a cross tabulation and then plot it. Since it’s the<br>
sort of thing I’m likely to do often seemed like a good candidate to<br>
write a function for.</p>
<div>
<div>
<pre><code><span>### with dplyr and ggplot manually</span><span>
</span><span>mtcars</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>!</span><span>is.na</span><span>(</span><span>am</span><span>),</span><span> </span><span>!</span><span>is.na</span><span>(</span><span>cyl</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>am</span><span>,</span><span>cyl</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>count</span><span>()</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes</span><span>(</span><span>fill</span><span>=</span><span>am</span><span>,</span><span> </span><span>y</span><span>=</span><span>n</span><span>,</span><span> </span><span>x</span><span>=</span><span>cyl</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_bar</span><span>(</span><span>position</span><span>=</span><span>&quot;dodge&quot;</span><span>,</span><span> </span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i2.wp.com/ibecav.github.io/images/evenbetter1-1.png?w=456" data-recalc-dims="1"></p>
<p><a rel="nofollow" href="https://ibecav.github.io/betterfunctions2/" target="_blank">By the end of the last<br>
post</a> we had accomplished<br>
the following tasks:</p>
<ol>
<li>Our function (called <code>PlotMe</code>) was a lot more robust. It checked for<br>
basic user entry errors, added a useful plot title and generally did<br>
what we wanted.</li>
<li>Along the way we learned the <strong>“tricks”</strong> of working with <code>dplyr</code><br>
and <code>ggplot2</code> inside of functions.</li>
<li>It allowed the user to choose the plot type from among three options</li>
<li>We could feed it a pair of bare variable names e.g. <code>am</code> &amp; <code>vs</code> or<br>
through a helper we could also feed it multiple column numbers from<br>
the data frame and it would produce plots of all the combinations.</li>
</ol>
<p>Here’s the <code>PlotMeX</code> function as we left it (with error checking removed<br>
for clarity). If you’re not familiar with <code>enquo</code> or the <code>!!</code> notation<br>
please <a rel="nofollow" href="https://ibecav.github.io/customize/" target="_blank">refer back to an earlier post<br>
here</a>.</p>
<div>
<div>
<pre><code><span>PlotMeX</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>dataframe</span><span>,</span><span> </span><span>x</span><span>,</span><span> </span><span>y</span><span>,</span><span> </span><span>plottype</span><span> </span><span>=</span><span> </span><span>&quot;side&quot;</span><span>){</span><span>
</span><span>switch</span><span>(</span><span>plottype</span><span>,</span><span>
</span><span>side</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>position</span><span>=</span><span>&quot;dodge&quot;</span><span>,</span><span> </span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Count&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>,</span><span>
</span><span>stack</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Count&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>,</span><span>
</span><span>percent</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>,</span><span> </span><span>position</span><span>=</span><span>&quot;fill&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Percent&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>
</span><span>)</span><span>
</span><span>aaa</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>x</span><span>)</span><span>
</span><span>bbb</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>y</span><span>)</span><span>
</span><span>dfname</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>dataframe</span><span>)</span><span>
</span><span>dataframe</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>),</span><span> </span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>!!</span><span>quo_name</span><span>(</span><span>aaa</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>aaa</span><span>),</span><span> </span><span>!!</span><span>quo_name</span><span>(</span><span>bbb</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>,</span><span>!!</span><span> </span><span>bbb</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>count</span><span>()</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes_</span><span>(</span><span>fill</span><span>=</span><span>aaa</span><span>,</span><span> </span><span>y</span><span>=~</span><span>n</span><span>,</span><span> </span><span>x</span><span>=</span><span>bbb</span><span>))</span><span> </span><span>+</span><span>
</span><span>whichbar</span><span> </span><span>+</span><span>
</span><span>ggtitle</span><span>(</span><span>bquote</span><span>(</span><span>&quot;Crosstabs&quot;</span><span>*</span><span>.</span><span>(</span><span>dfname</span><span>)</span><span>*</span><span>.</span><span>(</span><span>aaa</span><span>)</span><span>~</span><span>&quot;by&quot;</span><span>*</span><span>.</span><span>(</span><span>bbb</span><span>)))</span><span> </span><span>-></span><span> </span><span>p</span><span>
</span><span>plot</span><span>(</span><span>p</span><span>)</span><span>
</span><span>}</span><span>
</span><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span> </span><span>am</span><span>,</span><span> </span><span>vs</span><span>,</span><span> </span><span>&quot;stack&quot;</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i1.wp.com/ibecav.github.io/images/evenbetter2-1.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span> </span><span>am</span><span>,</span><span> </span><span>vs</span><span>,</span><span> </span><span>&quot;percent&quot;</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i2.wp.com/ibecav.github.io/images/evenbetter2-2.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code><span>PlotMeX</span><span>(</span><span>esoph</span><span>,</span><span> </span><span>alcgp</span><span>,</span><span> </span><span>tobgp</span><span>,</span><span> </span><span>&quot;side&quot;</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i1.wp.com/ibecav.github.io/images/evenbetter2-3.png?w=456" data-recalc-dims="1"></p>
<p>As you can see it works fine as far as we can tell on the <code>mtcars</code> data<br>
set as well as the <code>esoph</code> dataset (which is also smallish). The problem<br>
I discovered was that it was gross in performing on bigger datasets.<br>
Especially if I fed it to <code>mapply</code>. Made no sense since I was not<br>
plotting a full dataset I was plotting the crosstab data which is<br>
already summarized and doesn’t have a lot of rows or columns. Something<br>
was wrong.</p>
<h2>What went wrong</h2>
<p>Turns out I made two mistakes. Both of them had to do with how much data<br>
I was accumulating especially over larger data sets or over repetitions.<br>
3 keys tools may help you figure these things out. <code>microbenchmark</code>,<br>
<code>benchplot</code> and just good old fashioned inspection of what the results<br>
the function returns are.</p>
<div>
<div>
<pre><code><span># deliberately surpressing the figures!</span><span>
</span><span>microbenchmark</span><span>(</span><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span> </span><span>am</span><span>,</span><span> </span><span>cyl</span><span>),</span><span> </span><span>times</span><span> </span><span>=</span><span> </span><span>10</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<div>
<div>
<pre><code>## Unit: milliseconds
##                      expr      min       lq     mean   median       uq
##  PlotMeX(mtcars, am, cyl) 244.5679 254.0199 255.1998 256.5568 257.5296
##       max neval
##  262.8945    10
</code></pre>
</div>
</div>
<div>
<div>
<pre><code><span>benchplot</span><span>(</span><span>mtcars</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>!</span><span>is.na</span><span>(</span><span>am</span><span>),</span><span> </span><span>!</span><span>is.na</span><span>(</span><span>cyl</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>am</span><span>,</span><span>cyl</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>count</span><span>()</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes</span><span>(</span><span>fill</span><span>=</span><span>am</span><span>,</span><span> </span><span>y</span><span>=</span><span>n</span><span>,</span><span> </span><span>x</span><span>=</span><span>cyl</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_bar</span><span>(</span><span>position</span><span>=</span><span>&quot;dodge&quot;</span><span>,</span><span> </span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>))</span><span>
</span></code></pre>
</div>
</div>
<div>
<div>
<pre><code>##        step user.self sys.self elapsed
## 1 construct     0.005    0.000   0.005
## 2     build     0.019    0.000   0.020
## 3    render     0.150    0.003   0.157
## 4      draw     0.065    0.009   0.095
## 5     TOTAL     0.239    0.012   0.277
</code></pre>
</div>
</div>
<div>
<div>
<pre><code><span># don't forget to check your &quot;returns&quot;</span><span>
</span><span>inspectthisobject</span><span> </span><span>&lt;-</span><span> </span><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span> </span><span>am</span><span>,</span><span> </span><span>cyl</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p>In my case I decided to play it extra safe and add a intermediate<br>
dataframe called <code>tempdf</code>. That way it would be much harder to ever<br>
accidentally return too much data no matter how I called or invoked the<br>
function.</p>
<div>
<div>
<pre><code><span> </span><span>count</span><span>()</span><span> </span><span>-></span><span> </span><span>tempdf</span><span>
</span><span>tempdf</span><span> </span><span>%>%</span><span>
</span></code></pre>
</div>
</div>
<p>But the real culprit was <code>dfname &lt;- enquo(dataframe)</code> which should have<br>
been <code>dfname &lt;- deparse(substitute(dataframe))</code> or you run the risk of<br>
passing back way too much data within the subsequent<br>
<code>ggtitle(bquote(&quot;Crosstabs&quot;*.(dfname)*.(aaa)~&quot;by&quot;*.(bbb)))</code>.</p>
<p>Okay, now our <code>PlotMeX</code> has become…</p>
<div>
<div>
<pre><code><span>PlotMeX</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>dataframe</span><span>,</span><span> </span><span>x</span><span>,</span><span> </span><span>y</span><span>,</span><span> </span><span>plottype</span><span> </span><span>=</span><span> </span><span>&quot;side&quot;</span><span>){</span><span>
</span><span>switch</span><span>(</span><span>plottype</span><span>,</span><span>
</span><span>side</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>position</span><span>=</span><span>&quot;dodge&quot;</span><span>,</span><span> </span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Count&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>,</span><span>
</span><span>stack</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Count&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>,</span><span>
</span><span>percent</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>,</span><span> </span><span>position</span><span>=</span><span>&quot;fill&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Percent&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>
</span><span>)</span><span>
</span><span>aaa</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>x</span><span>)</span><span>
</span><span>bbb</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>y</span><span>)</span><span>
</span><span>xname</span><span> </span><span>&lt;-</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>x</span><span>))</span><span>
</span><span>yname</span><span> </span><span>&lt;-</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>y</span><span>))</span><span>
</span><span>dfname</span><span> </span><span>&lt;-</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>dataframe</span><span>))</span><span>
</span><span>dataframe</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>),</span><span> </span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>!!</span><span>quo_name</span><span>(</span><span>aaa</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>aaa</span><span>),</span><span> </span><span>!!</span><span>quo_name</span><span>(</span><span>bbb</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>,</span><span>!!</span><span> </span><span>bbb</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>count</span><span>()</span><span> </span><span>-></span><span> </span><span>tempdf</span><span>
</span><span>tempdf</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes_</span><span>(</span><span>fill</span><span>=</span><span>aaa</span><span>,</span><span> </span><span>y</span><span>=~</span><span>n</span><span>,</span><span> </span><span>x</span><span>=</span><span>bbb</span><span>))</span><span> </span><span>+</span><span>
</span><span>whichbar</span><span> </span><span>+</span><span>
</span><span>ggtitle</span><span>(</span><span>bquote</span><span>(</span><span>&quot;Crosstabs &quot;</span><span>*</span><span>.</span><span>(</span><span>dfname</span><span>)</span><span>~</span><span>.</span><span>(</span><span>xname</span><span>)</span><span>~</span><span>&quot;by &quot;</span><span>~</span><span>.</span><span>(</span><span>yname</span><span>)))</span><span> </span><span>-></span><span> </span><span>p</span><span>
</span><span>plot</span><span>(</span><span>p</span><span>)</span><span>
</span><span>return</span><span>(</span><span>dfname</span><span>)</span><span>
</span><span>}</span><span>
</span><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span>am</span><span>,</span><span>vs</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i2.wp.com/ibecav.github.io/images/evenbetter5-1.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code>## [1] &quot;mtcars&quot;
</code></pre>
</div>
</div>
<div>
<div>
<pre><code><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span>am</span><span>,</span><span>vs</span><span>,</span><span> </span><span>&quot;stack&quot;</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i0.wp.com/ibecav.github.io/images/evenbetter5-2.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code>## [1] &quot;mtcars&quot;
</code></pre>
</div>
</div>
<div>
<div>
<pre><code><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span>am</span><span>,</span><span>vs</span><span>,</span><span> </span><span>&quot;percent&quot;</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i2.wp.com/ibecav.github.io/images/evenbetter5-3.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code>## [1] &quot;mtcars&quot;
</code></pre>
</div>
</div>
<p>That’s better. To summarize we now have <code>PlotMeX</code> which does our<br>
plotting, the <code>CrossXYs</code> function which generates lists of things to be<br>
plotted, and our error-checking code for user input that I have been<br>
ignoring for awhile now. To remind you here’s <code>CrossXYs</code>.</p>
<div>
<div>
<pre><code><span>CrossXYs</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>dataframe</span><span>,</span><span> </span><span>xwhich</span><span>,</span><span> </span><span>ywhich</span><span>){</span><span>
</span><span># Build two vectors</span><span>
</span><span>indvars</span><span>&lt;-</span><span>list</span><span>()</span><span> </span><span># create empty list to add to</span><span>
</span><span>depvars</span><span>&lt;-</span><span>list</span><span>()</span><span> </span><span># create empty list to add to</span><span>
</span><span>totalcombos</span><span> </span><span>&lt;-</span><span> </span><span>1</span><span> </span><span># keep track of where we are</span><span>
</span><span>message</span><span>(</span><span>&quot;Creating the variable pairings...&quot;</span><span>)</span><span>
</span><span>for</span><span> </span><span>(</span><span>j</span><span> </span><span>in</span><span> </span><span>seq_along</span><span>(</span><span>xwhich</span><span>))</span><span> </span><span>{</span><span>
</span><span>for</span><span> </span><span>(</span><span>k</span><span> </span><span>in</span><span> </span><span>seq_along</span><span>(</span><span>ywhich</span><span>))</span><span> </span><span>{</span><span>
</span><span>depvars</span><span>[[</span><span>totalcombos</span><span>]]</span><span> </span><span>&lt;-</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>xwhich</span><span>[[</span><span>j</span><span>]]]))</span><span>
</span><span>indvars</span><span>[[</span><span>totalcombos</span><span>]]</span><span> </span><span>&lt;-</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>ywhich</span><span>[[</span><span>k</span><span>]]]))</span><span>
</span><span>cat</span><span>(</span><span>&quot;Pairing #&quot;</span><span>,</span><span> </span><span>totalcombos</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>xwhich</span><span>[[</span><span>j</span><span>]]])),</span><span>
</span><span>&quot; with &quot;</span><span>,</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>ywhich</span><span>[[</span><span>k</span><span>]]])),</span><span> </span><span>&quot;\n&quot;</span><span>,</span><span> </span><span>sep</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>)</span><span>
</span><span>totalcombos</span><span> </span><span>&lt;-</span><span> </span><span>totalcombos</span><span> </span><span>+1</span><span>
</span><span>}</span><span>
</span><span>}</span><span>
</span><span>return</span><span>(</span><span>invisible</span><span>(</span><span>list</span><span>(</span><span>depvars</span><span>=</span><span>depvars</span><span>,</span><span>indvars</span><span>=</span><span>indvars</span><span>)))</span><span>
</span><span>}</span><span>
</span><span>CrossXYs</span><span>(</span><span>mtcars</span><span>,</span><span>c</span><span>(</span><span>10</span><span>:</span><span>11</span><span>),</span><span>c</span><span>(</span><span>2</span><span>,</span><span>9</span><span>))</span><span>
</span></code></pre>
</div>
</div>
<div>
<div>
<pre><code>## Creating the variable pairings...

## Pairing #1 gear with cyl
## Pairing #2 gear with am
## Pairing #3 carb with cyl
## Pairing #4 carb with am
</code></pre>
</div>
</div>
<h2>Consolidate for success</h2>
<p>My original plan had been to leave them as separate functions and use<br>
<code>mapply</code> to invoke a multiplot option. But the more I thought about it<br>
the more I liked the idea of one function that took care of everything.<br>
So what I needed to do was combine the two and figure out from what the<br>
user supplies which path to pursue. Here’s the finished product. For now<br>
(as we troubleshoot) I have programmed it to return the arguments it was<br>
passed. If you want to refresh your memory on the error checking pieces<br>
<a rel="nofollow" href="https://ibecav.github.io/betterfunctions/" target="_blank">please refer to this post</a>.</p>
<div>
<div>
<pre><code><span>PlotMeX</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>dataframe</span><span>,</span><span> </span><span>xwhich</span><span>,</span><span> </span><span>ywhich</span><span>,</span><span> </span><span>plottype</span><span> </span><span>=</span><span> </span><span>&quot;side&quot;</span><span>){</span><span>
</span><span># error checking</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>require</span><span>(</span><span>ggplot2</span><span>))</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;Can't continue can't load ggplot2&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>theme_set</span><span>(</span><span>theme_bw</span><span>())</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>require</span><span>(</span><span>dplyr</span><span>))</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;Can't continue can't load dplyr&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>if</span><span> </span><span>(</span><span>length</span><span>(</span><span>match.call</span><span>())</span><span> </span><span>&lt;=</span><span> </span><span>3</span><span>)</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;Not enough arguments passed... requires a dataframe, plus at least two variables&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>argList</span><span> </span><span>&lt;-</span><span> </span><span>as.list</span><span>(</span><span>match.call</span><span>()[</span><span>-1</span><span>])</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>exists</span><span>(</span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>dataframe</span><span>))))</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;The first object in your list does not exist. It should be a dataframe&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>is</span><span>(</span><span>dataframe</span><span>,</span><span> </span><span>&quot;data.frame&quot;</span><span>))</span><span> </span><span>{</span><span>
</span><span>stop</span><span>(</span><span>&quot;The first name you passed does not appear to be a data frame&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>switch</span><span>(</span><span>plottype</span><span>,</span><span>
</span><span>side</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>position</span><span>=</span><span>&quot;dodge&quot;</span><span>,</span><span> </span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Count&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>,</span><span>
</span><span>stack</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Count&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>,</span><span>
</span><span>percent</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>geom_bar</span><span>(</span><span>stat</span><span>=</span><span>&quot;identity&quot;</span><span>,</span><span> </span><span>position</span><span>=</span><span>&quot;fill&quot;</span><span>),</span><span>
</span><span>ylab</span><span>(</span><span>&quot;Percent&quot;</span><span>))</span><span> </span><span>-></span><span> </span><span>whichbar</span><span>
</span><span>)</span><span>
</span><span># If both variables are found in the dataframe immediately print the plot</span><span>
</span><span>if</span><span> </span><span>(</span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>xwhich</span><span>))</span><span> </span><span>%in%</span><span> </span><span>names</span><span>(</span><span>dataframe</span><span>)</span><span> </span><span>&amp;</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>ywhich</span><span>))</span><span> </span><span>%in%</span><span> </span><span>names</span><span>(</span><span>dataframe</span><span>))</span><span> </span><span>{</span><span>
</span><span>aaa</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>xwhich</span><span>)</span><span>
</span><span>bbb</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>ywhich</span><span>)</span><span>
</span><span>xname</span><span> </span><span>&lt;-</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>xwhich</span><span>))</span><span>
</span><span>yname</span><span> </span><span>&lt;-</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>ywhich</span><span>))</span><span>
</span><span>dfname</span><span> </span><span>&lt;-</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>dataframe</span><span>))</span><span>
</span><span>dataframe</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>),</span><span> </span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>!!</span><span>quo_name</span><span>(</span><span>aaa</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>aaa</span><span>),</span><span> </span><span>!!</span><span>quo_name</span><span>(</span><span>bbb</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>,</span><span>!!</span><span> </span><span>bbb</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>count</span><span>()</span><span> </span><span>-></span><span> </span><span>tempdf</span><span>
</span><span>tempdf</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes_</span><span>(</span><span>fill</span><span>=</span><span>aaa</span><span>,</span><span> </span><span>y</span><span>=~</span><span>n</span><span>,</span><span> </span><span>x</span><span>=</span><span>bbb</span><span>))</span><span> </span><span>+</span><span>
</span><span>whichbar</span><span> </span><span>+</span><span>
</span><span>ggtitle</span><span>(</span><span>bquote</span><span>(</span><span>&quot;Crosstabs dataset: &quot;</span><span>*</span><span>.</span><span>(</span><span>dfname</span><span>)</span><span>*</span><span>&quot; variables &quot;</span><span>*</span><span>.</span><span>(</span><span>xname</span><span>)</span><span>~</span><span>&quot;by &quot;</span><span>*</span><span>.</span><span>(</span><span>yname</span><span>)))</span><span> </span><span>-></span><span> </span><span>p</span><span>
</span><span>return</span><span>(</span><span>p</span><span>)</span><span>
</span><span>}</span><span>
</span><span># If the user has given us integers indicating the column numbers rather than bare variable names</span><span>
</span><span># we need to build a list of what is to be plotted and then do the plotting</span><span>
</span><span># Build two lists</span><span>
</span><span>indvars</span><span>&lt;-</span><span>list</span><span>()</span><span> </span><span># create empty list to add to</span><span>
</span><span>depvars</span><span>&lt;-</span><span>list</span><span>()</span><span> </span><span># create empty list to add to</span><span>
</span><span>totalcombos</span><span> </span><span>&lt;-</span><span> </span><span>1</span><span> </span><span># keep track of where we are</span><span>
</span><span>message</span><span>(</span><span>&quot;Creating the variable pairings...&quot;</span><span>)</span><span>
</span><span>for</span><span> </span><span>(</span><span>j</span><span> </span><span>in</span><span> </span><span>seq_along</span><span>(</span><span>xwhich</span><span>))</span><span> </span><span>{</span><span>
</span><span>for</span><span> </span><span>(</span><span>k</span><span> </span><span>in</span><span> </span><span>seq_along</span><span>(</span><span>ywhich</span><span>))</span><span> </span><span>{</span><span>
</span><span>depvarsbare</span><span> </span><span>&lt;-</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>xwhich</span><span>[[</span><span>j</span><span>]]]))</span><span>
</span><span>indvarsbare</span><span> </span><span>&lt;-</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>ywhich</span><span>[[</span><span>k</span><span>]]]))</span><span>
</span><span>cat</span><span>(</span><span>&quot;Pairing #&quot;</span><span>,</span><span> </span><span>totalcombos</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>xwhich</span><span>[[</span><span>j</span><span>]]])),</span><span>
</span><span>&quot; with &quot;</span><span>,</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>ywhich</span><span>[[</span><span>k</span><span>]]])),</span><span> </span><span>&quot;\n&quot;</span><span>,</span><span> </span><span>sep</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>)</span><span>
</span><span>aaa</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>depvarsbare</span><span>)</span><span>
</span><span>bbb</span><span> </span><span>&lt;-</span><span> </span><span>enquo</span><span>(</span><span>indvarsbare</span><span>)</span><span>
</span><span>xname</span><span> </span><span>&lt;-</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>depvarsbare</span><span>))</span><span>
</span><span>yname</span><span> </span><span>&lt;-</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>indvarsbare</span><span>))</span><span>
</span><span>dfname</span><span> </span><span>&lt;-</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>dataframe</span><span>))</span><span>
</span><span>dataframe</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>),</span><span> </span><span>!</span><span>is.na</span><span>(</span><span>!!</span><span> </span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>!!</span><span>quo_name</span><span>(</span><span>aaa</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>aaa</span><span>),</span><span> </span><span>!!</span><span>quo_name</span><span>(</span><span>bbb</span><span>)</span><span> </span><span>:=</span><span> </span><span>factor</span><span>(</span><span>!!</span><span>bbb</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>!!</span><span> </span><span>aaa</span><span>,</span><span>!!</span><span> </span><span>bbb</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>count</span><span>()</span><span> </span><span>-></span><span> </span><span>tempdf</span><span>
</span><span>tempdf</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes_</span><span>(</span><span>fill</span><span>=</span><span>aaa</span><span>,</span><span> </span><span>y</span><span>=~</span><span>n</span><span>,</span><span> </span><span>x</span><span>=</span><span>bbb</span><span>))</span><span> </span><span>+</span><span>
</span><span>whichbar</span><span> </span><span>+</span><span>
</span><span>ggtitle</span><span>(</span><span>bquote</span><span>(</span><span>&quot;Crosstabs dataset: &quot;</span><span>*</span><span>.</span><span>(</span><span>dfname</span><span>)</span><span>*</span><span>&quot; variables &quot;</span><span>*</span><span>.</span><span>(</span><span>xname</span><span>)</span><span>~</span><span>&quot;by &quot;</span><span>*</span><span>.</span><span>(</span><span>yname</span><span>)))</span><span> </span><span>-></span><span> </span><span>p</span><span>
</span><span>print</span><span>(</span><span>p</span><span>)</span><span>
</span><span>totalcombos</span><span> </span><span>&lt;-</span><span> </span><span>totalcombos</span><span> </span><span>+1</span><span>
</span><span>}</span><span>
</span><span>}</span><span>
</span><span>return</span><span>(</span><span>argList</span><span>)</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
</div>
<p>It’s a bit ugly and we need to clean it up, but it works whether the<br>
user gives me two bare variable names, or two sets of variables, or even<br>
just two column numbers</p>
<div>
<div>
<pre><code><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span> </span><span>vs</span><span>,</span><span> </span><span>cyl</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<p><img alt="" src="https://i1.wp.com/ibecav.github.io/images/evenbetter8-1.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span> </span><span>c</span><span>(</span><span>8</span><span>:</span><span>9</span><span>),</span><span> </span><span>c</span><span>(</span><span>2</span><span>,</span><span>10</span><span>),</span><span> </span><span>plottype</span><span> </span><span>=</span><span> </span><span>&quot;stack&quot;</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<div>
<div>
<pre><code>## Creating the variable pairings...

## Pairing #1 vs with cyl
</code></pre>
</div>
</div>
<p><img alt="" src="https://i1.wp.com/ibecav.github.io/images/evenbetter8-2.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code>## Pairing #2 vs with gear
</code></pre>
</div>
</div>
<p><img alt="" src="https://i2.wp.com/ibecav.github.io/images/evenbetter8-3.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code>## Pairing #3 am with cyl
</code></pre>
</div>
</div>
<p><img alt="" src="https://i0.wp.com/ibecav.github.io/images/evenbetter8-4.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code>## Pairing #4 am with gear
</code></pre>
</div>
</div>
<p><img alt="" src="https://i2.wp.com/ibecav.github.io/images/evenbetter8-5.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code>## $dataframe
## mtcars
## 
## $xwhich
## c(8:9)
## 
## $ywhich
## c(2, 10)
## 
## $plottype
## [1] &quot;stack&quot;
</code></pre>
</div>
</div>
<div>
<div>
<pre><code><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span> </span><span>2</span><span>,</span><span> </span><span>8</span><span>,</span><span> </span><span>&quot;percent&quot;</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<div>
<div>
<pre><code>## Creating the variable pairings...

## Pairing #1 cyl with vs
</code></pre>
</div>
</div>
<p><img alt="" src="https://i2.wp.com/ibecav.github.io/images/evenbetter8-6.png?w=456" data-recalc-dims="1"></p>
<div>
<div>
<pre><code>## $dataframe
## mtcars
## 
## $xwhich
## [1] 2
## 
## $ywhich
## [1] 8
## 
## $plottype
## [1] &quot;percent&quot;
</code></pre>
</div>
</div>
<p>For those of you who have followed his whole series of posts you’ll<br>
notice that most of what is now in the function you have seen before.<br>
It’s just reorganized. We only handle the two “clean” cases of user<br>
input all bare variables or all integers. The key differences I would<br>
note are:</p>
<div>
<div>
<pre><code><span> </span><span># capture the arguments we're passed in</span><span>
</span><span>argList</span><span> </span><span>&lt;-</span><span> </span><span>as.list</span><span>(</span><span>match.call</span><span>()[</span><span>-1</span><span>])</span><span>
</span><span># An if test to see if both variables are bare </span><span>
</span><span># if they are we'll execute immediately</span><span>
</span><span>if</span><span> </span><span>(</span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>xwhich</span><span>))</span><span> </span><span>%in%</span><span> </span><span>names</span><span>(</span><span>dataframe</span><span>)</span><span> </span><span>&amp;</span><span> </span><span>deparse</span><span>(</span><span>substitute</span><span>(</span><span>ywhich</span><span>))</span><span> </span><span>%in%</span><span> </span><span>names</span><span>(</span><span>dataframe</span><span>))</span><span>
</span><span># these two commands move us from column number inside the loop to bare variable name</span><span>
</span><span>depvarsbare</span><span> </span><span>&lt;-</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>xwhich</span><span>[[</span><span>j</span><span>]]]))</span><span>
</span><span>indvarsbare</span><span> </span><span>&lt;-</span><span> </span><span>as.name</span><span>(</span><span>colnames</span><span>(</span><span>dataframe</span><span>[</span><span>ywhich</span><span>[[</span><span>k</span><span>]]]))</span><span>
</span></code></pre>
</div>
</div>
<p>Performance wise, let’s rerun the same <code>microbench</code> as earlier. The<br>
original mean time was ~255 milliseconds.</p>
<div>
<div>
<pre><code><span># deliberately surpressing the figures!</span><span>
</span><span>microbenchmark</span><span>(</span><span>PlotMeX</span><span>(</span><span>mtcars</span><span>,</span><span> </span><span>am</span><span>,</span><span> </span><span>cyl</span><span>),</span><span> </span><span>times</span><span> </span><span>=</span><span> </span><span>10</span><span>)</span><span>
</span></code></pre>
</div>
</div>
<div>
<div>
<pre><code>## Unit: milliseconds
##                      expr      min       lq     mean   median       uq
##  PlotMeX(mtcars, am, cyl) 9.073721 9.444969 10.52728 9.970719 10.86919
##       max neval
##  14.90618    10
</code></pre>
</div>
</div>
<p>Our new benchmark? About 9 milliseconds! Very nice! We seem to have<br>
accomplished what we set out to do. Just to be safe I also tested<br>
against the much larger (N=51020) <code>happy</code> dataset from the<br>
<code>productplots</code> package it took ~18 milliseconds.</p>
<h2>All done (not yet!)</h2>
<p>This has become a very long post so I’m going to end here. Next post<br>
we’ll cleanup our code and try and address some likely issues.</p>
<p>I hope you’ve found this useful. I am always open to comments,<br>
corrections and suggestions.</p>
<p>Chuck (ibecav at gmail dot<br>
com)</p>
<h3>License</h3>
<p><a rel="nofollow" href="http://creativecommons.org/licenses/by-sa/4.0/" target="_blank"><img alt="Creative Commons License" src="https://i1.wp.com/i.creativecommons.org/l/by-sa/4.0/88x31.png?w=456&ssl=1" data-recalc-dims="1"></a><br>This<br>
work is licensed under a<br>
<a rel="nofollow" href="http://creativecommons.org/licenses/by-sa/4.0/" target="_blank">Creative<br>
Commons Attribution-ShareAlike 4.0 International License</a>.</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://ibecav.github.io/betterfunctions3/"> Chuck Powell</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/NGPdyzn98Bk" height="1"></a></div>