andrew brooks Jekyll 2018-07-05T04:18:25+00:00 http://brooksandrew.github.io/simpleblog/ andrew brooks http://brooksandrew.github.io/simpleblog/ andrewbrooksct@gmail.com <![CDATA[Sleeping Giant Rural Postman Problem]]> http://brooksandrew.github.io/simpleblog/articles/sleeping-giant-rural-postman-problem 2017-12-01T00:00:00+00:00 2017-12-01T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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&amp;q=325264&amp;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>&lt;class 'networkx.classes.digraph.DiGraph'&gt; </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">&gt;</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 &gt;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" &amp; "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> <![CDATA[50 states Rural Postman Problem]]> http://brooksandrew.github.io/simpleblog/articles/fifty-states-rural-postman-problem 2017-11-19T00:00:00+00:00 2017-11-19T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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 &amp; 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>&lt;class 'networkx.classes.digraph.DiGraph'&gt; 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 &amp; 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 &gt;= 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 &gt; 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 &gt;100,000 possible node pairings. That means &gt;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" &amp; "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 &amp; 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> <![CDATA[Intro to graph optimization: solving the Chinese Postman Problem]]> http://brooksandrew.github.io/simpleblog/articles/intro-to-graph-optimization-solving-cpp 2017-10-07T00:00:00+00:00 2017-10-07T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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 &amp; 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&lt;---&gt;B == B&lt;---&gt;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---&gt;B != B---&gt;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&gt;=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> &amp; <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 &amp; 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 HCxJGjdunFfly4+396IxRgMGDNDAgQO1ceNGNWvWTF27dlVKSopGjRqluLg4t2Cb+7q98cYbuuuu uxQREaEePXooPDxckyZNUqtWrTyGvfP1wZozZ07ez7Vr166qVq2avvnmG7Vr187tDz0ZGRm66aab 9PrrryspKUndunVT48aN9a9//Ut9+/b16n322LFj2rRpkxwOh/r27Vvg/Qpybd48M+cepyif3eJw 5swZtW7dWlOnTlXLli3VrVs3RUZGSpKWLl2qJ554Qvv27VPjxo3Vq1cv1a9fX998843i4uI0bdo0 j9dd1E3H+/Tpo8DAQH322Wcuy//3v/8pOztbAwcOzHffi7mGF198UcOGDVPFihXVo0cPBQYGavz4 8WrdurVbv0igVDIACqxNmzbG4XCYzz//vNDHsCzLOBwOEx0dbQ4ePOi2/vjx42bx4sVuy/fu3Wvq 1Klj/P39zb59+1zWDRkyJO+4H3/8scu6Z555xliWZa677jqX5Z9++mnePiNGjHBZ9/bbbxvLsky7 du0KfF0jR440lmWZUaNGua1bsmSJsSzLNGrUyON1hYeHm8jISLNkyRKXdd99950JDAw0tWvXNpmZ mW5ltyzL3H333SY7Oztv3bx584y/v78JDw83f/zxh8t5cvdp06aNOX36tFtZvvzyS2NZlmnSpIn5 9ddfXda9+OKLxrIs079//7xle/bsMZZlmbp165qTJ0+6bJ+enm7Wrl3rsuyhhx4ylmWZAQMGuJw/ KSnJdO3a1TgcDvPBBx+47BMVFWUsyzLVqlUzu3btylt+/Phx06BBA+NwOMzSpUtd9mnfvr1xOBxu 90mu7du3m59++slt+YIFC0xQUJBp0KCB27qoqCjjcDg8Hs8Y5z3ocDjM8uXLXZZfc801xuFwmGee ecZl+YwZM4yfn5+JjIw0hw4dylue+zo5HA4TFxdnkpKS8tZt3Lgx77VNTk7Otyxn++qrr4xlWaZm zZpm9+7dectPnz5tbrzxRuNwOMzw4cNd9lm2bFneveWNBx54IO8ea9mypRk1apT55ptvzNGjR/Pd J79zeXsvGmPM66+/bizLMjfddJM5cuRI3vLMzEwzdOhQj69D+/btjWVZJjAw0MyfPz9veVZWlrnz zjuNZVmmZ8+eLvvkPn/nPuu570P+/v5mzpw5ectzcnJMnz59jMPhMC+++KLLPi+//LKxLMu0atXK 5ZnYt2+fqVWrVt69UBCLFi0ylmWZ6OjoAm3vSX7XVthnpqif3YLKfT8+3z28ffv2vPu1U6dOJiUl xW2bXbt2mU2bNrktX7t2rYmIiDCVK1c2GRkZLutyX+uNGze6LG/RooVxOBzm+PHjBbqGr7/+2uX+ 69GjhwkMDHR5nq6//npz2WWXmfT0dDN+/HhjWZZ59NFHL/oaWrRoYSzLMiEhIS7vaRkZGaZ3797G siwzaNCgAl0H4EsEPcALjRo1Mg6HwyxYsMDj+nvuuccMGTLE5ev777932Sb3g8uMGTO8Pv/48eON w+Ew7733nsvy3A9YN954o9s+mZmZpmbNmsbhcLiUJfcDTb169VxClDHOD3kVKlQwQUFBbuvy4yno /fnnn2bu3Lmmdu3aJiIiwqxcudJtv7///e/G4XCYcePGeTxu7vpZs2a5lT0yMtKcOnXKbZ9+/foZ h8NhXn311bxlZwcIT7/0jTGmSZMmxuFwePxAZ4wxzZo1MwEBAXkfVNatW2csyzK9evXyuP3Zjhw5 YgIDA01UVJRJT093W3/o0CETFBRkmjZt6rI8N2BNmDDBbZ8333zT44fSi/mweOeddxqHw2G2b9/u sRz58RT0li5daizLMlFRUSYrK8ttn969exuHw2FGjx6dtyz3dfL393f5cJyrW7duHgNlftq2bWsc DocZP36827qtW7cah8NhIiMjXV6Twga91NRUc++99xo/Pz/jcDjyPkQ7HA4TExNjpk6d6rZPfufy 9l7MysoyV1xxhYmIiPAYLFNTU03VqlXN5Zdf7rI8917x9KH1+PHjJiwszPj5+Znff/89b/mFgt7g wYPdjrVx40ZjWZbp0KGDy/IaNWoYh8NhVq9e7bZP7gf3gga9qVOnGsuyTOvWrT2unzt3rtv781NP PeWyTX7Xdj4XemZK6tk9mzdBz8/Pz+zYscPrczz++OPG4XCYZcuWuSwvrqA3bdo0Y1lW3u+/Xbt2 GcuyzNChQ40xJt+gV5hryC3rgw8+6LbPgQMHTFBQkAkMDCzwtQC+wmAsQBGaNGmS29x5HTp0UOvW rV2WWZalW2+99bzH+v7777Vs2TIdOHBAaWlpMsbo4MGDkqRdu3a5bW9Zlu644w635f7+/urTp4/e eecdrVy50q0s7du3l7+/61uBn5+f6tSpo82bN+v48eNeDbIxcuRIjRw50mVZhQoVtGbNGl111VVu 2y9cuFCS1LNnT4/Ha9Omjd59912tW7fOpamTJHXu3NnjoBf9+/fX1KlT3eYsk6SqVat67Dt59OhR bd26VdHR0WrUqJHHstxwww3asmWLNm7cqE6dOqlhw4YKCwvTvHnzNHbsWA0cODCvCe65li1bpszM TN18880KDAx0W1+5cmU1aNBA27ZtU3p6uoKCglzWd+rUyW2f6OhoScq7L7yRkZGh+fPna926dTp6 9KgyMjIkKa+J765duzy+Xt7I/fn37dvXYz+jQYMGacaMGVq5cqXbwEa1a9dW/fr13faJjo7WvHnz CnTNWVlZSkhIkORsYnuua665Rtdee622bt2qH374Qddff32Bris/wcHBGj9+vJ599llNnz5dq1at 0vr163X48GGtW7dO/fr105o1a/TWW2+d9ziFuRc3bdqkY8eOqXPnzh77CAYHB6t58+b65ptvtGvX LjVo0MBlvaf3jgoVKqhz586aPXu2Vq1a5XGbc1mWVeB7df/+/Tpw4ICqVq2qVq1aue1zxx136L77 7rvgOQtqy5YtmjRpUt7/zf/vC/fGG28UaP/CPjNF/ewWtfr16+vKK6/Md312drYWLlyoNWvW6PDh w3nNf3P7XO7atUvt2rUr9nJ269ZN5cqV05QpU/Twww9r8uTJsiyrQIOeFfYaPN3z1apVU9u2bbV4 8WKtWbNGXbt2vcgrA4oPQQ/wQu6AIvm1zc/MzMz794MPPqgPP/zQ43aVKlVSQECAx3WnT59Wz549 tXTp0nz7OZw5c8bj8tq1a3tcHhUVJWOMx742NWrU8LhP7shz5/bpuZDcefSMMTpy5IiWLVumEydO aMCAAVqzZo1CQ0Ndtt+7d68k5y/P/FiW5fFnfr7rleTxevMb/j+3HLt27ZLDkX/35bPLEhERoY8+ +kjDhg1TfHy8RowYoejoaHXo0EGDBg1yCdW5x//www/zvS9yj3/ixAm3wOjpdSrsa7Rt2zZ1795d +/bt8/oe88Yff/yRN4+ZJ7nLDxw44LauKO7L48ePKyMjQ1dccYXbSH1nl2Hr1q0ey1BYdevW1fDh wzV8+HBJzjnNRo4cqTlz5ujdd99V3759PQabXIW5F3P3WbBgQYH2OTfoFeZZyo+n1y53CpqzX7fc kFOzZk2PxwkPD9dll13mMmjJ+Vzo/fm5557Tc889J0k6fPhwvn+U8eRinpmifHaLw/mmRNmzZ4+6 du2qHTt2FOt7RUEEBQWpd+/e+uSTT/TLL7/o888/V40aNS4YMi/mGoryuQB8gaAHeKFJkyZavXq1 Nm/erP79+xf6OLmDNngyYsQILV26VB06dNCoUaN01VVX6bLLLpNlWVq4cKFuvvnmIp3/7nwfCgvj 3Hn0Dh48qPbt22v79u16+umn9e6777psn1sDeqEBB2JiYoqkfPn97HPLUaVKFd18883nPcbZv/z7 9eunTp06afbs2VqwYIGWL1+uDz/8UB988IGeeOIJjR071uX4zZo1U5MmTc57/HNr84pa3759tX// fj300EMaNmyY6tatq7CwMEnOD8NjxowpljkWz3W+ARuK+r4sTBmKStOmTTVz5kzFxMRo48aNmjdv 3nmDXmHuxdx9GjRo4DZv3LlyA1FxKanX7lzXXnutJOnXX39VUlKS2/ymF6O0PDPF4Xy/jwYNGqSd O3fqzjvv1OOPP64GDRrkhdS33npLTz75ZIle98CBAzVhwgQ99thj2r17t+Lj4y+4T2m7BqAkEfQA L3Tp0kXjxo3TtGnT9K9//atYPiTOmjVL/v7+mjNnTt4HiVznTu57rn379uW73LKs89aaFZeqVavq 008/1Q033JAXfs6u4alRo4Z+/fVXvfnmmy6jXxbE+a5XOn8t4bly/+pesWJFrycYvvzyy3XPPffo nnvukeSsVenbt6/eeust3XvvvWrUqFHe8du0aaN33nnHq+MXpR07dmjnzp1q2bKl3nvvPbf1u3fv LrJzVatWTcaYfF+n3Fqo6tWrF9k5z3b55ZcrMDBQx44d8zj/VkmUIZdlWWrXrp02bNhwwdH6CnMv 5u7TsGHDQk2QvW/fPl199dUel0vePUsFlVujljtv4bmSkpJ06tSpAr/PXnHFFXmTZn/55Zd5z+PF KslnpjQ5duyYVq9erXr16rk0ec21e/fuEvlDydnat2+v6tWr581Zeb7RNqWLv4Z9+/Z5bJFQnM8F UJSYXgHwwi233KJGjRpp//79eu2114rlHCdPnlRkZKRbyJOkqVOn5vtLyRijL7/80m15dnZ23hD2 bdq0KdrCFlCrVq102223KSsrS2PGjHFZl9t/ZebMmV4fd8GCBTp9+rTb8i+++EKWZenGG28s8LGq V6+uhg0b6qefftIvv/zidVnO1rlz57x+Gz/++KMkZ19NPz8/ff311x7nyytKuX0Ac+d1O9vJkycl 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 &lt;=&gt; Red Diamond and Blue &lt;=&gt; 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 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 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">' =&gt; '</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 =&gt; y_rs =&gt; 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 =&gt; y_rc =&gt; 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 =&gt; v_rs =&gt; 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 =&gt; b_tt_1 =&gt; 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 =&gt; b_v =&gt; 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 =&gt; v_rh =&gt; v_rd =&gt; 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 =&gt; b_tt_2 =&gt; tt_rt =&gt; v_rt =&gt; 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 =&gt; g_rc =&gt; b_rc =&gt; v_rc =&gt; 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 =&gt; w_gy2 =&gt; b_gy2 =&gt; b_o =&gt; b_y =&gt; 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 kiRJLcC4JEmSpFrJmTnAyxiXJElqCcYlSZIk1dEsjEuSJLUE45IkSZLqyLgkSVKLMC5JkiSpjmZi XJIkqSUYlyRJklRHs4CRVQ8hSZLemnFJkiRJdeRtcZIktQjjkiRJkurIuCRJUoswLkmSJKmOjEuS JLUI45IkSZLqaBawbAh0VD2IJElaNOOSJEmS6mhW4+NylU4hSZLeknFJkiRJdfRGXPLWOEmSas64 JEmSpDoyLkmS1CKMS5IkSaoj45IkSS3CuCRJkqQ6Mi5JktQijEuSJEmqnZx5HXgV45IkSbVnXJIk SVJdzQJGVj2EJElaNOOSJEmS6moWnlySJKn2jEuSJEmqK+OSJEktwLgkSZKkujIuSZLUAoxLkiRJ qivjkiRJLcC4JEmSpLoyLkmS1AKMS5IkSaor45IkSS3AuCRJkqS6mgW8PQR/ZpUkqc78B7UkSZLq ahYQgGWrHkSSJC2ccUmSJEl1Navx0VvjJEmqMeOSJEmS6sq4JElSCzAuSZIkqa5mNj6OrHQKSZK0 SMYlSZIk1ZUnlyRJagHGJUmSJNXVa8BsjEuSJNWacUmSJEm1lDOZ4vSScUmSpBozLkmSJKnOjEuS JNWccUmSJEl1ZlySJKnmjEuSJEmqM+OSJEk1Z1ySJElSnRmXJEmqOeOSJEmS6sy4JElSzRmXJEmS VGfGJUmSas64JEmSpDqbBSwfAqHqQSRJ0oIZlyRJklRjz70Af2mHw99T9SSSJGnBQs656hkkSZKk NwkhBOCr7e1LnNDdPfttIYRu4Kqc8xdzzrOqnk+SJP2LcUmSJEm1E0I4Gjhzn332Ycstt+Svf/0r F1xwQferr756T3d399jsD7GSJNWGcUmSJEm1EkIY1t7e/vc99tjj7ccff/w/X586dSqHHHIIwBY5 59uqmk+SJL2ZO5ckSZJUN6t0d3e/fcstt3zTi2PHjmXYsGE9wPrVjCVJkhbEuCRJkqRa2WWXXV5p b2/vmT59+ptef+yxx5gzZ04bMKOaySRJ0oJ0VD2AJEmSBJBS6gD2P/nkk7/Z3d0dvv/97+fVV189 bLbZZjz++OMcd9zxtLd3/qO7e+4vqp5VkiT9izuXJEmSVKmUUgB2BU4B1gIm3nLLLWcceeSR53R3 d2/W2dnJ3LlzaW9foae7+6pH4aOjc+blaqeWJElvMC5JkiSpMimljwCnA5sANwPHxhjvBTjssMPC mDFjZl133XV3Tpo06YcwbTqs/d/ATcAeOdNT3eSSJOkNxiVJkiQNuJTSesBpwA7AvRRR6eb5vuYD wJ+BHWKM1wOEwM7AFGB8zpw4sFNLkqQFceeSJEmSBkxKaXXgRODTwCPA3sCkGOOCTiGNbXz8/Rsv 5MwvQuAE4KQQeDBnrlncM0uSpEUzLkmSJGmxSymtCBwPHArMBA4DfhhjnLuIbxsL/DHG+Px8r58C jAIuC4GxOZMWx8ySJKl3jEuSJElabFJKSwNfAY4CMvAt4OwY4yu9+PaxwB3zv5gzOQQOAG4HpoTA mJyZ1cSxJUlSHxiXJEmS1HQppWHAwcAJwHLA+cBpMcbnevn9ywDrNr7v3+TMyyGwK3A3cGUIbJ8z XU0ZXpIk9YlxSZIkSU2TUmoD9gFOAlYHLgXGxxj/r4+X2ghoA6Yu7Aty5tEQ2JPi6XFnUpyQkiRJ A8y4JEmSpH5LKQVgW4onwI0GfgnsEmMsuw9pLPAP4OFFfVHO3BoCRwDnhsD9OXNpyfeTJEklGZck SZLULymljYAzgI9S7EHaPMb4P/287FjgzoU8RW5+51MErf8KgYdz5q5+vrckSeqDtqoHkCRJUmtK Ka2ZUpoE3AmsCOxME8JS49a6BS7zXpCcyRRPn7sP+HkIvKs/7y9JkvrGk0uSJEnqk5TSKsB44EDg SeCzwE9ijN1Neos1gLeziH1L88uZ2SGwG3APMDkEPpozs5s0jyRJWgTjkiRJknolpbQccAxwOPAa cDRwYYzx9Sa/1VggU5yI6rWceSoEPgH8DrgwBD7XONUkSZIWI+OSJEmSFimltBQwDjgOWAKYAJwV Y3xhMb3lWGBajPHFvn5jztwVAgcDl1DcJndes4eTJElvZlySJEnSAqWUOoD9gW8C7wQuAk6KMT61 mN96U4rF4KXkzKUhMAr4bghMy5nfNG80SZI0P+OSJEmS3iSlFIBdgVOAtYCJwPExxukD8N7LAmsD 3+7npY4B1gWuCoENc+bRfg8nSZIWyKfFSZIk6Z9SSh+hWKQ9mWJZ94Yxxr0HIiw1bAwEevmkuIXJ mS5gH+B5YEoILN2E2SRJ0gJ4ckmSJEmklNYDTgN2AO4Ftokx3lzBKGOBWcCf+3uhnJkVArsAvwd+ HAJ75UxPf68rSZLezJNLkiRJQ1hKabWU0mXA/cAawN7ARhWFJSj2Ld0RY2zKU95yZhqwL7A78PVm XFOSJL2ZJ5ckSZKGoJTSihSx5TBgZuPjD2OMcyucqY3itrizmnndnJkSAuOBE0PgwZyZ0szrS5I0 1BmXJEmShpCU0tLAV4CjgAx8Czg7xvhKpYMV1gKWpZ/7lhbiZGAU8JMQ2KRxokmSJDWBcUmSJGkI SCkNAw4GTgCWA84HTo0xzqx0sDcbC/QAdzX7wjnTEwL7U4SrKSGwUc7Mavb7SJI0FBmXJEmSBrHG rWb7ACcBqwGXAuNjjI9VOddCbAo8GGN8eXFcPGdebiz4vhv4WQjs0HiqnCRJ6gfjkiRJ0iCUUgrA thRPgBsN/ALYOcZY59vBxgK3Ls43yJm/hsBewA3A6RS3B0qSpH7waXGSJEmDTEppI+AW4HrgFWDz GOMudQ5LKaXlgQ+yePYtvUnO3EKxd+rIENhvcb+fJEmDnSeXJEmSBomU0prAKcDuwDRgZ+DaGGOu dLDe2aTxcbHHpYbzKE50XRQCD+fM3QP0vpIkDTrGJUmSpBaXUloFGA8cCDwJfBb4SYyxu8q5+mgs 8CzwyEC8Wc7kEDiU4gl114TAhjnz1EC8tyRJg41xSZIkqUWllJYDjgEOB14DjgYujDG+Xulg5YwF 7hjIU1Y5MzsEdgPuAa4OgS1yZvZAvb8kSYOFcUmS1HJCCMsAewPvB/4ETMw5v1rtVNLASSktBYwD jgOWACYAZ8UYX6h0sJJSSu3AxhS39A2onHkqBD4B/A64IAQ+nzOtcBuhJEm1YVySJLWUEML6HXBT Nyz/Luh6Cjrb4fQQwpY55z9UPZ+0OKWUOoD9gW8C7wQuAk6KMbb67VwRWJqB27f0JjlzVwgcDFwC 3A+cX8UckiS1KuOSJKllhBDaOuDqdWC5KRDeC52PADvBCtNhYghh3ZyzJw406KSUArArxcmetYAr geNjjH+pdLDmGQt0Q3VLtXPm0hBYHzg7BFLO3FbVLJIktZq2qgeQJKkPxnbB6udB+3sbL7wfmADt XbAOMKrC2aTFIqX0YWAqMBl4AtgwxrjPIApLUMSl+2OMVd/eejRwGzApBFardhRJklqHJ5ckSa1k JMDq8734vvk+Lw0GKaX1gNOAHYB7gW1ijDdXO9ViMxa4oeohcqYrBPYG7gKmhMCmOfNK1XNJklR3 nlySJLWSuwN0/3S+Fy8H2mjrhnfcX8VQUjOllFZLKV1GsftnDYrl9RsN1rCUUloR+AAV7VuaX87M BHahOBj54xAIFY8kSVLtGZckSS0j5/wU8L1jIR8K/BQ4CDgJ6OHodvj75SHwzkqHlEpKKa2YUjob +DOwNXAYsHaMcWKMsafa6RarTRofp1Y6xTxyJgH7AXsAX6t4HEmSai+491SS1EpCCO3AsR1wRBeM 7IBnuuAseH0aLHExxf9xckDO/KriUaVeSSktDXwFOArIwJnA2THGIXE7VkrpVOAAYOUYY61+MA2B 8RRP5tslZ35R8TiSJNWWcUmS1JJCCG3AcODVnHNP8RorAT8CdgQuAI7Omdeqm1JauJTSMOBg4ARg OeB84NQY48xKBxtgKaVbgedjjLtVPcv8QqANmERxkmyTnPlDxSNJklRLxiVJ0qDS2I9yGPBt4BHg kznzULVTSf+SUmoD9qG4o3M14FJgfIzxsSrnqkJKqQN4AfhmjPGsqudZkBBYhuKWvSWBjXLm+YpH kiSpdty5JEkaVHIm58wFwIZAD3B3CHzJpbyqWkoppJS2pXjy2+VAAtaLMR4wFMNSw3oUJxBrs29p fjnzEsWC7+WBn4Xg05YlSZqfcUmSNCjlzDRgI+D7wDnAdSHwjmqn0lCVUtoIuAX4NfAysFmMcZcY 47RqJ6vcWGAuRXCrrZz5K7AXsBVwWsXjSJJUO8YlSdKglTOv58yXgR2ADYCHQmDHisfSEJJSWjOl NAm4E1gJ2Bn4cIzx9monq42xwH0xxterHuSt5MwtwJHAUSHw6arnkSSpTjzWK0ka9HLm+hBYj2LZ 97UhcD7wVZd9a3FJKa0CjAcOBJ4EPgv8JMbYXeVcNbQptNRT2M4F1gd+EAJ/ypl7qh5IkqQ6cKG3 JGnIaOxd+iLFsu/pwKdc9q1mSiktBxwDHA68BpwMXNgKJ3MGWkrpHcDfgb1jjBOrnqe3QmBJ4LfA ysCYnPl7xSNJklQ5b4uTJA0ZjWXf51Ms+waXfatJUkpLpZSOBv4KfAmYALwvxvhdw9JCjW18vKPS KfooZ14HPgG0A1eHwBIVjyRJUuW8LU6SNOTkTAqBMcAZFMu+twuBA3Lm6YpHU4tJKXUA+wPfBN4J XAScFGN8qsq5WsRY4MkY4+NVD9JXOTMjBHajOMF0fggcnDPeDiBJGrKMS5KkIalx+uDwEPg18GPg wUZguq7aydQKUkqB4vH0pwJrAVcCx8cY/1LpYK1lU1rs1NK8cub3IfAFil1u9wHfq3gkSZIq421x kqQhLWeuB9ajeBT6r0LgnMZOFWmBUkofBm4Hfg48AWwYY9zHsNR7KaVhFLenTq16lv7ImYspTj+e EwIfrXgcSZIq48klSdKQlzNPh8COwDjgLGCLEPhUzqSKR9MACyEMB/YDtgBeBq4AfpNzziml9YDT gB0oYuQ2McabKxu2tY0ClqSFTy7N4yhgXeCqEBiTM3+reB5JkgacJ5ckSeKfy77PA8ZQ/PPxnhAY 57LvoSOEsHwH3B3gwk1hj/cXu5RuHrn88j948MEHLwPuB9YA9gY2Miz1y1hgDsXtZC0tZ7qAvYCX gGtC4G0VjyRJ0oAzLkmSNI+ceYgiMF0EnAdcGwIrVTuVBsj4pWDNByDcDu3ToeO7wMxZsw685557 tgcOA9aOMU6MMfZUPGtLCiEMCyFs/5Of/GTvJ5544oEY4+yqZ2qGnJlJsYPrP4CLjdKSpKEm5OyD LSRJWpDGrXIXAxn4bGM/kwapzhCe/RKs8J15XusBVguh5+nOzv+aPXv2oVXNNhiEELZub2+/oru7 ewWAtra23NPT8x3gq3mQ/EDaeILc1cDXc+bUqueRJGmgeHJJkqSFyJlfUexSuRe4zmXfg1uGJZeb 77U2YJmce+bMmdNZxUyDRQhhlba2tl+OGTNm+auvvprbbruNcePGBYp9RYdVPV+z5Mxk4FvAySHw 8arnkSRpoBiXJElahJx5GtgROBw4BLgrBGK1U2lx6IFf/wi6Xpzntd8Bf4AOOPQ1b3Xql892dnZ2 TpgwoW2NNdZg5MiRfP7zn2fbbbfNHR0dX656uCY7EZgC/DQE1qp6GEmSBoJPi5Mk6S3kTAbODYFb KZ4edncIHA1c0PicBoEM459qb99pPej4ZHc3zwKXQU87a83q5pxxwAdC4As+DWzBUkrDgFWAVRu/ 3vPGf95+++03eeyxx9qXWWaZN33P6NGjw0033bTqgA+7GOVMTwh8huJJeFNCYKOc+UfVc0mStDgZ lyRJ6qWceSgExgBnUiz73jYEPpczz1Q8mprgoYcemjF9+vRXzjzjjBnfufPOpYGX58Kl8MezoPOj wIXAtBA4Hjg3Z7orHXgApZQCMJL5otF8v94FbzrdNRN4DHhsxIgR6U9/+tNmzz33XFhhhRX++QW3 3357T1tb258G5ncxcHLmpRDYBbgbuCIEPj6U/rxIkoYeF3pLklTCPMu+e4D9c+aGikdSP6WUzgEO BNaMMc6Y//MhsAxwCjAOuAc4KGceHNgpF4+U0pL8KxotLB4tNc+3zKERjhby64kY4ytvfPF+++23 +pQpU6a/+93vbh83bhwjR45k8uTJTJw4EeDTOeefLu7fYxVCYBvg18C3c+aYqueRJGlxMS5JklRS CLyTIjBtB5wNHJczr1c7lcpIKa0L3AccF2M8a1FfGwKbAD8A1qQ4xXZSnf97Tym1ASux6HC00nzf 9jT/Howen+c/Pxtj7Onl+y8L3Dht2rQPHnnkkfnJJ59cFqC9vf2l7u7uE3LO5/Tzt1hrIXAEMAH4 dM4MyogmSZJxSZKkfgiBNuBLwBnAw8CncmZatVOpLxq3fN0KvBNYL8Y4562+JwSGAccAxwN/Aw7O md/+6/NhGLAM8HzOuVcRpqyU0ttYdDh6DzBsnm95lYVHozdOHTUlljXC0g0UIW6rnPPku+66686D DjrobOCBnPOrzXifOmssgv8xsBewWc7cW+1EkiQ1n3FJkqQmCIFRwE+B91E8Xv17LvtuDSmlfSgW tW8bY7yxL9/beBrYRcCHio+XfgP2P7YdDu6GpTrg713FrXQX5BI/dKWU2il2GS0sHK0KLD/Pt2Rg BguORm/8mhVjXOx/NlNKIyjC0geBrRsv3wNsE2O8eXG/f52EwJIUDx98F7Bh4ymUkiQNGsYlSZKa JASWAr4NHAZcCxyYM89WO5UWJaW0NMWJs7tijLuVuUbj9NohwBltbNfZyQ1LHA1hFMUfgkuKLzs6 5/ztBbz/siw6HK3Cmx/A8hKL3nU0ozcnrxa3Rlj6NbA2sHWM8Z6U0qnAwcC7YoxzKx2wAiGwCkVc ewTYMmcq/+9JkqRm8WlxkiQ1Sc68BnwxBK6n2MX0UAgu+665r1M8Be0rZS+QMz3AhSHs9kgPN9xw MfDJxuf2AIYDF3d0fGvq1KlLjRgxYmXeHI9GzHOpbuBJ/hWKbme+eBRjfKHsnAMlpbQMcD1FWNqm EZYCxV+OKUMxLAHkzJMhsBtwG3B+CBzi6UZJ0mBhXJIkqcly5toQWJdiz8qvQ+Bs4NicmV3tZJpX SmkN4EjglBjj3/p/xZ+vFoA953t1H+DCrq7hTz/99JEjRoz4G0Uo+i3/vvfoqRhjV//nqM48YSlS hKW7G5+KwAeAL1c1Wx3kzB0h8AXgRxQL5C+seCRJkprCuCRJ0mKQM38PgR3417LvLULgUznzh4pH E/9c4n0OxUmhM5t02ecy8FdgjXlenF58yLvtttsHc85/b9J71U7jFsPrgPUowtJd83x6d+AF4JYq ZquTnLlawIa6AAAgAElEQVQ4BEYD54bAtJz5XdUzSZLUX21VDyBJ0mCVMz05czawEdAJ3BsChzae HqVq7QRsBxwRY3ytSde8rgNmHRQCTzReuAc4Hrra4ddDJCyNAj4WY7xzvi/ZHfhljNHTe4WjgP8G JoXAe6seRpKk/jIuSZK0mOXMA8AYilthvgdcEwIrVjvV0JVSWhI4G7gRmNKs6+acXz/59NNveXD4 cN4LrABdY4Dn4JFuOKhZ71M3KaW3Ab8C1qd44t7v5/v8mhS3xV1dwXi1lDNzgb2AVyj+92B4xSNJ ktQvxiVJkgZAzryaM18EdgE2BR4MgY9VPNZQdTTwbuBLMcamLVROKe2644477jlx8uSv9sBBM+Fk 4BNdEHPOM5r1PnXSCEvXAhtQhKU7FvBlu1NEFBfbzyNnnqP434M1gB95olGS1MrcuSRJ0gDKmV+E wHoUT6i/IQS+Cxznsu+BkVJ6L3AccHaM8U9Nvu7FwDUrr7zyt3POg/4pYCml4cAvKU7lbRtjnLqQ L90d+FUTbz8cNHLmwRD4DDAJuB84veKRJEkqxZNLkiQNsJx5imLfz5HAF4E7Q2DtaqcaMr4D/AM4 qVkXTCl1Aj+jWFh9YDNPQ9XVPGFpI2C7GOPt839NCCHce++976M41eQtcQuRM1dT/Hk8NQR2rHoe SZLKMC5JklSBxrLvCcDGwBK47HuxSyltTXGK5qgY40tNvPQpwIbAPjHG55t43VpqhKVfUPzZ3T7G +D/zfj6EsFwI4by2trYXx4wZ88j+++/fs+22275YybCt45sUse6nIfDBimeRJKnPjEuSJFUoZ+4H /j+KW6reWPa9QrVTDT6N00XnUjyh64omXncHih1Ox82/yHowCCGs1dbWdlV7e/urHR0dL3R2dv7g ySefvB4YC+wQY/zv+b6+s729/ealllrq0AMOOGDpY489ljlz5oSnnnrq2hDCRyv5TbSAnOkB9gOe AKaEwHIVjyRJUp+EIbASQJKklhACO1M8UW4u8JmcuanikQaNlNJXgLOADWKMDzTpmu+m2JNzJ7BT jLGnGdetixDCf7S3t9+70korDd9jjz06Xn/9da666qo8YsQIzjzzzI/vvffe1y3ge/YArrrssssY PXo0AF1dXey7777dDz/88B1dXV2bD/Tvo5WEwH8AdwN3ADvlTHfFI0mS1Csu9JYkqSYay77XpVj2 fWMIfAf4usu++yel9C6K244ubGJY6gB+CrwO7D/YwlLDMcstt9zwSZMmdYwYMQKAXXfdNey88875 a1/72ofXWWedF4EV5v211VZb7TB9+vQ8evTof97e2dHRwU477dQ+bdq0TUMIYSgsOy8rZ/4SAnsD 11PcbnlsxSNJktQrxiVJkmokZ54Kge2AL1M8OWqrEPhkzjxc8Wit7HRgNvCNJl5zPLApsEWM8bkm Xrc2Ojs7P7b99tv/MywBrLrqqmy88cahs7PzGOCYxssZmAXMXGmllYbfddddzJkzh2HDhv3z+555 5hmGDRs2+9577x3I30JLypkbQ+Bo4Dsh8EDOzbuNU5KkxcWdS5Ik1cx8y76XBP43BA5x2XffpZQ+ BHwG+FqMcVaTrrk18HXgG/PvHBpMcs4vzpw5M8/3Gs8++2zPww8/fDOwFrAi0BljXCHGuOYVV1yx zUsvvcSECROYM2cOAPfddx9XXnkle+6551LA3SmlHVJK/lletO8ClwE/CoENqh5GkqS34s4lSZJq LASGAxOAQ4ApwEE5MyhPyjRbSqkduAfoAjaJMfZ7f01K6Z3AA41f2w3S2+EAaG9vP7qtre3Mc889 l80335yenh4mTpzIKaecAvDxnPOvFvR9IYT/BM4ZMWJEGDFiRPcTTzzR3t7efs/ll1/+zXXWWedY YDOKnULfAG6JMfrD6AKEwFLA74B3ABvmzDMVjyRJ0kIZlyRJagEhsCvwA2AOxbLvmyseqfZSSl8A LqQIS3c24XrtwI3A2sDoGOPT/b1mXaWU2l599dVLjjjiiE9PnTo1rL766rzyyitdzzzzTEcI4Xs5 53GL2p104oknHjRjxoyLJk2a9OOZM2deC0zJOXc1TixtA5wEbAT8FjhhMJ8A648QeDdFIP0zsHXO zKl4JEmSFsi4JElSiwiBlYFLga3AZd+LklIaSfEv5FNijAc26ZonAN8Cto4x/qYZ16yjRgC6EDh4 9uzZ+15yySXbzJgx49OTJ0++MOd8FXD7Wy3lTimNB/4TWHFBJ5Ma77EjRWQaDdxEEZn6HQEHmxDY FLgN+GHOHFrxOJIkLZBxSZKkFhICbcBXgFOBBHzKZd//LqV0IfApYI1mnDBKKX0E+A1wcoxxfH+v V1eN6PNd4HDggBjjj1NKlwOrxRg/1Ifr/AoIMcYd3uLr2oBPUES7dYBfUeyy+t+yv4fBKAQ+R3Fy 8dCc+X7V80iSND8XekuS1EIay76/DWwCDMdl3/8mpbQBxY6qbzQpLK0IXEGx/+bE/l6vrhph6VSK sHRYjPHHjU+Notgx1ZfrbATc9VZfG2PsiTFe3XiPTwEfAO5NKU1OKa3bt9/B4JUzPwTOB84Lgc2r nkeSpPkZlyRJakE587/ABhS3yX0fmBwCI6udqnqNkzDnA38Avtek610KdACfbsZS8Bo7HjgWODLG eCFASmlJ4IPAg324zmrACvQiLr0hxtgdY7yC4vTSZylulXsgpXRFSmnNPrz3YPYV4H+Aq0Ng1aqH kSRpXsYlSZJaVM68mjNfoLit6MPAgyGwVcVjVW1fYCzwnzHGuU243tHAdsB+McYZTbheLaWUjqI4 lXV8jHHCPJ9aG2inDyeXKE4tAdzd1zlijF0xxkuANSlOn30I+ENK6ZKU0vv7er3BJGfmAnsCrwLX NJ4kKUlSLRiXJElqcTlzDbAu8EfgphA4MwSGVTzWgEspjQDOBCbGGG9twvU2BU4BTo8x3tDf69VV SmkccBZwSozxlPk+PQrIwEN9uOTGwKMxxmfLzhRjnBtjvIjiNrnDKZ4w93BK6aKU0pA9tZMzzwG7 UMS3H3o7rCSpLoxLkiQNAjkzA/gYcAzwZeCOEPhgtVMNuPHAMsBR/b1Q42lzPwN+D5zQ3+vVVUrp IOA8YAIL/n2OAh6JMb7ch8v2at9Sb8QYZ8cYzwfeT/Fnexdgekrp/JTSys14j1aTMw9Q3Dq4D/DV aqeRJKlgXJIkaZBoLPs+i2LZ99IUy74PHgqnG1JKawNfonia2+P9vFYALgbeBnwyxtjVhBFrJ6W0 L/BfFLupjooxLugRwuvRt2XenRS7wJoSl94QY3ytcbve+ygi4qeAR1JKE1JKKzXzvVpBzlwFnAyc FgKLfCKfJEkDwbgkSdIgM8+y758A/49iAfCgXfbdiEHnAn+jOIHTX18GdgI+299QVVcppT2AS4Af U+yn+rew1Pjr2qcnxVEs5F6KJselN8QYX44xnk6xNPw04HPAoyml0xunzYaS8cC1wBUh4NJzSVKl jEuSJA1COfNKzhwM7AZ8hMG97Ht3YCvg8Bjj7P5cKKW0EXAGMCHG+MtmDFc3KaWdgCuAK4HPxxh7 FvKlqwDL0/dl3t3Aff0a8i3EGF+MMZ4IrA6cDYyjiEwnppSWW5zvXRc500OxwP5JYEoILFvxSJKk Icy4JEnSIJYzP6e4telhBuGy75TScIrTStfGGK/r57WWowgu9wHHNWG82kkpbQNMAn4J7B9j7F7E l49qfOxrXEoxxldKjtgnMcZZMcavU0Sm/0exb+vRlNLXU0rLDMQMVcqZFyn2UL0DuDwE2iseSZI0 RBmXJEka5HLmSYqnbb2x7HvqILqN5jiKf7H+cn8u0rgF7AfA24F9YoxzmjBbraSUPgJMAW6m+D3O fYtvGQX8A3isD2/TtGXefRFjfDbGeDTF4u9LgW9QRKajGwFy0MqZ6RTLvbcHTqp4HEnSEGVckqQh IhQ+EkI4O4RwbghhmxDCoF/0rMI8y77HUjxR7X9D4KBWXvadUno/cDRwVozxkX5e7lCK2+sOjDE+ 2u/haialNJZiP89UYPdexrNRwIMLWfS9oPdYmmLn0p2lB+2nGONTMcbDgf+gOKF1KvDXlNLhKaUl q5prccuZGyji8XEhsHfV80iShh7jkiQNASGEtgA/Am5bBb74nuJfpG9sg4khhI6q59PAyZl7KZZ9 Xw5cBEwKgeWrnaq07wLPUCx2Li2ltH7jWufHGCc3Y7A6SSltAFxPcbvfLjHG13v5raOAB/vwVhtQ /Gw54CeX5hdjfDzG+AVgDeA64DvAX1JKX0gpDZrbQufzHYq/ry8OgfWrHkaSNLQYlyRpaNgzw2d/ CDwOHf8HHVcCGfYADqh4Ng2weZZ97w5sQbHse4uKx+qTlNIOFE90O7I/+30ae3kmAtMoTkENKiml dYGbKHZufby3f60at5J9gL7vW3oF+ENf51xcYoyPxhgPBNYCbgO+B/wppXRgSmlQhfWcycDnKf76 XxMCK1U8kiRpCDEuSdIQ0Ab7bQrdBwKh8WsvYFvo6YDPVDudqpIzkymWff8ZuCUETm+FZd8ppSWA c4DfUNz6VPY6gWIJ9DuAvfpwoqclpJQ+SLFf6TFg+xjji3349nUofk7sa1y69y2WhFcixjg9xrgv EIG7gR8Cf0wp7ZtSGjRLsHPmNWBXYAmKU4m1//tZkjQ4GJckaQhog+VW4d+fIrQytLXBkHhstxYs Z56gWPZ9HHAkxbLvNaqd6i0dQfF0sC/1dh/QQnwO+CRwcIzxL02ZrCYa+6huAZ4DPhZjfL6PlxgF 9ACpD99TyTLvvogx/iHGuBewPsUJn8uAh1JKe6WUBsXPxY2/p3cHNgHOrngcSdIQMSj+ISpJWrQu uOVa6Jkxz2vPAVdD95ziZIOGsJzpzpkzKJZ9jwDuq+uy75TSu4ETgHNjjNP6cZ11gfOAi2KMP2vW fHWQUlqVIiy9AmwVY3y2xGVGAX+OMb7Wy/d8B/Beah6X3hBjvD/GuAtFEPs/4ErgvpTSro0TbS0t Z24HvggcGgKHVD2PJGnwMy5J0tBwwVx4ZgPoOhE4BRhNOy/Di8CEimdTTeTMPRRLma+gWPZ9VQ2X fZ8FvAR8q+wFUkpvo9iz9Bfg8CbNVQsppZUpwlKmCEt/L3mpUfT9ljhokbj0hhjj3THG7YEPUTT3 nwN3p5S2b/XIlDMXARcA54fA5lXPI0ka3IxLkjQE5Jyf6YJNnoGfnQivfoMw50l2p5trzsg5P171 fKqPnHk5Zw6iWPa+JTVa9p1S+iiwD3BMjPGFflzqAmBVij1LvTqZ0wpSSitRnERcEtgyxljq7+1G VFmPvselZyj2O7WcGOPUGONWFH/mX6d4wtztKaWtWjwyHQHcTrF/6T1VDyNJGryMS5I0ROSc/68n 5/26cn5bd+5ZAq78OezyuRD+fReTlDNXU5xemU6x7Pu0KpcDN57sdR5wB8WenLLX2R/YHzg0xvjH Jo1XuZTS8hRPhXs7xYmlR/txufcCy9L3uHRXP3dgVS7GeCuwObAd0EER625NKbXkyZ+cmQvsCbxG 8QS54RWPJEkapIxLkjR0nUrxqPE9qh5E9ZQzjwNbUyz7Pgq4PQQ+UNE4h1E8wWxcjLGnzAUaT0/7 HnBJjPHSZg5XpZTSssANwMrA1jHGP/fzkqMaH3sVlxone2q/zLu3Yow5xngDsDGwM0Vo+11K6caU 0sbVTtd3OfMsxRPk1gIuquMuNUlS6zMuSdIQ1divcyPwNf9lQwszz7LvTSn+Jfu+EDhwIP/MNG73 OhH4rxj/f/buPM7quf3j+OtzzrQRSYuEUEJcLUoj/KyhLCUkkj2RNdzdt/vOEiGyhex77mQrJaQs SZESSl3cbttdtoqkTdvMOZ/fH5/v1JSWWc4yy/V8PM5jcuZ7vt9rZs6MOe+5PtdHPivhOWoQ5iz9 QBh0XCGoak3CEq49CLvClXjIeSEtgd+BX7Z0YGQPwq6TFSJcKhCFTK8BbQghfENgqqq+rqqts1td 8XjPTOBc4AxCUGyMMcaklIVLxhhTud1KmK1yfLYLMWWb90wnDPt+EXgSeMk5amfo8rcBSeDaUpzj XkKnXjcR+TMlVWVZFJiNAZoDHUVkRopO3RL4vBhL3AqGeU9P0fXLFBFJikjBMtEzCM+jT1V1pKpK dqsrOu95idCxOsg5Oma7HmOMMRWLhUvGGFO5TSYMe73WupfMlkTDvnsSZrgcRRj2fXg6rxktQzof uFZEfi/hOU4HLgQuF5HZqawvW1S1GvAKYenW8SIyLYWnbwHMKsbxucC3IrIohTWUOSKSEJHnCcsz zwP2A2ap6vOquld2qyuy64E3gBecY89sF2OMMabisHDJGGMqMe/xhO6ldlA2dgQzZZ/3jCAEEN8B E6Jh31VSfR1VjQEPADOBx0p4jqbA48DzhI6rck9VqxA6yI4AOovI5BSeuybQhOIP805luFWmiUi+ iDwD7AX0Bg4GvlTVoaraJKvFbYH3JIEzgXnAq85RK8slGWOMqSAsXDLGGDMO+IzSLTkylUw07Ls9 4XnTF5iShmHf5wP7E4Z4J4r7YFWtTghh5gO9y/tOZgCqGifslncccLKIvJviSzQHHEUf5l2V0MFT oeYtFYWI5InIY4Rlcn2Ao4GvVPVxVW204fHOuVrOuV2dczmZrrUw71kCnAjsCDxnO4YaY4xJBQuX jDGmkou6lwYCRzpHu2zXY8qPaNj3bYRh39uRwmHfqlqbMGtpmIh8WMLT3ElYwtRNRJaWtqZsizq5 niIMlz5NRMam4TItgXzgyyIe3xyoRiUMlwqIyGoReYDQ8XUNIbj5RlUfUNWGzrl6cededLAImJMD vzjnLnHOZW0psvd8DZwOHEsYlm+MMcaUioVLxhhjAEYBXwH9sl2IKX+iYd/7EXZjexJ4MQXDvgcA 1YF/lOTBqnoKcBlwdQoHXWeNqjrgIeAs4CwRGZWmS7UEvhKR1UU8PpcQRs1MUz3lhoisFJF7gMZA f+CMRCLx3U477PDFdnDKvRAbC/SAesCDQK9s1us944B/EnYMPS2btRhjjCn/LFwyxhhTMIfjNqCT c7TIdj2m/ImGfZ8PdCMsD/rcOQ4ryblUtQVwCXCTiMwrweN3J4RcIwmBTLkWBUuDgYuAntFQ6XRp SfHnLX0uIqvSVE+5IyLLReR2YPdnn3125M8LFtR7FeJXENqEniFsOZcDNzjnsv27+F3AcOBp52iV 5VqMMcaUY877cj9+wBhjTApEA5m/BqZ6T/ds12PKL+fYhTAX6FBCaHmj9+QV5bFRkPI+obujpYis Kc61oxlAk6PHtxaRxcV5fFkTfT4GEjpMLhWRtIVl0bK7pYRQ784iPuZLYKKIXJKuusoz59z1teGG RbDenKWRhLWN48ePH9WwYcO5wALCbLCCt/OB30QkP/01UgP4AKgL7A9uf8Kw8nHe+6/SfX1jjDEV Q1YHChpjjCk7vCfPOQYBDzrHDd7zTbZrMuWT9/zoHO0J82duAo5yjh7e820RHt4dOAQ4prjBUuQ2 whK9g8t7sBS5jhAs/S2dwVKkMbA1RR/mXQvYG7gjnUWVc/OXQHweYXp2gS+Aajk5ye2337424XPY AP6ylNSr6kLWD5w2FkItABaKSLIkBXrPSufoApNmxmPHz0skw4Bv59xg59znwAHe+6IukzTGGFNJ WeeSMcaYtZyjOvA98Kb39Mx2Pab8c45cwrKbHYDLgaHREPm/UNVtCLO/porIKcW9lqp2AsYQ5iwN LnnVZYOq9iUMJb9ORG7NwPVOJjTVNBCRBUU4/kjgXWBfESnqAPBKxTm3XRx+OhxqPAWxnYHXge6Q WAGPe+8vLjhWVasB9QnfKw2i2w4bvC3497YbXCoB/MaWQ6j5wB8b7pzonKsSj+esqFe3Ts4/rrmG Jk2aMGHCBIYMGUIymZzivT84lZ8XY4wxFY91LhljjFnLe1Y5x93A7c5xk/f8kO2aTPnmPR87x37A /cDTwHHOcZH3/LGRw68Dtgf+VtzrqOouhHE2Y4B7S15x2aCqlxGCpVszESxFWgILihIsRXKBZcB/ 01dS+ea9X+yc6zwRRu8K21SD5GqIxWk2D/6z3rD6aIj6j9Fts1S1BpsPofYkdAA2ALba4OF5qrqA QsFThw4d9hw/fnzOPYMH07x5cwAaN27M0qVLGTp06EHOuVre+yUl/kQYY4yp8CxcMsYYs6FHCbvG 9QWuyHItpgLwnmXAec7xJvAYYdj3meDyYrHYP2OxWLtq1ar9ceWVV+7RtWvXm1u1ajWnOOdX1SrA C8CfwHkbdmWUN6p6ATAEuAe4PoOXbgnMKsbxucAnIpJIUz0Vgvd+gnOuIdBlNdSHJ/ZMcN75ENue EM4Vm4isBOZEt81S1ZpsOoTaAWi5fPny5tWqVVsbLBVo164dTz/9NEBzwlwmY4wxZqOyvUOFMcaY MsZ7lhM6P3o5xw7ZrsdUHN7zEtACmAPjJjoX/3C33XY7/rzzzqt/4IEH7jVw4MB4bm7uriU49QDg AOB0EVmUypozTVXPJARwDwN9MxyUFWmnOOdcLefcSePGjTv0t99+m5mBuso97/1y7/0w7/090LMv xP4AbszEtaPd674VkQ9EZCTwPDAdWEIIl1rttdde1VavXs1//7t+E9qMGTOIxWIA/8lErcYYY8ov m7lkjDHmL5yjNjAXeMh7/pntekzF4tzEeDx+xrz99tul3uOPP0pOTmikfvHFF7nlllsAmnvvtSjn UtUOwDjgnyIyKG1FZ4CqdgVeBIYCF5R0QHMJr10LWAycJSLDNnWcc653LBa7J5lM1gCoUqXKmry8 vEu9909kqtaKwDkuJ4T44n16gxtV3YmwRK7gVtCe9DMwCZj87bffft6tW7cPGjZs6Pr370/jxo15 9913uf3228nLy5vpvd8vnTUaY4wp/yxcMsYYs1HOcTtwCbDrJubjGFMizrkGwLy77rqLDh06rL0/ Ly+Pdu3aJdesWfP30OGxearaEJgJfAocn8kwJtVU9QRgFPAyIeDJyFIz51wM6NC0adMzjjvuuDOr VavWYdCgQW9t4tgjgAldu3alV69eeO959NFHGTVqFMAh3ntbNlVEzlGNMKtquvecmqrzqqoDmgCH EoKkQwm7AAJ8DUyObpOAOSLio2DxjYkTJ7a++qqrquTl568dmxFzbk7S+1Y2b8kYY8yWWLhkjDFm o6IlcXOAgd5zc5bLMRWEqm7zzTffnHnyySc/NGDAAE466aS171u2bBmHHHKITyQSl3vvH9zCeeKE ncqaAq1E5Lf0Vp4+qno0YROxN4DTRCQvE9d1zm0Tj8fHJRKJg+rVq5dYvnx5fNWqVUnv/YXe+yc3 PD4Wi41s3Lhx51GjRuU45wBIJpN07tw5sXDhwtemTp16LvCniORnov7yzjnOJQy53997Pi3JOVQ1 RuhEKuhKOpQwS8kTljgWBEkfiMj8jTy+HjAe2A04tnnz5h8fcsgh9+6xxx5XqGq3jz/++OWS1GWM MabysYHexhhjNsp7FjjHE8CVzjE4msVkTLGpalWgA9AD6Ny0adMaLVq0WPzkk09ue8ghh8Tq1q1L IpEo2PY8Sejg2ZLrCS+mjyznwdJhwKvAO4SZURkJliIDqlSpcsAjjzzCAQccEF+5ciV33HFHbOTI kY81aNDgg3feeccTdh3bE9hz9913P6ZVq1ZrgyWAWCxGy5Yt43Pnzu1CWFaHquYDK4HlwFLCoPWS 3JZveJ+IrEnz5ySThsGv/4JBw2OxwXOi7qBhwGt+E3/9jb6X2rAuSDoY2A7II8xRGkoIk6aIyOLN XVxVdwbeBmoDh4vILO89qjqGsJlDiQIvY4wxlZOFS8YYYzbnTqA3cBFwd5ZrMeVI1FFxMCFQOhXY HlDC8O3nZ82aVSMej3/QoUOH2q1bt3bffTeX336b56DKVd6v+WUL5z4SuAHoLyLvp/lDSRtVPZDQ sTQFOCWTwYlzzsXj8fO6d+8eb9euHQBbbbUV11xzDePHj4+dcsopX7Ju45cVwDc77LDD79OmTdsq Pz8/VjAnKy8vj+nTp/u99977F+APYEfC13qb6NaAsCPan8BqQgiSABzh99AawNbRbYu/l0bBVUnD qo0GVoVuqzM7QN3tEI9vUycWW1PnwAMP3fPXXxckvvrqq1Odcw875y713ntV3Rpox7plbu0In7M/ gY8IOwpOBqZFO8gViao2IXT+OeAQEfmm0LsLnodVS/0hGmOMqTQsXDLGGLNJ3vODczwL9HWOB71n VbZrMmWbqgohUDoDaAT8CDwOPCciswuO897jnGuWSCR6TZ06dX9olA/TT4X9V2/h/DsAzwHvAQPT 9oGkmaq2Bt4EZgAnikimv7dcIpHYtmHDhuvdWaNGDbbffvvkRx99NPHiiy++BfgG+EVEkh999NH+ zrlpffr08T179nTeex5//HE/f/78xLx5844Xkc+jj60q4WvfGNg9eltwawLUKnTJJcD30W0O8Asw H/gtel811oVPG95qbuS+ups4tihBSVJVUx1YFdxWbiS4umXbbXNqvfDCCKKvQ/yFF17g1ltvvfi2 226rFQVAbQi/ry8CPiB07E0GZpS0yy36Hn2LEPodJSI/bnBIwXmrlOT8xhhjKiebuWSMMWaznKMp 8BVwqfc8ku16TNmjqo2A7oRQqTmhg+UlYDhh1kuRBm07x3PAEcAe3rNiI9eJEXaGawm03NgMmfJA VZsDE4FvgaNFZGk26sjJyZnWvHnz/Z955plYPB4vqI3u3bsDnOa9f2nDxzjnusTj8YcTiUSD6By/ 5OfnX+S9f72o11XV2qwfOBW+7QrEo0OThHCyIHz6X6F/fw8sLGqnkarmsOmQakuB1ZZu1YtQgid0 gK0NnHJzc/c599xzY5dccsnag5LJJMcccwyHH3748uuuu+411s1M+k8qBtaralvC99CPQAcRWbCR Y/L7pfUAACAASURBVNoAnwBtROSz0l7TGGNM5WDhkjHGmC1yjheAA4A9vSeTM2FMGaWq2wNdCYHS ocAqYAyhq2hcSZZ4OUdjQpDZ33tu28g1+wG3AMeIyDulKD9rVHUvQljwC2FeVNZ2YnTOHQOMa9Om DSeeeKKbP38+w4YNS/7555+aSCTaeu83+jV0zuUA+xECkxne+5TtbBeFQLvw146ngludQocvZ/2w qfBtbqa6waLh8ltRzMCqdevWl15yySWxCy64YO25vPd07Ngx/5dffnnEe395ius8HHgNmE3YXXGj zz1VbUEYBt5ORKalsgZjjDEVl4VLxhhjtsg5Cl5snOM9z2a7HpMdqloD6EQIlI4ldJi8Q+hQGpWK DhznuB84G2jiPb8XuvYhhG6f20TkutJeJxtUtTEhWFpCGKCc9UHkzrmOjRo1GvbDDz/UqVq1avKo o45aPm3atMYLFy78fcuPzjxVrcWmg6fdWLeUyxMCvE2FTwsyO1/pr2Kx2Mgdd9yx88svv5yz7bbb AvDuu+9y5ZVXAnT03o9P1bVU9XhgBGFp3UkisskNGlS1GfAlYRbTB6mqwRhjTMVm4ZIxxpgicY4x hG3f9/WeUi/PMOVD1ElyJGGG0smEIc3TCR1KL6Z6aZpz1Ae+g0VPQp3RwJpRo0Z9t8cee3xKCAWO LI9b3UdLBycRhiUfWpaW9Knq7GXLlk2NxWLDtt5664mEOTzvZruu4oo6iBqy6SV39QsdvpKNh07/ A/4nIn9Zlplqzrm94/H4tG233XarDh065Pz660ImTpzggTeSyeSJ3vuU/JxV1dMIu9C9QdiRcLMd Xaq6B2HW1pEi8l4qajDGGFPxWbhkjDGmSJyjHWF3oq7eMzLb9Zj0UVUH7E/oUDod2IHwYvM5YPgG O0ulnHNXvBaLPXtCMrkEgDp16qweMGDA6kMPPXRfEfkpnddOB1VtCLxPGMx86EYGKGeNqm5D6KS6 AHiasGTqPyJyalYLSwNVrcmmu552JwwPLzCfTXc9zUvF/CMA51wT4J/xeI3O3jeun0zWuAM+uc57 n5Llx6p6AfAY4Xv3/KIMAVfVXQnD1TuIyFupqMMYY0zFZ+GSMcaYInOOd4HaQBvvsf+BVDCq2pR1 O701BRYALxBemH6SiWVEzrljgbFdunThzDPPZOXKlTz00EN8/PHH+YlEYh/vfVqDrVRT1fqE5Xzb EIKl/2W3ovWp6mGE+pqLiKrqZcBgoJGIzMtqcRkUDYtvwKa7nnYsdPhq1h8uvt6/RWRZUa7pnHPA 1fF4/MZEIlETIB7f5rtEYtkp3vvPU/AxXQ3cDTwMXFbUQCwKQ38GThCRN0pbhzHGmMohJ9sFGGOM KVduBd4FOhK2UTflnKo2AE4jhEptCduTvwJcCryX6SVo8Xj86mbNmiUGDBgQD6+94f7776d9+/Ys Xbq0N/C3TNZTGtHQ87cJgexhZS1YiuQSdi/7T/Tf/wYGAT0Jw9MrhSh4+SW6/WXOkKpuRZjptGHo dARwPmGgd8Gxv7HprqefRaRgAPpZwF3dunXjpJNO4rfffuPee+/b7fvvV0xwzu3hvS/RsPeo8/BG 4AbgdqBfMYPhgkHuVUtyfWOMMZWThUvGGGOK4z1gKtAPC5fKLVXdFjiJECi1BxLAWELI9JqIrMxW bbFYrNkBBxywNlgCqF69Ovvtt1/O++9/0dY5YuVh5lc0eHo8sBMhWPo6yyVtSi6hKy0BICJLVPV5 4EJVva1QEFKpRTOYvoxu64nCnPpsvOPpEMJzoOAJnaeqc4HvGzRokNusWTPfr18/B9CsWTP23nvv +DHHHFObEDzdX9w6ow6se4A+wL9E5PbingPW7ghaZbNHGWOMMYVYuGSMMabIvMc7x63Aa85xqPdM ynZNpmhUtSqh46wH0BmoThgwfTEwQkQWZbG8tWKx2P9mzJjR0HvvCgKmNWvW8PnnXwA9DgEWOMdb hODmLe8pM4OxC0SzfcYCexCGIn+R5ZI2Jxd4cYP7HiF0Lh0LvJ7xisqZqCtoQXT7aMP3q2p1YFc2 CJ5+++237c4///z1jq1fvz677757/rffftusuHVEA80fI3RSXSoiDxX3HBELl4wxxhSbhUvGGGOK 6w1gFnAtWLhUlkVdDP9HCJROJSzPmkVYMvO8iPyQver+SlUPvPXWW5v27dvXDRw4kLPOOouVK1cy ZMgQv2TJ7wlodB7QDOhAmAuFc8wkBE3jgCner13SkxWqWgMYAzQHjhaRGdmsZ3OiJZGNgI8L3y8i n6jqJ4Tg0cKlUop2Z/tvdFvLOfe/WbNm7dq9e/e1bXpLlixh7twfc8DNKc41ovB4GGFHx7NEZFgp SrZwyRhjTLHZQG9jjDHF5hynEQY953rP9GzXY9anqi0I4Ut3QnjwAzAceE5ENJu1bYyq5gDXRbfp J5xwwts//vhj32QyWQMgHo//nkgkzvfejyl4jHPUB44mBE0dCMuSlhOWbo4DxnvPdxn+OKoBo4FD gY4iMjmT1y8uVe1ECMJ23TBoVNWewONAYxGZk4XyKjzn3BXAfX369OGkk05i4cKFDBp0h//00y9d Mvn5m9D4bO9ZuKXzRPOgRhCWuJ4mIqNLU1e0zC8JXCgij5fmXMYYYyoPC5eMMcYUm3PECbNHvvCe k7NdjwFVbUQIlHoAAiwCXiKESh+mauv0VFPVxoSOiwOAAcCtIpLvnNuW0HW1Bpjkvd9kR5JzxICW hGV/HYCDCd3Z3xK6msYD73nP8jR+HFWAl6MajheRd9N1rVRR1ZuBXsCOGw58VtWtCTuGPSgi12aj vorOORcD7nLO9fHexwDi8fivicS/hsDNVxF2pTvXe97a1Dmi+WmvA22AE0XknVTUpqp5QJ9SLK0z xhhTyVi4ZIwxpkSc4zzgKUC8pyzPlKmwVLUO0JUQKB0CrCR0ojwHjBeRrC4R25yoO+Js4AHgN6CH iPxlXk1JOMe2hF28OhDCnt0JS30+IOpqAmZ5T0p+CYpm3TxHWJLURUTGpuK86aaq44HVItJ5E++/ nzDkfZey/Fwq7+66665OzrkxY8eOvXDChAnPeO/znKMh8AyhO+9e4F/g2gAXxePxRolEYsZRRx01 fPDgwQ8TZnsdJyJTUlWTqq4gDAS/L1XnNMYYU7FZuGSMMaZEnKMqoTNkkvecme16KotoCUwnQqDU EYgTtrt/DhgtIsuyWF6RqOr2hKHRpwJDgStEZGk6ruUcjvDiu6Cr6QjCtvHzYO1g8LeLsvxoY6K5 Vk8TzbUSkVGpqDvdonBvEXC3iNyyiWP2BZSw1OqlTNZXmahqZ+BVoIGILCi4P+rIuwK4HW7/Hf7V cJdddsnfZ599cqZOnZpYvXp17KGHHlrStm3bI0RkZoprWgLcIiJ3pvK8xhhjKi4b6G2MMaZEvGeN c9wB3Occ/TM936YyiWYStScEGCcBNQlDmPsCLxZ+QVrWqeoRwL+BrclAaBF1J30T3YY4RzXCcruC rqZzAO8cn7Cuq2ma9+RveC7nXHXC1+AYYJVz7qWZM2d2isViZxE6r8pFsBTZA9iODYZ5FyYiX6jq ZKA3YYmlSY960dvfC9/pPUngXude+sy5G97v1u00+vXrlxOLxVixYkW8V69eXHbZZb+tWLHi8zT8 sXgNNtDbGGNMMcSyXYAxxphy7UlgIfCPbBdS0aiqU9VcVb0P+IkQfBwA3Ak0FZEDROT+8hIsqWpV Vb0DeJcQ9LTIRjeM96z2nne95x/e0wLYGegJfA9cSlg6t9A5RjhHL+doBOCc2zYej09xzj3RsmXL rk2aNDnDe/96//79L0okEj1F5PlMfyyllBu9/WQLxz0MHKGqe6e5nsqsPrBIRP4SaAan7eZ9Hpde eimxWPjVfauttqJnz56sWLGiKdA4DTXlYeGSMcaYYrDOJWOMMSXmPSud4x5ggHMM8J6fs11Teaeq exK6Y84gdJfMJwzlHg58uuHg5fJAVZsRlu0JcA1hKVaZGDAePWefBp6OBtXvz7qupkeAmHP8B05b lpPzasuhQ59h3333jXnvY6+++irXX389o0eP/rUcjhnIBb4RkUVbOO4VQoB8EXBV2quqnOoR5o5t Sg5ATs76v7ZXqbI2+4mnoSYLl4wxxhSLdS4ZY4wprYeBFYQlWqYEVLWBql6pqtOB/xJexH9AGOa7 s4hcLSKflLdgKeq+uhj4lDDnqJ2I3FlWgqUNeU/Ce6Z5zwDvOQioS5gLNSUn5+M2nTqdENt3330B cM5x4okn0qRJk3ygWxbLLqlcNrMkroCIrCYM7j9XVWukvarKaUvh0njnXPKZZ55Ze0deXh5Dh/6b eLzRSlixKg01WbhkjDGmWKxzyRhjTKl4z1LnuB/o6xwDvd/siyQTibYQP5nQpXQkkADeAO4AXheR lVksr9RUtT5h2eQJhACyr4isyG5VxeM9fwAjgBFVqsw/sWbNmnULv985R82aNWNA9awUWEKqWhXY DyjqUr7HCEtfTyPsYGZSqx7w66beOXv27O2GDBmy8rHHHtv6448/TjRr1iw+efLk/J9//iXm/cg/ ocYXztEXeCxVOyBi4ZIxxphiss4lY4wxqXA/4IE+2S6kLIvmDp2oqi8BCwjLsaoQBibvICInicjL FSBYOg6YTZgR1VlELilvwRKEneaco6NzjMvP7153zJixLF68eO37v/jiC2bNmhUjDAEvT5oD1ShC 5xKAiHxH+Bh7p7OoSqw+m+hcinbse+/yyy//rlGjRufMnj17wogRI77++eefX/Y+mQtd9iCEhI8A 7zjH7imqycIlY4wxxWKdS8YYY0rNe353jkeAy5zjTu9Zku2ayopoq/pDCB1KXYHawOfADcALIvJj FstLqWjZ1J2EwdhvAueLyPzsVlV8zrEVcBYhLG0GfAonX7VkydAbTjzxxG06d+6cs2zZMl5//XUf i8VmJhKJ4dmtuNhygXygONvXPwKMUtX9RGRGesqqtDa6LE5VBZgA/AIcNXfu3IXAsxt5/IXO8TLw BDDbOa4BHo52myspC5eMMcYUi3UuGWOMSZW7CcuDLs12IWWBqrZQ1UHAHGAiYfv6RwARkVbR7KGK FCy1Iuw81hO4HDi+vAVLzrGTcwwEfgQeAv4DHAq09f74exOJxP6LFi16ZtiwYfMnTZq07PTTT19a v379I7z36Zh5k065wOciUpy6Xwd+Jgz2Nimiqo6NhEuq2hx4j/A5by8iCzd3Hu95mzAw/1ngAWCC czQpRWlrgKqleLwxxphKxjqXjDHGpIT3zHOOp4CrnONe7yl3y6BKS1V3Jezydgbhhd7vwEuEndI+ KquDrEsj6sy6ChgIfAXsLyJfZLeq4nGO/YErCTOFVhI6QIZ4z/8KH+e9/x7oBaCqBwEf9u3btw2h u6Q8yQXeL84DRCRfVR8H/q6q/xCRpekprdKpSViiuDZcUtUWwLuEkPNoEfm9KCfynmXAJVEX05OE LqZ/EZ7Lxf3ZY51LxhhjisU6l4wxxqTSHYRlX72yXUimqGodVe2tqpMJXUrXAwp0AhpG84Y+rKDB 0k7AW8BdwBAgt7wES84Rd45TnGMyMB04CPg7sLP3XL1hsLQRHwHfAOekudSUigbJN6OI85Y28ASh O7FHSouq3OpHb38FUNWWhLDyR+CoogZLhXnPe0ALwtfrXmCSc+xZzNNYuGSMMaZYrHPJGGNMynjP HOd4Dvi7czziPauzXVM6qOpWQGfCi+yOgAPeJszpGS0iy7NYXkao6imEXcRWEbor3slySUXiHLWA 84ErgN2ASYRd+8Z4T6Ko5xERr6rPAv9U1UvL0de8DeH5WuxwSUR+VtXXgItV9RERSdXOZJWSc26/ 3Xbb7W+5ubnMmTOn9e233764Xr1644G5hO+pRSU9t/csB65wjhHAU8DnznEdcG8Rn+cWLhljjCkW 61wyxhiTarcBDYGzs11IKqlqjqp2VNV/E7oMnifMSrka2ElEjhWRYeUoZCgRVa2pqk8CIwizpFqU h2DJOZo4x72EjpBBwAfA/t5zmPeMKk6wVMi/ga2BU1JYarrlAsuA/5bw8Q8Tdps7MGUVVULOuWuB z5YuXXr6Z599xscff3zH5ZdfPm3JkiU/EDqWShwsFeY9kwhdTA8Thu1/4BzNivBQC5eMMcYUi3Uu GWOMSSnv+co5RgLXOMfT3pOf7ZpKKhq2m0voUDqNsITlv4RwYni0RXuloaoHEOZHNSAM7n66LHev OIcjDOS+EjgRWATcDzzkPb+U9vwiMldV3yMsjRta2vNlSC7wiYiUJEwDeAf4HugNTElZVZWIc641 cMtFF11E79694zk5OcycOZOLLroo3qFDhw+XL1/+RyqvF82/uzrqYnoamOEc/YG7N/PzOQ+okco6 jDHGVGzWuWSMMSYdBgJNgG7ZLqQkVHUvVR1AmKkzFegKDAP2B5qJyM2VKViKurauBz4kDClvJSJP ldVgyTmqOsfZwKeE7qo9Cbuc7eI916UiWCpkKHBENMy9PMilZPOWAIhmhz0KdFPVOimrqnI5o3bt 2vm9e/cmJyf8nbdVq1acfPLJrFq16vR0XdR7pgCtCAHrQGCKc+y7icOtc8kYY0yxWLhkjDEm5bxn BvAm0M+58vH/GlXdUVWvUtVPCLue9SHM4zkK2EVE/iYin5bVQCVdVHV3QkBzI+EF6f+JyLfZrGlT nKNeNFdmLiH0WQB0AMR7HveelWm47EjgT8K8rTJNVRsCO1OKcCnyNGFu07mlramyUdUd9t1337Z1 69aNFwRLBerWrYv3vmY6r+89K73nH4QB9jWBz5zjWuf+EiRZuGSMMaZYnPeV6ndkY4wxGeIcBxPm 2pzkPaOzXc/GqGotwjDnM4AjgXzgDWA48IaIpCOMKBeiJYE9gIcI3UpnicgH2a1q45xDCGHgmYAH ngXu857/ZOL6qjqUMINor7IcPqrqicBoQlj6UynP9RzQFti7Iu6EmEqq2gToEt0OHjt2LNdcc40b Pnw4zZs3B2D16tV069YtMWfOnLcSicRxmajLOaoDNwD/AD4HzgM3GzguNzf3vlgsVnvq1Kn9gWe8 9xV6lpwxxpjSs5lLxhhj0sJ7PnSO9wndS696T5l40a2q1YBjCcFJJ6Aq8D5h2dRIEUnpvJPySFW3 IwwAPp2wHPAyEVmS3arWF3XEdQCuAo4GfgEGAI95T7G3by+loYQB9gdStucQ5QLzgJ9TcK5HCKHs EcC7KThfhREFs62AkwiBUnNgNfAW0LNhw4bj4/H467169WrVtWtXV6dOHUaPHp2YM2dOIplM9s9U nd6zivDz+RXgaUh+AofNgvfb/PHHH7527douFovd75y71Dn3f977TH9fGWOMKUcsXDLGGJNOA4Hx hKVlb2erCFWNEQY79yDMT9oOmAlcB7xQ2i6OikRVDyN0/tQCzhCR57Nc0nqcY2vCErQ+wN7AJ4Sv 68vek5elsiYCPxAGe5f1cOnjFHVXfQB8AVyMhUuoag7wf6wLlBoBi4HXCUtK3yrYSVJEWLx48UXT pk37+KWXXlqxatWqHOfce8lk8gbv/fRM1+49nzjH/vDo4/D+Wddffz2nnnqqc87x3XffuR49ejT9 888/rycMxjfGGGM2ypbFGWOMSZtot66PgT+95/BMXjvqHmhBCB66E2bNzCEseXtORL7MZD1lnapW BW4CrgEmA2eLyNzsVrWOc+wMXEroMKsFjAIGA1PKQlecqt4CXAbsWBaXU0YB6yLgDhEZmKJzXgbc CzQSkVQOSS8XVHUrQtfcSYQuyO0JXWGjCc/PSSKy0cBTVZ8idN41FpHVmal485xzjzRsuNMF48a9 GXfOrb3/jjvuYPjwMSsSicW3AKsK3VZv8N+bu391ed451BhjzJZZ55Ixxpi08R7vHLcCo5zjYO/5 MN3XVNXdCMt1egD7EOYFvQg8B3xUlmfiZIuq7kX4/LQE+gF3lmKr+pRyjlxCx8SpwArgCWCI98zJ Zl0b8SxwLdCZ8Hwra5oSQrnSDvMu7N/AIOB84JYUnrfMUtXtgRMI3UkdgRrAl4RlgqOALQ79V9Vd CPPB/lVWgiUA51zVmjW3pnCwBLD11lsDrgbwN6A6UI0SvIZwjgSlCKeKeN9mj/Uemw9mjDFpYuGS McaYdBtDWD7TDzg+HRdQ1bqE8KEHcDAhhBhNGFT71qa6Byq7qLurF6ED6CfgQBH5JLtVgXPkEF68 X0XY1ep7wgvbp71nWTZr2xQR+VpVPyIsjSuL4VJu9DZlX18RWaKqzwMXquptZSWQTDVVbQScSHhO HgbEgamE5W6jReTrYp7yKsIOg4+lsMwSi7rautx4441H9e/fPz59+nTatm0LwJIlSxg1alR+IrH4 Re85s+Ax0fdoNULYVH2Dfxf3vg3vrwHU3sLjaxB2LCwW58gjQ0HWJu5bXRY6LY0xJh1sWZwxxpi0 c44ehMHQrb1nRirOqapbE7pEehCWlzjCwNzngFcL5puYjVPVesDjhBfNjwFXi8if2azJObYDegKX A7sSBq0PBl73njIfXKjqRYTd9XYWkXnZrqcwVR0CHC0ie6f4vG0IgVVnEXktlefOlih03Yd185Pa AHnABEJ30piSfn1VtQ4wFxgsItenpuKSiT7OToTlsK3WrFnzTvv27estX768+bHHHhurXbs2b7zx Rv7ixYv/TCQSud774oZoaRMtuc6h6IFVaQOvTd1XEoXDp0yFW4Xvz7OAyxiTDta5ZIwxJhNeJOzk 1Y/QYVQi0dDcownL3k4CtgY+InQCvCQiv5a+1IpPVTsAzwBVgC4i8mo263GOPYArgPMIL96eB+7z ns+yWVcJvAjcRwg878pyLRvKJbVL4gAQkU9V9ROgN1Buw6Woe6cd6wKlPYDlwFjC1/LNFO2YeBkQ A+5PwblKJAqVjiX8TG5DGEh/aOvWrScvXrx4K+DKN99882znXM28vLxxwG3e+++yVe/GROFIXnTL SjdjFHBVJfWBVcF92xXhuKolKN07l5EurU3eb/O3jKmYrHPJGGNMRjhHL+BRYB/v+aqoj4teCB1A eMF+GlAP+IrQoTRcRL5PQ7kVkqpWJ8zIuYLQ5XVutjpsohdmhxGCwU6E2VgPAw97T5nq+ikOVX2R 0PXSoqzM91LVasBS4G8i8kAazt+T0AXXWETmpPr86RJ9Xo4kBEqdgR2AX4FXCR1KE1I5EynqtvyB sKHAFak6bzGu7wjh/ADCz9QPgBtE5L1M12JSwzlihIApG11bBfdVKUHpBfO30t2ltan7VpeHbtiK yDm3DWE3zZ+994uzXY9JLetcMsYYkynPAv0h/5/OVekPrPTeb7LTSFX3JgRKZwCNgV+icwwHZpSV F+7lhao2J3zumhIGZA8RkYwPt3WOasDpUQ2tCPO4LgSe854yt8taCQwF3gD2gzLTedWC8AI05Z1L kReAuwlfx35pukZKqGotQtdOF+A4YBvgO8Jw8lHAtDTOjrqAMFT97jSdf6OiUOkIQqh0MGFe1DHA O/ZztHyLBpQXBCZZ4Rxxtjx/qzSB13ZbOLYGoRuwuHXnkYWh8qwfcFWa7z/nXFXgjhj0TkK1GOTH nBvqoY/3PqtL8k3qWLhkjDEmI7xntXP93orHXzwvkeAcgJycnPcSiUTvglkeqtqQEDz0AFoDS4CR hKHT71fUgcHpFC33uYLQsfRfoK2IzM50Hc5Rn7B06hJCh8hYwsD1dyrYL9hvAfMJg73LSriUS1g+ 9Hk6Ti4if6rqs0BPVb1RRNak4zolpao7EjqTTiJ0KlUBPgXuIAz+/yLdIYuqViUMpR8uInPTea0N rnsoIVQ6jDAb6zhgnIVKJlWiDqAV0S0rogHz6erQqgnUKcJxJRkwv4b0d2lt7r6Mzd9ycH8cel0P sfbAFMjpD+euCcP7T8lEDSb9LFwyxhiTEc65Y4BzDz74MLp1u5o//viDRx999ND58+d/8Prrr9+0 2267FbzwywNeB24FxopI1v4iW95FYd0zhKUw9xK2Ps/o59M5mhO6lHoAyaie+4uzNLI8EZF8VX0O OEdV/15GgpZcYGaat71/lDCIvQvwUhqvUySq2pR185PaEZ577xMCnldF5IcMl3QGsAsh0Eo7VT2I ECq1B2YSwrXXLVQyFVE0w2l5dMu4aJl3FUq/JHFTIVitIhxbrQSle+cy0aX1Sg0HvQZC7O/RhQ8G 6kH8PDjZObdnWdowwJSchUvGGGMyIh6PX9usWbPkkCH3x2Ox0MHerl27+LHHHltv8uTJQ3bbbbeJ hA6lkSJi6/BLSVW7AE8QwroOIvJWpq4dzQE5ljBPqT3wM9AfeNx7FmWqjiwaSggxjiXM78m2XODd dF5ARL5Q1cnAxWQhXIqWfrVhXaC0D7ASGAecC7whIr9nuq6othhwDfCaiGiar3UAYfe3DsBs4GRg tIVKxqRP1P2zJrplRaEB8+mYq1Ud2L4Ix25i/lYdPHDCBvcW+u/mgIVLFYCFS8YYYzKldfv27dcG SwANGjRgn332ST700EOvDBo0qMS7yJl1oqHBgwlB3avABSKyMBPXdo6tCcvB+gB7AtMJHRsjvCcv EzWUBSIyW1VnED4XWQ2XohlDewO3ZeByDwPDVXVvEUl7Z5qqVgEOJQRKJwI7A4sIu9b1A94Wkawt 1SmkM+FrcH66LqCqbQih0vHAl0A3QlCf8blqxpjMiwKu1dEtFTtbFlv0h6WNdFRNbQqM+RxoVuj4 mev++XPmqjTpZOGSMcaYjKhevfrib7/9tmbh+9asWcOcOXOSy5cvtx3fUkBV2xJ20duJMFz5iUx0 LDjHLoQt1i8EtiXMyToP+KiCzVMqjqHAnapaJ1sdM5H9o7fpGuZd2CvAQuAiQtdaykXhaQdCoHQC YdjvD9G1RwEfiEiZ2eY86qj6FzBJRD5Kw/lbATcSwrWvCWHuSzafzhiTadGA+ZXRrZBrvqriJvl0 WAAAIABJREFU/jnxKvi/+pBzBGFXgYsgvwp8lQfTMl+tSQcLl4wxxqSVqu4E3H7xxRfvfM8999Cm TRu6dOnCsmXLuOuuu1i2bFkMeDrbdZZnqhonLLu5ifDHwBNEJO0t5s5xACFE6Ar8SdiOfoj3ZGxg cRk2HLgL6A48kMU6coGlZGDJgYisVtWngAtV9dpUdQ2pal2gEyFQOprw1/DZwBDCQO6yvHvkYYSv wXGpPKmqCiFUOoWw293ZwPNlKVgzxpgC+XDGQhjbHlo5wAM5MCcfunjvy+rPb1NMzr6Wxhhj0kFV axDmzvwLWL569errcnNzD04mk+fk5OT4RCLhwOV5nzzfez8sy+WWW6q6K2Eb9f8jLH26UUTStgQt 2pXnZMKQ7gMJL2zvA57xnmXpum55pKqvAg1FpG0WaxgFbCMiR2Xoeo0Jz4nzROSZUpxnN8LspC7A IYSdmD4khEmvisi3pS42A1R1PGF3xP1SEYCpajPC/LJuwFzC0O5/W6hkjCnrnHOOELjvDXwPvOu9 ty7LCsTCJWOMMSkVLQM5mdC1sRMheLhFRJYAOOf2hfqdYOBt0OZC71s9nsVyyzVV7U6Yc7MEOEtE JqXrWs6xHWGO0+WEXa8mEmY7vRFtRW02oKonE5YI7isiX2aphp+BoSLSL4PXHAdsJyLtivEYRxjq WjCQuxVhOO7bhEDpNRFZkIZy00ZVWwOfAt1F5IVSnmtP4AbCsrefgJsJX9eysBuhMcYYY8vijDHG pI6qtiRseX848AZhl7L1luN4778AvnCOC1l/tqMpomhI84NAD+B54JJ07bDnHE0JA7rPJewE8zxw r/eFZ3GaTXiDMGD6HMKyxYyKlqQ2JDPzltZatWrVY1OnTh159NFHvzx//vx5hHlI72+49CFaznkQ 6wKl3QlL+N4ABgLjRKQ8d8NdQ/jr/IiSniDqBLuesOxtHnAp8JSIrE5JhcYYY0yKWLhkjDGm1KKZ KDcTBjp/AxwnIm9u4WHTgawtFyqvVPX/gGFAbeBMEXku1deItjQ+gjBP6XjCkOa7gYe9Z36qr1dR RTOInp8zZ845rVu3/jgvL+8n4OMMzpfIjd5mLFxyzlWNx+O9EokEu+6668k77LBDcsGCBZc7555w zl04e/bsasBRhECpE1CPEJq8ShjIPbEidOOoalPCLLJLS7JkLVoWeC1hMP5vhGWoj4vIqlTWaYwx xqSKhUvGGGNKLNoK/BLCYFlHmLH0YBFn/kwHbnKOuC2r2rLoc92fMMPqI+BwEZmTyms4R3XCAOor gRaAAhcAw73HXtQWk3OuRv369ff89ddfdyDqXsnJyfnCOdfFe5+JmUG5wM8i8ksGrlXgYu99hwce eIDDDjss5r2PjRw5kptuuumC66+/fl/C82prwoDxpwiB0nQRSWawxkz4OyEUeqY4D1LVXYB+QE/g j+g8j4jIys0+0BhjjMkyC5eMMcaUiKp2ICyB2wt4DLheRH4rximmA1sRlsZp6iusOKIuiOeA1oSA 6fZUDvB1jh2A3oSgsD5hWdLVwATvseGMJXf34sWL2/fv358jjjiCr7/+mptvvnmvefPmjXfO7ZmB Qaa5ZHhJXE5OzjmHH344hx12GADOObp27cqIESOYMGHCXt26dbsVGCUiX2WyrkxS1YaEpZD9i9pp FD3mX4Tuz2WErqWHROTPtBVqjDHGpJCFS8YYY4olCjruAU4A3icMqy3J/J3PCLvRtsXCpY2Khhyf TxiKPg84SERSFhY4R0vCPKUeQD6hy+I+79O/bX1F55zbJhaL9ezdu3esa9euABx44IHceeedOaef fnpjoAMwNl3XV9UY4XtrYLquUeg6TYEDgAN23HHHferUqeM2PK5OnTpMnjz5ExG5LZ31lBFXAqsI w/Y3S1UbEGYzXQysIHSBPlDOZ00ZY4yphCxcMsYYUyTREOnrCGHEL8CpwMiSbq/tPcuc4yvCC+Cn U1ZoBaGqdYDHCbNpngSuFJHlpT2vc8QIc5SuIsxV+okwMPgJ71lU2vObtRomk8mqrVq1Wu/OffbZ h5ycHDp27Hiuqv4KzErTjKG9gG1IcedSNF/tgEK3XGC76N1fNWnSZM5bb73V9PLLL4/VqlULgJ9+ +okpU6YkvfcTUllLWaSqtQlB0QMFO2Ru4rh6wD8IA7rXALcC92/uMcYYY0xZZuGSMcaYzYp2dDqX 0AFRExgA3J2iGSDTgf1TcJ4KRVWPAoYC1YFTROSV0p7TOWoSvo59gD2AacDpwCveU5QZWaYIVHVr 4KQpU6ac1759e6ZNm0bbtuvm1s+YMYP8/Hw6dep0MiGgXa2qnxG+HgW3OSUNbQvJJXQGflrSE6hq NaAV64dJTaJ3LyTUeg8wlTA3afHEiRN3i8fjM0455ZRtunbtGl+zZg0jRoygbt26iQ4dOrxQmg+o nLiEsKvifRt7ZxQa9wUuB5LAXcBgEfkjYxUaY4wxaeAyt2GJMcaY8ibamew+wqyf54B/ishPqTq/ c1xG2IVsG+8p9ztElVb0Yn4gYd7RO8C5IvJzac7pHI2Ay4BehE6WkcC93vNRKcs1kWj54iGEOTvd CCHs+2efffaqWbNmHdOnTx9XMHNp0KBB+YsWLfp62LBh+++7774bBje7R6f8ldBxVBA2TReRxUWp xTlXBTj6oosu+tuRRx65W7du3Zps8UHrPoYmG9TTCqgKrAZmsH4A9r9NBWDOuT2dcwOcc52cc3m1 a9d++8UXXzymfv3604Djizjwv9xR1a2AOYSOzos3eF9twvf1lYTND+4nhPS/Z7pOY4wxJh0sXDLG GPMX0Y5Fgwg7h30C9BGRKam+jnO0I+x81tZ7Pkn1+csTVd0XGA7sTRjse29pdtByjgMJL2RPAZYT hq4/4D0/pKBcA6jq7sDZhFBpd+B/hI6zf4vI9865qs65e4GLvPcxgHg8/kEikejuvf9LSKuq9Qkd R4WXnNWK3v0V64c7szcMaZxzbePx+KuJRGLHgvtisdioZDLZw3u/Xqehqm6/kWvVid79zQbX+ry0 S/dU9QhgPPAs0CsFnVlljqpeSgiN9hSR76L7ahG+D68mdDQ9ANxZzM0PjDHGmDLPwiVjjDFrRX95 /zthwOxS4J/As+naJtw5qhN2RrrC+y0Pv62Ioo6Ry4A7ge+AM0Tk800d75xrTljOVoPQ3TTOe58M 76MKcDJhntIBwLeEzrNnvKfU85oMqOo2QFdCoHQYIbh7iRAqfbCx75XBgwd3qFWr1rhPP/30xAcf fHBMMa4VA/Zk/W6iFoSxBqsIS96mAdOmTJky65JLLvmwWbNmtW688cb4rrvuyltvvcWNN96YTCaT D86cOfPfG5ynaXSZRazrkpoKfCwiaZm9papnEcKla0UkrYPGM8E5FwPOzoGecajXoXPnnU4//fSJ 3bt37xQ9T64gLIGrThjuPUhEFmSzZmOMMSZdLFwyxhhTEHCcSgg4GgCDgYEisjTd13aOz4AZ3tMz 3dcqa6Kdop4GOgJDgGs2N8vKOXc9MGA7yN8G/I9QJQ7vJhh2FvQ4izDHZWdgAnAv8Ib3pCUYrEyi kOcIQqB0CiHYm0DYXW/UlraLV9XDgImEjpZvSllLDcIy1cJB0a5jxozhuuuuY+zYsey8885rjx8y ZAjDhg1j8uTJVK1aNQ+YyfpdSd9msotIVW8AbgJ6iMjwTF031ZxzzsGTHs47GpJNIPZqPM5C71cN HDTosY4dO/YgLEN9FLhdRH7JcsnGGGNMWtlAb2OMqeRUdT9Cd8shwKtAXxH5NoMlTAcOzOD1ygRV 7QQ8BSSA40Tkzc0d75xrBwy4AbgOcnIIa4w6445M8PVcwvDm4YR5SpvsfDJFp6pNCYHSWUAjwnKx W4FhIlKc5YU1orelHoIfhY8fRreCOncYNWrUXdtuu+0ZO++8c6zw8fvssw8rVqxg0qRJxx911FET RGRVaWsopZuBxsDTqvqTiEzKcj0l1dbDeY8DF0AM4I5EgnaxWPVXRoy4vGPHjo8QAvqUzagzxhhj yjLrXDLGmEoqmu9yC3AB8B/CVvdvZ7oO5+gFPAJs6z2b7QCpCKKlh3cDvYHXgAtE5NctPc459+BO cOEPkFM4PegFDGW7xXn8sbf32JKbUlLV7QhDuc8BDgKWAC8SupSmlqTLR1VPAl4B6qZrgLNz7kRg 9PPPP4+IrL1/wIABvPLKK78nEokG3vv8dFy7uFS1KvAmsB9wkIh8leWSis05d9N20G8h5MQL3f8w Ybs4oIb3PttBnjHGGJMx1rlkjDGVTPTC7jKgP2Er7D7AI1ncwWk64S//+wEfZKmGjFDV1oTuokbA xcCjxQgrttsZXGyDO3cGPIuxYKnkVDUOHAWcC3Qh7JD2FmG21ZjNLVUsoq2itytKeZ7NeaNKlSrf XHXVVU2vuOIKCmYuvfzyywCDykqwBCAia1T1FEL31VhVbVeUgLVsaVgzwfx4kiSFw6Xoh2iS0Elo jDHGVBoWLhljTCWiqscR5intQegW6i8iC7NbFV8QhhPvTwUNl6Lwoi9hSZACrUvQrTFpOpzxH6BZ dMcq4DnIT8J7qau28lDVZqxb9tYQ+JIQug5L8YycgmVxaetk8d7njxgx4p177rmnSb9+/Qp2pvsT uAO4K13XLSkRWRz9PJoKjFHVI0UkneFbSjhHK6AvjD1tGa3cvYQdEAB+AwZDIgZjE96vzl6Vxhhj TObZsjhjjKkEVHVv4B7gWEIQ0UdEZme3qnWcYwrwP+/pke1aSsM5dz5hqPbWhM/zP2bPnr0t8G/g UMIL/RtKsq37a6+9dkyfSy8dt+znn7k0mXTbA08659X7vCQc6L3/LIUfSoWlqtsTOpLOBdoSdkt7 nrDs7dN0DLdW1SsIQ5232uLBJb/G/oQB3dc1b958GFAP+K/3vkwvNVXVNsAkwgixU0UkkeWS/sI5 HHAMISA+CpgLDIatdoeVfVpBYg+Ij4XEGlicDwd577/OatHGGGNMhlnnkjHGVGDR/JgbCIHHj4Rt 6kdncneoIvqEsGNaueWcmwgcVrdOHbavU4evv/66adUqVc778ccfV+6yyy5LgSNFZGJJzq2q7Xff fffRjzzxxAcnnHDC9zcnk928czX2a9FiRfLzz4+0YGnzVLUK0IHQpdQZiANjga7A6yKS7i6TGqRg mPemREtdnwJmAXd57/MI3+9lnoh8qqqnA6MJu1VeneWS1nKOqoQgsi/QHPg0+u+R3pPv3EoHvPM5 nDsb6iZC5+VD3nvbGc4YY0ylY+GSMcZUQNEyrJ6Ena1qEAKmwWVgp6hNmQ5c7hzbec/ibBdTXM65 s/6fvTuPs3reHzj++pwz055KIlkiWW7eZUlc3ERaJVskZClakOxliRtdW7aSXC5yyVJZQlGJIsS9 Iept/4nQRqG9ppn5/P74fEdxW2amc873TPN+Ph7zmGs65/t5n9m633fvBWhx0UUX0bNnT5LJJJ9+ +indu3fP7dGjx8qJEyc2EZFfS3NtVW1LuPF+q169eifn5eWtds51++jDD0/Nzc0dA5SxWTWZo6pN CAmlrsCOhOTLNcDTIpLJGVVVSO+8pf5AI6BZjLPTSk1ExkXVXfer6rciMizOeJyjBtCTMI9uF0Ii si/wlvfrZyn5UP4/PnozxhhjyjVLLhljzDZGVY8ChgIHAk8A16Z4fkw6zIjeNwXeiDOQUrp0++23 /z2xBLD//vvTuXNnRo4cWWMrEkvHA88ThkufVpQc9N57VZ0E5AMdgOEpeRXbAFWtA5xJSCodRBiF 8xTwuIh8HFNYaatcUtVGwA3AYBGZmY4zMkFEhqtqA2CIqs4VkZczHYNz7EZIKPUEKgJPAvd4z6eZ jsUYY4wpayy5ZIwx2whVrU+Y6dMZ+C/wVxH5T7xRFdtXwHLCDJyymFyqvN122/2eWCpSq1YtvPeu NBdU1ZOAMYSqiC5/ntMkIstUdRqWXCpqC+tASCh1IGzqGgcMBCZkQTVPWiqXogrFR4E5wM2pvn4M rgb2AJ5R1RYi8kEmDnWOAwitb12AlYSfp/u8Z0EmzjfGGGO2BX/eaGyMMaaMUdWqqnoT8AXQHDgH OLwMJZbwnkLCPJNmccdSUv36LTi3Vauz9vzuu++YOXN94ciaNWsYO3YseP9zSa+pqqcCzxLa4U7f zADw8UBLVa1amtjLMlV1qtpUVe8D5gMvALsClwP1RKSTiLycBYklSF/l0iXAYcD5WdzyWmwiUkjY 3DcbGB8lzNPCOZxztHGO14CPCQP3rwZ2855rLbFkjDHGlIxtizPGmDJKVR3hX9oHE+bJ3AXcJiIr Yg2slJxjMNDFe3aPO5biuOqqBac0brz6/qZNV+381Vf5eWd0Ody5hM/t1KkTtWvX5uWXX+aHH36g sLCwq/f+qeJeV1XPIGyXGw2cKyL5m3nsPsCXwAkiMm6rX1QZoKo7A2cRqpQEWEj4fD0uIlnZvqSq zwA7isixKbxmA0IS5lER6Zuq62YDVd0ReA9YAxwpIimbw+Ycuawf0t0E+IgwSPw579nkz5oxxhhj Ns+SS8YYUwZF67uHAkcSKjauFpE58Ua1dZzjNEIbWF3vyeSw5RK54oqFrfbff/UjzZqtrL9oUW7+ e+9VG7FoUU6fBx6ouwPwQk4yeaiHhC8sXFjo/ZXe+6eLe21VPQd4jJAsOb84a9lV9Stgqoj0KvWL ynKqWomw5e1cwlbBdcBLwL+ByZtLwGUDVX0RyBGR41N0PQdMBhoCUlYTypujqvsSEkwfA+02U71X LM6xHeuHdO8KTCAkld7ccEi3McYYY0rHZi4ZY0wZoqp1CRvgugGfAseKyJR4o0qZoqHehwCvxBnI xlx++cIj9ttvzWPnnLNin19/zSkYN67mU/Pn5/YYPnyn1QDDh/sFwOGlvb6qng88TJih0ytqESqO V4DTVNWJyDZzkxwlUA4jJJS6ADWB94GLgDGlHZIek8rAshRerztwLNB2W0wsAYjIl9HcscnAw6p6 Xmm+v51jV9YP6a7M+iHdmtKAjTHGmHLOkkvGGFMGqGpFwirsGwhVG32Af2V7xUYJzQWWEOYuZU1y 6dJLFx6wzz5rR55zzorGK1Yk/MSJNV788ccK591//05LU3WGqvYG/hm99SlBYgnC3KXLgAMIVR5l mqruSpi7cy6wL/Aj4fPyuIh8GWdsW6EKoX1vq6lqPeBu4N8i8loqrpmtRGSaqnYjbPubA9xU3Oc6 RxNC69sZhCHdDwDDvCfbN2caY4wxZZIll4wxJotF1RvHA/cAexJukAaKyC+xBpYG3uOdYwZZMtS7 b99F++y115onzz57RbO8POdff327Sd9/X+HcYcN2SmnLnqr2JbQ4DgUuL0V1xtuETXsdKKPJJVWt ApxMSCi1IszaeYGQRJ1anPbALJeSgd7R74N/Rte6YmuvVxaIyNOqugdwi6p+17hx4xcIFYJ5wLve +98HtjuHI1R0XQ20Ab6P/vej3rM848EbY4wx5Ygll4wxJkupaiPgXsJN0mTgpGwdWJxCM4BezuHi moNyySWLdttzz7UjzzprRQuAadOqT/v224rnDBu209xUn6WqVxIGsd8F9CtN24+I5KnqZEIS8pYU h5g2UaLkSOA8oDNQnZAo6wE8KyKpbCOLWxVgVQqu05kwe6pTGWsL3Fq3AQ2eeuqpEbm5uQ+uW7eu EkAymVzsnDsX/GTgdEKl0gHATOBM4Fkb0m2MMcZkhiWXjDEmy6hqLeDvhKqN74ATgXHb0jydzZhB aP3bjVB1kDF9+iyqU79+3sgzzljepkIF7959t9qMOXMqnTN06E5fpOM8Vb0WuDV6G7CVX9/xwKOq WkdEfk5JgGkSVaGcE73tRfgevxd4QkS+iS+ytNrqyiVV3QEYBjwnIi+kJKoyQkR8lSpVxq9evfr8 zp07V+ratSurV69m2LBhtd99971x3n/6E+xflzCk+wpgqg3pNsYYYzLLkkvGGJMlVDWHULUxCKgI XAcMFZG1sQaWWR9E75uRoeRSnz6LauyyS96Izp1XnFS9emFi+vRqs7/+uuK5Q4bUnZmO86KKnRuB gdHbzSlIHE4AHNAeeGIrr5VyqloN6ESoUjqaMAPnWeACYFoJZ0yVRamoXBpC+P9tl2x9OGVPXl5e 3wMPPLBgwIABSeccAEOGDHHHHtvWLV06cAk829qGdBtjjDHxseSSMcZkAVU9hnDz2ISwiv46EUnJ AOCyxHsWOMc8QnLp+XSedfHFiyrvvPO6f51yyoozatfOT77/frWvvvii0vn33lv3nXSdGSWWBgHX A9eLyK2puK6ILFTVGYS5S1mRXFLVBNCCkFDqBFQFphDmKr2wrW4524StqlxS1Q7AWcC55fH3AkAi kdj3kEMO+T2xBFCxYkUOOGB/pk17bo4llowxxph4WXLJGGNipKp7AncSbr7fAw4VkRnxRhW7GcAh 6br4xRcvyt1xx/xhJ5644vy6ddflzJhRde748TV73nNP3bRu3ooSS3cQBgxfLSJ3pfiIV4DLVTVX RNZt8dFpoqoNWd/2Vh/4BrgdGCkiKZ9bVUaUunJJVbcDHgQmASNTGVRZUq1atfkffPBBPe89RQmm NWvW8PHHH+cDX8cbnTHGGGMsuWSMMTGI2oSuIQygXUyoSnimnMxV2pIZQD/nSHhPytqlLrpoUbJO nfw7OnRYecnuu+dV+PDDKgtfe227i++6a+e0z6+JEkv3ApcCl4rIfWk4Zjyhze5I4M00XH+TVLUG cBqhSulIYBkwGngcmF6ev69VNRdIUvrKpTuAmkCv8vh5VNWawK2DBg1q2qdPH2666SbOPvtsVq1a xf333++XL1/ugYfijtMYY4wp7yy5ZIwxGRS1Cp1JuGHcHhgM3CEiK2MNLKus/Ag+rAE39HZu2kve +3lbc7WLLlrktt++4O9t267st9deayt/8knlxW++WfuqwYN3fjxVEW9O9DUfBlwEXCQi/0zTUTOB hYTWuDfTdMbvVDVJWPt+HnAyYU7YZML394sislUDrLchVaL3Ja5cUtWjgd5An/JW9RUlZLsQkrJV WrRocVkymcwfO3bs4Oeff74qQDJZcYn3/mzv/VexBmuMMcYYnPfl7h/BjDEmFqp6KDAU+CthmHE/ Efku1qCyjHOuaTJZYWxBQd5u0X8XAv/03l/qvS8o6fWuu27+FU2brhq4775rqn/2WaWlM2dWGXDb bfXuT3ngmxAllh4kDK7uKSKPpPm8R4AjReQvaTxjP8LcpLOBXYAvgH8DT4rIViUCt0WqWhdYAHQU kfEleF4V4BNCwrBFORh6/ruotXI40AZ4Dris6HvLOVcVDmgHw56Dg7p4X210nLEaY4wxJrDKJWOM STNV3Rm4jXBD/glwtIi8FW9U2cc5t10ymZy8774Nt7v22mvZZZddGD9+fGLIkCEXee8XALcU91r9 +y/ocdBBq+4488zVtb7+uuLKZ57Z/tpff03e8cADO2XsX1Siyp5HCF/3biKSiUqpV4DzVXUvEfkm VRdV1VqEKpJzgcOAX4FRhKTSjPLYrlUClaP3Ja3kGgjsBhxfXhJLqlqRMJNsACEhd7yIvLLhY7z3 K4HnnWMhIIT2S2OMMcbEzJJLxhiTJqpaCbiMsBlsDdALeFRESlyBU0508d7XHDp0qKtbty4A3bp1 Y968ee6555673Dl3m/d+szfZV1+9oEuTJquHnn32qh2//bbCmtGja926ZEnOgEwmlQBUNYcwb6gL 0FVEns7Q0a8D6witcVs11yl6DW0JCaUTCXODJhJmK40TkbVbF2q5UeK2OFVtBlxJ2Cj4ZVqiyjKq 2oJQ5dcQuBu4WUQ29zmbBTTORGzGGGOM2TJLLhljTIpFs0JOJNwg7Q7cD9wkIr/FGlj2a1CnTp38 unXr5m74wQMPPJDRo0fXBho55+4AmgIrgIe893cCXHnlwo4iqx4499xVu/74Y+66556rdd9PP+Vc 8cADO2U8kRcNcH6SsAGwi4g8m6mzRWS5qr7JViSXVLUxIaF0FlAXmA1cBzwlIgtTFGp5UqLKJVWt ADwKfAykeqNg1lHVHQiv81xgOnCwiMwuxlNnEX7GjDHGGJMFLLlkjDEppKoCDCEMOp5EaOv4PN6o sp+qJo4//vjtXnnlldwffviB3Xbb7fc/e//9/5BIVF/t3KpPnHOJQw89lHnz5u00d+7cwZUq1Tx3 2LCZlc85Z2WDn3/OKRg7tuaIhQtzLxo+fKdYqmqixMAo4HjgNBEZG0MYrwCDVbWaiKwozhOiG/wz CTf4BxM2GD5NaHv72NretkpJK5euAf4CNBOR/PSEFL8oCd8NuBNwQE9CZWdxWwBnAVc5x3besyxN YRpjjDGmmCy5ZIwxKaCq2wM3ARcCcwjJhVftpnzzohvMdsAtN95440Hvvvvu2j59+uRceeWVyV13 3ZXx48fz0ksvAjUr1a5d0z3zzDPsvPPOeO959NFHGTp06P7z5o0tfOWVzmPmzcu9YPjwnZbH+Foq EoYPtwFOKcnw5hQbX1hYOGT69OmnN27c+AXv/a8be1CUCGtP2PbWgXCDPx4YRPjezctUwNu4Ylcu qer+hHlDd4jIx2mNKkaq2ojQAtccGAlcJSI/lfAyRdVNQqh4MsYYY0yMbFucMcZshWguTS/gZkLC /mZgmN2Yb5mqHkkYdN4ceBu4rnHjxr/k5OSMys/PbwyQTCbzCgoK7nTOXd+3b18uuOCC35+/bt06 WrRowcqVa94vKMg7PJYXEVHVysALwNHASSIyKa5YnHOn7rLLLk/PmzcvF/CJRGJiYWHhRd7776Jk 3oGEhNKZwA7AR4T5UM+IyM9xxb2tUtWTCd8bO4jIks08Lgm8C9QADhKRNRkKMWOin5MBhKHd3wIX isiU0lzLOSoCK4E+3vNg6qI0xhhjTGlY5ZIxxpSSqh4LDAUaEWakDBCRRfFGlf1U9QAjGa92AAAg AElEQVTC5rcOhLkyxwETRcR773HOHdCzZ88uhx122NPr1q1r1bt37/9676+vXLnyH66Tk5NDhQoV WL58ucv8q1gvWhn/MnAEoQ3yjbhicc4dBzzbsGFD+vXrx+LFi93DDz/c+pdffnl36tSpw+rUqXMm YQjyIkJC6fFizrcxpVfcyqW+wKHA37bRxFI7YDiwK+Hn/46teZ3es9Y5vgCapChEY4wxxmwFSy4Z Y0wJqepehAG0JwHvAIeIyEfxRpX9VLUhobLrDOBrwia1Z/88Y8V771X1w/z8fICE935tMpn8ZcyY MduffPLJVKkSRti89tprLFmyBMKMo1ioajVCK9khQHsReSuuWACSyeQNTZo0KRw2bFjCuZBz++tf /5rTsWPHelOmTBl0+umnjwWuBSZty/N8skzRzKVNJlKi3ym3EKoet6kWL1XdmTCHrjMwhfBz8lWK Lm8b44wxxpgsYcklY4wpJlWtTtiadQWh8qMLMMbmKm2equ4C3AicDywkDO79t4is29jjnXMtK1Wq NHjNmjXk5OS8lkgkRvbp02fR/fffv/0JJ5xAu3btmD9/Pm+88QaJRGJ+YWHh0Ay+nN+p6nbAq4TK ibYi8m4ccWyosLCwaevWrX9PLAHsvvvu7L333oV3333304MGDTo3xvDKq8rAmk0Nqo5aFR8m/E65 PpOBpVPU5tcbuBVYC5xN2DiYyt+Xs4AOzuG8x34PG2OMMTGy5JIxxmyBqiYIN0a3E+ah3ArcKSLF 3f5ULqlqbcLmqz6E2Sj9gQdEZJPtQc65o51zr+2zzz7uxBNP5Oeff67w9NNPnz9p0qTC1q1bD5g0 aVL3p59+ur73fl1hYeGrQFcfw/BAVa0JTAT2A1qLyH8yHcPG5ObmLv7mm2923vBja9as4ccff/Sr V6+eG1dc5VwVNr8p7gLgGKBNcbf7ZTtVPQh4CGgG/Au4RkQ2Olh+K80CtgN2B+z72xhjjImRJZeM MWYzVPWvwH2Em6RRQH8R+T7eqLJb1Cp2OXAVkAAGA3eLyBbXhSeTyZv3228/Hn/88UROTvgr6uij j6ZLly6JL7/88hvv/V7pjL04os2ArwENgGNF5MOYQwJAVU/t1q3bdo8++ihNmzalffv2LF++nMGD B/tVq1ZBmLFkMq8ym5i3FFX13QWMEJHJGY0qDaLqzpuAS4HPgCPT3OZXNC+sCZZcMsYYY2JlySVj jNmI6KbvdqArMBM4SkTejjeq7KaqFQltMNcTKrweAG4tyQaywsLCIzp27JgsSiwB7L///tSvX3/d 3LlzmxPjfCUAVd0BmAzsBhwjIp/EGQ+Aqu5EGJTcqUePHi8++eSTyeuuu67jwIEDCwsKChKJRMJ7 78/x3n8Td6zl1EaTS1E73D8JVU1XZTqoVIpey0mERHxtwlyvezfV+ppCPwK/EZJL49J8ljHGGGM2 w5JLxhizAVWtBFxJmK20AugBPCYiBbEGlsVUNYfQNjiQsAnq38BNJanwUtUKwAnVqlXzCxcu/MOf 5eXlsWTJEgeko62m2FR1R+ANYEfgaBHRmONxwFmEjYUFQOeKFSs+t2LFCu+cOzgvL+/o008//YiL L764Q61atV6NM9ZyblNtcacDHYFT0tQylhGqWh8YRngtrwB9ROS7TJztPd45ZmEb44wxxpjYWXLJ GGP4/Ub9FEKLyi6EG/Z/iMjSWAPLYht8zv5BmD30HGGw9RcluEZjoDuhQmyHVq1aLRg9evRORx11 VKJZs2asWbOGe++9l5UrV+Y0atTohXS8jmLGuTMhsVSLkFj6PK5Yonh2BR4EOgBPA5eKyOKiP/fe fwR8pKrPECpKziBUyZjM+5/KJVWtQ0jIPCsiY2OJaiupai6h/e0mQuK3EzA2hgUHs4BjM3ymMcYY Y/7EkkvGmHJPVZsQkklHE/7lvW0KV2Vvc6KkUivCYPNDgElA1+LOHoqGYXchJJWaAT8T5gE9Nnbs 2O+TyeRr3bt3/2vdunXXLVu2LLFq1apk//7913Tt2vVBVe1Qkja7VIgSOVMIFSgt4vzeiD735wN3 E4aknygiL2/q8SKyQFVfJXyuLbkUj41VLg0hzCO7JPPhbL1oFt1DgBCSZDeIyPKYwpkFXOQclbxn TUwxGGOMMeWeJZeMMeVWND9nENAT+Bo4TkQmxBtVdotuKm8jJOLeI1TxvFWM5yWAFoQkx6lABeBV QuXTKyKSB+C9xzn3N+C4hQsXtgCWAU937dq1OjABmK6qbUVkTspf3Mbjrk9ILOUQEkuxzS1S1T0I K+tbASOAK0Xkt2I8dQQwVlWbiMisNIZoNu4PlUuqejxwJnCOiCyKLapSUNVahKRyL+BD4NAsGGg/ i5CoawR8FHMsxhhjTLllySVjTLkTtXNcSGjncIQZS8MzMHy2zFJVAW4BTiBsaDoBGL+lFhhV3Q04 F+hG2K72NeHz/oSIzN/Yc7z3BYThvH8Y0KuqRxCqpKaransRmblVL2oLVHVPYCpQSEgsfZfO8zYT RwK4iDBgfgmhsu61ElziFeAnwtfg8tRHaLagCiFJiqrWILQzTgSejDOokogq5s4A7iUkyy4FHsiS WXSfRu+bYMklY4wxJjaWXDLGlCuq2obQkrIf8C9CO0dG26zKElVtQEgGnQV8S5iNNGpzN5XR1rgT CO1bbQhVG2MISaZ3SzuTRUTmqOqRwHjgLVU9WUTeKM21tkRVGxISS2uAliLyQzrOKUYcewOPAs0J 2/euKWn7kYisU9WRwHmq2r+oSsxkTGWgqELpDsImxV4xzCYqlehn4QGgNfAscLmIzIs3qvW8Z4Vz fIMN9TbGGGNiZcklY8w2xTm3D6FtaDXwsvd+Cfx+k343YaPRW8CZIvJxbIFmuWiA9QDCtrzFwMXA o5tLTESzq4qGc9cmtM31AMakah6LiPykqi0Jw8MnqOo5IjIqFdcuoqr7EVrhlhESSxutsEonVU0C lxGGpc+jmO2Hm/EYoUKvI/D81kdoSqAKsEpVjya0k11ckk2KcYmSxP2A64EFQAcRydatg7OAxnEH YYwxxpRnzvsy8Q9nxhizWc65BHA/cGEikfDeewfk1axZs++0adP2ItyozweuAp4vK1UDmRbNVOlH aHtZQ6i0GCYiG1ulXjSc+wxClVJTQvvV48Bj6dyoFrU2PgqcDVwmIkNTdN39CVvhFgPHxjETJ4ph BGHY+b2E6rqNfv5LeN33gSUi0mFrr2W2zDl3iHPu+po1a3asUKHC8k6dOhV0797984oVK7YQkcK4 49ucKBH2ILAXYYPmoFR8D6aLcwwELvSeneKOxRhjjCmvLLlkjNkmOOcuBB645pprOPXUU1m5ciX3 3HMP48aN49lnn129zz773ArcLSKrt3St8khVqwJ9gX6LFy+ucO+99/5n0qRJ89euXfs58Jj3fv4G j00QBnqfTxjInUuY6zMCeDVTs6uiOTC3E5JhgwktY6X+S01VDwBeJyQhW8WwlS6X8FpuBOYA3UXk vRRevydhY9zu2dTWtC1yzv3NOTdl9913d+3atcuZN28eEydOpGrVqq8vXbq0jc/S//OlqnUIyaRz gHeB3iKi8Ua1Zc5xCqEir673lKkh6cYYY8y2wpJLxphtQm5u7uxjjjlm/3vuuccVfWzdunW0atXK FxYWPvrrr7/2iDO+bKWqFQitazcA27/22msv9r/qquOS3lduDIUKiXWwpgCOmz179rfAeYTB0HsA XxGqh0aKyIKYXgKqehmhwucJ4ILSJLdU9WBgMvAd0EZElqQ0yC2ffyChda0xIVF2s4ikdK16NEx6 AaEK5bZUXtv8UU5OzvR99933sJEjRyYqVKgAwMSJE7n66qsBjvLevx1rgH8SJYy7Eb73HCHJOSLb K6yKOMfehN9HbbxnctzxGGOMMeVRIu4AjDEmRXbZe++93YYfyM3NpUGDBtSpU+dgVf1LVOliCDN9 VPVs4AtgGDBx+fLl+/a/8spmTb2vPA8SMyBnAST+BpV3qFFjUn5+/neEm84pwN+A/URkcJyJJQAR GUJozTsDGKeq1UryfFVtRmiF+z9CK1zGEkuqWlFVBwEzCH8nHyYi16U6sQQgIksJA5m7289C+jjn KhcUFBzeuXPn3xNLAG3atKFGjRr5hCH3WSNqw3wLeIQwLH9fEXmkrCSWInOAVdhQb2OMMSY2llwy xpR5zrFDYWGjFVOmvEVh4fr7ocWLFzNr1izXvn37A4HPgHmq+qSqdlPV+rEFHCNVdap6IvAJodLn Y6CxiJx3xBFH1MmHPe6ARO3o8TWBO8EtXrq04uOPP34nUFdEzheRUm99S4doqHd74AhgStTes0Wq ejihFe5zQsXSb+mL8n/OPoywOr0/MAhoJiIfpvnYEUBDQnLQpJCq1lLVzjNmzHgomUyyfPkfZ9iv W7eOtWvXOsKygdipahVVvY3wO2BHwvD6c8vi9kzvKQAUSy4ZY4wxsbG2OGNMmeUclQhzgq6HyUlo W7V58+Z06XI6y5Yt46GHHir44YcflrZu3brpnXfeuR9wLNASOIjQ+vENoQrnDWCqiPwU12vJhGjL 2q3AYYTXfJ2I/Lfoz52r1x4WvPop0GiD530H7Bn+Z0fv/fhMxVsaqnoQMIGw6a2diMzZzGObA68C MwmbsFKy0a4YMVYGbgauICSXuovI7Ayd7YCvgbdFpFsmztxWRZ/LxsBx0dsRQBLQM888M2fBggV7 jxw5MrnrrrtSUFDAfffdx4gRIzywr/f+6xhDR1XbA8OBeoTfCXeIyNo4Y9pazvEw0NR7Do47FmOM MaY8suSSMabMcY4EoQXqVsLN0YPAzfD3O5PJJ88tKAj5hGQyOb2goKCn9/7TDZ+vqrWBFqxPNu0X /dFs1iebpkVtRGVe1PZ1K9CK0H51rYi8UfTnziFAL1h6dpKda/RhNUM2eP71wO2QVwj1vPcZnUVU GqraAJgEVAfai8hM51wNoAGwwHu/UFWPIbQA/QfoKCIrMxRbc8Kcqt0Jg7vvEZH8TJy9QQzXA9cB O4vIskyeXdapanXCz9FxhEq5XYCVhOq3CcAEEfneObdblSpVPszLy6tzwAEH+B9++KHgp59+ygH6 e+8Hxxh/PWAIcBrh99yFIhJroitVnOMSwjDyqt6T0Z8pY4wxxlhyyRhTxjjH0YQbiKbAWOAa7/nK OaoA30L+y5B7G7Dae1+sWUDRDVfL6O1Ywo1/ISERU5Rsmr6pTXPOue0Jm9MOI6ywf8x7/5/Sv8rU UNW/AP8gbHT7DBgAvCgi3jkqA52BnoSKi0XACNgrAXP6d3COlt7zNvgXQ5XXTd77gfG8kpJT1R2B V/Lz8/ft3LnzpG+++aZjYWFhRcDXq1fv3dGjRx9Ss2bNacDJmVixHs2Bug3oA0wnVCt9me5zNxHL rsD3QE8ReSSOGMqKqDrpL4RE0nFAc8J2xC8JVW+vEqrA/qfq5+23354yevTovYcPHz4dWAI8Htfv BVVNAhcCtwBrgMuBZ7KptXVrOUcL4E1gf+/5LOZwjDHGmHLHkkvGmDLBOf4C3AF0BP4LXOk972zw 55cDdwJ7e8+3pT0nuplswPqqppZAHWAtISlQlGz6QETWOecaJJPJ6c65OgcffLCbO3duwaJFi3JC fP6e0saxNaJ5UgMJ68R/AP4OPCkiBc6xP9ALOJswUmky8C/gZe/Jc865iy++eNLkCROO+b85c/KT MGcd3AOMyNb16ZuiqtWuv/762a+++uoePXr0oHnz5nz++ecMGzaMunXr/jps2LB6rVq1Svng7I3E 0Qp4mDDX5lpguIgUpPvcLcQ0AaghIkfEGUc2UtWqwDGsb3erT0jITCEkkyZsrt0yukZT4AOgi4iM Tm/EmxdtQnwIOCR6f62I/BpnTOngHNsTknhneM+ouOMxxhhjyhtLLhljsppz7ERIlPQgVFtcC4zx Hr/BYyoTtgVN8J7uqTw/WtG9P+uTTUcT2q1WAG+ddNJJe65cuXLfkSNHJuvWrUthYSH33HMPjz/+ eCGwl/f+u1TGs4VYdyR0sfUGfiNULf2rcWNJENpgehGqlH4iDHZ+xHu++dM1qgLzgWEiMiBTsaeD c267RCLxU8+ePStefPHFv3986tSp9O3bF+Cv6awkUdUahCq7C4CpwAVbSkpkiqqeBowBGonI53HH EzdV3Zv1rW5HAxUJv1OKqpPe3FTl4iauNwY4mLBRMZYWraiF72bCXLpPgV4i8l4csWSKc/wIPOE9 18UdizHGGFPe5MQdgDHGbEzU5nY5cA2QD/QDhnvPxobOXkCoLrol1XFE67hnR29DVDWH0JJ37PLl y1t9++23jfr370/dunUBSCQSXHTRRTzzzDPk5eWdSkgupFWUxLiK8PnKJ9xQDm3cWOoDgwkVTDUJ c2E6Ay95T94mLteFkDx7ON1xZ0CDwsLCis2bN//DBzf4byHMXEo5Ve1AqBLZjpDsezjLVru/DPwC dCP8bJUrqlqJMHetqDqpIZAHvEX4nTMB+Ko0bWNRoupUwjyjjCeWourLk4H7gFqE1zNERNZlOpYY zMI2xhljjDGxsOSSMSarOEeS0LL1D0Ib0TDgFu/5ZROPr0S4eXrqz1U46RDdLP4H+I9z7gHg1+rV q//hMRUrViQ3N9fn5eVVSmcs0daxPoTXXxm47403qt932WX1jwUmAkcCPxOSHI94z/8V47K9CW0/ c9MUdibNB/xnn33mmjRZf7/56ae/z3f/IdUHRsPihwBdCV+DXiLyfarP2VoislZVnwTOUdXry0Pi QVX3YH110rGEn5kfCJVJVwJTRGRFCo66mlAd+HgKrlUiUUvs/cDxhIH1fbaRn+XimkVY9mCMMcaY DLPkkjEmazhHa0KlTxNCy8613rOlNqLuQF3SULW0Jd7733Jycj4aNWrUge3atUvk5uYCMH78eFau XJmsVavWG1u4RKmoai5hgPgNhATcw4MG1Rs9Zsz2JwNKqFZ4AzgdeHEzVUp/vm5TwlyWE9MRd6Z5 739q1KiRDhs2rHGdOnU46qij+OyzzxgwYEBBMpn8vqCgIKVfH1XtBDwAVADOA57I8oHJIwgtU+0J lUzbFFWtAPyN9dVJfyFU9r1DmEP2KvBZKr9G0XKAc4EbRSTt87w2ODcXuIzQQvwrYYj/i1n+/ZcO s4D+zlHTe36LOxhjjDGmPLGZS8aY2DlHY0L7VjvgXeAq73m/GM+rCPwf8Jb3dE1vlBvXoEGD43/8 8cdxu+66K61ateL777/3kydPdu3atfN33HHHe8BpIjI/FWdF85+6ENreGqxbx+grrtj9gzff3O4k wk30z8BjhCqlEq8XV9V/ERINe8Y1JyZVotag25YuXdr/7LPPnvvtt9/WL/qz2rVr/7ZkyZK/eu9T sq1NVXciVIucCrxEaIcq1qbCuKnqh8APInJS3LGkQrQJr3301hqoBixk/eyk10VkaRrPH0yYbbZ7 Os/505mHE6oT9ye0wt0oIsszcXa2cQ4htDAfFZZdGmOMMSZTLLlkjImNc9QjJEq6EYbn9gfGbjis ewvP7wX8k7B6OuNDiaMExphPPvmk3YUXXjh99erVBznnfu7Ro0eVHj165OTk5CSAJCHBVOobneic DoTqrCbLliWm9uu327x3363egVClNIWw8e3FTcykKs4Z2xHayO4UkZtKG2s2iNauDyfc5F8uIkOc c4cAjQcOHHj8SSed1DyZTO62sfXxJTzHEVpw7gM8oUVxTFmqFlHVi4GhwK4isjDueEoqmoF2OOur k5oAhcB7RJvdgI8z8TVR1ZqEpQPDReTaDJxXC7gd6EnYTNdLRD5K97nZzDlygZXA5d4zPO54jDHG mPLE2uKMMRnnHNUIc0muAlYT2jkeKm77VnSNCsB1hM1xcW276g2cesABB5y6bNmy54s+qKoNgU+A 54HdgSmqeiVhA1uJbnJV9SjgVuDIRYtyvrjxxl0+mT69+jHAYuARQpXSVyl4LWcBlaJrlllRK9QT hO143UXkMQDv/QfAB6r6PvAZYeBxqdeVq+ouhMRmx+g6fUXk560MPw5PA3cTZkSlffh8KqhqXUKV Y3ugLVCD8PMwAbgNeE1ENjqjLc0uJLREDk3nIVFS80zgHsLcqEuAf4pIQTrPLQu8Z51zfI4N9TbG GGMyziqXjDEZ4xw5hCqlQYTtZUOA27ynxO0jznEBYaOZeM+nW3p8qqnqgcD7wCMi0mcjf94LeBA4 gbDa/ArCjXxPEVlZjOsfREgqtZs/P/enf/yjXuW3365WHdxUQpXS2NJWKW3kLAfMBL4VkZNTcc04 qGoV4DnCsOYzROSFTTzuTcCJSItSnOEI38P3EBKjF4rIi6UOOguo6tPAgcD+2Vh1FVWiNWN9dVJT QqXYDNZXJ30Q5za+aLj+d8BYEemdxnP2Jsz1agU8C1yWqrbbbYVzjAT28p4j4o7FGGOMKU+scskY k3bO4QhVBncCjYAngQHeU6otRlHrw3XAczEllqoBo4HPCdVXG/MvQmLpYaAx8F/gUaDx+PHjO3fs 2LF9Tk7Ouc65GuvWrZsMDPbe/5+q7pOfzy05OZw6f37u6rvvrsvkydslvXcPAQ+nqErpzw4DDiBs nSuTVLUGMI6QeDheRCZv5uH/BEapaiMR+awEZ9QnfD1bA/8GrhCRX0sfddYYAUwmfB9scdZZJqjq DoSqpPaEKqXahEHVkwiVQZNE5Kf4Ivwf5wE7kKbqL1WtSGgbvo7QvnqciExIx1nbgFnASc6R8J7Y Eo7GGGNMeWPJJWNMWjnHQYQbrpbAm8A53vPhVl72LGBPIONDiKPKlX8CuwAHb2ojlIh4VT2fsL3t IaAToIWFhWNvv/32WclkMqdly5bUqVPHTZw4sdvSpUvPGD581DvNm0vbJUty/PDhOzJuXK3/5ue7 h4AXUlWltAm9CFUXr6XxjLRR1R2BiYTviVYi8t4WnjKWMPy8F3BpMa6fILRA3kFIcLQXkYlbFXR2 mUKYFXQ+MSWXos/xQayvTjoMKKqoe5BQofTfbBw0H819uhp4VkT+Lw3XP4bwOWhASND/Q0RWpfqc bcgswiD3PWCL20aNMcYYkyLWFmeMSQvn2I0wgLor8CXh5uuV4g7r3sx1c4AvgFnec8pWB1pCqnoe YSNbVxF5qhiPP4Uwe+k8EXl8l112OW3+/Plj7r//flq0CF1Zy5cv5/TTT6dBg7/QoMGTK8eM2f7h lSuTD3pPSraZbSG+WoRKiJtF5LZ0n5dqqro7oeqmBtBGRGYV53kzZ868fdq0aX369+//0Nq1axcB T3vvf9zI9RsSKs6OItzg9xeRZal7BdlBVQcCVwJ1i9O2maIzawJtWL/dbSdgGeHr+SowsSy0fKnq GYSW14NFZGYKr1uHMA/rbOAdoLeIZLxSs6xxjp0Jv9NO9p4y3bJqjDHGlCVWuWSMSSnn2I7QXnU5 4UbxQuBR70lVxcEZwF6Egc0Zpap/IWwhG1GcxBKAiLygqk98//3397do0aL50l9+6VC5UqXC3Nzc RNFjqlevzimnnMKwYQ+se+utOjt4z0arodLkbMLfBSMyeGZKqOo+wOuE7WB/K27ViHOuRtWKFduv XLu2aj3nLv0F3Fq41TnXzXs/Mrp2klDV9A9gAdBSRKam6aVkg38DfwdOBR5PxwFR1V9j1lcnHUHY pqjRma8C00VkXTrOT4foNV1DaNNLSWIpquLqDgwmzJY6H/h3nDOlypiFwBLCUG9LLhljjDEZYskl Y0xKRHOQehJuUKsRWuEGe8/yFJ6RBAYA47wnZRUCxREN7B1DaB/rW5LndurU6bEf5849u/K6dd07 g5u1Zg29evWib9++9OjRA4DVq1fjXOGaTCaWohvj3oQhxIsydW4qRAPPJxG2hLUWkXklePptbu3a /d8CjvI+uZywbusJeMw59+bs2bOrE5JthxLm+wzIVDVPXETkO1V9g5DUSFlySVWrE4ZPH0eoTtqF sCr+DeBiYIKIfJ+q82LQjpDE2GJ7ZXGoqhAq5I4kfB2uLqNbCGPjPd45ZmEb44wxxpiMsuSSMWar RMO6TyTMo9mbUAFxg/eU5Ga/uE4H9iHMXMq0IYSKqWYlTTTM+eqrwQJ+GiSqE0oRrgfuGDaM448/ noKCAkaPHp1fUFAwJg1xb05z4C/A/2y7y2aq+jfgFeBroJ2ILC7uc51ziSScexkkj4o+Vh0YBowG 1/K44x4GjgG+JVRDTU9x+NlsBPCUqu4tIl+X5gJRwnI/1lcnNQdyCa2xYwjVSW+LSDpniGVSf+A/ wFtbc5Fo0+GNhNbEb4BjROTNrY6u/JpFSGYaY4wxJkMsuWSMKTXnOJRQodScMCels/d8kqaziqqW XvWeD9JxxqaoahdCVVaPks48cc7VBZr1IyQxIEwpvha403t69+7N999/X+i9nwfckMq4i6EXIUFT Ztq9VLUd8AJh+94JpZh/lFsAVfb80werA3WSSbfjjju2ISRKb9rUsPZt2FhgKWHz2fXFfZKqViUk 5NoTEkp7AGsI31dXEKqTvklxrLFT1cOBFsDJIlLqWXKqehyh3XZn4GZg8DaUfIvLLKCvc1TxHht+ bowxxmSAJZeMMSXmHHsCtwJdCPNS2nnPpDQf24lQZdMtzef8QTTQ+V/AM4TBziWVgDBYZkNF/z1n zpxPCe0vD3vvfyttnCUVrXo/Fbhua26MM0lVOwNPEjbDnS4iq0t6De/92lxX+YuRrN3vPDxFg6/e AX4oKHBz5869UkTuSWHYZYaIrL766qvfnzx58lWfffbZ+YWFhZ8WFBTc5b3/n5X30c9FUXXS0UBF QrXXeEJ10pul+fqUMf0JywVeLs2TVbUeoe3yVMLssDalrRgz/2MWIY+/PzAj5liMMcaYcsG2xRlj is05ahEqGi4hDEwdADzuPQVpPjdBuFn40XvapfOsDalqRWA6sB3QtDRbwpxzLtlcWPAAACAASURB VAdmNoXGUyFROfr4LcCA0CHX0Huf8XXZqnpVFMYuJWkri4uq9gAeImzl6lbaoc/O0QleGgknV26J 913BfQcMcc6vhpnrvD/Ue5/W7+ds5Zy7Ghh86KGHcsABB/D+++8XzJ49Own0mD179pOEKp2i2Ul7 A3mEdrAJhITSV2UlUbm1VLUR8CnQXUQeK+Fzk8BFhJ+/1cBlwKjy8rnLBOeoAqwAenhfqn8UMMYY Y0wJWXLJGLNFzlGBcDN0I1CB0DZ0j/dkZMhxSAjwHHCk92RsBo6qDiFsuztcRD4q7XWcc80T8Hpd SHaE5GwomB6Kl27z3l+XsoCLKdpG9SXwHxHpmunzS0pVryZszhoO9C3N1iznyCFU211dpUrBC717 X5+cMO6FEz//+msqJJP5eQUFI4D+maweyybOuVqJRGLhWWedVaFfv34AeO8ZMGAAU6ZMyZ86dWpe pUqVqgA/EBJJrwJTRGRFjGHHRlX/TRhU3kBE8krwvKaEJOnB0fvrROTXtARZzjnHl8BE71MzbN0Y Y4wxm2dtccaYTYqGdZ8K3E6Yo/II8HfvWZjBGBKEpNYbGU4snUTYANV3axJLAN77t51zB1fbZ5/h b+Xnt5gzd+5bFBQ8QJgdFIdjgIaEzWBZKxoOfQthRNUtwA2lqe5wjp2AUUDz00775f4bbpjf1rmu 9bt163r9mjVrbnHO9WzatGmJqk+2JaqaPOSQQzp/8MEHFbp2XZ9rdM7RtWtXXn755ZyXX3754c6d Oz8AfFreK2xUdXfCUoF+xU0sqep2wCDC8HwFjhCR99MXpQHbGGeMMcZkkiWXjDEb5RxHEIZ1H07Y zHWC95RomHWKnEC4QThqSw9MFVWtDzwGvAjcn4preu8/VdWXgUNE5NhUXHMr9AY+I4waykpRddX9 hMqxq0Tk7tJcxzkOB56rUqUgZ9Sob17cc8+8iwnbvU4Evq1UqdItQKla7MqaqB1rL6ARYRZN0fv9 zj///IoffPABK1f+sRix6L8HDRr02M0336yZjThrXQEsBx7e0gOjBOkpwH1ATcKcpqGlbes0JTIL uNQ5nPeU64SoMcYYkwmWXDLG/IFzNCRUKnUCZgLHes+UmGJxhKqlN73n7Uycqaq5hOHdSwnzVFJ5 U7ITZK7qa2NUtS5wEnBFtlagRF+DfxMGxl8gIiWemRJ971wM3NOy5bIv7777+xo5ORxHSAwME5EC Va0WPTw/RaFnBVXNYeNJpH0Jg7cBfiXMDHofGNGwYcOvcnJyRt13333b3X333a5ChQqsWrWK4cOH +2Qy+WNBQcGHMbyUrBMNwu8B3LWllkBV3YOQIO0AjAMuEZG5aQ/SFJkF1CZs4ZsfcyzGGGPMNs+S S8YYAJxjB+AGwmylhcA5wFPeU+L5Nil0PHAQoY0rUwYBzYDmaZiFUhdYlOJrllR3QqXOyJjj2ChV rQyMAdoSNsI9V9JrOEdV4KFq1QrOuvvuH2YfccSKxoTB0y1F5P82eGjR34FlMrkUJZEasvEkUoXo Yb8QkkjTCW2tnxKq1hZtmFwUEfLz88956623nm/ZsiWNGzfO+eSTT/y6devcEUccce20adPi/D2Q TfoQtpAN29QDouToFcDfCYsPTgZeytZk7jZsVvS+CZZcMsYYY9LOkkvGlBPOuT2B63OhI5C3Lmzd uh38asL2t+uBBCHBNNR7Yl0jvkHV0tuExEDaqWpbQttKvzTNQ4m1cilqi+pB2EyVdYOro7k0LwOH Ah1FZFJJr+EcewMvtGixrOGdd/6wpHJlvychYfrQRgaB50bvs7pFKUpW7EVIHG2YRNqH9UmkJYTE 0TvAv1ifRPqpuEkN7/3LzrnGS5cu7fnOO+/sValSpW+ee+65TvXr179YVUeJSLncoldEVasSflc+ vKkNi6p6BGFQdyNgKPB3EVmeuSjNBuYSNsY1ASbGHIsxxhizzbPkkjHlgHNujxyYURtqnAs5K4HH 4Mo8ap2Zz/JCqF4PeBC42Xt+jjncIu2AQ4DWmZiXoar1CNU8E4BSzfcphp2A99J07eJoQxjM/lCM MWxU1G40kVCJ01pE3i3pNZzjxBo18kfecMN837btskrANKDnZlqRsqpyKUoiNeSPCaRGhEqkokTY YkLi6G3Cz+xnhCHbP6UiBu/9F4Sqm6KYno/OuprQLlueXQDUAO758x+o6vaEz08PYAZhttrMzIZn NuQ9hc4xGxvqbYwxxmSEJZeMKR/614QasyGnTvSBnpA8iN92hbs+hptae89XsUa4gahq6e+EVp43 0n1eVNHzFKGC5dzSrLovprjb4noBHwP/jTGG/6GquwKTge2Bo0Xk45I83zmSwKCWLZddO2jQj2ur Vy9cQ2j/+/cWqnZiSS5FSaS9+d8k0j6sTyL9TEgiTQP+yfokUkaTvyLyrqoOBm5W1Qki8kkmz88W qloBuBJ4esNkZTSw+yxCwqkiYc7XQ+W9yiuLzCIspTDGGGNMmllyyZhyoAJ0OGuDxBIUrV/z/k1u /s77m7ImsRRpDRwGtMvQlp8BhG10LdN18x4lsOoQU1tclMDpCFycTbNfVHVvQmLJEeZcleh70Tnq 7LTTuueuumpB83btluE9rzlHbxEpzoyVor8D09IWFyUk9mZ9AmnDJFLR2T8RkkhvAsMJSaTPMp1E 2oK/A8cBI1W1mYisjTugGJwB7AYMLvqAqu5DSPy1BEYDl4vIgnjCM5swC+juHBW8Jy/uYIwxxpht mSWXjCkHPKza2ICdX6EQ4p2t9GcbVC39F3gt3eep6tGE2U43iUg6ZzvVBpLEV7l0PrCKUKGVFVT1 AGAS8BuhFe6HTT3WOVeV0Ca5GvjAe1+Yk+MPPfHE3yZcddXCWlWrFiwHejvHqOImzx544IE9mzZt yk8//VRbRLbmdVQgJIz+PFh7b9b/PbuIkDiaQtgg9ikhibTR2T3ZRETWqurZhHavm4BrYg4pY5xz 7q677nJt27btD4wTEVXVSoTPwbXAj0B7EbGZPtlpFqEacF9gdsyxGGOMMds0533W/AO2MSZNnHM3 VICBb0LicMAThgudG/74JO/9S/FF90fOcSzwOtDBe15N51mqWgf4BPiCkNxIWyuLqjYm3OgcISIZ mbvknPsr0DvHuT1P6tTp4BNPPPGVrl27dsnE2VsSDT5+BZgDtNtcpY5z7pIk3FoA1QByYO6O9e6b cM01J/Q65pjlbuXKxLiqVQsvKO7cIedcrUQi8XhhYWHHoo8lEokXCgsLu3nvl20m5opsOomUjB62 kKiFbcP3IrKkOLFlM1W9BrgVOEpE3ok7nnRyzjVJJBK3ee/bJhKJwuOOOy73yCOPPKlDhw7LCdVK ewJ3Av8QkaxK0Jv1nKMGIXnd1fvsSawbY4wx2yJLLhlTDjjnqubAG/lwWDMoWA7+C8hxMNLDed77 rFkz7hxvAVWBZulsiVPVBCG50RQ4sJhtVFtzXitC+1cDEfk2nWcBOOcuAB7eE/KbQc5bySSLCwvz Crxv671/M93nb46qtgHGAh8StsIt3dRjnXOdgOd6EYbZ/AJcj2NmxYo8PXr86p133vm8Qw9tNKYk 5+fk5EyoXLly6/79+ycPPvhgZsyYwR133FGwdu3alwsKCk7ZIIn05+1sDfljEulT/phE+nxbSCJt StTaOY0wO+wAEVkRc0hp4ZzbN5FIfLjbbrtVOu2005Jr1qxh1KhReO9XvfTSS1Vq1KjxNtBbRD6L O1azZc4xFxjlPf3jjsUYY4zZlllyyZhywjlXEegMtAfygGeBV30W/RJwjhaE2TMnes/L6TxLVfsB dxCqZkq88r4U53UlFIxVFZFV6TzLOVczAQu6QaV/AQlCL1kbKHwfvs2HveP6uqvqqcDThETbaVv6 XOQ69/7foNkUSLjoY0uBXV0CV63q4GXLlpXohtE5ty/wxe23306HDh1+//gLL7zAwIEDGTdu3Jz6 9evXZ30SaQF/qkIiVCL9UpJztxWq2pBQ7TdSRHrHHU86OOdG1KlT5+xx48blVK1aFYD58+fTsWNH jjzyyGfvu+++Lmkc+m9SzDnGATne0z7uWIwxxphtmc1cMqac8N6vJSQ3RsYdy2b8nbDNbFw6D1HV wwntPbdnIrEU2QlYnu7EUqRNIVS6iZBYAqgMDIBEO9iLUInzaQbi+ANV7Q48DIwhbOUrzoDd/Vpt kFiCsAv+YF9Y+GmFCgeq6sElieGYY445aurUqRx22GF/+Pihhx6K954ZM2Z8Ur9+/dtZn0T6tSTX 39aJyP+p6pXAP1X1JRGZEHdMqZabm3ts27Ztf08sAdSrV49mzZoxderUypZYKnNm8XsXuDHGGGPS xZJLxpis4BzNgWOAU9LcDlcLGAX8hzDIO1PqksZh3lHLUhPg6H79+p01ePDg33faF6mw/n8myTBV vQK4G3gQ6FOc+Vaq6mrUqLH4nWXLarBBodVKYFYymTjtlFPaAG1KEkffvn2ZOnUqM2fOpHXr1r9/ fObMmQDcdNNNVw8cOPCbklyzHHoIOAl4VFUbbyutgM6RCxyXTO5Rc9GiP47v8t6zcOHCAkLhnClb ZgG7OEdt79kmvleNMcaYbJTY8kOMMSYjbiBs80nbcHFVdcAIoDpwhoikZQX9JuxECpNLqppQ1QNV 9XJVfQlYDHwE3NamTZvVOYlE4Z0bPD4fuBt8bthulbGqJVV1qjooHM9twEXFTCz9BZh01TXX7DXR e/oBc4GZwCnglxcWrtthhx2OJ8zMKvZbw4YNm9asWfPDQYMGFUyePJklS5YwceJEbrvttoJkMjnB e2+JpS2ItvGdD1QChscczlZzjgOdYwgwD3ixoKDrsjfeeJ3XX38d7z0FBQU88cQTfPPNN0myu/LT bNys6H3jWKMwxhhjtnE2c8kYEzvnOByYDpzmPc+l6xxVvQS4DzhJRDK6IU9VJxHa4k4t5fMTRJVJ 0dtRQC1gLeFz92b09l8RWeOc6wfc0QwK/grJV8lhDvmFHk7J1HbAKOahQB+gv4gMLsZzahLaI/sA 87z3lYcNG5Yc8fDD2xWEleLkwOJ86Oq9L1VLo3Nux2Qy+WxBQcFRRR+rWrXqOytXrjzRe18uZymV hqp2AZ4hJGpHxR1PSTjHjsBZwHmEn6ufgCeBx8F9nkgkni8sLOy44447F+bl5SV++20JhATp1dk0 p85smXPkACuAft5zX9zxGGOMMdsqSy6Z/2fvvsOjqrY+jn/XTGiCCCoqNrCjLkRRESt2rl2xey3X rth7AXsvqHjtXhWwvLarVxDFBvaGosISO9ixgYgNJDP7/WOfSIAQUmZyJmF9nifPkMnJPmtC8Zmf a6/tXOpEeBJYHugaAkWZZ2Jm6xJDmJtV9cRi3KM6Y8eOfS+TybysqsfU5PokmOnKrDCpF7PCpNeY FSa9oarTq1pDRHbMwrFZWGkmOy8dOGRkCLvsVN/XUhNm1ozYJfZP4slat83n+ixwMHEW1kLEEHAv YoftZl27dv0D2Jg4m/yFEEK9u85EpOuSSy651s033zxolVVWOVFVG30XTkMzs/uJWxO7quo3addT HRFaADsQA6XtgRwwFBgMPBUCM2ddKxlgS9j+YlhldRi4VQjhrRTKdgUgwhhgTAgclnYtzjnnXFPl 4ZJzLlUi9CDOP9o3BIrS/WBmbYlbxqYCG6vqjGLcZ04iIkDfsrKyU3K53Art27f/ecqUKWcDt87Z /ZCESUqcO7U5dQiTqq+FM4kdQcsWe+6ImbUEHiC+gd9fVR+Yz/UbEcOkdYndI1cn378QsJmqfl7k ep8B8qrau5j3aYrMbDHidtaxwHbJlrmSIYIQ/1wdBOwHLAqMBgYRj6evtlNNhBOBi0OgTZFLdUUk wiBgjRDokXYtzjnnXFPlA72dc2k7F/gQeKgYiydzlm4FlgB6N1SwlLgI6LftttuGddddl9GjR7cb MWLEzcBSZnYhMUzanFlh0qLAX8Qw6XpimPR6XcKkKtwBXAAcAlw1n2vrzMwWJs7N6gnsXN1pYma2 NHAFsD/wNrEz6WPi625LAwRLiaHAADNrq6rTGuB+TYaqTjazQ4EngCOJA9tTJ0JH4p+rg4A1gUnA f4DBITC+FktNAVqL0CIEGvLfDldYY4E9RciGwHxnvjnnnHOu9rxzyTmXGhHWBd4C9g+Be4txDzM7 DLidBp4LIyKLi8i3hx9+eLPjjjvu7+cHDhzIkCFD8s8999zUdu3aVYRJrwOjmNWZ9GdxamIwcVbT ysV4g5V0sTwJrAbsqKovzeO6FsBJQH/gD+As4C6gHfAcsDTQS1U/LHSN86inMzAR2FNVizbzqykz s1uAA4BuqvppGjWI0BLYmbjtrTcwE/gfsUvp2RAor8OaOwLDgI4h8F3BinUNSoStgWeAVUPgk7Tr cc4555oiPy3OOZemc4FPiFugCs7MFPg3cFsKA4fXDyE022233WZ7ctddd+Wvv/7KDB8+/AlgS6Cd qvZS1fNV9fliBUuJG4HOwHaFXtjMlgFeTNbfoqpgKTk5bifiaXUXAbcBq6rqHcQT/J4ClgO2aqhg CSDpjhpLDCZc3ZwKfAcMSeZnNQgRRISeItxM7E56gBhS9gWWCoF9QmBEXYKlRMW2ucUKUK5LT8WJ cWulWoVzzjnXhHm45JxLhQjrEN/MX1yPN37zZGatgQeBT4EGH+ANTAP44YcfZnuy4vPLL7/8BlUd VeQwaTYh8CZx3syxhVzXzFYCXiIGRJuq6pgqrulC7GoaCnwGrKWqJ6vq1GQr3ZPAysA2qmqFrK+G hgE7mJlvF68DVf0NOJC4HfK0Yt9PhGVFOAv4gLiNdEfgJqBLCGwUAreGwNQC3KpiPtmiBVjLpSQE fiCeCOjhknPOOVckHi4559LSH5gA3Fek9f8NdAL2asgAp5LXs9nsl1dffXV+8uT4/vSnn35iwIAB ubKysgnEkCcNNwK9RVilEIuZWVfgZeIWpE1U9aM5vr6ImV1NHPq8CrAr8A9V/SD5+kLEYEeJM7He KURddTCUGCBslNL9Gz1VfQW4ErjQzLoVen0RFhJhPxGeAr4EziFuq90G6BwC/ULgo2oXqb2KziUP lxq/sXi45JxzzhWNz1xyzjU4EdYC3gMODYE7C72+me0P3A0crKqDCr1+TS2++OKbzJgx48UZM2ZI 586dmTBhQgCm5XK5rdM61jyZS/M1cHcInFSftcysJ3GQ8xfEYOiHSl/LEGffXAa0AS4Brqk8nDw5 VW4YsCGwraq+Wp966iOp9xvgXlU9Na06GrtknlZFcLp+fQfoJ6e9bUT8s7QXcdD7S8Bg4KEQKOoA dhHKiMHpISFwVzHv5YpLhAHAriGwUtq1OOecc02Rdy4559LQH/icGAAVlJmtSjyx6m7iG9DUPP/8 8xs++eST+Q033HBQ9+7dWW211QbkcrkV0wqWAEJgOvHUrINFaF3Xdcxsa+BZYDxxxlLlYKkncUj5 Hck1q6nqpXMESy2A/xJPiNshzWAJQFXzxKBrl+SEQVcHSZh0ANCFeDphnYjQSYT+xNMDXyZ2J11H HEa/WQjcUexgCSDZsjsNn7nUFIwFVhShTdqFOOecc02Rdy455xqUCGsSt0gdGQK3F3LtpBPmdaAV sG4yByYVZrYU8Y3xoOTj7aSmueYRNTQROhPnHh0dArfV9vvNbDfgfmAksLuq/pE83xG4nDh75x3g eFV9uYrvbwY8BPwD2ElVn6njSykoM6s4GWz1hhwo3hSZ2RnErrXNqvozUJUk7NwdOIg47P534GHi 358XQyBfnGrnW9cE4P4QODuN+7vCSOb8jQE2DIHX067HOeeca2q8c8k519D6A19RnK6iAcSOib3S DJYSlxC305yfch1zCYHPgceBY5JtRzVmZv8ivuF/DNhFVf8wsxZmdjoxTNseOIK4JaqqYKkMuDe5 rk+pBEuJ54A/8VPjCuFq4LXPP//83latWl0rIo+JyHUisnrli0TIiNBLhLuIp80NBoS4DW6pEPhX CDyfVrCUmILPXGoKPgBy+Nwl55xzrig8XHKuCRKRfZqLjG4m8nMzkddFZI+0awIQoQuwN3BZCPxV yLXNbHfi8eMnqep7hVy7DrWsBxwMnKOqU+Z3fUpuIL7J2qSm32BmJwB3Ebe77auqf5nZDoABlwJ3 Aquq6u2qmqvi+7PJ9/chBoBP1P9lFE4y+P1pYKe0a2nsVDV39NFH37Rnnz7Lt5ox44TtYefF4BiB sSKyqwgrinA+sYPueWAz4jDwFUJgyxAYHAJpB8QVPFxqApItwR/j4ZJzzjlXFH7ksnNNjIicDlyx OeR7QWYkrD8SHhKRk0II16VcXj/i0OSCDsY1sxWIgcfDxHlLqUnm9VxPDFxqveWsAT1HfKN1DHFA 8jwlr+m85ONK4ExgFTO7ltiB9Bywq6q+X80aGeLPYz9iMPW/QryIIhgK3G5mHVT1x7SLaaxEJFsG l20MYThIa2AGlO0N4XHaPJRjehm0/BV4kNit9HIIlOo+/SlAh7SLcAXhJ8Y555xzReKdS841ISLS LgMXnAw8DZl+wHOQ6Qtk4RIRSW2QqQirEoOFy0OgXidIVWZmzYnzf6YAh6tq2m9Q9yWefnaiqpan XMs8JduMbgR2F6HjvK5LQqHriMHSWcTtflcQw7M1iF1I28wnWBJip9TBwEGq+mChXkcRDCduy9o+ 7UIaue7lsNyFSbAE0AK4BCTHb2Vw4ZXEbW+HhcBLJRwsAUzGO5eairFA19puB3bOOefc/Hm45FzT smEeWvad48ljgBwsBGyQQk0Vzga+J3YYFdKlwDrA3qo6tcBr14qZtSZ29jyiqiPTrKWGBgMziDOS 5pLMR7oTOI74x2gS8BFwLHAhsIaqPlpdoJcES9cARxPDv3sK+goKTFW/B97A5y7Vyw477NAFmOtY rlmfX/ZqCPzRkDXVg2+LazrGAu2AZdMuxDnnnGtqPFxyrmn5E+DnOZ6s9Hkqb+ZEWAnYH7gimXtR EMm8n1OAM1R1dKHWrYczgMWB09IupCZC4BfgbuBIEZpV/lpy8t5DwD+Bc4kneA0izsdZTVUvTmYU zVMSLF0GnAgco6qFDhaLZSjQO/kZuBoysyXN7EQzG3PBBRcMademTRgIs7UkDQQyMdB8MZ0q62QK sFjaRbiCGJs8+tY455xzrsA8XHKuaXmlDL4/C/IVk3CnAWdDvgy+Bt5Mqa6zgZ8o4AwiM1uW2Hnz OHHbVqrMrDMxVBqgqhNSLqc2boRvO8LOt4lIfxHZ+KWXXmpD/Ln+AxgFXETc1dRLVfdV1a9quPZ5 xMDtZFW9qSjVF8dQoDWwRdqFlDoza2Vme5vZcOI8tSuBiS1atNj1z5kzjxoCbAC5fkAvyF0L5OGc EMKcGXgpmwy0FqFF2oW4evsK+AUPl5xzzrmC84HezjUhIYSZIrL/SHi8I5R1B3mbjPxJ80yeZY4M 4dO5TvAqNhFWAA4EzgiBajtdairZrnUfsVPrXyUwZwnim+qfiZ06jYj0EDKUEf7VCsqnwUWnnnzy 1JtvvbVV8+bNc0B34pa2Kk+AmxczO4tkTpOqXluk4otlPDCBuDXuyZRrKTnJHK5NiH+v9wTaAq8R t0s+WHFC4vTp0xGRL9+BU9+FNQN8ClwXQvhvWrXXUcWJj+2B79IsxNVPCAQRxuHhknPOOVdwHi45 18SEEJ4VkS6/wWEvwsqw1Hfw6uHQqTeQxtHvZxJDl1sLuOZ5wEbA5qo6uYDr1omZ9SK+yT5QVUvl +PT5EpHVgNsPJc/VwMJQ9gjwz7ffbvef//wn9O3b90bgvIqwoKbM7GTiLKzzVfXywldeXKoazGwo sKeZ9S2R8DJ1ZrYqcABxi2tn4HPiTre7VfWTqr4nhDACGNFAJRZLxZ//RfFwqSkYC2yedhHOOedc U+PhknNNUAjhc6B/xecifAVcJcLdIfBWQ9UhwvLEE8L6hcDvhVjTzLYG+gH9VfXlQqxZz3qyxDfY bwD3plxObR20CORvgEzFfp89gOdCYNDtt/900003HVfbBc3sGGAAsYPrwgLW2tCGEmdFrQOMSbmW 1JjZosDexC6lnsSdtg8CQ4BXVDWfYnkNpSJc8rlLTcNY4py5FoU8udQ555xb0Hm45NyCYSCx4+BW ETYIgfIGuu+ZxDejNxdiMTNbErgHeBYolY6Yw4BuwAaN8I324svDXINkVgFmlJcvUtvFzOxw4Abg WqBfI+/4eRmYStwat0CFS2bWHNieGCjtSJzPOIIYMg2b3yD3JqiiO9JPjGsSJn4I72fhmpNFRt0T QqjpDDnnnHPOVcPDJecWACFQLsIRwOvEuShFH4AtwrLAocD5IVDvrWLJnJeKY+wPKIUgx8zaA5cA g1U1rWHp9fGmweEfAl2SJ3LAA5DL1HL4u5kdRNz6eCNwSiMPllDVmWb2BDFcOj/lcoouOdmvBzFQ 2ocYpIwhDqm/X1W/T7G8tFUMH/dwqZETkW2y8EAyPO5SgUtE5N/ASSGE1P+b4pxzzjVmflqccwuI EHgTuAm4SITlGuCWZwC/ETtZCuFMYCtg/xJ6o3susfHnrLQLqaP/y8Lnm0P5dcD/Ab0hjIZMOVxQ 00XMbB/gTuAO4PjGHixVMgxYx8wa4u9LKsyss5n1Bz4khs+7ALcDqqrrqurAEvr7loqk03Mavi2u URORZTIwbCtYZDxxr+MVIALHA7XeAuycc8652XnnknMLln5AH+B6YLdi3USEpYHDgYtD4Nf6rmdm mwIXAZeo6rP1Xa8QzGx1YhfYOao6aV7XiUiPDosvft7SSy7JpB9+uOCHH3+8MIQwuuEqnbcQwu8i sskPMPBk2C1Apgw+CHBGCKFGP2cz60PsKLsXOLIUOsoKaARQDuxEDGabBDNrSxyvdSDQC/gd+C9w DDCqNqcCLkCm4J1Ljd2/mkPZg5Cp2PN7GvAuhIfgBOL2ceecc87VkYdLkC46lQAAIABJREFUzi1A QuAXEU4AHhRhlxB4rEi3Oh34E/h3fRcys8WA+4BXqEU3TTElW4iuBb6kmi2GIrKvwL1tfvopv/ZP P/ELbCewvYjsG0J4sMEKrkYI4RtgDxFZCGhZDj+HEGrUeWRmOwL3Aw8DhzSxYAlVnWpmLxC3xjXq cMnMyoBtiIHSrsSOu+eSzx9tTKccpmQyHi41dp1WhTDnMLmeIP8Hy6ZSkXPOOdeEeLjk3ILnYeBJ 4AYRRhais6gyEZYCjgQuD4Ff6rNWEuIMAloB+6lqQw0in5/tgd7Abqo6vaoLRKRlGdzUB7gPslkg B9m9IAyFm0XksRBCyZxUFEL4A/ijpteb2bbEbpfHiTOwSuX3ptCGAlebWVtVnZZ2MbWR/P3pRgyQ 9gOWBN4HzgPuU9WvUyyvsfHOpcbv/fGQ/RZYutKTT0I+Cx+lVZRzzjnXVPjMJecWMCEQiNtfFqM4 nUCnAn8Rt97V14nE06oOKpU3wslJWtcSuz6q6/zapBza9QfJJk9kgf4g5fFN6oZFLrVozGwL4mt/ BthHVWemXFIxDQOaAdumXUhNmdnSZnYa8B7wDvBP4kit7kBXVb2yVP4+NSJT8JlLjd0QYMo2kHsM eAM4Angyzpi7NN3SnHPOucbPO5ecWwCFwEQRLgAuFeHuEHinEOuKsATQFxgQwt8nLNWJmfUArgAG qOrwQtRXIMcDKwJ95jO4WmDuBD8zx9cbGzPbhNit9CKwh6r+lXJJRaWqE81sHHHu0sNp1zMvZtaa OEftAGBrYCbwP+Kw+aebeADYEKYAq6VdhKu7EMLPIrLFxzBkV1gboAx+AfqHEP4v5fKcc865Rs/D JecWXNcA+wO3idAzBAoxxPcU4mn219ZnETNrR5zl8w5wdgHqKggzW5J4QtzNqmrzufyVLEy7FNre TQyVcsT/PZ5l4VyOl38scrkFZ2YbAE8Ab1LNlsAmaChwlJmVldL2PzPLApsTA6U9gNbAS8RtqQ+r 6tT0qmtyfOZSExBCGCci3YFVgYXLwUIIC8q/Y84551xRebjk3AIqBGaKcATwKnA0cEN91hNhceJ2 u+tDYEpd10nmxNxOfCO3VYl1xlxC7Ag5b34XhhD+EJFj74PBb0GuF5S9kM3yaT5PPlz7E6z1pghn AjeEQMkPwjaz7sBTwFhgJ1Wt8XymJmAo8aTFDYnhTarMbA1ioLQ/cRDxp8Quv3tUdWKatTVhPnOp iUgOLPAZS84551yBebjk3AIsBF4T4Vbi9rhHQ+Cbeix3cvJ4TT3LOpLYhbFHKb1RNrN1gUOA41S1 RuFZCOFuEZnwKRz/OXRZdvnl/xh84YU9l1hi/f1792Zn4tHXu4lwcAh8Xrzq68fMuhLnK30EbL8A niz2FvAd8dS4VMIlM1sC2Ic4nHtd4Gdid98Q4I35bNF09TcFaCNC8xAopcDbOeecc64kSA1PnHbO NVEitAc+AF4KgT3ruMaiwBfATSFwRl1rMbNuxDmrd6jqMXVdp9CSbqqXgHbA2nXdGmVmGeKWshyw YdeuujlwF7Ej4iTgjmTgeskws9WBF4CviZ1k9Zql1ViZ2e3AZqraYHN3zKwlcdbTgcA/gAAMB+4G hqtqyZw22NSJsCNxuHvHEPgu7Xqcc84550qNnxbn3AIuGbx9ErCHCDvUcZkTif+eDKhrHWbWBngQ +JA4u6mU7A1sDJxQn5k7qponnqbXA9grBEYCXYEHiFsBh4vMdkp2qsxsFeKpeN8B2y6owVJiKLCq mRU1XDIzMbNNzOxW4s/9QaAD8e/Y0qq6m6o+4sFSg6voVvStcc4555xzVfDOJeccIggwgnga0poh 8Hstvrc98DlwewicWpf7J51BQ4inXXVX1Y/rsk4xmNlCxO1gb6nqbgVa8zGgG9ClYih2EuzdDrQE jgX+L80uJjNbgXgi3G/A5qr6fVq1lILkz8FPwHmqelUR1l+JOEfpAOJphF8SO5TuVlWfD5MyEboQ Ozw3CyH9uVvOOeecc6XGO5eccyQhRl9gSWowrHoOxwPNgavrUcJBxOHER5VSsJQ4A1gC6haczcPp xEHMx1U8EQLDAQWeBO4FHhKhQwHvWWNmtjwwEphO3Aq3QAdLAMkA82eIc5cKwszam9mRZvYKcSj3 ycDzxBPgVlDV/h4slQzvXHLOOeecq4Z3Ljnn/ibC2cCFQPcQGFuD6xchdi0NDoET63LPZKbPW8AD qnpIXdYoFjPrRNymd62qnl3gtW8gBmorq+pPlb8mwh7AzcQZO0eGwKOFvPd86lqa2LGUJc4Y+qqh 7l3qzOxQ4DZgyTl/z2qxRnPi/KQDifOUyoin8A0Bhi5gp/A1GiKUEU+KPCQE7kq7Huecc865UuOn xTnnKrsa+Cdwqwgbh0B+PtcfB7QCrqzLzcysFXGmzBdU6uIpIVcST+W6rAhrX0DcAnUusfvrbyHw sAgvAbcAj4hwD3B8Mh+raMxsSeKMpRZ4sFSVxwEBtieGQTWSbPtcjxgo7QMsDrwLnAXcp6o+ILrE hUC5CNPwziXnnHPOuSr5tjjn3N+SI7aPAnoCR1R3rQgLE7fx3B4C39bxltcBKwN7qWqN5zw1BDPb DNgLOFNVfy30+qr6I3ApcLSZrTrn10Pge6APszpcTIR/FLqOCma2OPAssAiwpapOLNa9Gqtke+Ab 1HBrnJktb2ZnAeOJpwTuDgwCuqnqOqp6jQdLjcoUYLG0i3DOOeecK0XeueScm00IvCTCHcDlIjwW ApPmcemxQGvgirrcx8z2IQZYh6uq1a3a4jCzLDCQGAjcU8RbDSTOurqCOMx8NsksrLtFGAXcATwp wm3AqSFQsMDLzNoT5wktQRze/Umh1m5KRET69u376dh339139GuvvTsjhFeB60IIf88JM7OFiSHS gcTZSX8CjwInAM+pai6F0l1hTME7l5xzzjnnquQzl5xzcxFhUeKsoZEhsE8VX29DnLX0YAj0re36 ZrYyMAYYDuynqiX1D5GZHU6crbOhqr5e5HvtRxzgvbmqvjCv65IT/Y4ABgA/AgeHwPMFuH9bYsfS SkkN4+q7ZlMlIpcBZ26YydAln+dxKJ8CM1u2br3V66+/3pYYKO1GPPFvFHHr3CPF6HxzDU+Ep4Gp IbBX2rU455xzzpUa3xbnnJtLCEwBTgH2nsdWrKOBtsDltV3bzFoA9wM/AEeWYLDUDriEeAR8UYOl xP1//vnnW4MGDRqUyWQez2QyQ0XkEBFpXvmiEAghcCuwFvGY+lEiXCfCQnW9sZm1IZ5OtwqwjQdL 8yYiqwBnXgK8ms9zJzARytYSablSp04vACOAdYgD8Tup6laqOtiDpSbFt8U555xzzs2Db4tzzs3L PcC/gJtE0BD4A0CE1sBpwKAQ+LIO614BdCV2BU0rVLEFdA6wEHHYctF17dq1Rbt27VpOmzatc48e PTrlcrnw9ttv75TJZA4SkW1DCDMqXx8CE0TYgjgE/DJgOxEOCoFaBWFmthAwjPh7sbWqjinUa2rM kuHbixC3Py1W8bHddtv1GTliRDgpBKm4tjVwUghy4PjxzV544YWte/XqNbLUwlJXUFOA1dIuwjnn nHOuFHm45JyrUggEEY4GxgH9RWQA0A5+2w1atycOo64VM9uVOHvm+FIMM8ysCzG0OU9Vv2mg2x45 bdq0NQcPHszaa68tgIwePZpDDz10U+AQ4OY5vyE5xe86EUYAg4FXRLgCuCAEZsx5/ZzMrCXwP2B9 oLeqvlnIF1QqktMIKwKi2cKiaj5fFMjOudaaa66ZGzVihMz5fEWSdOyxx74XfJ95U+czl5xzzjnn 5sHDJefcPIXAxyLvXyfS78wQ5EwIks2uEHK5A9+AAV/Mems9f2a2PHAnMdS4oVg119M1wFfJY4PI ZrN79erVi7XXXvvv59Zff3023nhjXnvttb2oIlyqEAIfirAxcDpwPrBj0sX0zry+x8yaAw8DmwLb q+orBXopRWNmZUB7ah4UVTzXqorl8sDPwGRiWDAZ+HSOzyfP+XmbNm12nR7CPQOA/slCvwLXQK4M Rs8M4acCv2xXeibj4ZJzzjnnXJU8XHLOzZOIlGWzzXZs23YR6dv3bJZffnmeeuopeeSRAT2Jw6Vv rck6ZtYM+D/i+/FDS3HrkJltD2wH9FHV6Q11XxFp3qJFi7k6Ylq0aCHdunXbzMzeBN5JPt4Fxqrq HxXXhUA5cKkIw4ldTG+KcCFwOUgzYB9ih9IPSy655L3PPvvs5cA2wE6qOqroL7CSZMtZW2reRVTx scg8lvyN2cOgH4APqCIcqvT5VFXN16LmhYDLdt999+PHjx//xTkPPtjpf2RZkxzDoXwq/JWD42rx Y3CN1xSgjQjNQ+CvtItxzjnnnCslHi4556qzfS43c40bbhjIWmutBcBGG23EjBkzeOqpp84RkdtD CDV5o34hsAGwqapOKWbBdZF081wLjCR2VjWY8vLyx5577rm1v/jii2ynTp0AmDBhAi+++GLYcsst hxPf0PYkbpErA/Jm9hExaKoInd4JQd8ToQdxZtR58NnuZTRbPMfMZVaHmV9B5scffjh32LBhuZ12 2mlXVX26PnUnW+vqsuWsqv/u/MXcYdB7VNNJBExR1aK+wTeznsTAbnnghB49etzw4IOfHjCGZQa9 xyuflTPlCeD6EMKnxazDlYyKf7sWBb5LsxDnnHPOuVIjPiLCOTcvInJ+u3bt+r300kuzBQJPPfUU p556KsDiIYTJ1a1hZr2JJ2mdoapXFq/aujOzk4GrgLUb+sQ0EWnfsmXLMZlMpnPv3r3J5/OMGDEi V15e/kkul9sghDAtqbElsCawNvFUsnWAbsS50gBfkwRNzz238G9nn3n4eW2nj2w9ihxdgD+BI4H7 RMpzISwTQvghWTfL7FvOahoWVXVKXWDWlrNqt5nN8fnvpdTNlpxoeB5wBjAaOEhVPwIQYRdiALlc CHydXpWuoSVbUF8G1gyB8WnX45xzzjlXSrxzyTlXnW+nTZuW/fHHH+nQocPfT37yySdkMpk/8/l8 tcesm9nSwN3EcOnq4pZaN2a2BDFIuKWhgyWAEMLPI0eOfPf+++/v/Oijj/4wderUyeXl5Q8B11YE SwDJVr23k4+K2rPASswKm9YBjt5gg0kdps94lisIdEmubUVszfq/EMpOOOGEN8wsRwyK2s2jtN+Y PQz6EfiI6sOiX1Q1V4AfS2rMrBswBFid2AV2paqWV7pkXeB7oKEGvrvSURGk+9wl55xzzrk5eLjk nKvOg8A1Z555ZqsLLrgg07FjR0aOHMmgQYNy+Xz+jhDCPLclJcHHPUA5cGBt5tw0sIuBHHBuQ99Y RBbaa6+9tj/kkEN2Of7448uPP/74Lqr6c02/PwlyPjazycwKPL749ddfe+RD6NZxjuvbAS1FwqRJ k34Enqf6LWfzPXWuKUmGhp9BDBo/ANZX1fequHQ94K0QajHN3jUVFdviFku1Cuecc865EuTb4pxz 1RKRLbLZ7KO5XG6RZs2aMXPmTLLZ7NO5XK5PCOH3eX2fmZ1LfKO+lao+32AF14KZrUPsBDpBVf/d UPcVEQHOyEK/HLQB6LLyyj9++OmnG4QQJs7r+5KtcWsAXef4qMiR/gI+yOfz47bcdNPtekybtujj IJnkiw8Qp3sDG4YQXi/CS2uUzKwLcbbSesBlwIVVzXMSQYgh3k0hcH6DFulSJ0Iz4t+xQ0LgrrTr cc4555wrJd655JyrVghhlIgsk81mdznllFPuWXXVVT8+5JBD/hGqSabNbHNisHRhCQdLAlxP7FK5 pYFvfwxw2bHAvsAE4KxPP120DEaJyGrjxo2bCazA3CHSKkA2WWMiMA64M3kcB3yiqjMBJk+b1udJ eLgX5PeEzIfA7ZDPwvAcvNFwL7V0mVkGOJ4YKH0JbKSq1f1slgM6UGlroltwhMBMEabh2+Kcc845 5+bi4ZJzbr6SDqX7zOxmoMN8gqUOwH3Ai8QtZ6VqL2ATYJuKQKYhiIiUwVn7Atclz20ArAVZhU7n nnuuETuRKgZ1TyYGR88A1yS/fl9Vq513FUJ4RER2fB3OewW6Z2FyOdwKXFrd79+Cwsw6A4OAXsBA 4GxV/WM+37Ze8ujh0oJrCr4tzjnnnHNuLh4uOedq43tgZTNrmQyYnk3SCTKE+G/LP0t1uLOZLUQ8 He4xVX22gW+/cDksvf0cT64JLJPNhnfeeefPPffc83xiiDQW+K6uJ6mFEJ4AnqhXtU1M0rF2KHG+ +WRgS1UdVcNvXw/4NgS+LVZ9ruRNwTuXnHPOOefm4uGSc642JhC3Zq1OPPZ+TqcC/wC2U9VSfgN+ GrAksd6G9nsWfhkNi+xT6clvgEm5vAwb1sGGDdObQmB+XTSulpLTC28HtgfuAE5W1WnVf9ds1gPe KkZtrtHwcMk555xzrgqZ+V/inHN/+yB57DrnF8xsQ+AS4ApVHdGgVdWCmS1PPBXsWlX9tKHvH0LI dV177ZE3iHA78DuxPWkvyAstZ8KAvYHPRegnQvuGrq8pMjMxs30BA7oDO6rqYbUJlpJh3h4uucl4 uOScc845NxcPl5xztfFZ8jhbuGRm7YH7gdHAOQ1dVC1dAfxCDMIanJmV3XHHHWtssNFGk44gHhXX DXgTfsrx5+bQbhXgYeLP8UsRrhJh6TRqbQrMbHHgQeIcsBGAqurwOizVGWiPh0sLOp+55JxzzjlX BQ+XnHO18VXyuG7FE8kMmzuBhYF9G3I4dm2Z2abAPsBZ8xuIXUQHNW/efLWbbrllR6ALcBCwYzks F0J4NQQmhEBfoBPwb+AIYKII/xFhtZRqbpTMbGfgfWALYC9V3U9VJ9dxOR/m7cC3xTnnnHPOVcln LjnnauPr5HHNSs8dC+wK7KaqXzR8STVjZlniqWBvEYeOp1FDS+B84EFVHZMc2vZRVdeGwPfA2SJc ARwJnAQcIsIjwOUheAfNvJjZIsTD+P4FDAOOUNXv6rnsesBXIfBDPddxjZuHS84555xzVfDOJedc jb333nuTBg4cyI477rhENpv9tHPnzneUl5dfDVyvqv9Lu775OBhYBzheVfMp1dAX6Egttg6GwC8h cCWwAjFk6gaMFuFZEbZOZgG5hJltTTxprw/x93yXAgRL4POWXDQZaCNC87QLcc4555wrJZL8n3Pn nKuWiLTIZDKf5/P5pVZYYQUAJk6cSPv27ct32mmnRQcPHpzWNrP5SjpZPgGeUtUDUqqhLfG0vUdU 9Yi6riNClhicnEkcTv02cDnwaAjkClFrY2RmrYnztI4BRgIHq+qXhVhbhAyxY+XKELi0EGu6xkmE nYChQMcQKERo6ZxzzjnXJHjnknOupm7N5/NLDRw4kKFDhzJ06FAGDhzIzz//XDZkyJDr0y5uPs4B WhMDmbScQpzffWF9FgmBXAg8ROyk2ZY4nPwh4AMRDhOhRb0rbWTMbCPgXeAQ4jbNbQoVLCVWAhbB O5dcDBnBt8Y555xzzs3GwyXnXI1kMpldNtxwQ7bccsu/n9tyyy3p2bMnmUxm1xRLq5aZrQacAFyq qt+kVMMSwMnAv1X16/ldXxMhEELgmRDYCuhB3Ap2G3H496kitC3EfUqZmbU0syuAl4AfgW6qemMR tj36MG9XwcMl55xzzrkqeLjknKuRTCbTrF27dnM93759ezKZTLMUSqqpAcRB5NekWMPZQJ64fa3g QmB0COwOrA48AVwKfCHCJSIsUYx7ps3MuhM7iU4k/nw3VdVPinS79YCJIVDXk+Zc01HxZ2CxVKtw zjnnnCsxHi4552qkvLx8zKhRo/juu1ljRr777jtGjRpFeXn5mBRLmycz2w7YAThVVf9MqYZOwNHA Vapa1HAiBD4KgcOIw7/vIHZsfSHCjSKsUMx7NxQza2Zm5wJvADOB9VT1ClUt5rwpH+btKvycPHrn knPOOedcJT7Q2zlXIyKyRjabHdemTZtMnz59AHjkkUf47bff8rlcrmsIYXzKJc7GzJoRt4pNArZU 1VT+sTOzu4DtgZVU9beGvLcIixJPqDsBaA88AFwRAmPj16UtcU7RFsBvwL3Ak6FE/8NgZmsAg4mn /l0KXKyqfxXznskw71+Ai0PgimLeyzUOIkwDLgiBAWnX4pxzzjlXKsrSLsA51ziEEMaLSI/y8vJH 77nnnuUAZs6cOR44sNSCpcQxwCrA3ikGS2sABwInNnSwBBACU4CLRbiGGCKdCrwnwhMw/NYyuBZY YXNgEuTfh/2Am0Tk2FIKmMwsSzI3C5gIbKSqbzbQ7VclDmL3ziVXYTLeueScc845NxvfFuecq7EQ wtuvv/76zmPGjGHMmDG5EMKaIYSSG3JsZh2A84HbVPW9FEu5GPiKOGg7NSHwRwjcQAzb9geWh2GP tSG74niQZ0DGQfaGeHlfYJP0qp2dma0IjAKuBm4EujdgsASzhnmX5NZPl4op+Mwl55xzzrnZeOeS c662Kk47K+Vw+mIgAOekVYCZ9QB2Aw5S1Rlp1VFZCMwE7hXhvjLu+PUocq1XSb4mxMFQl0H5N7An 8QS21JiZAEcQB7L/AGyhqi+kUMp6wKch/D1rx7kpeOeSc84559xsSvnNoXOuNE0GcsQ8ouSY2drA 4cB5qvpTiqVcBrxPnGNUUkIgBMql9RzPZ4CF4i+bN3RNlZnZMsCTwC3En1+3lIIl8GHebm4eLjnn nHPOzcHDJedcrSTzi36Hv2fhlIyk22Ug8CFwc4p1bA1sCfQr8ilmdZfJjLgzkwlTKz31NPBJ7Gh9 Mo2SzEzMbH/AgK7Adqp6pKr+mkY9IpQRh4d7uOQqm4xvi3POOeecm42HS865upiWPC6eahVz2wPY DDhJVWemUUAScF0GvA4MTaOG+TGzhe6+554OU1q1ktUhdxLwT2AHCFl4Dng8hZqWAB4G7gaGA6qq Ixq6jjl0ITZzebjkKvPOJeecc865OXi45JyriynJY8mES2bWijj0eZiqPpViKX2IW6nOSuuUuuqY 2SLAiK5du3Y/6bTTDvoOBt0EX7+14or53jvs8FQOdgwhNGi3lZntRuxW2gzYQ1X3V9VSmHFUMcz7 nVSrcKXGwyXnnHPOuTl4uOScq4sfk8dSeoN1KtAROCWtAsysjDhM/GlVfT6tOubFzBYHRhK3nG19 3nnnDQkhHDYjhOX++9hjT1x++eUtQgjTG7CedmY2BHgEeJXYrfTfhrp/DawHfBTC3516zgFf/g7j 2oisv3TalTjnnHPOlQoPl5xzdTEpeeyQahUJM1sOOAu4TlU/SbGUA4lbqc5OsYYqJUOyXwSWBXqp 6utzXPIMsImZzTnnu1j1bEvsVtoZOAjYTVW/b4h718K6+JY4lxCRrIhcmmXF62EthLe+yoo8JCKl FLI755xzzqWiLO0CnHON0hfJY+c0i6jkCuIcqIvTKsDMWgLnAw+p6ttp1VEVM1sReJb4b/6mqvpx FZc9DTQjbk0r2kBvM2sDXAUcRQy0DlXVr4p1v7oSoRmwNvBA2rW4knGhwJmnk5MdgXch0w92+w06 isimIYSS2wbrnHPOOddQvHPJOVcXE5LHTqlWAZjZJsC+xBlHaW5fOhpYGjgnxRrmYmZrAi8D5cAm 8wiWAD4Cvga2LWItmwLvETu8+gK9SzFYSqwBtMQ7lxwgIq2zcNIZIJcCGxH/AN8D2XLYGOiZboXO Oeecc+nyziXnXF1UBBQd0yzCzDLAQOBtYHCKdbQlboW7S1U/SquOOZnZusBTwDfAttVtO1PVYGZP U4RwKenquhg4mThbqbeqflro+xTYekAeeDftQlxJ6JyDVjvM8eR2gAAB1gJea/iynHPOOedKg3cu Oefq4rPkcclUq4B/Ad2B41U1n2IdJwMLAxekWMNszGwzYBTwCbB5DecZPQ2skcxnKlQd6wFjgOOA 04nznko9WIIYLn0QAr+lXYgrCd8L5Oc8NnAskOyF+7qhC3LOOeecKyXeueScq4ufksfF0iog6Ra6 DLhPVV9NsY4OxBPqblDVkniDaWbbMesEtl1UtaYByXPE98rbAIPqWUMzoD/Qj7gVrruqvl+fNRvY esSOOOcIIfyUFXmoP+zRCbI7EIOlAyFXBpPKY4egc84559wCyzuXnHO1pqozk18ukmIZ/YE2wBkp 1gBxO1yeGHSlzsz2BB4jDsveoRbBEqr6E7HLaJt61qDAG8Rg6WKgZ2MKlkRoAXTD5y25SvJw1B/w yi7E/zPXHfgQvi2H7UII5SmX55xzzjmXKu9ccs7VR5s0bmpmqwAnAhel2S1kZssT5/perKqT06qj Uj0HA/8B7gf+VSkErI1ngEPNLFPbrYZmliV2cV0EfApsUGon59WQEk/O83DJ/S2EMFVENgd6EGcs fV0Oz3iw5JxzzjnnnUvOuboLwEIp3fsa4Fvg6pTuX+F84Bfg2pTrwMxOAO4EbgcOqGOwBHHuUgfi m+fa3H9l4AXgcuB6YN1GGiwBrAvkiNv5nPtbiN4IIdweQnjSgyXnnHPOucg7l5xzdZUDmptZmao2 2BssM/sHsCOwp6r+2VD3raKO1YGDgJNqs/WsCHUIcYvghcCVwJmqGuqx5KvAH8RT4+Z7UlpyYt9R wFXAd8BmqvpyPe6fGhFZCTgYttkDen0P/ZtD+CPtupxzzjnnnCt13rnknKurXPLYsaFumAyJvpbY IfPfhrrvPFwMfAXcmlYBSbB0FTFY6kf9gyVUdQbx5zvfuUtmthxxkPGNwGCgWyMOlvYU+GhhOHMd Rq6apf/SZfCRiKyadm3OOeecc86VOu9ccs7V1UygBbAcMWQpiqSbZF9gkaOOOqrdUUcdtWo2m923 viFKfZjZ+kAf4lyjGSnVkAVuBg4HjlPVGwq4/NPA5WbWqqrusCTUOpC4/e1XoLeqPl3A+zcoEWmX gcF7QOYukIXI8RWwBSz2Rdxm2CvtGp1zzjnnnCtlHi455+pqBnF/SPRUAAAUd0lEQVSg93LFuoGI HAXc2KpVq9C2bdtwyy23lD311FPfT5w48bMQUsuWAC4FxgP3pHHzpIPrbmBPYsA1uMC3eIbYIbYp MWiqfO8lid1auwBDgBNUdWqB79/QdspDq+uYNURsOeA8yB4Im4lIxxDCpBTrc84555xzrqT5tjjn XF1NJw71XrYYiyfbkW7ae++9My+++GL22WefLbvzzjuZNGlSB+I2sFSY2VbA1kA/Vc3N7/oi3L8V 8Cixc2rPIgRLrL/++j9cf/31v+62887/yYg8IiK7iYiY2R7A+8BGwG6qelATCJYA2mQgLDrHk0tU +nqDVuOcc84551wj4+GSc66uZhDDpWJ1Lu3funXr3GmnnUbLli0BWH/99dlnn30y2Wz24CLds1rJ drDLgDeAx1K4/8LAE8CWwE6q+kih7yEincqnTx97z3/+00YnTlxuXdgZeGTLLbb4KITwEHEe05qq +r9C3ztFo/Igd1V6IhD3w5XBN8CEdMpyzjnnnHOucfBwyTlXVxWzeIoVLrVbdNFFQ4sWLWZ7smPH juRyuYVFRIp03+rsBqwPnFXsmU8isoSIHCIiR4jI8ma2GPAc0B3YVlWfKsp94ZLFYfFPQpBHgdGQ vQkYOWrUKkOGDDkf2ENVfyzGvdMSQvhQ4K6+EA4EBgCbQf6/QDmcHkJo8A4155xzzjnnGhNJeW6J c66RMrPRxKDjbVXtUej1RWQv4IH77ruPrl27ApDL5TjggAPy48ePf728vHzjQt+zOmZWBowFvlbV bYt5LxE5VuLMo4q5eOGf++//0+mnny4i0ltVx9T3HkkXVmtgsYqPXC636Prdu99zXj5f1q/StXmg I5T/AANDCKfW996lSESywInN4Jg8dBR4txwuDiEMT7s255xzzjnnSp0P9HbO1ZqIZI888sj2U6dO lZ49e66kqgW/x7Bhw8aecsopM4866qhm++67L0sssQRDhw7NmxkhhHMKfsP5OwBYnXhKWtGIyMbA v48BLgCaA9eAnHfPPR0++OCDk9566625giUza04MiBalUlg0n88XTZb/WyaTQTIZmuXzs9cENIu/ zBbqdZaapDtpQPLhnHPOOeecqwXvXHLO1YqI7FAGj5b/nTdAFr7LwVohhIJslzKzFYHnf/755xk7 7LDD67///vvu+Xy+VTabfTOXy/ULITxbiPvUop6WwEfAm6q6ZzHvJSKDV4L9PoayyvuWNxcJk1ZY 4dv/PvbYy8wdFs1r4PRUYAowudLHlORjIeKWxi7AGsSg6bsD99//r6ljxy77dgiZ9skiDwD7xF9u FUIYWbAX65xzzjnnnGsSvHPJOVdjItKqDB5bBbL/AZQ41foIWCoXBz2vUd97mNkKwChgevv27Tef Nm3atyJyEJAtLy+fWd/16+goYBmgf7FvlIFl154jWAJYOwSZ8McfHYAOxHDoM2YPjOYMkH5W1XL4 ewvcSsRT7rYhdmG1A34DngcGAc8C4995770uWXhtFWi9B5R9TZwgnoGH8/H3xTnnnHPOOedm451L zrkaE5GLgX7vAWtVev4yYuqSh6VDCJPqur6ZdSaGHTOBzVX1m7pXWxjJCW0TgMdU9bBi3UeE9sAh cMw5bbl1ka/I0Tb52kxgdSifAP/Nh7BPTdYzsyWIp8ptnXx0AsqB14lB0rPETqy5AjsRWQE4pRnL /StPm79yfHAWcEcIoby+r9M555xzzjnX9HjnknOuNro0A7rO8eQGxKHPxJlEdQqXzKwTsTOmHNii FIKlxMnAwsQRSAUnQlfgOGB/oAyOePx3btluC2h2FmRbAtdCfgIQ4Op5rWNmrYFNmRUmdav4EvAo MUx6UVV/nV9NIYSJwLEiLAYsGQK31uMlOuecc84555o4D5ecc7XxxkzY/SVgs0pPPk2c9JyDd+qy qJktT+xYyhODpa/rW2ghmFkH4BTgRlX9qlDrilAG7EIMlXoB3xIbwG4Lodv3IvkNxsIte8LaAGUw IcBxIYS3KtVWBqzHrDBpI+IcrG+AZ4CrgJGqWudOMuAXYNV6fL9zzjnnnHNuAeDb4pxzNSYi2TL4 bTFoeTWxg+kxYktPHl4NIWxc2zXNbDnivCaIW+G+LFzF9WNm1wCHASuq6k/1XU+ExYHDgaOJw7Rf Af4NPBICVW1P60T8nwATxo0bB7Aas8KkLYC2wDRgJLO2un2sqgX5h12EK4DdQ2DlQqznnHPOOeec a5q8c8k5V2MhhJyI9PwJRh4QTyojAyy7/PJTv/zyyy1ru56ZLUvsWBJKL1haDugLXFrfYEmE7sQu pX2Tp+4D/h1C9Z1e48aN+4u41e0cYqC0DHEE0yvAlcQw6e2Kwd1FMA3+Hv3knHPOOeecc1XycMk5 VyshhPeAxURkEzjrksU6HLDW8OG5z1R1Rm3WqRQsZYnB0hdFKLc+ziOGK9fW5ZtFaAbsTgyVNgK+ TNa8IwSqDKuS4eG9mNWdtGbypfeA+4lh0kuq+ntdaqqDX4BFGuhezjnnnHPOuUbKwyXnXJ2EEF4W 4YHJk8PGf/01ftnafK+ZLUMc3t2MGCx9Xowa68rMugAHAyfXZAB2ZSIsBRwBHAV0JL7OPsCwEJit w8jMmhHnoVeESRsQ/13+kjg36WLi3KQf6vWC6u4XoLkILUNgeko1OOecc84550qch0vOufp4N5+X 7MSJLZZs3txa1KR7ycyWJgYuLYjB0sSiV1l7FwFfA7fU5GIRhBgMHQfsSdy6djdwQwhYxXVmJsRu pK2BrYDNgTbAz8S5SccRu5M+K9TcpHr6JXlcBDxccs4555xzzlXNwyXnXH2MA/jww5asttr0ZYAJ 1V1sZhWdPK2IwVK116fBzNYD9gAOnl9YJkILYG9iKLQe8fWfCdwVAj8n6y1LDJIqupOWAmYALwOX EMOkd1Q1V5QXVD/Tkse2wPdpFuKcc84555wrXR4uOefqLAR+bd48/8VHH7XsBCxLNeFSpWCpNTFY +qyByqytS4HxxM6jKomwLHHb2xFAB+BpYCfgyXHjrA2wudnfYVIXIABjgMHEMOkVVf2zmC+iQCp3 LjnnnHPOOedclTxccs7VSwjyThIuLTeva8xsKeK2r4WBXqr6aUPVVxtmtiWwDdBnzk6iZOvbJsQu pT7An8Cgzp1n3Dps2CeLEYOkfkAP4iF6E4hB0rnAqPqeOJcSD5ecc84555xz8+XhknOuXsrLZcyH H7bcJZ+vOlwysyWJwdIilGCwJCJZoFPLli1/Gz169GXAm8D/Zn2dVsB+xFCpm0j4uHfvX64655xv f23bNr8p8AawEDAZeA64E3iuFLf81YGHS84555xzzrn58nDJOVdf706bViaffdaiy1przf4FM1uC GCy1A7ZQ1U9SqG+eRGT/MriiHJaePn06Rx52GNvvtNP+/fr1CyJ0Bo4GDuvY8a/222//y7g99pjy /DLLzFxThDOJA65fBM4ndii9p6r51F5MgYnICpA9uxlLAb/dJPJLV2BACOG3tGtzzjnnnHPOlRYJ oRQOJHLONVYiLA98cdFFX7/Rv/+yPSueN7MOxBlLixGDpQ/TqrEqIrIL8L89gEOA74CLMpnwVb7Z lLaLfvlW9+4t/r+9uw+5u6zjOP65zn2mzWxpU8SEcImReEshJYlON6UHCBoFJUqSFggKVj6Q/yQp FGX0NHuS1GxBYxlOBSWyqFyQf2jZrFliaUtKsvJhrpntvs/VH+eWxpwrvqLnbL5e/5xzX4cD37/O DW+u6/q99YQTts6tXLll29Kl8wckGSW5K+OQ9KMkd8zOzu6VT1Brrb12mNx5YLLk/cnw8SRrk9F8 ctdcclLv/X8+FRAAAHjpsHMJeL4eWrx49PSDD+77mmcWFsLSj5MclPHl3VMVlpJkmFy6PBldnwza wtrJo1E7Mk8vPe+8r7z9tNPel9EomweD/DDjmPTT2dnZxyY48ovp4wclS36TDJcuLJyTDI4f3yd1 WpJvT3A2AABgyti5BHuA1triJO9NclSSB5Os671v2f23XhyttaP32+/0O/YdbNr/ia333HjEkUd+ Z/369ZclOSTjsPTbCY+4S4PWtq9OhufvtP6GwUyfP+r1t69bt+4Ds7Ozf5rIcBO2T2uPXJgc/Jmd 1o9L5u9Mru+9nzGRwQAAgKk0mPQAwO611l43TH6fZM2rk4sGyVUzyebW2nFTMNspg+TuV267fv9V W+9pRyer7r///huuueaaZRkfhZvKsJQkM8kjv95p7Z9J/jCaH23atOknL9WwtODpJ3da6Em2jF/2 yqOAAABAnbgEU26YrD08OeS+JH9OFm1O2rHJK4bJ+oUnnU1Ea60Nk6tOTGYeyHy7LsnGZOaCJF9e vXrxMccc8/dJzfb/mEu+9s2kfzPJ9iQPJzkr6dvGAWXNRIebsO3J2m8l8xt3WFuT5L7xUervTWYq AABgWjkWB1OstXZUkntvSrJqh/U7M778JvnS1clHHsg4FLeF153f7+6z5/Gdu5Ykb37HLUneucNs j2Z8g3eSs3rvUxtpWmuLBsmaUXL6MOlzSRskT42SM3vvN0x6vklqrR0wTDbMJ7PLk/wjGW1KZlqy pidnd/84AACAHbjQG6bbq5Jk2U6L//374DMyPqY0ynjHzWgX71+gzwaLk3Fp2rWZ5/5oCvTetyc5 o7X26bnk5CRbRsnNvfcnJj3bpPXeH2+tvSXJmRuStyV5Ksl3e3KLsAQAAOzMziWYYq21JTPJXy9K XnbFDuurk1yQ9J4s671vntBsbZjcd0JyxA+Swb4Z16eLk3wxw/T88d7ksEuT3NR7RpOYEQAAgBee O5dgivXet8wnV3w2ydlJ1iY5P8mF445z7aTC0sJsfS4592fJ/LJk7kNJ3pjMfyFJz5u+mhz2lyQ3 JLm7tbynNb83AAAAeyM7l2DKtdZakg8Pk0vmkkOHyaNzyZVJPjXuOxOfbzbJRxclx84nm0fJ13vv t40/y/Ikn0hyapKNSS7PeCeTHx4AAIC9hLgEe4iFyPTyJNt673vUMbPWclLGkemUJL/KODLdLDIB AADs+RxTgT1EH9u6p4WlJOk9G3rPqUlWJHksyY1JftFaVrW2mzvBAQAAmHriEvCi6T23955TkqxM siXJTRlHpnc9E5laa4e21i5rrd3aWruutXbiJGcGAABg9xyLAyamtazI+IjcSUl+mVx97UzO+eQ+ yZJTk5l7k7kHkmGSi3vvn5/osAAAAOySuARM1MKOpRVJLh9k5fIjsiE/zygHZfxIvI8l+VwySnJ4 7/2hCY4KAADALohLwFRobcmByZOPXpvkgzusb01yYDKaSy7ovV85ofEAAAB4Du5cAqbEk4uSZL+d VvfJ+FzcwlsAAACmjLgETIu/DZONVyajf++w+I0k/xr/Vn1/QnMBAACwG47FAVOjtbZikNx2eNLe nQx/l4xuHYelq3rv5056PgAAAJ5NXAKmSmvt2JZcsig5fpQ8PDfevHRd73006dkAAAB4NnEJAAAA gDJ3LgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAA UCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQ Ji4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAm LgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYu AQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4B AAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEA AABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAAAFAmLgEAAABQJi4BAAAAUCYuAQAA 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> <![CDATA[Exploring convolutional neural networks with DL4J]]> http://brooksandrew.github.io/simpleblog/articles/convolutional-neural-network-training-with-dl4j 2016-04-14T00:00:00+00:00 2016-04-14T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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">=&gt;</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">&lt;-</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">&lt;-</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">&amp;</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">&amp;</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">&amp;</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">=&gt;</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">&gt;</span> <span class="n">h</span> <span class="k">=&gt;</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">&lt;</span> <span class="n">h</span> <span class="k">=&gt;</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">=&gt;</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 -&gt; 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">=&gt;</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">=&gt;</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">=&gt;</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">=&gt;</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 -&gt; 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">=&gt;</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">=&gt;</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">=&gt;</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 -&gt; bizID)</li> <li><strong>dataMap</strong> (imgID -&gt; img data)</li> <li><strong>labMap</strong> (bizID -&gt; 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">=&gt;</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">=&gt;</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">-&gt;</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">=&gt;</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">-&gt;</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">=&gt;</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">-&gt;</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">=&gt;</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 -&gt; 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">=&gt;</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">-&gt;</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">=&gt;</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">&lt;-</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">&amp;&amp;</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">&lt;-</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">=&gt;</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">=&gt;</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">=&gt;</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">=&gt;</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">=&gt;</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">=&gt;</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">&lt;-</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> <![CDATA[Managing managed libraries with Scala and Eclipse]]> http://brooksandrew.github.io/simpleblog/articles/managing-managed-dependencies-with-scala-and-eclipse 2015-12-29T00:00:00+00:00 2015-12-29T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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">&gt;</span> sbt <span class="o">&gt;</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 />    =&gt; click “Build Path”<br />    =&gt; click “Configure Build Path”<br />    =&gt; 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> <![CDATA[Interactive association rules exploration app]]> http://brooksandrew.github.io/simpleblog/articles/association-rules-explore-app 2015-11-30T00:00:00+00:00 2015-11-30T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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> <![CDATA[Association rule analysis beyond transaction data]]> http://brooksandrew.github.io/simpleblog/articles/association-rules-beyond-transactional-data 2015-11-11T00:00:00+00:00 2015-11-11T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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&amp;q=%22Association+rules%22&amp;tz=Etc/GMT%2B5&amp;content=1&amp;cid=TIMESERIES_GRAPH_0&amp;export=5&amp;w=500&amp;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} ==&gt; {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&amp;rep=rep1&amp;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&amp;pg=PA297&amp;lpg=PA297&amp;dq=what+is+the+vast+search+effect&amp;source=bl&amp;ots=Sq0VDTxlEK&amp;sig=KADUdlw8nea73esrTQ5c8FImXKc&amp;hl=en&amp;sa=X&amp;ei=OCA-VaqBDMfUggTUwYDABg&amp;ved=0CD0Q6AEwBA#v=onepage&amp;q=what%2520is%2520the%2520vast%2520search%2520effect&amp;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> <![CDATA[Advanced tips and tricks with data.table]]> http://brooksandrew.github.io/simpleblog/articles/advanced-data-table 2015-08-31T00:00:00+00:00 2015-08-31T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@gmail.com <ul id="markdown-toc"> <li><a href="#1-data-structures--assignment" id="markdown-toc-1-data-structures--assignment">1. DATA STRUCTURES &amp; 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 &amp; 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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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] &lt;- 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] &lt;- 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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&amp;</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">&lt;-</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">&lt;-</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">&amp;</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">&amp;</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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> <![CDATA[Render reports directly from R scripts]]> http://brooksandrew.github.io/simpleblog/articles/render-reports-directly-from-R-scripts 2015-03-05T00:00:00+00:00 2015-03-05T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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 &amp; 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 &amp; bold*** </span><span class="w"> </span><span class="cd">#' * Skip lines with `#' &lt;br&gt;`</span><span class="w"> </span><span class="cd">#' * Keep comments in code, but hide from printing in report with `#' &lt;!-- this text will not print in report --&gt;` </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">#' &lt;br&gt;</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` &lt;!-- simply for illustrative purposes in the document--&gt;</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">#' &lt;br&gt;</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">#' &lt;br&gt;</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">#' &lt;br&gt;</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">#' &lt;br&gt;</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">#' &lt;br&gt;</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">&lt;-</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">&lt;-</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">#' &lt;br&gt; </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">#' &lt;br&gt;</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">&lt;-</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">&lt;-</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">#' &lt;br&gt;</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">&lt;-</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> <![CDATA[Blogging with Jekyll and R Markdown using knitr]]> http://brooksandrew.github.io/simpleblog/articles/blogging-with-r-markdown-and-jekyll-using-knitr 2015-01-25T00:00:00+00:00 2015-01-25T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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 ==&gt; 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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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 &amp; 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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&amp;&amp;</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">&lt;-</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">&lt;-</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> <![CDATA[Latent Dirichlet Allocation - under the hood]]> http://brooksandrew.github.io/simpleblog/articles/latent-dirichlet-allocation-under-the-hood 2015-01-17T00:00:00+00:00 2015-01-17T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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, &amp; 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 &amp; 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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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=&gt;scatters document clusters</span><span class="w"> </span><span class="n">eta</span><span class="w"> </span><span class="o">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">'=&gt;'</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=&gt;2" ## [1] "doc:1 token:4 topic:1=&gt;2" ## [1] "doc:1 token:5 topic:2=&gt;1" ## [1] "doc:1 token:6 topic:2=&gt;1" ## [1] "doc:2 token:1 topic:1=&gt;2" ## [1] "doc:2 token:3 topic:2=&gt;1" ## [1] "doc:3 token:2 topic:1=&gt;2" ## [1] "doc:3 token:3 topic:1=&gt;2" ## [1] "doc:3 token:5 topic:2=&gt;1" ## [1] "doc:3 token:6 topic:2=&gt;1" ## [1] "doc:5 token:1 topic:2=&gt;1" ## [1] "doc:5 token:2 topic:2=&gt;1" ## [1] "doc:5 token:4 topic:1=&gt;2" ## [1] "doc:7 token:1 topic:1=&gt;2" ## [1] "doc:7 token:2 topic:2=&gt;1" ## [1] "doc:7 token:6 topic:1=&gt;2" ## [1] "doc:7 token:7 topic:1=&gt;2" ## [1] "doc:1 token:5 topic:1=&gt;2" ## [1] "doc:2 token:2 topic:2=&gt;1" ## [1] "doc:2 token:3 topic:1=&gt;2" ## [1] "doc:2 token:5 topic:1=&gt;2" ## [1] "doc:7 token:3 topic:1=&gt;2" ## [1] "doc:7 token:4 topic:1=&gt;2" ## [1] "doc:7 token:8 topic:1=&gt;2" ## [1] "doc:8 token:1 topic:2=&gt;1" ## [1] "doc:8 token:3 topic:2=&gt;1" ## [1] "doc:1 token:5 topic:2=&gt;1" ## [1] "doc:2 token:2 topic:1=&gt;2" ## [1] "doc:2 token:3 topic:2=&gt;1" ## [1] "doc:2 token:5 topic:2=&gt;1" ## [1] "doc:4 token:4 topic:2=&gt;1" ## [1] "doc:5 token:1 topic:1=&gt;2" ## [1] "doc:5 token:2 topic:1=&gt;2" ## [1] "doc:7 token:2 topic:1=&gt;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 &lt;- 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">&lt;-</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">&lt;-</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">&lt;-</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> <![CDATA[New York Times Article Search API to MongoDB]]> http://brooksandrew.github.io/simpleblog/articles/new-york-times-api-to-mongodb 2015-01-06T00:00:00+00:00 2015-01-06T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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">&amp;facet_field=source&amp;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">&lt;-</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&amp;facet_filter=true&amp;begin_date=20130105&amp;end_date=20130105&amp;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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">'&amp;'</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">&lt;-</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?&amp;begin_date=20130101&amp;end_date=20130102&amp;api-key=sample-key&amp;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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;=</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&gt;</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&gt;</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;</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">&lt;=</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">&lt;-</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">&lt;-</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">&amp;</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">&lt;-</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">&lt;-</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 &lt;- 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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&#8617;</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">&#8617;</a></p> </li> <li id="fn:3"> <p>Still working on the villa … <a href="#fnref:3" class="reversefootnote">&#8617;</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> <![CDATA[Scraping with Selenium]]> http://brooksandrew.github.io/simpleblog/articles/scraping-with-selenium 2014-12-11T00:00:00+00:00 2014-12-11T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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#!&amp;ntf=N&amp;ft=BAL_all&amp;msrV=advanced&amp;sortBy=FUND_MST_MSTAR_CTGY_NM&amp;pgNo=1">here</a>. 1,586 funds as of today in 80 conveniently paginated URLs. Each URL ends in <code class="highlighter-rouge">&amp;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">&lt;-</span><span class="w"> </span><span class="s1">'https://www.fidelity.com/fund-screener/evaluator.shtml#!&amp;ft=BAL_all&amp;ntf=N&amp;expand=%24FundType&amp;rsk=5'</span><span class="w"> </span><span class="n">page</span><span class="w"> </span><span class="o">&lt;-</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">&lt;-</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">&lt;-</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">&lt;tbody id="tbody"&gt;</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">&lt;-</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">&lt;-</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">&lt;-</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#!&amp;ntf=N&amp;ft=BAL_all&amp;msrV=advanced&amp;sortBy=FUND_MST_MSTAR_CTGY_NM&amp;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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&gt;</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> <![CDATA[DIY building an R package]]> http://brooksandrew.github.io/simpleblog/articles/personal-R-package 2014-11-20T00:00:00+00:00 2014-11-20T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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 &amp; 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 /> =&gt; Build<br /> =&gt; Configure Build Tools<br /> =&gt; Check box for “Generate Documentation with Roxygen”<br /> =&gt; Click “Configure”<br /> =&gt; 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> <![CDATA[Getting feet wet with AWS]]> http://brooksandrew.github.io/simpleblog/articles/getting-feet-wet-with-aws 2014-11-10T00:00:00+00:00 2014-11-10T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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> <![CDATA[Deploying Shiny apps with shinyapps.io]]> http://brooksandrew.github.io/simpleblog/articles/deploying-apps-with-shinyapps-io 2014-10-11T00:00:00+00:00 2014-10-11T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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> <![CDATA[Walking around DC with a camera]]> http://brooksandrew.github.io/simpleblog/articles/dc-night-photography-monuments 2014-10-05T00:00:00+00:00 2014-10-05T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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> <![CDATA[When Google Search fails, and when it doesn't]]> http://brooksandrew.github.io/simpleblog/articles/when-google-fails 2014-09-28T00:00:00+00:00 2014-09-28T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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">!#$%&amp;*+-/.,;:</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&amp;pg=PA85&amp;lpg=PA85&amp;dq=%22editing+lapse%22&amp;source=bl&amp;ots=xmq938KI5G&amp;sig=6EAvhXLUvJ0hN7ERVdHvuA6kKg4&amp;hl=en&amp;sa=X&amp;ei=0MwkVM_kINiiyAS7_oD4Cw&amp;ved=0CD8Q6AEwBg#v=onepage&amp;q=%22editing%20lapse%22&amp;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">&amp;</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> <![CDATA[How accurate is Next Bus IV: visualizing]]> http://brooksandrew.github.io/simpleblog/articles/nextbus4_viz 2014-09-18T00:00:00+00:00 2014-09-18T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;</span><span class="m">30</span><span class="p">]</span><span class="w"> </span><span class="o">&lt;-</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">&lt;</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">&lt;-</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> <![CDATA[How accurate is Next Bus III: getting the answers]]> http://brooksandrew.github.io/simpleblog/articles/nextbus3_analyze 2014-09-17T00:00:00+00:00 2014-09-17T00:00:00+00:00 andrew brooks http://brooksandrew.github.io/simpleblog andrewbrooksct@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">&lt;-</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">&lt;-</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">&lt;=</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;=</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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 (&lt;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">&lt;-</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">&lt;-</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">&lt;=</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;=</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">&lt;-</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">&gt;=</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">&lt;-</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">&lt;-</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">&lt;-</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">&lt;-</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>