<p><div><div><div><div data-width="100" data-show-faces="false" data-send="true" data-layout="button_count" data-height="21" data-href="https://www.r-bloggers.com/predicting-food-preferences-with-sparklyr-machine-learning/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://shiring.github.io/machine_learning/2017/02/19/food_spark"> Shirin's playgRound</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>This week I want to show how to run machine learning applications on a Spark cluster. I am using the <a target="_blank" rel="nofollow" href="http://spark.rstudio.com/"><strong>sparklyr</strong></a> package, which provides a handy interface to access Apache Spark functionalities via R.</p>
<p>The question I want to address with machine learning is whether the preference for a country’s cuisine can be predicted based on preferences of other countries’ cuisines.</p>
<p></p>
<h3>Apache Spark</h3>
<p><a target="_blank" rel="nofollow" href="http://spark.apache.org/">Apache Spark™</a> can be used to perform large-scale data analysis workflows by taking advantage of its parallel cluster-computing setup.<br>
Because machine learning processes are iterative, running models on parallel clusters can vastly increase the speed of training.<br>
Obviously, Spark’s power comes to pass when dispatching it to external clusters, but for demonstration purposes, I am running the demo on a local Spark instance.</p>
<h4>MLlib</h4>
<p>Spark’s distributed machine learning library MLlib sits on top of the Spark core framework. It implements many popular machine learning algorithms, plus many helper functions for data preprocessing.<br>
With <strong>sparklyr</strong> you can easily access <a target="_blank" rel="nofollow" href="http://spark.rstudio.com/mllib.html">MLlib</a>. You can work with a couple of different machine learning algorithms and with functions for manipulating features and Spark dataframes. Additionally, you can also perform SQL queries. <strong>sparklyr</strong> also implements <strong>dplyr</strong>, making it especially convenient for handling data.</p>
<p>If you don’t have Spark installed locally, run:</p>
<div>
<pre><code><span>library</span><span>(</span><span>sparklyr</span><span>)</span><span>
</span><span>spark_install</span><span>(</span><span>version</span><span> </span><span>=</span><span> </span><span>&quot;2.0.0&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p>Now we can connect to a local Spark instance:</p>
<div>
<pre><code><span>library</span><span>(</span><span>sparklyr</span><span>)</span><span>
</span><span>sc</span><span> </span><span>&lt;-</span><span> </span><span>spark_connect</span><span>(</span><span>master</span><span> </span><span>=</span><span> </span><span>&quot;local&quot;</span><span>,</span><span> </span><span>version</span><span> </span><span>=</span><span> </span><span>&quot;2.0.0&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p></p>
<h3>Preparations</h3>
<p>Before I start with the analysis, I am preparing my custom ggplot2 theme and load the packages <strong>tidyr</strong> (for gathering data for plotting), <strong>dplyr</strong> (for data manipulation) and <strong>ggrepel</strong> (for non-overlapping text labels in plots).</p>
<div>
<pre><code><span>library</span><span>(</span><span>tidyr</span><span>)</span><span>
</span><span>library</span><span>(</span><span>ggplot2</span><span>)</span><span>
</span><span>library</span><span>(</span><span>ggrepel</span><span>)</span><span>
</span><span>library</span><span>(</span><span>dplyr</span><span>)</span><span>
</span><span>my_theme</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>base_size</span><span> </span><span>=</span><span> </span><span>12</span><span>,</span><span> </span><span>base_family</span><span> </span><span>=</span><span> </span><span>&quot;sans&quot;</span><span>){</span><span>
</span><span>theme_minimal</span><span>(</span><span>base_size</span><span> </span><span>=</span><span> </span><span>base_size</span><span>,</span><span> </span><span>base_family</span><span> </span><span>=</span><span> </span><span>base_family</span><span>)</span><span> </span><span>+</span><span>
</span><span>theme</span><span>(</span><span>
</span><span>axis.text</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>12</span><span>),</span><span>
</span><span>axis.title</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>14</span><span>),</span><span>
</span><span>panel.grid.major</span><span> </span><span>=</span><span> </span><span>element_line</span><span>(</span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;grey&quot;</span><span>),</span><span>
</span><span>panel.grid.minor</span><span> </span><span>=</span><span> </span><span>element_blank</span><span>(),</span><span>
</span><span>panel.background</span><span> </span><span>=</span><span> </span><span>element_rect</span><span>(</span><span>fill</span><span> </span><span>=</span><span> </span><span>&quot;aliceblue&quot;</span><span>),</span><span>
</span><span>strip.background</span><span> </span><span>=</span><span> </span><span>element_rect</span><span>(</span><span>fill</span><span> </span><span>=</span><span> </span><span>&quot;lightgrey&quot;</span><span>,</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;grey&quot;</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>1</span><span>),</span><span>
</span><span>strip.text</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>face</span><span> </span><span>=</span><span> </span><span>&quot;bold&quot;</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>12</span><span>,</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;black&quot;</span><span>),</span><span>
</span><span>legend.position</span><span> </span><span>=</span><span> </span><span>&quot;right&quot;</span><span>,</span><span>
</span><span>legend.justification</span><span> </span><span>=</span><span> </span><span>&quot;top&quot;</span><span>,</span><span> </span><span>panel.border</span><span> </span><span>=</span><span> </span><span>element_rect</span><span>(</span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;grey&quot;</span><span>,</span><span> </span><span>fill</span><span> </span><span>=</span><span> </span><span>NA</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>0.5</span><span>)</span><span>
</span><span>)</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p></p>
<h3>The Data</h3>
<p>Of course, the power of Spark lies in speeding up operations on large datasets. But because that’s not very handy for demonstration, I am here working with a small dataset: the raw data behind <a target="_blank" rel="nofollow" href="http://fivethirtyeight.com/features/the-fivethirtyeight-international-food-associations-2014-world-cup">The FiveThirtyEight International Food Association’s 2014 World Cup</a>.</p>
<p>This dataset is part of the <strong>fivethirtyeight</strong> package and provides scores for how each person rated their preference of the dishes from several countries. The following categories could be chosen:</p>
<ul>
<li>5: I love this country’s traditional cuisine. I think it’s one of the best in the world.</li>
<li>4: I like this country’s traditional cuisine. I think it’s considerably above average.</li>
<li>3: I’m OK with this county’s traditional cuisine. I think it’s about average.</li>
<li>2: I dislike this country’s traditional cuisine. I think it’s considerably below average.</li>
<li>1: I hate this country’s traditional cuisine. I think it’s one of the worst in the world.</li>
<li>N/A: I’m unfamiliar with this country’s traditional cuisine.</li>
</ul>
<p>Because I think that whether someone doesn’t know a country’s cuisine is in itself information, I recoded NAs to 0.</p>
<div>
<pre><code><span>library</span><span>(</span><span>fivethirtyeight</span><span>)</span><span>
</span><span>food_world_cup</span><span>[</span><span>food_world_cup</span><span> </span><span>==</span><span> </span><span>&quot;N/A&quot;</span><span>]</span><span> </span><span>&lt;-</span><span> </span><span>NA</span><span>
</span><span>food_world_cup</span><span>[,</span><span> </span><span>9</span><span>:</span><span>48</span><span>][</span><span>is.na</span><span>(</span><span>food_world_cup</span><span>[,</span><span> </span><span>9</span><span>:</span><span>48</span><span>])]</span><span> </span><span>&lt;-</span><span> </span><span>0</span><span>
</span><span>food_world_cup</span><span>$</span><span>gender</span><span> </span><span>&lt;-</span><span> </span><span>as.factor</span><span>(</span><span>food_world_cup</span><span>$</span><span>gender</span><span>)</span><span>
</span><span>food_world_cup</span><span>$</span><span>location</span><span> </span><span>&lt;-</span><span> </span><span>as.factor</span><span>(</span><span>food_world_cup</span><span>$</span><span>location</span><span>)</span><span>
</span></code></pre>
</div>
<p>The question I want to address with machine learning is whether the preference for a country’s cuisine can be predicted based on preferences of other countries’ cuisines, general knowledge and interest in different cuisines, age, gender, income, education level and/ or location.</p>
<p>Before I do any machine learning, however, I want to get to know the data.<br>
First, I am calculating the percentages for each preference category and plot them with a pie chart that is facetted by country.</p>
<div>
<pre><code><span># calculating percentages per category and country
</span><span>percentages</span><span> </span><span>&lt;-</span><span> </span><span>food_world_cup</span><span> </span><span>%>%</span><span>
</span><span>select</span><span>(</span><span>algeria</span><span>:</span><span>vietnam</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>gather</span><span>(</span><span>x</span><span>,</span><span> </span><span>y</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>x</span><span>,</span><span> </span><span>y</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>summarise</span><span>(</span><span>n</span><span> </span><span>=</span><span> </span><span>n</span><span>())</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>Percent</span><span> </span><span>=</span><span> </span><span>round</span><span>(</span><span>n</span><span> </span><span>/</span><span> </span><span>sum</span><span>(</span><span>n</span><span>)</span><span> </span><span>*</span><span> </span><span>100</span><span>,</span><span> </span><span>digits</span><span> </span><span>=</span><span> </span><span>2</span><span>))</span><span>
</span><span># rename countries &amp; plot
</span><span>percentages</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_&quot;</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>x</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;(^|[[:space:]])([[:alpha:]])&quot;</span><span>,</span><span> </span><span>&quot;\\1\\U\\2&quot;</span><span>,</span><span> </span><span>x_2</span><span>,</span><span> </span><span>perl</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;And&quot;</span><span>,</span><span> </span><span>&quot;and&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</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>&quot;&quot;</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>Percent</span><span>,</span><span> </span><span>fill</span><span> </span><span>=</span><span> </span><span>y</span><span>))</span><span> </span><span>+</span><span> </span><span>geom_bar</span><span>(</span><span>width</span><span> </span><span>=</span><span> </span><span>1</span><span>,</span><span> </span><span>stat</span><span> </span><span>=</span><span> </span><span>&quot;identity&quot;</span><span>)</span><span> </span><span>+</span><span> </span><span>theme_minimal</span><span>()</span><span> </span><span>+</span><span>
</span><span>coord_polar</span><span>(</span><span>&quot;y&quot;</span><span>,</span><span> </span><span>start</span><span> </span><span>=</span><span> </span><span>0</span><span>)</span><span> </span><span>+</span><span>
</span><span>facet_wrap</span><span>(</span><span>~</span><span> </span><span>x_2</span><span>,</span><span> </span><span>ncol</span><span> </span><span>=</span><span> </span><span>8</span><span>)</span><span> </span><span>+</span><span>
</span><span>scale_fill_brewer</span><span>(</span><span>palette</span><span> </span><span>=</span><span> </span><span>&quot;Set3&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>labs</span><span>(</span><span>fill</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p><img src="https://i1.wp.com/shiring.github.io/machine_learning/2017/02/19/food_spark_files/figure-markdown_github/unnamed-chunk-7-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>As we can already see from the distributions, there are big differences between countries. Some countries’ cuisines are very well known and liked (e.g. Italy, Mexico and the United States), while others are only known to a handful of people (e.g. Algeria, Croatia, Ghana, etc.).</p>
<p></p>
<h4>Imputing missing values</h4>
<p>In the demographic information, there are a few missing values. These, I want to impute:</p>
<div>
<pre><code><span>library</span><span>(</span><span>mice</span><span>)</span><span>
</span><span>dataset_impute</span><span> </span><span>&lt;-</span><span> </span><span>mice</span><span>(</span><span>food_world_cup</span><span>[,</span><span> </span><span>-</span><span>c</span><span>(</span><span>1</span><span>,</span><span> </span><span>2</span><span>)],</span><span> </span><span>print</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>)</span><span>
</span><span>food_world_cup</span><span> </span><span>&lt;-</span><span> </span><span>cbind</span><span>(</span><span>food_world_cup</span><span>[,</span><span> </span><span>2</span><span>,</span><span> </span><span>drop</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>],</span><span> </span><span>mice</span><span>::</span><span>complete</span><span>(</span><span>dataset_impute</span><span>,</span><span> </span><span>1</span><span>))</span><span>
</span></code></pre>
</div>
<p></p>
<h4>Transforming preference values</h4>
<p>Strictly speaking, the preference data is categorical. But because using them as factor levels would make the models much more complex and calculation-intensive, I am converting the factors to numbers and transform them by dividing through the mean of non-zero values for each country.</p>
<div>
<pre><code><span>food_world_cup</span><span>[</span><span>8</span><span>:</span><span>47</span><span>]</span><span> </span><span>&lt;-</span><span> </span><span>lapply</span><span>(</span><span>food_world_cup</span><span>[</span><span>8</span><span>:</span><span>47</span><span>],</span><span> </span><span>as.numeric</span><span>)</span><span>
</span><span>countries</span><span> </span><span>&lt;-</span><span> </span><span>paste</span><span>(</span><span>colnames</span><span>(</span><span>food_world_cup</span><span>)[</span><span>-</span><span>c</span><span>(</span><span>1</span><span>:</span><span>7</span><span>)])</span><span>
</span><span>for</span><span> </span><span>(</span><span>response</span><span> </span><span>in</span><span> </span><span>countries</span><span>)</span><span> </span><span>{</span><span>
</span><span>food_world_cup</span><span>[</span><span>paste</span><span>(</span><span>response</span><span>,</span><span> </span><span>&quot;trans&quot;</span><span>,</span><span> </span><span>sep</span><span> </span><span>=</span><span> </span><span>&quot;_&quot;</span><span>)]</span><span> </span><span>&lt;-</span><span> </span><span>food_world_cup</span><span>[</span><span>response</span><span>]</span><span> </span><span>/</span><span> </span><span>mean</span><span>(</span><span>food_world_cup</span><span>[</span><span>food_world_cup</span><span>[</span><span>response</span><span>]</span><span> </span><span>></span><span> </span><span>0</span><span>,</span><span> </span><span>response</span><span>])</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>As we can see by plotting the distribution of transformed values, they are far from being normal distributions. Moreover, we still see big differences between well known and not well known countries – this means that the data is unbalanced.</p>
<div>
<pre><code><span>food_world_cup</span><span> </span><span>%>%</span><span>
</span><span>gather</span><span>(</span><span>x</span><span>,</span><span> </span><span>y</span><span>,</span><span> </span><span>algeria_trans</span><span>:</span><span>vietnam_trans</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_trans&quot;</span><span>,</span><span> </span><span>&quot;&quot;</span><span>,</span><span> </span><span>x</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_&quot;</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>x_2</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;(^|[[:space:]])([[:alpha:]])&quot;</span><span>,</span><span> </span><span>&quot;\\1\\U\\2&quot;</span><span>,</span><span> </span><span>x_2</span><span>,</span><span> </span><span>perl</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;And&quot;</span><span>,</span><span> </span><span>&quot;and&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>ggplot</span><span>(</span><span>aes</span><span>(</span><span>y</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_density</span><span>(</span><span>fill</span><span> </span><span>=</span><span> </span><span>&quot;navy&quot;</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.7</span><span>)</span><span> </span><span>+</span><span>
</span><span>my_theme</span><span>()</span><span> </span><span>+</span><span> </span><span>facet_wrap</span><span>(</span><span>~</span><span> </span><span>x_2</span><span>,</span><span> </span><span>ncol</span><span> </span><span>=</span><span> </span><span>8</span><span>)</span><span> </span><span>+</span><span>
</span><span>labs</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>&quot;transformed preference&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p><img src="https://i1.wp.com/shiring.github.io/machine_learning/2017/02/19/food_spark_files/figure-markdown_github/unnamed-chunk-15-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p></p>
<h4>Most liked cuisines and gender biases</h4>
<p>Then, I wanted to know which countries were the most liked and whether we see a gender bias in preference for some country’s cuisines. The first plot shows the sum of preference values for each country, separated by male and female answers.</p>
<div>
<pre><code><span>food_world_cup_gather</span><span> </span><span>&lt;-</span><span> </span><span>food_world_cup</span><span> </span><span>%>%</span><span>
</span><span>collect</span><span> </span><span>%>%</span><span>
</span><span>gather</span><span>(</span><span>country</span><span>,</span><span> </span><span>value</span><span>,</span><span> </span><span>algeria</span><span>:</span><span>vietnam</span><span>)</span><span>
</span><span>food_world_cup_gather</span><span>$</span><span>value</span><span> </span><span>&lt;-</span><span> </span><span>as.numeric</span><span>(</span><span>food_world_cup_gather</span><span>$</span><span>value</span><span>)</span><span>
</span><span>food_world_cup_gather</span><span>$</span><span>country</span><span> </span><span>&lt;-</span><span> </span><span>as.factor</span><span>(</span><span>food_world_cup_gather</span><span>$</span><span>country</span><span>)</span><span>
</span></code></pre>
</div>
<div>
<pre><code><span>food_world_cup_gather</span><span> </span><span>&lt;-</span><span> </span><span>food_world_cup_gather</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_&quot;</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>country</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;(^|[[:space:]])([[:alpha:]])&quot;</span><span>,</span><span> </span><span>&quot;\\1\\U\\2&quot;</span><span>,</span><span> </span><span>x_2</span><span>,</span><span> </span><span>perl</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;And&quot;</span><span>,</span><span> </span><span>&quot;and&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</span><span>
</span><span>order</span><span> </span><span>&lt;-</span><span> </span><span>aggregate</span><span>(</span><span>food_world_cup_gather</span><span>$</span><span>value</span><span>,</span><span> </span><span>by</span><span> </span><span>=</span><span> </span><span>list</span><span>(</span><span>food_world_cup_gather</span><span>$</span><span>x_2</span><span>),</span><span> </span><span>FUN</span><span> </span><span>=</span><span> </span><span>sum</span><span>)</span><span>
</span><span>food_world_cup_gather</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>factor</span><span>(</span><span>x_2</span><span>,</span><span> </span><span>levels</span><span> </span><span>=</span><span> </span><span>order</span><span>$</span><span>Group.1</span><span>[</span><span>order</span><span>(</span><span>order</span><span>$</span><span>x</span><span>,</span><span> </span><span>decreasing</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)]))</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>x_2</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>value</span><span>,</span><span> </span><span>fill</span><span> </span><span>=</span><span> </span><span>gender</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_bar</span><span>(</span><span>stat</span><span> </span><span>=</span><span> </span><span>&quot;identity&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>scale_fill_brewer</span><span>(</span><span>palette</span><span> </span><span>=</span><span> </span><span>&quot;Set1&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>my_theme</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme</span><span>(</span><span>axis.text.x</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>angle</span><span> </span><span>=</span><span> </span><span>90</span><span>,</span><span> </span><span>vjust</span><span> </span><span>=</span><span> </span><span>0.5</span><span>,</span><span> </span><span>hjust</span><span> </span><span>=</span><span> </span><span>1</span><span>))</span><span> </span><span>+</span><span>
</span><span>labs</span><span>(</span><span>fill</span><span> </span><span>=</span><span> </span><span>&quot;Gender&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;sum of preferences&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p><img src="https://i1.wp.com/shiring.github.io/machine_learning/2017/02/19/food_spark_files/figure-markdown_github/unnamed-chunk-17-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>Cuisines from Italy, the United States and Mexico were the most liked, from Ghana, Cameroon and the Ivory Coast were least liked (that they were also less well known playes into it, of course). No country shows an obvious gender bias, though.</p>
<p>To dig a bit deeper into gender differences, I am calculating the differences between mean preference of males and females for each country. Here, I am using the country list that I defined earlier when transforming the values.</p>
<p>Because I want to paste the country list to <strong>dplyr</strong>’s functions, I need to use standard evaluation (SE). Be default, <strong>dplyr</strong> uses non-standard evalutaion (NSE), i.e. variable names are given without quotation marks. This makes it possible to easily convert between R and SQL code. But each <strong>dplyr</strong> function also has a version to use with SE: they each have a “<em>” appended to the function name, here e.g. *mutate_each</em>()*.</p>
<div>
<pre><code><span>food_world_cup</span><span> </span><span>%>%</span><span>
</span><span>collect</span><span> </span><span>%>%</span><span>
</span><span>mutate_each_</span><span>(</span><span>funs</span><span>(</span><span>as.numeric</span><span>),</span><span> </span><span>countries</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>gender</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>summarise_each_</span><span>(</span><span>funs</span><span>(</span><span>mean</span><span>),</span><span> </span><span>countries</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>summarise_each_</span><span>(</span><span>funs</span><span>(</span><span>diff</span><span>),</span><span> </span><span>countries</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>gather</span><span>(</span><span>x</span><span>,</span><span> </span><span>y</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_&quot;</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>x</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;(^|[[:space:]])([[:alpha:]])&quot;</span><span>,</span><span> </span><span>&quot;\\1\\U\\2&quot;</span><span>,</span><span> </span><span>x_2</span><span>,</span><span> </span><span>perl</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;And&quot;</span><span>,</span><span> </span><span>&quot;and&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</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>x_2</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>y</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_bar</span><span>(</span><span>stat</span><span> </span><span>=</span><span> </span><span>&quot;identity&quot;</span><span>,</span><span> </span><span>fill</span><span> </span><span>=</span><span> </span><span>&quot;navy&quot;</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.7</span><span>)</span><span> </span><span>+</span><span>
</span><span>my_theme</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme</span><span>(</span><span>axis.text.x</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>angle</span><span> </span><span>=</span><span> </span><span>90</span><span>,</span><span> </span><span>vjust</span><span> </span><span>=</span><span> </span><span>0.5</span><span>,</span><span> </span><span>hjust</span><span> </span><span>=</span><span> </span><span>1</span><span>))</span><span> </span><span>+</span><span>
</span><span>labs</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;difference\nbetween gender&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p><img src="https://i1.wp.com/shiring.github.io/machine_learning/2017/02/19/food_spark_files/figure-markdown_github/unnamed-chunk-19-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>All gender differences are very close to zero, so it seems that men and women generally have similar food preferences.</p>
<p></p>
<h3>Spark</h3>
<p>Now, that I’m somewhat familiar with the data, I copy it to the Spark instance:</p>
<div>
<pre><code><span>food_world_cup</span><span> </span><span>&lt;-</span><span> </span><span>copy_to</span><span>(</span><span>sc</span><span>,</span><span> </span><span>food_world_cup</span><span>)</span><span>
</span></code></pre>
</div>
<p></p>
<h4>Principal Component Analysis (PCA)</h4>
<p>One of the functions of Spark’s machine learning functions is for PCA: <em>ml_pca()</em>. I am using it to get an idea about where the countries fall on a 2-dimensional plane of the first two principal components.</p>
<div>
<pre><code><span>pca</span><span> </span><span>&lt;-</span><span> </span><span>food_world_cup</span><span> </span><span>%>%</span><span>
</span><span>mutate_each_</span><span>(</span><span>funs</span><span>(</span><span>as.numeric</span><span>),</span><span> </span><span>countries</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>ml_pca</span><span>(</span><span>features</span><span> </span><span>=</span><span> </span><span>paste</span><span>(</span><span>colnames</span><span>(</span><span>food_world_cup</span><span>)[</span><span>-</span><span>c</span><span>(</span><span>1</span><span>:</span><span>47</span><span>)]))</span><span>
</span><span>library</span><span>(</span><span>tibble</span><span>)</span><span>
</span><span>as.data.frame</span><span>(</span><span>pca</span><span>$</span><span>components</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>rownames_to_column</span><span>(</span><span>var</span><span> </span><span>=</span><span> </span><span>&quot;labels&quot;</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_trans&quot;</span><span>,</span><span> </span><span>&quot;&quot;</span><span>,</span><span> </span><span>labels</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_&quot;</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>x_2</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;(^|[[:space:]])([[:alpha:]])&quot;</span><span>,</span><span> </span><span>&quot;\\1\\U\\2&quot;</span><span>,</span><span> </span><span>x_2</span><span>,</span><span> </span><span>perl</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;And&quot;</span><span>,</span><span> </span><span>&quot;and&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</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>PC1</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>PC2</span><span>,</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>x_2</span><span>,</span><span> </span><span>label</span><span> </span><span>=</span><span> </span><span>x_2</span><span>))</span><span> </span><span>+</span><span> </span><span>geom_point</span><span>(</span><span>size</span><span> </span><span>=</span><span> </span><span>2</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.6</span><span>)</span><span> </span><span>+</span><span>
</span><span>geom_text_repel</span><span>()</span><span> </span><span>+</span><span>
</span><span>labs</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>paste0</span><span>(</span><span>&quot;PC1: &quot;</span><span>,</span><span> </span><span>round</span><span>(</span><span>pca</span><span>$</span><span>explained.variance</span><span>[</span><span>1</span><span>],</span><span> </span><span>digits</span><span> </span><span>=</span><span> </span><span>2</span><span>)</span><span> </span><span>*</span><span> </span><span>100</span><span>,</span><span> </span><span>&quot;% variance&quot;</span><span>),</span><span>
</span><span>y</span><span> </span><span>=</span><span> </span><span>paste0</span><span>(</span><span>&quot;PC2: &quot;</span><span>,</span><span> </span><span>round</span><span>(</span><span>pca</span><span>$</span><span>explained.variance</span><span>[</span><span>2</span><span>],</span><span> </span><span>digits</span><span> </span><span>=</span><span> </span><span>2</span><span>)</span><span> </span><span>*</span><span> </span><span>100</span><span>,</span><span> </span><span>&quot;% variance&quot;</span><span>))</span><span> </span><span>+</span><span>
</span><span>my_theme</span><span>()</span><span> </span><span>+</span><span> </span><span>guides</span><span>(</span><span>fill</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>,</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>)</span><span>
</span></code></pre>
</div>
<p><img src="https://i1.wp.com/shiring.github.io/machine_learning/2017/02/19/food_spark_files/figure-markdown_github/unnamed-chunk-22-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>The least well known countries cluster on the top right, while the most liked are on the bottom right. PC2 seems to be mainly driven by how many 0s there are in the data.</p>
<p></p>
<h4>Preparing the data for machine learning</h4>
<p>First, I need to convert the factor strings of the non-country features into indexes. To do so, I am using the <em>ft_string_indexer()</em> function. For other feature transformation functions, check out <a target="_blank" rel="nofollow" href="http://spark.rstudio.com/"><strong>sparklyr</strong>’s website</a>.</p>
<div>
<pre><code><span>food_world_cup</span><span> </span><span>&lt;-</span><span> </span><span>tbl</span><span>(</span><span>sc</span><span>,</span><span> </span><span>&quot;food_world_cup&quot;</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>ft_string_indexer</span><span>(</span><span>input_col</span><span> </span><span>=</span><span> </span><span>&quot;interest&quot;</span><span>,</span><span> </span><span>output_col</span><span> </span><span>=</span><span> </span><span>&quot;interest_idx&quot;</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>ft_string_indexer</span><span>(</span><span>input_col</span><span> </span><span>=</span><span> </span><span>&quot;gender&quot;</span><span>,</span><span> </span><span>output_col</span><span> </span><span>=</span><span> </span><span>&quot;gender_idx&quot;</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>ft_string_indexer</span><span>(</span><span>input_col</span><span> </span><span>=</span><span> </span><span>&quot;age&quot;</span><span>,</span><span> </span><span>output_col</span><span> </span><span>=</span><span> </span><span>&quot;age_idx&quot;</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>ft_string_indexer</span><span>(</span><span>input_col</span><span> </span><span>=</span><span> </span><span>&quot;household_income&quot;</span><span>,</span><span> </span><span>output_col</span><span> </span><span>=</span><span> </span><span>&quot;household_income_idx&quot;</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>ft_string_indexer</span><span>(</span><span>input_col</span><span> </span><span>=</span><span> </span><span>&quot;education&quot;</span><span>,</span><span> </span><span>output_col</span><span> </span><span>=</span><span> </span><span>&quot;education_idx&quot;</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>ft_string_indexer</span><span>(</span><span>input_col</span><span> </span><span>=</span><span> </span><span>&quot;location&quot;</span><span>,</span><span> </span><span>output_col</span><span> </span><span>=</span><span> </span><span>&quot;location_idx&quot;</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>ft_string_indexer</span><span>(</span><span>input_col</span><span> </span><span>=</span><span> </span><span>&quot;knowledge&quot;</span><span>,</span><span> </span><span>output_col</span><span> </span><span>=</span><span> </span><span>&quot;knowledge_idx&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p></p>
<p>Now I can divide the data into training and test sets using the <em>sdf_partition()</em> function.</p>
<div>
<pre><code><span>partitions</span><span> </span><span>&lt;-</span><span> </span><span>food_world_cup</span><span> </span><span>%>%</span><span>
</span><span>sdf_partition</span><span>(</span><span>training</span><span> </span><span>=</span><span> </span><span>0.75</span><span>,</span><span> </span><span>test</span><span> </span><span>=</span><span> </span><span>0.25</span><span>,</span><span> </span><span>seed</span><span> </span><span>=</span><span> </span><span>753</span><span>)</span><span>
</span></code></pre>
</div>
<p></p>
<h4>Modeling</h4>
<p>Now, I run the Random Forest algorithm to predict each country’s preference based on all other countries’ preferences and the demographic information. Check back with <a target="_blank" rel="nofollow" href="http://spark.rstudio.com/"><strong>sparklyr</strong>’s website</a> to find out about other machine learning algorithms you can use.</p>
<p>For each country (as response variable), I am defining the features as all other countries’ transformed values and the indexed factor variables.</p>
<p>Then, I am filtering out all data rows where the response variable was 0. When I left the 0s in the data, the countries with many 0s introduced a very strong bias to the prediction. Here, I needed to use standard evaluation again, this time with <strong>lazyeval</strong>’s <em>interp()</em> function and a formula.</p>
<p>I am using the <em>ml_random_forest()</em> function to run classification models. Inititally, I run a model on all features, then extract the 10 features with highest importance and re-run the model again on this subset of features. This improved the prediction accuracy compared to all-feature-models.</p>
<p>The <em>sdf_predict()</em> function is used to predict the classes of the test set. To obtain the quality metrics F1, weighted precision and weighted recall, I need to copy the prediction table to the Spark instance and run the <em>ml_classification_eval()</em> function.</p>
<p>Finally, I am combining the output tables from all countries’s models to compare.</p>
<div>
<pre><code><span>library</span><span>(</span><span>lazyeval</span><span>)</span><span>
</span><span>for</span><span> </span><span>(</span><span>response</span><span> </span><span>in</span><span> </span><span>countries</span><span>)</span><span> </span><span>{</span><span>
</span><span>features</span><span> </span><span>&lt;-</span><span> </span><span>colnames</span><span>(</span><span>partitions</span><span>$</span><span>training</span><span>)[</span><span>-</span><span>grep</span><span>(</span><span>response</span><span>,</span><span> </span><span>colnames</span><span>(</span><span>partitions</span><span>$</span><span>training</span><span>))]</span><span>
</span><span>features</span><span> </span><span>&lt;-</span><span> </span><span>features</span><span>[</span><span>grep</span><span>(</span><span>&quot;_trans|_idx&quot;</span><span>,</span><span> </span><span>features</span><span>)]</span><span>
</span><span>fit</span><span> </span><span>&lt;-</span><span> </span><span>partitions</span><span>$</span><span>training</span><span> </span><span>%>%</span><span>
</span><span>filter_</span><span>(</span><span>interp</span><span>(</span><span>~</span><span> </span><span>var</span><span> </span><span>></span><span> </span><span>0</span><span>,</span><span> </span><span>var</span><span> </span><span>=</span><span> </span><span>as.name</span><span>(</span><span>response</span><span>)))</span><span> </span><span>%>%</span><span>
</span><span>ml_random_forest</span><span>(</span><span>intercept</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>,</span><span> </span><span>response</span><span> </span><span>=</span><span> </span><span>response</span><span>,</span><span> </span><span>features</span><span> </span><span>=</span><span> </span><span>features</span><span>,</span><span> </span><span>type</span><span> </span><span>=</span><span> </span><span>&quot;classification&quot;</span><span>)</span><span>
</span><span>feature_imp</span><span> </span><span>&lt;-</span><span> </span><span>ml_tree_feature_importance</span><span>(</span><span>sc</span><span>,</span><span> </span><span>fit</span><span>)</span><span>
</span><span>features</span><span> </span><span>&lt;-</span><span> </span><span>as.character</span><span>(</span><span>feature_imp</span><span>[</span><span>1</span><span>:</span><span>10</span><span>,</span><span> </span><span>2</span><span>])</span><span>
</span><span>fit</span><span> </span><span>&lt;-</span><span> </span><span>partitions</span><span>$</span><span>training</span><span> </span><span>%>%</span><span>
</span><span>filter_</span><span>(</span><span>interp</span><span>(</span><span>~</span><span> </span><span>var</span><span> </span><span>></span><span> </span><span>0</span><span>,</span><span> </span><span>var</span><span> </span><span>=</span><span> </span><span>as.name</span><span>(</span><span>response</span><span>)))</span><span> </span><span>%>%</span><span>
</span><span>ml_random_forest</span><span>(</span><span>intercept</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>,</span><span> </span><span>response</span><span> </span><span>=</span><span> </span><span>response</span><span>,</span><span> </span><span>features</span><span> </span><span>=</span><span> </span><span>features</span><span>,</span><span> </span><span>type</span><span> </span><span>=</span><span> </span><span>&quot;classification&quot;</span><span>)</span><span>
</span><span>partitions</span><span>$</span><span>test</span><span> </span><span>&lt;-</span><span> </span><span>partitions</span><span>$</span><span>test</span><span> </span><span>%>%</span><span>
</span><span>filter_</span><span>(</span><span>interp</span><span>(</span><span>~</span><span> </span><span>var</span><span> </span><span>></span><span> </span><span>0</span><span>,</span><span> </span><span>var</span><span> </span><span>=</span><span> </span><span>as.name</span><span>(</span><span>response</span><span>)))</span><span>
</span><span>pred</span><span> </span><span>&lt;-</span><span> </span><span>sdf_predict</span><span>(</span><span>fit</span><span>,</span><span> </span><span>partitions</span><span>$</span><span>test</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>collect</span><span>
</span><span>pred_2</span><span> </span><span>&lt;-</span><span> </span><span>as.data.frame</span><span>(</span><span>table</span><span>(</span><span>pred</span><span>[[</span><span>response</span><span>]],</span><span> </span><span>pred</span><span>$</span><span>prediction</span><span>))</span><span>
</span><span>pred_2</span><span>$</span><span>response</span><span> </span><span>&lt;-</span><span> </span><span>response</span><span>
</span><span>pred_sc</span><span> </span><span>&lt;-</span><span> </span><span>select</span><span>(</span><span>pred</span><span>,</span><span> </span><span>-</span><span>rawPrediction</span><span>,</span><span> </span><span>-</span><span>probability</span><span>)</span><span>
</span><span>pred_sc</span><span> </span><span>&lt;-</span><span> </span><span>copy_to</span><span>(</span><span>sc</span><span>,</span><span> </span><span>pred_sc</span><span>,</span><span> </span><span>overwrite</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>feature_imp</span><span>$</span><span>response</span><span> </span><span>&lt;-</span><span> </span><span>response</span><span>
</span><span>f</span><span>1</span><span> </span><span>&lt;-</span><span> </span><span>ml_classification_eval</span><span>(</span><span>pred_sc</span><span>,</span><span> </span><span>response</span><span>,</span><span> </span><span>&quot;prediction&quot;</span><span>,</span><span> </span><span>metric</span><span> </span><span>=</span><span> </span><span>&quot;f1&quot;</span><span>)</span><span>
</span><span>wP</span><span> </span><span>&lt;-</span><span> </span><span>ml_classification_eval</span><span>(</span><span>pred_sc</span><span>,</span><span> </span><span>response</span><span>,</span><span> </span><span>&quot;prediction&quot;</span><span>,</span><span> </span><span>metric</span><span> </span><span>=</span><span> </span><span>&quot;weightedPrecision&quot;</span><span>)</span><span>
</span><span>wR</span><span> </span><span>&lt;-</span><span> </span><span>ml_classification_eval</span><span>(</span><span>pred_sc</span><span>,</span><span> </span><span>response</span><span>,</span><span> </span><span>&quot;prediction&quot;</span><span>,</span><span> </span><span>metric</span><span> </span><span>=</span><span> </span><span>&quot;weightedRecall&quot;</span><span>)</span><span>
</span><span>ml_eval</span><span> </span><span>&lt;-</span><span> </span><span>data.frame</span><span>(</span><span>response</span><span> </span><span>=</span><span> </span><span>response</span><span>,</span><span>
</span><span>f</span><span>1</span><span> </span><span>=</span><span> </span><span>f</span><span>1</span><span>,</span><span>
</span><span>weightedPrecision</span><span> </span><span>=</span><span> </span><span>wP</span><span>,</span><span>
</span><span>weightedRecall</span><span> </span><span>=</span><span> </span><span>wR</span><span>)</span><span>
</span><span>if</span><span> </span><span>(</span><span>response</span><span> </span><span>==</span><span> </span><span>&quot;algeria&quot;</span><span>)</span><span> </span><span>{</span><span>
</span><span>feature_imp_df</span><span> </span><span>&lt;-</span><span> </span><span>feature_imp</span><span>
</span><span>ml_eval_df</span><span> </span><span>&lt;-</span><span> </span><span>ml_eval</span><span>
</span><span>pred_df</span><span> </span><span>&lt;-</span><span> </span><span>pred_2</span><span>
</span><span>}</span><span> </span><span>else</span><span> </span><span>{</span><span>
</span><span>feature_imp_df</span><span> </span><span>&lt;-</span><span> </span><span>rbind</span><span>(</span><span>feature_imp_df</span><span>,</span><span> </span><span>feature_imp</span><span>)</span><span>
</span><span>ml_eval_df</span><span> </span><span>&lt;-</span><span> </span><span>rbind</span><span>(</span><span>ml_eval_df</span><span>,</span><span> </span><span>ml_eval</span><span>)</span><span>
</span><span>pred_df</span><span> </span><span>&lt;-</span><span> </span><span>rbind</span><span>(</span><span>pred_df</span><span>,</span><span> </span><span>pred_2</span><span>)</span><span>
</span><span>}</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p></p>
<h4>Model evaluation</h4>
<p>Now, I can compare the prediction accuracies for each country’s model by plotting the F1, weighted precision and weighted recall values.</p>
<ul>
<li><em>Precision</em></li>
</ul>
<p>In classification models, precision gives the proportion of correct classifications or “true positives” (i.e. how many of the samples that were classified as “5” were actually a “5”). If we have a high precision, this means that our model classified most samples correctly.</p>
<ul>
<li><em>Recall</em></li>
</ul>
<p>Recall, or sensitivity, gives the proportion of how many of all true “5” samples in the training data were correctly classified. If we have a high recall, this means that our model correctly detected most classes.</p>
<ul>
<li><em>F1 score</em></li>
</ul>
<p>The F-score gives the harmonic mean or weighted average of precision and recall.</p>
<p>Let’s say we had 10 “5s” in the training data. The prediction table classified 8 samples as “5s”, 6 of which were correctly classified. In this example, we have 2 false positives and 4 false negatives. This means we would have a precision of 6/8 and a recall of 6/10.</p>
<div>
<pre><code><span>results</span><span> </span><span>&lt;-</span><span> </span><span>ml_eval_df</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_&quot;</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>response</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;(^|[[:space:]])([[:alpha:]])&quot;</span><span>,</span><span> </span><span>&quot;\\1\\U\\2&quot;</span><span>,</span><span> </span><span>x_2</span><span>,</span><span> </span><span>perl</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;And&quot;</span><span>,</span><span> </span><span>&quot;and&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</span><span>
</span><span>order</span><span> </span><span>&lt;-</span><span> </span><span>results</span><span>$</span><span>x_2</span><span>[</span><span>order</span><span>(</span><span>results</span><span>$</span><span>f</span><span>1</span><span>,</span><span> </span><span>decreasing</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)]</span><span>
</span><span>gather</span><span>(</span><span>results</span><span>,</span><span> </span><span>x</span><span>,</span><span> </span><span>y</span><span>,</span><span> </span><span>f</span><span>1</span><span>:</span><span>weightedRecall</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>factor</span><span>(</span><span>x_2</span><span>,</span><span> </span><span>levels</span><span> </span><span>=</span><span> </span><span>order</span><span>))</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>x_2</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>y</span><span>,</span><span> </span><span>fill</span><span> </span><span>=</span><span> </span><span>x</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_bar</span><span>(</span><span>stat</span><span> </span><span>=</span><span> </span><span>&quot;identity&quot;</span><span>,</span><span> </span><span>position</span><span> </span><span>=</span><span> </span><span>&quot;dodge&quot;</span><span>,</span><span> </span><span>alpha</span><span> </span><span>=</span><span> </span><span>0.9</span><span>)</span><span> </span><span>+</span><span>
</span><span>scale_fill_brewer</span><span>(</span><span>palette</span><span> </span><span>=</span><span> </span><span>&quot;Set1&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>my_theme</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme</span><span>(</span><span>axis.text.x</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>angle</span><span> </span><span>=</span><span> </span><span>90</span><span>,</span><span> </span><span>vjust</span><span> </span><span>=</span><span> </span><span>0.5</span><span>,</span><span> </span><span>hjust</span><span> </span><span>=</span><span> </span><span>1</span><span>))</span><span> </span><span>+</span><span>
</span><span>labs</span><span>(</span><span>fill</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>,</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;&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;value&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p><img src="https://i0.wp.com/shiring.github.io/machine_learning/2017/02/19/food_spark_files/figure-markdown_github/unnamed-chunk-40-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>The plot above shows that the model predicting preference for Spanish dishes had the highest accuracy, while the model for Italy, India and Ireland had the lowest accuracy.</p>
<p></p>
<p>To see what features had been used in more and less successful models, I am plotting the values of the 10 final features for classifying Spanish, Greece and Italian food preference categories 1 – 5 in the original dataset.</p>
<div>
<pre><code><span>as.data.frame</span><span>(</span><span>food_world_cup</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>select_</span><span>(</span><span>.dots</span><span> </span><span>=</span><span> </span><span>c</span><span>(</span><span>&quot;spain&quot;</span><span>,</span><span> </span><span>as.character</span><span>(</span><span>feats</span><span>$</span><span>feature</span><span>)))</span><span> </span><span>%>%</span><span>
</span><span>gather</span><span>(</span><span>x</span><span>,</span><span> </span><span>y</span><span>,</span><span> </span><span>-</span><span>spain</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>spain</span><span> </span><span>></span><span> </span><span>0</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>spain</span><span>,</span><span> </span><span>x</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>summarise</span><span>(</span><span>mean</span><span> </span><span>=</span><span> </span><span>mean</span><span>(</span><span>y</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_trans&quot;</span><span>,</span><span> </span><span>&quot;&quot;</span><span>,</span><span> </span><span>x</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_idx&quot;</span><span>,</span><span> </span><span>&quot;&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_&quot;</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>x_2</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;(^|[[:space:]])([[:alpha:]])&quot;</span><span>,</span><span> </span><span>&quot;\\1\\U\\2&quot;</span><span>,</span><span> </span><span>x_2</span><span>,</span><span> </span><span>perl</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;And&quot;</span><span>,</span><span> </span><span>&quot;and&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</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>x_2</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>spain</span><span>,</span><span> </span><span>fill</span><span> </span><span>=</span><span> </span><span>mean</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_tile</span><span>(</span><span>width</span><span> </span><span>=</span><span> </span><span>0.9</span><span>,</span><span> </span><span>height</span><span> </span><span>=</span><span> </span><span>0.9</span><span>)</span><span> </span><span>+</span><span>
</span><span>scale_fill_gradient2</span><span>(</span><span>low</span><span> </span><span>=</span><span> </span><span>&quot;white&quot;</span><span>,</span><span> </span><span>high</span><span> </span><span>=</span><span> </span><span>&quot;red&quot;</span><span>,</span><span> </span><span>name</span><span> </span><span>=</span><span> </span><span>&quot;mean&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>my_theme</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme</span><span>(</span><span>axis.text.x</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>angle</span><span> </span><span>=</span><span> </span><span>45</span><span>,</span><span> </span><span>vjust</span><span> </span><span>=</span><span> </span><span>1</span><span>,</span><span> </span><span>hjust</span><span> </span><span>=</span><span> </span><span>1</span><span>))</span><span> </span><span>+</span><span>
</span><span>labs</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;Spain&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p><img src="https://i0.wp.com/shiring.github.io/machine_learning/2017/02/19/food_spark_files/figure-markdown_github/unnamed-chunk-42-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<div>
<pre><code><span>feats</span><span> </span><span>&lt;-</span><span> </span><span>feature_imp_df</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>response</span><span> </span><span>==</span><span> </span><span>&quot;greece&quot;</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>slice</span><span>(</span><span>1</span><span>:</span><span>10</span><span>)</span><span>
</span><span>as.data.frame</span><span>(</span><span>food_world_cup</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>select_</span><span>(</span><span>.dots</span><span> </span><span>=</span><span> </span><span>c</span><span>(</span><span>&quot;greece&quot;</span><span>,</span><span> </span><span>as.character</span><span>(</span><span>feats</span><span>$</span><span>feature</span><span>)))</span><span> </span><span>%>%</span><span>
</span><span>gather</span><span>(</span><span>x</span><span>,</span><span> </span><span>y</span><span>,</span><span> </span><span>-</span><span>greece</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>greece</span><span> </span><span>></span><span> </span><span>0</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>greece</span><span>,</span><span> </span><span>x</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>summarise</span><span>(</span><span>mean</span><span> </span><span>=</span><span> </span><span>mean</span><span>(</span><span>y</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_trans&quot;</span><span>,</span><span> </span><span>&quot;&quot;</span><span>,</span><span> </span><span>x</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_idx&quot;</span><span>,</span><span> </span><span>&quot;&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_&quot;</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>x_2</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;(^|[[:space:]])([[:alpha:]])&quot;</span><span>,</span><span> </span><span>&quot;\\1\\U\\2&quot;</span><span>,</span><span> </span><span>x_2</span><span>,</span><span> </span><span>perl</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;And&quot;</span><span>,</span><span> </span><span>&quot;and&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</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>x_2</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>greece</span><span>,</span><span> </span><span>fill</span><span> </span><span>=</span><span> </span><span>mean</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_tile</span><span>(</span><span>width</span><span> </span><span>=</span><span> </span><span>0.9</span><span>,</span><span> </span><span>height</span><span> </span><span>=</span><span> </span><span>0.9</span><span>)</span><span> </span><span>+</span><span>
</span><span>scale_fill_gradient2</span><span>(</span><span>low</span><span> </span><span>=</span><span> </span><span>&quot;white&quot;</span><span>,</span><span> </span><span>high</span><span> </span><span>=</span><span> </span><span>&quot;red&quot;</span><span>,</span><span> </span><span>name</span><span> </span><span>=</span><span> </span><span>&quot;mean&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>my_theme</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme</span><span>(</span><span>axis.text.x</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>angle</span><span> </span><span>=</span><span> </span><span>45</span><span>,</span><span> </span><span>vjust</span><span> </span><span>=</span><span> </span><span>1</span><span>,</span><span> </span><span>hjust</span><span> </span><span>=</span><span> </span><span>1</span><span>))</span><span> </span><span>+</span><span>
</span><span>labs</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;Greece&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p><img src="https://i1.wp.com/shiring.github.io/machine_learning/2017/02/19/food_spark_files/figure-markdown_github/unnamed-chunk-43-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<div>
<pre><code><span>feats</span><span> </span><span>&lt;-</span><span> </span><span>feature_imp_df</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>response</span><span> </span><span>==</span><span> </span><span>&quot;italy&quot;</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>slice</span><span>(</span><span>1</span><span>:</span><span>10</span><span>)</span><span>
</span><span>as.data.frame</span><span>(</span><span>food_world_cup</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>select_</span><span>(</span><span>.dots</span><span> </span><span>=</span><span> </span><span>c</span><span>(</span><span>&quot;italy&quot;</span><span>,</span><span> </span><span>as.character</span><span>(</span><span>feats</span><span>$</span><span>feature</span><span>)))</span><span> </span><span>%>%</span><span>
</span><span>gather</span><span>(</span><span>x</span><span>,</span><span> </span><span>y</span><span>,</span><span> </span><span>-</span><span>italy</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>filter</span><span>(</span><span>italy</span><span> </span><span>></span><span> </span><span>0</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>group_by</span><span>(</span><span>italy</span><span>,</span><span> </span><span>x</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>summarise</span><span>(</span><span>mean</span><span> </span><span>=</span><span> </span><span>mean</span><span>(</span><span>y</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_trans&quot;</span><span>,</span><span> </span><span>&quot;&quot;</span><span>,</span><span> </span><span>x</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_idx&quot;</span><span>,</span><span> </span><span>&quot;&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;_&quot;</span><span>,</span><span> </span><span>&quot; &quot;</span><span>,</span><span> </span><span>x_2</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;(^|[[:space:]])([[:alpha:]])&quot;</span><span>,</span><span> </span><span>&quot;\\1\\U\\2&quot;</span><span>,</span><span> </span><span>x_2</span><span>,</span><span> </span><span>perl</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>))</span><span> </span><span>%>%</span><span>
</span><span>mutate</span><span>(</span><span>x_2</span><span> </span><span>=</span><span> </span><span>gsub</span><span>(</span><span>&quot;And&quot;</span><span>,</span><span> </span><span>&quot;and&quot;</span><span>,</span><span> </span><span>x_2</span><span>))</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>x_2</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>italy</span><span>,</span><span> </span><span>fill</span><span> </span><span>=</span><span> </span><span>mean</span><span>))</span><span> </span><span>+</span><span>
</span><span>geom_tile</span><span>(</span><span>width</span><span> </span><span>=</span><span> </span><span>0.9</span><span>,</span><span> </span><span>height</span><span> </span><span>=</span><span> </span><span>0.9</span><span>)</span><span> </span><span>+</span><span>
</span><span>scale_fill_gradient2</span><span>(</span><span>low</span><span> </span><span>=</span><span> </span><span>&quot;white&quot;</span><span>,</span><span> </span><span>high</span><span> </span><span>=</span><span> </span><span>&quot;red&quot;</span><span>,</span><span> </span><span>name</span><span> </span><span>=</span><span> </span><span>&quot;mean&quot;</span><span>)</span><span> </span><span>+</span><span>
</span><span>my_theme</span><span>()</span><span> </span><span>+</span><span>
</span><span>theme</span><span>(</span><span>axis.text.x</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>angle</span><span> </span><span>=</span><span> </span><span>45</span><span>,</span><span> </span><span>vjust</span><span> </span><span>=</span><span> </span><span>1</span><span>,</span><span> </span><span>hjust</span><span> </span><span>=</span><span> </span><span>1</span><span>))</span><span> </span><span>+</span><span>
</span><span>labs</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;Italy&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p><img src="https://i1.wp.com/shiring.github.io/machine_learning/2017/02/19/food_spark_files/figure-markdown_github/unnamed-chunk-44-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p></p>
<h3>Conclusions</h3>
<p>This dataset was a bit difficult because the preferences were highly unbalanced, i.e. the distributions of preferences were very different between countries. Some countries’ cuisines were largely unknown, while others’ were well known and generally popular. If I kept the unknown class (0) in the prediction models, countries with many 0s jumped up in prediction accuracy. But this was mainly due to the fact, that the chance of correctly classifying a sample as 0 was over-proportionally high (leading to high precision). Removing the 0s while working on raw preference values showed the same effect as before but now countries with a majority of 5s (e.g. Italy) were overly “accurate”. Transforming the data and removing the 0s led to a more evenly distributed accuracy of well known and less well known countries. But by removing them, the number of samples used for modeling varied strongly between countries, introducing another type of bias.</p>
<p>It was not possible to avoid bias entirely with this dataset. But I wanted to show it as an example nonetheless. Usually, machine learning examples show datasets where the models worked very well, leaving the reader in awe of the powers of machine learning. And while there are certainly powerful and impressive prediction models, real-life data is not always as simple. As can be seen with this dataset, it’s not always as straight forward to build a good classification model, even though you’d intuitively assume that it should be easy to predict food preferences based on which other cuisines someone likes…</p>
<p>The model could potentially be improved by engineering features, modeling factors and/ or different algorithms but I’ll leave this for another time.</p>
<p></p>
<p>Next week, I’ll be looking into how to use the <strong>h2o</strong> package with Spark using <strong>rsparkling</strong>.</p>
<hr>
<p>Other machine learning topics I have covered include</p>
<ul>
<li>a basic machine learning workflow: <a target="_blank" rel="nofollow" href="https://shiring.github.io/machine_learning/2016/11/27/flu_outcome_ML_post">Can we predict flu deaths with Machine Learning and R?</a></li>
<li>extreme gradient boosting: <a target="_blank" rel="nofollow" href="https://shiring.github.io/machine_learning/2016/12/02/flu_outcome_ML_2_post">Extreme Gradient Boosting and Preprocessing in Machine Learning – Addendum to predicting flu outcome with R</a></li>
<li>feature selection: <a target="_blank" rel="nofollow" href="https://shiring.github.io/machine_learning/2017/01/15/rfe_ga_post">Feature Selection in Machine Learning (Breast Cancer Datasets)</a></li>
</ul>
<hr>
<p></p>
<div>
<pre><code>## R version 3.3.2 (2016-10-31)
## Platform: x86_64-apple-darwin13.4.0 (64-bit)
## Running under: macOS Sierra 10.12.1
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] tibble_1.2            fivethirtyeight_0.1.0 dplyr_0.5.0          
## [4] ggrepel_0.6.5         ggplot2_2.2.1         tidyr_0.6.1          
## [7] sparklyr_0.5.1       
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_0.12.9        knitr_1.15.1       magrittr_1.5      
##  [4] rappdirs_0.3.1     munsell_0.4.3      colorspace_1.3-2  
##  [7] R6_2.2.0           plyr_1.8.4         stringr_1.1.0     
## [10] httr_1.2.1         tools_3.3.2        parallel_3.3.2    
## [13] grid_3.3.2         gtable_0.2.0       config_0.2        
## [16] DBI_0.5-1          withr_1.0.2        htmltools_0.3.5   
## [19] lazyeval_0.2.0     yaml_2.1.14        assertthat_0.1    
## [22] rprojroot_1.2      digest_0.6.12      RColorBrewer_1.1-2
## [25] base64enc_0.1-3    evaluate_0.10      rmarkdown_1.3     
## [28] labeling_0.3       stringi_1.1.2      scales_0.4.1      
## [31] backports_1.0.5    jsonlite_1.2
</code></pre>
</div>
<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://shiring.github.io/machine_learning/2017/02/19/food_spark"> Shirin's playgRound</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 title="The R Project for Statistical Computing" rel="nofollow" href="https://www.r-project.org/">R</a> news and <a title="R tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/tutorial">tutorials</a> on topics such as: <a title="Data science" rel="nofollow" href="https://www.r-bloggers.com/search/data%20science">Data science</a>, <a title="Big Data" rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data">Big Data, <a title="R jobs" rel="nofollow" href="https://www.r-users.com/">R jobs</a>, visualization (<a title="ggplot and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2">ggplot2</a>, <a title="Boxplots using lattice and ggplot2 tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/boxplot">Boxplots</a>, <a title="Maps and gis" rel="nofollow" href="https://www.r-bloggers.com/search/map">maps</a>, <a title="Animation in R" rel="nofollow" href="https://www.r-bloggers.com/search/animation">animation</a>), programming (<a title="RStudio IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/RStudio">RStudio</a>, <a title="Sweave and literate programming" rel="nofollow" href="https://www.r-bloggers.com/search/sweave">Sweave</a>, <a title="LaTeX in R" rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX">LaTeX</a>, <a title="SQL and databases" rel="nofollow" href="https://www.r-bloggers.com/search/SQL">SQL</a>, <a title="Eclipse IDE for R" rel="nofollow" href="https://www.r-bloggers.com/search/eclipse">Eclipse</a>, <a title="git and github, Version Control System" rel="nofollow" href="https://www.r-bloggers.com/search/git">git</a>, <a title="Large data in R using Hadoop" rel="nofollow" href="https://www.r-bloggers.com/search/hadoop">hadoop</a>, <a title="Web Scraping of google, facebook, yahoo, twitter and more using R" rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping">Web Scraping</a>) statistics (<a title="Regressions and ANOVA analysis tutorials" rel="nofollow" href="https://www.r-bloggers.com/search/regression">regression</a>, <a title="principal component analysis tutorial" rel="nofollow" href="https://www.r-bloggers.com/search/PCA">PCA</a>, <a title="Time series" rel="nofollow" href="https://www.r-bloggers.com/search/time+series">time series</a>, <a title="finance trading" rel="nofollow" href="https://www.r-bloggers.com/search/trading">trading</a>) and more...
<img height="1" alt="" width="1" src="http://feeds.feedburner.com/~r/RBloggers/~4/wTqN4AU9CS8"></a></div>