<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rodolfo Ferro</title>
    <description>The latest articles on DEV Community by Rodolfo Ferro (@rodolfoferro).</description>
    <link>https://dev.to/rodolfoferro</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F16357%2F7a96a819-3add-402d-a5e3-a6bab64db75e.jpg</url>
      <title>DEV Community: Rodolfo Ferro</title>
      <link>https://dev.to/rodolfoferro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rodolfoferro"/>
    <language>en</language>
    <item>
      <title>Running Jupyter notebooks in parallel</title>
      <dc:creator>Rodolfo Ferro</dc:creator>
      <pubDate>Fri, 09 Sep 2022 20:09:54 +0000</pubDate>
      <link>https://dev.to/rodolfoferro/running-jupyter-notebooks-in-parallel-4f4</link>
      <guid>https://dev.to/rodolfoferro/running-jupyter-notebooks-in-parallel-4f4</guid>
      <description>&lt;p&gt;As we have shared with you before, there are &lt;a href="https://ploomber.io/blog/notebook-execution/" rel="noopener noreferrer"&gt;several tools to run Jupyter notebooks on our computer&lt;/a&gt;. Some of these tools include certain functionalities that, beyond just executing our notebooks from the start to the end, these functionalities allow us to take advantage of the computer's resources to even carry out parallel executions. In this post we will show you how you can run some notebooks in parallel and we will compare the execution times of some of these tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why run notebooks in parallel?
&lt;/h2&gt;

&lt;p&gt;First of all, we need to understand what advantages it has and in what cases it helps us to be able to run notebooks in parallel. Among some of the advantages that exist, we highlight the following: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We can run different tasks or processes simultaneously by using multiple computing resources during parallel notebook executions.&lt;/li&gt;
&lt;li&gt;Parallel notebook executions will allow us to save time, allowing general process executions to be carried out in less time by executing independent processes simultaneously (as mentioned in the previous point).&lt;/li&gt;
&lt;li&gt;Parallel notebook executions can generally help us to keep a more organized code structure because of the requirements to be able to perform those executions simultaneously.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now that we know some of the benefits, a natural interrogative would be to look for a practical use case where running notebooks in parallel would be useful, so let's take a look at a use case.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use case: Parallelizing ML model training
&lt;/h3&gt;

&lt;p&gt;Let's imagine that we are working on a data process in which the obtaining, cleaning and preparation of data has been previously carried out. We are now at a crucial point in our process: &lt;strong&gt;we need to fit a model (or more than one) to our data.&lt;/strong&gt; Ideally, we have an idea of ​​which models might work, however, what we would like to do is try different models (with different parameters) so that, based on the results obtained, we can choose the one that best fits our data.&lt;/p&gt;

&lt;p&gt;A first approach might be to work in a Jupyter notebook, running the entire code from the start to the end of the notebook, adding the corresponding code to load and prepare the data, and later to model and evaluate the results for that data. Then, a copy of the notebook would be created to test with another model, and so on until you have &lt;em&gt;n&lt;/em&gt; notebooks for the &lt;em&gt;n&lt;/em&gt; different models to be tested. The entire process would look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fan5ilpeqdce3uxnsjd86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fan5ilpeqdce3uxnsjd86.png" alt="Serial notebooks" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This process could be executed in parallel, since the notebooks are independent of each other and each one returns its own results. Furthermore, to add good code execution practices and a better work structure, since the data that enters a model is the same for each one, we can separate the data from the modeling and make our execution more efficient:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2mxftpz3nmob6ahompi0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2mxftpz3nmob6ahompi0.png" alt="Parallel notebooks" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Again, running model training from a notebook for each model can be done in parallel to solve our problem in this use case.&lt;/p&gt;

&lt;p&gt;As we have seen, running notebooks in parallel can be very useful, and even more so by adding a good work structure. Now it is time to know about some tools that will allow us to carry out these actions at a technical level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison of different tools
&lt;/h2&gt;

&lt;p&gt;Some of the &lt;a href="https://ploomber.io/blog/notebook-execution/" rel="noopener noreferrer"&gt;Jupyter notebook tools&lt;/a&gt; stand out for their versatility and simplicity of use to run an entire notebook, cell by cell. The extra benefits about some of these tools come when considering executions in parallel.&lt;/p&gt;

&lt;p&gt;Here we will share the results after testing and evaluating some of these tools. Note that to make this comparison fair, it takes into account the use of the same code for all executions and we also use Python's &lt;code&gt;time&lt;/code&gt; module to measure the execution time. The notebooks used for benchmarking can be found &lt;a href="https://github.com/h3abionet/african_microbiome_portal_data/tree/main/Notebooks" rel="noopener noreferrer"&gt;here&lt;/a&gt; and correspond to &lt;strong&gt;&lt;em&gt;the african_microbiome_portal_data&lt;/em&gt;&lt;/strong&gt; repository. Serial execution cases (each notebook sequentially) are evaluated first, followed by parallel notebook execution cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Papermill
&lt;/h3&gt;

&lt;p&gt;As a first option, we will use &lt;a href="https://github.com/nteract/papermill" rel="noopener noreferrer"&gt;Papermill&lt;/a&gt;, which has a Python API that allows us to run different notebooks using some functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This requires:
# pip install papermill
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;papermill&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pm&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nb&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*.ipynb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute_notebook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;input_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;output_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execution time: &lt;strong&gt;&lt;code&gt;1:58.79 total&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ploomber serial
&lt;/h3&gt;

&lt;p&gt;As a second option, we will use &lt;a href="https://github.com/ploomber/ploomber" rel="noopener noreferrer"&gt;Ploomber&lt;/a&gt; with serial execution, which also has a Python API that allows us to execute different notebooks using the &lt;code&gt;NotebookRunner&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This requires:
# pip install ploomber
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ploomber&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DAG&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ploomber.products&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ploomber.tasks&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;NotebookRunner&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ploomber.executors&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Parallel&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;iglob&lt;/span&gt;

&lt;span class="n"&gt;dag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DAG&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;iglob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*.ipynb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nc"&gt;NotebookRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;dag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;papermill_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;embedded&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;  &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;dag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;force&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execution time: &lt;strong&gt;&lt;code&gt;59.324 total&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Papermill with ploomber-engine
&lt;/h3&gt;

&lt;p&gt;As a third option we will use Papermill again, but now with the &lt;a href="https://github.com/ploomber/ploomber-engine" rel="noopener noreferrer"&gt;ploomber-engine&lt;/a&gt;, which adds debugging and profiling features to Papermill:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This requires:
# pip install papermill ploomber-engine
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;nb&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*.ipynb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute_notebook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;input_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;output_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;engine_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;embedded&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execution time: &lt;strong&gt;&lt;code&gt;51.256 total&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Ploomber in parallel (the fastest option!)
&lt;/h3&gt;

&lt;p&gt;Finally, as a fourth option we use Ploomber again but now with its parallel notebook execution feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This requires:
# pip install ploomber
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ploomber&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DAG&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ploomber.products&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ploomber.tasks&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;NotebookRunner&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ploomber.executors&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Parallel&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;iglob&lt;/span&gt;

&lt;span class="n"&gt;dag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DAG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;executor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Parallel&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;


&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;iglob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*.ipynb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nc"&gt;NotebookRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;dag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;papermill_params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;embedded&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;  &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;dag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;force&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Execution time: &lt;strong&gt;&lt;code&gt;25.440 total&lt;/code&gt;&lt;/strong&gt; (&lt;strong&gt;the fastest option!&lt;/strong&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As we could see, executing notebooks in parallel can be very useful because this allows us to carry out several independent processes at the same time and thus reduce processing time. To do so, there are different tools such as Papermill and Ploomber, which are similar in that each one has its Python API in order to be integrated into our workflows, but different in terms of performance as we have seen; being that the parallel executor of Ploomber allows the parallel execution of notebooks in record time. It should be noted that if you are more familiar with working with Papermill, ploomber-engine in its integration with Papermill gives it parallel execution capacity in a very good time too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Even more advantages using Ploomber: Ploomber Cloud
&lt;/h2&gt;

&lt;p&gt;Ploomber and plumber-engine can be run remotely in our servers via &lt;a href="https://ploomber.io/cloud/" rel="noopener noreferrer"&gt;Ploomber Cloud&lt;/a&gt;, so you don't need to worry about a robust infrastructure that can support your runs, we take care of it. You just need to prepare your pipelines with Ploomber and we do the magic for you!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you have a particular use case?&lt;/strong&gt; We'd love to hear what you're working on and help you. Send us a message through &lt;a href="http://ploomber.io/community" rel="noopener noreferrer"&gt;our Slack channel&lt;/a&gt; or drop an email to &lt;a href="//mailto:rodo@ploomber.io"&gt;rodo@ploomber.io&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ploomber.io/blog/notebook-execution/" rel="noopener noreferrer"&gt;Three Tools for Executing Jupyter Notebooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ploomber/ploomber" rel="noopener noreferrer"&gt;Ploomber Source Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.ploomber.io/en/stable/" rel="noopener noreferrer"&gt;Ploomber Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ploomber/ploomber-engine" rel="noopener noreferrer"&gt;Ploomber-engine Source Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nteract/papermill" rel="noopener noreferrer"&gt;Papermill Source Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://papermill.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;Papermill Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>datascience</category>
      <category>machinelearning</category>
      <category>jupyter</category>
      <category>python</category>
    </item>
    <item>
      <title>A simple linear regression with TensorFlow 2.0</title>
      <dc:creator>Rodolfo Ferro</dc:creator>
      <pubDate>Thu, 08 Sep 2022 23:54:17 +0000</pubDate>
      <link>https://dev.to/rodolfoferro/a-simple-linear-regression-with-tensorflow-20-1aap</link>
      <guid>https://dev.to/rodolfoferro/a-simple-linear-regression-with-tensorflow-20-1aap</guid>
      <description>&lt;h1&gt;
  
  
  Linear regression
&lt;/h1&gt;

&lt;p&gt;A very simple approach to perform a linear regression with a single neuron using Keras.&lt;/p&gt;

&lt;h3&gt;
  
  
  Package import
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tensorflow&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ggplot&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Random data generation
&lt;/h3&gt;

&lt;p&gt;We create our samples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;linspace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.,
       13., 14., 15., 16., 17., 18., 19., 20., 21., 22., 23., 24., 25.,
       26., 27., 28., 29., 30., 31., 32., 33., 34., 35., 36., 37., 38.,
       39., 40., 41., 42., 43., 44., 45., 46., 47., 48., 49., 50.])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And for each sample add some random noise for the $y$ value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;array([ 4.59333333, 10.1888939 ,  3.10342612,  3.78295369, 10.57957367,
        8.31186454, 11.97466834,  8.38350117, 14.58165746, 12.7179244 ,
       16.04800824, 16.04253531, 17.7570093 , 15.36504093, 23.32077078,
       19.38063338, 25.72030949, 20.81364232, 18.55875267, 25.1340618 ,
       28.48036   , 21.73467374, 30.81790828, 28.56736033, 28.83225669,
       28.18684725, 34.95836113, 29.90731219, 30.90521404, 38.67280311,
       33.28501437, 40.01292045, 33.16216509, 34.99748693, 35.87077378,
       35.66317699, 36.37898628, 42.26194454, 47.36216501, 45.62434907,
       46.47169133, 48.05329522, 45.83970327, 50.68483177, 53.01284414,
       54.96997999, 46.42993498, 50.41667051, 53.26256812, 58.97071734,
       55.3635401 ])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The generated data looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Generated  data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Funzi1xldsv3zh2yq81l9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Funzi1xldsv3zh2yq81l9.png" alt="png" width="368" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Modelling
&lt;/h3&gt;

&lt;p&gt;The model has just a single neuron that will model the linear equation $y = mx + b$.&lt;/p&gt;

&lt;p&gt;The trained weight will correspond to the slope $m$ of the equation and the bias to the intersection value $b$.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;mean_squared_error&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optimizers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 1)                 2         
=================================================================
Total params: 2
Trainable params: 2
Non-trainable params: 0
_________________________________________________________________
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We proceed to fit the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Epoch 1/200
2/2 [==============================] - 0s 4ms/step - loss: 653.8051
Epoch 2/200
2/2 [==============================] - 0s 2ms/step - loss: 399.1392
Epoch 3/200
2/2 [==============================] - 0s 2ms/step - loss: 205.5257
Epoch 4/200
2/2 [==============================] - 0s 2ms/step - loss: 83.4503
Epoch 5/200
2/2 [==============================] - 0s 2ms/step - loss: 23.8983
Epoch 6/200
2/2 [==============================] - 0s 2ms/step - loss: 14.8980
Epoch 7/200
2/2 [==============================] - 0s 2ms/step - loss: 30.8598
Epoch 8/200
2/2 [==============================] - 0s 2ms/step - loss: 53.7728
Epoch 9/200
2/2 [==============================] - 0s 2ms/step - loss: 69.0219
Epoch 10/200
2/2 [==============================] - 0s 2ms/step - loss: 70.0617
Epoch 11/200
2/2 [==============================] - 0s 2ms/step - loss: 58.6065
Epoch 12/200
2/2 [==============================] - 0s 2ms/step - loss: 43.6842
Epoch 13/200
2/2 [==============================] - 0s 2ms/step - loss: 26.3015
Epoch 14/200
2/2 [==============================] - 0s 2ms/step - loss: 15.8109
Epoch 15/200
2/2 [==============================] - 0s 1ms/step - loss: 12.0864
Epoch 16/200
2/2 [==============================] - 0s 2ms/step - loss: 13.2904
Epoch 17/200
2/2 [==============================] - 0s 2ms/step - loss: 17.2666
Epoch 18/200
2/2 [==============================] - 0s 2ms/step - loss: 20.2788
Epoch 19/200
2/2 [==============================] - 0s 1ms/step - loss: 21.0044
Epoch 20/200
2/2 [==============================] - 0s 2ms/step - loss: 19.3135
Epoch 21/200
2/2 [==============================] - 0s 2ms/step - loss: 16.5099
Epoch 22/200
2/2 [==============================] - 0s 1ms/step - loss: 13.8078
Epoch 23/200
2/2 [==============================] - 0s 1ms/step - loss: 12.4786
Epoch 24/200
2/2 [==============================] - 0s 1ms/step - loss: 11.5450
Epoch 25/200
2/2 [==============================] - 0s 2ms/step - loss: 12.2430
Epoch 26/200
2/2 [==============================] - 0s 2ms/step - loss: 12.6910
Epoch 27/200
2/2 [==============================] - 0s 2ms/step - loss: 13.0053
Epoch 28/200
2/2 [==============================] - 0s 1ms/step - loss: 12.8281
Epoch 29/200
2/2 [==============================] - 0s 1ms/step - loss: 12.4289
Epoch 30/200
2/2 [==============================] - 0s 1ms/step - loss: 11.6947
Epoch 31/200
2/2 [==============================] - 0s 1ms/step - loss: 11.3287
Epoch 32/200
2/2 [==============================] - 0s 2ms/step - loss: 11.3578
Epoch 33/200
2/2 [==============================] - 0s 1ms/step - loss: 11.3632
Epoch 34/200
2/2 [==============================] - 0s 1ms/step - loss: 11.5163
Epoch 35/200
2/2 [==============================] - 0s 1ms/step - loss: 11.5517
Epoch 36/200
2/2 [==============================] - 0s 2ms/step - loss: 11.4354
Epoch 37/200
2/2 [==============================] - 0s 2ms/step - loss: 11.2493
Epoch 38/200
2/2 [==============================] - 0s 2ms/step - loss: 11.0766
Epoch 39/200
2/2 [==============================] - 0s 2ms/step - loss: 11.0697
Epoch 40/200
2/2 [==============================] - 0s 2ms/step - loss: 10.9828
Epoch 41/200
2/2 [==============================] - 0s 1ms/step - loss: 11.0126
Epoch 42/200
2/2 [==============================] - 0s 1ms/step - loss: 11.0186
Epoch 43/200
2/2 [==============================] - 0s 1ms/step - loss: 10.9801
Epoch 44/200
2/2 [==============================] - 0s 1ms/step - loss: 10.9340
Epoch 45/200
2/2 [==============================] - 0s 1ms/step - loss: 10.7914
Epoch 46/200
2/2 [==============================] - 0s 2ms/step - loss: 10.7687
Epoch 47/200
2/2 [==============================] - 0s 2ms/step - loss: 10.6795
Epoch 48/200
2/2 [==============================] - 0s 2ms/step - loss: 10.6936
Epoch 49/200
2/2 [==============================] - 0s 1ms/step - loss: 10.6416
Epoch 50/200
2/2 [==============================] - 0s 1ms/step - loss: 10.6058
Epoch 51/200
2/2 [==============================] - 0s 1ms/step - loss: 10.5609
Epoch 52/200
2/2 [==============================] - 0s 1ms/step - loss: 10.5371
Epoch 53/200
2/2 [==============================] - 0s 1ms/step - loss: 10.4772
Epoch 54/200
2/2 [==============================] - 0s 3ms/step - loss: 10.4357
Epoch 55/200
2/2 [==============================] - 0s 1ms/step - loss: 10.4067
Epoch 56/200
2/2 [==============================] - 0s 2ms/step - loss: 10.3866
Epoch 57/200
2/2 [==============================] - 0s 2ms/step - loss: 10.3872
Epoch 58/200
2/2 [==============================] - 0s 1ms/step - loss: 10.3384
Epoch 59/200
2/2 [==============================] - 0s 2ms/step - loss: 10.3408
Epoch 60/200
2/2 [==============================] - 0s 1ms/step - loss: 10.3051
Epoch 61/200
2/2 [==============================] - 0s 1ms/step - loss: 10.2206
Epoch 62/200
2/2 [==============================] - 0s 1ms/step - loss: 10.1830
Epoch 63/200
2/2 [==============================] - 0s 2ms/step - loss: 10.2140
Epoch 64/200
2/2 [==============================] - 0s 2ms/step - loss: 10.1338
Epoch 65/200
2/2 [==============================] - 0s 1ms/step - loss: 10.1010
Epoch 66/200
2/2 [==============================] - 0s 1ms/step - loss: 10.0534
Epoch 67/200
2/2 [==============================] - 0s 2ms/step - loss: 10.0265
Epoch 68/200
2/2 [==============================] - 0s 1ms/step - loss: 9.9996
Epoch 69/200
2/2 [==============================] - 0s 1ms/step - loss: 9.9761
Epoch 70/200
2/2 [==============================] - 0s 1ms/step - loss: 9.9521
Epoch 71/200
2/2 [==============================] - 0s 2ms/step - loss: 9.9255
Epoch 72/200
2/2 [==============================] - 0s 1ms/step - loss: 9.8958
Epoch 73/200
2/2 [==============================] - 0s 4ms/step - loss: 9.8855
Epoch 74/200
2/2 [==============================] - 0s 2ms/step - loss: 9.8750
Epoch 75/200
2/2 [==============================] - 0s 2ms/step - loss: 9.8222
Epoch 76/200
2/2 [==============================] - 0s 2ms/step - loss: 9.7902
Epoch 77/200
2/2 [==============================] - 0s 2ms/step - loss: 9.7729
Epoch 78/200
2/2 [==============================] - 0s 2ms/step - loss: 9.7519
Epoch 79/200
2/2 [==============================] - 0s 2ms/step - loss: 9.7254
Epoch 80/200
2/2 [==============================] - 0s 2ms/step - loss: 9.7084
Epoch 81/200
2/2 [==============================] - 0s 2ms/step - loss: 9.6988
Epoch 82/200
2/2 [==============================] - 0s 2ms/step - loss: 9.6648
Epoch 83/200
2/2 [==============================] - 0s 2ms/step - loss: 9.6532
Epoch 84/200
2/2 [==============================] - 0s 2ms/step - loss: 9.6367
Epoch 85/200
2/2 [==============================] - 0s 2ms/step - loss: 9.6036
Epoch 86/200
2/2 [==============================] - 0s 2ms/step - loss: 9.6125
Epoch 87/200
2/2 [==============================] - 0s 2ms/step - loss: 9.5628
Epoch 88/200
2/2 [==============================] - 0s 2ms/step - loss: 9.5510
Epoch 89/200
2/2 [==============================] - 0s 2ms/step - loss: 9.5662
Epoch 90/200
2/2 [==============================] - 0s 2ms/step - loss: 9.5147
Epoch 91/200
2/2 [==============================] - 0s 2ms/step - loss: 9.5191
Epoch 92/200
2/2 [==============================] - 0s 1ms/step - loss: 9.5031
Epoch 93/200
2/2 [==============================] - 0s 1ms/step - loss: 9.4601
Epoch 94/200
2/2 [==============================] - 0s 2ms/step - loss: 9.4431
Epoch 95/200
2/2 [==============================] - 0s 2ms/step - loss: 9.4269
Epoch 96/200
2/2 [==============================] - 0s 2ms/step - loss: 9.4388
Epoch 97/200
2/2 [==============================] - 0s 2ms/step - loss: 9.3951
Epoch 98/200
2/2 [==============================] - 0s 2ms/step - loss: 9.4153
Epoch 99/200
2/2 [==============================] - 0s 1ms/step - loss: 9.3706
Epoch 100/200
2/2 [==============================] - 0s 1ms/step - loss: 9.3629
Epoch 101/200
2/2 [==============================] - 0s 4ms/step - loss: 9.3394
Epoch 102/200
2/2 [==============================] - 0s 2ms/step - loss: 9.3237
Epoch 103/200
2/2 [==============================] - 0s 2ms/step - loss: 9.3269
Epoch 104/200
2/2 [==============================] - 0s 2ms/step - loss: 9.3081
Epoch 105/200
2/2 [==============================] - 0s 2ms/step - loss: 9.2812
Epoch 106/200
2/2 [==============================] - 0s 2ms/step - loss: 9.2657
Epoch 107/200
2/2 [==============================] - 0s 2ms/step - loss: 9.2867
Epoch 108/200
2/2 [==============================] - 0s 2ms/step - loss: 9.2592
Epoch 109/200
2/2 [==============================] - 0s 2ms/step - loss: 9.2355
Epoch 110/200
2/2 [==============================] - 0s 2ms/step - loss: 9.2726
Epoch 111/200
2/2 [==============================] - 0s 2ms/step - loss: 9.2075
Epoch 112/200
2/2 [==============================] - 0s 2ms/step - loss: 9.2053
Epoch 113/200
2/2 [==============================] - 0s 1ms/step - loss: 9.1904
Epoch 114/200
2/2 [==============================] - 0s 2ms/step - loss: 9.1810
Epoch 115/200
2/2 [==============================] - 0s 1ms/step - loss: 9.1972
Epoch 116/200
2/2 [==============================] - 0s 2ms/step - loss: 9.1841
Epoch 117/200
2/2 [==============================] - 0s 2ms/step - loss: 9.1773
Epoch 118/200
2/2 [==============================] - 0s 2ms/step - loss: 9.1964
Epoch 119/200
2/2 [==============================] - 0s 2ms/step - loss: 9.1943
Epoch 120/200
2/2 [==============================] - 0s 1ms/step - loss: 9.1598
Epoch 121/200
2/2 [==============================] - 0s 1ms/step - loss: 9.1316
Epoch 122/200
2/2 [==============================] - 0s 1ms/step - loss: 9.1139
Epoch 123/200
2/2 [==============================] - 0s 2ms/step - loss: 9.1245
Epoch 124/200
2/2 [==============================] - 0s 2ms/step - loss: 9.1076
Epoch 125/200
2/2 [==============================] - 0s 1ms/step - loss: 9.0872
Epoch 126/200
2/2 [==============================] - 0s 1ms/step - loss: 9.1018
Epoch 127/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0746
Epoch 128/200
2/2 [==============================] - 0s 4ms/step - loss: 9.0583
Epoch 129/200
2/2 [==============================] - 0s 2ms/step - loss: 9.1542
Epoch 130/200
2/2 [==============================] - 0s 2ms/step - loss: 9.1178
Epoch 131/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0470
Epoch 132/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0456
Epoch 133/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0353
Epoch 134/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0327
Epoch 135/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0275
Epoch 136/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0258
Epoch 137/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0356
Epoch 138/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0048
Epoch 139/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0333
Epoch 140/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0226
Epoch 141/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0144
Epoch 142/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0049
Epoch 143/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9832
Epoch 144/200
2/2 [==============================] - 0s 1ms/step - loss: 8.9752
Epoch 145/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0019
Epoch 146/200
2/2 [==============================] - 0s 1ms/step - loss: 9.0445
Epoch 147/200
2/2 [==============================] - 0s 4ms/step - loss: 8.9637
Epoch 148/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9682
Epoch 149/200
2/2 [==============================] - 0s 1ms/step - loss: 8.9812
Epoch 150/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9747
Epoch 151/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9863
Epoch 152/200
2/2 [==============================] - 0s 1ms/step - loss: 8.9593
Epoch 153/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9487
Epoch 154/200
2/2 [==============================] - 0s 1ms/step - loss: 8.9373
Epoch 155/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9841
Epoch 156/200
2/2 [==============================] - 0s 1ms/step - loss: 9.1398
Epoch 157/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0232
Epoch 158/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9637
Epoch 159/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9288
Epoch 160/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9415
Epoch 161/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9729
Epoch 162/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9534
Epoch 163/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9379
Epoch 164/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9516
Epoch 165/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9502
Epoch 166/200
2/2 [==============================] - 0s 2ms/step - loss: 9.0555
Epoch 167/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9306
Epoch 168/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9888
Epoch 169/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9640
Epoch 170/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9570
Epoch 171/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9267
Epoch 172/200
2/2 [==============================] - 0s 1ms/step - loss: 8.9134
Epoch 173/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9231
Epoch 174/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9520
Epoch 175/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9192
Epoch 176/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9162
Epoch 177/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9310
Epoch 178/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9030
Epoch 179/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9056
Epoch 180/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9027
Epoch 181/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9037
Epoch 182/200
2/2 [==============================] - 0s 2ms/step - loss: 8.8955
Epoch 183/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9029
Epoch 184/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9420
Epoch 185/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9328
Epoch 186/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9198
Epoch 187/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9586
Epoch 188/200
2/2 [==============================] - 0s 2ms/step - loss: 8.8910
Epoch 189/200
2/2 [==============================] - 0s 2ms/step - loss: 8.8981
Epoch 190/200
2/2 [==============================] - 0s 1ms/step - loss: 8.9199
Epoch 191/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9941
Epoch 192/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9090
Epoch 193/200
2/2 [==============================] - 0s 2ms/step - loss: 8.8938
Epoch 194/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9167
Epoch 195/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9029
Epoch 196/200
2/2 [==============================] - 0s 2ms/step - loss: 8.8897
Epoch 197/200
2/2 [==============================] - 0s 2ms/step - loss: 8.8889
Epoch 198/200
2/2 [==============================] - 0s 1ms/step - loss: 8.8904
Epoch 199/200
2/2 [==============================] - 0s 2ms/step - loss: 8.8932
Epoch 200/200
2/2 [==============================] - 0s 2ms/step - loss: 8.9216
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And we can plot the loss during the training.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;loss&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F382pbjgyfi444z1hdzcx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F382pbjgyfi444z1hdzcx.png" alt="png" width="375" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Model prediction
&lt;/h3&gt;

&lt;p&gt;There are two ways to generate the adjusted model. The first one will be simlpy to use the &lt;code&gt;.predict()&lt;/code&gt; method directly over the $x$ samples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;y_pred_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Generated data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_pred_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Predicted with model&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54kocswxgadfmztqqcpc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F54kocswxgadfmztqqcpc.png" alt="png" width="368" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second (and my favorite) way is to understand the guts inside the network and access the information to literally replicate the model.&lt;/p&gt;

&lt;p&gt;In this case we acces the first (and only) layer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;layer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;tensorflow.python.keras.layers.core.Dense at 0x7fe81910e828&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, we get and print the weights and biases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;weights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_weights&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;weights&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[array([[1.014319]], dtype=float32), array([4.2396894], dtype=float32)]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As we previously mentioned, the only weight will correspond to the slope and the bias to the intersection point. In order to replicate the linear equation we simply do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1.014319]
[4.2396894]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;y_pred_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;y_pred_params&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;array([ 4.23968935,  5.25400829,  6.26832724,  7.28264618,  8.29696512,
        9.31128407, 10.32560301, 11.33992195, 12.35424089, 13.36855984,
       14.38287878, 15.39719772, 16.41151667, 17.42583561, 18.44015455,
       19.4544735 , 20.46879244, 21.48311138, 22.49743032, 23.51174927,
       24.52606821, 25.54038715, 26.5547061 , 27.56902504, 28.58334398,
       29.59766293, 30.61198187, 31.62630081, 32.64061975, 33.6549387 ,
       34.66925764, 35.68357658, 36.69789553, 37.71221447, 38.72653341,
       39.74085236, 40.7551713 , 41.76949024, 42.78380919, 43.79812813,
       44.81244707, 45.82676601, 46.84108496, 47.8554039 , 48.86972284,
       49.88404179, 50.89836073, 51.91267967, 52.92699862, 53.94131756,
       54.9556365 ])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Generated data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_pred_params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Line fitted using parameter values&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;c&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1afjmuhp4bgnj25oefkz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1afjmuhp4bgnj25oefkz.png" alt="png" width="368" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to run the code above directly on Google Colab, please follow &lt;a href="https://colab.research.google.com/drive/1zC47uLBWbc2BOPlwxFAxENTxc7irVCND?usp=sharing" rel="noopener noreferrer"&gt;this link&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>tensorflow</category>
      <category>tutorial</category>
      <category>neuralnets</category>
    </item>
    <item>
      <title>Setup your Raspberry Pi Model B as Google Colab (Feb '19) to work with Tensorflow, Keras and OpenCV</title>
      <dc:creator>Rodolfo Ferro</dc:creator>
      <pubDate>Fri, 22 Mar 2019 17:26:14 +0000</pubDate>
      <link>https://dev.to/rodolfoferro/setup-your-raspberry-pi-model-b-as-google-colab-feb-19-to-work-with-tensorflow-keras-and-opencv-k6p</link>
      <guid>https://dev.to/rodolfoferro/setup-your-raspberry-pi-model-b-as-google-colab-feb-19-to-work-with-tensorflow-keras-and-opencv-k6p</guid>
      <description>&lt;p&gt;&lt;em&gt;Read this post in a better format, visit &lt;a href="https://rodolfoferro.xyz/Setup-your-Raspberry-Pi-as-Google-Colab/" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Description:&lt;/strong&gt; Setup OpenCV, Tensorflow and Keras as in Google Colab but in your Raspberry Pi, LOL.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivation (The struggle is real!)
&lt;/h2&gt;

&lt;p&gt;The other day I was happily training some neural networks I built with Keras using the Tensorflow backend on Google Colab. After I finished training like 4 or 5 different deep neural nets, I downloaded the trained models into my Raspberry Pi 3 Model B and realized that it was not able to compile any of these models... But Google Colab is able to compile them... &lt;/p&gt;

&lt;p&gt;It looked pretty weird to me at the beginning, but soon I noticed that it might be caused by the versions (of Python, Tensorflow and Keras) I was using. My Raspberry Pi was running Python 3.4 with Tensorflow 1.1.0 (compiled from scratch) and Keras 2.1.0, meanwhile Google Colab is running the following:&lt;/p&gt;

&lt;center&gt;
  &lt;img alt="Raspberry Pi" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frodolfoferro.xyz%2Fassets%2Fposts%2Fraspi_colab.png" width="800" height="635"&gt;
&lt;/center&gt;

&lt;p&gt;Anyway, after a couple of days trying some installations, after reading a lot of posts and Stack Overflow answers, I ended up solving everything and writing this blog post, which I hope it becomes very helpful for those having this struggle with these installations on their &lt;em&gt;Raspis&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's get started
&lt;/h2&gt;

&lt;p&gt;Before any installation, please be sure that you're working on &lt;a href="https://www.raspberrypi.org/downloads/raspbian/" rel="noopener noreferrer"&gt;Raspbian Stretch&lt;/a&gt;. You can download it from the official site and write the OS image into your memory card using &lt;a href="https://etcher.io/" rel="noopener noreferrer"&gt;Etcher&lt;/a&gt;. &lt;em&gt;(Yes, I totally broke my Raspbian Jesse before noticing that this will work fine and easy with Raspbian Stretch.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After doing the basic configuration on your Raspberry Pi (connecting it to Wi-Fi, enabling &lt;code&gt;ssh&lt;/code&gt; connection, and everything else), we are ready to start the installation of main packages.&lt;/p&gt;

&lt;p&gt;First of all, we will need to install &lt;code&gt;pip&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://bootstrap.pypa.io/get-pip.py
&lt;span class="nb"&gt;sudo &lt;/span&gt;python3 get-pip.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating a virtual environment
&lt;/h2&gt;

&lt;p&gt;We will be working on a local environment, so we will need to install &lt;code&gt;virtualenv&lt;/code&gt; and &lt;code&gt;virtualenvwrapper&lt;/code&gt;. To install them using &lt;code&gt;pip&lt;/code&gt; we just need to run in our terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;virtualenv virtualenvwrapper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to add the following lines to &lt;code&gt;~/.profile&lt;/code&gt;. Let's open it using nano by doing &lt;code&gt;sudo nano ~/.profile&lt;/code&gt; and append these lines to the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# virtualenv and virtualenvwrapper&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;WORKON_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.virtualenvs
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;VIRTUALENVWRAPPER_PYTHON&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/usr/bin/python3
&lt;span class="nb"&gt;source&lt;/span&gt; /usr/local/bin/virtualenvwrapper.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now close the file and save it (&lt;code&gt;CTRL+X&lt;/code&gt;, &lt;code&gt;Y&lt;/code&gt;, &lt;code&gt;Y&lt;/code&gt;), and we need to "source it" in our terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.profile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we have the virtual environment setup, we will create a new virtual environment named &lt;code&gt;tfk&lt;/code&gt; (which stands for Tensorflow &amp;amp; Keras). To do so, we simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mkvirtualenv tfk &lt;span class="nt"&gt;-p&lt;/span&gt; python3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should create a virtual environment with our Stretch's default Python 3 version (3.5.3) and it should be also activated. For any case, to activate/deactivate the virtual environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Activate environment after sourcing ~/.profile&lt;/span&gt;
workon tfk

&lt;span class="c"&gt;# Deactivate environment&lt;/span&gt;
deactivate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing OpenCV
&lt;/h2&gt;

&lt;p&gt;We will be installing OpenCV for any image pre-processing that will feed our convolutional neural networks (at least for me it results very useful).&lt;/p&gt;

&lt;p&gt;Let's install some dependencies before OpenCV:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;libcblas-dev libatlas-base-dev libjasper-dev 
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;libhdf5-dev libhdf5-serial-dev
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;libqtgui4 libqt4-test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing the dependencies, inside the virtual environment install OpenCV:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;opencv-contrib-python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should install OpenCV in the virtual environment, and we should be able to test it to verify the installation:&lt;/p&gt;

&lt;center&gt;
  &lt;img alt="OpenCV on Raspberry Pi" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frodolfoferro.xyz%2Fassets%2Fposts%2Fraspi_cv2.png" width="800" height="219"&gt;
&lt;/center&gt;

&lt;h2&gt;
  
  
  Installing Tensorflow and Keras
&lt;/h2&gt;

&lt;p&gt;To install Tensorflow in our Raspberry Pi, we will use &lt;code&gt;pip&lt;/code&gt; and install it directly from a &lt;code&gt;whl&lt;/code&gt; file that we will get from &lt;a href="https://github.com/lhelontra/tensorflow-on-arm/" rel="noopener noreferrer"&gt;https://github.com/lhelontra/tensorflow-on-arm&lt;/a&gt;. Specifically, we will be installing the &lt;a href="https://github.com/lhelontra/tensorflow-on-arm/releases/tag/v1.13.1" rel="noopener noreferrer"&gt;1.13.1&lt;/a&gt; version.&lt;/p&gt;

&lt;p&gt;To install Tensorflow directly from this source, we can simply run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;https://github.com/lhelontra/tensorflow-on-arm/releases/download/v1.13.1/tensorflow-1.13.1-cp35-none-linux_armv7l.whl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should have done the magic, at least with Tensorflow.&lt;/p&gt;

&lt;p&gt;Now, to proceed with Keras we will be installing some (more) dependencies and an update:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;libblas-dev liblapack-dev gfortran
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;python3-dev python3-setuptools
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install &lt;/span&gt;python3-numpy python3-scipy python3-h5py

&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally we can install Keras using &lt;code&gt;pip&lt;/code&gt; inside our virtual environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;keras
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should have done the magic, now with Keras.&lt;/p&gt;

&lt;p&gt;Let's verify our installations:&lt;/p&gt;

&lt;center&gt;
  &lt;img alt="Tensorflow and Keras on Raspberry Pi" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Frodolfoferro.xyz%2Fassets%2Fposts%2Fraspi_tfk.png" width="800" height="289"&gt;
&lt;/center&gt;

&lt;h2&gt;
  
  
  Conclusion and installation of other packages
&lt;/h2&gt;

&lt;p&gt;So far, we have installed some basic packages inside our virtual environment for Python 3, as the versions used in Google Colab (possibly a better name for the virtual environment should have been &lt;code&gt;gcolab&lt;/code&gt; or something...). This will allow us to compile and run models in our Raspberry Pi, that were trained in the cloud using Google Colab.&lt;/p&gt;

&lt;p&gt;To install other packages that are also useful we can keep using &lt;code&gt;pip&lt;/code&gt; inside our virtual environment, for instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# To install pandas, matplotlib, scikit-learn, flask, and requests&lt;/span&gt;
pip &lt;span class="nb"&gt;install &lt;/span&gt;pandas matplotlib scikit-learn flask requests
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I hope this post turns out to be helpful.&lt;/p&gt;

</description>
      <category>python</category>
      <category>raspberrypi</category>
      <category>tensorflow</category>
      <category>opencv</category>
    </item>
    <item>
      <title>Building a traffic fine scraper with Python</title>
      <dc:creator>Rodolfo Ferro</dc:creator>
      <pubDate>Mon, 07 Jan 2019 09:44:18 +0000</pubDate>
      <link>https://dev.to/rodolfoferro/building-a-traffic-fine-scraper-with-python-2j76</link>
      <guid>https://dev.to/rodolfoferro/building-a-traffic-fine-scraper-with-python-2j76</guid>
      <description>&lt;p&gt;&lt;small&gt;&lt;em&gt;To see this post in a better format, check &lt;a href="https://rodolfoferro.xyz/traffic-fine-scraper/" rel="noopener noreferrer"&gt;my blog&lt;/a&gt;.&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

&lt;h2&gt;&lt;span&gt;Motivation&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;The other day I was remembering that during my visit to Mexico City back in June '17 (for my participation on the first edition of the &lt;a href="https://rodolfoferro.xyz/pythondaymx/" rel="noopener noreferrer"&gt;PythonDay México&lt;/a&gt;), a &lt;a href="https://twitter.com/JMireles_" rel="noopener noreferrer"&gt;friend of mine&lt;/a&gt; hosted me at his house during my time there. The thing is that during my stay we were talking about building something that could be useful, so we decided to scrape a website in which car owners from Mexico City would be able to verify their traffic fines.&lt;/p&gt;

&lt;p&gt;The website is the following: &lt;a href="http://www.multasdetransito.com.mx/infracciones/df-distrito-federal" rel="noopener noreferrer"&gt;http://www.multasdetransito.com.mx/infracciones/df-distrito-federal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you may have noticed if you opened the site, it contains an input to write down the car plate from which you can search the traffic attached to that plate (if it has any).&lt;/p&gt;

&lt;p&gt;My friend told me that only a small group of Mexico City residents knew about that site, so it might be useful to create something in which they can consult this info in an easier way.&lt;/p&gt;

&lt;p&gt;After this, I was like: &lt;em&gt;"Dude, today I held a workshop on how to build a TwitterBot in 30 minutes for the PythonDay, what if we build a TwitterBot that inputs the plate in the site and then scrapes the info from it automatically?"&lt;/em&gt;. He said yes. With this, we built &lt;a href="https://twitter.com/MultaBot/with_replies" rel="noopener noreferrer"&gt;MultaBot&lt;/a&gt; a TwitterBot that used to read a car plate and scrape for its traffic fines.&lt;/p&gt;

&lt;p&gt;We started with this project as a private project, but the other day I was invited by the &lt;em&gt;&lt;a href="http://www.ddpg.ugto.mx/" rel="noopener noreferrer"&gt;Division of Law, Politics and Government&lt;/a&gt;&lt;/em&gt; of my university to give a tech talk about how automation can be useful for future jobs not for only people in tech industry, but also for politicians and lawyers. When I remembered about this, I thought that it would be a nice example, so I wanted to improve on its base and ended with this example script that now I want to share with you.&lt;/p&gt;

&lt;h2&gt;&lt;span&gt;Experimentation&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;I'll explain the whole code, so you'll understand what's happening every tep of the way. To begin, I'll import &lt;a href="https://selenium-python.readthedocs.io/" rel="noopener noreferrer"&gt;Selenium&lt;/a&gt; and the Python &lt;a href="https://docs.python.org/3/library/pprint.html" rel="noopener noreferrer"&gt;data pretty printer&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;selenium&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;
 &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pprint&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pprint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Selenium will allow us to automate the control of a web browser, so the idea will be to use it to automatically open the website, input the car plate and after the traffic fines are loaded, extract and parse them for the &lt;code&gt;pprint&lt;/code&gt; output.&lt;/p&gt;

&lt;p&gt;After this, I created a function to launch the browser and scrape the info off of the car plate. If &lt;code&gt;verbose&lt;/code&gt; is set to &lt;code&gt;True&lt;/code&gt;, the function will print the details of each traffic fine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="c1"&gt;# Browser opener function:
&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;launch_browser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;placa&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
 &lt;span class="mi"&gt;7&lt;/span&gt;     &lt;span class="c1"&gt;# Browser launch with chromedriver:
&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;     &lt;span class="n"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;webdriver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Chrome&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="mi"&gt;9&lt;/span&gt;
&lt;span class="mi"&gt;10&lt;/span&gt;     &lt;span class="c1"&gt;# Set url and open it on Chrome:
&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;     &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://www.multasdetransito.com.mx/infracciones/df-distrito-federal&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="mi"&gt;12&lt;/span&gt;     &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;13&lt;/span&gt;
&lt;span class="mi"&gt;14&lt;/span&gt;     &lt;span class="c1"&gt;# Search plate:
&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;     &lt;span class="n"&gt;multas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;busca_placa_df&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;placa&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;16&lt;/span&gt;
&lt;span class="mi"&gt;17&lt;/span&gt;     &lt;span class="c1"&gt;# Close browser:
&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;     &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;19&lt;/span&gt;     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;multas&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the function I set the url to be scraped, then I called function named &lt;code&gt;busca_placa_df&lt;/code&gt; (which means &lt;em&gt;search_plate_df&lt;/em&gt;, &lt;em&gt;df&lt;/em&gt; stands for Federal District in Spanish) and then I closed and quit the opened browser for this search.&lt;/p&gt;

&lt;p&gt;Then, I built the main function that inputs data and then scrapes the traffic fines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="mi"&gt;22&lt;/span&gt; &lt;span class="c1"&gt;# Plate finder function:
&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;busca_placa_df&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;placa&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="mi"&gt;24&lt;/span&gt;     &lt;span class="c1"&gt;# Find ID and input test data:
&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;     &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;plate&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;26&lt;/span&gt;     &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;plate&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send_keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;placa&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;27&lt;/span&gt;
&lt;span class="mi"&gt;28&lt;/span&gt;     &lt;span class="c1"&gt;# Look for button and click it:
&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;     &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element_by_xpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;//*[@id=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]/div[2]/div/a&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="mi"&gt;31&lt;/span&gt;     &lt;span class="c1"&gt;# Search result and return it:
&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;     &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_element_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secciones&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;33&lt;/span&gt;     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;INFRACCIONES&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="mi"&gt;34&lt;/span&gt;         &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;¡No tienes adeudos!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="mi"&gt;35&lt;/span&gt;     &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="mi"&gt;36&lt;/span&gt;         &lt;span class="n"&gt;resultado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;
&lt;span class="mi"&gt;37&lt;/span&gt;
&lt;span class="mi"&gt;38&lt;/span&gt;         &lt;span class="c1"&gt;# Search infraction tables:
&lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="mi"&gt;40&lt;/span&gt;             &lt;span class="n"&gt;infractions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_elements_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tablaDatos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;41&lt;/span&gt;             &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;infractions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="mi"&gt;42&lt;/span&gt;                 &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;infraction&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;infractions&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="mi"&gt;43&lt;/span&gt;                     &lt;span class="n"&gt;raw_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;infraction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;44&lt;/span&gt;                     &lt;span class="n"&gt;folio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fecha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="mi"&gt;45&lt;/span&gt;                     &lt;span class="n"&gt;situation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;span class="mi"&gt;46&lt;/span&gt;                     &lt;span class="n"&gt;motive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
&lt;span class="mi"&gt;47&lt;/span&gt;                     &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; , &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="mi"&gt;48&lt;/span&gt;                     &lt;span class="n"&gt;its&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="mi"&gt;49&lt;/span&gt;                     &lt;span class="n"&gt;art&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fac&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;par&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;its&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="mi"&gt;50&lt;/span&gt;                     &lt;span class="n"&gt;sanc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="mi"&gt;51&lt;/span&gt;
&lt;span class="mi"&gt;52&lt;/span&gt;                     &lt;span class="n"&gt;data_dict&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;53&lt;/span&gt;                         &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Folio&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;folio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;54&lt;/span&gt;                         &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Fecha de Infracción&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fecha&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;55&lt;/span&gt;                         &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Situación&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;situation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;56&lt;/span&gt;                         &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Motivo&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;motive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;57&lt;/span&gt;                         &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Fundamento&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="mi"&gt;58&lt;/span&gt;                             &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Artículo&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;art&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;59&lt;/span&gt;                             &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Facción&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fac&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;60&lt;/span&gt;                             &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Párrafo&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;par&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;61&lt;/span&gt;                             &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Inciso&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="mi"&gt;62&lt;/span&gt;                         &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="mi"&gt;63&lt;/span&gt;                         &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Sanción&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sanc&lt;/span&gt;
&lt;span class="mi"&gt;64&lt;/span&gt;                     &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="mi"&gt;65&lt;/span&gt;                     &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Infracción {}:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="mi"&gt;66&lt;/span&gt;                     &lt;span class="nf"&gt;pprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;67&lt;/span&gt;                     &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;68&lt;/span&gt; 
&lt;span class="mi"&gt;69&lt;/span&gt;     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resultado&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you see, in lines &lt;code&gt;24-26&lt;/code&gt; I clear the data in the input field with &lt;code&gt;id=plate&lt;/code&gt; from the HTML source, then input the car plate that I want to look for, and after this I look for the button by its XPath and click it (lines &lt;code&gt;28-29&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;I now want to know the results for the search, for this I look for the element with &lt;code&gt;id=secciones&lt;/code&gt; in the HTML of the response (lines &lt;code&gt;31-32&lt;/code&gt;) and first verify if it has any debts by looking if the resulting text is only &lt;code&gt;"INFRACCIONES"&lt;/code&gt;, if so I returned a message saying t has no debts (lines &lt;code&gt;33-34&lt;/code&gt;). In the other case, in lines &lt;code&gt;35-36&lt;/code&gt; I save the result with the text it contains (which specifies the number of traffic fines for the plate).&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;verbose&lt;/code&gt; flag is turned on, then the scraper will get all the info of each traffic fine (lines &lt;code&gt;38-40&lt;/code&gt;). For this, it will look for the element with &lt;code&gt;id=tablaDatos&lt;/code&gt; in the HTML, which contains all the info of each traffic fine and if it is not empty (line &lt;code&gt;41&lt;/code&gt;) it will iterate for each traffic fine and then extract all the info them (lines &lt;code&gt;42-50&lt;/code&gt;). I now build a dict with the response to serve it in a nice way using &lt;code&gt;pprint&lt;/code&gt; (lines &lt;code&gt;52-67&lt;/code&gt;) and return the result (line &lt;code&gt;69&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To test the script I just called the function &lt;code&gt;launch_browser&lt;/code&gt; with a demo car plate (that coincidently has 2 traffic fines) and print out the results (lines &lt;code&gt;72-74&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="mi"&gt;72&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="mi"&gt;73&lt;/span&gt;     &lt;span class="n"&gt;multas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;launch_browser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MKJ3940&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;74&lt;/span&gt;     &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;multas&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run this in a script, you'd get an output like this one (note that it prints the 2 traffic fines I mentioned 😝):&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyl4ut00hqsj2opmponc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvyl4ut00hqsj2opmponc.png" alt="Running the scraper" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;&lt;span&gt;Conclusion&lt;/span&gt;&lt;/h2&gt;

&lt;p&gt;At the beginning, what we thought would be a project just for fun to work together that night &lt;em&gt;–like a mini hackathon–&lt;/em&gt; ended up being a useful project that could be helpful for citizens in Mexico City.&lt;/p&gt;

&lt;p&gt;As you have seen, Python has tools that help to automate some things in very cool ways. I mean, if you run the script as it is provided, you should see a browser window to open automatically, then the text gets written alone in the input field and the results are shown by their own. &lt;strong&gt;Isn't this really awesome?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Please let me know what you build with Selenium and Python in the comments! 💻🐍🤙🏼&lt;/p&gt;

</description>
      <category>python</category>
      <category>scraping</category>
      <category>automation</category>
      <category>selenium</category>
    </item>
    <item>
      <title>DisAtBot - How I Built a Chatbot With Telegram And Python</title>
      <dc:creator>Rodolfo Ferro</dc:creator>
      <pubDate>Tue, 12 Dec 2017 23:13:04 +0000</pubDate>
      <link>https://dev.to/rodolfoferro/disatbot---how-i-built-a-chatbot-with-telegram-and-python-ajn</link>
      <guid>https://dev.to/rodolfoferro/disatbot---how-i-built-a-chatbot-with-telegram-and-python-ajn</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally guest posted by &lt;a href="https://pybit.es/author/rodolfo-ferro.html"&gt;Rodolfo Ferro&lt;/a&gt; on Sun 10 December 2017 in &lt;a href="https://pybit.es/category/tools.html"&gt;Tools&lt;/a&gt; @ &lt;a href="https://pybit.es/guest-telegram-python-chatbot.html"&gt;PyBites&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Rodolfo recently joined our &lt;a href="https://pybit.es/pages/challenges.html"&gt;Code Challenges&lt;/a&gt; and built Disaster Attention Bot (DisAtBot), a chatbot that helps people affected by natural disasters. In this article he shows how he built this bot with Telegram and (of course) Python. Show him some love because who knows, this could be a life saver (pun intended)! We are delighted to have him show this interesting project he submitted for &lt;a href="https://pybit.es/codechallenge43.html"&gt;Code Challenge 43&lt;/a&gt; which earned him a book on chatbots. /Rod please share ...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"¿Quién convocó a tanto muchacho, de dónde salió tanto voluntario, cómo fue que la sangre sobró en los hospitales, quién organizó las brigadas que dirigieron el tránsito de vehículos y de peatones por toda la zona afectada? No hubo ninguna convocatoria, no se hizo ningún llamado y todos acudieron"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"El jueves negro que cambió a México"&lt;/strong&gt; &lt;br&gt;
– Emilio Viale, 1985.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  A bit of context...
&lt;/h2&gt;

&lt;p&gt;Since September 19th, 2017 &lt;a href="https://en.wikipedia.org/wiki/2017_Central_Mexico_earthquake"&gt;Mexico has been hit by several earthquakes&lt;/a&gt; (&lt;a href="https://www.theguardian.com/world/live/2017/sep/20/mexico-city-earthquake-dozens-dead-powerful-quake-live-updates"&gt;The Guardian&lt;/a&gt;, &lt;a href="http://edition.cnn.com/2017/09/19/americas/mexico-earthquake/index.html"&gt;CNN&lt;/a&gt;). This made me wonder how we could better handle the reporting of damaged zones, people buried under the rubble of buildings, injured people in need of medical attention and other situations.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.verificado19s.org/"&gt;Verificado 19s&lt;/a&gt; was an immediate solution to follow up reports from social media and visualize the info on an online map. This required a lot of real-time (24/7) monitoring of posts on social media from people that were located in the affected areas. And that data was updated every ~10 minutes.&lt;/p&gt;

&lt;p&gt;So I started thinking about a way to optimize this process for future situations, not only for earthquakes, but for disaster situations in general. This incentivized me to work on this bot for Pybites &lt;a href="https://pybit.es/codechallenge43.html"&gt;Code Challenge 43 - Build a Chatbot Using Python&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  So DisAtBot was born
&lt;/h2&gt;

&lt;p&gt;DisAtBot automates the process of reporting incidents via messaging platforms, such as Telegram, Facebook Messenger, Twitter, etc. At this time it only supports Telegram, but I hope to expand it to other social media. If you'd like to contribute, see the Contribute section at the end.&lt;/p&gt;

&lt;p&gt;You can find DisAtBot at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Telegram: &lt;a href="https://t.me/DisAtBot"&gt;https://t.me/DisAtBot&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The official repo: &lt;a href="https://github.com/RodolfoFerro/DisAtBot"&gt;https://github.com/RodolfoFerro/DisAtBot&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The idea was to have a simple flow that allowed disaster reporting to be quick and easy. The general process of DisAtBot is as follows:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Fa5N6iKn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/RodolfoFerro/DisAtBot/master/imgs/flow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fa5N6iKn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/RodolfoFerro/DisAtBot/master/imgs/flow.png" alt="DisAtBot flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea is that any user can interact with the bot by selecting options from button menus in the conversation. This greatly speeds up incidents reporting.&lt;/p&gt;

&lt;p&gt;The next step would be opening a ticket which will be stored in a database, for the corresponding government instance/public organization/NGO/etc. to validate and send assistance. When no more help is needed, or the situation is under control, the ticket is closed.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;First clone &lt;a href="https://github.com/RodolfoFerro/DisAtBot"&gt;the repo&lt;/a&gt;. I used Python 3.6 and the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://pandas.pydata.org/"&gt;pandas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://geopandas.org/"&gt;geopandas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://geocoder.readthedocs.io/"&gt;geocoder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/maps/documentation/"&gt;googlemaps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://geojson.io/"&gt;geojsonio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://shapely.readthedocs.io/en/latest/"&gt;Shapely&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://python-telegram-bot.org/"&gt;python-telegram-bot&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To install all dependencies create &lt;a href="https://pybit.es/the-beauty-of-virtualenv.html"&gt;a virtual env&lt;/a&gt; and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then cd into the scripts folder and run the bot as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;python DisAtBot.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Design
&lt;/h2&gt;

&lt;p&gt;The focus of the initial version was the creation of menu buttons for an easy interaction with the user. The second –&lt;em&gt;and main&lt;/em&gt;– issue addressed was the conversation handler. A &lt;a href="https://en.wikipedia.org/wiki/Finite-state_machine"&gt;finite state machine&lt;/a&gt; was needed to preserve the desired flow and the responses for each state.&lt;/p&gt;

&lt;p&gt;I won’t go too deep into the explanation, but the code below will show how I tackled this.&lt;/p&gt;

&lt;p&gt;First of all, Telegram’s library has several methods to create button menus for user responses during the conversation flow. The idea is to create a Keyboard Markup to handle responses through buttons. This can either be Inline (buttons will appear in the conversation window) or as a Reply Keyboard (buttons will be displayed under the textbox to write messages).&lt;/p&gt;

&lt;p&gt;An example can be seen in the menu function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bot&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""
    Main menu function.
    This will display the options from the main menu.
    """&lt;/span&gt;
    &lt;span class="c1"&gt;# Create buttons to select language:
&lt;/span&gt;    &lt;span class="n"&gt;keyboard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;send_report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LANG&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;view_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LANG&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
                &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;view_faq&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LANG&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;view_about&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LANG&lt;/span&gt;&lt;span class="p"&gt;]]]&lt;/span&gt;

    &lt;span class="n"&gt;reply_markup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ReplyKeyboardMarkup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keyboard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                       &lt;span class="n"&gt;one_time_keyboard&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                                       &lt;span class="n"&gt;resize_keyboard&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_user&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Menu command requested by {}."&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reply_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main_menu&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LANG&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;reply_markup&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;reply_markup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SET_STAT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, the &lt;code&gt;keyboard&lt;/code&gt; variable is a list that contains the four buttons to be displayed. The layout can be set by nesting lists inside. In this case the &lt;strong&gt;Report&lt;/strong&gt; and &lt;strong&gt;Map&lt;/strong&gt; buttons are in the first row, while &lt;strong&gt;FAQ&lt;/strong&gt; and &lt;strong&gt;About&lt;/strong&gt; buttons are in the second row. This looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rBluG3K6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/RodolfoFerro/DisAtBot/master/imgs/screenshot_menu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rBluG3K6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://raw.githubusercontent.com/RodolfoFerro/DisAtBot/master/imgs/screenshot_menu.jpg" alt="Menu buttons screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Continuing with the code, a &lt;code&gt;ReplyMarkup&lt;/code&gt; is needed to handle the button responses. It specifies the layout of the menu: if only one menu is displayed, if it needs to be resized, etc.&lt;/p&gt;

&lt;p&gt;A logger is used for the bot, and the &lt;code&gt;update.message.reply(...)&lt;/code&gt; function is used to update the displayed text according to the response from the user. The &lt;code&gt;SET_STAT&lt;/code&gt; variable returned in this function is a (predefined) integer to return the state at that time, and to follow the flow.&lt;/p&gt;

&lt;p&gt;We now understand the menu creation and handling. The reason of using buttons is that we want a quick interaction because the bot is used in an emergency situation.&lt;/p&gt;

&lt;p&gt;The conversation handler - Telegram's &lt;code&gt;ConversationHandler&lt;/code&gt; - takes care of setting the state or step of the flow we're currently at, the finite state machine I mentioned earlier. Note that each state also needs to handle its respective information (button responses, etc.)&lt;/p&gt;

&lt;p&gt;This code shows the conversation handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="s"&gt;"""
    Main function.
    This function handles the conversation flow by setting
    states on each step of the flow. Each state has its own
    handler for the interaction with the user.
    """&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;LANG&lt;/span&gt;
    &lt;span class="c1"&gt;# Create the EventHandler and pass it your bot's token.
&lt;/span&gt;    &lt;span class="n"&gt;updater&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Updater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;telegram_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Get the dispatcher to register handlers:
&lt;/span&gt;    &lt;span class="n"&gt;dp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;updater&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dispatcher&lt;/span&gt;

    &lt;span class="c1"&gt;# Add conversation handler with predefined states:
&lt;/span&gt;    &lt;span class="n"&gt;conv_handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ConversationHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;entry_points&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CommandHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'start'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;

        &lt;span class="n"&gt;states&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;SET_LANG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;RegexHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'^(ES|EN)$'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;set_lang&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;

            &lt;span class="n"&gt;MENU&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CommandHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'menu'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;

            &lt;span class="n"&gt;SET_STAT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;RegexHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="s"&gt;'^({}|{}|{}|{})$'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="n"&gt;send_report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'ES'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;view_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'ES'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                            &lt;span class="n"&gt;view_faq&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'ES'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;view_about&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'ES'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                        &lt;span class="n"&gt;set_state&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                       &lt;span class="n"&gt;RegexHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="s"&gt;'^({}|{}|{}|{})$'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="n"&gt;send_report&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'EN'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;view_map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'EN'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                            &lt;span class="n"&gt;view_faq&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'EN'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;view_about&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'EN'&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                        &lt;span class="n"&gt;set_state&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;

            &lt;span class="n"&gt;LOCATION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MessageHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Filters&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                       &lt;span class="n"&gt;CommandHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'menu'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;

        &lt;span class="n"&gt;fallbacks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;CommandHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'cancel'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                   &lt;span class="n"&gt;CommandHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'help'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conv_handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Log all errors:
&lt;/span&gt;    &lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_error_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Start DisAtBot:
&lt;/span&gt;    &lt;span class="n"&gt;updater&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_polling&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Run the bot until the user presses Ctrl-C or the process
&lt;/span&gt;    &lt;span class="c1"&gt;# receives SIGINT, SIGTERM or SIGABRT:
&lt;/span&gt;    &lt;span class="n"&gt;updater&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It might seem a bit confusing at first, but it boils down to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The conversation handler has the states of the flow. &lt;/li&gt;
&lt;li&gt;It also has entry points (such as the &lt;code&gt;start&lt;/code&gt; function), and fallbacks (such as the &lt;code&gt;cancel&lt;/code&gt; and &lt;code&gt;help&lt;/code&gt; functions). &lt;/li&gt;
&lt;li&gt;It also contains some error handlers. &lt;/li&gt;
&lt;li&gt;A global &lt;code&gt;LANG&lt;/code&gt; variable is used, since the implementation &lt;/li&gt;
&lt;li&gt;I forgot to mention - support interacting in English or Spanish! To support this I created dictionaries for each interaction in both languages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to check the full code of this bot, check out the scripts directory where you'll find the main script and the language dictionaries.&lt;/p&gt;

&lt;p&gt;Some other features implemented are geolocation handling and &lt;code&gt;About&lt;/code&gt; / &lt;code&gt;FAQ&lt;/code&gt; sections. But the best way to know about this project is by watching it in action (for a live demo go to 8:30):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://drive.google.com/file/d/1dOvF17AYKiic85HmzMjnK5Qza2Tg0PNw/preview"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GWympY3e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/7r4luug079vm8ysxduu4.png" alt="DisAtBot video preview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Future work
&lt;/h2&gt;

&lt;p&gt;For future development I am thinking about adding a map. The system already creates a GeoJSON file from the locations acquired.&lt;/p&gt;

&lt;p&gt;As mentioned I am considering expanding this to other platforms like Facebook Messenger and Twitter. Another good thing to add would be a website explaining the main use cases of the bot, maybe a wiki –&lt;em&gt;kinda&lt;/em&gt;– site?&lt;/p&gt;

&lt;p&gt;If you have any other ideas or suggestions feel free to &lt;a href="https://twitter.com/FerroRodolfo"&gt;contact me&lt;/a&gt; or:&lt;/p&gt;

&lt;h2&gt;
  
  
  Contribute
&lt;/h2&gt;

&lt;p&gt;If you're interested in contributing to this project, feel free to take a look at the repo's &lt;a href="https://github.com/RodolfoFerro/DisAtBot/blob/master/CONTRIBUTING.md"&gt;CONTRIBUTING&lt;/a&gt; file. I'd be very pleased if this project would grow out to something used in real life to alleviate the dramatic consequences of natural disaster, which always seem to hit when least expected.&lt;/p&gt;




&lt;p&gt;Keep Calm and Code in Python!&lt;br&gt;
– &lt;a href="https://pybit.es/pages/guests.html#rodolfoferro"&gt;Rod&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>bots</category>
      <category>chatbots</category>
      <category>pythontelegrambot</category>
    </item>
    <item>
      <title>Sentiment analysis on Trump's tweets using Python 🐍</title>
      <dc:creator>Rodolfo Ferro</dc:creator>
      <pubDate>Tue, 12 Sep 2017 03:51:41 +0000</pubDate>
      <link>https://dev.to/rodolfoferro/sentiment-analysis-on-trumpss-tweets-using-python-</link>
      <guid>https://dev.to/rodolfoferro/sentiment-analysis-on-trumpss-tweets-using-python-</guid>
      <description>

</description>
      <category>twitter</category>
      <category>python</category>
      <category>tweepy</category>
      <category>textblob</category>
    </item>
    <item>
      <title>Knight's tour solved with Python 🐍</title>
      <dc:creator>Rodolfo Ferro</dc:creator>
      <pubDate>Sat, 15 Apr 2017 11:58:17 +0000</pubDate>
      <link>https://dev.to/rodolfoferro/knights-tour-solved-with-python-</link>
      <guid>https://dev.to/rodolfoferro/knights-tour-solved-with-python-</guid>
      <description>

</description>
      <category>knightstour</category>
      <category>python</category>
      <category>pygame</category>
      <category>heuristic</category>
    </item>
    <item>
      <title>My @JuliaSetBot: A (python) bot that Tweets fractals. ðŸ¤–</title>
      <dc:creator>Rodolfo Ferro</dc:creator>
      <pubDate>Fri, 14 Apr 2017 08:46:29 +0000</pubDate>
      <link>https://dev.to/rodolfoferro/juliasetbot-</link>
      <guid>https://dev.to/rodolfoferro/juliasetbot-</guid>
      <description>&lt;p&gt;&lt;a href="https://www.python.org" rel="noopener noreferrer"&gt;Python&lt;/a&gt;Â is a languageÂ that can be easily learnt andÂ usedÂ for many things. A cool thing about Python is that many interesting stuff has already been developed. An example of this isÂ &lt;a href="http://www.tweepy.org" rel="noopener noreferrer"&gt;Tweepy&lt;/a&gt;, which is an easy-to-use Python library for accessing the Twitter API.&lt;/p&gt;

&lt;p&gt;I really like to tryÂ integrating different technologies, so I gave myself the task of trying to build a Twitter bot using Tweepy. Te result: I built a bot that everyday at 11:00 UTC (6:00 inÂ Mexico) it generates a random complex number, then it iterates it in a function in order to generate a Julia set, and finally the bot Tweets the fractal generated. You can check it out atÂ &lt;a href="https://twitter.com/JuliaSetBot" rel="noopener noreferrer"&gt;@JuliaSetBot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An example of what it does is embed here:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-852476953542225920-708" src="https://platform.twitter.com/embed/Tweet.html?id=852476953542225920"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-852476953542225920-708');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=852476953542225920&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Awesome right? ðŸ¤–&lt;/p&gt;

</description>
      <category>python</category>
      <category>tweepy</category>
      <category>bot</category>
      <category>fractals</category>
    </item>
    <item>
      <title>Hi, I'm Rod!</title>
      <dc:creator>Rodolfo Ferro</dc:creator>
      <pubDate>Fri, 14 Apr 2017 08:32:51 +0000</pubDate>
      <link>https://dev.to/rodolfoferro/hi-im-rodolfo-ferro</link>
      <guid>https://dev.to/rodolfoferro/hi-im-rodolfo-ferro</guid>
      <description>&lt;p&gt;I'm a math student, and a science &amp;amp; technology enthusiast. I have served as a Google Student Ambassador on 2014-2015. Right now, I'm on charge of a science section of a radio program at my university (&lt;a href="http://ugto.mx" rel="noopener noreferrer"&gt;University of Guanajuato&lt;/a&gt;), and I'm a team member in &lt;a href="http://clubesdeciencia.mx" rel="noopener noreferrer"&gt;CdeCMx&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I have been coding for 6 years, mostly in Python ðŸ’™, but I also use R and C/C++. I like to learn about what seems interesting to me, from the theory to &lt;a href="http://rodolfoferro.wordpress.com/2015/06/07/inestabilidad-de-electrones-en-dos-haces/" rel="noopener noreferrer"&gt;simulate particles interactions&lt;/a&gt; to the creation of &lt;a href="http://twitter.com/JuliaSetBot" rel="noopener noreferrer"&gt;bots that tweet fractals&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/FerroRodolfo" rel="noopener noreferrer"&gt;@FerroRodolfo&lt;/a&gt;, and see a bit more of what I like to do on my &lt;a href="https://rodolfoferro.wordpress.com" rel="noopener noreferrer"&gt;blog&lt;/a&gt; or my &lt;a href="https://github.com/RodolfoFerro" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
      <category>python</category>
      <category>science</category>
      <category>math</category>
    </item>
  </channel>
</rss>
