andrew brooksJekyll2018-07-05T04:18:25+00:00http://brooksandrew.github.io/simpleblog/andrew brookshttp://brooksandrew.github.io/simpleblog/andrewbrooksct@gmail.comhttp://brooksandrew.github.io/simpleblog/articles/sleeping-giant-rural-postman-problem2017-12-01T00:00:00+00:002017-12-01T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<p>This problem originated from a blog post I wrote for DataCamp on graph optimization <a href="https://www.datacamp.com/community/tutorials/networkx-python-graph-tutorial">here</a>. The algorithm I sketched out there for solving the Chinese Problem on the
<a href="http://www.ct.gov/deep/cwp/view.asp?a=2716&q=325264&deepNav_GID=1650%20">Sleeping Giant state park</a> trail network has since been formalized into the <a href="https://github.com/brooksandrew/postman_problems">postman_problems</a> python library. I’ve also added the Rural Postman solver that is implemented here.</p>
<p>So the three main enhancements in this post from the original DataCamp article and my second iteration published <a href="http://brooksandrew.github.io/simpleblog/articles/intro-to-graph-optimization-solving-cpp">here</a> updating to networkx 2.0 are:</p>
<ol>
<li>OpenStreetMap for graph data and visualization.</li>
<li>Implementing the Rural Postman algorithm to consider optional edges.</li>
<li>Leveraging the <a href="https://github.com/brooksandrew/postman_problems">postman_problems</a> library.</li>
</ol>
<p>This code, notebook and data for this post can be found in the <a href="https://github.com/brooksandrew/postman_problems_examples">postman_problems_examples</a> repo.</p>
<p>The motivation and background around this problem is written up more thoroughly in the previous posts and <a href="https://github.com/brooksandrew/postman_problems">postman_problems</a>.</p>
<h4 id="rpp-solution-route-animation">RPP Solution Route Animation</h4>
<p>Here’s the full route animation. More details <a href="https://github.com/brooksandrew/postman_problems_examples/tree/master/sleepinggiant/animation">here</a>. Kudos to my sister <a href="https://github.com/laurabrooks">@laurabrooks</a> for coding this up!</p>
<iframe src="http://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/sleepinggiant/animation/index.html" height="400" width="750"></iframe>
<h4 id="table-of-contents">Table of Contents</h4>
<ul id="markdown-toc">
<li><a href="#create-graph-from-osm" id="markdown-toc-create-graph-from-osm">Create Graph from OSM</a></li>
<li><a href="#viz-sleeping-giant-trails" id="markdown-toc-viz-sleeping-giant-trails">Viz Sleeping Giant Trails</a></li>
<li><a href="#connect-edges" id="markdown-toc-connect-edges">Connect Edges</a></li>
<li><a href="#viz-connected-component" id="markdown-toc-viz-connected-component">Viz Connected Component</a></li>
<li><a href="#viz-trail-color" id="markdown-toc-viz-trail-color">Viz Trail Color</a></li>
<li><a href="#contract-edges" id="markdown-toc-contract-edges">Contract Edges</a></li>
<li><a href="#solve-cpp" id="markdown-toc-solve-cpp">Solve CPP</a></li>
<li><a href="#solve-rpp" id="markdown-toc-solve-rpp">Solve RPP</a></li>
<li><a href="#viz-rpp-solution" id="markdown-toc-viz-rpp-solution">Viz RPP Solution</a> <ul>
<li><a href="#viz-rpp-optional-edges" id="markdown-toc-viz-rpp-optional-edges">Viz: RPP optional edges</a></li>
<li><a href="#viz-rpp-edges-counts" id="markdown-toc-viz-rpp-edges-counts">Viz: RPP edges counts</a></li>
</ul>
</li>
<li><a href="#create-geojson-solution" id="markdown-toc-create-geojson-solution">Create geojson solution</a></li>
</ul>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">mplleaflet</span>
<span class="kn">import</span> <span class="nn">networkx</span> <span class="k">as</span> <span class="n">nx</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">Counter</span>
<span class="c"># can be found in https://github.com/brooksandrew/postman_problems_examples</span>
<span class="kn">from</span> <span class="nn">osm2nx</span> <span class="kn">import</span> <span class="n">read_osm</span><span class="p">,</span> <span class="n">haversine</span>
<span class="kn">from</span> <span class="nn">graph</span> <span class="kn">import</span> <span class="n">contract_edges</span><span class="p">,</span> <span class="n">create_rpp_edgelist</span>
<span class="kn">from</span> <span class="nn">postman_problems.tests.utils</span> <span class="kn">import</span> <span class="n">create_mock_csv_from_dataframe</span>
<span class="kn">from</span> <span class="nn">postman_problems.solver</span> <span class="kn">import</span> <span class="n">rpp</span><span class="p">,</span> <span class="n">cpp</span>
<span class="kn">from</span> <span class="nn">postman_problems.stats</span> <span class="kn">import</span> <span class="n">calculate_postman_solution_stats</span></code></pre></figure>
<h2 id="create-graph-from-osm">Create Graph from OSM</h2>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># load OSM to a directed NX</span>
<span class="n">g_d</span> <span class="o">=</span> <span class="n">read_osm</span><span class="p">(</span><span class="s">'sleepinggiant.osm'</span><span class="p">)</span>
<span class="c"># create an undirected graph</span>
<span class="n">g</span> <span class="o">=</span> <span class="n">g_d</span><span class="o">.</span><span class="n">to_undirected</span><span class="p">()</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><class 'networkx.classes.digraph.DiGraph'>
</code></pre></div></div>
<h4 id="adding-edges-that-dont-exist-on-osm-but-should">Adding edges that don’t exist on OSM, but should</h4>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">g</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="s">'2318082790'</span><span class="p">,</span> <span class="s">'2318082832'</span><span class="p">,</span> <span class="nb">id</span><span class="o">=</span><span class="s">'white_horseshoe_fix_1'</span><span class="p">)</span></code></pre></figure>
<h4 id="adding-distance-to-osm-graph">Adding distance to OSM graph</h4>
<p>Using the haversine formula to calculate distance between each edge.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'distance'</span><span class="p">]</span> <span class="o">=</span> <span class="n">haversine</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="s">'lon'</span><span class="p">],</span>
<span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="s">'lat'</span><span class="p">],</span>
<span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]][</span><span class="s">'lon'</span><span class="p">],</span>
<span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]][</span><span class="s">'lat'</span><span class="p">])</span></code></pre></figure>
<h4 id="create-graph-of-required-trails-only">Create graph of required trails only</h4>
<p>A simple heuristic with a couple tweaks is all we need to create the graph with required edges:</p>
<ol>
<li>Keep any edge with ‘Trail’ in the name attribute.</li>
<li>Manually remove the handful of trails that are not part of the required Giant Master route.</li>
</ol>
<p><img src="https://github.com/brooksandrew/postman_problems_examples/raw/master/sleepinggiant/fig/sleepinggiant_3trailsmap.jpg" alt="trail_map_3builds" /></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">g_t</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="c"># remove non trails</span>
<span class="n">name</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'name'</span><span class="p">]</span> <span class="k">if</span> <span class="s">'name'</span> <span class="ow">in</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">else</span> <span class="s">''</span>
<span class="k">if</span> <span class="p">(</span><span class="s">'Trail'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">name</span><span class="o">.</span><span class="n">split</span><span class="p">())</span> <span class="ow">or</span> <span class="p">(</span><span class="n">name</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">):</span>
<span class="n">g_t</span><span class="o">.</span><span class="n">remove_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="c"># remove non Sleeping Giant trails</span>
<span class="k">elif</span> <span class="n">name</span> <span class="ow">in</span> <span class="p">[</span>
<span class="s">'Farmington Canal Linear Trail'</span><span class="p">,</span>
<span class="s">'Farmington Canal Heritage Trail'</span><span class="p">,</span>
<span class="s">'Montowese Trail'</span><span class="p">,</span>
<span class="s">'(white blazes)'</span><span class="p">]:</span>
<span class="n">g_t</span><span class="o">.</span><span class="n">remove_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="c"># cleaning up nodes left without edges</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">nx</span><span class="o">.</span><span class="n">isolates</span><span class="p">(</span><span class="n">g_t</span><span class="o">.</span><span class="n">copy</span><span class="p">()):</span>
<span class="n">g_t</span><span class="o">.</span><span class="n">remove_node</span><span class="p">(</span><span class="n">n</span><span class="p">)</span></code></pre></figure>
<h2 id="viz-sleeping-giant-trails">Viz Sleeping Giant Trails</h2>
<p>All trails required for the Giant Master:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">8</span><span class="p">))</span>
<span class="n">pos</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g_t</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g_t</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g_t</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g_t</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">2.5</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'black'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.7</span><span class="p">)</span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'maps/sleepinggiant_trails_only.html'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/sleepinggiant/maps/sleepinggiant_trails_only.html" height="400" width="750"></iframe>
<h2 id="connect-edges">Connect Edges</h2>
<p>In order to run the RPP algorithm from <a href="https://github.com/brooksandrew/postman_problems">postman_problems</a>, the required edges of the graph must form a single connected component. We’re almost there with the Sleeping Giant trail map as-is, so we’ll
just connect a few components manually.</p>
<p>Here’s an example of a few floating components (southwest corner of park):</p>
<p><img src="https://github.com/brooksandrew/postman_problems_examples/raw/master/sleepinggiant/fig/sleepinggiant_disconnected_components.png" width="500" /></p>
<p><a href="https://www.openstreetmap.org/#map=17/41.42201/-72.89983">OpenStreetMap</a> makes finding these edge (way) IDs simple. Once grabbing the <code class="highlighter-rouge">?</code> cursor, you can click on any edge to retrieve IDs and attributes.</p>
<p><img src="https://github.com/brooksandrew/postman_problems_examples/raw/master/sleepinggiant/fig/osm_edge_lookup.png" width="1000" /></p>
<h4 id="define-osm-edges-to-add-and-remove-from-graph">Define OSM edges to add and remove from graph</h4>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">edge_ids_to_add</span> <span class="o">=</span> <span class="p">[</span>
<span class="s">'223082783'</span><span class="p">,</span>
<span class="s">'223077827'</span><span class="p">,</span>
<span class="s">'40636272'</span><span class="p">,</span>
<span class="s">'223082785'</span><span class="p">,</span>
<span class="s">'222868698'</span><span class="p">,</span>
<span class="s">'223083721'</span><span class="p">,</span>
<span class="s">'222947116'</span><span class="p">,</span>
<span class="s">'222711152'</span><span class="p">,</span>
<span class="s">'222711155'</span><span class="p">,</span>
<span class="s">'222860964'</span><span class="p">,</span>
<span class="s">'223083718'</span><span class="p">,</span>
<span class="s">'222867540'</span><span class="p">,</span>
<span class="s">'white_horseshoe_fix_1'</span>
<span class="p">]</span>
<span class="n">edge_ids_to_remove</span> <span class="o">=</span> <span class="p">[</span>
<span class="s">'17220599'</span>
<span class="p">]</span></code></pre></figure>
<h4 id="add-attributes-for-supplementary-edges">Add attributes for supplementary edges</h4>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">way_id</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'id'</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">'-'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="n">way_id</span> <span class="ow">in</span> <span class="n">edge_ids_to_add</span><span class="p">:</span>
<span class="n">g_t</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">**</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>
<span class="n">g_t</span><span class="o">.</span><span class="n">add_node</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">lat</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="s">'lat'</span><span class="p">],</span> <span class="n">lon</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="s">'lon'</span><span class="p">])</span>
<span class="n">g_t</span><span class="o">.</span><span class="n">add_node</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">lat</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]][</span><span class="s">'lat'</span><span class="p">],</span> <span class="n">lon</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]][</span><span class="s">'lon'</span><span class="p">])</span>
<span class="k">if</span> <span class="n">way_id</span> <span class="ow">in</span> <span class="n">edge_ids_to_remove</span><span class="p">:</span>
<span class="k">if</span> <span class="n">g_t</span><span class="o">.</span><span class="n">has_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span>
<span class="n">g_t</span><span class="o">.</span><span class="n">remove_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">nx</span><span class="o">.</span><span class="n">isolates</span><span class="p">(</span><span class="n">g_t</span><span class="o">.</span><span class="n">copy</span><span class="p">()):</span>
<span class="n">g_t</span><span class="o">.</span><span class="n">remove_node</span><span class="p">(</span><span class="n">n</span><span class="p">)</span></code></pre></figure>
<p>Ensuring that we’re left with one single connected component:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="nb">len</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">nx</span><span class="o">.</span><span class="n">connected_components</span><span class="p">(</span><span class="n">g_t</span><span class="p">)))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1
</code></pre></div></div>
<h2 id="viz-connected-component">Viz Connected Component</h2>
<p>The map below visualizes the required edges and nodes of interest (intersections and dead-ends where degree != 2):</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">12</span><span class="p">))</span>
<span class="c"># edges</span>
<span class="n">pos</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g_t</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'lon'</span><span class="p">),</span> <span class="n">g_t</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'lat'</span><span class="p">))</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g_t</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g_t</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">3.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'black'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.6</span><span class="p">)</span>
<span class="c"># nodes (intersections and dead-ends)</span>
<span class="n">pos_x</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g_t</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g_t</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g_t</span><span class="o">.</span><span class="n">nodes</span><span class="p">()</span> <span class="k">if</span> <span class="p">(</span><span class="n">g_t</span><span class="o">.</span><span class="n">degree</span><span class="p">(</span><span class="n">k</span><span class="p">)</span><span class="o">==</span><span class="mi">1</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">g_t</span><span class="o">.</span><span class="n">degree</span><span class="p">(</span><span class="n">k</span><span class="p">)</span><span class="o">></span><span class="mi">2</span><span class="p">)}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_nodes</span><span class="p">(</span><span class="n">g_t</span><span class="p">,</span> <span class="n">pos_x</span><span class="p">,</span> <span class="n">nodelist</span><span class="o">=</span><span class="n">pos_x</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">node_size</span><span class="o">=</span><span class="mf">35.0</span><span class="p">,</span> <span class="n">node_color</span><span class="o">=</span><span class="s">'red'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.9</span><span class="p">)</span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'maps/trails_only_intersections.html'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/sleepinggiant/maps/trails_only_intersections.html" height="400" width="750"></iframe>
<h2 id="viz-trail-color">Viz Trail Color</h2>
<p>Because we can and it’s pretty.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">name2color</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">'Green Trail'</span><span class="p">:</span> <span class="s">'green'</span><span class="p">,</span>
<span class="s">'Quinnipiac Trail'</span><span class="p">:</span> <span class="s">'blue'</span><span class="p">,</span>
<span class="s">'Tower Trail'</span><span class="p">:</span> <span class="s">'black'</span><span class="p">,</span>
<span class="s">'Yellow Trail'</span><span class="p">:</span> <span class="s">'yellow'</span><span class="p">,</span>
<span class="s">'Red Square Trail'</span><span class="p">:</span> <span class="s">'red'</span><span class="p">,</span>
<span class="s">'White/Blue Trail Link'</span><span class="p">:</span> <span class="s">'lightblue'</span><span class="p">,</span>
<span class="s">'Orange Trail'</span><span class="p">:</span> <span class="s">'orange'</span><span class="p">,</span>
<span class="s">'Mount Carmel Avenue'</span><span class="p">:</span> <span class="s">'black'</span><span class="p">,</span>
<span class="s">'Violet Trail'</span><span class="p">:</span> <span class="s">'violet'</span><span class="p">,</span>
<span class="s">'blue Trail'</span><span class="p">:</span> <span class="s">'blue'</span><span class="p">,</span>
<span class="s">'Red Triangle Trail'</span><span class="p">:</span> <span class="s">'red'</span><span class="p">,</span>
<span class="s">'Blue Trail'</span><span class="p">:</span> <span class="s">'blue'</span><span class="p">,</span>
<span class="s">'Blue/Violet Trail Link'</span><span class="p">:</span> <span class="s">'purple'</span><span class="p">,</span>
<span class="s">'Red Circle Trail'</span><span class="p">:</span> <span class="s">'red'</span><span class="p">,</span>
<span class="s">'White Trail'</span><span class="p">:</span> <span class="s">'gray'</span><span class="p">,</span>
<span class="s">'Red Diamond Trail'</span><span class="p">:</span> <span class="s">'red'</span><span class="p">,</span>
<span class="s">'Yellow/Green Trail Link'</span><span class="p">:</span> <span class="s">'yellowgreen'</span><span class="p">,</span>
<span class="s">'Nature Trail'</span><span class="p">:</span> <span class="s">'forestgreen'</span><span class="p">,</span>
<span class="s">'Red Hexagon Trail'</span><span class="p">:</span> <span class="s">'red'</span><span class="p">,</span>
<span class="bp">None</span><span class="p">:</span> <span class="s">'black'</span>
<span class="p">}</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">))</span>
<span class="n">pos</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g_t</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g_t</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g_t</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">e_color</span> <span class="o">=</span> <span class="p">[</span><span class="n">name2color</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'name'</span><span class="p">)]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_t</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)]</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g_t</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">3.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="n">e_color</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_nodes</span><span class="p">(</span><span class="n">g_t</span><span class="p">,</span> <span class="n">pos_x</span><span class="p">,</span> <span class="n">nodelist</span><span class="o">=</span><span class="n">pos_x</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">node_size</span><span class="o">=</span><span class="mf">30.0</span><span class="p">,</span> <span class="n">node_color</span><span class="o">=</span><span class="s">'black'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.9</span><span class="p">)</span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'maps/trails_only_color.html'</span><span class="p">,</span> <span class="n">tiles</span><span class="o">=</span><span class="s">'cartodb_positron'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/sleepinggiant/maps/trails_only_color.html" height="400" width="750"></iframe>
<h4 id="check-distance">Check distance</h4>
<p>This is strikingly close (within 0.25 miles) to what I calculated manually with some guess work from the <a href="http://www.ct.gov/deep/lib/deep/stateparks/maps/sleepgiant.pdf">SG trail map</a> on the first pass at this problem <a href="http://brooksandrew.github.io/simpleblog/articles/intro-to-graph-optimization-solving-cpp/#stats">here</a>, before leveraging OSM.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="s">'{:0.2f} miles of required trail.'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">sum</span><span class="p">([</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'distance'</span><span class="p">]</span><span class="o">/</span><span class="mf">1609.34</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_t</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)])))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>25.56 miles of required trail.
</code></pre></div></div>
<h2 id="contract-edges">Contract Edges</h2>
<p>We could run the RPP algorithm on the graph as-is with >5000 edges. However, we can simplify computation by contracting edges into logical trail segments first. More details on the intuition and
methodology in the <a href="http://brooksandrew.github.io/simpleblog/articles/fifty-states-rural-postman-problem/#41-contract-edges">50 states post</a>.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="s">'Number of edges in trail graph: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g_t</span><span class="o">.</span><span class="n">edges</span><span class="p">())))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Number of edges in trail graph: 5141
</code></pre></div></div>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># intialize contracted graph</span>
<span class="n">g_tc</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">MultiGraph</span><span class="p">()</span>
<span class="c"># add contracted edges to graph</span>
<span class="k">for</span> <span class="n">ce</span> <span class="ow">in</span> <span class="n">contract_edges</span><span class="p">(</span><span class="n">g_t</span><span class="p">,</span> <span class="s">'distance'</span><span class="p">):</span>
<span class="n">start_node</span><span class="p">,</span> <span class="n">end_node</span><span class="p">,</span> <span class="n">distance</span><span class="p">,</span> <span class="n">path</span> <span class="o">=</span> <span class="n">ce</span>
<span class="n">contracted_edge</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">'start_node'</span><span class="p">:</span> <span class="n">start_node</span><span class="p">,</span>
<span class="s">'end_node'</span><span class="p">:</span> <span class="n">end_node</span><span class="p">,</span>
<span class="s">'distance'</span><span class="p">:</span> <span class="n">distance</span><span class="p">,</span>
<span class="s">'name'</span><span class="p">:</span> <span class="n">g</span><span class="p">[</span><span class="n">path</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">path</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'name'</span><span class="p">),</span>
<span class="s">'required'</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="s">'path'</span><span class="p">:</span> <span class="n">path</span>
<span class="p">}</span>
<span class="n">g_tc</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">start_node</span><span class="p">,</span> <span class="n">end_node</span><span class="p">,</span> <span class="o">**</span><span class="n">contracted_edge</span><span class="p">)</span>
<span class="n">g_tc</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">start_node</span><span class="p">][</span><span class="s">'lat'</span><span class="p">]</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">start_node</span><span class="p">][</span><span class="s">'lat'</span><span class="p">]</span>
<span class="n">g_tc</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">start_node</span><span class="p">][</span><span class="s">'lon'</span><span class="p">]</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">start_node</span><span class="p">][</span><span class="s">'lon'</span><span class="p">]</span>
<span class="n">g_tc</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">end_node</span><span class="p">][</span><span class="s">'lat'</span><span class="p">]</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">end_node</span><span class="p">][</span><span class="s">'lat'</span><span class="p">]</span>
<span class="n">g_tc</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">end_node</span><span class="p">][</span><span class="s">'lon'</span><span class="p">]</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">end_node</span><span class="p">][</span><span class="s">'lon'</span><span class="p">]</span></code></pre></figure>
<p>Edge contraction reduces the number of edges fed to the RPP algorithm by a factor of ~40.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="s">'Number of edges in contracted trail graoh: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g_tc</span><span class="o">.</span><span class="n">edges</span><span class="p">())))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Number of edges in contracted trail graoh: 124
</code></pre></div></div>
<h2 id="solve-cpp">Solve CPP</h2>
<p>First, let’s see how well the Chinese Postman solution works.</p>
<h4 id="create-cpp-edgelist">Create CPP edgelist</h4>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># create list with edge attributes and "from" & "to" nodes</span>
<span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_tc</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">tmpi</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="c"># so we don't mess w original graph</span>
<span class="n">tmpi</span><span class="p">[</span><span class="s">'start_node'</span><span class="p">]</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">tmpi</span><span class="p">[</span><span class="s">'end_node'</span><span class="p">]</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">tmp</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tmpi</span><span class="p">)</span>
<span class="c"># create dataframe w node1 and node2 in order</span>
<span class="n">eldf</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span>
<span class="n">eldf</span> <span class="o">=</span> <span class="n">eldf</span><span class="p">[[</span><span class="s">'start_node'</span><span class="p">,</span> <span class="s">'end_node'</span><span class="p">]</span> <span class="o">+</span> <span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">eldf</span><span class="o">.</span><span class="n">columns</span><span class="p">)</span><span class="o">-</span><span class="p">{</span><span class="s">'start_node'</span><span class="p">,</span> <span class="s">'end_node'</span><span class="p">})]</span>
<span class="c"># create edgelist mock CSV</span>
<span class="n">elfn</span> <span class="o">=</span> <span class="n">create_mock_csv_from_dataframe</span><span class="p">(</span><span class="n">eldf</span><span class="p">)</span></code></pre></figure>
<h4 id="start-node">Start node</h4>
<p>The route is designed to start at the far east end of the park on the Blue trail (node ‘735393342’). While the CPP and RPP solutions will return a Eulerian circuit (loop back to the starting node),
we could truncate this last long doublebacking segment when actually running the route</p>
<p><img src="https://github.com/brooksandrew/postman_problems_examples/raw/master/sleepinggiant/fig/sleepinggiant_starting_node.png" width="600" /></p>
<h4 id="solve">Solve</h4>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">circuit_cpp</span><span class="p">,</span> <span class="n">gcpp</span> <span class="o">=</span> <span class="n">cpp</span><span class="p">(</span><span class="n">elfn</span><span class="p">,</span> <span class="n">start_node</span><span class="o">=</span><span class="s">'735393342'</span><span class="p">)</span></code></pre></figure>
<h4 id="cpp-stats">CPP Stats</h4>
<p><em>(distances in meters)</em></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">cpp_stats</span> <span class="o">=</span> <span class="n">calculate_postman_solution_stats</span><span class="p">(</span><span class="n">circuit_cpp</span><span class="p">)</span>
<span class="n">cpp_stats</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>OrderedDict([('distance_walked', 54522.949121342645),
('distance_doublebacked', 13383.36715945256),
('distance_walked_once', 41139.581961890086),
('distance_walked_optional', 0),
('distance_walked_required', 54522.949121342645),
('edges_walked', 170),
('edges_doublebacked', 46),
('edges_walked_once', 124),
('edges_walked_optional', 0),
('edges_walked_required', 170)])
</code></pre></div></div>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="s">'Miles in CPP solution: {:0.2f}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">cpp_stats</span><span class="p">[</span><span class="s">'distance_walked'</span><span class="p">]</span><span class="o">/</span><span class="mf">1609.34</span><span class="p">))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Miles in CPP solution: 33.88
</code></pre></div></div>
<h2 id="solve-rpp">Solve RPP</h2>
<p>With the CPP as benchmark, let’s see how well we do when we allow for optional edges in the route.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="o">%%</span><span class="n">time</span>
<span class="n">dfrpp</span> <span class="o">=</span> <span class="n">create_rpp_edgelist</span><span class="p">(</span><span class="n">g_tc</span><span class="p">,</span>
<span class="n">graph_full</span><span class="o">=</span><span class="n">g</span><span class="p">,</span>
<span class="n">edge_weight</span><span class="o">=</span><span class="s">'distance'</span><span class="p">,</span>
<span class="n">max_distance</span><span class="o">=</span><span class="mi">2500</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CPU times: user 1min 39s, sys: 1.08 s, total: 1min 40s
Wall time: 1min 42s
</code></pre></div></div>
<h4 id="required-vs-optional-edge-counts">Required vs optional edge counts</h4>
<p>(<em>1=required and 0=optional</em>)</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">Counter</span><span class="p">(</span> <span class="n">dfrpp</span><span class="p">[</span><span class="s">'required'</span><span class="p">])</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Counter({0: 3034, 1: 124})
</code></pre></div></div>
<h4 id="solve-rpp-1">Solve RPP</h4>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># create mockfilename</span>
<span class="n">elfn</span> <span class="o">=</span> <span class="n">create_mock_csv_from_dataframe</span><span class="p">(</span><span class="n">dfrpp</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="o">%%</span><span class="n">time</span>
<span class="c"># solve</span>
<span class="n">circuit_rpp</span><span class="p">,</span> <span class="n">grpp</span> <span class="o">=</span> <span class="n">rpp</span><span class="p">(</span><span class="n">elfn</span><span class="p">,</span> <span class="n">start_node</span><span class="o">=</span><span class="s">'735393342'</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CPU times: user 5.81 s, sys: 59.6 ms, total: 5.87 s
Wall time: 5.99 s
</code></pre></div></div>
<h4 id="rpp-stats">RPP Stats</h4>
<p><em>(distances in meters)</em></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">rpp_stats</span> <span class="o">=</span> <span class="n">calculate_postman_solution_stats</span><span class="p">(</span><span class="n">circuit_rpp</span><span class="p">)</span>
<span class="n">rpp_stats</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>OrderedDict([('distance_walked', 49427.7740637624),
('distance_doublebacked', 8288.19210187231),
('distance_walked_once', 41139.58196189009),
('distance_walked_optional', 5238.9032692701385),
('distance_walked_required', 44188.870794492264),
('edges_walked', 152),
('edges_doublebacked', 28),
('edges_walked_once', 124),
('edges_walked_optional', 12),
('edges_walked_required', 140)])
</code></pre></div></div>
<p>Leveraging the optional roads and trails, we’re able to shave about 3 miles off the CPP route. Total mileage checks in at 30.71, just under a 50K (30.1 miles).</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="s">'Miles in RPP solution: {:0.2f}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rpp_stats</span><span class="p">[</span><span class="s">'distance_walked'</span><span class="p">]</span><span class="o">/</span><span class="mf">1609.34</span><span class="p">))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Miles in RPP solution: 30.71
</code></pre></div></div>
<h2 id="viz-rpp-solution">Viz RPP Solution</h2>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># hack to convert 'path' from str back to list. Caused by `create_mock_csv_from_dataframe`</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">circuit_rpp</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">])</span> <span class="o">==</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">exec</span><span class="p">(</span><span class="s">'e[3]["path"]='</span> <span class="o">+</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">"path"</span><span class="p">])</span></code></pre></figure>
<h4 id="create-graph-from-rpp-solution">Create graph from RPP solution</h4>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">g_tcg</span> <span class="o">=</span> <span class="n">g_tc</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="c"># calc shortest path between optional nodes and add to graph</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">circuit_rpp</span><span class="p">:</span>
<span class="n">granular_type</span> <span class="o">=</span> <span class="s">'trail'</span> <span class="k">if</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'required'</span><span class="p">]</span> <span class="k">else</span> <span class="s">'optional'</span>
<span class="c"># add granular optional edges to g_tcg</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">]</span>
<span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">path</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">path</span><span class="p">[</span><span class="mi">1</span><span class="p">:])):</span>
<span class="k">if</span> <span class="p">(</span><span class="n">g_tcg</span><span class="o">.</span><span class="n">has_edge</span><span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span> <span class="ow">and</span> <span class="p">(</span><span class="n">g_tcg</span><span class="p">[</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]][</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'granular_type'</span><span class="p">)</span> <span class="o">==</span> <span class="s">'optional'</span><span class="p">):</span>
<span class="n">g_tcg</span><span class="p">[</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]][</span><span class="mi">0</span><span class="p">][</span><span class="s">'granular_type'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'trail'</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">g_tcg</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">granular</span><span class="o">=</span><span class="s">'True'</span><span class="p">,</span> <span class="n">granular_type</span><span class="o">=</span><span class="n">granular_type</span><span class="p">)</span>
<span class="c"># add granular nodes from optional edge paths to g_tcg</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">path</span><span class="p">:</span>
<span class="n">g_tcg</span><span class="o">.</span><span class="n">add_node</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">lat</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lat'</span><span class="p">],</span> <span class="n">lon</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lon'</span><span class="p">])</span></code></pre></figure>
<h3 id="viz-rpp-optional-edges">Viz: RPP optional edges</h3>
<p>The RPP algorithm picks up some logical shortcuts using the optional trails and a couple short stretches of road.</p>
<ul>
<li><strong><font color="black">black</font></strong>: required trails</li>
<li><strong><font color="blue">blue</font></strong>: optional trails and roads</li>
</ul>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">8</span><span class="p">))</span>
<span class="n">pos</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g_tcg</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'lon'</span><span class="p">),</span> <span class="n">g_tcg</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'lat'</span><span class="p">))</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g_tcg</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">el_opt</span> <span class="o">=</span> <span class="p">[</span><span class="n">e</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_tcg</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="k">if</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'granular_type'</span><span class="p">)</span> <span class="o">==</span> <span class="s">'optional'</span><span class="p">]</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g_tcg</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">edgelist</span><span class="o">=</span><span class="n">el_opt</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">6.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'blue'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
<span class="n">el_tr</span> <span class="o">=</span> <span class="p">[</span><span class="n">e</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_tcg</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="k">if</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'granular_type'</span><span class="p">)</span> <span class="o">==</span> <span class="s">'trail'</span><span class="p">]</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g_tcg</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">edgelist</span><span class="o">=</span><span class="n">el_tr</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">3.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'black'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.8</span><span class="p">)</span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'maps/rpp_solution_opt_edges.html'</span><span class="p">,</span> <span class="n">tiles</span><span class="o">=</span><span class="s">'cartodb_positron'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/sleepinggiant/maps/rpp_solution_opt_edges.html" height="400" width="750"></iframe>
<h3 id="viz-rpp-edges-counts">Viz: RPP edges counts</h3>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c">## Create graph directly from rpp_circuit and original graph w lat/lon (g)</span>
<span class="n">color_seq</span> <span class="o">=</span> <span class="p">[</span><span class="bp">None</span><span class="p">,</span> <span class="s">'black'</span><span class="p">,</span> <span class="s">'magenta'</span><span class="p">,</span> <span class="s">'orange'</span><span class="p">,</span> <span class="s">'yellow'</span><span class="p">]</span>
<span class="n">grppviz</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">MultiGraph</span><span class="p">()</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">circuit_rpp</span><span class="p">:</span>
<span class="k">for</span> <span class="n">n1</span><span class="p">,</span> <span class="n">n2</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">][:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">][</span><span class="mi">1</span><span class="p">:]):</span>
<span class="k">if</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">has_edge</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span> <span class="n">n2</span><span class="p">):</span>
<span class="n">grppviz</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="n">n2</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s">'linewidth'</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">2</span>
<span class="n">grppviz</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="n">n2</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s">'cnt'</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">grppviz</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span> <span class="n">n2</span><span class="p">,</span> <span class="n">linewidth</span><span class="o">=</span><span class="mf">2.5</span><span class="p">)</span>
<span class="n">grppviz</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="n">n2</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s">'color_st'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'black'</span> <span class="k">if</span> <span class="n">g_t</span><span class="o">.</span><span class="n">has_edge</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span> <span class="n">n2</span><span class="p">)</span> <span class="k">else</span> <span class="s">'red'</span>
<span class="n">grppviz</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="n">n2</span><span class="p">][</span><span class="mi">0</span><span class="p">][</span><span class="s">'cnt'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">grppviz</span><span class="o">.</span><span class="n">add_node</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span> <span class="n">lat</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="s">'lat'</span><span class="p">],</span> <span class="n">lon</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="s">'lon'</span><span class="p">])</span>
<span class="n">grppviz</span><span class="o">.</span><span class="n">add_node</span><span class="p">(</span><span class="n">n2</span><span class="p">,</span> <span class="n">lat</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n2</span><span class="p">][</span><span class="s">'lat'</span><span class="p">],</span> <span class="n">lon</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n2</span><span class="p">][</span><span class="s">'lon'</span><span class="p">])</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'color_cnt'</span><span class="p">]</span> <span class="o">=</span> <span class="n">color_seq</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="s">'cnt'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">else</span> <span class="n">color_seq</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'cnt'</span><span class="p">]</span> <span class="p">]</span>
</code></pre></figure>
<p>Edge walks per color:</p>
<p><strong><font color="black">black</font></strong>: 1 <br />
<strong><font color="magenta">magenta</font></strong>: 2 <br /></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">))</span>
<span class="n">pos</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">grppviz</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">e_width</span> <span class="o">=</span> <span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'linewidth'</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)]</span>
<span class="n">e_color</span> <span class="o">=</span> <span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'color_cnt'</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)]</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">grppviz</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="n">e_width</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="n">e_color</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.7</span><span class="p">)</span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'maps/rpp_solution_edge_cnts.html'</span><span class="p">,</span> <span class="n">tiles</span><span class="o">=</span><span class="s">'cartodb_positron'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/sleepinggiant/maps/rpp_solution_edge_cnts.html" height="400" width="750"></iframe>
<h2 id="create-geojson-solution">Create geojson solution</h2>
<p>Used for the D3 route animation at the beginning of the post (also <a href="http://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/sleepinggiant/animation/index.html">here</a>). More details <a href="https://github.com/brooksandrew/postman_problems_examples/tree/master/sleepinggiant/animation">here</a>.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">geojson</span> <span class="o">=</span> <span class="p">{</span><span class="s">'features'</span><span class="p">:[],</span> <span class="s">'type'</span><span class="p">:</span> <span class="s">'FeatureCollection'</span><span class="p">}</span>
<span class="n">time</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">path</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">circuit_rpp</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">]))</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">circuit_rpp</span><span class="p">:</span>
<span class="k">if</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">path</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
<span class="n">path</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">]))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">]</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">path</span><span class="p">:</span>
<span class="n">time</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">doc</span> <span class="o">=</span> <span class="p">{</span><span class="s">'type'</span><span class="p">:</span> <span class="s">'Feature'</span><span class="p">,</span>
<span class="s">'properties'</span><span class="p">:</span> <span class="p">{</span>
<span class="s">'latitude'</span><span class="p">:</span> <span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lat'</span><span class="p">],</span>
<span class="s">'longitude'</span><span class="p">:</span> <span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span>
<span class="s">'time'</span><span class="p">:</span> <span class="n">time</span><span class="p">,</span>
<span class="s">'id'</span><span class="p">:</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'id'</span><span class="p">)</span>
<span class="p">},</span>
<span class="s">'geometry'</span><span class="p">:{</span>
<span class="s">'type'</span><span class="p">:</span> <span class="s">'Point'</span><span class="p">,</span>
<span class="s">'coordinates'</span><span class="p">:</span> <span class="p">[</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lat'</span><span class="p">]]</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">geojson</span><span class="p">[</span><span class="s">'features'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">doc</span><span class="p">)</span>
</code></pre></figure>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">'circuit_rpp.geojson'</span><span class="p">,</span><span class="s">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">geojson</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span></code></pre></figure>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/sleeping-giant-rural-postman-problem/">Sleeping Giant Rural Postman Problem</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on December 01, 2017.</p>http://brooksandrew.github.io/simpleblog/articles/fifty-states-rural-postman-problem2017-11-19T00:00:00+00:002017-11-19T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<h4 id="motivation">Motivation</h4>
<p>Recently I spent a considerable amount of time writing the <a href="https://github.com/brooksandrew/postman_problems">postman_problems</a> python library implementing solvers for the Chinese and Rural Postman Problems (CPP and RPP respectively). I wrote about
my initial motivation for the project: finding the optimal route through a trail system in a state park <a href="http://brooksandrew.github.io/simpleblog/articles/intro-to-graph-optimization-solving-cpp/">here</a>. Although I’ve still yet to run the 34 mile optimal trail
route, I am pleased with the optimization procedure. However, I couldn’t help but feel that all those nights and weekends hobbying on this thing deserved a more satisfying visual than my static SVGs
and hacky GIF. So to spice it up, I decided to solve the RPP on a graph derived from geodata and visualize on an interactive Leaflet map.</p>
<h4 id="the-problem">The Problem</h4>
<p>In short, ride all 50 state named avenues in DC end-to-end following the shortest route possible.</p>
<p>There happens to be an annual <a href="https://org.salsalabs.com/o/451/p/salsa/event/common/public/?event_KEY=99906">50 states ride</a> sponsored by our regional bike association, <a href="http://www.waba.org/">WABA</a>, that takes riders to each of the 50<sup>†</sup> state named avenues in DC. Each state’s avenue is
<em>touched</em>, but not covered in full. This problem takes it a step further by instituting this requirement. Thus, it boils to the RPP where the required edges are state avenues (end-to-end) and the
optional edges are every other road within DC city limits.</p>
<p>For those unfamiliar with DC street naming convention, that can (and should) be remedied with a read through the history behind the street system <a href="https://dc.curbed.com/2014/8/13/10061100/facts-and-myths-about-dcs-street-system">here</a>. Seriously, it’s an
interesting read. Basically there are 50 state named avenues in DC ranging from 0.3 miles (Indiana Avenue) to 10 miles (Massachusetts Avenue) comprising <a href="https://en.wikipedia.org/wiki/List_of_state-named_roadways_in_Washington,_D.C.#cite_note-AL2-2">115 miles</a> in total.</p>
<h4 id="the-solution">The Solution</h4>
<p>The data is grabbed from Open Street Maps (OSM). Most of the post is spent wrangling the OSM geodata into shape for the RPP algorithm using NetworkX graphs. The final route (and intermediate steps)
are visualized using Leaflet maps through <a href="https://github.com/jwass/mplleaflet">mplleaflet</a> which enable interactivity using tiles from Mapbox and CartoDB among others.</p>
<p>Note to readers: the rendering of these maps can work the browser pretty hard; allow a couple extra seconds for loading.</p>
<h4 id="the-approach">The Approach</h4>
<p>Most of the heavy lifting leverages functions from the <a href="https://github.com/brooksandrew/postman_problems_examples/blob/master/graph.py">graph.py</a> module in the <a href="https://github.com/brooksandrew/postman_problems_examples">postman_problems_examples</a> repo. The majority of pre-RPP processing employs heuristics that simplify the computation
such that this code can run in a reasonable amount of time. The parameters employed here, which I believe get pretty darn close to the optimal solution, run in about 50 minutes. By tweaking a couple
parameters, accuracy can be sacrificed for time to get run time down to ~5 minutes on a standard 4 core laptop.</p>
<p>Verbose technical details about the guts of each step are omitted from this post for readability. However the interested reader can find these in the docstrings in <a href="https://github.com/brooksandrew/postman_problems_examples/blob/master/graph.py">graph.py</a>.</p>
<p>The table of contents below provides the best high-level summary of the approach. All code needed to reproduce this analysis is in the <a href="https://github.com/brooksandrew/postman_problems_examples">postman_problems_examples</a> repo, including the jupyter notebook
used to author this blog post and a conda environment.</p>
<p><sup>†</sup> While there are 50 <em>roadways</em>, there are technically only 48 state named <em>avenues</em>: Ohio Drive and California Street are the stubborn exceptions.</p>
<!-- #### Animation
Big thanks and kudos to my sister [@laurabrooks](https://github.com/laurabrooks) for helping me create this. Street names are there, they just need a bit of zoom. Code [here][rpp_animation_gh].
[rpp_animation_gh]: https://github.com/brooksandrew/postman_problems_examples/tree/master/50states/animation
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/9d4f0965ca02ff69cbbe80a477f9baa1b1678b2f/50states/animation/index.html" height="600" width="750"></iframe>
-->
<h4 id="table-of-contents">Table of Contents</h4>
<ul id="markdown-toc">
<li><a href="#0-get-the-data" id="markdown-toc-0-get-the-data">0: Get the data</a></li>
<li><a href="#1-load-osm-to-networkx" id="markdown-toc-1-load-osm-to-networkx">1: Load OSM to NetworkX</a></li>
<li><a href="#2-make-graph-w-state-avenues-only" id="markdown-toc-2-make-graph-w-state-avenues-only">2: Make Graph w State Avenues only</a> <ul>
<li><a href="#21-viz-state-avenues" id="markdown-toc-21-viz-state-avenues">2.1 Viz state avenues</a></li>
</ul>
</li>
<li><a href="#3-remove-redundant-state-avenues" id="markdown-toc-3-remove-redundant-state-avenues">3. Remove Redundant State Avenues</a> <ul>
<li><a href="#31-create-state-avenue-graph-with-one-way-edges-only" id="markdown-toc-31-create-state-avenue-graph-with-one-way-edges-only">3.1 Create state avenue graph with one-way edges only</a></li>
<li><a href="#32-split-connected-components" id="markdown-toc-32-split-connected-components">3.2 Split connected components</a></li>
<li><a href="#33--34-match-connected-components" id="markdown-toc-33--34-match-connected-components">3.3 & 3.4 Match connected components</a></li>
<li><a href="#35-build-graph-without-redundant-edges" id="markdown-toc-35-build-graph-without-redundant-edges">3.5 Build graph without redundant edges</a></li>
</ul>
</li>
<li><a href="#4-create-single-connected-component" id="markdown-toc-4-create-single-connected-component">4. Create Single Connected Component</a> <ul>
<li><a href="#41-contract-edges" id="markdown-toc-41-contract-edges">4.1 Contract edges</a></li>
<li><a href="#42-calculate-haversine-distance-between-components" id="markdown-toc-42-calculate-haversine-distance-between-components">4.2 Calculate haversine distance between components</a></li>
<li><a href="#43-find-minimum-distance-connectors" id="markdown-toc-43-find-minimum-distance-connectors">4.3 Find minimum distance connectors</a></li>
<li><a href="#44-build-single-component-graph" id="markdown-toc-44-build-single-component-graph">4.4 Build single component graph</a></li>
<li><a href="#45-viz-single-connected-component" id="markdown-toc-45-viz-single-connected-component">4.5 Viz single connected component</a></li>
</ul>
</li>
<li><a href="#5-solve-cpp" id="markdown-toc-5-solve-cpp">5. Solve CPP</a> <ul>
<li><a href="#51-create-cpp-edgelist" id="markdown-toc-51-create-cpp-edgelist">5.1 Create CPP edgelist</a></li>
<li><a href="#52-cpp-solver" id="markdown-toc-52-cpp-solver">5.2 CPP solver</a></li>
<li><a href="#53-cpp-results" id="markdown-toc-53-cpp-results">5.3: CPP results</a></li>
</ul>
</li>
<li><a href="#6-solve-rpp" id="markdown-toc-6-solve-rpp">6. Solve RPP</a> <ul>
<li><a href="#61-create-rpp-edgelist" id="markdown-toc-61-create-rpp-edgelist">6.1 Create RPP edgelist</a></li>
<li><a href="#62-rpp-solver" id="markdown-toc-62-rpp-solver">6.2 RPP solver</a></li>
<li><a href="#63-rpp-results" id="markdown-toc-63-rpp-results">6.3 RPP results</a></li>
<li><a href="#64-viz-rpp-graph" id="markdown-toc-64-viz-rpp-graph">6.4 Viz RPP graph</a></li>
<li><a href="#65-serialize-rpp-solution" id="markdown-toc-65-serialize-rpp-solution">6.5 Serialize RPP solution</a></li>
</ul>
</li>
</ul>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">mplleaflet</span>
<span class="kn">import</span> <span class="nn">networkx</span> <span class="k">as</span> <span class="n">nx</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">Counter</span>
<span class="c"># can be found in https://github.com/brooksandrew/postman_problems_examples</span>
<span class="kn">from</span> <span class="nn">osm2nx</span> <span class="kn">import</span> <span class="n">read_osm</span><span class="p">,</span> <span class="n">haversine</span>
<span class="kn">from</span> <span class="nn">graph</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">states_to_state_avenue_name</span><span class="p">,</span> <span class="n">subset_graph_by_edge_name</span><span class="p">,</span> <span class="n">keep_oneway_edges_only</span><span class="p">,</span> <span class="n">create_connected_components</span><span class="p">,</span>
<span class="n">create_unkinked_connected_components</span><span class="p">,</span> <span class="n">nodewise_distance_connected_components</span><span class="p">,</span>
<span class="n">calculate_component_overlap</span><span class="p">,</span> <span class="n">calculate_redundant_components</span><span class="p">,</span> <span class="n">create_deduped_state_road_graph</span><span class="p">,</span>
<span class="n">create_contracted_edge_graph</span><span class="p">,</span> <span class="n">shortest_paths_between_components</span><span class="p">,</span> <span class="n">find_minimum_weight_edges_to_connect_components</span><span class="p">,</span>
<span class="n">create_rpp_edgelist</span>
<span class="p">)</span>
<span class="c"># can be found in https://github.com/brooksandrew/postman_problems</span>
<span class="kn">from</span> <span class="nn">postman_problems.tests.utils</span> <span class="kn">import</span> <span class="n">create_mock_csv_from_dataframe</span>
<span class="kn">from</span> <span class="nn">postman_problems.solver</span> <span class="kn">import</span> <span class="n">rpp</span><span class="p">,</span> <span class="n">cpp</span>
<span class="kn">from</span> <span class="nn">postman_problems.stats</span> <span class="kn">import</span> <span class="n">calculate_postman_solution_stats</span></code></pre></figure>
<h2 id="0-get-the-data">0: Get the data</h2>
<p>There are many ways to grab Open Street Map (OSM) data, since it’s, well, open. I grabbed the DC map from GeoFabrik <a href="http://download.geofabrik.de/north-america/us/district-of-columbia.html">here</a>.</p>
<h2 id="1-load-osm-to-networkx">1: Load OSM to NetworkX</h2>
<p>While some libraries like <a href="https://github.com/gboeing/osmnx">OSMnx</a> provide an elegant interface to downloading, transforming and manipulating OSM data in NetworkX, I decided to start with the raw
data itself. I adopted an OSM-to-nx parser from a hodge podge of Gists (<a href="https://gist.github.com/aflaxman/287370/">here</a> and <a href="https://gist.github.com/Tofull/49fbb9f3661e376d2fe08c2e9d64320e">there</a>) to <a href="https://github.com/brooksandrew/50states/blob/master/osm2nx.py"><code class="highlighter-rouge">read_osm</code></a>.</p>
<p><code class="highlighter-rouge">read_osm</code> creates a directed graph. However, for this analysis, we’ll use undirected graphs with the assumption that all roads are bidirectional on a bike one way or another.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="o">%%</span><span class="n">time</span>
<span class="c"># load OSM to a directed NX</span>
<span class="n">g</span> <span class="o">=</span> <span class="n">read_osm</span><span class="p">(</span><span class="s">'district-of-columbia-latest.osm'</span><span class="p">)</span>
<span class="c"># create an undirected graph</span>
<span class="n">g_ud</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">to_undirected</span><span class="p">()</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code><class 'networkx.classes.digraph.DiGraph'>
CPU times: user 46.6 s, sys: 2.1 s, total: 48.7 s
Wall time: 50.2 s
</code></pre></div></div>
<p>This is a pretty big graph, about 275k edges. It takes about a minute to load on my machine (Macbook w 4 cores)</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">edges</span><span class="p">()))</span> <span class="c"># number of edges</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>275429
</code></pre></div></div>
<h2 id="2-make-graph-w-state-avenues-only">2: Make Graph w State Avenues only</h2>
<h4 id="generate-state-avenue-names">Generate state avenue names</h4>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">STATE_STREET_NAMES</span> <span class="o">=</span> <span class="p">[</span>
<span class="s">'Alabama'</span><span class="p">,</span><span class="s">'Alaska'</span><span class="p">,</span><span class="s">'Arizona'</span><span class="p">,</span><span class="s">'Arkansas'</span><span class="p">,</span><span class="s">'California'</span><span class="p">,</span><span class="s">'Colorado'</span><span class="p">,</span>
<span class="s">'Connecticut'</span><span class="p">,</span><span class="s">'Delaware'</span><span class="p">,</span><span class="s">'Florida'</span><span class="p">,</span><span class="s">'Georgia'</span><span class="p">,</span><span class="s">'Hawaii'</span><span class="p">,</span><span class="s">'Idaho'</span><span class="p">,</span><span class="s">'Illinois'</span><span class="p">,</span>
<span class="s">'Indiana'</span><span class="p">,</span><span class="s">'Iowa'</span><span class="p">,</span><span class="s">'Kansas'</span><span class="p">,</span><span class="s">'Kentucky'</span><span class="p">,</span><span class="s">'Louisiana'</span><span class="p">,</span><span class="s">'Maine'</span><span class="p">,</span><span class="s">'Maryland'</span><span class="p">,</span>
<span class="s">'Massachusetts'</span><span class="p">,</span><span class="s">'Michigan'</span><span class="p">,</span><span class="s">'Minnesota'</span><span class="p">,</span><span class="s">'Mississippi'</span><span class="p">,</span><span class="s">'Missouri'</span><span class="p">,</span><span class="s">'Montana'</span><span class="p">,</span>
<span class="s">'Nebraska'</span><span class="p">,</span><span class="s">'Nevada'</span><span class="p">,</span><span class="s">'New Hampshire'</span><span class="p">,</span><span class="s">'New Jersey'</span><span class="p">,</span><span class="s">'New Mexico'</span><span class="p">,</span><span class="s">'New York'</span><span class="p">,</span>
<span class="s">'North Carolina'</span><span class="p">,</span><span class="s">'North Dakota'</span><span class="p">,</span><span class="s">'Ohio'</span><span class="p">,</span><span class="s">'Oklahoma'</span><span class="p">,</span><span class="s">'Oregon'</span><span class="p">,</span><span class="s">'Pennsylvania'</span><span class="p">,</span>
<span class="s">'Rhode Island'</span><span class="p">,</span><span class="s">'South Carolina'</span><span class="p">,</span><span class="s">'South Dakota'</span><span class="p">,</span><span class="s">'Tennessee'</span><span class="p">,</span><span class="s">'Texas'</span><span class="p">,</span><span class="s">'Utah'</span><span class="p">,</span>
<span class="s">'Vermont'</span><span class="p">,</span><span class="s">'Virginia'</span><span class="p">,</span><span class="s">'Washington'</span><span class="p">,</span><span class="s">'West Virginia'</span><span class="p">,</span><span class="s">'Wisconsin'</span><span class="p">,</span><span class="s">'Wyoming'</span>
<span class="p">]</span></code></pre></figure>
<p>Most state avenues are written in the long form (ex. Connecticut Avenue Northwest). However, some, such as Florida Ave NW, are written in the short form. To be safe, we grab any permutation OSM
could throw at us.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">candidate_state_avenue_names</span> <span class="o">=</span> <span class="n">states_to_state_avenue_name</span><span class="p">(</span><span class="n">STATE_STREET_NAMES</span><span class="p">)</span>
<span class="c"># two states break the "Avenue" pattern</span>
<span class="n">candidate_state_avenue_names</span> <span class="o">+=</span> <span class="p">[</span><span class="s">'California Street Northwest'</span><span class="p">,</span> <span class="s">'Ohio Drive Southwest'</span><span class="p">]</span>
<span class="c"># preview</span>
<span class="n">candidate_state_avenue_names</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">20</span><span class="p">]</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>['Alabama Ave Southeast',
'Alabama Ave Southwest',
'Alabama Ave Northeast',
'Alabama Ave Northwest',
'Alabama Ave SE',
'Alabama Ave SW',
'Alabama Ave NE',
'Alabama Ave NW',
'Alabama Avenue Southeast',
'Alabama Avenue Southwest',
'Alabama Avenue Northeast',
'Alabama Avenue Northwest',
'Alabama Avenue SE',
'Alabama Avenue SW',
'Alabama Avenue NE',
'Alabama Avenue NW',
'Alaska Ave Southeast',
'Alaska Ave Southwest',
'Alaska Ave Northeast',
'Alaska Ave Northwest']
</code></pre></div></div>
<h4 id="create-graph-w-state-avenues-only">Create graph w state avenues only</h4>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">g_st</span> <span class="o">=</span> <span class="n">subset_graph_by_edge_name</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">candidate_state_avenue_names</span><span class="p">)</span>
<span class="c"># Add state edge attribute from full streetname (with avenue/drive and quandrant)</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_st</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'state'</span><span class="p">]</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'name'</span><span class="p">]</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="s">' '</span><span class="p">,</span> <span class="mi">2</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span></code></pre></figure>
<p>This is a much smaller graph:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g_st</span><span class="o">.</span><span class="n">edges</span><span class="p">()))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>7148
</code></pre></div></div>
<p>But every state is represented:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">edge_count_by_state</span> <span class="o">=</span> <span class="n">Counter</span><span class="p">([</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'state'</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_st</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)])</span>
<span class="c"># number of unique states </span>
<span class="k">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">edge_count_by_state</span><span class="p">))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>50
</code></pre></div></div>
<p>Here they are by edge count:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">edge_count_by_state</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Counter({'Alabama': 348,
'Alaska': 36,
'Arizona': 89,
'Arkansas': 64,
'California': 24,
'Colorado': 59,
'Connecticut': 283,
'Delaware': 66,
'Florida': 253,
'Georgia': 185,
'Hawaii': 84,
'Idaho': 50,
'Illinois': 37,
'Indiana': 29,
'Iowa': 30,
'Kansas': 74,
'Kentucky': 47,
'Louisiana': 37,
'Maine': 199,
'Maryland': 233,
'Massachusetts': 581,
'Michigan': 225,
'Minnesota': 214,
'Mississippi': 102,
'Missouri': 66,
'Montana': 74,
'Nebraska': 183,
'Nevada': 122,
'New Hampshire': 259,
'New Jersey': 170,
'New Mexico': 66,
'New York': 333,
'North Carolina': 87,
'North Dakota': 16,
'Ohio': 391,
'Oklahoma': 48,
'Oregon': 170,
'Pennsylvania': 433,
'Rhode Island': 282,
'South Carolina': 60,
'South Dakota': 124,
'Tennessee': 40,
'Texas': 123,
'Utah': 66,
'Vermont': 154,
'Virginia': 134,
'Washington': 58,
'West Virginia': 56,
'Wisconsin': 257,
'Wyoming': 27})
</code></pre></div></div>
<h3 id="21-viz-state-avenues">2.1 Viz state avenues</h3>
<p>As long as your NetworkX graph has <code class="highlighter-rouge">lat</code> and <code class="highlighter-rouge">lon</code> node attributes, <a href="https://github.com/jwass/mplleaflet">mplleaflet</a> can be used to pretty effortlessly plot your NetworkX graph on an interactive map.</p>
<p>Here’s the map with all the state avenues…</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">8</span><span class="p">))</span>
<span class="n">pos</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g_st</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g_st</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g_st</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g_st</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">4.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'black'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.7</span><span class="p">)</span>
<span class="c"># save viz </span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'state_avenues_all.html'</span><span class="p">,</span> <span class="n">tiles</span><span class="o">=</span><span class="s">'cartodb_positron'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/50states/maps/state_avenues_all.html" height="400" width="750"></iframe>
<p>You can even customize with your favorite tiles. For example:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mplleaflet.display(fig=ax.figure, tiles='stamen_wc')
</code></pre></div></div>
<p><img src="https://github.com/brooksandrew/postman_problems_examples/raw/master/50states/fig/stamen_wc_state_ave.jpeg" width="700" /></p>
<p>…But there’s a wrinkle. Zoom in on bigger avenues, like New York or Rhode Island, and you’ll notice that there are two parallel edges representing each direction as a separate one-way road. This
usually occurs when there are several lanes of traffic in each direction, or physical dividers between directions. Example below:</p>
<p>This is great for OSM and point A to B routing problems, but for the Rural Postman problem it imposes the requirement that each main avenue be cycled twice. We’re not into that.</p>
<p><strong>Example:</strong> Rhode Island Ave (parallel edges) vs Florida Ave (single edge)</p>
<p><img src="https://github.com/brooksandrew/postman_problems_examples/raw/master/50states/fig/parallel_edge_ex.png" alt="parallel_edge_ex" /></p>
<h2 id="3-remove-redundant-state-avenues">3. Remove Redundant State Avenues</h2>
<p>As it turns out, removing these parallel (redundant) edges is a nontrivial problem to solve. My approach is the following:</p>
<ol>
<li>Build graph with one-way state avenue edges only.</li>
<li>For each state avenue, create list of connected components that represent sequences of OSM ways in the same direction (broken up by intersections and turns).</li>
<li>Compute distance between each node in a component to every other node in the other candidate components.</li>
<li>Identify redundant components as those with the majority of their nodes below some threshold distance away from another component.</li>
<li>Build graph without redundant edges.</li>
</ol>
<h3 id="31-create-state-avenue-graph-with-one-way-edges-only">3.1 Create state avenue graph with one-way edges only</h3>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">g_st1</span> <span class="o">=</span> <span class="n">keep_oneway_edges_only</span><span class="p">(</span><span class="n">g_st</span><span class="p">)</span></code></pre></figure>
<p>The one-way avenues are plotted in red below. A brief look indicates that 80-90% of the one-way avenues are parallel (redundant). A few, like Idaho Avenue NW and Ohio Drive SW, are single one-way
roads with no accompanying parallel edge for us to remove.</p>
<p>NOTE: you’ll need to zoom in 3-4 levels to see the parallel edges.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">6</span><span class="p">))</span>
<span class="n">pos</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g_st1</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g_st1</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g_st1</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g_st1</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">3.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'red'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.7</span><span class="p">)</span>
<span class="c"># save viz</span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'oneway_state_avenues.html'</span><span class="p">,</span> <span class="n">tiles</span><span class="o">=</span><span class="s">'cartodb_positron'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/50states/maps/oneway_state_avenues.html" height="400" width="750"></iframe>
<h4 id="create-connected-components-with-one-way-state-avenues">Create connected components with one-way state avenues</h4>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">comps</span> <span class="o">=</span> <span class="n">create_connected_components</span><span class="p">(</span><span class="n">g_st1</span><span class="p">)</span></code></pre></figure>
<p>There are 163 distinct components in the graph above.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="nb">len</span><span class="p">(</span><span class="n">comps</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>163
</code></pre></div></div>
<h3 id="32-split-connected-components">3.2 Split connected components</h3>
<h4 id="remove-kinked-nodes">Remove kinked nodes</h4>
<p>However, we need to break some of these components up into smaller ones. Many components, like the one below, have bends or a connected cycle that contain both the parallel edges, where we only want
one. My approach is to identify the nodes with sharp angles and remove them. I don’t know what the proper name for these is (you can read about <a href="https://en.wikipedia.org/wiki/Angular_resolution_(graph_drawing)">angular resolution</a>), but we’ll call them “kinked
nodes.”</p>
<p>This will split the connected component below into two, allowing us to determine that one of them is redundant.</p>
<p><img src="https://github.com/brooksandrew/postman_problems_examples/raw/master/50states/fig/kinked_node_ex.png" alt="kinked_node_ex" /></p>
<p>I borrow <a href="https://gist.github.com/jeromer/2005586">this code</a> from <code class="highlighter-rouge">jeromer</code> to calculate the compass bearing (0 to 360) of each edge. Wherever the the bearing difference between two adjacent edges is greater than
<code class="highlighter-rouge">bearing_thresh</code>, we call the node shared by both edges a “kinked node.” A relative low <code class="highlighter-rouge">bearing_thresh</code> of 60 appeared to work best after some experimentation.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># create list of comps (graphs) without kinked nodes</span>
<span class="n">comps_unkinked</span> <span class="o">=</span> <span class="n">create_unkinked_connected_components</span><span class="p">(</span><span class="n">comps</span><span class="o">=</span><span class="n">comps</span><span class="p">,</span> <span class="n">bearing_thresh</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
<span class="c"># comps in dict form for easy lookup</span>
<span class="n">comps_dict</span> <span class="o">=</span> <span class="p">{</span><span class="n">comp</span><span class="o">.</span><span class="n">graph</span><span class="p">[</span><span class="s">'id'</span><span class="p">]:</span><span class="n">comp</span> <span class="k">for</span> <span class="n">comp</span> <span class="ow">in</span> <span class="n">comps_unkinked</span><span class="p">}</span> </code></pre></figure>
<p>After removing these “kinked nodes,” our list of components grows from 163 to 246:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="nb">len</span><span class="p">(</span><span class="n">comps_unkinked</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>246
</code></pre></div></div>
<h4 id="viz-components-without-kinked-nodes">Viz components without kinked nodes</h4>
<p><strong>Example:</strong> Here’s the Massachusetts Ave example from above after we remove kinked nodes:</p>
<p><img src="https://github.com/brooksandrew/postman_problems_examples/raw/master/50states/fig/unkinked_node_ex.png" alt="unkinked_node_ex" /></p>
<p><strong>Full map:</strong> Zoom in on the map below and you’ll see that we split up most of the obvious components that should be. There are a few corner cases that we miss, but I’d estimate we programmatically
split about 95% of the components correctly.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">6</span><span class="p">))</span>
<span class="k">for</span> <span class="n">comp</span> <span class="ow">in</span> <span class="n">comps_unkinked</span><span class="p">:</span>
<span class="n">pos</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">comp</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">comp</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">comp</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">comp</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">3.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'orange'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.7</span><span class="p">)</span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'oneway_state_avenues_without_kinked_nodes.html'</span><span class="p">,</span> <span class="n">tiles</span><span class="o">=</span><span class="s">'cartodb_positron'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/50states/maps/oneway_state_avenues_without_kinked_nodes.html" height="500" width="750"></iframe>
<h3 id="33--34-match-connected-components">3.3 & 3.4 Match connected components</h3>
<p>Now that we’ve crafted the right components, we calculate how close (parallel) each component is to one another.</p>
<p>This is a relatively coarse approach, but performs surprisingly well:</p>
<p><strong>1.</strong> Find closest nodes from candidate components to each node in each component (pseudo code below):</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> For each node N in component C:
For each C_cand in components with same street avenue as C:
Calculate closest node in C_cand to N.
</code></pre></div></div>
<p><strong>2.</strong> Calculate overlap between components. Using the distances calculated in <strong>1.</strong>, we say that a node from component <code class="highlighter-rouge">C</code> is matched to a component <code class="highlighter-rouge">C_cand</code> if the distance is less than
<code class="highlighter-rouge">thresh_distance</code> specified in <code class="highlighter-rouge">calculate_component_overlap</code>. 75 meters seemed to work pretty well. Essentially we’re saying these nodes are close enough to be considered interchangeable.</p>
<p><strong>3.</strong> Use the node-wise matching calculated in <strong>2.</strong> to calculate which components are redundant. If <code class="highlighter-rouge">thresh_pct</code> of nodes in component <code class="highlighter-rouge">C</code> are close enough (within <code class="highlighter-rouge">thresh_distance</code>) to nodes in
component <code class="highlighter-rouge">C_cand</code>, we call <code class="highlighter-rouge">C</code> redundant and discard it.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># caclulate nodewise distances between each node in comp with closest node in each candidate</span>
<span class="n">comp_matches</span> <span class="o">=</span> <span class="n">nodewise_distance_connected_components</span><span class="p">(</span><span class="n">comps_unkinked</span><span class="p">)</span>
<span class="c"># calculate overlap between components</span>
<span class="n">comp_overlap</span> <span class="o">=</span> <span class="n">calculate_component_overlap</span><span class="p">(</span><span class="n">comp_matches</span><span class="p">,</span> <span class="n">thresh_distance</span><span class="o">=</span><span class="mi">75</span><span class="p">)</span>
<span class="c"># identify redundant and non-redundant components</span>
<span class="n">remove_comp_ids</span><span class="p">,</span> <span class="n">keep_comp_ids</span> <span class="o">=</span> <span class="n">calculate_redundant_components</span><span class="p">(</span><span class="n">comp_overlap</span><span class="p">,</span> <span class="n">thresh_pct</span><span class="o">=</span><span class="mf">0.75</span><span class="p">)</span></code></pre></figure>
<h4 id="viz-redundant-component-solution">Viz redundant component solution</h4>
<p>The map below visualizes the solution to the redundant parallel edges problem. There are some misses, but overall this simple approach works surprisingly well:</p>
<ul>
<li><strong><font color="red">red</font></strong>: redundant one-way edges to remove</li>
<li><strong><font color="black">black</font></strong>: one-way edges to keep</li>
<li><strong><font color="blue">blue</font></strong>: all state avenues</li>
</ul>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">8</span><span class="p">))</span>
<span class="c"># plot redundant one-way edges</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">road</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">remove_comp_ids</span><span class="p">):</span>
<span class="k">for</span> <span class="n">comp_id</span> <span class="ow">in</span> <span class="n">remove_comp_ids</span><span class="p">[</span><span class="n">road</span><span class="p">]:</span>
<span class="n">comp</span> <span class="o">=</span> <span class="n">comps_dict</span><span class="p">[</span><span class="n">comp_id</span><span class="p">]</span>
<span class="n">posc</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">comp</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">comp</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">comp</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">comp</span><span class="p">,</span> <span class="n">posc</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">7.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'red'</span><span class="p">)</span>
<span class="c"># plot keeper one-way edges </span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">road</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">keep_comp_ids</span><span class="p">):</span>
<span class="k">for</span> <span class="n">comp_id</span> <span class="ow">in</span> <span class="n">keep_comp_ids</span><span class="p">[</span><span class="n">road</span><span class="p">]:</span>
<span class="n">comp</span> <span class="o">=</span> <span class="n">comps_dict</span><span class="p">[</span><span class="n">comp_id</span><span class="p">]</span>
<span class="n">posc</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">comp</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">comp</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">comp</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">comp</span><span class="p">,</span> <span class="n">posc</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">3.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'black'</span><span class="p">)</span>
<span class="c"># plot all state avenues</span>
<span class="n">pos_st</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g_st</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g_st</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g_st</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g_st</span><span class="p">,</span> <span class="n">pos_st</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'blue'</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.7</span><span class="p">)</span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'redundant_edges.html'</span><span class="p">,</span> <span class="n">tiles</span><span class="o">=</span><span class="s">'cartodb_positron'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/50states/maps/redundant_edges.html" height="500" width="750"></iframe>
<h3 id="35-build-graph-without-redundant-edges">3.5 Build graph without redundant edges</h3>
<p>This is the essentially the graph with just <strong>black</strong> and <strong><font color="blue">blue</font></strong> edges from the map above.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># create a single graph with deduped state roads</span>
<span class="n">g_st_nd</span> <span class="o">=</span> <span class="n">create_deduped_state_road_graph</span><span class="p">(</span><span class="n">g_st</span><span class="p">,</span> <span class="n">comps_dict</span><span class="p">,</span> <span class="n">remove_comp_ids</span><span class="p">)</span></code></pre></figure>
<p>After deduping the redundant edges, our connected component count drops from 246 to 96.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="nb">len</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">nx</span><span class="o">.</span><span class="n">connected_components</span><span class="p">(</span><span class="n">g_st_nd</span><span class="p">)))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>96
</code></pre></div></div>
<h2 id="4-create-single-connected-component">4. Create Single Connected Component</h2>
<p>The strategy I employ for solving the Rural Postman Problem (RPP) in <a href="https://github.com/brooksandrew/postman_problems">postman_problems</a> is simple in that it reuses the machinery from the Chinese Postman Problem (CPP) solver <a href="https://github.com/brooksandrew/postman_problems/blob/master/postman_problems/solver.py#L14">here</a>.
However, it makes the strong assumption that the graph’s required edges form a single connected component. This is obviously not true for our state avenue graph as-is, but it’s not too off. Although
there are 96 components, there are only a couple more than a few hundred meters to the next closest component.</p>
<p>So we hack it a bit by adding required edges to the graph to make it a single connected component. The tricky part is choosing the edges that add as little distance as possible. This was the first
computationally intensive step that required some clever tricks and approximations to ensure execution in a reasonable amount of time.</p>
<p>My approach:</p>
<ol>
<li>
<p>Build graph with <a href="https://en.wikipedia.org/wiki/Edge_contraction">contracted edges</a> only.</p>
</li>
<li>
<p>Calculate haversine distance between each possible pair of components.</p>
</li>
<li>
<p>Find minimum distance connectors: iterate through the data structure created in <strong>2.</strong> to calculate shortest paths for top candidates based on haversine distance and add shortest connectors to
graph. More details below.</p>
</li>
<li>
<p>Build single component graph.</p>
</li>
</ol>
<h3 id="41-contract-edges">4.1 Contract edges</h3>
<p>Nodes with degree 2 are collapsed into an edge stretching from a dead-end node (degree 1) or intersection (degree >= 3) to another. This achieves two things:</p>
<ul>
<li>Limits the number of distance calculations.</li>
<li>Ensures that components are connected at logical points (dead ends and intersections) rather than arbitrary parts of a roadway. This will make for a more continuous route.</li>
</ul>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Create graph with contracted edges only</span>
<span class="n">g_st_contracted</span> <span class="o">=</span> <span class="n">create_contracted_edge_graph</span><span class="p">(</span><span class="n">graph</span><span class="o">=</span><span class="n">g_st_nd</span><span class="p">,</span>
<span class="n">edge_weight</span><span class="o">=</span><span class="s">'length'</span><span class="p">)</span></code></pre></figure>
<p>This significantly reduces the nodes needed for distances computations by a factor of > 15.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="s">'Number of nodes in contracted graph: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g_st_contracted</span><span class="o">.</span><span class="n">nodes</span><span class="p">())))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of nodes in original graph: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g_st_nd</span><span class="o">.</span><span class="n">nodes</span><span class="p">())))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Number of nodes in contracted graph: 347
Number of nodes in original graph: 5962
</code></pre></div></div>
<h3 id="42-calculate-haversine-distance-between-components">4.2 Calculate haversine distance between components</h3>
<p>The 345 nodes from the contracted edge graph translate to >100,000 possible node pairings. That means >100,000 distance calculations. While applying a shortest path algorithm over the graph would
certainly be more exact, it is painfully slow compared to simple haversine distance. This is mainly due to the high number of nodes and edges in the DC OSM map (over 250k edges).</p>
<p>On my laptop I averaged about 4 shortest path calculations per second. Not too bad for a handful, but 115k would take about 7 hours. Haversine distance, by comparison, churns through 115k in a
couple seconds.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># create dataframe with shortest paths (haversine distance) between each component</span>
<span class="n">dfsp</span> <span class="o">=</span> <span class="n">shortest_paths_between_components</span><span class="p">(</span><span class="n">g_st_contracted</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">dfsp</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="c"># number of rows (node pairs)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>116526
</code></pre></div></div>
<h3 id="43-find-minimum-distance-connectors">4.3 Find minimum distance connectors</h3>
<p>This gets a bit tricky. Basically we iterate through the top (closest) candidate pairs of components and connect them iteration-by-iteration with the shortest path edge. We use pre-calculated
haversine distance to get in the right ballpark, then refine with true shortest path for the closest 20 candidates. This helps us avoid the scenario where we naively connect two nodes that are
geographically close as the crow flies (haversine), but far away via available roads. Two nodes separated by highways or train tracks, for example.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># min weight edges that create a single connected component</span>
<span class="n">connector_edges</span> <span class="o">=</span> <span class="n">find_minimum_weight_edges_to_connect_components</span><span class="p">(</span><span class="n">dfsp</span><span class="o">=</span><span class="n">dfsp</span><span class="p">,</span>
<span class="n">graph</span><span class="o">=</span><span class="n">g_ud</span><span class="p">,</span>
<span class="n">edge_weight</span><span class="o">=</span><span class="s">'length'</span><span class="p">,</span>
<span class="n">top</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span></code></pre></figure>
<p>We had 96 components to connect, so it makes sense that we have 95 connectors.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="nb">len</span><span class="p">(</span><span class="n">connector_edges</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>95
</code></pre></div></div>
<h3 id="44-build-single-component-graph">4.4 Build single component graph</h3>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># adding connector edges to create one single connected component</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">connector_edges</span><span class="p">:</span>
<span class="n">g_st_contracted</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">distance</span><span class="o">=</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'distance'</span><span class="p">],</span> <span class="n">path</span><span class="o">=</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'path'</span><span class="p">],</span> <span class="n">required</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">connector</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span></code></pre></figure>
<p>We add about 12 miles with the 95 additional required edges. That’s not too bad: an average distance of 0.13 miles per each edge added.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="nb">sum</span><span class="p">([</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'distance'</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_st_contracted</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> <span class="k">if</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'connector'</span><span class="p">)])</span><span class="o">/</span><span class="mf">1609.34</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>12.341087779659958
</code></pre></div></div>
<p>So that leaves us with a single component of 125 miles of required edges to optimize a route through. That means the distance of deduped state avenues alone, without connectors (~112 miles) is just a
couple miles away from what <a href="https://en.wikipedia.org/wiki/List_of_state-named_roadways_in_Washington,_D.C.">Wikipedia reports</a> (115 miles).</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="nb">sum</span><span class="p">([</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'distance'</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_st_contracted</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)])</span><span class="o">/</span><span class="mf">1609.34</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>125.06645388481837
</code></pre></div></div>
<p>Make graph with granular edges (filling in those that were contracted) connecting components:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">g1comp</span> <span class="o">=</span> <span class="n">g_st_contracted</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_st_contracted</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="k">if</span> <span class="s">'path'</span> <span class="ow">in</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]:</span>
<span class="n">granular_type</span> <span class="o">=</span> <span class="s">'connector'</span> <span class="k">if</span> <span class="s">'connector'</span> <span class="ow">in</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="k">else</span> <span class="s">'state'</span>
<span class="c"># add granular connector edges to graph </span>
<span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'path'</span><span class="p">][:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'path'</span><span class="p">][</span><span class="mi">1</span><span class="p">:])):</span>
<span class="n">g1comp</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">granular</span><span class="o">=</span><span class="s">'True'</span><span class="p">,</span> <span class="n">granular_type</span><span class="o">=</span><span class="n">granular_type</span><span class="p">)</span>
<span class="c"># add granular connector nodes to graph</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'path'</span><span class="p">]:</span>
<span class="n">g1comp</span><span class="o">.</span><span class="n">add_node</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">lat</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lat'</span><span class="p">],</span> <span class="n">lon</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lon'</span><span class="p">])</span></code></pre></figure>
<h3 id="45-viz-single-connected-component">4.5 Viz single connected component</h3>
<p><strong>Black</strong> edges represent the deduped state avenues.
<strong><font color="red">Red</font></strong> edges represent the 12 miles of connectors that create the single connected component.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">6</span><span class="p">))</span>
<span class="n">g1comp_conn</span> <span class="o">=</span> <span class="n">g1comp</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="n">g1comp_st</span> <span class="o">=</span> <span class="n">g1comp</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g1comp</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="k">if</span> <span class="p">(</span><span class="s">'granular_type'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="ow">or</span> <span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'granular_type'</span><span class="p">]</span> <span class="o">!=</span> <span class="s">'connector'</span><span class="p">):</span>
<span class="n">g1comp_conn</span><span class="o">.</span><span class="n">remove_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g1comp</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="k">if</span> <span class="p">(</span><span class="s">'granular_type'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span> <span class="ow">or</span> <span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'granular_type'</span><span class="p">]</span> <span class="o">!=</span> <span class="s">'state'</span><span class="p">):</span>
<span class="n">g1comp_st</span><span class="o">.</span><span class="n">remove_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">pos</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g1comp_conn</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g1comp_conn</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g1comp_conn</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g1comp_conn</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">5.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'red'</span><span class="p">)</span>
<span class="n">pos_st</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g1comp_st</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g1comp_st</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g1comp_st</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g1comp_st</span><span class="p">,</span> <span class="n">pos_st</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">3.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'black'</span><span class="p">)</span>
<span class="c"># save viz</span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'single_connected_comp.html'</span><span class="p">,</span> <span class="n">tiles</span><span class="o">=</span><span class="s">'cartodb_positron'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/50states/maps/single_connected_comp.html" height="500" width="750"></iframe>
<h2 id="5-solve-cpp">5. Solve CPP</h2>
<p>I don’t expect the Chinese Postman solution to be optimal since it only utilizes the required edges. However, I do expect it to execute quickly and serve as a benchmark for the Rural Postman
solution. In the age of “deep learning,” I agree with Smerity, <a href="http://smerity.com/articles/2017/baselines_need_love.html">baselines need more love</a>.</p>
<h3 id="51-create-cpp-edgelist">5.1 Create CPP edgelist</h3>
<p>The <a href="https://github.com/brooksandrew/postman_problems/blob/master/postman_problems/solver.py#L65">cpp solver</a> I wrote operates off an edgelist (text file). This feels a bit clunky here, but it works.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># create list with edge attributes and "from" & "to" nodes</span>
<span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_st_contracted</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">tmpi</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span> <span class="c"># so we don't mess w original graph</span>
<span class="n">tmpi</span><span class="p">[</span><span class="s">'start_node'</span><span class="p">]</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">tmpi</span><span class="p">[</span><span class="s">'end_node'</span><span class="p">]</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">tmp</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tmpi</span><span class="p">)</span>
<span class="c"># create dataframe w node1 and node2 in order</span>
<span class="n">eldf</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span>
<span class="n">eldf</span> <span class="o">=</span> <span class="n">eldf</span><span class="p">[[</span><span class="s">'start_node'</span><span class="p">,</span> <span class="s">'end_node'</span><span class="p">]</span> <span class="o">+</span> <span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">eldf</span><span class="o">.</span><span class="n">columns</span><span class="p">)</span><span class="o">-</span><span class="p">{</span><span class="s">'start_node'</span><span class="p">,</span> <span class="s">'end_node'</span><span class="p">})]</span></code></pre></figure>
<p>The first two columns are interpeted as the <em>from</em> and <em>to</em> nodes; everything else as edge attributes.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">eldf</span><span class="o">.</span><span class="n">head</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span></code></pre></figure>
<div>
<style scoped="">
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>start_node</th>
<th>end_node</th>
<th>comp</th>
<th>name</th>
<th>connector</th>
<th>path</th>
<th>distance</th>
<th>required</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>3788079770</td>
<td>649840206</td>
<td>0.0</td>
<td>Texas Avenue Southeast</td>
<td>NaN</td>
<td>[649840206, 649840209, 649840220, 30100500, 64...</td>
<td>1244.893849</td>
<td>1</td>
</tr>
<tr>
<th>1</th>
<td>3788079770</td>
<td>49744479</td>
<td>NaN</td>
<td>NaN</td>
<td>True</td>
<td>[3788079770, 49751669, 4630443674, 49751671, 4...</td>
<td>674.458290</td>
<td>1</td>
</tr>
<tr>
<th>2</th>
<td>49765126</td>
<td>49765287</td>
<td>1.0</td>
<td>Georgia Avenue Northwest</td>
<td>NaN</td>
<td>[49765126, 49765129, 49765130, 49765131, 49765...</td>
<td>559.251509</td>
<td>1</td>
</tr>
</tbody>
</table>
</div>
<h3 id="52-cpp-solver">5.2 CPP solver</h3>
<h4 id="starting-point">Starting point</h4>
<p>I fix the starting node for the solution to OSM node <code class="highlighter-rouge">49765113</code> which corresponds to (<strong>38.917002</strong>, <strong>-77.0364987</strong>): the intersection of New Hampshire Avenue NW, 16th St NW and U St NW… and also
the close to my house:</p>
<p><img src="https://github.com/brooksandrew/postman_problems_examples/raw/master/50states/fig/start_node_map.png" alt="start_node_map" /></p>
<h4 id="solve">Solve</h4>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># create mockfilename</span>
<span class="n">elfn</span> <span class="o">=</span> <span class="n">create_mock_csv_from_dataframe</span><span class="p">(</span><span class="n">eldf</span><span class="p">)</span>
<span class="c"># solve</span>
<span class="n">START_NODE</span> <span class="o">=</span> <span class="s">'49765113'</span> <span class="c"># New Hampshire Ave NW & U St NW.</span>
<span class="n">circuit_cpp</span><span class="p">,</span> <span class="n">gcpp</span> <span class="o">=</span> <span class="n">cpp</span><span class="p">(</span><span class="n">elfn</span><span class="p">,</span> <span class="n">start_node</span><span class="o">=</span><span class="n">START_NODE</span><span class="p">)</span></code></pre></figure>
<h3 id="53-cpp-results">5.3: CPP results</h3>
<p>The CPP solution covers roughly 390,000 meters, about <strong>242 miles</strong>.
The optimal CPP route doubles the required distance, doublebacking every edge on average… definitely not ideal.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># circuit stats</span>
<span class="n">calculate_postman_solution_stats</span><span class="p">(</span><span class="n">circuit_cpp</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>OrderedDict([('distance_walked', 391523.723281576),
('distance_doublebacked', 190249.27638658223),
('distance_walked_once', 201274.44689499377),
('distance_walked_optional', 0),
('distance_walked_required', 391523.723281576),
('edges_walked', 688),
('edges_doublebacked', 337),
('edges_walked_once', 351),
('edges_walked_optional', 0),
('edges_walked_required', 688)])
</code></pre></div></div>
<h2 id="6-solve-rpp">6. Solve RPP</h2>
<p>The RPP should improve the CPP solution as it considers optional edges that can drastically limit the amount of doublebacking.</p>
<p>We could add every possible edge that connects the required nodes, but it turns out that computation blows up quickly, and I’m not that patient. The <code class="highlighter-rouge">get_shortest_paths_distances</code> is the bottleneck
applying dijkstra path length on all possible combinations. There are ~14k pairs to calculate shortest path for (4 per second) which would take almost one hour.</p>
<p>However, we can use some heuristics to speed this up dramatically without sacrificing too much.</p>
<h3 id="61-create-rpp-edgelist">6.1 Create RPP edgelist</h3>
<p>Ideally optional edges will be relatively short, since they are, well, optional. It is unlikely that the RPP algorithm will find that leveraging an optional edge that stretches from one corner of the
graph to another will be efficient. Thus we constrain the set of optional edges presented to the RPP solver to include only those less than <code class="highlighter-rouge">max_distance</code>.</p>
<p>I experimented with several thresholds. 3200 meters certainly took longer (~40 minutes), but yielded the best route results. I tried 4000m which ran for about 4 hours and returned a route with the
same distance (160 miles) as the 3200m threshold.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="o">%%</span><span class="n">time</span>
<span class="n">dfrpp</span> <span class="o">=</span> <span class="n">create_rpp_edgelist</span><span class="p">(</span><span class="n">g_st_contracted</span><span class="o">=</span><span class="n">g_st_contracted</span><span class="p">,</span>
<span class="n">graph_full</span><span class="o">=</span><span class="n">g_ud</span><span class="p">,</span>
<span class="n">edge_weight</span><span class="o">=</span><span class="s">'length'</span><span class="p">,</span>
<span class="n">max_distance</span><span class="o">=</span><span class="mi">3200</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CPU times: user 34min 38s, sys: 20.5 s, total: 34min 59s
Wall time: 36min 3s
</code></pre></div></div>
<p>Check how many optional edges are considered (0=optional, 1=required):</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">Counter</span><span class="p">(</span><span class="n">dfrpp</span><span class="p">[</span><span class="s">'required'</span><span class="p">])</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Counter({0: 16021, 1: 351})
</code></pre></div></div>
<h3 id="62-rpp-solver">6.2 RPP solver</h3>
<p>Apply the RPP solver to the processed dataset.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="o">%%</span><span class="n">time</span>
<span class="c"># create mockfilename</span>
<span class="n">elfn</span> <span class="o">=</span> <span class="n">create_mock_csv_from_dataframe</span><span class="p">(</span><span class="n">dfrpp</span><span class="p">)</span>
<span class="c"># solve</span>
<span class="n">circuit_rpp</span><span class="p">,</span> <span class="n">grpp</span> <span class="o">=</span> <span class="n">rpp</span><span class="p">(</span><span class="n">elfn</span><span class="p">,</span> <span class="n">start_node</span><span class="o">=</span><span class="n">START_NODE</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CPU times: user 7min 25s, sys: 1.68 s, total: 7min 27s
Wall time: 7min 31s
</code></pre></div></div>
<h3 id="63-rpp-results">6.3 RPP results</h3>
<p>As expected, the RPP route is considerably shorter than the CPP solution. The <strong>~242</strong> mile CPP route is cut significantly to <strong>~160</strong> with the RPP approach.</p>
<p>~26,000m (~161 miles) in total with ~59,000m (37 miles) of doublebacking. Not bad… but probably a 2-day ride.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># RPP route distance (miles)</span>
<span class="k">print</span><span class="p">(</span><span class="nb">sum</span><span class="p">([</span><span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'distance'</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">circuit_rpp</span><span class="p">])</span><span class="o">/</span><span class="mf">1609.34</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>161.58546891004886
</code></pre></div></div>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># hack to convert 'path' from str back to list. Caused by `create_mock_csv_from_dataframe`</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">circuit_rpp</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">])</span> <span class="o">==</span> <span class="nb">str</span><span class="p">:</span>
<span class="k">exec</span><span class="p">(</span><span class="s">'e[3]["path"]='</span> <span class="o">+</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">"path"</span><span class="p">])</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">calculate_postman_solution_stats</span><span class="p">(</span><span class="n">circuit_rpp</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>OrderedDict([('distance_walked', 260045.958535698),
('distance_doublebacked', 58771.511640704295),
('distance_walked_once', 201274.4468949937),
('distance_walked_optional', 51891.485571184385),
('distance_walked_required', 208154.47296451364),
('edges_walked', 447),
('edges_doublebacked', 96),
('edges_walked_once', 351),
('edges_walked_optional', 57),
('edges_walked_required', 390)])
</code></pre></div></div>
<p>As seen below, filling the contracted edges back in with the granular nodes adds considerably to the edge count.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="s">'Number of edges in RPP circuit (with contracted edges): {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">circuit_rpp</span><span class="p">)))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of edges in RPP circuit (with granular edges): {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">rppdf</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Number of edges in RPP circuit (with contracted edges): 447
Number of edges in RPP circuit (with granular edges): 9081
</code></pre></div></div>
<h3 id="64-viz-rpp-graph">6.4 Viz RPP graph</h3>
<h4 id="create-rpp-granular-graph">Create RPP granular graph</h4>
<p>Add the granular edges (that we contracted for computation) back to the graph.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># calc shortest path between optional nodes and add to g1comp graph</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="p">[</span><span class="n">e</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">circuit_rpp</span> <span class="k">if</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'required'</span><span class="p">]</span><span class="o">==</span><span class="mi">0</span><span class="p">]</span> <span class="p">:</span>
<span class="c"># add granular optional edges to g1comp</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">]</span>
<span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">path</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">path</span><span class="p">[</span><span class="mi">1</span><span class="p">:])):</span>
<span class="k">if</span> <span class="n">g1comp</span><span class="o">.</span><span class="n">has_edge</span><span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]):</span>
<span class="k">continue</span>
<span class="n">g1comp</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">granular</span><span class="o">=</span><span class="s">'True'</span><span class="p">,</span> <span class="n">granular_type</span><span class="o">=</span><span class="s">'optional'</span><span class="p">)</span>
<span class="c"># add granular nodes from optional edge paths to g1comp</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">path</span><span class="p">:</span>
<span class="n">g1comp</span><span class="o">.</span><span class="n">add_node</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">lat</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lat'</span><span class="p">],</span> <span class="n">lon</span><span class="o">=</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lon'</span><span class="p">])</span></code></pre></figure>
<h4 id="visualize-rpp-solution-by-edge-type">Visualize RPP solution by edge type</h4>
<ul>
<li><strong><font color="black">black</font></strong>: required state avenue edges</li>
<li><strong><font color="red">red</font></strong>: required non-state avenue edges added to form single component</li>
<li><strong><font color="blue">blue</font></strong>: optional non-state avenue roads</li>
</ul>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">12</span><span class="p">))</span>
<span class="n">g1comp_conn</span> <span class="o">=</span> <span class="n">g1comp</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="n">g1comp_st</span> <span class="o">=</span> <span class="n">g1comp</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="n">g1comp_opt</span> <span class="o">=</span> <span class="n">g1comp</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g1comp</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="k">if</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'granular_type'</span><span class="p">)</span> <span class="o">!=</span> <span class="s">'connector'</span><span class="p">:</span>
<span class="n">g1comp_conn</span><span class="o">.</span><span class="n">remove_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g1comp</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="c">#if e[2].get('name') not in candidate_state_avenue_names:</span>
<span class="k">if</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'granular_type'</span><span class="p">)</span> <span class="o">!=</span> <span class="s">'state'</span><span class="p">:</span>
<span class="n">g1comp_st</span><span class="o">.</span><span class="n">remove_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g1comp</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="k">if</span> <span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'granular_type'</span><span class="p">)</span> <span class="o">!=</span> <span class="s">'optional'</span><span class="p">:</span>
<span class="n">g1comp_opt</span><span class="o">.</span><span class="n">remove_edge</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="n">pos</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g1comp_conn</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g1comp_conn</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g1comp_conn</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g1comp_conn</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">6.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'red'</span><span class="p">)</span>
<span class="n">pos_st</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g1comp_st</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g1comp_st</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g1comp_st</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g1comp_st</span><span class="p">,</span> <span class="n">pos_st</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">4.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'black'</span><span class="p">)</span>
<span class="n">pos_opt</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">g1comp_opt</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g1comp_opt</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">g1comp_opt</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g1comp_opt</span><span class="p">,</span> <span class="n">pos_opt</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mf">2.0</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'blue'</span><span class="p">)</span>
<span class="c"># save vbiz</span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'rpp_solution_edge_type.html'</span><span class="p">,</span> <span class="n">tiles</span><span class="o">=</span><span class="s">'cartodb_positron'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/50states/maps/rpp_solution_edge_type.html" height="500" width="750"></iframe>
<h4 id="visualize-rpp-solution-by-edge-walk-count">Visualize RPP solution by edge walk count</h4>
<p>Edge walks per color:</p>
<p><strong><font color="black">black</font></strong>: 1 <br />
<strong><font color="magenta">magenta</font></strong>: 2 <br />
<strong><font color="orange">orange</font></strong>: 3 <br /></p>
<p>Edges walked more than once are also widened.</p>
<p>This solution feels pretty reasonable with surprisingly little doublebacking. After staring at this for several minutes, I could think of roads I’d prefer not to cycle on, but no obvious shorter
paths.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c">## Create graph directly from rpp_circuit and original graph w lat/lon (g_ud)</span>
<span class="n">color_seq</span> <span class="o">=</span> <span class="p">[</span><span class="bp">None</span><span class="p">,</span> <span class="s">'black'</span><span class="p">,</span> <span class="s">'magenta'</span><span class="p">,</span> <span class="s">'orange'</span><span class="p">,</span> <span class="s">'yellow'</span><span class="p">]</span>
<span class="n">grppviz</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">Graph</span><span class="p">()</span>
<span class="n">edges_cnt</span> <span class="o">=</span> <span class="n">Counter</span><span class="p">([</span><span class="nb">tuple</span><span class="p">(</span><span class="nb">sorted</span><span class="p">([</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]]))</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">circuit_rpp</span><span class="p">])</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">circuit_rpp</span><span class="p">:</span>
<span class="k">for</span> <span class="n">n1</span><span class="p">,</span> <span class="n">n2</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">][:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">][</span><span class="mi">1</span><span class="p">:]):</span>
<span class="k">if</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">has_edge</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span> <span class="n">n2</span><span class="p">):</span>
<span class="n">grppviz</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="n">n2</span><span class="p">][</span><span class="s">'linewidth'</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">2</span>
<span class="n">grppviz</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="n">n2</span><span class="p">][</span><span class="s">'cnt'</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">grppviz</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span> <span class="n">n2</span><span class="p">,</span> <span class="n">linewidth</span><span class="o">=</span><span class="mf">2.5</span><span class="p">)</span>
<span class="n">grppviz</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="n">n2</span><span class="p">][</span><span class="s">'color_st'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'black'</span> <span class="k">if</span> <span class="n">g_st</span><span class="o">.</span><span class="n">has_edge</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span> <span class="n">n2</span><span class="p">)</span> <span class="k">else</span> <span class="s">'red'</span>
<span class="n">grppviz</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="n">n2</span><span class="p">][</span><span class="s">'cnt'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">grppviz</span><span class="o">.</span><span class="n">add_node</span><span class="p">(</span><span class="n">n1</span><span class="p">,</span> <span class="n">lat</span><span class="o">=</span><span class="n">g_ud</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="s">'lat'</span><span class="p">],</span> <span class="n">lon</span><span class="o">=</span><span class="n">g_ud</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n1</span><span class="p">][</span><span class="s">'lon'</span><span class="p">])</span>
<span class="n">grppviz</span><span class="o">.</span><span class="n">add_node</span><span class="p">(</span><span class="n">n2</span><span class="p">,</span> <span class="n">lat</span><span class="o">=</span><span class="n">g_ud</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n2</span><span class="p">][</span><span class="s">'lat'</span><span class="p">],</span> <span class="n">lon</span><span class="o">=</span><span class="n">g_ud</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n2</span><span class="p">][</span><span class="s">'lon'</span><span class="p">])</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'color_cnt'</span><span class="p">]</span> <span class="o">=</span> <span class="n">color_seq</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'cnt'</span><span class="p">]]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="o">.</span><span class="n">subplots</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">12</span><span class="p">))</span>
<span class="n">pos</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="p">(</span><span class="n">grppviz</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="s">'lat'</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">nodes</span><span class="p">()}</span>
<span class="n">e_width</span> <span class="o">=</span> <span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'linewidth'</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)]</span>
<span class="n">e_color</span> <span class="o">=</span> <span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'color_cnt'</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">grppviz</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)]</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">grppviz</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="n">e_width</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="n">e_color</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.7</span><span class="p">)</span>
<span class="c"># save viz</span>
<span class="n">mplleaflet</span><span class="o">.</span><span class="n">save_html</span><span class="p">(</span><span class="n">fig</span><span class="p">,</span> <span class="s">'rpp_solution_edge_cnt.html'</span><span class="p">,</span> <span class="n">tiles</span><span class="o">=</span><span class="s">'cartodb_positron'</span><span class="p">)</span></code></pre></figure>
<iframe src="https://cdn.rawgit.com/brooksandrew/postman_problems_examples/master/50states/maps/rpp_solution_edge_cnt.html" height="500" width="750"></iframe>
<h3 id="65-serialize-rpp-solution">6.5 Serialize RPP solution</h3>
<h4 id="csv">CSV</h4>
<p>Remember we contracted the edges in <strong>4.1</strong> for more efficient computation. However, when we visualize the solution, the more granular edges within the larger contracted ones are filled back in, so
we can see the exact route to ride with all the bends and squiggles.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># fill in RPP solution edgelist with granular nodes</span>
<span class="n">rpplist</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">ee</span> <span class="ow">in</span> <span class="n">circuit_rpp</span><span class="p">:</span>
<span class="n">path</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">ee</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">][:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">ee</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">][</span><span class="mi">1</span><span class="p">:]))</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">path</span><span class="p">:</span>
<span class="n">rpplist</span><span class="o">.</span><span class="n">append</span><span class="p">({</span>
<span class="s">'start_node'</span><span class="p">:</span> <span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
<span class="s">'end_node'</span><span class="p">:</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
<span class="s">'start_lat'</span><span class="p">:</span> <span class="n">g_ud</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="s">'lat'</span><span class="p">],</span>
<span class="s">'start_lon'</span><span class="p">:</span> <span class="n">g_ud</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="s">'lon'</span><span class="p">],</span>
<span class="s">'end_lat'</span><span class="p">:</span> <span class="n">g_ud</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]][</span><span class="s">'lat'</span><span class="p">],</span>
<span class="s">'end_lon'</span><span class="p">:</span> <span class="n">g_ud</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]][</span><span class="s">'lon'</span><span class="p">],</span>
<span class="s">'street_name'</span><span class="p">:</span> <span class="n">g_ud</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'name'</span><span class="p">)</span>
<span class="p">})</span>
<span class="c"># write solution to disk</span>
<span class="n">rppdf</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">rpplist</span><span class="p">)</span>
<span class="n">rppdf</span><span class="o">.</span><span class="n">to_csv</span><span class="p">(</span><span class="s">'rpp_solution.csv'</span><span class="p">,</span> <span class="n">index</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span></code></pre></figure>
<h4 id="geojson">Geojson</h4>
<p>Similarly, we create a geojson object of the RPP solution using the <code class="highlighter-rouge">time</code> attribute to keep track of the route order. This data structure can be used for fancy js/d3 visualizations. Coming soon,
hopefully.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">geojson</span> <span class="o">=</span> <span class="p">{</span><span class="s">'features'</span><span class="p">:[],</span> <span class="s">'type'</span><span class="p">:</span> <span class="s">'FeatureCollection'</span><span class="p">}</span>
<span class="n">time</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">path</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">circuit_rpp</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">]))</span>
<span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">circuit_rpp</span><span class="p">:</span>
<span class="k">if</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">!=</span> <span class="n">path</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
<span class="n">path</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">reversed</span><span class="p">(</span><span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">]))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="s">'path'</span><span class="p">]</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="n">path</span><span class="p">:</span>
<span class="n">time</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">doc</span> <span class="o">=</span> <span class="p">{</span><span class="s">'type'</span><span class="p">:</span> <span class="s">'Feature'</span><span class="p">,</span>
<span class="s">'properties'</span><span class="p">:</span> <span class="p">{</span>
<span class="s">'latitude'</span><span class="p">:</span> <span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lat'</span><span class="p">],</span>
<span class="s">'longitude'</span><span class="p">:</span> <span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span>
<span class="s">'time'</span><span class="p">:</span> <span class="n">time</span><span class="p">,</span>
<span class="s">'id'</span><span class="p">:</span> <span class="n">e</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'id'</span><span class="p">)</span>
<span class="p">},</span>
<span class="s">'geometry'</span><span class="p">:{</span>
<span class="s">'type'</span><span class="p">:</span> <span class="s">'Point'</span><span class="p">,</span>
<span class="s">'coordinates'</span><span class="p">:</span> <span class="p">[</span><span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lon'</span><span class="p">],</span> <span class="n">g</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="s">'lat'</span><span class="p">]]</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">geojson</span><span class="p">[</span><span class="s">'features'</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">doc</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">'circuit_rpp.geojson'</span><span class="p">,</span><span class="s">'w'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">geojson</span><span class="p">,</span> <span class="n">f</span><span class="p">)</span></code></pre></figure>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/fifty-states-rural-postman-problem/">50 states Rural Postman Problem</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on November 19, 2017.</p>http://brooksandrew.github.io/simpleblog/articles/intro-to-graph-optimization-solving-cpp2017-10-07T00:00:00+00:002017-10-07T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<p><strong>This post was originally published as a tutorial for DataCamp <a href="https://www.datacamp.com/community/tutorials/networkx-python-graph-tutorial">here</a> on September 12 2017</strong> using NetworkX <strong>1.11</strong>. On September 20 2017, NetworkX <a href="https://networkx.github.io/documentation/stable/release/release_2.0">announced</a> the release of a new
version <strong>2.0</strong>, after two years in the making. While <strong>2.0</strong> introduces lots of great features (some have already been used to improve this project in <a href="https://github.com/brooksandrew/postman_problems">postman_problems</a>), it also introduced
backwards incompatible API changes that broke the original tutorial :(. I’ve commented out lines deprecated by <strong>2.0</strong> and tagged with <code class="highlighter-rouge"># deprecated after NX 1.11</code>, so the changes made here are
explicit. Most of the changes are around the passing and setting of attributes and return values deprecating lists for generators.</p>
<p>So… <strong>TL;DR:</strong></p>
<ol>
<li>This is the NetworkX <strong>2.0</strong> compatible version of the Chinese Postman DataCamp tutorial originally posted <a href="https://www.datacamp.com/community/tutorials/networkx-python-graph-tutorial">here</a>.</li>
<li>The ideas introduced in this tutorial are packaged into the <a href="https://github.com/brooksandrew/postman_problems">postman_problems</a> library which is the mature implementation of these concepts.</li>
</ol>
<p><strong>A note on the making of this post</strong>. The original post was created in a Jupyter notebook and converted to HTML with some style tweaks by the DataCamp publishing team. This post was converted from
an <a href="https://github.com/brooksandrew/simpleblog/tree/gh-pages/_ipynb">updated notebook</a> to a Jekyll flavored markdown document for my blog using <a href="https://github.com/jsoma/nb2jekyll">nb2jekyll</a> with just a few <a href="https://github.com/brooksandrew/simpleblog/tree/gh-pages/nb2jekyll">tweaks of my own</a>. This was the first Jupyter notebook I’ve converted to a blog post, but
the conversion was smoother than I might have expected. I would recommend <a href="https://github.com/jsoma/nb2jekyll">nb2jekyll</a> and <a href="http://rjbaxley.com/posts/2017/02/25/Jekyll_Blogging_with_Notebooks.html">this post</a> to comrade Jekyll bloggers looking to generate posts directly from Jupyter notebooks.</p>
<hr />
<h2 id="intro-to-graph-optimization-with-networkx-in-python">Intro to Graph Optimization with NetworkX in Python</h2>
<h3 id="solving-the-chinese-postman-problem">Solving the Chinese Postman Problem</h3>
<p>With this tutorial, you’ll tackle an established problem in graph theory called the Chinese Postman Problem. There are some components of the algorithm that while conceptually simple, turn out to be
computationally rigorous. However, for this tutorial, only some prior knowledge of Python is required: no rigorous math, computer science or graph theory background is needed.</p>
<p>This tutorial will first go over the basic building blocks of graphs (nodes, edges, paths, etc) and solve the problem on a real graph (trail network of a state park) using the <a href="https://networkx.github.io/">NetworkX</a> library in
Python. You’ll focus on the core concepts and implementation. For the interested reader, further reading on the guts of the optimization are provided.</p>
<ul id="markdown-toc">
<li><a href="#intro-to-graph-optimization-with-networkx-in-python" id="markdown-toc-intro-to-graph-optimization-with-networkx-in-python">Intro to Graph Optimization with NetworkX in Python</a> <ul>
<li><a href="#solving-the-chinese-postman-problem" id="markdown-toc-solving-the-chinese-postman-problem">Solving the Chinese Postman Problem</a></li>
</ul>
</li>
<li><a href="#motivating-graph-optimization" id="markdown-toc-motivating-graph-optimization">Motivating Graph Optimization</a> <ul>
<li><a href="#the-problem" id="markdown-toc-the-problem">The Problem</a></li>
<li><a href="#personal-motivation" id="markdown-toc-personal-motivation">Personal Motivation</a></li>
</ul>
</li>
<li><a href="#introducing-graphs" id="markdown-toc-introducing-graphs">Introducing Graphs</a> <ul>
<li><a href="#networkx-graph-manipulation-and-analysis" id="markdown-toc-networkx-graph-manipulation-and-analysis">NetworkX: Graph Manipulation and Analysis</a></li>
<li><a href="#installing-packages" id="markdown-toc-installing-packages">Installing Packages</a></li>
</ul>
</li>
<li><a href="#load-data" id="markdown-toc-load-data">Load Data</a> <ul>
<li><a href="#edge-list" id="markdown-toc-edge-list">Edge List</a></li>
<li><a href="#node-list" id="markdown-toc-node-list">Node List</a></li>
<li><a href="#note-on-generating-the-node--edge-lists" id="markdown-toc-note-on-generating-the-node--edge-lists">Note on Generating the Node & Edge Lists</a></li>
</ul>
</li>
<li><a href="#create-graph" id="markdown-toc-create-graph">Create Graph</a></li>
<li><a href="#inspect-graph" id="markdown-toc-inspect-graph">Inspect Graph</a> <ul>
<li><a href="#edges" id="markdown-toc-edges">Edges</a></li>
<li><a href="#nodes" id="markdown-toc-nodes">Nodes</a></li>
<li><a href="#summary-stats" id="markdown-toc-summary-stats">Summary Stats</a></li>
</ul>
</li>
<li><a href="#visualize" id="markdown-toc-visualize">Visualize</a> <ul>
<li><a href="#manipulate-colors-and-layout" id="markdown-toc-manipulate-colors-and-layout">Manipulate Colors and Layout</a></li>
<li><a href="#plot" id="markdown-toc-plot">Plot</a></li>
</ul>
</li>
<li><a href="#overview-of-cpp-algorithm" id="markdown-toc-overview-of-cpp-algorithm">Overview of CPP Algorithm</a></li>
<li><a href="#assumptions-and-simplifications" id="markdown-toc-assumptions-and-simplifications">Assumptions and Simplifications</a></li>
<li><a href="#cpp-step-1-find-nodes-of-odd-degree" id="markdown-toc-cpp-step-1-find-nodes-of-odd-degree">CPP Step 1: Find Nodes of Odd Degree</a></li>
<li><a href="#cpp-step-2-find-min-distance-pairs" id="markdown-toc-cpp-step-2-find-min-distance-pairs">CPP Step 2: Find Min Distance Pairs</a> <ul>
<li><a href="#step-21-compute-node-pairs" id="markdown-toc-step-21-compute-node-pairs">Step 2.1: Compute Node Pairs</a></li>
<li><a href="#step-22-compute-shortest-paths-between-node-pairs" id="markdown-toc-step-22-compute-shortest-paths-between-node-pairs">Step 2.2: Compute Shortest Paths between Node Pairs</a></li>
<li><a href="#step-23-create-complete-graph" id="markdown-toc-step-23-create-complete-graph">Step 2.3: Create Complete Graph</a></li>
<li><a href="#step-24-compute-minimum-weight-matching" id="markdown-toc-step-24-compute-minimum-weight-matching">Step 2.4: Compute Minimum Weight Matching</a></li>
<li><a href="#step-25-augment-the-original-graph" id="markdown-toc-step-25-augment-the-original-graph">Step 2.5: Augment the Original Graph</a></li>
</ul>
</li>
<li><a href="#cpp-step-3-compute-eulerian-circuit" id="markdown-toc-cpp-step-3-compute-eulerian-circuit">CPP Step 3: Compute Eulerian Circuit</a> <ul>
<li><a href="#naive-circuit" id="markdown-toc-naive-circuit">Naive Circuit</a></li>
<li><a href="#correct-circuit" id="markdown-toc-correct-circuit">Correct Circuit</a></li>
</ul>
</li>
<li><a href="#cpp-solution" id="markdown-toc-cpp-solution">CPP Solution</a> <ul>
<li><a href="#text" id="markdown-toc-text">Text</a></li>
<li><a href="#stats" id="markdown-toc-stats">Stats</a></li>
</ul>
</li>
<li><a href="#visualize-cpp-solution" id="markdown-toc-visualize-cpp-solution">Visualize CPP Solution</a> <ul>
<li><a href="#create-cpp-graph" id="markdown-toc-create-cpp-graph">Create CPP Graph</a></li>
<li><a href="#visualization-1-retracing-steps" id="markdown-toc-visualization-1-retracing-steps">Visualization 1: Retracing Steps</a></li>
<li><a href="#visualization-2-cpp-solution-sequence" id="markdown-toc-visualization-2-cpp-solution-sequence">Visualization 2: CPP Solution Sequence</a></li>
<li><a href="#visualization-3-movie" id="markdown-toc-visualization-3-movie">Visualization 3: Movie</a></li>
</ul>
</li>
<li><a href="#next-steps" id="markdown-toc-next-steps">Next Steps</a></li>
<li><a href="#references" id="markdown-toc-references">References</a></li>
</ul>
<h2 id="motivating-graph-optimization">Motivating Graph Optimization</h2>
<h3 id="the-problem">The Problem</h3>
<p>You’ve probably heard of the <a href="https://en.wikipedia.org/wiki/Travelling_salesman_problem">Travelling Salesman Problem</a> which amounts to finding the shortest route (say, roads) that connects a set of nodes (say, cities). Although lesser known, the <a href="https://en.wikipedia.org/wiki/Route_inspection_problem">Chinese
Postman Problem</a> (CPP), also referred to as the Route Inspection or Arc Routing problem, is quite similar. The objective of the CPP is to find the shortest path that covers all the links (roads) on a
graph at least once. If this is possible without doubling back on the same road twice, great; That’s the ideal scenario and the problem is quite simple. However, if some roads must be traversed more
than once, you need some math to find the shortest route that hits every road at least once with the lowest total mileage.</p>
<h3 id="personal-motivation">Personal Motivation</h3>
<p><em>(The following is a personal note: cheesy, cheeky and 100% not necessary for learning graph optimization in Python)</em></p>
<p>I had a real-life application for solving this problem: attaining the rank of Giantmaster Marathoner.</p>
<p>What is a Giantmaster? A <a href="http://www.sgpa.org/hikes/masters.html">Giantmaster</a> is one (canine or human) who has hiked every trail of Sleeping Giant State Park in Hamden CT (neighbor to my hometown of Wallingford)… in their lifetime. A
Giantmaster Marathoner is one who has hiked all these trails in a single day.</p>
<p>Thanks to the fastidious record keeping of the Sleeping Giant Park Association, the full roster of Giantmasters and their level of Giantmastering can be found <a href="http://brooksandrew.github.io/simpleblog/">here</a>. I have to admit this motivated
me quite a bit to kick-start this side-project and get out there to run the trails. While I myself achieved Giantmaster status in the winter of 2006 when I was a budding young volunteer of the
Sleeping Giant Trail Crew (which I was pleased to see recorded in the <a href="http://www.sgpa.org/gnews/archive/84.pdf">SG archive</a>), new challenges have since arisen. While the 12-month and 4-season Giantmaster categories are impressive and
enticing, they’d also require more travel from my current home (DC) to my formative home (CT) than I could reasonably manage… and they’re not as interesting for graph optimization, so Giantmaster
Marathon it is!</p>
<p>For another reference, the Sleeping Giant trail map is provided below:</p>
<iframe width="600" height="450" src="http://www.ct.gov/deep/lib/deep/stateparks/maps/sleepgiant.pdf" frameborder="0" allowfullscreen=""></iframe>
<h2 id="introducing-graphs">Introducing Graphs</h2>
<p>The nice thing about graphs is that the concepts and terminology are generally intuitive. Nonetheless, here’s some of the basic lingo:</p>
<p><strong>Graphs</strong> are structures that map relations between objects. The objects are referred to as <strong>nodes</strong> and the connections between them as <strong>edges</strong> in this tutorial. Note that edges and nodes are
commonly referred to by several names that generally mean exactly the same thing:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node == vertex == point
edge == arc == link
</code></pre></div></div>
<p>The starting graph is <strong>undirected</strong>. That is, your edges have no orientation: they are <strong>bi-directional</strong>. For example: <code class="highlighter-rouge">A<--->B == B<--->A</code>.
By contrast, the graph you might create to specify the shortest path to hike every trail could be a <strong>directed graph</strong>, where the order and direction of edges matters. For example: <code class="highlighter-rouge">A--->B !=
B--->A</code>.</p>
<p>The graph is also an <strong>edge-weighted graph</strong> where the distance (in miles) between each pair of adjacent nodes represents the weight of an edge. This is handled as an <strong>edge attribute</strong> named
“distance”.</p>
<p><strong>Degree</strong> refers to the number of edges incident to (touching) a node. Nodes are referred to as <strong>odd-degree nodes</strong> when this number is odd and <strong>even-degree</strong> when even.</p>
<p>The solution to this CPP problem will be a <strong>Eulerian tour</strong>: a graph where a cycle that passes through every edge exactly once can be made from a starting node back to itself (without backtracking).
An Euler Tour is also known by several names:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Eulerian tour == Eulerian circuit == Eulerian cycle
</code></pre></div></div>
<p>A <strong>matching</strong> is a subset of edges in which no node occurs more than once. A <strong>minimum weight matching</strong> finds the <strong>matching</strong> with the lowest possible summed edge weight.</p>
<h3 id="networkx-graph-manipulation-and-analysis">NetworkX: Graph Manipulation and Analysis</h3>
<p>NetworkX is the most popular Python package for manipulating and analyzing graphs. Several packages offer the same basic level of graph manipulation, notably igraph which also has bindings for R and
C++. However, I found that NetworkX had the strongest graph algorithms that I needed to solve the CPP.</p>
<h3 id="installing-packages">Installing Packages</h3>
<p>If you’ve done any sort of data analysis in Python or have the Anaconda distribution, my guess is you probably have <code class="highlighter-rouge">pandas</code> and <code class="highlighter-rouge">matplotlib</code>. However, you might not have <code class="highlighter-rouge">networkx</code>. These should be
the only dependencies outside the Python Standard Library that you’ll need to run through this tutorial. They are easy to install with <code class="highlighter-rouge">pip</code>:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip install pandas
pip install networkx>=2.0
pip install matplotlib
</code></pre></div></div>
<p>These should be all the packages you’ll need for now. <code class="highlighter-rouge">imageio</code> and <code class="highlighter-rouge">numpy</code> are imported at the very end to create the GIF animation of the CPP solution. The animation is embedded within this post,
so these packages are optional.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">itertools</span>
<span class="kn">import</span> <span class="nn">copy</span>
<span class="kn">import</span> <span class="nn">networkx</span> <span class="k">as</span> <span class="n">nx</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span></code></pre></figure>
<h2 id="load-data">Load Data</h2>
<h3 id="edge-list">Edge List</h3>
<p>The edge list is a simple data structure that you’ll use to create the graph. Each row represents a single edge of the graph with some edge attributes.</p>
<ul>
<li><strong>node1</strong> & <strong>node2:</strong> names of the nodes connected.</li>
<li><strong>trail:</strong> edge attribute indicating the abbreviated name of the trail for each edge. For example: <em>rs = red square</em></li>
<li><strong>distance:</strong> edge attribute indicating trail length in miles.</li>
<li><strong>color</strong>: trail color used for plotting.</li>
<li><strong>estimate:</strong> edge attribute indicating whether the edge distance is estimated from eyeballing the trailmap (<em>1=yes</em>, <em>0=no</em>) as some distances are not provided. This is solely for reference; it is
not used for analysis.</li>
</ul>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Grab edge list data hosted on Gist</span>
<span class="n">edgelist</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s">'https://gist.githubusercontent.com/brooksandrew/e570c38bcc72a8d102422f2af836513b/raw/89c76b2563dbc0e88384719a35cba0dfc04cd522/edgelist_sleeping_giant.csv'</span><span class="p">)</span> </code></pre></figure>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Preview edgelist</span>
<span class="n">edgelist</span><span class="o">.</span><span class="n">head</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span></code></pre></figure>
<div>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>node1</th>
<th>node2</th>
<th>trail</th>
<th>distance</th>
<th>color</th>
<th>estimate</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>rs_end_north</td>
<td>v_rs</td>
<td>rs</td>
<td>0.30</td>
<td>red</td>
<td>0</td>
</tr>
<tr>
<th>1</th>
<td>v_rs</td>
<td>b_rs</td>
<td>rs</td>
<td>0.21</td>
<td>red</td>
<td>0</td>
</tr>
<tr>
<th>2</th>
<td>b_rs</td>
<td>g_rs</td>
<td>rs</td>
<td>0.11</td>
<td>red</td>
<td>0</td>
</tr>
<tr>
<th>3</th>
<td>g_rs</td>
<td>w_rs</td>
<td>rs</td>
<td>0.18</td>
<td>red</td>
<td>0</td>
</tr>
<tr>
<th>4</th>
<td>w_rs</td>
<td>o_rs</td>
<td>rs</td>
<td>0.21</td>
<td>red</td>
<td>0</td>
</tr>
<tr>
<th>5</th>
<td>o_rs</td>
<td>y_rs</td>
<td>rs</td>
<td>0.12</td>
<td>red</td>
<td>0</td>
</tr>
<tr>
<th>6</th>
<td>y_rs</td>
<td>rs_end_south</td>
<td>rs</td>
<td>0.39</td>
<td>red</td>
<td>0</td>
</tr>
<tr>
<th>7</th>
<td>rc_end_north</td>
<td>v_rc</td>
<td>rc</td>
<td>0.70</td>
<td>red</td>
<td>0</td>
</tr>
<tr>
<th>8</th>
<td>v_rc</td>
<td>b_rc</td>
<td>rc</td>
<td>0.04</td>
<td>red</td>
<td>0</td>
</tr>
<tr>
<th>9</th>
<td>b_rc</td>
<td>g_rc</td>
<td>rc</td>
<td>0.15</td>
<td>red</td>
<td>0</td>
</tr>
</tbody>
</table>
</div>
<h3 id="node-list">Node List</h3>
<p>Node lists are usually optional in <code class="highlighter-rouge">networkx</code> and other graph libraries when edge lists are provided because the node names are provided in the edge list’s first two columns. However, in this case,
there are some node attributes that we’d like to add: X, Y coordinates of the nodes (trail intersections) so that you can plot your graph with the same layout as the trail map.</p>
<p>I spent an afternoon annotating these manually by tracing over the image with <a href="https://www.gimp.org/">GIMP</a>:</p>
<ul>
<li><strong>id:</strong> name of the node corresponding to <strong>node1</strong> and <strong>node2</strong> in the edge list.</li>
<li><strong>X:</strong> horizontal position/coordinate of the node relative to the topleft.</li>
<li><strong>Y</strong> vertical position/coordinate of the node relative to the topleft.</li>
</ul>
<h3 id="note-on-generating-the-node--edge-lists">Note on Generating the Node & Edge Lists</h3>
<p>Creating the node names also took some manual effort. Each node represents an intersection of two or more trails. Where possible, the node is named by <em>trail1_trail2</em> where <em>trail1</em> precedes
<em>trail2</em> in alphabetical order.</p>
<p>Things got a little more difficult when the same trails intersected each other more than once. For example, the Orange and White trail. In these cases, I appended a <em>_2</em> or <em>_3</em> to the node name.
For example, you have two distinct node names for the two distinct intersections of Orange and White: <em>o_w</em> and <em>o_w_2</em>.</p>
<p>This took a lot of trial and error and comparing the plots generated with X,Y coordinates to the real trail map.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Grab node list data hosted on Gist</span>
<span class="n">nodelist</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s">'https://gist.githubusercontent.com/brooksandrew/f989e10af17fb4c85b11409fea47895b/raw/a3a8da0fa5b094f1ca9d82e1642b384889ae16e8/nodelist_sleeping_giant.csv'</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Preview nodelist</span>
<span class="n">nodelist</span><span class="o">.</span><span class="n">head</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span></code></pre></figure>
<div>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>id</th>
<th>X</th>
<th>Y</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>b_bv</td>
<td>1486</td>
<td>732</td>
</tr>
<tr>
<th>1</th>
<td>b_bw</td>
<td>716</td>
<td>1357</td>
</tr>
<tr>
<th>2</th>
<td>b_end_east</td>
<td>3164</td>
<td>1111</td>
</tr>
<tr>
<th>3</th>
<td>b_end_west</td>
<td>141</td>
<td>1938</td>
</tr>
<tr>
<th>4</th>
<td>b_g</td>
<td>1725</td>
<td>771</td>
</tr>
</tbody>
</table>
</div>
<h2 id="create-graph">Create Graph</h2>
<p>Now you use the edge list and the node list to create a graph object in <code class="highlighter-rouge">networkx</code>.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Create empty graph</span>
<span class="n">g</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">Graph</span><span class="p">()</span></code></pre></figure>
<p>Loop through the rows of the edge list and add each edge and its corresponding attributes to graph <code class="highlighter-rouge">g</code>.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Add edges and edge attributes</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">elrow</span> <span class="ow">in</span> <span class="n">edgelist</span><span class="o">.</span><span class="n">iterrows</span><span class="p">():</span>
<span class="c"># g.add_edge(elrow[0], elrow[1], attr_dict=elrow[2:].to_dict()) # deprecated after NX 1.11</span>
<span class="n">g</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">elrow</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">elrow</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">**</span><span class="n">elrow</span><span class="p">[</span><span class="mi">2</span><span class="p">:]</span><span class="o">.</span><span class="n">to_dict</span><span class="p">())</span></code></pre></figure>
<p>To illustrate what’s happening here, let’s print the values from the last row in the edge list that got added to graph <code class="highlighter-rouge">g</code>:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Edge list example</span>
<span class="k">print</span><span class="p">(</span><span class="n">elrow</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="c"># node1</span>
<span class="k">print</span><span class="p">(</span><span class="n">elrow</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="c"># node2</span>
<span class="k">print</span><span class="p">(</span><span class="n">elrow</span><span class="p">[</span><span class="mi">2</span><span class="p">:]</span><span class="o">.</span><span class="n">to_dict</span><span class="p">())</span> <span class="c"># edge attribute dict</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>o_gy2
y_gy2
{'estimate': 0, 'distance': 0.12, 'color': 'yellowgreen', 'trail': 'gy2'}
</code></pre></div></div>
<p>Similarly, you loop through the rows in the node list and add these node attributes.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Add node attributes</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">nlrow</span> <span class="ow">in</span> <span class="n">nodelist</span><span class="o">.</span><span class="n">iterrows</span><span class="p">():</span>
<span class="c"># g.node[nlrow['id']] = nlrow[1:].to_dict() # deprecated after NX 1.11</span>
<span class="n">nx</span><span class="o">.</span><span class="n">set_node_attributes</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="p">{</span><span class="n">nlrow</span><span class="p">[</span><span class="s">'id'</span><span class="p">]:</span> <span class="n">nlrow</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span><span class="o">.</span><span class="n">to_dict</span><span class="p">()})</span> </code></pre></figure>
<p>Here’s an example from the last row of the node list:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Node list example</span>
<span class="k">print</span><span class="p">(</span><span class="n">nlrow</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>id y_rt
X 977
Y 1666
Name: 76, dtype: object
</code></pre></div></div>
<h2 id="inspect-graph">Inspect Graph</h2>
<h3 id="edges">Edges</h3>
<p>Your graph edges are represented by a list of tuples of length 3. The first two elements are the node names linked by the edge. The third is the dictionary of edge attributes.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Preview first 5 edges</span>
<span class="c"># g.edges(data=True)[0:5] # deprecated after NX 1.11</span>
<span class="nb">list</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">))[</span><span class="mi">0</span><span class="p">:</span><span class="mi">5</span><span class="p">]</span> </code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[('v_end_west',
'b_v',
{'color': 'violet', 'distance': 0.13, 'estimate': 0, 'trail': 'v'}),
('rt_end_north',
'v_rt',
{'color': 'red', 'distance': 0.3, 'estimate': 0, 'trail': 'rt'}),
('b_o',
'park_east',
{'color': 'orange', 'distance': 0.11, 'estimate': 0, 'trail': 'o'}),
('b_o',
'o_gy2',
{'color': 'orange', 'distance': 0.06, 'estimate': 0, 'trail': 'o'}),
('b_o',
'b_y',
{'color': 'blue', 'distance': 0.08, 'estimate': 0, 'trail': 'b'})]
</code></pre></div></div>
<h3 id="nodes">Nodes</h3>
<p>Similarly, your nodes are represented by a list of tuples of length 2. The first element is the node ID, followed by the dictionary of node attributes.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Preview first 10 nodes</span>
<span class="c"># g.nodes(data=True)[0:10] # deprecated after NX 1.11</span>
<span class="nb">list</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">nodes</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">))[</span><span class="mi">0</span><span class="p">:</span><span class="mi">10</span><span class="p">]</span> </code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[('v_end_west', {'X': 359, 'Y': 1976}),
('rt_end_north', {'X': 681, 'Y': 850}),
('b_o', {'X': 2039, 'Y': 1012}),
('rh_end_north', {'X': 205, 'Y': 1472}),
('rh_end_tt_1', {'X': 558, 'Y': 1430}),
('o_y_tt_end_west', {'X': 459, 'Y': 1924}),
('w_rt', {'X': 926, 'Y': 1490}),
('b_rd_dupe', {'X': 268, 'Y': 1744}),
('b_tt_2', {'X': 857, 'Y': 1287}),
('rd_end_south_dupe', {'X': 273, 'Y': 1869})]
</code></pre></div></div>
<h3 id="summary-stats">Summary Stats</h3>
<p>Print out some summary statistics before visualizing the graph.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="s">'# of edges: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">number_of_edges</span><span class="p">()))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'# of nodes: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">number_of_nodes</span><span class="p">()))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code># of edges: 123
# of nodes: 77
</code></pre></div></div>
<h2 id="visualize">Visualize</h2>
<h3 id="manipulate-colors-and-layout">Manipulate Colors and Layout</h3>
<p><strong>Positions:</strong> First you need to manipulate the node positions from the graph into a dictionary. This will allow you to recreate the graph using the same layout as the actual trail map. <code class="highlighter-rouge">Y</code> is
negated to transform the Y-axis origin from the topleft to the bottomleft.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Define node positions data structure (dict) for plotting</span>
<span class="n">node_positions</span> <span class="o">=</span> <span class="p">{</span><span class="n">node</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span> <span class="p">(</span><span class="n">node</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="s">'X'</span><span class="p">],</span> <span class="o">-</span><span class="n">node</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="s">'Y'</span><span class="p">])</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">g</span><span class="o">.</span><span class="n">nodes</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)}</span>
<span class="c"># Preview of node_positions with a bit of hack (there is no head/slice method for dictionaries).</span>
<span class="nb">dict</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">node_positions</span><span class="o">.</span><span class="n">items</span><span class="p">())[</span><span class="mi">0</span><span class="p">:</span><span class="mi">5</span><span class="p">])</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{'b_o': (2039, -1012),
'rh_end_north': (205, -1472),
'rh_end_tt_1': (558, -1430),
'rt_end_north': (681, -850),
'v_end_west': (359, -1976)}
</code></pre></div></div>
<p><strong>Colors:</strong> Now you manipulate the edge colors from the graph into a simple list so that you can visualize the trails by their color.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Define data structure (list) of edge colors for plotting</span>
<span class="c"># edge_colors = [e[2]['color'] for e in g.edges(data=True)] # deprecated after NX 1.11</span>
<span class="n">edge_colors</span> <span class="o">=</span> <span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'color'</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="nb">list</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">))]</span>
<span class="c"># Preview first 10</span>
<span class="n">edge_colors</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">10</span><span class="p">]</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>['violet',
'red',
'orange',
'orange',
'blue',
'blue',
'red',
'red',
'black',
'black']
</code></pre></div></div>
<h3 id="plot">Plot</h3>
<p>Now you can make a nice plot that lines up nicely with the Sleeping Giant trail map:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="n">node_positions</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="n">edge_colors</span><span class="p">,</span> <span class="n">node_size</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">node_color</span><span class="o">=</span><span class="s">'black'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s">'Graph Representation of Sleeping Giant Trail Map'</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">15</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></code></pre></figure>
<p><img src="data:image/png;base64,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
bVSuXDmFhYWpSZMmGjNmjNLT0122czgceWHs008/zbvWuLi48x7/5MmTysrKkqQirQ3y5l7M9cUX
XyguLk4VKlRQSEiIGjdurFGjRik1NdVt2/bt2+e9vlOmTFGLFi0UFhamypUra8iQIfrjjz/c9smv
H9vZ98CKFSsUFxenyMhIlStXTrfeeqt+/vlnj+VNSUnR008/rTp16igkJEQNGjTQK6+8oqysLJf7
vyDGjh0ry7I0atQojyHvbP7+/mrcuHGBrs2bZyZXcTy7RenHH3+Uw+FQ9+7dderUKT366KOKiopS
YGBgXquMEydO6O2331anTp1Uu3ZtBQcHq1KlSurWrVu+fVbz66N3MQYNGqSkpCTNmjXLZfnRo0e1
aNEidenSJd/XuzDXcHZ/wo8//lhNmzbNe+3uv/9+HT16tMiuDShOBD3AC99++60sy9Ltt99+UU3j
cnJy1KNHD40dO1b169dXjx49VLVqVUnOZmP33XefNm7cqDp16qhHjx5q1qyZEhIS1L9/f4+DBOQ2
9/nyyy916623KisrS927d1f16tU1c+ZMtWrVStu2bfNYlj179qhly5basGGDOnbsqOuuu06bNm1S
z549tWjRokJf47mSk5MlSZUqVXJbN2vWLDVr1kyTJ0/WFVdcodtuu01169bVtGnTdP3112vVqlUe
r/mXX35RTEyMtmzZoptvvlktW7bU2rVrdeutt2rixIkey5Gamqp27dpp0qRJatasmW677TaVL18+
b/3TTz+tW265RUuWLFHDhg112223KSAgQG+99ZZiYmLcfsEPGDBAjzzyiBITE9WqVSv16NFDtWvX
1vfff68PPvjAZdu0tDR16tRJDz/8sHbt2qVWrVqpc+fOOnTokP7xj3+oT58+Hq9TkuLj4/Xoo4+q
WrVquuWWWyRJH374oW677ba8bcPDwzVkyBBVrlxZlmWpT58+GjJkSN5XrtmzZ+uZZ57RkSNH1KRJ
E/Xq1UvVq1fXrFmzdMMNN7i87lWqVNGQIUMUGhoqy7Jcjnf77be7lNPTM7Ft2zY1a9ZM48ePV2ho
qHr37q3o6GjNmjVLrVu31vTp0z2+ThkZGercubM+/vhjtWzZUnFxcfrjjz/09NNPuzQNLohhw4bp
rrvu0ubNm9W2bVvdeuutOnTokJ599lnddNNNSktLy9t2yJAh+tvf/iZJql+/ft615i7LT8WKFRUc
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
eW5OdurUqXyn1Mg95rl9UM8n9+c/bdo0j38xz+1j07Zt2wIf0xv+/v6KjY2V5ByG/Vzbt2/Xli1b
FB4erqZNmxZLGc72yy+/yLKsC4bKwtyLLVu2VLly5bR8+XKdOnXK67J5eu84efKkFixYIMuyLlhL
WBi1atVS9erVdejQIa1du7ZAZbqQp556SsYYvfDCCzp+/HhRFLPQz0xhnO/ZLWm51+0pzKSnpxfp
XKsFZVmW7r77blWsWFE33HCDxz9OnO1ir8HTPXjo0CGtWLHC5f0FKK0IeoAXLMvS5MmTFRgYqH/+
85+Kj4/3GDSOHz+uHTt2FOoc0dHROnnypNsvmLfeekvLli07776rVq3SJ5984rLshRde0P79+9Wk
SZNi+bB2tvP9ZTR3gJaJEye6DEDw5JNPKjg4WE899ZTHsJeRkaHp06d77AuRlJSkf/zjHy7B6dtv
v9W0adMUEhLi9fxTzz//vLKzs9WrVy9t2bLFbf2JEyc0fvz4vP//8MMPmjlzpkvfzNztcj+45vY/
qlatmu655x7t2bNH/fr18zhx/O7duzVjxgyvyuxJ7oeanTt3uq2rX7++HA6HlixZ4hIi0tPTNWzY
sLwPRt4cMz/t27fXNddco7179+r55593WTdz5kzNnDlTERERuvvuuwt8TG89+uijMsZo5MiR2rNn
T97ypKQkPfLII5KkBx54wOMAOd74888/FRMTo+nTp7vdD8YYjR8/XnPmzJHD4ch34KGzeXsvBgYG
asSIEXl9fM++1lx//PGHpkyZ4rbcGKOpU6dqwYIFecuys7P1+OOPKzk5Wd26dcu3z+TFeuCBB2SM
0ZNPPunyXrpv3z69/PLLXh/vjjvuUJ8+fXTw4EHdcMMNHgdkkqTVq1cX+JiFfWYKozDPWXGpWbOm
goODtX79em3evDlveVZWlv7+979r//79PinXSy+9pCNHjuQ72fnZLuYajDH69NNPXe6hzMxMPfro
o0pPT1ffvn2LvRk0cLFougl46brrrtPixYt1++23a+zYsXr33XcVExOjatWqKS0tTb///ru2bNmi
rKwsNWzYUM2bN/fq+M8884wGDRqkfv366b///a9q1KihLVu2aOfOnXriiSf073//2+N+lmXpwQcf
1NChQ/XBBx+oXr162rp1q3788Udddtll+vTTT4vg6s/vfP0cmjRpoh49emjmzJl644038q6jXr16
+uKLLzRw4ED17t1b9evXV6NGjRQWFqYDBw5o06ZNSklJ0ebNm93+Kjtw4EDNnDlTy5YtU0xMjA4e
PJj3y/8///mP181q+vfvr59++kmjR49W8+bN1bRpU9WrV0/GGO3evVtbt25VRESEhg4dKsn5YbR3
794qV66cWrRooSpVqujUqVNasWKFkpKS1L17d5e+he+884727dunGTNmaP78+WratKlq1aql5OTk
vNqbHj16qFevXl6V+1zdu3fXxIkT1b9/f5eRST/66CNdccUVuvfeezV+/Hg1adJEcXFxCgkJ0cqV
K5WTk6MhQ4a4/bEg95jLly9XXFycOnTooLCwMFWsWPGCNdufffaZ4uLi9Nprr2nmzJlq2rSp9u/f
r++//14BAQH6+OOPvRrVVTr/fXau3r17a9iwYfrwww919dVXKy4uTqGhoVq2bJmOHTumVq1aadSo
UV6dPz/r16/X7bffrvDwcDVv3lzVqlXTmTNntH37du3du1cOh0OjR4++YC2E5P29KDknWN+5c6cm
T56sRo0aqVmzZqpTp44yMjK0c+dO/fTTT2rSpInbKIWWZen+++9Xly5d1LZtW1WtWlUJCQnas2eP
atSoof/85z9F8vPxZPjw4Zo3b57Wrl2revXqqUOHDkpPT9eSJUvUsWNHGWN06NAhr475+eef68EH
H9SECRPUrl07RUVFqUmTJgoNDdXhw4eVmJio33//Xf7+/urXr98Fj1fYZ6YwzvfslrTg4GD94x//
0JgxYxQbG6u4uDiVK1dOa9as0alTp/TAAw/o/fffL/FyeeNirsGyLN17772Ki4tTu3btVKlSJa1e
vVr79+9X3bp19eabb5bw1QDeo0YPKITWrVtr9+7deuedd3TjjTcqMTFRM2bM0OLFi5WUlKQ77rhD
M2fO1LZt2zwOt32+mq8BAwbkDdawZcsWzZ8/XzVq1NDSpUvVrVs3WZaV7/59+/bV3Llz8/r4HThw
QD179tTq1avzBio4txznK4u3/S8udLyRI0fK4XBo/PjxOnHiRN7y7t27a+vWrXr44YflcDi0aNEi
ffPNNzp69Ki6d++uadOmqXHjxm7Hq1+/vtasWaMmTZpowYIFWr9+vVq3bq2vv/7aYy3RhconSS+/
/LKWL1+uPn366PDhw5o9e7aWLVumnJwcPfzww5ozZ07etrGxsXr11VfVokULJSYm6quvvtLGjRvV
pEkTffLJJ/rqq69cjh0cHKxvv/1WEydOVGxsrHbs2KHp06dr48aNqlSpkl5++WW9/vrrHsudH0/X
1LNnT72zhg+gAAAgAElEQVT99tuqWbOmvv76a02YMMHlg+j777+vN998U3Xr1tWSJUu0atUqde7c
WRs2bFCtWrU8nu+xxx7T888/r4iICM2YMUMTJkwoUNO6q6++Wps2bdJ9992n5ORkTZ8+XYmJierV
q5e+//579e7du0DXVNCfhyf/93//p0mTJum6667TihUr9PXXX6ty5coaPXq0Fi9e7HEwioLcK2cr
V66c1q5dq1GjRqlly5bav3+/Zs2apcWLF8vf31933XWXVq1alTcSZ0HO5c29mHucTz/9VLNnz1bn
zp21d+9ezZgxQ99//71CQkIUHx+fb/+9p556Sp988olOnz6t2bNn68yZM7rrrru0du1aj7V53v58
zt7vbIGBgVq0aJFGjBih8PBwzZ07Vz/99JOGDx+uqVOn6vDhw17Xmvj7++ujjz7SunXrNGzYMAUH
B2vJkiWaPn26fvzxR9WvX18vvfSSdu3apdGjRxfo2grzzHi63gud50LPrjcK8hpdaJtXX31VH3zw
gRo3bqyVK1dq2bJlatWqldatW6errrqqUL8jvN3em308bX8x1zBy5EiNGzdOx44d0+zZs5WWlqah
Q4dq9erVqlSpklfXAviCZRhqCCjz7r77bk2aNElLly4ttv5OpcnEiRN19913a+TIkS4jfALwTocO
HbRixQrt2bPnvMPs+8LatWvVunVr3XLLLT7pD4ZLV8uWLbVp0yYdPXpUFSpU8HVxgEKjRg8AAPjM
Dz/84NYc99dff9WwYcMKPCE2AMAdffQAAIDP9O/fX3/++aeuueYaXX755dq/f782btyojIwM3Xbb
bQXqRwcAcEfQA1AmFbaPEABXvn6OHnvsMX355Zfatm2bTpw4oeDgYDVr1kyDBg3SsGHDfFo2XLp8
/VwARYE+egAAAABgM/TRAwAAAACbIegBAAAAgM0Q9AAAAADAZgh6AAAAAGAzBD0AAAAAsBmCHgAA
AADYDEEPAAAAAGyGoAcAAAAANkPQAwAAAACbIegBAAAAgM0Q9AAAAADAZgh6AAAAAGAzBD0AAAAA
sBmCHgAAAADYDEEPAAAAAGyGoAcAAAAANkPQAwAAAACbIegBAAAAgM0Q9AAAAADAZgh6AAAAAGAz
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
8Oy/Ji//PDlz0YCdcud7C8e9Z1zu/b97s/Gp7dH2asxtfe3njZ0b80r3K7uc69D64RnbUJ8xDVuz
4dkN/b5fR0fHkA4n+7UBAIOhrq+vb2DXfQeSVGdvVq9eveP3iRMn7vE9dVu3Jh/9aLJmTXVxyZ6e
Su0CobcrWfruZPQpyYeWDMgpFy1alPPPP3+X48f+/bEZecLIjG0YmzENYzK6YXTGNIx53e9jG0Zn
TMNvMvptj2dsQ3vGNDyUhkO6U1f37iTnpFJ5Z5qbL9vl3O3t7eIJADjomdGDGliwYMHrIi9JVq9e
nQULFmTmzJlv6RxdXcknPpE88ECyfHly2mlJUsMNnZ9ZmLz8dHLW4n06TV9fX+69997MmTMnS5cu
7fc5X3j/FzLz4pmpq6vb6ZHnkyx/9WtFkt8mGZlkapJPJTknyR8kSZqaktbWX7oMEgCgHxZjgRpY
s2bNHh3fWU9PMmNGsmxZsnhxctZZAzm6fvR2JY//UzJuejLmfXt1iq6urnzrW9/KaaedlpaWljz7
7LO56qqr+n3uhPdOeDXytiX5QaorZZ6a5PeSXJxkbZLPJLkvyW+SLE7yt9keedvNnj077Z/7XG6v
r097e3uuv/76vRo7AEBpzOhBDZx++un56le/2u/xN9PXl3zmM8miRdWvc8+txQh38vS/JJufST70
73v80o0bN+ZrX/tavvKVr+S5557LOeeckxUrVuTss89OXV1durq6dpp1+3Samh5MMivJPUk2Jzkm
1a0RWpN8JMnb3/L7N51ySpp6epJTT93jsQMAlMo9elAjO9+j1/SBprQ/1P6Gr+nrS664IvnSl5Jv
fjP55CdrPMgk6dmWLG1Mxp6enPXdt/yyp556KjfffHNuu+22dHV15cILL8xll12Wk08+eadnvpxK
ZX46OpansfGnaWp6LtW/MX0wybmpXo75vuz1BQbf+17ysY8lv/518va3HogAACUzowc1UqlUsmDB
glx+2eq8/+3vz8pFb35v3rXXViPvllsGKfKS5JlvJpvXJx/u/36639XX15cf/vCHmTt3bpYsWZKj
jjoqV1xxRS655JIcc8wx25+V5Mep3me3LMn9aWrqSlPTCUmmpRp3LUmOHJjxjxxZ/f7ii0IPAOBV
Qg9qaObMmfn+f34qv320+003TZ87N7nmmuS665JLLx2c8aVnW/L4rOT4jyejd56Je013d3cWL16c
OXPmZPXq1TnppJMyf/78XHTRRWloaEj1Prpv57WFVJ5PcniqQTc31Vm7E5PsvPjKANgeeps2Dfy5
AQAOUEIPamzCKXX55xX16d3Uvdvn3Hpr9ZLNz38+ufLKQRzc07clW36RTPivfh/etGlTvv71r+fm
m2/O+vXrM2XKlCxdujTnnfeRDBu2Jsl1qc7aPZjqTN6EJBelGnZnJjms9p9B6AEA7ELoQY1NmJD8
ZvOw/HJ9b/6wn8e/853k05+uzuLNmjWIA+t5JXliVvIH5yej3vu6h9atW5d58+bl1ltvTWdnZy64
4IJcfvkFOfXU/03yjSR/leTFJGNTXTzl71JdTOW4QfwArxo1qvpd6AEA7CD0oMYmTKh+f+Knw3YJ
vbvvTi66qPo1b16yy7ZytfTUgmTLc8nJV+84tHr16sydOzd33nlnjjzyyFx66Xn57GdH5bjj7k+y
MNUFU5qSXJ7qrN1pSeoHcdD9MKMHALALoQc1Nn580nBYXx5fW5c//53j99yTfPzjybRpyYIFybBB
2tWyUqmk48kn0vj8NWk684L0jGjMfyxZkrlz5+b+++/P+PFH5ctfflcuvviZjBixKNVZunOTfCHJ
2UnGDM5A36rDDkulvj4dK1em8V3vsmE6AECEHtRcfX3ynnf25YlnX5uua2+vBt7kyckddyTDB+l/
Yltb2+v2tDt78to884vfz1NPPZ8zzzw0ixcn06a9lPr6DyT561QD772pySIqA6TtyitzQ09Pcvvt
ye23p7W1NbNnz97fwwIA2K/soweD4JMf68lja/ry0Lr6/PiJukyeXL2kc9my5PDDB2cMlUolzc3N
uxw/++xk1qzjM3HiX6R6OeaHU10xc+jb3Wdqb283swcAHNQG6WIxGFoqlUoWLlyYSqUyKO834Y+S
J371YK774u2ZPLmSE09Mli4dvMhLko6Ojn6Pz5gxJxMnrkvy5STn5UCJvGT3n2l3xwEADhZCj4NO
W1tbmpubM2PGjDQ3N6etra3m77n6ic9nW8+kXHXtxXnhheZMmtS2Yw2RwdLY2Lib4x8c3IEMoN1/
pv6PAwAcLFy6yUFld5f6TZ7cntGjm9Lbm/T2Jn192fHzvh7bvLmSdeuGxuWFO9+j19bWluuvv35Q
xzDQSvxMAAD7ymIsHFR2d0nfhg0dOeKIptTVVVe/3P71Zr+/lec8+WRH1q3b9T1/9pOfDXrozZ49
O9OnT09HR0caGxuLuI+txM8EALCvzOhxUNkfi3fs7j1X/uPKnHXhWTn01ENTVz90V7UEAODA4x49
DipNTU1pbW193bG2traazgL1956t/9CaSR+alC3f35JN8zdl2+Pb4m8uAAAMFDN6HJQqlcqgX+rX
33t2/6o7W3+wNV1ru1J/TH0aWhoy/MThqaszwwcAwN4TejAEdP+iO50/6Ez3uu7Uj6tPw5SGHHL8
Ift7WAAAHKCEHgwRfX196X66O533dKbn+Z4MHz88DS0NeWj9QxYaAQBgjwg9GGL6+vrS9dOudP5P
Z67+9tWZd/+8HY+1trZm9uzZ+3F0AAAcCIQeDFHtD7Rn0hmTdj2+H/bfAwDgwGLVTRii1v58bb/H
d7cXIAAAbCf0YIhqbGzco+MAALCd0IMhan/s+QcAQBncowdD3P7Y8w8AgAOb0AMAACiMSzcBAAAK
I/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QA
AAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAK
I/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QA
AAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAK
I/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QA
AAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAK
I/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QA
AAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAK
I/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QA
AAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAK
I/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QA
AAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAK
I/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QA
AAAKI/QAAAAKI/QAAAAKI/QAAAAKI/QAAAAK8//iZmEttFEAIgAAAABJRU5ErkJggg==" alt="png" /></p>
<p>This graph representation obviously doesn’t capture all the trails’ bends and squiggles, however not to worry: these are accurately captured in the edge <code class="highlighter-rouge">distance</code> attribute which is used for
computation. The visual does capture distance between nodes (trail intersections) as the crow flies, which appears to be a decent approximation.</p>
<h2 id="overview-of-cpp-algorithm">Overview of CPP Algorithm</h2>
<p>OK, so now that you’ve defined some terms and created the graph, how do you find the shortest path through it?</p>
<p>Solving the Chinese Postman Problem is quite simple conceptually:</p>
<ol>
<li>
<p>Find all nodes with odd degree (very easy).<br />
<em>(Find all trail intersections where the number of trails touching that intersection is an odd number)</em>
<br /></p>
</li>
<li>
<p>Add edges to the graph such that all nodes of odd degree are made even. These added edges must be duplicates from the original graph (we’ll assume no bushwhacking for this problem). The set of
edges added should sum to the minimum distance possible (hard…np-hard to be precise).<br />
<em>(In simpler terms, minimize the amount of double backing on a route that hits every trail)</em>
<br /></p>
</li>
<li>
<p>Given a starting point, find the Eulerian tour over the augmented dataset (moderately easy).<br />
<em>(Once we know which trails we’ll be double backing on, actually calculate the route from beginning to end)</em></p>
</li>
</ol>
<h2 id="assumptions-and-simplifications">Assumptions and Simplifications</h2>
<p>While a shorter and more precise path could be generated by relaxing the assumptions below, this would add complexity beyond the scope of this tutorial which focuses on the CPP.</p>
<p><strong>Assumption 1: Required trails only</strong></p>
<p>As you can see from the trail map above, there are roads along the borders of the park that could be used to connect trails, particularly the red trails. There are also some trails (Horseshoe and
unmarked blazes) which are not required per the <a href="http://www.sgpa.org/hikes/MasterLog.pdf">Giantmaster log</a>, but could be helpful to prevent lengthy double backing. The inclusion of optional trails is actually an established variant of the
CPP called the <a href="https://en.wikipedia.org/wiki/Route_inspection_problem#Variants">Rural Postman Problem</a>. We ignore optional trails in this tutorial and focus on required trails only.</p>
<p><strong>Assumption 2: Uphill == downhill</strong></p>
<p>The CPP assumes that the cost of walking a trail is equivalent to its distance, regardless of which direction it is walked. However, some of these trails are rather hilly and will require more energy
to walk up than down. Some metric that combines both distance and elevation change over a directed graph could be incorporated into an extension of the CPP called the <a href="https://en.wikipedia.org/wiki/Route_inspection_problem#Windy_postman_problem">Windy Postman Problem</a>.</p>
<p><strong>Assumption 3: No parallel edges (trails)</strong></p>
<p>While possible, the inclusion of parallel edges (multiple trails connecting the same two nodes) adds complexity to computation. Luckily this only occurs twice here (Blue <=> Red Diamond and Blue <=>
Tower Trail). This is addressed by a bit of a hack to the edge list: duplicate nodes are included with a <em>_dupe</em> suffix to capture every trail while maintaining uniqueness in the edges. The CPP
implementation in the <a href="https://github.com/brooksandrew/postman_problems">postman_problems</a> package I wrote robustly handles parallel edges in a more elegant way if you’d like to solve the CPP on your own graph with many parallel edges.</p>
<h2 id="cpp-step-1-find-nodes-of-odd-degree">CPP Step 1: Find Nodes of Odd Degree</h2>
<p>This is a pretty straightforward counting computation. You see that 36 of the 76 nodes have odd degree. These are mostly the dead-end trails (degree 1) and intersections of 3 trails. There are a
handful of degree 5 nodes.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Calculate list of nodes with odd degree</span>
<span class="c"># nodes_odd_degree = [v for v, d in g.degree_iter() if d % 2 == 1] # deprecated after NX 1.11</span>
<span class="n">nodes_odd_degree</span> <span class="o">=</span> <span class="p">[</span><span class="n">v</span> <span class="k">for</span> <span class="n">v</span><span class="p">,</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">g</span><span class="o">.</span><span class="n">degree</span><span class="p">()</span> <span class="k">if</span> <span class="n">d</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">]</span>
<span class="c"># Preview</span>
<span class="n">nodes_odd_degree</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">5</span><span class="p">]</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>['v_end_west',
'rt_end_north',
'rh_end_north',
'rh_end_tt_1',
'o_y_tt_end_west']
</code></pre></div></div>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Counts</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of nodes of odd degree: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">nodes_odd_degree</span><span class="p">)))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of total nodes: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">nodes</span><span class="p">())))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Number of nodes of odd degree: 36
Number of total nodes: 77
</code></pre></div></div>
<h2 id="cpp-step-2-find-min-distance-pairs">CPP Step 2: Find Min Distance Pairs</h2>
<p>This is really the meat of the problem. You’ll break it down into 5 parts:</p>
<ol>
<li>Compute all possible pairs of odd degree nodes.</li>
<li>Compute the shortest path between each node pair calculated in <strong>1.</strong></li>
<li>Create a <a href="https://en.wikipedia.org/wiki/Complete_graph">complete graph</a> connecting every node pair in <strong>1.</strong> with shortest path distance attributes calculated in <strong>2.</strong></li>
<li>Compute a <a href="https://en.wikipedia.org/wiki/Matching_(graph_theory)">minimum weight matching</a> of the graph calculated in <strong>3.</strong> <br />
<em>(This boils down to determining how to pair the odd nodes such that the sum of the distance between the pairs is as small as possible).</em></li>
<li>Augment the original graph with the shortest paths between the node pairs calculated in <strong>4.</strong></li>
</ol>
<h3 id="step-21-compute-node-pairs">Step 2.1: Compute Node Pairs</h3>
<p>You use the <code class="highlighter-rouge">itertools combination</code> function to compute all possible pairs of the odd degree nodes. Your graph is undirected, so we don’t care about order: For example, <code class="highlighter-rouge">(a,b) == (b,a)</code>.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Compute all pairs of odd nodes. in a list of tuples</span>
<span class="n">odd_node_pairs</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">itertools</span><span class="o">.</span><span class="n">combinations</span><span class="p">(</span><span class="n">nodes_odd_degree</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="c"># Preview pairs of odd degree nodes</span>
<span class="n">odd_node_pairs</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">10</span><span class="p">]</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[('v_end_west', 'rt_end_north'),
('v_end_west', 'rh_end_north'),
('v_end_west', 'rh_end_tt_1'),
('v_end_west', 'o_y_tt_end_west'),
('v_end_west', 'b_v'),
('v_end_west', 'y_gy2'),
('v_end_west', 'nature_end_west'),
('v_end_west', 'y_rh'),
('v_end_west', 'g_gy2'),
('v_end_west', 'b_bv')]
</code></pre></div></div>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Counts</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of pairs: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">odd_node_pairs</span><span class="p">)))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Number of pairs: 630
</code></pre></div></div>
<p>Let’s confirm that this number of pairs is correct with a the combinatoric below. Luckily, you only have 630 pairs to worry about. Your computation time to solve this CPP example is trivial (a
couple seconds).</p>
<p>However, if you had 3,600 odd node pairs instead, you’d have ~6.5 million pairs to optimize. That’s a ~10,000x increase in output given a 100x increase in input size.</p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"></script>
<script type="math/tex; mode=display">\#\;of\;pairs = n\;choose\;r = {n \choose r} = \frac{n!}{r!(n-r)!} = \frac{36!}{2! (36-2)!} = 630</script>
<h3 id="step-22-compute-shortest-paths-between-node-pairs">Step 2.2: Compute Shortest Paths between Node Pairs</h3>
<p>This is the first step that involves some real computation. Luckily <code class="highlighter-rouge">networkx</code> has a convenient implementation of <a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">Dijkstra’s algorithm</a> to compute the shortest path between two nodes. You apply
this function to every pair (all 630) calculated above in <code class="highlighter-rouge">odd_node_pairs</code>.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">get_shortest_paths_distances</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">pairs</span><span class="p">,</span> <span class="n">edge_weight_name</span><span class="p">):</span>
<span class="s">"""Compute shortest distance between each pair of nodes in a graph. Return a dictionary keyed on node pairs (tuples)."""</span>
<span class="n">distances</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="n">pairs</span><span class="p">:</span>
<span class="n">distances</span><span class="p">[</span><span class="n">pair</span><span class="p">]</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">dijkstra_path_length</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">weight</span><span class="o">=</span><span class="n">edge_weight_name</span><span class="p">)</span>
<span class="k">return</span> <span class="n">distances</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Compute shortest paths. Return a dictionary with node pairs keys and a single value equal to shortest path distance.</span>
<span class="n">odd_node_pairs_shortest_paths</span> <span class="o">=</span> <span class="n">get_shortest_paths_distances</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">odd_node_pairs</span><span class="p">,</span> <span class="s">'distance'</span><span class="p">)</span>
<span class="c"># Preview with a bit of hack (there is no head/slice method for dictionaries).</span>
<span class="nb">dict</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">odd_node_pairs_shortest_paths</span><span class="o">.</span><span class="n">items</span><span class="p">())[</span><span class="mi">0</span><span class="p">:</span><span class="mi">10</span><span class="p">])</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{('b_bv', 'rs_end_north'): 0.8999999999999999,
('b_v', 'rh_end_tt_3'): 0.6500000000000001,
('g_gy2', 'b_bw'): 1.73,
('o_y_tt_end_west', 'rh_end_tt_4'): 0.35,
('rd_end_north', 'g_gy1'): 1.37,
('rd_end_south', 'b_tt_3'): 1.1300000000000001,
('rd_end_south', 'g_gy1'): 1.3,
('rh_end_tt_1', 'rd_end_south'): 0.6000000000000001,
('rt_end_north', 'rd_end_south'): 1.31,
('v_end_west', 'b_end_west'): 0.45}
</code></pre></div></div>
<h3 id="step-23-create-complete-graph">Step 2.3: Create Complete Graph</h3>
<p>A <a href="https://en.wikipedia.org/wiki/Complete_graph">complete graph</a> is simply a graph where every node is connected to every other node by a unique edge.</p>
<p>Here’s a basic example from Wikipedia of a 7 node complete graph with 21 (7 choose 2) edges:</p>
<p><img src="fig/png/148px-Complete_graph_K7.png" alt="title" /></p>
<p>The graph you create below has 36 nodes and 630 edges with their corresponding edge weight (distance).</p>
<p><code class="highlighter-rouge">create_complete_graph</code> is defined to calculate it. The <code class="highlighter-rouge">flip_weights</code> parameter is used to transform the <code class="highlighter-rouge">distance</code> to the <code class="highlighter-rouge">weight</code> attribute where smaller numbers reflect large distances and high
numbers reflect short distances. This sounds a little counter intuitive, but is necessary for Step <strong>2.4</strong> where you calculate the minimum weight matching on the complete graph.</p>
<p>Ideally you’d calculate the minimum weight matching directly, but NetworkX only implements a <code class="highlighter-rouge">max_weight_matching</code> function which maximizes, rather than minimizes edge weight. We hack this a bit by
negating (multiplying by -1) the <code class="highlighter-rouge">distance</code> attribute to get <code class="highlighter-rouge">weight</code>. This ensures that order and scale by distance are preserved, but reversed.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">create_complete_graph</span><span class="p">(</span><span class="n">pair_weights</span><span class="p">,</span> <span class="n">flip_weights</span><span class="o">=</span><span class="bp">True</span><span class="p">):</span>
<span class="s">"""
Create a completely connected graph using a list of vertex pairs and the shortest path distances between them
Parameters:
pair_weights: list[tuple] from the output of get_shortest_paths_distances
flip_weights: Boolean. Should we negate the edge attribute in pair_weights?
"""</span>
<span class="n">g</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">Graph</span><span class="p">()</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">pair_weights</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">wt_i</span> <span class="o">=</span> <span class="o">-</span> <span class="n">v</span> <span class="k">if</span> <span class="n">flip_weights</span> <span class="k">else</span> <span class="n">v</span>
<span class="c"># g.add_edge(k[0], k[1], {'distance': v, 'weight': wt_i}) # deprecated after NX 1.11 </span>
<span class="n">g</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">k</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">k</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="o">**</span><span class="p">{</span><span class="s">'distance'</span><span class="p">:</span> <span class="n">v</span><span class="p">,</span> <span class="s">'weight'</span><span class="p">:</span> <span class="n">wt_i</span><span class="p">})</span>
<span class="k">return</span> <span class="n">g</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Generate the complete graph</span>
<span class="n">g_odd_complete</span> <span class="o">=</span> <span class="n">create_complete_graph</span><span class="p">(</span><span class="n">odd_node_pairs_shortest_paths</span><span class="p">,</span> <span class="n">flip_weights</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="c"># Counts</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of nodes: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g_odd_complete</span><span class="o">.</span><span class="n">nodes</span><span class="p">())))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of edges: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g_odd_complete</span><span class="o">.</span><span class="n">edges</span><span class="p">())))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Number of nodes: 36
Number of edges: 630
</code></pre></div></div>
<p>For a visual prop, the fully connected graph of odd degree node pairs is plotted below. Note that you preserve the X, Y coordinates of each node, but the edges do not necessarily represent actual
trails. For example, two nodes could be connected by a single edge in this graph, but the shortest path between them could be 5 hops through even degree nodes (not shown here).</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Plot the complete graph of odd-degree nodes</span>
<span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
<span class="n">pos_random</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">random_layout</span><span class="p">(</span><span class="n">g_odd_complete</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_nodes</span><span class="p">(</span><span class="n">g_odd_complete</span><span class="p">,</span> <span class="n">node_positions</span><span class="p">,</span> <span class="n">node_size</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">node_color</span><span class="o">=</span><span class="s">"red"</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g_odd_complete</span><span class="p">,</span> <span class="n">node_positions</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.1</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s">'off'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s">'Complete Graph of Odd-degree Nodes'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></code></pre></figure>
<p><img src="data:image/png;base64,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
ACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSM
hRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBC
CCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGE
ACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSM
hRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBC
CCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGE
ACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSM
hRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBC
CCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGE
ACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSM
hRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBC
CCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGEACSMhRBCCCGE
ACSMhRBCCCGEAKDjQg9ACCHE4cLMbgaeAdyfUrrvQo9HCCEycoyFEEKcF8xsrNPs/cA9wPuAezvN
3m9moxd4aEIIAUgYCyGEOE90wJ/2w4vfCjwKvBXohxd3wH+5wEMTQggALKV0occghBDiMifCJ+55
K/DS0vS3Ai/zX29WWIUQ4kIjx1gIIcSBYmZtwJcBvKAy74XFrzeevxEJIURtJIyFEEIcCGbWZmZD
eKJdH8AdlWU+Uvz60HkbmBBC1EFVKYQQQuwrZtYO9AOjwBAwBjy3DZZfCT0Jd4o/ArwKNtrhjg2Y
MbP+lNLChRu5EOKwoxhjIYQQ+0II4oHSC2AY+Drg5UBbO6xvwJfkddrh7zbgu4BNXEyvANMppY3z
OXYhhAA5xkIIIfZISRD3AT1AO7AMHAG+FPhmIAF/vQFvw13krwTu3YBP4UI4mdkyMAIcN7OZlNLi
+T8aIcRhRsJYCCHErghBPAj04mK4HXd8DQ+feAbuFh8BPgf8PTAHPBk/l4EuXFAvpJRWzOwM7jKP
mFkvco+FEOcRJd8JIYTYEWbWYWYjwAncIQYPhVgCNoCjwFXA1wI3AI8Df4sn2K0Aq8AaLqA3gAEz
M4DkTANncfPmmJn1nadDE0IcciSMhRBCtERJEB/HBfEKHiIB7gB3ACdxx/c5wK3ANPAx4F5cOG/i
wngdF8XruNPcW95XSmkFGI99jJjZWDjUQghxYEgYCyGEaEgI4lFcEHfjIng1fl/H3d0x4Bj+ufKV
wC2x+heAL+LhE2ux/Gb8nnBRvESRrHeOlNJmSmkKmMRDLo5FeIUQQhwIijEWQghREzProIgh3gBm
8PCHQVzUTuEi95pYZgV4PnAT7ig/DHwWF8XLsdnVWHcj1u3ARXKvmfWmlJaq40gpLZdij0dLsceb
+3/UQojDjBxjIYQQWzCzTjMbwx3iLjwcYhJPkhsCFoEz+GfIDbhzPA88G7g5llnAK048jYdELFKI
4E3cOc7kpL3BemMqucdTMabjZtZTb3khhNgNEsZCCCGALYL4GNCJC+Lx+P1YLDaRUprBxe91uPM7
DXw5Lor78c+WzwKncWG8jgtiKIRxip8buLs8B3Q0E7vhKJ/BnecxMxuNltNCCLFnFEohhBCHHDPr
wmN8e3ARO43H/fZQxA3PppTmo83zMeAK3CVeoBDFuZbxw8BdMX8CF8BtuBguO8Wb8WqnSMobpAi7
qEmEUExGSMUw7h5Pp5QarieEEM2QMBZCiENKCOJBiiS6qZTSUlR/GIvpy8BMSmkjYo6P43WJp3FR
fDtwGy6Ie3Hn9xO4M/w4Lnrncdd5PUW7VTMrO8btFEl9R8ysO6pSNCTGuoqL4zEzW8QFvGKPhRC7
QsJYCCEOGQ0EsZnZQMzbBCazC2tm3Xjd4iE8vGIJeBbe3rkbF74Ad+NVKhLuFvfFsn0U4RTE9sE/
h1aA7pTSgpmt4c5zU2EMEM0/JqPW8TDQHe5xS+sLIUQZCWMhhDgkhLgdwIXsGiGIY14X3o65A3d4
50rubj8uinuBp3DRegvuFHdSdK97GvgMHmf8UMxbxkVyJ56Al8lxxu24OO+LJh9zuPvblVJabfXY
UkqLZrYSx3Ak3OOZfAxCCNEKEsZCCHGZE4J4EBewa2x1gttwF7gPj/EdTymtxTwjYnhjU4/jIvYm
XBj34MJ2AA+r+GQst4wL6BFc6GY3uSx0cygF8dOArijNth7bnNzJcYZ7fDaE/BByj4UQO0TCWAgh
LlMaCeKYn5PXDHdXF0rz2oBRPPluFa8EkfDybDfirvAmLqgT8AAunI8Aj+CfL5u4u5xbOlcT76o/
u2P5ObxecWcW6TshQjKWKdzjBTz2WO6xEKIhEsZCCHGZESXPBnBBvAqcLbumkUQ3jAvRJVw0blTm
H8WF8QIeU2x4I4/rY911XHT34aL50xQC/Ak8eW8ppZTMrBNYqwjTcnOPc3HGcC6pbiiOYWo356CG
e9xjZlM7Cc8QQhw+VPtRCCEuE8ysJ0qpjcWksymliSyKI7luEHeBO2L+VEUU9+DxxGN4p7unY9Yp
XBgfx0VsLy6KF/C2z/O4AH0cF9FtFDHFnWxNvAN3mdtwgZ1jkTtLNYnn8G54ezJwwgUfx6tfHDWz
oQgREUKIbcgxFkKIS5wQs4O4wNzmEMcy3bjT246L2blqaEFUpBjDBe/ZeHUAVwJXx88FPIyiO1Z7
CK9bPEARW9yPl2ZbCxHawdbEOyjiitdj+Tzenlh2KY5pAC8Nt2tSSuvARKniRk/EHss9FkJsQcJY
CCEuUSJGeJAiFGGiKvbCgR3GHd5VPM54vbJMTrIbwcV1FsVdwEncLT6Ji1XDhWwPnhx3Jy6IrwAe
xIVu7mRHjM3Y7hjnph95ev69G1iMEIx5YNjM5squ9m6JBiXLeIjI0dj+tgcEIcThRcJYCCEuMWoI
4pruZ9T2HYq30ymlqmubhfNYabmzeFxvFx5ScQUePpHbOl+JC90VXBRP4YJ6GW8B3RPzl2J7uSJF
LWGcHeO8XDlRD9w5zq7xTJ3TsSPioWC84h5P7SbJTwhx+SFhLIQQlwgVQbxMfUHcgYvVLlxc1uwG
F0lxY7HNtdjeTNQ0PhGvoxS1ja+M5fpwd/ipeD8CPJhSWo2kuZWSw9tFqeNdifzeKBLxloGBXI0i
XOOFmDa/H67xuZ27e5zrHh8zszlgXu6xEIcbCWMhhLiIiTCHXtw1zeKxpsMZy2aHdZ0ascalZXvw
kIJ+CpE9H6I4t30eoagMcQQXs/3x/v74eQJ3h0+HIO9iayWJHPdcJQv17Bpn8Z1w1zkf30KMoR+Y
rXOadkXEQE/E9suxx3KPhTikSBgLIcRFSEkQD+IJc3UFcSzfjQvZNjy+t677GWEEw7gAXcBF8VI4
yEcpRPFRvK1zT4ylHReu9+AiNccvZ7d4MObn5iH1Eu+gEMbnYovDIc5l2+YAUkqb4Rr3h2u8zfne
C3GO5qqxxymluSarCiEuQySMhRDiIiLEZB/uYrbjbux8A0HcjscH9+IxujPV5LrKtkdw97UTF8WT
IWpz7eIxXOwew8ucJdwVXsZF+oN4HPIscBUues/ELvqI2sXxvl7iHRShFLlkW24JvYIn3FlpO/Mx
5n6KpL59JdzjcfwYB8NRn6p3LoUQlycSxkIIcRFQRxDPNRJmpeYVCRdxSw2Wbccd0V6KGsNnU0rr
IYqP4aJ5JH6fxcXwjbiAHsFDJB6Mn50x1odDWHfHuMvucL3EO9geSmEUznhuPrIM51zjRQrX+EDi
gGO7s6WueceiIsb8QexPCHHxIWEshBAXkF0K4k6K0mp1k+sqy4/h8b9QiOLNEMxHcDE6jIvnZVwY
X4M7uJ24cL0r5i3gHfDKbnEvsFFJBuykduIdETaRm3zkOOiOlNKyma1TEsbBfJyn/vj9wAihn93j
oXCPp+UeC3H5I2EshBAXgBDE/bggzg7ufBNBXE2u21a3uMY6vRQiejP2MxXCtB0PnxjGnedhXACP
465xDrc4CtyHC9JJimS47BbneOiqYK3V8a5MAtpCoG9SdMBbweOaz5VoSyltmNkSXqFi4aCrR9Rx
j2ejk54Q4jJFwlgIIc4jdQRx0wYW4VoOxzqzQFNxGMlwOXlvPdaZiXllp7gvXt14LeK+mDeNl2ib
wDvcLeEVJq6JcU/ErnLt4mqSXSdFPeNa5FrGUFSmABfG/WbWUXlQyK5xbkV94JTc4yE89rkXf7DY
t9JxQoiLBwljIYQ4D1QEcRaRTWvzhoDNFSSW8eS6ZuvkJLtcSWIDD7eYj/ltuPAdiu0Oxj7GcbF6
Cndre+P9XUQcM0UXvUdLpeD6gNXyuCJ8o17iXSZ3vyOWy6EeK7G/booGIEQ8dHaNF89XzeHYz0zJ
PT4u91iIyxMJYyGEOEBChOaKCi0L4lg319fdpElyXWmddjyeOCe+rRPl2ErjORLb7Yqfo3iIxCxw
Ky7A13Bn+C7c9Z2JcRzD3drx0v66cXe5TKPEu0yOMc7j7INz8cersd2q+JzD6yz3UrsM3IGRUlox
szMU7nEzPlUeAAAgAElEQVSOPZZ7LMRlgoSxEEIcACVBPBCTdiKIu3BnNsf4zrbijsZ6oxRic5Mo
xxbzDRfNOdEvV6GYw4XuDbHuNHAdHlbxcGxnFo817gYeK7nFvbjArYr2uol3JcqO8XoMMYdPrOBl
08pl27JrvBzHcF6Fcey/lns8U6vdthDi0kPCWAgh9pEQxDk5DVzYttSYItYdjHXXgPFWu7CVkuxS
vDaJcmwx33CnOIvi0fh9FXgSOIk7odMxbxNv5NGBi+aOWL8cWwzu8i7XEMDNEu+gaAUNRchER/y+
EuPpoqhakZnDk+F6W3HRD4Jwj3Ps8Uicf7nHQlziSBgLIcQ+sBdBHOv3UlSFmNlJ/GopyW6DomHG
2bzvklPcH/PHcKfXgEdwQX0CD5dYx53hu+MYlnEhehIXqY9ntzgc6g5K1SNK5AoTjTjnGEfViXOV
KaLhxibuUG8RxjFvBT/fF0QYxzg2gelwj4dxsT5zocS6EGLvSBgLIcQeqCGI5/HqD60K4hzSkOv2
Nk2uK61ruLvbg7uzWYxOZQe3Ioqza9wZ6zyGi90riQ57wM3A08ADsdwsLqJHcKFcdotz7eItwjUa
hjRLvIOtMcawtTIFcSzdddadB46YWU9KqZkAP1Ci9vIqUQe65B7va/tqIcTBI2EshBC7IATtAB5K
kNi5IM5VKnJy3eROBF4pya4DD4foolSOrbSP0RgjuCjO4RrjuPC8mXCp8aS2DeBeXJDO4KETV+Mi
ebzkFufaxbVia1tJvIOt5drAhXFn6f0K3iq6vfqwEKEMq/g1uKDCOMazCUxF1Yxy7LHcYyEuISSM
hRBiB+xVEMc2unDx1BHrz+2k9FisPxb7X8dF8blybCVyybbsGrfhMbGzuCt8M+4cT8Xyx/AqFAsU
CXeDsc4ScLa07R6KOsxVuvDEu2bnJId6tMWyazHeTHaiu+vsZx4YM7Puqmt9oQj3+AyFe9yDfwsg
91iISwAJYyGEaIEagniOFppsVLaRhWkf7vK2nFxX2kYfLrrWYxyd1CjlZmYjsZ+2WD7XQ17DwyRu
iLEs4qL3NjwJ7/5YbzL2kQX8mYr47MVrF9fq1NdK4h0xfmKMm1QqU0RHvDXqCOMQoWv4dbkohDFs
cY9z7PFxM5u+0CEfQojmSBgLIUQDQhAP4mJxk10I4thOHy5EYYfJdaVtDFGEDnTgYvdstS20mQ1T
JNr140J1ABeidwFX4A7yBu4WX4UL9XtwJ3gBD6PIraKXcaGct99GpWVzhVYS7yAcY7Z2v4OiMgWx
nX7qM487s13N2mOfb1JKS5EkOII720vIPRbiokbCWAghahAJZNkhzmEFuxHEHbjA7CYaZexUGFWS
7BYpEtImqo5tRRR3U7R67sIrTYzgwrgNr1Pci8cefwEXxJ242Cw7zVW3OLvm2+Jnd5B4B4Uwrlam
KH825XrGnbXc9RCfg/i1mqzOv9DEtZ4sVR3JlSvkHgtxESJhLIQQJULYDRIVF4gEtF0IYsPF2kBs
5+xu4mDDsT6CC9S52N6WcmylZYcoRHFuEpJd40dxwXol/r9/Fhe3N+Dxxo/EMc/HfnLN4xW2C85e
YKWOwG818Q62hlJkqgl4a7FcrrxRi3m8lnBN8XwxEAJ+lcI9XsTjwuUeC3ERIWEshBDsnyCObXVT
uK3zeD3j3WwnJ9ltxnYGqZRjKy2bXdM2iiQ7KCpQnKVItlvDxe91uPC9m6KRxizuMA/Fdra4xWbW
iQvXuTrD7sRLuDUVfBFDDA0qU0R76JUYU719LsVxDlAkEl50RGWNs6U48e6IPb5o4qOFOOxIGAsh
DjUh9AbYH0Gcww968ZjdyTrJaa1sqw93F1dwITtIpRxbadmBmG8UFSgSflzzwIPAM+O9AWdi+WHg
i3gIRTewFM7mcYoEwenK7npxoV5PzHXFeq1SbgsNLox7K8usAMOl6hVbCPE8H8vM7facny9SSoul
2OMjZtZy228hxMEiYSyEOJSEIB7EHdQNXAAu7VacVJLrplNKtcqLtbqtHCe8gIvGAWqXY8PM+mO/
uVlGbgud6yN/Ebgej1HOccVtMW0cD7HoIZqLxHHkttFny7GwER7SR+Pz1GriXaba5GMtdlWuXZyr
O3Q12PYihWtcFfMXHSX3OF+/HrnHQlx4JIyFEIeKiiBeZ++CuJNCtO0pbjQc51Hcvc0hDV3UKMcW
y+ev5DcpyrG1x3qdwGfwVs5HcKd4Hndzb4ifX8A/BzZxEb5BUYFjje1hCd3Ur12808S7TC3HmBj/
BpxLylun6A64jZJrPBiucUvdAy80KaWFKOs2itxjIS44EsZCiENBxOsOUAjimmJzB9szCodyHa8Q
setyYSEqcxOOqdh2GzXKscXyuU3zBi6Gh/D/6Tnp705c4J7ARWbCk+iO4QL6LjxEIbuwc7F8jlOe
qFE5oRdYa5DgtpPEu8yW7nchghPbP59WaFwiDlzc54THRstdVISInyi5xzn2+KIqPyfEYUDCWAhx
WROCeBB3G/csiGObPRQVH+bYZXJdaXvduGO4iTvYwzFrWzm2WL43ls+ieAA/vg1c+D6Iu7o52a4d
eDyWuQpPxHsYF7rruDsNhZO+RiUcoVS7uF4CHOwg8a5E1TEm9l9LGPfn5h+1NhSu8QIwEK7xJVXx
IdzjHHt8NBzwHXVFFELsDQljIcRlSUUQr7E/gjg7s724UJvZa6JXuITDsb0FXPDWLMcWy/eUlmmP
sfTF+ieBp3ARfGtM78CT7Qy4BhfPn6Vwd5dLtYBzp7yzddxio04YRdBqx7sy1Rhj2F6yDfz4EsUD
Tj3KrvFsg+UuSuJ+miglVPbIPRbi/CFhLIS4rAj3dRAPEVjDK0PsuZlCJcltP0S2xfZykt0aHkpR
sxxbrJOd5XVcTPbgAnAJD5mYw7vX3UhRbm0hXlfg5+XO2FcWmDPhBucwk21ucdCLi+hGLmxn7Gsn
bAmlCLZVpgg3eDXGXXcfUQJuAXeX5y811ziTUpovxR7LPRbiPCFhLIS4LDhAQdyJf7WdRd+ev6Kv
JNlN487vCHXKscU63bhwzk5xjplewZPr1oHPA6di24YL46dxkXwKjzF+mKI03XxKaT2qYGS3eNt5
i/jnLhrUCA43vY2dlWqD+qEU1coUUHTBsyYCcR5/4OincejHRU24x+OlGtU9ZjZ1sTYxEeJyQMJY
CHFJUxHEuXbwfgjisqO7xh6T60rbLSfZncUFaS91yrHFOrnRR3aKczOS9RhfrkAxgDvHuTLFY/Hz
alwI/zPuCmcBOxeCNodc5CodVXJb7EbntSt+7lcoBZQqUwQr+DXJzUhqb9Bd40UK1/iSdllTSnPh
Ho/gLaX3HNcuhKiNhLEQ4pIkYm0HcfG0yi5bLjfYdk6um8Wd3D2LkEqS3QRFmbe6oRnhWGdHGPz/
dk7Os/j9C7iAvCbmd+OiewM4jovnu3DR2hXTZyM8IXf721a3uEQvzUva7SbxDvxcUHaB61WmSCmt
mdlGHF+za112jWs+cFxKxLFP4A8/5dhjucdC7CMSxkKIS4oDFsS5FvC5hhf7VQ+3lGS3jJcSO0KD
cmyxThbFWfzk8IlcK/gq4H48ROIWigoUSzHtCJ6QN4VXqujHHdqVSLjroHCLc9e/6hi6S9tsxG4S
7yCEMX4uyud6ndqfUbk9dENCXGfXeF8ebC40cQzZPc6xx3P1vmkQQuwcCWMhxCVBlCgbwAXYCvsU
2hDbNlw05m5x+xKOUdp2juGdxwXm0ZhdsxxbrNeBC9ssFrtijN143Ox1wJN457ob8XOTXdbHY9mT
sf6nY/8Wy2QBPISL6Q7qu8V9wHoL53o3iXfEeGC7MK5Vsg382vfViD+uxTw+/r5dju2iJNzjcfx+
HYq/jamLvRW2EJcCEsZCiIua+NAfxP9f7asgju134cI1C7t96zoWSXZjse1pXPgdpUE5tlgvi+LN
WKc7Xn24+3t9/LyXItluAxfHT+Hnaize3x3764rtLUTCXRceIpEFaS232HDh3NCRLCXe7cUxblqZ
IsjfDnTTuHQccZxL+Hm4bIQxnHOPZ6uxx3KPhdgb1YQHIYS4KDCzXjM7TlGebCKlVDfsYBfbb4tq
DNm9HU8pzeyjKO7Am2104PG+4GI3i/t6org9lkt4qEgPLmqH8PCIq/BwjDvxB4YTsWyu27uAC/0T
sfz9FKEHmxRVGoZwwZ5jnOvFFjerXQy763iXKYdSlFknKlOUJ8Z5y+XmWmEeaI8HrMuO+HsYx6/7
kJkdjXtPCLEL9McjhLhoCIcyh0x0UNT03dcEoxBJw7jom0kp7aubWGnCMYk7vYM0KMcW67VTCPUV
PBwil3abwhPp2oHPUTTsaKOo0vA07hQfj23kShW5JFpOuOvBhWWuRFGvEUYvHo/cLGShC0+82008
djmUoky+5jn+ucwyfm6ab9zDDpbx87+n2tMXK3Xc49n9vq+FOAzIMRZCXHDM6cMF3Qgu1sZTSpP7
KYrNrMPMjuBCcwU4cwCieAAXpyt45YkhXJTNNhHFbbhTDO7Q5kS5MTwMI1cjuDPmPwMXt4aL5Sdx
AT4cy92DO845RGGlVPkiJy924Q8G29ziEOndtCYmd5t4l0XdtpJtIbIT2zvggZ/btkhObIV5oCMe
CC5bSu7xIjAc7nF7k9WEECXkGAshLhjhEPfhoi9XPpg/AIfYKNoE72tyXWUf5SS7eVzUNizHFutm
UWzEV+IxzmPxvgt/aLgvpXTWzK7HhfNm/ByniF8+jrvL91PEHrcTMcThlnfFtEZucR8uTFsVxnt5
wKjV/Q7qV6ZYw8eWO/U1JKW0amYr+APBvl73i4140JgpucfH5R4L0ToSxkKI804dQTx3EFn1kWQ2
gv+/O5C2upUkuyncqT1Kk3JspXWP4OdhDhfX67goXolt3YhXmnjCzE5QlHAbjnUm8Zjio7jA/BRF
A5B2ig53uWnJuVrHDQR7K7WL95p4l6nV/Q7qCOMIB8ll21rtbDcPHDGz7v0q73cxk1JaMbMz+D0y
HG759H6VHxTickXCWAhx3jjPgrgNF4F9uLgcP4hmCPF1/hguSM/iTmbTcmyxrsW67bhzm0XxGC4W
Z4Bb8ZCMByhKsK3Fca3gVShGYt4wHmqxSiGMywl3fbh4z0K2plscDxMd1KhUUYO9JN5lanW/y9us
F/6wggu+tlaaioRQzOflshfGcM49no7KHNk9nkkpNUumFOLQImEshDhwSnWCB3ABtEi4mAe0vz5c
FIO7ZAciBGok2eUyaw3LscW6FsvmUm5ZFA/Hdk4DN+NO5924eL4eP38WyzwRP4fwEIpJvITbGC6O
cxhHiv0Nxvo9eDhJPbe4D0+ma0VAdgKbe3QiG4VSWJ2axcsUnQNbDY+YB8bMrGs/S/5d7MRDwTh+
n4zEfbtvzWuEuJyQMBZCHBgXQBB34M5YF+5Gz+yiRXGr+xqkqHQwjYcejFBU0qgbglByisuiOMcL
9+KJdM/AndQ7cYF4Mx46sBrLn8WF3klcnHfgIRTlKhTlhLvs0jdzi3NlkFbr4e468a7EJrU/j8pt
sLeIuOhst07RpbApKaXlWGeQooTeoSD+DqYrlStmGsW+C3EYkTAWQuwZM7sZF3L3p5TuqwjiXAd3
/qAcqkpy3Qb72Ca6zr5GcPE4l1KaK4nkhuXYSuuP4uJ9miLRLjcaeRJv2tELfC6ltGhmV8f2F2Pd
ReAM7hJnQf5FXKTnihvduIOcw0qyMG7mFvfg16xVwdTF3ptn1AyliLjo3M2v1vVcoX6oRT3mgFEz
6zyI0JqLnXg4yLHHo5GMOX1QD5BCXGqoXJsQYteY2Vin2fvx0mDvA+7tMPtb3N3MbuqZaJxxUKK4
G09UG8BdzvEDFMW5znAPnmQ3b2ajtFCOrcQoLlqnYj1wwXoEr0M8Gr/fk1KaivJyR/FzOYi7s09T
uMvHKEIohnGx2MVWZz479oa7sI0S1vqA1VZc/X1KvIP6oRTg461Xlm0Fb97RsskTDwTZNT6UpJQ2
U0pT+H3ThcceX5YNUITYKRLGQohd0wF/2g8vfivwKPBWYAC+vh3eyMEL4rYQpbl18nhKad8rTpT2
10lRaWICF2VjhEhupRVvjDeL6ixWE+78jse8U8BDwOkQK1fjLngPLqDP4uEUo/HqBD7N1oYX5xLu
Qrz248KzFxfwNd3gHdYuhv1JvIP6VSmgfsk28GuQaL0LXmYe6DnsHeKiZOEZ4n4ys9H4dkGIQ4v+
AIQQu8LMbl6Hb3kjtL8UV28vBX4b2jfgG4BbzazzID5ozawfF5Pd+NfADas/7MP+enFRvImL4s14
30njkmflbeTwiylcqHbiguQKPKRiA0+uO40/Z7QBN8Tqm7gwnqUozZbL0N2DhzL04bG23USHu1g3
J9xlZ7eRW9xL67WLYX8S7yAc4wgzqbJGHWEcx7jKzoXxEn6+D61rnAn3eBK/L7tx9/iyboQiRCMO
9dOyEGJPPAPgBZWJLyx+/V7go8CkmeVEsUVcyGzgTuAGXv2gJZc3XNtciWARF4AHGhtZI8muA3eK
oUk5ttI2cuOPKVzg5uTAq3BROwvcjpdHuxcXp9dTxO8eoWj5nJMLT8T27mFrFYpzCXfhiPbFMHpp
0mgkll3ewTndj8Q7KNpCW+n3zDre5a5WZQrw8zJoZtbqfRRVOubxcm+zqs7gISZRzm4Yr9xxoMmr
QlysSBgLIXbLAwB34E5x5iPFr5/GRdMp4DpcBC/iAnkWF3zLwHpkypfFclk0b5RKjQ3EvImDLrdV
SbKbTSnNRzzzGC2UYyttZwh3iKdx4dqLH/spXMxOALfE73dHwtlJPClvkaJF9tO46zscr07gM7G9
dlwg9hMJd0EuWZe73NV1i+Oho4P6nfBq0Unr7nIj8nlsK/2eqVuZIljBj7OLndUnXqS4p1qJDb/s
iQeEyVK5w1y54rLuFihEGQljIcRuWW2HO18JtyXcKf4I8CrYaIc7NuDDFCK3E4+HPU7RpCJRiLXl
eK3EOpu4qN6MZhO5/fEMLmjaQsitH0RMccTajuH/Iycjk7+PFsuxlbZTFl451ncBD58Ab85xE35+
Ph+u3VDMX8Yd3BzTPAtcS5God2dMO4afkz5KCXdx3vJX4q26xZutiqAIkWlnfxzjsjDeQrPKFCml
NTPbwMMAWhbGJdd40MwOrGLKpUhUQlnB7/cxMzsv384IcTEgYSyE2DGRRHbbBrxrHk68zIUaAO3w
kQ14FS54O3BRtg48jDeq6MHF4ijufA7gIjThwmYZF3obsW5bTMtu5yClCgZmtkkdt5kdhGmUttdV
Gs9ECK+Wy7GVtjMQ62QHdpAiLKIDjyPOZdjuTinNxL6vxcVmGy725vHEvBMx7STuCt+Dn8MNXKCW
O9zl/RH7ahhbXKpdvJNGKF3xcz+c+3yNGiXg1atMAUV5up2yiN9//ezMKb/siQeFs/FAOAx0m9n0
YWinLQ43EsZCiB0R4QS340Jqc8ON4sfxeNfHN+Bv8bCBQdwpnY/fRwmBllIaB8bDdezGxckg/gHc
i4vAoVj+LC58+uL9GkU1gs3SzzZcrLVXxlsVy+cEdNUBiyS7kdjHJJAiaa6PCKdo8RwNxPjnYl+j
uCgexUXYo7jTexx4MKV0Os7FMygaoeS44TOx/+xY5xCK7jjeuTh351zsuEbdcW5acYu7Y787CYvY
r8Q7KBzjRiXbGn1erQB9DeKQa5JS2jSzBWAgXGM5ohUq7vGROF+zO33gFOJSQcJYCNEyId5uJ1oG
U3RIuwt4EHd2r8SbVCRc6M6klCbDDR3Ev5pdxT9cV3ExtoQL5W5cFA/jgpDYRy/uNOcqBOvxym5x
nrZGUXEgf3B34GK5M7ZxzpWMr+izWO6jcGizKzxG0Va5JdEYFTOGYjtrsY3sTA4Dj+Hi+Bo8lOKx
WPXq2P8sRQm6XBbuuhj3MTyEYgYX1YtxblYq4ys3DVmjeRe7PmBthw0v9ivxLoc11GzyEazT2BHO
LmY3O3O9wR9YsmvcqGLHoaXkHud7u8fMpg5TW21xeJAwFkLshGfgztEUXlEh4SJtKn4fx4XxWLig
4Jn/Fm7r2RC/Q8DRcKJmceGTk9SWgKdTSqtRVaEbF24DuLDtJdxKCoHcRSGUoRSjTCGYF0u/t8cr
i+Yjse/FeH8Cd3fBxWlPjmmmcJu3OZOlr51zYuERihJqR3EhbMCNuBN+f4jCY7iAnonzYHFOJ3HB
nOK8TuAhFMOxy404hnMJd+F6d1LUPp5OKdUViyXXfqehBPuVeJdpJIzX8Ljytlqubji/a+xCGJdc
4/5wjeWE1iGltFByj4/KPRaXIxLGQoiWMLPjuEg7Q9HSeBMPm5jFhc0cLgpPmtlkSmk2xPGQmZFS
mo8YxfGolToU2+zABc10OVwhEsnWY5vjIU67cXE8GGPoLI2lHGecS3/lWNjsLhM/1+LnEO44PxlJ
drmT3iyFc9xBJUwjjqscmtFBET6xhIvi7KidwEXtEu64LwL3RsWNPrxCxRJFKbdF/CHj2cCzcJG8
AvwDRdz2bJyDcsJdrt6Rk9HWae4W97KzFtD7nXiXadb9Dvxa14txXWZrk5OdsBDr9tP8fB1q4l6b
KMXQ59hjucfiskDCWAjRlPgQfCYuFJdxxzKHIUzhwiK3B57A3c0BPARhNr4mHwrnOH9dvUYheLIg
6mgUJxpf9a/hrZgncKHUTZHQ14X/Xys7yjkOeZXCkczJZrmc2RTe+ctiOyt4o42VshsW86tuc3us
k2sN98Txr+MC91RsfxUXxe3AF1JKK1H94nqK2OlcCm6tHf48GqWAr/TRqPQxQtH2uZpw10tR1qwH
D2Np5qDutHYx7F/HuzJ1u981q0wR5HrGXTsVafGAsoTHGi/IAW1OlC9cpnCP5/H8AZ07cUmjzndC
iIaES/tMXGw9QVHbN5dVm6QIQUi4k7kKXBGhEIQYnsOFy2AI7eO4wHoSb2qRm18cN7Nha9IxLzmr
ydtAj+NVLx7GY3ZPUzignfHqi+13EqEccQwTuMDL4Q6JQqSeNLPjZjYWlSm6Y9crKaWFlNIsRUzz
o8D9pXMyEce4FMf+LNw5nonzcAXuCOdmIVfg/5On2uG3BuDrKq22n9cO76BIkuuh9DV2yS3O8bgN
6xbHOvkhYqdxuZ1xHvaz22CjUApokoAXYniT3VWnAD9XbRQNUUQTUkrrKaVcSrAfr3vcqHqIEBc9
coyFEHUJcXoj7ojeTVEdAQrHOLvIUIQqnMVF5iAueEkpzYUQuxYXzk+z1WFaiHqpORGqL1yohVbc
zNjOSrww77bXhQulHKec6yn34UJoMablr9FzKEg5XjnhDnM/IdyiRFwO1xikSNg7SiFIr41jf4wi
HvvTcdwdMa0nlj0R45gHbtiAF7+RonHKS33l9pfBN8ayG8BqJeGunyK8IVeraBYe0RfHudMSXF3s
T5m2MnUd46BZyTYo2kPvOImu4hovyvlsnZJ7PIqLY7nH4pJFwlgIUZNwIE/hrucjuOAapRAnWYjO
UIREbOL/V7IwHjGzuZg+RFHFYhPOidlzxPu5XEIrXv0lgdzyB22I6dw4JIv8K3DxOBnjz0K5B4+V
nqcICcnHmF/l0I/NWOd4zFsGbo15k3jTDoD74jxciZe0eyyS7bIQfyLOyVLsewoXv41abX8Z7tA9
nifEsQ3EGLOb34ow6QWWdiFg9jvxDop7px7NKlOAX4eRekl6LTCHX9Od1nQ+9ES4ywRF6cUce7yf
4TZCHDgSxkKIehzBXc+JeB2lKHu2jovHVYpmHOUSaYu4yBjGxUp2XWcis70fr1ZBhCNsIUTNbEkg
D1EI5B27eeFUj+Hi66GI7+3AhXIW8jlRLyft5QQ9YloOyci/5+oTp2PbWdzmph2P4W779Xgi3Vm8
ukUXLpxTnNPRGNeZOG/L0LDV9iBeHaTXzGbx89xNEVvcklscSYbtzZarsd5BJN5Bc8e4YWWKIDvf
XRTfYrRMiLtl/J6TMN4hpQfbHHt8LB6MVe1DXDJIGAshthGVEq7FxcUjuIPWT9EIYgUXRzkcIccb
d1CUT5vBXdQ2PFR2KifVhTiGopRbzW5ysfxMCOIholOemc3uoK5wN4X4nAjxk1s+r7NVKOewi1zt
ItdOzk1E8gPBIEU3uRwSMYs77N142AlxDmdx0XsylrsOF9dn8VCGJTy84kngOcDVbTD/Shio0Wr7
ExvwKdxZzs7cBi7Ax3AX+SHc/c4d7+rRh5ed22lIxEEk3kFrMcZ5/zVDPyIcYh0/zzsWxsEcLuh6
W73HxFaSd4ssu8e57vF+xqQLcSBIGAshthDJMzfg4vB+XHj1Ufy/yFUejKJeb64ZnEuNZSFat+5v
iOOEf/VNPXEcy24AUyGQB/EKEgN4uEBdARQCP1dxmIqatZ0UCW8T+cO6Uhoun4eyUG7HBdcYRWx1
Lls3Hr+P4qEUV+GucBueWJhwsXoMF8CT8ftKnLsh4EuArwCetwnj8zD1MnefgXNVKX4FF24zsc8j
7fDmDXheabl/3IAfAroiFnq19FqLUI42ivjmnXIQiXfQuFwbFN9INKpMAUVlkF0Rom4FF3USxruk
4h7n2OO51GL3SCEuFBLGQohzhGC6Bhefj+MC7iiFMGzDBUoOp8iiOIce9MfvI3gnvIeIZLf4UKyK
48VwjkfCOZ5uNL6IV6zVRW8u6iOXj2U4xnOuCUG4x9kpnqxXFq60r1wazijKsOUKGyN4uMkSXrXj
OB5y0klRjeJuXMB2xLQrYpkxigeLdVyE3RzbGQPu3oA/jH1eDXx2w13is7jA7QKsHX5vAJ77Rjwm
+Q7glfCcefitDXhFXJPcwMPwFter+LXsYnfCb9863lXYBL8Ha4VKxPXL9aIbsYKH3XTsQbzP4SXI
eho9eInmxIPGOP73OhT1y6flHouLFQljIQRwLtnuJC6Ez+KCrhcXULk+cDsuhntwIbNEUZ2gBxdg
E9g64qAAACAASURBVLH+cvwciXmDuGu6hYo4ppk4jnVW2dpF74gVXfQ2cDHeTcQ0x/Fl93gZd493
EvOYhS34w8IgLmZzfG8/Hi4yjovfTrx03CzF+RvGQyYsxjFMEeP7LOCWWPdJ4O3AFwiRjJ/TGyge
TkaAUxvw9XWqV7wAD6/ISZMrbI0DPxrjOG7eMW41lllt4bw0arKxF/J+2ygqglRZozVhnChK1u18
IN51cRW/xhLGeyTuqdlq7LHcY3ExImEshMiM4sI4J5St4h9ibfHKcba5IsMqLuo6cJHXhgvFcVxE
5iSw1Vi+pmsM58RxIppspJSmWhlw2t5F7wpczC/gYRK5dNsgLmYXmwnvcM1zN70cZ5zrG2dH2IAH
cKF2DfD5mHc9LmafwuOKLc7P9RSx1znWeCOWuwl3i4/HtE/G9Cycp2Pfj8QQc73dF0HD6hXDsW4P
Raz0OoUAHacoV5dbbhNCeYUIvyi7t3FuOthdCEYz8n4ahVOs06S7XTjL+Z5b2MN45vAHru7qtxFi
d8QDxzj+tyr3WFyUSBgLIbKbegoXTacp2g23E00tYtENXDB1xM9eXFTlTnGdsc4q0B31TcfxEARw
8VUv0W4pnOPRcI5bEsex7nII6ytjDG141Yb1OI4+PJxii0MVLnmuNpGFcDmWOrdWnsad3Fzd4iwu
iq/DHw6eoKgwcQ8em51jlHMZt0U8LGIsfp/Eq0s8L9brAD4DfDzO0RWx3JcQQh8XFBMxnrPQsHpF
Gx7HPBdjbaeou9xD0cI6O+1rpTH3UgjldQqhnDmwUAqaJ+A1q0wBRRc82201hEjIXKPohCj2gbge
M1EzOscez+ZvdoS40EgYC3HIiSSza3BheBqPZW2jcOZyCbPcZjm3U17FhcoELrpyPeB2QpjE+mdx
l7Qbj3GdrxfbG+I44bHD4G5SU2GTy7/hAi9X0RiiaM38eLjSudNbFsHZ/c11ilcohOQmLnYXK8eY
ayNfF8s9Hvu+AResD+REPjM7hgvns7gIzqEcC3iC3nNim0Ox3wdi7CNxfp/ChfS98X4szuVtwHe1
wdIrobdG9Yo7NuCLcQ1GcYE/H8c5RhEOk6uLjMSpXIl5uYReuUFKP/6A0Qsshiu7uo9uXzmUoh5Z
kOcHs3qs4Oe0i72J2jn8Xtxxm2nRmHCPzxDVZkrucd24fyHOBxLGQhxi4qvxq3CxM4XH3q6b2Wgs
kjucDVDUmb0ipp/FY2bz19ZrMT87xmZmnZF8M02R5V/XNYZz7u8kUeUhyjzVFMfh+A4RSXa5skXE
MuZEwHbguohBzjWV12O8S/FzrbyPOC9H4ngm4ueROK55/EHC8FrFPbgoXsGd4vV42DiGi+cU83NM
8iIupG+PsVus+0/AnbH91RhXP/5/OrcqHsJjh78ZuH4TPjEPR17mMcrAuaoUr8aTH3PHvpyI2B/j
nacI1ViLMa1QtFQepgiVmYsyaG0U4R45/IJIiDtX+WK3DR2iYgg0r0xB7L+uUI17Lrv9uxbGcS/m
5MjJ3W5H1KbkHufY4+NmNpNSUg1pccGQMBbikBKi8gQughZxt2YhRF3untaHC5C2mNYRrylcXC1R
CJmN+L2NolJFV/yeKzG0Ea2em1SEWDazKRqI4xBquVzaNC5Is6t5HBd9UxSxvZ2laXUbDpREcXuM
m3i/jgv6q3HB9Xick1twwfkA7tDmZMPb8ybjXDxF0b3tREyfiv3cDXyUra58/j2XhTuJP8R8Ax5e
8QTwjg0XwB24WJ/cgE/EGK6jSEaciu2M4ddjOfaxGfsfjHmrMW8l9j8IrIVwyetMppRm4jx1lV5D
fvq2lIhb2aFQbtjkI+KH12ntsyuXbdvWQGaHzOOJoZ27Ff2iMRG2cgb/XzRiZr3IPRYXCAljIQ4v
w3iowBouLKdL07Pbthbvj+Ci6MnS9Oy6QlGuDaA9BMwaLpgWQnAv4UJlkSauMWxxjseoiOOoRnEi
xrIQY8xiMjvTp3Fhth7rtFM0HOizGl304mFhDBeLZykc8jZcYN0a83O3u2ti3w9QiPAOvOzaSpzT
LoqOdN2xzlGKB4/TwAdj/VzdoifOeRce+51DA74UD8mYAD6EJ9C1xzY+g4vhPlwsj8Q+ligeDPri
OJZjnJ2xzCyFW9xLkVy5HOv2x/kdA06H+F2KUma55baxVSjn8lyJklCm4s5XaNbkg9I5bsYKfp3b
9yiwliiqkLQc9y52RtwT0/F/IleumJV7LM43EsZCHEIqyXYzFM0veijCJ4ZwkZKTxZZwEdWBi9Hs
DFYd4/Z4n5PzMuO42zpNC64xnHOSpnBxOhhitp+iycY4RWJYFr5P465mqmyrXhe9eQqxdZRCPB6n
qDc8GedrGBeuOW46AZ+NaTms47YY4+Nx/jooQiJOULjc+Wv+z+Bx0WO4OzmLO8M5qXExtn07HjKx
hFeueIyi0cdKHMM0HlfdHfP6Sue+GxfCkzGWLGBzmb1ceSTHIueHjA2KetUb+DW9AXfol2K8sxGD
uxKvcmJj3k8/LjDzQ1O58kW+Vs2afEARYtKMHELRzR7aO8dD3jweBzunCgoHS/zN58oVI/E/aUbu
sThfSBgLccgwb45xJUV5tZlSYlGuUpArLKzgQio3u+jFhUsWSXm9cimw3DJ4FRee2bGbiv3mMI1+
Kl9zV8RU/pmF9nCMbxkXv2dyZYIoxzZAnXJspTJj+ZXDCMYoEvRyC+VxXHyO4OLy6dg3wH24W3sl
LpyfoogzHsaF/whew3g9lskPG0coWmvnEIaH8RbPOexkLrZ9PUV5tmHcJb4KF3j/jItxKBzfflwU
j5e2nev4XhnHmR9kNnC3d6Pk8mY3eTC21U5xTdvivGfxnMNoemP5U8DVEcM9H+dsMcIOslOcr0Mt
oVwuEZePpxEtVaaIB71V9iiMg/wtxwA1anGL/SWu63Sl7vFMUotucR6QMBbiEBEC8QqKBKz5lNJc
zMvJWR144thTuKiAon3wMC6YVuNnFjNQCOOyY0xsYzGESo4bfhTvTrbE9nJpUFSJyMlxuSLDqXh/
Opw8izH1xfhWIj6xg+1COLMRY12iqAl8MsY9iQufAYrY6EHc6Z3EhecxIp4XF68juEgci2N7CBdS
11KEJozGPnNSYw7N+BQuNK+jSJS7Osa1ENNvpWjIcR9ezm2SIn77CYrY4XL76pVY5wlc2I7itZVH
4VzSXHZtl6OU3ZkIOemPdYbi/OXQmnJN5pk4P49RJOwN4g8AG3Ft83HkdtT5ASs3XcnOdT5Pw3jY
TG77nB3lsljOjm2zyhTENlpxlxsS99oCHhpSsxa32H8inCrHHo+WYo8bleoTYk9IGAtxSAgReRQX
O0tEB7iY144Lsiwgz+LiZTCWzR9EOcwid1DLtW+3xBhnNy8Spbrw8l5ZDF6DO6nZocyhDKu4oFwF
1kvxxDmcowMXnUPAqah0cSy2k8eaS8RtsrXyxHq8Nmok8Y3iAu5pXKDdEOchl307GfNPUyS1LeEP
DkcowhKO4OETs7h4zI01hmP5sdheFmufxB8QRuPcP0ohQldwh/hZFImETwH/SDiyFBU2unAHeDqO
Zy7GPE/hiBPnaRO/tkYhonN1iewor8T2ZuOe6Y7z2hX7W4zjGo1tr8Uxj8f12cQfLIZi/zmOfcXM
8vUtl3pbj21m57g/5ucScbmW8ipbHehWhfHgPpVbW6BwjRvGx4v9I0TwVLjHwxSVK+QeiwNBwliI
w8MQLiSzKJ6Or9P7cSHVhSfX5Vq7WcR1xvtchSA3vliniCsm3ueqAu3h+nXgsZndFE5yin08Gds+
XXbgQozl9XtizLnbWj9F6bRrcXd3AhdWWWStV8VvPUIU9+IxyctmNhzHus7W9thP4QLyeopwglyz
OcUYz+IC8boYZ66lvBzLXYk7vSdxAflYHNezYvyPxDI9cV6uj/VzJY3P4uL9XMJbjHOQUqhA1Gue
i3l3x9iujW0coQgHyPHLuepIFsq5ukT+ZmAFF4JPsDVuN9eA7o9t3hznYiGOcyHOCRRl4kYoHlpW
KxUscl3slZLIz/fcFhGPi/JOM5uglGBZJWrl5qTCPQnjkms8EK6xXMvzSNQ4X8HvodFS7LGug9hX
JIyFOAREst1JCgGyQNGAIseOPhK/t+Pi+QhF+MQcLvQ6Kdrs5jhjKERzL0X75Oz6deFCLu97ERd9
s7GPY/G1exbSWUB3U8Q8n6FwqomfI7jwGt/Nh6OZ5RCIqRDFuR7y6Rj/zbjwW49x5rjrpynCFNYp
HOE53OXNTvFQjHkO+ApcXA7EuXgkztmJOJa7Yvs5VvoURWONxZj/GIX7nc/9NO42V4XhfJyf3FL6
SKw7QxEekRMsc7x1PaGc3eJ87Avxaqco5zdJ0filH3e52yjCIRYoGpvkDnwdFA9S3TGtD+gOAZRd
5XLli3yf5dCb4ZjeqERcvg/3o4112TXeaxk4sUPi73wyQiqyezwd94gQ+4KEsRCXOZFsdwVFTHCO
Dz5G0e0ti60soLIbuBmvXLYNipbQPfhX5Sdi+iJbKxvkr5tPxfRcH7kztnULLi5GcMFVDnvIYv0x
XLiWy7SNxZjvw8XaETM7uxNxHM5wH+6aL5lZWexs4AJ3FW/Y0YXXDb4mxpNDEcr1nRdwYZsTygZj
O48DXxXncBl/OPkcRRvmq3DRn0MT+vEGHktxDjZiDE/HftspKkSkcIdXKZzUzBJF4xNw4bpCUXGj
N8b0NFsd2dwBL4dzLFLEXOfGLdm1h+KatVM8UOVOf0ZR8aKvtF6OGV+neAhaoaivnNtS5zCKcgOR
fL9OxjbP0LxE3AbQ0yxZrxUiPGgBj4+fl1t5YYi/2VX8/8hYhOjM6nqI/UDCWIjLmIgdPoYLoRlc
dHSwtZ7t8ZiXqxFkJzeHLmRX9AgutrJrO0nx1XmuhZtr/g5QiOvcmneaovTXo7jAfTi2u5hSmosw
iuzkzuTEwDiWvpi3QpRjM7OzsX7L4rjkDM+EsMwd5eYpYnt7cBG8grvbY/F+Cn8QyJUrbqSo/5vj
agfjHNyNC+phXCA/Cw9HOB0/22I/U7Hu0dh3fjDowDvh5bhgKLrUZYeUOP99ZtadUlqBc1/7L1J0
/1uMmOEU03KoDPjDQS6xVi90IccnZ6FcXS4L3Fyury2Oo/wgll/tFN8u5IevPop46d443v+fvTeL
sexKr/S+E/M85xA5MZNkcqpJVSpJbrW6ZBmQIT34tQ1IqAc/CUbpwW8NA4YNN9B+sNsGDFgPBgwD
Nlp6MmC4AdttCGi3hlZJ1lQDq4osJpnMeYh5Hm8cP/xrxb/j5o3IgUkykzw/EIiIe8+wzz7n3r32
2utf/7LeO1JApDiGn+Gdov3tFnEG9DN6e5VHLeKeNmwZOMzzYaGbeIaQ/GpRn99xYqXh8Fluooln
jQYYN9HEFzQEEqYIMGlJxA5aUpe+2H7ALjZxQHwvnCaAySxZCnek2L9Xfxt8tCfnHeicTpqq6rqe
K9q2SQDIcbQ8rdcmdeylMrlGdmyjtNmx1VH6d54APo8Fx4Wt26qKjlj3uql2zKof7hIg9G1CM/yQ
APNm1gcJJrgiWNdJ9bVdPX5G6IVfJUDwFQKMvkvolZeAbxb987aOYe/nfoIpfqj/V0nG1omGBmV2
evD9cWxwtKw1qlhXF9sORrdE8RT1Xbt0wYyvnyefs2SU24Fy6ZNskOwJ1S7JzB8Qk4NBknUe0H3o
Iktwr+kaDHyH1JbTRGU+9+MeAXrX3QmyiHMxk04WcQbKT8Q2ijXeJFnjZwXYTTyH0OTW2uNp3ZuV
5r408azRAOMmmviCRVVVbxC+t9bCtggQsQ3cth6v0OltEDrVGW1jhnmHAC41CXTKSnebBGixNdgi
wepB2MCt6zzdRAJe5cFKgHZN53xf7XhFbVmwg0CbHdtqCXgcdV3vF+B4pqqq+U4gR3KJUR9HEpNJ
AuivEkzwBMHooj48RwC/u2TxjZoo4jGo915RGw0i39d7v0wwyyP6/y8IULxC6Jf7CbD9FgHwHqoN
QwQ7/aH+XiAnHJskwDQIrgjg2F+6L2jiA9BfJqcVzPEoafHWsey2QOA2CYB3SO3zoK7N7iQGyitq
k4GxXS0so4Fkk+2usUquNDjR0p7YLldtKdCatl8jnrn94lx22CilFLtqe39d1w86WMSNaJ+S4W63
iGuPkjV+5Jls4rMN3auFhj1u4nlEA4ybaOILElVVTfXAHwK/5de64fst+CcEILsN9CjhbpCQPVQE
ODETuEIMLAsEcFgkAMgAAUbsNDAMzAtgDhJOEAcCJGX1O0gA18dRRnOOkCJYOtEL3KyzhLMZyj7a
GOT2KMDxNAGOF9qcLuzLu6Y292pbg6ZT+n+D+F6c0v81AYof+PxVVRkwW+M8pT4zy3sA/CMyIe8d
4CeEtKJbxx1WX7+lc98kvZAXCcbZVQldDW6PAGH9hCewwX9FanNHdX/M9rYIm7SBMkFJspVafWLp
RkdwTILZPfXpJmmv1kMC5cPKdjxq+zZPgtEJbTemvnDZ6hVd37z+dpGSLpIptl/ydHGMByTI9sSt
vYhIH2HbZv/q3VqlhjVxc9uOs4jbKZ8nTTo2iZWOjYadfDGiA3u8QUyEm/vTxBNHA4ybaOILEj3w
h8Pwm38AfAf4U+B78Cvr8N+04PeAqwTY2COTp+6QRTy8ZD0AfERICObIJConTVkrWtpfeeAxe3cI
jAVarRUtgfG62vE6wY5aX7omsDKl4yw+CfOj87RrjlsFi7QuQNijbfYIEDpJJifukaWhRwj292OD
oqqqLhLyiNsEOzlLWte5dPNvqE/fIyQUt4Efk+z8kLa/qHPf0HWeJUDbjwmwbheI83rdco8zpDMI
pO52jQC3vXJlGCST4+yGUfbXusDxOFnAoxM4tk/1I5ZohQ+xC3YYvJolHquO+iNb62x/5HESKLv4
yQAxUXign17S6cMlyP38OpHT7bOMx8+qJRsG2aP63e5ksYuW3wv5SDsLXSYBusrfEOmj3cQLEAV7
7MnwgJ7pT+pj3cSXJBpg3EQTX4CQfOK3/gD4Xb32u0ANXd+FXwG+BfycLNYxSAI562IPiOQvM7Wu
GNdFJke5up11yfBoVbmKKNlbFQBrlwAZbq+T7HZJN4ghQre5TTLY88d51HaKDrKKdQRIBcjM2B6Q
0o9XtftdAvC8ofP/rK7ra0V7z+i9+wTQukAAM/s+/xT4ho55h9T3/pwAda7i10dMOkYIUHxAgN99
7XeLYJHnyf4+IIBYL2mDdtidcen1VqHFtmuDNeElYC77a0Pg2P7CncBxL0/oDV1nZbv1IhHOQNn+
yLaG2yHu7wMBamvOr5JFYDYJPfYK8YzsF8cbKK7RbesiGWZX8IP03q51PMs07GRRwaHu2OB3XRMr
66f9M14cs5+wDLvd3rdNfL6hZ9vs8UzDHjfxpNEA4yaa+GLEaxBMcRm/nn+eIhwgXEXO1bsuEeBh
jxhALhAs3RW9Zm3nObKM8Q4BOvYFJCaA7aqqVggwcwi0tRztBKshgV4DsW6CGbxCANmHev2SzrP4
GJ1nxxCYmde1nCF01SsCONPabIEAam+rPdcI4HRV2/yMYLEtSZghmG07a1zUNZ0nwNuPdB0XCYnF
IjEhmSNB24b68yqpI95V31rSYQbfRTUsTTBbXGp6HeXEZB2YkLyll5COlB7Ny7SFlp9rgrGteRQc
97ad74lC+xpk2nGklCwMwpHS1FukE4Wt3CaIZ8ogeUPXuEtMHKbIYivWDtsjuSwacqDrmCyuxQyw
deNl+zpZxW2TCY8GyTWxalBV4cVtNtklsBsQ9jmGJtXzRX6BtccNe9zEsdEA4yaa+GLEhxDyid8t
XvyT/PPfECC0lwAZtwhAMEkAXpf5NVh9lQAc9h8+BDg6XkUydTWZeGbbMgMNM8i9ZHlgs3grpLPA
KwQoPKN9PyCX4csfM9Xl//7bbbFsA7WxT/KJCdKhYZoAqHuEXKJP1zxOgOTrWlZ3uy+SyW/n9dpZ
AqT9kABHVwkt90dE4t0SAZgH1AfniQlMPzH5aBETlgO1aZ60yJvTvfD1bag9/YTetQRcllJAgMtR
HdcgDeRkUVVVR69Xsc0Gx1CAY+Lebbbv87ShNpspbreGs/MFZGW+h0Q/2DlkWL9HyJUPF4DZ0Gul
XZvlF/ac3iUTLVtkoZDSBs4JeOsk69xuFVeyynOkS8kaKdeogLqD80UDlD+HkGxom2SP14lJY3M/
mngkGmDcRBNfjLjdDX/9Pfh2DdWvE6D49+GgG/6qFaBrgwACywQonSbAiJO6xghQZ1nDA3LpeIis
XObCEwZLTnxaI75TXLziYbHNAQEuewnJgot/dBPs6tcIEHODZP/MTFs+UHrldvrxeXrIUszrBNP7
Lf29TIDTUzr+bYLpHdfPIsEmDwkUT+hYQwSoek39NqVrLB01VglQfZUAR/+frvMeATi/RpZ3hgRt
y8REZY8Af6vqN1ukbQKbBZB035Vht49ag/5Z4FYx8Nse71jvXTHLi7o2a4BP6+3nzrCdYA03SCYi
QmrBDdIniL7zSkQvWTwGsoqf9cjdZHnuGe3zkEz42+eovdwhY0zqlUvniR4KNwudY1TXsSrHld62
Y9kirtQ0P7FFXBOfPDqwx9YeNxKYJo5EA4ybaOIlD+lmX2/B/7wO099NzSzd8Dct+K8JMHAhXjoE
pn0EKHDC3GkCLLxKgIFeYrAfJ0CJXRaG9PsByShv632DWbNsZm6HSdnBPPHd0yJLGxt0/1T7DRBO
EIeMjpbiy5+utv/tgTtNgE1bgLVIADVGACs7IRhkWWO7Q4DKIbJQxymyUMkwAYi8BH9B1zVEaI/f
Bt4Eruv4g9r/CgnWpklWfVH9sUhMHAzC7ARxQCZ2uS/by9+WjDGkltYJak/svVvX9U6RwFipnQME
uP9UQyBxS5IcF4wpZReuqrhCJolOEWy9C4J4ImY22H2zRfSbNfWTpCuJn+vtuq6dROjn2scpq/05
yW+ffPaG1Y7+Nqu4DdLn2Ql9pUVcyT4/ziKuiecQBXs8SZSjXyP05A173ATQAOMmmnipQ2DxEjEo
L7fgXxCFI24BP2zB/0OAMrsSDJPleSFAwRIBEu4SAMhV76aIwd+soT2RK3IQbynBZUMDjiuSLZFe
szME4PuYTBzrJr5/zhIAZ1nbXdI5pwiQsUbKJywraAGt9qS8KnyJRxHQFHvqxLhrJGN6jyxZbf30
GiFHWSGX628TbLPBuyuuob56QDDFXSRb/hoBzm4RQGiWLC9tr+Ra1wyZDHZV79mFwiy5nTsM8nqI
JXrrZq3X7lLf22Vij5CibBVtdwndYYHkuhMYqOt6t7C+s2Z3qqqqxc8IPBwQBWFOsoazr/MS0Sc9
xH1sEWB0kWCFPUnrK/Z5i+iHj4lnwY4Ye+qvFcJm7lD2UZy/BMtm/F0CfZQsMuLEv1Ht7qRE+zBb
y92uaT7WIq6J5xdFkm7JHi837HET0ADjJpp42WOKLCPcrd+3gL8m9I99RCLZ14nB94ZeM+hdIgbr
CQKc9hLA4q627yUYT7sKmJVdFRDd42jy137xfy8BdnsIwFeTXsG12rCsNhwQJZMr/V8RzJp9e7vb
zmO7LQPl0uViifBrHiGAqZOm9gnwZAnFFgFC+wiQNE8ApB713VdINvKAcJKo1Z/X9P+u3l8iQP4q
8Gc6/lW1/QYBos/p2jfJ5DFfu63aHpAOIdb2ulS3mWrrXf1TFmSpij6e0d+eANi3+LTaXIvdLHXa
BtvuV1uhnSI8exeL9+sTfg4+AYi2HOZIHGMN54mAV0CGiefqFHHfzcgvAZPd8L+04N/3Mbvh/23B
f0I+Z5NoRUGTh2XCYm6nOL/9rK1nNlgeIyY3vqeeUEEm9llHXVrFuWhLCeA7WsQ9jUNLEyeHns+1
QnvcsMdNAA0wbqKJlzbkPPCa/rWN1QqpG14lwNEdAgi9QizxQy619xIsbZ+2mSUGfjO7/WTVs21i
QB8iQa8Zy30NMC5G0UOAhAXCkmtPQALtbz3ooR1bVVVzBDDZJpi80xxd3rZcopvUHNuf1m1xsZJp
Eqiuqy2X9f8SAaZO6/dtAggbxG8SE4nLBKitCJDcR3gTf0wAautVDcouEB7EH2v7Kb13k3QC2dVr
9wnQdkdtGCBB5RpZUvuBrmNb+y+RkxH/+Jg7ZHnuOVIOYk2xpSeTHK1iWNryHZl8EPfZTG2tfrSz
RQmO2/93sZfjAPRJwHoQ6K2iXHfHbeq6PtAz5Sp79zlqDTdKPJeX9bPeDf98BL7T5vP9nXX45y34
xxxlcC3TmAF2ZfVly7jdWkEhmRDbPK1tDIQHOCrBsCuL792hVRyZ1LdO+mkfsYhr84TebRjOTx51
lpVv1x43k5AvaTTAuIkmXsLQsu6rxCA+T+harT3dIQZhJ9TNEsDhgADHC3rPjOxFjlYKe6Dj7pJa
V3T8fWLgv0tqk6eIAcXAZJoABGvAnBOMJG2o1J5FHrVjWyCYvvG6rherrCy2WQARs3ZlPwwSQHCB
ACHn1Y4PieX08wQ42iRAa0Usp88SwBdCG+ziJ29q+5sEuHxd27xLgOgzBAgeIO3DflF9/BOi0t2E
Xr9P6rf71J772u8WySBuE/exS33ZDSyrz2rt20LuFMX121HEtmx9wMO6rhcK7+Wtuq5Xin1O61gG
lcdptq1pXiYr+zlWin262vbvIscWH6su/qf4nw7vDZEOKe0g+kDX4P1cCMYTBG+3rD7uI+7FN1rw
Gx18vru/C78JnKrr+oMqq+AZII+oPdPqy32CZfRKx7bvh/p/l7j/08A1HbNdglFqn/farn+AlDmZ
Lba8o3TxsCe0wXljEfcJoo09PtQe1x1K0DfxxY8GGDfRxEsWAjznCBB5lyxYYT2uk4yWiIH9LAES
fwL8EqE5/pAEbcMEczmrY91GWlZioHaSnJmufULju0uwaUukv+85YtB2IYsZaZCtK3Ym/3z7GWIL
uwAAIABJREFUAC5gsa59lnhMZbEqK9i1yDLVLhX8sa7/oq7/FsH2HhAgdZ1gz20HZoZ8ggDS6yTj
WGv/FgGSrxTbbxNAukVILF4lgNoG6QTistfbul/WW3si0aX3zD66n3sFYg1QNzuAnkOGV/3Rp+v2
RGSDmFysFQ4IvjYX5OgYVVQMXCPAvDXHZnH3SR3345IiT/q/03sQz8puh/cMKiFB8ADpCtEpPAk8
yef714tEuB3iHm1q3x5SQuQqfad17g0lK84Dvd3wh60A2gD0VtW/An6nrmsnr3aSYJiVh0wA9TX2
cFTLXLLKNfkMlRZx7c4XDVB+whB7PEdWbRwgJqgNe/wligYYN9HEyxeTBPNrD1XbjBl87RMgwvZs
HlT3CYnCGCGfeEAmk9n/dpeUJewW73tg6CL1px7kHcN67zapld0lbb8sJdgjliu3OwzacwTwHKyj
8MQWBWvsjaqsYFeTkpEhnfO2+uEywfI9IIDovra7oOu1VdsAAZKtI94mwOBF7bug/+3s4RLQ2zre
FJmI5yp+1j2/SgDzfkKX7P5xYZQ90nrMQHCfmLTskC4aZsCPC0sQbIHmcFEQtwtdux02Olm/OcqK
dy6aYnBsDawT8p4b+JJEyOWwHweiLdsxWCzfGyL6/y2iTPdJPt+LZBEbP9NO+DQYdQKdXTGctDcL
dHXDfzYC32yTavzmBvwR8Ns+UbsEQ9dsNthguYejEozD7uGoVZyT9VaJe2/Gu7GIe8bQ/Vlt0x6v
WtLVxBc/GmDcRBMvUVRVNUzoig3eXiWAjvWNrr5lR4Me0o1ihABbNwmAd5YYZG8QA/4ZvdfS65ZY
7JHVyOxhXEogXBluD3kA63UXSnBBBlc1u4C0zBq0rZd0AZE9He+m/j9NwRoLFM/oHHskY94imbRZ
YsIwT1S+266qaopgg+0icE5t2iVAxOtq63WSEVwkWN4+ohz0BqnxXSIkGEsEoO8nmHez90MEaJ7S
MTyp6CUAuZMlzR56GX1F96wlSYTt60Y0EVmrs3JXyZ4OUSztw6FN2wZp03bQxiSfVCLXLg7lsRZ0
PYfOJp+CW0XZ/scydWLKIe6DJ31v6fcrxH2b7YbV78FozRGf71Y3/Gu5t1jD3s9RRtf/m7l1G1vE
fe8B3m7Bt4+RavxWVVXvAO8dB0rrNk/n4rrcBoPlcpLrSUBZHMWge0PtM8t+nEXcTgOUO4fcWeaI
Z2pcE7aGPf4SRAOMm2jiJQll4bsU8U8JINtDgDwDQy/Jm1lysY1BUkLgRLqLxJf+HQK47hf7GXRP
EiDPMo2KozrGPtI32OWPy4H2lH4v1HXtpWQDQif3jcbLh4lFW4Q92D0tbR6yxqTrQj/JtlpyYWeO
YTJp8J6YZ2uth3Udo6Ted4Yo33yacPMYVx8sEkzwIAGuNnXOEUJacVH9c9vXqGu3w4ELdtwk2N4l
AnSXzL410pB2cltqC9KQmhnfUdsm1BdLJIjs1bV3qlC3ruOWxT1c8OM4mYqZ2CPHK8BxTU62qqqq
Fp4jOPbz08XRZ+mRENM6ToDgGXJC1EdMfM4T/ftBC/7HdfjH3y0UFD3wx62QOpzIBhYgtfw9QUwu
Xwf+AzhRqvFNYFnP+F75cxzQegIXjD5yRafsJ79fJvVtk59fg//GIu4xoWd6pWGPv1zRAOMmmngJ
QgDgDAGYXNp5kGQwh8nB1gPgGKmh7db/zni/R4CGETLJyNXFLhHgwuVzbUVliYYrlQ0hRwoi4Wtf
g3dNfLeMq3135Qnr2AV6NbhsFAO+HQVaBBh8o6qqO8X1DamdbpuXkM1gukS1l6Dv13W9JpZ9lgBK
EOztTbXtEmGr1kVosM+rvxb1M0iwjgbsE9p3nADL2wQg3iBZ9WH18xtFX28SzLwTyixhMADd0HsP
dM9K1w1IYLOh458iQFmLo2WNt2XxdcTz2ftVVbUh1rjlCQcdgDHJTj6iQRbjvKh/DY55juC4BMaP
hCZWp4jPw6vEfZ0i7oMnd3YNWQd+APzfBDj+34hEyRngL/fq+oMnbFOLeDbHdewrZInvq/r/JKnG
z8hJRhdHGVwzwP787hOA+cik4AklGPa/hqOTpjKJ1hNQs9NHrOSqxiLukaij8M1Dkj229riZRHwB
owHGTTTxcsQEAdDMYl4ls+63CGBgN4p9xOQRoOwyyXK5wEUXASptizZEALcWwaSOEuBjk3QgGCMG
9DUxsJZIAEdKEltasQUstYFiiAF3qKqqqoPt1ZoYSSdUecAeI5LcNgmWd4EY2M8QrK1t2cyC3ieY
nn7121UCdPyMYHt7iOV2a2av6xpfIdnzXgJQQ8pRbmm7b+g8f0+ysC1ts6jj9AMf6Ly3yOQ+SFs7
V3NzH66XQER9uUUkus23ve4kMMsa5sildbtFOLp8rVV4tfr8I2LDtgjphgd6A6mOyXkFOK7VDutZ
nwc49v6H7ZfbxhnimTxHXPcA+Tx4wvC6rhOivPmHwJ8T+u5xYmXjLvDXZX+2hyZrnohZl+5nbYR4
Hs+SqxDvdcPu9+DNGrrapBp/0opzlnIHs7SeSHpyOKi/DVDbwfIRkHqCBKMdLJfhEtluC2SyoeOw
xHbVWMQBHdnj01VVrdR13WmVpomXOBpg3EQTL3hUUajiMjE4fUwMyAbAthjzbzOFfQRYMONrPeIg
Wea5Iti0N4lB/xZHfW9nSYeJBb32KiEhsPZ2W8es1VZbSUFKK9rDutU+ispiDoGuOwSY3dQ5nLy3
qP0nSHB0jwDzU7quOW1nq7XXCOD393pvggBXg8R3oCUJZ0nphBPMLNVAfdACvk2whX9BFlHZ1P6L
audpEkTfJF0dfJ+sNe4mizvYYqwMW6Ttli8KEK3I8aOfoyW2lyR58LK52ecDMkHSbLQTCpfg0AbN
AL+HyMxvZ59bxYRmUYznmH6eBzg2UzpYVdVZAgyfQtUQ1RcPiD4dIJ7Hr5KOGXN67zrxfF9DtnXk
isIjz51WQOx/PE36GLvAjPW6E8Rnw5Z83wf+rxb0rcN/9V34NR+zkGosVVlmul2WYcmDZRaetHji
dFiOWn19BCzTZtFWSDB8XQbdJVj2SoQnHwNkEqj10570Qq44VdWX3CJO7LG1xxOF9rhhj78g0QDj
Jpp4gUNA08v7H5DawEWCvdoiAYEHsl7kTqAlc8jBzoBsmmSDXRXODNkaCdQMEHfJwg7bpLzhcLm3
kFaYwWqRA/BhSHJh8P4IQFFs6nouEQChBfwtWdnuTbL88x4hWxgjANO6ru88AZrWiMIbqwR4nSRZ
OtSGM6QE5Q4BxC7r+C737PO8SdyLn6kNiwQAd2GHs9rP/rM3tJ01szscteAysF7vkAhlrfJxWlsf
47b6Zphg49cJz+MSIO3qOvdkH0ZVVZaieHJgED1M+lQbFFIcy89TWTVvUP3WW1XVw6cFCgJwthd8
gwTu9nB+SBbZsOPEZWIy1Evcp2Wi7+8SOvybpJXZKukRvC1AY3eOaVKmY3cTJ1HukpOds9rmAHgf
+EuCHD5NlGT/D9WfF4FrpVRD9/ZImWlddzePAmZLWeCoYwnEvTjUCOsYBsOldrml85YrMt7+OAmG
J1PWIfs+l57LBu1fWos43ctlscfjpPa4YY+/ANEA4yaaeEFDA+Zp0q/YSVml6bz9gitiULIn72Yc
ojLDNkQAgz1yOfgOCawM3pzsZXC9Ri6XT+qcH5Gss23Syip589oeOgBjhW3c1o553/u9QYDQ99UO
O1rUwN/Xdb1ehdevmd0+Arga7BwAPyedLpyQaMC/Qy691yQzfppgb1e0z57O+3UCoP2F+vAhAYqt
+5wl9cjbxFK+gYyvu5v47nXynQt/dNL69nPU17ZTP/URHsebAsSWNoxINuECKS5zPCKtcV3X9ZZA
VX9d1574eJXisMBBB/a5/e9d9dM4MTmaqsKLup1tPsI863SjBOCcJhMnT+m65wjQvqL+MWg+T5Y1
31BfW8c9D3xQ1/VdyQqs+XZC3lmdd5BcHRjUdeyQZdKHSTu2cf1fqU0fE6D4h8TkDeIe9gM/qev6
3WPu1yMhAPvIJOKYhL9yzDZgNVA1yDW7bM17mey3r/v+NBIMg3T7afs+7nNUEvSls4irs6iLk2Kt
Pf5CXu+XJRpg3EQTL25MEwP5EiEXmCQGoQ0CfGyRrKwHq2Gy7GwPWUZ4iqx+Z2CwQoCCfgI8vkYw
aF5StnOCWSMzSLV0hvNVVY0TrN0IcKOu62XpQa2dPe47ZhcYtc7YLwqAjZIaaVeWs1/zKWLA/juB
Oi97r2vbfV3TKbX3rvptktTL7pIgf5AEyAt67+v6/z0CiI/r+t/WMb6v63NVvSGyIt6mjrml9+dI
Z45afeoJiLXh+wQIPTKYyoXEYO24GC6OVUosDJDHyQIfLljRXjRlg7gXq5JgeHm/tGqzLvakeCDt
ufu+W+czgDb7bDnCjH4bcJWM+jIxcbut108RgHiGo/7Vbtc6cY/uAB/WdT1X6MvHiX4fIj5PIxxl
w/cJMO22zhD31UDdIHGdmMi9RwDiG8RnaZiQa4wQVQafC1vaLomAI24h7YC5nICWz1G7XMPscjtY
bj2FBKNkm0vnC4NlT6K+FBZxupYlJbOW2uOtx+zaxAsaDTBuookXMAQwzhEDjZeDe0gw3Ecs4VcE
ECzLN28QIMAFH5w8t6v/pwnHhr2qqqaJQW2LAM4unGGGaIMAH2uETOE8MKml9E2yLPI80FeFV7CX
5A+Arnbwq3Dxil61y7KRcZKFXCYLYXg5e1l9QlVVoyQwXVAbKzLZ8JquqSLAy4Ta9pr6ZpNk0p3M
9zW17z1S7tBLsNCDwI90rdvqp9MEGLOtnRn6JQLUGYDX6ifrmq0HHycmPcexxbZp6+jQoOM9UihF
LOSyALK1kC7y0V40xdZttnM7MfHupKjrelVMpfXAfk57CMB5mixY4omCNfKuYLhC9MsAUV75lK7B
pbLdVy31zW0SsD0k3DfOantbCRrM+RiV2uVJ1wj5LLkv/Bzuk5rmD4F3pRke0/XcIz2DP1UbL90v
A9rDkDSinVlud6goHWN6iGt1bkC7jdw+AZiPk2CUYLlkkyGlT2aUKc7ZbhHnhL6XXp8r9vgh8exO
ij1e+SJNAr4s0QDjJpp4wUJfqLMEeLhJDtB75BKvGRozcNsEkHA525pMROshwIG1mn1EKWc7Tdgf
uCKY418hs9aHCSnDml5bIMDVJMGW7RIA457a4qX0w4Q8YnA+MvAJlNcEmN4nmWqDdxfQaBFWWPs6
76L6ZVZtcFGNuzrnW2rXQwIwGfS1iGS48yQL66Ik+9r3HfXND9VMJ/yNkH7Rt8hKe9YSj5FFViYI
qck8WbK3TGjqJUHyhPpm6ZjB0yAbOkgpxMw/4jVchljARbHAYwRgPSDlA5tiiTdRERCOVrx76pC8
pSb6+m0SNFXEc7pDat33iWfqHum3bK2ykxWHSEC8S1aFs2f3Rb2/TSTh2TrPcp4R0r3FQPqWXnNy
n+0CR0iQXalNK8Tn6Doh0dhW318ingUnfu62u0Z8VqHn5wiIhUMge1zCn++vGV57aruSYV2wy2Wi
35NIMKwPL8OfbYp2tFvEGSi/lBZxBXtsqdnpqqqW1WdNvCTRAOMmmniBQrriM2TVtlX9bQ3vHjGY
mB31wLdNsqxmfC0RGCYGbzOvO9p+ghi8rI00G/UQ+BaZ6GQ9rMH5pvY1kN0nyCzr7WxzZjbabGB7
7BJgzeVtDd7N4poldx/c1LnHCQC8Cfy0ruuHknS8TUgfHgDvkpKJgWK/syQguKVrHSGLmXxIgIML
5DK6mfr31Cf2f94g2foHBICf04+X7q0jXtDxe0i/5UlSx3wkNGnp07W32205vCJwktQCiIkIsCBW
3pZ2l6qq+kisoO3OBnW+p2aLBcKGSBeJaeL+HhB94nNYW/6RXu/V6zPa/jTx/AySOlpXHxwjmWbr
tZcJWcMkKQ86RTyjC8jujlx9mCFZaE/CnHBnZtUTsWWyMMtt6bS7CFBcE8+QNeSHGu0XJZ4x4c9A
GY4WoPFKjd1PSrC8WRy7kwTD5yklHz4OxXbDwEH1klvESeZle8YpySwa9vgliQYYN9HECxIaUAwq
1gmwZTbS4Nc6v9Kmq7Rn8xKm2RovBS+TnrdLeu+s9t3UeXYIwOcCF2bhSiZtnwAW9o89TQCgBYJl
PKiqaoUECdOEA8Bcm5bYzgeTBLhY0TkM5s3yuurepPrAfrLbwB2B4klCAnGKYB7/nhjczShvqZ/e
0HGXSTcOO2nYum6J9MIdJAbnWQJ4fV/HOKv9hzlqoXdAltd2OWUnQhp8uGz1qF6bP2aw9BL1Dm0a
UfVfWdnwiZndOjyld8RoXQEuVFW1TIBAezW7jPhjo0huO0Nqcg0qrxHP1WWd6wGx+mCbvxGCae0h
+mOGrFrXr+tb0fGukGXOXV7cGvR7pN2Ymf1FUvbilZFzOscKOTkcIZPq0N87pC3gBrlKMCxQeJZ4
Zj4gPcNLV5gXPjol/BUJlscl/JWWdf5+qYH96tEiJXtoNULH7iTB8HEs97Ccw+0wUG7p+LaHeyks
4nTti3I/adjjlygaYNxEEy9OmC3bI0CnfUXtFbxKgDRboXk5uk/7rJOMjJepBwgQYVs3yzMgQInt
zrz9GR33OukLvEIAyEkda40oOFFX6ec5XVXVUh3V7DzALRCDnMsGL8sDdJhk/lZJGy0zx/2k04Ct
xKYIwGpgdEfHvEIkWI0QS+Q/IQbaMfWLNay/TADn6zqfy0L3krZvSwTomSIr1r2u6/23BCieJQbo
19Uv3yfB1W31zyQBhlvEd+yazu2Jhl0+dunAFisGCL9gg45O77v4x3HOH8eG5A531PZe4rlrkbrq
xeP2lYxglCx44QnEEgF6e4jrdcXAD0npzwZZQc5FSqYIoNmDKovp9Z3i9VUd34l242qOnxFLMqwb
tkvJlNo4Xmw3Tz5vW6T2u5f4bFjqMUc8Z2am+9Sei0jLrJ8p4n5PVh08n4GDl4EpLBIsnybhr9QX
l2WoWwSgLYuU7BEWgi0dt12C4R8z15YfuVqkj79HsMovhUWc2GN7r09JtrT6MjwTX9ZogHETTbwA
IVbhHPGZvE+ClHnSG9hM2gIxmOwQQM3M2QHJ6NiTt2SyrM1cJkCNAbWBijWcHozuEoDpDAESZtWe
xbZBaAlJFaRlLUsz2we2i2BMDFZdfMQ2Xa4KZjawpXP3a/s1bbdNMI+LwC+oz5bVZx+RYMuShU3g
O9rup6T9mrW/LnW9QHof9xIg95za9S/V1osEsH5V/bNKLKmPkAy/vV1tR7dESjLMpBoUbtKmCS3C
Nm1w1HPZYTDqe/4sYQC5qmPYq7cirh84IutwURU7SdjJY4kE16+pvcvE/VgUuB8ngPLrJMCdJPrb
QNtezw/I+71G3LPSeeW8zn1T75UJe35edwnA6pLn60R/T5PFPlzi1w4dLkizq2M/KJfwpf2f0XXd
5qhcaVWbPc73+RHQzFEA/cKBu6dI+PNvv95fbo5cKzqAZZeeh0clGAOkBMMSFz8L/cVr+23OFy+U
RZwmAwtVeL2PA/0mCj7npjXRIRpg3EQTn3OIOZkl2d01AiSskkkxS8Sg7IpUrkhntsrbou1d7GFL
zK7Z512SgXZS2DmyQIIZXmeUf0wA0H4CjBqwty8br5IMn5lfSwfQee00cDhwCUhf0LEXSQeBV7St
k/26ieX0+9r/LdIWbY9g9pxwZVC8BfwqAV5/SIJS66LP6hi3dX0+5w1dx3ngrwig9g7pzzxCFHXY
Bb6i/jQAPk8wzeVEw1INTxDGSCb7Ee2kZCZmmg9fLt7vUjtXOOoG8FRR1/WudJAjsjfb1DVcAmb1
Xh/B/totZFPXZynDWcKxw9Zs14A5sWQVUWzESXTWZ79DglHrUQ903LvEc25w69UEa9fNzP9EbahJ
OcwE8YyYla9I2cwMcX+7CdBrrfEewWjbVWJd7x9JiNRn9KKOe1u6bLT6sVy3lZfWtZc+z+2+zyXY
K/c7ETgTqwgvBOA7IeHPz2+7Q4Zfdx6B45HiJBwPlr3q5bLnpSWkv2sOiORiA2XrlD/3fqvDa9zf
k9P6zK28iBOiL3M0wLiJJj7H0AB6hkzmcinjnTqLV2yT9koe9CGdBe6QDPEQWYnMS/cQX8Rrem2U
TOSzpvhjkin2cqU9hb30fOihXFXVgdiOw4G9zmIRZ3S+DWKAM/PnBCyb4c+S5a3vatAYJjSpFant
NPO3SLLI+wSQukzqRW2xZWeObxPs7o+17ylSh21v44dq/qskKO7ScW8QoOlV0k3hW0SxkYdqyyIB
Fi1LWCY10rsEQ2ppyAYBiksJRKekIjNtJWNchm22tsikyWeNNWBGEydbyHURgN+V1eaJvrA2/TQB
hgeIfrlN9Me6JmHdsjIbIfphgGRyrSGGZM3XdI5e0mpvhXiGfI+2iGf6IwK4mnnr1Y8r5p1TW++S
Zb7tYe1Ev7NE39/XeQyu7gP3ahU1cegzelbXcb0AxXZeeEQOI6DTsXBH27ENljuB6JeSfS70y0+a
8GdHkEFylcueyLtkop/BsmUVBsvDxTG8/yDpwX4A7AmQfu4WcQV7bElZwx6/YNEA4yaa+HxjktQ+
mi2tCA9ae94ukYzdBimBOKffG6RvsH2FzbjVGnwnSVZzipRlOMnOhR8c3sd63mHC9cEJYVNVVZUs
WQ2HNmwPCAb8sq5pl2ARDQKXqvDUvUwAqxVCj3iKtIC7LkZzkmD2uskS0ffJKoB31aYJciCFYJRf
I+znHuq4G2r7uNq3RgCzy7r26zrPZb3+Y5KBvgP8GsFgv08yx7dINnxc53MlO98Pl9c9SybudXE8
eOnnUYarZBbtXXxQZbnvZ41a57N/8yUyIdMluAeIyc1F0oN5gWDSlwvNaF8V/sFOwjNosd3aKnHv
pknXki0CsE4RfbNNPItmzP+OlPss6rUzJANpCcagznWLeCam9bNPTPq6iUmNteN3OVqy/Cbw0KC3
LfwZvd8Gmm1t9sxJd7rHJzKZHdjndhD9JOxzRxD9WbKoT5nwZ9BreY0t5CzD8OS3E7PsRExPLCCd
Nax131MC6udmEVfX9YbaMEmwxxuE9rhhjz/naIBxE018TiHGYJb4orYUYZjQZbaqKGBhva4ZkC0C
gNn7d5EERh6o7WPspXtrXG/r9Vf1uotimKnxQNJNfFkfaBszGfNq7/vafprOBQ3somBd4WHVtEI2
MkPYn20QoGxE51kh2ON9sY6zZDW/FQLQjGv7TV3/NMls95FaV1dOmyVdKKYIgHdAgPZLBOj6SP1g
S7UPi35/QDCoXYS0op8A4iuke8ErJMO+pkFvkhjIH5Aa7V21e4q0pbKdlsGwGWZH6eZhhtQyC/fx
E0WhFx4hK8/Zeu8uIYWw1KCbdGAwo3wPuFXX9YqONSqpxGmyQmA7UFwj7r8nD2ZnIVj8X1K/3CAn
L3PkysckabdmT2Kz0b3kysQqIdWwl/EN4rk5R1aNvE7cj5q08btHSCc6lWX2Z3SVeL7KGCKkSp8q
uHxK9vk4+Ua7A4T3MaN6HPP8qbLPz5DwZ8A7WFyLnXgsE7P3NBx1tzDL7JU12/Xtk0B5i5R6feoW
cXrm5juwx8flHjTxGUQDjJto4nMIJaGd078uezxEZG1vF2zxsl7vI50OrDGtiC9yD1pDpP64TMya
5igguwD8jGDSznB0iX+AAC9bBIDwoNVLAE1rfd9HOjlUDEID8zgJ4m8TgOYScEp6ulMk0+ryyNaR
7qstB2KUr+j1dfXDMgEa31LbrYl2UpUlIld0zJu6PuuUTxGg2LpiL6nfVt95OXaVGFjN1p/Rtt9X
P4/oPpittrTDoH1JANYsle32BtSnd3S8He3XT1YE8/HXq+qwYmCZfGepjCcrZaGGjiGQMUBaorny
3J6u72MyWWqQAJcXtc8dYpIwRzxD54Arkl7YQcDJdtd0DLuZuPiIbfmceLmp6z5FauR/RNynmnhm
DojJiHXu9kB28RgX3/CKx1fJqoIPCFB8RtcCmfDniWSfrmmemMg80of6jFrqc69Nc2yrxBfGu7hg
n49lPl8W9vkpE/6sOTbYPUz00/6eVJcFhwbI71VrnicoGGlJL5wg+6laxGkibe3xTBWFdjo+l018
+tEA4yaa+IxDX+5nSbC7Tlal87Kg2WIn2EFqSp144i/uA+KL3dXA7ENrdnCYAAST2mafAJUuUGEN
cb+2cTKZbaqsV94hAMdbBPj8UPtNVlW1RFYaWyLZ5y0ycdAesQ/IJDS7U7QIgDpIsL22N3NSno9v
HWFF6qp9TbbmqggWcEzn2tD5z2ub+8QABEfLNpuR+oi0izul9lhXPKZtnATo0ttmOu+T+lffD1fK
cwKama516wqlv+wnAP6AzjMqm6duoFegxtXqyqplnUBdd3Ecg2Hfw0WyeIyT1y4SSXG1+uRj/W3t
7wVSEjGoY++TOt1pYiVimJQXmO118QxXnttTmzaA/137XCDu5x2yQMcwsargKnp29nDRDbTfG9rm
Gnmv3yCZdfe5LcYgJjELx3nK6jN6Wm252UH/OUSWTH5p4mVnn58i4c+scg/xDPq+e6K/Q05qLOfo
J10w/PmFlGzsCrAe+ik/T+AqKce8SIFRYKBhjz+faIBxE0189uFCBgZf9iOeE/NassXOwt4l2WCD
aDOHXvLfLLb1QD6m1/pI32CXgIZkVsZI/10XRSg1mF0oYaWqqg+J5KsLBEC5QOhy76LqTkrC8wA1
wVEAP6r9rHl2Up9Z8wsEa/qQBHGjBFiqdA3W7g6T5ZivaH9LRh6S+t+zxJL4AqnRfkCAH7stXFSf
z+kcF7SfGUgnKq4SwNtuC+6rfe3rctk7xfnGdX3rZHLdIRumJdVN2Tl5suBJ0Ij2r3y9VVX1aCA9
BMaSqVgOMkWyZ1u6N0sEUDzQdi54YReSDb1/q3j/rK7Blnm+zn215TXgG7oMT/Ign3EcQIZ3AAAg
AElEQVTr4h8SIHpM9/IjYmLlNrpEtoux9KoPpslErjldQzcBlM9r20VC243ac07X8IB8Ni6QQPkh
IZ04SVNqb+WHdV2X7iClK8hapx2/CPEM7HMnEP049vlYEP207PMJCX9lgp8nvoPk5NWfHyf4reu3
kx/NSHtF7bTauUV8Di3jeW4WcUq6tva4YY8/h2iAcRNNfIYh3fBpkmG0ddpKMVCPEq4Uu1VVzZBW
Xy5pawZhnxgMzBZvkODWfrr2ObYe19Zo/sJ3eWezcZ0G+5oY4HYBJPW4SSTj+VrWOcpeGmxb+mEA
u0xqRz1AOVmv9AReUd90keBtVMe9Rlagu6vz2cPWbKIHOEsDLqudZsxuqS/6CZbybV3jHQL0nicl
KPfIgf9A5xxQm1xsZY9IRKvFXu2Qnq5j+tuThl46DP5VVgfzs7APOEGnVbR9iKzC5sqCZoVtlbeB
bMdIj2v78J5Rm3C79XtUxzij/T7SfVsi2WLLMqbJaohe8TDT209WLbSjxYHuQR/BAm8X/7u63Ajw
dV33+7qnrrBoQHxJ9+aAeG5apJTGoMXb+7rM8i/o3i2fBDKKz+iq9mkPS2Q2O7z3pYmXgX0uPkeH
KwMdEv7MLltGVtq/mS32hK8Ey14hA63eCcQessrPCpTV7rk29njps9A9N9EA4yaa+MxCukQXJzCr
2084DGxoG5e1Xa6yMhTEl/MQAVSu6zjOsHZyWi8BnsxCu4KYS+Pa8u2B9hklBogREhAbqEBmgpfS
BSeAeWl8mgA+dhsYF4sySYIqW8V5qXuAYPVsNTdEAjoD8NukvvciyTrf1rZl4s1Zgilc0rVZw1oR
LPIlcmKxTQDGSzr/Rzr+OcKF4n21/QKZyGPP3i5iUrFKJNvZ3myQYPt3xfa76toWqbddIAfXXjrb
tPlety/vO0HpQOffV3/Mkh7C9rK+TzCiLpIyoOs5pd/u5y0SMLhS4W297kS3ae03oWPu6zWvWpT3
oIcAkz3EpOYe8ZzO6R7M6vo/LPp3g3guXaHRfbpDSnzua7vLxDPf0mtzOtd5ciVhntStL+o1T85W
CemEJRgdQ5+/08Tz8vAYS69h5Apy0rGaiHjR2OenSPgb1I/15J4Yt8giRaXmeZyYeB7K3KqqWtV2
mzyDRZzYY2uPT1VVtYZsEZ/mOE08XTTAuIkmPoMQi3iOtK3yl7UTlxwlWzxGfOE6cc5geJMEsE6A
WiC+mHdIVnGUABC3xGQadN8h/HVfIwDMIgGYrJk1+IKjJVlbVfrT7hFFFt5Uu24RwPQ8ASw8uJ3R
9X5kqysNQHtkMYlFtfu8ruNmXddLRXudyObjbxBV7C4RAOs1tfPH5HLpNuF2cV5tscXYLe03RgDk
USLJ66727ybY4zXSJcMAcJvUGQ9rH19fqQ3vI0DgnNo9BswXA7SdFNqjn9Ctdho8rREeJxnQltpz
R9d2QDo2OMnRzG6t61kr2ruu/10u/Kyu9et6b0PXOEFKCwwavDrQQxZN+Smp/XXZZgP3e+pLJzya
iR1U+2yf9y55v/sIQDxOMsRzpGf117Stj22pkPXmW8X/7Z+zR0Kf0Rmd924n/bES8gz+m3hO8RzZ
537aSqQ/Afvs5MH2hL/V4pz+HnKiXpl82k3KOHaK9rjcOTrHhoDtCir+8yQWcbLAnKfwBZf2uGGP
P6VogHETTXzKISBooGL9rr1ZFwyYBAR7iQQMWwpBflFPEGxZf3GMIQKU+LO8QzByXs5eKL5AbfNm
26th4G/IKmBOjBokgZ5LsPYQX/J7em9DYPumjvsaAVpsWWb5hJ0pquIaret1YtcYaaH2kazAenW+
c+Ty+6S2f0Am1VwlAJVBmZf5v6prcsne6wTIu6TrvUeAt39H/fe3BFj7d/X/Ijn5MDtjre0VnbNX
1/lQfeFEvD29b233PcJpw8y5gXp7GNBbG2kniTNEYpwtw6wDXta1rKrNBuFXtI8rxq2pz+Z1DUsa
bO1EcYqYYEzoHq6Q9oGXSG9jP2dOfvIz9oH60vZ+68Tk4qr6yF7PUyQ7PU4+v5PEc3KNdBr5JvDL
xCTwr0k2uCImO1eJZ/On5GdhgUw43CUBSFlwpWPo82Z23xrzTjFEgKimGMPnEE/CPsPhJOd5s89b
WtlbKs5RTty9WmRLRTPTllSNE8+Yn9dtSS+s/d8+DuwKtK+1a4/b9e9NPJ9ogHETTXz6MUZWSYME
xettA2zJFg+STIQ1lDXxJTpFgjUnFNkH+AzxxWtpxTIcAq1hUqfs980wH5CgZ1BttbvFrK5hjpAM
lINSTYCuCwQQva72eKncYLlXoPgVYpCYU9sMqg2Ut8TQTBEAyKz3oN6/TbCIF/V+L/D3aoOXOs+T
Uo19gtme02v2fr4H/CP1xb8mQNk/0D4/IL2PPQibPT5NgvOrBBO8I2DlYiCrdVTxO00A41vq90li
4IRHbagMhA+qqrpIMsNmyFxw5AHxjFjL7H6aIZ08tnQfbqvPLNlxIt+kzueBfY+sBDena/wauVpg
Ju6u+s2FO+yDDZnUdh74Fb1/Uz8zBFiHZNUWycTQ9wiJRUU4W1zQ39dIgLGha7UEZl5thSyj7pUK
u5ws1XW9pgkJnMxGGrSsEj7inZw+7Aqy3v5eEy9W1B2KibRHoTXuBKKflH32386L8KqQP89O9hss
XvOE1MWLrqCVwIJRXiI+80cs4jShnUOFbfSd+rhE0iaeMhpg3EQTn2Loi+sC8cW5S2pVzeSV2/WS
RQSGtZ2/gMcIwGXQbFcAa0S9XO7CFa+T9liQTJrZxQekl2evjjOh80/oWCOk/neZNs1llRX1xklL
tiFtu6Dz2cpshgCbe8ANAcdptdNL6LMEeLVsZIoEIU6c8jnMhjpDHGKwmdV+9mf+G7J88zAJ4L5O
gPR3CSD8FW3zd+TEY0XnqIt7dUZ95ImKC1W4wtsusKr7eehEUWeVugtAV13XdzUw2yJqVj8us20f
6RUCXJ8igG4vcEGg20mF2wRI/DkBwu8XqxAehM1e73G0QpjBge+1JyOuJLhMMr77ZALkPZIRWyDG
kn+odi4Rk5F1YtIzpXthreYq6Rn7Q+3/Oil7eag+HtT5pgnwYKs/e0xv6397gu/pnK6U5mfHXssd
wYOYfq+GLJwAMobIRNYmXvI4TmvcHs/CPpMJxs5rmCcnufZONmge1m8nEB/aORK5JnbwWUGTYuI7
xt/Zp6qqWquLqoxVVb1BfPau1XX9wVN1TBMNMG6iiU8rBEoukCDLhSC6CaaxZKVGCc3ZbpF050Q6
SxNcbcxFHnoJAGWweEfHsp3UPFESuiIA3RDhT7uktmyTZXPNfpjJnCVZxOXifV+bl+BPq503CHD2
lrb7iFhOd9suEyzmx7J8mya1wR/UWUntFdKezEv6c/qZIRjDKbX9ffWBbbsGdR4zhO8RwGlabbDl
mH1uHxKV7M4RwOsaqQ28UfSLpRGX9P+S2v5A19JFJgRuikE+pbY9MEit63qriiInZ6uqelVtdFW5
MbXvrvp7Q89CH6HTnSUrxzkbfpUo1PJTYtKypz7sEzA3EC2rIZq58jW1dB8vk0u+G6QEwVKFt9Q3
17Wvky/tLuHn/H0C6A4T8o8u9Vele7ioe9xHPK9niElJN6khLguYmOUfI1hlg/PrOtYMaVVol5d1
4hnpJguo+F4eiUKy06s+PAn0DhHL3U+VQNXEyx2fEvtslnmVTODz5NUSqlHic/U68fnZIQDxHPHd
tUB8XkaBMX3mqx74X4Hf8ol6q+pf7cPvPC7xtImMBhg30cSnEAUYtfOCCyL00FZ+tmCLnZBkZsrl
lF0xzMU7erWdy0Pb9cAJeEMcZcymCWA1X9f1nBhnCGAxRQBoO1zYcaCHo4l5e1q+r0hLr25yyW9V
+9naq49gGSdJWcINAUkvH7aQpljtsS7ZxR5ukUDxNAFMXZWviwD5B8AvEODsNFng46/VlllSMmKN
7FfVP/9Wx3lDfXCXAIAubrJJLs2P6OcBAcZapDTGbKsHLpeM3iAq2LkoxjAhARkhAJ+t4O7o/Pbd
HQFmqygpPU168Fq/+7G2X9F5lgkwXBZAceb8JpmMV1aeg3wupkitsCspbqi/f0nvObltVO+t6DxX
SYu9h8Rz9IruxYpeb6nti0Tynb1fX1ef3COr21m/fLY4tpMiX1Pf/6W29XPiBDv7P5u965VutJf0
Xz6MQrIzorYdm5xXPVqKu4kmDuMTss/+e4dknx+Q2mVLoCZIRxdP9vy5WwI2uuF/GIbv/AHwHeBP
ge/Bb27AHwG//Rwv+QsdDTBuoolPJwxq7hOfM1eP26zreqttW7PF1qoa2BoUQ9pYWceKjmdga32b
Laoso5gkbbns+esv1RXSCcLs4gShCy3Lp3YTJVLNzo4TAMTL2H26VghruLeIog9lhaluoEdg75Le
cwKZl7PPEmDJTgt2bpglAKV1rWPq1wc6Vj9plTROaI4/JICVHREMbF7XNf6VzvNVAohdI8BqRQwy
Tr6yhOAMR2Urc2Jou0nZy4ZeO0WymGdJ9qdX/WQrM5c1Rsd3prslDj061woByGx/tkHqfKdJ5xLL
c+z4cUrnPSCLb1i24QRIVxbsJb1/99XfLo99l3jOzur469rfleFcRa+bBPH3SNu8e9rvLR3Xkp9b
OrcHf09c3lS7l3Vua6Rv6Jou6Xhr2qdFeBP7c1ULEPeQOumdDkzvBPEsrRGT1ZMssJx017FSXhNN
PEk8I/tcJvn1IYaY+PzNELKwMeB8C37jD4Df1bF+F6ih+7vwW1VVXW1kFU8WDTBuoonnHAJ55zjq
FmA7opW2bdvZ4tLsvotcQqukUzU7abbW5Zu7yCIOtguz5GCTrAAGKaPYIfWrLsBRk4xiWdRhjABG
NQGcXayiX+dZIktLOxFqllhaf5+QVbxNaj3voSQnHeMNAsjaQeKW/v4K6ZjhanMrBPA9r3b1at8t
4C8IwPuWrmGz6JNhAoB+TADht9RvHxHfhad0bdaDOwlxSvuvkLpuM4e+H5tElvkpHbdf+7tc9bq2
WSBlNVMEc95HMto1CRB93+7pXCu6VidYOrvddncDZMW7Hp3XAN/FN0bI0svW6s7o/t3TPTur835I
sL8XtP01HXuW1AO7/LcdHTZ0/w50zbfVP/+e2r1ATGruk4lLnph9jQTf76svzqmdd4h736XX0H67
xHPUztRZ7uEJaXsJ4VHSGeNE66si6a7RFn+JQ8/BST+QOSRmgjv99BS/u4v/u4vXutv+94TZSXtj
xGdumvgsXiQ+l3ynrd2/nn++TqwKNfGYaIBxE008xxCrepEYcOdID9aKzqzUIVus/4fJwdzL+E5g
g/ginCQZ1VECgIwRQGKsbf8lAgxtEayvv2i9bOeSzPNkUlmvjjlIsGqXCFBwE7hjEKKl6Gntv0aW
SF7UbztDHKgtToj7ObKpU3u+SiyTrxOs4Ip+XiWZ3hUCwNllYlb9MESAt0Eikeua2uFlebPAC7ov
20SCnR0tbuna3lBfL+v3sI4xTFYIdHnZdQIE95IstUsxu2KeSzC76pwnIJOk9ZglBa+RmeuWBlim
Ycb/tP6397ArJjpRzkl81tX6/g6R2fBmabfIgdZLsYME89RFMvyz2tZWaq8C31a/WeKyQwzQk6RF
2gDB5i8TYPebOt67Opb16ma57TBSaZt99as9v28TE4gJ0nbuMvE8/eAYza+1xdbFl9IlrzB0EZ/J
Tp7SZXiC0wDjFyROAKkc83qnn9ITuROANXNbdfi/lEFUbcdwG8q2lFEXr3k86Cae1y7yszxKfP9Y
xlVqj/2Zc/XJPWKC/4t/SjLGAH+Sf157tCeb6BQNMG6iiecU+rI+RwCH68QXWI0Abjsr1c4WF0l3
Zn43yWIGO1VVjROAwMvbAwRw8eDfRZaM3iaXtwcIpwKzszXpX2uf3mUy2c9f/sMEE3tAJMjZgaEE
xU7k8nltw7VLsH5nCabYkgAvRRsUf5sAYF42d6LfVQK81EQS3TkCLP252j2l6/qWtnlX12JW8Rap
1TazMkhIKGybdocAhmfUJvvXdpMFMey9a7mCAZa1v+dIJxDfB9uadZOA1vfkts4zTOrB+4j7uKE2
+f5Y++tS2g/IxMpRkiG2rtguJoc+qeQzaC24mXOXWh4nkuRq3Ts/b1tE4t0qIW34bXLytUKA6XXd
k5qYrJiB7iLu+3cIwHtP/b6udlkPPEOsCFgic4eUjyyp/2cIYD1IMNj2Mv4R8dy8VlXVhx3AsV1b
XErbk7lu4v7bq/vEoh+KIUKK0VhidYgCpMKTg9In2bYEqCVg7T5h/64O56Btfzq8zzH/Q8raLAHy
Ssde8f9+8XfVti8k8LX0zOB3iHTvGSAdKgy2zRIPcbS4jwmIHxMe7H8MfNAD//J78Js1dP86AYp/
H1o98Md7jYziiaMBxk008fxihgCIt0mwUhGDaifv0xGOssV2m/CX+zrJejn5oiZAXx/J7FpGMUMM
+u/qfX+xdpEyCjOMEMDjDsFYWurhhL4LZALafQoJSFEMYZgE0St1XW/IM3aAdCY4SzCN9ua8oWs5
o9cnSYb0lq7jWzpvKT2xX7E1u3tEYpiLf9g72cyJWVb75l4hgJXtxm5rW5dMXiaYSIPrFbIgyjBp
xzZGal5n1F4nmU3q+FtkopYT6lzFzZXeukiZy02d2zpel0HuIWUyQ6SdG2rPJGkt5wp2znKfIFcK
bJU2RpbV7iEAsZnza7qPNZkI10doxd/RsT4mJT+17uE+AVJbJLs1reuASJS7p/NZz9tFTJa82vGe
2mkJiN0rJnTf7FtsW8F5OXZsEM/Q61VVXWsDxwax/frd0nPrVYZNgi0+saxzMVl9aTL6n2DJ/3mD
2K6nONZxgPTIJei3wWj5Wvm7Ln6X2x8Uf7cfq9OPVzBKcFu3/V22vf16DXot2fIql0GtqzgOFK9V
ZAXJruJc28T30ihZ/MYrQgfEZ+MOAYj/hvjOPCwRXVXV72zAH323cKXogT/eh985trebeCQaYNxE
E88hpP2dJYDDFglizSa2b2/2wGxxRQLjSRJsnSbAhoHSBgEuXIZ3l/hiHSQz/u8Sy9O2HtsmGOdJ
bbNIMH6ndA67Jhg4eBn7rwng0YeYUrVzRj/WwK4KFI/pGpbU1lH9PUwAuOsquDBIVDXr1nVuEmB2
l5RPGBRuEppdFw7x8uFXdN3XCNDkgcN2Xe+QsoXTpKxhnAB4HkxP67x31C+WBIyQ+mVLY+xucEAm
022QLHsXAb5/qm3sRDFNarRdjMJSj2FSC2zZixmlcZKh9iDszHQXY5lXH2wQg66T+DaJQdTH2dY1
Hqg/z5M+wF6KNVD3pOJ13edtsijKA/XHOUISc5N0t3Db7VV8j/R59sTQCXg9OpZdT6xzvqG2nCG9
jm+Qz39FlMTdlxf2h8TE7mpVVR8U4NirMy6dvU+W8t5HnuA8PvyZfKaku+ew5P+k25Xbd2xK8dPO
qh63/Un/l9EOTEtwWvHkALfT6+3H7fRz8Al+l1KKdpeInuJ/M71OgPO2ft0SiN5im0p/+zwQn9kt
cmXH29ii0qXXh0i/+5vEd/pHxGf9DscU9ZAl229XVXWV+Pxea5jip48GGDfRxCcMec1ah2s7L4gv
vaVjNJDt2mIzux64lokvV4OpeTKhz04V28QgP6kfdH6zDwaLqwQI7iUBi8+zpx8XSKgIFsLJRgaJ
BxrkLxBf3gtksp2TAi2XsHG97elu6fwXZEp/Wcce17X8gBioXiWXvVsEsPuGflvDDAGsbIO3QpZh
/phkI0+RrGMXyXS+r/9P6f8eYtCZV3umSfa9JgDikPa3rZcH7YekU8QIWRLZXsOWO7jghIt22HN3
R687SdNVsaZ1vNvaxsypnUTmde6alAtcRtUU9V6f9nPS4gEBIC9r+w91rLPEAG9Q3KdzvUI6eviZ
sqvGLgFWlwgN8RnSEcO6bINeJ33OklXrburedes+DJK66VnSp9lV+PZ0vHWSlR6uopzuuq7lNeAN
geN96dctO1knwUeX/t8UG/w4oHlK7Rp9Rib2WeJpWNVO27S/1g4k90nQedw2pSTgJBB7HIAugW2n
+KSAtj7ORUT3qRPgbQe+pazCrjy9HAXGBsUUf5eguLTP3CMnYS4+tE9+x5bnmCC/I8bJXAbLjG6S
7jz3iM/CPFGW+qR+jc4NMNwA4meMBhg30cQnCA2+Thy6TSb11IR91yNMUztbrHAlNyeooeN62X+I
ABB3yQp2TrYbIfVu/nJukTZYGwRztwkMyVJsSOcweJshvkjvq12XyDLTrjRnV4M7ZPKcNXEulTtI
6nHNuNgG7NeIAcF+t2YxbT9kJ4hNYhB4h6zqNqI2fF3X9DMdw0zjA13nL6ud98kyzAaia8WxegkQ
5knEGVSVTvtYIjJFAO5ttfuW9nVp6Xm1/1W1HVI33CJLSbf0msFuRbLSZmztXnGga7ha3MtNgqF9
SFZQnCUA4aquzQ4RE2TyZ0v38hXt8yEx0I4X93OOBOCvk3Z890gmu0vtWScmA+/oXhiIW688rr9t
0TZO+ExPFNfg52RMfXNN7T1LasS3CG3zBCnFGFb/bmpfu1Ns6F5cAX65qqrruu4ZUhZjTfoWyUg/
Luwfu6V9OwGSTsC0ZEjLbZ4ExHr/8nf7cTuxpeXPcec4DuCWE3JLA04Kn9P67acFtCfKV06Kwge4
W38fx/iWUb7uSnUlG1xeP8X7pVuEWWEzvf5MlhN5yO9fM8F9xLPuHAfnFRgI2zllifjcLJKTwEW9
vtLo2z/baIBxE018sjhDDNIfE5+n0nd49Zh9jrDFhY4R/Z4jl5HN1o2SbESfjn2R+HJeIZg1+9Q6
ees8AWIe1HW9pMIaZqjNjk4SwKKLo8lnGyTDdkA4R6wQJUZLvbQ1s3Y2qLTvhI5jGUkJss+o3T/U
Pld0bi97f0Qk5Vkv7ES/N8nCI2u6Tvs7G3ieIwCWbcmc9GbP3NMkyLLW9CrJuHufj3UNHxPSCBfS
OCAAaa12ndc5DVDNvs7rfK4gN0wywpYcODnQOuphAszZs9krENeK8xvsnyHuoRnhPtLBwl7G9vzt
0/XfIkE8HNWnv6Zjtgjwvlz8+J7tEc/6r5PJltd13Zd17Jsku/5Vknl3f7iAS6X/d8nCLCMk6+zJ
ybzO6aRRT6h2SOmJteC3Sc/rD3Xs8wSA/7leWyJlFseFgdIoyfx5ovQk0QmsngRky9ehM5AugWsn
IFv+/yRtK/Wzrbb/j/39JGzls0QbyH1SwAsJQkvrM29v9tfMtgG/r7W3bZveYn/34x7xPC5x1OHE
27ioh6UUfWSCnEGwtcf9xTlss2hZ2yoxAfP3+RJPyA438fyjAcZNNPGMIZeI08QX2yapzd3nmIIB
BVu8WLxsizZXbeshvhxHOQqqdsllO2vQHqgN9tkdIT1lawIs7IrZ7gM25LV7mpRa3CQAxKCuxUvy
06Qs5AC4VYLiwvZql3TTWCXZOV+DnR1WkBE9kZRVk9nVp0n/2ivqi58Rg8VFArxad3zobEEAs01t
/4+64fdaoT+GOPhPW/Cfq58mCY1rTYDnXRKsuyjFQ7WhjwBwPydZHRe+cBLctK7Pvr83dZ5VYuJz
IJnNIAmmK+27TibknCHBsuUSPyPLWRsYGvAPqK+WCYDqFQsP0PYatg/zR7pGW61tkMmC58iBe0vn
tu3aHgGYDVKHCeZ5lXCh8ATsKzq/XSxmddweAiTf0zWPqE0u8b2tY1v3+xHpyLJFAHn7MVtD7SQn
s/O2prO/6y7xzP5qN/ynLfgH2o5u+LMW/B5Zxe84oGr2r1b7Nzts02m/dg3vkwLZJ9H8HqenfRLW
9kTpwacZj2F1y9/tYbDu64MEryXw7eXRiUSr+Dkg2V7I8sxOyvT2lgK5iE9dbO99azKvwyWcB8iS
82aBDZL9mbFkZ4e0xZwjPoMG1gbfGyd5ajfx2UQDjJto4hlCoPAC6TxgUNzi5KWvUaK88raOU5Hy
g1mScTMjacswSIcEDwYu7OCl8y5ta+CzQ5ZPNoPhpcMSIC0TX+7DxTkgvTKva5vD7wsBvilycNtT
X8yQyYIGdFtqr7XAN8iiHWtkgsoqAagukNX8LpDa41XSJqlLfbWiNn+tG/7jEXizrRzqW+vwT1rw
XxLg+pSOtUi4Kdjbc5dMmOwjwKZLQ8+q/a7MN6C2WKJxjwCydi4YAqZlx9ejY45oH9vkGSyb0TZY
3iELwkyrLZeIycICWfnOBTvGiefPKwGnyYTLn+s1a7ItUbH22xIW2//NE8u582rvKyTz7wnfD9WG
BwSgf1PX/x7x3HyFlB9YitFLssRLpO/2JbJKoydNnoSgPhgiNZt7+m3njTIZygVS+oD73fA/jcAv
tj0Lv7oO/91+XR8pjVtoUsvfYzrvJglmTwK8J8VxgLV1zOtPrKf9vEIT7cexu48DvJYdGOR6X6/o
mGEtw/po72+dvvcvXSD8PWnpiFcb/Lm21aXPbzDrdntbr0bZN9yMsKUQJctshtjh79iHxOfGRZQg
n+VVGnb4hYoGGDfRxFOGWJBLJCNrh4Ia2K7rumMhgGPYYn/Bnie+ND+u63pfDg9e7vPAa+2ql7on
iC9jyyGsJ36o9lnj6uXm7uKY1mWO69iWP7gC3DJZiW2OAC6Tkn1A+ufWBHhYJksQ76tdHgCdVDJG
lkO+SpYl7ias2F4hlr3v6sd2bjXJsBrUXSfZzbeAr7Tg7Q7lULu+G7Zuv6F+uanr/4GOMax2OVaJ
7c9qWyeXHWi7LjIhZp0At/vqu9PkQN4iBlYPqgasZnZ9LzwBsEvFBCm/mFA/W56yRCYUuk/nCGZ1
Uudw+3ZJRvuAmIBYhuPS3ue13bLa4GIyv6T7Y3u3feLZdNW+8yR7bdDxi2rXPpmY6UIdToCzY4s9
nPt0TzZ03h397z5w6Wv3GRwFotZl2w7PKyBvteCXTiiN+8vE5OwkUOuJ2wifDCSA61kAACAASURB
VNA+s57284gC8HYCuScBXvdLCXjNVhvsGnx6MmPGtwyXYLeG96A4dsn2DhbHLKUPXkGwB/wO8Rzt
kQ4Slq7ZtrImvcI9ESqLGxlo+/pLIOzvdLfDBXpWied9kVxxcL9tIsedhh1+MaMBxk008RQhdsnL
1B8RX45eLtvm5IIBR9hixQwJaH5WMM395MDsrP4x0pGgm/iyPUcAoJt6b4IccFok47el9tXEQLFJ
fpGj167oPGZ/p0hnCi8xjhIDwajeWyMGAeuVu8gBySWlnThoFtHa4W/o+v5M2xio2WLtV3Qdt8ml
SGtgl/Ta6wQouwonlkOF0Ji6EhwcdfNwH5wlGNYBIsFsiLin93TOOZ2/JicCizqmE+0gtcReYnXF
PK8EDJBltM1SW1bh6/I+G7rudwhGdoXUEU8RbKyrI9rP2asDLm89pPbZsg9Sez2v7UaJCoCvEADj
PumesaTX/FxNk3Zw7+jcKwQYcFW+SdKucEvHdxlvS2vGSWnKOumSsUgC+27SqaJcVu8mEz+dTHge
PQYnPAsXCYb/OEBrvf/cFwW4PAbwlq+1x3GA169BAl3r5u3ha7DoMGtrOcIWRwH0ASlPKCs5mpU1
+D0gVxC2yGfUALgq2mMnFX/m7dVum8htUoYzQ65ylY4VJSD2e26bj7mmn3myOI0tHnvJz9A6DTv8
wkcDjJto4uligvgCvUt8sdoGbY8TCgZ0YourqpoiAKB1pWt63Ut7Zhb7CcBkULxHAIFJ/V4iAE7J
LJv9tWm9LbQekgDWDKwrLlnHaOuwZbWjT1XzNokkK7fX1mTWifarjatqQ00uPc4RDG2rOPc8MfC8
Qtqn/Q3wjW74Z61I3oLohB+04J+SdmlvEiDoazpHP8SS+THlUP+cuGcQILdMzBslWaRZvfcTYgAd
IQCiwesKyShNqj0fk4O6vZxLbew+WRrbA7MtnA7I5d6zOv8aWRZ7iPQ29TMyr2O8rvfmiYkRJPtt
bewSydK+Qtwv+wsPEM/NDgGmv67z3SHAP8U1VKS20hXwrHNfIfXVLbWpi0x43CIrdzkxcYUELmvk
ioD71BXuXKVujZxkjOlnmpT7TBOfkUvqw5OehR/Vdb3GMaHVmr2XARR3ALzHAd92/XLJfJtlLV/z
bzsyeOJWylfaga8B6y753Pv4ZZKcmd9hksEtXSIg5RJeEXA+wDYJivfbjjfOUcBq8D1PfBY2yeI3
Lt8+QuIgkxKevBoIHxR/e9s90mt+SX/7c+3Vi0qvPaRhh1+qaIBxE008YUgzeoFkDidIW661xxQM
GEFssQYzMxT+4i8LDjgxxLo2yxIekGDTVdfKQcilgl0ZzgPBCMl6Wo+3T37R95EV2KYJEHKftDrr
E1M+SrLTD2X79oq2a5EV8mwf56IWW4Te1SxQFwFyfkYywxuE5neiG/6LEXinTR/69XX4py34Z9p3
hADpUzrnzS5Y/h5M1AQ7+CfA78NBN/yoFee+TIC1YQJUniKZKC/bGxi6SIk1xq8SA/Mt0kt6Uttd
JQdC61LXSCAwRhYeMeDzSsABKZmYJgbxe2rjeVIec0PnbhGs8Snta59h6x+7SS2yVwVm9bNJaKpL
+7gDgrmf1XX9la7JS9xm/60BfpN4hjxBuMbRSYaL0ywU21j6sUc8O2and0jXlR4yyW+cWAlx5a9J
cgXCGk5bEfqZP0/q6/+PbviH34Nv1TxdaVxNSp04+rmFviMeJ2d4ZsCriW5pKVaWKi4lD+XxzRo7
Uc2yB7O9cBTk+njtWlzIyaBZaK9IGVibcd0vftwuTxYHSCmPq3SaCbZ8wRPYi8Rz6O8fn3ObZIAt
z7AdWymTcNsWi/O42uQORyvd7RLP/wYNO/xSRgOMm2jiCULa2ivEl/Udss59F5FJfBID5QFiUccx
o2YNr1k5h5NApsjkJSeZTBNgYo34/A6RvrAuRmG20S4XmwTwtkuC5R8+/qKuq4cYQO6Q1dw2iEHh
CgHm7ul691T++ZLa/77aUUo/LqrNHxTvWSd9S9c6RrJJM8CbLfjWMVrhrxLOCnYeGCYGoHXg2wfw
cB12vxv9AHEBH7XgvyetkwyebA82RzDJrqy2r/6FAPWeXLxPTC7sPjBDSk62ySQbL83aim2LAJpu
J6Sl3i6pIbakoZSr2CVjQffWbiK2rHPy0aCOOUeWkzYgvahjfUjKHCxZeIsE0++TINevLZNJhq8S
gNwyhzldyyJp92Z2bkETQJfbtnRinVwhqEggbfAySn4OPGEbImU7JVivyQRETzD/gpDlfNCCP1yH
//a7haLiCUvjOvFx6zHbPVOcAHjbX+sEeA1snYxYOi8cAt7iXAa+pTyhl5jolslpDh/XriQGqGZ8
LWso5Q0+pplar3Z1kZ8Vt71s807xv4tgGAD73vreW+OL3tsmNe+bBPg80KTGpMEE8dx5P7PH9gC3
/MZaYX8XO4HO7d4sfvwZ96Sgh/TjLrdtnCVe8miAcRNNPCaKim89BMiriS/VXjJz+aQwg1uTTO86
AYrMOJQD8RABgDYJAPQ1EiQ4w/kc6dU7RLKSXv5H/xtUmY02IDZgXiAHCrNM/tI3eJ/UPu/pWmeq
qjqrPukmANUm6UN7kWBnDwhA5opl3Wrnj9UXl7XPhzrW27quk/Sh0yQId6LMOzruD1rwf5KFQvpb
yVauEqyrrd1cAOOnxD016LROvI90vThHggRboY0TcouPyHtnOzIIwGggWBGD5W5VVXYfmdb7qzrn
BbIYxSqZ8NhSf/6SruOm+qsf+CZx798jGHm7NVhKc4rUddu9o1v9dVnXYp/kO/r/NAEAnFzYS0xG
3iLureURrnBo5vqAnAT0VlV1hnhmRkhQcob0BrZbioGc3SfgUQsuJw9Cls29SPo2/wD4vvrGwO5O
C/4jMinxSUvjDiOg9QTbHkYb4D2J6f3EgLftnKXEoV/Pl8Fqe2Jbqe/dKP72OUtXCAPgYdImrZRP
eDuzq+W1uCJn6SZywFH2t5RCWCJjvXgpbXBSnD1+dwq2257BFzRJt5a/ZLX9zA+RxWNMRuyQ4NYk
gv2F/V1q7fIKyQxbtuE+9XfRZsMOfzGiAcZNNPH4MANxU0zYNDEY7RHWbK3jdizY4m3ii9lJGGfJ
hLJdJ92ptPI54ov7Y+LL/jIBSFz8wEvxM8QXtquy2VfZrgAzJMDdl++yLcJ2yAQ+6zZvEuBlkCxW
cUrXOk8kIx1Ig3meGLBuqR+cpPYqAVpaBOBy9bB9AhTNk9XYvBTqhMHLBDN9oj6UAG1nSG30BYIp
/TckwFvTcV3I5IbaZ8bHFnkTRMJZN2m9Zps49J6Z5V2dB5LJHSWTDJ2Es2lgVVWVgXKtycS07tGS
fsxwTeqYt3WMHdK/2Uls75Gez+Nq50P1qb18e3W8UdLFwhn95/W6fbFvqj/Xda5+Xd8c8VxMAb9K
PAN31IdOBhwhnuGzZFXFKVJi4lLcruR3mvQF3uIo42iHCldztB+zk0RPk+BllnS/+IAAxT8mpUHW
fhq4/Lyu67/lCUJ5AN06p19z8tXjEtdOAryWmrQnrp1YMEPAt59geMtl/bJQhKNMbNsmy4ybmd3j
UdBrUOiJtNnestCFJylOTDQQLpPn/L+vuZ0BttyinQU+UQ9csq7qi0HgnEBwKYuw9vgBqfH16pBl
ELZqcy6AnYQsqXDuhlllO+1sk4y4GWY78WypnSdJ6Jp4CaMBxk00cUIUQHW+rutF/e/Eso26rh+3
5OqSy2j7lUJOYR3jls5lb9tuslTyKeKL+hpZGW6KWI7eIkDJLjG4ndG+94jByADe5zMLskay2NZo
bhGD6QYJ9M4RA8+PicFhWNdvxvkOCYbuEcvpF9SeG7q+V0j96D218y3SGN/OAx7wx07QCv9VK4D4
L6p96wT7WQHvEoObfYq7SU2gqwZeI0DzGdKR4VxxLyzpeI0AYwb8twgQuU2AyhYxCHep/bXOPdcB
6HiAniQ1vQYUttuzPdt1neMMAcgt+3ivuE/2171BWr65f7dJx4l7qAQ4MaB7dcHyjjX1Wa+ud4dg
4nd0nivAt3RPruv6DghwYmcJAyL7X58iC6dsEMDC2mBLJ3pI0Gyg1UVW9fNSeU3q8M+SE6wDgqX/
uX7fIl1SWkVfum86LmkfA3htQeiCOJ8K4C3a0KOJsyfP7cC33dGhdHNYLv633AE6Sx2Gi2PZw7y7
+F1qf319nqC0A9ySHS7f2wP2C0nDIKkJNwg+Vg/cTi6ob5zYa5mN7SE9YfKE0IyzCx257ZY4mZV2
KXhXJfWkwe03M+x8A8skPDlwuw/lGzTxhYwGGDfRxDGhZclXiC/CuwK0BnHrPCZBRyyPdarLhb/x
NDEQmbncqqrKSXNODLH36wFZyMMMiDWqH5IA2Et9ZosGdazTxTEXyBK9Xvo1oFokNcUDBPM7Brxb
1/W82E4X2vByv7PK7xPMphO8HhJspQHRBAHkBgid8A4Bri6StmDb2n/wAN5bhyvfDYAI0bB3W/Av
gF8o2vm2ru9dgl2/r9fcD84IP1tc6wRZpc6FJsy+Q4DIA4I1rYjB95ZWCnqI52FI17dJgEmDtlNV
Va3Udb0jwDOtPnO1NzOZBu1OkPT38BjhDHFa9+uG+nmEtNG7rdds1WaLtq/r/5tq2yDBwFufvkIW
WLmjdpzVtVhnbuvAiwSjv0cA0MXifE6Qs6+y/an7yKQ6388ptfuATGb08jT63xMQM/KWEZXs8ynt
c1M/9/TjMuIl8LYjypDOaz1tOwhuB7zufxeRMQN6RNbwpEvlAt7WSZdJaKUkofRQLhPbbLF3yPgW
K0o+bgmAS30v5GTD75fyh/+fvTeL0SzLrvO+G2NGRmRGzvNUU1cVu9UDJ7ElUtRESYYsAR7gBxNt
QBDgB7UBv/jBkB8EGdAA2H4yCBi2H2xDFATYAgw/SBRkE5JMmhTZI3uqKec5MzIjYx4y/vj9sPeX
+0RUZFZVsylld90DBDIy4g7nnnv/uOuss/ZaMp5QTO4aO5nd7WabAbvALwmAsz+CzgPAVNd12rUp
gdlTD7x7rPJv5QHqM+rfFgGr8epPqULTk7mNRa8C4WGzjXUgG5RDihMwC2WfsLNmQ0cfgbxSt54d
/pS0Hhj3rW97tGSMzhN/HK9TDJZ+vHtGPjf7jxHABOC2f1DzxWaAhqBFi6+nBCgQ0EEAC2UYB7Mv
UMV4x6ilQIHrGhULPUKAxgV2ft51vNjIvqj3WyXA35AAUI8TtBvK8DC3n86vBcLhQTsxgxws+DmX
xz6S46GP7iEC2P9BXvMv57UuA/cG4Y6gFOPJIK7jTxAvvjuUh/A1Aixt5fH3EWyuS6JqU0cJgLme
P5sgwPxRSupiFLQTl5E81lYu357I310G7jWe05td163lNZ3KojMZs+ns7xJlAbVOMVPk+Mnsjue9
fJzfz+Y+i82XjOwIqbGkigans49Qsp0J4jmxeOhc3oe5vJcrBMg4nf8KuK9lPy1qmqQcWXTdkPn3
OZ1szg9VKCpD28pOnua1LmZ/LlEabR0pxrKfykiM1DUMxWhzQdtpSk+6RnlA717y363jdRXo/sdh
AncVtk3s8bVXYVub3NfKHDZbxrRhqwXAM/n3RFnUs035sC7Y87pdW9zWSh92y7+8Hzt0wP6Na653
P7A/V7eUI3l9Pteyqhsv0EZb/GZx5hQlZ1oii3wpCYbR625n4akhIH6+dS2xGO4O5X8uWJcZbjX5
PrNOLhwDnSV6dvhT1Hpg3Le+7d1OEX+Mr2bRlOB1i3B4eG7VcbIfshlXdrEMR4mXiXZvrYbPMI53
h8Phctd1FnkZgfyQACaX8tjqMA270CbNZcMtAvg8oUzvn1Ig1wIxmp8LRrQjmqUAhJXbrQ7zsxQo
G1DezvsokDJFLM1bZDZKyIj/gEik+3kCYDyi/Hi1fdMJ4gJV1DNNFcR9k2BRV5qxnSBAgO4aNwlZ
wGeJF6W6aq3ZnJTcz3OOUpOg9fy99k23iYnObmAxmr8/T4HQm1TRkED7KQXsDuR1vEY5AdwmXuQC
LF/ORjrLvB0gALUe0V0e61j+/jal+1Xra7HiPuLezmefX6EizfcTYPX7BPM7Q7HscxRY0TvY6v8R
Asw8yb49pIr3HFNT9nzmXqNkQSOUDv1w9msh79c+ivVezf/va7ZzIikAsuDq0XA4nONjtK7rponU
SplQJQeth+/uxLYW+LaFbYbitMB3N0vqJGmUAJotA9yCX4FlK3toGWD/duiL3To9bFHFn7a9CuC2
drlZWNR3OBlgQbCgUZCtddkqDYjeY2zHiM+b2mBDNJzEL1A6df2xD1C+xNpL+gw4IRUwT1N64SV2
RqQ7Pi0z7Dn8bDg+OyQYPTv86W09MO5b33a11LadIFjBxVyK1cJqYTgcrrxgX0HnOME+rTS/U9og
i6dPsEyWDOVy13UnqBSwm1Qx3FECfOlfe5RiVZRadMRLwKItgbXLg7LMAmZBnfrmK/m9BWEWQ+ku
oYzgtTz/+xQoV1N9Jv8/mee7T+k+v5PX9FcI1tb4XwHjkGBv/wJl4TVKvDyPExrlcQIUX6GihKcJ
QGghzXGqSEZHhGvZFwNMFvN+DSnGSSbQ5dVxysrp4S52z3E73RzzA4q5PUxpescov1dZ1ot5zbdy
X8+nddwG5VzhpOBVysN5kWJa54jJhsvr0xTgNNFtIq/zUY6PMgXH7yoBiqco5xPZOZ+/cQqM6GCh
/rgFj+rY16jUvwPEBOUSJUmR/T2SfX9MuWwYdX6FKtxUZy/zN7/rczbNC/TFuc2zwra8lpPASrpp
PK+wrZU6PAO9BCj8EKPYgN/JhvHdC/y6bwt8Wy2wgLT1i3YctDdrWWLYWx+8tRu8ph54ugHA2inq
3qDc5wGlB97iOa1xi5jhw7IIJ3n381+dSaZze1dvJpv+O9ZQq1yHKYnEJvX3yKJOx8HnQ3cKWWo/
z7bWMrNnh/vWA+O+9a1tCYIvEC/l+00Yx36KZdtrv47yyvUP+W5vY6vvbxLAQPDl10kCHJ0gwKRg
4hHF2hiMcC29hNUKn6GCCR7keVyy3qa0yS4Z6zzQEQyOFme382efp6JNtXLTAxRCy3swz3Ge0u5Z
6Gea2SwF+I4SIGoR+DLBHs/lce5RQH+OYDF9ae7P45uSNUvIGX6bChZZpVhnmTK1gjK493Nbl1Tn
89xOTi5QwRFLBDhbJ17ab+extIral9d9Oo/3iFjuF7y2y/UW7Mkan6MmPQsEGHX8tXyTXV2jfF0F
GIepidTxvJc3816pQVU/fIMqUnIlwLCECSrW+VBew3VC/22MrswnFBDT6q+16jpPPL8P89oPZp82
8/gXsq8+S0/zHrb6boscdeUwKGEfsDwcDjcAk+kc45U9JqqCIwu49kpsa999MznGnrf18N1gD0Bp
E/zuYnz9freG2M/b7sI3P6s+l7KWToZa6UML/Np0uBYI76mFzoK2tiBuLz3wChUOs/5RILGRRcj0
z1KWax5PRx2fnRnK1cRJqCDcwsJBM5aHqQAOi/csLnV1xW1lhpepifkMVZfRumuQ5+vZ4b7taD0w
7lvfsuUf+UvEH84b6ZdpRb+64ucxQ7K1T4g/4FutY0UyM7JzZwkwcJlIkFtP2cQhSjqwQMkiIF4i
LmPPE6zyCMXQ7qesjqAAkozSDAFWLOwRHFmgorbPwr91iqERfK8RgOn1PMeAWoJfpKKH1Ue7rD+V
+9whgKm+w3eJl951gjG9mMc6zU7d6Km8ZnW1V4joaIuGIFhI3SVkgL6T+7xB2S65lHsr95PJmqIK
Ex8T91+3EAu7nhDg74uUtOFecyyXfwUu2xTTNkMw7DorKHFRvnA8x26NAPB3KR35ODHxuZTHHad0
6Tezv16zzNv95hyLFIt8PO/FPBWzbOz10xxHpSVqeh3jY815ZUu3KVb5GmVjd4iSXMgEP6F00MZf
d3kewZMs4iLwOD8bJ3I70yfVO6vbV7Yk23iOShyULZft3e3fu5nXtfy8kJ6u60bz87ub9XUFxrZb
u9uyvqa/ycS27O8yO8MtPH7XHKcFzLK/ezK3WcymZVkrhVAPPKAkDEohPiT3eM6xlUXMsjNEo3U7
uZ3/6pgyldvOUCBWWdFWbvuUknvppCF7rZ/xTSrlU7Z/H8UMLzde4a1UopWVjFJFd6s9O9y3vVoP
jPvWt2pniT/iHwyHw618CR8kXlaLMlZtyxfFUYo1hCpSattBAiToCHEzv0a6rjtMLI8b6DGd+/iH
X53xEwIgWUhnMUrrb+yLt11+7QhAt5jbypDZb1llWatHeT5Za90MTlNM9y2KoZ7Pfp+ggB95PecI
tvUu8HXChmx/7n+OeNFfJaKGxwng5rVaEOS5RokX5O/ndfwMIbnYl+deJmQdsl0Puq67kGNzJc/3
BuVdejyvV4/TRzkmjpOTHtnXCaoY7gmlbZaRavWn+qlu5j17hbjHc9nnG1TBj4z4TUovPEYtR1/I
fgvGNyibvoeUPd/FvDfvEpOQ7RzX16kCM4vbDA6Zyms4Q2nHb1FgWycWwShUwIfP8uXsw0Qe80he
6wRV5CSzqc/1cn7dpLylHTcLAie6rjuS92mk67pN4jk2zGY+z9UWtql9tXhw4yN8xg2wWG98jHcD
4N3gVxZ32GzrxKNlo93WSZVAUDa3BdetBl3m1AK4F/VfSchua7QfSg+869itLOIQtXI2QdUTWIzr
hNyVqaPUCoeTA8dDq7ktyk5STb+2bgPqudDfWtbYc9+ngnNGCFcMpRK7JWQQ92F1r7/jfetb23pg
3Le+AfkCPgbcGg6HK8kQaSIvu7Z7HwuAtgh2a5DH2c0WjxMA5RgB3EwIm6aKRwSIAwoAvUL5dvpz
X1azxMtF3SUEYNIzWcZ1nLLYukcxVy0o9gWtdZo+tS5xb+b+U/l7/XhXCWDTUSzqHPEyskDKpLqv
EwDnUPbLIrzv5dicyLEA+Hb261Xixev2lwgQdoOyepukQNYt4mU5BSykm8YR4p6udV33gPLsvZDn
+oBi+dvwgmEuO5/Pa1sh2FDty6byd6/n2Dm5kDUz1MIq+Q2i4PBy9umVHI+55ms7fwflJHGRKoic
p+zKtMO7TwD3NygPa1c+9Ii2CNIJ1dPcZ4OYMDzJc2qNtU7ZfQm6xik9p3pxdedPCcB6OK9LiYgF
e0OqMNBVkWuUc8i+/LnyhVl2glHT85xoXCeew2U+7Ohg+tlCY4/o7/YCvSf5cGvlCe3nw0JCwe/u
FLVVdsofYCdr7HHaEIxVigF+LgBu+u/qkCB4sumHhX/GeL9QD7zH8f3cOiFTGqakRkcYk+H8W+RK
hP0ZpZheUz4F+v5O2ZBAmhwzJ11q8vUSFgw/oMBwR+i3j7AzZl2/bLXKO0J3+ta3j2o9MO7bp74l
wD1HLR1DLRMus4c1WxdBF8+Yq5Rd+Ed+vtluAvgCAUTeI4CNjhdQhWVKFYxG9UV6lXKMMLCjBRxH
2bm0rV5P9u0Q5d/psrd+rbovPMy+yOi9TSWMXaUskW5RGtmpHBttvsYIkCkDph2dVnBfoDSWLnHe
yPOdy/6tA7+V5/wFim06SDkfXMsxsEDrdNOXh7nPel776/lzg1nOUeD1IaW5PUYxpo+pQIyTBNDb
Zqfl3Ss5zspMBA4PKCu71wnw/YgAnwKJc3nPDMKYz20ESwPi2biYYzNChWuYvCf7+zrl6DFPgG7l
EWcpdxCZwsUcD8en1W0bmjCgwMoxyslEGYzez4bNONlxFeIhxeyfJOLMvXeO02qOkcvh6kIfs1Pb
q9ezy/bqQx8Ph0OdLXa3Z0EZyR62ARa73Rlarbl2hRYW7mv2c3tXFpYoAOwzLVj2C4q1NIBDBvjj
ShbUAbdFcfZZb11dStY/Clg/5xymXh6iVgVGKImHkhzrCxxfJTVtGIksup7B/r/dZx81Oe9yW912
LJ6bJp69D4Hh7Lf31s+fEwzZc2UdCz073LcfpvXAuG+f6pYszCvkkn0CXDV0m0Qwx1azfVtkt7RL
l3iAZIuTfTmYxz5IgMabBGDRimqRWoJXO/cKO83qDeuQUb1L/MFfS0bTF9MCpW0VaO/LYy1Q7KFO
BuNUaMQYJYPoCLCsPtUIXwGA/rKnqaVsi5WWKY9WWRwtzDzPGQJMXc/jHstzDAige58IATmb13Eo
r2kE+D+JF+Bsbvsovz9OJa2NZR/O5LjeJwCa9nXfpNhi7aFGCSDqfZjN3+mW8QOqAFImFQIgack2
m+f8WSok5AlRkLdOOGmoi10iwL8TqMOUp+rZvP5ZKtpbELdOsffHc79HBGg3LOY8Ab6nc98rOQaL
xHP4M5S93hg7bdBaMCZYfkiAnEd5zIuUreAsVVi4kdd8gHpWD1CpiE6+7hJAR0eBRWJi+VwA00ia
ngH7/NleDLBJaW2qmVptKKnLFPWZcLVgu9le8KsDRLfrfEpSoBjmDSqEYutjAmBZ11YLvFsPLBhv
/YE/Efspu0oB4cOU1MHVn3lKk+7nVT9yV892Txig5C9t7UJb7Ls7yU9A/4haCZhhZ3rhfZpAja7r
RnJy69g4wYVa1dCurWeH+/aHaj0w7tuntuXL4jzxh/bdlEKMUW4GD9vl2F1FdvN7yCX2AfONxMKi
o1tUpf4U4YP7OM9vVK+BItqlCTgmCBA6QwCKOXYW5bR+oNOUFk9d8hJlfu8L/ATlA6w2s2VafamY
LnUtf3+WkCJAsXtr+XvlBTocmChnoMNJCoReBb6RxxujWMyNPP4pyknjDgHGvkmwya9R2tiDxAu0
1VYu5P9foSYe25TnM5S2+BbBjutc4Mtd+co8VYRmFLauCgInI6bP5LgamqI28hQVaXubKpAcJ0Ci
DPE5ggE+nvt+n2IlH1BsmrHPxyh3CBk55UDzhG2bwN+Cyjfy9/coFwaZbKU3snQWfJl493kqmtnm
da5RfrGCpq3sQ+vbrPWczPEyod3fvRrTgtB9Ob7HKPDp0nvryrBOWcZpMiBZhwAAIABJREFUBabN
YpsM10YdjzT3xPuuvlsG2JUddp2rtUD7WCDsE+qB9b/e/Lhpe7vOpexCfXDrFiHDep8Ap07KdYiY
oQoZtfizABeqeE0nmq7ZfrbZTzBsqMYitTrivWn1yrvBcJd/S5UjyUavU0WrThh7drhvP7LWA+O+
fZqby8DXM8ZXtvQAAS6eRT4n8D1CFqftYe9zgHoxtxZjW5TVmyBBTaegcZqKKb2VlfjqfB/lOZcJ
gNRaZMnoCHB8iQt6BYIX8rqMuBZACtI+oAq31P75sjZM41gzLtcoOcgPCA3xqwQYlXE9Q7GRBkQI
1B9lnz7DzsJBi5fUX1/Pf5eB36R0qLfyeiYIkG089Zv5/7dzLC1AO5L/FwQKaLU3s+DuJuWx+jlC
/rFKsL1W8ssIHqXAqN/PExryJUob7DhfofS8ygKWiUnP23m+fQRo1bJsLq91kpKcqFk1ge5K3qdX
877JDrdBHuOEE8iBHBMZbi3fDC9RxgNVlDhJBWms5zkfUVZ++6i4baO3r1LL/eqtXfKGkk4MKI/f
3eyvfTDBcYNKMTO0QgcDAeY45UghiPIZlP21D35WFimwahP0PiuA4wWWbXu1T6AHlq1f+yR64D3O
pxPDAT4si5DJVurjZ1Ewq7OEemGBcDuRWKeCS5zg6gG92wrPe72Q57NQU8JAMPwhZnjXtbRSicX8
tffa4rzVTyoh6VvfPqr1wLhvn8qWy3JngLnhcOiStuzKKo01215FdruOpQ3YkHqpLBMvdSv9r+c2
G8PhcDtBuEu5Y8QLYpIIGRBYLhMA5Bj1ItXHGGpZcS2B/QgFIhao4Amjes9lH/+AqiZXd/wGZX0k
I71JgJ0W0FynwOWjPNfniEnG/jzfLMGGfouqTtfGbI4AjWeodDooBtMQCa3jjgL/hPJbHicYtbfz
ngyoBMGTFKv67Rw/NYcCxKPN9xezv2cp7e6JPN7nc9ub1FKzjJ/erQKKa4S0Q131wbzO9/OYSjOG
+b02ZacJQLs/j3GZYvsFq1+kqvFlOG/m8fUb/gz1DMne6oDwWo6VKX5KdEaJ50rPa6UNT5svgZP6
X63nBETacBmK4fI4lI/zBsGEyywLetvYaMFXC0a3qQJR2XI1zxa+KX1w5WI5j79MPKct2NblQ9bz
cHPOHUEYn5Sh/TehB951vtYtQv9gA1eg9OTz+a+JgDK5Oje0jPBuLODfGyUy6qinm31k1b1WtcWP
iHvQUTaIFuNpcbi2CwyPUOOnVGKVeg4PUH939nQI6lvfflStB8Z9+9S1fJFdpKqsLZLTEWC+Wc5T
K7lG6I13L/t6rCkCbLp86B93waMFcUv5YjtJvPifUEymjLWyhluU1/Dt7MMhijF2KXE1XyxnqJAQ
LeA6ArR1eb3fo6KPDxNg+SQBgK8Q4EfHiHWqwG+F0MtCALqHeYwv5c8E1AcI2cPXc7sLVHHetRzj
E3nsD4gXtz7RHZWYt0SA9e/l+MloG49sEeP53O+bxMv8i5R/8RTBYvtSFoyaQKhf7wOKcZdts9Dv
GvGyFwwLfCZzHG9SVlUt8JIVXKGWy89TOu+JPNciVWDpZMj7M0OAm5uUVdYPiGfiC4ReeCKP8Ti3
kQnX+/hEjq1a51vEM2/a3AnKeUFNelvUuUCATAvmjlDyjzMUIDbNcTL7MkrpxGX99breK7RCdlXW
8iD1eRRkDfI8LfurV+4YJVVSLuR90PZPyYDShx1yqI9q+bmVzWylEIZk/Ej0wHuct5VFzFKyCAve
LFDT61t/ae+HriaTu/6FnQz2RvPl36OpZntZ4ZH8V1Zeidd6HtPC1Tbtbi8wrASjlUo4fkollID1
7HDf/o21Hhj37VPV8o/xJeKP/rWGvRV4PBwOh4LXQ6RP8G7z//z9NOW/+YR4MXeUtnWOsl7bT7Fo
xwkW5SH1EjL8wyVLwaiss2EQAINGn6wO8i2COXQpUxcJi8C0k+oIkCnTJPtzm2B5j1MvNP2U9wG/
l/tcoCQdFwkA8s3s6+sE2H0vf/ezlPuAFk8HKJ/gFYrtncxrHhIA/csEKPvXlAZ6Kb8/mv2bp8Dm
ap5T9vs4JaFQUiHYM5TjzRy/28SL3II78txqcecp8GXhmWwcxD2WQRMEO+4dtaR8Iq/LivtHOSay
ud+lNMML+fPjeT3b2ZcTeR0nKCmJaXOysk7yNvK+/YAA28cpYGlc7wniuVUTrSXZBuXEMUtMlmTn
z+U4Pqb8i2fzHKsUwL6f236PArO6E1iQJfsrUBaYred9cWXjaPZdDXCb2ga1VG84zmOeE4LRRXKe
SW97tpxo7g7JsPAMyhasjSP+ofTAe5xb8O0KlkVnnlf/YC3xBJt+lmWPTdRzrLvmSxcbx1vw7oqH
+8oGa8MmkysQV47TJtkpk/gQGN51fa1Uog00Okyxw0vD4fC596lvffujaD0w7tunrVnI9sFwOFQi
MEu5NcwnQ2Ph3IdYpWSXXY4cobSQaubU5mkvpaZVN4ERSnt6hgrFuJtuE8epJd7DVCGOllPjBKB5
K8/hi+QhtSy/ToDY81TB0yFqyXOdqjJfy22OES9VJQObFCN1mnjx3ct+H8mfXyVAlXrhy4RF1yvN
cQSchikIVvQZHSXA7ZAoOjuZ1/E7ud1JdoaemN73kGIlP5vHu5HHGs9x0F5M94GrVOz1L2YfjX5e
y6+zBJhezHE+R91rgdAw+3iJerkrN1CKMEdMFl6hLNocN7Wlg+zPZp5nMu+PkhLDVXQE2cprMjDi
LmW1Rm5j9Ph3gPfSl1tJyRSlf56ioniVTWxRk5gjxPOzSTyjZ3Kbe4Su3InaDcrmzvOYArifeO70
6rbfre1ZW8ymWwqUI8Sx/GrT0p42+z1tPMSniJWdPcFUTij3E+zjMH/W+jW3emA/xxarGZW8xg8h
uXhBf5RFuIqjF7PFlXp0O17+3VIK4fOuPluA3LEzhVFXkw3qmYJibJ2kCKKnmn2XKKcai4X1Oh+n
mOFF9gbDz5NKtNIcQXXPDvft32rrgXHfPjUtmaITBABdzp8ZQrFBMHg6T0Doj582+6tztVhumQCB
AwIc3CdeKCcI4COTqc5umQAQpjsdI16EK4RThQB8mniBuTysROMYAcQ2KQP+u8RS+xUCnL7KTq2s
cb362n6beImdJ4DOFeLlf47yc9URQ1b7NAGmvkMAS2UIqwT4vkS8MK/kcT9L6aAFiC7rruS1CHq0
ohslQPV2nusGARhn81rJ65aVNBjhaV7/KwQQfj/3+VyOvxX+9ykG8hDBFj+liixdAThGuSfsp0Ip
LOCS2dTNQ12rziCO5WHiuXotr3uN8hR+t9nW2OStPOcDSkpwiwpMeY2KrF4gnlXt6Iy7NsxlgpBO
vJ+A0QCGi9QStduv5/Hcd7XZxpAFLQav51irbTXM5FSOP9TSvJOM9/Iar1PsvCmLLs8LysZyzA5R
DLbM7CixmvMi6YPA/ulev2xWWQ4SSXpH+LAeWEbWCdD6H6Yobo8+tLIIpTutLEKP8meyiOFw+LQB
0D4bMrpt+IhgWllHG3u927LOSQyU9Gu0+dkm8dl5Qun9XZ0SxDpheB4YfpFUQi9uHWJ6drhvL03r
gXHfPhUtWd6LFPiQxdBR4A4FVp8STHGbqKUNmYV14wT4GgW+3QBtNZjG5Q4JsAgBYtUXy9LpzbrS
9EnLqeMEaBzJ7y1AuZv7GJJxhwAvl6jqel+Eo6PwXw+CHYXo8HcG8OuU9+05AjDey/NYJHY/j3OA
WA6/TWhbL1JBEJfyOD+gHCxcTh8Q0oppAggsUwluK1SBoE4G14Cfo4Is9EJWm2pYiC/+N/LYS3lP
lyiXAnJbddNnKOZymNdkYd2RPP90jsUtYoIh8zrMPtzIvk1RDLR6Y+/RobwmmV2LjWT63qfkDORx
1CZvU04lj6jEOPuxSDHN6wSA0l9YO71JAozOAacaT25lJqbaGUF9nyr4g0ofmyQmD7M57jLxP53H
uEd9XtayX9pyzRHgbTt/fpaaeMhA29oCOpnHW8B9QXB+JmZ4QUsQpoRj6wV6YG3ulLH8SPXAe/RL
z2RlEa1bhMDyDhWrvJmTmWdAuKuYY4GwHuX6lbs6JRPcfvl3qA0t6Zp/lQC5//2mL1omSgaMUczw
EnuA4eaa95JKODmcoZwpena4by9d634Eq0F969tL3fLF+gbxh/0d/wgniD1N2ZZ9qMiucXrQn3Yr
txNQvzscDhdzW3Wy8xQztUbZZG0QzNo4ATS0dZsbDocLzbm+mOc5S4C2bxMvrCG1lPvF7Pu3qZfj
a3mN3yKY3JOj8F/NwE/9Goz+KSKT+KswXIbLA/gfKCb0evb3HAFe5intrS9ci9YMqdD8/908hj6+
x/NYXydesjovaNv1fl6XxXk3CZ3yxbyGy9kvo2FlZLepycQgx08XggcESD+Z33s9Ak79e5VKvEVo
ekcIxvNG7nuJAnk6b+gnrcZWdwzZWwueXH6epVYMjuT1XM3f6cwwwU497ESeW8eKjbxWmT/9k7+Z
Y3qaeJYsDDyZx72e90rPWlcd1GU/yPt6K+/dq9RkcCXH5nUqXvoyVXjo5MB0PcfIgi69qA2QWKBW
IHQ8Gcnj7gjByLCa43neOT9Ttq7rzhCfyx0xz/k7l+nfyrF7QoFAHS/Wsm8zxHOw8KOQQuzRD50b
BMJOWnTXcEKoLGKzqXNQa68m2LRAmVelEvZbX+eWHfZ36qNdnWo9pqean8n4WgS8nfscoIJeBPAv
AsMvkkooX7FYeINIsuvZ4b69lK1njPv2aWjniD/27zWg2BfxCsUgLrZRs13XCXKglqtn8l99Qdui
vIMUQDpDsXsQnzXDQa7ldoYWDPPFfyK/zhMAZI0AQt+iUuNmCfAySzGRrafoPOWpPDuAP/ZrwK9m
J341Lrb7SoAfk/Qmif8PKa31g/z9e9nHP0bZqz3M/htFrRYaKj3vRv7/FOV8MEMAefWr54hJyXep
AsI7BFAWeOlYoLXcnezzoRyPM9m/2TyWOubVvB/nKd2sUcuvUEz4BCVLkb2eIADmvdzuMJXet5Z9
uJNj5LNjFb5er7Jyt/Pcb1KFgKt5DWq/T+X++/J8h3J8liiXiAcU8NHRxCAG79kHFKOutvpg3odB
HuMOAV5+Ke9Llz8zoXBfXvsVavKzmf19QklLXDE4RjHDspr6XT+mivBOUL7Hgz18a/VKfszOz5Rt
m5A/PE8PvD/H8WGe80N64HSYGfAjAsVNX9QHt7II2Jkmpy7+afblmf1ZrmYJngXCrQOEE1+L2rSA
k2mHKoDTJWO72VfAPUJJdlpwTu5ncapg+KOY4RdJJTYoOz/T9VYIQNyzw317qVsPjPv2E926rjtK
+tE2S7NGIMu+jBL+xOv5e6OITQODSttSBzhO84JNED1OvKhcLr5JgJhZivHUC/YEFf98kUpmU9M3
1xznMOVKYJHSQ2ppWL2r7N025RfMn9o1Jr9c3yoh0VVDoKTV0w/yPBfy/48JwPSUAFxqhGUeDQeQ
lTydY/KEAG93iOK61yhHiAc5zp/LPv/f+fNLVCztAwJYLFEa4RkCSI8SE427BCBbpmzKHuf4v0ZZ
Shlv+y4V4HKcmBjMEZIRAw30IB4Q93I993tEgIEjeXy9fpdzrM5mf25TgHGEisDVE9lENxPlBOVG
MXudN/J4ghYoR4T9VHT14RwzY7LHqEJLGcXTVCHj9/P3F/I8V/P6O2KF5SLBLN+jJhmyxDLYuiOo
7Z3Nfj1oZQld11l8+ZSSdLRpkjM5ho8b4NjauJ2j3BRcBWj1wCP5/fXhcPgsmGdX21F090laA2SV
RWjjaMCJHr33qQnxxq44+QkCCFs05zVC+QGb0KeDjYWeFsK2vsK6j1jwOMx/1YgLsjcpLf0KJadR
398m4i3n155gOK/jRVIJZRvKzvQ23vhRM/R969sfVeuBcd9+YlsWHZ0jXrZzza+OEH+4rYh/bJFd
ajIPUgyNukddHPRUdWnUl+YRSu9q4YrhB1pOnSFeJucpPfBlAjCajPcZ6oUlUzhHgVH9b2VotWLz
JfmAeDEadcy/ohhjgH9Z3z7MPo1RjCV5zV+nvIJ1yXAScYxaOrcY53D24wbBADsh0VN5lABZx4A/
nvu9k9sez+v7PeLF/VPsfKFre7ae/f1MHvtiHuMYAX5PZj8FncZW38wxVkP9fSLk5DO5n8Vod5vx
m83xkR3fasbnbN4fk+Vkpy/kWNwg2NvT1NL2k7yWKYqZm6ZA6kb+XpnBNFVYOUV5TXuMU3m+JwTg
PkRFmasV1UPbpewnlP/yKFUk+AT4/ezHW7nNfO4/ldcrU25QxCYhbWiBn4BpYQ+t7jKl757oum48
P3NKU5QEnMxJphNNXUxGc6wtvtzcVQNg2MvzCu/U5H5IivGc7Z2kKItQCy6g1VbxPjtlEW2fxjNI
yMJTXSIErzpf+DdGH2R11zLCXpPR7gJrJ9tQDLPvdKOl1ee74rWPeHYEw8qiVngxGH6RVMIJsv7c
/q5nh/v2Y9l6YNy3n8iWf8hfpYCRPz9AAALIpK7U+FmpPbHrUDJ+Vumvka4TDQNyggBc96hgCb1H
DVv4BQKEPKZ0hh9k33xxqiPUEmmTDBvpuu4EAbQmCHDosir5vZHPh6iktB+MwgdfhdeG0P0yAYr/
M9gehT8YxPnPE6DLRLT9BHM4RgDYVyl2Ui3pkGBDpwhwto9iJG8SQOpiju8s8WJ/L///5ezjFQKc
bhJssRMAwR3ZF4NLBCQWch1otpNtvU7pjwUzprHJ8E3lOGrv9jD77P24StmijVKJaoZevElpaZfy
PLp03CdA8Woe/xABJkcpyY4yAW25Wt3vE2pZXlBzPO/PeWKFQeA0keN6O4/xiHJ8EEhtUL7PUK4C
b1Jyh+9m305QqYI387p16ZigJicTxLPvs9e2WUIq8KHf5WdMP+8x4Hyu3Jxrjq/9mrZuAi+lOttN
SuXu9qzw7jm/3599ex5w9tmeoZIaBY+6bLS6d2URLSs+ngBc4CoIFgjLCAsslUQ4XlrRtaywdQsC
6wFlszbZHNOVLD3CnfRbjKqV3SgVoPNRYPi5UomMrR+jEhBlh+cJJ4+eHe7bj23rgXHfflLbReL5
frcp8BknGMIpogBsLn8uaHIJ06KUJUr7+GQ4HK42zNRq43d8Ko81l8c/QLx8ZGaWiBfHu5TX8GGq
sGyFeKmMUOEPskX7u667SABCk8Zkkg3luESwnzJv2pwdHcBvLcP+r8S+wDNXiv+Jqkj3pX+ACmE4
QzGF1ynmUIeGM9nXkwRwXMi+GKRxJcdGTeMqkdR2Mfu+QoCQX84+/AEVH32UWiaXtVNf+zD7KBP/
HSolTU3uJgFIP0cVEs4Cfz7H+30CwH4/79krOeZqdwcUSNUn+lKeQ122hYjKN27kv29Ty97v5PF1
dhhkXw8Rz4euHyPEBEMdt/puteQCnxuUt/JIHttERGU2M3lfZuFZuIgTprfzZ/eJ4JS5vGZt7W4P
h8PlXDXRsvB2Xv/ZZpu9QjO0PZtrfibYVA88TXwmlCX4nF+hCiP39Afuuk7N7POaiXcfAr6NRdpC
/n8vWYQTWcGnIRY+u8/0we31JbvdAmEoTbBFdLK7Mtpazpnc5wTmme6YCo1p5VMWuzpJ3CKe+SXi
2VMyoz/5MQoMfyxmOK/rRVKJIeGU4YTpGXP8o7S161vf/m223pWibz9xLdnVs8DV4XD4JH/WEUv0
Jwhnirup+bM4RCZlg3gJWIg2RkgtNhptsq4Fh4gXiNq/VwkAtUi8gMYIMDPMczzK/dQ3f3sX43SY
AHNQPp9KKGSB5wjQt0yAGpfYfeE+IIDPFwggdI54KVoQ9Lu5zaH8vwVfywQ4GSH0theIF+916qX6
Vl6bGlMlAXcImcQk5YdscZjxtOsEa66XswV0R4B/RkhKJigJhrrNcSqFzmK/Lq9Z9t2UQAsRrb43
uMUwgnOEHvlfAFeSiX81x/Auoau1wNBrUQcuULLISesp7clGKXnF9ygHCkGTns8ypEs5ToKkfZTG
c4sCRT6XA+KZll0dUPIC2GnJZZ+2iOfxi3nffpB9e0RMbA5Tk4gFKgRmnLKEm6U0vaPsnQIpq6/8
RRs7tdWufujI4f2A+Hw8+iiGseu6Q8D4cDh8uMfvxogJ6cpwOLy1x+91kVHOISvv6pCTML2TlUVs
7TqOQN8VHgGwDK4TTUGy900QqhzJegDHdB/lXjHabKcFXbtSs0lZPCqRUOYzxU4G1wK6VT4aDD9X
KjEcDrfy2p3gyA7r89yDiL79RLWeMe7bT1RLtusMUfwjKB6l4osvA/fTG9SXo3ZOi80S4bE8ZBvy
oduDLOYoxZzKgM0RS/IWDi1TelWr9E8SQG8s2Rmr0i8SwGmdePmNUkv2ghF1mW/m9awQoE4gvY8A
Qxepl+Q9AgzdJUDha3mOsxRb+JAAShfzetTkzlCR1hYa3aeKdwyKuJDHHc8+jxGMqYzYl7Ov7xAA
bYKoC/xG3hOLrCw4m2z6cCvPJ+gyxliv533NeS1cMyVwi5A1jBNKkod5rNkMfPlcjq3HOZPjpiXb
EiGvuE7Z9MnY3s+xO0UtNVv8t5+agJhopnzhXUo3btNH9jAh9TCVTtB2hmC/r2RfnERMU8lnjwnX
D4sdf4541uaBrzXj/Hbel9vEcwE7g2vUFhsr/SS9dWeAgzmh3KKA1LHc34hgn1mlEM+0t/lZfCv3
XSSkQh8HWCkt2KtpS2dB325ZxKXm907SlqhitI22j7Y8jiBY0AoFWg3WUCssA6z0RpZYeYTAVDs0
WWEoGQWUhEOAqma8lUhsU37aulH4GZHl/igw/FFSiY7yUZ6kZ4f79ilpPTDu209MyxfZK8TL7k7+
bIIALmcIgPWIAEEWAvmSXMlq+EkCnAwIpnjQHFtdqKDpNPFCuZVfU1RYx0HiZbZG6UgnCHBzmAAR
JpnJcmoN94hyGRAcb+e1nchtNNsXBFrFLpOln2tHyBSsOj9CgFiZbhmqhRwjC7qeZH9vZb9ep/Sm
vowthrqV+96kCtS+S8Vk/1LucyOvbZRgjzeJIj+yD1p/TVCFaLeIF/1P5dhZsNbqJT8g7reew2cJ
llTP4zsUq75ITD7OUEvOc805T+W1XSOA40Ru/xnq3st6HidA3tO8D+S9WqNCPE5R4Rw/yDFy3NsJ
1jbFJrtULgOoO8n3crwmidUJnRiMs14knpmfIQDxHMHG64Lx+fz3GuHeMGgsCZVd6NU8ksfbIiYR
FsQdye2NtTZI4p0cgx262z2akx5XZib5eAVxe0opErxNkVaJ6U2uW4TaXgs/XWHYJIDwcNexLIgT
DLdAGErzay2AbLAFaOS/glk/txa9zTbHNUFRv+ppduqIjaB2JWSdYpD1R/YaW6nDC8FwXudzpRKp
BR/LSaPssEWwPTvct09F66UUffuJaPmCfI14WbyTy38ykCcpNlfgsUqA2MVGg6zvpkVv2/myPEhI
Ey5RgRgWIl0lXmCyVDcpr9klKiDDiOTzlP7UpVf1mW9SwOUS8SI1+vcVAvSsEwDToIRb2b9lArzK
cr2afZwhwJQV4zeyDxO5D8QL9TTlvTyXPzPMwYS/m9mPKQoAqO1U33iUAJTzOR4nKWs2fWV9If9W
jt8+Cvyp675H2YS9SYBQtZ6CNse+jW8+k9uOEwV/SzmO43mtc5R+dyav6S4Fko1nvk25lzgh2Mwx
28jxms9zXKMkHWq1p/N+nCSA+RUqHrwNUGhjeu3jFmXbJ5NuISPUfd3Ovt/JbT5PfAYGBHP89Tz/
uTz3EyqSW8ZvLO/Javb/MCVjkYm1oM+leyhJh7KVhx9DDmHho6BSpvbBi/bLfS2Iu0eFVyiJOEXc
z9uUdEAPXpnOu88Bwm3hq0DYOoOR5ndq+3WJ2Gq2hWLKfT59nmR/BbA63Xg+mVr1wrLsFni6MqPc
womvgPzjguGPkkoIuk1y3M5jr/TscN8+ba0Hxn37iWhd150lANH7w+FwJRkPC2rUoMrwLBKV9U+b
/U2qU2sooD5JRf3eIMCQGtD5/NlGbjdOACeBmYVst3ObUQIsLVIJYYKEV4E/TYHKE9mPIaVbXCRA
mMdVs2yBlul+RynGcUiA50O5nSDKZeSHBCg9T8UXXyYkDkeBv5rn/x3ihfxnc18Z7wM5pkeyD08I
dnyBKrYaG4VfHUT/IDb83gD+OyoKWD9i2WzBr9Zlgg5dCZ4SINcUNu3ytL26nffmDcp+z0je23kf
Duc2MosC11dym0Wq+M60Qt0l1nPsbudKwyjxDEBMJI7k+F3LL5e7n1LL8kZkj1CgTGlM6xQxR4CV
L1FSgHFqBeRtKizmcp5P8H88t/tBFo+qz76U/VjI6xcQL1BR1gLmDXYVxSVQPZHHuP5RKWa54qKH
8v388Qxxrx4Nh8ONF+ynM8Pp7I/xxMpPprPv36GkG1sJBk8S0oDl/L9At7U2ayUU7e+hrPpa4CmQ
bVlh97MYT/3x012/d+KqD7MFcesEI7uZ1yyoFqgKrD8JGH6eVGKt8WzfrR3etD89O9y3T2vrgXHf
fuxbauBeJUCfWtlJ4oUni3qPtFsy6KPZXx2oPqFWc6ultIhFtlgAJUiazH1M7VIqMdFsP0Oweeco
f911YP8o/P0B/KL9GYV3B/CPKQuzmwRwVce8TAHljrLjMmziaZ7/OCXLuJjX9/3s8zUCvJ2lWL/x
POdvZ9/+XQJUfjv7/zrlGLFCAYBp4mU9l9em68ZBYGUU/voMvPlrMNLEUm8vwzsD+Nt5bJ0j3sh+
3Ce0tLN5vFsU2H2dACRzVATzGCVjGW+u//Xmdxs5jrPNPk9yfB9QRXZnKJZU1w4L++42Y3omj/s0
x+WNPOep3OYJJccwDniaYg1lDAXJNyngr7/yI3bah93PvjiZUVt8Jfu2TKXTQSY6UuEvRpmvUQWk
T3N8bxBBDB/pPZugSx37rReEarjtiTz3Q+K+jVEhJMvD4fBx4xb5gXS4AAAgAElEQVSxj9IHO7lV
wqPnt0EUm8QzzHA4vLzrvAdyLPwstkC41QkLZgWfsr+GZkABWcGw/dQpovVcNn3Qn8sOu7JiIItg
2OI2meHdYNhtPxIM53XvJZVQc7zdAGYZ6J4d7lvfmtYD4779WLfUEL9FWWbpQmCM8X5CtvCAeAG3
rNcoBVZbP1BfuDI6x4kXhz7GamGN6VXv+pAC1psEmNG94BBVLPd+/n4wCr8+A7/4azDagMbhMlwZ
wN/J7fR7HRAA6AZV3HWKYnq+QICgG1TB1xoF1lYJ+cEjYqLw54mX42XiZT8kQNaAYD33E3HUBwiN
r/paU9Jcfjfl7Wnu/2cJ0LiU9+Nv/AN2hoz8A+Ar8e1/SYD0BQLojVLWb8pYblFLx0eyL7ebsYGK
yD1EAIoVAqhuU96uY9n3z+bPf5+qrrdwzJS1CzkuD3IMlT7cyWObjriPcpw4TxXlyTYriegoxwdl
OPbzHrHUv5WTvLcpwKsW3Ijn7byf53OcrlOTN88xRlnXHSNAlUD5PpVeuJ8qUtQXe/HjMIUJOmey
XweIJfknz9nWhMBF4F6j29eBRJmNmmodGCyKtUDO8X+WXpef4Tfyeu+yUxph4IsFhur5BZ6CVVcj
dl93C4SH7ATCTgrdzvhyWWH1v7pxtBKJdbW8ec1+TebxtvjkYPiFUolmrKbZyQ4LmHsg0Le+ZeuL
7/r2Y9uS+XiVeKnfIUCAy9JvES/ubwF3dlXFHyeWZV8nXhLzlA/xBqXf3KKS4QREVre7HDxOAWGX
3aHsqNQgWhy1RhXxvTaAX/41CjT+ahyk+0oA9qNEERvEi/YKwfha+OULeo0K2rhNaWXJa3RZdkDp
Jv8kATKtcNcO7U1imf0AAQxNmdNi7DBlJXaSSlo7RQDYn879ZaVehRfGUh8nAOo0AQTHcpwfZ79u
UcvlY9mf0xTjpe53nnjJO2GZyX+VncjQLhETpXUCWI4QExglCgJIKLZP1lim/iFVPPUKFeusjl1A
K7vs/bbgU5/kBeLZ3Oy6brLrOkM8yGMYp6013+cooPddSs96NH/vs3yjGT8nO+9RxZnHmuMsJEjT
z3df13ULL5JG5GdohmAYl7qu2wIOd13HbnCcxz1KhcRM5s9kwc8Sz+cidQ+NAFeD/LSxSnzagOKR
5jjbeQ+gnvNt4n5rhaZeeiPPt9vpwuS5DUryMknFLk802/l5n6AYbT8XJl+uUasNGym5GSdioXeD
YQvgPgkYfqGrhNt0ETrSTjgEzHuGnfStb5/21gPjvv04twtUwZsvL037R4BvDYfDm13XjXZdd4Z4
cZ6kGJrHBNB0GfgAFUoxpJLrrhIvuLE8xialj7Qo5wmlZ54mANYC5SF8OPfx5efy+4tAo9rJc8TL
zwr2bQoUWsy2SoCfB821naU8aafy3Hrb6qCxTBV5nSOYyP2UllnnA+3iHuf1CMyvUozeNOEGsZXf
rxLg+kWx1Opnz1FLzfPEhET3g6m81oPEhGeFAHXfpmysaPaZIgC0sb4LxIThDuWKsEVIAW4T90+2
V+3y9/N8jwggvEyFeugkcZKYeBzIczyh2NtH+TM16h2pbc9rUnazr+s6GX2L5B5R7PsZKkJ7jEoQ
NMDGZ+C7BHsMxWoeIZ4VWWvZREH9RG63mhrcNdJbuuu6dQI07yWrkLleAhgOh2uB0TjcdV03HA7n
E7RNExMjQ1C8Nx0FULXPmycmQevPOacTzH1dpcsZ0iGTLJjcTznPQNn4KRMwjQ4KCCudUMYh6ywr
rBzBbYxnd5VJsP0MDAtuc1XrQIJhAzqg3GA+NhjO473QVSK3kRl3VWCTeA56drhvffuI1gPjvv1Y
tlyePUK8UA9SFftrVFQuXdf9ceIlqV5YfZ9BE0ohDlBsnoUz6gp9yWsDZQHQBAUQT1OxqwK3x3kc
AfHD/NLCbQNeCBrfz203KJ/it6hks408/zLltqCVmVHFAyrV7yDF3ll8910qnEKmXJ/dYf5cdm0k
+/82AaCuN9d8jfAq3qRiczvg5Ag8/Coc2yOW+sog7tWXqDCR9eznBXZqcpUuqIF+h5TGJPA4R9ns
aYm3kuP3hABRX6Bs+97LMTzejO0aYW1n4eBFmkCLrhLUdOaYyXsg6+6yvwDsFYoJn6eswtS8Wrx2
Mu+pz+YoAZT/nbzmR3lPjEqeoNjpG4QMQ4bQ+yxDuEiBPYhnVx/qA8ChLKSTZXzUWLid6LpucdhE
PKed4RQf9h8WoJ/puu5cjsd54vkQ6K/lub0vsq76gHctKE5w3foIn6QCTPz8KAswvVL5AlQQDrmN
8gGBsGlyk7mvrC/UZ193ihYwew6vQzu1tUa2MJEFwLvBsJaBnxQMf6RUIrdToyyD3LPDfevbJ2w9
MO7bj03ruu4zhMTgJrUsOksFaTwkGDwDLLSiWiCYTVPLZE864sU9QxWgdRS4PpbH7XLfw1TBmy8j
QyCWKV2pcgBN+qcoxguK7VochW99FT4/hJFdoPGbgzjWq7nvI4J9FYxtEIzwBuUNDJUmpzeummsI
8H6PkGRYBLVGaLHP5r6LRHW/hXnGCcukvkaANgvdnhA+wr9EMXfKFi4C3Tb8y2X4ua/E/yF++c4A
/iHFSN+i/J8tGrxMxWsrZ9ik5Aknc4JkzLJLxRcpx4o5iunrCFD6AQWolMp8kNuaBGia3ZGu6x4T
Ewqt4M5SUoQVaknc6G+LIdcJQGuxp8EPspkz1ITKuF19pg/mvfrN7NsGIaUQ/D8ALg+HQyU9OkXo
wHEnj6nsZpTSUQ8TTM13XeeYH+m6bpPQGK91Xadrih7Gpu3N5jG28nzKItrUtQPU5PJdasKzya5Y
5ez3eo77dNd1rYRBPbYg1ZWWkeZ+69yhhhdKNrROOVd4fr2KDzbnGaUmxR5DSzj7AfV3Y7055jOG
O8Gwf48Ew2qlfxgw/JFSidxuNzv8lJ4d7lvffujWF9/17aVvXdcdGYNf34K/5M9G4fcH8Lcou6lJ
CrTdza+H1MtQjacuEWNUMVlrtv8k/7Wg7i7xolFHuEgVth3L4zzIf49RbhiGJWi1ZgiDoR9W9Z8d
hb85CAmC1/a7A/hvCcZ4PyELmCdYcIt81KJamHYwf/Z5ypLuNFXkpePEu5TX8kVqOf213OcbBCh8
lQCASjjWKDb9Zo6lWmDPO6CWr1vAMZfjuEbION4hPHYfEIVwR6nqe4sX71NA9mYeUwD6KK9X9xF9
kJ3AbBBMuABRne4lCkBdoooo1ZOP5Nhez3HdT0waZF0FSXrLPsx+jucYLOYYTFE6X8NbdFUQPHaU
Xd9c3rMTBDBeBH6PiDTfShbwbWLSd5sICtlHgNiVZMz1ata/dyLv6TIV/mAohIV2q83S+76mP2sE
+NrqKjZdpvIgNencTwFX46xXKVZ9DvjO85wOGhcKreUmqclaWww3Tk0ifLZ9Xi7mdjcpMG5k9z0q
MMb7p95cx4nNHI9u1zatRMLnvwXD6px9/nw2BdFP2ckkfywwnMd8oatEs91udlhniZ4d7lvf/hCt
B8Z9e+nbeNf902n4lV3ODdp9/Y/U0uI0AbZuUy/sLYq9WaQKvPT4bXWtskWybBrujxAv7m0q9Uwd
rS/Aw8RLap14uetsMU2xzveSjZvM4x3L/c8SQE3Q9fU8r9rlC1SQxlMCBB7La9VRYg34M8TE4P8l
QJHM41HKf/kW5ZNsWIhR0JcpQO31jOSYmZonE3uBYscNMTBiW+mFY/l9QmqhtZ1A+QwBjL+f1zJK
yDGMd1aru48KnFjMbV1mP0oxuDLBhqIMKHszNebzFBC/TLDnZwjQKQOu9GSacMDYzj7rkazn7lKO
jdID2VxlKuqCba2UR7A2SgVrmG73vSw4GyXutQWmT4ArWfBmGIsg6ikR3fw0mdyTeT/ebT2Cs4hN
CzTsT8N67qe0wAJGY58v5Fjeo/x3n8U+U57Uurys0sQ+N0C4lUf4OZ0hAPh8XqeyhTYWeYpKqiR/
93reg2uUe8Tp7JvPyAS1arLdbCd73EYzK9HYwQqTSXmNvEOJRBv+scUPD4Y/rlRiL3bY7fqXed/6
9iNoPTDu20vdUj7x7gvsvv5nggWdJF4QV6gXtlZpWmitUeBthGJx5ylvU1/S+3Kf/QQwOUi8gC3M
M+BAnfJheBbDfIdKCNtPAOMZAlAIuk9QVfHniBfcXUJvOwL874RDxBtUGt4UAdT25XlNptsg3CD+
MgEy383/axkloAT4Zvb/QJ7/JFXkJvMnA28hkeEP2qMJHt6k2E9dK65TbKK63W/ltVlENyQmL2/k
fv86f/cnKRmErL/yl2XK7s4Jx0yO8yIBKA9ToRojlIXcceDn8x6aMPYeNZmSYTOgQzeKrRybk1Tk
91b2ZSv/r8/wK3n8B8RzMySeKyctPo+m5r1BSV7WCKnPu8PhcCFB0hGqcO1e9vcoJWF5hXLSWErm
eIwAlzowrA2HQ6Oqd7Q8xwyVuujzL1A8Sml2fcba2OgFYG6XJniMWmUw1OYEZUsnEFbeoGuGk4Nz
+f096tkTXOqFvE08+21M+k2KqT6W1+XzDhXSAXVvncwZwtEW4ckKP83r6pp92qAOcl/3+aRg+CMD
OJptdWHp2eG+9e2PuPUa47697O01eKFzgwzUCAEafNG3mlNjel3edxn2CcUMuqTevoDfoCrQZRpl
lmYoQOWy6zoB5mS0dAWYZifDOUtpmXXB2KAY5NMESNjMfk8RRWEj+a8s6QEiVe7vDgIIA/wHo3B1
AP+cKg46Tvn1CsQmm358kP3/DJXEZiGZ+k113GvA0ij8F7vkHzcH8I+opL6OmhwcpID1vhz3MxQz
fCHv10FCZrFNgP4rFKtnvLIpYisEWLxOBWUcz2sxUW4776VFd1eIScOtHHdlAeQYH8yxd1XAhL+x
3H+eAsXD/HqdAtxP8v7JqD6lQJeuFj9PTH4GxLNygwCRc8DT1KieyWtdBb4xHA7nAdL5QXvA2dz/
wS67NYvyZqnn81nbVdCmPlhdui4XCwS4v5G7WXh2gwpVOQgcT2u3tTyuwSKOme4ds3lOmX7ZUVdy
LGabz2NbF6AERSC9QNiePUwQfpjS/atrdvKwTjHe7d+D1hHD7dQvt3phbc7a4rkWDLvvJwLDeeyP
dJXI7fZihxfo2eG+9e2PtPXAuG8ve/sou69rFNtqFfpT4mUG5Ut8kNL/mkx1JLeRudJlwmho9aKC
s1aTKEOt3vRAHku3DNm7J3k8k9J80XZUMZfey6NUId0FKpxiEvgLhKZ1gUoumxmFvzcDn/k1YvKQ
MpNLy/BXB/BPCPnAJCX3uEXpcucIYPmQkHLcpYq+lFsoK5BN/GAU/u4MfHbXOc8tw78/gP+V0vne
z2MJfnRouE85O6j1ltW/muN4n2DHZ/OaT+R9Mw1wLo/7OcqG7iHxDDixeTXH8QIBin8rf36Gkh+s
5LnH8zinqAjq84R22qjvm7mNwS4WcupMIMDTm1b3j2Fe75+jwPt3c4yXiGdkf/ZTdv46ETet5Vfr
jLJESQ5GsgBxgrLeI8d1NcGVS/8yxC0gVRryQe4no9smPR7P8R2nJEYPKXDsZ+csFSwiS+zqjb7h
fmacDDo+NGN+mNIrG75Bnn8m2W59jfdRumgLOecpJnaMKpZV8tEywxuNzrprLNUcIwty9cv+YcHw
x5JK5LZ7scOrn/Scfetb33641gPjvr3UbTgcvjfedb/xVfiVIYzucm54d1ARrvcphlUnA50FlgmA
9pgAE2pjTarStssQiSfEi2t//kx9bguAVggguU05GTyiJAkz+X89gmWmNdt3aVnGUomCYOJPECCv
LfwTtFpcdH4Abz0nIOQU8bVEvdTn8lrO5v/vEsDkEsHMH8xrO0CFdCw1fdwmAPfnXhBKcpEqmFvI
MbDo8JUchy/kuWR3dWswotg+uLR+Ou/FPUJ/rXfzGAHQ1rO/6wTrbeCKkpgPgN8hJixHKQ9eEwX1
P5aVI8fuKVEA+f0c/w/y3EfzWg5QRYC3s3+rFIi273+aYNdXCdnITQqUb+aYHSKA3WKO2eMGsMnQ
Kt14SAV6ONmby6AQ2chjlMZZrbgA0bAZ09U2CQ2tbKlssmEuYwRbPMx+nqEmP3pan8jrv0ZNHF1h
MWHOCcO9/Fc2V4C+lOM4w04plPKnw5Q22kjnJYpdPsrOok8L9bZoWOG81mchIbvCNuwv/CEK6PLY
z5NKLLa6b/tB/b1xvD7EIvetb337o289MO7bS9+24D9ehv/jKxE1DMAo/PYA/jfi5X+fWnIdEC9x
l9EtaloiXjyzBHAzEtdoW5dX5ykd5X4CFN2lisGGBDDwRWshkwV2R4iX4Mncx2In9aWjxMt6lWCO
tDbTb3WVABfKN6aogsJLBCATEH2UzMRCKcM2jmUfHlNL2xMECHRZd4NgWpepIkb9cHXIeNE5TxGA
fpadzOCbFOg4k/0ScLZ+1OqYxwkQuEUlul2hpC0Ciyd5XU/yOn+O0mBfp1jUL1GaZ3IsjWge5PUt
slNHfI9gdh27w5Sf8ijlduFES4b4MMF2nyVY0hnCZeJ32SkdsA9OiGSC55vI4FmK8dd6bjzHzEnF
JnAsi+4EkAcJAK1v7kazrbZpewKuBG0bCbJNTnyFkgu1/r/q0pXbvJHfC0a1KYPyIj5NafMXCdZ2
K4EkOdavUc8n7LRt87Niat6pvB8HqMmo17lDLww7wHDrQuHEwX12hHR8kvZxpRK57WSzbc8O961v
L0HrgXHfXvqWSVr/CWGd9TZwbRCWVeeoF+YkATLWqeKYOYLxkx08TLxE/xil+9W6Sob4QX65vHlz
OBwKpqzaVw7QES/neQIMavll0pfJZQeowj+Xdk/l+Y5QARRHCdCwTgCIN6gQhxMU23uJ0Nf+c+A/
fYHM5EZ+WZm/n3jxX6CY0XN5LtPMZNhuU7ZcApEz2dcXSVvU8cqGz+Xx1UzP5PG3Ceb4JDsT+VaJ
+7SWY3o593uLYtKu5hgeo6KpLZQbUvKTL+c2BqvcpyQ2bXGcYO9Q/vy7BMByFWE7+3SGcqfQ4UT3
hk3inswAP0NplbcIUHyX8sWGipD2WvRpHiP8mV0lcCViKftjn04Sz6nAGXYCxyWCmW6B8EfqUlN6
Ieg1TfIRJTcRpK8Rz8zbud2t3E5tt6y0riVQwTsWPM7ncSdTW+3ESc9wCyu1U3Ql5nj2xc+EoPwx
9dzuSNBLRna3rVqbaveHBcMyvso3XiSV2L1tzw73rW8vUeuBcd9+XNoUATxuEi/H88SL+AqhM91H
vFxcdn5MAA7BoMysGuMBtUQrWFumlv73kbZjyWS57HuC0jeqBVYH6UtNzWNHSSqUfGjp9BpV5X+P
KqpaIMDsmTzfH1DASAmGy8ujo3D3q3BqV6rcMFPldAk4nPt/kF8yx69RS8/3qEnCBlXUeJgKE7kA
LI/C7a/CmT2S7G4NwoHCKG2T+/bnfRvPMXif0nAfJoCVrPVynvebBAg9QgFgLd0uUU4KTnJWcrtB
XouhIKbOQa0MQMkmnlIFjqs5Pg8oScxn83wDAowOiEnZQ+L5OEWFuPwZCgQuZv+v5PfjlNd1G8ct
S/4wx8zwCtnLIWW7d4myzxOoGte9SskiDhIA7wkf0Rog3IZdQFkT3qFkP1PUvXK/AfGMqtX2Wg/n
uD4kJyDJgneUM8cJ4nlXx+tE9VEzXnpjq5HW/nA1z3kvt58lmHbj3dukwtZWzfP4WfzDgOHnSSUW
dkslcvt2W3LbJz073Le+vVytB8Z9e+lbLk2OES/RbYI9fEgAGH1r2yV25RAdwcK+SUXiKpmYI5hB
j3mKAgOvEi/iOeIF7nIxlCXXCBW7e49yc1CvuEbpUFcJlgvKJ3c6+32PAI3G4n6Qv3fZfKs539H8
mczkFwfwr5bhy18J8ARxAe8P4O/kOd4kQMNjAqy8SmlrZazGKF22LOOreW23KBeMOcLx4vEy/JXU
MXvOuwP4X/J6ZHfVbK/ksQ8SzOnX8/yn8l5M5Dldkr9DpdttU/KGYzkOJ4glfqUDFq8Z7GGh4yIB
2lrG9ygFnu9RqwtP8pw6m7jkf4LyfDYspo0aPpljrH73Wm53jPJ8Fjjvy3t5l0pfU1azj9IaO4GD
cnDYnz97mOc2Gln7NidnMud72ng1xXiywrv1tK113USOsVaE6oDvE8/LG1RKpHZvhujcoGQ408BY
hoUoWxhQBbEPKNbdfcaJids4NanU9cPUyieEXIYc35UGDMu4/0jBcI7hbqmETh57SSX2YoeXaMJV
+ta3vr1crfcx7ttL31I7eYkAJOeIJfh/nb8+SIADl30XqNCM05SrAlSc8A2qUM5l92nKQeIStdTa
LlMrg5jL/5/Oba7kOfVjdWlePbP/tyDwi7n/AuV2YRSyhUsyZfuBr+V1zBNM+TkCrJ3O/r9LvKR/
iYhz/o3c/2eaMdogAM5NAtBs57i1llD6wx7JcytB+UL2+3Je07Hsy/Xsz0zem98lJgOHCQAn03gv
x+0tgi1+kMfUamuUAJRafG01fZnO6zXYQWeEqdx/hfAwvk65G+zP8XlC3POj2Ue1xCu576H82XUq
Jnt/bq/U5ggBwod5nlO57TqhI/5i9vV3qbjneSotz5WEVQIQr1LPqjHQJ3K/MQpkSlrsz38fZX9W
83yHchyh2GNyLA8S4HWFCkaRFfa4ar8Fh4JlHVYOEc9nC7xtB4j7vJXXZCGcFn+jOb7tZHGUKqjb
poD0LDVZ3U85NkzmmNzPL8fFZ+0Q8Rn/bo7nfup583MqaP1RgOHdAHdA6YE/lOyXkwCLbSGel5We
He5b317+1jPGfftxaBbWWYw0T7ychxSb9U7+7IsEeNE+TZB1k3iJCwD0Bj1GMImGcEwQL+E7xEva
KOkD1FK6L7uTBMg25EKwuUQV3Yzkl+ltbxEv9R8QL3QL3h5kPwRqC3n8nyKA09Xs24Xcbo0AqlrD
PSbinN/LcdGV4B2KQdsiQOY4ocXUrWBAAFb9YGfyGs7m9neyv+qnrxKA5Fb2/U/m9p/Pvr2X2wi8
JghW1YS9S/m9cgpyTE5RlloDyq5L/9zJHBOPKbs8A/xi/l9vagvrBF1XqFjqUwRQeUhNfr5EAVP7
dSj3/VdUcMZmXu9c7vt+jsUmpRs3bfFQHuvdHJ+jxP2foEDcbJ5XCzSvWSZ/Jc9FXrsaXPW+UA4M
apX357lPU3pXvZR1wtAjWG1vG3bRUd7KUPp0i+P0Cv5gOBwuwTOZgOl4+iHbR+VL+6hiQCeDE5SL
yByVmqjcCcpxY4wK7NG9wc+vqZVdnuNHAYY/qVSiZ4f71refgNYD4779OLQJ4iVznngBzlAJaQ+J
l9bP5O/1xH1AADfBzxQFvEyfExxbtPQKJTuAAChbBFu3SDoGEC/8C1Qsrl6q+6kX/grFuq5SoQAz
BHC8nX14nNuepLTJ81Th1nge7ylh4XaO8ghWJztKLXEfJID0CAESTxKM502q0MziP2UaxlsbA71J
AG5DJt6hnCzWsu/3Kc3p4zz/MH/+BwRoNyL51ezPBKHZla13wrCd427inalnU1T4x5m8VlnIAeFq
cZsAgFM5bh2VFqjW+X6O+2eposDHZFgCVfh4ohmH7byGd4g2CfxC3jOX5gV96tShns97lIvGobwO
reLUQxtKcyvHb41y4RgAj4bDoZINuq6zCHQ9x1qPaCdv2rR5jRvs9DU+TNxTgy6eUizvPFUcafCK
k09dXQyh0fllM4vmlKNoY2hfnCj6HI8Tz90FytZuNY+ltdwi5eCyQElmNilAPEJ8DsgxdWIhi/tD
g2H4ZFKJ3H4vdnhP8Ny3vvXt5W89MO7bS926rnuLSAtbJwDECvFyXSBAmQzkMgFEvpPbHCJebCeo
QAsLiKyIXyde0i63yloJJtRUGo6xRoA60+w+IIC38cQWYgkGRingPEWAP5fXz+R+7xPAzljmpaa/
A0ru8GcIBnebAHqrBCgwoGOSAH5e2wy1TG+giLpmY6q3CEAym+dSyy1AvkwFp8xkP29TxX9fyHP8
dh5nkQCSqzmu0zkmb+Vx9U2+Qel1r1ByA90PZITPUR7QJscZU7xMFb8ZknKOAG5jxOTjLmV5d4ia
CB2k9NrkvoZauKT/NPv/x3M89uW92RqFvz6Ioj+IA/7+IKLJZSqVErT+w0sEkNW6bIvSwpPXdIjS
ei8CBzPRTvbUGG+ZXgsMyX4v5rjIklusphYeCuhqP0geQxcNC1fXczxaz9+jxORTb24lEoaC6B5h
H9RqqzV3G0GrqyWLxDMmON7MQj0LCi8m+DRFz2fZJL27JKvMD9meI5XY01Wi2X6qubaeHe5b335C
Wg+M+/ZStq7rjozBrwN/yZ+NwjcG8N8TAEjd521C+wnBkMqKzVD6RbWWWlm5jLxGsJtaih0lXrK3
8ncW7+h1e3s4HC5l0tgqcCVZobn8melpG4RThmBnf/58hXj576eYufMUw2uq3cm8Lpfi36TS2JQv
WJ3/Ncq54Fx+/y7FaK7leQ5QvrCjlJ7W0AuotLMVQvOrXdtJAgTcpBLxzuV+X6MY73XKQu9I9kWP
4m/kNZ+hGGctx05TE5KjlHXcBgHOt/JnBwggLaNsLLPMuUzuUm4ne6usZqQ57hY1AXCp/3R+f5+K
ez6d+94ELo/C398j9e9nl2F2AH8vr0O5jQBxPfdXGqCsAWrCdjD/P5/jaX/dRs2tYTK6Xxg646TB
gkbZyqc5xutU5LkTxN3BH5O5n6zvJJGsJxA9RyXZ+e4QDAv4Ba9OQtTXy/Qb5KLWWH2yxY1HCbu6
1eynfuSb1OdY0Poov3/Y+hR/3PZJpRK5j7IS5VNrL9q+b33r249f64Fx317KNga/Pg2/sguAfGkZ
/vYA/hmlL4UAFYK8u1TKm1G1+s66bK4N1mvEi01t43WKMdWVYo4qjDrQdd0+MjnOl2FWwp/KY9zI
vuide5paij5LuSJMUlrRcYrlPtcc42he0ywBer5HANcZCt2uLdkAACAASURBVLwuECD8DFXIt5h9
PpTnVfc8m2NlxLL67CsUOB/Pazbx6zEB3tXrvpXbnaJcQVpwo/uEEpV3854M8nrUuD4iJjLqui/k
MU2z28jjWGD4ft5r0/Vu5Plk5Y3SfkSw1qdzPLy3B6ioa58VQZ72YrqSXCJAe5fXv5h9+Q8H8LPP
Sf37DOV2spHj72TkQP5fi7fdhWxT1DOynT+zWE5bOkGk99PJg9KZNsXxYfZdVthiNtldVxW8L1De
yGsUc6yUYIKaNCxRz59A1Sh1VybU9+pXrVTJSYwTU0G6kyEBvjITfaZXc0xuUQ4xnnvrk4LiH0Iq
sZsddhx6drhvffsJbD0w7ttL17qu+wzwl54DQC5QS7AWKt2nKvnniJfygIpTnmZn5bovfYgX88/n
Ma9RVlBalMlE3qf8iz8D3ExArKThKCGtMMxiPP+doKyrDlBs4KsUsypQvkAVB36WnXHFA0oaImM3
AfxFChQvUmEY2m0ZFGLf71OASuurI7ntVcrWbJjXc5wAo8pHtNi6RzgxbFFRvGpHvWaB2pBiaTfz
PpzN32uFdrjpy4G8XlnnO3luwbMaXYGWQPoEVWA4RoA5nSt0NjhPpQ8qT1ArfDTHa4SYJGklN53H
fhVemPqns8ls9kMpBZSEQRs7Y5edUKi/1V5M14iVZj+TGp0oWRA3oAod9UTWZ1i2XEApWHY1ROmH
161/sxIiQfEWAUw3CQB8lALC9tO+rjd9MmzjGYBsNLmzxORtHzsTCJeoItDbhCzmTDMmXrcuHR/Z
PqlUoulnyw732uG+9e1T0Hpg3LeXsX1U1LEvtiElS/CFvZ8Ax1bpQ4UDqAXUV/gpwQjOUJpJo4GN
bz5JADSBm/HOAsJzlPZ2lLI6kw27TgCNC/n76xQwMxnuGAHYLCy6mP22z/fzetSqHqHsqExHu5vH
dDJwahT+3CAKCiFOem8A/w8BQh4SgPNSbn+D8oq2eEtLs5Xs92b+fxP4HQLcClAMBbmXxziTp31E
yAgeEMDvBKWL1XVhqfle4CJTqtXbWap40rS44xRjrN3dXSodzmOS+7d2bRZMHqLYXa345vOejTR9
0fLvRal/X6OCYtQrb+fYHaUmdD5PjpuWbK2XsIWJByh3hwOUG0cLngV22szpgyww1eUD4jOjNEO/
YAG3bLryiDVKm/w+pRt21cXzWni6L/dZJZ4BVxLGuq57OhwOh+le4fmVYIzmMQXIUJ+nSeIzepx4
dpapz5cRynu2H1IqYSiQ16lmerVN0utb3/r2k9t6YNy3l7FdhhcCkGtUjKqV9b6QLeDZoMIHHubP
tEyboAJCjGC+RYCrgxTDaeDDXQr0HiNe2iu53QwVxPEKJY3Yl/ttUZ7DG1Rhnc4FSwT4tghJOcEU
AZCXCEBuSMU5AhjcyLGYJsCcIR2HgI1R+LMzcGmXFOXkMvzFAfxfeTyDT94n2DvB+v287uN5vS6f
u8z/ewTQlME+SgAlbc782Uru92rud5oKZLmQY2MohCzrNFWEeJICxNqgPaIs9R5nPw8QLL4paspJ
1vNYhlqsUYVfp3J8dc64STwTgsj9uc0b1ATg6ii881V4YwijTerfYBR+exD3SaeJTeI5PUTpfM9T
rg7X8xr1txYIt0ltrnqokzdNUYb5KTWRGMmx1o1CEOfxfC4N2NDzucuxF6AqfejyHr2S51XjrmZ4
hALd7Tkt4JyhEvxGgdGu6wSmgna9vI2GlqGdppItXTl4RNnsKd95nvThE0klmn1M2HOMF3t2uG99
+/S1Hhj37aVrw+HwvfGu+42vwq/sAUC+MYjYYZfLfYk/Il5mulG0dmC+IA3ymKXswARSxtdalKal
1Rqhk90gQMIrxEt2JPedIwr4lihrsXMESLpGeeMuE0DuCQEU5wkA2rKnbmtfnxC64m3CBUHW8RoF
1u8QQF3pxChwfACvPkeKciyvT63xVQJ4bFHL/+qEtVC7Q4Dan83tTYNbzjG6mmP4U9nv1ezTQcp3
+ARlATZCANJbFHOre4bSiCnKyUDLswVK97xGMeeec5G699qfuUrQ5X05m18C8Ov5ZXGaEdUXiYmB
Ouk7wM0B/Noy/DdfCQkLRIe/NoC/T7Dk1yl7PlczLIjbn318jyp285lsLc+MDRdwblCFjLoyjLMz
avxp3iOZakFmKwWQoR2jtL6y1X5eZJ2niWdlndJvC7Lt3yi1GqPjhDHbXs8YBcgFyRYkLuU91TbP
VZ9Dee6LVPSz7h0/TXwWvk987oAfWirRs8N961vfPtT65Lu+vZSt67rDo/CPBvAX/Nko/IsB/A3i
5fkWVVB3lHjJGhurZZp6SZO2RgjwcIYAfLNxWG7k94IqQUxbnKbuUb3qq3neLQIMDSigcIIAry7h
uiT+XQJwXMq+vk+85P8iVZj1BpXyZfzzecIhYYkAa99lp9XXChFQcS6P+zngz93IHW03eZYb/evA
N3Pbk5SDQltspszgVl7jTxMSl8uUQ8VVAgAdogCQ4MLQCJf6tSIjr1XgqnXaPuDb+ftHlJ3dUu47
SyUWrhDgdpxiYg2ncMkcqphuHwV4DxHPwQc5tit5PcfzHLp0bFGTDpnR6znuEPfwUt4DdcqPsr9K
MWSnDWRZJECkYy0QVv/bsq8GZLSgUoC7nOP8oLnWkRyT9tj+rv1XBtWQjzOUM8VU9gXK7/ge9Rmy
mE5QLcB2kqjbhSEcI9SkROcPme9hcy6PrUWcVoL7CIA8Dewfhb85gC/nPozCbwzgr1GAWkZ69UVM
73PY4dXhcLj+vH361re+fXpazxj37aVsw+Fwvuu6f48ojPs8MDcI4nhIgc6zBHNq4Y8AaDL/vZw/
VwcrY/YeBToMS7hCvNgt/LJIbT8BHg5SiXGCiWGeyxCCxWZfwcsGZXN1lgIVT0fhHw7gT3vNo3A9
NcCCyfnsE9nndWpJ+zYBCI5TOmdByCi8UIryrezbRQoUjxAg6A7lf7zcbHeSAK4Cm0VKHvI49zWI
4xt5jav5MyOwL7NzyV4W+WFe6/cJdnWY16L12Qzw+wRzeynHcT8BVI/kGCxQYNTiylZOYDrgt4h7
bZGh2mPty7YJV4srub0yg1tUoZfOHfso5n2anQBykQB1Bs74XB7Mn1soKVMP9fzJ/OsgIWgWeFq0
Z2qddnwHCHAOtZKipZ1FdwLgqeyHDL2TMQtPHV/ZeZrjCaRdkTHcQlnICiXvGGuOS27rRMpt/Ex4
TPus5npkFP7zGXhzlzToV5bjM/Qf8dFSCa97mp4d7lvf+vaC1gPjvr3MzWK1e5SFkyzj+5QV22Hi
xX+HADDTwNuEs8NDyhpMeYTM63YeW+mCrPNRymbtKgE4zlIJWzKrx7I/Bkscya85gs2bz+P6gp/J
c82Mwt+agZ/f9aK/sAx/eQD/gmB071FL5ws8I3zZIoCby+4TlBvCuTz+/a/CiSF0jRRlmFKUewRT
bUHgHAFar+f3umosUiz7+4QLhZ7MMsCTBMBQV2voxHT2dYQAtbpKvEWwzcs5dneba3IZf56SIwyI
idAjgrEeoXTGX8qfPaFA9EZexwjBvlsseC/Pu02Aby3SlNNY6Pd+9knpwi1iEjLIcwqGddN4J/vj
BEn3CN0onuR51FDfznOqP1dO4QRI6YRg2KaX8CylxzUBUNcKg0FGKdCt7ncm+2RwjJHlD9hZmDeV
/bnDznAaJ5da+ik/8GdQsiSZ27bob6T5su8ty+zERJDtGB4Ezg3g7T2kQaNfieCbw8Ph0PjqHa3R
G+tksQ4s9exw3/rWt+e1Hhj37WVuvmifUFZhproJBq/ldhZ7WYT3tfzZBFX8Nkn536pvPEwBkAmC
7b1PAC6ZOZmwMSp173D+u5jbfJMAYV/KY0+xk807RtlavTWAX3iOBvgkAfL0D16migdNo1ugfGNf
oeQhR3Ms7g7gHy/DX0t/XQfz6gB+E/i57JPFa+s5rocJwKzm+AoBkmXZZ/McF3OMruc96XI/C+ne
pEJXyH3UjR5q7tGdPPal/N0yO3XIWwSY3s7tZSvPU8v6CwTYXCOA7Wae/yQV5kFem+mC6rhlPi1g
vExZxulrrP0b+f1x4t4+oJL6nEhYaGi/rlIFfzpnbOe2r1C+xbKsFqTZdHUwBOQQFY8s+JRh1VtX
/+7xvF6dTZ5Sbi3DvCdq6i2qG8/+386vtkBvsvmS/W11eAJ0PYX1YFZiowOGbiM6TngcmXOvV6cM
NcMvcql5nfK5btnh/c35ena4b33r28dqPTDu28vc2uXkJUoXOE8BlBFiCf6nKDZN1gwCDLxHgJeL
BEi2gO4DAtwIgiYJkLZCvFBdLtdhYpwCA+cI0PEWVQh3ngB796nK+TcpD9jrBPP8OrzwRb8v+6lN
mul5twg5gcDGEJCLBOjaIADCPgIc/38EOFsh9Nmn8txTBIicoyKttcESwCwTYPt4jtPZPM4DSuYh
IFshJhJ68T6gPJ1nib8zJrTdJ2K7f48Aw1/I64MqAJN9P57nuEw5jIwToPtajtECZYf203kP1ghg
p4Vcq9nV0UKt7O0cC8f0EJVgeJUC605CVijA28pxICYagrv7ObYLFKAUJFp0eHs4HH7Ihzf9c3Uv
EdS2PtAywUY3GzEuOyzDu5r3SQmFbK4OHTcsTEtm9TVqgtBRqYECTB0n/L5NsoOdkw3boPlXoO/Y
QxV5GvJhEMki8Qzdzf7/wxdIgz5orqFlh5X5bAz7Ypq+9a1vH7P1wLhvL3MTGG8RwFidr3Zck8DB
4XD4pOu6u8RLWQ2nfrSnqCXUrxMv9dfyGJ+hLL2GBKCbI8BVK9vQZuwDytpsnABmS5Tt2xTBOO7L
c5/Jr0fZh1OEs8N78EINsM4GtwjGVDu0WwRgnMzzHaU8mO8SoPxdAiB+OcftNyk7rLPZv3mCOTdh
byX7KaC6SoDFL/D/t/emMZbd6Xnf79Stfe2q6r2b3c21SQ6HM6MZSjOSHMVKJpDtIIaBfMnEDBw4
HwITlj8Yhg3YQRAE3mAnNmyNsyNBMhrkQxAk8AcpGluRZY01+z4ckk2y2ftSvVR37V116/jD+z58
T9d0F0lpZNaQzw8oVNW9557zP/97u+s573n+zxvCUIkQt6gkDV2k3M3jv0UJ1yHgk/n+3c6xjxBC
XZX056gmF8NUdVNV4dHc3ys557JXzFGxd22O/QXiPdVCyg2q2v8GtShPMXlDVJc8XfCoqcWhPNfv
UJ7uJyjrxEKOT3m/as+sRjMrhIVDFy6LVJqGLnKWqIWZq5mo0M33VetqXXjIrqB/C1pYuk4IV31G
b+e+5XUXsk3osfkc7yMpwoeJz/xMjvU091eGux79zTy27jR0fdIas/zNWpyneZ+iFkCqHbcqukvE
BdNbxOdYlf0NYGkQHpZS86U+XGqaZj/VQnoFWHF12BjzB8GpFGbP0jSNxOZ1Knf3NhHQf7tpmhdy
028S4mA4nz9CCZBtovK4RXhMR6goLCUi6LUSS7oFL4/wIerW8xol5NQtboZaxHWGqEKOAL+S23w3
9/EcIdrP9+BXJ+H0r8FA5w/99jK82oe/S4iD64TAVMORTaJCPUGI1nFCrA5RNoBpws6xQlRltQDq
JCHMf0QIfNkCLuUcKgN5Io+rhXnyHl+lfKrqqLdFeYQV47ZEVN1VfVbL7bM5vp8lbtfP5bZqn7xI
LSjs5Xt4Ld/bbtSeLCCPU81UejmOK5S4X6Ji56AWzsnfquSDDeJzMZDjWOm8TovltNjuZud9UAMY
eW2VMaz5PkaIxCvANXlam6aZzjGvU/YRCdBuVVVCWAtGJcCPUeJeQnSA+AwuUs0ytOitTzUr0Xb6
nOu5/fklX7xSKzaptAj579UpTwvmZPPoRrONUF3/pnO8k53tZB1ZIN7zyzm/Wuzay2Mut217L+dt
dhC+uBX/piA2+ud9eIn6HK3g6rAx5g+JK8ZmT5JVNHmMu7eQe8BoPn+NatKgrmktIXSWCHE1QPyR
Vq7uPrKq2Lbt1aZpblIr5dX2d5gQjwepquTXqYQJtYo+T/zBP5HHUNOPfUTVcIjoECfh82p+P9yH
31iGwRdjO4gTO9OHX8t9H6VaLF+kvLC6XbxKVe5uE4L3U5SPdZn49z1DiMgDlLdX8VYzlNf6LnU7
XhXQ7xFiS007dLGwlfMuMXSTEP3Kfe76OtX29zhVtV6jFn29SlVflRCixWgSxRLsavTxUaLCqQq2
FvNBiC0tnNtHibjRPPcL1EI92UaezP1fybmZJD5Th3N+XqVEsQTqQarj4hJVPZZw1mLBGWCjaZob
VKV6P7XwbpT43Mhzq2xuiTtF/Wkep6jYM1lPZD+A+kzc2/ElO4X81FC+5WHiAug6VfHv+n61KG+a
imdTlrLGrczmKepugsS5EkbuUHdlblFiW6/tEZ+N5bZt5VUG3k6p+ZPEgtqPABf7MeZds4qNMea9
YmFs9ioSNH1gq23b7aZplqgFOxKHuq2uRUWjbdsuA7ebplknhO408Qd3gah8DgEHm6ZZJv4ILzZN
c4eqCB+jMm1nCDF4lYp+U4Xybo5FsV5rRGX5hfz9EtUBTPFdo7mv1/plyzgM3OuHEJQAkodziIg7
26KqmGtEBfY4IQx/QKRwSJyr6nuWqDjPU5FjNzv7vkZUoCepFr5XiAuKVyjRrAqrMouP5rwrjWKd
sBts5tzp4uL7VJvq2dzPQo7jzRyn7Bf7qJSQx/K4DeVBPUiI4V4eXyJXEXP9nEfZZG7mc4qG66Y8
7KMuEI5Qle4RKv1ECzgVLyfRepQQf5s5f4pdUwVVlW393/o4Ibx1USLv7nS+p+OdfcjuoON1kyfU
NEXtunVBtEo1OFnIc93eWTVtmmaQyntWOspojk92jYOdMXQTM6AEsbo6zlCNQIY62ymB5VaOSVaS
23meG23bbuUCuQnqc7FGpEX8mMDNsUts3wL+We573dVhY8xPGlspzJ6kaZpRSoBdbtu2bZpmnhCD
l4g/1MuET/gidWt5s23bm7mPAarK+EQ+/3XiD/Uk8ce2JUTRKiFmDuQxn8rj3yWEkNr3zhOVqruE
uFG8mLpzfYZKh5jM113NbdWU4quUgJLVo0cI2dM5Domlw4RQXKQWkY1RlUP5SeVNlff29dznn8px
SCh/nRCNqnqq2j1CeJ/ncqy6vb2Q45OYXqcq8Rq/KvVKXoBqeyxRp25oB3K+vpz7fJ7KGD5CWQW+
nK+TZ1wXKZt5rG/nOQ3nezVNCNXXc1/jlBjWYi8lmyjveIbKxd6i/NsbVMzaGNVgRIsI1VhG1dVu
Hm83vQGqyqvGHys5J8qPXs99KslE3f/U6lzbQ1Vtlf18K/9dHCFE5TK8ncqgsaiCO5fzqkWTstcM
EBdoauctkdxQUWpTVH6yLhDkg75HfS67DTruUm2570nAdgSxxPkqcXF6nyDO7ZSRLO+wq8PGmD9y
XDE2exVVqLY6VaGuH1OVQCiv5DTQa5pmIIP+JXzPEUJpPyG8RgnxtELdpp7o7Ev+1PP5+jOEIH+S
Si+YpjyWN3KsjxJ/vG8QPt9bhBA5TQmyK9TK+YV8/JXcjxZsQXWkmyRE6iuEkNFYlcv8cSpr93Dn
+EM5BiVQXKYsJocowacWwUoaWCCajCh/WR3oJAAfJwTseue1LSFKlwiRuUIIbl2s6GLjZo5zHxHK
obGe7MHf6se5AJB5y1/svIe63S9ryV2iSn44f/4KISRnqUYXWowpy4QugoaJC6WhnJujVHMN3dLX
IrdlykssUdjt5qZIN1kglM8svzA5F1NUMokW3x2jmtHookOWjabzpRbKinQjf+81TaMLrK38WVFn
SrTQGFTl1jinci7folpnK+JMIniC+60d96iUDsWzSdivUEJ44wFCVxdSE1RixvLOBXJZHda/jwHK
vuPqsDHm3wiuGJs9SS5SOgTcVnh/VpGeJv6oys97mBCJV/LnWeI2/QZREV2jmgooU1he2G7742ni
VvNtQlRINB2jFrh9lEpakPd1MfetBWTK/t2Xr386j3mZWiw3kd+1GOkrud1JQng8RsTPydrwf+a5
fSbHcZvqqjZEiOb1HP9dQlz9W1Tra8XSSSCv5LZHqArl+TzmAlFZPpzHkMiUsJ0mBJZsKY/lPl7J
saji+2zO0fk8h1uECHyW8nxvAaM9+AuT8OTnYaDT7KRdhrf68N9RntRzRHV4kxJ6aubxWOcxckxQ
Gb13qQurA/ldfuKhHMsdyiKjz8xwzpc+K7owkWUASiTC/a2etbhvi7igmKc6yQ1RF0uyBN2hvMIS
nTofCcaDVPOV9TzPOepz2xWy8gLvy+/yUOuzrkVrU9QiOgn+DUoMKx5O57lB/RvUwsAHLnpLQSyR
DQ8QxJ3qsC4+XB02xrxvuGJs9irdqDYA8rbxMvGH/TohgjcJX/F2LqSbIwTdIhXTNp+/dyOwJgjh
PZLPreX3MULYvkGJ0PncboEQE7O5j0uEOPh4Hnec6lSnCLchQmjeIYTqQcpj+xQhHKeJqrJitU7l
OF4hMntPE1XHkTzeQULsqCo6SFXWWkIkHiVE8A+oxhvThOCYyW2Wc05UbZaAeSSPc4/ytv4o9/N0
vu4yFe/1an4/lPMzSIjxhRz/fJ6T7B+LeZ7jwFP9bPX7gGYnj+b7ItH37xOfi0UqqeMj+Zw85Lr1
rtzjFULAL1Fd/PReq9KpyuqdPLc73N9QQ7nHykBep9ITFjvPSUhqbPIczxKfCXVGPJtzqu6JvZxL
iU41IJEthdy3FqOq9bTuMkx2xtgVxbqjspXvoxrNnMzt5eHXPN2lFtttd57TOXe/fqwq3KVpGllX
JIhXCEG83dlmZ3X4Hq4OG2PeZyyMzV5FlbOdWaR3CDGgP95aEETbthspjg9RbZSnCDvGKkDTNBv5
mquEYJkjBEa3g9h5QgycoJpafJIQTZcIkbGPqrYNEdW4PlGNPEKIyz6Rh3s5Hz9MVDjfJCqI20Q1
9CNU7vHpfN1rVIzYM1RMmmK5zlHpEfKQPptjHSHE91eoxVZKPhjN+ZkkBPY8dav/fL5+kIiYU3MK
ZcP+TB5nm7KNXMxxfIaygSwRwvgEESs3kuckv7K8qlN5brs1OzlFNWwg50X+3hHi4uAC1RpbFWKo
VsUTnfm/R1hj9Jox4n3V4rs54oJlkHhPbnfmV/YK+b+VZHIzv5T2If921y+8SFzoPJbz36MWzvWo
RaSrlHdXVgpyG8ULqoWykjgUPaeLJHmMRwkhLG/0QI5rlfgMqgos5N9WHJ0SLXatCndJQTxJ+c6X
iUzh7Xz+QdXhtdzG1WFjzPuOhbHZq3Qjo7rIv6nq5yww3PEV3yBu5x+kbAs3O69XO+WW+8XxYUog
qYkFefwnqcV+ivVSjJY6wl3I16i6PESIQ2XaHs/t3qB8lj3g36YaQYwS4vGVPL97+boZQmwPEhXY
S9Siua0e/Af9EFwQO73Uhy8QAkzNNeZyvrTAC0IAaYxvENVlLYLbn8e+mMd/Kh/XnNzL/T+T28rr
eyffowOE0L9FeYK1UG8mn3ua7Hq3S7MTLSaUv1Xe3es551pI2KOsKVrUtd3Zh5qUqMqvHOZLbdsu
Zdc0NZ6QkFdranmNZylhukB8TqYoz/l2ZyyyI/RzTKoar3XGcj3HKaEsP7G863TOSfnEULnCytiW
uJR1QpnFet3VPM5R4nN2gfvtEqoKq/X522L43YrVFMRapPcgQawKcrc6vAisuTpsjNlLWBibPUdW
lYao2Ki3adt2s2maNe73vu6jcmrl6xwkhN1C27YbD3i9UgxuULff9Uf9JiEirhJ/wE9TyQqbhEhc
Jv7IHyIWMC3nzxK5b1G372eJKtpiHmuUskaMURXQs1S1UNXIRztjlbA7lvuZ78GnJ+GRzxNV1/Tn
Hl2G/7gPv9U55jYlTm/m/vtU5VvjVUVYYvh4HvfZPA91klNGsPynV3P/i5Q3doO60JB15SSx8E3R
bd/uQf8l+MSOrmbbPfheH76Uc/QU5ee+QVThNwlBrlbP5PFuUlXOU4RwP5PnOJHzOpjbnOpUMZVG
oRbRM8TnbCofv5jneoi4IyBPrmwqm4TYXafuZsjGsEKI1zbP/2i+j8oUnszvan/eUM1KJIrH83zl
K5bX+jbVOEOd6fTeLlBNVEaIOw1K3NCFZ7eJyHtqkJF2CFWI1T1wJW1PTabLqNmLq8PGmD2PhbHZ
i6jaJZ/jTpaovNlF6nb7KvFHWLeBdTt3J3epBg3yXp4jhM4IIYRVaXucEL2vEX/UnyTEom5dv061
l1Y19pvAy4QI1GLBG5QweppKuLiSx75AiJfP5NiUMztJCMtXCHE1Sy1Omu/DyYf4c4/nXFymqqjz
hGicyPm7l49/LceniC5F012mWv0qi/bqjvdEXdRu5txpod0WIfyezvMaz7EfzOe+SfiWh/twZhn+
xothKdFO/2Uf/joV4XaVyBVeznl+lOripu56bxARZpuZ0PDRPM+zhHVgX762Kzy1mE5V0lHKUrNK
fFbGKFGvphVqYLGa789Zyi+7TXwuJTpl95F4v0l85hRdp3bm84TgVuMORa6pVbQ8uYrpk7DVQkal
YyhhY4DySw/kHEj0v+eqcJessE/mPPTzOKspiHtN07g6bIz5qcTC2OxFJOQ2uot1OqirnbqG9YHJ
9Bcrq1W38UebphnZUTXu5yK+SaLy1hCCQZmzqt49R4imM4R4madSAh4jBK1i44YJUXORsCTMEWLo
ezm+XyY8vI8Songzt1UXtumMLHte4xyAhW34DUIUT1Kd6RSdNgS7+nNlE5GPdYBKIriSj10gROrd
3J8Wo8m7e5AQtxACTPm6Wzm/WjAoz+/+nEfFpE3kNlOEIHuDEFEXcr5OAMt9+DxlV/lWPyqdP0e8
x+eI3GIIsaUq9wIh7mTtOAIcaJpmOMfdJ8T3KnGxM0JVtZVBrC5y8t8qj1lWjJb7o8/kMz6f86AO
e1N5Xit5HC341CJA3c2QVWKLWLT5c1S3vvkcU7filSES3QAAIABJREFU3FILKzfyPV0nPq9KU2k7
53OPSr3QRYySVd7gD1AV7pKCWCkWOwXxaApi2V+ULLH50B0aY8wew8LY7EXURezeQ55XRXi6bdtL
TdOsEAJFVU/dJl7Mfc02TbOwIzN1mRCac0QlTdVedYabJ0TIKuWZ3UeIrwb4PaLCeZwQmarinctt
xqlc3+epBhLP5f7eJNIcrgEbPfi/J+EjOywR+5fhl/sxBnUCfIUSn6uwqz/3tTyfOUL0LRCifYCo
fq4SiwOVZqFzm6RaSGuhFLndZJ7z61RChxYGqsGHWjUrhaMlLgIu5DZPEEJVFo5vUb5YRcm9QNk+
blFRZvIaa2GdusnJ43qIsmpcoWLjlqi8aXX7W8/HlD08kfuYy/PS/m8TFglFsc0TF0ZKstCCRfI4
sq+M5GvUUnk450fpH2M5R7PERccQ1UjkUu5L6SDyVqtyrMWLsl4olaKhOh3eybm8Dry8MzP4vZAX
G1N5XCWLyNc82TSNUjq00NDVYWPMTyUWxmYv8nZzjwc9mRXfVeIPckMIp5OE6FCUlvyoNwmRN9s0
zc3OH2s1jlC6xUGqDbEqb2pnK9vGo/ncy5Q3uEc1yrhEeVDv5LEfIxaoDROC5Soh2C5QC/Z+uQ/P
7WKJaAhBLGE0RHbU68GZl+DxFgY6/tx+D77TD1E1SVWIL+frDhPPfYOofKrj32FCmD2bwzhHiKHl
/P6zhGXgfI7pSaplsTqdbef5T+XcnMt5eC3n/Ik81reISrWSJE7k+6cFZFeo8V/P1+j/qxVCrC7m
7zPE+3+EEJpbOc+jeU7KnD5CCLdbRCX5GrXQTVVQLdxTm+epHNdxqg3zVWrRorqyqXX0bI5nnfiM
PEL55ZWPrc+dLCBHqKSIS1Tc3zK1+E4JF4rmu0ZVuzep9AqoiL0jObbX/6CiOC0pShHZInLF19I7
PEtZT1wdNsZ8ILAwNnuRh0W1dblDiJURQqx8hBAx68Qf6htUYwM1xJgC7uYfe6VaDBLidYkQIicJ
AXeDEB3ysSp94Qe5H+XWaoHecaqS18/nnybEyTzVBOONPIZi1vYRHundLBHjhHBcyu2XiervWB9+
axn+ZGb+avK+0Yd/RHW+U8e0O3nME8D3CfE1k2M9SOU6LxEibYbKH36LaoOtVttaQHeLEKmHCSE4
nuf5eu7jGCVsZTWRKD5JLTJU/NvlnK/pfO8UAaZs3m76h94LpT9cIIS7Fqcpw1iZuqpMn6ZsK2pY
oQVosjw0lNjvJk0oU1gicF+eY48SxCdznFqcp46KupiSmL6S491Pxa4dIj43ioBbzzluKR941zqh
3GRd4C3mvM8Bb7Vtu8Z7JP+NaG51MbEJjDdNoxQNV4eNMR84LIzNXkTCeLdFQfpjr0V36rC1RAhA
ZdmOtm270jTNXWC6aRpFva1TXkilPuyjhOddqrPdU4RwuUStwJfoOZuvl+dWsVSKPFOM2KvAvyJ8
pSuEiHmaEExrsKsl4lKOVZ38tBjrAnC7D/8TIWSfAKb6YY9Q844pqrvfMarSvUH4WyV4juWx7uXr
DhOiuEdExH2XEP+Hc17USW459/0ZygLwo9zHUaqd8gAhrhcI8Tyb+5nP+ThHiOmrhKibzvPV+6AE
jDVKqMpasUHlDN/K1y8Rlf2tHLc+U8P5vuj9W+/8rLsUi/n6dcrTPZZjmsu5UqVbc7lJXUhowZku
7G5Q1d4250H71uLBOSLz+WUqzeR2571TAsYwJYb7wDVVg7NbpJrinCQSWW7zHshKsLK57+V8QrWZ
VqV7xdVhY8wHEQtjsxdRBXA3YSxBpLxfWSiGqMVAG+QCvbZtl7MKdoqK81IV8zYVU9YSIllNRFS9
O5/HgxDHM1Qb5BGqE5+aaWjBlppQvExUpg8QglZtfJ8GjvfgjZfg0R2WiLYHL/dDlL5AdSh7hhD/
En6bhNh6lRDxA4SgUUTbm4RIfYKqNu8nxJ78ymtUpq780PL8rhO2iSlC9M503ofHKK/yd4iLgo9R
7ahvdd4XpT4cpDqiKWdZC+Emc0zHcvzLeX53KVE8l6+X2DyQz9+gkkga4Bfz3OT/1jbynmtRoESf
mnPsoz5fK1Q3OM2HLjhmCQHa5OMrRLVbFV2oLON1qsnKHFXhVbzgtzpz/EbOnzKK1dJan2fy8e2O
KFZs2irlH7/Eu6RpmjGqPbY60A1Sd0w26Sy0e7f7NcaYnzYsjM1eRHaEh1opsgW0FnupyjsK9Dt/
uNeJKnGTj6mTWEuIM2WrLhNiZbCzH1WVj+c21wlhdjz3fZ6qoE1TAkIxVgtU3NdpolKs2/jqcHYs
x36uD/9gGf7zF2NxHsTOvt+H/4Wwiah5iSK+zlOe43UqJeMmYUt4lhBZ8qs+k+d3Jo89n8dWlrNa
F49T7YK7VdYtqtJ5iBDg24RP+Uf5+CdzXpXaoBbaErTrhI1jLh+/S92ul1g9nueizOTFHKOykw/k
dhLcRwg7wia10E+Ct6HEuaLyyP2oqnuH8qPLPjCR76eadaxRF1+6U6F0inXqAmiYaiiz1plDdaHT
3Epoy4KiHOVL1HutuxNLbdvezWMq47ulKsdiJver5jVvvhsBm4J4ivIu3819z+LqsDHmQ4iFsdlT
NE2j/Nb+u1gwtESIy01CoAwA203TDOUf8nVCMIxmzNQwIe5UjVNsl/y3TxBC6mjuf44QJxepauoy
IS6fpNIHfpYQqxJwtwih9BYh1rYJ8XyIah19LL9fyOdn+/CP87hPAuf7dYsdaqFZn/LvzufYz1OJ
Bx8hxCeUB3SMqOLeIkSbrB+3qcVyEoZQom+I8CL/KJ87QVSuRwifsNol/xIhyNQE4xaV9atK9GNU
RN0t0iOd45kkRN4EYdXQhcVCPvZxKu5N57CfeG9vU3YHLaaTl3kxf56kkjPIc97Mx/tUhzzlQ6vC
q1zsoZyjIepC6iaVaDFApZqogUg/n1PFWRVf+ZeHc85mqaYoF3K+nqCq0PNN0yx3YgsljBWtJ/vD
CCG8J4Azu2UTp7hWhVjpL7KUjFDV4bWHxCUaY8wHFgtjs9fQ7fHld7HtBiUI1GGsT4iDxUyv2KSi
t+5QbYlHCWG1SIgtJU5IAA1SFVUJ8GXCljBPCLIx4NOU33SYEJHjuf1hokGIjquUgVOEaJ4mxNFK
/n4px3E1x7WfEMbXKQGnW/byNm/m8bTwsJ/ntZ3jf47w/w7k2BQjpgWCM1QDCnUm09y+DHyZEP6q
QK8RlWkd90Ru+/s5V2o/vE1UlZV3K3G4nPs6QvmgZ3OOlIOs7nYQIvBuzo2aVTya79NazrEuAFTB
X6FygcntlA2sCyRlO6vrodIw+p1tNzvH1OK34TzOfqpJinztKzlWVYjVklnRZuOEGFWShT6v24RF
YS3TVsYJH/a53H4y9yvkh95MkTtDVbsvtm27wgPIbTUGLQDcohaSruU4HhaTaIwxH3gsjM1eoxtJ
9U6oDe4kIZzk3RxrmuZuVrv6lEe4T1VgBwhh+SolUJcJsaM4LVWAjxHC5ywhSpTeoNvtN4nq5vnc
VhFnakKynvtSR7UtQtAdytcp2m2OEGATROVXldmbhG90Kx+T0LrM/Yu4ns59zvTgU/2yfdCDhWya
MZRjUyOIAaqBhBaZLRCi6SRRrdXixAt5rCb3cZXwFc9R8XZqN/x4brdJRLUt53mponsln5/LeVL1
diiPc4PyHcuPqwWBiuFbpy42pqk2z2NU049NqgmGouX0fZ3qgjdIZTiPU50X1c5Z5y2LjxJNdIE1
SVWSdXEwRHyujlIVXjUlaSgrzzgw1DSNMpBfy/0pg/hgp2qsarEah2i8+4iufwvsYIcg1nmqgYi6
Gro6bIwxWBibvUePElQPJf/Ya6HbPPHHfY7ykY41TaMFef3cnzy0E9SCpsOEeBkmRMiRfL0E8z5C
NJ4lhMQThNBZI0TwbaJaqlxfZb6qggshmCbzse/mtkqkGMt9zFPNRNQM4iohSI9TbauVs6tjXyPE
8GaO62gPfn4SDjygWcgf68c+R3JMi1QnOAn+5RzLKUI0LhDd+6AW9Z2lxN16ZwwQfupDVEONCUJg
q/nGK7lPibURwvbwrTxvta0e6BxD7YWV6SyRPZbzoEYbEuUSfcqkVgc5xazpOTUGkZdaTWEu5c+D
xGdqhlr0tpnHUOVe71m3KczJ3HYl38MzuY06Ao4TYl/2H10sjBLv+23iguhTxGfzTr5O75NEOzmv
+3O+L9Ah/41MEJ+9bqtrJaG4OmyMMTuwMDZ7DQnj3RIpoKp665QA3aYWo0lM6Xa4xKxuO18lROGn
CIGl3OOWEEaHch+XCOE2QwlUKCH7CiE0TuZ+xvM4K/n7OhUD93u5v1OU+F+imjeomcggtejs43m8
69RiviWiovwaIdy0YG0K2OjDwYc0CzlMLUhTrq78zw3VzW2I8DC/nuPRrffzhPi6R3UYVOW5BT6b
+zpDiGfFjc1RQvImVTleIwSiKt8/k8dR6+W287MugpYpny2EUNdjijWT0NXnaItayClx2G22ofMY
oDKdFY+2mmPuxrJJTE7nnCvTeSvn9Fo+r4QLtRK/S7zHEJ+TeSobGcrKM0FcPPyQWNB4AFjLyEGo
OyXKiN4gFtttw9s+fQniceoCRoLe1WFjjHkIFsZmryGv6zstHpJYW6daFes2+iJxK3+VECknCKGg
CpoWQp2gsmF7lLXikXzum9RiPLW8VSe0i4TAniCEqbp/qUkEhMg5SgjYH1FWDbX91e3464QIfSbH
PU4lYizlsRqiGqnItimien2Zyk2W0NutWcgGkSSh5iLqFnci510tom9SIl9pG48QonGF6go4Rgjf
0TyPN6kFZ+oKOEdUuwdz7uTvXc2fjxCZyocIX7OizeQXf5RqOa3FkhJ5sllACeDuZ0cd4XRMZRYr
+3o4z/NAZ/6WKc+whLAaiOg974pqbScPskS6qsnyHM8TIlp5zHpOF3kS7Vr0eS3nU63H1ZZa56B8
5nNt297rCOK5fF/kSV8lkiVcHTbGmHfAwtjsNeS73C2RQrm48kdqlf0W1fxCDSFmCMExRq3AV6zV
LCWQtABskhB/V/PxRwhxMUyJ4nM5hoOUEL6a+1/JfZ0iqnnfJcTNWG4/QwhAZeqqAcOzhEBV3NeR
HOcZQoQqN1fiUt7Y/ZTwv55j3q1ZyFXKTjJD5QlfIxYANlQk3KU8nyNUrjE5t2o4skIId1XJR4jq
+dM57htEpXk8z/ujlE2hT4jFa515Xci5VpVdCQ8L1HsqwSd/tby3+lI1XpaKAUq43iM+O8oslkC/
SUXLSWD3chslOOhuhsS3BLMsGdtU5VnHG6Gi4bby53HK1w6VddxSFiJ91m4QFz9PUTnYpylf9yvA
UtM0M1Q2tXKIVwi7hKvDxhjzLrEwNnsNZeY+UBh3qsW6Fa/Oa1OEwJFoXKCEG9Qt+q4oUvX1Hvd7
jRUBdpCwBBzlfhGltspqCX2FqgoeonJ6v0GI4gnurxgO5TEGCPE4T4idfYTQkYdYCwRb7u+2Nwd8
Lcf66dxGrY/39+BHL8HpHc1Ctntwph9+4RnCDz1LdZHbIMThELHNRj5/Osd+kahqa14OUDaF7Tyf
G9RFwscpW8sYUQ2fzmNdzfcQQvgrgWSZatAxkdvLOqIFb0v5vin7V2xSolKVU1lUtikfryq9a5S1
oVt5VkKHqsJQecdq+jGw40s+5cHOa3qdn7c6+5b9R1VjpaqM57aqHOvi8DAZ/9eD/7UfFxY6wO/1
4c8RolnZ2JeJ6vC7WbxqjDFmB42bGJm9RNM0TwH32rZ96yHPT1Bd6W62bbvaNM04UaFVK9zvEaLi
FBXfNZ7PydPZEBXKQ4SAOtLZ7xWiWjqVXxIpj1OLwvYRtotr1MIrtaW+S1gnlFH7MUJotXmciXzd
7+Z+nqB8uJv5szyhV6iM3AFCnB4nhOgw8MfyOGdzzEPA3R78+X7YEwDowet9+B2iqqzK+jp16//7
hEg9kNvMEeL/GCGY1VBkgIonU5VSVWNFpskKcJRqz6y4NlXzp6nK7wQhimWjmKPaX6uJxkruR1Xh
e50v8jj7qJg0LbST73ibeN/V7ns1XyeBLYHabUcuIfxOedotP16xlmju/qyxDHZ+17EVITdN+eMV
7TbQg/9wEh7/PDSdBZX9ZfhqH/4scVGy4uqwMcb84XDF2OwZmqaRkFl6yPOqFg8RHcEkbuQ5nScE
zXjnZWOE0DtOiOBLhEh6ixAlWhw1Ty1SOk/5Y5X5ezzHdjnHcJNq8KHK6ThRqX6TqsTOUdm8qiCe
zfF+Jh9XDvI6IZy1gGuUEMCvEZYO+XVX8udfpJIelBRxCRjvw18hFrO9AKz1KynjXG5zkGon/SYh
So9SXeCO5DHOd85zJI89QAjRfr52iqhaTub+blA2ByWAvJljP8T9C84kbOVtPpZj26AqxLepiDlZ
EiZzfFM5LlkcdBGjNsaqCi+qiprtk0eoFAjyWLfyuBvqGpefOX110yx2fr3X51RlVsVZFz93qTSU
oZyzJ/vwxAMWVPZehJ8HBtu2feC/GWOMMe8NC2Ozl5BQeNgiId1y1q1toU5iqsTtpxY+NdSiMSUp
nMvnnsnnjhFiTlXPx6hb9o9QHdau5bFGCcGoRWjPUbFrV/MYagCh118iROIs5Y9WMxG9bj6/n6O6
9imNQlFmWmT4LHGb/dvk7XMiMULi8ighIO9Q1eG13L9E5wAh5K9R4r4lKthaAChhd4O4GICKXoNK
qFAjCl1QrBBC83u5v+fzWLeoaqysLdc6834s5/5yjvVG5/1VAoREerdyDJVPrCi65bZt1QRjJH24
slfotUvA+sM6xaVA1m21+yrHHdE8sON7txLcrQbr4kgL/lQV1s9jVAydtpUFZLcFlU8Q1X5jjDF/
SCyMzV7ioc09dniL7+7wUOq2fHeRnVbjH6EE6AVCaK4Ri8M+QVgH3iSsDxJfEDYCNby4Qwi0qRzb
JSJndoCIe5skhLKqdmrOcIQQ5Ldy34eoxXYjRJVX9o0T+dzXcjyTRPzZp3P7Jwihfpvyr75GVFpv
EmLwOiEcn6Ri31Zye4m6S5Q4vJ2vV9zcc9QFRo8Qsj/IccrnLA+1bBWKc9PYtMhwOn++Rtg/ZqmG
KYdzLhuqpfWJ3NeF/F3RZNpWEW9qzKHntdBtLed/LcXwICGG1Qq629Vug7LTDAADTdNokVxX4A5R
nnS1S5bA1TxpGwlYJZzoIk/Pa596XBdxUIvublMXZ0oGUcb1d3ZZUPk6xhhjfiJYGJu9hLyhD6re
KRmgK4rkOZ4gRPBRQkRpMdVRQshMEtaJ87nts8C/Q1Rkv52PH6WiuZQIsEUI4k1CtL1JdTQ7QcSI
yfe7leOX1ePR3I/E3AyV0KBkhONU9NoQIWzHiOzaKUJgTuXjVymf7mOEKP4y5ZV+lPAUaz6g7BnD
hNjaJsTpJwmhepHqOvdMbn8nx3KXEM33chulYsgPfJNa9Njk95NU+2S1657J7c8Tolrzd5IQfF/O
/R4n/NTXch8nCSEu4duNRFPnNglctXAeBQ6kyJVForuQc4AQ9arGdr+6i+d2Nv3QMXVcLY6DEtJC
F2wDnW2F9iUhrxbSy9QdjvUH+IQvDjXNb74En22h11lQ2R+EL222ravFxhjzE8LC2Owl5Od90C1r
icxbbdtu5uPDhPAin1N2qzJ3xwjxcYMQl31CFH48t/tyPvYkIViW8jhqWjFOCMAVShSdpoSSvMBq
krGZ+9OtcQlMVYzlfd0m7AbKrB0lhPs+QnjeIaq1Es1zRIX7dWrx2lcJm8I+4I8TCw2nqQzeXo7t
OiH6D+WYnsvzP0dUg5+gbBELVFrHMlVp36YqrqqMa6yrlIj8Ws7bbD4vESxryjKRmvGX+zEOgF/t
wQ/78F/lMU7k40ptUPMW+cbVSGOb+zsZjlEebnmN5fPWewclVrc6X2odrc+exOzO9AnZJLqiWTnJ
3d+7x9BnSZVq/bzetu07Lep7my343Ap88UX4FT02CF/ags+9230YY4x5ZyyMzV5C6QE7K8ZjhOhT
hU0L9ZStO0SIJLUKPkYInHPcvzDv54kFb1eIiut+avGc2glL2N4hRKDydGdyH1P5+nO5jRo+KP0C
QsTOUZVV7XM9H5ui2iE3wBtUd7VlQqRp8dpHcjv5aE8QCRKvAr9ACEwtVlvM15+lMnP35fydIirD
Smb4Su77dO5fUW2K/VKe7x3qouNuPjZPiMO7lL1FyRNNztsP8/jzOb5TwOkevDgJj+xoV/3MMvyN
Pvwd7s/7lUUBSmR2WyhLJCu1QuNWdJs80xK7EtQSuDpf+X5lnRF6je4kdCvAWjTX9R9rLPpaIxJW
3qmL4zvStu1t4E80TfMkcTHzuivFxhjzk8fC2OwlhoHNtpMhmNXiGVKItW3bz8fmqdvgSqPYzm1H
icVbrxMiYp4QxEcJ0bZORK9tU5Fgl6hFZBDC5zFC9G4QVd/ThP3gX1C+4P2EuLqdxz5IWA8WCfvD
GaIiPUyI2Ta3G89x/pCo/C5TWcf93O9jeYyx3NejObYp4D+j2lJfIUTqmTyf1dzmKDDWgz/XD6sE
wJ/uwZv92E4VdX2pGcp1yq6iGLRN4v8L2TTI85SI309VeXV+k7m9bBiP9+HEA9IVBl6MxXm66FAX
weXcX5+yK2xRiwdX8/gSqRLTErlqRNL1TavyC1UhvpfHUpZxN3JNAlo/6zVqMCIBvAlstX/E+Zdt
iGELYmOM+SPCwtjsJdQQossY5VNVI4hZakGUGk2MEbf+7xEi9wohDH+WEHCHKZ/qKUL4Xc+vC8S/
hccJYasGELeIRXmniIr1AhGNNp/bTufxZFmQiD5HiLE1KhHja4RY/iRRTd7Kx/4FIfD2Ubf9nwfG
e/Bn+7E9AAOwsA2/TVTE7xL2i4v5HUoMThKV3n09+GuTcHpHhfbR5RDL/zOV3KE4txs5v0eoSr0q
6WM5N8oK3qAqsmpgoTQG2Q+2O8/3Ydd0hSXgX+bPI1Q6g9ImVAFWp0N5syV6ZXGQH7hb7VUjF1Wk
ZbXQgjktrFM1Wt7kjXytLBD/RgSwMcaY9wcLY7MnyCqwWjZ3mSGE0e22bbebppkihJ+qq1uUD3eB
sCU8D/ynVAe1w3RirwgheoMQ2i2x8OsAFcu2QHl1dzb+mM3j9wnLgirDY1RXuxlCUG0SYv1intfz
+dpVolX0V6hGGBP5/RFCFP/5bOjQFbQHluGX+vD/5HEXCMGm9sD7qDSFTSL/9ukHVGibF2Nx2xFK
GE/lOY3kY6qc3qIuVpao7nvqPteNeWupBXFdIaqq/H7gc7ukK9whKvzdRZjdXGIJXtGnKtYSwbLO
dD9HmhO1d+6K6W7VeCnfG713W26YYYwxHy4sjM1e4cei2rKj3SwhmFabphkjxN84IQYhROs0YZG4
0oMv9KPxBQADcGM7qr6XSM8nIbokUNeoWLPrlE94k7BOTBEVWXlPJQKVA9zmGJ6nhPpIjvsoIcpu
ERXmI5TNowH+XUIQq/HFCFEJ7vfhyQcIWl4M8a32zco13qJixWapiu0jsGuFtiHEtTy93yWq3epM
p3ORz1pWAgnPJSoBpGttUBW26+8dBrZ68JWX4IUd6QrbPfhmv9p7q0LdrTTvFL6bnccVgybbgz4n
w53HVQHezHHLBrFF2HcsgI0xxlgYmz2D/J/dfGKJ31vEZ3WOEGxqkqGM2teAN3rwm5Pw6R1V1v3L
8Ew/fJl3qOiyLarNsdo0K/t3MI+xSgjHR6iOcz1CmK8Rgnmc8AIfIkQXhHhdIywWVwkB9hEqy/cG
6f8lhPdoju1svu6Pw66CVmkX6gAnz+sWFaO2CnwD+FO7VGgvUPFo1/NnLTSEiltTlXU952Mpvzao
RXG9zvayKTTc33iFPvzXy/BfvhgWF4gX/qs+/MWcFwlfCWMJ2pYSvt3OdSOdx2TdkIiWANY4N99L
EoQxxpgPHxbGZq8wkt8Vxaaqn8TSQaJCOktVBDeBb+X3P92Hn39IlXU/FUG2L59ez31qAV1XUEGI
5vOExWIfUeU9R9kW1ghrxSPEvyM1ZFCzi+/m/i4BH83zO0OlNYxREWhq5HCCWCS3H0LYP0TQfp2K
ZLtJiPo+ZXuQ93a7B99+CT7WwsCOCu23+3FO4/naO1RrbHLfsrFs5nncyWOoYkuerxZHQlkdtMhN
VdrtfN2lPvwZ4kLiBPBaH15VxbZpmu6CN3WIkwDW40LJE1qk93YaxU8iCcIYY8yHDwtjs1dQzq8E
zQFCTN0ixOhhyjYxTQjCHxIicp7wCe9WZb1INKyYpW7XP04Iusu5PzVueIOojCoCrgFezvEdIwT1
FvAU4YndJpp/LOV4LubP/Xz+GUL4vkFFy83kGG7kaz5Bddb7Rg+eeQk++gBB+71+iF/5cJU7TM6L
bAX7gLYP/80y/JUX4WOaiBTF/1tuM0otFpyh/Lyqiq9QrZyVADGW74l8v1qk1q3ySqTKb7wObGjR
WtM013JOB4Gppmm6neXU2U/Ix6xFcNr/Fl4IZ4wx5ieIhbHZK4wC/Vxgp4rwVUKgHaeEsYTcdULY
jlKe392qrN8kBOh+ajHWfkLwKY94nbBHbBLid5CyBEwSlonDlO3jEUIAv0wtFFvPfR3K171AiLnz
hHBV9vJintun8lyXiXi5t4CLffjmMvztF6sltATt38vjTFH+Wy2IU97wjZy7SWC9D/8F8DNEvvJ3
+mE9OZljUbValWNZFGQF0SLFHMLbC++6WcHd1AilQKgjHZQ9ZbQjgLsL4FRllm1CvuW3xS87YvyM
McaYPwosjM1eYYjyFx+imiU8SgjQI4QAfqvzuOwI28D3evDll+DTD1jY9Z1+CcezhPXgeer2vppS
vEaIwmFC8KoSrSi3+Xz8HFEtHiEE7nFCxF0mxPYAISxloXgtv6sRxzDRmGM8X/81opq8mMefBkb7
8PcJL/JRYKEfYheqVbXEZZvnodbIaiQiuwgS1cpUAAALNElEQVQ5HjXhOJzjvEtU3WWNkF/5HOE/
vkl5hyd2HEt+XlWFJWr7lECf4X4BLLTdfQkQlA3CC+GMMca8LzQuwpi9QNM0TxPibYFoiHGdEHWn
CeF5h/D0DhICtaGsCGpwMd6Df9LvOCp68PU+/F1KAF8lbAuPUCkKC/nzOHW7fpCoqs5TgnSVsEmc
zjH2CZF7lRC/qgD3iOzjCcJrvJSvVzV2iKhUv061qlaUGNzvy1VVuLsgTTFpWqg2RIhaLZIb78yP
GnJMEuL+6/n7/hzbJeJCZJoQ0mdzTgephXdKmOi2OlYzjG6Xum6WsM5D5/L2AjiqAmwBbIwxZk9h
YWz2BE3TfJQQqONUJfiTRLV0kRCS04SwVFqEutipqcUkIeIOEML1JvB/EYL04/n744Tvd5SKPbtE
VT8VTTaV47iez0/nOOYIz/Aq5ce9kj9/NI89nl8/yNcfyP0NEJXcC7kvxZGpatpd1AaVxiBBKs/v
Sv6uaux4/jxBidhNarHcBCHw/wxhm9giGpV8hxDwg3mOF/N8ZnO8spJI2O4Uw1AeYwng+6q/OAnC
GGPMTxEWxuZ9p2maHmFtUJV4iIjzOkhUgpW0sEL4Xi8SomuUEK+Duc3t/FojxN1TwPeJ6ujHiMrz
cUI4LhKV3DUq4UHNLW4Rwk8NMPbn89uEsO7nca4DN3vwl/phjYB44eI2/NPcj7KNFwkhr5g1fSmF
obuQrVsNXurMQdsZp3y5m1SG8EqOcZgQ99O5zVQP/tt++IyBt/3K/z1xYaCK+DTVHEQZz6tUtVrV
4rd9v9xvgXAShDHGmJ9qLIzN+05Wi3+J8A+vEaL4KCHKtqhotOv5EiVYrBICdZHK0h2kfLr/HlWR
nQKezeffIiqkk/maFarj3QZlhRglKrwTeawnCVF6ixC53+/B35yEz3weBjrZySyHJ/grhC3hQo59
kRLGcH/XNcWOSRSrccUY1elvmKrgrlIxZUpq6Pp8B8jWzj34HybhkzvGuL0Mr/bhb1K+5EWymUrO
SbcS7CQIY4wxH3i8+M68bzRNMzcIvw78ih7rwVv9uMW/SAi2BUqwqlvdbarz3CiRh9tt+TzWg7/a
D7+v9nujH9YGdcBTt7uB3H93oZmqsTeotsincjwXiMVpbwKP9+EXHpKdfIAQz1/NY96jEi5kjVA7
Y3mdW2qhm3J71UDjFlW93e6c7yBxEaCmF4o7UxX6sT688IAxDrwYlpBt4NuEYHcShDHGmA81Fsbm
fWMQfn0CPrujU92pJZjYhv+XqF7KQzxMVX61oKwbDXaPEHebPfiHk/CJB3TAe7of7aElOpeJBWZH
CIG8kvtUdVYV5UcJC8aN/LpIeI1/BnbNTj5LiOMRwgeslspK31Bs3Egeb5iqzKpjmzy9iplTuoaE
7wAlhLUITlnGDeF73m2My8BrXghnjDHGWBib94mmaZ4CfmWXausUIYxlKRjIr1VCNK5T1VN9Bzi1
SxX3MCGCLxMeXEWcDVGWgXtU5FpDCOdHCAH5KhGrdojKHt4tO3mJauSxlmOUmB2mkiPuEqJcvt6d
59wVwUp/UFV7u/PVtTzo69vAr+4yxlcsio0xxpjAwti8XzwOu1Yyb1C3+NVFTnYDJTX0d/wO2dJ4
l/3+LvDbhDDtEZaNw4Q94zIhPD9B2BOmiErxBeBLhM/5BBVJdr4H38kOdd3s5H4Pfr8Pv8P9VVy1
V5Y/WJ5iid/BHJci3VQJlp1B2c6yV3R9xW//vEPoLgw1zW++BJ/dOcZB+NJm257BGGOMMYCFsXn/
eAN2rbb+74QgVWW021mtm4Rwnwe2aZqNd9jvPyeSKqDsCepWp/bTsjU8l8f5Z0RF9+cI4b1BiOQz
ffj9ZfjHL8Iv6gA9+Gp2mxvP1ytVQg04ZJ84wv3VYCjrhDrAPVAAvxfv7xZ8bgW++GLHyz0IX9qC
z73bfRhjjDEfBpxKYd43hprmNybgs7+2o5K5EpXMP9E0jbyyyusdoiqp4seiwwbhnz5ov8vwO334
TwiBuUQI3AOESJ3N/f0CYZU4kvv7/wmv8XHC5nCJSs+YyLH0iarzYcJXfIaKOGuoFsjyA3dFruwc
PyaAf9IL35qmeZLIcH69daXYGGOM+TEsjM37RtM0s4Pwxa37K5m/uQWfa9v29i6v06K1wR3fVXWd
7sHn+/DLek0P/r8+/EeEIFajEFkTTvTgf+zDZzrbX+3D/0E14bhIWC3W83gP6uambXvcn/kr8bvO
/akPfac+GGOMMXsHC2PzvvOTqmQ2TSM/r4TyU7nfc0QlVzYFdZcbA3o9+PVJ+MXPQ6+TYtEuw+U+
fIEQxcuEEFZ2cHcBYJ9KkdDjFr/GGGPMTxkWxuYDT3bWkw2jW2UGOA389he435P8BeDF+PGvEp5k
NRJZIwSwxHEfi19jjDHmA4EX35kPPG3bqoPbuh5LO8Yg8ALsmmLxGvBbuQ9jjDHGfIAZeOdNjPng
0QabRMMPfnfH850Uix9aFBtjjDEfDlwxNh9q2rZ9zTm/xhhjjAF7jI35A6djGGOMMeaDhYWxMYlz
fo0xxpgPNxbGxhhjjDHG4MV3xhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhj
jDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHG
ABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbG
xhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhj
jDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHG
ABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbG
xhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhj
jDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHG
ABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbG
xhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhj
jDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHG
ABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbG
xhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhj
jDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHG
ABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbG
xhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhj
jDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGABbGxhhjjDHGAPCvAYP/OHuo
iHC5AAAAAElFTkSuQmCC" alt="png" /></p>
<h3 id="step-24-compute-minimum-weight-matching">Step 2.4: Compute Minimum Weight Matching</h3>
<p>This is the most complex step in the CPP. You need to find the odd degree node pairs whose combined sum (of distance between them) is as small as possible. So for your problem, this boils down to
selecting the optimal 18 edges (36 odd degree nodes / 2) from the hairball of a graph generated in <strong>2.3</strong>.</p>
<p>Both the implementation and intuition of this optimization are beyond the scope of this tutorial… like <a href="https://networkx.github.io/documentation/networkx-1.10/_modules/networkx/algorithms/matching.html#max_weight_matching">800+ lines of code</a> and a body of academic literature beyond this scope.</p>
<p>However, a quick aside for the interested reader:</p>
<p>A huge thanks to Joris van Rantwijk for writing the orginal implementation on <a href="http://jorisvr.nl/article/maximum-matching">his blog</a> way back in 2008. I stumbled into the problem a similar way with the same intention as Joris. From Joris’s
2008 post:</p>
<blockquote>
<p>Since I did not find any Perl implementations of maximum weighted matching, I lightly decided to write some code myself. It turned out that I had underestimated the problem, but by the time I
realized my mistake, I was so obsessed with the problem that I refused to give up.</p>
</blockquote>
<p>However, I did give up. Luckily Joris did not.</p>
<p>This Maximum Weight Matching has since been folded into and maintained within the NetworkX package. Another big thanks to the <a href="https://github.com/networkx/networkx/blob/master/networkx/algorithms/matching.py">10+ contributors on GitHub</a> who have maintained this hefty codebase.</p>
<p>This is a hard and intensive computation. The first breakthrough in 1965 proved that the Maximum Matching problem could be solved in polynomial time. It was published by Jack Edmonds with perhaps
one of the most beautiful academic paper titles ever: “Paths, trees, and flowers” [<a href="https://cms.math.ca/openaccess/cjm/v17/cjm1965v17.0449-0467.pdf">1</a>]. A body of literature has since built upon this work, improving the optimization procedure. The code
implemented in the NetworkX function <a href="http://networkx.readthedocs.io/en/networkx-1.10/reference/generated/networkx.algorithms.matching.max_weight_matching.html?highlight=max_weight_matching]">max_weight_matching</a> is based on Galil, Zvi (1986) [<a href="https://pdfs.semanticscholar.org/6fc3/371dc5d40b638a6b4acb548c8420fa67aac1.pdf">2</a>] which employs an O(n<sup>3</sup>) time algorithm.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Compute min weight matching.</span>
<span class="c"># Note: max_weight_matching uses the 'weight' attribute by default as the attribute to maximize.</span>
<span class="n">odd_matching_dupes</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">algorithms</span><span class="o">.</span><span class="n">max_weight_matching</span><span class="p">(</span><span class="n">g_odd_complete</span><span class="p">,</span> <span class="bp">True</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of edges in matching: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">odd_matching_dupes</span><span class="p">)))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Number of edges in matching: 36
</code></pre></div></div>
<p>The matching output (<code class="highlighter-rouge">odd_matching_dupes</code>) is a dictionary. Although there are 36 edges in this matching, you only want 18. Each edge-pair occurs twice (once with node 1 as the key and a second time
with node 2 as the key of the dictionary).</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Preview of matching with dupes</span>
<span class="n">odd_matching_dupes</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{'b_bv': 'v_bv',
'b_bw': 'rh_end_tt_1',
'b_end_east': 'g_gy2',
'b_end_west': 'b_v',
'b_tt_3': 'rt_end_north',
'b_v': 'b_end_west',
'g_gy1': 'rc_end_north',
'g_gy2': 'b_end_east',
'g_w': 'w_bw',
'nature_end_west': 'o_y_tt_end_west',
'o_rt': 'o_w_1',
'o_tt': 'rh_end_tt_2',
'o_w_1': 'o_rt',
'o_y_tt_end_west': 'nature_end_west',
'rc_end_north': 'g_gy1',
'rc_end_south': 'y_gy1',
'rd_end_north': 'rh_end_north',
'rd_end_south': 'v_end_west',
'rh_end_north': 'rd_end_north',
'rh_end_south': 'y_rh',
'rh_end_tt_1': 'b_bw',
'rh_end_tt_2': 'o_tt',
'rh_end_tt_3': 'rh_end_tt_4',
'rh_end_tt_4': 'rh_end_tt_3',
'rs_end_north': 'v_end_east',
'rs_end_south': 'y_gy2',
'rt_end_north': 'b_tt_3',
'rt_end_south': 'y_rt',
'v_bv': 'b_bv',
'v_end_east': 'rs_end_north',
'v_end_west': 'rd_end_south',
'w_bw': 'g_w',
'y_gy1': 'rc_end_south',
'y_gy2': 'rs_end_south',
'y_rh': 'rh_end_south',
'y_rt': 'rt_end_south'}
</code></pre></div></div>
<p>You convert this dictionary to a list of tuples since you have an undirected graph and order does not matter. Removing duplicates yields the unique 18 edge-pairs that cumulatively sum to the least
possible distance.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Convert matching to list of deduped tuples</span>
<span class="n">odd_matching</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">pd</span><span class="o">.</span><span class="n">unique</span><span class="p">([</span><span class="nb">tuple</span><span class="p">(</span><span class="nb">sorted</span><span class="p">([</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">]))</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">odd_matching_dupes</span><span class="o">.</span><span class="n">items</span><span class="p">()]))</span>
<span class="c"># Counts</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of edges in matching (deduped): {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">odd_matching</span><span class="p">)))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Number of edges in matching (deduped): 18
</code></pre></div></div>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Preview of deduped matching</span>
<span class="n">odd_matching</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[('o_tt', 'rh_end_tt_2'),
('nature_end_west', 'o_y_tt_end_west'),
('b_tt_3', 'rt_end_north'),
('rs_end_south', 'y_gy2'),
('b_bw', 'rh_end_tt_1'),
('rd_end_south', 'v_end_west'),
('b_bv', 'v_bv'),
('b_end_west', 'b_v'),
('rh_end_south', 'y_rh'),
('g_gy1', 'rc_end_north'),
('rc_end_south', 'y_gy1'),
('rd_end_north', 'rh_end_north'),
('rt_end_south', 'y_rt'),
('rh_end_tt_3', 'rh_end_tt_4'),
('b_end_east', 'g_gy2'),
('rs_end_north', 'v_end_east'),
('g_w', 'w_bw'),
('o_rt', 'o_w_1')]
</code></pre></div></div>
<p>Let’s visualize these pairs on the complete graph plotted earlier in step <strong>2.3</strong>. As before, while the node positions reflect the true graph (trail map) here, the edge distances shown (blue lines)
are as the crow flies. The actual shortest route from one node to another could involve multiple edges that twist and turn with considerably longer distance.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
<span class="c"># Plot the complete graph of odd-degree nodes</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">g_odd_complete</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="n">node_positions</span><span class="p">,</span> <span class="n">node_size</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.05</span><span class="p">)</span>
<span class="c"># Create a new graph to overlay on g_odd_complete with just the edges from the min weight matching</span>
<span class="n">g_odd_complete_min_edges</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">Graph</span><span class="p">(</span><span class="n">odd_matching</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">g_odd_complete_min_edges</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="n">node_positions</span><span class="p">,</span> <span class="n">node_size</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'blue'</span><span class="p">,</span> <span class="n">node_color</span><span class="o">=</span><span class="s">'red'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s">'Min Weight Matching on Complete Graph'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></code></pre></figure>
<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA3oAAAKUCAYAAABSako+AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz
AAAPYQAAD2EBqD+naQAAIABJREFUeJzs3XmYHGW59/FfVfW+JDPJLAlJ2JIAQQyyHJYQVlnD4gkC
AiqIGAyLICgHQUADsgRkC4cgL2ETDAgIHgRU1BcVAsruedkCCQrKEpLM3vtS7x/jU+me6ZnpmUyS
Sef7uS4uSU13V3XNNOY39/Pct+W6risAAAAAQM2wN/QFAAAAAACGF0EPAAAAAGoMQQ8AAAAAagxB
DwAAAABqDEEPAAAAAGoMQQ8AAAAAagxBDwAAAABqDEEPAAAAAGoMQQ8AAAAAagxBD0DNsG1bl112
2Ya+jCGZOHGiTjvttCE/9+ijjx7mKxr5Lr74Ytm2rY6OjgEfuzb3F+vHzJkzdfDBB2/oy9iofOUr
X1F9ff2GvgwAIxRBD8CIcs8998i2bdm2reeee67iYyZNmiTbtnXUUUeVHbcsS5ZlDct1nHHGGXIc
R21tbWXHW1tbZdu2wuGwstls2df+/ve/y7ZtXXzxxYM+n23bQ772ap/3xhtvaN68efrXv/5V1eMv
ueQS2bYtn8+nTz75pNfX29vbFQqFZNu2zjvvvEFdsyQlEgnNmzdPzz777KCfKw3u+70293dj0tHR
oR/84AfacccdFY/HFYlENH36dF100UUVv4cjydp8f6644gr96le/GsarWaNYLOqee+7RQQcdpMbG
RgUCATU3N+vQQw/VHXfcoVwut07OW43h/G8egNpD0AMwIoXDYS1evLjX8T/96U/68MMPFQqFen0t
lUrp+9///rCcf++995YkLVmypOz4c889J8dxlMvl9NJLL5V9bcmSJbIsy3vuYCxfvly33nrr0C+4
Cq+//rrmzZunDz74YFDPCwaDeuCBB3odf/jhh9cqQHV1dWnevHn685//PKTnD8b6uL8b2rJlyzR9
+nRdffXVmj59uq699lotWLBA++23n26//XYdeOCBG/oS15kf/ehH6yToJZNJHXLIITrllFOUzWZ1
/vnn6/bbb9cFF1ygYDCo008/XWefffawnxcAhoNvQ18AAFQya9YsPfTQQ1qwYIFse83vpBYvXqxd
d91Vq1at6vWcQCAwbOefOXOmXNfVs88+q8MPP9w7vmTJEu24445KpVJ69tlnNWPGDO9rzzzzjGzb
1p577jno8/n9/mG57v64rjvoUGZZlmbNmqX7779f3/72t8u+tnjxYh1xxBF6+OGHh3w968v6uL8b
Uj6f1+zZs9Xa2qpnnnlGu+22W9nXr7jiCl177bUb6Oo2Xmeffbb+7//9v1q4cKHmzp1b9rXzzjtP
y5Yt0x/+8Id+XyOfz0uSfD7+ygVg/aKiB2DEsSxLJ5xwglavXq3f/e533vFcLqeHH35YJ554YsWQ
0HOP3g9/+EPZtq3ly5fra1/7murr61VXV6evf/3rSqfT/V7DpEmTNGnSpF4VvSVLlmivvfbSjBkz
Klb7PvOZz2jUqFHesUwmo0svvVRTpkxRKBTSFltsoQsvvLDXcq9Ke8hee+017bPPPopEItp88811
9dVX6/bbb5dt2/roo496XfOf//xn7bbbbgqHw5oyZUpZRfSOO+7QiSeeKKk7xNq2Lcdx+lweW+rE
E0/Uiy++qOXLl3vHPvroI/3pT3/yXrNUJpPRJZdcol122UV1dXWKxWLab7/99Mwzz3iPWb58uTbb
bDNZluXttbNtW1deeaX3mLfeekvHHnusGhsbFYlENG3aNP3gBz/odb6WlhaddNJJqqurU319vebM
maNMJlP2mJ73d9GiRbJtW3/961/17W9/W42NjYrFYjrmmGPU2tpa9txisahLL71Um222mWKxmA48
8EAtXbpUkyZNqmrfX1dXl84991xNmjRJoVBI06ZN04033lj2mEKh4C2BfeSRR7TDDjsoFArps5/9
rH7/+98PeI6f//zneuONN3TppZf2CnmSFI/He+1ffeCBB7TzzjsrHA6rqalJJ598cq/lnWYP2Pvv
v69Zs2YpHo9r0qRJuu222yRJf/vb33TAAQcoFotpq6220oMPPlj2fHOfn3vuOc2ZM0djx45VXV2d
TjnlFLW3tw/4vgb6/Jj7ls1mvXPZtl32ffnwww/1ta99TePGjfPu6T333DPgud9//33dfffdOvLI
I3uFPGPKlCn65je/6f15+fLlsm1bN910k66//npNnjxZ4XBY77zzTlWfi9LXWLBggX784x9riy22
UCQS0QEHHKC33nqr4nX861//0lFHHaV4PK6mpiZ973vfG/D9Aah9/HoJwIi05ZZbao899tD999+v
Qw45RJL05JNPqqOjQ8cff7xuuummAV/DVK+OO+44bb311rr66qv1yiuvaNGiRWpubtZVV13V7/Nn
zpypRx99VLlcTn6/X7lcTi+++KLOOOMMJRIJXXDBBd5j29ra9Oabb+r000/3jrmuq8MPP1wvvPCC
5s6dq2222UZ/+9vfdN1112n58uVlfynuWWn75z//qf3331/BYFAXX3yxQqGQbr/9doVCoYpVuaVL
l+r444/XN77xDZ1yyilatGiRTj75ZP3Hf/yHpk6dqv33319nnnmmFi5cqB/84AeaOnWqJGnbbbcd
8D7uv//+Gj9+vO6//35v/+H999+v+vp6HXroob0e39bWprvvvlsnnHCCvvnNb6qjo0OLFi3SwQcf
rJdeekmf+cxnNG7cON1yyy0688wzdeyxx+oLX/iCJOlzn/ucpO6Qu++++yoUCun000/X5ptvrmXL
lumJJ57QvHnzyu7xF7/4RU2ZMkXz58/XSy+9pDvvvFPjxo3T5Zdf3uf9NX8+44wz1NDQoMsuu0zv
vfeebrzxRoXDYd17773eY88//3zdcMMNmj17tg488EC9+uqrOuSQQwb8ZYG5vsMPP1xLlizRnDlz
NH36dP3617/Weeedp48//ljz588ve/wf//hHPfTQQzrjjDMUi8V044036otf/KI++OADjR49us/z
PPbYY7IsS1/5ylcGvCapO4Cddtpp2mOPPXTNNdfo448/1o033qjnnntOr776qmKxmHef8vm8Djvs
MH3+85/XUUcdpXvvvVdnnHGGIpGILrzwQp100kk65phjtHDhQn31q1/VjBkzNHHixLL7fPrpp2vs
2LG67LLL9Pbbb2vhwoX617/+VfaLnL7uXX+fH8dxdN999+mUU07RzJkzdeqpp0rqDmCS9Mknn2i3
3XZTIBDQ2WefrbFjx+rJJ5/UKaecokQioTPOOKPP8z/55JNyXVdf/vKXq7qnpW6//XblcjnNnTtX
gUBAdXV1VX0uSt1xxx1KJpP61re+pVQqpZtuukkHHHCAXn/9dY0dO9Z7XDab1cEHH6y9995b1113
nZ566ilde+21mjp1qnc/AGyiXAAYQe6++27Xtm335Zdfdm+55RZ39OjRbjqddl3XdY877jj385//
vOu6rrvlllu6Rx55ZNlzLcty582b5/35hz/8oWtZljtnzpyyxx199NFuY2PjgNeycOFC17Ztd8mS
Ja7ruu7zzz/v2rbt/vOf/3Tfeust17Is96233nJd13WfeOIJ17Is9/777/eef9ddd7k+n8/961//
Wva6t9xyi2vbtvviiy96xyZOnFh2naeffrrrOI77xhtveMdWr17t1tfXu7Ztux9++GHZc23bdv/y
l794xz755BM3EAi4F154oXfsgQceKHs/A7n44otd27bd9vZ299xzz3W3335772s777yzO3fuXDef
z7uWZbnnnnuu97VCoeDmcrmy12pra3MbGxvduXPnll2jZVnuFVdc0evcM2bMcOvr692PPvqo3+uz
LMs9/fTTy44fddRR7vjx48uO9by/ixYtci3LcmfNmlX2uLPPPtv1+/1uIpFwXdd1P/roI9fn87lf
+tKXyh53ySWXVPzZ6unhhx92Lctyr7322rLjRx99tOvz+dz333/fdV3Xu4/hcNg75rqu+8orr7iW
Zbm33XZbv+eZPn16VT/Truu6mUzGbWhocHfeeWc3m816x//nf/7HtSzL/dGPfuQd+8pXvuLatu1e
d9113rGWlhY3FAq5juO4jz76qHf8zTff7PX9NPd5zz33dAuFgnf8qquucm3bdn/96197x2bOnOke
dNBB3p8H8/kJhUIVvxcnn3yyO2nSJLetra3s+LHHHuuOHTu27P33dPbZZ7u2bbtvvvlm2fFsNuuu
WrXK+6elpcX72rJly1zLstwxY8a4ra2tZc+r9nNhXiMej7srVqzwjj///POuZVnuBRdc4B0z35/5
8+eXve6OO+7o7rnnnn2+NwCbBpZuAhixjjvuOCWTST3++OPq6urS448/PujfrluWVba0SuputLJ6
9Wp1dXX1+9zSfXpS99LMCRMmaOLEidpuu+00ZswYb/nms88+K8uyNHPmTO/5Dz/8sD772c9q8uTJ
Wr16tffP/vvvL9d19fTTT/d57t/+9rfae++9tf3223vHxowZoxNOOKHi46dPn67dd9/d+3Nzc7Om
Tp2q9957r9/3WK0TTzxRb7/9tv72t7/p7bff1quvvlpx2aYkr1On1F2VaW1tVS6X06677qpXXnll
wHOtWLFCzz//vObMmaPx48f3+9i+vr8rVqwYsOLW13MLhYLXsOb3v/+9isViWaVWkr71rW8N+D4k
6de//rUCgYDOPPPMsuPnnXeeCoWCfvOb35QdP/TQQ7X55pt7f95pp50UjUYH/D52dHQoHo9XdU0v
vPCCVq9erTPPPLNs7+JRRx2lKVOm6Iknnuj1nNLKUH19vaZOnarRo0frP//zP73j06ZNUywW63Wt
5j6X7rU988wzZVmWnnzyyT6vc20+P1L3z96jjz6qL3zhC8rn82WvcfDBB6u1tVWvvfZan883YztM
ddN47LHH1NjY6P0zefLkXs897rjjVFdXV3ZssJ+LL37xi2pqavL+vMcee2iXXXapeM96LiGeOXPm
sH32AWy8WLoJYMRqaGjQgQceqMWLFyuRSKhYLOqYY44Z9OuU/sVZkjd3qrW1tddf4krtsMMOqqur
88Kc2Z9n7LnnnlqyZIlOPfVULVmyRJMmTfKWrEnSu+++q2XLlqmxsbHXa1uWpU8//bTPc3/wwQc6
4IADeh03S9IGeo9S9/vsud9sqHbddVdv318wGNTEiRO9UFTJXXfdpeuvv15Lly71mlFI0jbbbDPg
ucxewJ5L2frS3/d3oKA4adKkPp8rde/Tknrf98bGxqqC1fvvv6+JEycqHA6XHZ82bVrZ6/d1PZJU
V1c34Pdx1KhR+vjjjwe8HnNOy7Iqfi+22247vfzyy2XHYrFYr2Wjo0ePrriEePTo0RWvtef9i8fj
am5u1j/+8Y8+r3NtPj9S97LNzs5OLVy4ULfccsugX8N8f3v+Qmjffff19k1eddVVve6X1L30vJLB
fC4qfda32WabXt1FY7FYr1A5nJ99ABsvgh6AEe3EE0/UnDlz9PHHH+uwww6rumpRynGcisfdAbo+
WpalPffc02tYsmTJkrLxDTNmzNBdd93ljVqYPXt22fOLxaI+97nP6cc//nHFc1UKZ0M11Pc4GCec
cILuvPNOBYNBHX/88X0+7u6779app56qY445RhdeeKEaGxvlOI4uv/xyffjhh8N2PcbavPf1cd8G
Y6jXs9122+n111/XihUr1NzcvF6uaV3fu7X9/BSLRUnSySef3OfexR133LHP52+33XaSuseSmGAu
df8CyvwS5q677qr43J7BXlp3n4uR9jMMYOQg6AEY0WbPnq1vfvOb+utf/6qf//zn6/38M2fO1G9+
8xs99thj+vTTT8sqejNmzNDFF1+sJ598UqlUqmzZpiRNnjxZS5cu1f777z/o85rmIz29++67g38T
/7a2g5VPPPFEXXbZZbIsq89lm5L0i1/8Qttuu22vDowXXXRRVddjlsK9/vrra3W9w2GLLbaQ1D2j
bsKECd7xlStXqrOzs6rnP/PMM0qlUmV/+TfdE83rr60jjzxSDz30kO677z595zvfGfCaXNfV0qVL
e/3MLl26dNiuqdS7775b9tnp7OzUihUr+qx8SYP7/FT6WRo3bpyi0aiKxWLF6vhAZs2apbPPPls/
+9nPdOyxxw76+T1V+7kwKn3W33nnnX7vGQCUYo8egBEtGo3qJz/5iX74wx/qyCOPXO/nN/v05s+f
r2g06nWFlKTddttNjuPommuu6bU/T+rep/P+++9X/K1/KpVSKpXq87yHHHKInnnmGb3xxhvesVWr
VlUcXF6taDQq13XV1tY2pOdvs802uuGGG3T11VeX3YeeKlUYlixZohdffLHX9UjqdT3Nzc2aMWOG
Fi1atE4qgINx4IEHyrZtLVy4sOz4ggULqnr+rFmzlM1mez3/hhtukOM4Ouyww4blOr/0pS9p++23
1+WXX97rPkvd+80uueQSSd0/t2PHjtWtt95atnzwV7/6ld59910dccQRw3JNhuu6uu2228qW+f73
f/+3XNfVrFmz+nzeYD4/0Wi018+R4ziaPXu2HnzwwYpjCSrN4iy15ZZb6uSTT9avfvUrb5xET6Zq
WI1qPxfGI488Ujbu4vnnn9fLL7/c7z0DgFJU9ACMOD2XHH31q1/dQFcirzX7888/r/3337+soUQ4
HNaOO+6o559/XvX19dphhx3Knvu1r31NDz30kObMmaPf//73mjFjhvL5vN566y099NBDevrppzV9
+vSK5/3e976n+++/XwcccIC+9a1vKRQKadGiRdpqq6302muvDak6t9NOO8m2bV111VVatWqVgsGg
DjroII0ZM6bq1zjnnHMGfMwRRxyhxx57TEcffbQOO+wwLV++XLfddpu23377svl20WhU22yzje6/
/35tvfXWqq+v1/Tp0zVt2jTdfPPN2nfffbXTTjvptNNO05Zbbqn33ntPTz31lF566aVBv/dK+lra
Vnp8/PjxOuuss7RgwQLNnj1bBx98sF599VX97ne/09ixYwf8PsyePVv77LOPLrjgAi1btswbr/DE
E0/o/PPPr7gnbyj8fr8effRRHXzwwdprr730pS99SXvttZd8Pp9ef/11LV68WM3Nzbr88ssVCAR0
9dVX67TTTtM+++yjE044QR999JEWLFigKVOm6Oyzzx6WayqVSqV04IEH6phjjtGbb76pn/zkJ9pv
v/0qjucwBvP52WWXXfTUU0/pxhtv1Pjx4zV58mTtuuuuuuaaa7z5knPmzNG0adPU0tKil156Sc88
80yvuYE9LViwQB988IHOOOMMLV68WIcffriampq0cuVKLVmyRI8//rg++9nPVnUPqv1cGFtvvbVm
zpypuXPnKplM6qabblJzc7O++93vVnU+ACDoARhxqgkxlmVVnI22tssTewoGg9pll130l7/8pWzp
mbHXXnvplVde0YwZM3p9zbZtPf7447ruuut077336pFHHlE0GtXkyZP1ne98p6xbX89r33zzzfX0
00/rnHPO0ZVXXqmGhgadddZZCgQCeu211xQKhap636XHN9tsM916662aP3++vvGNb6hQKOiZZ56p
eO2D0fP83/jGN/Tpp5/q9ttv129/+1ttv/32euCBB3TffffphRdeKHvunXfeqXPOOUfnnnuustms
Lr/8ck2bNk077bSTnn/+eV1yySW69dZblclktMUWW/S7N3Aw12iO9fXYUtdff73i8bgWLVqk3/3u
d9pzzz3129/+VrvvvnvZ96Gv13riiSd0ySWX6MEHH9Rdd92lLbfcUtdff32v0NzX97Han+upU6fq
tdde0/XXX69f/vKX+uUvf6lisaitt95ac+bM0be//W3vsaeeeqpisZiuueYaXXDBBYrFYjr22GN1
9dVX92pQVO196utaLcvSwoULdc899+jSSy9VoVDQSSed1GtofM/XHMzn58Ybb9TcuXN18cUXK5VK
6dRTT9Wuu+6qcePG6cUXX9S8efO8CtnYsWO1ww479JphWEk0GtVTTz2ln/70p7r33nt17bXXqqOj
Q/X19dpxxx1122236aSTThrwHkiD+1xI0te//nXl83ktWLBAn376qfbcc0/dfPPNamho6POeVXMc
wKbDctmtCwAbjbPOOkv33HNPVfvDsO6sXr1ajY2Nmj9/vs4///wNfTkj1h133KHTTjtNr776ap/V
a5Rbvny5pk6dqhtvvHGdVFcBbDrYowcAI1TPOXArV67U4sWLte+++26gK9o0VZrHd8MNN8iyLO23
337r/4IAAKgCSzcBYITafffddeCBB2q77bbTRx99pDvuuEOJRMJrqoH1Y/HixfrZz36mww47TNFo
VH/605/04IMP6ogjjtB//Md/bOjLG/FYOAQAGwZBDwBGqFmzZumRRx7RbbfdJtu2teuuu+q+++7T
7rvvvqEvbZOy44476v7779c111yjjo4OjRs3Tt/97nc1b968DX1pGwX2ig3euthvDGDTwx49AAAA
AKgx7NEDAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAA
gBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACA
GkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAa
Q9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD
0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQ
AwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9AD
AAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMA
AACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAA
AIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAA
gBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACA
GkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAa
Q9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD
0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQ
AwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9AD
AAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMA
AACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAAAIAaQ9ADAAAAgBpD0AMAAACAGkPQAwAA
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
CDjz2DuvvPLKq+XygJ5XXjl15coVfes3fZM+8PGPLzWkPxAI6O1vfaseffRRazqQaNLwIOOEsWI2
C6MLt6GSTkPTyW3DuCWRSCzJsWB7cBqUtCRtTKfTNpcFawTLguwPMwuYpn6/b8wPc2gEXbsr+DCV
bkNXKBRM4kVD5RpbuI6P0onTJZbq1WpVlUrFWIN8Pm/gejgcGmjq9/v2fljFcDisX/qFf6zE4gv6
WTnzk9eu6ec+/GH94x/5EWWzWZsnkqSdnR0Vi0UdHx+bwc1gMDDm6/9n792jJT3rKuFd9/tb9db9
1Ll2n6TT6ZDEtElMMhAgMggzLL+lgoyyArLIAGGBRPgC+Bk1iijeAkh0ZiTCoJEYPgaWwwIZnKWj
mU9umkS6E9Kdvp173eutt+qt++X742T/+qmimzQXBYZnr3VWh+5zqt56L4dnP3v/9uYCutvtCsGp
1WpotVqwLAuLi4twHAfnzp0TokwFg5/z1KlTYollmmi325UET9pW1VCUwWCAYrEoSg1JHQk7Z7JI
YNg7yPlM3j8kbJxFpArE+TQulnmsJIDT6VTuH3UerN/vy8ydx+NBtVpFtVqVY2H9hdrhyOh9y7JQ
q9VgWRYmkwlyuRxM0xTl9OOf/CR+7vbbcfszIUcAEAu/ADulh1Au9xEM9sUGSBWPpGc8HotSTEId
jUbl3lcX8lS3SOxI+OZnZkl41FlI2on5PKpWTP4s51hVlXBeLVTfm887zxU3DeZnzGgZ5ftbliXP
LENc+B6c9WUKqxriQkVQtYGqpJfzlzw+VeXjz5AgzRNHWoNpD+Yzy+c0HA5LGu8TT+xfj2uvPd8P
OY/vhDVTq3caGhoaF4cmehoac/jYww/jZ17xCtz+N38jf/ejz3sePvzRjwopUxd/3W4X7XZ7pnCb
iwwm7RHq7j/JGePPA4GA1DYAkDRP1UpH5YGLrPF4LJ1xJBOpVEpslSya9vl8Ysuk4hYOh2VGLRaL
zSzGGDjj8XiQTCaFrBqGIcEpVP9UokAixPmqXC6HtbU1hEIhbG5uolqtAoDM4ZmmKbNGDJfhAp9q
ElWCRx999MKBHtMpbj91StQgEjIed6VSQa/XkzoHqhUApIg8EAhgeXlZlLSNjQ30ej2k02lZFHNO
kcSJ6YasEKCySkWCqh4JMasrmNaodnRNp/udieVyGYlEQr6H6i9fj9el2WyKIsvUQ84AdjodeV0m
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
z+eVTqe1sLCgN73hDXrwoYfcbb7o0kv1Mz/3cxobG1On03FnxKyF0Ko2tqzchlLYome7QLdhLoVC
Qe12WyMjIxoeHtbs7KwbMmL3zc7OBYNBt9phYWFB1WrV7aKzdkg7S2ZVrUqlotXVVXf+0No+bdKl
ncWqVCrujF0ymXT3P5vN6rd+4zc0/XQgc1W3kyf1sbvv1u/9wR8omUy6ymChUHChzwKHVfYkuaEy
7XZbTzzxhKTt2yBbrZZGR0ddSLXnw8KlVcxsqIyd37OgbZVAG1hj58qsSmeBzjtJ0nu/bQKpBUkL
rB/88If1rre/Xbc++KC7zze8/OX6X4cPq1QqbalY2u+GdH4HnneIilXPtgtyxluFs9fMu7rBWy30
Bjob2NNf7QMAAC8MBD3saDYl06vb7aper7uLe0lu0IZV+uzsXrVa1fr6upLJpPL5vBKJhNbX1/Wf
3/hGfevhh7cEnHcdPar7/vIv9cvvfa9rE7RQMDIy4kLbyMiIms2mu/C31Q22n21pacmtULAzcN5W
zVKppPX1dTUaDVepSqfTKhaLWlpaUrlcdtWn9fV1txh9dHRU4XBYuVxO8XhcMzMzqlQqbpdfNptV
qVRye+ja7ba7j6lUSmNjY4pGo4pEIlpbW9NDDz2kr3z96xeuuj3xhNbW1lwrqj3GXq/nll5Lm6HX
/t4mgKZSKQ0PD+vw4cPbtkFedNFF6na7brDLxsaGG2zjXRJvIalUKrkBNValtVBn00i9IcpbybKK
owUmm3Jp5ze950BzuZz+6hOf0FNPPaXjx49r3759rmXTXhPv0BJveNsuyHl/b/v31Hmrc952Trst
e4wXat8EAAAvbAQ97Fh2Adx/YWuTE1OplLtgt3CwsbHh1i3YBMdsNquRkRENDAxocXFRR44c0b9+
6UsXDjinTqlSqWjXrl0aHByUJDeCv9vtqlwuq1araXV1VWtra1uGaHh39aXTaY2NjbkWz3K5rFQq
5XbqRSIRN7UzlUqp2+2qWCy6qZ5WxdrY2FAymdTU1JQymYza7bby+byWl5fdoJKRkRHt3r1bgUDA
TZ1sNBpaX1/X6OioO/vX6/VULBZ14sRJPfzwkP7iLzZD8rerutnycrs/GxsbboedvTa2xsI7gfK6
a6/VL33lK+p1u+fbIINB/eh11+nKK690y81tqIoNYLGQZ+sYbFCMDbSJRCKuouUdJuINXhZ0rcJr
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" alt="png" /></p>
<p>To illustrate how this fits in with the original graph, you plot the same min weight pairs (blue lines), but over the trail map (faded) instead of the complete graph. Again, note that the blue lines
are the bushwhacking route (as the crow flies edges, not actual trails). You still have a little bit of work to do to find the edges that comprise the shortest route between each pair in Step <strong>3.</strong></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">6</span><span class="p">))</span>
<span class="c"># Plot the original trail map graph</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="n">node_positions</span><span class="p">,</span> <span class="n">node_size</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.1</span><span class="p">,</span> <span class="n">node_color</span><span class="o">=</span><span class="s">'black'</span><span class="p">)</span>
<span class="c"># Plot graph to overlay with just the edges from the min weight matching</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw</span><span class="p">(</span><span class="n">g_odd_complete_min_edges</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="n">node_positions</span><span class="p">,</span> <span class="n">node_size</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">node_color</span><span class="o">=</span><span class="s">'red'</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="s">'blue'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">title</span><span class="p">(</span><span class="s">'Min Weight Matching on Orginal Graph'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></code></pre></figure>
<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA3oAAAKUCAYAAABSako+AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz
AAAPYQAAD2EBqD+naQAAIABJREFUeJzs3Xt8k/Xd//H3laSH0DRNeqCAgKggAorToQ6GMgR0Hqa3
Z8XbzcMY4jyfEIUpcz88baJueBgoThE2ZW5D8TDdHCJTp/M4QeWgwuTUpmmTpklzun5/xOZuaEub
Nj2lr+fjwQO4cl3f65M0hb7zPRmmaZoCAAAAAGQNS3cXAAAAAADILIIeAAAAAGQZgh4AAAAAZBmC
HgAAAABkGYIeAAAAAGQZgh4AAAAAZBmCHgAAAABkGYIeAAAAAGQZgh4AAAAAZBmCHoA+xWKx6Oc/
/3l3l9EugwcP1k9+8pN2X3v66adnuKKeb+7cubJYLPL5fK2e25HXF3s3ceJEHXfccZ16j7lz5yon
J6dT79EVHn30UVksFn300UfdXQqAXo6gB6DX+d3vfieLxSKLxaJ//vOfzZ4zZMgQWSwWnXLKKSnH
DcOQYRgZqeOyyy6T1WpVdXV1ynGv1yuLxSK73a5wOJzy2BdffCGLxaK5c+emfT+LxdLu2tt63Sef
fKL58+frv//9b5vOnzdvniwWi2w2m3bu3Nnk8ZqaGuXn58tisejaa69Nq2ZJCgQCmj9/vt544420
r5XS+3p35PXtTSorK3Xddddp5MiRstvtKi0t1QknnKAXX3yx0+6Zye+7TN1jzZo1OuusszR48GDl
5eXJ5XJp/Pjx+sUvfqGKiopOrLR1feF9CKDzEfQA9Fp2u13Lly9vcnzNmjX6+uuvlZ+f3+SxYDCo
W265JSP3P/rooyVJ69atSzn+z3/+U1arVZFIRO+++27KY+vWrZNhGMlr07F582Y99NBD7S+4Df7z
n/9o/vz52rp1a1rX5eXl6fe//32T4ytXruxQgKqtrdX8+fP1+uuvt+v6dHTF69vdNmzYoLFjx+qh
hx7Scccdp0WLFmnOnDnatWuXTjrppIx9b+zptdde0wsvvNApbbfHzTffrMmTJ+vDDz/UxRdfrIcf
flgLFizQ6NGj9ctf/lLHHHNMd5cIAB1m6+4CAKC9TjzxRD3zzDN64IEHZLH83+dWy5cv17hx41RZ
Wdnkmtzc3Izdf+LEiTJNU2+88YZOOumk5PF169bp0EMPVTAY1BtvvKEJEyYkH1u7dq0sFovGjx+f
9v26YliaaZpphzLDMHTiiSdqxYoVuvrqq1MeW758uU4++WStXLmy3fV0lWwY9rc3kUhEZ5xxhgKB
gNatW6fDDjss+dg111yjc889V3feeafGjRun0047rcV2QqFQsx+i7I3N1nN+3Fi2bJnuvPNOnX/+
+Xr88cdltVpTHl+4cKHuv//+Vttpz+sAAF2JHj0AvZJhGDrvvPPk8Xj0yiuvJI9HIhGtXLlS06dP
bzYk7DlH77bbbpPFYtHmzZt14YUXyu12y+Vy6eKLL1YoFNprDUOGDNGQIUOa9OitW7dO3/3udzVh
woRme/vGjBkjp9OZPFZfX6+f/exnGj58uPLz87Xvvvtqzpw5ikQiKdc2N4fsgw8+0DHHHKN+/fpp
6NChuvPOO7V48WJZLBZt3769Sc2vv/66jjzySNntdg0fPjylR/TRRx/V9OnTJSVCrMVikdVqbXF4
bGPTp0/XO++8o82bNyePbd++XWvWrEm22Vh9fb3mzZunb3/723K5XHI4HPre976ntWvXJs/ZvHmz
Bg0aJMMwknPtLBaLFixYkDxnw4YNOuuss1RWVqZ+/fpp1KhRuvXWW5vcr6qqSj/84Q/lcrnkdrs1
Y8YM1dfXp5yz5+u7ZMkSWSwWvf3227r66qtVVlYmh8OhM888U16vN+XaeDyun/3sZxo0aJAcDoem
Tp2qzz77TEOGDGnTvL/a2lpdc801GjJkiPLz8zVq1Cjdd999KefEYrHkENhnn31WBx98sPLz83XI
IYfo1VdfbfUef/jDH/Tpp5/qlltuSQl5UuL74re//a0KCwt12223JY//7W9/k8Vi0cqVK3XzzTdr
8ODBcjgcqqurk9T299+ec/Qa2v3Tn/6k22+/XYMHD1a/fv00bdo0ffHFFym1NQyxHDp0aPL74/rr
r2/y9Wur2267TeXl5Vq8eHGTkCdJTqdT8+bNSznWMMf1pZde0rhx45Sfn6/HHntMUuL7ZsqUKSov
L5fdbtfBBx+sxYsXN2m3cRvf+ta3kuf+5S9/abbOYDDY6vsOAPam53zEBgBpGjZsmL7zne9oxYoV
Ov744yVJL7zwgnw+n84999w2fSrf0Ht19tlna//999edd96p9957T0uWLFF5ebnuuOOOvV4/ceJE
/elPf1IkElFOTo4ikYjeeecdXXbZZQoEApo9e3by3Orqaq1fv16zZs1KHjNNUyeddJL+9a9/6dJL
L9WBBx6oDz/8UL/61a+0efNmPf30001qbbBt2zZNnjxZeXl5mjt3rvLz87V48WLl5+c32yv32Wef
6dxzz9WPf/xjXXTRRVqyZIl+9KMf6YgjjtCIESM0efJk/fSnP9WDDz6oW2+9VSNGjJAkjRw5stXX
cfLkyRo4cKBWrFiRnH+4YsUKud1uff/7329yfnV1tR5//HGdd955mjlzpnw+n5YsWaLjjjtO7777
rsaMGaMBAwZo0aJF+ulPf6qzzjpLp556qiTpW9/6lqREyJg0aZLy8/M1a9YsDR06VJs2bdLq1as1
f/78lNf4jDPO0PDhw3XXXXfp3Xff1WOPPaYBAwbo9ttvb/H1bfj7ZZddptLSUv385z/Xli1bdN99
98lut+vJJ59MnnvDDTdo4cKFOu200zR16lS9//77Ov7441v9sKChvpNOOknr1q3TjBkzNHbsWL34
4ou69tprtWPHDt11110p5//jH//QM888o8suu0wOh0P33XefzjjjDG3dulVFRUUt3ue5556TYRi6
4IILmn3c5XLpBz/4gZYvX66tW7dq6NChycduu+022e123XjjjQoGg8rJyUnr/ddSL/EvfvEL5eTk
aPbs2aqqqtLdd9+tH/7whymB/+mnn1Z9fb0uv/xyFRcX66233tL999+vHTt26Kmnnmr19W1sw4YN
2rJliy677LK0euMMw9Ann3yi//3f/9Wll16qmTNnatSoUZKkhx56SIcddphOPfVU2Ww2/eUvf9HM
mTMlSTNmzEhpY8OGDTr//PM1a9YsXXTRRXr00Ud15pln6pVXXtH3vve95LmmabbpfQcAe2UCQC/z
+OOPmxaLxfz3v/9tLlq0yCwqKjJDoZBpmqZ59tlnm1OmTDFN0zSHDRtm/uAHP0i51jAMc/78+cm/
33bbbaZhGOaMGTNSzjv99NPNsrKyVmt58MEHTYvFYq5bt840TdN88803TYvFYm7bts3csGGDaRiG
uWHDBtM0TXP16tWmYRjmihUrktcvXbrUtNls5ttvv53S7qJFi0yLxWK+8847yWODBw9OqXPWrFmm
1Wo1P/nkk+Qxj8djut1u02KxmF9//XXKtRaLxXzrrbeSx3bu3Gnm5uaac+bMSR77/e9/n/J8WjN3
7lzTYrGYNTU15jXXXGOOHj06+djhhx9uXnrppWY0GjUNwzCvueaa5GOxWMyMRCIpbVVXV5tlZWXm
pZdemlKjYRjm//t//6/JvSdMmGC63W5z+/bte63PMAxz1qxZKcdPOeUUc+DAgSnH9nx9lyxZYhqG
YZ544okp51155ZVmTk6OGQgETNM0ze3bt5s2m80855xzUs6bN29es++tPa1cudI0DMO85557Uo6f
fvrpps1mM7/66ivTNM3k62i325PHTNM033vvPdMwDPORRx7Z630OOeSQVt/T99xzj2mxWMyXXnrJ
NE3TfPXVV03DMMyRI0ea4XA45dx03n8TJ040p02blvx7Q7tjx441o9Fo8vi9995rWiwW87PPPkse
a/jebuwXv/iFabVaU772c+fONXNycvb6/J599lnTMAzzwQcfbPJYZWVlyq9YLJZ8rOH757XXXmty
XXP1TZ061TzooINSjjW08fzzzyePVVdXm+Xl5eZRRx2VPNbW9x0AtIahmwB6tbPPPlt1dXV6/vnn
VVtbq+eff17nn39+Wm0YhpH8BL7B0UcfLY/Ho9ra2r1e23ienpQYmrnPPvto8ODBOuigg1RcXJwc
vvnGG2/IMAxNnDgxef3KlSt1yCGH6IADDpDH40n+mjx5skzT1GuvvdbivV9++WUdffTRGj16dPJY
cXGxzjvvvGbPHzt2rI466qjk38vLyzVixAht2bJlr8+xraZPn65PP/1UH374oT799FO9//77zQ7b
lJRcqVNK9F54vV5FIhGNGzdO7733Xqv32rVrl958803NmDFDAwcO3Ou5LX19d+3a1WqPW0vXxmKx
5II1r776quLxeEpPrSRdccUVrT4PSXrxxReVm5urn/70pynHr732WsViMb300kspx7///e+n9LYd
dthhKigoaPXr6Pf7VVhYuNdzGh7fczuKiy66qMkcxnTff8255JJLUoZPHn300TJNM+W55OXlJf9c
V1cnj8ejCRMmyDRNffDBB22+l5R4XoZhyOFwpBz3eDwqKytT//79VVZWprKyMv3nP/9JOWfEiBEp
vW7N1efz+eTxeDRp0iR9/vnnCgaDKecOHTo0ZT5vUVGRLrjgAr3zzjuqqqpKHm/L+w4AWsPQTQC9
WmlpqaZOnarly5crEAgoHo/rzDPPTLudxj84S5Lb7ZaU2Cphzx8KGzv44IPlcrmSYa5hfl6D8ePH
a926dbrkkku0bt06DRkyRIMHD04+vnHjRm3atEllZWVN2jYMQ7t3727x3lu3btWxxx7b5Pjw4cPb
9BylxPPM1LyfcePGJef95eXlafDgwckfTpuzdOlS3Xvvvfrss88UjUaTxw888MBW79UwF3DMmDFt
qm1vX9/WguKQIUNavFaSvvrqK0lNX/eysrJWg1XD9YMHD5bdbk853jA0sKH9luqREsMuW/s6FhYW
NrsFRmN+vz95bmPDhg1rcm6677/mtPbaSonnP2/ePK1evTrluGEYqqmpafO9pMTzMk2zyQc4RUVF
yXmOL7zwghYuXNjk2v3226/ZNteuXatbb71V//rXv5JzFxvX1/jr2txr0/B+//LLL1VcXJw83pbX
BgD2hqAHoNebPn26ZsyYoR07duiEE05o0w/Xe2puUQap9VUfDcPQ+PHjkwuWrFu3LmWJ+gkTJmjp
0qXJrRb2XM0wHo/rW9/6ln75y182e6/mwll7tfc5puO8887TY489pry8PJ177rktnvf444/rkksu
0Zlnnqk5c+aorKxMVqtVt99+u77++uuM1dOgI8+9K163dLS3nlGjRumTTz7Rzp07NWDAgGbP+fDD
DyUppZdOUpMQmimtPZdYLKapU6fK7/fr5ptv1siRI9WvXz9t3bpVF198seLxeFr3O+iggySpSW+d
zWZLhtY9F4Np0NxrsHHjRk2bNk0HH3ywFi5cqCFDhig3N1erVq3Sr3/967Tra6ynve8A9D4EPQC9
3mmnnaaZM2fq7bff1h/+8Icuv//EiRP10ksvadWqVdq9e3dKj96ECRM0d+5cvfDCCwoGgynDNiXp
gAMO0GeffabJkyenfd+GxUf2tHHjxvSfxDc6ulHz9OnT9fOf/1yGYbQ4bFOS/vjHP2rkyJEpi81I
if3N2lLPAQccIKnpD+zdYd9995Ukbdq0Sfvss0/yeEVFRbKHrLXr165dq2AwmBImNmzYkNJ+R518
8sl65pln9MQTT+jGG29s8nhNTY2ee+45HXLIIW36gKEz3n97+uCDD7R582atWLFC55xzTvL4nsNZ
22r06NHaf//99ac//Un33ntvyrDL9li1apUikYhWr16t8vLy5PGXX3652fObe70+++wzSc33mgJA
RzBHD0CvV1BQoIcffli33XabfvCDH3T5/Rvm6d11110qKChIrgopSUceeaSsVqvuvvvuJvPzpMQc
w6+++kpLly5t0m4wGGwyx6ex448/XmvXrtUnn3ySPFZZWdnsxuVtVVBQINM0VV1d3a7rDzzwQC1c
uFB33nlnyuuwp+Z6K9atW6d33nmnST2SmtRTXl6uCRMmaMmSJZ3SA5iOqVOnymKx6MEHH0w5/sAD
D7Tp+hNPPFHhcLjJ9QsXLpTVatUJJ5yQkTrPOeccjRw5UgsWLND777+f8lg8HtfMmTPl9/ubbE/R
Utju6PuvLR8qNLxPGveMmaap+++/v90fStx6663auXOnZsyY0eyw4nR64Zqrz+v16oknnmj2/K1b
t+q5555L/r26ulrLli3TEUcckTJsEwAygR49AL3SnsOXWloyvisceeSRys3N1ZtvvqnJkyenbN5u
t9t16KGH6s0335Tb7dbBBx+ccu2FF16oZ555RjNmzNCrr76qCRMmKBqNasOGDXrmmWf02muvaezY
sc3e96abbtKKFSt07LHH6oorrlB+fr6WLFmi/fbbTx988EG7fhA+7LDDZLFYdMcdd6iyslJ5eXma
Nm1aWj+EXnXVVa2ec/LJJ2vVqlU6/fTTdcIJJ2jz5s165JFHNHr06JT90QoKCnTggQdqxYoV2n//
/eV2uzV27FiNGjVKv/71rzVp0iQddthh+slPfqJhw4Zpy5Yt+utf/6p333037efenJaGyTU+PnDg
QF1++eV64IEHdNppp+m4447T+++/r1deeUUlJSWtfh1OO+00HXPMMZo9e7Y2bdqU3F5h9erVuuGG
G5qdk9ceubm5WrlypaZNm6bvfve7uvjii3X44YfL6/Xqqaee0ocffqibbrqpyfDill6Djr7/2jIE
ccyYMdpvv/109dVX66uvvpLD4dDKlSubLBaTjgsuuECffPKJ7rnnHr311ls655xztP/++6u2tlYf
f/yxVqxYoaKiIrlcrlbbOv744zV79mydeOKJmjFjhnw+nxYvXqyBAwc2O7925MiRuvDCCzVr1iyV
lpZqyZIl8ng8WrFiRcp5bXnfAUBrCHoAeqW2hBjDMJrdz6ujwxP3lJeXp29/+9t66623UoZtNvju
d7+r9957TxMmTGjymMVi0fPPP69f/epXevLJJ/Xss8+qoKBABxxwgK677rrkEMXmah86dKhee+01
XXXVVVqwYIFKS0t1+eWXKzc3Vx988EHKPmF7e96Njw8aNEgPPfSQ7rrrLv34xz9WLBbT2rVrm609
HXve/8c//rF2796txYsX6+WXX9bo0aP1+9//XsuWLdO//vWvlGsfe+wxXXXVVbrmmmsUDod1++23
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
9bv72e62LHSiFojuXOD72RrxNRERERH5gUs36bQx2VK/YrEPsdiFEARAkgBRBAShdlv7ciAIzon/
LUAUnTEeU/v/7n2vvnoIR45MvrwwkwF+/nPgqquAj38c+OEP4Xtzlh1dXdiyaRO2jVy22tmJHV1d
/h6ojhrxNRERERH5gUGPThsjl/qNrK65S/1++tOVWLHC37lwPT0r8O//Pv4xzzrrLDiOA0EQsGYN
8A//AHzoQ8BllwF33OHrqSCdTmPX7t3o7e1FX19f3RrRBKkRXxMRERGRH7h0k04rc7HUb7xjXrx2
LX6yYwdkWUYikUD0xHrNz3ymNlR91y7gne8M5JSIiIiIqMEx6NFpZWhoCFs2bapr182JjplMJlEs
FlGtVqEoChKJBGQ5gne/G3juOeDpp4FzzgnktIiIiIiogTHo0WlpLpb6TXRMXddRKBSg6zpCoRAM
I4m1a0NIpYDvf78Hr79ev5l/RERERLTwMegRzSOapqFQKMAwDDz1VAU3vf+jMO2Hve8HXX0kIiIi
osbAoEc0D1UqFfzBf/tveP6xx/Etx8Y61Bq63MHRAUREREQ0BQx6RPPQZDP/3Pl7RERERERjEef6
BIjoVJPN/Ovr66vr+RARERHRwsKgRzQPjZz5N5I7f6+jo6Ou50NERERECwuDHtE8tHLlSmxcvx53
SBK2A3gNtWWbd0oSNq5fz2WbRERERDQh7tEjmqfmYuYfERERETUGBj2ieW4uZv4RERER0cLGoEdE
RERERNRguEePiIiIiIiowTDoERERERERNRgGPSIiIiIiogbDoEdERERERNRgGPSIiIiIiIgaDIMe
ERERERFRg2HQIyIiIiIiajAMekRERERERA2GQY+IiIiIiKjBMOgRERERERE1GAY9IiIiIiKiBsOg
R0RERERE1GAY9IiIiIiIiBoMgx4REREREVGDYdAjIiIiIiJqMAx6REREREREDYZBj4iIiIiIqMEw
6BERERERETUYBj0iIiIiIqIGw6BHRERERETUYBj0iIiIiIiIGgyDHhERERERUYNh0CMiIiIiImow
DHpEREREREQNhkGPiIiIiIiowTDoERERERERNRgGPSIiIiIiogbDoEdERERERNRgGPSIiIiIiIga
DIMeERERERFRg2HQIyIiIiIiajAMekRERERERA2GQY+IiIiIiKjBMOgRERERERE1GAY9IiIiIiKi
BsOgR0RERERE1GAY9IiIiIiIiBoMgx4REREREVGDYdAjIiIiIiJqMAx6REREREREDYZBj4iIiIiI
qMEw6BERERERETUYBj0iIiIiIqIGw6BHRERERETUYBj0iIiIiIiIGgyDHhERERERUYNh0CMiIiIi
ImowDHpEREREREQNhkGPiIiIiIiowTDoEREREdH/334dyAAAAAAM8re+x1cWATOiBwAAMCN6AAAA
M6IHAAAwI3oAAAAzogcAADAjegAAADOiBwAAMCN6AAAAM6IHAAAwI3oAAAAzogcAADAjegAAADOi
BwAAMCN6AAAAM6IHAAAwI3oAAAAzogcAADAjegAAADOiBwAAMCN6AAAAM6IHAAAwI3oAAAAzogcA
ADAjegAAADOiBwAAMCN6AAAAM6IHAAAwI3oAAAAzogcAADAjegAAADOiBwAAMCN6AAAAM6IHAAAw
I3oAAAAzogcAADAjegAAADOiBwAAMCN6AAAAM6IHAAAwI3oAAAAzogcAADAjegAAADOiBwAAMCN6
AAAAM6IHAAAwI3oAAAAzogcAADAjegAAADOiBwAAMCN6AAAAM6IHAAAwI3oAAAAzogcAADAjegAA
ADOiBwAAMCN6AAAAM6IHAAAwI3oAAAAzogcAADAjegAAADOiBwAAMCN6AAAAM6IHAAAwI3oAAAAz
ogcAADAjegAAADOiBwAAMCN6AAAAM6IHAAAwI3oAAAAzogcAADAjegAAADOiBwAAMCN6AAAAM6IH
AAAwI3oAAAAzogcAADAjegAAADMBw8rCWX3X/JsAAAAASUVORK5CYII=" alt="png" /></p>
<h3 id="step-25-augment-the-original-graph">Step 2.5: Augment the Original Graph</h3>
<p>Now you augment the original graph with the edges from the matching calculated in <strong>2.4</strong>. A simple function to do this is defined below which also notes that these new edges came from the augmented
graph. You’ll need to know this in ** 3.** when you actually create the Eulerian circuit through the graph.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">add_augmenting_path_to_graph</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">min_weight_pairs</span><span class="p">):</span>
<span class="s">"""
Add the min weight matching edges to the original graph
Parameters:
graph: NetworkX graph (original graph from trailmap)
min_weight_pairs: list[tuples] of node pairs from min weight matching
Returns:
augmented NetworkX graph
"""</span>
<span class="c"># We need to make the augmented graph a MultiGraph so we can add parallel edges</span>
<span class="n">graph_aug</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">MultiGraph</span><span class="p">(</span><span class="n">graph</span><span class="o">.</span><span class="n">copy</span><span class="p">())</span>
<span class="k">for</span> <span class="n">pair</span> <span class="ow">in</span> <span class="n">min_weight_pairs</span><span class="p">:</span>
<span class="n">graph_aug</span><span class="o">.</span><span class="n">add_edge</span><span class="p">(</span><span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
<span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
<span class="o">**</span><span class="p">{</span><span class="s">'distance'</span><span class="p">:</span> <span class="n">nx</span><span class="o">.</span><span class="n">dijkstra_path_length</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span> <span class="n">pair</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">pair</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="s">'trail'</span><span class="p">:</span> <span class="s">'augmented'</span><span class="p">}</span>
<span class="c"># attr_dict={'distance': nx.dijkstra_path_length(graph, pair[0], pair[1]),</span>
<span class="c"># 'trail': 'augmented'} # deprecated after 1.11</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">graph_aug</span></code></pre></figure>
<p>Let’s confirm that your augmented graph adds the expected number (18) of edges:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Create augmented graph: add the min weight matching edges to g</span>
<span class="n">g_aug</span> <span class="o">=</span> <span class="n">add_augmenting_path_to_graph</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">odd_matching</span><span class="p">)</span>
<span class="c"># Counts</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of edges in original graph: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">edges</span><span class="p">())))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of edges in augmented graph: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g_aug</span><span class="o">.</span><span class="n">edges</span><span class="p">())))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Number of edges in original graph: 123
Number of edges in augmented graph: 141
</code></pre></div></div>
<p>Let’s also confirm that every node now has even degree:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># pd.value_counts(g_aug.degree()) # deprecated after NX 1.11</span>
<span class="n">pd</span><span class="o">.</span><span class="n">value_counts</span><span class="p">([</span><span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_aug</span><span class="o">.</span><span class="n">degree</span><span class="p">()])</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>4 54
2 18
6 5
dtype: int64
</code></pre></div></div>
<h2 id="cpp-step-3-compute-eulerian-circuit">CPP Step 3: Compute Eulerian Circuit</h2>
<p>Now that you have a graph with even degree the hard optimization work is over. As Euler famously postulated in 1736 with the <a href="https://en.wikipedia.org/wiki/Seven_Bridges_of_K%C3%B6nigsberg">Seven Bridges of Königsberg</a> problem, there exists a path which visits
each edge exactly once if all nodes have even degree. Carl Hierholzer fomally proved this result later in the 1870s.</p>
<p>There are many Eulerian circuits with the same distance that can be constructed. You can get 90% of the way there with the NetworkX <code class="highlighter-rouge">eulerian_circuit</code> function. However there are some limitations.</p>
<p><strong>Limitations you will fix:</strong></p>
<ol>
<li>
<p>The augmented graph could (and likely will) contain edges that didn’t exist on the original graph. To get the circuit (without bushwhacking), you must break down these augmented edges into the
shortest path through the edges that actually exist.</p>
</li>
<li>
<p><code class="highlighter-rouge">eulerian_circuit</code> only returns the order in which we hit each node. It does not return the attributes of the edges needed to complete the circuit. This is necessary because you need to keep
track of which edges have been walked already when multiple edges exist between two nodes.</p>
</li>
</ol>
<p><strong>Limitations you won’t fix:</strong></p>
<!-- hack to start bulleted list at 3. when separated by text block -->
<ol start="3">
<li>To save your legs some work, you could relax the assumption of the Eulerian circuit that one start and finish at the same node. An [Eulerian path] (the general case of the Eulerian circuit), can
also be found if there are exactly two nodes of odd degree. This would save you a little bit of double backing...presuming you could get a ride back from the other end of the park. However, at the
time of this writing, NetworkX does not provide a Euler Path algorithm. The [eulerian_circuit code] isn't too bad and could be adopted for this case, but you'll keep it simple here. </li>
</ol>
<h3 id="naive-circuit">Naive Circuit</h3>
<p>Nonetheless, let’s start with the simple yet incomplete solution:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">naive_euler_circuit</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">nx</span><span class="o">.</span><span class="n">eulerian_circuit</span><span class="p">(</span><span class="n">g_aug</span><span class="p">,</span> <span class="n">source</span><span class="o">=</span><span class="s">'b_end_east'</span><span class="p">))</span></code></pre></figure>
<p>As expected, the length of the naive Eulerian circuit is equal to the number of the edges in the augmented graph.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="s">'Length of eulerian circuit: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">naive_euler_circuit</span><span class="p">)))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Length of eulerian circuit: 141
</code></pre></div></div>
<p>The output is just a list of tuples which represent node pairs. Note that the first node of each pair is the same as the second node from the preceding pair.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Preview naive Euler circuit</span>
<span class="n">naive_euler_circuit</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">10</span><span class="p">]</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[('b_end_east', 'b_y'),
('b_y', 'y_gy2'),
('y_gy2', 'rs_end_south'),
('rs_end_south', 'y_rs'),
('y_rs', 'y_gy2'),
('y_gy2', 'o_gy2'),
('o_gy2', 'o_rs'),
('o_rs', 'o_w_2'),
('o_w_2', 'w_rc'),
('w_rc', 'y_rc')]
</code></pre></div></div>
<h3 id="correct-circuit">Correct Circuit</h3>
<p>Now let’s define a function that utilizes the original graph to tell you which trails to use to get from node A to node B. Although verbose in code, this logic is actually quite simple. You simply
transform the naive circuit which included edges that did not exist in the original graph to a Eulerian circuit using only edges that exist in the original graph.</p>
<p>You loop through each edge in the naive Eulerian circuit (<code class="highlighter-rouge">naive_euler_circuit</code>). Wherever you encounter an edge that does not exist in the original graph, you replace it with the sequence of edges
comprising the shortest path between its nodes using the original graph.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">create_eulerian_circuit</span><span class="p">(</span><span class="n">graph_augmented</span><span class="p">,</span> <span class="n">graph_original</span><span class="p">,</span> <span class="n">starting_node</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
<span class="s">"""Create the eulerian path using only edges from the original graph."""</span>
<span class="n">euler_circuit</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">naive_circuit</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">nx</span><span class="o">.</span><span class="n">eulerian_circuit</span><span class="p">(</span><span class="n">graph_augmented</span><span class="p">,</span> <span class="n">source</span><span class="o">=</span><span class="n">starting_node</span><span class="p">))</span>
<span class="k">for</span> <span class="n">edge</span> <span class="ow">in</span> <span class="n">naive_circuit</span><span class="p">:</span>
<span class="n">edge_data</span> <span class="o">=</span> <span class="n">graph_augmented</span><span class="o">.</span><span class="n">get_edge_data</span><span class="p">(</span><span class="n">edge</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">edge</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="k">if</span> <span class="n">edge_data</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s">'trail'</span><span class="p">]</span> <span class="o">!=</span> <span class="s">'augmented'</span><span class="p">:</span>
<span class="c"># If `edge` exists in original graph, grab the edge attributes and add to eulerian circuit.</span>
<span class="n">edge_att</span> <span class="o">=</span> <span class="n">graph_original</span><span class="p">[</span><span class="n">edge</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">edge</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span>
<span class="n">euler_circuit</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">edge</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">edge</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">edge_att</span><span class="p">))</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">aug_path</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">shortest_path</span><span class="p">(</span><span class="n">graph_original</span><span class="p">,</span> <span class="n">edge</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">edge</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">weight</span><span class="o">=</span><span class="s">'distance'</span><span class="p">)</span>
<span class="n">aug_path_pairs</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">aug_path</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">aug_path</span><span class="p">[</span><span class="mi">1</span><span class="p">:]))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Filling in edges for augmented edge: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">edge</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Augmenting path: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s">' => '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">aug_path</span><span class="p">)))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Augmenting path pairs: {}</span><span class="se">\n</span><span class="s">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">aug_path_pairs</span><span class="p">))</span>
<span class="c"># If `edge` does not exist in original graph, find the shortest path between its nodes and </span>
<span class="c"># add the edge attributes for each link in the shortest path.</span>
<span class="k">for</span> <span class="n">edge_aug</span> <span class="ow">in</span> <span class="n">aug_path_pairs</span><span class="p">:</span>
<span class="n">edge_aug_att</span> <span class="o">=</span> <span class="n">graph_original</span><span class="p">[</span><span class="n">edge_aug</span><span class="p">[</span><span class="mi">0</span><span class="p">]][</span><span class="n">edge_aug</span><span class="p">[</span><span class="mi">1</span><span class="p">]]</span>
<span class="n">euler_circuit</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">edge_aug</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">edge_aug</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">edge_aug_att</span><span class="p">))</span>
<span class="k">return</span> <span class="n">euler_circuit</span></code></pre></figure>
<p>You hack <strong>limitation 3</strong> a bit by starting the Eulerian circuit at the far east end of the park on the Blue trail (node “b_end_east”). When actually running this thing, you could simply skip the last
direction which doubles back on it.</p>
<p>Verbose print statements are added to convey what happens when you replace nonexistent edges from the augmented graph with the shortest path using edges that actually exist.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Create the Eulerian circuit</span>
<span class="n">euler_circuit</span> <span class="o">=</span> <span class="n">create_eulerian_circuit</span><span class="p">(</span><span class="n">g_aug</span><span class="p">,</span> <span class="n">g</span><span class="p">,</span> <span class="s">'b_end_east'</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Filling in edges for augmented edge: ('y_gy2', 'rs_end_south')
Augmenting path: y_gy2 => y_rs => rs_end_south
Augmenting path pairs: [('y_gy2', 'y_rs'), ('y_rs', 'rs_end_south')]
Filling in edges for augmented edge: ('rc_end_south', 'y_gy1')
Augmenting path: rc_end_south => y_rc => y_gy1
Augmenting path pairs: [('rc_end_south', 'y_rc'), ('y_rc', 'y_gy1')]
Filling in edges for augmented edge: ('v_end_east', 'rs_end_north')
Augmenting path: v_end_east => v_rs => rs_end_north
Augmenting path pairs: [('v_end_east', 'v_rs'), ('v_rs', 'rs_end_north')]
Filling in edges for augmented edge: ('b_bw', 'rh_end_tt_1')
Augmenting path: b_bw => b_tt_1 => rh_end_tt_1
Augmenting path pairs: [('b_bw', 'b_tt_1'), ('b_tt_1', 'rh_end_tt_1')]
Filling in edges for augmented edge: ('rd_end_south', 'v_end_west')
Augmenting path: rd_end_south => b_v => v_end_west
Augmenting path pairs: [('rd_end_south', 'b_v'), ('b_v', 'v_end_west')]
Filling in edges for augmented edge: ('rh_end_north', 'rd_end_north')
Augmenting path: rh_end_north => v_rh => v_rd => rd_end_north
Augmenting path pairs: [('rh_end_north', 'v_rh'), ('v_rh', 'v_rd'), ('v_rd', 'rd_end_north')]
Filling in edges for augmented edge: ('b_tt_3', 'rt_end_north')
Augmenting path: b_tt_3 => b_tt_2 => tt_rt => v_rt => rt_end_north
Augmenting path pairs: [('b_tt_3', 'b_tt_2'), ('b_tt_2', 'tt_rt'), ('tt_rt', 'v_rt'), ('v_rt', 'rt_end_north')]
Filling in edges for augmented edge: ('g_gy1', 'rc_end_north')
Augmenting path: g_gy1 => g_rc => b_rc => v_rc => rc_end_north
Augmenting path pairs: [('g_gy1', 'g_rc'), ('g_rc', 'b_rc'), ('b_rc', 'v_rc'), ('v_rc', 'rc_end_north')]
Filling in edges for augmented edge: ('g_gy2', 'b_end_east')
Augmenting path: g_gy2 => w_gy2 => b_gy2 => b_o => b_y => b_end_east
Augmenting path pairs: [('g_gy2', 'w_gy2'), ('w_gy2', 'b_gy2'), ('b_gy2', 'b_o'), ('b_o', 'b_y'), ('b_y', 'b_end_east')]
</code></pre></div></div>
<p>You see that the length of the Eulerian circuit is longer than the naive circuit, which makes sense.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="s">'Length of Eulerian circuit: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">euler_circuit</span><span class="p">)))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Length of Eulerian circuit: 158
</code></pre></div></div>
<h2 id="cpp-solution">CPP Solution</h2>
<h3 id="text">Text</h3>
<p>Here’s a printout of the solution in text:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Preview first 20 directions of CPP solution</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">edge</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">euler_circuit</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">20</span><span class="p">]):</span>
<span class="k">print</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">edge</span><span class="p">)</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0 ('b_end_east', 'b_y', {'estimate': 0, 'distance': 1.32, 'color': 'blue', 'trail': 'b'})
1 ('b_y', 'y_gy2', {'estimate': 0, 'distance': 0.28, 'color': 'yellow', 'trail': 'y'})
2 ('y_gy2', 'y_rs', {'estimate': 0, 'distance': 0.16, 'color': 'yellow', 'trail': 'y'})
3 ('y_rs', 'rs_end_south', {'estimate': 0, 'distance': 0.39, 'color': 'red', 'trail': 'rs'})
4 ('rs_end_south', 'y_rs', {'estimate': 0, 'distance': 0.39, 'color': 'red', 'trail': 'rs'})
5 ('y_rs', 'y_gy2', {'estimate': 0, 'distance': 0.16, 'color': 'yellow', 'trail': 'y'})
6 ('y_gy2', 'o_gy2', {'estimate': 0, 'distance': 0.12, 'color': 'yellowgreen', 'trail': 'gy2'})
7 ('o_gy2', 'o_rs', {'estimate': 0, 'distance': 0.33, 'color': 'orange', 'trail': 'o'})
8 ('o_rs', 'o_w_2', {'estimate': 0, 'distance': 0.15, 'color': 'orange', 'trail': 'o'})
9 ('o_w_2', 'w_rc', {'estimate': 0, 'distance': 0.23, 'color': 'gray', 'trail': 'w'})
10 ('w_rc', 'y_rc', {'estimate': 0, 'distance': 0.14, 'color': 'red', 'trail': 'rc'})
11 ('y_rc', 'rc_end_south', {'estimate': 0, 'distance': 0.36, 'color': 'red', 'trail': 'rc'})
12 ('rc_end_south', 'y_rc', {'estimate': 0, 'distance': 0.36, 'color': 'red', 'trail': 'rc'})
13 ('y_rc', 'y_gy1', {'estimate': 0, 'distance': 0.18, 'color': 'yellow', 'trail': 'y'})
14 ('y_gy1', 'y_rc', {'estimate': 0, 'distance': 0.18, 'color': 'yellow', 'trail': 'y'})
15 ('y_rc', 'y_rs', {'estimate': 0, 'distance': 0.53, 'color': 'yellow', 'trail': 'y'})
16 ('y_rs', 'o_rs', {'estimate': 0, 'distance': 0.12, 'color': 'red', 'trail': 'rs'})
17 ('o_rs', 'w_rs', {'estimate': 0, 'distance': 0.21, 'color': 'red', 'trail': 'rs'})
18 ('w_rs', 'b_w', {'estimate': 1, 'distance': 0.06, 'color': 'gray', 'trail': 'w'})
19 ('b_w', 'b_gy2', {'estimate': 0, 'distance': 0.41, 'color': 'blue', 'trail': 'b'})
</code></pre></div></div>
<p>You can tell pretty quickly that the algorithm is not very loyal to any particular trail, jumping from one to the next pretty quickly. An extension of this approach could get fancy and build in some
notion of trail loyalty into the objective function to make actually running this route more manageable.</p>
<h3 id="stats">Stats</h3>
<p>Let’s peak into your solution to see how reasonable it looks.<br />
<em>(Not important to dwell on this verbose code, just the printed output)</em></p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Computing some stats</span>
<span class="n">total_mileage_of_circuit</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">([</span><span class="n">edge</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'distance'</span><span class="p">]</span> <span class="k">for</span> <span class="n">edge</span> <span class="ow">in</span> <span class="n">euler_circuit</span><span class="p">])</span>
<span class="n">total_mileage_on_orig_trail_map</span> <span class="o">=</span> <span class="nb">sum</span><span class="p">(</span><span class="n">nx</span><span class="o">.</span><span class="n">get_edge_attributes</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="s">'distance'</span><span class="p">)</span><span class="o">.</span><span class="n">values</span><span class="p">())</span>
<span class="n">_vcn</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">value_counts</span><span class="p">(</span><span class="n">pd</span><span class="o">.</span><span class="n">value_counts</span><span class="p">([(</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">euler_circuit</span><span class="p">]),</span> <span class="n">sort</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">node_visits</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">({</span><span class="s">'n_visits'</span><span class="p">:</span> <span class="n">_vcn</span><span class="o">.</span><span class="n">index</span><span class="p">,</span> <span class="s">'n_nodes'</span><span class="p">:</span> <span class="n">_vcn</span><span class="o">.</span><span class="n">values</span><span class="p">})</span>
<span class="n">_vce</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">value_counts</span><span class="p">(</span><span class="n">pd</span><span class="o">.</span><span class="n">value_counts</span><span class="p">([</span><span class="nb">sorted</span><span class="p">(</span><span class="n">e</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">e</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">nx</span><span class="o">.</span><span class="n">MultiDiGraph</span><span class="p">(</span><span class="n">euler_circuit</span><span class="p">)</span><span class="o">.</span><span class="n">edges</span><span class="p">()]))</span>
<span class="n">edge_visits</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">({</span><span class="s">'n_visits'</span><span class="p">:</span> <span class="n">_vce</span><span class="o">.</span><span class="n">index</span><span class="p">,</span> <span class="s">'n_edges'</span><span class="p">:</span> <span class="n">_vce</span><span class="o">.</span><span class="n">values</span><span class="p">})</span>
<span class="c"># Printing stats</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Mileage of circuit: {0:.2f}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">total_mileage_of_circuit</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Mileage on original trail map: {0:.2f}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">total_mileage_on_orig_trail_map</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Mileage retracing edges: {0:.2f}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">total_mileage_of_circuit</span><span class="o">-</span><span class="n">total_mileage_on_orig_trail_map</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Percent of mileage retraced: {0:.2f}</span><span class="si">%</span><span class="se">\n</span><span class="s">'</span><span class="o">.</span><span class="n">format</span><span class="p">((</span><span class="mi">1</span><span class="o">-</span><span class="n">total_mileage_of_circuit</span><span class="o">/</span><span class="n">total_mileage_on_orig_trail_map</span><span class="p">)</span><span class="o">*-</span><span class="mi">100</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of edges in circuit: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">euler_circuit</span><span class="p">)))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of edges in original graph: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">edges</span><span class="p">())))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of nodes in original graph: {}</span><span class="se">\n</span><span class="s">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">nodes</span><span class="p">())))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of edges traversed more than once: {}</span><span class="se">\n</span><span class="s">'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">euler_circuit</span><span class="p">)</span><span class="o">-</span><span class="nb">len</span><span class="p">(</span><span class="n">g</span><span class="o">.</span><span class="n">edges</span><span class="p">())))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Number of times visiting each node:'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">node_visits</span><span class="o">.</span><span class="n">to_string</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="bp">False</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'</span><span class="se">\n</span><span class="s">Number of times visiting each edge:'</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">edge_visits</span><span class="o">.</span><span class="n">to_string</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="bp">False</span><span class="p">))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Mileage of circuit: 33.59
Mileage on original trail map: 25.76
Mileage retracing edges: 7.83
Percent of mileage retraced: 30.40%
Number of edges in circuit: 158
Number of edges in original graph: 123
Number of nodes in original graph: 77
Number of edges traversed more than once: 35
Number of times visiting each node:
n_nodes n_visits
18 1
38 2
20 3
1 4
Number of times visiting each edge:
n_edges n_visits
88 1
35 2
</code></pre></div></div>
<h2 id="visualize-cpp-solution">Visualize CPP Solution</h2>
<p>While NetworkX also provides functionality to visualize graphs, they are <a href="https://networkx.github.io/documentation/networkx-1.10/reference/drawing.html">notably humble</a> in this department:</p>
<blockquote>
<p>NetworkX provides basic functionality for visualizing graphs, but its main goal is to enable graph analysis rather than perform graph visualization. In the future, graph visualization functionality
may be removed from NetworkX or only available as an add-on package.</p>
</blockquote>
<blockquote>
<p>Proper graph visualization is hard, and we highly recommend that people visualize their graphs with tools dedicated to that task. Notable examples of dedicated and fully-featured graph visualization
tools are Cytoscape, Gephi, Graphviz and, for LaTeX typesetting, PGF/TikZ.</p>
</blockquote>
<p>That said, the built-in NetworkX drawing functionality with matplotlib is powerful enough for eyeballing and visually exploring basic graphs, so you stick with NetworkX <code class="highlighter-rouge">draw</code> for this tutorial.</p>
<p>I used <a href="http://www.graphviz.org/">graphviz</a> and the <a href="https://en.wikipedia.org/wiki/DOT_(graph_description_language)">dot</a> graph description language to visualize the solution in my Python package <a href="https://github.com/brooksandrew/postman_problems">postman_problems</a>. Although it took some legwork to convert the NetworkX graph structure to
a dot graph, it does unlock enhanced quality and control over visualizations.</p>
<h3 id="create-cpp-graph">Create CPP Graph</h3>
<p>Your first step is to convert the list of edges to walk in the Euler circuit into an edge list with plot-friendly attributes.</p>
<p><code class="highlighter-rouge">create_cpp_edgelist</code> Creates an edge list with some additional attributes that you’ll use for plotting:</p>
<ul>
<li><strong>sequence:</strong> records a sequence of when we walk each edge.</li>
<li><strong>visits:</strong> is simply the number of times we walk a particular edge.</li>
</ul>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">def</span> <span class="nf">create_cpp_edgelist</span><span class="p">(</span><span class="n">euler_circuit</span><span class="p">):</span>
<span class="s">"""
Create the edgelist without parallel edge for the visualization
Combine duplicate edges and keep track of their sequence and # of walks
Parameters:
euler_circuit: list[tuple] from create_eulerian_circuit
"""</span>
<span class="n">cpp_edgelist</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">e</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">euler_circuit</span><span class="p">):</span>
<span class="n">edge</span> <span class="o">=</span> <span class="nb">frozenset</span><span class="p">([</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]])</span>
<span class="k">if</span> <span class="n">edge</span> <span class="ow">in</span> <span class="n">cpp_edgelist</span><span class="p">:</span>
<span class="n">cpp_edgelist</span><span class="p">[</span><span class="n">edge</span><span class="p">][</span><span class="mi">2</span><span class="p">][</span><span class="s">'sequence'</span><span class="p">]</span> <span class="o">+=</span> <span class="s">', '</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="n">cpp_edgelist</span><span class="p">[</span><span class="n">edge</span><span class="p">][</span><span class="mi">2</span><span class="p">][</span><span class="s">'visits'</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">cpp_edgelist</span><span class="p">[</span><span class="n">edge</span><span class="p">]</span> <span class="o">=</span> <span class="n">e</span>
<span class="n">cpp_edgelist</span><span class="p">[</span><span class="n">edge</span><span class="p">][</span><span class="mi">2</span><span class="p">][</span><span class="s">'sequence'</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="n">cpp_edgelist</span><span class="p">[</span><span class="n">edge</span><span class="p">][</span><span class="mi">2</span><span class="p">][</span><span class="s">'visits'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">cpp_edgelist</span><span class="o">.</span><span class="n">values</span><span class="p">())</span></code></pre></figure>
<p>Let’s create the CPP edge list:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">cpp_edgelist</span> <span class="o">=</span> <span class="n">create_cpp_edgelist</span><span class="p">(</span><span class="n">euler_circuit</span><span class="p">)</span></code></pre></figure>
<p>As expected, your edge list has the same number of edges as the original graph.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="k">print</span><span class="p">(</span><span class="s">'Number of edges in CPP edge list: {}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">cpp_edgelist</span><span class="p">)))</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Number of edges in CPP edge list: 123
</code></pre></div></div>
<p>The CPP edge list looks similar to <code class="highlighter-rouge">euler_circuit</code>, just with a few additional attributes.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Preview CPP plot-friendly edge list</span>
<span class="n">cpp_edgelist</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">3</span><span class="p">]</span></code></pre></figure>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[('o_w_2',
'w_rs',
{'color': 'gray',
'distance': 0.26,
'estimate': 0,
'sequence': '79',
'trail': 'w',
'visits': 1}),
('y_rc',
'rc_end_south',
{'color': 'red',
'distance': 0.36,
'estimate': 0,
'sequence': '11, 12',
'trail': 'rc',
'visits': 2}),
('o_w_1',
'o_rt',
{'color': 'orange',
'distance': 0.13,
'estimate': 0,
'sequence': '51, 52',
'trail': 'o',
'visits': 2})]
</code></pre></div></div>
<p>Now let’s make the graph:</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># Create CPP solution graph</span>
<span class="n">g_cpp</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">Graph</span><span class="p">(</span><span class="n">cpp_edgelist</span><span class="p">)</span></code></pre></figure>
<h3 id="visualization-1-retracing-steps">Visualization 1: Retracing Steps</h3>
<p>Here you illustrate which edges are walked once (<span style="color:gray">gray</span>) and more than once (<span style="color:blue">blue</span>). This is the "correct" version of the visualization
created in <b>2.4</b> which showed the naive (as the crow flies) connections between the odd node pairs (<span style="color:red">red</span>). That is corrected here by tracing the shortest path
through edges that actually exist for each pair of odd degree nodes.</p>
<p>If the optimization is any good, these blue lines should represent the least distance possible. Specifically, the minimum distance needed to generate a <a href="https://en.wikipedia.org/wiki/Matching_(graph_theory)">matching</a> of the odd degree nodes.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span>
<span class="n">visit_colors</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">:</span><span class="s">'lightgray'</span><span class="p">,</span> <span class="mi">2</span><span class="p">:</span><span class="s">'blue'</span><span class="p">}</span>
<span class="n">edge_colors</span> <span class="o">=</span> <span class="p">[</span><span class="n">visit_colors</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'visits'</span><span class="p">]]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_cpp</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)]</span>
<span class="n">node_colors</span> <span class="o">=</span> <span class="p">[</span><span class="s">'red'</span> <span class="k">if</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">nodes_odd_degree</span> <span class="k">else</span> <span class="s">'lightgray'</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">g_cpp</span><span class="o">.</span><span class="n">nodes</span><span class="p">()]</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx</span><span class="p">(</span><span class="n">g_cpp</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="n">node_positions</span><span class="p">,</span> <span class="n">node_size</span><span class="o">=</span><span class="mi">20</span><span class="p">,</span> <span class="n">node_color</span><span class="o">=</span><span class="n">node_colors</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="n">edge_colors</span><span class="p">,</span> <span class="n">with_labels</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s">'off'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></code></pre></figure>
<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABJcAAAM1CAYAAADNehCDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz
AAAPYQAAD2EBqD+naQAAIABJREFUeJzs3XmUHVW5uP9n9xAgQkACqKAIegWBDQn8CBAElUkmGWRW
QQQRBHNFBAQUjDIPGhnF70VFQERCiEQRZBL0XoJMl2lH0Yh4GYIMCTKTpLv37486aIhJ6K4+6arT
/XzWymrX6e46bzBI87jrrZBzRpIkSZIkSSqjreoBJEmSJEmS1LqMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0oxLkiRJkiRJKs24JEmSJEmSpNKMS5IkSZIkSSrNuCRJkiRJkqTS
jEuSJEmSJEkqzbgkSZIkSZKk0jqqHkCSJElDWwhhOPC5Nvg40NMDVwOX5pznVDyaJEnqhZBzrnoG
SZIkDVEhhKU74Lc9sP42wFzIt0JbG9zaDdsZmCRJqj9vi5MkSVKV/jPA6Lsh/BrCLdB2C9ADWwCf
qXo4SZL01oxLkiRJqkwn7LU7tG0wz2tbFL962mCPquaSJEm9Z1ySJElSldqHLeDFYRCA9oEeRpIk
9Z1xSZIkSZWZC9dMhO6/zPPafcBNQA/8oqKxJElSH7jQW5IkSZUJIYzsgDs7YbW9oH0OcHXxxLgH
u2CznPMrVc8oSZIWzbgkSZKkSoUQRgKHd/KOQzIrLN/FtPHAeTnnl6qeTZIkvTXjkiRJkmohBMYB
3waWyhl/SJUkqUW4c0mSJEl1MQtYAliq6kEkSVLvGZckSZJUF7MaH5evdApJktQnxiVJkiTVhXFJ
kqQWZFySJElSXcxsfDQuSZLUQoxLkiRJqgtPLkmS1IKMS5IkSaqLF4AMjKx6EEmS1HvGJUmSJNVC
zvQAz+PJJUmSWopxSZIkSXUyC+OSJEktxbgkSZKkOjEuSZLUYoxLkiRJqhPjkiRJLca4JEmSpDox
LkmS1GKMS5IkSaoT45IkSS3GuCRJkqQ6MS5JktRijEuSJEmqE+OSJEktxrgkSZKkOpkFDA+BJase
RJIk9Y5xSZIkSXUys/Hx7ZVOIUmSes24JEmSpDqZ1fg4stIpJElSrxmXJEmSVCdvxCX3LkmS1CKM
S5IkSaoT45IkSS3GuCRJkqQ6+Ufjo3FJkqQWYVySJElSbeRMF/ACxiVJklqGcUmSJEl1MwvjkiRJ
LcO4JEmSpLoxLkmS1EKMS5IkSaob45IkSS3EuCRJkqS6MS5JktRCjEuSJEmqG+OSJEktxLgkSZKk
upmJcUmSpJZhXJIkSVLdzAJGVj2EJEnqHeOSJEmS6mYWsHQIDKt6EEmS9NaMS5IkSaqbWY2Pb690
CkmS1CvGJUmSJNXNG3HJvUuSJLUA45IkSZLqxrgkSVILMS5JkiSpboxLkiS1EOOSJEmS6ub5xkfj
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
AFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAA
UCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQ
Ji4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAm
LgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYu
AQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4B
AAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEA
AABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAA
AFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAA
UCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQ
Ji4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAm
LgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYu
AQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4B
AAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQ9h91QhXQd5kqsAAAAABJRU5E
rkJggg==" alt="png" /></p>
<h3 id="visualization-2-cpp-solution-sequence">Visualization 2: CPP Solution Sequence</h3>
<p>Here you plot the original graph (trail map) annotated with the sequence numbers in which we walk the trails per the CPP solution. Multiple numbers indicate trails we must double back on.</p>
<p>You start on the blue trail in the bottom right (0th and the 157th direction).</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">plt</span><span class="o">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span>
<span class="n">edge_colors</span> <span class="o">=</span> <span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'color'</span><span class="p">]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_cpp</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)]</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx</span><span class="p">(</span><span class="n">g_cpp</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="n">node_positions</span><span class="p">,</span> <span class="n">node_size</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span> <span class="n">node_color</span><span class="o">=</span><span class="s">'black'</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="n">edge_colors</span><span class="p">,</span> <span class="n">with_labels</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
<span class="n">bbox</span> <span class="o">=</span> <span class="p">{</span><span class="s">'ec'</span><span class="p">:[</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span> <span class="s">'fc'</span><span class="p">:[</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">]}</span> <span class="c"># hack to label edges over line (rather than breaking up line)</span>
<span class="n">edge_labels</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">get_edge_attributes</span><span class="p">(</span><span class="n">g_cpp</span><span class="p">,</span> <span class="s">'sequence'</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edge_labels</span><span class="p">(</span><span class="n">g_cpp</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="n">node_positions</span><span class="p">,</span> <span class="n">edge_labels</span><span class="o">=</span><span class="n">edge_labels</span><span class="p">,</span> <span class="n">bbox</span><span class="o">=</span><span class="n">bbox</span><span class="p">,</span> <span class="n">font_size</span><span class="o">=</span><span class="mi">6</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s">'off'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">show</span><span class="p">()</span></code></pre></figure>
<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABJcAAAM1CAYAAADNehCDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz
AAAPYQAAD2EBqD+naQAAIABJREFUeJzs3Xm4lXW58PHvvdkMItPD4MCgaDlrzqKVOVtmWpolTpUV
pnWy4e1Up1oprtOxem04nTcr6zRoFmVappYpOOYQmphTOA8oKgKPArKZ9v69fzyLRAWFhw3PWvD9
XBfX1s3mWTfp1bX5+vvdK1JKSJIkSZIkSWW0VT2AJEmSJEmSWpdxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpRmXJEmSJEmSVJpxSZIkSZIkSaUZlyRJkiRJklSa
cUmSJEmSJEmlGZckSZIkSZJUmnFJkiRJkiRJpbVXPYAkSZIEEBEjgSHArJTSk1XPI0mSVk6klKqe
QZIkSeu5iDgYGAsMAOYAE1JKE6udSpIkrQyvxUmSJKlSjRNLY4EApjY+jm18XpIkNTnjkiRJkqo2
BBiwLwzYH7YDnqI4wTSk0qkkSdJKMS5JkiSparOAOTMha4dewAiKq3Gzqh1LkiStDOOSJEmSKtVY
3j2hE5Y8DSOBRLFzyaXekiS1ABd6S5IkqSlcFHFMgr2Phe8aliRJah2eXJIkSVJTeB888X54PhU7
lyRJUoswLkmSJKlZdADtjR+SJKlFGJckSZLULDoaHzeodApJkrRKjEuSJElqFsYlSZJakHFJkiRJ
zcK4JElSCzIuSZIkqVkYlyRJakHGJUmSJDWLBUAC+lY9iCRJWnnGJUmSJDWHlBJFYPLkkiRJLcS4
JEmSpGbSgXFJkqSWYlySJElSMzEuSZLUYoxLkiRJaibGJUmSWoxxSZIkSc3EuCRJUosxLkmSJKmZ
GJckSWoxxiVJkiQ1E+OSJEktxrgkSZKkZmJckiSpxRiXJEmS1Ew6gJ5EtFc9iCRJWjnGJUmSJDWT
+Y2Pnl6SJKlFGJckSZLUTDoaH41LkiS1COOSJEmSmolxSZKkFmNckiRJUjMxLkmS1GKMS5IkSWom
CxofjUuSJLUI45IkSZKaR0pdFIHJuCRJUoswLkmSJKnZdGBckiSpZRiXJEmS1GyMS5IktRDjkiRJ
kpqNcUmSpBZiXJIkSVLTiIgjnoUlwAYR0R4R0fh8PSJ6VzyeJElaDuOSJEmSKrc0IgFfeAwSxcml
k4H2xucPBAZXMJokSXodxiVJkiQ1g6VxadZ10I8iLn0eeH9EDKUITgMqmk2SJL2G9tf/EkmSJGmt
uft3sMsDsDlwFTAc+ARwCfBMpZNJkqTlipRS1TNIkiRJ/3JkxOntcMzNcMKzMAfYOaV0Q9VzSZKk
5fPkkiRJkppGRGR3wbU7FfuVclKaB9wQEXsD81NKd1U8oiRJegV3LkmSJKlyyyz0PuVIeB/AMbB9
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
SZIkSZIqM1ySJEmSJElSZYZLkiRJkiRJqsxwSZIkSZIkSZUZLkmSJEmSJKkywyVJkiRJkiRVZrgk
SZIkSZKkygyXJEmSJEmSVJnhkiRJkiRJkiozXJIkSZIkSVJlhkuSJEmSJEmqzHBJkiRJkiRJlRku
SZIkSZIkqTLDJUmSJEmSJFVmuCRJkiRJkqTKDJckSZIkSZJUmeGSJEmSJEmSKjNckiRJkiRJUmWG
S5IkSZIkSarMcEmSJEmSJEmVGS5JkiRJkiSpMsMlSZIkSZIkVWa4JEmSJEmSpMoMlyRJkiRJklSZ
4ZIkSZIkSZIqM1ySJEmSJElSZYZLkiRJkiRJqsxwSZIkSZIkSZUZLkmSJEmSJKkywyVJkiRJkiRV
ZrgkSZIkSZKkygyXJEmSJEmSVJnhkiRJkiRJkiozXJIkSZIkSVJlhkuSJEmSJEmqzHBJkiRJkiRJ
lRkuSZIkSZIkqTLDJUmSJEmSJFVmuCRJkiRJkqTKDJckSZIkSZJUmeGSJEmSJEmSKjNckiRJkiRJ
UmWGS5IkSZIkSarMcEmSJEmSJEmVGS5JkiRJkiSpMsMlSZIkSZIkVWa4JEmSJEmSpMoMlyRJkiRJ
klSZ4ZIkSZIkSZIqM1ySJEmSJElSZYZLkiRJkiRJqsxwSZIkSZIkSZUZLkmSJEmSJKkywyVJkiRJ
kiRVZrgkSZIkSZKkygyXJEmSJEmSVJnhkiRJkiRJkiozXJIkSZIkSVJlhkuSJEmSJEmqzHBJkiRJ
kiRJlRkuSZIkSZIkqTLDJUmSJEmSJFVmuCRJkiRJkqTKDJckSZIkSZJUmeGSJEmSJEmSKjNckiRJ
kiRJUmWGS5IkSZIkSarMcEmSJEmSJEmVGS5JkiRJkiSpMsMlSZIkSZIkVWa4JEmSJEmSpMoMlyRJ
kiRJklSZ4ZIkSZIkSZIqM1ySJEmSJElSZYZLkiRJkiRJqsxwSZIkSZIkSZUZLkmSJEmSJKkywyVJ
kiRJkiRVZrgkSZIkSZKkygyXJEmSJEmSVJnhkiRJkiRJkiozXJIkSZIkSVJlhkuSJEmSJEmqzHBJ
kiRJkiRJlRkuSZIkSZIkqTLDJUmSJEmSJFVmuCRJkiRJkqTKDJckSZIkSZJUmeGSJEmSJEmSKjNc
kiRJkiRJUmWGS5IkSZIkSarMcEmSJEmSJEmVGS5JkiRJkiSpMsMlSZIkSZIkVWa4JEmSJEmSpMoM
lyRJkiRJklSZ4ZIkSZIkSZIqM1ySJEmSJElSZYZLkiRJkiRJqsxwSZIkSZIkSZUZLkmSJEmSJKky
wyVJkiRJkiRVZrgkSZIkSZKkygyXJEmSJEmSVJnhkiRJkiRJkiozXJIkSZIkSVJlhkuSJEmSJEmq
zHBJkiRJkiRJlRkuSZIkSZIkqTLDJUmSJEmSJFVmuCRJkiRJkqTKDJckSZIkSZJUmeGSJEmSJEmS
KjNckiRJkiRJUmWGS5IkSZIkSarMcEmSJEmSJEmVGS5JkiRJkiSpMsMlSZIkSZIkVWa4JEmSJEmS
pMr+P2Cw2B6F/CV4AAAAAElFTkSuQmCC" alt="png" /></p>
<h3 id="visualization-3-movie">Visualization 3: Movie</h3>
<p>The movie below that traces the Euler circuit from beginning to end is embedded below. Edges are colored black the first time they are walked and <span style="color:red">red</span> the second time.</p>
<p>Note that this gif doesn’t do give full visual justice to edges which overlap another or are too small to visualize properly. A more robust visualization library such as graphviz could address this
by plotting splines instead of straight lines between nodes.</p>
<p>The code that creates it is presented below as a reference.</p>
<p><img src="https://gist.githubusercontent.com/brooksandrew/2a70bbc88899791241cfb88be1372f44/raw/87d1a0ce438d6f4d9a23ce89df2984cbe30ba993/sleeping_giant_cpp_route_animation.gif" alt="Alt Text" /></p>
<p>First a PNG image is produced for each direction (edge walked) from the CPP solution.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">visit_colors</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">:</span><span class="s">'black'</span><span class="p">,</span> <span class="mi">2</span><span class="p">:</span><span class="s">'red'</span><span class="p">}</span>
<span class="n">edge_cnter</span> <span class="o">=</span> <span class="p">{}</span>
<span class="n">g_i_edge_colors</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">e</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">euler_circuit</span><span class="p">,</span> <span class="n">start</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
<span class="n">edge</span> <span class="o">=</span> <span class="nb">frozenset</span><span class="p">([</span><span class="n">e</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">e</span><span class="p">[</span><span class="mi">1</span><span class="p">]])</span>
<span class="k">if</span> <span class="n">edge</span> <span class="ow">in</span> <span class="n">edge_cnter</span><span class="p">:</span>
<span class="n">edge_cnter</span><span class="p">[</span><span class="n">edge</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">edge_cnter</span><span class="p">[</span><span class="n">edge</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
<span class="c"># Full graph (faded in background)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx</span><span class="p">(</span><span class="n">g_cpp</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="n">node_positions</span><span class="p">,</span> <span class="n">node_size</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="n">node_color</span><span class="o">=</span><span class="s">'gray'</span><span class="p">,</span> <span class="n">with_labels</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.07</span><span class="p">)</span>
<span class="c"># Edges walked as of iteration i</span>
<span class="n">euler_circuit_i</span> <span class="o">=</span> <span class="n">copy</span><span class="o">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">euler_circuit</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="n">i</span><span class="p">])</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">euler_circuit_i</span><span class="p">)):</span>
<span class="n">edge_i</span> <span class="o">=</span> <span class="nb">frozenset</span><span class="p">([</span><span class="n">euler_circuit_i</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="n">euler_circuit_i</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">1</span><span class="p">]])</span>
<span class="n">euler_circuit_i</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">2</span><span class="p">][</span><span class="s">'visits_i'</span><span class="p">]</span> <span class="o">=</span> <span class="n">edge_cnter</span><span class="p">[</span><span class="n">edge_i</span><span class="p">]</span>
<span class="n">g_i</span> <span class="o">=</span> <span class="n">nx</span><span class="o">.</span><span class="n">Graph</span><span class="p">(</span><span class="n">euler_circuit_i</span><span class="p">)</span>
<span class="n">g_i_edge_colors</span> <span class="o">=</span> <span class="p">[</span><span class="n">visit_colors</span><span class="p">[</span><span class="n">e</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s">'visits_i'</span><span class="p">]]</span> <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">g_i</span><span class="o">.</span><span class="n">edges</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="bp">True</span><span class="p">)]</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_nodes</span><span class="p">(</span><span class="n">g_i</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="n">node_positions</span><span class="p">,</span> <span class="n">node_size</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.6</span><span class="p">,</span> <span class="n">node_color</span><span class="o">=</span><span class="s">'lightgray'</span><span class="p">,</span> <span class="n">with_labels</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">linewidths</span><span class="o">=</span><span class="mf">0.1</span><span class="p">)</span>
<span class="n">nx</span><span class="o">.</span><span class="n">draw_networkx_edges</span><span class="p">(</span><span class="n">g_i</span><span class="p">,</span> <span class="n">pos</span><span class="o">=</span><span class="n">node_positions</span><span class="p">,</span> <span class="n">edge_color</span><span class="o">=</span><span class="n">g_i_edge_colors</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.8</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">axis</span><span class="p">(</span><span class="s">'off'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">savefig</span><span class="p">(</span><span class="s">'fig/png/img{}.png'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">i</span><span class="p">),</span> <span class="n">dpi</span><span class="o">=</span><span class="mi">120</span><span class="p">,</span> <span class="n">bbox_inches</span><span class="o">=</span><span class="s">'tight'</span><span class="p">)</span>
<span class="n">plt</span><span class="o">.</span><span class="n">close</span><span class="p">()</span></code></pre></figure>
<p>Then the the PNG images are stitched together to make the nice little gif above.</p>
<p>First the PNGs are sorted in the order from 0 to 157. Then they are stitched together using <code class="highlighter-rouge">imageio</code> at 3 frames per second to create the gif.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="kn">import</span> <span class="nn">glob</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">imageio</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="k">def</span> <span class="nf">make_circuit_video</span><span class="p">(</span><span class="n">image_path</span><span class="p">,</span> <span class="n">movie_filename</span><span class="p">,</span> <span class="n">fps</span><span class="o">=</span><span class="mi">5</span><span class="p">):</span>
<span class="c"># sorting filenames in order</span>
<span class="n">filenames</span> <span class="o">=</span> <span class="n">glob</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="n">image_path</span> <span class="o">+</span> <span class="s">'img*.png'</span><span class="p">)</span>
<span class="n">filenames_sort_indices</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">argsort</span><span class="p">([</span><span class="nb">int</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">'.'</span><span class="p">)[</span><span class="mi">0</span><span class="p">][</span><span class="mi">3</span><span class="p">:])</span> <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">filenames</span><span class="p">])</span>
<span class="n">filenames</span> <span class="o">=</span> <span class="p">[</span><span class="n">filenames</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">filenames_sort_indices</span><span class="p">]</span>
<span class="c"># make movie</span>
<span class="k">with</span> <span class="n">imageio</span><span class="o">.</span><span class="n">get_writer</span><span class="p">(</span><span class="n">movie_filename</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s">'I'</span><span class="p">,</span> <span class="n">fps</span><span class="o">=</span><span class="n">fps</span><span class="p">)</span> <span class="k">as</span> <span class="n">writer</span><span class="p">:</span>
<span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">filenames</span><span class="p">:</span>
<span class="n">image</span> <span class="o">=</span> <span class="n">imageio</span><span class="o">.</span><span class="n">imread</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
<span class="n">writer</span><span class="o">.</span><span class="n">append_data</span><span class="p">(</span><span class="n">image</span><span class="p">)</span>
<span class="n">make_circuit_video</span><span class="p">(</span><span class="s">'fig/png/'</span><span class="p">,</span> <span class="s">'fig/gif/cpp_route_animation.gif'</span><span class="p">,</span> <span class="n">fps</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span></code></pre></figure>
<h2 id="next-steps">Next Steps</h2>
<p>Congrats, you have finished this tutorial solving the Chinese Postman Problem in Python. You have covered a lot of ground in this tutorial (33.6 miles of trails to be exact). For a deeper dive into
network fundamentals, you might be interested in Datacamp’s <a href="https://www.datacamp.com/courses/network-analysis-in-python-part-1">Network Analysis in Python</a> course which provides a more thorough treatment of the core concepts.</p>
<p>Don’t hesitate to check out the <a href="http://networkx.readthedocs.io/en/stable/overview.html">NetworkX documentation</a> for more on how to create, manipulate and traverse these complex networks. The docs are comprehensive with a good number of <a href="http://networkx.readthedocs.io/en/stable/examples/index.html">examples</a> and a
series of <a href="http://networkx.readthedocs.io/en/stable/tutorial/index.html">tutorials</a>.</p>
<p>If you’re interested in solving the CPP on your own graph, I’ve packaged the functionality within this tutorial into the <a href="https://github.com/brooksandrew/postman_problems">postman_problems</a> Python package on Github. You can also piece together the
code blocks from this tutorial with a different edge and node list, but the postman_problems package will probably get you there more quickly and cleanly.</p>
<p>One day I plan to implement the extensions of the CPP (Rural and Windy Postman Problem) here as well. I also have grand ambitions of writing about these extensions and experiences testing the routes
out on the trails on my blog <a href="http://brooksandrew.github.io/simpleblog/">here</a>. Another application I plan to explore and write about is incorporating lat/long coordinates to develop (or use) a mechanism to send turn-by-turn directions to my
Garmin watch.</p>
<p>And of course one last next step: getting outside and trail running the route!</p>
<h2 id="references">References</h2>
<p><a href="https://cms.math.ca/openaccess/cjm/v17/cjm1965v17.0449-0467.pdf">1</a>: Edmonds, Jack (1965). “Paths, trees, and flowers”. Canad. J. Math. 17: 449–467. <br />
<a href="https://pdfs.semanticscholar.org/6fc3/371dc5d40b638a6b4acb548c8420fa67aac1.pdf">2</a>: Galil, Z. (1986). “Efficient algorithms for finding maximum matching in graphs”. ACM Computing Surveys. Vol. 18, No. 1: 23-38.</p>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/intro-to-graph-optimization-solving-cpp/">Intro to graph optimization: solving the Chinese Postman Problem</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on October 07, 2017.</p>http://brooksandrew.github.io/simpleblog/articles/convolutional-neural-network-training-with-dl4j2016-04-14T00:00:00+00:002016-04-14T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<ul id="markdown-toc">
<li><a href="#motivation" id="markdown-toc-motivation">Motivation</a> <ul>
<li><a href="#why" id="markdown-toc-why">Why…</a></li>
<li><a href="#what-i-did-instead" id="markdown-toc-what-i-did-instead">What I did instead…</a></li>
<li><a href="#the-kaggle-problem" id="markdown-toc-the-kaggle-problem">The Kaggle problem</a></li>
<li><a href="#initial-approach" id="markdown-toc-initial-approach">Initial approach</a></li>
<li><a href="#pivot" id="markdown-toc-pivot">Pivot</a></li>
</ul>
</li>
<li><a href="#approach" id="markdown-toc-approach">Approach</a> <ul>
<li><a href="#image-processing" id="markdown-toc-image-processing">Image processing</a> <ul>
<li><a href="#1-square-images" id="markdown-toc-1-square-images">1. Square images</a></li>
<li><a href="#2-re-size-images" id="markdown-toc-2-re-size-images">2. Re-size images</a></li>
<li><a href="#3-grayscale" id="markdown-toc-3-grayscale">3. Grayscale</a></li>
</ul>
</li>
<li><a href="#pipeline---images" id="markdown-toc-pipeline---images">Pipeline - images</a> <ul>
<li><a href="#image-processing-1" id="markdown-toc-image-processing-1">Image processing</a></li>
<li><a href="#io" id="markdown-toc-io">I/O</a></li>
<li><a href="#wrangling" id="markdown-toc-wrangling">Wrangling</a></li>
<li><a href="#data-structure" id="markdown-toc-data-structure">Data structure</a></li>
<li><a href="#make-nd4j-dataset" id="markdown-toc-make-nd4j-dataset">Make ND4J dataset</a></li>
<li><a href="#run" id="markdown-toc-run">Run</a></li>
</ul>
</li>
<li><a href="#pipeline---dl4j" id="markdown-toc-pipeline---dl4j">Pipeline - DL4J</a> <ul>
<li><a href="#batch-mode" id="markdown-toc-batch-mode">Batch-mode</a></li>
<li><a href="#train-convolutional-network" id="markdown-toc-train-convolutional-network">Train convolutional network</a></li>
<li><a href="#saveload-networks" id="markdown-toc-saveload-networks">Save/load networks</a></li>
<li><a href="#scoring" id="markdown-toc-scoring">Scoring</a></li>
<li><a href="#submit-to-kaggle" id="markdown-toc-submit-to-kaggle">Submit to Kaggle</a></li>
<li><a href="#run-1" id="markdown-toc-run-1">Run</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#thoughts" id="markdown-toc-thoughts">Thoughts</a></li>
</ul>
<h1 id="motivation">Motivation</h1>
<p><strong>TL;DR version:</strong> This post walks through an image classification problem hosted on Kaggle for Yelp. I use Scala, DeepLearning4J and convolutional neural networks. For a self-guided tour, check out the project on Github <a href="https://github.com/brooksandrew/kaggle_yelp">here</a>.</p>
<h3 id="why">Why…</h3>
<p>This project was motivated by a personal desire of mine to:</p>
<ol>
<li>explore deep learning on a computer vision problem.</li>
<li>implement an end-to-end data science project in Scala.</li>
<li>build an image processing pipeline using real images.</li>
</ol>
<p>Rather than using the <a href="https://en.wikipedia.org/wiki/MNIST_database">MNIST</a> or <a href="https://www.cs.toronto.edu/~kriz/cifar.html">CIFAR</a> datasets with pre-processed and standardized images, I wanted to go with a more “wild” dataset of “real-world” images.</p>
<p>I opted for the <a href="https://www.kaggle.com/c/yelp-restaurant-photo-classification">Kaggle Yelp Restaurant Photo Classification</a> problem. The ~200,000 training images are raw uploads from Yelp users from mobile devices or cameras with a variety of sizes, dimensions, colors and quality.</p>
<h3 id="what-i-did-instead">What I did instead…</h3>
<p>I was initially going to document this project end-to-end from image processing to training the convolutional neural networks. However, upon more research and practice actually tuning convolutional networks, I’ve reconsidered my process. While the Kaggle Yelp Photo Classification problem is a novel problem, it turns out not to be a great match with the deep learning techniques I wanted to explore. Thus, this article will focus mainly on the image processing pipeline using Scala. While I introduce DL4J here, I plan to discuss my experience with it in more detail in a forthcoming post.</p>
<h3 id="the-kaggle-problem">The Kaggle problem</h3>
<p>The Kaggle problem is this. Yelp wants to auto-classify restaurants on the 9 characteristics below:</p>
<ol>
<li>good_for_lunch</li>
<li>good_for_dinner</li>
<li>takes_reservations</li>
<li>outdoor_seating</li>
<li>restaurant_is_expensive</li>
<li>has_alcohol</li>
<li>has_table_service</li>
<li>ambience_is_classy</li>
<li>good_for_kids</li>
</ol>
<p>Each restaurant has some number of images (from a couple to several hundred). However there are no restaurant features beyond these images. Thus it is a <a href="https://en.wikipedia.org/wiki/Multiple-instance_learning">multiple-instance learning</a> problem where each business in the training data is represented by its bag of images.</p>
<p>This is also a <a href="https://en.wikipedia.org/wiki/Multi-label_classification">multiple-label classification</a> problem where each business can have one or more of the 9 characteristics listed above.</p>
<h3 id="initial-approach">Initial approach</h3>
<p>To deal with the <strong>multiple-instance issue</strong>, I simply applied the labels of the restaurant to all of the images associated with it and treated each image as a separate record.</p>
<p>To deal with with the <strong>multiple-label problem</strong>, I simply handled each class as a separate binary classification problem. While there are breeds of neural networks capable of classifying multiple labels, such as <a href="backpropagation for multilabel learning">BP-MLL</a>, these are not currently available in DL4J.</p>
<h3 id="pivot">Pivot</h3>
<p>While I didn’t expect my initial approach would land me at the top of the Kaggle leaderboard, I did expect it would allow me to build a reasonable model while exploring new and untested (to me) tools and techniques: DeepLearning4j, Scala and convolutional nets. That assumption turned out to bigger than I expected.</p>
<p>The noise-to-signal ratio turned out to be too high with the Yelp data to train a meaningful convolutional network given my self-imposed constraints. From what I’ve deduced from the <a href="https://www.kaggle.com/c/yelp-restaurant-photo-classification/forums">Kaggle forum</a>, most teams are using pre-trained neural networks to extract features from each image. From there it can be tackled as a classical (non-image) classification problem with crafty feature creation and aggregation from the image to restaurant level.</p>
<p>While this is far more computationally efficient and could yield better predictions, it cuts out exactly the part I wanted to explore. I eventually compromised with myself and decided to re-factor the image pipeline I developed on this project for a similar better posed problem using <a href="https://www.cs.toronto.edu/~kriz/cifar.html">CIFAR</a> or dataset created myself from using <a href="http://www.image-net.org/">image-net</a>.</p>
<h1 id="approach">Approach</h1>
<h2 id="image-processing">Image processing</h2>
<p>Images in the training set come in various shapes and sizes. See some examples below. My first pass at processing consists of:</p>
<ol>
<li>squaring images</li>
<li>resizing image to same same dimensions</li>
<li>grayscaling image</li>
</ol>
<h5 id="some-images-are-tall">Some images are tall…</h5>
<figure class="half">
<img src="/simpleblog/assets/dl4j-article/54.jpg" alt="tall image - mussels" />
<img src="/simpleblog/assets/dl4j-article/21.jpg" alt="tall image - cup" />
</figure>
<h5 id="some-images-are-wide">Some images are wide…</h5>
<figure class="half">
<img src="/simpleblog/assets/dl4j-article/244159.jpg" alt="wide image - Tashan" />
<img src="/simpleblog/assets/dl4j-article/290501.jpg" alt="wide image - Wine price" />
</figure>
<h5 id="some-images-are-outside">Some images are outside…</h5>
<figure class="half">
<img src="/simpleblog/assets/dl4j-article/76.jpg" alt="outside image - moab diner" />
<img src="/simpleblog/assets/dl4j-article/159.jpg" alt="outside image - japanese restaurant" />
</figure>
<h5 id="some-images-are-inside">Some images are inside…</h5>
<figure class="half">
<img src="/simpleblog/assets/dl4j-article/28.jpg" alt="inside restaurant - chairs" />
<img src="/simpleblog/assets/dl4j-article/26.jpg" alt="inside restaurant - counter" />
</figure>
<h5 id="some-images-are-food">Some images are food…</h5>
<figure class="half">
<img src="/simpleblog/assets/dl4j-article/20.jpg" alt="food - pizza" />
<img src="/simpleblog/assets/dl4j-article/403044.jpg" alt="food - rice" />
</figure>
<h5 id="and-some-are-random-other-things">And some are random other things…</h5>
<figure class="half">
<img src="/simpleblog/assets/dl4j-article/299.jpg" alt="food - nfl cake" />
<img src="/simpleblog/assets/dl4j-article/570.jpg" alt="food - dog" />
</figure>
<h3 id="1-square-images">1. Square images</h3>
<p>While images in the training set varied from portrait to landscape and the number of pixels, most were roughly square. Many were exactly 500 x 375, which was also the largest size, presumably the output of Yelp’s own image processing system.</p>
<p>To train a convolutional net, all images need to be the same shape and size. While there are likely fancier tricks and techniques that allow for different sized images, I started simple: make all images square, while preserving as much of the image as possible. I assume that the material of interest is centered, so I capture the middle-most square of each image.</p>
<p>Example:</p>
<p><img src="/simpleblog/assets/dl4j-article/20.jpg" alt="food - pizza" /></p>
<figcaption>original 500 x 375</figcaption>
<p><img src="/simpleblog/assets/dl4j-article/20square.jpg" alt="food - pizza square" /></p>
<figcaption>squared 375 x 375</figcaption>
<p>This example was created with the following code:
<script src="https://gist.github.com/brooksandrew/8138798fc9cc249882152d5234edc9aa.js"></script></p>
<h3 id="2-re-size-images">2. Re-size images</h3>
<p>Now that images are squared, the re-sizing problem is relatively straightforward.</p>
<p>Example:</p>
<p><img src="/simpleblog/assets/dl4j-article/20.jpg" alt="food - pizza color" height="500" width="500" /></p>
<figcaption>original 500 x 375</figcaption>
<p><img src="/simpleblog/assets/dl4j-article/20resize256.jpg" alt="food - pizza square" style="width:375px; height:375px; image-rendering: pixelated; -ms-interpolation-mode: bicubic;" /></p>
<figcaption>re-sized 256 x 256</figcaption>
<p><img src="/simpleblog/assets/dl4j-article/20resize128.jpg" alt="food - pizza square" style="width:375px; height:375px; image-rendering: pixelated; -ms-interpolation-mode: bicubic;" /></p>
<figcaption>re-sized 128 x 128</figcaption>
<p><img src="/simpleblog/assets/dl4j-article/20resize64.jpg" alt="food - pizza square" style="width:375px; height:375px; image-rendering: pixelated; -ms-interpolation-mode: bicubic;" /></p>
<figcaption>re-sized 64 x 64</figcaption>
<p><img src="/simpleblog/assets/dl4j-article/20resize32.jpg" alt="food - pizza square" style="width:375px; height:375px; image-rendering: pixelated; -ms-interpolation-mode: bicubic;" /></p>
<figcaption>re-sized 32 x 32</figcaption>
<p>This example was created with the following code:
<script src="https://gist.github.com/brooksandrew/7f123b4acb3dcf52ecb9951858974efb.js"></script></p>
<h3 id="3-grayscale">3. Grayscale</h3>
<p>While DL4J and convolutional nets can certainly handle color images, I decided to simplify computation and start with grayscale. This way a single 64 x 64 pixel image is represented by 4096 features rather than 4096*3 (one for each color channel: R, G, B). There is a good discussion of the numerous ways to do this <a href="http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/">here</a>. I opted to start with the simplest of all (averaging) which appeared to work quite well.
Here’s an example:</p>
<figure class="half">
<img src="/simpleblog/assets/dl4j-article/20.jpg" alt="food - pizza color" />
<img src="/simpleblog/assets/dl4j-article/20gray.jpg" alt="food - pizza gray" />
</figure>
<figcaption>original image (left); grayscale conversion using RGB averaging (right)</figcaption>
<p>This example was created with the following code:
<script src="https://gist.github.com/brooksandrew/c9c3ab6ba93ea03fb3fa1ecccef2607a.js"></script></p>
<!--
<script src="http://gist-it.appspot.com/https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/processing/extendBufferedImage.scala"></script> -->
<h2 id="pipeline---images">Pipeline - images</h2>
<p>Much of this section is specific to the Kaggle problem and discusses the data structures I created and used to keep store and manage images with their corresponding labels. It’s mainly an exploration of how to structure a data science project with Scala. If you’re primarily interested in DL4J, skip ahead to the Pipeline - DL4J section.</p>
<h3 id="image-processing-1">Image processing</h3>
<p>In my image processing pipeline, I modified the functions in the Gists above to methods of the <code class="highlighter-rouge">java.awt.image.BufferedImage</code> class.</p>
<p>This allows me to operate on images with chaining like this:</p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">import</span> <span class="nn">imgUtils._</span>
<span class="k">val</span> <span class="n">img</span> <span class="k">=</span> <span class="nc">ImageIO</span><span class="o">.</span><span class="n">read</span><span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="s">"myimagefile.jpg"</span><span class="o">))</span>
<span class="o">.</span><span class="n">makeSquare</span>
<span class="o">.</span><span class="n">resizeImg</span><span class="o">(</span><span class="mi">128</span><span class="o">,</span> <span class="mi">128</span><span class="o">)</span>
<span class="o">.</span><span class="n">image2gray</span></code></pre></figure>
<p>I’m not sure if this approach of extending an existing class with new methods is preferred to creating a new class, but it seemed to work well for my problem. I imagine it would be less clean if all instances of the original class do not need the newly defined methods. However, this wasn’t the case for me: all images need the new methods.</p>
<p>Code below: <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/processing/extendBufferedImage.scala">extendBufferedImage.scala</a></p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">package</span> <span class="nn">modeling.processing</span>
<span class="k">import</span> <span class="nn">scala.Vector</span>
<span class="k">import</span> <span class="nn">org.imgscalr._</span>
<span class="k">object</span> <span class="nc">imgUtils</span> <span class="o">{</span>
<span class="k">implicit</span> <span class="k">class</span> <span class="nc">extendingImageClass</span><span class="o">(</span><span class="n">img</span><span class="k">:</span> <span class="kt">java.awt.image.BufferedImage</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// image 2 vector processing
</span> <span class="k">def</span> <span class="n">pixels2gray</span><span class="o">(</span><span class="n">red</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">green</span><span class="k">:</span><span class="kt">Int</span><span class="o">,</span> <span class="n">blue</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="o">(</span><span class="n">red</span> <span class="o">+</span> <span class="n">green</span> <span class="o">+</span> <span class="n">blue</span><span class="o">)</span> <span class="o">/</span> <span class="mi">3</span>
<span class="k">def</span> <span class="n">pixels2color</span><span class="o">(</span><span class="n">red</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">green</span><span class="k">:</span><span class="kt">Int</span><span class="o">,</span> <span class="n">blue</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">Vector</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nc">Vector</span><span class="o">(</span><span class="n">red</span><span class="o">,</span> <span class="n">green</span><span class="o">,</span> <span class="n">blue</span><span class="o">)</span>
<span class="k">private</span> <span class="k">def</span> <span class="n">image2vec</span><span class="o">[</span><span class="kt">A</span><span class="o">](</span><span class="n">f</span><span class="k">:</span> <span class="o">(</span><span class="kt">Int</span><span class="o">,</span> <span class="kt">Int</span><span class="o">,</span> <span class="nc">Int</span><span class="o">)</span> <span class="k">=></span> <span class="n">A</span> <span class="o">)</span><span class="k">:</span> <span class="kt">Vector</span><span class="o">[</span><span class="kt">A</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">w</span> <span class="k">=</span> <span class="n">img</span><span class="o">.</span><span class="n">getWidth</span>
<span class="k">val</span> <span class="n">h</span> <span class="k">=</span> <span class="n">img</span><span class="o">.</span><span class="n">getHeight</span>
<span class="k">for</span> <span class="o">{</span> <span class="n">w1</span> <span class="k"><-</span> <span class="o">(</span><span class="mi">0</span> <span class="n">until</span> <span class="n">w</span><span class="o">).</span><span class="n">toVector</span>
<span class="n">h1</span> <span class="k"><-</span> <span class="o">(</span><span class="mi">0</span> <span class="n">until</span> <span class="n">h</span><span class="o">).</span><span class="n">toVector</span>
<span class="o">}</span> <span class="k">yield</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">col</span> <span class="k">=</span> <span class="n">img</span><span class="o">.</span><span class="n">getRGB</span><span class="o">(</span><span class="n">w1</span><span class="o">,</span> <span class="n">h1</span><span class="o">)</span>
<span class="k">val</span> <span class="n">red</span> <span class="k">=</span> <span class="o">(</span><span class="n">col</span> <span class="o">&</span> <span class="mh">0xff0000</span><span class="o">)</span> <span class="o">/</span> <span class="mi">65536</span>
<span class="k">val</span> <span class="n">green</span> <span class="k">=</span> <span class="o">(</span><span class="n">col</span> <span class="o">&</span> <span class="mh">0xff00</span><span class="o">)</span> <span class="o">/</span> <span class="mi">256</span>
<span class="k">val</span> <span class="n">blue</span> <span class="k">=</span> <span class="o">(</span><span class="n">col</span> <span class="o">&</span> <span class="mh">0xff</span><span class="o">)</span>
<span class="n">f</span><span class="o">(</span><span class="n">red</span><span class="o">,</span> <span class="n">green</span><span class="o">,</span> <span class="n">blue</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">def</span> <span class="n">image2gray</span><span class="k">:</span> <span class="kt">Vector</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="n">image2vec</span><span class="o">(</span><span class="n">pixels2gray</span><span class="o">)</span>
<span class="k">def</span> <span class="n">image2color</span><span class="k">:</span> <span class="kt">Vector</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="n">image2vec</span><span class="o">(</span><span class="n">pixels2color</span><span class="o">).</span><span class="n">flatten</span>
<span class="c1">// make image square
</span> <span class="k">def</span> <span class="n">makeSquare</span> <span class="k">=</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">w</span> <span class="k">=</span> <span class="n">img</span><span class="o">.</span><span class="n">getWidth</span>
<span class="k">val</span> <span class="n">h</span> <span class="k">=</span> <span class="n">img</span><span class="o">.</span><span class="n">getHeight</span>
<span class="k">val</span> <span class="n">dim</span> <span class="k">=</span> <span class="nc">List</span><span class="o">(</span><span class="n">w</span><span class="o">,</span> <span class="n">h</span><span class="o">).</span><span class="n">min</span>
<span class="n">img</span> <span class="k">match</span> <span class="o">{</span>
<span class="k">case</span> <span class="n">x</span> <span class="k">if</span> <span class="n">w</span> <span class="o">==</span> <span class="n">h</span> <span class="k">=></span> <span class="n">img</span>
<span class="k">case</span> <span class="n">x</span> <span class="k">if</span> <span class="n">w</span> <span class="o">></span> <span class="n">h</span> <span class="k">=></span> <span class="nc">Scalr</span><span class="o">.</span><span class="n">crop</span><span class="o">(</span><span class="n">img</span><span class="o">,</span> <span class="o">(</span><span class="n">w</span><span class="o">-</span><span class="n">h</span><span class="o">)/</span><span class="mi">2</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">dim</span><span class="o">,</span> <span class="n">dim</span><span class="o">)</span>
<span class="k">case</span> <span class="n">x</span> <span class="k">if</span> <span class="n">w</span> <span class="o"><</span> <span class="n">h</span> <span class="k">=></span> <span class="nc">Scalr</span><span class="o">.</span><span class="n">crop</span><span class="o">(</span><span class="n">img</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="o">(</span><span class="n">h</span><span class="o">-</span><span class="n">w</span><span class="o">)/</span><span class="mi">2</span><span class="o">,</span> <span class="n">dim</span><span class="o">,</span> <span class="n">dim</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="c1">// resize pixels
</span> <span class="k">def</span> <span class="n">resizeImg</span><span class="o">(</span><span class="n">width</span><span class="k">:</span> <span class="kt">Int</span><span class="o">,</span> <span class="n">height</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span> <span class="k">=</span> <span class="o">{</span>
<span class="nc">Scalr</span><span class="o">.</span><span class="n">resize</span><span class="o">(</span><span class="n">img</span><span class="o">,</span> <span class="nc">Scalr</span><span class="o">.</span><span class="nc">Method</span><span class="o">.</span><span class="nc">BALANCED</span><span class="o">,</span> <span class="n">width</span><span class="o">,</span> <span class="n">height</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<h3 id="io">I/O</h3>
<p>We need to load a couple CSV files containing metadata about each image. There are some Scala CSV reader libraries out there like <a href="https://github.com/tototoshi/scala-csv">scala-csv</a>, however I forwent these to get more experience testing out Scala. I defined a basic file-reader <code class="highlighter-rouge">readcsv</code> which is used by <code class="highlighter-rouge">readBizLabels</code> and <code class="highlighter-rouge">readBiz2ImgLabels</code> to read in text files containing the labels for each Yelp business and image-to-business mappings respectively.</p>
<p>Code below: <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/io/readCsvData.scala">readCsvData.scala</a></p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">package</span> <span class="nn">modeling.io</span>
<span class="k">import</span> <span class="nn">scala.io.Source</span>
<span class="k">object</span> <span class="nc">readCsvData</span> <span class="o">{</span>
<span class="cm">/** Generic function to load in CSV */</span>
<span class="k">def</span> <span class="n">readcsv</span><span class="o">(</span><span class="n">csv</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">rows</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span><span class="k">=</span><span class="nc">List</span><span class="o">(-</span><span class="mi">1</span><span class="o">))</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">List</span><span class="o">[</span><span class="kt">String</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">src</span> <span class="k">=</span> <span class="nc">Source</span><span class="o">.</span><span class="n">fromFile</span><span class="o">(</span><span class="n">csv</span><span class="o">)</span>
<span class="k">def</span> <span class="n">reading</span><span class="o">(</span><span class="n">csv</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">List</span><span class="o">[</span><span class="kt">String</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
<span class="n">src</span><span class="o">.</span><span class="n">getLines</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span> <span class="n">x</span><span class="o">.</span><span class="n">split</span><span class="o">(</span><span class="s">","</span><span class="o">).</span><span class="n">toList</span><span class="o">)</span>
<span class="o">.</span><span class="n">toList</span>
<span class="o">}</span>
<span class="k">try</span> <span class="o">{</span>
<span class="k">if</span><span class="o">(</span><span class="n">rows</span><span class="o">==</span><span class="nc">List</span><span class="o">(-</span><span class="mi">1</span><span class="o">))</span> <span class="n">reading</span><span class="o">(</span><span class="n">csv</span><span class="o">)</span>
<span class="k">else</span> <span class="n">rows</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">reading</span><span class="o">(</span><span class="n">csv</span><span class="o">))</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span>
<span class="n">src</span><span class="o">.</span><span class="n">close</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="cm">/** Create map from bizid to labels of form bizid -> Set(labels) */</span>
<span class="k">def</span> <span class="n">readBizLabels</span><span class="o">(</span><span class="n">csv</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">rows</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span><span class="k">=</span><span class="nc">List</span><span class="o">(-</span><span class="mi">1</span><span class="o">))</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">String</span>, <span class="kt">Set</span><span class="o">[</span><span class="kt">Int</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">src</span> <span class="k">=</span> <span class="n">readcsv</span><span class="o">(</span><span class="n">csv</span><span class="o">)</span>
<span class="n">src</span><span class="o">.</span><span class="n">drop</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// drop header
</span> <span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span> <span class="n">x</span> <span class="k">match</span> <span class="o">{</span>
<span class="k">case</span> <span class="n">x</span> <span class="o">::</span> <span class="nc">Nil</span> <span class="k">=></span> <span class="o">(</span><span class="n">x</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="n">toString</span><span class="o">,</span> <span class="nc">Set</span><span class="o">[</span><span class="kt">Int</span><span class="o">]())</span>
<span class="k">case</span> <span class="k">_</span> <span class="k">=></span> <span class="o">(</span><span class="n">x</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="n">toString</span><span class="o">,</span> <span class="n">x</span><span class="o">(</span><span class="mi">1</span><span class="o">).</span><span class="n">split</span><span class="o">(</span><span class="s">" "</span><span class="o">).</span><span class="n">map</span><span class="o">(</span><span class="n">y</span> <span class="k">=></span> <span class="n">y</span><span class="o">.</span><span class="n">toInt</span><span class="o">).</span><span class="n">toSet</span><span class="o">)</span>
<span class="o">}).</span><span class="n">toMap</span>
<span class="o">}</span>
<span class="cm">/** Create map from imgID to bizID of form imgID -> busID */</span>
<span class="k">def</span> <span class="n">readBiz2ImgLabels</span><span class="o">(</span><span class="n">csv</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">rows</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="nc">List</span><span class="o">(-</span><span class="mi">1</span><span class="o">))</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">String</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">src</span> <span class="k">=</span> <span class="n">readcsv</span><span class="o">(</span><span class="n">csv</span><span class="o">)</span>
<span class="n">src</span><span class="o">.</span><span class="n">drop</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span> <span class="c1">// drop header
</span> <span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span> <span class="n">x</span> <span class="k">match</span> <span class="o">{</span>
<span class="k">case</span> <span class="n">x</span> <span class="o">::</span> <span class="nc">Nil</span> <span class="k">=></span> <span class="o">(</span><span class="n">x</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="n">toInt</span><span class="o">,</span> <span class="s">"-1"</span><span class="o">)</span>
<span class="k">case</span> <span class="k">_</span> <span class="k">=></span> <span class="o">(</span><span class="n">x</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="n">toInt</span><span class="o">,</span> <span class="n">x</span><span class="o">(</span><span class="mi">1</span><span class="o">).</span><span class="n">split</span><span class="o">(</span><span class="s">" "</span><span class="o">).</span><span class="n">head</span><span class="o">)</span>
<span class="o">}).</span><span class="n">toMap</span>
<span class="o">}</span></code></pre></figure>
<h3 id="wrangling">Wrangling</h3>
<p>I make heavy use of the Scala map class. Essentially we have three maps:</p>
<ol>
<li><strong>bizMap</strong> (imgID -> bizID)</li>
<li><strong>dataMap</strong> (imgID -> img data)</li>
<li><strong>labMap</strong> (bizID -> labels)</li>
</ol>
<p>I suppose I could have made classes for each of these as well, but they’re really just intermediate data structures, so I didn’t bother.</p>
<p><code class="highlighter-rouge">readBizLabels</code> from the code above creates the <strong>bizMap</strong> and <code class="highlighter-rouge">readBiz2ImgLabels</code> creates the <strong>imgMap</strong>. <code class="highlighter-rouge">processImages</code> from the code below creates the <strong>dataMap</strong>. Next step: create a single data representation of these three separate but related data structures.</p>
<p>Code below: <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/processing/images.scala">images.scala</a></p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">package</span> <span class="nn">modeling.processing</span>
<span class="k">import</span> <span class="nn">java.io.File</span>
<span class="k">import</span> <span class="nn">javax.imageio.ImageIO</span>
<span class="k">import</span> <span class="nn">scala.util.matching.Regex</span>
<span class="k">import</span> <span class="nn">imgUtils._</span>
<span class="k">object</span> <span class="nc">images</span> <span class="o">{</span>
<span class="cm">/** Define RegEx to extract jpg name from the image class which is used to match against training labels */</span>
<span class="k">val</span> <span class="n">patt_get_jpg_name</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">Regex</span><span class="o">(</span><span class="s">"[0-9]"</span><span class="o">)</span>
<span class="cm">/** Collects all images associated with a BizId. */</span>
<span class="k">def</span> <span class="n">getImgIdsForBizId</span><span class="o">(</span><span class="n">bizMap</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">String</span><span class="o">],</span> <span class="n">bizIds</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
<span class="n">bizMap</span><span class="o">.</span><span class="n">filter</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span> <span class="n">bizIds</span><span class="o">.</span><span class="n">exists</span><span class="o">(</span><span class="n">y</span> <span class="k">=></span> <span class="n">y</span> <span class="o">==</span> <span class="n">x</span><span class="o">.</span><span class="n">_2</span><span class="o">)).</span><span class="n">map</span><span class="o">(</span><span class="k">_</span><span class="o">.</span><span class="n">_1</span><span class="o">).</span><span class="n">toList</span>
<span class="o">}</span>
<span class="cm">/** Get a list of images to load and process
*
* @param photoDir directory where the raw images reside
* @param ids optional parameter to subset the images loaded from photoDir.
*
* @example println(getImageIds("/Users/abrooks/Documents/kaggle_yelp_photo/train_photos/", ids=List.range(0,10)))
*/</span>
<span class="k">def</span> <span class="n">getImageIds</span><span class="o">(</span><span class="n">photoDir</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="n">bizMap</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">String</span><span class="o">]</span> <span class="k">=</span> <span class="nc">Map</span><span class="o">(-</span><span class="mi">1</span> <span class="o">-></span> <span class="s">"-1"</span><span class="o">),</span> <span class="n">bizIds</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">String</span><span class="o">]</span> <span class="k">=</span> <span class="nc">List</span><span class="o">(</span><span class="s">"-1"</span><span class="o">))</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">String</span><span class="o">]</span> <span class="k">=</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">d</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">photoDir</span><span class="o">)</span> <span class="c1">// new File("data/images/") // too many photos?
</span> <span class="k">val</span> <span class="n">imgsPath</span> <span class="k">=</span> <span class="n">d</span><span class="o">.</span><span class="n">listFiles</span><span class="o">().</span><span class="n">map</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span> <span class="n">x</span><span class="o">.</span><span class="n">toString</span><span class="o">).</span><span class="n">toList</span>
<span class="k">if</span> <span class="o">(</span><span class="n">bizMap</span> <span class="o">==</span> <span class="nc">Map</span><span class="o">(-</span><span class="mi">1</span> <span class="o">-></span> <span class="s">"-1"</span><span class="o">)</span> <span class="o">||</span> <span class="n">bizIds</span> <span class="o">==</span> <span class="nc">List</span><span class="o">(-</span><span class="mi">1</span><span class="o">))</span> <span class="o">{</span>
<span class="n">imgsPath</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">imgsMap</span> <span class="k">=</span> <span class="n">imgsPath</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span> <span class="n">patt_get_jpg_name</span><span class="o">.</span><span class="n">findAllIn</span><span class="o">(</span><span class="n">x</span><span class="o">).</span><span class="n">mkString</span><span class="o">.</span><span class="n">toInt</span> <span class="o">-></span> <span class="n">x</span><span class="o">).</span><span class="n">toMap</span>
<span class="k">val</span> <span class="n">imgsPathSub</span> <span class="k">=</span> <span class="n">getImgIdsForBizId</span><span class="o">(</span><span class="n">bizMap</span><span class="o">,</span> <span class="n">bizIds</span><span class="o">)</span>
<span class="n">imgsPathSub</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span> <span class="n">imgsMap</span><span class="o">(</span><span class="n">x</span><span class="o">))</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="cm">/** Read and process images into a photoID -> vector map
*
* @param imgs list of images to read-in. created from getImageIds function.
* @param resizeImgDim dimension to rescale square images to
* @param nPixels number of pixels to maintain. mainly used to sample image to drastically reduce runtime while testing features.
*
* @example
val imgs = getImageIds("/Users/abrooks/Documents/kaggle_yelp_photo/train_photos/", ids=List(0,1,2,3,4))
println(processImages(imgs, resizeImgDim = 128, nPixels = 16)) */</span>
<span class="k">def</span> <span class="n">processImages</span><span class="o">(</span><span class="n">imgs</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">String</span><span class="o">],</span> <span class="n">resizeImgDim</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="mi">128</span><span class="o">,</span> <span class="n">nPixels</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="o">)</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">Vector</span><span class="o">[</span><span class="kt">Int</span><span class="o">]]</span> <span class="k">=</span> <span class="o">{</span>
<span class="n">imgs</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span>
<span class="n">patt_get_jpg_name</span><span class="o">.</span><span class="n">findAllIn</span><span class="o">(</span><span class="n">x</span><span class="o">).</span><span class="n">mkString</span><span class="o">.</span><span class="n">toInt</span> <span class="o">-></span> <span class="o">{</span>
<span class="k">val</span> <span class="n">img0</span> <span class="k">=</span> <span class="nc">ImageIO</span><span class="o">.</span><span class="n">read</span><span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">x</span><span class="o">))</span>
<span class="o">.</span><span class="n">makeSquare</span>
<span class="o">.</span><span class="n">resizeImg</span><span class="o">(</span><span class="n">resizeImgDim</span><span class="o">,</span> <span class="n">resizeImgDim</span><span class="o">)</span> <span class="c1">// (200, 200)
</span> <span class="o">.</span><span class="n">image2gray</span>
<span class="k">if</span><span class="o">(</span><span class="n">nPixels</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="o">)</span> <span class="n">img0</span><span class="o">.</span><span class="n">slice</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">nPixels</span><span class="o">)</span>
<span class="k">else</span> <span class="n">img0</span>
<span class="o">}</span>
<span class="o">).</span><span class="n">filter</span><span class="o">(</span> <span class="n">x</span> <span class="k">=></span> <span class="n">x</span><span class="o">.</span><span class="n">_2</span> <span class="o">!=</span> <span class="o">())</span>
<span class="o">.</span><span class="n">toMap</span>
<span class="o">}</span></code></pre></figure>
<h3 id="data-structure">Data structure</h3>
<p>So there are four pieces of information to keep track of for each image:</p>
<ol>
<li>imageID</li>
<li>bizID</li>
<li>labels</li>
<li>pixel data</li>
</ol>
<p>The data is represented like this:</p>
<p><img src="/simpleblog/assets/dl4j-article/dataflow.png" alt="diagram of data organization" /></p>
<p>I defined a class <code class="highlighter-rouge">alignedData</code> to manage it all. When instantiating an instance of <code class="highlighter-rouge">alignedData</code>, the <strong>bizMap</strong>, <strong>dataMap</strong> and <strong>labMap</strong> are provided. I used Scala’s <code class="highlighter-rouge">Option</code> type for <strong>labMap</strong> since we don’t have this information when we score test data. <code class="highlighter-rouge">None</code> is provided that case.</p>
<p>Under the hood, the primary data structure has the following type:</p>
<p><code class="highlighter-rouge">List[(Int, String, Vector[Int], Set[Int])]</code></p>
<p>which corresponds to a list of Tuple4s containing this information:</p>
<p>List[(<strong>imgID</strong>, <strong>bizID</strong>, <strong>pixel data vector</strong>, <strong>labels</strong>)]</p>
<p>Code below: <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/processing/alignedData.scala">alignedData.scala</a></p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">package</span> <span class="nn">modeling.processing</span>
<span class="k">class</span> <span class="nc">alignedData</span><span class="o">(</span><span class="n">dataMap</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">Vector</span><span class="o">[</span><span class="kt">Int</span><span class="o">]],</span> <span class="n">bizMap</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">String</span><span class="o">],</span> <span class="n">labMap</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">Map</span><span class="o">[</span><span class="kt">String</span>, <span class="kt">Set</span><span class="o">[</span><span class="kt">Int</span><span class="o">]]])</span>
<span class="o">(</span><span class="n">rowindices</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="n">dataMap</span><span class="o">.</span><span class="n">keySet</span><span class="o">.</span><span class="n">toList</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// initializing alignedData with empty labMap when it is not provided (we are working with training data)
</span> <span class="k">def</span> <span class="k">this</span><span class="o">(</span><span class="n">dataMap</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">Vector</span><span class="o">[</span><span class="kt">Int</span><span class="o">]],</span> <span class="n">bizMap</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">String</span><span class="o">])(</span><span class="n">rowindices</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">])</span> <span class="k">=</span> <span class="k">this</span><span class="o">(</span><span class="n">dataMap</span><span class="o">,</span> <span class="n">bizMap</span><span class="o">,</span> <span class="nc">None</span><span class="o">)(</span><span class="n">rowindices</span><span class="o">)</span>
<span class="k">def</span> <span class="n">alignBizImgIds</span><span class="o">(</span><span class="n">dataMap</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">Vector</span><span class="o">[</span><span class="kt">Int</span><span class="o">]],</span> <span class="n">bizMap</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">String</span><span class="o">])</span>
<span class="o">(</span><span class="n">rowindices</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="n">dataMap</span><span class="o">.</span><span class="n">keySet</span><span class="o">.</span><span class="n">toList</span><span class="o">)</span><span class="k">:</span> <span class="kt">List</span><span class="o">[(</span><span class="kt">Int</span>, <span class="kt">String</span>, <span class="kt">Vector</span><span class="o">[</span><span class="kt">Int</span><span class="o">])]</span> <span class="k">=</span> <span class="o">{</span>
<span class="k">for</span> <span class="o">{</span> <span class="n">pid</span> <span class="k"><-</span> <span class="n">rowindices</span>
<span class="k">val</span> <span class="n">imgHasBiz</span> <span class="k">=</span> <span class="n">bizMap</span><span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="n">pid</span><span class="o">)</span> <span class="c1">// returns None if img does not have a bizID
</span> <span class="k">val</span> <span class="n">bid</span> <span class="k">=</span> <span class="k">if</span><span class="o">(</span><span class="n">imgHasBiz</span> <span class="o">!=</span> <span class="nc">None</span><span class="o">)</span> <span class="n">imgHasBiz</span><span class="o">.</span><span class="n">get</span> <span class="k">else</span> <span class="s">"-1"</span>
<span class="k">if</span> <span class="o">(</span><span class="n">dataMap</span><span class="o">.</span><span class="n">keys</span><span class="o">.</span><span class="n">toSet</span><span class="o">.</span><span class="n">contains</span><span class="o">(</span><span class="n">pid</span><span class="o">)</span> <span class="o">&&</span> <span class="n">imgHasBiz</span> <span class="o">!=</span> <span class="nc">None</span><span class="o">)</span>
<span class="o">}</span> <span class="k">yield</span> <span class="o">{</span>
<span class="o">(</span><span class="n">pid</span><span class="o">,</span> <span class="n">bid</span><span class="o">,</span> <span class="n">dataMap</span><span class="o">(</span><span class="n">pid</span><span class="o">))</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">def</span> <span class="n">alignLabels</span><span class="o">(</span><span class="n">dataMap</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">Vector</span><span class="o">[</span><span class="kt">Int</span><span class="o">]],</span> <span class="n">bizMap</span><span class="k">:</span> <span class="kt">Map</span><span class="o">[</span><span class="kt">Int</span>, <span class="kt">String</span><span class="o">],</span> <span class="n">labMap</span><span class="k">:</span> <span class="kt">Option</span><span class="o">[</span><span class="kt">Map</span><span class="o">[</span><span class="kt">String</span>, <span class="kt">Set</span><span class="o">[</span><span class="kt">Int</span><span class="o">]]])</span>
<span class="o">(</span><span class="n">rowindices</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="n">dataMap</span><span class="o">.</span><span class="n">keySet</span><span class="o">.</span><span class="n">toList</span><span class="o">)</span><span class="k">:</span> <span class="kt">List</span><span class="o">[(</span><span class="kt">Int</span>, <span class="kt">String</span>, <span class="kt">Vector</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span>, <span class="kt">Set</span><span class="o">[</span><span class="kt">Int</span><span class="o">])]</span> <span class="k">=</span> <span class="o">{</span>
<span class="k">def</span> <span class="n">flatten1</span><span class="o">[</span><span class="kt">A</span>, <span class="kt">B</span>, <span class="kt">C</span>, <span class="kt">D</span><span class="o">](</span><span class="n">t</span><span class="k">:</span> <span class="o">((</span><span class="kt">A</span><span class="o">,</span> <span class="kt">B</span><span class="o">,</span> <span class="kt">C</span><span class="o">),</span> <span class="n">D</span><span class="o">))</span><span class="k">:</span> <span class="o">(</span><span class="kt">A</span><span class="o">,</span> <span class="kt">B</span><span class="o">,</span> <span class="n">C</span><span class="o">,</span> <span class="n">D</span><span class="o">)</span> <span class="k">=</span> <span class="o">(</span><span class="n">t</span><span class="o">.</span><span class="n">_1</span><span class="o">.</span><span class="n">_1</span><span class="o">,</span> <span class="n">t</span><span class="o">.</span><span class="n">_1</span><span class="o">.</span><span class="n">_2</span><span class="o">,</span> <span class="n">t</span><span class="o">.</span><span class="n">_1</span><span class="o">.</span><span class="n">_3</span><span class="o">,</span> <span class="n">t</span><span class="o">.</span><span class="n">_2</span><span class="o">)</span>
<span class="k">val</span> <span class="n">al</span> <span class="k">=</span> <span class="n">alignBizImgIds</span><span class="o">(</span><span class="n">dataMap</span><span class="o">,</span> <span class="n">bizMap</span><span class="o">)(</span><span class="n">rowindices</span><span class="o">)</span>
<span class="k">for</span> <span class="o">{</span> <span class="n">p</span> <span class="k"><-</span> <span class="n">al</span>
<span class="o">}</span> <span class="k">yield</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">bid</span> <span class="k">=</span> <span class="n">p</span><span class="o">.</span><span class="n">_2</span>
<span class="k">val</span> <span class="n">labs</span> <span class="k">=</span> <span class="n">labMap</span> <span class="k">match</span> <span class="o">{</span>
<span class="k">case</span> <span class="nc">None</span> <span class="k">=></span> <span class="nc">Set</span><span class="o">[</span><span class="kt">Int</span><span class="o">]()</span>
<span class="k">case</span> <span class="n">x</span> <span class="k">=></span> <span class="o">(</span><span class="k">if</span><span class="o">(</span><span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="o">.</span><span class="n">keySet</span><span class="o">.</span><span class="n">contains</span><span class="o">(</span><span class="n">bid</span><span class="o">))</span> <span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="n">bid</span><span class="o">)</span> <span class="k">else</span> <span class="nc">Set</span><span class="o">[</span><span class="kt">Int</span><span class="o">]())</span>
<span class="o">}</span>
<span class="n">flatten1</span><span class="o">(</span><span class="n">p</span><span class="o">,</span> <span class="n">labs</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="c1">// pre-computing and saving data as a val so method does not need to re-compute each time it is called.
</span> <span class="k">lazy</span> <span class="k">val</span> <span class="n">data</span> <span class="k">=</span> <span class="n">alignLabels</span><span class="o">(</span><span class="n">dataMap</span><span class="o">,</span> <span class="n">bizMap</span><span class="o">,</span> <span class="n">labMap</span><span class="o">)(</span><span class="n">rowindices</span><span class="o">)</span>
<span class="c1">// getter functions
</span> <span class="k">def</span> <span class="n">getImgIds</span> <span class="k">=</span> <span class="n">data</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="k">_</span><span class="o">.</span><span class="n">_1</span><span class="o">)</span>
<span class="k">def</span> <span class="n">getBizIds</span> <span class="k">=</span> <span class="n">data</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="k">_</span><span class="o">.</span><span class="n">_2</span><span class="o">)</span>
<span class="k">def</span> <span class="n">getImgVectors</span> <span class="k">=</span> <span class="n">data</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="k">_</span><span class="o">.</span><span class="n">_3</span><span class="o">)</span>
<span class="k">def</span> <span class="n">getBizLabels</span> <span class="k">=</span> <span class="n">data</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="k">_</span><span class="o">.</span><span class="n">_4</span><span class="o">)</span>
<span class="k">def</span> <span class="n">getImgCntsPerBiz</span> <span class="k">=</span> <span class="n">getBizIds</span><span class="o">.</span><span class="n">groupBy</span><span class="o">(</span><span class="n">identity</span><span class="o">).</span><span class="n">mapValues</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span> <span class="n">x</span><span class="o">.</span><span class="n">size</span><span class="o">)</span>
<span class="o">}</span></code></pre></figure>
<h3 id="make-nd4j-dataset">Make ND4J dataset</h3>
<p>Last step is to create the data structure that DL4J needs for training convolutional nets. That data structure is an <a href="http://nd4j.org/doc/org/nd4j/linalg/dataset/DataSet.html">ND4J DataSet</a>.</p>
<p>This is relatively straightforward once you figure out how to convert native Scala data structures to this type.</p>
<p>Code below: <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/processing/makeDataSets.scala">makeDataSets.scala</a></p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">package</span> <span class="nn">modeling.processing</span>
<span class="k">import</span> <span class="nn">org.nd4j.linalg.dataset.</span><span class="o">{</span><span class="nc">DataSet</span><span class="o">}</span>
<span class="k">import</span> <span class="nn">org.nd4s.Implicits._</span>
<span class="k">import</span> <span class="nn">org.nd4j.linalg.api.ndarray.INDArray</span>
<span class="k">import</span> <span class="nn">alignedData._</span>
<span class="k">object</span> <span class="nc">makeDataSets</span> <span class="o">{</span>
<span class="cm">/** Creates DataSet object from the data structure of data structure from alignLables function in form List[(imgID, bizID, labels, pixelVector)] */</span>
<span class="k">def</span> <span class="n">makeDataSet</span><span class="o">(</span><span class="n">alignedData</span><span class="k">:</span> <span class="kt">alignedData</span><span class="o">,</span> <span class="n">bizClass</span><span class="k">:</span> <span class="kt">Int</span><span class="o">)</span><span class="k">:</span> <span class="kt">DataSet</span> <span class="o">=</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">alignedXData</span> <span class="k">=</span> <span class="n">alignedData</span><span class="o">.</span><span class="n">getImgVectors</span><span class="o">.</span><span class="n">toNDArray</span>
<span class="k">val</span> <span class="n">alignedLabs</span> <span class="k">=</span> <span class="n">alignedData</span><span class="o">.</span><span class="n">getBizLabels</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span> <span class="k">if</span> <span class="o">(</span><span class="n">x</span><span class="o">.</span><span class="n">contains</span><span class="o">(</span><span class="n">bizClass</span><span class="o">))</span> <span class="nc">Vector</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="mi">0</span><span class="o">)</span> <span class="k">else</span> <span class="nc">Vector</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">1</span><span class="o">)).</span><span class="n">toNDArray</span>
<span class="k">new</span> <span class="nc">DataSet</span><span class="o">(</span><span class="n">alignedXData</span><span class="o">,</span> <span class="n">alignedLabs</span><span class="o">)</span>
<span class="o">}</span>
<span class="k">def</span> <span class="n">makeDataSetTE</span><span class="o">(</span><span class="n">alignedData</span><span class="k">:</span> <span class="kt">alignedData</span><span class="o">)</span><span class="k">:</span> <span class="kt">INDArray</span> <span class="o">=</span> <span class="o">{</span>
<span class="n">alignedData</span><span class="o">.</span><span class="n">getImgVectors</span><span class="o">.</span><span class="n">toNDArray</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<h3 id="run">Run</h3>
<p>The code to actually run the image processing pipeline boils down to the following:</p>
<p>Code below: snippet from <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/main.scala">main.scala</a></p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">import</span> <span class="nn">io.readCsvData._</span>
<span class="k">import</span> <span class="nn">processing.alignedData</span>
<span class="k">import</span> <span class="nn">processing.images._</span>
<span class="k">import</span> <span class="nn">processing.makeDataSets._</span>
<span class="k">object</span> <span class="nc">runPipeline</span> <span class="o">{</span>
<span class="k">def</span> <span class="n">main</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">Array</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">{</span>
<span class="c1">// image processing on training data
</span> <span class="k">val</span> <span class="n">labMap</span> <span class="k">=</span> <span class="n">readBizLabels</span><span class="o">(</span><span class="s">"data/labels/train.csv"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">bizMap</span> <span class="k">=</span> <span class="n">readBiz2ImgLabels</span><span class="o">(</span><span class="s">"data/labels/train_photo_to_biz_ids.csv"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">imgs</span> <span class="k">=</span> <span class="n">getImageIds</span><span class="o">(</span><span class="s">"data/images/train"</span><span class="o">,</span> <span class="n">bizMap</span><span class="o">,</span> <span class="n">bizMap</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="k">_</span><span class="o">.</span><span class="n">_2</span><span class="o">).</span><span class="n">toSet</span><span class="o">.</span><span class="n">toList</span><span class="o">)</span>
<span class="k">val</span> <span class="n">dataMap</span> <span class="k">=</span> <span class="n">processImages</span><span class="o">(</span><span class="n">imgs</span><span class="o">,</span> <span class="n">resizeImgDim</span> <span class="k">=</span> <span class="mi">64</span><span class="o">)</span>
<span class="k">val</span> <span class="n">alignedData</span> <span class="k">=</span> <span class="k">new</span> <span class="n">alignedData</span><span class="o">(</span><span class="n">dataMap</span><span class="o">,</span> <span class="n">bizMap</span><span class="o">,</span> <span class="nc">Option</span><span class="o">(</span><span class="n">labMap</span><span class="o">))()</span></code></pre></figure>
<h2 id="pipeline---dl4j">Pipeline - DL4J</h2>
<p>I didn’t find many examples of DL4J applications in Scala… one of the reasons I’m documenting this project in detail. However, there are some useful examples <a href="https://github.com/kogecoo/dl4j-0.4-examples-scala/tree/master/src/main/scala/org/deeplearning4j/examples">here</a>.</p>
<h3 id="batch-mode">Batch-mode</h3>
<p>This took some exploring to figure out. The default speficification for DL4J networks that run with the ND4J DataSet do not train in batches. That is, each epoch (full pass through the training examples) will train on all training examples in one computation step. So all images, their data and corresponding weights must be held in memory at once.</p>
<p>This hogs memory with all but the smallest of datasets. I was running into heap space errors with just ~2,000 images sized 128 x 128. After switching to batch-mode, I was able to train on tens of thousands of images without memory issues.</p>
<p>Before I discovered this was the cause of my heap space problem, I posed my problem to the project contributors on the <a href="https://gitter.im/deeplearning4j/deeplearning4j">DL4J Gitter</a>. I was pleased to learned that the next release of DL4J (3.9) is planned to move some computational operations off heap.</p>
<h4 id="how-to-use-batches">How to use batches</h4>
<p>It’s easier to figure this out now that the <a href="https://github.com/deeplearning4j/dl4j-0.4-examples/tree/master/src/main/java/org/deeplearning4j/examples/convolution">DL4J examples repo</a> has a convolutional net example (MNIST) using batches, which as of a few weeks ago was not there.</p>
<p>The biggest difference from mini-batch to full-batch mode is that you need to pass a <code class="highlighter-rouge">MultipleEpochsIterator</code> object rather than a ND4J <code class="highlighter-rouge">DataSet</code> to the <code class="highlighter-rouge">fit</code> method of your <code class="highlighter-rouge">MultiLayerNetwork</code> object. My approach doesn’t fully embrace iterators for their intended purpose, but hey it works and made for a smooth transition using my pipeline. You also need to add <code class="highlighter-rouge">.miniBatch(true)</code> to your <code class="highlighter-rouge">MultiLayerConfiguration.Builder</code>.</p>
<p>The distinction between iterations and epochs can be slightly confusing when moving from full-batch to mini-batch mode. If you’re not using miniBatches, the <code class="highlighter-rouge">iterations</code> method is used to specify how many epochs you want. However, when using batches, this is done directly in <code class="highlighter-rouge">MultipleEpochsIterator</code> and <code class="highlighter-rouge">iterations</code> can be set to 1. Explained <a href="http://deeplearning4j.org/troubleshootingneuralnets">here</a> in the DL4J documentation.</p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">import</span> <span class="nn">org.deeplearning4j.datasets.iterator.MultipleEpochsIterator</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.datasets.iterator.impl.ListDataSetIterator</span>
<span class="k">val</span> <span class="n">nbatches</span> <span class="k">=</span> <span class="mi">128</span>
<span class="k">val</span> <span class="n">nepochs</span> <span class="k">=</span> <span class="mi">100</span>
<span class="k">val</span> <span class="n">dsiterTr</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">ListDataSetIterator</span><span class="o">(</span><span class="n">trainTest</span><span class="o">.</span><span class="n">getTrain</span><span class="o">.</span><span class="n">asList</span><span class="o">(),</span> <span class="n">nbatch</span><span class="o">)</span>
<span class="k">val</span> <span class="n">dsiterTe</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">ListDataSetIterator</span><span class="o">(</span><span class="n">trainTest</span><span class="o">.</span><span class="n">getTest</span><span class="o">.</span><span class="n">asList</span><span class="o">(),</span> <span class="n">nbatch</span><span class="o">)</span>
<span class="k">val</span> <span class="n">epochitTr</span><span class="k">:</span> <span class="kt">MultipleEpochsIterator</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MultipleEpochsIterator</span><span class="o">(</span><span class="n">nepochs</span><span class="o">,</span> <span class="n">dsiterTr</span><span class="o">)</span>
<span class="k">val</span> <span class="n">epochitTe</span><span class="k">:</span> <span class="kt">MultipleEpochsIterator</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MultipleEpochsIterator</span><span class="o">(</span><span class="n">nepochs</span><span class="o">,</span> <span class="n">dsiterTe</span><span class="o">)</span></code></pre></figure>
<h3 id="train-convolutional-network">Train convolutional network</h3>
<p>This is the function that actually trains the convolutional net. It’s is long, probably too long. Lots of hyper-parameters hardcoded within that could be moved to function arguments or better yet, a config file. However, I was running locally on laptop with lots of tinkering, so this worked fine for me.</p>
<p>The CNN training function below does a lot: logging, test/train splitting, creating the <code class="highlighter-rouge">MultipleEpochsIterator</code>, training, reporting performance on test data, and saving the trained models to file.</p>
<p>I’ll save the intuition behind tuning for another post after I gain a better understanding myself on a more well posed problem. For now I’ll just ramble about what I tried and what happened.</p>
<p><strong>Layers:</strong> I observed from some papers benchmarking convolutional nets solving the MNIST problem that a single convolutional layer generates decent results (certainly better than a benchmark of random, at least enough get started with). I trained with runs with up to three convolutional layers without errors, but my training was obviously slower (although not exponentially) and results were not any better than with one layer. Next time I plan to start with one convolutional layer, start tuning other parameters to get above benchmark results… and then explore additional layers.</p>
<p><strong># of samples:</strong> Training on all images took so much time, I didn’t have the patience to let it finish. It took me about 2 days to run a watered down CNN on my laptop with 50,000 images.</p>
<p><strong>nepochs:</strong> This is the number of passes through all the training records. I’ve seen some networks with as few as 20 to as many as 1000 epochs. <a href="http://deeplearning4j.org/earlystopping">This</a> is the main idea. There’s also an in-depth discussion about this <a href="http://neuralnetworksanddeeplearning.com/chap3.html">here</a>. I spent most of my tuning time trading off <code class="highlighter-rouge">nepochs</code> and the # of samples. I could tolerate training with lots of images to expose the network to a broader universe of features to learn… but only by cutting down the number of epochs to make run-time manageable.</p>
<p><strong>nOut:</strong> This is the number feature maps. I tried runs with 10 to 500, chosen mostly by reviewing configurations for other image problems and the example DL4J networks.</p>
<p><strong>learningRate:</strong> From what I’ve read this is pretty important. I didn’t fiddle with this much though. I think I tried the commonly used .01 and .001.</p>
<p><strong>nbatch:</strong> This is the # of records in each batch. I tried 32, 64 and 128. I’m not sure how much of a difference this makes for results vs. computation.</p>
<p>Code below: <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/training/cnnEpochs.scala">cnnEpochs.scala</a>. A simpler version using full-batch training is <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/training/cnn.scala">here</a>.</p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">package</span> <span class="nn">modeling.training</span>
<span class="k">import</span> <span class="nn">modeling.processing.makeDataSets._</span>
<span class="k">import</span> <span class="nn">modeling.io._</span>
<span class="k">import</span> <span class="nn">modeling.processing.alignedData</span>
<span class="k">import</span> <span class="nn">java.util.Random</span>
<span class="k">import</span> <span class="nn">java.nio.file._</span>
<span class="k">import</span> <span class="nn">java.io.</span><span class="o">{</span><span class="nc">DataOutputStream</span><span class="o">,</span> <span class="nc">File</span><span class="o">}</span>
<span class="k">import</span> <span class="nn">org.apache.commons.io.FileUtils</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.eval.Evaluation</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.nn.api.OptimizationAlgorithm</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.nn.conf.layers.setup.ConvolutionLayerSetup</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.nn.conf.layers.</span><span class="o">{</span><span class="nc">ConvolutionLayer</span><span class="o">,</span> <span class="nc">OutputLayer</span><span class="o">,</span> <span class="nc">SubsamplingLayer</span><span class="o">,</span> <span class="nc">DenseLayer</span><span class="o">}</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.nn.conf.</span><span class="o">{</span><span class="nc">MultiLayerConfiguration</span><span class="o">,</span> <span class="nc">NeuralNetConfiguration</span><span class="o">}</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.nn.multilayer.MultiLayerNetwork</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.nn.weights.WeightInit</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.optimize.api.IterationListener</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.optimize.listeners.ScoreIterationListener</span>
<span class="k">import</span> <span class="nn">org.nd4j.linalg.api.ndarray.INDArray</span>
<span class="k">import</span> <span class="nn">org.nd4j.linalg.dataset.SplitTestAndTrain</span>
<span class="k">import</span> <span class="nn">org.nd4j.linalg.factory.Nd4j</span>
<span class="k">import</span> <span class="nn">org.nd4j.linalg.lossfunctions.LossFunctions</span>
<span class="k">import</span> <span class="nn">org.slf4j.LoggerFactory</span>
<span class="k">import</span> <span class="nn">scala.collection.JavaConverters._</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.datasets.iterator.MultipleEpochsIterator</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.datasets.iterator.impl.ListDataSetIterator</span>
<span class="k">object</span> <span class="nc">cnnEpochs</span> <span class="o">{</span>
<span class="k">def</span> <span class="n">trainModelEpochs</span><span class="o">(</span><span class="n">alignedData</span><span class="k">:</span> <span class="kt">alignedData</span><span class="o">,</span> <span class="n">bizClass</span><span class="k">:</span> <span class="kt">Int</span> <span class="o">=</span> <span class="mi">1</span><span class="o">,</span> <span class="n">saveNN</span><span class="k">:</span> <span class="kt">String</span> <span class="o">=</span> <span class="s">""</span><span class="o">)</span> <span class="k">=</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">ds</span> <span class="k">=</span> <span class="n">makeDataSet</span><span class="o">(</span><span class="n">alignedData</span><span class="o">,</span> <span class="n">bizClass</span><span class="o">)</span>
<span class="n">println</span><span class="o">(</span><span class="s">"commence training!!"</span><span class="o">)</span>
<span class="n">println</span><span class="o">(</span><span class="s">"class for training: "</span> <span class="o">+</span> <span class="n">bizClass</span><span class="o">)</span>
<span class="k">val</span> <span class="n">begintime</span> <span class="k">=</span> <span class="nc">System</span><span class="o">.</span><span class="n">currentTimeMillis</span><span class="o">()</span>
<span class="k">lazy</span> <span class="k">val</span> <span class="n">log</span> <span class="k">=</span> <span class="nc">LoggerFactory</span><span class="o">.</span><span class="n">getLogger</span><span class="o">(</span><span class="n">cnn</span><span class="o">.</span><span class="n">getClass</span><span class="o">)</span>
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="o">(</span><span class="s">"Begin time: "</span> <span class="o">+</span> <span class="n">java</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="nc">Calendar</span><span class="o">.</span><span class="n">getInstance</span><span class="o">().</span><span class="n">getTime</span><span class="o">())</span>
<span class="k">val</span> <span class="n">nfeatures</span> <span class="k">=</span> <span class="n">ds</span><span class="o">.</span><span class="n">getFeatures</span><span class="o">.</span><span class="n">getRow</span><span class="o">(</span><span class="mi">0</span><span class="o">).</span><span class="n">length</span> <span class="c1">// hyper, hyper parameter
</span>
<span class="k">val</span> <span class="n">numRows</span> <span class="k">=</span> <span class="nc">Math</span><span class="o">.</span><span class="n">sqrt</span><span class="o">(</span><span class="n">nfeatures</span><span class="o">).</span><span class="n">toInt</span> <span class="c1">// numRows * numColumns must equal columns in initial data * channels
</span> <span class="k">val</span> <span class="n">numColumns</span> <span class="k">=</span> <span class="nc">Math</span><span class="o">.</span><span class="n">sqrt</span><span class="o">(</span><span class="n">nfeatures</span><span class="o">).</span><span class="n">toInt</span> <span class="c1">// numRows * numColumns must equal columns in initial data * channels
</span> <span class="k">val</span> <span class="n">nChannels</span> <span class="k">=</span> <span class="mi">1</span> <span class="c1">// would be 3 if color image w R,G,B
</span> <span class="k">val</span> <span class="n">outputNum</span> <span class="k">=</span> <span class="mi">2</span> <span class="c1">// # of classes (# of columns in output)
</span> <span class="k">val</span> <span class="n">iterations</span> <span class="k">=</span> <span class="mi">1</span>
<span class="k">val</span> <span class="n">splitTrainNum</span> <span class="k">=</span> <span class="n">math</span><span class="o">.</span><span class="n">ceil</span><span class="o">(</span><span class="n">ds</span><span class="o">.</span><span class="n">numExamples</span><span class="o">*</span><span class="mf">0.8</span><span class="o">).</span><span class="n">toInt</span> <span class="c1">// 80/20 training/test split
</span> <span class="k">val</span> <span class="n">seed</span> <span class="k">=</span> <span class="mi">123</span>
<span class="k">val</span> <span class="n">listenerFreq</span> <span class="k">=</span> <span class="mi">1</span>
<span class="k">val</span> <span class="n">nepochs</span> <span class="k">=</span> <span class="mi">20</span>
<span class="k">val</span> <span class="n">nbatch</span> <span class="k">=</span> <span class="mi">128</span> <span class="c1">// recommended between 16 and 128
</span>
<span class="c1">//val nOutPar = 500 // default was 1000. # of output nodes in first layer
</span>
<span class="n">println</span><span class="o">(</span><span class="s">"rows: "</span> <span class="o">+</span> <span class="n">ds</span><span class="o">.</span><span class="n">getFeatures</span><span class="o">.</span><span class="n">size</span><span class="o">(</span><span class="mi">0</span><span class="o">))</span>
<span class="n">println</span><span class="o">(</span><span class="s">"columns: "</span> <span class="o">+</span> <span class="n">ds</span><span class="o">.</span><span class="n">getFeatures</span><span class="o">.</span><span class="n">size</span><span class="o">(</span><span class="mi">1</span><span class="o">))</span>
<span class="cm">/**
*Set a neural network configuration with multiple layers
*/</span>
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="o">(</span><span class="s">"Load data...."</span><span class="o">)</span>
<span class="n">ds</span><span class="o">.</span><span class="n">normalizeZeroMeanZeroUnitVariance</span><span class="o">()</span> <span class="c1">// this changes ds
</span> <span class="nc">System</span><span class="o">.</span><span class="n">out</span><span class="o">.</span><span class="n">println</span><span class="o">(</span><span class="s">"Loaded "</span> <span class="o">+</span> <span class="n">ds</span><span class="o">.</span><span class="n">labelCounts</span><span class="o">)</span>
<span class="nc">Nd4j</span><span class="o">.</span><span class="n">shuffle</span><span class="o">(</span><span class="n">ds</span><span class="o">.</span><span class="n">getFeatureMatrix</span><span class="o">,</span> <span class="k">new</span> <span class="nc">Random</span><span class="o">(</span><span class="n">seed</span><span class="o">),</span> <span class="mi">1</span><span class="o">)</span> <span class="c1">// this changes ds. Shuffles rows
</span> <span class="nc">Nd4j</span><span class="o">.</span><span class="n">shuffle</span><span class="o">(</span><span class="n">ds</span><span class="o">.</span><span class="n">getLabels</span><span class="o">,</span> <span class="k">new</span> <span class="nc">Random</span><span class="o">(</span><span class="n">seed</span><span class="o">),</span> <span class="mi">1</span><span class="o">)</span> <span class="c1">// this changes ds. Shuffles labels accordingly
</span> <span class="k">val</span> <span class="n">trainTest</span><span class="k">:</span> <span class="kt">SplitTestAndTrain</span> <span class="o">=</span> <span class="n">ds</span><span class="o">.</span><span class="n">splitTestAndTrain</span><span class="o">(</span><span class="n">splitTrainNum</span><span class="o">,</span> <span class="k">new</span> <span class="nc">Random</span><span class="o">(</span><span class="n">seed</span><span class="o">))</span> <span class="c1">// Random Seed not needed here
</span>
<span class="c1">// creating epoch dataset iterator
</span> <span class="k">val</span> <span class="n">dsiterTr</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">ListDataSetIterator</span><span class="o">(</span><span class="n">trainTest</span><span class="o">.</span><span class="n">getTrain</span><span class="o">.</span><span class="n">asList</span><span class="o">(),</span> <span class="n">nbatch</span><span class="o">)</span>
<span class="k">val</span> <span class="n">dsiterTe</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">ListDataSetIterator</span><span class="o">(</span><span class="n">trainTest</span><span class="o">.</span><span class="n">getTest</span><span class="o">.</span><span class="n">asList</span><span class="o">(),</span> <span class="n">nbatch</span><span class="o">)</span>
<span class="k">val</span> <span class="n">epochitTr</span><span class="k">:</span> <span class="kt">MultipleEpochsIterator</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MultipleEpochsIterator</span><span class="o">(</span><span class="n">nepochs</span><span class="o">,</span> <span class="n">dsiterTr</span><span class="o">)</span>
<span class="k">val</span> <span class="n">epochitTe</span><span class="k">:</span> <span class="kt">MultipleEpochsIterator</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MultipleEpochsIterator</span><span class="o">(</span><span class="n">nepochs</span><span class="o">,</span> <span class="n">dsiterTe</span><span class="o">)</span>
<span class="k">val</span> <span class="n">builder</span><span class="k">:</span> <span class="kt">MultiLayerConfiguration.Builder</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">NeuralNetConfiguration</span><span class="o">.</span><span class="nc">Builder</span><span class="o">()</span>
<span class="o">.</span><span class="n">seed</span><span class="o">(</span><span class="n">seed</span><span class="o">)</span>
<span class="o">.</span><span class="n">iterations</span><span class="o">(</span><span class="n">iterations</span><span class="o">)</span>
<span class="o">.</span><span class="n">miniBatch</span><span class="o">(</span><span class="kc">true</span><span class="o">)</span>
<span class="o">.</span><span class="n">optimizationAlgo</span><span class="o">(</span><span class="nc">OptimizationAlgorithm</span><span class="o">.</span><span class="nc">STOCHASTIC_GRADIENT_DESCENT</span><span class="o">)</span>
<span class="o">.</span><span class="n">learningRate</span><span class="o">(</span><span class="mf">0.01</span><span class="o">)</span>
<span class="o">.</span><span class="n">momentum</span><span class="o">(</span><span class="mf">0.9</span><span class="o">)</span>
<span class="o">.</span><span class="n">list</span><span class="o">(</span><span class="mi">4</span><span class="o">)</span>
<span class="o">.</span><span class="n">layer</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="k">new</span> <span class="nc">ConvolutionLayer</span><span class="o">.</span><span class="nc">Builder</span><span class="o">(</span><span class="mi">6</span><span class="o">,</span><span class="mi">6</span><span class="o">)</span>
<span class="o">.</span><span class="n">nIn</span><span class="o">(</span><span class="n">nChannels</span><span class="o">)</span>
<span class="o">.</span><span class="n">stride</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="mi">2</span><span class="o">)</span> <span class="c1">// default stride(2,2)
</span> <span class="o">.</span><span class="n">nOut</span><span class="o">(</span><span class="mi">20</span><span class="o">)</span> <span class="c1">// # of feature maps
</span> <span class="o">.</span><span class="n">dropOut</span><span class="o">(</span><span class="mf">0.5</span><span class="o">)</span>
<span class="o">.</span><span class="n">activation</span><span class="o">(</span><span class="s">"relu"</span><span class="o">)</span> <span class="c1">// rectified linear units
</span> <span class="o">.</span><span class="n">weightInit</span><span class="o">(</span><span class="nc">WeightInit</span><span class="o">.</span><span class="nc">RELU</span><span class="o">)</span>
<span class="o">.</span><span class="n">build</span><span class="o">())</span>
<span class="o">.</span><span class="n">layer</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="k">new</span> <span class="nc">SubsamplingLayer</span><span class="o">.</span><span class="nc">Builder</span><span class="o">(</span><span class="nc">SubsamplingLayer</span><span class="o">.</span><span class="nc">PoolingType</span><span class="o">.</span><span class="nc">MAX</span><span class="o">,</span> <span class="nc">Array</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span><span class="mi">2</span><span class="o">))</span>
<span class="o">.</span><span class="n">build</span><span class="o">())</span>
<span class="o">.</span><span class="n">layer</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="k">new</span> <span class="nc">DenseLayer</span><span class="o">.</span><span class="nc">Builder</span><span class="o">()</span>
<span class="o">.</span><span class="n">nOut</span><span class="o">(</span><span class="mi">40</span><span class="o">)</span>
<span class="o">.</span><span class="n">activation</span><span class="o">(</span><span class="s">"relu"</span><span class="o">)</span>
<span class="o">.</span><span class="n">build</span><span class="o">())</span>
<span class="o">.</span><span class="n">layer</span><span class="o">(</span><span class="mi">3</span><span class="o">,</span> <span class="k">new</span> <span class="nc">OutputLayer</span><span class="o">.</span><span class="nc">Builder</span><span class="o">(</span><span class="nc">LossFunctions</span><span class="o">.</span><span class="nc">LossFunction</span><span class="o">.</span><span class="nc">MCXENT</span><span class="o">)</span>
<span class="o">.</span><span class="n">nOut</span><span class="o">(</span><span class="n">outputNum</span><span class="o">)</span>
<span class="o">.</span><span class="n">weightInit</span><span class="o">(</span><span class="nc">WeightInit</span><span class="o">.</span><span class="nc">XAVIER</span><span class="o">)</span>
<span class="o">.</span><span class="n">activation</span><span class="o">(</span><span class="s">"softmax"</span><span class="o">)</span>
<span class="o">.</span><span class="n">build</span><span class="o">())</span>
<span class="o">.</span><span class="n">backprop</span><span class="o">(</span><span class="kc">true</span><span class="o">).</span><span class="n">pretrain</span><span class="o">(</span><span class="kc">false</span><span class="o">)</span>
<span class="k">new</span> <span class="nc">ConvolutionLayerSetup</span><span class="o">(</span><span class="n">builder</span><span class="o">,</span> <span class="n">numRows</span><span class="o">,</span> <span class="n">numColumns</span><span class="o">,</span> <span class="n">nChannels</span><span class="o">)</span>
<span class="k">val</span> <span class="n">conf</span><span class="k">:</span> <span class="kt">MultiLayerConfiguration</span> <span class="o">=</span> <span class="n">builder</span><span class="o">.</span><span class="n">build</span><span class="o">()</span>
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="o">(</span><span class="s">"Build model...."</span><span class="o">)</span>
<span class="k">val</span> <span class="n">model</span><span class="k">:</span> <span class="kt">MultiLayerNetwork</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MultiLayerNetwork</span><span class="o">(</span><span class="n">conf</span><span class="o">)</span>
<span class="n">model</span><span class="o">.</span><span class="n">init</span><span class="o">()</span>
<span class="n">model</span><span class="o">.</span><span class="n">setListeners</span><span class="o">(</span><span class="nc">Seq</span><span class="o">[</span><span class="kt">IterationListener</span><span class="o">](</span><span class="k">new</span> <span class="nc">ScoreIterationListener</span><span class="o">(</span><span class="n">listenerFreq</span><span class="o">)).</span><span class="n">asJava</span><span class="o">)</span>
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="o">(</span><span class="s">"Train model...."</span><span class="o">)</span>
<span class="nc">System</span><span class="o">.</span><span class="n">out</span><span class="o">.</span><span class="n">println</span><span class="o">(</span><span class="s">"Training on "</span> <span class="o">+</span> <span class="n">dsiterTr</span><span class="o">.</span><span class="n">getLabels</span><span class="o">)</span> <span class="c1">// this might return null
</span> <span class="n">model</span><span class="o">.</span><span class="n">fit</span><span class="o">(</span><span class="n">epochitTr</span><span class="o">)</span>
<span class="c1">// TRAINING
</span> <span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="o">(</span><span class="s">"Evaluate model...."</span><span class="o">)</span>
<span class="nc">System</span><span class="o">.</span><span class="n">out</span><span class="o">.</span><span class="n">println</span><span class="o">(</span><span class="s">"Testing on ..."</span><span class="o">)</span>
<span class="k">val</span> <span class="n">eval</span> <span class="k">=</span> <span class="k">new</span> <span class="nc">Evaluation</span><span class="o">(</span><span class="n">outputNum</span><span class="o">)</span>
<span class="k">while</span><span class="o">(</span><span class="n">epochitTe</span><span class="o">.</span><span class="n">hasNext</span><span class="o">)</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">testDS</span> <span class="k">=</span> <span class="n">epochitTe</span><span class="o">.</span><span class="n">next</span><span class="o">(</span><span class="n">nbatch</span><span class="o">)</span>
<span class="k">val</span> <span class="n">output</span><span class="k">:</span> <span class="kt">INDArray</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">output</span><span class="o">(</span><span class="n">testDS</span><span class="o">.</span><span class="n">getFeatureMatrix</span><span class="o">)</span>
<span class="n">eval</span><span class="o">.</span><span class="n">eval</span><span class="o">(</span><span class="n">testDS</span><span class="o">.</span><span class="n">getLabels</span><span class="o">(),</span> <span class="n">output</span><span class="o">)</span>
<span class="o">}</span>
<span class="nc">System</span><span class="o">.</span><span class="n">out</span><span class="o">.</span><span class="n">println</span><span class="o">(</span><span class="n">eval</span><span class="o">.</span><span class="n">stats</span><span class="o">())</span>
<span class="k">val</span> <span class="n">endtime</span> <span class="k">=</span> <span class="nc">System</span><span class="o">.</span><span class="n">currentTimeMillis</span><span class="o">()</span>
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="o">(</span><span class="s">"End time: "</span> <span class="o">+</span> <span class="n">java</span><span class="o">.</span><span class="n">util</span><span class="o">.</span><span class="nc">Calendar</span><span class="o">.</span><span class="n">getInstance</span><span class="o">().</span><span class="n">getTime</span><span class="o">())</span>
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="o">(</span><span class="s">"computation time: "</span> <span class="o">+</span> <span class="o">(</span><span class="n">endtime</span><span class="o">-</span><span class="n">begintime</span><span class="o">)/</span><span class="mf">1000.0</span> <span class="o">+</span> <span class="s">" seconds"</span><span class="o">)</span>
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="o">(</span><span class="s">"Write results...."</span><span class="o">)</span>
<span class="k">if</span><span class="o">(!</span><span class="n">saveNN</span><span class="o">.</span><span class="n">isEmpty</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// model config
</span> <span class="nc">FileUtils</span><span class="o">.</span><span class="n">write</span><span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="n">saveNN</span> <span class="o">+</span> <span class="s">".json"</span><span class="o">),</span> <span class="n">model</span><span class="o">.</span><span class="n">getLayerWiseConfigurations</span><span class="o">().</span><span class="n">toJson</span><span class="o">())</span>
<span class="c1">// model parameters
</span> <span class="k">val</span> <span class="n">dos</span><span class="k">:</span> <span class="kt">DataOutputStream</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">DataOutputStream</span><span class="o">(</span><span class="nc">Files</span><span class="o">.</span><span class="n">newOutputStream</span><span class="o">(</span><span class="nc">Paths</span><span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="n">saveNN</span> <span class="o">+</span> <span class="s">".bin"</span><span class="o">)))</span>
<span class="nc">Nd4j</span><span class="o">.</span><span class="n">write</span><span class="o">(</span><span class="n">model</span><span class="o">.</span><span class="n">params</span><span class="o">(),</span> <span class="n">dos</span><span class="o">)</span>
<span class="o">}</span>
<span class="n">log</span><span class="o">.</span><span class="n">info</span><span class="o">(</span><span class="s">"****************Example finished********************"</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<h3 id="saveload-networks">Save/load networks</h3>
<p>This is definitely something you’ll want to do. These things take too long to train to not save immediately.</p>
<p><code class="highlighter-rouge">saveNN</code> is pretty straightforward. It saves a .json file with the network configuration and a .bin with all the weights and parameters of the network you just trained.</p>
<p><code class="highlighter-rouge">loadNN</code> just reads back the .json and .bin file you created with <code class="highlighter-rouge">saveNN</code> to a <code class="highlighter-rouge">MultiLayerNetwork</code> object that you can use to score new test data.</p>
<p>Code below: <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/io/nn.scala">nn.scala</a></p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">package</span> <span class="nn">modeling.io</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.nn.conf.</span><span class="o">{</span><span class="nc">GradientNormalization</span><span class="o">,</span> <span class="nc">MultiLayerConfiguration</span><span class="o">,</span> <span class="nc">NeuralNetConfiguration</span><span class="o">}</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.nn.multilayer.MultiLayerNetwork</span>
<span class="k">import</span> <span class="nn">org.nd4j.linalg.factory.Nd4j</span>
<span class="k">import</span> <span class="nn">java.io.File</span>
<span class="k">import</span> <span class="nn">org.apache.commons.io.FileUtils</span>
<span class="k">import</span> <span class="nn">java.io.</span><span class="o">{</span><span class="nc">DataInputStream</span><span class="o">,</span> <span class="nc">DataOutputStream</span><span class="o">,</span> <span class="nc">FileInputStream</span><span class="o">}</span>
<span class="k">import</span> <span class="nn">java.nio.file.</span><span class="o">{</span><span class="nc">Files</span><span class="o">,</span> <span class="nc">Paths</span><span class="o">}</span>
<span class="k">object</span> <span class="nc">nn</span> <span class="o">{</span>
<span class="k">def</span> <span class="n">loadNN</span><span class="o">(</span><span class="nc">NNconfig</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="nc">NNparams</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="o">{</span>
<span class="c1">// get neural network config
</span> <span class="k">val</span> <span class="n">confFromJson</span><span class="k">:</span> <span class="kt">MultiLayerConfiguration</span> <span class="o">=</span> <span class="nc">MultiLayerConfiguration</span><span class="o">.</span><span class="n">fromJson</span><span class="o">(</span><span class="nc">FileUtils</span><span class="o">.</span><span class="n">readFileToString</span><span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="nc">NNconfig</span><span class="o">)))</span>
<span class="c1">// get neural network parameters
</span> <span class="k">val</span> <span class="n">dis</span><span class="k">:</span> <span class="kt">DataInputStream</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">DataInputStream</span><span class="o">(</span><span class="k">new</span> <span class="nc">FileInputStream</span><span class="o">(</span><span class="nc">NNparams</span><span class="o">))</span>
<span class="k">val</span> <span class="n">newParams</span> <span class="k">=</span> <span class="nc">Nd4j</span><span class="o">.</span><span class="n">read</span><span class="o">(</span><span class="n">dis</span><span class="o">)</span>
<span class="c1">// creating network object
</span> <span class="k">val</span> <span class="n">savedNetwork</span><span class="k">:</span> <span class="kt">MultiLayerNetwork</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">MultiLayerNetwork</span><span class="o">(</span><span class="n">confFromJson</span><span class="o">)</span>
<span class="n">savedNetwork</span><span class="o">.</span><span class="n">init</span><span class="o">()</span>
<span class="n">savedNetwork</span><span class="o">.</span><span class="n">setParameters</span><span class="o">(</span><span class="n">newParams</span><span class="o">)</span>
<span class="n">savedNetwork</span>
<span class="o">}</span>
<span class="k">def</span> <span class="n">saveNN</span><span class="o">(</span><span class="n">model</span><span class="k">:</span> <span class="kt">MultiLayerNetwork</span><span class="o">,</span> <span class="nc">NNconfig</span><span class="k">:</span> <span class="kt">String</span><span class="o">,</span> <span class="nc">NNparams</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span> <span class="k">=</span> <span class="o">{</span>
<span class="c1">// save neural network config
</span> <span class="nc">FileUtils</span><span class="o">.</span><span class="n">write</span><span class="o">(</span><span class="k">new</span> <span class="nc">File</span><span class="o">(</span><span class="nc">NNconfig</span><span class="o">),</span> <span class="n">model</span><span class="o">.</span><span class="n">getLayerWiseConfigurations</span><span class="o">().</span><span class="n">toJson</span><span class="o">())</span>
<span class="c1">// save neural network parms
</span> <span class="k">val</span> <span class="n">dos</span><span class="k">:</span> <span class="kt">DataOutputStream</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">DataOutputStream</span><span class="o">(</span><span class="nc">Files</span><span class="o">.</span><span class="n">newOutputStream</span><span class="o">(</span><span class="nc">Paths</span><span class="o">.</span><span class="n">get</span><span class="o">(</span><span class="nc">NNparams</span><span class="o">)))</span>
<span class="nc">Nd4j</span><span class="o">.</span><span class="n">write</span><span class="o">(</span><span class="n">model</span><span class="o">.</span><span class="n">params</span><span class="o">(),</span> <span class="n">dos</span><span class="o">)</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<h3 id="scoring">Scoring</h3>
<p>I won’t say much here, since I didn’t end up putting much emphasis on this step for reasons explained at the beginning of this post.</p>
<p>My scoring approach assigns business-level labels by averaging the image-level predictions. I classify a business as label “0” if the average of the probabilities across all of its images belonging class “0” is greater than 0.5.</p>
<p>Code below: <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/processing/scoring.scala">scoring.scala</a></p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">package</span> <span class="nn">modeling.processing</span>
<span class="k">import</span> <span class="nn">org.nd4j.linalg.api.ndarray.INDArray</span>
<span class="k">import</span> <span class="nn">org.deeplearning4j.nn.multilayer.MultiLayerNetwork</span>
<span class="k">object</span> <span class="nc">scoring</span> <span class="o">{</span>
<span class="k">def</span> <span class="n">scoreModel</span><span class="o">(</span><span class="n">model</span><span class="k">:</span> <span class="kt">MultiLayerNetwork</span><span class="o">,</span> <span class="n">ds</span><span class="k">:</span> <span class="kt">INDArray</span><span class="o">)</span> <span class="k">=</span> <span class="o">{</span>
<span class="n">model</span><span class="o">.</span><span class="n">output</span><span class="o">(</span><span class="n">ds</span><span class="o">)</span>
<span class="o">}</span>
<span class="cm">/** Take model predictions from scoreModel and merge with alignedData*/</span>
<span class="k">def</span> <span class="n">aggImgScores2Biz</span><span class="o">(</span><span class="n">scores</span><span class="k">:</span> <span class="kt">INDArray</span><span class="o">,</span> <span class="n">alignedData</span><span class="k">:</span> <span class="kt">alignedData</span> <span class="o">)</span> <span class="k">=</span> <span class="o">{</span>
<span class="n">assert</span><span class="o">(</span><span class="n">scores</span><span class="o">.</span><span class="n">size</span><span class="o">(</span><span class="mi">0</span><span class="o">)</span> <span class="o">==</span> <span class="n">alignedData</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">length</span><span class="o">,</span> <span class="s">"alignedData and scores length are different. They must be equal"</span><span class="o">)</span>
<span class="k">def</span> <span class="n">getRowIndices4Biz</span><span class="o">(</span><span class="n">mylist</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">String</span><span class="o">],</span> <span class="n">mybiz</span><span class="k">:</span> <span class="kt">String</span><span class="o">)</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Int</span><span class="o">]</span> <span class="k">=</span> <span class="n">mylist</span><span class="o">.</span><span class="n">zipWithIndex</span><span class="o">.</span><span class="n">filter</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span> <span class="n">x</span><span class="o">.</span><span class="n">_1</span> <span class="o">==</span> <span class="n">mybiz</span><span class="o">).</span><span class="n">map</span><span class="o">(</span><span class="k">_</span><span class="o">.</span><span class="n">_2</span><span class="o">)</span>
<span class="k">def</span> <span class="n">mean</span><span class="o">(</span><span class="n">xs</span><span class="k">:</span> <span class="kt">List</span><span class="o">[</span><span class="kt">Double</span><span class="o">])</span> <span class="k">=</span> <span class="n">xs</span><span class="o">.</span><span class="n">sum</span> <span class="o">/</span> <span class="n">xs</span><span class="o">.</span><span class="n">size</span>
<span class="n">alignedData</span><span class="o">.</span><span class="n">getBizIds</span><span class="o">.</span><span class="n">distinct</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="n">x</span> <span class="k">=></span> <span class="o">(</span><span class="n">x</span><span class="o">,</span> <span class="o">{</span>
<span class="k">val</span> <span class="n">irows</span> <span class="k">=</span> <span class="n">getRowIndices4Biz</span><span class="o">(</span><span class="n">alignedData</span><span class="o">.</span><span class="n">getBizIds</span><span class="o">,</span> <span class="n">x</span><span class="o">)</span>
<span class="k">val</span> <span class="n">ret</span> <span class="k">=</span> <span class="k">for</span><span class="o">(</span><span class="n">row</span> <span class="k"><-</span> <span class="n">irows</span><span class="o">)</span> <span class="k">yield</span> <span class="n">scores</span><span class="o">.</span><span class="n">getRow</span><span class="o">(</span><span class="n">row</span><span class="o">).</span><span class="n">getColumn</span><span class="o">(</span><span class="mi">1</span><span class="o">).</span><span class="n">toString</span><span class="o">.</span><span class="n">toDouble</span>
<span class="n">mean</span><span class="o">(</span><span class="n">ret</span><span class="o">)</span>
<span class="o">}))</span>
<span class="o">}</span>
<span class="o">}</span></code></pre></figure>
<h3 id="submit-to-kaggle">Submit to Kaggle</h3>
<p>Also not much to say here, but <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/processing/kaggleSubmission.scala">this</a> is how I aggregated image predictions to business scores for each model. And <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/io/kaggleSubmission.scala">this</a> is the code to generate the output CSV for Kaggle.</p>
<h3 id="run-1">Run</h3>
<p>The whole project can be run from <a href="https://github.com/brooksandrew/kaggle_yelp/blob/master/src/main/scala/modeling/main.scala">main.scala</a>. Here it is:</p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="k">package</span> <span class="nn">modeling</span>
<span class="k">import</span> <span class="nn">io.nn._</span>
<span class="k">import</span> <span class="nn">io.kaggleSubmission._</span>
<span class="k">import</span> <span class="nn">io.readCsvData._</span>
<span class="k">import</span> <span class="nn">processing.alignedData</span>
<span class="k">import</span> <span class="nn">processing.images._</span>
<span class="k">import</span> <span class="nn">processing.kaggleSubmission._</span>
<span class="k">import</span> <span class="nn">processing.makeDataSets._</span>
<span class="k">import</span> <span class="nn">processing.scoring._</span>
<span class="k">import</span> <span class="nn">training.cnn._</span>
<span class="k">import</span> <span class="nn">training.cnnEpochs._</span>
<span class="k">object</span> <span class="nc">runPipeline</span> <span class="o">{</span>
<span class="k">def</span> <span class="n">main</span><span class="o">(</span><span class="n">args</span><span class="k">:</span> <span class="kt">Array</span><span class="o">[</span><span class="kt">String</span><span class="o">])</span><span class="k">:</span> <span class="kt">Unit</span> <span class="o">=</span> <span class="o">{</span>
<span class="c1">// image processing on training data
</span> <span class="k">val</span> <span class="n">labMap</span> <span class="k">=</span> <span class="n">readBizLabels</span><span class="o">(</span><span class="s">"data/labels/train.csv"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">bizMap</span> <span class="k">=</span> <span class="n">readBiz2ImgLabels</span><span class="o">(</span><span class="s">"data/labels/train_photo_to_biz_ids.csv"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">imgs</span> <span class="k">=</span> <span class="n">getImageIds</span><span class="o">(</span><span class="s">"data/images/train"</span><span class="o">,</span> <span class="n">bizMap</span><span class="o">,</span> <span class="n">bizMap</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="k">_</span><span class="o">.</span><span class="n">_2</span><span class="o">).</span><span class="n">toSet</span><span class="o">.</span><span class="n">toList</span><span class="o">).</span><span class="n">slice</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span><span class="mi">20000</span><span class="o">)</span> <span class="c1">// 20000 images
</span> <span class="k">val</span> <span class="n">dataMap</span> <span class="k">=</span> <span class="n">processImages</span><span class="o">(</span><span class="n">imgs</span><span class="o">,</span> <span class="n">resizeImgDim</span> <span class="k">=</span> <span class="mi">128</span><span class="o">)</span>
<span class="k">val</span> <span class="n">alignedData</span> <span class="k">=</span> <span class="k">new</span> <span class="n">alignedData</span><span class="o">(</span><span class="n">dataMap</span><span class="o">,</span> <span class="n">bizMap</span><span class="o">,</span> <span class="nc">Option</span><span class="o">(</span><span class="n">labMap</span><span class="o">))()</span>
<span class="c1">// training (one model/class at a time). Many microparameters hardcoded within
</span> <span class="k">val</span> <span class="n">cnn0</span> <span class="k">=</span> <span class="n">trainModelEpochs</span><span class="o">(</span><span class="n">alignedData</span><span class="o">,</span> <span class="n">bizClass</span> <span class="k">=</span> <span class="mi">0</span><span class="o">,</span> <span class="n">saveNN</span> <span class="k">=</span> <span class="s">"results/modelsV0/model0"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">cnn1</span> <span class="k">=</span> <span class="n">trainModelEpochs</span><span class="o">(</span><span class="n">alignedData</span><span class="o">,</span> <span class="n">bizClass</span> <span class="k">=</span> <span class="mi">1</span><span class="o">,</span> <span class="n">saveNN</span> <span class="k">=</span> <span class="s">"results/modelsV0/model1"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">cnn2</span> <span class="k">=</span> <span class="n">trainModelEpochs</span><span class="o">(</span><span class="n">alignedData</span><span class="o">,</span> <span class="n">bizClass</span> <span class="k">=</span> <span class="mi">2</span><span class="o">,</span> <span class="n">saveNN</span> <span class="k">=</span> <span class="s">"results/modelsV0/model2"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">cnn3</span> <span class="k">=</span> <span class="n">trainModelEpochs</span><span class="o">(</span><span class="n">alignedData</span><span class="o">,</span> <span class="n">bizClass</span> <span class="k">=</span> <span class="mi">3</span><span class="o">,</span> <span class="n">saveNN</span> <span class="k">=</span> <span class="s">"results/modelsV0/model3"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">cnn4</span> <span class="k">=</span> <span class="n">trainModelEpochs</span><span class="o">(</span><span class="n">alignedData</span><span class="o">,</span> <span class="n">bizClass</span> <span class="k">=</span> <span class="mi">4</span><span class="o">,</span> <span class="n">saveNN</span> <span class="k">=</span> <span class="s">"results/modelsV0/model4"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">cnn5</span> <span class="k">=</span> <span class="n">trainModelEpochs</span><span class="o">(</span><span class="n">alignedData</span><span class="o">,</span> <span class="n">bizClass</span> <span class="k">=</span> <span class="mi">5</span><span class="o">,</span> <span class="n">saveNN</span> <span class="k">=</span> <span class="s">"results/modelsV0/model5"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">cnn6</span> <span class="k">=</span> <span class="n">trainModelEpochs</span><span class="o">(</span><span class="n">alignedData</span><span class="o">,</span> <span class="n">bizClass</span> <span class="k">=</span> <span class="mi">6</span><span class="o">,</span> <span class="n">saveNN</span> <span class="k">=</span> <span class="s">"results/modelsV0/model6"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">cnn7</span> <span class="k">=</span> <span class="n">trainModelEpochs</span><span class="o">(</span><span class="n">alignedData</span><span class="o">,</span> <span class="n">bizClass</span> <span class="k">=</span> <span class="mi">7</span><span class="o">,</span> <span class="n">saveNN</span> <span class="k">=</span> <span class="s">"results/modelsV0/model7"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">cnn8</span> <span class="k">=</span> <span class="n">trainModelEpochs</span><span class="o">(</span><span class="n">alignedData</span><span class="o">,</span> <span class="n">bizClass</span> <span class="k">=</span> <span class="mi">8</span><span class="o">,</span> <span class="n">saveNN</span> <span class="k">=</span> <span class="s">"results/modelsV0/model8"</span><span class="o">)</span>
<span class="c1">// processing test data for scoring
</span> <span class="k">val</span> <span class="n">bizMapTE</span> <span class="k">=</span> <span class="n">readBiz2ImgLabels</span><span class="o">(</span><span class="s">"data/labels/test_photo_to_biz.csv"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">imgsTE</span> <span class="k">=</span> <span class="n">getImageIds</span><span class="o">(</span><span class="s">"data/images/test/"</span><span class="o">,</span> <span class="n">bizMapTE</span><span class="o">,</span> <span class="n">bizMapTE</span><span class="o">.</span><span class="n">map</span><span class="o">(</span><span class="k">_</span><span class="o">.</span><span class="n">_2</span><span class="o">).</span><span class="n">toSet</span><span class="o">.</span><span class="n">toList</span><span class="o">)</span>
<span class="k">val</span> <span class="n">dataMapTE</span> <span class="k">=</span> <span class="n">processImages</span><span class="o">(</span><span class="n">imgsTE</span><span class="o">,</span> <span class="n">resizeImgDim</span> <span class="k">=</span> <span class="mi">128</span><span class="o">)</span>
<span class="k">val</span> <span class="n">alignedDataTE</span> <span class="k">=</span> <span class="k">new</span> <span class="n">alignedData</span><span class="o">(</span><span class="n">dataMapTE</span><span class="o">,</span> <span class="n">bizMapTE</span><span class="o">,</span> <span class="nc">None</span><span class="o">)()</span>
<span class="c1">// creating csv file to submit to kaggle (scores all models)
</span> <span class="k">val</span> <span class="n">kaggleResults</span> <span class="k">=</span> <span class="n">createKaggleSubmitObj</span><span class="o">(</span><span class="n">alignedDataTE</span><span class="o">,</span> <span class="s">"results/ModelsV0/"</span><span class="o">)</span>
<span class="k">val</span> <span class="n">kaggleSubmitResults</span> <span class="k">=</span> <span class="n">writeKaggleSubmissionFile</span><span class="o">(</span><span class="s">"results/kaggleSubmission/kaggleSubmitFile.csv"</span><span class="o">,</span> <span class="n">kaggleResults</span><span class="o">,</span> <span class="n">thresh</span> <span class="k">=</span> <span class="mf">0.5</span><span class="o">)</span></code></pre></figure>
<h1 id="thoughts">Thoughts</h1>
<p>This was my first foray into deep neural networks. I haven’t used <a href="http://deeplearning.net/software/theano/">theano</a> or any of the other widely used implementations out there, so I unfortunately don’t have much to compare my experience to.</p>
<p>I will say that the current documentation will only take you so far. I spent a lot of time reading <a href="http://neuralnetworksanddeeplearning.com/index.html">Neural Networks and Deep Learning</a> to understand the concepts and reviewing the DL4J source code to try and figure out how to implement what I thought I wanted to do.</p>
<p>Discovering the <a href="https://gitter.im/deeplearning4j/deeplearning4j">DL4J Gitter</a> was the single most useful moment I had. The creators are actively answering all sorts of questions in real-time. There’s also a room for earlyadopters discussing testing and feature requests which was interesting to browse. Very impressed with the commitment and willingness to help. I even got an email from someone on the DL4J team after I pushed this project to GitHub offering to help and pointing me to the CNN specialists.</p>
<p>Gitter is where the action is. There’s way more here than on StackOverflow. However, the content doesn’t appear to be indexed nearly as well on Google, so found myself “Googling” in the Gitter search bar for keywords and perusing through conversations to get answers.</p>
<p>I recommend using the <a href="http://deeplearning4j.org/visualization">deeplearning4j-ui</a> tool if you can. I unfortunately wasn’t able to get it working, but it looks super useful for understanding how your net training is going.</p>
<p>Other awesome resources I found for visualizing training for CNNs are <a href="http://cs.stanford.edu/people/karpathy/convnetjs/">ConvNetJS</a> and <a href="http://scs.ryerson.ca/~aharley/vis/conv/">this one</a>.</p>
<!-- Links -->
<!-- Links to GitHub-->
<p><a href="http://brooksandrew.github.io/simpleblog/articles/convolutional-neural-network-training-with-dl4j/">Exploring convolutional neural networks with DL4J</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on April 14, 2016.</p>http://brooksandrew.github.io/simpleblog/articles/managing-managed-dependencies-with-scala-and-eclipse2015-12-29T00:00:00+00:002015-12-29T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<h3 id="my-story-skip-for-the-real-answer">My story [skip for the real answer]</h3>
<p>I have become increasingly intrigued with the functional programming paradigm and its implementation in Scala. I’m thoroughly enjoying working my way through Scala creator <a href="https://www.coursera.org/course/progfun">Martin Odersky’s coursera course</a> which I highly recommend to anyone from “timid and interested” to “hardcore.” As a data scientist with a statistics and economics background, I code every day in languages like R and Python wrangling data, implementing machine learning algorithms, tapping APIs and building data tools for data scientists. However, I don’t build [professional-grade] software. Ive never taken a formal computer science course in college/grad school or learned Java. Admittedly, I’ve felt overwhelmed at times by so many new concepts and tools with the course. I’m simultaneously figuring out Scala, Java, sbt, eclipse, functional and object oriented paradigms.</p>
<p>As a learner poking my head in the field, I find it refreshing reading stories from fellow newcomers battling similar problems, even if they appear trivial in hindsight. I also find it most effective teaching material when you still remember how you learned it. Thus, this post and [likely, yet currently unwritten] subsequent Scala posts will be experimental learning notes rather than wisdom and tested best practices.</p>
<h3 id="managed-vs-unmanaged-dependencies">Managed vs Unmanaged dependencies</h3>
<p>One of the stumbling blocks I encountered on my first Scala project was a simple one: working with external libraries with sbt and Eclipse. I started using unmanaged dependencies (downloading some jar files and pointing Eclipse to them) which worked well, until I encountered a library which had further dependencies – I was working with <a href="https://github.com/json4s/json4s">json4s</a>. More on <a href="http://www.scala-sbt.org/0.13/tutorial/Library-Dependencies.html">unmanaged vs managed dependencies here</a>. Managed dependencies have the advantage of being, well, managed. You simply specify a library with a version and <a href="https://ant.apache.org/ivy/">Ivy</a> (a tool similar to Maven) will go out on the web and download it along with any dependencies.</p>
<p>My issue was I initially couldn’t get Eclipse to actually go out and download my dependencies. As evidenced by <a href="http://stackoverflow.com/questions/9070336/how-to-have-eclipse-recognize-dependencies-from-sbt">this StackOverflow post</a>, there are probably many ways to achieve this. The piece I was missing was using sbt in the Terminal while Eclipse was running to actually download the libraries.</p>
<h3 id="make-eclipse-recognize-managed-dependencies">Make Eclipse recognize managed dependencies</h3>
<p>Here’s a step-by-step process</p>
<h5 id="step-1-create-a-buildsbt-file">Step 1: Create a build.sbt file</h5>
<p>Create <strong>build.sbt</strong> in the root project directory. For example, my <strong>build.sbt</strong> looks like this:</p>
<figure class="highlight"><pre><code class="language-scala" data-lang="scala"><span class="n">name</span> <span class="o">:=</span> <span class="s">"billscraper"</span>
<span class="n">scalaVersion</span> <span class="o">:=</span> <span class="s">"2.11.5"</span>
<span class="n">libraryDependencies</span> <span class="o">++=</span> <span class="nc">Seq</span><span class="o">(</span>
<span class="s">"org.json4s"</span> <span class="o">%%</span> <span class="s">"json4s-native"</span> <span class="o">%</span> <span class="s">"3.2.11"</span><span class="o">,</span>
<span class="s">"org.json4s"</span> <span class="o">%%</span> <span class="s">"json4s"</span> <span class="o">%</span> <span class="s">"3.2.11"</span><span class="o">,</span>
<span class="s">"io.spray"</span> <span class="o">%%</span> <span class="s">"spray-json"</span> <span class="o">%</span> <span class="s">"1.3.2"</span><span class="o">,</span>
<span class="s">"org.scalanlp"</span> <span class="o">%%</span> <span class="s">"breeze"</span> <span class="o">%</span> <span class="s">"0.11.2"</span>
<span class="o">)</span></code></pre></figure>
<h5 id="step-2-open-the-terminal">Step 2: Open the Terminal</h5>
<p>Assuming you’re on mac, type the following in the Terminal:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="o">></span> sbt
<span class="o">></span> eclipse</code></pre></figure>
<p>You should see a bunch of jar files downloading… something like this:</p>
<p><a data-flickr-embed="true" href="https://farm2.staticflickr.com/1535/24025973066_8bcbcbdda5.jpg" title="downloading dependencies in sbt"><img src="https://farm2.staticflickr.com/1535/24025973066_8bcbcbdda5.jpg" width="467" height="318" alt="Screen Shot 2015-12-29 at 4.31.14 PM" /></a></p>
<h5 id="step-3-refresh-project-in-eclipse">Step 3: Refresh project in Eclipse</h5>
<p>Now in Eclipse refresh your project by clicking F5, or right click on the project in the Package Explorer tab and click “Refresh”</p>
<h5 id="step-4-check-that-it-worked">Step 4: Check that it worked</h5>
<p>Now to check that libraries have downloaded and Eclipse has recognized them.</p>
<p>In Eclipse, right click on the project in the Package Explorer tab<br />
=> click “Build Path”<br />
=> click “Configure Build Path”<br />
=> click “Libraries” (icon with a stack of books)</p>
<p>Here you should see the libraries from build.sbt and all their dependencies. Now you should be good to go – import what you need from these libraries in your Scala code.</p>
<p><a data-flickr-embed="true" href="https://farm2.staticflickr.com/1689/23944025972_bcf7686627_b.jpg" title="downloading libraries with sbt"><img src="https://farm2.staticflickr.com/1689/23944025972_bcf7686627_b.jpg" width="1024" height="498" alt="Screen Shot 2015-12-29 at 4.38.29 PM" /></a></p>
<h3 id="my-environment">My environment</h3>
<p>I configured my environment as recommended by the <a href="https://www.coursera.org/course/progfun">Functional Programming Principles in Scala course</a>:</p>
<ul>
<li>Mac - OSX Yosemite 10.10</li>
<li>Scala IDE build of Eclipse SDK 4.2.0</li>
<li>sbt 0.13.9</li>
</ul>
<!-- Links -->
<p><a href="http://brooksandrew.github.io/simpleblog/articles/managing-managed-dependencies-with-scala-and-eclipse/">Managing managed libraries with Scala and Eclipse</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on December 29, 2015.</p>http://brooksandrew.github.io/simpleblog/articles/association-rules-explore-app2015-11-30T00:00:00+00:002015-11-30T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<ul id="markdown-toc">
<li><a href="#features" id="markdown-toc-features">Features</a></li>
<li><a href="#how-to-get" id="markdown-toc-how-to-get">How to get</a></li>
<li><a href="#how-to-use" id="markdown-toc-how-to-use">How to use</a></li>
<li><a href="#screenshots" id="markdown-toc-screenshots">Screenshots</a></li>
<li><a href="#code" id="markdown-toc-code">Code</a></li>
</ul>
<p>In a <a href="../association-rules-beyond-transactional-data">previous post</a>, I wrote about what I use association rules for and mentioned a Shiny application I developed to explore and visualize rules. This post is about that app. The app is mainly a wrapper around the <a href="http://www.jstatsoft.org/v14/i15/paper">arules</a> and <a href="https://cran.r-project.org/web/packages/arulesViz/vignettes/arulesViz.pdf">arulesViz</a> packages developed by Michael Hahsler.</p>
<h2 id="features">Features</h2>
<ul>
<li>train association rules
<ul>
<li>interactively adjust confidence and support parameters</li>
<li>sort rules</li>
<li>sample just top rules to prevent crashes</li>
<li>post process rules by subsetting LHS or RHS to just variables/items of interest</li>
<li>suite of interest measures</li>
</ul>
</li>
<li>visualize association rules
<ul>
<li>grouped plot, matrix plot, graph, scatterplot, parallel coordinates, item frequency</li>
</ul>
</li>
<li>export association rules to CSV</li>
</ul>
<h2 id="how-to-get">How to get</h2>
<p><strong>Option 1:</strong> Copy the code below from the <a href="https://gist.github.com/brooksandrew/706a28f832a33e90283b">arules_app.R gist</a></p>
<p><strong>Option2:</strong> Source gist directly.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="s1">'devtools'</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'shiny'</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'arules'</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'arulesViz'</span><span class="p">)</span><span class="w">
</span><span class="n">source_gist</span><span class="p">(</span><span class="n">id</span><span class="o">=</span><span class="s1">'706a28f832a33e90283b'</span><span class="p">)</span></code></pre></figure>
<p><strong>Option 3:</strong> Download the Rsenal package (my personal R package with a hodgepodge of data science tools) and use the <code class="highlighter-rouge">arulesApp</code> function:</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="s1">'devtools'</span><span class="p">)</span><span class="w">
</span><span class="n">install_github</span><span class="p">(</span><span class="s1">'brooksandrew/Rsenal'</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'Rsenal'</span><span class="p">)</span><span class="w">
</span><span class="o">?</span><span class="n">Rsenal</span><span class="o">::</span><span class="n">arulesApp</span></code></pre></figure>
<h2 id="how-to-use">How to use</h2>
<p><code class="highlighter-rouge">arulesApp</code> is intended to be called from the R console for interactive and exploratory use. It calls <code class="highlighter-rouge">shinyApp</code> which spins up a Shiny app without the overhead of having to worry about placing server.R and ui.R. Calling a Shiny app with a function also has the benefit of smooth passing of parameters and data objects as arguments. More on <code class="highlighter-rouge">shinyApp</code> <a href="https://support.rstudio.com/hc/en-us/articles/200404846-Working-in-the-Console">here</a>.</p>
<p><code class="highlighter-rouge">arulesApp</code> is currently highly exploratory (and highly unoptimized). Therefore it works best for quickly iterating on rule training and visualization with low-medium sized datasets. Check out Michael Hahsler’s <a href="https://cran.r-project.org/web/packages/arulesViz/vignettes/arulesViz.pdf">arulesViz</a> paper for a thorough description of how to interpret the visualizations. There is a particularly useful table on page 24 which compares and summarizes the visualization techniques.</p>
<p>Simply call <code class="highlighter-rouge">arulesApp</code> from the console with a data.frame or transaction set for which rules will be mined from:</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="s1">'arules'</span><span class="p">)</span><span class="w"> </span><span class="n">contains</span><span class="w"> </span><span class="n">Adult</span><span class="w"> </span><span class="n">and</span><span class="w"> </span><span class="n">AdultUCI</span><span class="w"> </span><span class="n">datasets</span><span class="w">
</span><span class="n">data</span><span class="p">(</span><span class="s1">'Adult'</span><span class="p">)</span><span class="w"> </span><span class="c1"># transaction set</span><span class="w">
</span><span class="n">arulesApp</span><span class="p">(</span><span class="n">Adult</span><span class="p">,</span><span class="w"> </span><span class="n">vars</span><span class="o">=</span><span class="m">40</span><span class="p">)</span><span class="w">
</span><span class="n">data</span><span class="p">(</span><span class="s1">'AdultUCI'</span><span class="p">)</span><span class="w"> </span><span class="c1"># data.frame</span><span class="w">
</span><span class="n">arulesApp</span><span class="p">(</span><span class="n">AdultUCI</span><span class="p">)</span></code></pre></figure>
<p>Here are the arguments:</p>
<ul>
<li><code class="highlighter-rouge">dataset</code> data.frame, this is the dataset that association rules will be mined from. Each row is treated as a transaction. Seems to work OK when a the S4 transactions class from <em>arules</em> is used, however this is not thoroughly tested.</li>
<li><code class="highlighter-rouge">bin</code> logical, <em>TRUE</em> will automatically discretize/bin numerical data into categorical features that can be used for association analysis.</li>
<li><code class="highlighter-rouge">vars</code> integer, how many variables to include in initial rule mining</li>
<li><code class="highlighter-rouge">supp</code> numeric, the support parameter for initializing visualization. Useful when it is known that a high support is needed to not crash computationally.</li>
<li><code class="highlighter-rouge">conf</code> numeric, the confidence parameter for initializing visualization. Similarly useful when it is known that a high confidence is needed to not crash computationally.</li>
</ul>
<h2 id="screenshots">Screenshots</h2>
<h6 id="association-rules-list-view">Association rules list view</h6>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/123438060@N05/23316969311/in/dateposted/" title="Association rule list view 1"><img src="https://farm6.staticflickr.com/5717/23316969311_8896fab691_c.jpg" width="800" height="473" alt="Screen Shot 2015-11-29 at 11.36.54 AM" /></a><script async="" src="//embedr.flickr.com/assets/client-code.js" charset="utf-8"></script></p>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/123438060@N05/23031568189/in/dateposted/" title="Association rule list view 2"><img src="https://farm1.staticflickr.com/619/23031568189_6ac03917bb_c.jpg" width="800" height="486" alt="Screen Shot 2015-11-29 at 11.34.51 AM" /></a><script async="" src="//embedr.flickr.com/assets/client-code.js" charset="utf-8"></script></p>
<h6 id="scatterplot">Scatterplot</h6>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/123438060@N05/23103789750/in/dateposted/" title="Association rule scatterplot"><img src="https://farm1.staticflickr.com/629/23103789750_d1147d6670_c.jpg" width="800" height="591" alt="Screen Shot 2015-11-29 at 11.40.47 AM" /></a><script async="" src="//embedr.flickr.com/assets/client-code.js" charset="utf-8"></script></p>
<h6 id="graph">Graph</h6>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/123438060@N05/23031583459/in/dateposted/" title="Association rule graph plot"><img src="https://farm6.staticflickr.com/5756/23031583459_a88886a7b1_c.jpg" width="800" height="547" alt="Screen Shot 2015-11-29 at 11.39.53 AM" /></a><script async="" src="//embedr.flickr.com/assets/client-code.js" charset="utf-8"></script></p>
<h6 id="grouped-plot">Grouped Plot</h6>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/123438060@N05/23031572029/in/dateposted/" title="Association rule grouped plot"><img src="https://farm6.staticflickr.com/5796/23031572029_5c6b830076_c.jpg" width="800" height="589" alt="Screen Shot 2015-11-29 at 11.40.58 AM" /></a><script async="" src="//embedr.flickr.com/assets/client-code.js" charset="utf-8"></script></p>
<h6 id="parallel-coordinates">Parallel Coordinates</h6>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/123438060@N05/23316983041/in/dateposted/" title="Association rule parallel coordinate plot"><img src="https://farm1.staticflickr.com/722/23316983041_8efe1dce89_c.jpg" width="800" height="530" alt="Screen Shot 2015-11-29 at 11.37.30 AM" /></a><script async="" src="//embedr.flickr.com/assets/client-code.js" charset="utf-8"></script></p>
<h6 id="matrix">Matrix</h6>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/123438060@N05/23031580439/in/dateposted/" title="Association rule matrix plot"><img src="https://farm6.staticflickr.com/5741/23031580439_f985d39777_c.jpg" width="800" height="602" alt="Screen Shot 2015-11-29 at 11.40.39 AM" /></a><script async="" src="//embedr.flickr.com/assets/client-code.js" charset="utf-8"></script></p>
<h6 id="item-frequency">Item frequency</h6>
<p><a data-flickr-embed="true" href="https://www.flickr.com/photos/123438060@N05/23031598109/in/photostream/" title="Screen Shot 2015-11-29 at 11.36.19 AM"><img src="https://farm6.staticflickr.com/5786/23031598109_70b34851fb_c.jpg" width="800" height="595" alt="Screen Shot 2015-11-29 at 11.36.19 AM" /></a><script async="" src="//embedr.flickr.com/assets/client-code.js" charset="utf-8"></script></p>
<h2 id="code">Code</h2>
<script src="https://gist.github.com/brooksandrew/706a28f832a33e90283b.js"></script>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/association-rules-explore-app/">Interactive association rules exploration app</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on November 30, 2015.</p>http://brooksandrew.github.io/simpleblog/articles/association-rules-beyond-transactional-data2015-11-11T00:00:00+00:002015-11-11T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<ul id="markdown-toc">
<li><a href="#what-is-association-analysis" id="markdown-toc-what-is-association-analysis">What is association analysis?</a></li>
<li><a href="#how-it-works" id="markdown-toc-how-it-works">How it works</a></li>
<li><a href="#how-to-measure-rule-strength" id="markdown-toc-how-to-measure-rule-strength">How to measure rule strength</a></li>
<li><a href="#how-to-use-association-analysis-with-tabular-data" id="markdown-toc-how-to-use-association-analysis-with-tabular-data">How to use association analysis with tabular data</a></li>
<li><a href="#when-to-use-association-rules-with-tabular-data" id="markdown-toc-when-to-use-association-rules-with-tabular-data">When to use association rules with tabular data?</a> <ul>
<li><a href="#1-learn-data-structure" id="markdown-toc-1-learn-data-structure">1. Learn data structure</a></li>
<li><a href="#2-learn-domain" id="markdown-toc-2-learn-domain">2. Learn domain</a></li>
<li><a href="#3-hypothesis-generation" id="markdown-toc-3-hypothesis-generation">3. Hypothesis generation</a></li>
</ul>
</li>
<li><a href="#what-makes-a-rule-interesting" id="markdown-toc-what-makes-a-rule-interesting">What makes a rule interesting?</a></li>
<li><a href="#validating-rules" id="markdown-toc-validating-rules">Validating rules</a></li>
</ul>
<p><strong>Note :</strong> I originally prepared this post as an article for Predictive Analytics Times, geared towards a broad audience with a business/practitioner leaning. I ended up writing <a href="http://www.predictiveanalyticsworld.com/patimes/from-code-to-reports-with-knitr-050915/5328/">this article</a> on knitr instead. In a subsequent post, I will discuss the <a href="https://github.com/brooksandrew/Rsenal/blob/master/R/shiny_arules.R">shiny app</a> I created to interactively explore and visualize association rules.</p>
<p>Most analysts think of association rules when dealing with transactional or market basket data. However, association analysis can also provide value with traditional <a href="https://en.wikipedia.org/wiki/Table_(information)">tabular data</a>, especially when little is known about the structure of the data and its domain.</p>
<h2 id="what-is-association-analysis">What is association analysis?</h2>
<p>Association analysis is an unsupervised learning data mining technique, which at heart is very simple and transparent. The goal is to discover previously unknown patterns (easy) that are also interesting (more challenging) from data. Results are easily interpreted by non-technical audiences and can be expressed in plain English. For example, “When X occurs, Y also occurs 85% of the time.” Many data mining techniques require upfront work in the form of parameter specification and statistical assumption satisfaction before yielding meaningful results. Association analysis is by contrast rather “hands off” upfront. Generating rules is a straightforward procedure that requires little to no knowledge of the underlying data. However, post-processing large rule sets often requires a “hands-on” approach to identify the interesting and valid rules.</p>
<p>Popularized in the early 1990s with <a href="http://www.almaden.ibm.com/cs/quest/papers/sigmod93.pdf">this paper</a> from Agrawal et al, association rule analysis has since declined in popularity. I’m still trying to figure out how correlated this decline is with it’s relative usefulness. My conclusion so far is that in most cases it isn’t strong enough to provide much value alone, but can provide value for knowledge discovery in highly exploratory settings. Particularly knowledge discovery of data quirks and structure; knowledge discovery of novel patterns takes more thought.</p>
<script type="text/javascript" src="//www.google.com/trends/embed.js?hl=en-US&q=%22Association+rules%22&tz=Etc/GMT%2B5&content=1&cid=TIMESERIES_GRAPH_0&export=5&w=500&h=330"></script>
<h2 id="how-it-works">How it works</h2>
<p>The inputs are transactions. In the canonical use-case, these transactions are market basket transactions from a grocery store. For example, 3 transactions could be: {Bread, Milk}, {Bread, Diapers, Beer, Eggs}, {Milk, Diapers, Beer, Cola}. The outputs are association rules that explain the relationship (co-occurrence) between the items. A classic rule example is {Beer} ==> {Diapers} which states that transactions including {Beer} tend to include {Diapers}. A thorough technical description following this example can be found in Kumar’s <a href="http://www-users.cs.umn.edu/~kumar/dmbook/ch6.pdf">Introduction to Data Mining textbook</a>.</p>
<h2 id="how-to-measure-rule-strength">How to measure rule strength</h2>
<p>Association analysis often produces many association rules, more than can be inspected by humans one-by-one. Support and confidence are the most common measures used to initially restrict the number of association rules to just the highest quality. Support measures the relative frequency of the items in a transaction relative to all other transactions. Confidence measures the relative strength of the rule: how often the right hand side (RHS) item occurs in transactions containing the left-hand-side (LHS) item set.</p>
<h2 id="how-to-use-association-analysis-with-tabular-data">How to use association analysis with tabular data</h2>
<p>These same principles can be applied to traditional tabular data (spreadsheets or tables from a relational database). Each row is treated as a transaction. All transactions have the same number of items (one per column). Items are represented by the variable name and the value of that variable for the given row. For example, one row from a five column dataset of students could be represented as: {finalMathGrade=B, eyeColor=brown, state=Minnesota, playSports=YES, inBand=NO}. Traditional association rules run on categorical data. If a table contains continuous data of interest, it can be discretized into bins for analysis.</p>
<h2 id="when-to-use-association-rules-with-tabular-data">When to use association rules with tabular data?</h2>
<p>I find association analysis to be most handy as a first-step approach when presented with a new dataset. One can think of lists of association rules as lists of facts (with regards to past training data). In market basket analysis problems, these facts can be useful and drive business decisions by themselves. With tabular data, I find association rules more useful as a means to develop a deeper understanding of the data and inform more sophisticated analyses.</p>
<h3 id="1-learn-data-structure">1. Learn data structure</h3>
<p>This is especially important if you don’t know how your data was generated. Many datasets are products of highly human processes that can appear unintuitive to an unfamiliar analyst. Rules with a perfect confidence of 1 will explain ground truths in your data that are usually indicative of business rules, which would be difficult to uncover without documentation or a domain expert. For example when one column V1 equals ‘A’ or ‘B’, column V5 always equals ‘C’.
These rules of confidence 1 often include items where variables are equal to “missing.”
Since association rules handles only categorical variables, imputation or exclusion of missing values to accommodate numerical computation is not necessary. Missing values are commonly coded as just another possible category rather than discarded. Rules that include “missing” can always be pruned ex post if they are uninteresting.</p>
<h3 id="2-learn-domain">2. Learn domain</h3>
<p>Association rules are often (and rightly) criticized for generating gobs of trivial and redundant rules. However, rules that are trivial to a seasoned domain expert might provide new and useful information to a data scientist jumping into a new domain (where I often find myself). While often not the final answer, association rules can be used to start the conversation and knowledge sharing process between analysts, domain experts and stakeholders. I often find myself in chicken-egg scenarios where domain experts ask us (the consulting data scientists), the data scientists, what we need to know. I often know so little about the domain and data
context, I don’t even know how to start asking intelligent questions. Association rules
can be that starting point.</p>
<h3 id="3-hypothesis-generation">3. Hypothesis generation</h3>
<p>This is a trickier endeavor. Discovering obvious patterns using association analysis as a newcomer to a dataset is useful, but relatively easy. Discovering the hidden insights that more directly lead to business decisions is difficult. On a recent project I was asked to discover “unknown unknowns” with little domain context and no specific problem to solve. We employed association rules with heavy amounts of rule post-processing using both human and statistical measures (discussed below) to home in on interesting rules which generated hypotheses to investigate further. Although most of the rules exposed database quality issues rather than “big picture” issues, it was a productive first step.</p>
<h2 id="what-makes-a-rule-interesting">What makes a rule interesting?</h2>
<p>Rules can be <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.53.2780&rep=rep1&type=pdf">objectively interesting (to a computer) and/or subjectively interesting</a> (to a human). Objectively interesting rules are quantified statistically from data by <a href="http://michael.hahsler.net/research/association_rules/measures.html">interest measures</a> such as Lift (Interest), Conviction and Leverage. Subjectively interesting rules provide insight that is unexpected and/or actionable to a person. The end goal is obviously to develop rules that are interesting (subjectively) to the user or analyst. Human (especially expert human) time is more expensive than computer time, so objective interest measures are used to first sort and prune massive rule sets. The process of identifying interesting rules is usually iterative, requiring input from domain experts and post-processing adjustments from analysts using quantitative interest measures at each iteration. Visualization helps analysts understand the structure of association rules when there are too many to inspect manually. Michael Hahsler introduces a handy toolkit for visualization in the R <a href="https://cran.r-project.org/web/packages/arulesViz/vignettes/arulesViz.pdf">arulesViz</a> package, which builds on the <a href="http://www.jstatsoft.org/v14/i15/paper">arules</a> package for mining rules.</p>
<h2 id="validating-rules">Validating rules</h2>
<p>It’s tempting to over-interpret association rules which present seemingly unbiased patterns very matter-of-factly. I experienced this on a recent project. We were searching for previously unknown relationships between software assets by monitoring time intervals where the same software assets consistently experienced issues in production. Initial feedback was stronger than expected, so we increased the weight of association rule relationships in our network model. However, once we began validating our results with software SMEs more thoroughly, we realized many of our rules were spurious. Association rules suffer from the <a href="https://books.google.com/books?id=U5np34a5fmQC&pg=PA297&lpg=PA297&dq=what+is+the+vast+search+effect&source=bl&ots=Sq0VDTxlEK&sig=KADUdlw8nea73esrTQ5c8FImXKc&hl=en&sa=X&ei=OCA-VaqBDMfUggTUwYDABg&ved=0CD0Q6AEwBA#v=onepage&q=what%2520is%2520the%2520vast%2520search%2520effect&f=false">Vast Search Effect</a>: the tendency to discover spurious patterns when considering many possibilities. Researchers have proposed techniques to mitigate the issue, such as <a href="http://www.cs.uoi.gr/~tsap/publications/gionis_2007_swap_randomization.pdf">Swap Randomization</a> and post-processing pruning. However, adoption in popular statistical software has been slow to catch on. For this reason, association analysis can be a dangerous approach to produce “final answers.” Instead, consider association analysis as a tool for exploratory data analysis to get familiar with a dataset’s structure, its domain and generate interesting questions to pursue further with more sophisticated analysis.</p>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/association-rules-beyond-transactional-data/">Association rule analysis beyond transaction data</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on November 11, 2015.</p>http://brooksandrew.github.io/simpleblog/articles/advanced-data-table2015-08-31T00:00:00+00:002015-08-31T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<ul id="markdown-toc">
<li><a href="#1-data-structures--assignment" id="markdown-toc-1-data-structures--assignment">1. DATA STRUCTURES & ASSIGNMENT</a> <ul>
<li><a href="#columns-of-lists" id="markdown-toc-columns-of-lists">Columns of lists</a> <ul>
<li><a href="#accessing-elements-from-a-column-of-lists" id="markdown-toc-accessing-elements-from-a-column-of-lists">Accessing elements from a column of lists</a></li>
</ul>
</li>
<li><a href="#suppressing-intermediate-output-with-" id="markdown-toc-suppressing-intermediate-output-with-">Suppressing intermediate output with {}</a></li>
<li><a href="#fast-looping-with-set" id="markdown-toc-fast-looping-with-set">Fast looping with <code class="highlighter-rouge">set</code></a></li>
<li><a href="#using-shift-for-to-leadlag-vectors-and-lists" id="markdown-toc-using-shift-for-to-leadlag-vectors-and-lists">Using <code class="highlighter-rouge">shift</code> for to lead/lag vectors and lists</a></li>
<li><a href="#create-multiple-columns-with--in-one-statement" id="markdown-toc-create-multiple-columns-with--in-one-statement">Create multiple columns with <code class="highlighter-rouge">:=</code> in one statement</a></li>
<li><a href="#assign-a-column-with--named-with-a-character-object" id="markdown-toc-assign-a-column-with--named-with-a-character-object">Assign a column with <code class="highlighter-rouge">:=</code> named with a character object</a></li>
</ul>
</li>
<li><a href="#2-by" id="markdown-toc-2-by">2. <code class="highlighter-rouge">BY</code></a> <ul>
<li><a href="#calculate-a-function-over-a-group-using-by-excluding-each-entity-in-a-second-category" id="markdown-toc-calculate-a-function-over-a-group-using-by-excluding-each-entity-in-a-second-category">Calculate a function over a group (using <code class="highlighter-rouge">by</code>) excluding each entity in a second category.</a> <ul>
<li><a href="#method-1-in-line" id="markdown-toc-method-1-in-line">METHOD 1: in-line</a></li>
<li><a href="#method-2-using--and-sd" id="markdown-toc-method-2-using--and-sd">METHOD 2: using <code class="highlighter-rouge">{}</code> and <code class="highlighter-rouge">.SD</code></a></li>
<li><a href="#method-3-super-fast-mean-calculation" id="markdown-toc-method-3-super-fast-mean-calculation">METHOD 3: Super Fast Mean calculation</a></li>
<li><a href="#speed-check" id="markdown-toc-speed-check">Speed check</a></li>
</ul>
</li>
<li><a href="#keyby-to-key-resulting-aggregate-table" id="markdown-toc-keyby-to-key-resulting-aggregate-table"><code class="highlighter-rouge">keyby</code> to key resulting aggregate table</a></li>
<li><a href="#using-1-n-setkey-and-by-for-within-group-subsetting" id="markdown-toc-using-1-n-setkey-and-by-for-within-group-subsetting">Using <code class="highlighter-rouge">[1]</code>, <code class="highlighter-rouge">[.N]</code>, <code class="highlighter-rouge">setkey</code> and <code class="highlighter-rouge">by</code> for within group subsetting</a></li>
</ul>
</li>
<li><a href="#3-functions" id="markdown-toc-3-functions">3. FUNCTIONS</a> <ul>
<li><a href="#passing-datatable-column-names-as-function-arguments" id="markdown-toc-passing-datatable-column-names-as-function-arguments">Passing <code class="highlighter-rouge">data.table</code> column names as function arguments</a> <ul>
<li><a href="#method-2-quotes-and-get" id="markdown-toc-method-2-quotes-and-get">Method 2: quotes and <code class="highlighter-rouge">get</code></a></li>
</ul>
</li>
<li><a href="#beware-of-scoping-within-datatable" id="markdown-toc-beware-of-scoping-within-datatable">Beware of scoping within data.table</a> <ul>
<li><a href="#dataframe-way" id="markdown-toc-dataframe-way"><code class="highlighter-rouge">data.frame</code> way</a></li>
<li><a href="#datatable-way" id="markdown-toc-datatable-way"><code class="highlighter-rouge">data.table</code> way</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#4-printing" id="markdown-toc-4-printing">4. PRINTING</a> <ul>
<li><a href="#print-datatable-with-" id="markdown-toc-print-datatable-with-">Print data.table with <code class="highlighter-rouge">[]</code></a></li>
<li><a href="#hide-output-from--with-knitr" id="markdown-toc-hide-output-from--with-knitr">Hide output from <code class="highlighter-rouge">:=</code> with knitr</a></li>
</ul>
</li>
</ul>
<h4 id="tips-and-tricks-learned-along-the-way">Tips and tricks learned along the way</h4>
<p>This is mostly a running list of <code class="highlighter-rouge">data.table</code> tricks that took me a while to figure out either by digging into the <a href="https://cran.r-project.org/web/packages/data.table/data.table.pdf">official documentation</a>, adapting StackOverflow posts, or more often than not, experimenting for hours. I’d like to persist these discoveries somewhere with more memory than my head (hello internet) so I can reuse them after my mental memory forgets them. A less organized and concise addition to DataCamp’s sweet <a href="https://s3.amazonaws.com/assets.datacamp.com/img/blog/data+table+cheat+sheet.pdf">cheat sheet for the basics</a>.</p>
<p>Most, if not all of these techniques were developed for real data science projects and provided some value to my data engineering. I’ve generalized everything to the <code class="highlighter-rouge">mtcars</code> dataset which might not make this value immediately clear in this slightly contrived context. This list is not intended to be comprehensive as DataCamp’s data.table cheatsheet is. OK, enough disclaimers!</p>
<p>Some more advanced functionality from <code class="highlighter-rouge">data.table</code> creator Matt Dowle <a href="http://user2014.stat.ucla.edu/files/tutorial_Matt.pdf">here</a>.</p>
<h1 id="1-data-structures--assignment">1. DATA STRUCTURES & ASSIGNMENT</h1>
<hr />
<h2 id="columns-of-lists">Columns of lists</h2>
<h5 id="summary-table-long-and-narrow">summary table (long and narrow)</h5>
<p>This could be useful, but is easily achievable using traditional methods.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="w"> </span><span class="n">.</span><span class="p">(</span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">gear</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">unique</span><span class="p">(</span><span class="n">gear</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl V1
## 1: 6 4
## 2: 6 3
## 3: 6 5
## 4: 4 4
## 5: 4 3
## 6: 4 5
## 7: 8 3
## 8: 8 5</code></pre></figure>
<h5 id="summary-table-short-and-narrow">summary table (short and narrow)</h5>
<p>Add all categories of <code class="highlighter-rouge">gear</code> for each <code class="highlighter-rouge">cyl</code> to original data.table as a list.</p>
<p>This is more nifty. It’s so simple, I find myself using this trick to quickly explore data ad hoc at the command line.
Can also be useful for more serious data engineering.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="n">.</span><span class="p">(</span><span class="n">gear</span><span class="p">,</span><span class="w"> </span><span class="n">cyl</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">gearsL</span><span class="o">:=</span><span class="nf">list</span><span class="p">(</span><span class="nf">list</span><span class="p">(</span><span class="n">unique</span><span class="p">(</span><span class="n">gear</span><span class="p">))),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span><span class="w"> </span><span class="c1"># original, ugly</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">gearsL</span><span class="o">:=</span><span class="n">.</span><span class="p">(</span><span class="nf">list</span><span class="p">(</span><span class="n">unique</span><span class="p">(</span><span class="n">gear</span><span class="p">))),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span><span class="w"> </span><span class="c1"># improved, pretty</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## gear cyl gearsL
## 1: 4 6 4,3,5
## 2: 4 6 4,3,5
## 3: 4 4 4,3,5
## 4: 3 6 4,3,5
## 5: 3 8 3,5
## 6: 3 6 4,3,5</code></pre></figure>
<p><strong>Update 10/29/2015:</strong> Per <a href="http://stackoverflow.com/questions/33113013/use-of-list-in-data-tables-j-argument">these comments</a>
on StackOverlow referencing my post, <code class="highlighter-rouge">t[,gearsL:=list(list(unique(gear))), by=cyl]</code> can be more elegantly written as <code class="highlighter-rouge">t[,gearsL:=.(list(unique(gear))), by=cyl]</code>. Thanks for pointing out my unnecessarily verbose and unusual syntax! I think I wrote the first thing that worked when I posted this, not realizing the normal <code class="highlighter-rouge">.(</code> syntax was equivalent to the outer list.</p>
<h3 id="accessing-elements-from-a-column-of-lists">Accessing elements from a column of lists</h3>
<p>Extract second element of each list in <code class="highlighter-rouge">gearL1</code> and create row <code class="highlighter-rouge">gearL1</code>.
This isn’t that groundbreaking, but explores how to access elements of columns which are constructed of lists of lists. <code class="highlighter-rouge">lapply</code> is your friend.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="n">gearL1</span><span class="o">:=</span><span class="n">lapply</span><span class="p">(</span><span class="n">gearsL</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="p">[</span><span class="m">2</span><span class="p">])]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">gearS1</span><span class="o">:=</span><span class="n">sapply</span><span class="p">(</span><span class="n">gearsL</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="p">[</span><span class="m">2</span><span class="p">])]</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## gear cyl gearsL gearL1 gearS1
## 1: 4 6 4,3,5 3 3
## 2: 4 6 4,3,5 3 3
## 3: 4 4 4,3,5 3 3
## 4: 3 6 4,3,5 3 3
## 5: 3 8 3,5 5 5
## 6: 3 6 4,3,5 3 3</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">str</span><span class="p">(</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">[,</span><span class="n">gearL1</span><span class="p">]))</span><span class="w"> </span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## List of 6
## $ : num 3
## $ : num 3
## $ : num 3
## $ : num 3
## $ : num 5
## $ : num 3</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">str</span><span class="p">(</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">[,</span><span class="n">gearS1</span><span class="p">]))</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## num [1:6] 3 3 3 3 5 3</code></pre></figure>
<p><strong>Update 9/24/2015:</strong> Per Matt Dowle’s comments, a slightly more syntactically succinct way of doing this:</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="n">gearL1</span><span class="o">:=</span><span class="n">lapply</span><span class="p">(</span><span class="n">gearsL</span><span class="p">,</span><span class="w"> </span><span class="n">`[`</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">gearS1</span><span class="o">:=</span><span class="n">sapply</span><span class="p">(</span><span class="n">gearsL</span><span class="p">,</span><span class="w"> </span><span class="n">`[`</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">)]</span></code></pre></figure>
<p>Calculate all the <code class="highlighter-rouge">gear</code>s for all cars of each <code class="highlighter-rouge">cyl</code> (excluding the current current row).
This can be useful for comparing observations to the mean of groups, where the group mean is not biased by the observation of interest.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="n">other_gear</span><span class="o">:=</span><span class="n">mapply</span><span class="p">(</span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w"> </span><span class="n">setdiff</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">),</span><span class="w"> </span><span class="n">x</span><span class="o">=</span><span class="n">gearsL</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">gear</span><span class="p">)]</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## gear cyl gearsL gearL1 gearS1 other_gear
## 1: 4 6 4,3,5 3 3 3,5
## 2: 4 6 4,3,5 3 3 3,5
## 3: 4 4 4,3,5 3 3 3,5
## 4: 3 6 4,3,5 3 3 4,5
## 5: 3 8 3,5 5 5 5
## 6: 3 6 4,3,5 3 3 4,5</code></pre></figure>
<p><strong>Update 9/24/2015:</strong> Per Matt Dowle’s comments, this achieves the same as above.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="n">other_gear</span><span class="o">:=</span><span class="n">mapply</span><span class="p">(</span><span class="n">setdiff</span><span class="p">,</span><span class="w"> </span><span class="n">gearsL</span><span class="p">,</span><span class="w"> </span><span class="n">gear</span><span class="p">)]</span></code></pre></figure>
<h2 id="suppressing-intermediate-output-with-">Suppressing intermediate output with {}</h2>
<p>This is actually a base R trick that I didn’t discover until working with data.table. See <code class="highlighter-rouge">?`{`</code> for some documentation and examples.
I’ve only used it within the J slot of data.table, it might be more generalizable. I find it pretty useful for generating columns
on the fly when I need to perform some multi-step vectorized operation. It can clean up code by allowing you to reference the same temporary variable
by a concise name rather than rewriting the code to re-compute it.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)</span></code></pre></figure>
<p>Defaults to just returning the last object defined in the braces unnamed.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,{</span><span class="n">tmp1</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">);</span><span class="w"> </span><span class="n">tmp2</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="nf">abs</span><span class="p">(</span><span class="n">mpg</span><span class="o">-</span><span class="n">tmp1</span><span class="p">));</span><span class="w"> </span><span class="n">tmp3</span><span class="o">=</span><span class="nf">round</span><span class="p">(</span><span class="n">tmp2</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">)},</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl V1
## 1: 6 1.19
## 2: 4 3.83
## 3: 8 1.79</code></pre></figure>
<p>We can be more explicit by passing a named list of what we want to keep.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,{</span><span class="n">tmp1</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">);</span><span class="w"> </span><span class="n">tmp2</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="nf">abs</span><span class="p">(</span><span class="n">mpg</span><span class="o">-</span><span class="n">tmp1</span><span class="p">));</span><span class="w"> </span><span class="n">tmp3</span><span class="o">=</span><span class="nf">round</span><span class="p">(</span><span class="n">tmp2</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">);</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="n">tmp2</span><span class="o">=</span><span class="n">tmp2</span><span class="p">,</span><span class="w"> </span><span class="n">tmp3</span><span class="o">=</span><span class="n">tmp3</span><span class="p">)},</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl tmp2 tmp3
## 1: 6 1.191837 1.19
## 2: 4 3.833058 3.83
## 3: 8 1.785714 1.79</code></pre></figure>
<p>Can also write it like this without semicolons.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,{</span><span class="n">tmp1</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">)</span><span class="w">
</span><span class="n">tmp2</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="nf">abs</span><span class="p">(</span><span class="n">mpg</span><span class="o">-</span><span class="n">tmp1</span><span class="p">))</span><span class="w">
</span><span class="n">tmp3</span><span class="o">=</span><span class="nf">round</span><span class="p">(</span><span class="n">tmp2</span><span class="p">,</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
</span><span class="nf">list</span><span class="p">(</span><span class="n">tmp2</span><span class="o">=</span><span class="n">tmp2</span><span class="p">,</span><span class="w"> </span><span class="n">tmp3</span><span class="o">=</span><span class="n">tmp3</span><span class="p">)},</span><span class="w">
</span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl tmp2 tmp3
## 1: 6 1.191837 1.19
## 2: 4 3.833058 3.83
## 3: 8 1.785714 1.79</code></pre></figure>
<p>This is trickier with <code class="highlighter-rouge">:=</code> assignments… I don’t think <code class="highlighter-rouge">:=</code> is intended to work when wrapped in <code class="highlighter-rouge">{</code>. Assigning multiple columns with <code class="highlighter-rouge">:=</code> at once
does not allow you to use the first columns you create to use building the ones after it, as we did with <code class="highlighter-rouge">=</code> inside the <code class="highlighter-rouge">{</code> above. Chaining and then dropping unwanted variables is a messy workaround… still exploring this one.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="n">.</span><span class="p">(</span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">mpg</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">tmp1</span><span class="o">:=</span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">][,</span><span class="n">tmp2</span><span class="o">:=</span><span class="n">mean</span><span class="p">(</span><span class="nf">abs</span><span class="p">(</span><span class="n">mpg</span><span class="o">-</span><span class="n">tmp1</span><span class="p">)),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">][,</span><span class="n">tmp1</span><span class="o">:=</span><span class="kc">NULL</span><span class="p">]</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl mpg tmp2
## 1: 6 21.0 1.191837
## 2: 6 21.0 1.191837
## 3: 4 22.8 3.833058
## 4: 6 21.4 1.191837
## 5: 8 18.7 1.785714
## 6: 6 18.1 1.191837</code></pre></figure>
<h2 id="fast-looping-with-set">Fast looping with <code class="highlighter-rouge">set</code></h2>
<p>I still haven’t worked much with the loop + <code class="highlighter-rouge">set</code> framework. I’ve been able to achieve pretty much everything with <code class="highlighter-rouge">:=</code> which is more flexible and powerful.
However, if you must loop, <code class="highlighter-rouge">set</code> is orders of magnitude faster than native R assignments within loops. Here’s a snippet from data.table news a while back:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>New function set(DT,i,j,value) allows fast assignment to elements
of DT. Similar to := but avoids the overhead of [.data.table, so is
much faster inside a loop. Less flexible than :=, but as flexible
as matrix sub-assignment. Similar in spirit to setnames(), setcolorder(),
setkey() and setattr(); i.e., assigns by reference with no copy at all.
M = matrix(1,nrow=100000,ncol=100)
DF = as.data.frame(M)
DT = as.data.table(M)
system.time(for (i in 1:1000) DF[i,1L] <- i) # 591.000s
system.time(for (i in 1:1000) DT[i,V1:=i]) # 1.158s
system.time(for (i in 1:1000) M[i,1L] <- i) # 0.016s
system.time(for (i in 1:1000) set(DT,i,1L,i)) # 0.027s
</code></pre></div></div>
<p>data.table creators do favor <code class="highlighter-rouge">set</code> for <a href="http://stackoverflow.com/questions/16846380/how-to-apply-same-function-to-every-specified-column-in-a-data-table">some things</a>, like this task which can also be done w/ <code class="highlighter-rouge">lapply</code> and <code class="highlighter-rouge">.SD</code>. I was actually directed to this solution after I posed <a href="http://stackoverflow.com/questions/31326691/apply-function-across-subset-of-columns-in-data-table-with-sdcols">this question</a> on StackOverflow. I was also pleased to learn that the
functionality I was looking for – applying a function to a subset of columns with <code class="highlighter-rouge">.SDcols</code> while preserving the untouched columns – was added as a feature request.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="m">1</span><span class="o">:</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">with</span><span class="o">=</span><span class="nb">F</span><span class="p">]</span><span class="w">
</span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">j</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">1L</span><span class="p">,</span><span class="m">2L</span><span class="p">,</span><span class="m">4L</span><span class="p">))</span><span class="w"> </span><span class="n">set</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="o">=</span><span class="n">j</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="o">=-</span><span class="n">dt</span><span class="p">[[</span><span class="n">j</span><span class="p">]])</span><span class="w"> </span><span class="c1"># integers using 'L' passed for efficiency</span><span class="w">
</span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">j</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">3L</span><span class="p">,</span><span class="m">5L</span><span class="p">))</span><span class="w"> </span><span class="n">set</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="n">j</span><span class="o">=</span><span class="n">j</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="o">=</span><span class="n">paste0</span><span class="p">(</span><span class="n">dt</span><span class="p">[[</span><span class="n">j</span><span class="p">]],</span><span class="s1">'!!'</span><span class="p">))</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## mpg cyl disp hp drat
## 1: -21.0 -6 160!! -110 3.9!!
## 2: -21.0 -6 160!! -110 3.9!!
## 3: -22.8 -4 108!! -93 3.85!!
## 4: -21.4 -6 258!! -110 3.08!!
## 5: -18.7 -8 360!! -175 3.15!!
## 6: -18.1 -6 225!! -105 2.76!!</code></pre></figure>
<h2 id="using-shift-for-to-leadlag-vectors-and-lists">Using <code class="highlighter-rouge">shift</code> for to lead/lag vectors and lists</h2>
<p>Note this feature is only available in version 1.9.5 (currently on Github, not CRAN)
Base R surprisingly does not have great tools for dealing with leads/lags of vectors that most social science
statistical software (Stata, SAS, even FAME which I used in my formative data years) come equipped with out of the box.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="n">.</span><span class="p">(</span><span class="n">mpg</span><span class="p">,</span><span class="w"> </span><span class="n">cyl</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">mpg_lag1</span><span class="o">:=</span><span class="n">shift</span><span class="p">(</span><span class="n">mpg</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">mpg_forward1</span><span class="o">:=</span><span class="n">shift</span><span class="p">(</span><span class="n">mpg</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">type</span><span class="o">=</span><span class="s1">'lead'</span><span class="p">)]</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## mpg cyl mpg_lag1 mpg_forward1
## 1: 21.0 6 NA 21.0
## 2: 21.0 6 21.0 22.8
## 3: 22.8 4 21.0 21.4
## 4: 21.4 6 22.8 18.7
## 5: 18.7 8 21.4 18.1
## 6: 18.1 6 18.7 14.3</code></pre></figure>
<h4 id="shift-with-by"><code class="highlighter-rouge">shift</code> with <code class="highlighter-rouge">by</code></h4>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1"># creating some data</span><span class="w">
</span><span class="n">n</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">30</span><span class="w">
</span><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="w">
</span><span class="n">date</span><span class="o">=</span><span class="nf">rep</span><span class="p">(</span><span class="n">seq</span><span class="p">(</span><span class="n">as.Date</span><span class="p">(</span><span class="s1">'2010-01-01'</span><span class="p">),</span><span class="w"> </span><span class="n">as.Date</span><span class="p">(</span><span class="s1">'2015-01-01'</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="s1">'year'</span><span class="p">),</span><span class="w"> </span><span class="n">n</span><span class="o">/</span><span class="m">6</span><span class="p">),</span><span class="w">
</span><span class="n">ind</span><span class="o">=</span><span class="n">rpois</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="m">5</span><span class="p">),</span><span class="w">
</span><span class="n">entity</span><span class="o">=</span><span class="n">sort</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="nb">letters</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="m">5</span><span class="p">],</span><span class="w"> </span><span class="n">n</span><span class="o">/</span><span class="m">5</span><span class="p">))</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="n">setkey</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="n">entity</span><span class="p">,</span><span class="w"> </span><span class="n">date</span><span class="p">)</span><span class="w"> </span><span class="c1"># important for ordering</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">indpct_fast</span><span class="o">:=</span><span class="p">(</span><span class="n">ind</span><span class="o">/</span><span class="n">shift</span><span class="p">(</span><span class="n">ind</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">))</span><span class="m">-1</span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">entity</span><span class="p">]</span><span class="w">
</span><span class="n">lagpad</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">k</span><span class="p">)</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="kc">NA</span><span class="p">,</span><span class="w"> </span><span class="n">k</span><span class="p">),</span><span class="w"> </span><span class="n">x</span><span class="p">)[</span><span class="m">1</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">x</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">indpct_slow</span><span class="o">:=</span><span class="p">(</span><span class="n">ind</span><span class="o">/</span><span class="n">lagpad</span><span class="p">(</span><span class="n">ind</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">))</span><span class="m">-1</span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">entity</span><span class="p">]</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="m">10</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## 1: 2010-01-01 3 a NA NA
## 2: 2011-01-01 2 a -0.3333333 -0.3333333
## 3: 2012-01-01 5 a 1.5000000 1.5000000
## 4: 2013-01-01 4 a -0.2000000 -0.2000000
## 5: 2014-01-01 1 a -0.7500000 -0.7500000
## 6: 2015-01-01 5 a 4.0000000 4.0000000
## 7: 2010-01-01 2 b NA NA
## 8: 2011-01-01 6 b 2.0000000 2.0000000
## 9: 2012-01-01 8 b 0.3333333 0.3333333
## 10: 2013-01-01 9 b 0.1250000 0.1250000</code></pre></figure>
<h2 id="create-multiple-columns-with--in-one-statement">Create multiple columns with <code class="highlighter-rouge">:=</code> in one statement</h2>
<p>This is useful, but note that that the columns operated on must be atomic vectors or lists. That is they must exist before running computation.<br />
Building columns referencing other columns in this set need to be done individually or chained.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="n">.</span><span class="p">(</span><span class="n">mpg</span><span class="p">,</span><span class="w"> </span><span class="n">cyl</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">`:=`</span><span class="p">(</span><span class="n">avg</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">med</span><span class="o">=</span><span class="n">median</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">min</span><span class="o">=</span><span class="nf">min</span><span class="p">(</span><span class="n">mpg</span><span class="p">)),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## mpg cyl avg med min
## 1: 21.0 6 19.74286 19.7 17.8
## 2: 21.0 6 19.74286 19.7 17.8
## 3: 22.8 4 26.66364 26.0 21.4
## 4: 21.4 6 19.74286 19.7 17.8
## 5: 18.7 8 15.10000 15.2 10.4
## 6: 18.1 6 19.74286 19.7 17.8</code></pre></figure>
<h2 id="assign-a-column-with--named-with-a-character-object">Assign a column with <code class="highlighter-rouge">:=</code> named with a character object</h2>
<p>This is the advised way to assign a new column whose name you already have determined and saved as a character. Simply surround the character object in parentheses.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="w"> </span><span class="n">.</span><span class="p">(</span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">mpg</span><span class="p">)]</span><span class="w">
</span><span class="n">thing2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s1">'mpgx2'</span><span class="w">
</span><span class="n">dt</span><span class="p">[,(</span><span class="n">thing2</span><span class="p">)</span><span class="o">:=</span><span class="n">mpg</span><span class="o">*</span><span class="m">2</span><span class="p">]</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl mpg mpgx2
## 1: 6 21.0 42.0
## 2: 6 21.0 42.0
## 3: 4 22.8 45.6
## 4: 6 21.4 42.8
## 5: 8 18.7 37.4
## 6: 6 18.1 36.2</code></pre></figure>
<p>This is old (now deprecated) way which still works for now. Not advised.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">thing3</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s1">'mpgx3'</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">thing3</span><span class="o">:=</span><span class="n">mpg</span><span class="o">*</span><span class="m">3</span><span class="p">,</span><span class="w"> </span><span class="n">with</span><span class="o">=</span><span class="nb">F</span><span class="p">]</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl mpg mpgx2 mpgx3
## 1: 6 21.0 42.0 63.0
## 2: 6 21.0 42.0 63.0
## 3: 4 22.8 45.6 68.4
## 4: 6 21.4 42.8 64.2
## 5: 8 18.7 37.4 56.1
## 6: 6 18.1 36.2 54.3</code></pre></figure>
<h1 id="2-by">2. <code class="highlighter-rouge">BY</code></h1>
<hr />
<h2 id="calculate-a-function-over-a-group-using-by-excluding-each-entity-in-a-second-category">Calculate a function over a group (using <code class="highlighter-rouge">by</code>) excluding each entity in a second category.</h2>
<p>This title probably doesn’t immediately make much sense. Let me explain what I’m going to calculate and why with an example.
We want to compare the <code class="highlighter-rouge">mpg</code> of each car to the average <code class="highlighter-rouge">mpg</code> of cars in the same class (the same # of cylinders). However, we don’t want
to bias the group mean by including the car we want to compare to the average in that average.</p>
<p>This assumption doesn’t appear useful in this example, but assume that <code class="highlighter-rouge">gear</code>+<code class="highlighter-rouge">cyl</code> uniquely identify the cars. In the real project where I faced this
problem, I was calculating an indicator related to an appraiser relative to the average of all other appraisers in their zip3. (<code class="highlighter-rouge">cyl</code> was really zipcode
and <code class="highlighter-rouge">gear</code> was the appraiser’s ID).</p>
<h3 id="method-1-in-line">METHOD 1: in-line</h3>
<h5 id="0a-biased-mean-simple-mean-by-cyl">0.a Biased mean: simple mean by <code class="highlighter-rouge">cyl</code></h5>
<p>However we want to know for each row, what is the mean among all the other cars with the same # of <code class="highlighter-rouge">cyl</code>s, excluding that car.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="n">.</span><span class="p">(</span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">gear</span><span class="p">,</span><span class="w"> </span><span class="n">mpg</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">mpg_biased_mean</span><span class="o">:=</span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl gear mpg mpg_biased_mean
## 1: 6 4 21.0 19.74286
## 2: 6 4 21.0 19.74286
## 3: 4 4 22.8 26.66364
## 4: 6 3 21.4 19.74286
## 5: 8 3 18.7 15.10000
## 6: 6 3 18.1 19.74286</code></pre></figure>
<h5 id="1a-grp-without-setting-key">1.a <code class="highlighter-rouge">.GRP</code> without setting key</h5>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">dt</span><span class="p">[</span><span class="o">!</span><span class="n">gear</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="n">unique</span><span class="p">(</span><span class="n">dt</span><span class="o">$</span><span class="n">gear</span><span class="p">)[</span><span class="n">.GRP</span><span class="p">],</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">],</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">gear</span><span class="p">]</span><span class="w"> </span><span class="c1">#unbiased mean</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## gear cyl V1
## 1: 4 6 19.73333
## 2: 4 8 15.10000
## 3: 4 4 25.96667
## 4: 3 6 19.74000
## 5: 3 4 27.18000
## 6: 3 8 15.40000
## 7: 5 6 19.75000
## 8: 5 4 26.32222
## 9: 5 8 15.05000</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1"># check</span><span class="w">
</span><span class="n">dt</span><span class="p">[</span><span class="n">gear</span><span class="o">!=</span><span class="m">4</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">cyl</span><span class="o">==</span><span class="m">6</span><span class="p">,</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">)]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] 19.73333</code></pre></figure>
<p><strong>Update 9/24/2015:</strong> Per Matt Dowle’s comments, this also works with slightly less code. For my simple example, there was also a marginal speed gain. Time savings relative to the <code class="highlighter-rouge">.GRP</code> method will likely increase with the complexity of the problem.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">dt</span><span class="p">[</span><span class="o">!</span><span class="n">gear</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="n">.BY</span><span class="p">[[</span><span class="m">1</span><span class="p">]],</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">],</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">gear</span><span class="p">]</span><span class="w"> </span><span class="c1">#unbiased mean</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## gear cyl V1
## 1: 4 6 19.73333
## 2: 4 8 15.10000
## 3: 4 4 25.96667
## 4: 3 6 19.74000
## 5: 3 4 27.18000
## 6: 3 8 15.40000
## 7: 5 6 19.75000
## 8: 5 4 26.32222
## 9: 5 8 15.05000</code></pre></figure>
<h5 id="1b-same-as-1a-but-a-little-faster">1.b Same as 1.a, but a little faster</h5>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">uid</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">unique</span><span class="p">(</span><span class="n">dt</span><span class="o">$</span><span class="n">gear</span><span class="p">)</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">dt</span><span class="p">[</span><span class="o">!</span><span class="n">gear</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="p">(</span><span class="n">uid</span><span class="p">[</span><span class="n">.GRP</span><span class="p">]),</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">gear</span><span class="p">][</span><span class="n">order</span><span class="p">(</span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">gear</span><span class="p">)]</span><span class="w"> </span><span class="c1">#unbiased mean</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## gear cyl V1
## 1: 3 4 27.18000
## 2: 4 4 25.96667
## 3: 5 4 26.32222
## 4: 3 6 19.74000
## 5: 4 6 19.73333
## 6: 5 6 19.75000
## 7: 3 8 15.40000
## 8: 4 8 15.10000
## 9: 5 8 15.05000</code></pre></figure>
<h5 id="why-does-this-work">Why does this work?</h5>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1"># 1.a pulling it apart with .GRP</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">.GRP</span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl GRP
## 1: 6 1
## 2: 4 2
## 3: 8 3</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">.</span><span class="p">(</span><span class="n">.GRP</span><span class="p">,</span><span class="w"> </span><span class="n">unique</span><span class="p">(</span><span class="n">dt</span><span class="o">$</span><span class="n">gear</span><span class="p">)[</span><span class="n">.GRP</span><span class="p">]),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl GRP V2
## 1: 6 1 4
## 2: 4 2 3
## 3: 8 3 5</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">.</span><span class="p">(</span><span class="n">.GRP</span><span class="p">,</span><span class="w"> </span><span class="n">unique</span><span class="p">(</span><span class="n">dt</span><span class="o">$</span><span class="n">gear</span><span class="p">)[</span><span class="n">.GRP</span><span class="p">]),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">],</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">gear</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## gear cyl GRP V2
## 1: 4 6 1 4
## 2: 4 4 2 3
## 3: 4 8 3 5
## 4: 3 6 1 4
## 5: 3 4 2 3
## 6: 3 8 3 5
## 7: 5 6 1 4
## 8: 5 4 2 3
## 9: 5 8 3 5</code></pre></figure>
<h5 id="1b-setting-key">1.b Setting key</h5>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">setkey</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="n">gear</span><span class="p">)</span><span class="w">
</span><span class="n">uid</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">unique</span><span class="p">(</span><span class="n">dt</span><span class="o">$</span><span class="n">gear</span><span class="p">)</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">dt</span><span class="p">[</span><span class="o">!</span><span class="n">.</span><span class="p">(</span><span class="n">uid</span><span class="p">[</span><span class="n">.GRP</span><span class="p">]),</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">gear</span><span class="p">]</span><span class="w"> </span><span class="c1">#unbiased mean</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## gear cyl V1
## 1: 3 6 19.74000
## 2: 3 4 27.18000
## 3: 3 8 15.40000
## 4: 4 6 19.73333
## 5: 4 8 15.10000
## 6: 4 4 25.96667
## 7: 5 6 19.75000
## 8: 5 8 15.05000
## 9: 5 4 26.32222</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">mean</span><span class="p">(</span><span class="n">dt</span><span class="p">[</span><span class="n">cyl</span><span class="o">==</span><span class="m">4</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">gear</span><span class="o">!=</span><span class="m">3</span><span class="p">,</span><span class="n">mpg</span><span class="p">])</span><span class="w"> </span><span class="c1"># testing</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] 27.18</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">mean</span><span class="p">(</span><span class="n">dt</span><span class="p">[</span><span class="n">cyl</span><span class="o">==</span><span class="m">6</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">gear</span><span class="o">!=</span><span class="m">3</span><span class="p">,</span><span class="n">mpg</span><span class="p">])</span><span class="w"> </span><span class="c1"># testing</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] 19.74</code></pre></figure>
<h3 id="method-2-using--and-sd">METHOD 2: using <code class="highlighter-rouge">{}</code> and <code class="highlighter-rouge">.SD</code></h3>
<p><code class="highlighter-rouge">{}</code> is used for to suppress intermediate operations.</p>
<h5 id="building-up">Building up</h5>
<p>No surprises here.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">.SD</span><span class="p">[,</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">)],</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">gear</span><span class="p">]</span><span class="w"> </span><span class="c1"># same as `dt[, mean(mpg), by=gear]`</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## gear V1
## 1: 3 16.10667
## 2: 4 24.53333
## 3: 5 21.38000</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">.SD</span><span class="p">[,</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">],</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">gear</span><span class="p">]</span><span class="w"> </span><span class="c1"># same as `dt[, mean(mpg), by=.(cyl, by=gear)]`</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## gear cyl V1
## 1: 3 6 19.750
## 2: 3 8 15.050
## 3: 3 4 21.500
## 4: 4 6 19.750
## 5: 4 4 26.925
## 6: 5 4 28.200
## 7: 5 8 15.400
## 8: 5 6 19.700</code></pre></figure>
<h5 id="nested-datatables-and-by-statements">Nested data.tables and <code class="highlighter-rouge">by</code> statements</h5>
<p>This chunk shows what happens with two <code class="highlighter-rouge">by</code> statements nested within two different data.tables. Explanatory purposes only - not necessary for our task.
<code class="highlighter-rouge">n</code> counts the # of cars in that <code class="highlighter-rouge">cyl</code>. <code class="highlighter-rouge">N</code> counts the number of cars by <code class="highlighter-rouge">cyl</code> and <code class="highlighter-rouge">gear</code>.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,{</span><span class="w">
</span><span class="n">vbar</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="n">mpg</span><span class="p">)</span><span class="w">
</span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">.N</span><span class="w">
</span><span class="n">.SD</span><span class="p">[,</span><span class="n">.</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">.N</span><span class="p">,</span><span class="w"> </span><span class="n">sum_in_gear_cyl</span><span class="o">=</span><span class="nf">sum</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">sum_in_cyl</span><span class="o">=</span><span class="n">vbar</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">gear</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl gear n N sum_in_gear_cyl sum_in_cyl
## 1: 6 3 7 2 39.5 138.2
## 2: 6 4 7 4 79.0 138.2
## 3: 6 5 7 1 19.7 138.2
## 4: 8 3 14 12 180.6 211.4
## 5: 8 5 14 2 30.8 211.4
## 6: 4 3 11 1 21.5 293.3
## 7: 4 4 11 8 215.4 293.3
## 8: 4 5 11 2 56.4 293.3</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="nf">sum</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span><span class="w"> </span><span class="c1"># test</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl V1
## 1: 6 138.2
## 2: 8 211.4
## 3: 4 293.3</code></pre></figure>
<h5 id="calculating-unbiased-mean">Calculating “unbiased mean”</h5>
<p>This is in a summary table. This would need to be merged back onto <code class="highlighter-rouge">dt</code> if that is desired.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,{</span><span class="w">
</span><span class="n">vbar</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">)</span><span class="w">
</span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">.N</span><span class="w">
</span><span class="n">.SD</span><span class="p">[,(</span><span class="n">n</span><span class="o">*</span><span class="n">vbar</span><span class="o">-</span><span class="nf">sum</span><span class="p">(</span><span class="n">mpg</span><span class="p">))</span><span class="o">/</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="n">.N</span><span class="p">),</span><span class="n">by</span><span class="o">=</span><span class="n">gear</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl gear V1
## 1: 6 3 19.74000
## 2: 6 4 19.73333
## 3: 6 5 19.75000
## 4: 8 3 15.40000
## 5: 8 5 15.05000
## 6: 4 3 27.18000
## 7: 4 4 25.96667
## 8: 4 5 26.32222</code></pre></figure>
<h3 id="method-3-super-fast-mean-calculation">METHOD 3: Super Fast Mean calculation</h3>
<h5 id="non-function-direct-way">Non-function direct way</h5>
<p>Using a vectorized approach to calculate the unbiased mean for each combination of <code class="highlighter-rouge">gear</code> and <code class="highlighter-rouge">cyl</code>. Mechanically,
it calculates the “biased average” for all cars by <code class="highlighter-rouge">cyl</code>. Then subtract off the share of cars with the combination of <code class="highlighter-rouge">gear</code> and <code class="highlighter-rouge">cyl</code>
that we want to exclude from the average and add that share. Then extrapolate out this pared down mean.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="n">.</span><span class="p">(</span><span class="n">mpg</span><span class="p">,</span><span class="n">cyl</span><span class="p">,</span><span class="n">gear</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">`:=`</span><span class="p">(</span><span class="n">avg_mpg_cyl</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">Ncyl</span><span class="o">=</span><span class="n">.N</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">`:=`</span><span class="p">(</span><span class="n">Ncylgear</span><span class="o">=</span><span class="n">.N</span><span class="p">,</span><span class="w"> </span><span class="n">avg_mpg_cyl_gear</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">)),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">.</span><span class="p">(</span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">gear</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">unbmean</span><span class="o">:=</span><span class="p">(</span><span class="n">avg_mpg_cyl</span><span class="o">*</span><span class="n">Ncyl</span><span class="o">-</span><span class="p">(</span><span class="n">Ncylgear</span><span class="o">*</span><span class="n">avg_mpg_cyl_gear</span><span class="p">))</span><span class="o">/</span><span class="p">(</span><span class="n">Ncyl</span><span class="o">-</span><span class="n">Ncylgear</span><span class="p">)]</span><span class="w">
</span><span class="n">setkey</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">gear</span><span class="p">)</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## mpg cyl gear avg_mpg_cyl Ncyl Ncylgear avg_mpg_cyl_gear unbmean
## 1: 21.5 4 3 26.66364 11 1 21.500 27.18000
## 2: 22.8 4 4 26.66364 11 8 26.925 25.96667
## 3: 24.4 4 4 26.66364 11 8 26.925 25.96667
## 4: 22.8 4 4 26.66364 11 8 26.925 25.96667
## 5: 32.4 4 4 26.66364 11 8 26.925 25.96667
## 6: 30.4 4 4 26.66364 11 8 26.925 25.96667</code></pre></figure>
<h5 id="wrapping-up-code-below-into-a-function">Wrapping up code below into a function</h5>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">leaveOneOutMean</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="n">ind</span><span class="p">,</span><span class="w"> </span><span class="n">bybig</span><span class="p">,</span><span class="w"> </span><span class="n">bysmall</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">dtmp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">copy</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span><span class="w"> </span><span class="c1"># copy so as not to alter original dt object w intermediate assignments</span><span class="w">
</span><span class="n">dtmp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dtmp</span><span class="p">[</span><span class="nf">is.na</span><span class="p">(</span><span class="n">get</span><span class="p">(</span><span class="n">ind</span><span class="p">))</span><span class="o">==</span><span class="nb">F</span><span class="p">,]</span><span class="w">
</span><span class="n">dtmp</span><span class="p">[,</span><span class="n">`:=`</span><span class="p">(</span><span class="n">avg_ind_big</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="n">get</span><span class="p">(</span><span class="n">ind</span><span class="p">)),</span><span class="w"> </span><span class="n">Nbig</span><span class="o">=</span><span class="n">.N</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">.</span><span class="p">(</span><span class="n">get</span><span class="p">(</span><span class="n">bybig</span><span class="p">))]</span><span class="w">
</span><span class="n">dtmp</span><span class="p">[,</span><span class="n">`:=`</span><span class="p">(</span><span class="n">Nbigsmall</span><span class="o">=</span><span class="n">.N</span><span class="p">,</span><span class="w"> </span><span class="n">avg_ind_big_small</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="n">get</span><span class="p">(</span><span class="n">ind</span><span class="p">))),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">.</span><span class="p">(</span><span class="n">get</span><span class="p">(</span><span class="n">bybig</span><span class="p">),</span><span class="w"> </span><span class="n">get</span><span class="p">(</span><span class="n">bysmall</span><span class="p">))]</span><span class="w">
</span><span class="n">dtmp</span><span class="p">[,</span><span class="n">unbmean</span><span class="o">:=</span><span class="p">(</span><span class="n">avg_ind_big</span><span class="o">*</span><span class="n">Nbig</span><span class="o">-</span><span class="p">(</span><span class="n">Nbigsmall</span><span class="o">*</span><span class="n">avg_ind_big_small</span><span class="p">))</span><span class="o">/</span><span class="p">(</span><span class="n">Nbig</span><span class="o">-</span><span class="n">Nbigsmall</span><span class="p">)]</span><span class="w">
</span><span class="nf">return</span><span class="p">(</span><span class="n">dtmp</span><span class="p">[,</span><span class="n">unbmean</span><span class="p">])</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="n">.</span><span class="p">(</span><span class="n">mpg</span><span class="p">,</span><span class="n">cyl</span><span class="p">,</span><span class="n">gear</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">unbiased_mean</span><span class="o">:=</span><span class="n">leaveOneOutMean</span><span class="p">(</span><span class="n">.SD</span><span class="p">,</span><span class="w"> </span><span class="n">ind</span><span class="o">=</span><span class="s1">'mpg'</span><span class="p">,</span><span class="w"> </span><span class="n">bybig</span><span class="o">=</span><span class="s1">'cyl'</span><span class="p">,</span><span class="w"> </span><span class="n">bysmall</span><span class="o">=</span><span class="s1">'gear'</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">biased_mean</span><span class="o">:=</span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## mpg cyl gear unbiased_mean biased_mean
## 1: 21.0 6 4 19.73333 19.74286
## 2: 21.0 6 4 19.73333 19.74286
## 3: 22.8 4 4 25.96667 26.66364
## 4: 21.4 6 3 19.74000 19.74286
## 5: 18.7 8 3 15.40000 15.10000
## 6: 18.1 6 3 19.74000 19.74286</code></pre></figure>
<h3 id="speed-check">Speed check</h3>
<p>Method 3 is roughly 100x faster than the other two. Great for this narrow task with the vectorization built in,
but less generalizable; The other two methods allow any function to be passed.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)</span><span class="w">
</span><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dt</span><span class="p">[</span><span class="n">sample</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">.N</span><span class="p">,</span><span class="w"> </span><span class="m">100000</span><span class="p">,</span><span class="w"> </span><span class="n">replace</span><span class="o">=</span><span class="nb">T</span><span class="p">),</span><span class="w"> </span><span class="p">]</span><span class="w"> </span><span class="c1"># increase # of rows in mtcars</span><span class="w">
</span><span class="n">dt</span><span class="o">$</span><span class="n">gear</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sample</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">300</span><span class="p">,</span><span class="w"> </span><span class="n">nrow</span><span class="p">(</span><span class="n">dt</span><span class="p">),</span><span class="w"> </span><span class="n">replace</span><span class="o">=</span><span class="nb">T</span><span class="p">)</span><span class="w"> </span><span class="c1"># adding in more cateogries</span></code></pre></figure>
<h5 id="method-3">Method 3:</h5>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">system.time</span><span class="p">(</span><span class="n">dt</span><span class="p">[,</span><span class="n">unbiased_mean_vectorized</span><span class="o">:=</span><span class="n">leaveOneOutMean</span><span class="p">(</span><span class="n">.SD</span><span class="p">,</span><span class="w"> </span><span class="n">ind</span><span class="o">=</span><span class="s1">'mpg'</span><span class="p">,</span><span class="w"> </span><span class="n">bybig</span><span class="o">=</span><span class="s1">'cyl'</span><span class="p">,</span><span class="w"> </span><span class="n">bysmall</span><span class="o">=</span><span class="s1">'gear'</span><span class="p">)])</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## user system elapsed
## 0.033 0.003 0.035</code></pre></figure>
<h5 id="method-2">Method 2:</h5>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">system.time</span><span class="p">(</span><span class="n">tmp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dt</span><span class="p">[,</span><span class="n">dt</span><span class="p">[</span><span class="o">!</span><span class="n">gear</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="n">unique</span><span class="p">(</span><span class="n">dt</span><span class="o">$</span><span class="n">gear</span><span class="p">)[</span><span class="n">.GRP</span><span class="p">],</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">],</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">gear</span><span class="p">]</span><span class="w"> </span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## user system elapsed
## 3.709 0.359 4.069</code></pre></figure>
<h5 id="method-1">Method 1:</h5>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">uid</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">unique</span><span class="p">(</span><span class="n">dt</span><span class="o">$</span><span class="n">gear</span><span class="p">)</span><span class="w">
</span><span class="n">system.time</span><span class="p">(</span><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">dt</span><span class="p">[</span><span class="o">!</span><span class="n">gear</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="p">(</span><span class="n">uid</span><span class="p">[</span><span class="n">.GRP</span><span class="p">]),</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">gear</span><span class="p">][</span><span class="n">order</span><span class="p">(</span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">gear</span><span class="p">)])</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## user system elapsed
## 3.345 0.331 3.677</code></pre></figure>
<h2 id="keyby-to-key-resulting-aggregate-table"><code class="highlighter-rouge">keyby</code> to key resulting aggregate table</h2>
<h5 id="without-keyby">Without <code class="highlighter-rouge">keyby</code></h5>
<p>Categories are not sorted</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1">## devtools::install_github('brooksandrew/Rsenal')</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'Rsenal'</span><span class="p">)</span><span class="w"> </span><span class="c1"># grabbing depthbin function</span><span class="w">
</span><span class="n">tmp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">.</span><span class="p">(</span><span class="n">N</span><span class="o">=</span><span class="n">.N</span><span class="p">,</span><span class="w"> </span><span class="n">sum</span><span class="o">=</span><span class="nf">sum</span><span class="p">(</span><span class="n">vs</span><span class="p">),</span><span class="w"> </span><span class="n">mean</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="n">vs</span><span class="p">)</span><span class="o">/</span><span class="n">.N</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">depthbin</span><span class="p">(</span><span class="n">mpg</span><span class="p">,</span><span class="w"> </span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">labelOrder</span><span class="o">=</span><span class="nb">T</span><span class="p">)]</span><span class="w">
</span><span class="n">tmp</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## depthbin N sum mean
## 1: (15.2,17.8] 2/5 15372 3131 1.325020e-05
## 2: (17.8,21] 3/5 21839 6204 1.300787e-05
## 3: [10.4,15.2] 1/5 25255 0 0.000000e+00
## 4: (21,24.4] 4/5 18817 18817 5.314343e-05
## 5: (24.4,33.9] 5/5 18717 15581 4.447571e-05</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">tmp</span><span class="p">[,</span><span class="n">barplot</span><span class="p">(</span><span class="n">mean</span><span class="p">,</span><span class="w"> </span><span class="n">names</span><span class="o">=</span><span class="n">depthbin</span><span class="p">,</span><span class="w"> </span><span class="n">las</span><span class="o">=</span><span class="m">2</span><span class="p">)]</span></code></pre></figure>
<p><img src="/assets/svg/2015_08_31_datatable/mean_barchart_1.svg" alt="plot of chunk barplot 1" /></p>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [,1]
## [1,] 0.7
## [2,] 1.9
## [3,] 3.1
## [4,] 4.3
## [5,] 5.5</code></pre></figure>
<h5 id="with-keyby">With <code class="highlighter-rouge">keyby</code></h5>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1">## devtools::install_github('brooksandrew/Rsenal')</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'Rsenal'</span><span class="p">)</span><span class="w">
</span><span class="n">tmp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">.</span><span class="p">(</span><span class="n">N</span><span class="o">=</span><span class="n">.N</span><span class="p">,</span><span class="w"> </span><span class="n">sum</span><span class="o">=</span><span class="nf">sum</span><span class="p">(</span><span class="n">vs</span><span class="p">),</span><span class="w"> </span><span class="n">mean</span><span class="o">=</span><span class="n">mean</span><span class="p">(</span><span class="n">vs</span><span class="p">)</span><span class="o">/</span><span class="n">.N</span><span class="p">),</span><span class="w"> </span><span class="n">keyby</span><span class="o">=</span><span class="n">depthbin</span><span class="p">(</span><span class="n">mpg</span><span class="p">,</span><span class="w"> </span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">labelOrder</span><span class="o">=</span><span class="nb">T</span><span class="p">)]</span><span class="w">
</span><span class="n">tmp</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## depthbin N sum mean
## 1: [10.4,15.2] 1/5 25255 0 0.000000e+00
## 2: (15.2,17.8] 2/5 15372 3131 1.325020e-05
## 3: (17.8,21] 3/5 21839 6204 1.300787e-05
## 4: (21,24.4] 4/5 18817 18817 5.314343e-05
## 5: (24.4,33.9] 5/5 18717 15581 4.447571e-05</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">tmp</span><span class="p">[,</span><span class="n">barplot</span><span class="p">(</span><span class="n">mean</span><span class="p">,</span><span class="w"> </span><span class="n">names</span><span class="o">=</span><span class="n">depthbin</span><span class="p">,</span><span class="w"> </span><span class="n">las</span><span class="o">=</span><span class="m">2</span><span class="p">)]</span></code></pre></figure>
<p><img src="/assets/svg/2015_08_31_datatable/mean_barchart_2.svg" alt="plot of chunk barplot 2" /></p>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [,1]
## [1,] 0.7
## [2,] 1.9
## [3,] 3.1
## [4,] 4.3
## [5,] 5.5</code></pre></figure>
<h2 id="using-1-n-setkey-and-by-for-within-group-subsetting">Using <code class="highlighter-rouge">[1]</code>, <code class="highlighter-rouge">[.N]</code>, <code class="highlighter-rouge">setkey</code> and <code class="highlighter-rouge">by</code> for within group subsetting</h2>
<h4 id="take-highest-value-of-column-a-when-column-b-is-highest-by-group">take highest value of column A when column B is highest by group</h4>
<p>Max of <code class="highlighter-rouge">qsec</code> for each category of <code class="highlighter-rouge">cyl</code>
(this is easy)</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="w"> </span><span class="n">.</span><span class="p">(</span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">mpg</span><span class="p">,</span><span class="w"> </span><span class="n">qsec</span><span class="p">)]</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">qsec</span><span class="p">),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl V1
## 1: 6 20.22
## 2: 4 22.90
## 3: 8 18.00</code></pre></figure>
<h5 id="value-of-qsec-when-mpg-is-the-highest-per-category-of-cyl">value of <code class="highlighter-rouge">qsec </code>when <code class="highlighter-rouge">mpg</code> is the highest per category of <code class="highlighter-rouge">cyl</code></h5>
<p>(this is trickier)</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">setkey</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="n">mpg</span><span class="p">)</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">qsec</span><span class="p">[</span><span class="n">.N</span><span class="p">],</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl V1
## 1: 8 17.05
## 2: 6 19.44
## 3: 4 19.90</code></pre></figure>
<h5 id="value-of-qsec-when-mpg-is-the-lowest-per-category-of-cyl">value of <code class="highlighter-rouge">qsec</code> when <code class="highlighter-rouge">mpg</code> is the lowest per category of <code class="highlighter-rouge">cyl</code></h5>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="n">qsec</span><span class="p">[</span><span class="m">1</span><span class="p">],</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl V1
## 1: 8 17.98
## 2: 6 18.90
## 3: 4 18.60</code></pre></figure>
<h5 id="value-of-qsec-when-mpg-is-the-median-per-category-of-cyl">value of <code class="highlighter-rouge">qsec</code> when <code class="highlighter-rouge">mpg</code> is the median per category of <code class="highlighter-rouge">cyl</code></h5>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="p">[,</span><span class="n">qsec</span><span class="p">[</span><span class="nf">round</span><span class="p">(</span><span class="n">.N</span><span class="o">/</span><span class="m">2</span><span class="p">)],</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl V1
## 1: 8 18.0
## 2: 6 15.5
## 3: 4 16.7</code></pre></figure>
<h5 id="subset-rows-within-by-statement">subset rows within by statement</h5>
<p><code class="highlighter-rouge">V1</code> is the standard deviation of <code class="highlighter-rouge">mpg</code> by <code class="highlighter-rouge">cyl</code>. <code class="highlighter-rouge">V2</code> is the standard deviation of <code class="highlighter-rouge">mpg</code> for just the first half of <code class="highlighter-rouge">mpg</code>.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)</span><span class="w">
</span><span class="n">setkey</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="n">mpg</span><span class="p">)</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="w"> </span><span class="n">.</span><span class="p">(</span><span class="n">sd</span><span class="p">(</span><span class="n">mpg</span><span class="p">),</span><span class="w"> </span><span class="n">sd</span><span class="p">(</span><span class="n">mpg</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="nf">round</span><span class="p">(</span><span class="n">.N</span><span class="o">/</span><span class="m">2</span><span class="p">)])),</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="n">cyl</span><span class="p">]</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl V1 V2
## 1: 8 2.560048 2.0926174
## 2: 6 1.453567 0.8981462
## 3: 4 4.509828 1.7728508</code></pre></figure>
<h1 id="3-functions">3. FUNCTIONS</h1>
<hr />
<h2 id="passing-datatable-column-names-as-function-arguments">Passing <code class="highlighter-rouge">data.table</code> column names as function arguments</h2>
<h4 id="method-1-no-quotes-and-deparse--substitute">Method 1: No quotes, and <code class="highlighter-rouge">deparse</code> + <code class="highlighter-rouge">substitute</code></h4>
<p>This way seems more data.table-ish because it maintains the practice of not using quotes on variable names in most cases.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[,</span><span class="n">.</span><span class="p">(</span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">mpg</span><span class="p">)]</span><span class="w">
</span><span class="n">myfunc</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">v</span><span class="m">2</span><span class="o">=</span><span class="n">deparse</span><span class="p">(</span><span class="nf">substitute</span><span class="p">(</span><span class="n">v</span><span class="p">))</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">v</span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">with</span><span class="o">=</span><span class="nb">F</span><span class="p">][[</span><span class="m">1</span><span class="p">]]</span><span class="w"> </span><span class="c1"># [[1]] returns a vector instead of a data.table</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">myfunc</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="n">mpg</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2
## [15] 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4
## [29] 15.8 19.7 15.0 21.4</code></pre></figure>
<h3 id="method-2-quotes-and-get">Method 2: quotes and <code class="highlighter-rouge">get</code></h3>
<p>However I tend to pass through column names as characters (quoted) and use <code class="highlighter-rouge">get</code> each time I reference that column. That can be annoying if you have a long function
repeatedly reference column names, but I often need to write such few lines of code with data.table, it hasn’t struck me as terribly unslick, yet.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)</span><span class="w">
</span><span class="n">myfunc</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="n">dt</span><span class="p">[,</span><span class="n">get</span><span class="p">(</span><span class="n">v</span><span class="p">)]</span><span class="w">
</span><span class="n">myfunc</span><span class="p">(</span><span class="n">dt</span><span class="p">,</span><span class="w"> </span><span class="s1">'mpg'</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2
## [15] 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4
## [29] 15.8 19.7 15.0 21.4</code></pre></figure>
<h2 id="beware-of-scoping-within-datatable">Beware of scoping within data.table</h2>
<h3 id="dataframe-way"><code class="highlighter-rouge">data.frame</code> way</h3>
<p>When you add something to a <code class="highlighter-rouge">data.frame</code> within a function that exists in the global environment, it does not affect that object in the
global environment unless you return and reassign it as such, or you use the <code class="highlighter-rouge"><<-</code> operator.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">df</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">mtcars</span><span class="p">[,</span><span class="nf">c</span><span class="p">(</span><span class="s1">'cyl'</span><span class="p">,</span><span class="w"> </span><span class="s1">'mpg'</span><span class="p">)]</span><span class="w">
</span><span class="n">add_column_df</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">df</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">df</span><span class="o">$</span><span class="n">addcol1</span><span class="o"><-</span><span class="w"> </span><span class="s1">'here in func!'</span><span class="w">
</span><span class="n">df</span><span class="o">$</span><span class="n">addcol2</span><span class="w"> </span><span class="o"><<-</span><span class="w"> </span><span class="s1">'in glob env!'</span><span class="w">
</span><span class="nf">return</span><span class="p">(</span><span class="n">df</span><span class="p">)</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<p>When we call the function, we see <code class="highlighter-rouge">addcol1</code> in the output. But not <code class="highlighter-rouge">addcol2</code>. That’s because it’s been added to the <code class="highlighter-rouge">df</code> in the global environment one level up.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">head</span><span class="p">(</span><span class="n">add_column_df</span><span class="p">(</span><span class="n">df</span><span class="p">))</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl mpg addcol1
## Mazda RX4 6 21.0 here in func!
## Mazda RX4 Wag 6 21.0 here in func!
## Datsun 710 4 22.8 here in func!
## Hornet 4 Drive 6 21.4 here in func!
## Hornet Sportabout 8 18.7 here in func!
## Valiant 6 18.1 here in func!</code></pre></figure>
<p>Here is <code class="highlighter-rouge">addcol2</code>, but not <code class="highlighter-rouge">addcol</code>.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">head</span><span class="p">(</span><span class="n">df</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## cyl mpg addcol2
## Mazda RX4 6 21.0 in glob env!
## Mazda RX4 Wag 6 21.0 in glob env!
## Datsun 710 4 22.8 in glob env!
## Hornet 4 Drive 6 21.4 in glob env!
## Hornet Sportabout 8 18.7 in glob env!
## Valiant 6 18.1 in glob env!</code></pre></figure>
<h3 id="datatable-way"><code class="highlighter-rouge">data.table</code> way</h3>
<p>Unlike data.frame, the <code class="highlighter-rouge">:=</code> operator adds a column to both the object living in the global environment and used in the function. I think this is because
these objects are actually the same object. data.table shaves computation time by not making copies unless explicitly directed to.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)</span><span class="w">
</span><span class="n">add_column_dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">dat</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">dat</span><span class="p">[,</span><span class="n">addcol</span><span class="o">:=</span><span class="s1">'sticking_to_dt!'</span><span class="p">]</span><span class="w"> </span><span class="c1"># hits dt in glob env</span><span class="w">
</span><span class="nf">return</span><span class="p">(</span><span class="n">dat</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">add_column_dt</span><span class="p">(</span><span class="n">dt</span><span class="p">))</span><span class="w"> </span><span class="c1"># addcol here</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## mpg cyl disp hp drat wt qsec vs am gear carb addcol
## 1: 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 sticking_to_dt!
## 2: 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 sticking_to_dt!
## 3: 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 sticking_to_dt!
## 4: 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 sticking_to_dt!
## 5: 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 sticking_to_dt!
## 6: 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 sticking_to_dt!</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span><span class="w"> </span><span class="c1"># addcol also here</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## mpg cyl disp hp drat wt qsec vs am gear carb addcol
## 1: 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 sticking_to_dt!
## 2: 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 sticking_to_dt!
## 3: 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 sticking_to_dt!
## 4: 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 sticking_to_dt!
## 5: 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 sticking_to_dt!
## 6: 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 sticking_to_dt!</code></pre></figure>
<p>So something like this renaming the local version using <code class="highlighter-rouge">copy</code> bypasses this behavior, but is likely somewhat less efficient (and elegant). I suspect there’s a cleaner and/or faster way to do this: keep some variables
local to the function while persisting and returning other columns.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)</span><span class="w">
</span><span class="n">add_column_dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">dat</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">datloc</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">copy</span><span class="p">(</span><span class="n">dat</span><span class="p">)</span><span class="w">
</span><span class="n">datloc</span><span class="p">[,</span><span class="n">addcol</span><span class="o">:=</span><span class="s1">'not sticking_to_dt!'</span><span class="p">]</span><span class="w"> </span><span class="c1"># hits dt in glob env</span><span class="w">
</span><span class="nf">return</span><span class="p">(</span><span class="n">datloc</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">add_column_dt</span><span class="p">(</span><span class="n">dt</span><span class="p">))</span><span class="w"> </span><span class="c1"># addcol here</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## mpg cyl disp hp drat wt qsec vs am gear carb addcol
## 1: 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 not sticking_to_dt!
## 2: 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 not sticking_to_dt!
## 3: 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 not sticking_to_dt!
## 4: 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 not sticking_to_dt!
## 5: 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 not sticking_to_dt!
## 6: 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 not sticking_to_dt!</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">head</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span><span class="w"> </span><span class="c1"># addcol not here</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## mpg cyl disp hp drat wt qsec vs am gear carb
## 1: 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## 2: 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## 3: 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## 4: 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## 5: 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## 6: 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1</code></pre></figure>
<h1 id="4-printing">4. PRINTING</h1>
<hr />
<h2 id="print-datatable-with-">Print data.table with <code class="highlighter-rouge">[]</code></h2>
<p>Nothing groundbreaking here, but a small miscellaneous piece of functionality.
In <code class="highlighter-rouge">data.frame</code> world, wrapping an expression in <code class="highlighter-rouge">()</code> prints the output to the console. This also works with data.table, but there is another way.
In <code class="highlighter-rouge">data.table</code> this is achieved by appending <code class="highlighter-rouge">[]</code> to the end of the expression. I find this useful because when I’m exploring at the console, I
don’t usually decide to print the output until I’m almost done and I’m already at the end of the expression I’ve written.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1"># data.frame way of printing after an assignment</span><span class="w">
</span><span class="n">df</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">head</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)</span><span class="w"> </span><span class="c1"># doesn't print</span><span class="w">
</span><span class="p">(</span><span class="n">df</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">head</span><span class="p">(</span><span class="n">mtcars</span><span class="p">))</span><span class="w"> </span><span class="c1"># does print</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## mpg cyl disp hp drat wt qsec vs am gear carb
## Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
## Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
## Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
## Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
## Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
## Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1"># data.table way of printing after an assignment</span><span class="w">
</span><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">head</span><span class="p">(</span><span class="n">mtcars</span><span class="p">))</span><span class="w"> </span><span class="c1"># doesn't print</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">hp2wt</span><span class="o">:=</span><span class="n">hp</span><span class="o">/</span><span class="n">wt</span><span class="p">][]</span><span class="w"> </span><span class="c1"># does print</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## mpg cyl disp hp drat wt qsec vs am gear carb hp2wt
## 1: 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 41.98473
## 2: 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 38.26087
## 3: 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 40.08621
## 4: 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 34.21462
## 5: 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 50.87209
## 6: 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 30.34682</code></pre></figure>
<h2 id="hide-output-from--with-knitr">Hide output from <code class="highlighter-rouge">:=</code> with knitr</h2>
<p>It used to be that assignments using the <code class="highlighter-rouge">:=</code> operator printed the object to console when knitting documents with <code class="highlighter-rouge">knitr</code> and <code class="highlighter-rouge">rmarkdown</code>. This is actually fixed in data.table v1.9.5. However at the time of my writing, this currently not available on CRAN… only Github. For 1.9.4 users, <a href="http://stackoverflow.com/questions/15267018/knitr-gets-tricked-by-data-table-assignment">this StackOverflow post</a> has some hacky solutions. This least impedance approach I found was simply wrapping
the expression in <code class="highlighter-rouge">invisible</code>. Other solutions alter the way you use data.table which I didn’t like.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.table</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)</span><span class="w">
</span><span class="n">dt</span><span class="p">[,</span><span class="n">mpg2qsec</span><span class="o">:=</span><span class="n">mpg</span><span class="o">/</span><span class="n">qsec</span><span class="p">]</span><span class="w"> </span><span class="c1"># will print with knitr</span><span class="w">
</span><span class="nf">invisible</span><span class="p">(</span><span class="n">dt</span><span class="p">[,</span><span class="n">mpg2qsec</span><span class="o">:=</span><span class="n">mpg</span><span class="o">/</span><span class="n">qsec</span><span class="p">])</span><span class="w"> </span><span class="c1"># won't print with knitr</span></code></pre></figure>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/advanced-data-table/">Advanced tips and tricks with data.table</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on August 31, 2015.</p>http://brooksandrew.github.io/simpleblog/articles/render-reports-directly-from-R-scripts2015-03-05T00:00:00+00:002015-03-05T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<h4 id="workflow">Workflow</h4>
<p>This post is really about workflow. Specifically a data-science workflow, although it should be relevant for others. It will probably resonate most (if at all) with those who have some experience (mostly positive) generating reports from Rmarkdown files with knitr, but might have some gripes. Maybe not gripes, maybe just feelings of uncertainty over whether it makes sense to contain your hard work in an Rmarkdown file or an R script, or both.</p>
<h4 id="generate-reports-with-rmarkdown-rmd-files">Generate reports with Rmarkdown (Rmd) files</h4>
<p>With Rmarkdown, you can generate these stylish reports with <a href="http://rmarkdown.rstudio.com/">code like this</a>.</p>
<h4 id="generate-reports-directly-from-r-scripts">Generate reports directly from R scripts</h4>
<p>One can also cut out the middle-man (Rmd) and generate the exact same HTML, PDF and Word reports using native R scripts. This was news to me until this week. It’s a subtle difference, but one that I’ve found nimble and powerful in all the right places. <a href="http://rmarkdown.rstudio.com/r_notebook_format.html">Check this out</a> for a quick intro.</p>
<p><strong>How it works:</strong> Code as normal. Tweak the comments in your code to render the document text, headers, format, style, etc. of your report however you like. You can compile any old R script, regardless of it’s structure, but there are a lot of options at your disposal for formatting and prettifying, if that’s your thing. Then it’s a one liner to compile into a report:</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="s1">'rmarkdown'</span><span class="p">)</span><span class="w">
</span><span class="n">rmarkdown</span><span class="o">::</span><span class="n">render</span><span class="p">(</span><span class="s1">'/Users/you/Documents/yourscript.R'</span><span class="p">)</span></code></pre></figure>
<h4 id="rmarkdown-vs-r">Rmarkdown vs R</h4>
<ul>
<li>
<p><strong>Rmd != R:</strong> You can’t <code class="highlighter-rouge">source</code> an Rmarkdown file like you would an R script. I have no doubt there are tools that exist (or can be easily developed) to strip the code chunks from an Rmarkdown file, but this seems cumbersome.</p>
</li>
<li>
<p><strong>Competing incentives: presentation vs. workflow:</strong> When you’ve got tons of code chunks with just a few lines each, it can be annoying to test your code without knitting (compiling) your entire document. I often purposely keep chunks big to facilitate running blocks of selected code interactively. This makes for smooth coding, but slightly more obtuse documents. One strategy I’ve tried is to “Rmarkdownify” my code only after I’ve thoroughly developed and tested it… but then when it comes time to re-examine, change or pipe code someplace else, you’ve got this Rmarkdown document to overhaul. And in my work (many more parts analysis than development), I’m rarely ever done or know when I’m done.</p>
</li>
<li>
<p><strong>No need to duplicate Rmd and R scripts:</strong> Say you’re writing some data wrangling code that pulls from a handful of data sources, merges them all together, aggregates, scales and transforms them into an analytics ready dataset. You want to document this process… but you also want to be able to pipe this piece of ETL code elsewhere. I’ve been tempted in the past to maintain both a bare-bones R script and a verbose flowery Rmd file describing the process. This keeps both the developers (on your team or within yourself) happy and the consumers of your analysis happy… but it will probably drive you crazy maintaining two versions of more-or-less the same thing. With an R script formatted with markdown-style comments, you might be able to get the two birds with one stone.</p>
</li>
<li>
<p><strong>Run-time:</strong> This isn’t very well addressed by either method, but I certainly find it easier to work with bigger data anything computationally intensive using native R scripts. When I knit a big Rmarkdown script, I often cross my fingers and hope it doesn’t bug 95% through and I have to start over. By default, knitting .Rmd files does not persist objects to the Global Environment, although I’d be surprised if there wasn’t a way to change this.</p>
</li>
<li>
<p><strong>All pros, no cons:</strong> If you’re working on a team that doesn’t want to use knitr and Rmarkdown, no matter. Your team members might gaze at seemingly strange comments in your R scripts, but they can run, read, edit and pipe your code as if it was their own. You can even compile their code into reports. This will essentially just separate code from output and plots printed to the console. It might not be the prettiest, but it sure beats saving off graphics and results and copying and pasting into slides somewhere. And I find it’s easier to find your chart, finding, or what-have-you in a compiled document than within a script where you have to run code, dependencies and likely muddle up the current environment in which you’re working.</p>
</li>
</ul>
<h4 id="rendered-report-in-the-flesh">Rendered report in the flesh</h4>
<p>All the features I’m used to using with Rmarkdown documents worked when embedded in native R scripts.</p>
<p>The script below (<a href="https://github.com/brooksandrew/simpleblog/blob/gh-pages/assets/R/renderRscript2markdown_sample.R">also here</a>) generates <a href="http://htmlpreview.github.io/?https://raw.githubusercontent.com/brooksandrew/simpleblog/gh-pages/assets/R/renderRscript2markdown_sample.html">this html document</a> (below).</p>
<h4 id="html-report-generated-by-r-script-below">HTML report generated by R script below</h4>
<iframe src="http://htmlpreview.github.io/?https://raw.githubusercontent.com/brooksandrew/simpleblog/gh-pages/assets/R/renderRscript2markdown_sample.html" width="700" height="800"></iframe>
<h4 id="r-script-that-generates-the-html-report-above">R script that generates the html report above</h4>
<p>This is perhaps not a great example of how a typical R script would look. A typical R script/document would probably have significantly more code and less comments. However, I know how code appears in a report – my purpose is really to test the markdown functionality.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="cd">#' ---</span><span class="w">
</span><span class="cd">#' title: Sample HTML report generated from R script</span><span class="w">
</span><span class="cd">#' author: Andrew Brooks</span><span class="w">
</span><span class="cd">#' date: March 4, 2015</span><span class="w">
</span><span class="cd">#' output:</span><span class="w">
</span><span class="cd">#' html_document:</span><span class="w">
</span><span class="cd">#' toc: true</span><span class="w">
</span><span class="cd">#' highlight: zenburn</span><span class="w">
</span><span class="cd">#' ---</span><span class="w">
</span><span class="cd">#' ## Generate document body from comments</span><span class="w">
</span><span class="cd">#' All the features from markdown and markdown supported within .Rmd documents, I was able to</span><span class="w">
</span><span class="cd">#' get from within R scripts. Here are some that I tested and use most frequently: </span><span class="w">
</span><span class="cd">#' </span><span class="w">
</span><span class="cd">#' * Smart comment fomatting in your R script generate the body and headers of the document</span><span class="w">
</span><span class="cd">#' * Simply tweak your comments to begin with `#'` instead of just `#` </span><span class="w">
</span><span class="cd">#' * Create markdown headers as normal: `#' #` for h1, `#' ##` for h2, etc.</span><span class="w">
</span><span class="cd">#' * Add two spaces to the end of a comment line to start a new line (just like regular markdown)</span><span class="w">
</span><span class="cd">#' * Add `toc: true` to YAML frontmatter to create a table of contents with links like the one at the </span><span class="w">
</span><span class="cd">#' top of this page that links to h1, h2 & h3's indented like so:</span><span class="w">
</span><span class="cd">#' * h1</span><span class="w">
</span><span class="cd">#' * h2</span><span class="w">
</span><span class="cd">#' * h3</span><span class="w">
</span><span class="cd">#' * Modify YAML to change syntax highlighting style (I'm using zenburn), author, title, theme, and all the good stuff</span><span class="w">
</span><span class="cd">#' you're used to setting in Rmd documents.</span><span class="w">
</span><span class="cd">#' * Sub-bullets like the ones above are created by a `#' *` with 4 spaces per level of indentation.</span><span class="w">
</span><span class="cd">#' * Surround text with `*` to *italicize* </span><span class="w">
</span><span class="cd">#' * Surround text with `**` to **bold** </span><span class="w">
</span><span class="cd">#' * Surround text with `***` to ***italicize & bold*** </span><span class="w">
</span><span class="cd">#' * Skip lines with `#' <br>`</span><span class="w">
</span><span class="cd">#' * Keep comments in code, but hide from printing in report with `#' <!-- this text will not print in report -->` </span><span class="w">
</span><span class="cd">#' * Add hyperlinks:</span><span class="w">
</span><span class="cd">#' * [Rmarkdown cheatsheet](http://rmarkdown.rstudio.com/RMarkdownCheatSheet.pdf)</span><span class="w">
</span><span class="cd">#' * [Rmarkdown Reference Guide](http://rmarkdown.rstudio.com/RMarkdownReferenceGuide.pdf)</span><span class="w">
</span><span class="cd">#' * [Compiling R notebooks from R Scripts](http://rmarkdown.rstudio.com/r_notebook_format.html)</span><span class="w">
</span><span class="cd">#' </span><span class="w">
</span><span class="c1"># comments without the extra tick show up like this. And get included in code blocks</span><span class="w">
</span><span class="c1"># loading mtcars data</span><span class="w">
</span><span class="n">data</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)</span><span class="w">
</span><span class="cd">#' ## Messing with data</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'knitr'</span><span class="p">)</span><span class="w">
</span><span class="cd">#' ### 3 ways to print an object</span><span class="w">
</span><span class="cd">#' ...specifically a data.frame in this case. Ordered from least to most pretty (in my opinion).</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="n">head</span><span class="p">(</span><span class="n">mtcars</span><span class="p">))</span><span class="w">
</span><span class="n">knitr</span><span class="o">::</span><span class="n">kable</span><span class="p">(</span><span class="n">head</span><span class="p">(</span><span class="n">mtcars</span><span class="p">))</span><span class="w">
</span><span class="cd">#' including `#+ results='asis'` chunk option for formatting</span><span class="w">
</span><span class="c1">#+ results='asis'</span><span class="w">
</span><span class="n">knitr</span><span class="o">::</span><span class="n">kable</span><span class="p">(</span><span class="n">head</span><span class="p">(</span><span class="n">mtcars</span><span class="p">))</span><span class="w">
</span><span class="cd">#' ### Plotting</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">mtcars</span><span class="o">$</span><span class="n">mpg</span><span class="p">,</span><span class="w"> </span><span class="n">mtcars</span><span class="o">$</span><span class="n">disp</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="o">=</span><span class="n">mtcars</span><span class="o">$</span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">pch</span><span class="o">=</span><span class="m">19</span><span class="p">)</span><span class="w">
</span><span class="cd">#' We can change the chunk options we would use for a code block using `knitr` by using a comment that starts with `#+`.</span><span class="w">
</span><span class="cd">#' For example, to change the plot size, we can specify `#+ fig.width=4, fig.height=4` before plotting. </span><span class="w">
</span><span class="cd">#' <br></span><span class="w">
</span><span class="cd">#' A new chunk is automatically generated (chunk settings reset) whenever we add document text with `#'` or change.</span><span class="w">
</span><span class="cd">#' However, it is possible to specify global chunk options, if desired.</span><span class="w">
</span><span class="cd">#' chunk options again with `#+`. </span><span class="w">
</span><span class="cd">#' `#+ fig.width=4, fig.height=4` <!-- simply for illustrative purposes in the document--></span><span class="w">
</span><span class="c1">#+ fig.width=4, fig.height=4</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">mtcars</span><span class="o">$</span><span class="n">mpg</span><span class="p">,</span><span class="w"> </span><span class="n">mtcars</span><span class="o">$</span><span class="n">disp</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="o">=</span><span class="n">mtcars</span><span class="o">$</span><span class="n">cyl</span><span class="p">,</span><span class="w"> </span><span class="n">pch</span><span class="o">=</span><span class="m">19</span><span class="p">)</span><span class="w">
</span><span class="cd">#' Small plots often render with strange resolution and relative sizings of labels, axes, etc. The `dpi` chunk option can be used </span><span class="w">
</span><span class="cd">#' to fix this. Just be sure to adjust the fig.width and fig.height accordingly.</span><span class="w">
</span><span class="cd">#' </span><span class="w">
</span><span class="cd">#' **Bad plot: ** `#+ fig.width=2, fig.height=2`</span><span class="w">
</span><span class="c1">#+ fig.width=2, fig.height=2</span><span class="w">
</span><span class="n">hist</span><span class="p">(</span><span class="n">mtcars</span><span class="o">$</span><span class="n">mpg</span><span class="p">)</span><span class="w">
</span><span class="cd">#' **Good plot: ** `#+ fig.width=4, fig.height=4, dpi=50`</span><span class="w">
</span><span class="c1">#+ fig.width=4, fig.height=4, dpi=50</span><span class="w">
</span><span class="n">hist</span><span class="p">(</span><span class="n">mtcars</span><span class="o">$</span><span class="n">mpg</span><span class="p">)</span><span class="w">
</span><span class="cd">#' Generate a series of plots from a loop</span><span class="w">
</span><span class="c1">#+ fig.width=3, fig.height=3</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="n">ncol</span><span class="p">(</span><span class="n">mtcars</span><span class="p">))</span><span class="w"> </span><span class="n">hist</span><span class="p">(</span><span class="n">mtcars</span><span class="p">[,</span><span class="n">i</span><span class="p">],</span><span class="w"> </span><span class="n">breaks</span><span class="o">=</span><span class="m">40</span><span class="p">,</span><span class="w"> </span><span class="n">xlab</span><span class="o">=</span><span class="s1">''</span><span class="p">,</span><span class="w"> </span><span class="n">main</span><span class="o">=</span><span class="nf">names</span><span class="p">(</span><span class="n">mtcars</span><span class="p">)[</span><span class="n">i</span><span class="p">])</span><span class="w">
</span><span class="cd">#' ### Let's build a random forest model </span><span class="w">
</span><span class="cd">#' ... and explore some model output. First here's a big chunk of text from the random forest documentation: </span><span class="w">
</span><span class="cd">#' <br></span><span class="w">
</span><span class="cd">#' **Random forest documentation:** </span><span class="w">
</span><span class="cd">#' randomForest implements Breiman's random forest algorithm (based on Breiman and Cutler's original Fortran code) </span><span class="w">
</span><span class="cd">#' for classification and regression. It can also be used in unsupervised mode for assessing proximities among data points. </span><span class="w">
</span><span class="cd">#' <br></span><span class="w">
</span><span class="cd">#' **Note:** </span><span class="w">
</span><span class="cd">#' The forest structure is slightly different between classification and regression. For details on how the trees are stored, see the help page for getTree. </span><span class="w">
</span><span class="cd">#' <br></span><span class="w">
</span><span class="cd">#' If xtest is given, prediction of the test set is done “in place” as the trees are grown. If ytest is also given, and do.trace is set to some positive integer, </span><span class="w">
</span><span class="cd">#' then for every do.trace trees, the test set error is printed. Results for the test set is returned in the test component of the resulting randomForest object. </span><span class="w">
</span><span class="cd">#' For classification, the votes component (for training or test set data) contain the votes the cases received for the classes. If norm.votes=TRUE, the fraction </span><span class="w">
</span><span class="cd">#' is given, which can be taken as predicted probabilities for the classes. </span><span class="w">
</span><span class="cd">#' <br></span><span class="w">
</span><span class="cd">#' For large data sets, especially those with large number of variables, calling randomForest via the formula interface is not advised: There may be too </span><span class="w">
</span><span class="cd">#' much overhead in handling the formula. </span><span class="w">
</span><span class="cd">#' <br></span><span class="w">
</span><span class="cd">#' The “local” (or casewise) variable importance is computed as follows: For classification, it is the increase in percent of times a case is OOB </span><span class="w">
</span><span class="cd">#' and misclassified when the variable is permuted. For regression, it is the average increase in squared OOB residuals when the variable is permuted. </span><span class="w">
</span><span class="c1"># OK. now let's actually use random.forest</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'randomForest'</span><span class="p">)</span><span class="w">
</span><span class="n">mtcars</span><span class="o">$</span><span class="n">am</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">as.factor</span><span class="p">(</span><span class="n">mtcars</span><span class="o">$</span><span class="n">am</span><span class="p">)</span><span class="w">
</span><span class="n">rf</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">randomForest</span><span class="p">(</span><span class="n">am</span><span class="o">~</span><span class="n">.</span><span class="p">,</span><span class="w"> </span><span class="n">ntree</span><span class="o">=</span><span class="m">100</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="o">=</span><span class="n">mtcars</span><span class="p">)</span><span class="w">
</span><span class="cd">#' Here's the resulting confusion matrix on the training data. Not very clear to a non-technical or non-forest savvy audience.</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="n">rf</span><span class="p">)</span><span class="w">
</span><span class="cd">#' ### Dynamic comments</span><span class="w">
</span><span class="cd">#' We can get fancy and actually dynamically generate some commentary around these results. That is we can auto-fill parts of our document text</span><span class="w">
</span><span class="cd">#' with objects from the R environment. This could be useful with analyses that involve stochastic </span><span class="w">
</span><span class="cd">#' elements changing from run to run like random forest. Or any analysis where results are subject to change. </span><span class="w">
</span><span class="cd">#' <br> </span><span class="w">
</span><span class="cd">#' `r rf$confusion[1,1]` cars are correctly classified as 0. </span><span class="w">
</span><span class="cd">#' `r rf$confusion[2,2]` cars are correctly classified as 1. </span><span class="w">
</span><span class="cd">#' `r rf$confusion[1,2]` cars are misclassified as 1. </span><span class="w">
</span><span class="cd">#' `r rf$confusion[2,1]` cars are misclassified as 0. </span><span class="w">
</span><span class="cd">#' </span><span class="w">
</span><span class="cd">#' These numbers were generated by wrapping the R expression to excute into the ticks like so: </span><span class="w">
</span><span class="cd">#' I don't know how to write this within a `#'` comment without evaluating it, so I'm documenting here as a</span><span class="w">
</span><span class="cd">#' character string: </span><span class="w">
</span><span class="c1">#+ echo=F, eval=T</span><span class="w">
</span><span class="n">cat</span><span class="p">(</span><span class="s2">"#' `r rf$confusion[2,1]` cars are misclassified as 0. "</span><span class="p">)</span><span class="w">
</span><span class="cd">#' <br></span><span class="w">
</span><span class="cd">#' </span><span class="w">
</span><span class="cd">#' ### Generate comments in a loop</span><span class="w">
</span><span class="cd">#' </span><span class="w">
</span><span class="cd">#' This is useful if you want to generate lots of text without writing it manually. </span><span class="w">
</span><span class="cd">#' `#+ results='asis'`</span><span class="w">
</span><span class="c1">#+ results='asis'</span><span class="w">
</span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="m">10</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">rf</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">randomForest</span><span class="p">(</span><span class="n">am</span><span class="o">~</span><span class="n">.</span><span class="p">,</span><span class="w"> </span><span class="n">ntree</span><span class="o">=</span><span class="m">100</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="o">=</span><span class="n">mtcars</span><span class="p">)</span><span class="w">
</span><span class="n">cat</span><span class="p">(</span><span class="s2">"iteration "</span><span class="p">,</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="s2">": "</span><span class="p">,</span><span class="w"> </span><span class="n">rf</span><span class="o">$</span><span class="n">confusion</span><span class="p">[</span><span class="m">1</span><span class="p">,</span><span class="m">1</span><span class="p">],</span><span class="w"> </span><span class="s2">"cars are correctly classified as 0"</span><span class="p">,</span><span class="w"> </span><span class="s2">"\n"</span><span class="p">)</span><span class="w">
</span><span class="n">cat</span><span class="p">(</span><span class="s1">'\n'</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="cd">#' ## Toggle chunk settings globally by R variables</span><span class="w">
</span><span class="cd">#' Much like we used R objects to dynamically generate text to print in the document (in the form of comments),</span><span class="w">
</span><span class="cd">#' we can use R objects to dynamically specify chunk options. </span><span class="w">
</span><span class="cd">#' When we set `evaluateStuff` to `TRUE` or `FALSE`, the following 3 chunks will evaluate (or not) as we choose.</span><span class="w">
</span><span class="cd">#' We can toggle them all with one variable, instead of manually changing the chunk settings with `#+ eval=T`</span><span class="w">
</span><span class="cd">#' in the R script multiple times. Simply</span><span class="w">
</span><span class="cd">#' include the variable you want to execute in the chunk comments with ticks. </span><span class="w">
</span><span class="cd">#' Like so: **#+ eval=\`evaluateStuff\`**</span><span class="w">
</span><span class="n">evaluateStuff</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nb">T</span><span class="w">
</span><span class="c1">#+ eval=`evaluateStuff`</span><span class="w">
</span><span class="n">cat</span><span class="p">(</span><span class="s1">'first thing to evaluate'</span><span class="p">)</span><span class="w">
</span><span class="c1">#+ eval=`evaluateStuff`</span><span class="w">
</span><span class="n">cat</span><span class="p">(</span><span class="s1">'second thing to evaluate'</span><span class="p">)</span><span class="w">
</span><span class="c1">#+ eval=`evaluateStuff`</span><span class="w">
</span><span class="n">cat</span><span class="p">(</span><span class="s1">'third thing to evaluate'</span><span class="p">)</span><span class="w">
</span><span class="cd">#' <br></span><span class="w">
</span><span class="cd">#' Now let's just print the code and not evaluate anything.</span><span class="w">
</span><span class="n">evaluateStuff</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nb">F</span><span class="w">
</span><span class="c1">#+ eval=`evaluateStuff`</span><span class="w">
</span><span class="n">cat</span><span class="p">(</span><span class="s1">'first thing to evaluate'</span><span class="p">)</span><span class="w">
</span><span class="c1">#+ eval=`evaluateStuff`</span><span class="w">
</span><span class="n">cat</span><span class="p">(</span><span class="s1">'second thing to evaluate'</span><span class="p">)</span><span class="w">
</span><span class="c1">#+ eval=`evaluateStuff`</span><span class="w">
</span><span class="n">cat</span><span class="p">(</span><span class="s1">'third thing to evaluate'</span><span class="p">)</span><span class="w">
</span><span class="cd">#' ## Converting R Script to HTML/PDF </span><span class="w">
</span><span class="cd">#' If you did everyhing right, above this is the easy part. Simply render the script as desired with the `render` function from `rmarkdown`. </span><span class="w">
</span><span class="cd">#' `rmarkdown::render('/Users/you/Documents/yourscript.R')`</span></code></pre></figure>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/render-reports-directly-from-R-scripts/">Render reports directly from R scripts</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on March 05, 2015.</p>http://brooksandrew.github.io/simpleblog/articles/blogging-with-r-markdown-and-jekyll-using-knitr2015-01-25T00:00:00+00:002015-01-25T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<h4 id="use-knitr">use knitr</h4>
<p>One way to blog using R and Jekyll is to copy and paste every code chunk, output and plot into a plain vanilla markdown file by hand. This is cumbersome, especially for plots which need to be saved as images and embedded. I tried this for my first few posts. It was clunky.</p>
<p>A more seamless solution is to use <a href="http://yihui.name/knitr/">knitr</a> to convert <a href="http://rmarkdown.rstudio.com/">R Markdown</a> files to Jekyll friendly markdown files. Knitr allows you to write your entire post in R Markdown utilizing all the features of traditional markdown while conveniently running your code, printing your output and displaying your charts. And it looks fresh.</p>
<h4 id="rmd--jekyll-markdown">Rmd ==> Jekyll markdown</h4>
<p>Knitr is good at transforming R Markdown to HTML, PDF or even Word files. Jekyll is good at turning traditional/Jekyll markdown to HTML (your website). There might be an elegant way to shove the HTML generated by knitr into a jekyll site, but I haven’t found one. I found it much easier to convert R Markdown to its close cousin of markdown that is compatible with Jekyll. This conversion really just boils down to handling the R chunks: saving the plots as SVGs, formatting the code chunks with R syntax highlighting and printing the output for selected chunks.</p>
<p>A convenient feature provided in knitr is the ability to suppress code, messages, warnings, errors and output printed to the console for specific code chunks using the <code class="highlighter-rouge">echo</code>, <code class="highlighter-rouge">message</code>, <code class="highlighter-rouge">warning</code>, <code class="highlighter-rouge">error</code> and <code class="highlighter-rouge">eval</code> parameters respectively.</p>
<h4 id="fuzzy-middle">fuzzy middle</h4>
<p>I tried a few approaches, but this one from <a href="http://chepec.se/2014/07/16/knitr-jekyll.html">chepec</a> both worked the best and made the most sense to me. I had to make a couple adjustments to make it work for my setup, but they were small and included below. As I started generating more posts from R Markdown, I found a need to overwrite specific posts (rather than all or none). So I added a parameter <code class="highlighter-rouge">overwriteOne</code> which takes a string input and will overwrite any post that partially matches it (a simple <code class="highlighter-rouge">grep</code> ignoring case). However, my additions are trivial – all the credit goes to <a href="http://chepec.se/2014/07/16/knitr-jekyll.html">chepec</a>.</p>
<h4 id="how-to-use-knitpost">how to use KnitPost</h4>
<ol>
<li>Configure the directories at the top of <code class="highlighter-rouge">KnitPost</code> to match the file system of your blog. I could have included these as parameters, but I figured I wouldn’t re-architect my blog very often… so I left them hard-coded.</li>
<li>Create an R Markdown post and save it as a <code class="highlighter-rouge">.Rmd</code> file in <code class="highlighter-rouge">rmd.path</code>. Be sure to include the proper YAML front matter for Jekyll. This tripped me up initially. I forgot to change the date from the knitr style date (“Month, day YYYY”) that auto-generates when you create a new .Rmd to a Jekyll style date (‘YYYY-MM-DD’).</li>
<li>Run <code class="highlighter-rouge">KnitPost</code> to publish your R Markdown file.</li>
</ol>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">KnitPost</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">site.path</span><span class="o">=</span><span class="s1">'/pathToYourBlog/'</span><span class="p">,</span><span class="w"> </span><span class="n">overwriteAll</span><span class="o">=</span><span class="nb">F</span><span class="p">,</span><span class="w"> </span><span class="n">overwriteOne</span><span class="o">=</span><span class="kc">NULL</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="s1">'package:knitr'</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="n">search</span><span class="p">())</span><span class="w"> </span><span class="n">library</span><span class="p">(</span><span class="s1">'knitr'</span><span class="p">)</span><span class="w">
</span><span class="c1">## Blog-specific directories. This will depend on how you organize your blog.</span><span class="w">
</span><span class="n">site.path</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">site.path</span><span class="w"> </span><span class="c1"># directory of jekyll blog (including trailing slash)</span><span class="w">
</span><span class="n">rmd.path</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">paste0</span><span class="p">(</span><span class="n">site.path</span><span class="p">,</span><span class="w"> </span><span class="s2">"_Rmd"</span><span class="p">)</span><span class="w"> </span><span class="c1"># directory where your Rmd-files reside (relative to base)</span><span class="w">
</span><span class="n">fig.dir</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"assets/Rfig/"</span><span class="w"> </span><span class="c1"># directory to save figures</span><span class="w">
</span><span class="n">posts.path</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">paste0</span><span class="p">(</span><span class="n">site.path</span><span class="p">,</span><span class="w"> </span><span class="s2">"_posts/articles/"</span><span class="p">)</span><span class="w"> </span><span class="c1"># directory for converted markdown files</span><span class="w">
</span><span class="n">cache.path</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">paste0</span><span class="p">(</span><span class="n">site.path</span><span class="p">,</span><span class="w"> </span><span class="s2">"_cache"</span><span class="p">)</span><span class="w"> </span><span class="c1"># necessary for plots</span><span class="w">
</span><span class="n">render_jekyll</span><span class="p">(</span><span class="n">highlight</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"pygments"</span><span class="p">)</span><span class="w">
</span><span class="n">opts_knit</span><span class="o">$</span><span class="n">set</span><span class="p">(</span><span class="n">base.url</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'/'</span><span class="p">,</span><span class="w"> </span><span class="n">base.dir</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">site.path</span><span class="p">)</span><span class="w">
</span><span class="n">opts_chunk</span><span class="o">$</span><span class="n">set</span><span class="p">(</span><span class="n">fig.path</span><span class="o">=</span><span class="n">fig.dir</span><span class="p">,</span><span class="w"> </span><span class="n">fig.width</span><span class="o">=</span><span class="m">8.5</span><span class="p">,</span><span class="w"> </span><span class="n">fig.height</span><span class="o">=</span><span class="m">5.25</span><span class="p">,</span><span class="w"> </span><span class="n">dev</span><span class="o">=</span><span class="s1">'svg'</span><span class="p">,</span><span class="w"> </span><span class="n">cache</span><span class="o">=</span><span class="nb">F</span><span class="p">,</span><span class="w">
</span><span class="n">warning</span><span class="o">=</span><span class="nb">F</span><span class="p">,</span><span class="w"> </span><span class="n">message</span><span class="o">=</span><span class="nb">F</span><span class="p">,</span><span class="w"> </span><span class="n">cache.path</span><span class="o">=</span><span class="n">cache.path</span><span class="p">,</span><span class="w"> </span><span class="n">tidy</span><span class="o">=</span><span class="nb">F</span><span class="p">)</span><span class="w">
</span><span class="n">setwd</span><span class="p">(</span><span class="n">rmd.path</span><span class="p">)</span><span class="w"> </span><span class="c1"># setwd to base</span><span class="w">
</span><span class="c1"># some logic to help us avoid overwriting already existing md files</span><span class="w">
</span><span class="n">files.rmd</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.frame</span><span class="p">(</span><span class="n">rmd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">list.files</span><span class="p">(</span><span class="n">path</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">rmd.path</span><span class="p">,</span><span class="w">
</span><span class="n">full.names</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">T</span><span class="p">,</span><span class="w">
</span><span class="n">pattern</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"\\.Rmd$"</span><span class="p">,</span><span class="w">
</span><span class="n">ignore.case</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">T</span><span class="p">,</span><span class="w">
</span><span class="n">recursive</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">F</span><span class="p">),</span><span class="w"> </span><span class="n">stringsAsFactors</span><span class="o">=</span><span class="nb">F</span><span class="p">)</span><span class="w">
</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">corresponding.md.file</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">paste0</span><span class="p">(</span><span class="n">posts.path</span><span class="p">,</span><span class="w"> </span><span class="s2">"/"</span><span class="p">,</span><span class="w"> </span><span class="n">basename</span><span class="p">(</span><span class="n">gsub</span><span class="p">(</span><span class="n">pattern</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"\\.Rmd$"</span><span class="p">,</span><span class="w"> </span><span class="n">replacement</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">".md"</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">files.rmd</span><span class="o">$</span><span class="n">rmd</span><span class="p">)))</span><span class="w">
</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">corresponding.md.exists</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">file.exists</span><span class="p">(</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">corresponding.md.file</span><span class="p">)</span><span class="w">
</span><span class="c1">## determining which posts to overwrite from parameters overwriteOne & overwriteAll</span><span class="w">
</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">md.overwriteAll</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">overwriteAll</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="nf">is.null</span><span class="p">(</span><span class="n">overwriteOne</span><span class="p">)</span><span class="o">==</span><span class="nb">F</span><span class="p">)</span><span class="w"> </span><span class="n">files.rmd</span><span class="o">$</span><span class="n">md.overwriteAll</span><span class="p">[</span><span class="n">grep</span><span class="p">(</span><span class="n">overwriteOne</span><span class="p">,</span><span class="w"> </span><span class="n">files.rmd</span><span class="p">[,</span><span class="s1">'rmd'</span><span class="p">],</span><span class="w"> </span><span class="n">ignore.case</span><span class="o">=</span><span class="nb">T</span><span class="p">)]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nb">T</span><span class="w">
</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">md.render</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nb">F</span><span class="w">
</span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="nf">dim</span><span class="p">(</span><span class="n">files.rmd</span><span class="p">)[</span><span class="m">1</span><span class="p">])</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">corresponding.md.exists</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">F</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">md.render</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nb">T</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="k">if</span><span class="w"> </span><span class="p">((</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">corresponding.md.exists</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">T</span><span class="p">)</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="p">(</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">md.overwriteAll</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">T</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">md.render</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nb">T</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c1"># For each Rmd file, render markdown (contingent on the flags set above)</span><span class="w">
</span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="nf">dim</span><span class="p">(</span><span class="n">files.rmd</span><span class="p">)[</span><span class="m">1</span><span class="p">])</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">md.render</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">T</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">out.file</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">knit</span><span class="p">(</span><span class="nf">as.character</span><span class="p">(</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">rmd</span><span class="p">[</span><span class="n">i</span><span class="p">]),</span><span class="w">
</span><span class="n">output</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">as.character</span><span class="p">(</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">corresponding.md.file</span><span class="p">[</span><span class="n">i</span><span class="p">]),</span><span class="w">
</span><span class="n">envir</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parent.frame</span><span class="p">(),</span><span class="w">
</span><span class="n">quiet</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">T</span><span class="p">)</span><span class="w">
</span><span class="n">message</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="s2">"KnitPost(): "</span><span class="p">,</span><span class="w"> </span><span class="n">basename</span><span class="p">(</span><span class="n">files.rmd</span><span class="o">$</span><span class="n">rmd</span><span class="p">[</span><span class="n">i</span><span class="p">])))</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/blogging-with-r-markdown-and-jekyll-using-knitr/">Blogging with Jekyll and R Markdown using knitr</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on January 25, 2015.</p>http://brooksandrew.github.io/simpleblog/articles/latent-dirichlet-allocation-under-the-hood2015-01-17T00:00:00+00:002015-01-17T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<h3 id="lda-for-mortals">LDA for mortals</h3>
<p>I’ve been intrigued by LDA topic models for a few weeks now. I actually built one before I really knew what I was doing. That kind of frightens and excites me. On one hand, LDA provides rich output which is easy for the humanist researcher to interpret. On the other hand, shouldn’t I know what kind of machinery I’m operating that’s spitting out results? I would certainly like to know more than what’s provided in documentation of whatever software implementation I’m using (currently <a href="http://radimrehurek.com/gensim/models/ldamodel.html">gensim</a>), but I don’t necessarily need to be able to prove every last algorithm before I kick the tires and start building models.</p>
<p>I echo <a href="http://tedunderwood.com/2012/04/07/topic-modeling-made-just-simple-enough/">Ted Underwood</a>’s observation that it can be difficult to develop a basic intuition of LDA from the hardcore computer science literature. Proving that it works, understanding how it works, and making it work, are very different things. My goal for this exercise was to bridge the gaps in my brain between the technical theoretical papers and the high level LDA articles out there by developing a rudimentary LDA model from scratch.</p>
<h3 id="generative-so-what">Generative, so what?</h3>
<p>Most academic papers I encountered begin by describing LDA as a generative model. That is, a model that can randomly generate observable data (documents). <a href="http://machinelearning.wustl.edu/mlpapers/paper_files/BleiNJ03.pdf">Blei, Ng, & Jordan, 2003</a> outline this process in their seminal paper on the topic:</p>
<blockquote>
<p>LDA assumes the following generative process for each document w in a corpus D:</p>
<ol>
<li>Choose N ∼ Poisson(ξ).</li>
<li>Choose θ ∼ Dir(α).</li>
<li>For each of the N words w<sub>n</sub>:<br />
(a) Choose a topic z<sub>n</sub> ∼ Multinomial(θ).<br />
(b) Choose a word w<sub>n</sub> from p(w<sub>n</sub> | z<sub>n</sub> ,β), a multinomial probability conditioned on the topic z<sub>n</sub>.</li>
</ol>
</blockquote>
<p>I found this confusing at first. I was initially mixing up the generative and inference/training algorithms. They are different, very different. I already have my documents…why would I want to probabilistically generate new documents with my LDA model? Short answer, you probably don’t. However, the generative approach lets you do some cool things:</p>
<ul>
<li>Assign probabilities to just about everything: words, documents and topics. <a href="http://en.wikipedia.org/wiki/Probabilistic_latent_semantic_analysis">Probabilistic Latent Semantic Indexing</a> (pLSI), the precursor to LDA, pushed some boundaries in information retrieval, but fell short in providing a probabilistic model at the document level.</li>
<li>The ability to calculate probabilities (topic assignments) for previously unseen documents, which is not possible with pLSI.</li>
<li>Model updates. That is, you can continue training your model with new documents when they come in without repeatedly starting from scratch and re-training on the full corpus. <a href="http://en.wikipedia.org/wiki/Online_machine_learning">Online learning</a> should be supported in most LDA implementations.</li>
</ul>
<p>There is even some new research (<a href="http://jmlr.org/proceedings/papers/v28/zhai13.pdf">Zhai and Boyd-Graber, 2013</a>) exploring breeds of LDA that allow for infinite vocabularies – assigning probabilities to new documents with words outside of the training vocabulary.</p>
<h3 id="statistical-inference-how-we-actually-train-an-lda-model">Statistical inference… how we actually train an LDA model</h3>
<p>So the goal of LDA is to compute the 2 hidden parameters often commonly denoted as θ and φ, where θ represents topic-document distribution and φ represents the word-topic distribution.</p>
<p>However, when you do some fancy math, it becomes clear that the posterior distribution for these parameters is intractable. That is, we’re left with integrals that we cannot compute analytically in high dimensional space where numerical approximation gets hairy. How to handle this issue is the topic of a large swath of the LDA literature. It seems that most advocate one of two methods:</p>
<ul>
<li><strong>Variational inference</strong> seems to be the preferred method for getting fast and accurate results in most software implementations.</li>
<li><strong>Markov chain Monte Carlo (sampling)</strong> methods have the benefit of being unbiased and easy understand. However, it seems MCMCs are handicapped by being computationally inefficient when working with large corpora.</li>
</ul>
<h3 id="building-lda-from-scratch">Building LDA from scratch</h3>
<h6 id="purpose">Purpose</h6>
<p>I have no intention for anyone (including myself) to use this code for anything beyond pedagogical purposes. There are countless ways to optimize the following approach. I simply wanted to put the theory into action as clearly as possible and dispel any myths in my head that LDA is black magic. I leave the implementation and optimization to the experts.</p>
<h6 id="getting-started">Getting started</h6>
<p>Of all the academic papers I read trying to wrap my head around LDA, I found <a href="http://psiexp.ss.uci.edu/research/papers/SteyversGriffithsLSABookFormatted.pdf">Streyver & Griffith’s Probabilistic Topic Models</a> paper to be the most helpful for understanding implementation. <a href="http://psiexp.ss.uci.edu/research/papers/sciencetopics.pdf">Their 2004 paper, Finding Scientific Topics</a> that everyone seems to cite provides a more thorough derivation of the Baysesian magic, but I found their subsequent paper most useful. They clearly walk through how to conduct inference using Collapsed Gibbs Sampling which I translated into R code.</p>
<p><a href="http://blog.echen.me/2011/08/22/introduction-to-latent-dirichlet-allocation/">Edwin Chen’s Introduction to Latent Dirichlet Allocation post</a> provides an example of this process using Collapsed Gibbs Sampling in plain english which is a good place to start.</p>
<p>I did find some other homegrown R and Python implementations from <a href="https://github.com/shuyo/">Shuyo</a> and <a href="http://www.cs.princeton.edu/~mdhoffma/">Matt Hoffman</a> – also great resources. Especially Shuyo’s code which I modeled my implementation after.</p>
<h6 id="so-lets-code-it">So let’s code it</h6>
<p>I generated a very trivial corpus of 8 documents. To focus just on the LDA mechanics, I opted for the simplest of R objects: lists and matrices.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1">## Generate a corpus</span><span class="w">
</span><span class="n">rawdocs</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'eat turkey on turkey day holiday'</span><span class="p">,</span><span class="w">
</span><span class="s1">'i like to eat cake on holiday'</span><span class="p">,</span><span class="w">
</span><span class="s1">'turkey trot race on thanksgiving holiday'</span><span class="p">,</span><span class="w">
</span><span class="s1">'snail race the turtle'</span><span class="p">,</span><span class="w">
</span><span class="s1">'time travel space race'</span><span class="p">,</span><span class="w">
</span><span class="s1">'movie on thanksgiving'</span><span class="p">,</span><span class="w">
</span><span class="s1">'movie at air and space museum is cool movie'</span><span class="p">,</span><span class="w">
</span><span class="s1">'aspiring movie star'</span><span class="p">)</span><span class="w">
</span><span class="n">docs</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">strsplit</span><span class="p">(</span><span class="n">rawdocs</span><span class="p">,</span><span class="w"> </span><span class="n">split</span><span class="o">=</span><span class="s1">' '</span><span class="p">,</span><span class="w"> </span><span class="n">perl</span><span class="o">=</span><span class="nb">T</span><span class="p">)</span><span class="w"> </span><span class="c1"># generate a list of documents</span><span class="w">
</span><span class="c1">## PARAMETERS</span><span class="w">
</span><span class="n">K</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">2</span><span class="w"> </span><span class="c1"># number of topics</span><span class="w">
</span><span class="n">alpha</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="c1"># hyperparameter. single value indicates symmetric dirichlet prior. higher=>scatters document clusters</span><span class="w">
</span><span class="n">eta</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">.001</span><span class="w"> </span><span class="c1"># hyperparameter</span><span class="w">
</span><span class="n">iterations</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="c1"># iterations for collapsed gibbs sampling. This should be a lot higher than 3 in practice.</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">print</span><span class="p">(</span><span class="n">docs</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [[1]]
## [1] "eat" "turkey" "on" "turkey" "day" "holiday"
##
## [[2]]
## [1] "i" "like" "to" "eat" "cake" "on" "holiday"
##
## [[3]]
## [1] "turkey" "trot" "race" "on"
## [5] "thanksgiving" "holiday"
##
## [[4]]
## [1] "snail" "race" "the" "turtle"
##
## [[5]]
## [1] "time" "travel" "space" "race"
##
## [[6]]
## [1] "movie" "on" "thanksgiving"
##
## [[7]]
## [1] "movie" "at" "air" "and" "space" "museum" "is" "cool"
## [9] "movie"
##
## [[8]]
## [1] "aspiring" "movie" "star"</code></pre></figure>
<p>Abstracting the words away - now we have a numbers problem.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1">## Assign WordIDs to each unique word</span><span class="w">
</span><span class="n">vocab</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">unique</span><span class="p">(</span><span class="n">unlist</span><span class="p">(</span><span class="n">docs</span><span class="p">))</span><span class="w">
</span><span class="c1">## Replace words in documents with wordIDs</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">docs</span><span class="p">))</span><span class="w"> </span><span class="n">docs</span><span class="p">[[</span><span class="n">i</span><span class="p">]]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">match</span><span class="p">(</span><span class="n">docs</span><span class="p">[[</span><span class="n">i</span><span class="p">]],</span><span class="w"> </span><span class="n">vocab</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">print</span><span class="p">(</span><span class="n">docs</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [[1]]
## [1] 1 2 3 2 4 5
##
## [[2]]
## [1] 6 7 8 1 9 3 5
##
## [[3]]
## [1] 2 10 11 3 12 5
##
## [[4]]
## [1] 13 11 14 15
##
## [[5]]
## [1] 16 17 18 11
##
## [[6]]
## [1] 19 3 12
##
## [[7]]
## [1] 19 20 21 22 18 23 24 25 19
##
## [[8]]
## [1] 26 19 27</code></pre></figure>
<p>Now we need to generate some basic count matrices. First we randomly assign topics to each word in each document. Then we create a word-topic count matrix.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1">## 1. Randomly assign topics to words in each doc. 2. Generate word-topic count matrix.</span><span class="w">
</span><span class="n">wt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">matrix</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">K</span><span class="p">,</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">vocab</span><span class="p">))</span><span class="w"> </span><span class="c1"># initialize word-topic count matrix</span><span class="w">
</span><span class="n">ta</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">docs</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="nf">rep</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">x</span><span class="p">)))</span><span class="w"> </span><span class="c1"># initialize topic assignment list</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">d</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">docs</span><span class="p">)){</span><span class="w"> </span><span class="c1"># for each document</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">w</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">docs</span><span class="p">[[</span><span class="n">d</span><span class="p">]])){</span><span class="w"> </span><span class="c1"># for each token in document d</span><span class="w">
</span><span class="n">ta</span><span class="p">[[</span><span class="n">d</span><span class="p">]][</span><span class="n">w</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sample</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">K</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="c1"># randomly assign topic to token w.</span><span class="w">
</span><span class="n">ti</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">ta</span><span class="p">[[</span><span class="n">d</span><span class="p">]][</span><span class="n">w</span><span class="p">]</span><span class="w"> </span><span class="c1"># topic index</span><span class="w">
</span><span class="n">wi</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">docs</span><span class="p">[[</span><span class="n">d</span><span class="p">]][</span><span class="n">w</span><span class="p">]</span><span class="w"> </span><span class="c1"># wordID for token w</span><span class="w">
</span><span class="n">wt</span><span class="p">[</span><span class="n">ti</span><span class="p">,</span><span class="n">wi</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">wt</span><span class="p">[</span><span class="n">ti</span><span class="p">,</span><span class="n">wi</span><span class="p">]</span><span class="m">+1</span><span class="w"> </span><span class="c1"># update word-topic count matrix </span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">print</span><span class="p">(</span><span class="n">wt</span><span class="p">)</span><span class="w"> </span><span class="c1"># Word-topic count matrix</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13]
## [1,] 2 2 0 0 1 1 0 0 1 1 2 1 0
## [2,] 0 1 4 1 2 0 1 1 0 0 1 1 1
## [,14] [,15] [,16] [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24]
## [1,] 0 0 0 0 2 1 0 1 1 1 1
## [2,] 1 1 1 1 0 3 1 0 0 0 0
## [,25] [,26] [,27]
## [1,] 1 0 0
## [2,] 0 1 1</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">print</span><span class="p">(</span><span class="n">ta</span><span class="p">)</span><span class="w"> </span><span class="c1"># Token-topic assignment list</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [[1]]
## [1] 1 1 2 1 2 2
##
## [[2]]
## [1] 1 2 2 1 1 2 1
##
## [[3]]
## [1] 2 1 1 2 2 2
##
## [[4]]
## [1] 2 2 2 2
##
## [[5]]
## [1] 2 2 1 1
##
## [[6]]
## [1] 2 2 1
##
## [[7]]
## [1] 1 2 1 1 1 1 1 1 2
##
## [[8]]
## [1] 2 2 2</code></pre></figure>
<p>Now we generate a document-topic count matrix where the counts correspond to the number of tokens assigned to each topic for each document.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">dt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">matrix</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">docs</span><span class="p">),</span><span class="w"> </span><span class="n">K</span><span class="p">)</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">d</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">docs</span><span class="p">)){</span><span class="w"> </span><span class="c1"># for each document d</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">t</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="n">K</span><span class="p">){</span><span class="w"> </span><span class="c1"># for each topic t</span><span class="w">
</span><span class="n">dt</span><span class="p">[</span><span class="n">d</span><span class="p">,</span><span class="n">t</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="n">ta</span><span class="p">[[</span><span class="n">d</span><span class="p">]]</span><span class="o">==</span><span class="n">t</span><span class="p">)</span><span class="w"> </span><span class="c1"># count tokens in document d assigned to topic t </span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">print</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span><span class="w"> </span><span class="c1"># document-topic count matrix</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [,1] [,2]
## [1,] 3 3
## [2,] 4 3
## [3,] 2 4
## [4,] 0 4
## [5,] 2 2
## [6,] 1 2
## [7,] 7 2
## [8,] 0 3</code></pre></figure>
<p>I’m beginning to mix notation from the code and theory. Oops. Anything in <em>italics</em> refers to theory. Anything in an <code class="highlighter-rouge">inline code block</code> refers to my iterators and objects in R code.</p>
<p>If following along with <a href="http://psiexp.ss.uci.edu/research/papers/SteyversGriffithsLSABookFormatted.pdf">Streyvers and Griffiths</a>, <code class="highlighter-rouge">wt</code> corresponds to the C<sup>WT</sup> matrix and <code class="highlighter-rouge">dt</code> corresponds to the C<sup>DT</sup> matrix.</p>
<p>Now we get to the fun part where LDA starts learning topics. We will iteratively update the random (bad) topic assignments we populated into <code class="highlighter-rouge">ta</code> one token at a time. This is where I had to brush up on my Bayesian statistics.</p>
<p>Rather than directly estimating our parameters of interest (φ and θ), we can directly esimate the posterior over <strong>z</strong> which represents topic assignments for each token. This is <code class="highlighter-rouge">p_z</code>, the full-conditional distribution for <strong>z</strong> which represents the probability that token <code class="highlighter-rouge">w</code> belongs to topic <code class="highlighter-rouge">t</code>.</p>
<p>The left side of <code class="highlighter-rouge">p_z</code> (<code class="highlighter-rouge">(wt[,wid] + eta) / denom_b</code>) represents the probability of word <code class="highlighter-rouge">w</code> under topic <code class="highlighter-rouge">t</code>. After many tokens of a word have been assigned to a particular topic, LDA increasingly wants to assign new occurrences of this token to that topic.</p>
<p>The right side of <code class="highlighter-rouge">p_z</code> (<code class="highlighter-rouge">(dt[d,] + alpha) / denom_a</code>) represents the probablity of topic <code class="highlighter-rouge">t</code> in document <code class="highlighter-rouge">d</code>. If many tokens in a document have been assigned to a particular topic, LDA wants to assign tokens to to that topic at each iteration of Gibbs Sampling.</p>
<p><strong>Example:</strong> So if 90% of the tokens in a document belong to topic 1 at the start of an iteration of Gibbs Sampling AND those same tokens in other documents are assigned to topic 1, it’s a no-brainer for LDA. Topic 1 it is.</p>
<p>However, if those 90% of tokens that belonged to topic 1 in our document all belong to topic 2 in the other documents, then it’s a toss-up and LDA is forced to spread the wealth across the two topics.</p>
<p>Defining some notation…</p>
<blockquote>
<p><code class="highlighter-rouge">p_z</code>=
P(<strong>z</strong><sub>i</sub> = j | <strong>z</strong><sub>-i</sub>, <strong>w</strong><sub>i</sub>, <strong>d</strong><sub>i</sub>)<br />
where<br />
P(<strong>z</strong><sub>i</sub> = j) is the probability that token i is assigned to topic j<br />
<strong>z</strong><sub>-i</sub> represents topic assignments of all other tokens<br />
<strong>w</strong><sub>i</sub> is the word index of token i (1…<code class="highlighter-rouge">length(vocab)</code>)<br />
<strong>d</strong><sub>i</sub> is the document index of token i (1…<code class="highlighter-rouge">length(docs)</code>)</p>
</blockquote>
<p>This is really the only “magic” part of the whole LDA learning process far. To dispel the magic and truly understand why this works read <a href="http://psiexp.ss.uci.edu/research/papers/sciencetopics.pdf">Griffiths and Streyvers</a> – they walk through the derivation of the full-conditional distribution (<code class="highlighter-rouge">p_z</code>) much more elegantly than I could.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="n">iterations</span><span class="p">){</span><span class="w"> </span><span class="c1"># for each pass through the corpus</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">d</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">docs</span><span class="p">)){</span><span class="w"> </span><span class="c1"># for each document</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">w</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">docs</span><span class="p">[[</span><span class="n">d</span><span class="p">]])){</span><span class="w"> </span><span class="c1"># for each token </span><span class="w">
</span><span class="n">t</span><span class="m">0</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">ta</span><span class="p">[[</span><span class="n">d</span><span class="p">]][</span><span class="n">w</span><span class="p">]</span><span class="w"> </span><span class="c1"># initial topic assignment to token w</span><span class="w">
</span><span class="n">wid</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">docs</span><span class="p">[[</span><span class="n">d</span><span class="p">]][</span><span class="n">w</span><span class="p">]</span><span class="w"> </span><span class="c1"># wordID of token w</span><span class="w">
</span><span class="n">dt</span><span class="p">[</span><span class="n">d</span><span class="p">,</span><span class="n">t</span><span class="m">0</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dt</span><span class="p">[</span><span class="n">d</span><span class="p">,</span><span class="n">t</span><span class="m">0</span><span class="p">]</span><span class="m">-1</span><span class="w"> </span><span class="c1"># we don't want to include token w in our document-topic count matrix when sampling for token w</span><span class="w">
</span><span class="n">wt</span><span class="p">[</span><span class="n">t</span><span class="m">0</span><span class="p">,</span><span class="n">wid</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">wt</span><span class="p">[</span><span class="n">t</span><span class="m">0</span><span class="p">,</span><span class="n">wid</span><span class="p">]</span><span class="m">-1</span><span class="w"> </span><span class="c1"># we don't want to include token w in our word-topic count matrix when sampling for token w</span><span class="w">
</span><span class="c1">## UPDATE TOPIC ASSIGNMENT FOR EACH WORD -- COLLAPSED GIBBS SAMPLING MAGIC. Where the magic happens.</span><span class="w">
</span><span class="n">denom_a</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="n">dt</span><span class="p">[</span><span class="n">d</span><span class="p">,])</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">K</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">alpha</span><span class="w"> </span><span class="c1"># number of tokens in document + number topics * alpha</span><span class="w">
</span><span class="n">denom_b</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">rowSums</span><span class="p">(</span><span class="n">wt</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">vocab</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">eta</span><span class="w"> </span><span class="c1"># number of tokens in each topic + # of words in vocab * eta</span><span class="w">
</span><span class="n">p_z</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="p">(</span><span class="n">wt</span><span class="p">[,</span><span class="n">wid</span><span class="p">]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">eta</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">denom_b</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="n">dt</span><span class="p">[</span><span class="n">d</span><span class="p">,]</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">alpha</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">denom_a</span><span class="w"> </span><span class="c1"># calculating probability word belongs to each topic</span><span class="w">
</span><span class="n">t</span><span class="m">1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sample</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">K</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">prob</span><span class="o">=</span><span class="n">p_z</span><span class="o">/</span><span class="nf">sum</span><span class="p">(</span><span class="n">p_z</span><span class="p">))</span><span class="w"> </span><span class="c1"># draw topic for word n from multinomial using probabilities calculated above</span><span class="w">
</span><span class="n">ta</span><span class="p">[[</span><span class="n">d</span><span class="p">]][</span><span class="n">w</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">t</span><span class="m">1</span><span class="w"> </span><span class="c1"># update topic assignment list with newly sampled topic for token w.</span><span class="w">
</span><span class="n">dt</span><span class="p">[</span><span class="n">d</span><span class="p">,</span><span class="n">t</span><span class="m">1</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dt</span><span class="p">[</span><span class="n">d</span><span class="p">,</span><span class="n">t</span><span class="m">1</span><span class="p">]</span><span class="m">+1</span><span class="w"> </span><span class="c1"># re-increment document-topic matrix with new topic assignment for token w.</span><span class="w">
</span><span class="n">wt</span><span class="p">[</span><span class="n">t</span><span class="m">1</span><span class="p">,</span><span class="n">wid</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">wt</span><span class="p">[</span><span class="n">t</span><span class="m">1</span><span class="p">,</span><span class="n">wid</span><span class="p">]</span><span class="m">+1</span><span class="w"> </span><span class="c1">#re-increment word-topic matrix with new topic assignment for token w.</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="n">t</span><span class="m">0</span><span class="o">!=</span><span class="n">t</span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="n">print</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="s1">'doc:'</span><span class="p">,</span><span class="w"> </span><span class="n">d</span><span class="p">,</span><span class="w"> </span><span class="s1">' token:'</span><span class="w"> </span><span class="p">,</span><span class="n">w</span><span class="p">,</span><span class="w"> </span><span class="s1">' topic:'</span><span class="p">,</span><span class="n">t</span><span class="m">0</span><span class="p">,</span><span class="s1">'=>'</span><span class="p">,</span><span class="n">t</span><span class="m">1</span><span class="p">))</span><span class="w"> </span><span class="c1"># examine when topic assignments change</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] "doc:1 token:2 topic:1=>2"
## [1] "doc:1 token:4 topic:1=>2"
## [1] "doc:1 token:5 topic:2=>1"
## [1] "doc:1 token:6 topic:2=>1"
## [1] "doc:2 token:1 topic:1=>2"
## [1] "doc:2 token:3 topic:2=>1"
## [1] "doc:3 token:2 topic:1=>2"
## [1] "doc:3 token:3 topic:1=>2"
## [1] "doc:3 token:5 topic:2=>1"
## [1] "doc:3 token:6 topic:2=>1"
## [1] "doc:5 token:1 topic:2=>1"
## [1] "doc:5 token:2 topic:2=>1"
## [1] "doc:5 token:4 topic:1=>2"
## [1] "doc:7 token:1 topic:1=>2"
## [1] "doc:7 token:2 topic:2=>1"
## [1] "doc:7 token:6 topic:1=>2"
## [1] "doc:7 token:7 topic:1=>2"
## [1] "doc:1 token:5 topic:1=>2"
## [1] "doc:2 token:2 topic:2=>1"
## [1] "doc:2 token:3 topic:1=>2"
## [1] "doc:2 token:5 topic:1=>2"
## [1] "doc:7 token:3 topic:1=>2"
## [1] "doc:7 token:4 topic:1=>2"
## [1] "doc:7 token:8 topic:1=>2"
## [1] "doc:8 token:1 topic:2=>1"
## [1] "doc:8 token:3 topic:2=>1"
## [1] "doc:1 token:5 topic:2=>1"
## [1] "doc:2 token:2 topic:1=>2"
## [1] "doc:2 token:3 topic:2=>1"
## [1] "doc:2 token:5 topic:2=>1"
## [1] "doc:4 token:4 topic:2=>1"
## [1] "doc:5 token:1 topic:1=>2"
## [1] "doc:5 token:2 topic:1=>2"
## [1] "doc:7 token:2 topic:1=>2"</code></pre></figure>
<p>The printed output above is a window into the learning process. We printed a line each time a token got reassigned to a new topic. Remember we only made 3 passes (<code class="highlighter-rouge">iterations <- 3</code>) through the corpus, so our topic assignments are likely still pretty terrible. In practice, with many more iterations, these re-assignments would eventually stabilize.</p>
<p>So now we’ve finished learning topics. We just have to analyze them. <code class="highlighter-rouge">theta</code> normalizes the counts in the document-topic count matrix <code class="highlighter-rouge">dt</code> to compute the probability that a document belongs to each topic. <code class="highlighter-rouge">theta</code> is technically the posterior mean of the parameter θ.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">theta</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="p">(</span><span class="n">dt</span><span class="o">+</span><span class="n">alpha</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="n">rowSums</span><span class="p">(</span><span class="n">dt</span><span class="o">+</span><span class="n">alpha</span><span class="p">)</span><span class="w"> </span><span class="c1"># topic probabilities per document</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="n">theta</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [,1] [,2]
## [1,] 0.5000 0.5000
## [2,] 0.5556 0.4444
## [3,] 0.3750 0.6250
## [4,] 0.3333 0.6667
## [5,] 0.3333 0.6667
## [6,] 0.4000 0.6000
## [7,] 0.1818 0.8182
## [8,] 0.6000 0.4000</code></pre></figure>
<p><code class="highlighter-rouge">phi</code> normalizes the word-topic count matrix <code class="highlighter-rouge">wt</code> to compute the probabilities of words given topics. <code class="highlighter-rouge">phi</code> is technically the posterior mean of the parameter φ.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">phi</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="p">(</span><span class="n">wt</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">eta</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="p">(</span><span class="n">rowSums</span><span class="p">(</span><span class="n">wt</span><span class="o">+</span><span class="n">eta</span><span class="p">))</span><span class="w"> </span><span class="c1"># topic probabilities per word</span><span class="w">
</span><span class="n">colnames</span><span class="p">(</span><span class="n">phi</span><span class="p">)</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">vocab</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="n">phi</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## eat turkey on day holiday i like
## [1,] 0.133160 6.655e-05 6.655e-05 0.066613 0.199707 6.655e-05 6.655e-05
## [2,] 0.000037 1.110e-01 1.480e-01 0.000037 0.000037 3.704e-02 3.704e-02
## to cake trot race thanksgiving snail
## [1,] 0.066613 0.066613 6.655e-05 6.655e-05 0.133160 6.655e-05
## [2,] 0.000037 0.000037 3.704e-02 1.110e-01 0.000037 3.704e-02
## the turtle time travel space movie at
## [1,] 6.655e-05 0.066613 6.655e-05 6.655e-05 0.133160 6.655e-05 6.655e-05
## [2,] 3.704e-02 0.000037 3.704e-02 3.704e-02 0.000037 1.480e-01 3.704e-02
## air and museum is cool aspiring star
## [1,] 6.655e-05 6.655e-05 6.655e-05 6.655e-05 6.655e-05 0.066613 0.066613
## [2,] 3.704e-02 3.704e-02 3.704e-02 3.704e-02 3.704e-02 0.000037 0.000037</code></pre></figure>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/latent-dirichlet-allocation-under-the-hood/">Latent Dirichlet Allocation - under the hood</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on January 17, 2015.</p>http://brooksandrew.github.io/simpleblog/articles/new-york-times-api-to-mongodb2015-01-06T00:00:00+00:002015-01-06T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<ul id="markdown-toc">
<li><a href="#motivation" id="markdown-toc-motivation">Motivation</a></li>
<li><a href="#accessing-nyt-api" id="markdown-toc-accessing-nyt-api">Accessing NYT API</a></li>
<li><a href="#extracting-and-parsing-the-article-body-text" id="markdown-toc-extracting-and-parsing-the-article-body-text">Extracting and parsing the article body text</a></li>
<li><a href="#writing-to-mongodb" id="markdown-toc-writing-to-mongodb">Writing to MongoDB</a></li>
<li><a href="#pipeline" id="markdown-toc-pipeline">Pipeline</a></li>
<li><a href="#results" id="markdown-toc-results">Results</a></li>
</ul>
<h2 id="motivation">Motivation</h2>
<p>I’ve learned a little about a lot of different corners of the text mining and NLP world over the last few years… which sometimes makes me feel like I know nothing for certain. I’ve done a decent amount web scraping, processing HTML and parsing text recently, but never a full blown text mining project. I decided to start with some topic modeling using Latent Dirichlet Allocation and document clustering. Unsupervised learning techniques requiring minimal upfront work beyond the text pre-processing seemed like a good (and interesting) place to get started.</p>
<p>After surveying APIs for a few news sources, the New York Times seemed to be the most robust. I wanted the flexibility to acquire new documents in the future for testing models and from far enough in the past to build a hefty corpus. I also wanted to have some fun and scrape the documents myself, experiment with a NoSQL database pipeline and process the HTML from the rawest form.</p>
<h2 id="accessing-nyt-api">Accessing NYT API</h2>
<h5 id="api-documentation-and-keys">API Documentation and keys</h5>
<p>The <a href="http://developer.nytimes.com/docs/read/article_search_api_v2">New York Times API</a> is well documented and user-friendly. I didn’t experiment too much with targeted querying since I was pulling all articles over a period of time. However the <code class="highlighter-rouge">q</code> and <code class="highlighter-rouge">fq</code> parameters seem to provide a lot of functionality for filtered searches.</p>
<p>Requesting an a key for the Article Search API was easy and instantaneous. I saved my key as a global parameter using R options. I’m using <code class="highlighter-rouge">sample-key</code> here simply for illustrative purposes, but I found that this key (provided by default in the <a href="http://developer.nytimes.com/io-docs">NYT API Console</a>) actually works.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">options</span><span class="p">(</span><span class="n">nyt_as_key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'sample-key'</span><span class="p">)</span><span class="w"> </span><span class="c1">## copy and paste your API key here.</span><span class="w">
</span><span class="n">options</span><span class="p">()</span><span class="o">$</span><span class="n">nyt_as_key</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] "sample-key"</code></pre></figure>
<p>The <a href="http://developer.nytimes.com/io-docs">NYT API Console</a> is also a nifty way to kick the tires and understand the parameters at your disposal for constructing queries. It’s basically a GUI around the API which gives you everything you need on one page to quickly formulate a query, submit it and inspect the response. It also allowed me to quickly determine that this is a well developed and documented API worthy of pursuing further. I wish all APIs were like this… sigh.</p>
<h5 id="generate-url">Generate URL</h5>
<p>This is the easy part. I did find an R package <a href="https://github.com/ropengov/rtimes">rtimes</a> for accessing the API which worked for the few queries I tried. However, I had already started building my own pipeline, so I stuck with it.</p>
<p>The NYT API returns only 10 articles per request. Which 10 are dictated by the <code class="highlighter-rouge">page</code> parameter. <code class="highlighter-rouge">page=0</code> returns articles 1-10, <code class="highlighter-rouge">page=1</code> returns articles 11-20, etc. The tricky part is knowing how many pages to iterate through. On my first pass, I failed to find a way to figure out the total number of articles matching my query to tell me how many pages and API requests I would need. So instead, I simply started my requests with <code class="highlighter-rouge">page=0</code> and incrementally added 1 to <code class="highlighter-rouge">page</code> until the response stopped yielding articles.</p>
<p>However, after I already maxed out my database, I found a way to do this using the <code class="highlighter-rouge">facet_field</code> and <code class="highlighter-rouge">facet_filter</code> parameters. These can be used to count the number of articles matching a filtered query by simply adding <code class="highlighter-rouge">&facet_field=source&facet_filter=true</code> to your query URL.</p>
<p>And you get something like this:</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="p">{</span><span class="w">
</span><span class="s2">"facets"</span><span class="o">:</span><span class="p">{</span><span class="w">
</span><span class="s2">"source"</span><span class="o">:</span><span class="p">{</span><span class="w">
</span><span class="s2">"terms"</span><span class="o">:</span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="s2">"term"</span><span class="o">:</span><span class="s2">"The New York Times"</span><span class="p">,</span><span class="w">
</span><span class="s2">"count"</span><span class="o">:</span><span class="m">159</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="s2">"term"</span><span class="o">:</span><span class="s2">"International Herald Tribune"</span><span class="p">,</span><span class="w">
</span><span class="s2">"count"</span><span class="o">:</span><span class="m">7</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="s2">"term"</span><span class="o">:</span><span class="s2">""</span><span class="p">,</span><span class="w">
</span><span class="s2">"count"</span><span class="o">:</span><span class="m">1</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="s2">"status"</span><span class="o">:</span><span class="s2">"OK"</span><span class="p">,</span><span class="w">
</span><span class="s2">"copyright"</span><span class="o">:</span><span class="s2">"Copyright (c) 2013 The New York Times Company. All Rights Reserved."</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<p>Here’s an example using R and httr to get the same result<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup>. These counts almost perfectly match the counts I’ve calculated from my collection for the New York Times and International Herald Tribune. However, I’ve collected a lot of Reuters and AP articles from the Article Search API that interestingly don’t appear here.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="s1">'httr'</span><span class="p">)</span><span class="w">
</span><span class="n">resp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">GET</span><span class="p">(</span><span class="s1">'http://api.nytimes.com/svc/search/v2/articlesearch.json?facet_field=source&facet_filter=true&begin_date=20130105&end_date=20130105&api-key=sample-key'</span><span class="p">)</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="n">content</span><span class="p">(</span><span class="n">resp</span><span class="p">,</span><span class="w"> </span><span class="s1">'parsed'</span><span class="p">)</span><span class="o">$</span><span class="n">response</span><span class="o">$</span><span class="n">facets</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## $source
## $source$terms
## $source$terms[[1]]
## $source$terms[[1]]$term
## [1] "The New York Times"
##
## $source$terms[[1]]$count
## [1] 159
##
##
## $source$terms[[2]]
## $source$terms[[2]]$term
## [1] "International Herald Tribune"
##
## $source$terms[[2]]$count
## [1] 7
##
##
## $source$terms[[3]]
## $source$terms[[3]]$term
## [1] ""
##
## $source$terms[[3]]$count
## [1] 1</code></pre></figure>
<p>Another rub is that “pagination beyond page 100 is not allowed at this time.” So if you’re extracting large quantities of articles, best do it chunks. I chunked my queries into single days – usually returning about 700-800 articles. Without using any facets or query terms, I ran the risk of only collecting 1000 articles for a day when there were more than 1000. This occurred 12 days out of 120 for me.</p>
<p><code class="highlighter-rouge">makeURL</code> is a pretty trivial function that generates the URL to make the GET request from a collection of NYT API parameters. However, I found encapsulating this step in a function which gets called in subsequent functions kept things clean.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">makeURL</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">q</span><span class="o">=</span><span class="kc">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">fq</span><span class="o">=</span><span class="kc">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">begin_date</span><span class="o">=</span><span class="kc">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">end_date</span><span class="o">=</span><span class="kc">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="o">=</span><span class="n">getOption</span><span class="p">(</span><span class="s2">"nyt_as_key"</span><span class="p">),</span><span class="w"> </span><span class="n">page</span><span class="o">=</span><span class="m">0</span><span class="p">,</span><span class="w">
</span><span class="n">sort</span><span class="o">=</span><span class="kc">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">fl</span><span class="o">=</span><span class="kc">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">hl</span><span class="o">=</span><span class="kc">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">facet_field</span><span class="o">=</span><span class="kc">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">facet_filter</span><span class="o">=</span><span class="kc">NULL</span><span class="p">){</span><span class="w">
</span><span class="n">arglist</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="n">q</span><span class="o">=</span><span class="n">q</span><span class="p">,</span><span class="w"> </span><span class="n">fq</span><span class="o">=</span><span class="n">fq</span><span class="p">,</span><span class="w"> </span><span class="n">begin_date</span><span class="o">=</span><span class="n">begin_date</span><span class="p">,</span><span class="w"> </span><span class="n">end_date</span><span class="o">=</span><span class="n">end_date</span><span class="p">,</span><span class="w"> </span><span class="s1">'api-key'</span><span class="o">=</span><span class="n">key</span><span class="p">,</span><span class="w"> </span><span class="n">page</span><span class="o">=</span><span class="n">page</span><span class="p">,</span><span class="w">
</span><span class="n">sort</span><span class="o">=</span><span class="n">sort</span><span class="p">,</span><span class="w"> </span><span class="n">fl</span><span class="o">=</span><span class="n">fl</span><span class="p">,</span><span class="w"> </span><span class="n">hl</span><span class="o">=</span><span class="n">hl</span><span class="p">,</span><span class="w"> </span><span class="n">facet_field</span><span class="o">=</span><span class="n">facet_field</span><span class="p">,</span><span class="w"> </span><span class="n">facet_filter</span><span class="o">=</span><span class="n">facet_filter</span><span class="p">)</span><span class="w">
</span><span class="n">url</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s1">'http://api.nytimes.com/svc/search/v2/articlesearch.json?'</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">arglist</span><span class="p">)){</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="nf">is.null</span><span class="p">(</span><span class="n">unlist</span><span class="p">(</span><span class="n">arglist</span><span class="p">[</span><span class="n">i</span><span class="p">]))</span><span class="o">==</span><span class="nb">F</span><span class="p">){</span><span class="w">
</span><span class="n">url</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">paste0</span><span class="p">(</span><span class="n">url</span><span class="p">,</span><span class="w"> </span><span class="s1">'&'</span><span class="p">,</span><span class="w"> </span><span class="nf">names</span><span class="p">(</span><span class="n">arglist</span><span class="p">[</span><span class="n">i</span><span class="p">]),</span><span class="w"> </span><span class="s1">'='</span><span class="p">,</span><span class="w"> </span><span class="n">arglist</span><span class="p">[</span><span class="n">i</span><span class="p">])</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nf">return</span><span class="p">(</span><span class="n">url</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c1">## example: generate query which will return all articles for one day.</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'httr'</span><span class="p">)</span><span class="w">
</span><span class="n">url</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">makeURL</span><span class="p">(</span><span class="n">begin_date</span><span class="o">=</span><span class="s1">'20130101'</span><span class="p">,</span><span class="w"> </span><span class="n">end_date</span><span class="o">=</span><span class="s1">'20130102'</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="o">=</span><span class="s1">'sample-key'</span><span class="p">,</span><span class="w"> </span><span class="n">page</span><span class="o">=</span><span class="m">100</span><span class="p">)</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="n">url</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] "http://api.nytimes.com/svc/search/v2/articlesearch.json?&begin_date=20130101&end_date=20130102&api-key=sample-key&page=100"</code></pre></figure>
<h5 id="scrape-nyt-metadata">Scrape NYT metadata</h5>
<p>Here in <code class="highlighter-rouge">getMeta</code> we’re actually collecting the NYT article metadata and structuring it as a list object. Like most things, the meat of it is pretty simple. The rest is parsing, exception and error handling… which I find are worth it with web scraping, especially if you’re running a job overnight and want it to work by the time you wake up.</p>
<p><code class="highlighter-rouge">getMeta</code>:</p>
<ul>
<li>DOES iterate through <code class="highlighter-rouge">pages</code> until no new articles are returned.</li>
<li>DOES sleep for <code class="highlighter-rouge">sleep</code> seconds after each request. I had good luck with <code class="highlighter-rouge">sleep=0.1</code>.</li>
<li>DOES re-attempt failed requests <code class="highlighter-rouge">tryn</code> times. Failed requests were almost always successful after the second try, so I set <code class="highlighter-rouge">tryn=3</code> just to be safe.</li>
<li>DOES NOT cache responses to disc. Everything is saved in memory and returned as a list in R memory after the function is complete. I opted not to bother with caching with this step as it only takes ~20 seconds to run through 100 API calls (the max per query).</li>
</ul>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="s1">'httr'</span><span class="p">)</span><span class="w">
</span><span class="n">getMeta</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">url</span><span class="p">,</span><span class="w"> </span><span class="n">pages</span><span class="o">=</span><span class="kc">Inf</span><span class="p">,</span><span class="w"> </span><span class="n">sleep</span><span class="o">=</span><span class="m">0.1</span><span class="p">,</span><span class="w"> </span><span class="n">tryn</span><span class="o">=</span><span class="m">3</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">art</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">list</span><span class="p">()</span><span class="w">
</span><span class="n">i</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">1</span><span class="w">
</span><span class="n">e</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">seq</span><span class="p">(</span><span class="o">-</span><span class="n">tryn</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="n">tryn</span><span class="o">/</span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">length.out</span><span class="o">=</span><span class="n">tryn</span><span class="p">)</span><span class="w"> </span><span class="c1"># initialize list of failed pages with arbitrary negative numbers</span><span class="w">
</span><span class="k">while</span><span class="p">(</span><span class="n">i</span><span class="o"><=</span><span class="n">pages</span><span class="p">){</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">unique</span><span class="p">(</span><span class="n">e</span><span class="p">[(</span><span class="nf">length</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">-</span><span class="p">(</span><span class="n">tryn</span><span class="m">-1</span><span class="p">))</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">e</span><span class="p">)]))</span><span class="o">==</span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">i</span><span class="m">+1</span><span class="w"> </span><span class="c1">## attempt tryn times before moving on</span><span class="w">
</span><span class="n">tryget</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">try</span><span class="p">({</span><span class="w">
</span><span class="n">urlp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">gsub</span><span class="p">(</span><span class="s1">'page=\\d+'</span><span class="p">,</span><span class="w"> </span><span class="n">paste0</span><span class="p">(</span><span class="s1">'page='</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">),</span><span class="w"> </span><span class="n">url</span><span class="p">)</span><span class="w"> </span><span class="c1">## get the next page</span><span class="w">
</span><span class="n">p</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">GET</span><span class="p">(</span><span class="n">urlp</span><span class="p">)</span><span class="w"> </span><span class="c1">## actually make GET request</span><span class="w">
</span><span class="n">pt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">content</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="s1">'parsed'</span><span class="p">)</span><span class="w"> </span><span class="c1">## retrieve contents of response formatted in a nested R list</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">pt</span><span class="o">$</span><span class="n">response</span><span class="o">$</span><span class="n">docs</span><span class="p">)</span><span class="o">></span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="n">art</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">append</span><span class="p">(</span><span class="n">art</span><span class="p">,</span><span class="w"> </span><span class="n">pt</span><span class="o">$</span><span class="n">response</span><span class="o">$</span><span class="n">docs</span><span class="p">)</span><span class="w"> </span><span class="c1">## add articles to list</span><span class="w">
</span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="n">print</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="s1">' pages collected'</span><span class="p">));</span><span class="w"> </span><span class="k">break</span><span class="p">}</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">%%</span><span class="w"> </span><span class="m">10</span><span class="w"> </span><span class="o">==</span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="n">print</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="s1">' pages of metadata collected'</span><span class="p">))</span><span class="w">
</span><span class="n">i</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">i</span><span class="m">+1</span><span class="w">
</span><span class="p">})</span><span class="w">
</span><span class="c1">## if there was a fail...</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="nf">class</span><span class="p">(</span><span class="n">tryget</span><span class="p">)</span><span class="o">==</span><span class="s1">'try-error'</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="s1">' error - metadata page not scraped'</span><span class="p">))</span><span class="w">
</span><span class="n">e</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">e</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="c1">## add page i to failed list</span><span class="w">
</span><span class="n">e</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">e</span><span class="p">[(</span><span class="nf">length</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">-</span><span class="p">(</span><span class="n">tryn</span><span class="m">-1</span><span class="p">))</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">e</span><span class="p">)]</span><span class="w"> </span><span class="c1">## keep the failed list to just tryn elements</span><span class="w">
</span><span class="n">Sys.sleep</span><span class="p">(</span><span class="m">0.5</span><span class="p">)</span><span class="w"> </span><span class="c1">## probably scraping too fast -- slowing down</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Sys.sleep</span><span class="p">(</span><span class="n">sleep</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nf">return</span><span class="p">(</span><span class="n">art</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c1">## example: collect metadata for 3 pages (30 articles)</span><span class="w">
</span><span class="n">meta</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">getMeta</span><span class="p">(</span><span class="n">url</span><span class="p">,</span><span class="w"> </span><span class="n">pages</span><span class="o">=</span><span class="m">3</span><span class="p">)</span><span class="w">
</span><span class="n">str</span><span class="p">(</span><span class="n">meta</span><span class="p">[[</span><span class="m">1</span><span class="p">]])</span><span class="w"> </span><span class="c1">## look at just one article </span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## List of 19
## $ web_url : chr "http://thecaucus.blogs.nytimes.com/2013/01/02/obama-returns-to-hawaii-to-continue-vacation/"
## $ snippet : chr "President Obama eased back into the relaxing groove of his Christmas in Hawaii vacation after a brief hiatus to wrangle with Co"| __truncated__
## $ lead_paragraph : NULL
## $ abstract : chr "President Obama eased back into the relaxing groove of his Christmas in Hawaii vacation after a brief hiatus to wrangle with Co"| __truncated__
## $ print_page : NULL
## $ blog : list()
## $ source : chr "The New York Times"
## $ multimedia : list()
## $ headline :List of 2
## ..$ main : chr "Obama Returns to Hawaii to Continue Vacation"
## ..$ kicker: chr "The Caucus"
## $ keywords :List of 3
## ..$ :List of 3
## .. ..$ rank : chr "1"
## .. ..$ name : chr "persons"
## .. ..$ value: chr "Obama, Barack"
## ..$ :List of 3
## .. ..$ rank : chr "1"
## .. ..$ name : chr "glocations"
## .. ..$ value: chr "Hawaii"
## ..$ :List of 3
## .. ..$ rank : chr "1"
## .. ..$ name : chr "subject"
## .. ..$ value: chr "United States Politics and Government"
## $ pub_date : chr "2013-01-02T18:37:03Z"
## $ document_type : chr "blogpost"
## $ news_desk : NULL
## $ section_name : chr "U.S."
## $ subsection_name : NULL
## $ byline :List of 2
## ..$ person :List of 1
## .. ..$ :List of 6
## .. .. ..$ firstname : chr "Jeremy"
## .. .. ..$ middlename : chr "W."
## .. .. ..$ lastname : chr "PETERS"
## .. .. ..$ rank : int 1
## .. .. ..$ role : chr "reported"
## .. .. ..$ organization: chr ""
## ..$ original: chr "By JEREMY W. PETERS"
## $ type_of_material: chr "Blog"
## $ _id : chr "50e4c5c700315214fbb821e4"
## $ word_count : int 366</code></pre></figure>
<h2 id="extracting-and-parsing-the-article-body-text">Extracting and parsing the article body text</h2>
<p>So now we have a lot of information about NYT articles including URL, abstract, headline, publication date, section, author, type of material, etc. However, notably absent is the article text itself. The process for collecting article body text is much more manual. We’ve used the API road as much as we can, but now we have to go off-road a little bit and collect each article’s body text from its individual URL provided from the metadata field <code class="highlighter-rouge">web_url</code>.</p>
<p>After a while of trial-and-error and guessing and checking, I developed a basic utility function <code class="highlighter-rouge">parseArticleBody</code> to strip just the article body text from the raw HTML. At least one of three simple XPath queries seemed to work reasonably well for the normal plain vanilla articles. Most of the video and photography pages contain little to no text, so these often come up empty. Some of the more modern pages like this <a href="http://www.nytimes.com/roomfordebate/2013/01/02/should-social-security-cuts-be-considered">one</a> which utilize multimedia and spread content over several pages usually fail too.</p>
<p>However, there’s enough NYT articles in the world to sink a small ship<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup>, so I’m more concerned with precision than recall – I’m willing to let some articles slip through the cracks if it boosts the quality of text for the articles I am able to extract it for. In most cases the gains from nailing the XPath query were marginal as the most common cause for missing article body text was out-of-date URLs provided by the NYT API.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="s1">'XML'</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'httr'</span><span class="p">)</span><span class="w">
</span><span class="n">parseArticleBody</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">artHTML</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">xpath2try</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'//div[@class="articleBody"]//p'</span><span class="p">,</span><span class="w">
</span><span class="s1">'//p[@class="story-body-text story-content"]'</span><span class="p">,</span><span class="w">
</span><span class="s1">'//p[@class="story-body-text"]'</span><span class="w">
</span><span class="p">)</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">xp</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">xpath2try</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">bodyi</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">paste</span><span class="p">(</span><span class="n">xpathSApply</span><span class="p">(</span><span class="n">htmlParse</span><span class="p">(</span><span class="n">artHTML</span><span class="p">),</span><span class="w"> </span><span class="n">xp</span><span class="p">,</span><span class="w"> </span><span class="n">xmlValue</span><span class="p">),</span><span class="w"> </span><span class="n">collapse</span><span class="o">=</span><span class="s1">''</span><span class="p">)</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="n">nchar</span><span class="p">(</span><span class="n">bodyi</span><span class="p">)</span><span class="o">></span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="k">break</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nf">return</span><span class="p">(</span><span class="n">bodyi</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c1">## Example: extract article text for one article</span><span class="w">
</span><span class="n">p</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">GET</span><span class="p">(</span><span class="s1">'http://www.nytimes.com/2013/01/31/garden/faketv-can-fool-intruders.html'</span><span class="p">)</span><span class="w">
</span><span class="n">html</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">content</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="s1">'text'</span><span class="p">)</span><span class="w">
</span><span class="n">artBody</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">parseArticleBody</span><span class="p">(</span><span class="n">html</span><span class="p">)</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="n">artBody</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] "\nYou might not be home every evening watching television, but no burglar needs to know that. The coruscating light of a television set — signature feature of an occupied home — might be enough to scare prowlers off. \nThat’s the idea behind FakeTV ($35), a security gadget that replicates a television’s flickering light in all of its dynamic variety, from kinetic commercials to subdued news reports. \nThe lightweight wedge, smaller than a slice of cake, is the brainchild of Blaine Readler, an engineer, who intentionally left his TV on when going out one night. The fake version, which uses bright LEDs, saves wear and tear on a real TV, as well as the cost of electricity. Energy-wise, it’s equivalent to a 2-watt night light, said Rein Teder, president of the manufacturer, Hydreon Corporation. \nAnd unlike most TVs today, which turn on and off with buttons or remotes, FakeTV can be put on a timer. Information: faketv.com or (877) 532-5388. "</code></pre></figure>
<h2 id="writing-to-mongodb">Writing to MongoDB</h2>
<h5 id="choosing-mongodb">Choosing MongoDB</h5>
<p>Github was a logical place to store code for this project – my blog is already hosted there and integrates well with my workflow allowing me to work from my home, office or villa on a remote island<sup id="fnref:3"><a href="#fn:3" class="footnote">3</a></sup>. Where to store the data was less obvious. I wanted something more robust than a directory full of text files… some sort of NoSQL database that I could access from Python and R. I also wanted to make the data accessible via the web. And I wanted it all for free.</p>
<p><a href="https://mongolab.com/">mongolab</a> (MongoDB’s cloud database-as-a-service) fit the bill, for 500MB at least. I don’t have much experience with NoSQL databases and haven’t worked with Mongo in the past, but I had a lot of fun learning and working with Mongo. My grasp of the Mongo querying language is still tenuous, but I was able make it do everything I needed it to do.</p>
<p>I found the web interface intuitive and useful for testing queries or other Mongo command line operations when I was getting started. From here you can also create database users with read-only or full access – useful for sharing your work with the world while holding the keys to the kingdom to yourself.</p>
<h5 id="working-with-mongodb-in-python-and-r">Working with MongoDB in Python and R</h5>
<p>I used the <a href="http://cran.r-project.org/web/packages/RMongo/index.html">RMongo</a> R package and the <a href="https://pypi.python.org/pypi/pymongo/">pymongo</a> Python package for interacting with the database. No complaints on either. I like how the usage inside Python and R using these packages seems to mirror pretty closely usage at the command line.</p>
<h5 id="when-the-cloud-can-bring-you-down">When the cloud can bring you down</h5>
<p>So high, yet so low. I did experience a period of down-time where I was unable to access my database for an hour or so. Although mongolab does a decent job of documenting issues on their <a href="http://status.mongolab.com/">status page</a>, the list doesn’t appear to be short… As is life sometimes, I suppose, when you’re on the free-tier of a cloud service.</p>
<h5 id="pulling-it-all-together">Pulling it all together</h5>
<p><code class="highlighter-rouge">getArticles</code> does most of the heaviest lifting – extracts, parses and adds the article body text to the <code class="highlighter-rouge">meta</code> object and inserts to MongoDB after scraping each article.</p>
<p><code class="highlighter-rouge">getArticles</code>:</p>
<ul>
<li>DOES use the list of metadata as a starting point (the <code class="highlighter-rouge">meta</code> argument). Then scrapes, parses and adds the body as an attribute (text string) to the article’s metadata. Only adds to the <code class="highlighter-rouge">meta</code> object.</li>
<li>DOES cache – writes to MongoDB after extracting each article. I didn’t bump into any rate-limits from MongoDB and I had to wait a decisecond or two after each article anyway, so insert speed was not an issue for me. Had all the articles been pulled into memory first, I imagine a bulk insert would be more efficient.</li>
<li>DOES convert the R list of metadata for each article to JSON on the fly using the <code class="highlighter-rouge">toJSON</code> function which is then conveniently inserted to MongoDB as-is. MongoDB likes JSON.</li>
<li>DOES re-attempt failed article extraction, parsing and MongoDB inserts – If there was an error in one of these steps, I tried another 2 times before moving on to the next article.</li>
<li>DOES include parameters:
<ul>
<li><code class="highlighter-rouge">meta</code> is created from the function <code class="highlighter-rouge">getMeta</code>.</li>
<li><code class="highlighter-rouge">n</code> is the number of articles to scrape.</li>
<li><code class="highlighter-rouge">overwrite</code> decides whether to start scraping at the beginning or the first article that does not have a body attribute.</li>
<li><code class="highlighter-rouge">sleep</code> is the time in seconds to pause after each article. Defaults to 0.1 seconds.</li>
<li><code class="highlighter-rouge">mongo</code> is list of credentials used to write to the database. To return results in memory and not write to database, specify <code class="highlighter-rouge">mongo=NULL</code>.</li>
</ul>
</li>
</ul>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="s1">'XML'</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'RMongo'</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'rjson'</span><span class="p">)</span><span class="w">
</span><span class="n">getArticles</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">meta</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="o">=</span><span class="kc">Inf</span><span class="p">,</span><span class="w"> </span><span class="n">overwrite</span><span class="o">=</span><span class="nb">F</span><span class="p">,</span><span class="w"> </span><span class="n">sleep</span><span class="o">=</span><span class="m">0.1</span><span class="p">,</span><span class="w"> </span><span class="n">mongo</span><span class="o">=</span><span class="nf">list</span><span class="p">(</span><span class="n">dbName</span><span class="p">,</span><span class="w"> </span><span class="n">collection</span><span class="p">,</span><span class="w"> </span><span class="n">host</span><span class="o">=</span><span class="s1">'127.0.0.1'</span><span class="p">,</span><span class="w"> </span><span class="n">username</span><span class="p">,</span><span class="w"> </span><span class="n">password</span><span class="p">,</span><span class="w"> </span><span class="n">...</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">metaArt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">meta</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="nf">is.null</span><span class="p">(</span><span class="n">mongo</span><span class="o">$</span><span class="n">dbName</span><span class="p">)</span><span class="o">==</span><span class="nb">F</span><span class="p">){</span><span class="w">
</span><span class="n">con</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">mongoDbConnect</span><span class="p">(</span><span class="n">mongo</span><span class="o">$</span><span class="n">dbName</span><span class="p">,</span><span class="w"> </span><span class="n">mongo</span><span class="o">$</span><span class="n">host</span><span class="p">)</span><span class="w">
</span><span class="n">try</span><span class="p">(</span><span class="n">authenticated</span><span class="w"> </span><span class="o"><-</span><span class="n">dbAuthenticate</span><span class="p">(</span><span class="n">con</span><span class="p">,</span><span class="w"> </span><span class="n">username</span><span class="o">=</span><span class="n">mongo</span><span class="o">$</span><span class="n">username</span><span class="p">,</span><span class="w"> </span><span class="n">password</span><span class="o">=</span><span class="n">mongo</span><span class="o">$</span><span class="n">password</span><span class="p">))</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="n">overwrite</span><span class="o">==</span><span class="nb">T</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="n">artIndex</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="p">(</span><span class="nf">min</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">meta</span><span class="p">)))</span><span class="w">
</span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">ii</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">which</span><span class="p">(</span><span class="n">sapply</span><span class="p">(</span><span class="n">meta</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="nf">is.null</span><span class="p">(</span><span class="n">x</span><span class="p">[[</span><span class="s1">'bodyHTML'</span><span class="p">]])))</span><span class="w"> </span><span class="c1">## get index of articles that have not been scraped yet</span><span class="w">
</span><span class="n">artIndex</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">ii</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="nf">min</span><span class="p">(</span><span class="n">n</span><span class="p">,</span><span class="nf">length</span><span class="p">(</span><span class="n">ii</span><span class="p">))]</span><span class="w"> </span><span class="c1">## take first n articles</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">e</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">-3</span><span class="p">,</span><span class="m">-2</span><span class="p">,</span><span class="m">-1</span><span class="p">)</span><span class="w"> </span><span class="c1"># initialize failed list of articles with arbitrary negative numbers</span><span class="w">
</span><span class="n">i</span><span class="o"><</span><span class="m">-1</span><span class="w">
</span><span class="k">while</span><span class="p">(</span><span class="n">i</span><span class="o"><=</span><span class="nf">length</span><span class="p">(</span><span class="n">artIndex</span><span class="p">)){</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="nf">length</span><span class="p">(</span><span class="n">unique</span><span class="p">(</span><span class="n">e</span><span class="p">[(</span><span class="nf">length</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="m">-2</span><span class="p">)</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">e</span><span class="p">)]))</span><span class="o">==</span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">i</span><span class="m">+1</span><span class="w"> </span><span class="c1">## if we tried and failed 3 times, move on</span><span class="w">
</span><span class="n">tryget</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">try</span><span class="p">({</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="n">overwrite</span><span class="o">==</span><span class="nb">T</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="p">(</span><span class="nf">is.null</span><span class="p">(</span><span class="n">meta</span><span class="p">[[</span><span class="n">i</span><span class="p">]]</span><span class="o">$</span><span class="n">body</span><span class="p">)</span><span class="o">==</span><span class="nb">T</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">overwrite</span><span class="o">==</span><span class="nb">F</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">p</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">GET</span><span class="p">(</span><span class="n">meta</span><span class="p">[[</span><span class="n">i</span><span class="p">]]</span><span class="o">$</span><span class="n">web_url</span><span class="p">)</span><span class="w">
</span><span class="n">html</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">content</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="w"> </span><span class="s1">'text'</span><span class="p">)</span><span class="w"> </span><span class="c1">## metaArt[[i]]$bodyHTML <- content(p, 'text')</span><span class="w">
</span><span class="n">metaArt</span><span class="p">[[</span><span class="n">i</span><span class="p">]]</span><span class="o">$</span><span class="n">body</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">parseArticleBody</span><span class="p">(</span><span class="n">html</span><span class="p">)</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="nf">is.null</span><span class="p">(</span><span class="n">mongo</span><span class="o">$</span><span class="n">dbName</span><span class="p">)</span><span class="o">==</span><span class="nb">F</span><span class="p">)</span><span class="w"> </span><span class="n">dbInsertDocument</span><span class="p">(</span><span class="n">con</span><span class="p">,</span><span class="w"> </span><span class="n">mongo</span><span class="o">$</span><span class="n">collection</span><span class="p">,</span><span class="w"> </span><span class="n">toJSON</span><span class="p">(</span><span class="n">metaArt</span><span class="p">[[</span><span class="n">i</span><span class="p">]]))</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">%%</span><span class="w"> </span><span class="m">10</span><span class="o">==</span><span class="m">0</span><span class="p">)</span><span class="w"> </span><span class="n">print</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="s1">' articles scraped'</span><span class="p">))</span><span class="w">
</span><span class="n">i</span><span class="o"><-</span><span class="n">i</span><span class="m">+1</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">})</span><span class="w">
</span><span class="k">if</span><span class="p">(</span><span class="nf">class</span><span class="p">(</span><span class="n">tryget</span><span class="p">)</span><span class="o">==</span><span class="s1">'try-error'</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="s1">' error - article not scraped'</span><span class="p">))</span><span class="w">
</span><span class="n">e</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">e</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">)</span><span class="w">
</span><span class="n">e</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">e</span><span class="p">[(</span><span class="nf">length</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="m">-2</span><span class="p">)</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">e</span><span class="p">)]</span><span class="w">
</span><span class="n">Sys.sleep</span><span class="p">(</span><span class="m">0.5</span><span class="p">)</span><span class="w"> </span><span class="c1">## probably scraping too fast -- slowing down</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">Sys.sleep</span><span class="p">(</span><span class="n">sleep</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="nf">return</span><span class="p">(</span><span class="n">metaArt</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c1">## Example: get article bodies for first 10 articles. </span><span class="w">
</span><span class="n">art</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">getArticles</span><span class="p">(</span><span class="n">meta</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="o">=</span><span class="m">3</span><span class="p">,</span><span class="w"> </span><span class="n">mongo</span><span class="o">=</span><span class="kc">NULL</span><span class="p">)</span><span class="w"> </span><span class="c1">## scrape article body text for first 3 articles. Do not write to MongoDB</span><span class="w">
</span><span class="nf">length</span><span class="p">(</span><span class="n">art</span><span class="p">)</span><span class="w"> </span><span class="c1">## we only add to meta. Still returns articles for which we did not collect body text.</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] 30</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">str</span><span class="p">(</span><span class="n">art</span><span class="p">[[</span><span class="m">1</span><span class="p">]])</span><span class="w"> </span><span class="c1">## we now have a "body" attribute.</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## List of 20
## $ web_url : chr "http://thecaucus.blogs.nytimes.com/2013/01/02/obama-returns-to-hawaii-to-continue-vacation/"
## $ snippet : chr "President Obama eased back into the relaxing groove of his Christmas in Hawaii vacation after a brief hiatus to wrangle with Co"| __truncated__
## $ lead_paragraph : NULL
## $ abstract : chr "President Obama eased back into the relaxing groove of his Christmas in Hawaii vacation after a brief hiatus to wrangle with Co"| __truncated__
## $ print_page : NULL
## $ blog : list()
## $ source : chr "The New York Times"
## $ multimedia : list()
## $ headline :List of 2
## ..$ main : chr "Obama Returns to Hawaii to Continue Vacation"
## ..$ kicker: chr "The Caucus"
## $ keywords :List of 3
## ..$ :List of 3
## .. ..$ rank : chr "1"
## .. ..$ name : chr "persons"
## .. ..$ value: chr "Obama, Barack"
## ..$ :List of 3
## .. ..$ rank : chr "1"
## .. ..$ name : chr "glocations"
## .. ..$ value: chr "Hawaii"
## ..$ :List of 3
## .. ..$ rank : chr "1"
## .. ..$ name : chr "subject"
## .. ..$ value: chr "United States Politics and Government"
## $ pub_date : chr "2013-01-02T18:37:03Z"
## $ document_type : chr "blogpost"
## $ news_desk : NULL
## $ section_name : chr "U.S."
## $ subsection_name : NULL
## $ byline :List of 2
## ..$ person :List of 1
## .. ..$ :List of 6
## .. .. ..$ firstname : chr "Jeremy"
## .. .. ..$ middlename : chr "W."
## .. .. ..$ lastname : chr "PETERS"
## .. .. ..$ rank : int 1
## .. .. ..$ role : chr "reported"
## .. .. ..$ organization: chr ""
## ..$ original: chr "By JEREMY W. PETERS"
## $ type_of_material: chr "Blog"
## $ _id : chr "50e4c5c700315214fbb821e4"
## $ word_count : int 366
## $ body : chr "\tHONOLULU – President Obama eased back into the relaxing groove of his Christmas in Hawaii vacation on Wednesday after a brief"| __truncated__</code></pre></figure>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">print</span><span class="p">(</span><span class="n">art</span><span class="p">[[</span><span class="m">1</span><span class="p">]][</span><span class="s1">'body'</span><span class="p">])</span><span class="w"> </span><span class="c1">## full body text of the article.</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## $body
## [1] "\tHONOLULU – President Obama eased back into the relaxing groove of his Christmas in Hawaii vacation on Wednesday after a brief hiatus to wrangle with Congress over a deal to avert a fiscal crisis.\tIn most respects, Wednesday on the island of Oahu was 5,000 miles away and a world apart from the political brinksmanship of the nation’s capital. The morning included a trip to the local Marine Corps base, where the president went to the gym.\tAnd after speaking with Gov. Andrew M. Cuomo of New York and Gov. Chris Christie of New Jersey about the stalled efforts to provide tens of billions of dollars to the states to aid their recovery from Hurricane Sandy, Mr. Obama hit the golf course. \tThe White House announced Mr. Obama’s golf partners, as is standard protocol, and they once again included a friend who always creates a bit of a stir whenever he is spotted with the president. Bobby Titcomb, an old friend of the president’s from their days at the Punahou School here, was arrested in 2011 on a charge of soliciting prostitution after being swept up in an undercover sting. He later entered a plea of no contest. \tThe president’s group also included Marty Nesbitt, a Chicago friend. Mr. Nesbitt was an early backer of Mr. Obama, and he later served as treasurer for his 2008 presidential campaign. \tThe third in their foursome was Allison Davis, a Chicago developer and lawyer who was one of the founders of the firm the president once worked for and who was another financial backer of his early political career. \tThe White House also released a new taped message from the president on Wednesday in which he outlined his priorities for 2013 – listing them in order as winding down the war in Afghanistan, reforming immigration and gun control – and cautioned that many of the issues that made the tax-and-spending deal so difficult remain unresolved.\t“Obviously there’s still more to do when it comes to reducing our debt,” he said. “And I’m willing to do more as long as it does it in a balanced way that doesn’t put all the burden on seniors or students or middle-class families.”"</code></pre></figure>
<h2 id="pipeline">Pipeline</h2>
<p>So putting it all together, the pipeline looks like this:</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1">## dependencies</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'rjson'</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'httr'</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'RMongo'</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'XML'</span><span class="p">)</span><span class="w">
</span><span class="c1">## parameters</span><span class="w">
</span><span class="n">days</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">gsub</span><span class="p">(</span><span class="s1">'-'</span><span class="p">,</span><span class="w"> </span><span class="s1">''</span><span class="p">,</span><span class="w"> </span><span class="n">seq</span><span class="p">(</span><span class="n">as.Date</span><span class="p">(</span><span class="s1">'2013-01-01'</span><span class="p">),</span><span class="w"> </span><span class="n">Sys.Date</span><span class="p">()</span><span class="m">-1</span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="m">1</span><span class="p">))</span><span class="w">
</span><span class="n">mongoCreds</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="n">dbName</span><span class="o">=</span><span class="s1">'nyt'</span><span class="p">,</span><span class="w"> </span><span class="n">collection</span><span class="o">=</span><span class="s1">'articles1'</span><span class="p">,</span><span class="w"> </span><span class="n">host</span><span class="o">=</span><span class="s1">'ds063240.mongolab.com:63240'</span><span class="p">,</span><span class="w"> </span><span class="n">username</span><span class="o">=</span><span class="s1">'myUsername'</span><span class="p">,</span><span class="w"> </span><span class="n">password</span><span class="o">=</span><span class="s1">'myPassword'</span><span class="p">)</span><span class="w">
</span><span class="n">key</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s1">'myKey'</span><span class="w"> </span><span class="c1"># replace with your personal key</span><span class="w">
</span><span class="c1">## Letting it rip ... </span><span class="w">
</span><span class="n">all</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">list</span><span class="p">()</span><span class="w"> </span><span class="c1">## persist all results in memory in addition to MongoDB... just in case.</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">d</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="n">days</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">url</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">makeURL</span><span class="p">(</span><span class="n">begin_date</span><span class="o">=</span><span class="n">d</span><span class="p">,</span><span class="w"> </span><span class="n">end_date</span><span class="o">=</span><span class="n">d</span><span class="p">,</span><span class="w"> </span><span class="n">key</span><span class="o">=</span><span class="n">key</span><span class="p">)</span><span class="w"> </span><span class="c1"># generate URL</span><span class="w">
</span><span class="n">meta</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">getMeta</span><span class="p">(</span><span class="n">url</span><span class="p">,</span><span class="w"> </span><span class="n">pages</span><span class="o">=</span><span class="kc">Inf</span><span class="p">,</span><span class="w"> </span><span class="n">sleep</span><span class="o">=</span><span class="m">0.1</span><span class="p">)</span><span class="w"> </span><span class="c1"># extract metadata from NYT API</span><span class="w">
</span><span class="n">artxt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">getArticles</span><span class="p">(</span><span class="n">meta</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="o">=</span><span class="kc">Inf</span><span class="p">,</span><span class="w"> </span><span class="n">sleep</span><span class="o">=</span><span class="m">0.1</span><span class="p">,</span><span class="w"> </span><span class="n">overwrite</span><span class="o">=</span><span class="nb">T</span><span class="p">,</span><span class="w"> </span><span class="n">mongo</span><span class="o">=</span><span class="n">mongoCreds</span><span class="p">)</span><span class="w"> </span><span class="c1"># extract article text and write to MongoDB</span><span class="w">
</span><span class="n">print</span><span class="p">(</span><span class="n">paste0</span><span class="p">(</span><span class="s1">'day '</span><span class="p">,</span><span class="w"> </span><span class="n">d</span><span class="p">,</span><span class="w"> </span><span class="s1">' complete at '</span><span class="p">,</span><span class="w"> </span><span class="n">Sys.time</span><span class="p">()))</span><span class="w">
</span><span class="n">all</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">append</span><span class="p">(</span><span class="n">all</span><span class="p">,</span><span class="w"> </span><span class="n">artxt</span><span class="p">)</span><span class="w"> </span><span class="c1"># persist results</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<h2 id="results">Results</h2>
<p>It took me about 1 full day to max out the 500MB in my free mongolab database. I ended up with 85,000 articles covering roughly 4 months of NYT articles. Since I’m specifically interested in text mining the article text, my next step will likely be to delete the documents where the article body could not be extracted.</p>
<p>A lot of the URLs provided from the NYT API were stale – only ~35% of URLs contained a real article with text. It wasn’t until I was doing some preliminary analysis poking around on the full corpus that I realized links to historic AP and Reuters articles (of which there are many) were included and almost universally not fruitful. These could easily be filtered out using the <code class="highlighter-rouge">fq</code> parameter in the NYT API: <code class="highlighter-rouge">fq=source:("The New York Times")</code>.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1">## Crosstab of article source vs. whether article was successfully scraped </span><span class="w">
</span><span class="o">**</span><span class="n">body</span><span class="w"> </span><span class="n">scraped</span><span class="w"> </span><span class="n">successfully</span><span class="o">**</span><span class="w">
</span><span class="o">**</span><span class="n">Source</span><span class="o">**</span><span class="w"> </span><span class="kc">FALSE</span><span class="w"> </span><span class="kc">TRUE</span><span class="w">
</span><span class="n">The</span><span class="w"> </span><span class="n">New</span><span class="w"> </span><span class="n">York</span><span class="w"> </span><span class="n">Times</span><span class="w"> </span><span class="m">6686</span><span class="w"> </span><span class="m">34322</span><span class="w">
</span><span class="n">AP</span><span class="w"> </span><span class="m">28944</span><span class="w"> </span><span class="m">8</span><span class="w">
</span><span class="n">Reuters</span><span class="w"> </span><span class="m">24001</span><span class="w"> </span><span class="m">0</span><span class="w">
</span><span class="n">International</span><span class="w"> </span><span class="n">Herald</span><span class="w"> </span><span class="n">Tribune</span><span class="w"> </span><span class="m">9</span><span class="w"> </span><span class="m">1221</span><span class="w">
</span><span class="m">1007</span><span class="w"> </span><span class="m">4</span><span class="w">
</span><span class="n">du_recipe</span><span class="w"> </span><span class="m">273</span><span class="w"> </span><span class="m">0</span><span class="w">
</span><span class="n">The</span><span class="w"> </span><span class="n">Broadway</span><span class="w"> </span><span class="n">Channel</span><span class="w"> </span><span class="m">8</span><span class="w"> </span><span class="m">0</span><span class="w">
</span><span class="n">CNBC</span><span class="w"> </span><span class="m">6</span><span class="w"> </span><span class="m">0</span><span class="w">
</span><span class="n">ADAM</span><span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="m">0</span></code></pre></figure>
<p>I decided to use <a href="https://radimrehurek.com/gensim/">gensim</a> and <a href="http://www.nltk.org/">nltk</a> in Python for the text pre-processing and topic modeling. More to come on that analysis and visualization.</p>
<h5 id="footnotes">Footnotes</h5>
<div class="footnotes">
<ol>
<li id="fn:1">
<p>Note the use of the <code class="highlighter-rouge">content</code> function from the httr package with <code class="highlighter-rouge">as='parsed'</code> is not recommended by the authors for use in other R packages or production systems. It’s provided as a convenience function… which I found, well, convenient… so I used it. <a href="#fnref:1" class="reversefootnote">↩</a></p>
</li>
<li id="fn:2">
<p>In fact there are over 1000 articles alone matching the query parameters “ship+sink” <a href="#fnref:2" class="reversefootnote">↩</a></p>
</li>
<li id="fn:3">
<p>Still working on the villa … <a href="#fnref:3" class="reversefootnote">↩</a></p>
</li>
</ol>
</div>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/new-york-times-api-to-mongodb/">New York Times Article Search API to MongoDB</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on January 06, 2015.</p>http://brooksandrew.github.io/simpleblog/articles/scraping-with-selenium2014-12-11T00:00:00+00:002014-12-11T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<h3 id="if-youve-ever">If you’ve ever…</h3>
<p>felt like you’re playing Simon Says with mouse clicks when repeatedly extracting data in chunks from a
front-end interface to a database on the web, well, you probably are.
There’s probably a better solution – <a href="http://www.seleniumhq.org/">Selenium</a>.</p>
<p>ever used XML or httr in R or urllib2 in Python, you’ve probably encountered the situation where
the source code you’ve scraped for a website doesn’t contain all the information you see in your browser.
<a href="http://www.seleniumhq.org/">Selenium</a> can probably help.</p>
<h3 id="how-it-works">How it works</h3>
<p>Selenium is a web automation tool.
While not developed specifically for web scraping, Selenium does it pretty dang well.
Selenium literally “drives” your browser, so it can see anything you see when you right click and inspect element in Chrome or Firefox.
This vastly widens the universe of content that can be extracted from automation, but can be slow
as all content must be rendered in the browser.</p>
<p>There are headless (invisible browsers with no GUI) such as <a href="http://phantomjs.org/">phantomjs</a> that
speed some of this up. That said, I’ve found that Selenium works best for targeted extraction where the user knows exactly
what they want.</p>
<h3 id="example">Example</h3>
<p>I set out to collect tickers for all mutual funds in the asset allocation fund type. Fidelity provides a list
of all these funds <a href="https://www.fidelity.com/fund-screener/evaluator.shtml#!&ntf=N&ft=BAL_all&msrV=advanced&sortBy=FUND_MST_MSTAR_CTGY_NM&pgNo=1">here</a>.
1,586 funds as of today in 80 conveniently paginated URLs. Each URL ends in <code class="highlighter-rouge">&pgNo=5</code> to indicate you want page 5 (or whatever number between 1 and 80).</p>
<p>In my browser, when I hover my mouse over one of the fund names in the table, I see the 5 character ticker I’m looking for.
I also see the tickers directly on the webpage when I click the link to each fund.
<a href="https://fundresearch.fidelity.com/mutual-funds/summary/72201F433">Here</a> for example, where it says PSLDX in the top left.
However, if possible I’d like to scrape the tickers from the table rather than the individual fund pages.
This would mean 80 pages to scrape rather than 1,586.</p>
<h3 id="take-1-traditional-http-request">Take 1: traditional http request</h3>
<p>When possible, it makes sense to use the simple traditional methods. So I first tried to extract these tickers with the popular <code class="highlighter-rouge">httr</code> R package
by making standard http requests.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="s1">'httr'</span><span class="p">)</span><span class="w">
</span><span class="n">url</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s1">'https://www.fidelity.com/fund-screener/evaluator.shtml#!&ft=BAL_all&ntf=N&expand=%24FundType&rsk=5'</span><span class="w">
</span><span class="n">page</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">GET</span><span class="p">(</span><span class="n">url</span><span class="p">)</span></code></pre></figure>
<p>Success…</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">print</span><span class="p">(</span><span class="n">http_status</span><span class="p">(</span><span class="n">page</span><span class="p">))</span><span class="w"> </span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## $category
## [1] "success"
##
## $message
## [1] "success: (200) OK"</code></pre></figure>
<p>But did our http request return the information we want?</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">page_text</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">content</span><span class="p">(</span><span class="n">page</span><span class="p">,</span><span class="w"> </span><span class="n">as</span><span class="o">=</span><span class="s1">'text'</span><span class="p">)</span></code></pre></figure>
<p>Nope – can’t find the tickers (one of them anyway).</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">grepl</span><span class="p">(</span><span class="s1">'GMMAX'</span><span class="p">,</span><span class="w"> </span><span class="n">page_text</span><span class="p">,</span><span class="w"> </span><span class="n">ignore.case</span><span class="o">=</span><span class="nb">T</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] FALSE</code></pre></figure>
<p>Nope – can’t even find the fund name that I see in the table from the webpage in my browser.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">grepl</span><span class="p">(</span><span class="s1">'Aberdeen'</span><span class="p">,</span><span class="w"> </span><span class="n">page_text</span><span class="p">,</span><span class="w"> </span><span class="n">ignore.case</span><span class="o">=</span><span class="nb">T</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] FALSE</code></pre></figure>
<p>It appears that the content of interest is being generated dynamically with Javascript and Ajax on this webpage.
So the raw HTML of this page doesn’t help us much.</p>
<p>My plan B was to grab the url for each fund from the table, navigate to that fund’s page, and extract the ticker from there.
However these links weren’t in our http response. I noticed that the URLs for each fund followed a simple consistent structure. <br />
<a href="https://fundresearch.fidelity.com/mutual-funds/summary/72201F433">https://fundresearch.fidelity.com/mutual-funds/summary/72201F433</a> for example.
I thought maybe I could find 72201F433 which looks like some sort of fund ID in a list with all fund IDs in the http response.
No dice. Plan C – Selenium.</p>
<h3 id="take-2-selenium">Take 2: Selenium</h3>
<p>I used the <a href="http://www.github.com/ropensci/RSelenium/">RSelenium</a> R package for this mini project. There are also Selenium bindings for Python, Java, C#, Javascript and Ruby
which make replicating this process in your programming language of choice relatively straightforward.</p>
<p><strong>Step 1: Fire up Selenium</strong></p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="s1">'RSelenium'</span><span class="p">)</span><span class="w">
</span><span class="n">checkForServer</span><span class="p">()</span><span class="w"> </span><span class="c1"># search for and download Selenium Server java binary. Only need to run once.</span><span class="w">
</span><span class="n">startServer</span><span class="p">()</span><span class="w"> </span><span class="c1"># run Selenium Server binary</span><span class="w">
</span><span class="n">remDr</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">remoteDriver</span><span class="p">(</span><span class="n">browserName</span><span class="o">=</span><span class="s2">"firefox"</span><span class="p">,</span><span class="w"> </span><span class="n">port</span><span class="o">=</span><span class="m">4444</span><span class="p">)</span><span class="w"> </span><span class="c1"># instantiate remote driver to connect to Selenium Server</span><span class="w">
</span><span class="n">remDr</span><span class="o">$</span><span class="n">open</span><span class="p">(</span><span class="n">silent</span><span class="o">=</span><span class="nb">T</span><span class="p">)</span><span class="w"> </span><span class="c1"># open web browser</span></code></pre></figure>
<p><strong>Step 2: Start scraping</strong></p>
<p>To figure which DOM elements I wanted Selenium extract, I used the Chrome Developer Tools which can be invoked by right clicking a fund in the table and selecting Inspect Element. The HTML displayed here contains exactly what we want, what we didn’t see with our http request.</p>
<p>Since I want to grab all the funds at once, I tell Selenium to select the whole table. Going a few levels up from the individual cell in the table I’ve selected, I see that <code class="highlighter-rouge"><tbody id="tbody"></code> is the HTML tag that contains the entire table, so I tell Selenium to find this element. I use the nifty <code class="highlighter-rouge">highlightElement</code> function to confirm graphically in the browser that this is what I think it is.</p>
<p>Then it’s business as usual. I parse the string output from Selenium into an HTML tree and use XPath to parse the table for just the fund name and ticker.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">library</span><span class="p">(</span><span class="s1">'XML'</span><span class="p">)</span><span class="w">
</span><span class="n">master</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">()</span><span class="w">
</span><span class="n">n</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">5</span><span class="w"> </span><span class="c1"># number of pages to scrape. 80 pages in total. I just scraped 5 pages for this example.</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">site</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">paste0</span><span class="p">(</span><span class="s2">"https://www.fidelity.com/fund-screener/evaluator.shtml#!&ntf=N&ft=BAL_all&msrV=advanced&sortBy=FUND_MST_MSTAR_CTGY_NM&pgNo="</span><span class="p">,</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="c1"># create URL for each page to scrape</span><span class="w">
</span><span class="n">remDr</span><span class="o">$</span><span class="n">navigate</span><span class="p">(</span><span class="n">site</span><span class="p">)</span><span class="w"> </span><span class="c1"># navigates to webpage</span><span class="w">
</span><span class="n">elem</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">remDr</span><span class="o">$</span><span class="n">findElement</span><span class="p">(</span><span class="n">using</span><span class="o">=</span><span class="s2">"id"</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="o">=</span><span class="s2">"tbody"</span><span class="p">)</span><span class="w"> </span><span class="c1"># get big table in text string</span><span class="w">
</span><span class="n">elem</span><span class="o">$</span><span class="n">highlightElement</span><span class="p">()</span><span class="w"> </span><span class="c1"># just for interactive use in browser. not necessary.</span><span class="w">
</span><span class="n">elemtxt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">elem</span><span class="o">$</span><span class="n">getElementAttribute</span><span class="p">(</span><span class="s2">"outerHTML"</span><span class="p">)[[</span><span class="m">1</span><span class="p">]]</span><span class="w"> </span><span class="c1"># gets us the HTML</span><span class="w">
</span><span class="n">elemxml</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">htmlTreeParse</span><span class="p">(</span><span class="n">elemtxt</span><span class="p">,</span><span class="w"> </span><span class="n">useInternalNodes</span><span class="o">=</span><span class="nb">T</span><span class="p">)</span><span class="w"> </span><span class="c1"># parse string into HTML tree to allow for querying with XPath</span><span class="w">
</span><span class="n">fundList</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">unlist</span><span class="p">(</span><span class="n">xpathApply</span><span class="p">(</span><span class="n">elemxml</span><span class="p">,</span><span class="w"> </span><span class="s1">'//input[@title]'</span><span class="p">,</span><span class="w"> </span><span class="n">xmlGetAttr</span><span class="p">,</span><span class="w"> </span><span class="s1">'title'</span><span class="p">))</span><span class="w"> </span><span class="c1"># parses out just the fund name and ticker using XPath</span><span class="w">
</span><span class="n">master</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">master</span><span class="p">,</span><span class="w"> </span><span class="n">fundList</span><span class="p">)</span><span class="w"> </span><span class="c1"># append fund lists from each page together</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">master</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## [1] "FidelityAA Global Balanced Fund (FGBLX)"
## [2] "FidelityAA Global Strategies Fund (FDYSX)"
## [3] "Fidelity FreedomA 2055 Fund (FDEEX)"
## [4] "Aberdeen Dynamic Allocation Fund Class A (GMMAX)"
## [5] "Aberdeen Dynamic Allocation Fund Class C (GMMCX)"
## [6] "AllianceBernstein Real Asset Strategy Advisor Class (AMTYX)"</code></pre></figure>
<p><strong>Step 3: Extract ticker</strong></p>
<p>Nothing fancy here – just separating the ticker from the fund name.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">master2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.frame</span><span class="p">(</span><span class="n">sapply</span><span class="p">(</span><span class="n">master</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">substr</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">nchar</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="m">-5</span><span class="p">,</span><span class="w"> </span><span class="n">nchar</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="m">-1</span><span class="p">)))</span><span class="w">
</span><span class="n">master2</span><span class="o">$</span><span class="n">name</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">master</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">substr</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">nchar</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="m">-8</span><span class="p">))</span><span class="w">
</span><span class="nf">names</span><span class="p">(</span><span class="n">master2</span><span class="p">)</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'ticker'</span><span class="p">,</span><span class="w"> </span><span class="s1">'name'</span><span class="p">)</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">master2</span><span class="p">)</span></code></pre></figure>
<figure class="highlight"><pre><code class="language-text" data-lang="text">## ticker name
## 1 FGBLX FidelityAA Global Balanced Fund
## 2 FDYSX FidelityAA Global Strategies Fund
## 3 FDEEX Fidelity FreedomAA 2055 Fund
## 4 GMMAX Aberdeen Dynamic Allocation Fund Class A
## 5 GMMCX Aberdeen Dynamic Allocation Fund Class C
## 6 AMTYX AllianceBernstein Real Asset Strategy Advisor Class</code></pre></figure>
<h3 id="what-else-can-selenium-do">What else can Selenium do?</h3>
<p>My little example makes use of the simple functionality provided by Selenium for web scraping – rendering HTML that is dynamically generated with Javascript or Ajax. Since Selenium is actually a web automation tool, one can be much more sophisticated by using it to automate a human navigating a webpage with mouse clicks and writing and submitting forms. This can be a huge time saver for researchers that rely on front-end interfaces on the web to extract data in chunks.</p>
<p><a href="http://thiagomarzagao.com/2013/11/12/webscraping-with-selenium-part-1/">Here’s</a> a basic example using Python.<br />
<a href="http://cran.r-project.org/web/packages/RSelenium/vignettes/RSelenium-basics.html">Here’s</a> a basic example using R.</p>
<h3 id="getting-setup">Getting setup</h3>
<p>On the several computers I use, I’ve found setup ranging from seamless to frustrating.</p>
<p>The most frustrating issue I encountered while setting up on my Mac was this error message:</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="o">></span><span class="w"> </span><span class="n">remDr</span><span class="o">$</span><span class="n">open</span><span class="p">()</span><span class="w">
</span><span class="p">[</span><span class="m">1</span><span class="p">]</span><span class="w"> </span><span class="s2">"Connecting to remote server"</span><span class="w">
</span><span class="n">Error</span><span class="o">:</span><span class="w"> </span><span class="n">Summary</span><span class="o">:</span><span class="w"> </span><span class="n">UnknownError</span><span class="w">
</span><span class="n">Detail</span><span class="o">:</span><span class="w"> </span><span class="n">An</span><span class="w"> </span><span class="n">unknown</span><span class="w"> </span><span class="n">server</span><span class="o">-</span><span class="n">side</span><span class="w"> </span><span class="n">error</span><span class="w"> </span><span class="n">occurred</span><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="n">processing</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">command.</span><span class="w">
</span><span class="n">class</span><span class="o">:</span><span class="w"> </span><span class="n">java.lang.IllegalStateException</span></code></pre></figure>
<p>I was able to resolve it by killing all processes running on port 4444 and trying again.</p>
<p>At the terminal:</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">lsof</span><span class="w"> </span><span class="o">-</span><span class="n">i</span><span class="w"> </span><span class="o">:</span><span class="m">4444</span></code></pre></figure>
<p>Kill PIDs of any processes listed. For example:</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">kill</span><span class="w"> </span><span class="m">30681</span></code></pre></figure>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/scraping-with-selenium/">Scraping with Selenium</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on December 11, 2014.</p>http://brooksandrew.github.io/simpleblog/articles/personal-R-package2014-11-20T00:00:00+00:002014-11-20T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<h5 id="why-create-a-personal-r-package">Why create a personal R package?</h5>
<p>As a consulting data scientist, I write a lot of R code in a lot of different places – physically and virtually. Different computers, servers, evironments, VPNs, operating systems, all of the above.
Even when I have the luxury of working with the same client (and computing environment) for enough time to work on different projects, things can get messy.</p>
<h5 id="when-is-it-worth-it">When is it worth it?</h5>
<p>I find myself often facing a dilemma – do I keep project specific code consolidated in one location at the expense of possible duplication later on by copying around old general purpose functions to allow for customization and further development in the future?
Or do I maintain the general purpose functions which may be called from several different projects in one location at the expense of making customization and enhancing functionality more of a headache?</p>
<p>I find there are pros and cons to each method:</p>
<ul>
<li><strong>Decentralized:</strong> portable, customizable … but can be grossly duplicatitive and suffer from curse of versionality.</li>
<li><strong>Centralized:</strong> organized, clean, efficient, scalable … but can be rigid, requires discipline and can break old programs if you’re not careful.</li>
</ul>
<p>Surely centralization is the better solution after some tipping point. However, the unpredictable nature of my work sometimes makes it difficult to predict when (or if) that tipping point will occur – when the benefits of centralization begin to outweigh the costs of the portable lightweight decentralized method.</p>
<h5 id="why-not-just-a-folder-full-of-functions">Why not just a folder full of functions?</h5>
<p>I’m not sure I have a good answer to this yet. This was my previous solution for maintaining general purpose R functions until building a package.</p>
<p>Some current thoughts:</p>
<ul>
<li><strong>Organization:</strong> I’m finding it easier to organize my functions with structured documentation on parameters and examples, albeit with some upfront cost of actually writing this documentation.</li>
<li><strong>Sharing:</strong> makes it easier to share your code that is documented in a common-tongue with others.</li>
<li><strong>Version Control:</strong> If you’re using Github, you can always revert back to previous versions.</li>
<li><strong>Tests & Checks:</strong> When building a package, your code is evaluated for errors and missing dependencies, including your examples.</li>
<li><strong>Shiny apps:</strong> I realized during this process that you can actually wrap <a href="http://shiny.rstudio.com/">Shiny apps</a> up into functions and configure them to take arguments from your environment. Useful for quick and dirty exploratory work so you don’t have to worry about directories or change ui.R and server.R code around to fit something new you want to throw in a Shiny app.</li>
</ul>
<h5 id="how-to-start-building">How to start building</h5>
<ol>
<li>
<p>I got started following <a href="http://hilaryparker.com/2014/04/29/writing-an-r-package-from-scratch/">Hilary Parker’s post: Writing an R package from scrach</a>.
This gets you a minimal package on Github.</p>
</li>
<li>
<p>I had to fill in with some steps from <a href="http://stevemosher.wordpress.com/ten-steps-to-building-an-r-package-under-windows/">Steve Mosher’s post on building in Windows</a>.
I needed to add R to my path and install <a href="http://miktex.org/">Miktex</a>.</p>
</li>
<li>
<p>For anything else, you can probably find it on R guru <a href="http://r-pkgs.had.co.nz/">Hadley Wickham’s R packages page</a> soon to be published (2015) by <a href="http://www.oreilly.com/">O’Reilly</a> .</p>
</li>
</ol>
<h5 id="these-made-my-life-easier">These made my life easier</h5>
<ul>
<li><a href="http://cran.r-project.org/web/packages/devtools/index.html">devtools</a> R package.</li>
<li><a href="http://cran.r-project.org/web/packages/roxygen2/index.html">roxygen2</a> R package</li>
<li><a href="http://www.rstudio.com/">RStudio</a> for building and testing</li>
<li><a href="http://miktex.org/">Miktex</a></li>
</ul>
<h5 id="workflow-for-using-the-package">Workflow for using the package</h5>
<p>Once you’ve built a package on Github, it’s simple to pull it down wherever you are.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="w">
</span><span class="n">install.packages</span><span class="p">(</span><span class="s1">'devtools'</span><span class="p">)</span><span class="w"> </span><span class="c1"># if not already installed</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'devtools'</span><span class="p">)</span><span class="w">
</span><span class="n">install.packages</span><span class="p">(</span><span class="s1">'brooksandrew/Rsenal'</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s1">'Rsenal'</span><span class="p">)</span></code></pre></figure>
<h5 id="workflow-for-adding-to-a-package">Workflow for adding to a package</h5>
<ol>
<li>Clone the git repository from Github locally on whichever machine you’re on.</li>
</ol>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">
git clone https://github.com/brooksandrew/Rsenal.git Rsenal
</code></pre></figure>
<ol>
<li>Add function(s) to the <code class="highlighter-rouge">\R</code> folder of your package.</li>
<li>Good practice to add <code class="highlighter-rouge">packageName::</code> before each function from an external package, so it’s clear what your dependencies are for each function.</li>
<li>Update DESCRIPTION file with package dependencies: <a href="http://r-pkgs.had.co.nz/description.html">imports and suggests</a>.</li>
<li>Check and Build in RStudio.</li>
<li>Commit and push changes to Github.</li>
</ol>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">
git add <span class="nb">.</span>
git commit <span class="nt">-m</span> <span class="s2">"adding functions to R package"</span>
git push origin master</code></pre></figure>
<h5 id="gotchas">Gotchas</h5>
<p>If using RStudio and roxygen2, you might have to Configure Build Tools to allow Roxygen to generate the documentation you want it to.</p>
<p>In RStudio:<br />
=> Build<br />
=> Configure Build Tools<br />
=> Check box for “Generate Documentation with Roxygen”<br />
=> Click “Configure”<br />
=> Probably want to check boxes for at least “RD files” and “NAMESPACE”.</p>
<p>If your NAMESPACE file (simple list of your functions and dependencies) isn’t updating and you dont want to use RStudio, try <code class="highlighter-rouge">devtools::document()</code></p>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/personal-R-package/">DIY building an R package</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on November 20, 2014.</p>http://brooksandrew.github.io/simpleblog/articles/getting-feet-wet-with-aws2014-11-10T00:00:00+00:002014-11-10T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<p>I’ve been intrigued by <strong>Amazon Web Services (AWS)</strong> for a while now. I spent some time this week exploring
the workhorse (<a href="http://aws.amazon.com/ec2/">EC2</a>) and the warehouse (<a href="http://aws.amazon.com/s3/">S3</a>) among a couple other more lightly used AWS offerings (<a href="http://aws.amazon.com/simledb/">SimpleDB</a> and <a href="http://aws.amazon.com/rds/">RDS</a>).</p>
<p>Here’s <a href="http://slides.com/ajb073/web-scraping-and-persisting-data-in-the-cloud">the presentation</a> I shared with my company during an internal tech-time with my fellow data geeks:</p>
<iframe src="//slides.com/ajb073/web-scraping-and-persisting-data-in-the-cloud/embed" width="576" height="420" scrolling="no" frameborder="0" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
<h3 id="first-impression">First impression</h3>
<p>Admittedly, I don’t have a slew of cloud computing experience for comparison, but I was thoroughly impressed with the capabilities and usability of AWS, especially EC2. A data scientist with intermediate-ish command line skills, basic knowledge of technology, and a little bit of patience can be their own <a href="http://en.wikipedia.org/wiki/System_administrator">Sysadmin</a> and <a href="http://en.wikipedia.org/wiki/Database_administrator">DBA</a> pretty quickly.</p>
<p>In the past, I always felt like I was walking on eggshells working on servers, usually just a partition of some bigger machine doing at least something important. Usually some system or network admin would handle things my user role didn’t have permissions to do in the background, which could be nice, or slow, or a total road block. Not so with EC2. They take care of all the hardware and give you the reins for everything else – the fun stuff. I found I learned a lot more with the license to be dangerous. Worst case, terminate your instance and built it again. Just don’t do it on the beefy (and pricy) 8Xlarge 32 core instance…</p>
<h3 id="getting-started">Getting started</h3>
<p>I have to say I was thoroughly impressed with how easy it was to get started. The great thing about getting started with AWS is that there are minimal environment-specific issues to bog you down, since you’re really not working with your environment or your computer. The chunk of polycarbonate in front of you is just the vessel. And if you’re like me, those simple 2 line installation READMEs that go something like</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash">get someNew.thing
install someNew.thing</code></pre></figure>
<p>work maybe 1 in 5 times without having to install some hidden environment-specific dependency, manage multiple versions of the same thing, modify your PATH, or scour StackOverflow hoping someone had the same issue requiring you to modify your specific environment somehow to accommodate the new thing.</p>
<h3 id="aws-is-everywhere">AWS is everywhere</h3>
<p>I was doing some research on S3 vs. Dropbox… and then I discovered that <a href="http://www.datacenterknowledge.com/archives/2013/10/23/how-dropbox-stores-stuff-for-200-million-users/"><strong>Dropbox</strong> actually uses (or at least used to use) S3 to host</a> all your favorite kitten photos and documents you save to Dropbox.</p>
<p>Curious to see how <strong>slides.com</strong>, which I used to generate my slides would handle images when I exported the presentation to HTML, I inspected the exported HTML code to find that the platform automatically saves and hosts your content to S3. Each image (and other rich content, I expect) is available from a unique URL to an S3 bucket.</p>
<h3 id="making-of-the-slides">Making of the slides</h3>
<p>I also took this opportunity to experiment with some new slide/presentation technologies. Having used Powerpoint and LibreOffice Impress for most of my presentations in the past, I wanted to mess around with some of the web technologies/platforms. <a href="http://bartaz.github.io/impress.js/#/bored">impress.js</a> and <a href="http://prezi.com/your/">prezi</a> seemed a little dramatic and flashy for my purpose. I liked the simple style of <a href="http://lab.hakim.se/reveal-js/#/">reveal.js</a>, so I started there. The framework seemed relative straightforward and even supports markdown which I use to write this here blog, so that was cool.</p>
<p>However, not writing HTML and JavaScript everyday, I was spending more time tweaking code than working on content. For a more serious presentation, I definitely could have committed more time to this, but I was looking to throw together some casual slides together pretty quickly. I ended up using <a href="http://slides.com">slides</a> (the online graphical editor for reveal.js) which I found to be a simple yet useful and impressive solution.</p>
<h5 id="cool-things-about-slides">Cool things about <a href="http://slides.com">slides</a>:</h5>
<ul>
<li><strong>name.</strong> Seriously, no one thought of <a href="http://slides.com">slides.com</a> before now?</li>
<li><strong>free version</strong> for public presentations.</li>
<li><strong>export presentation to HTML</strong>, albeit messy HTML.</li>
<li><strong>images and content hosted on S3</strong>, so HTML presentation can stand-alone (no zipping and emailing dozens of files around) if you want to share presentation via email.</li>
<li><strong>simple features</strong> I used almost all the features available, but didn’t find myself desiring much more. Good balance that kept me focused on content.</li>
<li><strong>intuitive UI:</strong> I enjoyed not having to navigate worlds of dropdowns, ahem Powerpoint.</li>
<li><strong>code blocks:</strong> scrollable code blocks embedded directly in the presentation.</li>
<li>you get the code, so you can <strong>customize with reveal.js</strong> as much as you want after getting started with slides. <em>Note: untested…this may or may not be a good idea.</em></li>
</ul>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/getting-feet-wet-with-aws/">Getting feet wet with AWS</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on November 10, 2014.</p>http://brooksandrew.github.io/simpleblog/articles/deploying-apps-with-shinyapps-io2014-10-11T00:00:00+00:002014-10-11T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<p>So I’ve been messing around with Shiny for a year or so now. It’s great tool and getting greater.</p>
<p><strong>the good:</strong></p>
<ul>
<li>capability to rapidly build an interactive visualization with the full universe of R packages to choose from for the computation engine and visualization options.</li>
<li>ability to code and house the visualization/app in the same language/place as the code that actually conducts the analysis.</li>
<li>integrates seamlessly into analyst’s workflow.</li>
</ul>
<p><strong>the bad:</strong></p>
<ul>
<li>sharing can be hard</li>
<li>developed by analysts, used by analysts … and maybe others</li>
<li>need to download and run R to power app</li>
</ul>
<p><strong>the ugly:</strong></p>
<ul>
<li>if your app is ugly, it doesn’t have to be! Make it prettier with one of the 951,233,521 R graphics packages out there.</li>
</ul>
<h3 id="sharing-shiny-apps">Sharing Shiny apps</h3>
<p><strong>Option 1: Rstudio Shiny Server:</strong> If you have a linux server and the IT chops to configure it, you can set up your very own <a href="https://github.com/rstudio/shiny-server#shiny-server">Shiny Server</a> to host your whizbang Shiny apps.
We actually set one up at my company, and it is pretty awesome… however I didn’t set it up and I don’t pay for the server.</p>
<p><strong>Option 2: Shinyapps.io:</strong> If you’re just a mere human, like myself, without a server running in your house to host your app on some domain (which also costs $$),
<a href="http://shiny.rstudio.com/articles/shinyapps.html">shinyapps.io</a> is for you!</p>
<p>It’s pretty nifty. You can deploy all your apps to the cloud by interacting soley with R and a little configuration within the shinyapps.io interface in the web browser.<br />
For free.</p>
<p>Shinyapps.io is the successor to the Glimmer and Spark hosting services Rstudio experimented around 2012-2013. I setup a Glimmer account last year (which still works as of now – October 2014). You actually interact with Rstudio in the internet browser. I never established a steady workflow… unsure if I should be developing my apps locally and then SSHing into the Glimmer server and copying the apps there, or developing on the server’s file system…</p>
<p>In any case, shinyapps.io makes things even easier. Simply develop and test your apps locally on your computer, and when you’re ready to deploy to the world, you simply run:</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="w"> </span><span class="n">deployApp</span><span class="p">()</span></code></pre></figure>
<h3 id="getting-started-with-shinyappsio">Getting started with shinyapps.io</h3>
<p>A comprehensive walkthrough can be found <a href="http://shiny.rstudio.com/articles/shinyapps.html">here</a>. But the gist of it is pretty simple.</p>
<p>First register for an account <a href="https://www.shinyapps.io/">here</a>.</p>
<p>Then run the following R code:</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">require</span><span class="p">(</span><span class="s1">'devtools'</span><span class="p">)</span><span class="w">
</span><span class="n">devtools</span><span class="o">::</span><span class="n">install_github</span><span class="p">(</span><span class="s1">'rstudio/shinyapps'</span><span class="p">)</span><span class="w">
</span><span class="n">require</span><span class="p">(</span><span class="s1">'shinyapps'</span><span class="p">)</span><span class="w">
</span><span class="n">shinyapps</span><span class="o">::</span><span class="n">setAccountInfo</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s1">'yourUserNameHere'</span><span class="p">,</span><span class="w"> </span><span class="n">token</span><span class="o">=</span><span class="s1">'yourTokenHere'</span><span class="p">,</span><span class="w"> </span><span class="n">secret</span><span class="o">=</span><span class="s1">'yourSecretHere'</span><span class="p">)</span></code></pre></figure>
<p>Then navigate to directory of app</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">setwd</span><span class="p">(</span><span class="s1">'/Users/whoeverYouAre/yourShinyApps/yourFavoriteApp'</span><span class="p">)</span><span class="w">
</span><span class="n">deployApp</span><span class="p">()</span></code></pre></figure>
<p>And voila - you’ve deployed yourFavoriteApp Shiny App to the world… viewable at the URL something like: https://yourUsersName.shinyapps.io/yourFavoriteApp/</p>
<p>shinyapps.io is still very much a work-in-progress. For example, It’s currently <a href="https://github.com/rstudio/shinyapps/issues/23">not possible to delete deployed apps</a>. However, for
free hosting of multiple apps with an easy-to-use R and web interface and unintrusive workflow, it’s pretty good start.</p>
<p>###Proof that it works:</p>
<p>This is a visualization around the <a href="http://www.personal.psu.edu/j5j/IPIP/">IPIP-NEO personality test</a>. I generated some fake personalities for some familiar names (if you’re a <a href="http://en.wikipedia.org/wiki/Game_of_Thrones">GoT</a> geek).</p>
<p>Also viewable at the URL: <a href="https://brooksandrew.shinyapps.io/ipipex/">https://brooksandrew.shinyapps.io/ipipex/</a></p>
<p><strong>Update (9/1/2015):</strong> It appears I’ve been bumping up against my monthly limit of free hours with shinyapps.io, so if the app below is not rendered, that’s why. If you’re hosting an app on a website like this, you can change Idle Instance Timeout time in Settings to 5 minutes instead of the default of 15 to conserve some hours.</p>
<iframe src="https://brooksandrew.shinyapps.io/ipipex/" style="border: none; width: 1000px; height: 1000px"></iframe>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/deploying-apps-with-shinyapps-io/">Deploying Shiny apps with shinyapps.io</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on October 11, 2014.</p>http://brooksandrew.github.io/simpleblog/articles/dc-night-photography-monuments2014-10-05T00:00:00+00:002014-10-05T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<p>Having some fun walking around the monuments at night messing around with my new(ish) DSLR and tripod.</p>
<figure>
<a href="https://farm4.staticflickr.com/3935/15265881927_b6ddb27cd3_h.jpg" title="Maine Ave SW, Washington DC"><img src="https://farm4.staticflickr.com/3935/15265881927_b6ddb27cd3_h.jpg" width="1600" height="1064" alt="DSC_0115" /></a>
<figcaption>Maine Ave SW, Washington DC. Red+Yellow+Green stoplight??!! F/16 for 10 seconds.</figcaption>
</figure>
<figure>
<a href="https://farm6.staticflickr.com/5601/15265747140_323d60ef5c_k.jpg" title="Jefferson Memorial"><img src="https://farm6.staticflickr.com/5601/15265747140_323d60ef5c_k.jpg" width="2048" height="1362" alt="DSC_0121" /></a><figcaption>Jefferson Memorial, Washington DC. Obligatory DC monuments photo. F/16 for 8 seconds.</figcaption>
</figure>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/dc-night-photography-monuments/">Walking around DC with a camera</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on October 05, 2014.</p>http://brooksandrew.github.io/simpleblog/articles/when-google-fails2014-09-28T00:00:00+00:002014-09-28T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<h3 id="what-google-cant-do">What Google can’t do</h3>
<p>Google (Search) is pretty awesome. Sometimes it knows what I want more than I know what I want. But not with punctuation, special characters, symbols, whatever you want to call them – stuff like <code class="highlighter-rouge">!#$%&*+-/.,;:</code></p>
<h3 id="when-i-want-to-search-for-special-characters">When I want to search for special characters</h3>
<p>I find myself trying to search for special characters in two common situations:</p>
<ol>
<li>
<p><strong>Code:</strong> I’m often googling syntax for whichever programming language I’m coding in. Code is generally littered with special characters… especially if you’re doing something with <a href="http://en.wikipedia.org/wiki/Regular_expression">regular expressions</a>… like <code class="highlighter-rouge">([[^:]]+)://([[^:/]]+)(:([[0-9]]+))</code></p>
</li>
<li>
<p><strong>Writing:</strong> When I’m writing, I often use Google to help get a feel for how conventional/correct/mainstream the phrase or grammar I’m using is. If the <a href="http://www.nytimes.com/">New York Times</a> (or any organization of prestige) uses the piece of language I’m inquiring about, then I feel good about it. If Google returns only a couple sketchy websites with visibile editing lapses, I’ll probably rephrase my language. Take “editing lapses” for example. I thought of the phrase just as I was writing the previous sentence you just read. Having not used the phrase (that I can remember) before, I Googled it. Sure enough, one of the first hits was the <a href="http://books.google.com/books?id=CnwIVkAQgFwC&pg=PA85&lpg=PA85&dq=%22editing+lapse%22&source=bl&ots=xmq938KI5G&sig=6EAvhXLUvJ0hN7ERVdHvuA6kKg4&hl=en&sa=X&ei=0MwkVM_kINiiyAS7_oD4Cw&ved=0CD8Q6AEwBg#v=onepage&q=%22editing%20lapse%22&f=false">New York Times Manual of Style and Usage</a>:</p>
</li>
</ol>
<blockquote>
<p>If the justification is lame or lacking, the correction should acknowledge reporting or <strong>editing lapses</strong>.</p>
</blockquote>
<h3 id="what-special-characters-google-can-do">What special characters Google can do</h3>
<p>Google claims to provide search support for <a href="https://support.google.com/websearch/answer/2466433">some special characters</a>:</p>
<ul>
<li><code class="highlighter-rouge">+</code></li>
<li><code class="highlighter-rouge">@</code></li>
<li><code class="highlighter-rouge">&</code></li>
<li><code class="highlighter-rouge">%</code></li>
<li><code class="highlighter-rouge">$</code></li>
<li><code class="highlighter-rouge">-</code></li>
<li><code class="highlighter-rouge">_</code></li>
</ul>
<p>This wasn’t always the case – checkout <a href="http://insidesearch.blogspot.com/2012/04/search-quality-highlights-50-changes.html">Google’s official Search blog post from March 2012</a>. Search may support these special characters, but it does not allow (from what I can tell) to search for a specific quoted string with the character. I had decent luck with <code class="highlighter-rouge">$</code> and <code class="highlighter-rouge">%</code>, but could barely get any queries to work with <code class="highlighter-rouge">-</code> or <code class="highlighter-rouge">+</code>.</p>
<p>However noticably absent are the comma, period and colon and semicolon which account for nearly all the grammar queries I’d want to run by Google.</p>
<p>It appears I’m not alone. <a href="https://productforums.google.com/forum/#!topic/websearch/JJZ35b1ShFg">Here on Google’s product forms page</a>, a user complains of the same issue – inability to include a comma in a quoted string query.</p>
<h3 id="what-else-google-can-do">What else Google can do</h3>
<p>Google provides the simplicity of one search line that knows all (most of the time). There’s also the <a href="https://www.google.com/advanced_search">Google Advanced Search</a> page, which is not obviously located on <a href="http://google.com">the main search page</a>, where you can narrow your search by explicity guiding Google.</p>
<p>You can also utilize the simple search bar with basic <a href="https://support.google.com/websearch/answer/136861?hl=en">Google Search operators</a>. For some reason Google doesn’t document all of the operators – <a href="http://www.googleguide.com/advanced_operators_reference.html">here is a more extensive list</a>.</p>
<p>Some of my favorites are:</p>
<ul>
<li>
<p><code class="highlighter-rouge">filetype:pdf</code> returns just pdf documents… can replace with <code class="highlighter-rouge">:pdf</code> with <code class="highlighter-rouge">:R</code> if you’re looking for R scripts. You get the idea.</p>
</li>
<li>
<p><code class="highlighter-rouge">"this exact phrase"</code> returns hits with the exact phrase in quotes</p>
</li>
<li>
<p><code class="highlighter-rouge">d3 -diablo</code> returns hits on <code class="highlighter-rouge">d3</code> without the word <code class="highlighter-rouge">diablo</code>. This was a problem for me when I was constantly searching for the JavaScript library <a href="http://d3js.org/">D3.js</a> and not <a href="http://us.battle.net/d3/en/">Diablo 3</a> which admittedly consumed large part of my life for a short but intense period.</p>
</li>
<li>
<p><code class="highlighter-rouge">link:http://en.wikipedia.org/wiki/Catch-22</code> returns all the websites that link to the <a href="http://en.wikipedia.org/wiki/Catch-22">Catch 22 wiki page</a>. I like to use this on new websites/blogs/online-storefronts to scan for any red flags and general clout on the web.</p>
</li>
<li>
<p><code class="highlighter-rouge">~inexpensive dinner</code> returns hits for inexpensive dinners, cheap dinners, budget dinners, and any synonym of <code class="highlighter-rouge">inexpensive</code> with dinner. I’ve had mixed success with this one. A lot of the time the results appear the same with or without the tilda <code class="highlighter-rouge">~</code>.</p>
</li>
</ul>
<h3 id="where-you-can-search-for-special-characters">Where you can search for special characters</h3>
<p>For code specific queries, the Stack Overflow community seems to favor <a href="http://symbolhound.com/">SymbolHound</a>. For the few queries I tested with special characters, it returned some honest results with my exact string of special characters, but only a few hits (sometimes 2, sometimes 0).</p>
<p>Slightly unrelated… but when you find a special character that you can’t identify in a paper, or want to copy that special character somewhere, you can search for it on <a href="http://www.amp-what.com/unicode/search/">amp-what.com</a></p>
<p>It’s not just Google. The other big search engines, like <a href="http://bing.com">Bing</a> don’t support the full gamut of special characters either. I did encounter a new search engine called <a href="http://blekko.com">Blekko</a> with an interesting service – <a href="https://blekko.com/webgrep">webgrep</a> – that does exactly what I’m looking for. They search for specific strings of text including punctuation in the raw HTML and rank the top URLs. The only problem is that it takes 10 hours and is on reqest only. <code class="highlighter-rouge">:(</code> Cool concept though.</p>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/when-google-fails/">When Google Search fails, and when it doesn't</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on September 28, 2014.</p>http://brooksandrew.github.io/simpleblog/articles/nextbus4_viz2014-09-18T00:00:00+00:002014-09-18T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<p>See the prior 3 posts for context:</p>
<ul>
<li><a href="../nextbus1_api">How accurate is Next Bus I: Extracting data from API</a></li>
<li><a href="../nextbus2_wrangle">How accurate is Next Bus II: Wrangling data</a></li>
<li><a href="../nextbus3_analyze">How accurate is Next Bus III: Getting the answers</a></li>
</ul>
<iframe style="border: 0px;" src="/simpleblog/assets/html/d3nextbus.html" width="1000" height="600"></iframe>
<p>This one takes a long time to load. It makes a <code class="highlighter-rouge">d3.csv</code> call to a 24MB file. I was surprised to find that reading in the file took
all this time, but transformations that happen in the app take almost no time at all.</p>
<h3 id="one-week-of-next-bus-predictions">One week of Next Bus predictions</h3>
<iframe style="border: 0px;" src="/simpleblog/assets/html/busScatter.html" width="1000" height="550"></iframe>
<p>The scatter plot with zoom+pan+brush loaded too slow with the full dataset (24MB) of all 190,000 predictions for the week.
It also made for a crowded visualization. So I took a sample preserving a consistent distance between predictions. The sampled data (2.5MB) takes every 10th prediction which turns out to be approximately a prediction every 90 seconds.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1"># keeping just estimates every nth prediction when time between predictions is less than 30 seconds</span><span class="w">
</span><span class="n">df</span><span class="o">$</span><span class="n">timediff</span><span class="p">[</span><span class="m">2</span><span class="o">:</span><span class="n">nrow</span><span class="p">(</span><span class="n">df</span><span class="p">)]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">df</span><span class="o">$</span><span class="n">time</span><span class="p">[</span><span class="m">2</span><span class="o">:</span><span class="n">nrow</span><span class="p">(</span><span class="n">df</span><span class="p">)]</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">df</span><span class="o">$</span><span class="n">time</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="p">(</span><span class="n">nrow</span><span class="p">(</span><span class="n">df</span><span class="p">)</span><span class="m">-1</span><span class="p">)]</span><span class="w">
</span><span class="n">df</span><span class="o">$</span><span class="n">timediff</span><span class="p">[</span><span class="nf">is.na</span><span class="p">(</span><span class="n">df</span><span class="o">$</span><span class="n">timediff</span><span class="p">)]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">0</span><span class="w">
</span><span class="n">n</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">10</span><span class="w">
</span><span class="n">df</span><span class="o">$</span><span class="n">timediffSample</span><span class="p">[</span><span class="n">df</span><span class="o">$</span><span class="n">timediff</span><span class="o"><</span><span class="m">30</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">rep</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="n">n</span><span class="p">,</span><span class="w"> </span><span class="n">length.out</span><span class="o">=</span><span class="nf">sum</span><span class="p">(</span><span class="n">df</span><span class="o">$</span><span class="n">timediff</span><span class="o"><</span><span class="m">30</span><span class="p">))</span><span class="w">
</span><span class="n">df</span><span class="o">$</span><span class="n">timediffSample</span><span class="p">[</span><span class="nf">is.na</span><span class="p">(</span><span class="n">df</span><span class="o">$</span><span class="n">timediffSample</span><span class="p">)]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">0</span></code></pre></figure>
<p><a href="http://brooksandrew.github.io/simpleblog/articles/nextbus4_viz/">How accurate is Next Bus IV: visualizing</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on September 18, 2014.</p>http://brooksandrew.github.io/simpleblog/articles/nextbus3_analyze2014-09-17T00:00:00+00:002014-09-17T00:00:00+00:00andrew brookshttp://brooksandrew.github.io/simpleblogandrewbrooksct@gmail.com<p>So now that we’ve <a href="../nextbus1_api">collected data from the web</a> and <a href="../nextbus2_wrangle">wrangled it into something useful</a>, what can we say about how accurate Next Bus is?</p>
<p>This post is about the “making of the analysis” … which might be rather boring to those non data geeks (normal people). If you’re just interested in the story and the pictures, jump straight <a href="http://brooksandrew.github.io/projects/wmata/">here</a>!</p>
<p>I worked in R, as I usually do for most things statistical and graphical.</p>
<p>Our cleaned up data looks like this:</p>
<figure class="highlight"><pre><code class="language-bash" data-lang="bash"><span class="nb">time </span>Minutes VehicleID DirectionText RouteID TripID hour ID departure arrival est err
2014-08-12 10:56:04 98 6470 South to Federal Triangle 64 6464164 10 6464164_6470 1 0 100.90513 2.905133
2014-08-12 10:56:14 98 6470 South to Federal Triangle 64 6464164 10 6464164_6470 0 0 100.73572 2.735717
2014-08-12 10:56:24 98 6470 South to Federal Triangle 64 6464164 10 6464164_6470 0 0 100.56467 2.564667
2014-08-12 10:56:35 98 6470 South to Federal Triangle 64 6464164 10 6464164_6470 0 0 100.39257 2.392567
2014-08-12 10:56:45 98 6470 South to Federal Triangle 64 6464164 10 6464164_6470 0 0 100.22040 2.220400
2014-08-12 10:56:55 98 6470 South to Federal Triangle 64 6464164 10 6464164_6470 0 0 100.04953 2.049533
2014-08-12 10:57:05 97 6470 South to Federal Triangle 64 6464164 10 6464164_6470 0 0 99.87928 2.879283
2014-08-12 10:57:16 97 6470 South to Federal Triangle 64 6464164 10 6464164_6470 0 0 99.70852 2.708517
2014-08-12 10:57:26 97 6470 South to Federal Triangle 64 6464164 10 6464164_6470 0 0 99.53807 2.538067
2014-08-12 10:57:36 97 6470 South to Federal Triangle 64 6464164 10 6464164_6470 0 0 99.36845 2.368450</code></pre></figure>
<p><code class="highlighter-rouge">est</code> is the actual time until arrival from the time of prediction. <br />
<code class="highlighter-rouge">err</code> is the prediction error in minutes (postive values are late buses, negative values are early buses).<br />
<code class="highlighter-rouge">Minutes</code> is the prediction made at <code class="highlighter-rouge">time</code>.</p>
<p>Next Bus predictions are discrete, that is they are made in whole numbers such as 1, 2, 3 … up to 99 minutes — no decimals or seconds.
Each prediction (5 minutes, 10 minutes, etc) is made many times. So we can calculate some statistics around each prediction.
First I simply calculated the average prediction error.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="w">
</span><span class="n">mape</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">aggregate</span><span class="p">(</span><span class="n">err</span><span class="o">~</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">df</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">mean</span><span class="p">(</span><span class="nf">abs</span><span class="p">(</span><span class="n">x</span><span class="p">)))</span><span class="w">
</span><span class="n">mape60</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">mape</span><span class="p">[</span><span class="n">mape</span><span class="o">$</span><span class="n">Minutes</span><span class="o"><=</span><span class="m">60</span><span class="p">,]</span><span class="w">
</span><span class="n">plt4</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">ggplot</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">mape60</span><span class="p">,</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">err</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">geom_bar</span><span class="p">(</span><span class="n">stat</span><span class="o">=</span><span class="s1">'identity'</span><span class="p">,</span><span class="w"> </span><span class="n">fill</span><span class="o">=</span><span class="s1">'darkblue'</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">xlab</span><span class="p">(</span><span class="s1">'Prediction (minutes)'</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">ylab</span><span class="p">(</span><span class="s1">'Average prediction error (minutes)'</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">scale_x_continuous</span><span class="p">(</span><span class="n">breaks</span><span class="o">=</span><span class="n">seq</span><span class="p">(</span><span class="nf">floor</span><span class="p">(</span><span class="nf">min</span><span class="p">(</span><span class="n">mape60</span><span class="o">$</span><span class="n">Minutes</span><span class="p">)),</span><span class="w"> </span><span class="nf">ceiling</span><span class="p">(</span><span class="nf">max</span><span class="p">(</span><span class="n">mape60</span><span class="o">$</span><span class="n">Minutes</span><span class="p">)),</span><span class="w"> </span><span class="m">2</span><span class="p">))</span><span class="w">
</span><span class="n">ggsave</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s2">"/png/ggmapebar.png"</span><span class="p">,</span><span class="w"> </span><span class="n">plot</span><span class="o">=</span><span class="n">plt4</span><span class="p">,</span><span class="w"> </span><span class="n">width</span><span class="o">=</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">height</span><span class="o">=</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">dpi</span><span class="o">=</span><span class="m">200</span><span class="p">,</span><span class="w"> </span><span class="n">scale</span><span class="o">=</span><span class="m">1.3</span><span class="p">)</span><span class="w"> </span></code></pre></figure>
<p><img src="/simpleblog/assets/png/ggmapebar.png" alt="average prediction error by minute" /></p>
<p>Then I calculated the quantiles of actual arrival times (<code class="highlighter-rouge">df$est</code>) for each possible prediction (0, 1, 2, 3…100 minutes) using .05 increments for flexibilibity.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="w">
</span><span class="n">estq</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.frame</span><span class="p">(</span><span class="n">as.matrix</span><span class="p">(</span><span class="n">aggregate</span><span class="p">(</span><span class="w">
</span><span class="n">est</span><span class="o">~</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">df</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">quantile</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">seq</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">,</span><span class="m">.05</span><span class="p">)))</span><span class="w">
</span><span class="p">))</span></code></pre></figure>
<p>which turns out to be this (only showing predictions 0-5 minutes):</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="w"> </span><span class="n">Minutes</span><span class="w"> </span><span class="n">est.0.</span><span class="w"> </span><span class="n">est.5.</span><span class="w"> </span><span class="n">est.10.</span><span class="w"> </span><span class="n">est.15.</span><span class="w"> </span><span class="n">est.20.</span><span class="w"> </span><span class="n">est.25.</span><span class="w"> </span><span class="n">est.30.</span><span class="w"> </span><span class="n">est.35.</span><span class="w"> </span><span class="n">est.40.</span><span class="w"> </span><span class="n">est.45.</span><span class="w"> </span><span class="n">est.50.</span><span class="w"> </span><span class="n">est.55.</span><span class="w"> </span><span class="n">est.60.</span><span class="w"> </span><span class="n">est.65.</span><span class="w"> </span><span class="n">est.70.</span><span class="w"> </span><span class="n">est.75.</span><span class="w"> </span><span class="n">est.80.</span><span class="w"> </span><span class="n">est.85.</span><span class="w"> </span><span class="n">est.90.</span><span class="w"> </span><span class="n">est.95.</span><span class="w"> </span><span class="n">est.100.</span><span class="w">
</span><span class="m">0</span><span class="w"> </span><span class="m">0.0000000</span><span class="w"> </span><span class="m">0.0000000</span><span class="w"> </span><span class="m">0.000000</span><span class="w"> </span><span class="m">0.000000</span><span class="w"> </span><span class="m">0.1702833</span><span class="w"> </span><span class="m">0.1708667</span><span class="w"> </span><span class="m">0.171920</span><span class="w"> </span><span class="m">0.340590</span><span class="w"> </span><span class="m">0.341700</span><span class="w"> </span><span class="m">0.343200</span><span class="w"> </span><span class="m">0.510850</span><span class="w"> </span><span class="m">0.512670</span><span class="w"> </span><span class="m">0.5157933</span><span class="w"> </span><span class="m">0.6817667</span><span class="w"> </span><span class="m">0.6845333</span><span class="w"> </span><span class="m">0.7331833</span><span class="w"> </span><span class="m">0.8552367</span><span class="w"> </span><span class="m">1.021637</span><span class="w"> </span><span class="m">1.031120</span><span class="w"> </span><span class="m">1.203293</span><span class="w"> </span><span class="m">2.252650</span><span class="w">
</span><span class="m">1</span><span class="w"> </span><span class="m">0.1713333</span><span class="w"> </span><span class="m">0.6837833</span><span class="w"> </span><span class="m">0.853850</span><span class="w"> </span><span class="m">0.912685</span><span class="w"> </span><span class="m">1.0263000</span><span class="w"> </span><span class="m">1.1005667</span><span class="w"> </span><span class="m">1.197133</span><span class="w"> </span><span class="m">1.229026</span><span class="w"> </span><span class="m">1.366980</span><span class="w"> </span><span class="m">1.373926</span><span class="w"> </span><span class="m">1.536183</span><span class="w"> </span><span class="m">1.541720</span><span class="w"> </span><span class="m">1.7034033</span><span class="w"> </span><span class="m">1.7104717</span><span class="w"> </span><span class="m">1.7542533</span><span class="w"> </span><span class="m">1.8816333</span><span class="w"> </span><span class="m">2.0454300</span><span class="w"> </span><span class="m">2.058844</span><span class="w"> </span><span class="m">2.228947</span><span class="w"> </span><span class="m">2.560958</span><span class="w"> </span><span class="m">3.624817</span><span class="w">
</span><span class="m">2</span><span class="w"> </span><span class="m">0.8558500</span><span class="w"> </span><span class="m">1.5370892</span><span class="w"> </span><span class="m">1.710678</span><span class="w"> </span><span class="m">1.880133</span><span class="w"> </span><span class="m">2.0340733</span><span class="w"> </span><span class="m">2.0560000</span><span class="w"> </span><span class="m">2.219588</span><span class="w"> </span><span class="m">2.228256</span><span class="w"> </span><span class="m">2.389870</span><span class="w"> </span><span class="m">2.398855</span><span class="w"> </span><span class="m">2.559617</span><span class="w"> </span><span class="m">2.568933</span><span class="w"> </span><span class="m">2.7259833</span><span class="w"> </span><span class="m">2.7410317</span><span class="w"> </span><span class="m">2.9015967</span><span class="w"> </span><span class="m">2.9216333</span><span class="w"> </span><span class="m">3.0806933</span><span class="w"> </span><span class="m">3.248529</span><span class="w"> </span><span class="m">3.423398</span><span class="w"> </span><span class="m">3.760646</span><span class="w"> </span><span class="m">5.174917</span><span class="w">
</span><span class="m">3</span><span class="w"> </span><span class="m">1.3672333</span><span class="w"> </span><span class="m">2.3879967</span><span class="w"> </span><span class="m">2.568347</span><span class="w"> </span><span class="m">2.738833</span><span class="w"> </span><span class="m">2.9066067</span><span class="w"> </span><span class="m">3.0677500</span><span class="w"> </span><span class="m">3.087460</span><span class="w"> </span><span class="m">3.246477</span><span class="w"> </span><span class="m">3.271973</span><span class="w"> </span><span class="m">3.419170</span><span class="w"> </span><span class="m">3.461833</span><span class="w"> </span><span class="m">3.593877</span><span class="w"> </span><span class="m">3.6993467</span><span class="w"> </span><span class="m">3.7717700</span><span class="w"> </span><span class="m">3.9336867</span><span class="w"> </span><span class="m">4.0939833</span><span class="w"> </span><span class="m">4.1599733</span><span class="w"> </span><span class="m">4.334380</span><span class="w"> </span><span class="m">4.616890</span><span class="w"> </span><span class="m">4.962980</span><span class="w"> </span><span class="m">6.411083</span><span class="w">
</span><span class="m">4</span><span class="w"> </span><span class="m">1.9013167</span><span class="w"> </span><span class="m">3.2562533</span><span class="w"> </span><span class="m">3.588217</span><span class="w"> </span><span class="m">3.762400</span><span class="w"> </span><span class="m">3.9303300</span><span class="w"> </span><span class="m">4.0656333</span><span class="w"> </span><span class="m">4.145327</span><span class="w"> </span><span class="m">4.281953</span><span class="w"> </span><span class="m">4.443430</span><span class="w"> </span><span class="m">4.511590</span><span class="w"> </span><span class="m">4.628600</span><span class="w"> </span><span class="m">4.785950</span><span class="w"> </span><span class="m">4.8661900</span><span class="w"> </span><span class="m">4.9807400</span><span class="w"> </span><span class="m">5.1377533</span><span class="w"> </span><span class="m">5.3032667</span><span class="w"> </span><span class="m">5.4775833</span><span class="w"> </span><span class="m">5.666597</span><span class="w"> </span><span class="m">5.984240</span><span class="w"> </span><span class="m">6.335517</span><span class="w"> </span><span class="m">15.470133</span><span class="w">
</span><span class="m">5</span><span class="w"> </span><span class="m">2.5674667</span><span class="w"> </span><span class="m">4.1172400</span><span class="w"> </span><span class="m">4.453617</span><span class="w"> </span><span class="m">4.688427</span><span class="w"> </span><span class="m">4.9506233</span><span class="w"> </span><span class="m">5.1217750</span><span class="w"> </span><span class="m">5.205957</span><span class="w"> </span><span class="m">5.337202</span><span class="w"> </span><span class="m">5.481750</span><span class="w"> </span><span class="m">5.643520</span><span class="w"> </span><span class="m">5.803400</span><span class="w"> </span><span class="m">5.849483</span><span class="w"> </span><span class="m">5.9972100</span><span class="w"> </span><span class="m">6.1619100</span><span class="w"> </span><span class="m">6.3218600</span><span class="w"> </span><span class="m">6.4860917</span><span class="w"> </span><span class="m">6.6677600</span><span class="w"> </span><span class="m">6.863565</span><span class="w"> </span><span class="m">7.217443</span><span class="w"> </span><span class="m">7.708432</span><span class="w"> </span><span class="m">16.494933</span></code></pre></figure>
<p>So when the Next Bus app predicts 5 minutes:<br />
50% of the time the bus arrives between 5.1 and 6.5 minutes.<br />
70% of the time the bus arrives between 4.7 and 6.9 minutes.<br />
90% of the time the bus arrives between 4.1 and 7.7 minutes.</p>
<p>We can visualize this using the code below to explore the confidence intervals for each possible prediction: 0,1,2,3…60 minutes. I cut it off at 60 minutes because the data gets sparse after that and the lines generally continue to flat line.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">require</span><span class="p">(</span><span class="s1">'ggplot2'</span><span class="p">)</span><span class="w">
</span><span class="n">estq60</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">estq</span><span class="p">[</span><span class="n">estq</span><span class="o">$</span><span class="n">Minutes</span><span class="o"><=</span><span class="m">60</span><span class="p">,]</span><span class="w"> </span><span class="c1"># keeping just predictions 0-60</span><span class="w">
</span><span class="n">colfunc</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">colorRampPalette</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="s2">"pink"</span><span class="p">,</span><span class="w"> </span><span class="s2">"firebrick"</span><span class="p">))</span><span class="w">
</span><span class="n">cols</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">colfunc</span><span class="p">(</span><span class="m">4</span><span class="p">)</span><span class="w">
</span><span class="n">plt</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">ggplot</span><span class="p">(</span><span class="n">estq60</span><span class="p">,</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="w"> </span><span class="n">Minutes</span><span class="p">))</span><span class="w">
</span><span class="n">plt1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">plt</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_ribbon</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">ymin</span><span class="o">=</span><span class="n">est.5.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">ymax</span><span class="o">=</span><span class="n">est.15.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">),</span><span class="w"> </span><span class="n">fill</span><span class="o">=</span><span class="n">cols</span><span class="p">[</span><span class="m">3</span><span class="p">])</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_ribbon</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">ymin</span><span class="o">=</span><span class="n">est.15.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">ymax</span><span class="o">=</span><span class="n">est.25.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">),</span><span class="w"> </span><span class="n">fill</span><span class="o">=</span><span class="n">cols</span><span class="p">[</span><span class="m">2</span><span class="p">])</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_ribbon</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">ymin</span><span class="o">=</span><span class="n">est.25.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">ymax</span><span class="o">=</span><span class="n">est.50.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">),</span><span class="w"> </span><span class="n">fill</span><span class="o">=</span><span class="n">cols</span><span class="p">[</span><span class="m">1</span><span class="p">])</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_ribbon</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">ymin</span><span class="o">=</span><span class="n">est.50.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">ymax</span><span class="o">=</span><span class="n">est.75.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">),</span><span class="w"> </span><span class="n">fill</span><span class="o">=</span><span class="n">cols</span><span class="p">[</span><span class="m">1</span><span class="p">])</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_ribbon</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">ymin</span><span class="o">=</span><span class="n">est.75.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">ymax</span><span class="o">=</span><span class="n">est.85.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">),</span><span class="w"> </span><span class="n">fill</span><span class="o">=</span><span class="n">cols</span><span class="p">[</span><span class="m">2</span><span class="p">])</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_ribbon</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">ymin</span><span class="o">=</span><span class="n">est.85.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">ymax</span><span class="o">=</span><span class="n">est.95.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">),</span><span class="w"> </span><span class="n">fill</span><span class="o">=</span><span class="n">cols</span><span class="p">[</span><span class="m">3</span><span class="p">])</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">y</span><span class="o">=</span><span class="n">est.50.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">),</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"black"</span><span class="p">,</span><span class="w"> </span><span class="n">lwd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">y</span><span class="o">=</span><span class="m">0</span><span class="p">),</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"black"</span><span class="p">,</span><span class="w"> </span><span class="n">lwd</span><span class="o">=</span><span class="m">0.5</span><span class="p">,</span><span class="w"> </span><span class="n">linetype</span><span class="o">=</span><span class="s1">'dashed'</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">xlab</span><span class="p">(</span><span class="s2">"Prediction (minutes)"</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">ylab</span><span class="p">(</span><span class="s2">"Prediction error (minutes)"</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">scale_y_continuous</span><span class="p">(</span><span class="n">breaks</span><span class="o">=</span><span class="n">seq</span><span class="p">(</span><span class="nf">floor</span><span class="p">(</span><span class="nf">min</span><span class="p">(</span><span class="n">estq60</span><span class="o">$</span><span class="n">est.10.</span><span class="o">-</span><span class="n">estq60</span><span class="o">$</span><span class="n">Minutes</span><span class="p">)),</span><span class="w"> </span><span class="nf">ceiling</span><span class="p">(</span><span class="nf">max</span><span class="p">(</span><span class="n">estq60</span><span class="o">$</span><span class="n">est.95.</span><span class="o">-</span><span class="n">estq60</span><span class="o">$</span><span class="n">Minutes</span><span class="p">)),</span><span class="w"> </span><span class="m">1</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">scale_x_continuous</span><span class="p">(</span><span class="n">breaks</span><span class="o">=</span><span class="n">seq</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="m">60</span><span class="p">,</span><span class="w"> </span><span class="m">10</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_errorbar</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">estq</span><span class="p">[</span><span class="m">58</span><span class="p">,],</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">ymin</span><span class="o">=</span><span class="n">est.5.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">ymax</span><span class="o">=</span><span class="n">est.95.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">),</span><span class="w"> </span><span class="n">width</span><span class="o">=</span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">lwd</span><span class="o">=</span><span class="m">0.25</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_errorbar</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">estq</span><span class="p">[</span><span class="m">53</span><span class="p">,],</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">ymin</span><span class="o">=</span><span class="n">est.15.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">ymax</span><span class="o">=</span><span class="n">est.85.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">),</span><span class="w"> </span><span class="n">width</span><span class="o">=</span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">lwd</span><span class="o">=</span><span class="m">0.25</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_errorbar</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">estq</span><span class="p">[</span><span class="m">47</span><span class="p">,],</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">ymin</span><span class="o">=</span><span class="n">est.25.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">ymax</span><span class="o">=</span><span class="n">est.75.</span><span class="o">-</span><span class="n">Minutes</span><span class="p">),</span><span class="w"> </span><span class="n">width</span><span class="o">=</span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">lwd</span><span class="o">=</span><span class="m">0.25</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"text"</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="o">=</span><span class="s2">"50% confidence interval"</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="o">=</span><span class="m">47-1.5</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">estq60</span><span class="o">$</span><span class="n">est.65.</span><span class="p">[</span><span class="m">47</span><span class="p">]</span><span class="o">-</span><span class="n">estq60</span><span class="o">$</span><span class="n">Minutes</span><span class="p">[</span><span class="m">47</span><span class="p">],</span><span class="w"> </span><span class="n">size</span><span class="o">=</span><span class="m">2.5</span><span class="p">,</span><span class="w"> </span><span class="n">hjust</span><span class="o">=</span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"text"</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="o">=</span><span class="s2">"70% confidence interval"</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="o">=</span><span class="m">53-1.5</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">estq60</span><span class="o">$</span><span class="n">est.80.</span><span class="p">[</span><span class="m">53</span><span class="p">]</span><span class="o">-</span><span class="n">estq60</span><span class="o">$</span><span class="n">Minutes</span><span class="p">[</span><span class="m">53</span><span class="p">],</span><span class="w"> </span><span class="n">size</span><span class="o">=</span><span class="m">2.5</span><span class="p">,</span><span class="w"> </span><span class="n">hjust</span><span class="o">=</span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"text"</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="o">=</span><span class="s2">"90% confidence interval"</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="o">=</span><span class="m">58-1.5</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">estq60</span><span class="o">$</span><span class="n">est.90.</span><span class="p">[</span><span class="m">58</span><span class="p">]</span><span class="o">-</span><span class="n">estq60</span><span class="o">$</span><span class="n">Minutes</span><span class="p">[</span><span class="m">58</span><span class="p">],</span><span class="w"> </span><span class="n">size</span><span class="o">=</span><span class="m">2.5</span><span class="p">,</span><span class="w"> </span><span class="n">hjust</span><span class="o">=</span><span class="m">1</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">annotate</span><span class="p">(</span><span class="s2">"text"</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="o">=</span><span class="s2">"Median"</span><span class="p">,</span><span class="w"> </span><span class="n">x</span><span class="o">=</span><span class="m">12+1</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="o">=</span><span class="n">estq60</span><span class="o">$</span><span class="n">est.50.</span><span class="p">[</span><span class="m">12</span><span class="p">]</span><span class="o">-</span><span class="n">estq60</span><span class="o">$</span><span class="n">Minutes</span><span class="p">[</span><span class="m">12</span><span class="p">],</span><span class="w"> </span><span class="n">size</span><span class="o">=</span><span class="m">3</span><span class="p">,</span><span class="w"> </span><span class="n">hjust</span><span class="o">=</span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">fontface</span><span class="o">=</span><span class="s2">"bold"</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">plt1</span><span class="p">)</span><span class="w"> </span><span class="c1">#visualize plot before saving</span><span class="w">
</span><span class="n">ggsave</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s2">"/png/ggconf.png"</span><span class="p">,</span><span class="w"> </span><span class="n">plot</span><span class="o">=</span><span class="n">plt1</span><span class="p">,</span><span class="w"> </span><span class="n">width</span><span class="o">=</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">height</span><span class="o">=</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">dpi</span><span class="o">=</span><span class="m">200</span><span class="p">)</span><span class="w"> </span></code></pre></figure>
<p><img src="/simpleblog/assets/png/ggconf.png" alt="confidence intervals for Next Bus predictions" /></p>
<p>First note from the red waves above that <strong>predictions are consistently biased conservatively.</strong> That is, buses usually (~80% of the time) arrive after their predicted time.</p>
<p>Second note that the <strong>something weird aboout predictions of 11,12 and 13 minutes</strong>. As one would expect, the error of predictions is less when the bus is closer (<10 minutes away). As the bus gets closer, Next Bus only has to predict a couple periods ahead rather than many. It’s well known among forecasters (and non-forecasters) that the general happenings of tomorrow is a much
easier task than predicting the general happenings for a specific day decades in the future.
We have more information about tomorrow.</p>
<p>So why are predictions made a few months (11-13 minutes) into the future worse than
those made years into the future (14-60 minutes)? <strong>My first thought was that forecasts are recalibrated when they start predicting in the 11-13 minute window.</strong></p>
<p>I used to forecast macroeconomic indicators for a small <a href="http://en.wikipedia.org/wiki/Chile">emerging market country</a> when I worked at the <a href="http://www.federalreserve.gov/">Fed</a>. GDP, CPI inflation, monetary policy, all that good stuff. If there’s one thing I learned from my role as a country analyst, it was that forecasting is hard and usually more art than science… at least for macro indicators. Forecasts more than a couple years out are based on, well, usually not much. However macroeconomic forecasts for the
next quarter or two are more grounded.
There is higher frequency and more recent (useful) data to make forecasts based on nowcasts, timeseries models, and knowledge of policy, momentum, etc.</p>
<p>So when presented with new information about the economy of my forecast country during the forecast period (every month or two), I often faced a choice: revise or the stay the course. Knowing when to revise is hard. One doesn’t want to overreact
to information too soon just to revise a forecast in the opposite direction next time. Consumers of forecasts value both accuracy AND
consistency. The balance of which is tricky – there is usually a tradeoff.</p>
<p>This revision behavior explains why the Next Bus errors trend downward as predictions decrease from 10 to 0 minutes. But why the spike in
errors 11-13 minutes out? My second thought led me to create the visualization below which allows for an investigation of individual buses and their predictions throughout the week. Possibly a forecast bug? An idiosyncrasy of this particular bus route?</p>
<iframe style="border: 0px;" src="/simpleblog/assets/html/busScatter.html" width="1000" height="550"></iframe>
<p>Surprisingly, the revision hypothesis appears to be dead wrong (or at least very poorly implemented).
Predictions often follow a consistent trend (straight diagonal line) until some point where predictions
prematurely jump to 11, 12, or 13 minutes, when in reality, there is much longer to wait.</p>
<p><strong>Below:</strong> Exploring the variation around predictions 0, 1, 2, 3 … 60 minutes. Reaffirming that predictions of 11-13 minutes
are the most volatile.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">estvar</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">data.frame</span><span class="p">(</span><span class="n">as.matrix</span><span class="p">(</span><span class="n">aggregate</span><span class="p">(</span><span class="n">err</span><span class="o">~</span><span class="n">Minutes</span><span class="p">,</span><span class="w"> </span><span class="n">df</span><span class="p">,</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="nf">sqrt</span><span class="p">(</span><span class="n">var</span><span class="p">(</span><span class="n">x</span><span class="p">)))))</span><span class="w">
</span><span class="n">plt2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">ggplot</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">estvar</span><span class="p">[</span><span class="n">estvar</span><span class="o">$</span><span class="n">Minutes</span><span class="o"><=</span><span class="m">60</span><span class="p">,],</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">Minutes</span><span class="p">,</span><span class="n">y</span><span class="o">=</span><span class="n">err</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="o">=</span><span class="n">Minutes</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_text</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">Minutes</span><span class="p">,</span><span class="n">err</span><span class="p">),</span><span class="w"> </span><span class="n">size</span><span class="o">=</span><span class="m">3</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">ylab</span><span class="p">(</span><span class="s2">"Standard deviation of prediction error"</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">xlab</span><span class="p">(</span><span class="s2">"Prediction (minutes)"</span><span class="p">)</span><span class="w">
</span><span class="n">ggsave</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s2">"/png/ggstddev.png"</span><span class="p">,</span><span class="w"> </span><span class="n">plot</span><span class="o">=</span><span class="n">plt2</span><span class="p">,</span><span class="w"> </span><span class="n">width</span><span class="o">=</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">height</span><span class="o">=</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">dpi</span><span class="o">=</span><span class="m">200</span><span class="p">)</span><span class="w"> </span></code></pre></figure>
<p><img src="/simpleblog/assets/png/ggstddev.png" alt="standard deviations for Next Bus prediction errors" /></p>
<p><strong>Are Next Bus predictions less reliable during certain parts of the day, like rush hour?</strong>
Short answer, yes - predictions are off the mark (late) most in the morning between 8am and 10am.
Note this analysis is for the <a href="http://www.wmata.com/bus/timetables/dc/60-64.pdf">64 bus</a> heading from a residential neighborhood (Petworth) south to Federal Triangle (downtown DC). So peak ridership and traffic and thus prediction errors along the bus route would likely be in the morning.</p>
<p>I’m particularly interested in assessing relative accuracy of rush hour predictions, so I’m only looking at predictions on the weekdays. The <code class="highlighter-rouge">lubridate</code> R package makes working with POSIXct dates easy. First creating dummies for weekday and extracting hour.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">require</span><span class="p">(</span><span class="s1">'lubridate'</span><span class="p">)</span><span class="w">
</span><span class="n">df</span><span class="o">$</span><span class="n">day</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">weekdays</span><span class="p">(</span><span class="n">df</span><span class="o">$</span><span class="n">time</span><span class="p">)</span><span class="w">
</span><span class="n">df</span><span class="o">$</span><span class="n">weekday</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">ifelse</span><span class="p">(</span><span class="n">df</span><span class="o">$</span><span class="n">day</span><span class="w"> </span><span class="o">%in%</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'Monday'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Tuesday'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Wednesday'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Thursday'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Friday'</span><span class="p">),</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="m">0</span><span class="p">)</span><span class="w">
</span><span class="n">df</span><span class="o">$</span><span class="n">hour</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">hour</span><span class="p">(</span><span class="n">df</span><span class="o">$</span><span class="n">time</span><span class="p">)</span></code></pre></figure>
<p>Calculating the median prediction error for each prediction increment (1,2,3 … 60 minutes) by hour of day the prediction was made.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">agg</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">with</span><span class="p">(</span><span class="n">df</span><span class="p">[</span><span class="n">df</span><span class="o">$</span><span class="n">weekday</span><span class="o">==</span><span class="m">1</span><span class="p">,],</span><span class="w"> </span><span class="n">aggregate</span><span class="p">(</span><span class="n">err</span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="o">=</span><span class="nf">list</span><span class="p">(</span><span class="n">hour</span><span class="p">,</span><span class="w"> </span><span class="n">Minutes</span><span class="p">),</span><span class="w"> </span><span class="n">median</span><span class="p">))</span><span class="w">
</span><span class="nf">names</span><span class="p">(</span><span class="n">agg</span><span class="p">)</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'hour'</span><span class="p">,</span><span class="w"> </span><span class="s1">'Minutes'</span><span class="p">,</span><span class="w"> </span><span class="s1">'err'</span><span class="p">)</span></code></pre></figure>
<p>which returns something like this (sample below). So the average error for predictions made between 20:00 (8pm) 21:00 (9pm) when Next Bus predicts 3 minutes is 0.59874 minutes or 36 seconds (late).</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1">#print(agg)</span><span class="w">
</span><span class="n">hour</span><span class="w"> </span><span class="n">Minutes</span><span class="w"> </span><span class="n">err</span><span class="w">
</span><span class="m">20</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="m">0.59874167</span><span class="w">
</span><span class="m">21</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="m">0.26386667</span><span class="w">
</span><span class="m">22</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="m">-0.04255000</span><span class="w">
</span><span class="m">23</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="m">-0.25696667</span><span class="w">
</span><span class="m">0</span><span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">1.82138333</span><span class="w">
</span><span class="m">5</span><span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">0.62696667</span><span class="w">
</span><span class="m">6</span><span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">-0.06708333</span><span class="w">
</span><span class="m">7</span><span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">0.80045000</span><span class="w">
</span><span class="m">8</span><span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">0.96903333</span><span class="w">
</span><span class="m">9</span><span class="w"> </span><span class="m">4</span><span class="w"> </span><span class="m">0.80225000</span></code></pre></figure>
<p>To make this easier to interpret and analyze, I want to reshape the results from long to wide format.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">agg2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">reshape</span><span class="p">(</span><span class="n">agg</span><span class="p">[</span><span class="n">agg</span><span class="o">$</span><span class="n">Minutes</span><span class="o"><=</span><span class="m">60</span><span class="p">,],</span><span class="w"> </span><span class="n">timevar</span><span class="o">=</span><span class="s1">'Minutes'</span><span class="p">,</span><span class="w"> </span><span class="n">idvar</span><span class="o">=</span><span class="s1">'hour'</span><span class="p">,</span><span class="w"> </span><span class="n">direction</span><span class="o">=</span><span class="s1">'wide'</span><span class="p">)</span><span class="w">
</span><span class="n">agg2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">agg2</span><span class="p">[</span><span class="n">agg2</span><span class="o">$</span><span class="n">hour</span><span class="o">>=</span><span class="m">5</span><span class="p">,]</span></code></pre></figure>
<p>which creates something like this (sample):</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="c1">#print(agg2)</span><span class="w">
</span><span class="n">hour</span><span class="w"> </span><span class="n">err.0</span><span class="w"> </span><span class="n">err.1</span><span class="w"> </span><span class="n">err.2</span><span class="w"> </span><span class="n">err.3</span><span class="w"> </span><span class="n">err.4</span><span class="w"> </span><span class="n">err.5</span><span class="w"> </span><span class="n">err.6</span><span class="w"> </span><span class="n">err.7</span><span class="w"> </span><span class="n">err.8</span><span class="w">
</span><span class="m">5</span><span class="w"> </span><span class="m">0.5116583</span><span class="w"> </span><span class="m">0.5411750</span><span class="w"> </span><span class="m">0.73470833</span><span class="w"> </span><span class="m">0.7683667</span><span class="w"> </span><span class="m">0.62696667</span><span class="w"> </span><span class="m">0.3133833</span><span class="w"> </span><span class="m">0.5913083</span><span class="w"> </span><span class="m">0.8793417</span><span class="w"> </span><span class="m">1.04840000</span><span class="w">
</span><span class="m">6</span><span class="w"> </span><span class="m">0.3423917</span><span class="w"> </span><span class="m">0.1991000</span><span class="w"> </span><span class="m">0.05491667</span><span class="w"> </span><span class="m">-0.0438500</span><span class="w"> </span><span class="m">-0.06708333</span><span class="w"> </span><span class="m">0.1321667</span><span class="w"> </span><span class="m">0.1897833</span><span class="w"> </span><span class="m">0.3459500</span><span class="w"> </span><span class="m">0.07853334</span><span class="w">
</span><span class="m">7</span><span class="w"> </span><span class="m">0.5158500</span><span class="w"> </span><span class="m">0.8785333</span><span class="w"> </span><span class="m">0.91016666</span><span class="w"> </span><span class="m">1.0939833</span><span class="w"> </span><span class="m">0.80045000</span><span class="w"> </span><span class="m">0.9994833</span><span class="w"> </span><span class="m">0.8455833</span><span class="w"> </span><span class="m">0.9087167</span><span class="w"> </span><span class="m">0.77608333</span><span class="w">
</span><span class="m">8</span><span class="w"> </span><span class="m">0.5109667</span><span class="w"> </span><span class="m">0.7079833</span><span class="w"> </span><span class="m">0.90148333</span><span class="w"> </span><span class="m">1.1051333</span><span class="w"> </span><span class="m">0.96903333</span><span class="w"> </span><span class="m">1.1482167</span><span class="w"> </span><span class="m">1.1714500</span><span class="w"> </span><span class="m">1.0322583</span><span class="w"> </span><span class="m">1.39443333</span><span class="w">
</span><span class="m">9</span><span class="w"> </span><span class="m">0.5126917</span><span class="w"> </span><span class="m">0.7099667</span><span class="w"> </span><span class="m">0.91218333</span><span class="w"> </span><span class="m">0.5982667</span><span class="w"> </span><span class="m">0.80225000</span><span class="w"> </span><span class="m">0.9846500</span><span class="w"> </span><span class="m">1.2013000</span><span class="w"> </span><span class="m">1.8911333</span><span class="w"> </span><span class="m">2.78528333</span><span class="w">
</span><span class="m">10</span><span class="w"> </span><span class="m">0.3447833</span><span class="w"> </span><span class="m">0.3663167</span><span class="w"> </span><span class="m">0.43183333</span><span class="w"> </span><span class="m">0.3377000</span><span class="w"> </span><span class="m">0.50693334</span><span class="w"> </span><span class="m">0.5863583</span><span class="w"> </span><span class="m">0.8441750</span><span class="w"> </span><span class="m">0.7526417</span><span class="w"> </span><span class="m">1.30873333</span></code></pre></figure>
<p>Now creating the graphic that puts it all together. I chose to not show average errors when predictions are 1,2,3 … 60 minutes separately.
Firstly because the trend is the same and secondly because it’s messy. So I averaged together the median errors for predictions of 5,6,7,8,9 minutes in one
goup and 10,11,12,13,14 minutes in a separate group.</p>
<figure class="highlight"><pre><code class="language-r" data-lang="r"><span class="n">require</span><span class="p">(</span><span class="s1">'ggplot2'</span><span class="p">)</span><span class="w">
</span><span class="n">cols</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s1">'firebrick'</span><span class="p">,</span><span class="w"> </span><span class="s1">'forestgreen'</span><span class="p">)</span><span class="w">
</span><span class="n">agg2</span><span class="o">$</span><span class="n">err.5.9</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">rowMeans</span><span class="p">(</span><span class="n">agg2</span><span class="p">[,</span><span class="n">paste</span><span class="p">(</span><span class="s1">'err.'</span><span class="p">,</span><span class="w"> </span><span class="m">5</span><span class="o">:</span><span class="m">9</span><span class="p">,</span><span class="w"> </span><span class="n">sep</span><span class="o">=</span><span class="s1">''</span><span class="p">)])</span><span class="w">
</span><span class="n">agg2</span><span class="o">$</span><span class="n">err.10.14</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">rowMeans</span><span class="p">(</span><span class="n">agg2</span><span class="p">[,</span><span class="n">paste</span><span class="p">(</span><span class="s1">'err.'</span><span class="p">,</span><span class="w"> </span><span class="m">10</span><span class="o">:</span><span class="m">14</span><span class="p">,</span><span class="w"> </span><span class="n">sep</span><span class="o">=</span><span class="s1">''</span><span class="p">)])</span><span class="w">
</span><span class="n">plt3</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">ggplot</span><span class="p">(</span><span class="n">agg2</span><span class="p">,</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">hour</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">y</span><span class="o">=</span><span class="n">err.5.9</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="o">=</span><span class="n">cols</span><span class="p">[</span><span class="m">1</span><span class="p">]),</span><span class="w"> </span><span class="n">lwd</span><span class="o">=</span><span class="m">1.5</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_line</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">y</span><span class="o">=</span><span class="n">err.10.14</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="o">=</span><span class="n">cols</span><span class="p">[</span><span class="m">2</span><span class="p">]),</span><span class="w"> </span><span class="n">lwd</span><span class="o">=</span><span class="m">1.5</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_text</span><span class="p">(</span><span class="n">aes</span><span class="p">(</span><span class="n">y</span><span class="o">=</span><span class="n">err.10.14</span><span class="m">+.1</span><span class="p">,</span><span class="w"> </span><span class="n">label</span><span class="o">=</span><span class="n">military2std</span><span class="p">(</span><span class="n">hour</span><span class="p">)),</span><span class="w"> </span><span class="n">size</span><span class="o">=</span><span class="m">4</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">scale_x_continuous</span><span class="p">(</span><span class="n">breaks</span><span class="o">=</span><span class="n">seq</span><span class="p">(</span><span class="nf">min</span><span class="p">(</span><span class="n">agg2</span><span class="o">$</span><span class="n">hour</span><span class="p">),</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">agg2</span><span class="o">$</span><span class="n">hour</span><span class="p">),</span><span class="w"> </span><span class="m">2</span><span class="p">),</span><span class="w"> </span><span class="n">labels</span><span class="o">=</span><span class="n">military2std</span><span class="p">(</span><span class="n">seq</span><span class="p">(</span><span class="nf">min</span><span class="p">(</span><span class="n">agg2</span><span class="o">$</span><span class="n">hour</span><span class="p">),</span><span class="w"> </span><span class="nf">max</span><span class="p">(</span><span class="n">agg2</span><span class="o">$</span><span class="n">hour</span><span class="p">),</span><span class="w"> </span><span class="m">2</span><span class="p">)))</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">ylab</span><span class="p">(</span><span class="s1">'Average prediction error (minutes)'</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">xlab</span><span class="p">(</span><span class="s1">'Time of prediction'</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">scale_colour_manual</span><span class="p">(</span><span class="n">values</span><span class="o">=</span><span class="n">cols</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="m">2</span><span class="p">],</span><span class="w"> </span><span class="n">labels</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="s1">'average error when prediction is 5-9 minutes'</span><span class="p">,</span><span class="s1">'average error when prediction is 10-14 minutes'</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">theme</span><span class="p">(</span><span class="n">legend.title</span><span class="o">=</span><span class="n">element_blank</span><span class="p">())</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">theme</span><span class="p">(</span><span class="n">legend.position</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="m">.5</span><span class="p">,</span><span class="m">.1</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">theme</span><span class="p">(</span><span class="n">legend.text</span><span class="o">=</span><span class="n">element_text</span><span class="p">(</span><span class="n">size</span><span class="o">=</span><span class="m">12</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">theme</span><span class="p">(</span><span class="n">legend.background</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">element_rect</span><span class="p">(</span><span class="n">fill</span><span class="o">=</span><span class="n">alpha</span><span class="p">(</span><span class="s1">'white'</span><span class="p">,</span><span class="w"> </span><span class="m">0.5</span><span class="p">)))</span><span class="w">
</span><span class="n">ggsave</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="s2">"png/gghourmedian.png"</span><span class="p">,</span><span class="w"> </span><span class="n">plot</span><span class="o">=</span><span class="n">plt3</span><span class="p">,</span><span class="w"> </span><span class="n">width</span><span class="o">=</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">height</span><span class="o">=</span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="n">dpi</span><span class="o">=</span><span class="m">200</span><span class="p">,</span><span class="w"> </span><span class="n">scale</span><span class="o">=</span><span class="m">1.3</span><span class="p">)</span><span class="w"> </span></code></pre></figure>
<p><img src="/simpleblog/assets/png/gghourmedian.png" alt="average prediction error by hour" /></p>
<p>So predictions are wrong (late) the most between 8am and 10am on the weekdays. The errors jump around a bit throughout the day. Some of this could be the chosen frequency (hours)… it would likely be smoother if I chose 4 or 5 periods of the day spanning several hours each. Some of this could be the fact that I’m only analyzing one week of data for one bus line. Perhaps there was anomalous behavior around predictions made at 9pm for a couple buses that is driving the spike in prediction errors between 9pm and 10pm.</p>
<p>Analysis for next time!</p>
<!-- **Analysis for another day: possible extensions**
* **Interpolation:** One question that is still not fully answered is when does Next Bus swallow their pride and revise forecasts.
There is a lot of jumbling and flat lining around predictions of 8-13 minutes if you play with the scrolly d3 scatter plot app above.
I was thinking one could use some interpolation methods (revisiting my Numerical Methods class in grad school) to fit a curve (some n-degree polynomial)
to these data points. The slope of the curve at the various prediction increments would determine how Next Bus revises their forecasts
-->
<!-- The graphic below shows confidence intervals for Next Bus predictions ranging from 0-60 minutes.
So when the Next Bus app reads 10 minutes:
50% of the time the bus arrives between 31 seconds and 3:11 minutes late.
70% of the time the bus arrives between 19 seconds and 4:07 minutes late.
90% of the time the bus arrives between 50 seconds early and 6:20 minutes late. -->
<p><a href="http://brooksandrew.github.io/simpleblog/articles/nextbus3_analyze/">How accurate is Next Bus III: getting the answers</a> was originally published by andrew brooks at <a href="http://brooksandrew.github.io/simpleblog">andrew brooks</a> on September 17, 2014.</p>