<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/spookify-halloween-name-generation-in-r/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://masalmon.eu/2018/10/05/spookify/"> Posts on Maëlle's R blog</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>It’s October, time for spooky Twitter names! If you’re on this social<br>
media platform, you might have noticed some of your friends switching<br>
their names to something spooky and punny. Last year I was “Maelstrom<br>
Salmon”, which I find scary but is arguably not that funny. Anyhow, what<br>
if you want to switch your name but have no inspiration? In this post,<br>
we shall explore R’s abilities to help us with that with the help of<br>
webscraping, phonetic spelling and string distance algorithms, and the<br>
magic of randomness!</p>
<p>
My strategy for spooky name generation will be to replace each part of a<br>
name (e.g. first and last names) with the phonetically closest<br>
Halloween-related words. Therefore, the technical challenges here were<br>
to find a list of Halloween-related words, and to measure <em>phonetical</em><br>
string distance.</p>
<h1>Getting spooky words</h1>
<p>The <a rel="nofollow" href="https://masalmon.eu/tags/rcorpora/" target="_blank">otherwise very useful</a> package<br>
<a rel="nofollow" href="https://github.com/gaborcsardi/rcorpora" target="_blank"><code>rcorpora</code></a> doesn’t have a<br>
“spooky” category, so I decided to scrape <a rel="nofollow" href="https://holidappy.com/holidays/halloween-words-and-halloween-vocabulary-lists" target="_blank">this webpage of Halloween<br>
words for<br>
kids</a>.<br>
It was one of the first search results, and being for kids it couldn’t<br>
be offensive. Like the last two times I webscraped, I used the <a rel="nofollow" href="https://masalmon.eu/2018/07/31/alldatascience/" target="_blank">very<br>
cool</a><br>
<a rel="nofollow" href="https://github.com/dmi3kno/polite" target="_blank"><code>polite</code></a> package!</p>
<p>There were two less useful sections on the page, with French and Spanish<br>
words, that I very inelegantly removed after looking up their div ID in<br>
the page source.</p>
<pre><code># introduce myself
session &lt;- polite::bow(&quot;https://holidappy.com/holidays/halloween-words-and-halloween-vocabulary-lists&quot;,
                       user_agent = &quot;Maëlle Salmon https://masalmon.eu/&quot;)

# scrape
page &lt;- polite::scrape(session)
</code></pre>
<pre><code>## No encoding supplied: defaulting to UTF-8.
</code></pre>
<pre><code># remove the two sections I don't want
French &lt;- xml2::xml_find_all(page,
                            xpath = &quot;//div[@id='mod_37589248']&quot;)

xml2::xml_remove(French)

Spanish &lt;- xml2::xml_find_all(page,
                              xpath = &quot;//div[@id='mod_37589143']&quot;)

xml2::xml_remove(Spanish)

# extract the words
words &lt;- xml2::xml_find_all(page,
                            xpath = &quot;//td[contains(@class, 'tableCell')]&quot;)

words &lt;- xml2::xml_text(words)
head(words)
</code></pre>
<pre><code>## [1] &quot;All Hallows' Eve\n\t&quot; &quot;lantern\n\t&quot;          &quot;prank\n\t&quot;           
## [4] &quot;costume\n\t&quot;          &quot;make-believe\n\t&quot;     &quot;sweets\n\t&quot;
</code></pre>
<p>I cleaned the words a bit. Some of them were not <em>words</em> so I split<br>
them. I hesitated between this solution and keeping only one-word<br>
phrases… I’m still not sure it was the best decision!</p>
<pre><code>words &lt;- stringr::str_remove_all(words, &quot;\\\n\\\t&quot;)
words &lt;- trimws(words)
words &lt;- tokenizers::tokenize_words(words)
words &lt;- unlist(words[lengths(words) > 0])
words &lt;- words[!stringr::str_detect(words, &quot;[0-9]&quot;)]
head(words)
</code></pre>
<pre><code>## [1] &quot;all&quot;     &quot;hallows&quot; &quot;eve&quot;     &quot;lantern&quot; &quot;prank&quot;   &quot;costume&quot;
</code></pre>
<p>I obtained 258 words.</p>
<h1>Matching names and spooky words</h1>
<p>Once I had this vector of Halloween-related words, all I needed was a<br>
way to compute a phonetical distance between each of them and a name. It<br>
turned out more complicated than I thought! The <code>soundex</code> method of the<br>
<a rel="nofollow" href="https://github.com/markvanderloo/stringdist" target="_blank"><code>stringdist</code></a> package<br>
returned 1 or 0 only, so I set out to search another package supporting<br>
phonetical comparison. I found the<br>
<a rel="nofollow" href="https://github.com/howardjp/phonics" target="_blank"><code>phonics</code></a> package that has a<br>
paper in JOSS, that implements more algorithms translating strings to<br>
phonetic “codes”. I ended up using the <code>phonics::nysiis()</code> function,<br>
corresponding to the New York State Identification and Intelligence<br>
System phonetic algorithm. That package also has an algorithm suitable<br>
for German, via <code>phonics::cologne()</code>, and one for French, via<br>
<code>phonics::statcan()</code>, but I haven’t explored that further.</p>
<pre><code>phonics::nysiis(&quot;pain&quot;)
</code></pre>
<pre><code>## [1] &quot;PAN&quot;
</code></pre>
<pre><code>phonics::nysiis(&quot;pane&quot;)
</code></pre>
<pre><code>## [1] &quot;PAN&quot;
</code></pre>
<pre><code>phonics::nysiis(&quot;train&quot;)
</code></pre>
<pre><code>## [1] &quot;TRAN&quot;
</code></pre>
<p>I was at a loss as to how best compare output from <code>phonics::nysiis()</code><br>
and very hackily used… <code>stringdist::stringdist()</code> with a default method!<br>
Below is the function finding the closest match for any name part.</p>
<pre><code>spookify_word &lt;- function(word, seed = 42, words){

  phon &lt;- phonics::nysiis(words)
  dist &lt;- stringdist::stringdist(phonics::nysiis(word),
                                 phon)
  set.seed(seed)
  sample(words[dist == min(dist)], 1)
}
spookify_word(&quot;Jane&quot;, words = words)
</code></pre>
<pre><code>## [1] &quot;bones&quot;
</code></pre>
<p>So <code>spookify_word()</code> samples a word among the closest matches… that<br>
aren’t necessarily very close to the original name. But that’s fine!</p>
<h1>Mixing it all in a <del>chauldron</del> function</h1>
<p>I finally created a function taking a whole name, say “Maëlle Salmon” or<br>
“Ada Colau Ballano”, tokenizes it into words thanks to the<br>
<a rel="nofollow" href="https://github.com/ropensci/tokenizers" target="_blank"><code>tokenizers</code></a> package, gets the<br>
closest match for each part and then collapses everything together,<br>
capitalizing first letters thanks to<br>
<a rel="nofollow" href="https://github.com/Tazinho/snakecase" target="_blank"><code>snakecase</code></a>… before announcing<br>
the result with the cool <a rel="nofollow" href="https://github.com/sckott/cowsay" target="_blank"><code>cowsay</code></a><br>
package! I made sure to only use animals that are associated with<br>
Halloween.</p>
<pre><code>spookify &lt;- function(name, seed,
                     words){
  name_parts &lt;- unlist(tokenizers::tokenize_words(name))
  spook_names &lt;- purrr::map_chr(name_parts,
                                spookify_word,
                                seed, words)
  spook_name &lt;- paste(spook_names, collapse = &quot; &quot;)
  spook_name &lt;- snakecase::to_upper_camel_case(spook_name,
                                               sep_out =  &quot; &quot;)
  
  set.seed(seed)
  animal &lt;- sample(c(&quot;owl&quot;, &quot;spider&quot;,
                     &quot;pumpkin&quot;, &quot;ghost&quot;,
                     &quot;bat&quot;), 1)

  cowsay::say(what = paste0(&quot;Byebye &quot;, name, &quot;\n&quot;,
                           &quot;You are now &quot;, spook_name),
              by = animal)

}
</code></pre>
<p>And because I didn’t want to make fun of anyone else than me, I created<br>
7 fake names using the <code>charlatan</code> package and ran <code>spookify</code> on them!</p>
<pre><code>set.seed(42)
names &lt;- charlatan::ch_name(n = 7)
purrr::walk2(names, 1:length(names),
             spookify, words = words)
</code></pre>
<pre><code>## Colors cannot be applied in this environment :( Try using a terminal or RStudio.

## 
## 
##  ----- 
## Byebye Tyrik Graham PhD
## You are now Trick Grinning Giant 
##  ------ 
##     \   
##      \
##               |
##               |
##               |
##              __
##           | /  \ |
##          \_\\  //_/
##           .'/()\'.
##            \\  //  [nosig]
## 

## Colors cannot be applied in this environment :( Try using a terminal or RStudio.

## 
##  ----- 
## Byebye Jeremy Rippin
## You are now Horrify Rotten 
##  ------ 
##     \   
##      \  
##       \
##        /\___/\
##        {o}{o}|
##        \ v  /|
##        |    \ \
##         \___/_/       [ab] 
##           | |

## Colors cannot be applied in this environment :( Try using a terminal or RStudio.

## 
##  ----- 
## Byebye Margarett Purdy
## You are now Boogers Party 
##  ------ 
##     \   
##      \  
##       \
##        /\___/\
##        {o}{o}|
##        \ v  /|
##        |    \ \
##         \___/_/       [ab] 
##           | |

## Colors cannot be applied in this environment :( Try using a terminal or RStudio.

## 
## 
##  ----- 
## Byebye Miss Tilla Funk DDS
## You are now Ooze Vil Fangs Dead 
##  ------ 
##     \   
##      \
##                   ___
##                ___)__|_
##           .-*'          '*-,
##          /      /|   |\     \
##         ;      /_|   |_\     ;
##         ;   |\           /|  ;
##         ;   | ''--...--'' |  ;
##          \  ''---.....--''  /
##           ''*-.,_______,.-*'  [nosig]
## 

## Colors cannot be applied in this environment :( Try using a terminal or RStudio.

## 
## 
##  ----- 
## Byebye Wilton Carroll IV
## You are now Cartoon Cruella Eve 
##  ------ 
##     \   
##      \
##               |
##               |
##               |
##              __
##           | /  \ |
##          \_\\  //_/
##           .'/()\'.
##            \\  //  [nosig]
## 

## Colors cannot be applied in this environment :( Try using a terminal or RStudio.

## 
## 
##  ----- 
## Byebye Tevin Conn
## You are now Coffin Bones 
##  ------ 
##     \   
##      \
##      .-.
##     (o o)
##     | O \
##      \   \
##       `~~~' [nosig]
## 

## Colors cannot be applied in this environment :( Try using a terminal or RStudio.

## 
## 
##  ------------- 
## Byebye Dr. Ballard Langworth III
## You are now Dish Blood Cemetery Dish 
##  -------------- 
##               \   
##                \  
##                 \
##         __.--'\     \.__./     /'--.__
##     _.-'       '.__.'    '.__.'       '-._
##   .'                                      '.
##  /                                          \
## |                                            |
## |                                            |
##  \         .---.              .---.         /
##   '._    .'     '.''.    .''.'     '.    _.'
##      '-./            \  /           \.-'
##                       ''mrf
</code></pre>
<p>Note that <a rel="nofollow" href="https://github.com/sckott/cowsay/issues/65" target="_blank">I reported the message I got from<br>
<code>cowsay</code></a>. It’s not too bad,<br>
<code>cowsay</code> is not designed for use in R Markdown I think.</p>
<p>I found the results not fantastic, but not too bad either! I especially<br>
liked “Boogers Party”!</p>
<h1>Mucus, anyone?</h1>
<p>In conclusion, in this post I showed how to build a corpus of<br>
Halloween-related words by responsibly webscraping, and how to more or<br>
less hackily compare strings based on their pronunciation. I obviously<br>
tried the function on my own name (without the accent, useless in this<br>
case) and wasn’t too happy…</p>
<pre><code>spookify(&quot;Maelle Salmon&quot;, 42, words)
</code></pre>
<pre><code>## Colors cannot be applied in this environment :( Try using a terminal or RStudio.

## 
## 
##  ------------- 
## Byebye Maelle Salmon
## You are now Mucus Bulging 
##  -------------- 
##               \   
##                \  
##                 \
##         __.--'\     \.__./     /'--.__
##     _.-'       '.__.'    '.__.'       '-._
##   .'                                      '.
##  /                                          \
## |                                            |
## |                                            |
##  \         .---.              .---.         /
##   '._    .'     '.''.    .''.'     '.    _.'
##      '-./            \  /           \.-'
##                       ''mrf
</code></pre>
<p>But then, at least, it <em>is</em> scary.</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="https://masalmon.eu/2018/10/05/spookify/"> Posts on Maëlle's R blog</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/D8IGk1SJk3Q" height="1"></a></div>