<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/simulating-unown-encounter-rates-in-pokemon-go/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://tjmahr.github.io/pokemon-go-unown-simulation/"> Higher Order Functions</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p><em>Pokémon Go</em> is an augmented reality game where people with<br>
smartphones walk around and catch Pokémon. As in the classic games, players are<br>
Pokémon “trainers” who have to travel around and collect creatures. Some types<br>
are rarer than others, some have regional habitats or biomes, and so players<br>
explore the game world to find and collect them. Pokémon Go<br>
“augments reality” having these Pokémon spawn in the game world as players<br>
travel around the real world. I like the game; I’ve reached level 30.</p>
<p><img alt="The elusive unown!" src="https://i2.wp.com/tjmahr.github.io/assets/images/bulbapedia_unown.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>On February 16, 2017, a second “generation” of Pokémon were released into the<br>
wild, adding dozens of new species to the game. The <a title="How to catch Unown in Pokémon Go" target="_blank" rel="nofollow" href="http://www.imore.com/how-to-catch-unown-pokemon-go">rarest among this new<br>
generation</a> is <a title="Bulbapedia page on Unown" target="_blank" rel="nofollow" href="http://bulbapedia.bulbagarden.net/wiki/Unown_(Pok%C3%A9mon)"><strong>Unown</strong></a>. As part of a cruel scheme to torture<br>
completionists, the incredibly rare Unown comes in 26 varieties—one for each<br>
letter of the alphabet. Which brings us to the statistical question behind this<br>
blog post: <strong>How long will it take to encounter all 26 types of Unowns (taking<br>
into account repeats)?</strong> Somewhat more formally, how many random encounters<br>
(i.e., draws while sampling with replacement) will it take until we have<br>
encountered all 26 Unowns?</p>
<p>This general problem is called the <strong>coupon collector’s problem</strong>—hat tip<br>
to <a title="Silph Road thread on Unown encounters" target="_blank" rel="nofollow" href="https://www.reddit.com/r/TheSilphRoad/comments/5v3nv5/it_would_take_100_wild_catches_to_get_all_the/">r/TheSilphRoad</a>. The <a title="Wikipedia page on Coupon Collector's problem" target="_blank" rel="nofollow" href="https://en.wikipedia.org/wiki/Coupon_collector%27s_problem">Wikipedia</a><br>
article for the problem includes a table which says that the expected number<br>
of encounters for <em>n</em> = 26 is = 101. (The analytic solution is actually<br>
100.2, but we round up because there are no fractional encounters.) So problem<br>
solved?</p>
<p>Well, not quite. Suppose we had never heard of the coupon collector’s problem.<br>
Also, suppose that we want to get a sense of the uncertainty around the<br>
expected value. For example, how many encounters will it take for the<br>
unfortunate trainers in the 95th percentile? How might we tackle this problem?</p>
<p><img alt="S I M U L A T E" src="https://i0.wp.com/tjmahr.github.io/assets/images/unown_simulate.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p>When analytic solutions are difficult or tedious, we can write simulations and<br>
get very good approximations. That’s what we’re going to do in R.</p>
<p>We will write a function to simulate a single exhaustive set of Unown<br>
encounters. The main workhorse is <code>sample(..., replace = TRUE)</code> to sample with<br>
replacement. Using R’s built-in <code>LETTERS</code> constant, we can simulate a batch of<br>
Unown encounters.</p>
<div>
<pre><code><span>sample</span><span>(</span><span>LETTERS</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>1</span><span>,</span><span> </span><span>replace</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>#> [1] &quot;F&quot;
</span><span>sample</span><span>(</span><span>LETTERS</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>5</span><span>,</span><span> </span><span>replace</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>#> [1] &quot;H&quot; &quot;U&quot; &quot;C&quot; &quot;G&quot; &quot;D&quot;
</span><span>sample</span><span>(</span><span>LETTERS</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>10</span><span>,</span><span> </span><span>replace</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>#> [1] &quot;T&quot; &quot;K&quot; &quot;K&quot; &quot;D&quot; &quot;Z&quot; &quot;O&quot; &quot;Y&quot; &quot;K&quot; &quot;Q&quot; &quot;Q&quot;
</span></code></pre>
</div>
<p>The question now is how many samples does it take to get the 26 different<br>
Unowns. An absolute, and frankly miraculous, lower bound on this number would be<br>
26, so let’s draw 26 samples.</p>
<div>
<pre><code><span>set.seed</span><span>(</span><span>252</span><span>)</span><span> </span><span># For reproducble blogging
</span><span>n_unique</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>xs</span><span>)</span><span> </span><span>length</span><span>(</span><span>unique</span><span>(</span><span>xs</span><span>))</span><span>
</span><span># Unowns in the batch
</span><span>first_batch</span><span> </span><span>&lt;-</span><span> </span><span>sample</span><span>(</span><span>LETTERS</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>26</span><span>,</span><span> </span><span>replace</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>first_batch</span><span>
</span><span>#> [1] &quot;X&quot; &quot;S&quot; &quot;I&quot; &quot;T&quot; &quot;R&quot; &quot;J&quot; &quot;L&quot; &quot;N&quot; &quot;F&quot; &quot;I&quot; &quot;P&quot; &quot;Q&quot; &quot;K&quot; &quot;D&quot; &quot;Q&quot; &quot;Q&quot; &quot;K&quot;
#> [18] &quot;O&quot; &quot;S&quot; &quot;C&quot; &quot;F&quot; &quot;C&quot; &quot;P&quot; &quot;X&quot; &quot;V&quot; &quot;L&quot;
</span><span>
</span><span># Number of unique ones
</span><span>n_unique</span><span>(</span><span>first_batch</span><span>)</span><span>
</span><span>#> [1] 16
</span><span>
</span><span># Number of remaining Unowns we have not encountered yet
</span><span>leftover</span><span> </span><span>&lt;-</span><span> </span><span>26</span><span> </span><span>-</span><span> </span><span>n_unique</span><span>(</span><span>first_batch</span><span>)</span><span>
</span><span>leftover</span><span>
</span><span>#> [1] 10
</span></code></pre>
</div>
<p>We encountered 16 unique Unowns from the first batch of<br>
samples. The best-case lower bound for the number of the encounters remaining is<br>
now 10, so let’s take 10 more samples.</p>
<div>
<pre><code><span>second_batch</span><span> </span><span>&lt;-</span><span> </span><span>sample</span><span>(</span><span>LETTERS</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>leftover</span><span>,</span><span> </span><span>replace</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>second_batch</span><span>
</span><span>#> [1] &quot;Y&quot; &quot;X&quot; &quot;S&quot; &quot;F&quot; &quot;P&quot; &quot;Z&quot; &quot;F&quot; &quot;F&quot; &quot;Y&quot; &quot;G&quot;
</span><span>
</span><span># Combine the batches
</span><span>both_batches</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>first_batch</span><span>,</span><span> </span><span>second_batch</span><span>)</span><span>
</span><span>n_unique</span><span>(</span><span>both_batches</span><span>)</span><span>
</span><span>#> [1] 19
</span><span>
</span><span>leftover</span><span> </span><span>&lt;-</span><span> </span><span>26</span><span> </span><span>-</span><span> </span><span>n_unique</span><span>(</span><span>both_batches</span><span>)</span><span>
</span><span>leftover</span><span>
</span><span>#> [1] 7
</span></code></pre>
</div>
<p>We found 3 new Unowns in this<br>
batch, and we have encountered 19 unique ones so far<br>
from 36 total samples. That means the lower bound is now<br>
7.</p>
<div>
<pre><code><span>third_batch</span><span> </span><span>&lt;-</span><span> </span><span>sample</span><span>(</span><span>LETTERS</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>leftover</span><span>,</span><span> </span><span>replace</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>third_batch</span><span>
</span><span>#> [1] &quot;U&quot; &quot;A&quot; &quot;G&quot; &quot;P&quot; &quot;K&quot; &quot;L&quot; &quot;E&quot;
</span><span>
</span><span>all_batches</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>both_batches</span><span>,</span><span> </span><span>third_batch</span><span>)</span><span>
</span><span>n_unique</span><span>(</span><span>all_batches</span><span>)</span><span>
</span><span>#> [1] 22
</span><span>
</span><span>leftover</span><span> </span><span>&lt;-</span><span> </span><span>26</span><span> </span><span>-</span><span> </span><span>n_unique</span><span>(</span><span>all_batches</span><span>)</span><span>
</span><span>leftover</span><span>
</span><span>#> [1] 4
</span></code></pre>
</div>
<p>We found 3 new Unowns in this—</p>
<p>Actually, this is getting tedious. We all know where this process is going: Take<br>
a sample, see how many you have left to find, take another sample of that size,<br>
etc. until you have 0 left to find. Pretty simple? Great! Now, I don’t have to<br>
explain how the <code>while</code> loop inside the function works.</p>
<div>
<pre><code><span>simulate_unown</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>()</span><span> </span><span>{</span><span>
</span><span># Use a sequence of numbers instead of LETTERS
</span><span> </span><span>n_unowns</span><span> </span><span>&lt;-</span><span> </span><span>26</span><span>
</span><span>unown_set</span><span> </span><span>&lt;-</span><span> </span><span>seq_len</span><span>(</span><span>n_unowns</span><span>)</span><span>
</span><span>n_unique</span><span> </span><span>&lt;-</span><span> </span><span>0</span><span>
</span><span>encountered</span><span> </span><span>&lt;-</span><span> </span><span>character</span><span>(</span><span>0</span><span>)</span><span>
</span><span># Take 26 samples on first iteration, 26 - n_unique on next iteration, etc.
</span><span> </span><span>while</span><span> </span><span>(</span><span>n_unowns</span><span> </span><span>-</span><span> </span><span>n_unique</span><span> </span><span>></span><span> </span><span>0</span><span>)</span><span> </span><span>{</span><span>
</span><span>batch</span><span> </span><span>&lt;-</span><span> </span><span>sample</span><span>(</span><span>unown_set</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>n_unowns</span><span> </span><span>-</span><span> </span><span>n_unique</span><span>,</span><span> </span><span>replace</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span>encountered</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>encountered</span><span>,</span><span> </span><span>batch</span><span>)</span><span>
</span><span>n_unique</span><span> </span><span>&lt;-</span><span> </span><span>length</span><span>(</span><span>unique</span><span>(</span><span>encountered</span><span>))</span><span>
</span><span>}</span><span>
</span><span>length</span><span>(</span><span>encountered</span><span>)</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>Each call of the function simulates a process of encountering all 26 Unowns,<br>
returning how many encounters were required to find them all.</p>
<div>
<pre><code><span>simulate_unown</span><span>()</span><span>
</span><span>#> [1] 111
</span><span>simulate_unown</span><span>()</span><span>
</span><span>#> [1] 81
</span><span>simulate_unown</span><span>()</span><span>
</span><span>#> [1] 116
</span></code></pre>
</div>
<p>We use <code>replicate()</code> to call this function thousands of times.</p>
<div>
<pre><code><span>simulation</span><span> </span><span>&lt;-</span><span> </span><span>replicate</span><span>(</span><span>10000</span><span>,</span><span> </span><span>simulate_unown</span><span>())</span><span>
</span></code></pre>
</div>
<p>We can get summary statistics and other quantiles for these simulations.</p>
<div>
<pre><code><span>summary</span><span>(</span><span>simulation</span><span>)</span><span>
</span><span>#> Min. 1st Qu. Median Mean 3rd Qu. Max. #> 41.0 78.0 95.0 100.3 116.0 373.0
</span><span>quantile</span><span>(</span><span>simulation</span><span>,</span><span> </span><span>probs</span><span> </span><span>=</span><span> </span><span>c</span><span>(</span><span>.05</span><span>,</span><span> </span><span>.10</span><span>,</span><span> </span><span>.25</span><span>,</span><span> </span><span>.50</span><span>,</span><span> </span><span>.75</span><span>,</span><span> </span><span>.90</span><span>,</span><span> </span><span>.95</span><span>))</span><span>
</span><span>#> 5% 10% 25% 50% 75% 90% 95% #> 61 67 78 95 116 141 161
</span></code></pre>
</div>
<p>The mean in our simulations 100.3 is very close to<br>
the analytic solution of 100.2. The median 95 is less than<br>
the mean, which is a bit of good news: More than half of players will hit 26<br>
in less than the expected 100 encounters. The bad news is that there is a long<br>
tail to these simulations, as the RNG gods have cursed one player by requiring<br>
373 encounters.</p>
<p>We can visualize the distribution with a histogram.</p>
<div>
<pre><code><span>library</span><span>(</span><span>ggplot2</span><span>)</span><span>
</span><span>p</span><span>1</span><span> </span><span>&lt;-</span><span> </span><span>ggplot</span><span>(</span><span>data.frame</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>simulation</span><span>))</span><span> </span><span>+</span><span> </span><span>aes</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>x</span><span>)</span><span> </span><span>+</span><span> </span><span>geom_histogram</span><span>(</span><span>binwidth</span><span> </span><span>=</span><span> </span><span>5</span><span>,</span><span> </span><span>color</span><span> </span><span>=</span><span> </span><span>&quot;white&quot;</span><span>,</span><span> </span><span>center</span><span> </span><span>=</span><span> </span><span>102.5</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;Num. Unowns encountered until 26 unique Unowns encountered&quot;</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>&quot;Num. samples in 10,000 simulations&quot;</span><span>)</span><span> </span><span>+</span><span> </span><span>theme</span><span>(</span><span>axis.title.x</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>hjust</span><span> </span><span>=</span><span> </span><span>.995</span><span>),</span><span>
</span><span>axis.title.y</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>hjust</span><span> </span><span>=</span><span> </span><span>.995</span><span>))</span><span> </span><span>+</span><span>
</span><span>ggtitle</span><span>(</span><span>&quot;A long-tail of unfortunate RNG for Unown completionists&quot;</span><span>)</span><span>
</span><span>p</span><span>1</span><span>
</span></code></pre>
</div>
<p><img title="A long-tail of unfortunate RNG for Unown completionists" alt="A long-tail of unfortunate RNG for Unown completionists" src="https://i1.wp.com/tjmahr.github.io/figs//2017-03-22-pokemon-go-unown-simulation/plot-encounters-1.png?w=80%25&ssl=1" data-recalc-dims="1"></p>
<p>I haven’t seen any of these Pokémon in the month since they were added to the<br>
game. Assuming I see an Unown every month, I can expect to see them all in 100<br>
encounters over the course of 8.3 years. As I said, a cruel<br>
joke for completionists.</p>
<h2>What? SIMULATE_UNOWN is evolving!</h2>
<p>One nice thing about using simulations to compute statistics is that we can<br>
easily modify the simulation function to answer related questions. For example:</p>
<ul>
<li>The above simulation assumed that we can catch the Unowns 100% of the time.<br>
What if we fail on 5% of the encounters?</li>
<li>Two more Unowns were added to the series in the third Pokémon generation.<br>
What is the expected number of encounters for 28 Unowns?</li>
<li>Suppose we already have 20 Unowns. How many more encounters are required to<br>
collect the remaining 6?</li>
</ul>
<p>We can add some parameters to our function to address these questions. To<br>
simulate catching, we sample a <code>TRUE</code> or <code>FALSE</code> value for each Unown sampled. The<br>
<code>prob</code> argument for <code>sample()</code> lets us assign probabilities to elements in the<br>
sample, so we can use <code>c(p_catch, 1 - p_catch)</code> as probabilities for sampling<br>
<code>TRUE</code> or <code>FALSE</code>—that is, catching a Pokémon.</p>
<p>To handle already-captured Unowns, we add this information to the initial<br>
values for <code>encountered</code> and <code>n_unique</code> to give those values a head start<br>
before the encounter/catch loop. Afterwards, we have to adjust our encounter<br>
count by that head start.</p>
<div>
<pre><code><span># Defaults to 26 unowns, 0 already caught, and 100% success rate
</span><span>simulate_unown_catches</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>n_unowns</span><span> </span><span>=</span><span> </span><span>26</span><span>,</span><span> </span><span>n_already</span><span> </span><span>=</span><span> </span><span>0</span><span>,</span><span> </span><span>p_catch</span><span> </span><span>=</span><span> </span><span>1</span><span>)</span><span> </span><span>{</span><span>
</span><span>unown_set</span><span> </span><span>&lt;-</span><span> </span><span>seq_len</span><span>(</span><span>n_unowns</span><span>)</span><span>
</span><span>catch_probs</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>p_catch</span><span>,</span><span> </span><span>1</span><span> </span><span>-</span><span> </span><span>p_catch</span><span>)</span><span>
</span><span># Take into account any previously caught ones
</span><span> </span><span>n_unique</span><span> </span><span>&lt;-</span><span> </span><span>n_already</span><span>
</span><span>already_encountered</span><span> </span><span>&lt;-</span><span> </span><span>seq_len</span><span>(</span><span>n_already</span><span>)</span><span>
</span><span>already_caught</span><span> </span><span>&lt;-</span><span> </span><span>already_encountered</span><span>
</span><span>encountered</span><span> </span><span>&lt;-</span><span> </span><span>already_encountered</span><span>
</span><span>caught</span><span> </span><span>&lt;-</span><span> </span><span>already_caught</span><span>
</span><span># Encounter/catch loop </span><span> </span><span>while</span><span> </span><span>(</span><span>n_unowns</span><span> </span><span>-</span><span> </span><span>n_unique</span><span> </span><span>></span><span> </span><span>0</span><span>)</span><span> </span><span>{</span><span>
</span><span>batch</span><span> </span><span>&lt;-</span><span> </span><span>sample</span><span>(</span><span>unown_set</span><span>,</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>n_unowns</span><span> </span><span>-</span><span> </span><span>n_unique</span><span>,</span><span> </span><span>replace</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>)</span><span>
</span><span># Simulate catching success for each Unown
</span><span> </span><span>catches</span><span> </span><span>&lt;-</span><span> </span><span>sample</span><span>(</span><span>c</span><span>(</span><span>TRUE</span><span>,</span><span> </span><span>FALSE</span><span>),</span><span> </span><span>size</span><span> </span><span>=</span><span> </span><span>n_unowns</span><span> </span><span>-</span><span> </span><span>n_unique</span><span>,</span><span> </span><span>replace</span><span> </span><span>=</span><span> </span><span>TRUE</span><span>,</span><span> </span><span>prob</span><span> </span><span>=</span><span> </span><span>catch_probs</span><span>)</span><span>
</span><span>caught_in_batch</span><span> </span><span>&lt;-</span><span> </span><span>batch</span><span>[</span><span>catches</span><span>]</span><span>
</span><span>encountered</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>encountered</span><span>,</span><span> </span><span>batch</span><span>)</span><span>
</span><span>caught</span><span> </span><span>&lt;-</span><span> </span><span>c</span><span>(</span><span>caught</span><span>,</span><span> </span><span>caught_in_batch</span><span>)</span><span>
</span><span>n_unique</span><span> </span><span>&lt;-</span><span> </span><span>length</span><span>(</span><span>unique</span><span>(</span><span>caught</span><span>))</span><span>
</span><span>}</span><span>
</span><span>length</span><span>(</span><span>encountered</span><span>)</span><span> </span><span>-</span><span> </span><span>length</span><span>(</span><span>already_encountered</span><span>)</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
<p>With the default settings, the function should reproduce the original behavior<br>
and give us similar results.</p>
<div>
<pre><code><span>simulation2</span><span> </span><span>&lt;-</span><span> </span><span>replicate</span><span>(</span><span>10000</span><span>,</span><span> </span><span>simulate_unown_catches</span><span>())</span><span>
</span><span>summary</span><span>(</span><span>simulation2</span><span>)</span><span>
</span><span>#> Min. 1st Qu. Median Mean 3rd Qu. Max. #> 38.0 78.0 94.0 100.2 115.0 369.0
</span></code></pre>
</div>
<p>We should expect the average number of required encounters to catch all 26<br>
Unowns to increase by 1.05 if there’s a 95% catch rate. Our simulations confirm<br>
this intuition.</p>
<div>
<pre><code><span>simulation_95_rate</span><span> </span><span>&lt;-</span><span> </span><span>replicate</span><span>(</span><span>
</span><span>n</span><span> </span><span>=</span><span> </span><span>10000</span><span>,</span><span> </span><span>expr</span><span> </span><span>=</span><span> </span><span>simulate_unown_catches</span><span>(</span><span>n_unowns</span><span> </span><span>=</span><span> </span><span>26</span><span>,</span><span> </span><span>p_catch</span><span> </span><span>=</span><span> </span><span>.95</span><span>))</span><span>
</span><span>summary</span><span>(</span><span>simulation_95_rate</span><span>)</span><span>
</span><span>#> Min. 1st Qu. Median Mean 3rd Qu. Max. #> 41.0 82.0 100.0 106.2 124.0 338.0
</span></code></pre>
</div>
<p>We can also simulate the case for 28 Unowns with a 100% encounter rate, and see<br>
that the average number of required encounters increases by approximately 10.</p>
<div>
<pre><code><span>simulation_28_unowns</span><span> </span><span>&lt;-</span><span> </span><span>replicate</span><span>(</span><span>
</span><span>n</span><span> </span><span>=</span><span> </span><span>10000</span><span>,</span><span> </span><span>expr</span><span> </span><span>=</span><span> </span><span>simulate_unown_catches</span><span>(</span><span>n_unowns</span><span> </span><span>=</span><span> </span><span>28</span><span>,</span><span> </span><span>p_catch</span><span> </span><span>=</span><span> </span><span>1</span><span>))</span><span>
</span><span>summary</span><span>(</span><span>simulation_28_unowns</span><span>)</span><span>
</span><span>#> Min. 1st Qu. Median Mean 3rd Qu. Max. #> 44.0 85.0 104.0 109.9 127.0 322.0
</span></code></pre>
</div>
<p>Finally, we can simulate the home stretch of Unown completion where we<br>
have 20 Unowns with 6 more to go.</p>
<div>
<pre><code><span>simulation_last_6</span><span> </span><span>&lt;-</span><span> </span><span>replicate</span><span>(</span><span>
</span><span>n</span><span> </span><span>=</span><span> </span><span>10000</span><span>,</span><span> </span><span>expr</span><span> </span><span>=</span><span> </span><span>simulate_unown_catches</span><span>(</span><span>n_unowns</span><span> </span><span>=</span><span> </span><span>26</span><span>,</span><span> </span><span>n_already</span><span> </span><span>=</span><span> </span><span>20</span><span>,</span><span> </span><span>p_catch</span><span> </span><span>=</span><span> </span><span>1</span><span>))</span><span>
</span><span>summary</span><span>(</span><span>simulation_last_6</span><span>)</span><span>
</span><span>#> Min. 1st Qu. Median Mean 3rd Qu. Max. #> 8.00 42.00 57.00 63.39 79.00 282.00
</span></code></pre>
</div>
<p>This result is interesting: It says that we will spend the majority of our time<br>
working on the last 6 Unowns.</p>
<h2>Simulate ‘em all</h2>
<p>A natural next step is to run many simulations over a range of parameter<br>
values. Here, we can study the home-stretch behavior by running a simulation<br>
for each value of <code>n_already</code> from 0 to 25.</p>
<p>We will create a function to simulate 2000 home-stretch samples of required<br>
encounters for a given number of starting Unowns. This function will return a<br>
dataframe with one row per simulation sample. We use <code>Map()</code> to apply this<br>
function for each value of <code>n_already</code> from 0 to 25.</p>
<div>
<pre><code><span>library</span><span>(</span><span>dplyr</span><span>,</span><span> </span><span>warn.conflicts</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>)</span><span>
</span><span>simulate_2k</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>n_already</span><span>)</span><span> </span><span>{</span><span>
</span><span>n_sims</span><span> </span><span>&lt;-</span><span> </span><span>2000</span><span>
</span><span>sim_results</span><span> </span><span>&lt;-</span><span> </span><span>replicate</span><span>(</span><span>
</span><span>n</span><span> </span><span>=</span><span> </span><span>n_sims</span><span>,</span><span> </span><span>expr</span><span> </span><span>=</span><span> </span><span>simulate_unown_catches</span><span>(</span><span>n_unowns</span><span> </span><span>=</span><span> </span><span>26</span><span>,</span><span> </span><span>n_already</span><span>,</span><span> </span><span>p_catch</span><span> </span><span>=</span><span> </span><span>1</span><span>))</span><span>
</span><span># Package everything together in a dataframe </span><span> </span><span>data_frame</span><span>(</span><span>
</span><span>n_already</span><span> </span><span>=</span><span> </span><span>rep</span><span>(</span><span>n_already</span><span>,</span><span> </span><span>times</span><span> </span><span>=</span><span> </span><span>n_sims</span><span>),</span><span>
</span><span>simulation</span><span> </span><span>=</span><span> </span><span>seq_len</span><span>(</span><span>n_sims</span><span>),</span><span>
</span><span>n_encounters</span><span> </span><span>=</span><span> </span><span>sim_results</span><span>)</span><span>
</span><span>}</span><span>
</span><span>results</span><span> </span><span>&lt;-</span><span> </span><span>Map</span><span>(</span><span>simulate_2k</span><span>,</span><span> </span><span>n_already</span><span> </span><span>=</span><span> </span><span>0</span><span>:</span><span>25</span><span>)</span><span>
</span><span>df_results</span><span> </span><span>&lt;-</span><span> </span><span>bind_rows</span><span>(</span><span>results</span><span>)</span><span>
</span><span>df_results</span><span>
</span><span>#> # A tibble: 52,000 × 3
#> n_already simulation n_encounters
#> &lt;int> &lt;int> &lt;int>
#> 1 0 1 157
#> 2 0 2 125
#> 3 0 3 129
#> 4 0 4 107
#> 5 0 5 69
#> 6 0 6 65
#> 7 0 7 70
#> 8 0 8 147
#> 9 0 9 69
#> 10 0 10 77
#> # ... with 51,990 more rows
</span></code></pre>
</div>
<p>We can now plot the expected number of encounters for each starting value.<br>
Variance from random simulation keeps the points from following a neat curve,<br>
so let’s just appreciate the main trends in the results.</p>
<div>
<pre><code><span>ggplot</span><span>(</span><span>df_results</span><span>)</span><span> </span><span>+</span><span> </span><span>aes</span><span>(</span><span>x</span><span> </span><span>=</span><span> </span><span>n_already</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>n_encounters</span><span>)</span><span> </span><span>+</span><span> </span><span>stat_summary</span><span>(</span><span>fun.y</span><span> </span><span>=</span><span> </span><span>mean</span><span>,</span><span> </span><span>geom</span><span> </span><span>=</span><span> </span><span>&quot;point&quot;</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;Num. Unown types already encountered&quot;</span><span>,</span><span> </span><span>y</span><span> </span><span>=</span><span> </span><span>&quot;Expected num. encounters to find all 26&quot;</span><span>)</span><span> </span><span>+</span><span> </span><span>theme</span><span>(</span><span>axis.title.x</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>hjust</span><span> </span><span>=</span><span> </span><span>.995</span><span>),</span><span>
</span><span>axis.title.y</span><span> </span><span>=</span><span> </span><span>element_text</span><span>(</span><span>hjust</span><span> </span><span>=</span><span> </span><span>.995</span><span>))</span><span> </span><span>+</span><span>
</span><span>ggtitle</span><span>(</span><span>&quot;The painful home stretch of Unown completion&quot;</span><span>)</span><span>
</span></code></pre>
</div>
<p><img title="The painful home stretch of Unown completion" alt="The painful home stretch of Unown completion" src="https://i1.wp.com/tjmahr.github.io/figs//2017-03-22-pokemon-go-unown-simulation/plot-unown-home-stretch-1.png?w=80%25&ssl=1" data-recalc-dims="1"></p>
<p>Because the analytic solution for finding 26 Unowns starting from 0 is 100, we<br>
can also read the <em>y</em>-axis as a percentage. In other words, 60% of the work<br>
(number of encounters out of 100) will be spent on the last 5 Unowns.</p>
<h2>Simulation as a way to learn statistics</h2>
<p>An underlying theme for this post is best summarized by a line from a talk<br>
called Statistics for Hackers:</p>
<blockquote>
<p>“If you can write <em>for</em> loops, you can do<br>
statistics.” — <a title="Statistics For Hackers slides" target="_blank" rel="nofollow" href="https://speakerdeck.com/jakevdp/statistics-for-hackers">Statistics for Hackers</a></p>
</blockquote>
<p>Simulation provides a way for “hackers” to leverage one skill (programming) to<br>
learn another domain (statistics). I myself find that I have trouble learning<br>
statistics from equations alone. I need code to play with a problem and develop<br>
intuitions about it.</p>
<p>All of these points about the nice features of simulation must be painfully<br>
obvious to professional statisticians. But strangely, I only used simulations<br>
once or twice in my statistics courses, so it wasn’t part of my statistical tool<br>
kit. Indeed, I had the usefulness of simulation impressed upon me last year by<br>
<a target="_blank" rel="nofollow" href="http://amzn.to/2nnxVWA">Gelman and Hill’s textbook</a>. The book advises the<br>
reader to not worry about analytically computing statistics for tricky<br>
calculations—for example, trying to estimate a 95% prediction interval for the<br>
income difference between two groups when the underlying statistical model used<br>
log-dollars. Just have the model generate thousands for predictions, run the<br>
transformation, and find the interval on the transformed data. The book also<br>
uses simulation as a sneaky backdoor into informal Bayesian statistics: Measure<br>
uncertainty by simulating new data from perturbed model parameters. This idea<br>
made enough sense to me to lure me into the chapters on formal Bayesian<br>
inference and learn that statistical framework.</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://tjmahr.github.io/pokemon-go-unown-simulation/"> Higher Order Functions</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/0M4LXsbcgxY"></a></div>