├── 1-01_Introduction to the Training.ipynb ├── 1-02_The Python Environment for Data Analysis.ipynb ├── 1-03_Data Manipulation.ipynb ├── 1-04_Visualisation.ipynb ├── 1-05_Modelling.ipynb ├── 1-06_More Packages.ipynb ├── Data ├── airquality.csv ├── mtcars.csv └── tips.csv ├── Exercises.ipynb ├── Python_for_R_Users.pdf ├── README.md ├── binder └── environment.yml └── img └── fig ├── CellModeCommand.png ├── CellModeEdit.png ├── HelpFile.png ├── jupyter1.png ├── jupyter2.png ├── jupyter3.png └── jupyter4.png /1-01_Introduction to the Training.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Overview" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "This course has been designed to introduce Python in a way that means you can quickly get started with data analysis, building on your R knowledge. This includes functions for importing, manipulating and visualising data as well as some basic statistical analysis. With the emphasis on using Python for these tasks there will be a number of features of Python that would be taught in a typical programming course that we will not cover, including some of Python's in-built objects and their methods, working with matrices and arrays in NumPy and conditional flow and function writing. Where appropriate the material includes notes for further reference." 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "# Format of Course Material" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "Items appearing in this material are sometimes given a special appearance to set them apart\n", 29 | "from regular text. Here is how a code example will look:" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 1, 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "data": { 39 | "text/plain": [ 40 | "3" 41 | ] 42 | }, 43 | "execution_count": 1, 44 | "metadata": {}, 45 | "output_type": "execute_result" 46 | } 47 | ], 48 | "source": [ 49 | "myvar = 1 + 2 # This is a comment\n", 50 | "myvar" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "The format of these code blocks emulates how the code would be run in an interactive Python\n", 58 | "console, with lines starting with the prompt `>>>` showing input lines of code, and those without\n", 59 | "the prompt displaying the outputs you would expect to be returned on screen." 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": {}, 65 | "source": [ 66 | "In addition to the code environments there are three text boxes which highlight Exercises, Tips\n", 67 | "& Tricks, as well as Warnings." 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": {}, 73 | "source": [ 74 | "**Exercise: An Example Exercise Box** \n", 75 | "\n", 76 | "This box will detail exercises to be performed during (or after) the training course, e.g.,\n", 77 | "\n", 78 | "1. Load mtcars dataset into a data frame.\n", 79 | "2. Find the mean values of each column." 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": {}, 85 | "source": [ 86 | "**Tip: An Example Tip Box**\n", 87 | "\n", 88 | "These boxes will detail an additional feature of Python or a helpful shortcut based on user experience." 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "metadata": {}, 94 | "source": [ 95 | "**Warning: An Example Warning Box** \n", 96 | "\n", 97 | "These boxes will detail a warning, typically describing non-intuitive aspects of the Python language or common pitfalls that are encountered." 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": {}, 103 | "source": [ 104 | "## Course Script and Exercise Answers" 105 | ] 106 | }, 107 | { 108 | "cell_type": "markdown", 109 | "metadata": {}, 110 | "source": [ 111 | "A great deal of code will be executed within Python during the delivery of this training. This includes the answers to each exercise, as well as other code written to answer questions that arise. Following the course, you will be sent a notebook containing all the code that was executed." 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "# What is Python?" 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "Python is a powerful general purpose programming language with widespread use in many\n", 126 | "applications domains. Python is open source and free\n", 127 | "to use (even for commercial products), and available for all major operating systems." 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "The principal author of Python Guido van Rossum, who began work on it in the 1980’s, played a central role in its development as president of the Python Software Foundation (PSF) until the summer of 2018. In his absence, the non-profit organization will continue to be devoted to the Python programming language and its administration. Python has many contributors from all over the world, and the PSF is supported by many international sponsors." 135 | ] 136 | }, 137 | { 138 | "cell_type": "markdown", 139 | "metadata": {}, 140 | "source": [ 141 | "## Key Features" 142 | ] 143 | }, 144 | { 145 | "cell_type": "markdown", 146 | "metadata": {}, 147 | "source": [ 148 | "The main differentiating factors of the Python language can be described as follows:\n", 149 | "\n", 150 | "* At its core Python was designed for readability and clarity, and therefore has minimised the necessary syntax, making it easier to pick up and understand code you did not write.\n", 151 | "* Python comes with an extensive standard library, but also allows easy addition of custom libraries.\n", 152 | "\n", 153 | "Many ways exist to interface Python with other languages meaning that Python works well as 'glue' in many development applications. A few other advantages with working in Python are:\n", 154 | "\n", 155 | "* The multiple-purpose language allows for easier integration between your data science, data engineering and software development teams.\n", 156 | "* Python is multi-threaded making parallelisation easier.\n" 157 | ] 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "metadata": {}, 162 | "source": [ 163 | "## The Python Web Site" 164 | ] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": {}, 169 | "source": [ 170 | "There are many online Python resources, almost all of which can be reached via the main\n", 171 | "Python site: [http://www.python.org/](http://www.python.org/). From this site you can do many things, including:" 172 | ] 173 | }, 174 | { 175 | "cell_type": "markdown", 176 | "metadata": {}, 177 | "source": [ 178 | "* Download the latest copy of the core Python language.\n", 179 | "* Find links, source code and documentation to many additional Python libraries.\n", 180 | "* Find help on the use of Python in the online wiki.\n", 181 | "* Join the \"Python-Help\" mailing list.\n", 182 | "* Look for Python books and events." 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": {}, 188 | "source": [ 189 | "## Python Versions" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": {}, 195 | "source": [ 196 | "The most current version of Python is 3.6 and is the focus of this course. The rest of this section\n", 197 | "elaborates more on the history of Python versions and why this distinction is important." 198 | ] 199 | }, 200 | { 201 | "cell_type": "markdown", 202 | "metadata": {}, 203 | "source": [ 204 | "In 2010 Python 3.0 was released, and introduced a range of improvements to clean up the base\n", 205 | "language and improve its efficiency. However, some of these changes required fundamental\n", 206 | "changes under the hood, and the decision was made to focus on new features and future\n", 207 | "enhancements to the Python language, rather than patching them onto legacy code. For this\n", 208 | "reason, Python 3 is intentionally not backward-compatible with previous versions." 209 | ] 210 | }, 211 | { 212 | "cell_type": "markdown", 213 | "metadata": {}, 214 | "source": [ 215 | "This obviously has some knock-on effects, and even though the changes to syntax and usability\n", 216 | "of the language are minimal, it has resulted in a protracted effort to port over the vast amount\n", 217 | "of 3rd party libraries that have previously been written." 218 | ] 219 | }, 220 | { 221 | "cell_type": "markdown", 222 | "metadata": {}, 223 | "source": [ 224 | "Python 2.7.x is still the most widely used version mostly because of the concern over library\n", 225 | "compatibility mentioned above. However Python 2 is in its end of life stage (sunset in 2020), meaning that there will never be a Python 2.8 release as all future development of the language is now focused on Python 3." 226 | ] 227 | }, 228 | { 229 | "cell_type": "markdown", 230 | "metadata": {}, 231 | "source": [ 232 | "This course is taught using Python 3 as it has more consistent syntax for beginners to become\n", 233 | "familiar with, and will future proof any code that trainees end up writing after the course." 234 | ] 235 | }, 236 | { 237 | "cell_type": "markdown", 238 | "metadata": {}, 239 | "source": [ 240 | "**Tip: Python 3 Compatibility**\n", 241 | "\n", 242 | "A list of the top 360 Python packages and their compatibility with Python 3 is available from [http://py3readiness.org/](http://py3readiness.org/). Also, a detailed discussion of the differences between Python 2 and Python 3 can be found at [https://wiki.python.org/moin/Python2orPython3](https://wiki.python.org/moin/Python2orPython3) " 243 | ] 244 | }, 245 | { 246 | "cell_type": "markdown", 247 | "metadata": {}, 248 | "source": [ 249 | "## The Python Package Index (PyPI)" 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": {}, 255 | "source": [ 256 | "Similar to the R community, the Python community has actively produced many libraries of new classes and functions for Python (called packages), which extend the capabilities of Python in many directions. The Python Package Index (PyPI) is the main repository for these packages, and at the time of writing there are over 90,000 packages available to download." 257 | ] 258 | } 259 | ], 260 | "metadata": { 261 | "anaconda-cloud": {}, 262 | "kernelspec": { 263 | "display_name": "Python 3", 264 | "language": "python", 265 | "name": "python3" 266 | }, 267 | "language_info": { 268 | "codemirror_mode": { 269 | "name": "ipython", 270 | "version": 3 271 | }, 272 | "file_extension": ".py", 273 | "mimetype": "text/x-python", 274 | "name": "python", 275 | "nbconvert_exporter": "python", 276 | "pygments_lexer": "ipython3", 277 | "version": "3.6.6" 278 | }, 279 | "toc": { 280 | "colors": { 281 | "hover_highlight": "#DAA520", 282 | "navigate_num": "#000000", 283 | "navigate_text": "#333333", 284 | "running_highlight": "#FF0000", 285 | "selected_highlight": "#FFD700", 286 | "sidebar_border": "#EEEEEE", 287 | "wrapper_background": "#FFFFFF" 288 | }, 289 | "moveMenuLeft": true, 290 | "nav_menu": { 291 | "height": "216px", 292 | "width": "252px" 293 | }, 294 | "navigate_menu": true, 295 | "number_sections": false, 296 | "sideBar": true, 297 | "threshold": 4, 298 | "toc_cell": false, 299 | "toc_position": { 300 | "height": "603px", 301 | "left": "0px", 302 | "right": "1108px", 303 | "top": "107px", 304 | "width": "212px" 305 | }, 306 | "toc_section_display": "block", 307 | "toc_window_display": true, 308 | "widenNotebook": false 309 | } 310 | }, 311 | "nbformat": 4, 312 | "nbformat_minor": 2 313 | } 314 | -------------------------------------------------------------------------------- /1-02_The Python Environment for Data Analysis.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "One of the major hurdles in getting up and running with Python is the complexity of the installation\n", 8 | "process, as there are not only multiple versions of Python to consider, but packages must\n", 9 | "be downloaded and installed to the right location, and any dependencies between them must\n", 10 | "also be managed." 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "Fortunately, several Python distributions have been put together that work as a one stop installation of both Python and many of the extended libraries. " 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "# Installing the Anaconda Distribution" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "The Anaconda distribution is cross platform and comes with Python 2.7 or 3.6, as well as other tools and libraries such as Jupyter, Spyder, IPython, NumPy,\n", 32 | "SciPy, pandas, seaborn and matplotlib already configured." 33 | ] 34 | }, 35 | { 36 | "cell_type": "markdown", 37 | "metadata": {}, 38 | "source": [ 39 | "The fastest way to get up and running with Python is to download the Anaconda Python distribution\n", 40 | "from [https://www.anaconda.com/download](https://www.anaconda.com/download), and follow the installation instructions." 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "The default installation path for the Python 3 Anaconda distribution on Windows is:" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "```\n", 55 | " C:\\Users\\\\AppData\\Local\\Continuum\\Anaconda3\n", 56 | "```" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "# Jupyter Notebooks" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "There are several ways of using Python for data analysis. Spyder is a full interactive development environment (IDE), similar to RStudio. Another tool are Jupyter Notebooks which we will be using here. Like R Notebooks and R Markdown, they are designed for an easy integration of text and programing. They are aimed at providing a more interactive workflow for Python programming, analysis and reporting. While an R Notebook is a script that gets rendered into an output file in one step, Jupyter Notebooks contain cells which can all be executed and rendered interactively. " 71 | ] 72 | }, 73 | { 74 | "cell_type": "markdown", 75 | "metadata": {}, 76 | "source": [ 77 | "## Starting Jupyter" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "Once installed look for and run an application called Jupyter Notebook, which on Windows is located in:" 85 | ] 86 | }, 87 | { 88 | "cell_type": "markdown", 89 | "metadata": {}, 90 | "source": [ 91 | "```\n", 92 | " Start menu --> All programs --> Anaconda3 --> Jupyter Notebook \n", 93 | "```" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "Alternatively, open up a command line console and type:" 101 | ] 102 | }, 103 | { 104 | "cell_type": "markdown", 105 | "metadata": {}, 106 | "source": [ 107 | "```\n", 108 | " jupyter notebook\n", 109 | "```" 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [ 116 | "After about a minute, you should see the Jupyter application appear. The figure shows an\n", 117 | "example of what Jupyter looks like on Mac. The appearance on Windows and Linux operating\n", 118 | "systems will be slightly different." 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "metadata": {}, 124 | "source": [ 125 | "![](img/fig/jupyter1.png)" 126 | ] 127 | }, 128 | { 129 | "cell_type": "markdown", 130 | "metadata": {}, 131 | "source": [ 132 | "You should see three main tabs in Jupyter on start-up:\n", 133 | "\n", 134 | "* **Files** Your file directory\n", 135 | "\n", 136 | "* **Running** Lists all of the notebooks currently running\n", 137 | "\n", 138 | "* **Clusters** For using IPython in parallel with your cluster (beyond the scope of this course)" 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "metadata": {}, 144 | "source": [ 145 | "## Opening a new Jupyter Notebook" 146 | ] 147 | }, 148 | { 149 | "cell_type": "markdown", 150 | "metadata": {}, 151 | "source": [ 152 | "To open a Jupyter Notebook, click the New drop down menu on the File tab and select \"Python 3\" under the Notebooks heading." 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": {}, 158 | "source": [ 159 | "![](img/fig/jupyter2.png)" 160 | ] 161 | }, 162 | { 163 | "cell_type": "markdown", 164 | "metadata": {}, 165 | "source": [ 166 | "This will open a blank Notebook with an IPython console (using Python 3) running underneath it." 167 | ] 168 | }, 169 | { 170 | "cell_type": "markdown", 171 | "metadata": {}, 172 | "source": [ 173 | "![](img/fig/jupyter3.png)" 174 | ] 175 | }, 176 | { 177 | "cell_type": "markdown", 178 | "metadata": {}, 179 | "source": [ 180 | "The IPython console is used to input and execute Python code interactively. Outputs, errors\n", 181 | "and warning messages are directly shown in the same window. A command which has been\n", 182 | "input into the console is executed by simply pressing `Shift+Enter`." 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": {}, 188 | "source": [ 189 | "## The IPython Kernel" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": {}, 195 | "source": [ 196 | "The IPython kernel is the processing back-end that Jupyter notebooks use to execute Python code. The IPython kernel is a python interpreter designed for interactive use, and adds many helpful features such as:\n", 197 | "\n", 198 | "* Coloured input and output lines, as well as error messages for added clarity.\n", 199 | "* Aliases to useful operating system calls for directory navigation e.g. pwd, cd, ls and mkdir.\n", 200 | "* 'Magic' functions provide many other helpful shortcuts. Type `%quickref` for a full list. A few are covered later in this course.\n", 201 | "* Tab completion of variable names, imports, class attributes and functions as well as file names in the current working directory.\n", 202 | "* Object exploration through the use of `?` and `??` (see below).\n", 203 | "* Input/Output history referencing and searching." 204 | ] 205 | }, 206 | { 207 | "cell_type": "markdown", 208 | "metadata": {}, 209 | "source": [ 210 | "A detailed introduction and overview of these features can also be found by entering a single\n", 211 | "question mark `?` within IPython. Key features will be introduced gradually throughout this\n", 212 | "course with examples." 213 | ] 214 | }, 215 | { 216 | "cell_type": "markdown", 217 | "metadata": { 218 | "collapsed": true 219 | }, 220 | "source": [ 221 | "## Cell Based Execution" 222 | ] 223 | }, 224 | { 225 | "cell_type": "markdown", 226 | "metadata": {}, 227 | "source": [ 228 | "It is common when working interactively to only want to run a section of the code, rather than the entire script. To aid in this, Jupyter uses a concept of 'code cells', which can be executed individually in the IPython console. Each block represents a code cell and can be executed by:\n", 229 | "\n", 230 | "* Press `Ctrl+Enter` to execute all the code in the current active cell.\n", 231 | "\n", 232 | "* Press `Shift+Enter` to execute all the code in the current active cell and advance the cursor to the next cell." 233 | ] 234 | }, 235 | { 236 | "cell_type": "markdown", 237 | "metadata": {}, 238 | "source": [ 239 | "Using `Shift+Enter` multiple times to incrementally step through the code and investigate the results in the IPython console is a common workflow when prototyping and doing exploratory work." 240 | ] 241 | }, 242 | { 243 | "cell_type": "markdown", 244 | "metadata": {}, 245 | "source": [ 246 | "![](img/fig/jupyter4.png)" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "## Command and Edit Modes" 254 | ] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "metadata": {}, 259 | "source": [ 260 | "Jupyter notebook is a modal editor which means that the keyboard does different things depending on which mode the notebook is in. There are two modes: **edit mode** and **command mode.** To go from command mode to edit mode, press `Enter`. To return to command mode from edit mode, press `Esc`." 261 | ] 262 | }, 263 | { 264 | "cell_type": "markdown", 265 | "metadata": {}, 266 | "source": [ 267 | "Edit mode is indicated by a green cell border and left sidebar, and a prompt showing in the editor area:\n", 268 | "\n", 269 | "![](img/fig/CellModeEdit.png)\n", 270 | "\n", 271 | "When a cell is in edit mode, you can type into the cell, like a normal text editor. Enter edit mode by pressing `Enter` or using the mouse to click on a cell's editor area." 272 | ] 273 | }, 274 | { 275 | "cell_type": "markdown", 276 | "metadata": {}, 277 | "source": [ 278 | "Command mode is indicated by a grey cell border and a blue sidebar:\n", 279 | "\n", 280 | "![](img/fig/CellModeCommand.png)\n", 281 | "\n", 282 | "When you are in command mode, you are able to edit the notebook as a whole, but not type into individual cells. Most importantly, in command mode, the keyboard is mapped to a set of shortcuts that let you perform notebook and cell actions efficiently. For example, if you are in command mode and you press `c`, you will copy the current cell - no modifier is needed." 283 | ] 284 | }, 285 | { 286 | "cell_type": "markdown", 287 | "metadata": {}, 288 | "source": [ 289 | "**Warning: Cells in Command Mode** \n", 290 | "\n", 291 | "Don't try to type into a cell in command mode; unexpected things will happen!" 292 | ] 293 | }, 294 | { 295 | "cell_type": "markdown", 296 | "metadata": {}, 297 | "source": [ 298 | "A summary of useful shortcuts is included at the end of this section, however a full list is always available by going to:\n", 299 | "\n", 300 | "```\n", 301 | " Help --> Keyboard Shortcuts\n", 302 | "```" 303 | ] 304 | }, 305 | { 306 | "cell_type": "markdown", 307 | "metadata": {}, 308 | "source": [ 309 | "**Tip: Keyboard Shortcuts** \n", 310 | "\n", 311 | "You can also access the Keyboard Shortcuts list by pressing `h` in command mode." 312 | ] 313 | }, 314 | { 315 | "cell_type": "markdown", 316 | "metadata": {}, 317 | "source": [ 318 | "## Markdown Text Cells\n", 319 | "\n", 320 | "The default cells are IPython console cells though a cell can be changed to include Markdown text. To change the type of cell from code to Markdown go to the top menu bar:\n", 321 | "\n", 322 | "```\n", 323 | " Cell > Cell Type > Markdown\n", 324 | "```\n", 325 | "\n", 326 | "Or press `m` while in Command Mode and highlighting the cell. \n", 327 | "\n", 328 | "Markdown text cells support plain text, Markdown and HTML. For information about Markdown and HTML:\n", 329 | "\n", 330 | "* **Markdown** - [https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)\n", 331 | "* **HTML** - [https://web.stanford.edu/group/csp/cs21/htmlcheatsheet.pdf](https://web.stanford.edu/group/csp/cs21/htmlcheatsheet.pdf)" 332 | ] 333 | }, 334 | { 335 | "cell_type": "markdown", 336 | "metadata": {}, 337 | "source": [ 338 | "## Useful Keyboard Shortcuts\n", 339 | "\n", 340 | "All of the cell manipulation commands also have keyboard shortcuts to execute. A list of the commonly used ones are below; however, to view a full list of shortcuts either go to **Help > Keyboard Shortcuts**, or in Command Mode, press **H**." 341 | ] 342 | }, 343 | { 344 | "cell_type": "markdown", 345 | "metadata": {}, 346 | "source": [ 347 | "Command Mode (press Esc to enable)\n", 348 | "\n", 349 | "* **Enter** enter edit mode\n", 350 | "* **H** show keyboard shortcuts\n", 351 | "* **Shift + Enter** run cell, select below\n", 352 | "* **Ctrl + Enter** run cell\n", 353 | "* **Alt + Enter** run cell, insert below\n", 354 | "* **Y** to code\n", 355 | "* **M** to markdown\n", 356 | "* **A/B** insert cell above or below\n", 357 | "* **X** cut selected cell\n", 358 | "* **C** copy selected cell\n", 359 | "* **V** paste cell\n", 360 | "* **D, D** (i.e. **D** then **D** again) delete cell" 361 | ] 362 | }, 363 | { 364 | "cell_type": "markdown", 365 | "metadata": {}, 366 | "source": [ 367 | "Edit Mode (press Enter to enable)\n", 368 | "\n", 369 | "* **Tab** code completion or indent\n", 370 | "* **Ctrl + Z** undo" 371 | ] 372 | }, 373 | { 374 | "cell_type": "markdown", 375 | "metadata": {}, 376 | "source": [ 377 | "# Modules, Packages, and Libraries" 378 | ] 379 | }, 380 | { 381 | "cell_type": "markdown", 382 | "metadata": {}, 383 | "source": [ 384 | "## Modules" 385 | ] 386 | }, 387 | { 388 | "cell_type": "markdown", 389 | "metadata": {}, 390 | "source": [ 391 | "A module in Python is simply a `.py` file that contains additional code to define functions, classes or variables. Modules provide a way to logically group related code, making it easier to understand and use." 392 | ] 393 | }, 394 | { 395 | "cell_type": "markdown", 396 | "metadata": {}, 397 | "source": [ 398 | "In Python terms, a module is just another Python object with attributes that you can bind and reference, though in this case the attributes are the various functions, classes or variables defined in the `.py` file. To use them within our namespace we use the `import` statement in one of three ways:" 399 | ] 400 | }, 401 | { 402 | "cell_type": "markdown", 403 | "metadata": {}, 404 | "source": [ 405 | " import module_name\n", 406 | " import module_name as alias\n", 407 | " from module_name import object1, object2, object3" 408 | ] 409 | }, 410 | { 411 | "cell_type": "markdown", 412 | "metadata": {}, 413 | "source": [ 414 | "The method used to import will affect how the objects imported are used. Some examples are\n", 415 | "shown below." 416 | ] 417 | }, 418 | { 419 | "cell_type": "code", 420 | "execution_count": 1, 421 | "metadata": {}, 422 | "outputs": [ 423 | { 424 | "data": { 425 | "text/plain": [ 426 | "0.8660254037844386" 427 | ] 428 | }, 429 | "execution_count": 1, 430 | "metadata": {}, 431 | "output_type": "execute_result" 432 | } 433 | ], 434 | "source": [ 435 | "# method 1\n", 436 | "import math\n", 437 | "math.sin(math.pi/3)\n", 438 | "\n", 439 | "# method 2\n", 440 | "import math as m\n", 441 | "m.sin(m.pi/3)\n", 442 | "\n", 443 | "# method 3\n", 444 | "from math import sin, pi\n", 445 | "sin(pi/3)" 446 | ] 447 | }, 448 | { 449 | "cell_type": "markdown", 450 | "metadata": {}, 451 | "source": [ 452 | "There is also a fourth way of importing things with a * instead of specifying each object individually.\n", 453 | "This imports all the functions, classes and variables contained within the module." 454 | ] 455 | }, 456 | { 457 | "cell_type": "code", 458 | "execution_count": 2, 459 | "metadata": {}, 460 | "outputs": [ 461 | { 462 | "data": { 463 | "text/plain": [ 464 | "-0.14384103622589053" 465 | ] 466 | }, 467 | "execution_count": 2, 468 | "metadata": {}, 469 | "output_type": "execute_result" 470 | } 471 | ], 472 | "source": [ 473 | "from math import *\n", 474 | "log(sin(pi/3))" 475 | ] 476 | }, 477 | { 478 | "cell_type": "markdown", 479 | "metadata": {}, 480 | "source": [ 481 | "However, this method of importing objects is frowned upon as it is less clear what is imported and will also override variables already defined if their names clash." 482 | ] 483 | }, 484 | { 485 | "cell_type": "markdown", 486 | "metadata": {}, 487 | "source": [ 488 | "A module is loaded only once, regardless of the number of times it is imported. This prevents\n", 489 | "the module execution from happening over and over again if multiple imports occur in a single\n", 490 | "script." 491 | ] 492 | }, 493 | { 494 | "cell_type": "markdown", 495 | "metadata": {}, 496 | "source": [ 497 | "## Packages and Libraries" 498 | ] 499 | }, 500 | { 501 | "cell_type": "markdown", 502 | "metadata": {}, 503 | "source": [ 504 | "A package is a collection of modules, similar to packages in R. A collection of packages is usually referred to as a library. There is no formal distinction between a package and a library so sometimes package and library are used interchangeably.\n", 505 | "\n", 506 | "Packages and libraries can be made available in the same manner as above, simply using the package or library name instead of the `module_name` in the `import` statements.\n", 507 | "\n", 508 | "It is also possible to selectively import only certain modules in a package or library. To access a module (or sub-package), we must use the `.` operator. For example, to extract a module named `foo` from a package named `mypackage`, as the alias `mpf`, we use the following code:" 509 | ] 510 | }, 511 | { 512 | "cell_type": "markdown", 513 | "metadata": {}, 514 | "source": [ 515 | "```python\n", 516 | "import mypackage.foo as mpf\n", 517 | "```" 518 | ] 519 | }, 520 | { 521 | "cell_type": "markdown", 522 | "metadata": {}, 523 | "source": [ 524 | "Then to use any functions from this module, we simply call the module alias, the `.`, and then the function name, i.e., for function `func1` we have the following:" 525 | ] 526 | }, 527 | { 528 | "cell_type": "markdown", 529 | "metadata": {}, 530 | "source": [ 531 | "```python\n", 532 | "x = mpf.func1()\n", 533 | "```" 534 | ] 535 | }, 536 | { 537 | "cell_type": "markdown", 538 | "metadata": {}, 539 | "source": [ 540 | "### The Python Standard Library" 541 | ] 542 | }, 543 | { 544 | "cell_type": "markdown", 545 | "metadata": {}, 546 | "source": [ 547 | "Python comes with many useful modules and packages as standard. Details on using the Python Standard Library can\n", 548 | "be found in the documentation at [https://docs.python.org/3.6/library/](https://docs.python.org/3.6/library/), with additional examples available at this fantastic site [http://pymotw.com/2/contents.html](http://pymotw.com/2/contents.html)." 549 | ] 550 | }, 551 | { 552 | "cell_type": "markdown", 553 | "metadata": {}, 554 | "source": [ 555 | "**Exercise**\n", 556 | "\n", 557 | "1. Open up a new Jupyter Notebook and print \"Hello Python world!\" on the console.\n", 558 | "2. Add a markdown cell and include a note that this is the notebook for today's workshop.\n", 559 | "3. Import the **numpy** library using the alias np.\n", 560 | "\n", 561 | "Extension:\n", 562 | "\n", 563 | "4. Draw a (pseudo) random number from a uniform distribution on the interval [2, 5]." 564 | ] 565 | }, 566 | { 567 | "cell_type": "code", 568 | "execution_count": 3, 569 | "metadata": { 570 | "tags": [ 571 | "skip" 572 | ] 573 | }, 574 | "outputs": [ 575 | { 576 | "data": { 577 | "text/plain": [ 578 | "3.0721064635544777" 579 | ] 580 | }, 581 | "execution_count": 3, 582 | "metadata": {}, 583 | "output_type": "execute_result" 584 | } 585 | ], 586 | "source": [ 587 | "\"Hello Python world!\"\n", 588 | "\n", 589 | "import numpy as np\n", 590 | "\n", 591 | "import random\n", 592 | "random.uniform(2,5)" 593 | ] 594 | }, 595 | { 596 | "cell_type": "markdown", 597 | "metadata": {}, 598 | "source": [ 599 | "## Installing Additional Packages" 600 | ] 601 | }, 602 | { 603 | "cell_type": "markdown", 604 | "metadata": {}, 605 | "source": [ 606 | "If you have the Anaconda Python distribution, this comes with many third party python packages\n", 607 | "already installed. However you may come across additional packages that you wish to install." 608 | ] 609 | }, 610 | { 611 | "cell_type": "markdown", 612 | "metadata": {}, 613 | "source": [ 614 | "Unlike R's `install.packages`, Python itself has no built in system to manage packages, but there is a central repository for Python packages known as the Python Package Index or PyPI. Several command line utilities\n", 615 | "have been developed to look up and install Python packages from PyPI." 616 | ] 617 | }, 618 | { 619 | "cell_type": "markdown", 620 | "metadata": {}, 621 | "source": [ 622 | "The recommended tool to use to install additional Python packages is pip. Python >= 3.4 now comes with pip by default." 623 | ] 624 | }, 625 | { 626 | "cell_type": "markdown", 627 | "metadata": {}, 628 | "source": [ 629 | "You can search for packages on PyPI using," 630 | ] 631 | }, 632 | { 633 | "cell_type": "markdown", 634 | "metadata": {}, 635 | "source": [ 636 | "```python\n", 637 | "pip search \n", 638 | "```" 639 | ] 640 | }, 641 | { 642 | "cell_type": "markdown", 643 | "metadata": {}, 644 | "source": [ 645 | "Packages are then installed with," 646 | ] 647 | }, 648 | { 649 | "cell_type": "markdown", 650 | "metadata": {}, 651 | "source": [ 652 | "```python\n", 653 | "pip install \n", 654 | "```" 655 | ] 656 | }, 657 | { 658 | "cell_type": "markdown", 659 | "metadata": {}, 660 | "source": [ 661 | "Other helpful pip commands are `pip list`, which lists all the packages installed by pip, and\n", 662 | "`pip uninstall ` to remove an installed package." 663 | ] 664 | }, 665 | { 666 | "cell_type": "markdown", 667 | "metadata": {}, 668 | "source": [ 669 | "# The Help System" 670 | ] 671 | }, 672 | { 673 | "cell_type": "markdown", 674 | "metadata": {}, 675 | "source": [ 676 | "In Python, to find out information about a function we can use the online documentation for the package that it is in. However, we can also find out more about functions by using Jupyter's inbuilt help system.\n", 677 | "\n", 678 | "The `?` can be used to display help on a function, Jupyter allows the use of the `?` before or after the function in question. For example, to find out information about the `np.floor` function we can use the following:" 679 | ] 680 | }, 681 | { 682 | "cell_type": "markdown", 683 | "metadata": {}, 684 | "source": [ 685 | "```\n", 686 | ">>> import numpy as np\n", 687 | ">>> ?np.floor\n", 688 | "```" 689 | ] 690 | }, 691 | { 692 | "cell_type": "markdown", 693 | "metadata": { 694 | "collapsed": true 695 | }, 696 | "source": [ 697 | "![](img/fig/HelpFile.png)" 698 | ] 699 | } 700 | ], 701 | "metadata": { 702 | "kernelspec": { 703 | "display_name": "Python 3", 704 | "language": "python", 705 | "name": "python3" 706 | }, 707 | "language_info": { 708 | "codemirror_mode": { 709 | "name": "ipython", 710 | "version": 3 711 | }, 712 | "file_extension": ".py", 713 | "mimetype": "text/x-python", 714 | "name": "python", 715 | "nbconvert_exporter": "python", 716 | "pygments_lexer": "ipython3", 717 | "version": "3.6.6" 718 | }, 719 | "toc": { 720 | "colors": { 721 | "hover_highlight": "#DAA520", 722 | "navigate_num": "#000000", 723 | "navigate_text": "#333333", 724 | "running_highlight": "#FF0000", 725 | "selected_highlight": "#FFD700", 726 | "sidebar_border": "#EEEEEE", 727 | "wrapper_background": "#FFFFFF" 728 | }, 729 | "moveMenuLeft": true, 730 | "nav_menu": { 731 | "height": "512px", 732 | "width": "252px" 733 | }, 734 | "navigate_menu": true, 735 | "number_sections": false, 736 | "sideBar": true, 737 | "threshold": 4, 738 | "toc_cell": false, 739 | "toc_position": { 740 | "height": "603px", 741 | "left": "0px", 742 | "right": "1108px", 743 | "top": "107px", 744 | "width": "212px" 745 | }, 746 | "toc_section_display": "block", 747 | "toc_window_display": true, 748 | "widenNotebook": false 749 | } 750 | }, 751 | "nbformat": 4, 752 | "nbformat_minor": 2 753 | } 754 | -------------------------------------------------------------------------------- /1-03_Data Manipulation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "tags": [ 8 | "skip" 9 | ] 10 | }, 11 | "outputs": [], 12 | "source": [ 13 | "# Options for all cells \n", 14 | "import pandas as pd\n", 15 | "# change display setting of pandas\n", 16 | "pd.set_option('display.notebook_repr_html', False)\n", 17 | "# Setting the graphics\n", 18 | "%matplotlib inline\n", 19 | "# suppress all warnings (since anova gives a warning)\n", 20 | "import warnings\n", 21 | "warnings.filterwarnings(\"ignore\")" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "# Reading data" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "The **pandas** package provides lots of simple functions for reading data from and writing data to various different file formats, such as CSV, Excel, SQL, JSON, and HTML. All the read functions in the package (`pd.read_*` functions) create a **pandas** `DataFrame` object. This object, like a `data.frame` in R, is meant for storing tabular data where columns can potentially contain different data types. The dimension of a data frame are typically labelled with row names and column names in R. Here, the labels are called index and columns, respectively." 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 1, 41 | "metadata": {}, 42 | "outputs": [], 43 | "source": [ 44 | "import pandas as pd\n", 45 | "tips = pd.read_csv(\"Data/tips.csv\")" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "**Tip**\n", 53 | "\n", 54 | "In Python, only the equals sign `=` is used to assign values to variables. Variable names can start with an underscore `_` (unlike in R) and are case sensitive (like in R). " 55 | ] 56 | }, 57 | { 58 | "cell_type": "markdown", 59 | "metadata": {}, 60 | "source": [ 61 | "**Tip**\n", 62 | "\n", 63 | "Documentation for each function can be accessed via the websites for the package in question, e.g., [http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html), or can be viewed directly from Jupyter notebooks via `?`. It can be placed in front of the function call as in R, e.g., `?pd.read_csv`, or after it. " 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "## Functions, Methods and Attributes\n", 71 | "\n", 72 | "R has been characterised well by \"Everything that exists is an object. Everything that happens is a function call.\" The Python equivalent is \"Everything is an object, and all objects can have attributes.\"\n", 73 | "\n", 74 | "When working in R, in most cases we use a function on an object, i.e., `function(object, ...)`. This is the case for functions from a package, e.g., to read in data, generic functions like `summary` which do different things depending on the object class, or functions to access attributes of the object such as the dimension (via the `dim` function).\n", 75 | "\n", 76 | "In Python, functions from a package such as `pd.read_csv` are utilised like in R, i.e., `function(arguments)`. Beyond that, objects typically have attributes which are references to other Python objects. Those can be data types such as a list to store the dimension of a data frame but also can be functions specific to that object class. Such functions are referred to as object methods, or simply methods. " 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "metadata": {}, 82 | "source": [ 83 | "Attributes, including methods, are accessed via the dot operator `.`." 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "`.`" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": {}, 96 | "source": [ 97 | "For example, attributes of a **pandas** `DataFrame` include the dimension (`.shape`) and the dimension labels (`.index` and `.columns`)." 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 2, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "Index(['total_bill', 'tip', 'sex', 'smoker', 'day', 'time', 'size'], dtype='object')" 109 | ] 110 | }, 111 | "execution_count": 2, 112 | "metadata": {}, 113 | "output_type": "execute_result" 114 | } 115 | ], 116 | "source": [ 117 | "tips.columns" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "Methods require parentheses after the method name, where any argument can be specified." 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "metadata": {}, 130 | "source": [ 131 | "`.(arg=*)`" 132 | ] 133 | }, 134 | { 135 | "cell_type": "markdown", 136 | "metadata": {}, 137 | "source": [ 138 | "Methods for a `DataFrame` include the `.head` and `.tail` functions for preview the first or last few rows of the data frame as well the `.describe` function which provides a summary of the data frame, similar to R's `summary` function." 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 3, 144 | "metadata": {}, 145 | "outputs": [ 146 | { 147 | "data": { 148 | "text/html": [ 149 | "
\n", 150 | "\n", 163 | "\n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | " \n", 179 | " \n", 180 | " \n", 181 | " \n", 182 | " \n", 183 | " \n", 184 | " \n", 185 | " \n", 186 | " \n", 187 | " \n", 188 | " \n", 189 | " \n", 190 | " \n", 191 | " \n", 192 | " \n", 193 | " \n", 194 | " \n", 195 | " \n", 196 | " \n", 197 | " \n", 198 | " \n", 199 | " \n", 200 | " \n", 201 | " \n", 202 | " \n", 203 | " \n", 204 | " \n", 205 | " \n", 206 | " \n", 207 | " \n", 208 | " \n", 209 | " \n", 210 | " \n", 211 | " \n", 212 | " \n", 213 | " \n", 214 | " \n", 215 | " \n", 216 | " \n", 217 | " \n", 218 | " \n", 219 | " \n", 220 | " \n", 221 | " \n", 222 | " \n", 223 | " \n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | "
total_billtipsexsmokerdaytimesize
count244.000000244.000000244244244244244.000000
uniqueNaNNaN2242NaN
topNaNNaNMaleNoSatDinnerNaN
freqNaNNaN15715187176NaN
mean19.7859432.998279NaNNaNNaNNaN2.569672
std8.9024121.383638NaNNaNNaNNaN0.951100
min3.0700001.000000NaNNaNNaNNaN1.000000
25%13.3475002.000000NaNNaNNaNNaN2.000000
50%17.7950002.900000NaNNaNNaNNaN2.000000
75%24.1275003.562500NaNNaNNaNNaN3.000000
max50.81000010.000000NaNNaNNaNNaN6.000000
\n", 289 | "
" 290 | ], 291 | "text/plain": [ 292 | " total_bill tip sex smoker day time size\n", 293 | "count 244.000000 244.000000 244 244 244 244 244.000000\n", 294 | "unique NaN NaN 2 2 4 2 NaN\n", 295 | "top NaN NaN Male No Sat Dinner NaN\n", 296 | "freq NaN NaN 157 151 87 176 NaN\n", 297 | "mean 19.785943 2.998279 NaN NaN NaN NaN 2.569672\n", 298 | "std 8.902412 1.383638 NaN NaN NaN NaN 0.951100\n", 299 | "min 3.070000 1.000000 NaN NaN NaN NaN 1.000000\n", 300 | "25% 13.347500 2.000000 NaN NaN NaN NaN 2.000000\n", 301 | "50% 17.795000 2.900000 NaN NaN NaN NaN 2.000000\n", 302 | "75% 24.127500 3.562500 NaN NaN NaN NaN 3.000000\n", 303 | "max 50.810000 10.000000 NaN NaN NaN NaN 6.000000" 304 | ] 305 | }, 306 | "execution_count": 3, 307 | "metadata": {}, 308 | "output_type": "execute_result" 309 | } 310 | ], 311 | "source": [ 312 | "tips.describe(include=\"all\")" 313 | ] 314 | }, 315 | { 316 | "cell_type": "markdown", 317 | "metadata": {}, 318 | "source": [ 319 | "**Tip**\n", 320 | "\n", 321 | "In Jupyter, we can view all the attributes and methods associated with an object by using tab completion. Once an object has been created (i.e., tips for above), typing `tips.` into a cell and pressing the tab key shows all the attributes and methods that can be used on that object." 322 | ] 323 | }, 324 | { 325 | "cell_type": "markdown", 326 | "metadata": {}, 327 | "source": [ 328 | "**Exercise**\n", 329 | "\n", 330 | "1. Import the mtcars data (mtcars.csv), ensuring that the car names are used for the row index.\n", 331 | "2. What are the dimensions of the imported data?\n", 332 | "3. Print the top 5 rows of the data.\n", 333 | "\n", 334 | "Extension\n", 335 | "\n", 336 | "4. Print the last 10 rows of the data.\n", 337 | "5. Import only the miles per gallon (mpg) and weight (wt) columns from the mtcars data" 338 | ] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "execution_count": 4, 343 | "metadata": { 344 | "tags": [ 345 | "skip" 346 | ] 347 | }, 348 | "outputs": [ 349 | { 350 | "data": { 351 | "text/html": [ 352 | "
\n", 353 | "\n", 366 | "\n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 384 | " \n", 385 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 396 | " \n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | "
mpgwt
Mazda RX421.02.620
Mazda RX4 Wag21.02.875
Datsun 71022.82.320
Hornet 4 Drive21.43.215
Hornet Sportabout18.73.440
\n", 402 | "
" 403 | ], 404 | "text/plain": [ 405 | " mpg wt\n", 406 | "Mazda RX4 21.0 2.620\n", 407 | "Mazda RX4 Wag 21.0 2.875\n", 408 | "Datsun 710 22.8 2.320\n", 409 | "Hornet 4 Drive 21.4 3.215\n", 410 | "Hornet Sportabout 18.7 3.440" 411 | ] 412 | }, 413 | "execution_count": 4, 414 | "metadata": {}, 415 | "output_type": "execute_result" 416 | } 417 | ], 418 | "source": [ 419 | "# Solution\n", 420 | "import pandas as pd\n", 421 | "mtcars = pd.read_csv(\"Data/mtcars.csv\", index_col=0)\n", 422 | "mtcars.shape\n", 423 | "mtcars.head(5)\n", 424 | "\n", 425 | "mtcars.tail(10)\n", 426 | "mtcars2 = pd.read_csv(\"Data/mtcars.csv\", index_col=0, usecols=[0,1,6])\n", 427 | "mtcars2.head()" 428 | ] 429 | }, 430 | { 431 | "cell_type": "markdown", 432 | "metadata": {}, 433 | "source": [ 434 | "# Data Manipulation" 435 | ] 436 | }, 437 | { 438 | "cell_type": "markdown", 439 | "metadata": {}, 440 | "source": [ 441 | "The **pandas** package can be used for more than importing and exporting data. Written originally by Wes McKinney, the **pandas** package has grown to also include data manipulation, statistics and visualisation. Here, we will focus on the functionality for data manipulation." 442 | ] 443 | }, 444 | { 445 | "cell_type": "markdown", 446 | "metadata": {}, 447 | "source": [ 448 | "Common data manipulation tasks mostly have corresponding `DataFrame` methods:\n", 449 | "\n", 450 | "| Description | Method | \n", 451 | "| --- | --- | \n", 452 | "| Filter rows based on values | `.query` | \n", 453 | "| Sort rows | `.sort_values` | \n", 454 | "| Rename columns | `.rename` | \n", 455 | "| Summarise/Aggregate columns | `.agg` |\n", 456 | "| Group the data | `.groupby` | \n", 457 | "\n", 458 | "However, some tasks such as selecting columns, changing or adding new columns, or selecting rows based on position are not done via a corresponding method. We will show how this is done in Python and introduce the concept of dictionaries which are needed for setting arguments to the `.rename` and `.agg` methods." 459 | ] 460 | }, 461 | { 462 | "cell_type": "markdown", 463 | "metadata": {}, 464 | "source": [ 465 | "## Selecting Columns" 466 | ] 467 | }, 468 | { 469 | "cell_type": "markdown", 470 | "metadata": {}, 471 | "source": [ 472 | "We can access columns in a data frame by indexing with `[]` and supplying the corresponding column labels. To access a single column, a string with the column label is sufficient." 473 | ] 474 | }, 475 | { 476 | "cell_type": "code", 477 | "execution_count": 5, 478 | "metadata": {}, 479 | "outputs": [ 480 | { 481 | "data": { 482 | "text/plain": [ 483 | "0 Dinner\n", 484 | "1 Dinner\n", 485 | "2 Dinner\n", 486 | "3 Dinner\n", 487 | "4 Dinner\n", 488 | "Name: time, dtype: object" 489 | ] 490 | }, 491 | "execution_count": 5, 492 | "metadata": {}, 493 | "output_type": "execute_result" 494 | } 495 | ], 496 | "source": [ 497 | "tips['time'].head()" 498 | ] 499 | }, 500 | { 501 | "cell_type": "markdown", 502 | "metadata": {}, 503 | "source": [ 504 | "To access multiple columns, we provide the labels in form of a list. Lists are created using square brackets `[]`, with individual items separated by commas." 505 | ] 506 | }, 507 | { 508 | "cell_type": "code", 509 | "execution_count": 6, 510 | "metadata": {}, 511 | "outputs": [ 512 | { 513 | "data": { 514 | "text/html": [ 515 | "
\n", 516 | "\n", 529 | "\n", 530 | " \n", 531 | " \n", 532 | " \n", 533 | " \n", 534 | " \n", 535 | " \n", 536 | " \n", 537 | " \n", 538 | " \n", 539 | " \n", 540 | " \n", 541 | " \n", 542 | " \n", 543 | " \n", 544 | " \n", 545 | " \n", 546 | " \n", 547 | " \n", 548 | " \n", 549 | " \n", 550 | " \n", 551 | " \n", 552 | " \n", 553 | " \n", 554 | " \n", 555 | " \n", 556 | " \n", 557 | " \n", 558 | " \n", 559 | " \n", 560 | " \n", 561 | " \n", 562 | " \n", 563 | " \n", 564 | " \n", 565 | " \n", 566 | " \n", 567 | " \n", 568 | " \n", 569 | " \n", 570 | "
total_billsizeday
016.992Sun
110.343Sun
221.013Sun
323.682Sun
424.594Sun
\n", 571 | "
" 572 | ], 573 | "text/plain": [ 574 | " total_bill size day\n", 575 | "0 16.99 2 Sun\n", 576 | "1 10.34 3 Sun\n", 577 | "2 21.01 3 Sun\n", 578 | "3 23.68 2 Sun\n", 579 | "4 24.59 4 Sun" 580 | ] 581 | }, 582 | "execution_count": 6, 583 | "metadata": {}, 584 | "output_type": "execute_result" 585 | } 586 | ], 587 | "source": [ 588 | "list_of_names = ['total_bill', 'size', 'day']\n", 589 | "tips[list_of_names].head()" 590 | ] 591 | }, 592 | { 593 | "cell_type": "markdown", 594 | "metadata": {}, 595 | "source": [ 596 | "**Tip**\n", 597 | "\n", 598 | "Lists in Python, like lists in R, are very versatile and can hold any collection of objects with mixing of multiple types allowed. They are often used to specify a collection of elements for use in function argument. In R, we typically would do that via vectors or lists." 599 | ] 600 | }, 601 | { 602 | "cell_type": "markdown", 603 | "metadata": {}, 604 | "source": [ 605 | "### Series Objects" 606 | ] 607 | }, 608 | { 609 | "cell_type": "markdown", 610 | "metadata": {}, 611 | "source": [ 612 | "Selecting multiple columns returns another data frame but selecting a single column returns a `Series` object. This object consists of two parts, `values` and `index`, which can be accessed through the corresponding attributes. A `Series` has similar methods as a `DataFrame`, such as `.head` and `.describe`. Other helpful methods include\n", 613 | "\n", 614 | "* `.isnull()`/`.notnull()` to perform a boolean test for missing/non-missing values\n", 615 | "* `.isfinite()` to perform a boolean test for finite values\n", 616 | "* `.value_counts()` to return counts of unique values\n", 617 | "* `.idxmax()` to return the index of the row with the largest value" 618 | ] 619 | }, 620 | { 621 | "cell_type": "markdown", 622 | "metadata": {}, 623 | "source": [ 624 | "**Warning**\n", 625 | "\n", 626 | "Operations such as `+` on two `Series` objects are done based on the index, i.e., matching up elements with the same index, regardless of their position in the series. For comparison, addition of two vectors in R (which do not have an index), is carried out element-wise where the matching up is done by position, i.e, the two first elements are added up, the two second elements are added up, etc." 627 | ] 628 | }, 629 | { 630 | "cell_type": "markdown", 631 | "metadata": {}, 632 | "source": [ 633 | "## Adding and Editing Columns" 634 | ] 635 | }, 636 | { 637 | "cell_type": "markdown", 638 | "metadata": {}, 639 | "source": [ 640 | "To add a new column to a `DataFrame`, we select a new column via the indexing method (`[]` as above), using the new column name for which column is to be selected, and assign the new values to it. To edit a column, we can overwrite it and assign new values to the column in the same way.\n", 641 | "\n", 642 | "For example, we can add the tip share to the tips dataset by dividing the tip amount by the total amount of the bill and assign the result to a new column called `tip_share`." 643 | ] 644 | }, 645 | { 646 | "cell_type": "code", 647 | "execution_count": 7, 648 | "metadata": {}, 649 | "outputs": [ 650 | { 651 | "data": { 652 | "text/html": [ 653 | "
\n", 654 | "\n", 667 | "\n", 668 | " \n", 669 | " \n", 670 | " \n", 671 | " \n", 672 | " \n", 673 | " \n", 674 | " \n", 675 | " \n", 676 | " \n", 677 | " \n", 678 | " \n", 679 | " \n", 680 | " \n", 681 | " \n", 682 | " \n", 683 | " \n", 684 | " \n", 685 | " \n", 686 | " \n", 687 | " \n", 688 | " \n", 689 | " \n", 690 | " \n", 691 | " \n", 692 | " \n", 693 | " \n", 694 | " \n", 695 | " \n", 696 | " \n", 697 | " \n", 698 | " \n", 699 | " \n", 700 | " \n", 701 | " \n", 702 | " \n", 703 | " \n", 704 | " \n", 705 | " \n", 706 | " \n", 707 | " \n", 708 | " \n", 709 | " \n", 710 | " \n", 711 | " \n", 712 | " \n", 713 | " \n", 714 | " \n", 715 | " \n", 716 | " \n", 717 | " \n", 718 | " \n", 719 | " \n", 720 | " \n", 721 | " \n", 722 | " \n", 723 | " \n", 724 | " \n", 725 | " \n", 726 | " \n", 727 | " \n", 728 | " \n", 729 | " \n", 730 | " \n", 731 | " \n", 732 | " \n", 733 | " \n", 734 | " \n", 735 | " \n", 736 | " \n", 737 | " \n", 738 | "
total_billtipsexsmokerdaytimesizetip_share
016.991.01FemaleNoSunDinner20.059447
110.341.66MaleNoSunDinner30.160542
221.013.50MaleNoSunDinner30.166587
323.683.31MaleNoSunDinner20.139780
424.593.61FemaleNoSunDinner40.146808
\n", 739 | "
" 740 | ], 741 | "text/plain": [ 742 | " total_bill tip sex smoker day time size tip_share\n", 743 | "0 16.99 1.01 Female No Sun Dinner 2 0.059447\n", 744 | "1 10.34 1.66 Male No Sun Dinner 3 0.160542\n", 745 | "2 21.01 3.50 Male No Sun Dinner 3 0.166587\n", 746 | "3 23.68 3.31 Male No Sun Dinner 2 0.139780\n", 747 | "4 24.59 3.61 Female No Sun Dinner 4 0.146808" 748 | ] 749 | }, 750 | "execution_count": 7, 751 | "metadata": {}, 752 | "output_type": "execute_result" 753 | } 754 | ], 755 | "source": [ 756 | "tips['tip_share'] = tips['tip'] / tips['total_bill']\n", 757 | "tips.head()" 758 | ] 759 | }, 760 | { 761 | "cell_type": "markdown", 762 | "metadata": {}, 763 | "source": [ 764 | "## Selecting Rows" 765 | ] 766 | }, 767 | { 768 | "cell_type": "markdown", 769 | "metadata": {}, 770 | "source": [ 771 | "To select rows based on values in specific columns, we can use the `.query` method which takes logical statements to describe the rows which are to be selected. Unlike in for the `subset` and `filter` functions in R (from base R and the **dplyr** package, respectively), the logical statement is here provided in one string." 772 | ] 773 | }, 774 | { 775 | "cell_type": "code", 776 | "execution_count": 8, 777 | "metadata": {}, 778 | "outputs": [ 779 | { 780 | "data": { 781 | "text/html": [ 782 | "
\n", 783 | "\n", 796 | "\n", 797 | " \n", 798 | " \n", 799 | " \n", 800 | " \n", 801 | " \n", 802 | " \n", 803 | " \n", 804 | " \n", 805 | " \n", 806 | " \n", 807 | " \n", 808 | " \n", 809 | " \n", 810 | " \n", 811 | " \n", 812 | " \n", 813 | " \n", 814 | " \n", 815 | " \n", 816 | " \n", 817 | " \n", 818 | " \n", 819 | " \n", 820 | " \n", 821 | " \n", 822 | " \n", 823 | " \n", 824 | " \n", 825 | " \n", 826 | " \n", 827 | " \n", 828 | " \n", 829 | " \n", 830 | " \n", 831 | " \n", 832 | " \n", 833 | " \n", 834 | " \n", 835 | " \n", 836 | " \n", 837 | " \n", 838 | " \n", 839 | " \n", 840 | " \n", 841 | " \n", 842 | " \n", 843 | " \n", 844 | " \n", 845 | " \n", 846 | " \n", 847 | " \n", 848 | " \n", 849 | " \n", 850 | " \n", 851 | " \n", 852 | " \n", 853 | " \n", 854 | " \n", 855 | " \n", 856 | " \n", 857 | " \n", 858 | " \n", 859 | " \n", 860 | " \n", 861 | " \n", 862 | " \n", 863 | " \n", 864 | " \n", 865 | " \n", 866 | " \n", 867 | "
total_billtipsexsmokerdaytimesizetip_share
1920.653.35MaleNoSatDinner30.162228
2017.924.08MaleNoSatDinner20.227679
2120.292.75FemaleNoSatDinner20.135535
2215.772.23FemaleNoSatDinner20.141408
2339.427.58MaleNoSatDinner40.192288
\n", 868 | "
" 869 | ], 870 | "text/plain": [ 871 | " total_bill tip sex smoker day time size tip_share\n", 872 | "19 20.65 3.35 Male No Sat Dinner 3 0.162228\n", 873 | "20 17.92 4.08 Male No Sat Dinner 2 0.227679\n", 874 | "21 20.29 2.75 Female No Sat Dinner 2 0.135535\n", 875 | "22 15.77 2.23 Female No Sat Dinner 2 0.141408\n", 876 | "23 39.42 7.58 Male No Sat Dinner 4 0.192288" 877 | ] 878 | }, 879 | "execution_count": 8, 880 | "metadata": {}, 881 | "output_type": "execute_result" 882 | } 883 | ], 884 | "source": [ 885 | "tips_2 = tips.query(\"(time == 'Dinner' & day != 'Sun') | size > 4\")\n", 886 | "tips_2.head()" 887 | ] 888 | }, 889 | { 890 | "cell_type": "markdown", 891 | "metadata": {}, 892 | "source": [ 893 | "### Slicing Notation" 894 | ] 895 | }, 896 | { 897 | "cell_type": "markdown", 898 | "metadata": {}, 899 | "source": [ 900 | "To select rows based on their position, we can also use indexing via `[]` but instead of a string or list to select columns, we use numeric arguments to select rows. The basic concept of this so-called slicing notation is `object[start:stop:step]`. If we wanted to view the first 10 variables at even locations we would use `object[0:20:2]`. This works for selecting sections of lists, strings and rows within data frames. The value of start is inclusive, the value for stop is not, i.e., everything up until but not including `stop` will be selected. If the value of start, stop or step is left empty, then the default values will be taken, which are that start and stop are the first and last values in the object, and step is by default 1. " 901 | ] 902 | }, 903 | { 904 | "cell_type": "code", 905 | "execution_count": 9, 906 | "metadata": {}, 907 | "outputs": [ 908 | { 909 | "data": { 910 | "text/plain": [ 911 | "[45, 12, 62, 78]" 912 | ] 913 | }, 914 | "execution_count": 9, 915 | "metadata": {}, 916 | "output_type": "execute_result" 917 | } 918 | ], 919 | "source": [ 920 | "# Slicing a list\n", 921 | "my_list = [12, 45, 74, 12, 97, 62, 53, 78]\n", 922 | "my_list[1::2]" 923 | ] 924 | }, 925 | { 926 | "cell_type": "code", 927 | "execution_count": 10, 928 | "metadata": {}, 929 | "outputs": [ 930 | { 931 | "data": { 932 | "text/html": [ 933 | "
\n", 934 | "\n", 947 | "\n", 948 | " \n", 949 | " \n", 950 | " \n", 951 | " \n", 952 | " \n", 953 | " \n", 954 | " \n", 955 | " \n", 956 | " \n", 957 | " \n", 958 | " \n", 959 | " \n", 960 | " \n", 961 | " \n", 962 | " \n", 963 | " \n", 964 | " \n", 965 | " \n", 966 | " \n", 967 | " \n", 968 | " \n", 969 | " \n", 970 | " \n", 971 | " \n", 972 | " \n", 973 | " \n", 974 | "
total_billtipsexsmokerdaytimesizetip_share
016.991.01FemaleNoSunDinner20.059447
\n", 975 | "
" 976 | ], 977 | "text/plain": [ 978 | " total_bill tip sex smoker day time size tip_share\n", 979 | "0 16.99 1.01 Female No Sun Dinner 2 0.059447" 980 | ] 981 | }, 982 | "execution_count": 10, 983 | "metadata": {}, 984 | "output_type": "execute_result" 985 | } 986 | ], 987 | "source": [ 988 | "# Slicing a DataFrame for the 1st row\n", 989 | "tips[:1:] " 990 | ] 991 | }, 992 | { 993 | "cell_type": "code", 994 | "execution_count": 11, 995 | "metadata": {}, 996 | "outputs": [ 997 | { 998 | "data": { 999 | "text/html": [ 1000 | "
\n", 1001 | "\n", 1014 | "\n", 1015 | " \n", 1016 | " \n", 1017 | " \n", 1018 | " \n", 1019 | " \n", 1020 | " \n", 1021 | " \n", 1022 | " \n", 1023 | " \n", 1024 | " \n", 1025 | " \n", 1026 | " \n", 1027 | " \n", 1028 | " \n", 1029 | " \n", 1030 | " \n", 1031 | " \n", 1032 | " \n", 1033 | " \n", 1034 | " \n", 1035 | " \n", 1036 | " \n", 1037 | " \n", 1038 | " \n", 1039 | " \n", 1040 | " \n", 1041 | " \n", 1042 | " \n", 1043 | " \n", 1044 | " \n", 1045 | " \n", 1046 | " \n", 1047 | " \n", 1048 | " \n", 1049 | " \n", 1050 | " \n", 1051 | " \n", 1052 | " \n", 1053 | " \n", 1054 | " \n", 1055 | " \n", 1056 | " \n", 1057 | " \n", 1058 | " \n", 1059 | " \n", 1060 | " \n", 1061 | " \n", 1062 | " \n", 1063 | " \n", 1064 | " \n", 1065 | " \n", 1066 | " \n", 1067 | " \n", 1068 | " \n", 1069 | " \n", 1070 | " \n", 1071 | " \n", 1072 | " \n", 1073 | " \n", 1074 | " \n", 1075 | " \n", 1076 | " \n", 1077 | " \n", 1078 | " \n", 1079 | " \n", 1080 | " \n", 1081 | " \n", 1082 | " \n", 1083 | " \n", 1084 | " \n", 1085 | "
total_billtipsexsmokerdaytimesizetip_share
016.991.01FemaleNoSunDinner20.059447
5012.542.50MaleNoSunDinner20.199362
10011.352.50FemaleYesFriDinner20.220264
15014.072.50MaleNoSunDinner20.177683
20018.714.00MaleYesThurLunch30.213789
\n", 1086 | "
" 1087 | ], 1088 | "text/plain": [ 1089 | " total_bill tip sex smoker day time size tip_share\n", 1090 | "0 16.99 1.01 Female No Sun Dinner 2 0.059447\n", 1091 | "50 12.54 2.50 Male No Sun Dinner 2 0.199362\n", 1092 | "100 11.35 2.50 Female Yes Fri Dinner 2 0.220264\n", 1093 | "150 14.07 2.50 Male No Sun Dinner 2 0.177683\n", 1094 | "200 18.71 4.00 Male Yes Thur Lunch 3 0.213789" 1095 | ] 1096 | }, 1097 | "execution_count": 11, 1098 | "metadata": {}, 1099 | "output_type": "execute_result" 1100 | } 1101 | ], 1102 | "source": [ 1103 | "# Slicing a DataFrame to view 1 every 50 rows\n", 1104 | "tips[::50]" 1105 | ] 1106 | }, 1107 | { 1108 | "cell_type": "markdown", 1109 | "metadata": {}, 1110 | "source": [ 1111 | "**Warning**\n", 1112 | "\n", 1113 | "While indexing in R starts at 1, it starts at 0 in Python. For example, use index `2` to select the third element." 1114 | ] 1115 | }, 1116 | { 1117 | "cell_type": "markdown", 1118 | "metadata": {}, 1119 | "source": [ 1120 | "**Exercise**\n", 1121 | "\n", 1122 | "1. Create a subset of the mtcars data which includes cars that have a weight larger than 3 or four cylinders. How many cars are in that dataset?\n", 1123 | "2. Slice the mtcars dataset to show the first 10 even rows, i.e., the second, fourth, etc row.\n", 1124 | "3. Add a new variable which contains the ratio of horse power to weight.\n", 1125 | "\n", 1126 | "Extension\n", 1127 | "\n", 1128 | "4. Read in the tips dataset (tips.csv).\n", 1129 | "5. Calculate the mean tip for for each day.\n", 1130 | "6. Add a new variable which contains the party size as a binary factor (choose your own cutoff). Hint: The `pd.cut` function works similarly to R's `cut` function.\n", 1131 | "7. Ensure that the two categories are \"small/medium\" (four or fewer people) and \"large\" (more than four people) and labeled appropriately." 1132 | ] 1133 | }, 1134 | { 1135 | "cell_type": "code", 1136 | "execution_count": 12, 1137 | "metadata": { 1138 | "tags": [ 1139 | "skip" 1140 | ] 1141 | }, 1142 | "outputs": [ 1143 | { 1144 | "data": { 1145 | "text/html": [ 1146 | "
\n", 1147 | "\n", 1160 | "\n", 1161 | " \n", 1162 | " \n", 1163 | " \n", 1164 | " \n", 1165 | " \n", 1166 | " \n", 1167 | " \n", 1168 | " \n", 1169 | " \n", 1170 | " \n", 1171 | " \n", 1172 | " \n", 1173 | " \n", 1174 | " \n", 1175 | " \n", 1176 | " \n", 1177 | " \n", 1178 | " \n", 1179 | " \n", 1180 | " \n", 1181 | " \n", 1182 | " \n", 1183 | " \n", 1184 | " \n", 1185 | " \n", 1186 | " \n", 1187 | " \n", 1188 | " \n", 1189 | " \n", 1190 | " \n", 1191 | " \n", 1192 | " \n", 1193 | " \n", 1194 | " \n", 1195 | " \n", 1196 | " \n", 1197 | " \n", 1198 | " \n", 1199 | " \n", 1200 | " \n", 1201 | " \n", 1202 | " \n", 1203 | " \n", 1204 | " \n", 1205 | " \n", 1206 | " \n", 1207 | " \n", 1208 | " \n", 1209 | " \n", 1210 | " \n", 1211 | " \n", 1212 | " \n", 1213 | " \n", 1214 | " \n", 1215 | " \n", 1216 | " \n", 1217 | " \n", 1218 | " \n", 1219 | " \n", 1220 | " \n", 1221 | " \n", 1222 | " \n", 1223 | " \n", 1224 | " \n", 1225 | " \n", 1226 | " \n", 1227 | " \n", 1228 | " \n", 1229 | " \n", 1230 | " \n", 1231 | "
total_billtipsexsmokerdaytimesizesize_f
016.991.01FemaleNoSunDinner2small/medium
110.341.66MaleNoSunDinner3small/medium
221.013.50MaleNoSunDinner3small/medium
323.683.31MaleNoSunDinner2small/medium
424.593.61FemaleNoSunDinner4small/medium
\n", 1232 | "
" 1233 | ], 1234 | "text/plain": [ 1235 | " total_bill tip sex smoker day time size size_f\n", 1236 | "0 16.99 1.01 Female No Sun Dinner 2 small/medium\n", 1237 | "1 10.34 1.66 Male No Sun Dinner 3 small/medium\n", 1238 | "2 21.01 3.50 Male No Sun Dinner 3 small/medium\n", 1239 | "3 23.68 3.31 Male No Sun Dinner 2 small/medium\n", 1240 | "4 24.59 3.61 Female No Sun Dinner 4 small/medium" 1241 | ] 1242 | }, 1243 | "execution_count": 12, 1244 | "metadata": {}, 1245 | "output_type": "execute_result" 1246 | } 1247 | ], 1248 | "source": [ 1249 | "# solution\n", 1250 | "mtcars.query(\"wt > 3 | cyl == 4\").shape\n", 1251 | "mtcars[1:20:2]\n", 1252 | "mtcars[\"hp2wt\"] = mtcars[\"hp\"] / mtcars[\"wt\"]\n", 1253 | "\n", 1254 | "tips = pd.read_csv(\"Data/tips.csv\")\n", 1255 | "import numpy as np\n", 1256 | "tips.groupby(\"day\").agg({\"tip\" : np.mean})\n", 1257 | "tips[\"size_f\"] = pd.cut(tips[\"size\"], bins=2)\n", 1258 | "bins_size = pd.IntervalIndex.from_breaks([0,4,7])\n", 1259 | "tips[\"size_f\"] = pd.cut(tips[\"size\"], bins_size).cat.rename_categories([\"small/medium\", \"large\"])\n", 1260 | "tips.head()" 1261 | ] 1262 | }, 1263 | { 1264 | "cell_type": "markdown", 1265 | "metadata": {}, 1266 | "source": [ 1267 | "## Dictionaries" 1268 | ] 1269 | }, 1270 | { 1271 | "cell_type": "markdown", 1272 | "metadata": {}, 1273 | "source": [ 1274 | "Dictionaries are objects which hold an unordered collection of key-value pairs. They are defined with curly braces using the following notation: `{key : value}`, with different key-value pairs being separated with commas." 1275 | ] 1276 | }, 1277 | { 1278 | "cell_type": "markdown", 1279 | "metadata": {}, 1280 | "source": [ 1281 | "This can be used to define pairs of old and new names for the `.rename` method." 1282 | ] 1283 | }, 1284 | { 1285 | "cell_type": "code", 1286 | "execution_count": 13, 1287 | "metadata": {}, 1288 | "outputs": [ 1289 | { 1290 | "data": { 1291 | "text/html": [ 1292 | "
\n", 1293 | "\n", 1306 | "\n", 1307 | " \n", 1308 | " \n", 1309 | " \n", 1310 | " \n", 1311 | " \n", 1312 | " \n", 1313 | " \n", 1314 | " \n", 1315 | " \n", 1316 | " \n", 1317 | " \n", 1318 | " \n", 1319 | " \n", 1320 | " \n", 1321 | " \n", 1322 | " \n", 1323 | " \n", 1324 | " \n", 1325 | " \n", 1326 | " \n", 1327 | " \n", 1328 | " \n", 1329 | " \n", 1330 | " \n", 1331 | " \n", 1332 | " \n", 1333 | " \n", 1334 | " \n", 1335 | " \n", 1336 | " \n", 1337 | " \n", 1338 | " \n", 1339 | " \n", 1340 | " \n", 1341 | " \n", 1342 | " \n", 1343 | " \n", 1344 | " \n", 1345 | " \n", 1346 | " \n", 1347 | " \n", 1348 | " \n", 1349 | " \n", 1350 | " \n", 1351 | " \n", 1352 | " \n", 1353 | " \n", 1354 | " \n", 1355 | " \n", 1356 | " \n", 1357 | " \n", 1358 | " \n", 1359 | " \n", 1360 | " \n", 1361 | " \n", 1362 | " \n", 1363 | " \n", 1364 | " \n", 1365 | " \n", 1366 | " \n", 1367 | " \n", 1368 | " \n", 1369 | " \n", 1370 | " \n", 1371 | " \n", 1372 | " \n", 1373 | " \n", 1374 | " \n", 1375 | " \n", 1376 | " \n", 1377 | "
total_billtipsexsmokerdaytime_of_dayparty_sizesize_f
016.991.01FemaleNoSunDinner2small/medium
110.341.66MaleNoSunDinner3small/medium
221.013.50MaleNoSunDinner3small/medium
323.683.31MaleNoSunDinner2small/medium
424.593.61FemaleNoSunDinner4small/medium
\n", 1378 | "
" 1379 | ], 1380 | "text/plain": [ 1381 | " total_bill tip sex smoker day time_of_day party_size size_f\n", 1382 | "0 16.99 1.01 Female No Sun Dinner 2 small/medium\n", 1383 | "1 10.34 1.66 Male No Sun Dinner 3 small/medium\n", 1384 | "2 21.01 3.50 Male No Sun Dinner 3 small/medium\n", 1385 | "3 23.68 3.31 Male No Sun Dinner 2 small/medium\n", 1386 | "4 24.59 3.61 Female No Sun Dinner 4 small/medium" 1387 | ] 1388 | }, 1389 | "execution_count": 13, 1390 | "metadata": {}, 1391 | "output_type": "execute_result" 1392 | } 1393 | ], 1394 | "source": [ 1395 | "tips_2 = tips.rename(columns = {\"time\" : \"time_of_day\", \"size\" : \"party_size\"})\n", 1396 | "tips_2.head()" 1397 | ] 1398 | }, 1399 | { 1400 | "cell_type": "markdown", 1401 | "metadata": {}, 1402 | "source": [ 1403 | "Dictionaries are also used to specify which columns should be summarised or aggregated in which way, using the `.agg` method. Dictionaries can also hold lists as values, allowing us to specify several summary functions for a column.\n", 1404 | "\n", 1405 | "Some fundamental summary functions such as `min` and `max` are provided by base Python. More statistical summary functions such as `mean` and `median` are provided by the **NumPy** package." 1406 | ] 1407 | }, 1408 | { 1409 | "cell_type": "code", 1410 | "execution_count": 14, 1411 | "metadata": {}, 1412 | "outputs": [ 1413 | { 1414 | "data": { 1415 | "text/html": [ 1416 | "
\n", 1417 | "\n", 1430 | "\n", 1431 | " \n", 1432 | " \n", 1433 | " \n", 1434 | " \n", 1435 | " \n", 1436 | " \n", 1437 | " \n", 1438 | " \n", 1439 | " \n", 1440 | " \n", 1441 | " \n", 1442 | " \n", 1443 | " \n", 1444 | " \n", 1445 | " \n", 1446 | " \n", 1447 | " \n", 1448 | " \n", 1449 | " \n", 1450 | " \n", 1451 | " \n", 1452 | " \n", 1453 | " \n", 1454 | " \n", 1455 | "
sizetip
maxNaN10.000000
meanNaN2.998279
min1.01.000000
\n", 1456 | "
" 1457 | ], 1458 | "text/plain": [ 1459 | " size tip\n", 1460 | "max NaN 10.000000\n", 1461 | "mean NaN 2.998279\n", 1462 | "min 1.0 1.000000" 1463 | ] 1464 | }, 1465 | "execution_count": 14, 1466 | "metadata": {}, 1467 | "output_type": "execute_result" 1468 | } 1469 | ], 1470 | "source": [ 1471 | "import numpy as np\n", 1472 | "tips.agg({\"size\" : min, \"tip\" : [min, max, np.mean]})" 1473 | ] 1474 | }, 1475 | { 1476 | "cell_type": "markdown", 1477 | "metadata": {}, 1478 | "source": [ 1479 | "**Tip**\n", 1480 | "\n", 1481 | "In R, the `%>%` operator from the **magrittr** package allows us to make pipelines of a series of steps on an object, e.g., a data frame. In Python, the `.` can be used to chain multiple methods on an object together into one line of code, without having to reassign each time." 1482 | ] 1483 | }, 1484 | { 1485 | "cell_type": "markdown", 1486 | "metadata": {}, 1487 | "source": [ 1488 | "## Working with Different Data Types" 1489 | ] 1490 | }, 1491 | { 1492 | "cell_type": "markdown", 1493 | "metadata": {}, 1494 | "source": [ 1495 | "A `Series` in a `DataFrame` can hold different types of data such as numeric data, categorical data, datetimes, etc. For most common data types other than numeric, we need so-called accessors to access the type-specific attributes and methods. For example, the accessor for categorical data is `.cat` and the methods include `.cat.rename_categories()`, `.cat.remove_unused_categories()`, and `.cat.reorder_categories()`." 1496 | ] 1497 | }, 1498 | { 1499 | "cell_type": "markdown", 1500 | "metadata": {}, 1501 | "source": [ 1502 | "**Warning**\n", 1503 | "\n", 1504 | "It is, of course, possible to access the categorical data via `.values` and manipulate this directly. However, the resulting object is an array, not a `Series`." 1505 | ] 1506 | } 1507 | ], 1508 | "metadata": { 1509 | "kernelspec": { 1510 | "display_name": "Python 3", 1511 | "language": "python", 1512 | "name": "python3" 1513 | }, 1514 | "language_info": { 1515 | "codemirror_mode": { 1516 | "name": "ipython", 1517 | "version": 3 1518 | }, 1519 | "file_extension": ".py", 1520 | "mimetype": "text/x-python", 1521 | "name": "python", 1522 | "nbconvert_exporter": "python", 1523 | "pygments_lexer": "ipython3", 1524 | "version": "3.6.6" 1525 | } 1526 | }, 1527 | "nbformat": 4, 1528 | "nbformat_minor": 2 1529 | } 1530 | -------------------------------------------------------------------------------- /1-05_Modelling.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": { 7 | "tags": [ 8 | "skip" 9 | ] 10 | }, 11 | "outputs": [], 12 | "source": [ 13 | "# Options for all cells \n", 14 | "import pandas as pd\n", 15 | "# change display setting of pandas\n", 16 | "pd.set_option('display.notebook_repr_html', False)\n", 17 | "# Setting the graphics\n", 18 | "%matplotlib inline\n", 19 | "# suppress all warnings (since anova gives a warning)\n", 20 | "import warnings\n", 21 | "warnings.filterwarnings(\"ignore\")" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 1, 27 | "metadata": { 28 | "tags": [ 29 | "skip" 30 | ] 31 | }, 32 | "outputs": [], 33 | "source": [ 34 | "import pandas as pd\n", 35 | "tips = pd.read_csv(\"Data/tips.csv\")" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "## Statistical Modelling" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "There are a number of packages that contain functions for statistics and modelling in the Python standard library. We will use the **statsmodel** package which contains a large number of models and statistical tests, organised in several modules. Some of the more common model fitting functions can be found in the following table:\n", 50 | "\n", 51 | "| Package/Module | Function | Model |\n", 52 | "|----------------|----------|-------|\n", 53 | "| `statsmodels.formula.api` | `ols`/`OLS` | Linear Regression by OLS (Ordinary Least Squares) |\n", 54 | "| `statsmodels.formula.api` | `gls`/`GLS` | Linear Regression by GLS (Generalised Least Squares) |\n", 55 | "| `statsmodels.api` | `GLM` | GLM (Generalised Linear Model) |\n", 56 | "| `statsmodels.api` | `RLM` | RLM (Robust Linear Model) |\n", 57 | "| `statsmodels.tsa.arima_model` | `ARIMA` | Time Series Analysis - ARIMA Model |\n", 58 | "| `statsmodels.formula.api` | `phreg` | Survival Analysis - Cox Models |\n", 59 | "| `statsmodels.api` | `stats.anova_lm` | ANOVA (Analysis of Variance)\n", 60 | "\n", 61 | "\n", 62 | "For a full list of functionality, see the package's site [http://www.statsmodels.org/dev/index.html](http://www.statsmodels.org/dev/index.html)." 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "metadata": {}, 68 | "source": [ 69 | "Similar to modelling in R, the model is specified through a formula with a tilde (`~`) which typically has the response on the left-hand side and the independent variables on the right-hand side. The standard formula notation is the same as in R, e.g.,\n", 70 | "\n", 71 | "| Python Formula | Model | Actual Model Formula |\n", 72 | "|----------------|-------|----------------------|\n", 73 | "| `y ~ x` | Y against X + an intercept | $y = a + bx + \\epsilon$ |\n", 74 | "| `y ~ x-1` | Y against X (no intercept) | $y = bx + \\epsilon$ |\n", 75 | "| `y ~ x+z` | Y against X and Z + an intercept | $y = a + bx + cz + \\epsilon$ |\n", 76 | "| `y ~ x:z` | Y against the X/Z interaction term | $y = a + bxz + \\epsilon$ |\n", 77 | "\n", 78 | "where in the actual model formulae above, $\\epsilon$ is the error term." 79 | ] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": {}, 84 | "source": [ 85 | "In R, we typically provide a modelling function with the formula and the data and it returns a fitted model. Here, model specification and model fitting are two separate steps. Using the `ols` function, we specify a linear model for the tip as explained by the total amount of the bill." 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 2, 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "import statsmodels.formula.api as smf\n", 95 | "\n", 96 | "m1 = smf.ols(formula=\"tip ~ total_bill\", data=tips)" 97 | ] 98 | }, 99 | { 100 | "cell_type": "markdown", 101 | "metadata": {}, 102 | "source": [ 103 | "The resulting model object has a `.fit` method which is then used to estimate the parameters of the model. For the fitted model object, further methods and attributes are available, e.g., a summary method (`.summary`) and the estimated parameters (`.params`)." 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 3, 109 | "metadata": {}, 110 | "outputs": [ 111 | { 112 | "name": "stdout", 113 | "output_type": "stream", 114 | "text": [ 115 | " OLS Regression Results \n", 116 | "==============================================================================\n", 117 | "Dep. Variable: tip R-squared: 0.457\n", 118 | "Model: OLS Adj. R-squared: 0.454\n", 119 | "Method: Least Squares F-statistic: 203.4\n", 120 | "Date: Fri, 17 Aug 2018 Prob (F-statistic): 6.69e-34\n", 121 | "Time: 17:52:56 Log-Likelihood: -350.54\n", 122 | "No. Observations: 244 AIC: 705.1\n", 123 | "Df Residuals: 242 BIC: 712.1\n", 124 | "Df Model: 1 \n", 125 | "Covariance Type: nonrobust \n", 126 | "==============================================================================\n", 127 | " coef std err t P>|t| [0.025 0.975]\n", 128 | "------------------------------------------------------------------------------\n", 129 | "Intercept 0.9203 0.160 5.761 0.000 0.606 1.235\n", 130 | "total_bill 0.1050 0.007 14.260 0.000 0.091 0.120\n", 131 | "==============================================================================\n", 132 | "Omnibus: 20.185 Durbin-Watson: 2.151\n", 133 | "Prob(Omnibus): 0.000 Jarque-Bera (JB): 37.750\n", 134 | "Skew: 0.443 Prob(JB): 6.35e-09\n", 135 | "Kurtosis: 4.711 Cond. No. 53.0\n", 136 | "==============================================================================\n", 137 | "\n", 138 | "Warnings:\n", 139 | "[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.\n" 140 | ] 141 | } 142 | ], 143 | "source": [ 144 | "mf1 = m1.fit()\n", 145 | "print(mf1.summary())" 146 | ] 147 | }, 148 | { 149 | "cell_type": "markdown", 150 | "metadata": {}, 151 | "source": [ 152 | "**Exercise**\n", 153 | "\n", 154 | "Fit a linear model for `tip` as explained through `total_bill` and `smoker`." 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": 4, 160 | "metadata": { 161 | "tags": [ 162 | "skip" 163 | ] 164 | }, 165 | "outputs": [ 166 | { 167 | "name": "stdout", 168 | "output_type": "stream", 169 | "text": [ 170 | " OLS Regression Results \n", 171 | "==============================================================================\n", 172 | "Dep. Variable: tip R-squared: 0.459\n", 173 | "Model: OLS Adj. R-squared: 0.455\n", 174 | "Method: Least Squares F-statistic: 102.4\n", 175 | "Date: Fri, 17 Aug 2018 Prob (F-statistic): 6.57e-33\n", 176 | "Time: 17:52:57 Log-Likelihood: -349.93\n", 177 | "No. Observations: 244 AIC: 705.9\n", 178 | "Df Residuals: 241 BIC: 716.3\n", 179 | "Df Model: 2 \n", 180 | "Covariance Type: nonrobust \n", 181 | "=================================================================================\n", 182 | " coef std err t P>|t| [0.025 0.975]\n", 183 | "---------------------------------------------------------------------------------\n", 184 | "Intercept 0.9632 0.164 5.861 0.000 0.639 1.287\n", 185 | "smoker[T.Yes] -0.1489 0.135 -1.102 0.272 -0.415 0.117\n", 186 | "total_bill 0.1057 0.007 14.309 0.000 0.091 0.120\n", 187 | "==============================================================================\n", 188 | "Omnibus: 23.655 Durbin-Watson: 2.150\n", 189 | "Prob(Omnibus): 0.000 Jarque-Bera (JB): 43.834\n", 190 | "Skew: 0.524 Prob(JB): 3.03e-10\n", 191 | "Kurtosis: 4.792 Cond. No. 57.0\n", 192 | "==============================================================================\n", 193 | "\n", 194 | "Warnings:\n", 195 | "[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.\n" 196 | ] 197 | } 198 | ], 199 | "source": [ 200 | "# solutions\n", 201 | "import statsmodels.formula.api as smf\n", 202 | "model_s = smf.ols(formula=\"tip ~ total_bill + smoker\", data=tips)\n", 203 | "print(model_s.fit().summary())\n" 204 | ] 205 | }, 206 | { 207 | "cell_type": "markdown", 208 | "metadata": {}, 209 | "source": [ 210 | "Alternatively, we can fit a model with an interaction between `total_bill` and `smoker`, and compare this to the simpler model via an ANOVA (analysis of variance)." 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": 8, 216 | "metadata": {}, 217 | "outputs": [ 218 | { 219 | "name": "stderr", 220 | "output_type": "stream", 221 | "text": [ 222 | "/Users/hfrick/anaconda/envs/nb2docx/lib/python3.6/site-packages/scipy/stats/_distn_infrastructure.py:879: RuntimeWarning: invalid value encountered in greater\n", 223 | " return (self.a < x) & (x < self.b)\n", 224 | "/Users/hfrick/anaconda/envs/nb2docx/lib/python3.6/site-packages/scipy/stats/_distn_infrastructure.py:879: RuntimeWarning: invalid value encountered in less\n", 225 | " return (self.a < x) & (x < self.b)\n", 226 | "/Users/hfrick/anaconda/envs/nb2docx/lib/python3.6/site-packages/scipy/stats/_distn_infrastructure.py:1821: RuntimeWarning: invalid value encountered in less_equal\n", 227 | " cond2 = cond0 & (x <= self.a)\n" 228 | ] 229 | }, 230 | { 231 | "data": { 232 | "text/html": [ 233 | "
\n", 234 | "\n", 247 | "\n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | "
df_residssrdf_diffss_diffFPr(>F)
0242.0252.7887440.0NaNNaNNaN
1240.0229.8093862.022.97935811.9991750.000011
\n", 280 | "
" 281 | ], 282 | "text/plain": [ 283 | " df_resid ssr df_diff ss_diff F Pr(>F)\n", 284 | "0 242.0 252.788744 0.0 NaN NaN NaN\n", 285 | "1 240.0 229.809386 2.0 22.979358 11.999175 0.000011" 286 | ] 287 | }, 288 | "execution_count": 8, 289 | "metadata": {}, 290 | "output_type": "execute_result" 291 | } 292 | ], 293 | "source": [ 294 | "import statsmodels.api as sm\n", 295 | "\n", 296 | "mf2 = smf.ols(formula=\"tip ~ total_bill + smoker + total_bill:smoker\", data=tips).fit() # or total_bill*smoker\n", 297 | "#mf2.summary()\n", 298 | "sm.stats.anova_lm(mf1, mf2)" 299 | ] 300 | }, 301 | { 302 | "cell_type": "markdown", 303 | "metadata": {}, 304 | "source": [ 305 | "**Warning : Python Warnings**\n", 306 | "\n", 307 | "You may notice a warning appear when running the above function. This occurs due to the `NaN` values in our output; however, this function will always produce NaN values there so this is nothing to worry about.\n", 308 | "\n", 309 | "Warnings appear red in Jupyter, but do not stop the computation of the function, so can *in some cases* be ignored." 310 | ] 311 | }, 312 | { 313 | "cell_type": "markdown", 314 | "metadata": {}, 315 | "source": [ 316 | "## Machine Learning" 317 | ] 318 | }, 319 | { 320 | "cell_type": "markdown", 321 | "metadata": {}, 322 | "source": [ 323 | "While R has its strength in statistical modelling, Python shines in machine learning, in particular with the **scikit-learn** package." 324 | ] 325 | }, 326 | { 327 | "cell_type": "markdown", 328 | "metadata": {}, 329 | "source": [ 330 | "### Getting Data in the Right Format" 331 | ] 332 | }, 333 | { 334 | "cell_type": "markdown", 335 | "metadata": {}, 336 | "source": [ 337 | "So far, we stored all our data in one `DataFrame`. The functions in **scikit-learn** for models and algorithms expect the features, or explanatory variables, and the target, or response, in two separate objects: The features are in a 2-dimensional array with one row per sample or observation and one column per feature or variable. The target is in an one-dimensional array." 338 | ] 339 | }, 340 | { 341 | "cell_type": "markdown", 342 | "metadata": {}, 343 | "source": [ 344 | "We can convert a `DataFrame` using the `values` attribute. Here we will use the tips data to create an array of features and the one-dimensional array of the tips as our target." 345 | ] 346 | }, 347 | { 348 | "cell_type": "code", 349 | "execution_count": 9, 350 | "metadata": {}, 351 | "outputs": [], 352 | "source": [ 353 | "import pandas as pd\n", 354 | "tips_data = tips.drop(\"tip\", axis=1).values\n", 355 | "tips_target = tips[\"tip\"].values" 356 | ] 357 | }, 358 | { 359 | "cell_type": "markdown", 360 | "metadata": {}, 361 | "source": [ 362 | "The example datasets in **scikit-learn** come in form of dictionaries which hold the two arrays for features and target along with the corresponding names. Here we will use the iris data which contains three different species of iris flowers as the target and four different measurements (length and width of the sepal and petal, respectively) as the features." 363 | ] 364 | }, 365 | { 366 | "cell_type": "code", 367 | "execution_count": 10, 368 | "metadata": {}, 369 | "outputs": [ 370 | { 371 | "data": { 372 | "text/plain": [ 373 | "dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names'])" 374 | ] 375 | }, 376 | "execution_count": 10, 377 | "metadata": {}, 378 | "output_type": "execute_result" 379 | } 380 | ], 381 | "source": [ 382 | "from sklearn import datasets \n", 383 | "iris = datasets.load_iris()\n", 384 | "iris.keys()" 385 | ] 386 | }, 387 | { 388 | "cell_type": "markdown", 389 | "metadata": {}, 390 | "source": [ 391 | "In the following we will use the generic names `X` and `y` for the features and target, respectively. Python allows us to assign multiple objects at once as follows:" 392 | ] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": 11, 397 | "metadata": {}, 398 | "outputs": [], 399 | "source": [ 400 | "X, y = iris.data, iris.target" 401 | ] 402 | }, 403 | { 404 | "cell_type": "markdown", 405 | "metadata": {}, 406 | "source": [ 407 | "### Classification" 408 | ] 409 | }, 410 | { 411 | "cell_type": "markdown", 412 | "metadata": {}, 413 | "source": [ 414 | "Classification is common machine learning task so we will use this as example to illustrate a common workflow with **scikit-learn**. \n", 415 | "\n", 416 | "Similar to working with **statsmodel**, specifying a model, also called instantiating a model, is a separate step from fitting a model. Here we will first instantiate a K-nearest neighbor classifier and then fit it on the iris data." 417 | ] 418 | }, 419 | { 420 | "cell_type": "code", 421 | "execution_count": 12, 422 | "metadata": {}, 423 | "outputs": [ 424 | { 425 | "data": { 426 | "text/plain": [ 427 | "KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',\n", 428 | " metric_params=None, n_jobs=1, n_neighbors=5, p=2,\n", 429 | " weights='uniform')" 430 | ] 431 | }, 432 | "execution_count": 12, 433 | "metadata": {}, 434 | "output_type": "execute_result" 435 | } 436 | ], 437 | "source": [ 438 | "from sklearn import neighbors\n", 439 | "\n", 440 | "# create the model\n", 441 | "knn = neighbors.KNeighborsClassifier(n_neighbors=5)\n", 442 | "\n", 443 | "# fit the model\n", 444 | "knn.fit(X, y)" 445 | ] 446 | }, 447 | { 448 | "cell_type": "markdown", 449 | "metadata": {}, 450 | "source": [ 451 | "Predictions can be accessed with the `.predict` method for the model object." 452 | ] 453 | }, 454 | { 455 | "cell_type": "code", 456 | "execution_count": 13, 457 | "metadata": {}, 458 | "outputs": [ 459 | { 460 | "data": { 461 | "text/plain": [ 462 | "array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", 463 | " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n", 464 | " 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n", 465 | " 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,\n", 466 | " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2,\n", 467 | " 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,\n", 468 | " 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])" 469 | ] 470 | }, 471 | "execution_count": 13, 472 | "metadata": {}, 473 | "output_type": "execute_result" 474 | } 475 | ], 476 | "source": [ 477 | "knn.predict(X)" 478 | ] 479 | }, 480 | { 481 | "cell_type": "code", 482 | "execution_count": 14, 483 | "metadata": { 484 | "tags": [ 485 | "skip" 486 | ] 487 | }, 488 | "outputs": [ 489 | { 490 | "name": "stdout", 491 | "output_type": "stream", 492 | "text": [ 493 | "['versicolor']\n" 494 | ] 495 | } 496 | ], 497 | "source": [ 498 | "# What kind of iris has 3cm x 5cm sepal and 4cm x 2cm petal?\n", 499 | "result = knn.predict([[3, 5, 4, 2],])\n", 500 | "\n", 501 | "print(iris.target_names[result])" 502 | ] 503 | }, 504 | { 505 | "cell_type": "markdown", 506 | "metadata": {}, 507 | "source": [ 508 | "### Model Validation" 509 | ] 510 | }, 511 | { 512 | "cell_type": "markdown", 513 | "metadata": {}, 514 | "source": [ 515 | "These predictions can be used to calculate the accuracy of the predictions. However, choosing a model based on its accuracy on the same data that was used to fit the model often leads to choosing a model too closely adapted to the data.\n", 516 | "\n", 517 | "To avoid this over-fitting, the data is typically split into train and test data. We can easily do this with the `train_test_split` function and then train our classifier only on the training set." 518 | ] 519 | }, 520 | { 521 | "cell_type": "code", 522 | "execution_count": 15, 523 | "metadata": {}, 524 | "outputs": [ 525 | { 526 | "data": { 527 | "text/plain": [ 528 | "KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',\n", 529 | " metric_params=None, n_jobs=1, n_neighbors=5, p=2,\n", 530 | " weights='uniform')" 531 | ] 532 | }, 533 | "execution_count": 15, 534 | "metadata": {}, 535 | "output_type": "execute_result" 536 | } 537 | ], 538 | "source": [ 539 | "from sklearn import model_selection\n", 540 | "\n", 541 | "X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y)\n", 542 | "\n", 543 | "knn = neighbors.KNeighborsClassifier(n_neighbors=5)\n", 544 | "knn.fit(X_train, y_train)" 545 | ] 546 | }, 547 | { 548 | "cell_type": "markdown", 549 | "metadata": {}, 550 | "source": [ 551 | "Now we can calculate the accuracy on the test set." 552 | ] 553 | }, 554 | { 555 | "cell_type": "code", 556 | "execution_count": 16, 557 | "metadata": {}, 558 | "outputs": [ 559 | { 560 | "data": { 561 | "text/plain": [ 562 | "0.9210526315789473" 563 | ] 564 | }, 565 | "execution_count": 16, 566 | "metadata": {}, 567 | "output_type": "execute_result" 568 | } 569 | ], 570 | "source": [ 571 | "from sklearn import metrics\n", 572 | "\n", 573 | "y_pred = knn.predict(X_test)\n", 574 | "metrics.accuracy_score(y_test, y_pred)" 575 | ] 576 | }, 577 | { 578 | "cell_type": "markdown", 579 | "metadata": {}, 580 | "source": [ 581 | "This is also available as a method, `.score`, for the model object." 582 | ] 583 | }, 584 | { 585 | "cell_type": "code", 586 | "execution_count": 17, 587 | "metadata": {}, 588 | "outputs": [ 589 | { 590 | "data": { 591 | "text/plain": [ 592 | "0.9210526315789473" 593 | ] 594 | }, 595 | "execution_count": 17, 596 | "metadata": {}, 597 | "output_type": "execute_result" 598 | } 599 | ], 600 | "source": [ 601 | "knn.score(X_test, y_test)" 602 | ] 603 | }, 604 | { 605 | "cell_type": "markdown", 606 | "metadata": {}, 607 | "source": [ 608 | "Cross-validation takes this idea a step further: The data is split into k folds and the model is fit k times, always leaving one of the folds as the test set." 609 | ] 610 | }, 611 | { 612 | "cell_type": "code", 613 | "execution_count": 18, 614 | "metadata": {}, 615 | "outputs": [ 616 | { 617 | "data": { 618 | "text/plain": [ 619 | "0.9666666666666668" 620 | ] 621 | }, 622 | "execution_count": 18, 623 | "metadata": {}, 624 | "output_type": "execute_result" 625 | } 626 | ], 627 | "source": [ 628 | "from sklearn import model_selection\n", 629 | "\n", 630 | "cv = model_selection.cross_val_score(neighbors.KNeighborsClassifier(5), X, y, cv=10)\n", 631 | "cv.mean()" 632 | ] 633 | }, 634 | { 635 | "cell_type": "markdown", 636 | "metadata": {}, 637 | "source": [ 638 | "The modules in **scikit-learn** are designed such that we can easily swap out one model for another." 639 | ] 640 | }, 641 | { 642 | "cell_type": "markdown", 643 | "metadata": {}, 644 | "source": [ 645 | "**Exercise**\n", 646 | "\n", 647 | "1. Use the `SVC` function from `sklearn.svm` to solve the iris classification problem with a support vector classifier. What is the accuracy on the training set?\n", 648 | "\n", 649 | "Extension:\n", 650 | "\n", 651 | "2. What is the average accuracy when using a 10-fold cross-validation?" 652 | ] 653 | }, 654 | { 655 | "cell_type": "code", 656 | "execution_count": 19, 657 | "metadata": { 658 | "tags": [ 659 | "skip" 660 | ] 661 | }, 662 | "outputs": [ 663 | { 664 | "data": { 665 | "text/plain": [ 666 | "0.9800000000000001" 667 | ] 668 | }, 669 | "execution_count": 19, 670 | "metadata": {}, 671 | "output_type": "execute_result" 672 | } 673 | ], 674 | "source": [ 675 | "# solution\n", 676 | "from sklearn import svm \n", 677 | "\n", 678 | "svc = svm.SVC()\n", 679 | "svc.fit(X_train, y_train)\n", 680 | "knn.score(X_test, y_test)\n", 681 | "\n", 682 | "cv = model_selection.cross_val_score(svm.SVC(), X, y, cv=10)\n", 683 | "cv.mean()" 684 | ] 685 | } 686 | ], 687 | "metadata": { 688 | "celltoolbar": "Tags", 689 | "kernelspec": { 690 | "display_name": "Python 3", 691 | "language": "python", 692 | "name": "python3" 693 | }, 694 | "language_info": { 695 | "codemirror_mode": { 696 | "name": "ipython", 697 | "version": 3 698 | }, 699 | "file_extension": ".py", 700 | "mimetype": "text/x-python", 701 | "name": "python", 702 | "nbconvert_exporter": "python", 703 | "pygments_lexer": "ipython3", 704 | "version": "3.6.6" 705 | } 706 | }, 707 | "nbformat": 4, 708 | "nbformat_minor": 2 709 | } 710 | -------------------------------------------------------------------------------- /1-06_More Packages.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "tags": [ 8 | "skip" 9 | ] 10 | }, 11 | "outputs": [], 12 | "source": [ 13 | "# Options for all cells \n", 14 | "import pandas as pd\n", 15 | "# change display setting of pandas\n", 16 | "pd.set_option('display.notebook_repr_html', False)\n", 17 | "# Setting the graphics\n", 18 | "%matplotlib inline\n", 19 | "# suppress all warnings (since anova gives a warning)\n", 20 | "import warnings\n", 21 | "warnings.filterwarnings(\"ignore\")" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "# Taking Python further" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "Like R, Python’s strength comes from the range of packages that are being developed by the open source community." 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "So far, we have introduced the popular packages for data science. All of these are part of the standard distribution installed with Anaconda. Below are examples of more great packages for visualisation, modelling and general data science." 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "## More Visualisation" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "Python has a lot of packages created for data visualisation. **Seaborn** creates flexible graphics for plotting data but it doesn’t follow The Grammar of Graphics that R users are familiar with from **ggplot2**. **Seaborn** also has a limited number of diagnostic plots for visualising our models. To overcome these, we could use:" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "- **ggplot** - a plotting system for Python based on **ggplot2**\n", 64 | "- **bokeh** - a package native to Python and using The Grammar of Graphics. You can also use it to create interactive plots in either JSON or HTML for web applications.\n", 65 | "- **Yellowbrick** - a package extending on **scikit-learn** for creating diagnostic plots to help during model selection." 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "### Bokeh Example" 73 | ] 74 | }, 75 | { 76 | "cell_type": "markdown", 77 | "metadata": {}, 78 | "source": [ 79 | "Below is an example showing how to create an interactive plot in a notebook using **bokeh**:" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": 1, 85 | "metadata": {}, 86 | "outputs": [ 87 | { 88 | "data": { 89 | "text/html": [ 90 | "\n", 91 | "
\n", 92 | " \n", 93 | " Loading BokehJS ...\n", 94 | "
" 95 | ] 96 | }, 97 | "metadata": {}, 98 | "output_type": "display_data" 99 | }, 100 | { 101 | "data": { 102 | "application/javascript": [ 103 | "\n", 104 | "(function(root) {\n", 105 | " function now() {\n", 106 | " return new Date();\n", 107 | " }\n", 108 | "\n", 109 | " var force = true;\n", 110 | "\n", 111 | " if (typeof (root._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n", 112 | " root._bokeh_onload_callbacks = [];\n", 113 | " root._bokeh_is_loading = undefined;\n", 114 | " }\n", 115 | "\n", 116 | " var JS_MIME_TYPE = 'application/javascript';\n", 117 | " var HTML_MIME_TYPE = 'text/html';\n", 118 | " var EXEC_MIME_TYPE = 'application/vnd.bokehjs_exec.v0+json';\n", 119 | " var CLASS_NAME = 'output_bokeh rendered_html';\n", 120 | "\n", 121 | " /**\n", 122 | " * Render data to the DOM node\n", 123 | " */\n", 124 | " function render(props, node) {\n", 125 | " var script = document.createElement(\"script\");\n", 126 | " node.appendChild(script);\n", 127 | " }\n", 128 | "\n", 129 | " /**\n", 130 | " * Handle when an output is cleared or removed\n", 131 | " */\n", 132 | " function handleClearOutput(event, handle) {\n", 133 | " var cell = handle.cell;\n", 134 | "\n", 135 | " var id = cell.output_area._bokeh_element_id;\n", 136 | " var server_id = cell.output_area._bokeh_server_id;\n", 137 | " // Clean up Bokeh references\n", 138 | " if (id != null && id in Bokeh.index) {\n", 139 | " Bokeh.index[id].model.document.clear();\n", 140 | " delete Bokeh.index[id];\n", 141 | " }\n", 142 | "\n", 143 | " if (server_id !== undefined) {\n", 144 | " // Clean up Bokeh references\n", 145 | " var cmd = \"from bokeh.io.state import curstate; print(curstate().uuid_to_server['\" + server_id + \"'].get_sessions()[0].document.roots[0]._id)\";\n", 146 | " cell.notebook.kernel.execute(cmd, {\n", 147 | " iopub: {\n", 148 | " output: function(msg) {\n", 149 | " var id = msg.content.text.trim();\n", 150 | " if (id in Bokeh.index) {\n", 151 | " Bokeh.index[id].model.document.clear();\n", 152 | " delete Bokeh.index[id];\n", 153 | " }\n", 154 | " }\n", 155 | " }\n", 156 | " });\n", 157 | " // Destroy server and session\n", 158 | " var cmd = \"import bokeh.io.notebook as ion; ion.destroy_server('\" + server_id + \"')\";\n", 159 | " cell.notebook.kernel.execute(cmd);\n", 160 | " }\n", 161 | " }\n", 162 | "\n", 163 | " /**\n", 164 | " * Handle when a new output is added\n", 165 | " */\n", 166 | " function handleAddOutput(event, handle) {\n", 167 | " var output_area = handle.output_area;\n", 168 | " var output = handle.output;\n", 169 | "\n", 170 | " // limit handleAddOutput to display_data with EXEC_MIME_TYPE content only\n", 171 | " if ((output.output_type != \"display_data\") || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", 172 | " return\n", 173 | " }\n", 174 | "\n", 175 | " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", 176 | "\n", 177 | " if (output.metadata[EXEC_MIME_TYPE][\"id\"] !== undefined) {\n", 178 | " toinsert[toinsert.length - 1].firstChild.textContent = output.data[JS_MIME_TYPE];\n", 179 | " // store reference to embed id on output_area\n", 180 | " output_area._bokeh_element_id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", 181 | " }\n", 182 | " if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", 183 | " var bk_div = document.createElement(\"div\");\n", 184 | " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", 185 | " var script_attrs = bk_div.children[0].attributes;\n", 186 | " for (var i = 0; i < script_attrs.length; i++) {\n", 187 | " toinsert[toinsert.length - 1].firstChild.setAttribute(script_attrs[i].name, script_attrs[i].value);\n", 188 | " }\n", 189 | " // store reference to server id on output_area\n", 190 | " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", 191 | " }\n", 192 | " }\n", 193 | "\n", 194 | " function register_renderer(events, OutputArea) {\n", 195 | "\n", 196 | " function append_mime(data, metadata, element) {\n", 197 | " // create a DOM node to render to\n", 198 | " var toinsert = this.create_output_subarea(\n", 199 | " metadata,\n", 200 | " CLASS_NAME,\n", 201 | " EXEC_MIME_TYPE\n", 202 | " );\n", 203 | " this.keyboard_manager.register_events(toinsert);\n", 204 | " // Render to node\n", 205 | " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", 206 | " render(props, toinsert[toinsert.length - 1]);\n", 207 | " element.append(toinsert);\n", 208 | " return toinsert\n", 209 | " }\n", 210 | "\n", 211 | " /* Handle when an output is cleared or removed */\n", 212 | " events.on('clear_output.CodeCell', handleClearOutput);\n", 213 | " events.on('delete.Cell', handleClearOutput);\n", 214 | "\n", 215 | " /* Handle when a new output is added */\n", 216 | " events.on('output_added.OutputArea', handleAddOutput);\n", 217 | "\n", 218 | " /**\n", 219 | " * Register the mime type and append_mime function with output_area\n", 220 | " */\n", 221 | " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", 222 | " /* Is output safe? */\n", 223 | " safe: true,\n", 224 | " /* Index of renderer in `output_area.display_order` */\n", 225 | " index: 0\n", 226 | " });\n", 227 | " }\n", 228 | "\n", 229 | " // register the mime type if in Jupyter Notebook environment and previously unregistered\n", 230 | " if (root.Jupyter !== undefined) {\n", 231 | " var events = require('base/js/events');\n", 232 | " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", 233 | "\n", 234 | " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", 235 | " register_renderer(events, OutputArea);\n", 236 | " }\n", 237 | " }\n", 238 | "\n", 239 | " \n", 240 | " if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n", 241 | " root._bokeh_timeout = Date.now() + 5000;\n", 242 | " root._bokeh_failed_load = false;\n", 243 | " }\n", 244 | "\n", 245 | " var NB_LOAD_WARNING = {'data': {'text/html':\n", 246 | " \"
\\n\"+\n", 247 | " \"

\\n\"+\n", 248 | " \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n", 249 | " \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n", 250 | " \"

\\n\"+\n", 251 | " \"
    \\n\"+\n", 252 | " \"
  • re-rerun `output_notebook()` to attempt to load from CDN again, or
  • \\n\"+\n", 253 | " \"
  • use INLINE resources instead, as so:
  • \\n\"+\n", 254 | " \"
\\n\"+\n", 255 | " \"\\n\"+\n", 256 | " \"from bokeh.resources import INLINE\\n\"+\n", 257 | " \"output_notebook(resources=INLINE)\\n\"+\n", 258 | " \"\\n\"+\n", 259 | " \"
\"}};\n", 260 | "\n", 261 | " function display_loaded() {\n", 262 | " var el = document.getElementById(\"e993b1fb-55f6-479a-8a60-a49f865110d2\");\n", 263 | " if (el != null) {\n", 264 | " el.textContent = \"BokehJS is loading...\";\n", 265 | " }\n", 266 | " if (root.Bokeh !== undefined) {\n", 267 | " if (el != null) {\n", 268 | " el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n", 269 | " }\n", 270 | " } else if (Date.now() < root._bokeh_timeout) {\n", 271 | " setTimeout(display_loaded, 100)\n", 272 | " }\n", 273 | " }\n", 274 | "\n", 275 | "\n", 276 | " function run_callbacks() {\n", 277 | " try {\n", 278 | " root._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n", 279 | " }\n", 280 | " finally {\n", 281 | " delete root._bokeh_onload_callbacks\n", 282 | " }\n", 283 | " console.info(\"Bokeh: all callbacks have finished\");\n", 284 | " }\n", 285 | "\n", 286 | " function load_libs(js_urls, callback) {\n", 287 | " root._bokeh_onload_callbacks.push(callback);\n", 288 | " if (root._bokeh_is_loading > 0) {\n", 289 | " console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", 290 | " return null;\n", 291 | " }\n", 292 | " if (js_urls == null || js_urls.length === 0) {\n", 293 | " run_callbacks();\n", 294 | " return null;\n", 295 | " }\n", 296 | " console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", 297 | " root._bokeh_is_loading = js_urls.length;\n", 298 | " for (var i = 0; i < js_urls.length; i++) {\n", 299 | " var url = js_urls[i];\n", 300 | " var s = document.createElement('script');\n", 301 | " s.src = url;\n", 302 | " s.async = false;\n", 303 | " s.onreadystatechange = s.onload = function() {\n", 304 | " root._bokeh_is_loading--;\n", 305 | " if (root._bokeh_is_loading === 0) {\n", 306 | " console.log(\"Bokeh: all BokehJS libraries loaded\");\n", 307 | " run_callbacks()\n", 308 | " }\n", 309 | " };\n", 310 | " s.onerror = function() {\n", 311 | " console.warn(\"failed to load library \" + url);\n", 312 | " };\n", 313 | " console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", 314 | " document.getElementsByTagName(\"head\")[0].appendChild(s);\n", 315 | " }\n", 316 | " };var element = document.getElementById(\"e993b1fb-55f6-479a-8a60-a49f865110d2\");\n", 317 | " if (element == null) {\n", 318 | " console.log(\"Bokeh: ERROR: autoload.js configured with elementid 'e993b1fb-55f6-479a-8a60-a49f865110d2' but no matching script tag was found. \")\n", 319 | " return false;\n", 320 | " }\n", 321 | "\n", 322 | " var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-0.13.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.13.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.13.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-0.13.0.min.js\"];\n", 323 | "\n", 324 | " var inline_js = [\n", 325 | " function(Bokeh) {\n", 326 | " Bokeh.set_log_level(\"info\");\n", 327 | " },\n", 328 | " \n", 329 | " function(Bokeh) {\n", 330 | " \n", 331 | " },\n", 332 | " function(Bokeh) {\n", 333 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.13.0.min.css\");\n", 334 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-0.13.0.min.css\");\n", 335 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.13.0.min.css\");\n", 336 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.13.0.min.css\");\n", 337 | " console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-tables-0.13.0.min.css\");\n", 338 | " Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.13.0.min.css\");\n", 339 | " }\n", 340 | " ];\n", 341 | "\n", 342 | " function run_inline_js() {\n", 343 | " \n", 344 | " if ((root.Bokeh !== undefined) || (force === true)) {\n", 345 | " for (var i = 0; i < inline_js.length; i++) {\n", 346 | " inline_js[i].call(root, root.Bokeh);\n", 347 | " }if (force === true) {\n", 348 | " display_loaded();\n", 349 | " }} else if (Date.now() < root._bokeh_timeout) {\n", 350 | " setTimeout(run_inline_js, 100);\n", 351 | " } else if (!root._bokeh_failed_load) {\n", 352 | " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", 353 | " root._bokeh_failed_load = true;\n", 354 | " } else if (force !== true) {\n", 355 | " var cell = $(document.getElementById(\"e993b1fb-55f6-479a-8a60-a49f865110d2\")).parents('.cell').data().cell;\n", 356 | " cell.output_area.append_execute_result(NB_LOAD_WARNING)\n", 357 | " }\n", 358 | "\n", 359 | " }\n", 360 | "\n", 361 | " if (root._bokeh_is_loading === 0) {\n", 362 | " console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n", 363 | " run_inline_js();\n", 364 | " } else {\n", 365 | " load_libs(js_urls, function() {\n", 366 | " console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n", 367 | " run_inline_js();\n", 368 | " });\n", 369 | " }\n", 370 | "}(window));" 371 | ], 372 | "application/vnd.bokehjs_load.v0+json": "\n(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n\n if (typeof (root._bokeh_onload_callbacks) === \"undefined\" || force === true) {\n root._bokeh_onload_callbacks = [];\n root._bokeh_is_loading = undefined;\n }\n\n \n\n \n if (typeof (root._bokeh_timeout) === \"undefined\" || force === true) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n var NB_LOAD_WARNING = {'data': {'text/html':\n \"
\\n\"+\n \"

\\n\"+\n \"BokehJS does not appear to have successfully loaded. If loading BokehJS from CDN, this \\n\"+\n \"may be due to a slow or bad network connection. Possible fixes:\\n\"+\n \"

\\n\"+\n \"
    \\n\"+\n \"
  • re-rerun `output_notebook()` to attempt to load from CDN again, or
  • \\n\"+\n \"
  • use INLINE resources instead, as so:
  • \\n\"+\n \"
\\n\"+\n \"\\n\"+\n \"from bokeh.resources import INLINE\\n\"+\n \"output_notebook(resources=INLINE)\\n\"+\n \"\\n\"+\n \"
\"}};\n\n function display_loaded() {\n var el = document.getElementById(\"e993b1fb-55f6-479a-8a60-a49f865110d2\");\n if (el != null) {\n el.textContent = \"BokehJS is loading...\";\n }\n if (root.Bokeh !== undefined) {\n if (el != null) {\n el.textContent = \"BokehJS \" + root.Bokeh.version + \" successfully loaded.\";\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(display_loaded, 100)\n }\n }\n\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) { callback() });\n }\n finally {\n delete root._bokeh_onload_callbacks\n }\n console.info(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(js_urls, callback) {\n root._bokeh_onload_callbacks.push(callback);\n if (root._bokeh_is_loading > 0) {\n console.log(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls == null || js_urls.length === 0) {\n run_callbacks();\n return null;\n }\n console.log(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n root._bokeh_is_loading = js_urls.length;\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n var s = document.createElement('script');\n s.src = url;\n s.async = false;\n s.onreadystatechange = s.onload = function() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.log(\"Bokeh: all BokehJS libraries loaded\");\n run_callbacks()\n }\n };\n s.onerror = function() {\n console.warn(\"failed to load library \" + url);\n };\n console.log(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.getElementsByTagName(\"head\")[0].appendChild(s);\n }\n };var element = document.getElementById(\"e993b1fb-55f6-479a-8a60-a49f865110d2\");\n if (element == null) {\n console.log(\"Bokeh: ERROR: autoload.js configured with elementid 'e993b1fb-55f6-479a-8a60-a49f865110d2' but no matching script tag was found. \")\n return false;\n }\n\n var js_urls = [\"https://cdn.pydata.org/bokeh/release/bokeh-0.13.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.13.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.13.0.min.js\", \"https://cdn.pydata.org/bokeh/release/bokeh-gl-0.13.0.min.js\"];\n\n var inline_js = [\n function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\n \n function(Bokeh) {\n \n },\n function(Bokeh) {\n console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-0.13.0.min.css\");\n Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-0.13.0.min.css\");\n console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.13.0.min.css\");\n Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-widgets-0.13.0.min.css\");\n console.log(\"Bokeh: injecting CSS: https://cdn.pydata.org/bokeh/release/bokeh-tables-0.13.0.min.css\");\n Bokeh.embed.inject_css(\"https://cdn.pydata.org/bokeh/release/bokeh-tables-0.13.0.min.css\");\n }\n ];\n\n function run_inline_js() {\n \n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n inline_js[i].call(root, root.Bokeh);\n }if (force === true) {\n display_loaded();\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n } else if (force !== true) {\n var cell = $(document.getElementById(\"e993b1fb-55f6-479a-8a60-a49f865110d2\")).parents('.cell').data().cell;\n cell.output_area.append_execute_result(NB_LOAD_WARNING)\n }\n\n }\n\n if (root._bokeh_is_loading === 0) {\n console.log(\"Bokeh: BokehJS loaded, going straight to plotting\");\n run_inline_js();\n } else {\n load_libs(js_urls, function() {\n console.log(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n}(window));" 373 | }, 374 | "metadata": {}, 375 | "output_type": "display_data" 376 | }, 377 | { 378 | "data": { 379 | "text/html": [ 380 | "\n", 381 | "\n", 382 | "\n", 383 | "\n", 384 | "\n", 385 | "\n", 386 | "
\n" 387 | ] 388 | }, 389 | "metadata": {}, 390 | "output_type": "display_data" 391 | }, 392 | { 393 | "data": { 394 | "application/javascript": [ 395 | "(function(root) {\n", 396 | " function embed_document(root) {\n", 397 | " \n", 398 | " var docs_json = {\"f53f3a3a-be3d-4888-bc9c-4c7e56497b16\":{\"roots\":{\"references\":[{\"attributes\":{\"bottom_units\":\"screen\",\"fill_alpha\":{\"value\":0.5},\"fill_color\":{\"value\":\"lightgrey\"},\"left_units\":\"screen\",\"level\":\"overlay\",\"line_alpha\":{\"value\":1.0},\"line_color\":{\"value\":\"black\"},\"line_dash\":[4,4],\"line_width\":{\"value\":2},\"plot\":null,\"render_mode\":\"css\",\"right_units\":\"screen\",\"top_units\":\"screen\"},\"id\":\"991fb246-1734-4da5-908b-69877b587dfd\",\"type\":\"BoxAnnotation\"},{\"attributes\":{},\"id\":\"0ce33d70-3744-49cf-abf0-ff4dc26211b2\",\"type\":\"LinearScale\"},{\"attributes\":{},\"id\":\"b272d479-8a69-492e-aeee-2129a5484d2b\",\"type\":\"ResetTool\"},{\"attributes\":{\"callback\":null,\"overlay\":{\"id\":\"a77da5eb-e2d8-4d2e-b834-6df4d59f750c\",\"type\":\"BoxAnnotation\"}},\"id\":\"53bc94b5-779a-48a9-a4f6-43840c132b6f\",\"type\":\"BoxSelectTool\"},{\"attributes\":{\"callback\":null,\"overlay\":{\"id\":\"8f8565b0-b7c5-46c8-8f07-9e1315ddd5ca\",\"type\":\"PolyAnnotation\"}},\"id\":\"578bb15f-7a91-4584-b66e-2fe7eea2585c\",\"type\":\"LassoSelectTool\"},{\"attributes\":{},\"id\":\"615334c0-c959-440c-a8a3-8945e2a7d3cf\",\"type\":\"LinearScale\"},{\"attributes\":{\"fill_alpha\":{\"value\":0.1},\"fill_color\":{\"value\":\"#1f77b4\"},\"line_alpha\":{\"value\":0.1},\"line_color\":{\"value\":\"#1f77b4\"},\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"98c896d7-d67b-4840-8570-f24b2a2d0460\",\"type\":\"Circle\"},{\"attributes\":{\"source\":{\"id\":\"eb730804-e80b-450b-bf2f-d7181012986b\",\"type\":\"ColumnDataSource\"}},\"id\":\"09191e76-65bf-4947-98ee-30d1ac38316f\",\"type\":\"CDSView\"},{\"attributes\":{\"below\":[{\"id\":\"292d23d3-2d74-4cf1-969c-f2746f566ec4\",\"type\":\"LinearAxis\"}],\"left\":[{\"id\":\"7f10f8b2-cc18-4465-a577-850dde430a37\",\"type\":\"LinearAxis\"}],\"renderers\":[{\"id\":\"292d23d3-2d74-4cf1-969c-f2746f566ec4\",\"type\":\"LinearAxis\"},{\"id\":\"47f785cd-0324-400d-8acb-13f9356ee69f\",\"type\":\"Grid\"},{\"id\":\"7f10f8b2-cc18-4465-a577-850dde430a37\",\"type\":\"LinearAxis\"},{\"id\":\"df391af9-8563-42e3-9df9-b9fede72b547\",\"type\":\"Grid\"},{\"id\":\"991fb246-1734-4da5-908b-69877b587dfd\",\"type\":\"BoxAnnotation\"},{\"id\":\"a77da5eb-e2d8-4d2e-b834-6df4d59f750c\",\"type\":\"BoxAnnotation\"},{\"id\":\"8f8565b0-b7c5-46c8-8f07-9e1315ddd5ca\",\"type\":\"PolyAnnotation\"},{\"id\":\"3b5a9955-cc89-4dbe-a2d8-2ccfff7efbe7\",\"type\":\"GlyphRenderer\"}],\"title\":{\"id\":\"33a3c926-6e92-420b-a9ee-af274c687e48\",\"type\":\"Title\"},\"toolbar\":{\"id\":\"dcbaeb78-1a66-4912-be94-ad81d0fa14e5\",\"type\":\"Toolbar\"},\"x_range\":{\"id\":\"841b8a4d-d8bc-431e-bd5e-e855ae830420\",\"type\":\"Range1d\"},\"x_scale\":{\"id\":\"615334c0-c959-440c-a8a3-8945e2a7d3cf\",\"type\":\"LinearScale\"},\"y_range\":{\"id\":\"7b493ee8-a032-4f47-b0ec-d4b9b81478fa\",\"type\":\"Range1d\"},\"y_scale\":{\"id\":\"0ce33d70-3744-49cf-abf0-ff4dc26211b2\",\"type\":\"LinearScale\"}},\"id\":\"3150c668-fd1f-4387-bdc9-aadc212083ac\",\"subtype\":\"Figure\",\"type\":\"Plot\"},{\"attributes\":{\"plot\":null,\"text\":\"\"},\"id\":\"33a3c926-6e92-420b-a9ee-af274c687e48\",\"type\":\"Title\"},{\"attributes\":{\"bottom_units\":\"screen\",\"fill_alpha\":{\"value\":0.5},\"fill_color\":{\"value\":\"lightgrey\"},\"left_units\":\"screen\",\"level\":\"overlay\",\"line_alpha\":{\"value\":1.0},\"line_color\":{\"value\":\"black\"},\"line_dash\":[4,4],\"line_width\":{\"value\":2},\"plot\":null,\"render_mode\":\"css\",\"right_units\":\"screen\",\"top_units\":\"screen\"},\"id\":\"a77da5eb-e2d8-4d2e-b834-6df4d59f750c\",\"type\":\"BoxAnnotation\"},{\"attributes\":{\"fill_alpha\":{\"value\":0.5},\"fill_color\":{\"value\":\"lightgrey\"},\"level\":\"overlay\",\"line_alpha\":{\"value\":1.0},\"line_color\":{\"value\":\"black\"},\"line_dash\":[4,4],\"line_width\":{\"value\":2},\"plot\":null,\"xs_units\":\"screen\",\"ys_units\":\"screen\"},\"id\":\"8f8565b0-b7c5-46c8-8f07-9e1315ddd5ca\",\"type\":\"PolyAnnotation\"},{\"attributes\":{\"formatter\":{\"id\":\"f96861b1-9e62-4568-b81d-b35114a66518\",\"type\":\"BasicTickFormatter\"},\"plot\":{\"id\":\"3150c668-fd1f-4387-bdc9-aadc212083ac\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"fc7a597a-0b86-4706-8863-2d824a914c92\",\"type\":\"BasicTicker\"}},\"id\":\"292d23d3-2d74-4cf1-969c-f2746f566ec4\",\"type\":\"LinearAxis\"},{\"attributes\":{\"data_source\":{\"id\":\"eb730804-e80b-450b-bf2f-d7181012986b\",\"type\":\"ColumnDataSource\"},\"glyph\":{\"id\":\"8df93632-c3ac-4520-8823-5de2a522e97c\",\"type\":\"Circle\"},\"hover_glyph\":null,\"muted_glyph\":null,\"nonselection_glyph\":{\"id\":\"98c896d7-d67b-4840-8570-f24b2a2d0460\",\"type\":\"Circle\"},\"selection_glyph\":null,\"view\":{\"id\":\"09191e76-65bf-4947-98ee-30d1ac38316f\",\"type\":\"CDSView\"}},\"id\":\"3b5a9955-cc89-4dbe-a2d8-2ccfff7efbe7\",\"type\":\"GlyphRenderer\"},{\"attributes\":{},\"id\":\"fc7a597a-0b86-4706-8863-2d824a914c92\",\"type\":\"BasicTicker\"},{\"attributes\":{\"callback\":null,\"end\":168.0},\"id\":\"841b8a4d-d8bc-431e-bd5e-e855ae830420\",\"type\":\"Range1d\"},{\"attributes\":{\"plot\":{\"id\":\"3150c668-fd1f-4387-bdc9-aadc212083ac\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"fc7a597a-0b86-4706-8863-2d824a914c92\",\"type\":\"BasicTicker\"}},\"id\":\"47f785cd-0324-400d-8acb-13f9356ee69f\",\"type\":\"Grid\"},{\"attributes\":{},\"id\":\"40cefb62-b812-4614-8e09-4d9ed6db841d\",\"type\":\"BasicTickFormatter\"},{\"attributes\":{\"formatter\":{\"id\":\"40cefb62-b812-4614-8e09-4d9ed6db841d\",\"type\":\"BasicTickFormatter\"},\"plot\":{\"id\":\"3150c668-fd1f-4387-bdc9-aadc212083ac\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"eadf5f7c-54fe-4e6c-a315-2e13621ec8f9\",\"type\":\"BasicTicker\"}},\"id\":\"7f10f8b2-cc18-4465-a577-850dde430a37\",\"type\":\"LinearAxis\"},{\"attributes\":{},\"id\":\"f96861b1-9e62-4568-b81d-b35114a66518\",\"type\":\"BasicTickFormatter\"},{\"attributes\":{\"callback\":null,\"end\":20.7},\"id\":\"7b493ee8-a032-4f47-b0ec-d4b9b81478fa\",\"type\":\"Range1d\"},{\"attributes\":{},\"id\":\"eadf5f7c-54fe-4e6c-a315-2e13621ec8f9\",\"type\":\"BasicTicker\"},{\"attributes\":{},\"id\":\"e2826871-15cf-4e43-84d9-770c98ba3d48\",\"type\":\"UnionRenderers\"},{\"attributes\":{\"active_drag\":\"auto\",\"active_inspect\":\"auto\",\"active_multi\":null,\"active_scroll\":\"auto\",\"active_tap\":\"auto\",\"tools\":[{\"id\":\"6766f0cc-6630-46be-bf71-0bd5e4fac79a\",\"type\":\"CrosshairTool\"},{\"id\":\"b7051f64-19af-45af-a149-9fa810cb29d4\",\"type\":\"WheelZoomTool\"},{\"id\":\"e96d00db-65de-498b-8fcd-6b4d3fa0d28b\",\"type\":\"BoxZoomTool\"},{\"id\":\"b272d479-8a69-492e-aeee-2129a5484d2b\",\"type\":\"ResetTool\"},{\"id\":\"53bc94b5-779a-48a9-a4f6-43840c132b6f\",\"type\":\"BoxSelectTool\"},{\"id\":\"578bb15f-7a91-4584-b66e-2fe7eea2585c\",\"type\":\"LassoSelectTool\"}]},\"id\":\"dcbaeb78-1a66-4912-be94-ad81d0fa14e5\",\"type\":\"Toolbar\"},{\"attributes\":{\"dimension\":1,\"plot\":{\"id\":\"3150c668-fd1f-4387-bdc9-aadc212083ac\",\"subtype\":\"Figure\",\"type\":\"Plot\"},\"ticker\":{\"id\":\"eadf5f7c-54fe-4e6c-a315-2e13621ec8f9\",\"type\":\"BasicTicker\"}},\"id\":\"df391af9-8563-42e3-9df9-b9fede72b547\",\"type\":\"Grid\"},{\"attributes\":{},\"id\":\"b7051f64-19af-45af-a149-9fa810cb29d4\",\"type\":\"WheelZoomTool\"},{\"attributes\":{},\"id\":\"c7a441e0-ba49-4f96-8031-ede3570cf86d\",\"type\":\"Selection\"},{\"attributes\":{},\"id\":\"6766f0cc-6630-46be-bf71-0bd5e4fac79a\",\"type\":\"CrosshairTool\"},{\"attributes\":{\"callback\":null,\"data\":{\"x\":{\"__ndarray__\":\"AAAAAACAREAAAAAAAABCQAAAAAAAAChAAAAAAAAAMkAAAAAAAAD4fwAAAAAAADxAAAAAAAAAN0AAAAAAAAAzQAAAAAAAACBAAAAAAAAA+H8AAAAAAAAcQAAAAAAAADBAAAAAAAAAJkAAAAAAAAAsQAAAAAAAADJAAAAAAAAALEAAAAAAAABBQAAAAAAAABhAAAAAAAAAPkAAAAAAAAAmQAAAAAAAAPA/AAAAAAAAJkAAAAAAAAAQQAAAAAAAAEBAAAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAAN0AAAAAAAIBGQAAAAAAAwFxAAAAAAACAQkAAAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAA9QAAAAAAAAPh/AAAAAADAUUAAAAAAAIBDQAAAAAAAAPh/AAAAAAAA+H8AAAAAAAA3QAAAAAAAAPh/AAAAAAAA+H8AAAAAAAA1QAAAAAAAgEJAAAAAAAAANEAAAAAAAAAoQAAAAAAAACpAAAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAAD4fwAAAAAAAPh/AAAAAAAA+H8AAAAAAOBgQAAAAAAAgEhAAAAAAAAAQEAAAAAAAAD4fwAAAAAAAFBAAAAAAAAAREAAAAAAAEBTQAAAAAAAQFhAAAAAAABAWEAAAAAAAEBVQAAAAAAAAPh/AAAAAAAAJEAAAAAAAAA7QAAAAAAAAPh/AAAAAAAAHEAAAAAAAABIQAAAAAAAgEFAAAAAAACATkAAAAAAAMBTQAAAAAAAgE9AAAAAAAAAMEAAAAAAAAD4fwAAAAAAAPh/AAAAAAAAVEAAAAAAAABbQAAAAAAAADRAAAAAAAAASkAAAAAAAIBUQAAAAAAAAElAAAAAAAAAUEAAAAAAAIBNQAAAAAAAgENAAAAAAAAAIkAAAAAAAAAwQAAAAAAAgFNAAAAAAACAQUAAAAAAAIBQQAAAAAAAgF5AAAAAAABAVkAAAAAAAIBbQAAAAAAAAPh/AAAAAAAA+H8AAAAAAABGQAAAAAAAADxAAAAAAABAUEAAAAAAAAD4fwAAAAAAADZAAAAAAACATUAAAAAAAAA3QAAAAAAAAD9AAAAAAAAARkAAAAAAAAA1QAAAAAAAACJAAAAAAAAA+H8AAAAAAIBGQAAAAAAAAGVAAAAAAABAUkAAAAAAAAD4fwAAAAAAAFNAAAAAAACAXUAAAAAAAABVQAAAAAAAQFVAAAAAAAAAWEAAAAAAAIBTQAAAAAAAQFJAAAAAAADAVkAAAAAAAIBHQAAAAAAAAEBAAAAAAAAANEAAAAAAAAA3QAAAAAAAADVAAAAAAAAAOEAAAAAAAABGQAAAAAAAADVAAAAAAAAAPEAAAAAAAAAiQAAAAAAAACpAAAAAAAAAR0AAAAAAAAAyQAAAAAAAACpAAAAAAAAAOEAAAAAAAAAwQAAAAAAAACpAAAAAAAAAN0AAAAAAAABCQAAAAAAAABxAAAAAAAAALEAAAAAAAAA+QAAAAAAAAPh/AAAAAAAALEAAAAAAAAAyQAAAAAAAADRA\",\"dtype\":\"float64\",\"shape\":[153]},\"y\":{\"__ndarray__\":\"mpmZmZmZHUAAAAAAAAAgQDMzMzMzMylAAAAAAAAAJ0CamZmZmZksQM3MzMzMzC1AMzMzMzMzIUCamZmZmZkrQJqZmZmZGTRAMzMzMzMzIUCamZmZmZkbQGZmZmZmZiNAZmZmZmZmIkDNzMzMzMwlQGZmZmZmZipAAAAAAAAAJ0AAAAAAAAAoQGZmZmZmZjJAAAAAAAAAJ0BmZmZmZmYjQGZmZmZmZiNAmpmZmZmZMEBmZmZmZmYjQAAAAAAAAChAmpmZmZmZMEDNzMzMzMwtQAAAAAAAACBAAAAAAAAAKEDNzMzMzMwtQM3MzMzMzBZAmpmZmZmZHUAzMzMzMzMhQGZmZmZmZiNAmpmZmZkZMEBmZmZmZmYiQDMzMzMzMyFAmpmZmZmZLEBmZmZmZmYjQJqZmZmZmRtAmpmZmZmZK0AAAAAAAAAnQM3MzMzMzCVAZmZmZmZmIkAAAAAAAAAgQJqZmZmZmStAAAAAAAAAJ0DNzMzMzMwtQDMzMzMzszRAZmZmZmZmIkAAAAAAAAAnQJqZmZmZmSRAMzMzMzMzGUAzMzMzMzP7P2ZmZmZmZhJAMzMzMzMzGUAAAAAAAAAgQAAAAAAAACBAmpmZmZmZJEAAAAAAAAAnQM3MzMzMzC1AAAAAAAAAIEBmZmZmZmYQQGZmZmZmZiJAZmZmZmZmIkDNzMzMzMwlQGZmZmZmZhJAzczMzMzMJUBmZmZmZmYUQDMzMzMzMxlAzczMzMzMFkCamZmZmZkdQDMzMzMzMyFAmpmZmZmZLEDNzMzMzMwtQM3MzMzMzC1AmpmZmZmZLECamZmZmZkbQJqZmZmZmSRAMzMzMzMzGUBmZmZmZmYUQAAAAAAAACdAmpmZmZmZG0BmZmZmZmYjQAAAAAAAACdAMzMzMzMzIUAAAAAAAAAgQDMzMzMzMyFAAAAAAAAAKECamZmZmZkdQJqZmZmZmR1AmpmZmZmZHUBmZmZmZmYiQJqZmZmZmRtAmpmZmZmZK0CamZmZmZkdQJqZmZmZmRtAmpmZmZmZHUBmZmZmZmYSQAAAAAAAABBAmpmZmZmZJEAAAAAAAAAgQDMzMzMzMyFAAAAAAAAAJ0AAAAAAAAAnQAAAAAAAACdAZmZmZmZmI0AAAAAAAAAnQJqZmZmZmSRAMzMzMzMzGUCamZmZmZkdQM3MzMzMzCVAmpmZmZmZJEAAAAAAAAAvQJqZmZmZmSxAMzMzMzMzKUBmZmZmZmYjQDMzMzMzMwtAAAAAAAAAIEDNzMzMzMwWQGZmZmZmZiNAZmZmZmZmAkAzMzMzMzMZQDMzMzMzMxlAmpmZmZmZG0BmZmZmZmYUQGZmZmZmZgZAZmZmZmZmEkCamZmZmZkdQAAAAAAAAC9AzczMzMzMJUCamZmZmZkkQM3MzMzMzCVAZmZmZmZmI0DNzMzMzMwtQAAAAAAAAC9AMzMzMzMzGUDNzMzMzMwlQAAAAAAAACdAmpmZmZmZG0CamZmZmZkrQJqZmZmZmSRAmpmZmZmZJEAAAAAAAAAgQDMzMzMzMylAZmZmZmZmIkCamZmZmZkkQJqZmZmZmSRAmpmZmZmZMECamZmZmZkbQGZmZmZmZipAmpmZmZmZLEAAAAAAAAAgQAAAAAAAACdA\",\"dtype\":\"float64\",\"shape\":[153]}},\"selected\":{\"id\":\"c7a441e0-ba49-4f96-8031-ede3570cf86d\",\"type\":\"Selection\"},\"selection_policy\":{\"id\":\"e2826871-15cf-4e43-84d9-770c98ba3d48\",\"type\":\"UnionRenderers\"}},\"id\":\"eb730804-e80b-450b-bf2f-d7181012986b\",\"type\":\"ColumnDataSource\"},{\"attributes\":{\"fill_alpha\":{\"value\":0.6},\"fill_color\":{\"value\":\"#1f77b4\"},\"line_color\":{\"value\":null},\"x\":{\"field\":\"x\"},\"y\":{\"field\":\"y\"}},\"id\":\"8df93632-c3ac-4520-8823-5de2a522e97c\",\"type\":\"Circle\"},{\"attributes\":{\"overlay\":{\"id\":\"991fb246-1734-4da5-908b-69877b587dfd\",\"type\":\"BoxAnnotation\"}},\"id\":\"e96d00db-65de-498b-8fcd-6b4d3fa0d28b\",\"type\":\"BoxZoomTool\"}],\"root_ids\":[\"3150c668-fd1f-4387-bdc9-aadc212083ac\"]},\"title\":\"Bokeh Application\",\"version\":\"0.13.0\"}};\n", 399 | " var render_items = [{\"docid\":\"f53f3a3a-be3d-4888-bc9c-4c7e56497b16\",\"roots\":{\"3150c668-fd1f-4387-bdc9-aadc212083ac\":\"2fbe0fef-824a-44a3-bc10-ed3b9493be07\"}}];\n", 400 | " root.Bokeh.embed.embed_items_notebook(docs_json, render_items);\n", 401 | "\n", 402 | " }\n", 403 | " if (root.Bokeh !== undefined) {\n", 404 | " embed_document(root);\n", 405 | " } else {\n", 406 | " var attempts = 0;\n", 407 | " var timer = setInterval(function(root) {\n", 408 | " if (root.Bokeh !== undefined) {\n", 409 | " embed_document(root);\n", 410 | " clearInterval(timer);\n", 411 | " }\n", 412 | " attempts++;\n", 413 | " if (attempts > 100) {\n", 414 | " console.log(\"Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing\")\n", 415 | " clearInterval(timer);\n", 416 | " }\n", 417 | " }, 10, root)\n", 418 | " }\n", 419 | "})(window);" 420 | ], 421 | "application/vnd.bokehjs_exec.v0+json": "" 422 | }, 423 | "metadata": { 424 | "application/vnd.bokehjs_exec.v0+json": { 425 | "id": "3150c668-fd1f-4387-bdc9-aadc212083ac" 426 | } 427 | }, 428 | "output_type": "display_data" 429 | } 430 | ], 431 | "source": [ 432 | "import pandas as pd\n", 433 | "from bokeh.plotting import figure, output_file, show\n", 434 | "from bokeh.io import output_notebook\n", 435 | "output_notebook()\n", 436 | "\n", 437 | "# Load some data\n", 438 | "airq = pd.read_csv('Data/airquality.csv')\n", 439 | "# Select tools\n", 440 | "TOOLS=\"crosshair,wheel_zoom,box_zoom,reset,box_select,lasso_select\"\n", 441 | "\n", 442 | "# create a new plot with the tools above, and explicit ranges\n", 443 | "p = figure(tools=TOOLS, x_range=(0,airq.Ozone.max()), y_range=(0,airq.Wind.max()))\n", 444 | "\n", 445 | "# add a circle renderer with vecorized colors and sizes\n", 446 | "p.circle(airq.Ozone,airq.Wind , fill_alpha=0.6, line_color=None)\n", 447 | "\n", 448 | "# show the results\n", 449 | "show(p)" 450 | ] 451 | }, 452 | { 453 | "cell_type": "markdown", 454 | "metadata": {}, 455 | "source": [ 456 | "Plotting in **pandas** currently uses the **matplotlib** library. There is current development to integrate **bokeh** plots into the **pandas** library." 457 | ] 458 | }, 459 | { 460 | "cell_type": "markdown", 461 | "metadata": {}, 462 | "source": [ 463 | "### Yellowbrick Example " 464 | ] 465 | }, 466 | { 467 | "cell_type": "markdown", 468 | "metadata": {}, 469 | "source": [ 470 | "We can use **yellowbrick** with the iris data. If we did not know there were three flowers in our dataset (Setosa, Virginica and Versicolor), the Elbow method helps show how many clusters we need to model with.\n", 471 | "Here, we test using 1, 2, 3, 4, 5 and 6 clusters:\n" 472 | ] 473 | }, 474 | { 475 | "cell_type": "code", 476 | "execution_count": 2, 477 | "metadata": {}, 478 | "outputs": [ 479 | { 480 | "data": { 481 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAh0AAAFlCAYAAABP+VrWAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzs3Xd0VHX+//HnnZlMJr0XEgKBFKoQQEroIIrSFRQsKH51wbau7v52EXXtZUXXFcu64CruAioKiCK4FsoqEukQeirppPc65f7+iMwSCSRAJjfl/TiHozN37r2vO5OZec+9n6KoqqoihBBCCOFgOq0DCCGEEKJzkKJDCCGEEK1Cig4hhBBCtAopOoQQQgjRKqToEEIIIUSrkKJDCCGEEK1Cio4OKDMzkz59+jBz5kxmzpzJ9OnTmTdvHlu2bLE/ZtmyZWzcuPGi23n77bf5/vvvL3n/567XnP1cih07djB37lxmzJjB1KlT+d3vfseZM2dabPvNtWHDBoYMGWJ/js/++9Of/gTAY489xvvvvw9Ar169KCoqcmieEydOMGnSJG666SYyMzMvaxu7d++mV69eLF68+Lxl8+fPZ9CgQQBs3bqVF1544aLbys3NZd68eUDD52rGjBlMmTKFRYsWkZeX12Smzz77jDVr1lz0MW+99RbPPfdco8vmz5/Pf/7znwa5pkyZwvPPP4/NZmP+/Pn06tWLjIyMBuudfS7OvoZaKSsr44UXXmD69OnMnDmTWbNm8dlnn9mXT5w4kSNHjlzWtjMyMvjtb397yes15/UX4kIMWgcQjmEymfjiiy/st7OysliwYAF6vZ7Jkyfzu9/9rslt7N69m8jIyEve97nrNWc/zZWbm8vixYvZsGEDoaGhALz77rs88sgjfPLJJy22n+a6+uqrWb58eavvtzFbt25l+PDhvPjii1e0nYCAALZv3051dTUuLi5A/d9Oamqq/THXXHMN11xzzUW3ExQU1OA1+fVz9cwzz/Dmm282+eW1f/9+oqKiLudQzpOWlsbdd9/N3LlzWbRokf3+kJAQvvjiCx566CH7fRs3bsTf379F9nu5amtrueOOO5g+fTqff/45BoPB/j4GuPnmm69o+9nZ2Q1e1+ZqzusvxIVI0dFJhIaG8vDDD/P+++8zefJkHnvsMaKiorjnnnt48803+e6773BycsLHx4eXX36Z7777jqNHj7J06VL0ej0jRozg2Wef5eTJkyiKwpgxY/j973+PwWCgf//+XHPNNZw8eZLp06c3WG/r1q32/ezbt4+lS5dSXV2Nk5MTjzzyCGPHjmXDhg1899136HQ60tLSMJlMvPLKK0RERDQ4huLiYsxmM1VVVfb77rrrLnr37m2/vXz5cvsHdPfu3fnLX/6Ch4cH77zzDps3b0av19OjRw/+/Oc/ExAQwPz58/Hy8iIlJYVbb72VWbNm8eKLL5KQkIDZbCY2NpY//elPGAxX9lZ54403OHLkCDabjUceeYQJEyYANJrr8OHDfPDBB3z00UcATJ48malTp/Lwww9z5swZ5syZww8//IBOV3+i8ssvv+Tjjz/GarVSU1PDX//612Yf7/z58xvk9Pb2JiwsjO+//57p06cD9V/A06dPtxcRGzZs4JtvvmH58uXMnz+fmJgYDhw4QE5ODrGxsTz//PNkZ2czffp0Dh48eN5zYTabqaioICwsDICCggKeeuopCgsLyc/PJzQ0lDfeeIMDBw6wbds2fvrpJ0wmE3PnzuXVV19lx44d6PV6Bg0axNNPPw1ASkoK8+fPJz8/H39/f15//XUCAwPt+zx58iSLFi3i0UcfZdasWQ3yzJgxg02bNtmLjurqag4cOEBsbKz9Mbm5uTz33HPk5ORgNpuZOnUq9913HwD/+Mc/2Lp1KzU1NVRXV7N48WKuvfZa3nrrLbKyssjPzycrK4ugoCBeffVVAgMD+eijj/jkk09wcnLC2dmZ55577rwCf8uWLbi6uvKb3/zGft/Z58ZsNjd47O7du3n++ef56quvzrudnJzME088QV1dHaqqMmfOHObNm8eTTz5Jbm4u99xzD++//z4HDhzgtddeo7q6Gp1Ox0MPPcSECRPYsGED69ato7q6Gnd3d2688cYmX3+dTseGDRtYsWIFJpOJESNG8O9//5vjx4839vYQnYhcXulEevfuTUJCQoP7cnJy+Ne//sX69evZsGEDo0aNIj4+nttvv53+/fvzpz/9iWuvvZYXXngBb29vNm3axPr16zl16hQffPABUP8lMmHCBL755hseeuihBuudVVxczMMPP8wTTzzBpk2beOWVV/jjH/9oP629d+9e/vznP/PVV18xcOBAVqxY0Wj+W265hRtvvJEpU6bw5JNPsn37dsaMGQPU/9rfsGEDa9eu5auvvqJr166sXr2a9evX8+OPP7Ju3To2bdpEVFQUjz32mH27np6ebNmyhfnz5/PSSy/Rr18/NmzYwMaNGykuLmblypWNPp/79u077/LK+vXrG31s165d+fzzz3n11Vd57LHHKCoqumCu0aNHc+rUKcrKysjMzKSyspJdu3bZj3HSpEn2ggPqvzTnzZvHlClT+Otf/3pJx9uYWbNmNThL9vXXXzNt2rRGHwuQnp7OqlWr+PLLL/nhhx/Ys2fPBZ+rGTNmMHr0aPbs2cOcOXMA2Lx5MzExMaxdu5atW7faz9Jde+21TJw4kQULFnD77bfz0UcfcezYMb744gu++uorKisr7ZcMMzIyWLZsGf/5z3/w9PRscAniwIEDzJ8/n+DgYGbMmHFetj59+mA0Gjl8+DAA3377LRMnTmxQaP7xj39k9uzZ9i/gXbt2sWXLFrKysti1axerVq1i06ZNPProo7z55psNjvtsLhcXFz755BOsVisvvfQS//znP1m/fj233HIL+/fvPy/X0aNHGTx48Hn39+vXj5iYmAu+Hr/2/vvvM3HiRHsRsG/fPhRF4YUXXqBbt268//77lJaWsmTJEpYuXcrnn3/O3//+d5555hmys7MBSEpKYtWqVaxateq87Tf2+iclJfHaa6/x4YcfsnHjRtzd3bFarc3OLDouOdPRiSiKgslkanBfUFAQvXv35sYbb2Ts2LGMHTu2wS+8s3744Qc+/vhjFEXBaDQyb948/vWvf7Fw4UKg/vT5xcTHx9OtWzcGDhwIQFRUFIMHD2bPnj0oikK/fv0IDg4GoG/fvnz33XeNbuexxx5j0aJF7Nmzh71797J06VJWrVrFmjVriIuL4/rrr8fLywuAJUuWAPWXeG666SZcXV0BuPPOO/nHP/5BXV3dedl37NjBkSNHWLduHQA1NTUXPKZLubxy6623AhAdHU1ERAQHDx7khx9+aDSXTqdj5MiR/PTTTxQXFzN37lzWrl1LeXk527Zt4957773ovi603caOtzETJkzgmWeeoaCggLS0NHr27Gl/Ti/0eJ1Oh7u7O927d6e0tJSuXbs2eMy5z5XNZuPdd9/l3nvvZcuWLdx1113s27ePlStXcvr0aRITE+1/J+fatWsXM2fOtP8Nv/HGG0B9m45Ro0bh6+sL1Ben57ah+fLLL3nnnXd44YUX+Nvf/sYf/vCH87Y9c+ZMvvzySwYOHMjGjRtZsmSJvaiuqqpi7969lJaWsmzZMvt9J0+eZMqUKSxdupRNmzaRlpbG4cOHqaystG932LBhuLu7A/V/16Wlpej1eq6//nrmzZvH+PHjGT16NOPGjTsvk6IotMQsFddeey2LFy8mPj6e2NhYnnzyyQZFK8ChQ4fIz8/nwQcfbLD/U6dOAfXtks4ex6819vqfPHmSUaNG2d/Td9xxB2+99dYVH4to/6To6ESOHDlCdHR0g/t0Oh2rV6/myJEjxMXF8dJLLzFmzBh7g8izbDYbiqI0uG2xWOy3z37BXYjVam2wPoCqqlgsFpycnBoUQxf6sN26dSslJSXMnj2byZMnM3nyZB599FHGjRvH8ePH0ev1DfZRVlZGWVnZJWW32WwsW7bMfmmnrKzsvNyX49wPeZvNhsFguGiuSZMm8cMPP1BWVsa9995LSkoK33//PQkJCQwbNuyi+7rS18poNHLdddexefNmkpKSuPHGGy/6+Oa8dufS6XTMnz+fN998k8LCQlauXEl8fDyzZ89m+PDhWCyWRrfx60tcBQUF2Gy285b9OsPjjz/OsGHDWLZsGXPmzOGqq67iuuuua7Ct6dOnM3v2bBYsWEBFRUWD94nNZkNVVT755BN7O5eioiKcnZ05duwYDzzwAAsWLGDUqFEMHTqUZ599tsnn5rXXXiMhIYFdu3axYsUKvvjiC3tBc1ZMTEyjjWi3bt3Kvn37GjT4/fUxn3v55exZyF27dhEXF8c777zDhg0bGmzTarUSERHR4AxRbm4uvr6+bNq06aJ/M40do16vb5BHr9dfcH3RucjllU4iNTWVv//97/zf//1fg/tPnjzJtGnTiIiIYNGiRSxYsMDeGl6v19u/rEaPHs3q1atRVZW6ujo+/fRTRo4c2ei+zl3vrJiYGFJSUoiPjwcgMTGRvXv3NvkFei43Nzdef/11kpKS7PdlZGSg1+vp1q0bI0eO5LvvvqOiogKo/wX84YcfMmbMGNavX29vC7Jq1SqGDh2K0Wg8bx+jR4/mww8/tB/n/fffz+rVq5ud8UI+//xzAI4dO0Z6ejoDBw68aK6JEycSFxfHiRMnGDBgAKNGjWLZsmWMHTu2yQ/wSzneC5k1axaff/45e/futV++akk7duwgNDQUX19fdu7cyV133cWsWbPw8/Nj165d9lPx5/4txcbG8tVXX1FXV4fNZuOZZ55h8+bNTe7r7HH36NGD559/nscee4zk5OQGjwkKCqJXr148/vjjzJw5s8Eyd3d3YmJi7JfZysrKuPXWW9m6dSt79+6lf//+3H333QwbNoytW7c2eRmhqKiIcePG4e3tzYIFC3jkkUca7YFy3XXXUVFRwXvvvWffZkZGBn/5y1/Oa+/k6+tLdnY2hYWFqKra4Hn5wx/+wJYtW5g6dSpPP/007u7upKeno9fr7cVJTEwMaWlp7N27F6jvDTV58mRyc3ObfH4bM3r0aOLi4uzrn1vMiM5NznR0UDU1NfYPT51Oh7OzM7///e8ZP358g8f17t2bG264gdmzZ+Pq6orJZOLJJ58E6rvjvf7665jNZp588kl71z2z2cyYMWPsDel+7dz1zvL19WXZsmU8//zz1NTUoCgKL7/8Mj169Gi0sWFjRowYwZ///GcWL15MeXk5er2egIAA3nvvPby8vBg3bhxJSUn2SxmRkZE8//zzuLq6kpOTw80334zNZqN79+689tprje7jiSee4MUXX7Qf58iRIy94OeNsO4Vz6fX6835FQv2XxaxZs1AUhddffx1vb2/mzJlzwVweHh5ERETg4uKCXq9nzJgxPPHEE+f9Qm/MxbbbXIMGDaK6uvq8tg2X6+xzpSgKFosFb29v3nnnHXQ6HQ8++CBLly5l2bJlODk5MXjwYNLT0wEYO3Ysf/nLXwC49957ycrK4qabbkJVVYYNG8b8+fN59913m51jypQp7N27lwcffNB+Ce2smTNn8vjjjzd6GeC1117j+eefZ/r06dTV1TFt2jRmzJhBQUEB3377LTfccAM2m40JEyZQWlpqL3wb4+vry/3338+CBQswmUzo9fpGe/EYjUZWrlzJq6++yvTp09Hr9ej1eu6//35uuummBo+NjIxk3rx5zJ49m4CAAMaPH28vZB544AGeeOIJ1q5di16vZ9KkSQwdOpTS0lKcnZ2ZM2cOn332GW+++SZLly6ltrYWVVVZunQpXbt2bbSNTlN69OjBkiVLuOeeezAajfTp08d+lkh0bopMbS+EEKIlZWRk8MUXX/DAAw+g0+n49ttvee+99+SMh5AzHUIIIVpWcHAweXl59jM0Hh4evPTSS1rHEm2AnOkQQgghRKuQhqRCCCGEaBVSdAghhBCiVbSLNh0Wi4XCwkJMJtN5g9oIIYQQHY3NZqOmpgY/P78W6UHWVrSLIyksLLzsmTOFEEKI9iwoKEjrCC2mXRQdZ0e869q1a5OjKTZXQkLCeaNztldyLG1TRzmWjnIcIMfSFnWU44CWPZaqqioyMzPPm7qivWsXRcfZSyqurq54eHi02HZbcltak2NpmzrKsXSU4wA5lraooxwHtPyxdLQmBR3raIQQQgjRZknRIYQQQohWIUWHEEIIIVqFFB1CCCGEaBVSdAghhBCiVXTKouPZbw6zIj5P6xhCCCFEp9Iuusy2pGe/Ocxz38YDEPLNYZ6ePFDjREIIIUTn0KmKjnMLDsD+/1J4CCGEuFw5JUmk5B8iuzadmsRUegbE0MU7UutYbVKnKTp+XXCcJYWHEEKIy5VTksThjG2/3FIprymy35bC43ydok3HhQqOs577Np5nvznciomEEEJ0BCn5hy7p/s6uUxQdQgghhCNU1BTb/2tRa0A9e3+JhqnaLocWHYWFhYwbN47k5OQG969cuZKpU6cyf/585s+fT0pKiiNj8PTkgTx13YALLn/qugFyeUUIIcQlczf5YLVZqLNUY8MCytn7vbUN1kY5rE2H2WzmqaeeanSGvGPHjvHKK6/Qv39/R+3+PGeLil9fZnlgZLQUHEIIIS5Lz4AY4pI2AqDH2OB+cT6Hnel45ZVXmDdvHoGBgectO3bsGCtWrODWW29l+fLljopwnsbOeDgZ5AqTEEKIyxPs1ROT0R2D3hm9YsTD5MvAsInSiPQCFFVV1Zbe6IYNGzhz5gwPPPAA8+fP55lnniEiIsK+/O233+a2227D3d2dhx56iFtvvZUJEyZccHvl5eUkJCS0WL4V8XnYVNiYXIzZqrL5xmhMUnwIIYS4RHW2SrLMB/DQB+FviG7x7UdHR+Ph4dHi29WKQ4qO22+/HUVRUBSFEydOEB4ezrvvvktAQACqqlJRUWF/EtesWUNJSQkPPvjgBbd3tuhoySd///79fJ6r4+WtR/lg3kjuGhrR9Ept1P79+xkyZIjWMVqEHEvb01GOA+RY2qKOcBwWmxmrzcLRw8db7Fgc8b3XFjjk5/2aNWtYvXo1q1atok+fPrzyyisEBAQAUFFRwbRp06isrERVVXbv3t2qbTvOde+IKBQF3otL1GT/Qggh2j+Dzglng4vWMdqFVhscbNOmTVRVVTF37lweffRR7rzzToxGI7GxsYwbN661YjQQ7uvO9b1D+fpEFoezixgY4qtJDiGEEO1PXlkatZYqunhFYtA7aR2nXXB40bFq1SqABm06Zs2axaxZsxy962ZZOCKKr09ksSIukXdmD9c6jhBCiHYiJf8QJVW5BHh0k6KjmTp968kpfULp6uXKmv2pVNSatY4jhBCiHaisLaWkKhc/966YnNy0jtNudPqiw6DXce+IKMprzXx88LTWcYQQQrQDWcWnAAj1afkeKx1Zpy86AP5veCR6ncKKuJbrliuEEKJjUlUb2SWJGHROBHmGax2nXZGiAwj1cmVa364cyCxiX0ah1nGEEEK0YYWV2dSYKwn2ikCv6zSTtbcIKTp+sSi2/hTZ8l1ytkMIIcSFKSh4uwbJpZXLICXaL66N7kIPX3c+OZTKqzOG4O1ibHolIYQQnY6feyh+7qFax0BVbcQlf0FxZQ46Rc+oqNl4uvjblyec2cOpM7tRFB0DwyYS5tvHvuxY1k6qzeVcHX4DAMl5BzmW9SOKoiMq6Gp6dxnhkMxypuMXOp3Cb0ZEUVVnZc1+x856K4QQon1ywCDely298DhWm5mpAx9gSPgN7E3dbF9WVVfO8eyfmDLgfq7rdw/7T/8Hq82CxWrmh1OfcDInrsG29qVuYXL/e5ky4D6OZf1IraXKIZml6DjHgmEROOl1rIhLbFN/WEIIIdqG/Wn/4Wjmf1FVm9ZRyC07TahPLwACPbtRWJFlX1ZQnkGgZzh6nQGjwYSnyY/iyhysqpmIwMEMCGs435mPWzB11hqsNgugAopDMkvRcY4gDxduvCqMo2dK2HU6X+s4Qggh2pDK2lIKyjOoqitHUbT/+jRbazDqTfbbiqJgU62/LKttsMxJ70ydtQZng2ujbVF8XIPYdOgtNh74G119ejtsWHftn7U2ZuHZBqXSfVYIIcQ5skvq5+lqKw1InfQmzNZa+21VVdEp+l+WOTdYVl+ENF5IFFXmkFF8ijlXL2bO0MXUmCs5XRDvkMxSdPzK+IggogM8WXc4jcLK2qZXEEII0eGpqkpWcQJ6nRNBXj20jgNAoGd3MotPApBXlo6PW7B9mb9HGLllqVhsZuosNZRU5+PtFtTodox6EwadAb3OgE7RYXJyo9ZS7ZDM0nvlVxRFYVFsFH/4cj//3pfMo+P6ah1JCCGExooqc6gxVxDq0wuDrm3Ms9Ldrx/ZJUlsPvx3AEZFzeFY1o94mPzo5teXviGj+Dp+Oagqg7tfd8Hc7iYfooOH83X8P9Dp9HiY/IgMHOKQzFJ0NOLOoRE8vuUgK+ISeWRsHxTFMQ1qhBBCtA9ZxfWX3NvKpRUARdExMvLGBvd5uwba/z86eBjRwcMaXTcq6OoGt3t3GeGwbrLnkssrjfB1debmgeEk5JexIzlX6zhCCCE01iPgKiIDh+DjGtz0g8UFSdFxAYtiowAZoVQIIQT1lxyChsiZ7yskRccFxIYH0D/Ym8+PpJNb7pgGNUIIIdq+ippiGbuphUjRcQH1DUqjsdhUVu5J0jqOEEIIDVTVlbMz8TOOZP5X6ygdghQdF3H7kB64GvW893MiNptUuUII0dlk/9KA1Neti8ZJOgYpOi7Cy8XIrYN6cLqokm8TsrWOI4QQohWpqkpWSQI6xUBwGxmbo72ToqMJC2XKeyGE6JSKq85QXVdOsFcPDHqZebwlSNHRhKvD/BjS1ZfNJ7LILKnUOo4QQohW0hbH5mjvpOhohoWx0VhtKh/slgalQgjRGaiqjcKKLExO7vi6hWgdp8OQoqMZ5g0Kx8PZiX/uTsJi1X46YyGEEI6lKDrGRN/CkPDrZWyOFiRFRzO4Oztxx5AeZJVWsflEltZxhBBCtAK9zoCHyVfrGB2KFB3NdLZB6QqZ8l4IITq0GnMFaQVHqbPUaB2lw5Gio5kGhPgQ2z2Ab05lk1pYrnUcIYQQDpJVnMiJnF3klp3WOkqHI0XHJVg4MgpVhX9Kg1IhhOiQVFUlqzgBnaIn2Kun1nE6HCk6LsHNA7vj42Jk5Z4k6ixWreMIIYRoYSVVeVTVlRLkGY6TjM3R4qTouAQuTgbuGhpBbnkNXxzL1DqOEEKIFpZVfAqAUJ9eGifpmKTouES/GVE/5f0KGaFUCCE6FKvNwpnSFJwNbvi5y9gcjiBFxyXqHeTF+IggtiWdISG/TOs4QgghWkidpRpPF39CfaJQFPl6dAR5Vi/D2e6z78UlapxECCFES3ExejCs5zSigoZqHaXDkqLjMtx4VRgB7s58uDeJGrM0KBVCiI5ERiB1HCk6LoPRoOfuoZEUVdWxLj5N6zhCCCGuUFrBUQ6nb6W6rkLrKB2aFB2X6Tex9Q1K5RKLEEK0b6qqkl50nNyy0xh0TlrH6dCk6LhMPf08uDa6CztT8ziaU6x1HCGEEJeptDqfytoSAj2742Rw1jpOhyZFxxVYNPLsfCxytkMIIdqrrOL6IRBCfaI1TtLxSdFxBab17UqIpwur96dQWWvWOo4QQohLZLNZOVOajLPBFT/3rlrH6fAcWnQUFhYybtw4kpOTG9y/bds2Zs+ezdy5c/n0008dGcGhnPQ67hkeRWmNmbWHpEGpEEK0N3nlaZittYR4R6GTsTkczmHPsNls5qmnnsJkMp13/8svv8wHH3zAqlWrWLt2Lfn5+Y6K4XD3DI9Epygy5b0QQrRDni4B9AyIkUsrrcRhRccrr7zCvHnzCAwMbHB/cnIy3bp1w8vLC6PRyJAhQ9i3b5+jYjhcmI8bU/qEsjejkAOZhVrHEUIIcQlcjR5EBw/D3eSjdZROweCIjW7YsAFfX1/GjBnDihUrGiyrqKjAw8PDftvNzY2Kiub1i05IaNmzCfv372+R7VwToPAV8NKmXSwZps14/S11LG2BHEvb01GOA+RY2iKtjsOi1qLH2KKDgXWU18RRHFJ0rF+/HkVRiIuL48SJEyxevJh3332XgIAA3N3dqaystD+2srKyQRFyMdHR0c1+bFP279/PkCFDWmRbMYNs/C1+I9+mV/DB3VfhaWrd6ZBb8li0JsfS9nSU4wA5lrZIq+NQVZWfEtdRh8qoqDkt0p6jJY+lvLy8xX9otwUOubyyZs0aVq9ezapVq+jTpw+vvPIKAQEBAERERJCWlkZJSQl1dXXs27ePQYMGOSJGq9HrdPxmRBSVdRbWHEjVOo4QQogmlNcUUlFbjLuztzQgbUWt9kxv2rSJtWvX4uTkxGOPPcY999zDvHnzmD17NkFBQa0Vw2HuHhaBQafwXlwiqqpqHUcIIcRFZBWfAiDUp5fGSToXh1xeOdeqVauA+jMcZ02cOJGJEyc6etetqounKzP6h7EhPp3d6QWM6B6gdSQhhBCNsKlWskuSMOpN+HvI2BytSc4ptaBFv0x5v3xXx7sOJ4QQHUV+WXr92Bw+UegUvdZxOhUpOlrQxMhgIv09+PRQGsVVtVrHEUII0YjcstOADHuuBSk6WpBOp7BwRBQ1Fiur9qVoHUcIIUQj+ncdy9AeU/Ew+WkdpdORoqOF3TU0AqNex/K4BGlQKoQQbZBO0ePnHqp1jE5Jio4W5u9uYvaAbpzMK+OHlDyt4wghhDhHZtFJasyVTT9QOIQUHQ7wvynvpUGpaL9ySpL4KXEdKbX/5afEdeSUJGkdSYgrUlZdyNGsHzie/ZPWUTotKTocYHSPQPoEebE+Pp288mqt4whxyXJKkjicsY3SqnxsqpnymiIOZ2yTwkO0a9kl9T8EQ72lAalWpOhwAEVRWBQbhdlq4197pUGpaH9S8g+hqjZKq/OoVSswW+vs9wvRHtlUK9nFiTjpnQnwDNM6TqclRYeD3DGkJy5Oet77ORGbTRqUivbDarNQUVOMougw6J0BqK4rB6CipkTLaEJctoLyTOqsNYR4R8rYHBqSosNBfFxw6sPIAAAgAElEQVSduSUmnOTCcrYm5mgdR4gm1ZgrOJT+PXtSNuHmXD/Nt4fJF71iwGKtxWKtw93krXFKIS6PDHveNkjR4UCLYqMAWB6XqHESIS7MplpJyT/EjwmfcqY0BVAI8+trX27ABEC1uYKeATEapRTi8p0dvsDT5C9jc2jM4XOvdGbDuvkTE+LDl8cyyC6tIsTLVetIQjRQUJ7JieyfqKwrxUlvok/oKEJ9olEUBaPeSEr+IcrLKzAaDeh0BvnAFu2SoigM6n4dNtWKoihax+nUpOhwIEVRWDgymgfW7WblniSeuHaA1pGEsLPaLBzJ3E6tpZpuvn2JChqKk8HZvryLdyRdvCPZX7afnr27YrXV4eYsl1dE+yVtObQnl1cc7LZBPXB3NvDez4lYbTat44hOzmazUlZdCIBeZ+CqruMZGXkTfUNHNyg4fs3HLQh/jzD5lSjanfKaIg6mfUtJVa7WUQRSdDich8mJ2wb3IKOkiq9PZmsdR3Ri+eUZ7Excx77UzZgt9RMS+nuE4eni3+xtVNdVkFUsg96J9iOrOIHcstMyCmkbIUVHK1g4QkYoFdqprivnYNq37D/9NVV1pXTxjrjsMxYH077laOZ/qaora+GUQrQ8m2ojp6R+bI5Aj+5axxFI0dEqBnX1ZVg3P7acyCKtqELrOKKTsKlWkvMO8GPCZ+SWncbHNZhRUbPpEzIKg954WdsMDxiAikpq/uEWTitEyyusyKTWUk2wVwQ6nbTnaAuk6GglC2OjUVV4f7cMIy1ah4KO/PIMnPRODOg6gWE9p19x75Ngr564Gj3JLD5FjVkKaNG2nb0UGOojw563FVJ0tJK5MeF4mZz4YE8SZqs0KBWOUVVXRmZR/SBIiqIwIGwCo6PnEuIT1SKNQHWKjp4Bg1BVG6n58Ve8PSEcxWypJbfsNG7O3ni5BGgdR/xCusy2ElejgflX9+TtnafYdCyTmwZ00zqS6ECsNgsp+YdIzT+MqtrwcQvGzdkLV6Nni+8rxCeSpLz9ZBSdpGfgIJwNLi2+DyFaQmTgYJwNbh2215Wq2ohL/oLiyhx0ip5RUbMbNAxPOLOHU2d2oyg6BoZNJMy3j33ZsaydVJvLuTr8BqrqyvnvyY/sy4oqcxgSfj29u4xo8cxSdLSihbHRvL3zFMvjEqToEC0mryyNEzm7qK4rx9ngSq8uIxxSbJylU/REBMRQVJmDzWZ12H6EuBJOBmciAgdrHcOh0guPY7WZmTrwAfLK0tmbuplr+t4FQFVdOcezf2J6zG+x2ixsiX+XEO8oVFVlV9J68ssz6O7fHwBXowc3DFgE1H+eHEj7hujgYQ7JLEVHK+oX7M2YnoF8n5BDckE5Ef4eWkcS7Ziq2jiY9h155Wko6Aj3H0Bk4ODLbiR6KcL8+jYYKl2ItsRiM6NX9ChKx25BkFt22j6XTKBnNworsuzLCsozCPQMR68zoNcZ8DT5UVyZg4eLHxGBg+niHUlpdX6D7amqyu6ULxkbPQ+dg567jv2KtEELY+sbNL33s8zHIq6MouhwdnLF1y2EUVGz6d1lRKsUHL9Wa6lq9X0KcTEpeQfZcfJjymsKtY7iUGZrDUa9yX5bURRsqvWXZbUNljnpnamz1uBscL1gw9qMohN4uwbh5eq4NjBSdLSy2QO64efqzMo9SdRa5NS0aD5VVcktPU18xg77BFZ9uoxkaI+puJt8NMl0OH0rOxM+w2Kt02T/QvyaqtrIKk7AajPjavTSOo5DOelNmK219tuqqtqHenfSOzdYVl+EXLz9VUr+QYddVjlLio5W5mzQs2BYBAWVtWyIT9c6jmgnKmtL2X/6PxxM/5ac0iQqaosA0On0mjaSczf5YrbWkl50XLMMQpyrsCKbWksVXbwj0Os6dguCQM/uZBafBCCvLB0ft2D7Mn+PMHLLUrHYzNRZaiipzsfbLeii2yusyHL4IGpSdGjgNyPqp7yXSyyiKRabmYQze9iZ+BkFFRn4uYcyKnJOm5nttZtfPww6I6fz47HaLFrHEYKs4vou4yHeHX9sju5+/dDrnNh8+O/sTf2KoT2mcSzrR9ILj+Nq9KBvyCi+jl/ON0feY3D36zDonC64rRpzBQa9s8N/xHTsMrCNigrw5JqoYLYmnuFEbil9gjr2KUBxeVRVZXfyl5TXFGJycqd3lxEEefZoU93/nPRGuvv1Izn/IBlFJwj3v0rrSKITM1vryC07javRC2/XQK3jOJyi6BgZeWOD+8497ujgYRe8XBIVdHWD2yYnd2YO+l3Lh/wVOdOhkbMNSmU+FvFrZ7uhKopCN79+9AyIYXT0zQR79WxTBcdZ3f2vQq8zkJofL11ohaZyy1KxqVZCfaLb5HtFSNGhmZn9wwj2cOHf+1KoNstpaQEWq5lTZ3azM/EzLDYzAGG+vYkOHnbR06JaMxpMhPn2xWKro6yD9xYQbVuodxRX95giw563YVJ0aMRJr+PuYRGUVNfx6aE0reMIDamqSk5JMjsTPyU1/zA21UZ1O5vFNSJgEON73dYpTmmLtktRdPi7d8Xk5KZ1FHEBUnRo6N4RUSiKXGLpzCpqitmbupnDGVups9QQETiYMdG3tJmGos3lZHDGyeCsdQzRiRVWZFFVV651DNEEKTo0FO7rzvW9Q/k5rYDD2UVaxxGtTFVVjmTuoKgyG3+PMEZFzSEq6Op23c0vpySJA2nfoKoyqaFoPfXvpf+yK3G9tCtq46To0Nii2PrusyvipPtsZ6CqKuU19QWmoij0CRnF4O6TGdL9etyc238vpsKKLPLK0jhTmqp1FNGJFFVmU2OuINirBzqdXus44iKk6NDYDb1D6erlyur9KZTXmLWOIxyovKaIPalfsStpA5W1pUB997ZAz+4dpqV9j4AYoH5kw7OjpgrhaFnF9Zeoz85DItouKTo0ZtDruHdEFBW1Fj4+KL8OOyKLtY6TOXHsSlxPcWUOAe5h9qGKOxo3Zy+6eEdSXlNEfrmMuCscz2Kt40xpKq5GT7xdLz7iptCeFB1twP8Nj0SvU1gRlyi/DjuY7JIkfkxYy+mCI5iM7gzufj2DwyfjYnTXOprDRAQMAiA574D8PQuHO1Oaik21EOId1WHOGHZkUnS0AaFerkzr25WDWUXsy5BxDjqS/PJ0zNY6IgOHMDrqZgI9u2kdyeHcTT4EeYZTWp1PUWW21nFEB1djrkCn6AmRsTnahfbbTL6DWRQbzRdHM1gel8DQbv5axxGXyWyt40xpMmG+fQDoHTyCqKChuBo9NE7WuiKDhhDg0a3BBFRCOEJk0BDC/a/CoDdqHUU0g8OKDqvVypNPPklqaip6vZ6XX36Zbt3+9ytv5cqVrFu3Dl9fXwCeffZZevbs6ag4bd610V3o4evO2kOneW3G1Xi7yBuoPVFVleySRE6d2U2dpRoXp/rLJ85Orhon04aHya/djTUi2i8pONoPh11e2b59OwCffPIJDz/8MC+//HKD5ceOHeOVV15h1apVrFq1qlMXHAA6ncJvRkRRVWdlzf4UreOIS1BWXcjulC85krkDi9VMVNBQfN1CtI7VJlisdWSXJGkdQ3RAZ8e5yS09rXUUcQkcdqZj0qRJjB8/HoDs7Gz8/RteMjh27BgrVqwgPz+f8ePHs2jRIkdFaTcWDIvg6W8OszwugQdG9ZJGUe1Awpk9pOQfAiDIswe9u8R26Eailyo+czt5ZWm/9CyQIdJFyymuzLF3lQ3yCtc2jGg2RXVw8/LFixfz3Xff8eabbzJ69Gj7/W+//Ta33XYb7u7uPPTQQ9x6661MmDCh0W2Ul5eTkNA5hgp/Ymcm36WXsWJSODGBnfPUfHtSYkmn3JaDnyEKV52v1nHanGpbMTnmw7jq/Ah2kmnvRcvJN5+k3HaGLk4xuOi8tY7jMNHR0Xh4tL02YcWVZyirLgBFwdPk1+z2Ww4vOgDy8/O55ZZb2Lx5M66urqiqSkVFhf2JXLNmDSUlJTz44IONrn+26GjJJ3///v0MGTKkRbbVknYkneGad7/j9iE9+Pdto5tegbZ7LJejrR9LWXUBqfmHuarreHQ6PTbVCiqNjoLY1o+lua7kOFRVZXfKl5RU5TIqarbm7Tw6ymsCHedYLuc4LFYz20+uwqh3YWyveW3mrHBLviaO+N67UqqqcurMbo5n78RJ74ybszc6RUdFTTF11lr6hoyiV/AwFOXCLTcc1qZj48aNLF++HAAXFxcURUGvr/9grqioYNq0aVRWVtZ/KO3eTf/+/R0VpV0ZFxFErwBP1h1Oo6CiRus44hdmSy3HsnayK2kDOaXJ5JXXzwysU/Qy7PJFKIpCRODZcTsOapxGdBS5ZalYbRZCfGRsjta04+RqAKYOfJDpMb9lYp/5jO99O9NiHmLawAexqVa2nVh10W04rE3Hddddx5IlS7j99tuxWCw8/vjjfPvtt1RVVTF37lweffRR7rzzToxGI7GxsYwbN85RUdoVRVFYGBvFH77cz7/3pfD78X21jtSpqapKZvEpEs7sxmytxc3Zm74ho/BzD9U6Wrvh7x6Gp8mfM6UpVNaW4ObccU+Fi9bxv2HPZWyO1jQ6ei5OF+gpZDSY6BsyiqigoRfdRrOKjqqqKtLT0+nVqxfV1dW4ujbd1sDV1ZVly5ZdcPmsWbOYNWtWc3bf6dw5NILHtxxkRVwCj47rI5W8huIztpFTmoxeZyA6eDjh/v077BDmjnL2bMfpgiNYZQZQcYVUVSXQsxuuRg9cjZ5ax+lUzhYcteYqCiuzCPGOIj5jO4UV2QwJvx5PF78LFiVnNXl5JS4ujpkzZ/LAAw9QUFDAhAkT2LlzZ8scgWiUr6szNw8MJ7GgnO1JZ7SO0+nYzpmWPdQnmi5eEYyJnkvPgIFScFymQM9whkfMwNNFxu4QV0ZRFML9B9C/q5wd18p/T31MUUUO2SWJnC44Qje/PuxKWt+sdZssOl5//XU++ugjPD09CQgIYM2aNSxduvSKQ4uLOzvl/XKZ8r7VqKqNjMLj/HDqE2rMFQD4e4QxsNs1mJzcNE7Xvp17ts5srdUwiWjPVFWtb7wtNFVnqaZ/17GkFx4nMmgIEYGDm/2+brLosNlsBAQE2G9HRkZeflLRbLHhAVzVxZuNR9LJLa/WOk6HV1KVR1zyRo5l78RiraWsukjrSB1SYu4+dpxcYy/qhLgUJVW57DixhuwS+TGmJRWVgopM0guPE+bbm8KK7AZniC+myaIjODiY7du3oygKZWVlvPvuu4SEyGiLjqYoCgtHRGOxqazcIyM6OkqdpYajmT/wc/JGyqoL6OIdyejoWzrFxGxacHHywGqzkJofr3UU0Q5lFSdQZ63BaHDROkqnNiT8BvalbqFf6Bg8TH7EJX/OsB5Tm7Vuk0XHc889x6ZNm8jJyeHaa6/lxIkTPPfcc1ccWjTt9iE9cDXqee/nRKy25lWR4tKcyNlFZvFJPEy+DOs5nYFhE+VSigOF+ERicnIno+gktZYqreOIdsRqs3CmNBmTkzt+Ms2ApkK8I7n+qoX0C60fS2rawAfp4t28qyBN9l7597//zeuvv35lCcVl8XIxcuugHry/O4lvT+VwQx/pptkSKmtLcXP2AiAq6Gq8XALo5tcP3UUGtBEtQ6fo6REwkBPZP3G64Ai9godrHUm0E7llqVhsZrr59b/o4FPCcT7cuYRz+1Iqih6domC1WXDSO3Nb7DNNbqPJomP79u088sgj0m1TI4tio3l/dxIr4hKk6LhCtZZqEs7sJqs4gaE9puHnHoKr0ZNwfxmeuzV19elFSt4B0guP09M/BieDs9aRRDuQVVzfjkPG5tDOgtH1E7fGJX1OoGc4PQNiUBSF0wVH7GOnNKXJosPb25vrr7+efv364ez8vw+HX88aKxxjSJgfQ7r68tXxLDJLKunqLaf+L5Xtl14pibn7sNjq8DD5otc5bFw80QS9zkC4/0BOnfmZwsosgr069wzTomk15goKKzLxdg2yn6UU2skvzyA28kb77XD/q4jP2NasdZv85L3xxhubeohwsIWx0Sz67Gfe353E05MHah2nXSmuPMPx7J2U1xRh0Bnp02UkYX595VKKxsJ8+xDkGY6rswzuJJrmbHBjeM8ZqM3sISEcy6A3kpi7j3D/AaCqJOcfwNnQvAlKm1V0JCQksGfPHiwWC8OHD6dPnz5XHFo037xB4fxx037e353EE5OuwqCXL8zmKqjIpLymiFCfXkQHD8NZWr23CQa9Ewa9k9YxRDuhKEqzZzEVjjc2ei4/J3/B7pQvUVAI8Y5kTPTcZq3bZNGxceNG3n77bSZNmoTNZuOhhx7i/vvvZ86cOVccXDSPu7MTtw/uwbu7Eth8IouZ/cO0jtRm2VQb2SWJhHhHoVN09AyIIcCjG96ugVpHE40oqswhreAoA8ImyCUv0aiqujJU1SZz9rQh7iYfJvVbcFnrNvkuX7lyJZ999hk+Pj4A3Hfffdx5551SdLSyhbHRvLsrgeVxCVJ0XEBRZQ7Hs3ZSUVuM1Wqmu39/9DqDFBxtWEF5JrllqWQWdaG7v8w0Lc6Xmn+YjKITDO85Q852tBFZxQkcSPuWOksVqvq/++cM/VOT6zZZdNhsNnvBAeDr6ys9WTQwIMSHkeEBfHsqm9TCcnr4eWgdqc2oMVdyKudnckqTAejq07vZfcaFtsL9r+J0wRFS8g8T5tsHnU7mthH/Y7VZyClJxtngKj8e2pDdyV8ytOdUvF2DULi0eqDJxgG9evXixRdf5NSpU5w6dYoXXniB3r17X3ZYcfl+ExuFqsI/d8sIpWdlFp3ix4RPySlNxtMlgBERs+jfdSxGg0nraKIZjAYT3fz6UmupJKukeV3uROeRV5aGxVZHiE+UjM3Rhjg7uRLm2wcPky/uJh/7v+Zo8lV84YUXMBqNPP744yxZsgSj0cjTTz99xaHFpbt5YHd8XIx8sDuJOotMegT1DRJ1io5+oWOIjZgpv4baoXD/q9ApelLyDslkXqKBs4VoqLeMzdGWBHn2YE/KV2QVJ3CmNMX+rzmavLzi5OTE4MGD+eMf/0hRURHbtm3DzU3GitCCi5OBu4ZG8MYPJ9h4NINbYsK1jtTqasyVJObus/dECfLsgZ97KE56GWCqvTI5uRHq04uMouPklCTL4E8CqH+vF5Rn4OUS0Oxf0aJ1FFRkAFBUmd3g/uuvWtjkuk0WHU8++SQ2m41rrrkGgN27dxMfHy/zr2hkYWwUb/xwgvfiEjtV0WFTrZwuOEpy3n6sNguuRg8iAgejKIoUHB1Az4CBOBtcCPTornUU0UaUVRegUwxShLZBZ4sLs6UWG7ZLGoqgyaLj6NGjbNq0CahvRPrqq68yffr0y4wqrlSvQC/GRwSxLekMp/JK6RXY8UfnK6jI5ET2LiprS3DSO9M7dCRdfXppHUu0IBejB5FBQ7SOIdqQQM/uTOxzB0jHhTanvKaQ/578mPKaIlRU3J29Gd/7djxd/Jtct1m9V/Ly8ggMrL9WXlhYiE4nDXq0tDA2mh3Jubz3cyKvzbha6zgOlZx3kMTcvQCE+fYlOmiozNXRgdlUK/ll6QR6hksvOYFBb9Q6gmjErqTP6d91nH3eqtT8eH5KXM8NAxY1uW6TRcd9993HjTfeyJAh9b9CDh8+zBNPPHGFkcWVuPGqMALcnfnX3mReuGGQ1nFaRE5JEin5h8iuTac6IZWIwBi6eEcS5BlOQXkGfUJGNquKFu3bqZzdpBUeZXD3yQR6yqWWziqt4CgGvZEu3hHoFOlG3dbUmisbTJTZI2BAy829Mn36dIYNG8ahQ4cwGAz8+c9/JiAg4PLTiitmNOi5e2gkS7cfY118Gu19UPqckiQO//IHa1XryCw+SUlVLkPCoYt3JMMjZmgbULSarr69SSs8SnLeAQI8usnZjk7IZrOSlLcfRdHJeDttlE5noLAiCz/3+pnPCyoy0TdzWoMmr5Okp6eze/durr32Wnbs2MF9993H0aNHryyxuGK/iY0CYMWu9j+2QUr+IWyqjfKaIurUSmw2CxZbHSn5h7SOJlqZh8mXIM9wSqvzKazI0jqO0EBeeRpma619KgPR9gzrMZ3tJ1az6eBbfHnwTbafWM3wns1r69nkK7pkyRJsNhvbtm3j9OnTLFmyhBdeeOGKQ4sr09PPg+t6hfDT6XySS2q0jnNFiipzKK3Kw2ypQYceT5cATE5uVNSUaB1NaCAicDAAyXkHNE4itJBV/MvYHNJrpc0K9OzGTUP+H6Ojb2FM9C3MGvQoAR7dmrVuk0VHbW0ts2bNYvv27UyfPp2rr76aurq6Kw4trtzCX852bEgq1jjJ5csuSaKqtgwVFRejJ846D/vso+4mmeCpM/J08cffI4ziqjMUVeZoHUe0olpLFQXlGXi6+ONh8tU6jriA1Px4vjz0Jj5uQeh1Tnx+4HXSC481a90miw69Xs8333zDjh07GD9+PN9//730XmkjpvXtSoinC1tSS6msNWsd57IEenQj2KsnniZ/XIzuDZb1DIjRKJXQWkTAYFyNXthsMkJpZ5JTkoSKKiOQtnHxGduY3P9eADxd/Jge81sOpn/frHWbrB6ee+45duzYwVNPPUVgYCCbN2+WyytthJNexz3Do6g02/jk0Gmt4zSLqtpIyT9MdnEiUN8lblzvWxkSPvmXXzYKHiZfBoZNlEZknZiPWxBjom/B36Or1lFEK3I2uOHtGijv/TbOqlpxMf5v0lEXozsNppu9iCZ7r/Tq1YuXX37Zfvtvf/vbZUQUjnLP8Ehe/D6e9+ISuWd4lNZxLqq6roIjmdspqszB1ehFsHeEvaFYF+9IunhHsr9sP0OiZJAogb3nitVmQa9r8qNKdABdvCPo4h2hdQzRhCDP7vz35Mf0DIwBFE7nHyagmV3c5TpJOxfm48aoEHf2ZhSyP6NQ6zgXlFOSxE+J6yiqzCHQszvDI2ZIy3TRpMyiU2w/sZrymrb7ty1ahtrMX8pCeyMiZuHnHsqpnN0k5u7F1z205XqviLbvpsj6yZBW/Nz2us9abRbiM7ZzOGMbNtVGv9CxDOp23SWN1S86L2cnFyy2OpLzDmodRTiQTbXyY8KnJJzZo3UU0Qx6nYHu/v3p1WUE43vfRje/vs0+G9msoqOiooKcnByys7Pt/0TbMaKLO9193Pj4wGnKatpWzyKdoqfWXImXSwCjomYT5ttbBnwSzebvHoanyZ8zpSlU1koX6o4qvyyDqrpSrNJwuF1IzT/M1uP/Yk/KJmrN1Ww+/Pdm/zBosuj4xz/+wdixY7n99tu54447uOOOO5g/f/4VhxYtR69TuHdEFJV1FtYcSNU6Tv38GeX1Ux8rikJMt2sZHjEDN+eOPzmdaFmKohARWD/Uf3KeDBbXUWWVnAJkbI724kjmf5k64AGc9EZcjO7MGPQwRzK3N2vdJs+HrFu3ju+//x5fX+kz3ZbdPSyCZ785zPJdCdwXG63Z2YTK2hIOZ2yjrLqAYT2m4eseIhO0iSsS6BmOm7M3OSWJRAYNxtXoqXUk0YKsah3FZRl4mHzxdPHTOo5oBkXRNfhcr39PNu87p8kzHV26dMHLS36htnVdPF2Z2T+MIzkl/JxW0Or7V1WV9MLj/JS4gbLqAkJ9omWCNtEi6s92DEZFJbf0tNZxRAursOWhYiPUp5fWUUQzebsGciJ7FzbVRmFFNrsSN+DrFtKsdZs80xEeHs5tt93G8OHDMRr/N83wQw89dPmJhUMsjI1mfXw6K+ISiA1vvUn5ai3VHMv8gbzyNJz0zgwIHU+wV89W27/o+IK9euJq9MDbNUjrKKKFlVvPYEIvY3O0IyMiZhGfsQ29zomfEtfRxTuSoWFTm7Vuk0VHUFAQQUHyRm8PJkYGE+nvwaeH0vjrzKvxdW2dyxppBUfIK0/Dzy2Eq8LGY3Jyb3olIS6BTtFJwdFBBRh6ERYSKD3aLoOq2ohL/oLiyhx0ip5RUbMbnGFOOLOHU2d2oyg6BoZNJMz3f3OSH8vaSbW5nKvDbwCgoDyDPambARUXJw/G9JqLQdf4zLFOeiMx3SYxJPx6yqoLKK0usE9f0ZQmi46HHnqIoqIiDh8+jNVqJSYmBn9/OW3eFul0CgtHRPGnrw6wal8KvxvruEnvrTYLOkVvP/XtYvSkq08v6ZkiHKqytoSU/MNEBw+TL6kOwlnnQZhfX61jtEvphcex2sxMHfgAeWXp7E3dzDV97wKgqq6c49k/MT3mt1htFrbEv0uIdxSqqrIraT355Rl09+8P1F8e/ylpAxN6346niz8JZ/ZQWVOCl2vjZ8wPpX9PaVU+Q8Jv4Osjy/F2DSK7OIHhETOazNxkm44ff/yRmTNnsmHDBj7//HNmzJjB9u3Na6UqWt9dQyMw6nWsiEtw2GA7ZdUF7EraYJ/gR68zSFdY0SoKKrLIKj5FWsERraOIK2RTrZRVy6BvVyK37LS9LUygZzcKK7LsywrKMwj0DEevM2A0mPA0+VFcmYNVNRMROJgBYRPsjy2rLsBkcOV49k98Hb+cWkv1BQsOgIzCE4yKmkNK/iF6Bgxicv97yStPa1bmJouOv/3tb3z00Ue89dZbvPPOO6xdu5Y33nijWRsXrc/f3cTsAd04mVfGDyl5Lbrt+nlTDhGXvJHK2hJqLJUtun0hmtLVpxfOBhfSC49httRqHUdcgYLyTHYlrafY0rwvK3E+s7UGo95kv60oCjbV+suy2gbLnPTO1FlrcDa4ntc1ucZSSV55Gr27jGBy/3vJKUkiuyTpgvtVsWHQO5FZfIKuPr1QVRsWa/PGiGqy6LBYLISFhdlvh4WFYbPZmtyw1WplyZIlzJs3j9tvv5309PQGy7dt28bs2bOZO3cun376abPCiuZZNLL+D2r5rpYbobS6rpw9KV+RcGYPRr2Jq8On0Ct4eIttX4jm0OsMhPsPxGIzk1Z4VOs44gpkFdd/PrnqZDiGy0aQTLkAACAASURBVOWkN2G2/q/4VlUVnaL/ZZlzg2X1RUjjlySdDa54mPzwdg1Cp9MT6hPd4KzJr3XxjmLjgb9hs1kJ9urB10dWEObbvEtkTRYdISEhfPjhh1RUVFBRUcGHH35IaGhokxs+ewnmk08+4eGHH24waZzZbObll1/mgw8+YNWqVaxdu5b8/PxmBRZNG90jkL5BXmw4kk5eefUVb6+qroyfEtdTXHWGIM9wRkXNkdk/hWbCfPvgpHcmrfBos39dibalzlJDXnka7s4+GBVpeH65Aj27k1l8EoC8snR83ILty/w9wsgtS8ViM1NnqaGkOh9vt8YbY3uYfLFY6yirrh9uIbfs9EUbbg/tMYVJfe9mysAHUBQdw3vO4OoeNzQrc5NFx4svvsihQ4eYNGkS11xzDQcPHuS5555rcsOTJk3i+eefByA7O7tB49Pk5GS6deuGl5cXRqORIUOGsG/fvmYFFk1TFIWFsVGYrTb+tTflirfn4uRBoGd3+oeOI6bbtRgNpqZXEsJBDHonwv0HYLbWkl50Qus44jLklCajqjZCfbQbyLAj6O7XD73Oic2H/87e1K8Y2mMax7J+JL3wOK5GD/qGjOLr+OV8c+Q9Bne/7oK9UfQ6A6OiZvPDqU/YdOht3IxehPn2Pu9xOxM+o7S6/gSBu8nbPmmnn3v9GB3FlbnsTPjsopkV1cFT+y1evJjvvvuON998k9GjRwOwb98+Vq9ebW8bsmzZMkJCQrj55psb3UZ5eTkJCW1vMrO2rKzOytTPE/B3MbB+eiS6S3xjV9tKqLYV42vo4aCEQlw+m2qhyJqKl74rTor0Ymlvsur2U6uW080Yi0GREYsvJjo6Gg8PD61jAFBZW8qelK+oNpfVjxRs9EKn6KmoLSanNBk3oxdDe0zD3eR9wW38//buPL6p88wX+O8c7ZZky5a87yubMYtZQpYxmAyQAAkJDgSnhhYaaJtM00xLG/qhS5KZJjRz79wOvUwg06YpSW/DpJkMmSQNCSTNgllsdi94w/sq27K1WPu5f8gWGLxhJB0tz/fz4YN1js7R8/pYOo/e857nHfeW2V27duHgwYMoLCwcMxM9fvz4lILct28ffvSjH2HTpk344IMPEBYWBoVCAaPx+iBEo9E4pV+qJ3/55eXlyM/P98i++DZeW7Y02fGHs/XoVyZg1YypVYtzcg7UdZWjp6ceDBjMzPl7n86ZEgrHJdD4bztuf0yR/7bl9gVqWyx2E/qvXkKCfDYWpd0dsO0Yiyfb4o9ftuWSCKyY9QT05l609Fa5ez3CpWr8Xc7jUypjP27SMXJp5PDhw9MK7r333kNXVxd27doFmUwGhmEgELgGuGRmZqKpqQk6nQ5hYWEoKyvDjh07pvU6ZHw7l2XjD2frcai0dkpJh8Gsw6WWExg0ayETK5GXVEiTtBG/xnEc+oztiAyLA8sK+A6HTIFEGIYVs0pgtZv5DoVMk1KqxuzEe6e17bhJR0xMDADg5Zdfxv79+0et27ZtG954440Jd7xq1Srs2bMHTzzxBOx2O37605/i2LFjMJlM2Lx5M5577jns2LEDHMdh48aNVPXUC5akaDA/IRJHK1rQPmBCQkTYuM9t6a1EVccpODk7EiNnYFb8MggF4nGfT4g/aOq9guqOUsxJvG9UtUXi3wSsEDIxDSANReMmHU8//TSqqqrQ1dWFlStXupc7HA7ExcWNt5lbWFgYfvOb34y7vrCwEIWFhbcZLrkdDMNg5905+N47p/H7M3XY+/d54z7XbDdBwApo3hQSUOIiMlDTeQYNPReQGDnDPbCN+Kd+Yxf05l7Eq7Igoi81IWncpOPll1+GTqfD888/j1/+8pfXNxAKoVbT9MOBonhBOn78fjn+41Qt9qzMhYC9/qHcZ2iHSh4HlmGRGbMQyVGzIBXJeYyWkNsjFcmRFDkDzX2V6NDV3VL0iPiXpt7L6BxoQLhMA1VYDN/hkDtgc1ihN/ciMiwOdqdtyknkuF8LFAoFkpKSoNVqkZiY6P4XGxsLoXDSKVuIn1BKRShemI4WnQkfVbcDcM2bUtH2Jc5c+x9c67kIwDWhFiUcJBClR88HAxYNPRfAcZMXLiT8sNkt6B5sglyiQoTMd7NgE89r19Xh6Pnf4ETlHzFkM+Cdsy+7i71NZtK+SI1Gg7KyMlitVIQnUO2863qF0oGhHpys/Qta+qqglEYhJjyF5+gIuTMysQKJkdkwWnToHLjGdzhkHB0D9XByDqrNEQTONX6MB/K+A7FQijCxEg/k7ULZtQ+ntO2kXRaXL1/GN77xjVHLGIZBVRUV5QkUC5KisDRFjT5DBT6vroFEyCJNMxfZsYshYKnXigS+9Oj56NY3w8HZ+Q6FjKNd5/omnKDK5jkScqc4cAgTXy9fMVH10ptNesY5derU9KIifuXJpVG42lGGFl0UHl+8ARoFlTEnwUMuicDymcXueSeIfzFadNCZuqFRJNFl3CAgF4ejpa8KAAOLfQjVHaWQS8YvCHajSS+vDA0N4ZVXXsGjjz6Khx9+GC+99BJMJtOdxkx8gOM494yDmxcuwtfNsfjfX0UjQja1QmGEBJKRhMPJOeDlQsvkNtkcVkSGxdFA3yCxLOtRNHRfgNEygL+U/Rp9hg7cnf3olLadtKfjhRdegEwmw69+9SsAwJEjR/CLX/wCr7zyyp1FTbzK5rCgsu0rcOAwL3klwsRC5KcuxMkvq3G0ogUb81L5DpEQj9PqW3Cl7UvkJv0d9eb5EVVYDJZmPkTJYJCQiRUomLllWttOmnRUVFTg6NGj7sc///nP8eCDD07rxYhv9Bracbn1c5htBqjCYuFw2iAUiLHzrmzs/7Iah0prKekgQUkklMJsM6C++zwlHX6IBpAGh0btZVxu+RwW++hZzIsW/3jSbSdNOjiOw+DgIMLDwwEAg4OD7nLmxL84OQdqO8twTXsRDBhkxeQjI2aBu2DS7DgV7suIwac1HajTDiJLE85zxIR4VoQsGhplMrT6FvQZOxAlj+c7pJBX0fYlHE4HZifcA6Fg7FlOSWA5e+0D3JezCQpJ5G1vO2nS8c1vfhOPPfYYVqxYAQA4ceIEnnzyyduPkngVxzlxpuF96EzdCBOHIy95xZgjincuy8GXDd14rbQW+9YHxyRLhNwoM3ohtPoWNHSfR1Q6JR18sjmsaOuvhVQkpzvlgki4VI3Y8DQw06gAPOlfwcaNG5Gbm4uysjI4nU7s378fM2bMmFagxHsYhkVcRAYUkkjMjL973G8UG/NS8Ox7EvzhbD1eeGA+JELqtSLBJVIeiyh5ArSGVuhM3VT5kkedAw3D8zlRbY5gMifxPvz18muIi0gflXjMT7l/0m0nTVP+4R/+ATNmzMATTzyBkpISzJgxA9u2bbuziIlHWGwmVLWfdFdhTFXPRW5SwYRdmBKhANsWZ0JrtODdS82+CpUQn8qMWQAAU66SSLyjvZ9qcwSjiy0noJRGebanY7wJ3+x2O+LjqcuSb92DTbjc+jfYHGZInK7jMdVvEk/elY3/9XklDpXWYMvCdG+GSQgvouQJWJT2ANSKRL5DCVlGywD6TZ1QyxNoRtkg4+ScuDfnsWltO+mEb//8z/+MvXv3Xt+AJnzjld1pQ3V7KVr7q8EyAsyKvxs9jebb2kd2dDhWZsfheG0nKjt1mB03taIuhAQKhmGgUSbzHUZIG+nlSIyky/HBJkGVhar2k0iMzAHLXE8jFNLJzyXjJh0KhQIKhQK/+c1v0NDQgJkzZ+L9999HZWUlnnzySURFRXkmejJlA6YeXGw5AZN1AEppFPKSC6GURkHbVH7b+9q5LAfHazvx2qla/OuGxV6IlhD+WexDaNJeRmJkzpQrJhLPiFdlwck5ERORxncoxMNGJgqtaPvyhqWMZ26Z3b17N5KSkmCxWLB//348/PDD2LNnDw4ePDjtgMn02BwWmKwDSNPkISd2MVh2+oNAH85NRpxShj+WNeCfH1yAMDGNLCfBp9/YgYaeC7DYTZibtJzvcEKKQhqJGfFL+Q6DeEHR4p9Me9tJR4G0trZi9+7dOHbsGIqKivDUU09Bq9VO+wXJ7TFZ9bDYXGXnNcok3JezGTPj77qjhAMARAIW25dmQjdkxZELTZ4IlRC/ExueDrlEhfb+Wpiser7DCRkm6yBVHw1C55s+AQB8VfOfY/6bikmTDofDgb6+Pnz66adYvnw5enp6YLFY7ixyMimO49DWX4OTte/gcuvf3G9guSTCY6/x7aXZYBjgtVM0wp8EJ4ZhkBmzABw4XOu5wHc4IcHusOKrmndQ3vRXvkMhHqYZHpgdF5Ex5r+pmLRPfceOHdi0aRMKCwuRk5OD1atX45lnnrmzyMmEbHYLKtq/ROdAA4SsCPGqTK+8TmqUAmtmJuKjqjZcaOvD/EQap0OCT1xEJuq6ytHafxUqbjbf4QS9zsFrcHJ2qGRUHyXYJKtd7x+TdRB5yStGrStvnFqSOWnSsX79eqxfv979+MMPP6Qy6F7Ua2gbnjfFCFVYLPKSVyBM7L1y5buWZeOjqjYcKq3FgSK6/kqCD8uwyIiejyttX2DA0cJ3OEFvpDZKAs0oG3TKGj+C2WpAS18VBoeuD7PgOCd69C3IT1sz6T7GTTp27dqFgwcPorCwcMz6D8ePH59m2GQ8NocF55uOweG0Izt2EdKj57vnTfGWB2clIlkVhrfONWDfuoVQSmluBBJ8EiKz0W/qxKCZxhl4k8k6iP7hOW/CxEq+wyEelqbOhc7UjY6B+lGXUxiGxbyUlRNsed24SceLL74IADh8+PAdhkkm4+ScYBkWIoEEuUkFkIoUPivdLGBZ7FiajV9+fBH/7/w17FxG305I8GEZAeYmLUd51+3fXk6mrr2/FgD1cgQrjTIZGmUyUtRzIBZKp7WPcZOOkydPTrhhYiJV+rtTHMehubcCrf3VWJrxMIQC0ZQH43jS9qVZePGTSzhUWosn78qmORJIUNOb+yAVySESSPgOJeh065shYIWIC/f95xjxnekmHMAEScfp06cBAM3NzWhqakJBQQEEAgG++uorZGVlYcOGDdN+UQKYbUZcaf0btIZWiARSGK06RMiieYklMSIM6+ck4b3LLTjb0oslKRpe4iDE24wOLb6uLUdWTD6yYmmWZU+7K+Mh6M19NIU9Gde4ScdLL70EACgpKcHRo0fdFUgHBgbw1FNP+Sa6INU12IgrrV/A5jBDo0jG3KQCSERhvMa0864cvHe5BYdKayjpIEFLxkbCJuhEU+8VpGnmQigQ8x1SUGFZASLC+PnyRHynrqv8lqS9qr0UsxKWTbrtpHevdHd3Q6W6Xj5YJpOhp6dnGmESAKjtKkN99zn3vCkp6jl+cTnj73PikR6lwJ/PN+JfHloElYw+jEnwYRkB0jRzUdtVhua+KmREz+M7pKBgd9rQ1ncVcapMSIQyvsMhXlLR9hVsDjOudp6GwdLvXu7knLjWc2FKScekt0YsX74c3/rWt/DWW2/hzTffxLe+9S088MADdxZ5CNMokhEu02BZ1iNI1eT6RcIBACzLYOeybAzZHHizrIHvcAjxmhT1HAhZERp7LsLhtPMdTlDoGriGqo6TaNZe4TsU4kXhsuFe8JtuAhOwQtybPbVZZyft6dizZw8+/vhjnDlzBgzDYPv27aOmuicTc2WAFxGvykSYOByR8lgsy3zEb5KNG31zcSZ+/teLOHSqBk/dO8MvYyTkTokEEqSo56Ch5wJa+6qRqsnlO6SARzPKhobkqJlIjpqJNE3etO+wnNIsX6tXr8bq1aun9QKhzGQdxKWWz6AzdUFv7sX8lPsBwG9P5jFKGR6Zm4wjF5rw9bUe3JtBFQVJcErVzEVLXxVsDprS4U4NWQ3oNbYjMiwOYRLvFTIk/Pu04g+4f8438WnF6wBuPY95ZJZZcvs4jkO7rhZV7V/D7rQhLiIDcxLu4zusKdm1LAdHLjThYGkNJR0kaEmEMiyf+QQELH0E3ql2nas2RyLV5gh6GTHzAQDLZxZDKlJMax/eLXcZgmx2Cy62HMfl1s8BAHOTlmNe8kqIhIFRE6AgMxYzosPxzsUmaA1mvsMhxGtGEg6O42hG1GkamZiSZYS81BgivnW+6RM4OQdO1v0XFNLIW/5NBaX5HubgbOg1tCEyLA5zk1cEXClghnENKP3h0XL8sawB/7icJsgiwWtwSIuKti+Rqs5FQmQ23+EEHLvDCpnYVUGZbj8OfrHhaTj89V5wAN74ao97OQfXxZZt97406T4o6fAAp9MBk1UPhVQFqUiBpRkPQS6JAOPleVO8ZeviTPz0w/M4VFqDH/zdLLCsf45BIeROiQQSDA71or7nPOJVWX473spfiYQSLE5fC45z8h0K8YF7cx7DvTmP4XjlG1g5e9u09hGYZ0U/ojf3obT+v1DW+AFsdtegNIU0MmATDgCICpNg0/w01Gr1+Kyuk+9wCPEamViJhMhsGC06dA1e4zucgBXIn3fk9k034QAo6Zg2juPQqL2M0rr/gt7ch2hlChg2eH6dO+9ydTUfOlXLcySEeFdGtGtwXH33ORrbcRs6BxpwoflTGMw6vkMhASR4zpI+ZLYZUdb4Eao7SiFgRViYuhpzEu+DkA2e+QaWpUVjbrwK711uRufgEN/hEOI1ckkE4iMyoTf3oUffzHc4AaOlrxqdAw2gK1LkdlDSMQ2XWk6g19AKjTIZ92YXISY8le+QPI5hGOxalgO7k8PrZ+r4DocQr8qIWQAAaO6r5DmSwGC2GdBraIUqLAZyiWryDQgZRknHFN3Y7Tor4W7MSrgH+alreJ+ozZuKF6YjTCzAa6dq4XDSQDESvJTSKCxMXY0FKX/PdygBob3f9UUkUUW1Ocjt8UrSYbPZsHv3bhQXF6OoqAjHjx8ftf7111/H2rVrUVJSgpKSEjQ0+PdcHzpTF76ufQcGs2uCG6VUjVQ/majNmyJkYmxZkI6mfiOOXe3gOxxCvComPJWKhU2BqzbHVbCMAHGqTL7DIQHGK++wo0ePQqVS4ZVXXkF/fz8eeeSRUfO1VFRUYN++fcjN9e85D5ycEw3d510DzMCh19g+5QIowWLXshz87nQdDpbW4IFZiXyHQ4hXOZx2tPZVIyIsZtpzSwS7gaEeGK0DiIvIgEgQGEUPif/wStKxZs2aUXO1CASCUesrKipw6NAh9PT0YPny5di1a5c3wrgjJssgLrWegM7UDalIgblJy6FWJPAdls/lJ6uxKFmNDyrb0NJvRHKknO+QCPGawaFeVHWchEaRjEXpNJv2WKQiOTJjFkItD73PQ3LnGM6L94gZDAZ897vfxaZNm7B+/Xr38t/+9rcoLi6GQqHA008/jS1btmDFihXj7kev16OmpsZbYd5iyNmPTtsVcHBAzsZAI8yGgAmeO1Nu13t1/fjVmQ58O1eDnXn07Y8Et3brBZg5HRJF+ZCwgVVRmASfnJwcKJXB83fotQuYHR0deOqpp1BcXDwq4eA4Dtu2bXP/EgsKClBZWTlh0jHCk7/88vJy5Ofnj7nOajfjdEMfMmMWIEHl/6WRJ2qLJ8zIteG3l/6CD5uN+L9bF0Ao8N74Y2+3xZeCpS3B0g5gam1JM8Th7LUPIA23YmGq/7abj+NitZshEkg8Op4t1P6+psrXX7Z9xStnD61Wi+3bt2P37t0oKioatc5gMGDdunUwGo3gOA6nT5/2i7EdWn2r+x59sVCKe7OLAiLh8AWFRIRv5GegfXAI/1PZync4hHhVlDwBqrAYdA82Qm/u5Tscv3Kp9TN8cfXPsDksfIdCApRXko5XX30Vg4ODOHDggPsOlaNHj+Ltt9+GUqnEs88+i61bt6K4uBhZWVkoKCjwRhhT4nDaUdVeirLGD3Gl9Qs4nQ4AVNb3ZjuXUYVSEhoYhkFG9EIAQEP3BZ6j8R9mmxG9+laIhVIaQEqmzSuXV/bu3Yu9e/eOu37Dhg3YsGGDN156Uh26OjT0XEC7pRn66mrYHBY4nHbIxRHISykEywom30kImhsfibvTonHsajsaevXIUAfPNUZCbhatTEaCKhux4Wl8h+I3OnR14MAhMZJqc5DpC6mv8x26OlxsOQH9UB/snBntujr0DDYjQhaNu7M3IkIWzXeIfm3nshxwHPAf1NtBghzDMMhLXoHYiHS+Q/ELrtocNWAYFvERWXyHQwJYSCUdDT2urlIOHBycFQwYKKRRcHIOKgo0BUXzUhApE+P1M/Ww2h18h0OIT1hsJlhsJr7D4NWgWQuDpR8xylSIhHRphUxfSJ1pRyqKMgwDMSuHIkwBlhHQLIlTJBMJsW1xJv7PF1V470oLNs1P4zskQrxqwNSD0w1HkRiZgzmJ9/EdDm86da6q0XRpxb9wnBOl9f+NfmMHWEaAe7I3Ilymca+v6TyDq52nwTAs5iUXIjlqlntdRdtXGLLpsSjtgeHHX6K26ywkQlctpruzHkVEmOd7/0Oqp+PGaqIMWLCMYHg5TVg0Ve4BpaXBdysXITdTytSQiMLQ2n8VZpuR73B4kx23GPlpa6BRJvEdCrlBc28lHE4b1s77HvLTHsDZax+415mselS2f40H876LVXN2oLzxr3A47bA7bPji6p9R3VE6al+9hjbcm7MJD+TtwgN5u7yScAAhlnRkRM+/reXkVjNiIrAiKxaf1XXhavcA3+EQ4lUswyIjegE4zolG7SW+w+ENy7CIVqa4v6gR/9A12IjEyBkAgJjwFPQa2tzrtPoWxISnQcAKIRZKES5Vo9/YAQdnQ2bMQuQlj66N1Wtow+WWz/HhpX/HpZbPvBZzSCUd8aoszEsuhFIaBYCBUhqFecmFiFfRwKjb8eRdri7W12hAKQkBiZHZkIrkaO6tgsU+xHc4Ptehqw/pXh5/ZnOYIRZI3Y8ZhoGTcwyvs4xaJxJIYHWYIRGGjXmZLD16HpZlPYLVuU+ie7ARLX1VXok5pJIOwJV43JNdhAxJAe7JLqKEYxoemZuMaIUEb5ytx5DNznc4hHgVywiQrpkHJ2dHk/Yy3+H4lMVuwqWWEzjXdIzvUMgYRALpqEJtHMe5e6NEAsmoda4kRDbmfjiOw+yEeyEVySFghUiKmok+Q7tXYg65pIPcObFQgO1LstBnsuKdi818h0OI1yVFzYREKAu5b/zu2hxUndkvxYSnorW/GgDQPdiMSHmce51GmYyuwWuwO22w2s3QDfVAJY8dcz82hwXvnftX2BwWcByHDl091ArvzCoeUnevEM/59l3Z2HeiAq+V1qBkUQbf4RDiVQJWiHtzNoVcJU53bQ7qEfZLqeo5aNfV4YOLBwAA92QXoaLtSyilaqSoZ2N2wj346NJBgOOwMHUVhOzYE5eKhVLkp63GXy+/BgErQHxEFpKiZnolZko6yLRkqJVYNSMBx66243JHP+bGR06+ESEB7MaEg+M4j0565o8Gh7TQm/sQE54GsVA6+QbE5xiGxd1Zj4xapgq7PhN4TtwS5MQtGXPb7NhFox5nxixEZsxCzwd5E7q8QqZtl/v2WRpQSkLDkNWAc03HQuJOlrZ+1/uaanMQT6Kkg0zbutlJSAiX4c3yBhgtNr7DIcTrhAIR+gxtuNZzEQ5ncA+itjutkAjDEK1M5jsUEkQo6SDTJhSw2LE0G4NmG/58oZHvcAjxOpFAghT1HFgdZrT2VfMdjlfNTSrA3814nGpzEI+ipIPckR1Ls8AyDF1iISEjVTMXLCPENe1FOJ3BPQcRzUlFPI2SDnJHkiPlWDs7EWUtvShv6eU7HEK8TiKUIUU9C2abEW264JsOwGo343zTsVHVLQnxFEo6yB3bucw10OzQqeD7ACZkLGmaPDAMi0btZXAcx3c4HtWhq0PXYCP0ZvoSQTyPkg5yx1bPiEdqpBz/71wjBoasfIdDiNdJRXLMT16JJenrgu7W2bb+GjBgqDYH8QpKOsgdE7AsnrwrG0arHX86d43vcAjxidiIdEhEYXyH4VF6cy8GzVpEK1MgEQZX24h/oKSDeMS3lmRByDI4WFoTdN3NhIyH4zh0DVwLmvEPI7U5EiKp7DnxDko6iEfEhcvwcG4yLnfocKpJy3c4hPjEkFWP882foLqjNOCTbSfnRLuuFiKBBDHKVL7DIUGKkg7iMbuGB5QeLKUBpSQ0hEnCER+RCb25Dz36wJ78kOOcSFXnIl0zDyxLtTmId1DSQTxmRVYcsjRKHLnQiD6TZfINCAkCGTELAAD13ecDurdDwAqRGbMAGTHz+Q6FBDFKOojHsCyDnXdlw2J34nBZA9/hEOITSmkUYsLTMDDUjV5jYI7tcDodcHJOvsMgIYCSDuJR2xZnQixgcfAkDSgloSMz+npvRyBq7a/G36r/hD5DO9+hkCBHSQfxKI1CiqJ5qbjaM4i/1XfxHQ4hPhERFo2kyBmIC08PyGS7rb8GFrsJYZIIvkMhQY6SDuJxO2nKexKCcpMKkKrJDbhiYQZzPwaGeqBRJkMqkvMdDglylHQQj7s3PQazYyPw7uVmdOuH+A6HEJ9yOO0w24x8hzFlI/PHJKpyeI6EhAJKOojHMQyDXctyYHM48Yez9XyHQ4jPmG0G/K36T6hs/5rvUKaE45xo76+FkBUjJpxqcxDvo6SDeMU3FmVAJhLgtVO1cDoD7xo3IdMhEcoRJglHd4BMmNZrbIfFbkK8KpOmsSc+QUkH8QqVTIzN89PQ0GvAp7UdfIdDiE8wDIOM6IUAgIbuCzxHMzm1PBGL09ciTTOX71BIiKCkg3jNrrupQikJPdHKZCilanQM1MNoGeA7nAkxDAO1IhFyiYrvUEiIoKSDeM3iZDXmJ0Ti/YpWtA+Y+A6HEJ9gGAaZw1VKG3r8t7djwNQDk3WQ7zBIiKGkg3gNwzDYeXcOHE4Ovz9Tx3c4hPhMbHg65BIVjBad31b6rOo4iS+u/hkWO91hRnyHkg7iVcUL0qGQCPFaaS3sDv/8buWUiQAAGeRJREFU8CXE0xiGwZKMdVia8RBYxv8+Zo2WAehMXVArkiARyvgOh4QQ/3s3kKCilIrwxMIMtA6Y8FF1YM5LQch0SIRhflsorK3/KgAgMZJqcxDfoqSDeB1VKCWhyuaworLtK9R0nuE7FDeOc6JdVwshK0JseBrf4ZAQQ0kH8br5iVFYmqLBR9VtaOoz8B0OIT4jYAXo1jehUXvFb8ZO9BrbYbYZERdBtTmI71HSQXxi57IccBzwH6ept4OEDpYRIF0zD07OjibtZb7DAQAYzTowDEuXVggvvJJ02Gw27N69G8XFxSgqKsLx48dHrT9x4gQ2btyIzZs348iRI94IgfiZTfNTESEV4fen62GjAaUkhCRFzYRYKENzbwVsdgvf4SBVk4vCmSVQhcXyHQoJQV5JOo4ePQqVSoU//elPeO211/Diiy+619lsNrz00kv4/e9/j8OHD+Ptt99GT0+PN8IgfiRMLMTWxZno1A/haEUL3+EQ4jMCVoh0TR7sThuaeq/wHQ4AQCSU+O0gVxLcvJJ0rFmzBs8884z7sUAgcP9cX1+PlJQUREREQCwWIz8/H2VlZd4Ig/iZnXe5BpQePEkVSkloSY6aDZFAgqbeK3A6HbzFUd1xCh06qplD+OOVUURyuRwAYDAY8P3vfx8/+MEP3OsMBgOUSuWo5xoMUxtcWFPj2ZNVeXm5R/fHp0Bpy/zoMByv7cR7n5ciWSke8zmB0papCJa2BEs7AP7aInLEQcTIcP6856qU3k5bbNwQWqynIWVUSBD7V3l2+vsKHV4butzR0YGnnnoKxcXFWL9+vXu5QqGA0Wh0PzYajaOSkInk5ORM+bmTKS8vR35+vkf2xbdAassPmSiUvPUVSvVibFh+a8yB1JbJBEtbgqUdQGi3pbarDLpuJeYm3edXg0hD+ZhMRK/Xe/yLtj/wyuUVrVaL7du3Y/fu3SgqKhq1LjMzE01NTdDpdLBarSgrK8OCBQu8EQbxQxvzUqCRS/D6mXpY7Px1MxPCF52pG92DzT59TY7j0NZfAwErQmxEuk9fm5AbeaWn49VXX8Xg4CAOHDiAAwcOAAAee+wxDA0NYfPmzXjuueewY8cOcByHjRs3IjaWRlGHColQgG8uzsS/fF6Jv1xqRvFC+gAkocPmsOJMw/9ALJRAo3wcLCOYfCMP6DO2w2wzIDFyBoSsyCevSchYvJJ07N27F3v37h13fWFhIQoLC73x0iQAPLksG//yeSUOldZQ0kFCikggRop6Fhq1l9HWX4vkqJk+ed22fld9nERVtk9ej5DxUHEw4nNZmnCszI7Dlw3dqOzU8R0OIT6VpskDw7Bo6DnvsxloVWExiFamIFIe75PXI2Q8lHQQXuy62zWQ7dApqlBKQotUJEdS5EwMWfXo1NX75DVT1LORn7aGanMQ3lHSQXjx0JxkxCll+OPZepisdr7DIcSn0qPngQGL+p7z4DjOq6/F+ag3hZCpoKSD8EIkYLF9aSYGzDYcudDEdziE+FSYWIkU9SzEhKfCyXnvLi6TVY/Pqt5Ec2+F116DkNtBSQfhzbeXZoNhgEOlwXcvOiGTmZVwD2bELfXqTK/t/TWwOsxgGZpNlvgHSjoIb1KjFFgzMxGnm7W40NbHdziE8ILjOFhsJq/st01XA5YRIo5qcxA/QUkH4dWuZa5b+A6V0oBSEnocTju+qv1PnGs65vGxHf2mTgxZ9YiLSIdQMPaUA4T4GvW5EV49OCsRyaowvHWuASqZCL3d3TgYHBWRCZmUgBVCLlGhe7ARfcZ2qBWJHtt3e7/rsqU/lTwnhHo6CK8ELItv35UNg8WOfScq8B9XtHj+44t8h0WIz2RGu6aBqO8+57F9Opx2dA40QCpSIEqe4LH9EnKnqKeD8E5nso56/MKxSwCAX6yex0c4hPhURFg0NIpkaA0t6Dd2IlIed8f7ZBkB8tMehNUxRLU5iF+hng7Cq+c/voh//aLqluUvHLtEPR4kZGTGDPd29Jz3yP4YhkGkPBax4Wke2R8hnkJJB+HN8x9fdPdqjOWFY5ew53881+VMiL+KlMchSh4Pg7kfNrvljvZlsQ/BYO73UGSEeBZdXiF+7defVeC/r7RgcYoGi5PVWJyixryEKEhFvpmdkxBfyUsuhFgoveOZZ1v7qlHbdRbzU+5HXESGh6IjxDMo6SC8GRmzMV5vxz1p0ZCKBDjb0os3yxvwZnkDAFc107x41XAiosHiFDVmxoRDwFLHHQlcUpH8jvfBcRza+mvAMgKoFUkeiIoQz6Kkg/BqvMTj56vy3OucTg41PYM429KLs81anG3R4kJbP8pb+/AqXLcFKiRC5Ceph3tDXL0iKZFyGkRHAoqTc+BazyVY7CbMTrjntrfXmbphsg4gPiITIqrNQfwQJR2EdzcnHjcmHADAsgxmxkZgZmwESha5uoutdgcudeiGkxBXMvJFQxf+Vt/l3i5GIcXiFLW7N2RxsgZqucSHLSPk9jBg0TlQD725D6nqXMglEbe1fVv/VQBAYuQMb4RHyB2jpIP4hZEko729fUq3yoqFAixKVmNRshrfHV42aLbiXGsfzjb34kyLFmUtvfigsg0fVLa5t8tQK7A4WYMlKWosStZgYVIUwsT0NiD+gWEYZMYsxIXmT9HQcwFzkwqmvO1IbQ6JUA61gmpzhAKOc6K0/r/Rb+wAywhwT/ZGhMs07vU1nWdwtfM0GIbFvORCJEfNcq+raPsKQzY9FqU9MGqfJ2vfhVgku2W5p9CnLfEbv1g9D+Xl05/mPlwqxvKsOCzPul7noHNwCGeHE5Azzb0oa9Hi7QuNePtCIwBAwDKYE6ty9YQMX5bJjVNBKKDxIYQfseHpkEtUaO+vRVbMQsjEyiltpzf3wsk5kRKZDYahv99Q0NxbCYfThrXzvofuwWacvfYBVs7eBsA1w3Bl+9dYP/8f4HDa8eGlf0eCKhscx+Fk3V/Qo29BqiZ31P6udpxGv6kTsV6cq4eSDhLU4sJlWD8nGevnJANwDbRr6DXgTLMrETnbrMW5tj5c6ujH707XAQBkIgEWJkZh0fAlmSUpGmSoFTQ+hPgEwzDIjF6AS62foaHnIuYk3jul7VRhsSic9Q2Pz+FC/FfXYKP7UlpMeAp6Ddd7dbX6FsSEp0HACiFghQiXqtFv7IBSpkZmzELEq7IwMNTjfn73YBN69M3IiVsyarmnUdJBQgrDMMjUKJGpUWLLQlc2b3c4UdGlw5lmVxJS1tKLU81afN14/Y0XFSbGIvdlGTWWpGgQq5Tx1QwS5OJUmajtLkNb/1VkxS6ERBg2pe1oYrfQYnOYIRZI3Y8ZhoGTc4BlBLA5LKPWiQQSWB1mSIRhSIzMQW1XmXudyTqIC82fonBWCa5px6+d5AmUdJCQJxSwmJcQhXkJUXjyLtest0aLDefb+lHWonUlIy1aHLvajmNX293bpUTKXQnI8EDV/CQ1lFIRX80gQYRlWMxOuAcMw0IsmDy57dDVw+G0I16VCQFLH+uhQiSQwua4XkyO4zh3nReRQDJqnSsJGftvqVF7GRabCZ9UvI4hmwEOpxURsmhkxy7yeMz010nIGOQSEe7NiMG9GTHuZVqDGWWtvTg7nIScbe7Fu5ea8e6lZgAAwwCzYiLcY0MUxiHMtTsgFlIhM3L7opUpU3oex3Go6y7HkFWP2OHudBIaYsJT0dJXhfToPHQPNo+at0ejTMa5po9hd9rgdDqgG+qBSh475n5mJ9zjvkW7tqsMA0M9Xkk4AEo6CJkyjUKKNTMTsWama/pxjuPQojPhTLPWfetueWsvKrsG8MbZegDAzk+bMD8xEouTNViU4uoVyYkOB8vS+BAyNSarHgZzH2LCU8dcPzDUA6NFh7iIDIiEdEt4KElVz0G7rg4fXDwAALgnuwgVbV9CKVUjRT0bsxPuwUeXDgIch4WpqyBk+e+JpaSDkGliGAYpkXKkRMpRNM91QnA4najuHsTZ5l58eK4KjUMMzrf140xzL/C1a7twqQiLktSj7phJjAijgarkFhznxJmGo7A7rCiYWQyR4Nakoq3fVSAvMTLH1+ERnjEMi7uzHhm1TBV2vXc2J24JcuKWjLnteD0Z3urhGEFJByEeJGBZzIlTYU6cCnMFOuTn58Nsc+Bie9/wZRnXYNUTdZ04Udfp3i4+XDaqmuqiZDUiw+hba6hjGBYp6lzUdJ5Gc28FMmMWjlrvqs1RD4lQRmXPSUCgpIMQL5OKBFiaGo2lqdHuZbohK8pbXGNDXPVDenG0ohVHK1rdz8nWKG+Y6E6D+YmRkInoLRtqUqJm4VrPBTRqLyNVPRdCgQjPf3wR7e3d+GVmE2wOC9I188BSbQ4SAOgTjBAeqGRirMyJx8qcePeytgGT+5bdkToifzp3DX86dw0AIGQZzI2PHFXafXZsBE10F+SEAjFS1bmo6y5HS18l/nju+pQBaUliLE+PRkJkNs9REjI1lHQQ4icSI8KQODcFG+a67lpwOjnU9epHFTI739aH8219OFRaCwCQi4XIT4rCIvf8MmqkRVEhs2CTqs5Fo/YSPqr4Er/6VAnAlWju/Ws7fr4qD8uyovgNkJApoqSDED/FsgxyosOREx2Ob+Rfn+juSufoQmZfXuvGFw3d7u00csmoyzKLk9WIVkjHe5kJjXTjH8z3SJPINImEElzojMDf6vohEnCwOwGAA8C4ez2mMmcR8R56r0wNJR2EBBCxUICFSWosTFLjO3e77lbQm20419aHsmYtzgz3iHxU1YaPqq6XRE6LkrtLui9KVmNhUhQUkolvn3v+44vuE1rCxxfppDZNHMfB7uRgsTtgsTuH/x/+2eGA2XbDcodz1PPMdgesdic+qGzF8VoDgJFxQRy25HWi2yDG8YYovHDsEkobe/BwbjLEQhYSoQBSoQCSyX4WCSARuH6m+Yamj94rU0dJByEBTikVoSAzFgWZ1wv/dOuHhu+UuV7I7D8vNuE/LzYBAFiGwZy4CCwa7g1ZkqxBbrwKouETz40fogAC7tu03XHrSdxsc6Cm3wxHs/amBOD6Cd5id8J6Q0Jw47aux6O3sd607XiJg2emQ3FdMpupMeD+zD7kaIzQmsRoG5SgWqvAJzUd+KSmY9p7F7AMJEJ2OCkRjPmzeJzlN/8sFQlcyY9gOLGZIPlpN1iRODjkXi4RsgE1TinQ3yu+RkkHIUEoRinD2tlJWDvbdRslx3Fo7DO4S7qXDRcyu9yhw+tnXIXMpEIBFiRGwcE5XXVFbjLRh6nD6bzl5D3Wid3iGD6B33Bit45x4r9l25ET/si2jlufY76hB8E50Vn+owYP/IavYxkGUpHrBDty0oyQim85uY6csF3Pu7Wn4caTrlgoGD5hjywT4O3z11DWdBnb89shFTrcr79+Zg9WOuOwcsaiW5InV7I0/Lu9+ecbfmfWm35/Iz/3mayjlnvN0bpRD4UsM+p350pcXL+rkZ/FN/w8lWRpvB6eiZIisYCdsJDfzQnHCEo8xkdJByEhgGEYpKuVSFcrsXlBGgBXb0Bl14C7J+Rssxanmnow0ZfyF45dwm++qIJMJBw++btORg6n72Y2ZRiMOqlIhAIoJUJo5JJRJxyx8NaT+WBfH5IT4q4vE1w/yUtveu7N/9/8mr6+LPHgrET89rNKGIen03ByDIZsLNKiFJib4MA92clefX2O42C9qefo5stD5nETyFuXj2zf3tUDebjqejJpu55o3rjvQbPNnRDZHF5MgG4iErBj9tD0mSzo1JvH3Y4Sj7FR0kFIiBIKWOQlRCIvIRI7lrpuudz74Xm8dPzKhNtxHAeFRAi1XHzrN3nB9W/mY56oh/8XT3ASH+tb543LhSwz7btzysvLkZ8fuCP9sjUMrvVFwGbvh94iQFqUAmlRChjMOq+/NsMw7mPhSdM5Jk6nKwEaq3fGndCM0bPmGiMzfnI06mebw51k3dhLNGSzQzfkxKDZ6tHfQ6igpIMQ4vZPDy6ASMCO2WUMAD9flUff3HikkEYiLYpDYx8LucOCtCjF8HIVz5H5FssykLKuSyN8Gu/yCkDvlfEEzmgdQohP/GL1PPx8Vd4ty+lDlH8Z0fMBAGlRCiQoxLcsJ75F75XbRz0dhJBbjHxgjnyLow9R/xCvygIANPRcgF5vgFIahYzo+e7lxPfovXJ7KOkghIxp5IOzvb2dPkT9SLwqC/GqLJQPliM/O3DHpwQTeq9MnVcvr1y8eBElJSW3LH/99dexdu1alJSUoKSkBA0Nnr2FjRDiGb9YPQ8782ImfyIhIY7eK1PjtZ6O1157DUePHoVMJrtlXUVFBfbt24fc3FxvvTwhhBBC/IzXejpSUlKwf//+MddVVFTg0KFD2LJlCw4ePOitEAghhBDiRxiO80yB3rG0trbiH//xH3HkyJFRy3/729+iuLgYCoUCTz/9NLZs2YIVK1aMux+9Xo+amhpvhUkIIYT4pZycHCiVSr7D8BifDyTlOA7btm1z/xILCgpQWVk5YdIxwpO//EAvEnQjaot/Cpa2BEs7AGqLPwqWdgCebUuwftn2eZ0Og8GAdevWwWg0guM4nD59msZ2EEIIISHAZz0d77//PkwmEzZv3oxnn30WW7duhVgsxrJly1BQUOCrMAghhBDCE68mHUlJSe7xHOvXr3cv37BhAzZs2ODNlyaEEEKInwmI4mBOp2tGQZPJ5NH96vV6j+6PT9QW/xQsbQmWdgDUFn8ULO0APNeWkfPdyPkvWHj17hVP6erqQmtrK99hEEIIIT6VlJSE2NhYvsPwmIDo6VCr1QAAqVQKlqU56gghhAQ3p9MJs9nsPv8Fi4Do6SCEEEJI4KNuA0IIIYT4BCUdhBBCCPEJSjoIIYQQ4hOUdBBCCCHEJ0Im6bh48SJKSkpuWX7ixAls3LgRmzdvvmViOn80Xjtef/11rF27FiUlJSgpKUFDQwMP0U2NzWbD7t27UVxcjKKiIhw/fnzU+kA6JpO1JZCOi8PhwJ49e/D444/jiSeeQHNz86j1gXRcJmtLIB0XAOjt7UVBQQHq6+tHLQ+kYzJivLYE2jHZsGGDO9Y9e/aMWnfkyBE8+uij2LRpEz777DOeIvRTXAg4dOgQt27dOu6xxx4btdxqtXL3338/p9PpOIvFwj366KNcd3c3T1FObrx2cBzH/fCHP+QuX77MQ1S375133uH+6Z/+ieM4juvr6+MKCgrc6wLtmEzUFo4LrOPyySefcM899xzHcRx36tQp7jvf+Y57XaAdl4nawnGBdVysViv3ve99j1u1ahVXV1c3ankgHROOG78tHBdYx8RsNnMPP/zwmOu6u7u5devWcRaLhRscHHT/TFxCoqcjJSUF+/fvv2V5fX09UlJSEBERAbFYjPz8fJSVlfEQ4dSM1w4AqKiowKFDh7BlyxYcPHjQx5HdnjVr1uCZZ55xPxYIBO6fA+2YTNQWILCOy/33348XX3wRANDe3g6NRuNeF2jHZaK2AIF1XPbt24fHH38cMTExo5YH2jEBxm8LEFjHpLq6GkNDQ9i+fTu2bt2KCxcuuNddunQJCxYsgFgshlKpREpKCqqrq3mM1r+ERNKxevVqCIW31kEzGAxQKpXux3K5HAaDwZeh3Zbx2gEAa9euxS9/+Uu88cYbKC8v9+suPblcDoVCAYPBgO9///v4wQ9+4F4XaMdkorYAgXVcAEAoFOInP/kJXnzxRaxevdq9PNCOCzB+W4DAOS7vvvsuoqKicN99992yLtCOyURtAQLnmACuQpU7duzA7373Ozz//PP40Y9+BLvdDiDwjouvhUTSMR6FQgGj0eh+bDQaR/2xBAqO47Bt2zZERUVBLBajoKAAlZWVfIc1oY6ODmzduhUPP/zwqMkAA/GYjNeWQDwugOvb6Mcff4yf/exn7vkfAvG4AGO3JZCOy1/+8hecPHkSJSUlqKqqwk9+8hP09PQACLxjMlFbAumYAEB6ejoeeughMAyD9PR0qFSqgD0uvhbSSUdmZiaampqg0+lgtVpRVlaGBQsW8B3WbTMYDFi3bh2MRiM4jsPp06eRm5vLd1jj0mq12L59O3bv3o2ioqJR6wLtmEzUlkA7Lu+99567W1smk4FhGPflokA7LhO1JZCOy1tvvYU333wThw8fxqxZs7Bv3z5ER0cDCLxjMlFbAumYAMA777yDl19+GYBrbjCDweBuS15eHsrLy2GxWKDX61FfX4+cnBw+w/UrATH3iqe9//77MJlM2Lx5M5577jns2LEDHMdh48aNATWxzo3tePbZZ7F161aIxWIsW7YMBQUFfIc3rldffRWDg4M4cOAADhw4AAB47LHHMDQ0FHDHZLK2BNJxWbVqFfbs2YMnnngCdrsdP/3pT3Hs2LGAfK9M1pZAOi43C5bPLyBwP8OKioqwZ88ebNmyBQzD4Fe/+hUOHz6MlJQUrFy5EiUlJSguLgbHcXj22WchkUj4Dtlv0NwrhBBCCPGJkL68QgghhBDfoaSDEEIIIT5BSQchhBBCfIKSDkIIIYT4BCUdhBBCCPEJSjoIIWM6ffr0mJMLEkLIdFHSQQghhBCfoKSDEDKpN954AyUlJRgaGuI7FEJIAAvJiqSEkKl79913cezYMRw6dAgymYzvcAghAYx6Oggh46qpqcHPfvYzbN26FXK5nO9wCCEBjpIOQsi45HI59u/fj1//+tfuWVoJIWS6KOkghIwrMTERhYWFWLJkCf7t3/6N73AIIQGOkg5CyKR+/OMf4/3330dFRQXfoRBCAhjNMksIIYQQn6CeDkIIIYT4BCUdhBBCCPEJSjoIIYQQ4hOUdBBCCCHEJyjpIIQQQohPUNJBCCGEEJ+gpIMQQgghPkFJByGEEEJ84v8Do+uaNn+GgaYAAAAASUVORK5CYII=\n", 482 | "text/plain": [ 483 | "
" 484 | ] 485 | }, 486 | "metadata": {}, 487 | "output_type": "display_data" 488 | } 489 | ], 490 | "source": [ 491 | "%matplotlib inline\n", 492 | "from sklearn import datasets\n", 493 | "\n", 494 | "iris = datasets.load_iris()\n", 495 | "X, y = iris.data, iris.target\n", 496 | "\n", 497 | "from sklearn.cluster import MiniBatchKMeans\n", 498 | "from yellowbrick.cluster import KElbowVisualizer\n", 499 | "\n", 500 | "# Instantiate the clustering model and visualizer\n", 501 | "visualizer = KElbowVisualizer(MiniBatchKMeans(), k=(1,6))\n", 502 | "visualizer.fit(X) # Fit the training data to the visualizer\n", 503 | "visualizer.poof() # Draw/show/poof the data" 504 | ] 505 | }, 506 | { 507 | "cell_type": "markdown", 508 | "metadata": {}, 509 | "source": [ 510 | "## More Modelling" 511 | ] 512 | }, 513 | { 514 | "cell_type": "markdown", 515 | "metadata": {}, 516 | "source": [ 517 | "### Gensim\n", 518 | "\n", 519 | "**Gensim** is a Python library for topic modelling, document indexing and similarity retrieval with large corpora. Target audience is the natural language processing (NLP) and information retrieval (IR) community." 520 | ] 521 | }, 522 | { 523 | "cell_type": "markdown", 524 | "metadata": {}, 525 | "source": [ 526 | "### PyBrain\n", 527 | "\n", 528 | "**PyBrain** is a popular package for working in Reinforcement Learning, Artificial Intelligence and Neural Networks. **PyBrain** contains algorithms for neural networks, for reinforcement learning (and the combination of the two), for unsupervised learning, and evolution." 529 | ] 530 | }, 531 | { 532 | "cell_type": "markdown", 533 | "metadata": {}, 534 | "source": [ 535 | "## A few more Packages" 536 | ] 537 | }, 538 | { 539 | "cell_type": "markdown", 540 | "metadata": {}, 541 | "source": [ 542 | "There are many more packages, e.g.,\n", 543 | "\n", 544 | "- Beautiful Soup (**beautifulsoup4**) - a package for working with website text (HTML, XML). Beautiful Soup is similar to the tidyverse’s **rvest**\n", 545 | "- **Pipenv** - a software development package aimed at streamlining development and making managing requirements easy.\n", 546 | "- **NLTK** - the Natural Language Toolkit is a package created to contain a rich set of natural language processing tools and make prototyping quick." 547 | ] 548 | } 549 | ], 550 | "metadata": { 551 | "celltoolbar": "Tags", 552 | "kernelspec": { 553 | "display_name": "Python 3", 554 | "language": "python", 555 | "name": "python3" 556 | }, 557 | "language_info": { 558 | "codemirror_mode": { 559 | "name": "ipython", 560 | "version": 3 561 | }, 562 | "file_extension": ".py", 563 | "mimetype": "text/x-python", 564 | "name": "python", 565 | "nbconvert_exporter": "python", 566 | "pygments_lexer": "ipython3", 567 | "version": "3.6.6" 568 | } 569 | }, 570 | "nbformat": 4, 571 | "nbformat_minor": 2 572 | } 573 | -------------------------------------------------------------------------------- /Data/airquality.csv: -------------------------------------------------------------------------------- 1 | Ozone,Solar.R,Wind,Temp,Month,Day 2 | 41.0,190.0,7.4,67,5,1 3 | 36.0,118.0,8.0,72,5,2 4 | 12.0,149.0,12.6,74,5,3 5 | 18.0,313.0,11.5,62,5,4 6 | ,,14.3,56,5,5 7 | 28.0,,14.9,66,5,6 8 | 23.0,299.0,8.6,65,5,7 9 | 19.0,99.0,13.8,59,5,8 10 | 8.0,19.0,20.1,61,5,9 11 | ,194.0,8.6,69,5,10 12 | 7.0,,6.9,74,5,11 13 | 16.0,256.0,9.7,69,5,12 14 | 11.0,290.0,9.2,66,5,13 15 | 14.0,274.0,10.9,68,5,14 16 | 18.0,65.0,13.2,58,5,15 17 | 14.0,334.0,11.5,64,5,16 18 | 34.0,307.0,12.0,66,5,17 19 | 6.0,78.0,18.4,57,5,18 20 | 30.0,322.0,11.5,68,5,19 21 | 11.0,44.0,9.7,62,5,20 22 | 1.0,8.0,9.7,59,5,21 23 | 11.0,320.0,16.6,73,5,22 24 | 4.0,25.0,9.7,61,5,23 25 | 32.0,92.0,12.0,61,5,24 26 | ,66.0,16.6,57,5,25 27 | ,266.0,14.9,58,5,26 28 | ,,8.0,57,5,27 29 | 23.0,13.0,12.0,67,5,28 30 | 45.0,252.0,14.9,81,5,29 31 | 115.0,223.0,5.7,79,5,30 32 | 37.0,279.0,7.4,76,5,31 33 | ,286.0,8.6,78,6,1 34 | ,287.0,9.7,74,6,2 35 | ,242.0,16.1,67,6,3 36 | ,186.0,9.2,84,6,4 37 | ,220.0,8.6,85,6,5 38 | ,264.0,14.3,79,6,6 39 | 29.0,127.0,9.7,82,6,7 40 | ,273.0,6.9,87,6,8 41 | 71.0,291.0,13.8,90,6,9 42 | 39.0,323.0,11.5,87,6,10 43 | ,259.0,10.9,93,6,11 44 | ,250.0,9.2,92,6,12 45 | 23.0,148.0,8.0,82,6,13 46 | ,332.0,13.8,80,6,14 47 | ,322.0,11.5,79,6,15 48 | 21.0,191.0,14.9,77,6,16 49 | 37.0,284.0,20.7,72,6,17 50 | 20.0,37.0,9.2,65,6,18 51 | 12.0,120.0,11.5,73,6,19 52 | 13.0,137.0,10.3,76,6,20 53 | ,150.0,6.3,77,6,21 54 | ,59.0,1.7,76,6,22 55 | ,91.0,4.6,76,6,23 56 | ,250.0,6.3,76,6,24 57 | ,135.0,8.0,75,6,25 58 | ,127.0,8.0,78,6,26 59 | ,47.0,10.3,73,6,27 60 | ,98.0,11.5,80,6,28 61 | ,31.0,14.9,77,6,29 62 | ,138.0,8.0,83,6,30 63 | 135.0,269.0,4.1,84,7,1 64 | 49.0,248.0,9.2,85,7,2 65 | 32.0,236.0,9.2,81,7,3 66 | ,101.0,10.9,84,7,4 67 | 64.0,175.0,4.6,83,7,5 68 | 40.0,314.0,10.9,83,7,6 69 | 77.0,276.0,5.1,88,7,7 70 | 97.0,267.0,6.3,92,7,8 71 | 97.0,272.0,5.7,92,7,9 72 | 85.0,175.0,7.4,89,7,10 73 | ,139.0,8.6,82,7,11 74 | 10.0,264.0,14.3,73,7,12 75 | 27.0,175.0,14.9,81,7,13 76 | ,291.0,14.9,91,7,14 77 | 7.0,48.0,14.3,80,7,15 78 | 48.0,260.0,6.9,81,7,16 79 | 35.0,274.0,10.3,82,7,17 80 | 61.0,285.0,6.3,84,7,18 81 | 79.0,187.0,5.1,87,7,19 82 | 63.0,220.0,11.5,85,7,20 83 | 16.0,7.0,6.9,74,7,21 84 | ,258.0,9.7,81,7,22 85 | ,295.0,11.5,82,7,23 86 | 80.0,294.0,8.6,86,7,24 87 | 108.0,223.0,8.0,85,7,25 88 | 20.0,81.0,8.6,82,7,26 89 | 52.0,82.0,12.0,86,7,27 90 | 82.0,213.0,7.4,88,7,28 91 | 50.0,275.0,7.4,86,7,29 92 | 64.0,253.0,7.4,83,7,30 93 | 59.0,254.0,9.2,81,7,31 94 | 39.0,83.0,6.9,81,8,1 95 | 9.0,24.0,13.8,81,8,2 96 | 16.0,77.0,7.4,82,8,3 97 | 78.0,,6.9,86,8,4 98 | 35.0,,7.4,85,8,5 99 | 66.0,,4.6,87,8,6 100 | 122.0,255.0,4.0,89,8,7 101 | 89.0,229.0,10.3,90,8,8 102 | 110.0,207.0,8.0,90,8,9 103 | ,222.0,8.6,92,8,10 104 | ,137.0,11.5,86,8,11 105 | 44.0,192.0,11.5,86,8,12 106 | 28.0,273.0,11.5,82,8,13 107 | 65.0,157.0,9.7,80,8,14 108 | ,64.0,11.5,79,8,15 109 | 22.0,71.0,10.3,77,8,16 110 | 59.0,51.0,6.3,79,8,17 111 | 23.0,115.0,7.4,76,8,18 112 | 31.0,244.0,10.9,78,8,19 113 | 44.0,190.0,10.3,78,8,20 114 | 21.0,259.0,15.5,77,8,21 115 | 9.0,36.0,14.3,72,8,22 116 | ,255.0,12.6,75,8,23 117 | 45.0,212.0,9.7,79,8,24 118 | 168.0,238.0,3.4,81,8,25 119 | 73.0,215.0,8.0,86,8,26 120 | ,153.0,5.7,88,8,27 121 | 76.0,203.0,9.7,97,8,28 122 | 118.0,225.0,2.3,94,8,29 123 | 84.0,237.0,6.3,96,8,30 124 | 85.0,188.0,6.3,94,8,31 125 | 96.0,167.0,6.9,91,9,1 126 | 78.0,197.0,5.1,92,9,2 127 | 73.0,183.0,2.8,93,9,3 128 | 91.0,189.0,4.6,93,9,4 129 | 47.0,95.0,7.4,87,9,5 130 | 32.0,92.0,15.5,84,9,6 131 | 20.0,252.0,10.9,80,9,7 132 | 23.0,220.0,10.3,78,9,8 133 | 21.0,230.0,10.9,75,9,9 134 | 24.0,259.0,9.7,73,9,10 135 | 44.0,236.0,14.9,81,9,11 136 | 21.0,259.0,15.5,76,9,12 137 | 28.0,238.0,6.3,77,9,13 138 | 9.0,24.0,10.9,71,9,14 139 | 13.0,112.0,11.5,71,9,15 140 | 46.0,237.0,6.9,78,9,16 141 | 18.0,224.0,13.8,67,9,17 142 | 13.0,27.0,10.3,76,9,18 143 | 24.0,238.0,10.3,68,9,19 144 | 16.0,201.0,8.0,82,9,20 145 | 13.0,238.0,12.6,64,9,21 146 | 23.0,14.0,9.2,71,9,22 147 | 36.0,139.0,10.3,81,9,23 148 | 7.0,49.0,10.3,69,9,24 149 | 14.0,20.0,16.6,63,9,25 150 | 30.0,193.0,6.9,70,9,26 151 | ,145.0,13.2,77,9,27 152 | 14.0,191.0,14.3,75,9,28 153 | 18.0,131.0,8.0,76,9,29 154 | 20.0,223.0,11.5,68,9,30 155 | -------------------------------------------------------------------------------- /Data/mtcars.csv: -------------------------------------------------------------------------------- 1 | "","mpg","cyl","disp","hp","drat","wt","qsec","vs","am","gear","carb" 2 | "Mazda RX4",21,6,160,110,3.9,2.62,16.46,0,1,4,4 3 | "Mazda RX4 Wag",21,6,160,110,3.9,2.875,17.02,0,1,4,4 4 | "Datsun 710",22.8,4,108,93,3.85,2.32,18.61,1,1,4,1 5 | "Hornet 4 Drive",21.4,6,258,110,3.08,3.215,19.44,1,0,3,1 6 | "Hornet Sportabout",18.7,8,360,175,3.15,3.44,17.02,0,0,3,2 7 | "Valiant",18.1,6,225,105,2.76,3.46,20.22,1,0,3,1 8 | "Duster 360",14.3,8,360,245,3.21,3.57,15.84,0,0,3,4 9 | "Merc 240D",24.4,4,146.7,62,3.69,3.19,20,1,0,4,2 10 | "Merc 230",22.8,4,140.8,95,3.92,3.15,22.9,1,0,4,2 11 | "Merc 280",19.2,6,167.6,123,3.92,3.44,18.3,1,0,4,4 12 | "Merc 280C",17.8,6,167.6,123,3.92,3.44,18.9,1,0,4,4 13 | "Merc 450SE",16.4,8,275.8,180,3.07,4.07,17.4,0,0,3,3 14 | "Merc 450SL",17.3,8,275.8,180,3.07,3.73,17.6,0,0,3,3 15 | "Merc 450SLC",15.2,8,275.8,180,3.07,3.78,18,0,0,3,3 16 | "Cadillac Fleetwood",10.4,8,472,205,2.93,5.25,17.98,0,0,3,4 17 | "Lincoln Continental",10.4,8,460,215,3,5.424,17.82,0,0,3,4 18 | "Chrysler Imperial",14.7,8,440,230,3.23,5.345,17.42,0,0,3,4 19 | "Fiat 128",32.4,4,78.7,66,4.08,2.2,19.47,1,1,4,1 20 | "Honda Civic",30.4,4,75.7,52,4.93,1.615,18.52,1,1,4,2 21 | "Toyota Corolla",33.9,4,71.1,65,4.22,1.835,19.9,1,1,4,1 22 | "Toyota Corona",21.5,4,120.1,97,3.7,2.465,20.01,1,0,3,1 23 | "Dodge Challenger",15.5,8,318,150,2.76,3.52,16.87,0,0,3,2 24 | "AMC Javelin",15.2,8,304,150,3.15,3.435,17.3,0,0,3,2 25 | "Camaro Z28",13.3,8,350,245,3.73,3.84,15.41,0,0,3,4 26 | "Pontiac Firebird",19.2,8,400,175,3.08,3.845,17.05,0,0,3,2 27 | "Fiat X1-9",27.3,4,79,66,4.08,1.935,18.9,1,1,4,1 28 | "Porsche 914-2",26,4,120.3,91,4.43,2.14,16.7,0,1,5,2 29 | "Lotus Europa",30.4,4,95.1,113,3.77,1.513,16.9,1,1,5,2 30 | "Ford Pantera L",15.8,8,351,264,4.22,3.17,14.5,0,1,5,4 31 | "Ferrari Dino",19.7,6,145,175,3.62,2.77,15.5,0,1,5,6 32 | "Maserati Bora",15,8,301,335,3.54,3.57,14.6,0,1,5,8 33 | "Volvo 142E",21.4,4,121,109,4.11,2.78,18.6,1,1,4,2 -------------------------------------------------------------------------------- /Data/tips.csv: -------------------------------------------------------------------------------- 1 | total_bill,tip,sex,smoker,day,time,size 2 | 16.99,1.01,Female,No,Sun,Dinner,2 3 | 10.34,1.66,Male,No,Sun,Dinner,3 4 | 21.01,3.5,Male,No,Sun,Dinner,3 5 | 23.68,3.31,Male,No,Sun,Dinner,2 6 | 24.59,3.61,Female,No,Sun,Dinner,4 7 | 25.29,4.71,Male,No,Sun,Dinner,4 8 | 8.77,2.0,Male,No,Sun,Dinner,2 9 | 26.88,3.12,Male,No,Sun,Dinner,4 10 | 15.04,1.96,Male,No,Sun,Dinner,2 11 | 14.78,3.23,Male,No,Sun,Dinner,2 12 | 10.27,1.71,Male,No,Sun,Dinner,2 13 | 35.26,5.0,Female,No,Sun,Dinner,4 14 | 15.42,1.57,Male,No,Sun,Dinner,2 15 | 18.43,3.0,Male,No,Sun,Dinner,4 16 | 14.83,3.02,Female,No,Sun,Dinner,2 17 | 21.58,3.92,Male,No,Sun,Dinner,2 18 | 10.33,1.67,Female,No,Sun,Dinner,3 19 | 16.29,3.71,Male,No,Sun,Dinner,3 20 | 16.97,3.5,Female,No,Sun,Dinner,3 21 | 20.65,3.35,Male,No,Sat,Dinner,3 22 | 17.92,4.08,Male,No,Sat,Dinner,2 23 | 20.29,2.75,Female,No,Sat,Dinner,2 24 | 15.77,2.23,Female,No,Sat,Dinner,2 25 | 39.42,7.58,Male,No,Sat,Dinner,4 26 | 19.82,3.18,Male,No,Sat,Dinner,2 27 | 17.81,2.34,Male,No,Sat,Dinner,4 28 | 13.37,2.0,Male,No,Sat,Dinner,2 29 | 12.69,2.0,Male,No,Sat,Dinner,2 30 | 21.7,4.3,Male,No,Sat,Dinner,2 31 | 19.65,3.0,Female,No,Sat,Dinner,2 32 | 9.55,1.45,Male,No,Sat,Dinner,2 33 | 18.35,2.5,Male,No,Sat,Dinner,4 34 | 15.06,3.0,Female,No,Sat,Dinner,2 35 | 20.69,2.45,Female,No,Sat,Dinner,4 36 | 17.78,3.27,Male,No,Sat,Dinner,2 37 | 24.06,3.6,Male,No,Sat,Dinner,3 38 | 16.31,2.0,Male,No,Sat,Dinner,3 39 | 16.93,3.07,Female,No,Sat,Dinner,3 40 | 18.69,2.31,Male,No,Sat,Dinner,3 41 | 31.27,5.0,Male,No,Sat,Dinner,3 42 | 16.04,2.24,Male,No,Sat,Dinner,3 43 | 17.46,2.54,Male,No,Sun,Dinner,2 44 | 13.94,3.06,Male,No,Sun,Dinner,2 45 | 9.68,1.32,Male,No,Sun,Dinner,2 46 | 30.4,5.6,Male,No,Sun,Dinner,4 47 | 18.29,3.0,Male,No,Sun,Dinner,2 48 | 22.23,5.0,Male,No,Sun,Dinner,2 49 | 32.4,6.0,Male,No,Sun,Dinner,4 50 | 28.55,2.05,Male,No,Sun,Dinner,3 51 | 18.04,3.0,Male,No,Sun,Dinner,2 52 | 12.54,2.5,Male,No,Sun,Dinner,2 53 | 10.29,2.6,Female,No,Sun,Dinner,2 54 | 34.81,5.2,Female,No,Sun,Dinner,4 55 | 9.94,1.56,Male,No,Sun,Dinner,2 56 | 25.56,4.34,Male,No,Sun,Dinner,4 57 | 19.49,3.51,Male,No,Sun,Dinner,2 58 | 38.01,3.0,Male,Yes,Sat,Dinner,4 59 | 26.41,1.5,Female,No,Sat,Dinner,2 60 | 11.24,1.76,Male,Yes,Sat,Dinner,2 61 | 48.27,6.73,Male,No,Sat,Dinner,4 62 | 20.29,3.21,Male,Yes,Sat,Dinner,2 63 | 13.81,2.0,Male,Yes,Sat,Dinner,2 64 | 11.02,1.98,Male,Yes,Sat,Dinner,2 65 | 18.29,3.76,Male,Yes,Sat,Dinner,4 66 | 17.59,2.64,Male,No,Sat,Dinner,3 67 | 20.08,3.15,Male,No,Sat,Dinner,3 68 | 16.45,2.47,Female,No,Sat,Dinner,2 69 | 3.07,1.0,Female,Yes,Sat,Dinner,1 70 | 20.23,2.01,Male,No,Sat,Dinner,2 71 | 15.01,2.09,Male,Yes,Sat,Dinner,2 72 | 12.02,1.97,Male,No,Sat,Dinner,2 73 | 17.07,3.0,Female,No,Sat,Dinner,3 74 | 26.86,3.14,Female,Yes,Sat,Dinner,2 75 | 25.28,5.0,Female,Yes,Sat,Dinner,2 76 | 14.73,2.2,Female,No,Sat,Dinner,2 77 | 10.51,1.25,Male,No,Sat,Dinner,2 78 | 17.92,3.08,Male,Yes,Sat,Dinner,2 79 | 27.2,4.0,Male,No,Thur,Lunch,4 80 | 22.76,3.0,Male,No,Thur,Lunch,2 81 | 17.29,2.71,Male,No,Thur,Lunch,2 82 | 19.44,3.0,Male,Yes,Thur,Lunch,2 83 | 16.66,3.4,Male,No,Thur,Lunch,2 84 | 10.07,1.83,Female,No,Thur,Lunch,1 85 | 32.68,5.0,Male,Yes,Thur,Lunch,2 86 | 15.98,2.03,Male,No,Thur,Lunch,2 87 | 34.83,5.17,Female,No,Thur,Lunch,4 88 | 13.03,2.0,Male,No,Thur,Lunch,2 89 | 18.28,4.0,Male,No,Thur,Lunch,2 90 | 24.71,5.85,Male,No,Thur,Lunch,2 91 | 21.16,3.0,Male,No,Thur,Lunch,2 92 | 28.97,3.0,Male,Yes,Fri,Dinner,2 93 | 22.49,3.5,Male,No,Fri,Dinner,2 94 | 5.75,1.0,Female,Yes,Fri,Dinner,2 95 | 16.32,4.3,Female,Yes,Fri,Dinner,2 96 | 22.75,3.25,Female,No,Fri,Dinner,2 97 | 40.17,4.73,Male,Yes,Fri,Dinner,4 98 | 27.28,4.0,Male,Yes,Fri,Dinner,2 99 | 12.03,1.5,Male,Yes,Fri,Dinner,2 100 | 21.01,3.0,Male,Yes,Fri,Dinner,2 101 | 12.46,1.5,Male,No,Fri,Dinner,2 102 | 11.35,2.5,Female,Yes,Fri,Dinner,2 103 | 15.38,3.0,Female,Yes,Fri,Dinner,2 104 | 44.3,2.5,Female,Yes,Sat,Dinner,3 105 | 22.42,3.48,Female,Yes,Sat,Dinner,2 106 | 20.92,4.08,Female,No,Sat,Dinner,2 107 | 15.36,1.64,Male,Yes,Sat,Dinner,2 108 | 20.49,4.06,Male,Yes,Sat,Dinner,2 109 | 25.21,4.29,Male,Yes,Sat,Dinner,2 110 | 18.24,3.76,Male,No,Sat,Dinner,2 111 | 14.31,4.0,Female,Yes,Sat,Dinner,2 112 | 14.0,3.0,Male,No,Sat,Dinner,2 113 | 7.25,1.0,Female,No,Sat,Dinner,1 114 | 38.07,4.0,Male,No,Sun,Dinner,3 115 | 23.95,2.55,Male,No,Sun,Dinner,2 116 | 25.71,4.0,Female,No,Sun,Dinner,3 117 | 17.31,3.5,Female,No,Sun,Dinner,2 118 | 29.93,5.07,Male,No,Sun,Dinner,4 119 | 10.65,1.5,Female,No,Thur,Lunch,2 120 | 12.43,1.8,Female,No,Thur,Lunch,2 121 | 24.08,2.92,Female,No,Thur,Lunch,4 122 | 11.69,2.31,Male,No,Thur,Lunch,2 123 | 13.42,1.68,Female,No,Thur,Lunch,2 124 | 14.26,2.5,Male,No,Thur,Lunch,2 125 | 15.95,2.0,Male,No,Thur,Lunch,2 126 | 12.48,2.52,Female,No,Thur,Lunch,2 127 | 29.8,4.2,Female,No,Thur,Lunch,6 128 | 8.52,1.48,Male,No,Thur,Lunch,2 129 | 14.52,2.0,Female,No,Thur,Lunch,2 130 | 11.38,2.0,Female,No,Thur,Lunch,2 131 | 22.82,2.18,Male,No,Thur,Lunch,3 132 | 19.08,1.5,Male,No,Thur,Lunch,2 133 | 20.27,2.83,Female,No,Thur,Lunch,2 134 | 11.17,1.5,Female,No,Thur,Lunch,2 135 | 12.26,2.0,Female,No,Thur,Lunch,2 136 | 18.26,3.25,Female,No,Thur,Lunch,2 137 | 8.51,1.25,Female,No,Thur,Lunch,2 138 | 10.33,2.0,Female,No,Thur,Lunch,2 139 | 14.15,2.0,Female,No,Thur,Lunch,2 140 | 16.0,2.0,Male,Yes,Thur,Lunch,2 141 | 13.16,2.75,Female,No,Thur,Lunch,2 142 | 17.47,3.5,Female,No,Thur,Lunch,2 143 | 34.3,6.7,Male,No,Thur,Lunch,6 144 | 41.19,5.0,Male,No,Thur,Lunch,5 145 | 27.05,5.0,Female,No,Thur,Lunch,6 146 | 16.43,2.3,Female,No,Thur,Lunch,2 147 | 8.35,1.5,Female,No,Thur,Lunch,2 148 | 18.64,1.36,Female,No,Thur,Lunch,3 149 | 11.87,1.63,Female,No,Thur,Lunch,2 150 | 9.78,1.73,Male,No,Thur,Lunch,2 151 | 7.51,2.0,Male,No,Thur,Lunch,2 152 | 14.07,2.5,Male,No,Sun,Dinner,2 153 | 13.13,2.0,Male,No,Sun,Dinner,2 154 | 17.26,2.74,Male,No,Sun,Dinner,3 155 | 24.55,2.0,Male,No,Sun,Dinner,4 156 | 19.77,2.0,Male,No,Sun,Dinner,4 157 | 29.85,5.14,Female,No,Sun,Dinner,5 158 | 48.17,5.0,Male,No,Sun,Dinner,6 159 | 25.0,3.75,Female,No,Sun,Dinner,4 160 | 13.39,2.61,Female,No,Sun,Dinner,2 161 | 16.49,2.0,Male,No,Sun,Dinner,4 162 | 21.5,3.5,Male,No,Sun,Dinner,4 163 | 12.66,2.5,Male,No,Sun,Dinner,2 164 | 16.21,2.0,Female,No,Sun,Dinner,3 165 | 13.81,2.0,Male,No,Sun,Dinner,2 166 | 17.51,3.0,Female,Yes,Sun,Dinner,2 167 | 24.52,3.48,Male,No,Sun,Dinner,3 168 | 20.76,2.24,Male,No,Sun,Dinner,2 169 | 31.71,4.5,Male,No,Sun,Dinner,4 170 | 10.59,1.61,Female,Yes,Sat,Dinner,2 171 | 10.63,2.0,Female,Yes,Sat,Dinner,2 172 | 50.81,10.0,Male,Yes,Sat,Dinner,3 173 | 15.81,3.16,Male,Yes,Sat,Dinner,2 174 | 7.25,5.15,Male,Yes,Sun,Dinner,2 175 | 31.85,3.18,Male,Yes,Sun,Dinner,2 176 | 16.82,4.0,Male,Yes,Sun,Dinner,2 177 | 32.9,3.11,Male,Yes,Sun,Dinner,2 178 | 17.89,2.0,Male,Yes,Sun,Dinner,2 179 | 14.48,2.0,Male,Yes,Sun,Dinner,2 180 | 9.6,4.0,Female,Yes,Sun,Dinner,2 181 | 34.63,3.55,Male,Yes,Sun,Dinner,2 182 | 34.65,3.68,Male,Yes,Sun,Dinner,4 183 | 23.33,5.65,Male,Yes,Sun,Dinner,2 184 | 45.35,3.5,Male,Yes,Sun,Dinner,3 185 | 23.17,6.5,Male,Yes,Sun,Dinner,4 186 | 40.55,3.0,Male,Yes,Sun,Dinner,2 187 | 20.69,5.0,Male,No,Sun,Dinner,5 188 | 20.9,3.5,Female,Yes,Sun,Dinner,3 189 | 30.46,2.0,Male,Yes,Sun,Dinner,5 190 | 18.15,3.5,Female,Yes,Sun,Dinner,3 191 | 23.1,4.0,Male,Yes,Sun,Dinner,3 192 | 15.69,1.5,Male,Yes,Sun,Dinner,2 193 | 19.81,4.19,Female,Yes,Thur,Lunch,2 194 | 28.44,2.56,Male,Yes,Thur,Lunch,2 195 | 15.48,2.02,Male,Yes,Thur,Lunch,2 196 | 16.58,4.0,Male,Yes,Thur,Lunch,2 197 | 7.56,1.44,Male,No,Thur,Lunch,2 198 | 10.34,2.0,Male,Yes,Thur,Lunch,2 199 | 43.11,5.0,Female,Yes,Thur,Lunch,4 200 | 13.0,2.0,Female,Yes,Thur,Lunch,2 201 | 13.51,2.0,Male,Yes,Thur,Lunch,2 202 | 18.71,4.0,Male,Yes,Thur,Lunch,3 203 | 12.74,2.01,Female,Yes,Thur,Lunch,2 204 | 13.0,2.0,Female,Yes,Thur,Lunch,2 205 | 16.4,2.5,Female,Yes,Thur,Lunch,2 206 | 20.53,4.0,Male,Yes,Thur,Lunch,4 207 | 16.47,3.23,Female,Yes,Thur,Lunch,3 208 | 26.59,3.41,Male,Yes,Sat,Dinner,3 209 | 38.73,3.0,Male,Yes,Sat,Dinner,4 210 | 24.27,2.03,Male,Yes,Sat,Dinner,2 211 | 12.76,2.23,Female,Yes,Sat,Dinner,2 212 | 30.06,2.0,Male,Yes,Sat,Dinner,3 213 | 25.89,5.16,Male,Yes,Sat,Dinner,4 214 | 48.33,9.0,Male,No,Sat,Dinner,4 215 | 13.27,2.5,Female,Yes,Sat,Dinner,2 216 | 28.17,6.5,Female,Yes,Sat,Dinner,3 217 | 12.9,1.1,Female,Yes,Sat,Dinner,2 218 | 28.15,3.0,Male,Yes,Sat,Dinner,5 219 | 11.59,1.5,Male,Yes,Sat,Dinner,2 220 | 7.74,1.44,Male,Yes,Sat,Dinner,2 221 | 30.14,3.09,Female,Yes,Sat,Dinner,4 222 | 12.16,2.2,Male,Yes,Fri,Lunch,2 223 | 13.42,3.48,Female,Yes,Fri,Lunch,2 224 | 8.58,1.92,Male,Yes,Fri,Lunch,1 225 | 15.98,3.0,Female,No,Fri,Lunch,3 226 | 13.42,1.58,Male,Yes,Fri,Lunch,2 227 | 16.27,2.5,Female,Yes,Fri,Lunch,2 228 | 10.09,2.0,Female,Yes,Fri,Lunch,2 229 | 20.45,3.0,Male,No,Sat,Dinner,4 230 | 13.28,2.72,Male,No,Sat,Dinner,2 231 | 22.12,2.88,Female,Yes,Sat,Dinner,2 232 | 24.01,2.0,Male,Yes,Sat,Dinner,4 233 | 15.69,3.0,Male,Yes,Sat,Dinner,3 234 | 11.61,3.39,Male,No,Sat,Dinner,2 235 | 10.77,1.47,Male,No,Sat,Dinner,2 236 | 15.53,3.0,Male,Yes,Sat,Dinner,2 237 | 10.07,1.25,Male,No,Sat,Dinner,2 238 | 12.6,1.0,Male,Yes,Sat,Dinner,2 239 | 32.83,1.17,Male,Yes,Sat,Dinner,2 240 | 35.83,4.67,Female,No,Sat,Dinner,3 241 | 29.03,5.92,Male,No,Sat,Dinner,3 242 | 27.18,2.0,Female,Yes,Sat,Dinner,2 243 | 22.67,2.0,Male,Yes,Sat,Dinner,2 244 | 17.82,1.75,Male,No,Sat,Dinner,2 245 | 18.78,3.0,Female,No,Thur,Dinner,2 246 | -------------------------------------------------------------------------------- /Python_for_R_Users.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/python-for-r-users-workshop/d262d1fb877a63ea094b50d73d8d26cb788c45d1/Python_for_R_Users.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python for R Users Workshop 2 | 3 | [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/MangoTheCat/python-for-r-users-workshop/master) 4 | 5 | To follow along with the workshop please install the Anaconda distribution in the **Python 3.6 version** from . 6 | 7 | You will also need to download all of the data files, in the data directory, to have available during the workshop. 8 | 9 | For the final chapter, we mention different packages in Python for you to look into, some of these are not included in Anaconda. To install those, use `pip install `. 10 | 11 | To explore the material interactively without installing anything, click on the binder badge above. 12 | -------------------------------------------------------------------------------- /binder/environment.yml: -------------------------------------------------------------------------------- 1 | name: py4r 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - python 6 | - numpy 7 | - pandas 8 | - seaborn 9 | - statsmodels 10 | - bokeh 11 | - pip: 12 | - sklearn 13 | - yellowbrick 14 | -------------------------------------------------------------------------------- /img/fig/CellModeCommand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/python-for-r-users-workshop/d262d1fb877a63ea094b50d73d8d26cb788c45d1/img/fig/CellModeCommand.png -------------------------------------------------------------------------------- /img/fig/CellModeEdit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/python-for-r-users-workshop/d262d1fb877a63ea094b50d73d8d26cb788c45d1/img/fig/CellModeEdit.png -------------------------------------------------------------------------------- /img/fig/HelpFile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/python-for-r-users-workshop/d262d1fb877a63ea094b50d73d8d26cb788c45d1/img/fig/HelpFile.png -------------------------------------------------------------------------------- /img/fig/jupyter1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/python-for-r-users-workshop/d262d1fb877a63ea094b50d73d8d26cb788c45d1/img/fig/jupyter1.png -------------------------------------------------------------------------------- /img/fig/jupyter2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/python-for-r-users-workshop/d262d1fb877a63ea094b50d73d8d26cb788c45d1/img/fig/jupyter2.png -------------------------------------------------------------------------------- /img/fig/jupyter3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/python-for-r-users-workshop/d262d1fb877a63ea094b50d73d8d26cb788c45d1/img/fig/jupyter3.png -------------------------------------------------------------------------------- /img/fig/jupyter4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MangoTheCat/python-for-r-users-workshop/d262d1fb877a63ea094b50d73d8d26cb788c45d1/img/fig/jupyter4.png --------------------------------------------------------------------------------