<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/monkeying-around-with-code-and-paying-it-forward/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://ropensci.org/blog/2018/04/20/monkeydo/"> rOpenSci - open tools for open science</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<pre><code>library(tidyverse)
library(monkeylearn)
</code></pre>
<p>This is a story (mostly) about how I started contributing to the rOpenSci package <a rel="nofollow" href="https://github.com/ropensci/monkeylearn" target="_blank">monkeylearn</a>. I can’t promise any life flipturning upside down, but there will be a small discussion about git best practices which is almost as good <img alt="🤓" src="https://s.w.org/images/core/emoji/2.4/72x72/1f913.png" class="wp-smiley">. The tl;dr here is nothing novel but is something I wish I’d experienced firsthand sooner. That is, that tinkering with and improving on the code others have written is more rewarding for you and more valuable to others when you contribute it back to the original source.</p>
<p>We all write code all the time to graft aditional features onto existing tools or reshape output into forms that fit better in our particular pipelines. Chances are, these are improvements our fellow package users could take advantage of. Plus, if they’re integrated into the package source code, then we no longer need our own wrappers and reshapers and speeder-uppers. That means less code and fewer chances of bugs all around <img alt="🙌" src="https://s.w.org/images/core/emoji/2.4/72x72/1f64c.png" class="wp-smiley">. So, tinkering with and improving on the code others have written is more rewarding for you and more valuable to others when you contribute it back to the original source.</p>
<p></p>
<h3>Some Backstory</h3>
<p>My first brush with the <code>monkeylearn</code> package was at work one day when I was looking around for an easy way to classify groups of texts using R. I made the very clever first move of Googling “easy way to classify groups of texts using R” and thanks to the magic of what I suppose used to be PageRank I landed upon a GitHub README for a package called monkeylearn.</p>
<p>A quick <code>install.packages(&quot;monkeylearn&quot;)</code> and creation of an API key later it started looking like this package would fit my use case. I loved that it sported only two functions, <code>monkeylearn_classify()</code> and <code>monkeylearn_extract()</code>, which did exactly what they said on the tin. They accept a vector of texts and return a dataframe of classifications or keyword extractions, respectively.</p>
<p></p>
<p><img src="https://i1.wp.com/ropensci.org/img/blog-images/2018-04-20-monkeydo/monkeylearn_api.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p></p>
<p>For a bit of background, the <code>monkeylearn</code> package hooks into the <a rel="nofollow" href="https://monkeylearn.com/api/" target="_blank">MonkeyLearn API</a>, which uses natural language processing techniques to take a text input and hands back a vector of outputs (keyword extractions or classifications) along with metadata such as their confidence in relevance of the classification. There are a set of built-in “modules” (e.g., retail classifier, profanity extractor) but users can also create their own “custom” modules<sup><a rel="nofollow" href="https://ropensci.org/blog/2018/04/20/monkeydo/#fn:1" target="_blank">1</a></sup> by supplying their own labeled training data.</p>
<p>The monkeylearn R package serves as a friendly interface to that API, allowing users to process data using the built-in modules (it doesn’t yet support creating and training of custom modules). In the rOpenSci tradition it’s peer-reviewed and was contributed via the <a rel="nofollow" href="https://github.com/ropensci/onboarding/issues/45" target="_blank">onboarding process</a>.</p>
<p>I began using the package to attach classifications to around 70,000 texts. I soon discovered a major stumbling block: I could not send texts to the MonkeyLearn API in batches. This wasn’t because the <code>monkeylearn_classify()</code> and <code>monkeylearn_extract()</code> functions themselves didn’t accept multiple inputs. Instead, it was because they didn’t explicitly <em>relate</em> inputs to outputs. This became a problem because inputs and outputs are not 1:1; if I send a vector of three texts for classification, my output dataframe might be 10 rows long. However, there was no user-friendly way to know for sure<sup><a rel="nofollow" href="https://ropensci.org/blog/2018/04/20/monkeydo/#fn:2" target="_blank">2</a></sup> whether the first two or the first four output rows, for example, belonged to the first input text.</p>
<p>Here’s an example of what I mean.</p>
<pre><code>texts &lt;- c(
    &quot;It is a truth universally acknowledged, that a single man in possession of a good fortune, must be in want of a wife.&quot;,
    &quot;When Mr. Bilbo Baggins of Bag End announced that he would shortly be celebrating his eleventy-first birthday with a party of special magnificence, there was much talk and excitement in Hobbiton.&quot;,
    &quot;I'm not an ambiturner. I can't turn left.&quot;)

(texts_out &lt;- monkeylearn_classify(texts, verbose = FALSE))
</code></pre>
<pre><code>## # A tibble: 11 x 4
##    category_id probability label                text_md5                  
##          </code></pre>