├── .gitignore ├── LICENSE ├── README.md ├── _config.yml ├── _static └── custom.css ├── _toc.yml ├── contents ├── calculus │ ├── img │ │ ├── opti1.png │ │ └── opti2.png │ ├── ode_integration.ipynb │ └── optimization.ipynb ├── hpc │ ├── cython.ipynb │ ├── img │ │ ├── cython1.png │ │ ├── cython2.png │ │ ├── ipyparallel1.png │ │ ├── ipyparallel2.png │ │ ├── profiling1.png │ │ └── snakeviz.png │ ├── intro.ipynb │ ├── numba.ipynb │ ├── parallel.ipynb │ ├── profiling.ipynb │ ├── python.ipynb │ ├── src │ │ └── fractal.py │ └── vectorization.ipynb ├── jupyter │ ├── beyond_python.ipynb │ ├── img │ │ ├── jupyter1.png │ │ ├── jupyter2.png │ │ ├── jupyter_interface1.png │ │ ├── jupyter_interface2.png │ │ ├── notebook_components.png │ │ └── valdivia.png │ ├── intro.md │ ├── ipython_display.ipynb │ ├── script_interesante.py │ └── tutorial.ipynb ├── linalg │ ├── data │ │ └── helados.csv │ ├── eigvals.ipynb │ ├── intro.ipynb │ └── linalg1.ipynb ├── numpy │ ├── img │ │ ├── broadcast.png │ │ ├── ndarray.png │ │ ├── slicing.png │ │ └── transpose.jpg │ ├── numpy1.ipynb │ └── numpy2.ipynb ├── pandas │ ├── groupby.svg │ ├── part1.ipynb │ ├── part2.ipynb │ ├── part3.ipynb │ └── part4.ipynb ├── preliminaries │ ├── env_management.ipynb │ ├── git.ipynb │ ├── img │ │ ├── debug1.png │ │ ├── debug2.png │ │ ├── git-workflow.png │ │ ├── git-workflow2.svg │ │ └── git-workflow3.svg │ ├── intro.ipynb │ └── python3.ipynb ├── sklearn │ ├── data │ │ └── cancer.csv │ ├── img │ │ ├── conf-matrix.png │ │ ├── intro-ml1.png │ │ ├── intro-ml2.png │ │ ├── intro-ml4.png │ │ └── kmeans.png │ ├── intro.ipynb │ ├── kmeans.ipynb │ ├── metrics.ipynb │ ├── naivebayes.ipynb │ └── pca.ipynb ├── statistics │ ├── bootstrap.ipynb │ ├── data │ │ ├── botany.npy │ │ ├── energy.npy │ │ ├── gapminder.csv │ │ └── mistery_data.pkl │ ├── descriptive.ipynb │ ├── distributions.ipynb │ ├── hypothesis.ipynb │ ├── img │ │ ├── stats1.png │ │ ├── stats2.png │ │ ├── stats3.png │ │ ├── stats4.png │ │ ├── stats5.png │ │ ├── stats7.png │ │ └── stats8.png │ ├── intro.ipynb │ ├── model_fitting.ipynb │ └── more_stats.ipynb └── visualization │ ├── data │ ├── covid19_extract.csv │ ├── rrl.dat │ └── valdivia.png │ ├── goodvisualizations.ipynb │ ├── img │ └── vranking.svg │ ├── ipywidgets.ipynb │ ├── matplotlib1.ipynb │ ├── matplotlib2.ipynb │ └── seaborn.ipynb └── logo.png /.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | .vscode 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | MANIFEST 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | 53 | # Translations 54 | *.mo 55 | *.pot 56 | 57 | # Django stuff: 58 | *.log 59 | local_settings.py 60 | db.sqlite3 61 | 62 | # Flask stuff: 63 | instance/ 64 | .webassets-cache 65 | 66 | # Scrapy stuff: 67 | .scrapy 68 | 69 | # Sphinx documentation 70 | docs/_build/ 71 | 72 | # PyBuilder 73 | target/ 74 | 75 | # Jupyter Notebook 76 | .ipynb_checkpoints 77 | 78 | # pyenv 79 | .python-version 80 | 81 | # celery beat schedule file 82 | celerybeat-schedule 83 | 84 | # SageMath parsed files 85 | *.sage.py 86 | 87 | # Environments 88 | .env 89 | .venv 90 | env/ 91 | venv/ 92 | ENV/ 93 | env.bak/ 94 | venv.bak/ 95 | 96 | # Spyder project settings 97 | .spyderproject 98 | .spyproject 99 | 100 | # Rope project settings 101 | .ropeproject 102 | 103 | # mkdocs documentation 104 | /site 105 | 106 | # mypy 107 | .mypy_cache/ 108 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Computación Científica con Python 2 | 3 | Un libro virtual diseñado como recurso de aprendizaje para los estudiantes del curso de Computación Científica con Python (INFO147) de la carrera de Ingeniería Civil en Informática de la Universidad Austral de Chile. El libro fue escrito por Pablo Huijse y está en continuo desarrollo. 4 | 5 | El código fuente del libro está en https://github.com/phuijse/PythonBook. El libro virtual está publicado en : https://phuijse.github.io/PythonBook/. El libro fue desarrollado utilizando [`jupyter-book`](https://jupyterbook.org/intro.html). Si encuentras errores por favor deja un *issue* en el repositorio que contiene el libro. 6 | 7 | **Contenidos** 8 | 9 | - Exploración interactiva de datos con `Ipython` y `Jupyter` 10 | - Manejo de datos con `pandas` 11 | - Visualización de datos con `matplotlib` 12 | - Álgebra lineal con `numpy` y `scipy` 13 | - Optimización numérica con `scipy` 14 | - Estadística descriptiva e inferencial con `scipy` 15 | - Introducción a Machine Learning con `scikit-learn` 16 | - Optimización de cómputo con `cython` 17 | 18 | **Referencias** 19 | 20 | 1. [Jake VanderPlas, "Python Data Science Handbook", *O'Reilly*, 2016](https://jakevdp.github.io/PythonDataScienceHandbook/) 21 | 1. [Cyrille Rossant, "IPython Cookbook", 2ed, *Packt*, 2018](https://ipython-books.github.io/) 22 | 1. [Robert Johansson, "Numerical Python", 2ed, *Apress*, 2018](https://link.springer.com/book/10.1007%2F978-1-4842-4246-9) 23 | 1. [K. Reith y T. Schulesser, "The Hitchhiker's guide to Python", *O'Reilly*, 2016](https://docs.python-guide.org) 24 | 1. [J. VanderPlas, "Whirlwind Tour of Python", *O'Reilly*, 2016](https://github.com/jakevdp/WhirlwindTourOfPython) 25 | 1. [C.H. Swaroop, "A Byte of Python", 2015](https://python.swaroopch.com) 26 | 1. [Brett Slakin, "Effective Python", *Addison-Wesley*, 2015](https://effectivepython.com/) 27 | 1. [Greg Wilson, et al., "Best Practices for Scientific Computing", PLOS Biology, 2014](https://journals.plos.org/plosbiology/article?id=10.1371/journal.pbio.1001745) 28 | 1. [Adam Rule, et al. "Ten simple rules for writing and sharing computational analyses in Jupyter Notebook", PLOS Computational Biology, 2019](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1007007) 29 | 30 | **Como compilar este libro** 31 | 32 | 1. Clonar el repositorio: `git clone https://github.com/phuijse/PythonBook.git` 33 | 1. Instalar dependencias: `pip install -r requirements.txt` 34 | 1. Ejecutar los cuadernillos 35 | 1. Compilar libro: `jupyter-book build .` 36 | 1. (Opcional) Subir a github pages: `ghp-import -n -p -f _build/html/` 37 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # Book settings 2 | title: Computación Científica con Python 3 | author: Pablo Huijse Heise 4 | copyright: "2022" 5 | #logo: logo.png 6 | only_build_toc_files: true 7 | 8 | execute: 9 | execute_notebooks: off 10 | 11 | repository: 12 | url: https://github.com/phuijse/PythonBook 13 | 14 | html: 15 | home_page_in_navbar: false 16 | use_repository_button: true 17 | use_issues_button: true 18 | use_edit_page_button: false 19 | 20 | sphinx: 21 | config: 22 | language: es 23 | myst_enable_extensions: 24 | - amsmath 25 | - colon_fence 26 | - deflist 27 | - dollarmath 28 | - html_image 29 | - linkify 30 | - replacements 31 | - smartquotes 32 | - substitution 33 | - html_admonition 34 | 35 | -------------------------------------------------------------------------------- /_static/custom.css: -------------------------------------------------------------------------------- 1 | img { 2 | display:block; 3 | margin-left: auto; 4 | margin-right: auto 5 | } 6 | 7 | iframe{ 8 | display: block; 9 | margin: 0 auto; 10 | border: 0; 11 | } 12 | -------------------------------------------------------------------------------- /_toc.yml: -------------------------------------------------------------------------------- 1 | format: jb-book 2 | root: README 3 | parts: 4 | - caption: "Introducción" 5 | numbered: true 6 | chapters: 7 | - file: contents/preliminaries/intro 8 | - file: contents/preliminaries/python3 9 | - file: contents/preliminaries/env_management 10 | - file: contents/preliminaries/git 11 | - caption: "Ambiente jupyter" 12 | numbered: true 13 | chapters: 14 | - file: contents/jupyter/intro 15 | - file: contents/jupyter/tutorial 16 | - file: contents/jupyter/ipython_display 17 | - file: contents/jupyter/beyond_python 18 | - caption: "Análisis de datos con Pandas" 19 | numbered: true 20 | chapters: 21 | - file: contents/pandas/part1 22 | - file: contents/pandas/part2 23 | - file: contents/pandas/part3 24 | - file: contents/pandas/part4 25 | - caption: "Visualización de datos con Matplotlib" 26 | numbered: true 27 | chapters: 28 | - file: contents/visualization/matplotlib1 29 | - file: contents/visualization/matplotlib2 30 | - file: contents/visualization/goodvisualizations 31 | - file: contents/visualization/ipywidgets 32 | - caption: "Matemática computacional con Numpy y Scipy" 33 | numbered: true 34 | chapters: 35 | - file: contents/numpy/numpy1 36 | - file: contents/numpy/numpy2 37 | - file: contents/linalg/intro 38 | - file: contents/linalg/linalg1 39 | - file: contents/linalg/eigvals 40 | - file: contents/calculus/optimization 41 | - file: contents/calculus/ode_integration 42 | - caption: "Estadística con Scipy" 43 | numbered: true 44 | chapters: 45 | - file: contents/statistics/intro 46 | - file: contents/statistics/distributions 47 | - file: contents/statistics/descriptive 48 | - file: contents/statistics/model_fitting 49 | - file: contents/statistics/hypothesis 50 | - file: contents/statistics/bootstrap 51 | - caption: "Aprendizaje de máquinas con Scikit-Learn" 52 | numbered: true 53 | chapters: 54 | - file: contents/sklearn/intro 55 | - file: contents/sklearn/pca 56 | - file: contents/sklearn/kmeans 57 | - file: contents/sklearn/naivebayes 58 | - file: contents/sklearn/metrics 59 | - caption: "Alto rendimiento en Python" 60 | numbered: true 61 | chapters: 62 | - file: contents/hpc/intro 63 | - file: contents/hpc/profiling 64 | - file: contents/hpc/python 65 | - file: contents/hpc/vectorization 66 | - file: contents/hpc/cython 67 | - file: contents/hpc/parallel 68 | # - file: contents/hpc/appendix 69 | 70 | -------------------------------------------------------------------------------- /contents/calculus/img/opti1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/calculus/img/opti1.png -------------------------------------------------------------------------------- /contents/calculus/img/opti2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/calculus/img/opti2.png -------------------------------------------------------------------------------- /contents/hpc/img/cython1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/hpc/img/cython1.png -------------------------------------------------------------------------------- /contents/hpc/img/cython2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/hpc/img/cython2.png -------------------------------------------------------------------------------- /contents/hpc/img/ipyparallel1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/hpc/img/ipyparallel1.png -------------------------------------------------------------------------------- /contents/hpc/img/ipyparallel2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/hpc/img/ipyparallel2.png -------------------------------------------------------------------------------- /contents/hpc/img/profiling1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/hpc/img/profiling1.png -------------------------------------------------------------------------------- /contents/hpc/img/snakeviz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/hpc/img/snakeviz.png -------------------------------------------------------------------------------- /contents/hpc/intro.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Python y Rendimiento \n", 8 | "\n", 9 | "Python es un lenguaje interpretado de alto nivel que es muy conveniente para prototipar y hacer análisis \n", 10 | "exploratorio. Sin embargo, esta conveniencia tiene un costo: \n", 11 | "\n", 12 | "> Python tiene un menor **rendimiento** a igual **complejidad** en comparación a lenguajes compilados de bajo nivel\n", 13 | "\n", 14 | "Podemos ser más específicos y hablar de **eficiencia** de diversas índoles:\n", 15 | "\n", 16 | "- Eficiencia temporal: Tiempo para completar una tarea (tiempo en la CPU)\n", 17 | "- Eficiencia espacial: Utilización de espacio (memoria RAM, disco)\n", 18 | "\n", 19 | "Ambos son factores críticos en algunas aplicaciones, por ejemplo aplicaciones con muchos datos o mucho cómputo.\n", 20 | "\n", 21 | "Existe entonces una necesidad por **mejorar el rendimiento de nuestro código**. En esta serie de lecciones veremos distintas formas de **optimizar** código escrito en Python." 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "## ¿Qué es la optimización de códigos/software?\n", 29 | "\n", 30 | "**Optimización** se refiere a modificar una rutina computacional para mejorar su eficiencia, es decir reducir sus tiempos de ejecución y/o consumo de recursos. El aspecto que se intenta modificar es aquel que limita nuestro programa. Un programa puede estar:\n", 31 | "\n", 32 | "- limitado en CPU: *compute-bound*\n", 33 | "- limitado en memoria: *memory-bound*\n", 34 | "- limitado en ancho de banda: *bandwidth-bound*\n", 35 | "- limitado en entrada/salida: *I/O bound*\n", 36 | "\n", 37 | "En el ámbito de la computación científica lo más común es enfrentar programas que están **límitados en CPU**, es decir:\n", 38 | "\n", 39 | "- programas que utilizan la mayor parte de su tiempo haciendo cálculos\n", 40 | "- programas que mejoran su rendimiento con la velocidad del CPU\n", 41 | "\n", 42 | ":::{note}\n", 43 | "\n", 44 | "En ciertos casos podemos disminuir el tiempo de ejecución de una rutina incrementando el uso de memoria. Esto podría convertir un programa que es limitado en CPU a uno que es limitado en memoria. \n", 45 | "\n", 46 | "::: " 47 | ] 48 | }, 49 | { 50 | "cell_type": "markdown", 51 | "metadata": {}, 52 | "source": [ 53 | "## Antes de optimizar\n", 54 | "\n", 55 | "Considera las siguientes preguntas antes de comenzar el (a veces arduo) proceso de optimizar tus códigos.\n", 56 | "\n", 57 | "**¿Cuándo optimizar?**\n", 58 | "\n", 59 | "`Si:` \n", 60 | "\n", 61 | " tu rutina está incompleta o no entrega el resultado esperado\n", 62 | " \n", 63 | "`Entonces:`\n", 64 | "\n", 65 | " No es momento de optimizar \n", 66 | "\n", 67 | "Para casi cualquier rutina que escribamos, deberíamos considerar la secuencia:\n", 68 | "\n", 69 | "1. que (la rutina) corra\n", 70 | "1. que (la rutina) retorne el resultado correcto\n", 71 | "1. (opcionalmente) que (la rutina) tenga un buen rendimiento\n", 72 | "\n", 73 | ":::{important}\n", 74 | "\n", 75 | "La optimización está asociada al último punto y se lleva a cabo luego de cumplir los dos primeros\n", 76 | "\n", 77 | ":::\n", 78 | "\n", 79 | "En la práctica hay que considerar que optimizar podría:\n", 80 | "\n", 81 | "- Hacer el código más complicado y menos legible \n", 82 | "- Introducir bugs\n", 83 | "- Tomar tiempo y bastante dedicación\n", 84 | "\n", 85 | "Por lo tanto debemos evitar optimizar de forma prematura\n", 86 | "\n", 87 | "```{epigraph}\n", 88 | "La optimización prematura es la raíz de todos los males \n", 89 | "\n", 90 | "-- [Donald Knuth](http://wiki.c2.com/?PrematureOptimization)\n", 91 | "```\n", 92 | "\n", 93 | "**¿Por qué optimizar?**\n", 94 | "\n", 95 | "En la secuencia mostrada anteriormente, podemos notar que el último punto no es esencial como lo son los dos primeros. Optimizar solo es necesario si nuestro código:\n", 96 | "\n", 97 | "- no entrega el resultado correcto en el tiempo requerido\n", 98 | "- requiere más memoria que la disponible en el hardware donde va a correr\n", 99 | "\n", 100 | "**¿Dónde optimizar?**\n", 101 | "\n", 102 | "Se debe evitar gastar tiempo optimizando rutinas que influyan poco en el rendimiento total del programa. La optimización debería concentrarse en las secciones más lentas y/o costosas: **cuellos de botella**\n", 103 | "\n", 104 | "Previo a optimizar debemos hacer un **perfilado** (***profiling***) de nuestro código para encontrar las secciones críticas. Veremos como hacer perfilado con ipython a continuación." 105 | ] 106 | }, 107 | { 108 | "cell_type": "code", 109 | "execution_count": null, 110 | "metadata": {}, 111 | "outputs": [], 112 | "source": [] 113 | } 114 | ], 115 | "metadata": { 116 | "kernelspec": { 117 | "display_name": "Python 3 (ipykernel)", 118 | "language": "python", 119 | "name": "python3" 120 | }, 121 | "language_info": { 122 | "codemirror_mode": { 123 | "name": "ipython", 124 | "version": 3 125 | }, 126 | "file_extension": ".py", 127 | "mimetype": "text/x-python", 128 | "name": "python", 129 | "nbconvert_exporter": "python", 130 | "pygments_lexer": "ipython3", 131 | "version": "3.9.16" 132 | }, 133 | "toc": { 134 | "base_numbering": 1, 135 | "nav_menu": {}, 136 | "number_sections": true, 137 | "sideBar": true, 138 | "skip_h1_title": false, 139 | "title_cell": "Table of Contents", 140 | "title_sidebar": "Contents", 141 | "toc_cell": false, 142 | "toc_position": { 143 | "height": "calc(100% - 180px)", 144 | "left": "10px", 145 | "top": "150px", 146 | "width": "294.4px" 147 | }, 148 | "toc_section_display": true, 149 | "toc_window_display": true 150 | } 151 | }, 152 | "nbformat": 4, 153 | "nbformat_minor": 2 154 | } 155 | -------------------------------------------------------------------------------- /contents/hpc/numba.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Compilación Just-in-time (JIT) con [Numba](http://numba.pydata.org/)\n", 8 | "\n", 9 | "Podemos acelerar cálculos científicos de forma simple y semi-automática usando el compilador **Numba**. Este compilador no requiere cambiar el interprete de Python y tampoco es necesario aprender otro lenguaje\n", 10 | "\n", 11 | "A través de decoradores podemos pedirle a Numba que compile una función \"al vuelo\" (just-in-time). Internamente Numba traduce las funciones de Python a lenguaje de máquina usando el compilador [LLVM](https://llvm.org/)\n", 12 | "\n", 13 | "Para \"ciertas funciones\" el resultado será una versión compilada notoriamente más rápida en su ejecución que la original. Numba está diseñado para hacer más eficiente rutinas *compute-bound* que hagan **cálculos numéricos**. Tiene soporte para compilar funciones de Numpy y para paralelizar automaticamente ciclos `for`" 14 | ] 15 | }, 16 | { 17 | "cell_type": "markdown", 18 | "metadata": {}, 19 | "source": [ 20 | "Instalación utilizando conda:\n", 21 | "\n", 22 | " conda install numba\n", 23 | "\n", 24 | "A continuación veremos los decoradores fundamentales de *Numba* y algunos ejemplos\n", 25 | "\n", 26 | "Volvamos al código vectorizado para calcular la distancia euclidiana \"todos con todos\"" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 1, 32 | "metadata": { 33 | "ExecuteTime": { 34 | "end_time": "2020-08-19T02:26:39.807853Z", 35 | "start_time": "2020-08-19T02:26:39.679742Z" 36 | } 37 | }, 38 | "outputs": [ 39 | { 40 | "name": "stdout", 41 | "output_type": "stream", 42 | "text": [ 43 | "68.7 ms ± 5.64 ms per loop (mean ± std. dev. of 3 runs, 1 loop each)\n" 44 | ] 45 | } 46 | ], 47 | "source": [ 48 | "import numpy as np\n", 49 | "\n", 50 | "data = np.random.randn(1000, 2)\n", 51 | "\n", 52 | "def distancia_pares_numpy(data):\n", 53 | " return np.sqrt(np.sum((data.reshape(-1, 1, 2) - data.reshape(1, -1, 2))**2, axis=-1))\n", 54 | "\n", 55 | "time_numpy = %timeit -r3 -n1 -o distancia_pares_numpy(data)" 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "metadata": {}, 61 | "source": [ 62 | "Se utiliza numba para acelerar el cálculo de esta función:\n", 63 | "\n", 64 | "- Importamos el decorador `jit` y lo aplicamos a la función anterior\n", 65 | "- Usaremos el modo `nopython` o \"modo rápido\", esto indica al compilador que la función no usará el interprete de Python\n", 66 | "- La primera llamada a la función es lenta, pues acciona el compilador\n", 67 | "- La siguientes llamadas son más rápidas que la función de NumPy" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 2, 73 | "metadata": { 74 | "ExecuteTime": { 75 | "end_time": "2020-08-19T02:26:43.976239Z", 76 | "start_time": "2020-08-19T02:26:41.712506Z" 77 | } 78 | }, 79 | "outputs": [ 80 | { 81 | "name": "stdout", 82 | "output_type": "stream", 83 | "text": [ 84 | "20.1 ms ± 390 µs per loop (mean ± std. dev. of 3 runs, 1 loop each)\n" 85 | ] 86 | } 87 | ], 88 | "source": [ 89 | "from numba import jit\n", 90 | "\n", 91 | "@jit(nopython=True)\n", 92 | "def distancia_pares_numba(data):\n", 93 | " return np.sqrt(np.sum((data.reshape(-1, 1, 2) - data.reshape(1, -1, 2))**2, axis=-1))\n", 94 | "\n", 95 | "distancia_pares_numba(data) # Aquí se ejecuta la compilación\n", 96 | "\n", 97 | "time_numba = %timeit -r3 -n1 -o distancia_pares_numba(data)" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": 3, 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "3.4113508284087355" 109 | ] 110 | }, 111 | "execution_count": 3, 112 | "metadata": {}, 113 | "output_type": "execute_result" 114 | } 115 | ], 116 | "source": [ 117 | "time_numpy.average/time_numba.average" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 4, 123 | "metadata": {}, 124 | "outputs": [ 125 | { 126 | "data": { 127 | "text/plain": [ 128 | "True" 129 | ] 130 | }, 131 | "execution_count": 4, 132 | "metadata": {}, 133 | "output_type": "execute_result" 134 | } 135 | ], 136 | "source": [ 137 | "np.allclose(distancia_pares_numpy(data), distancia_pares_numba(data))" 138 | ] 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "metadata": {}, 143 | "source": [ 144 | "- Existe un alias para `jit(nopython=True)` llamado `njit`\n", 145 | "- Otros argumentos interesantes para decorar son: `parallel=True` y `fastmath=True` " 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": null, 151 | "metadata": {}, 152 | "outputs": [], 153 | "source": [] 154 | } 155 | ], 156 | "metadata": { 157 | "kernelspec": { 158 | "display_name": "Python 3 (ipykernel)", 159 | "language": "python", 160 | "name": "python3" 161 | }, 162 | "language_info": { 163 | "codemirror_mode": { 164 | "name": "ipython", 165 | "version": 3 166 | }, 167 | "file_extension": ".py", 168 | "mimetype": "text/x-python", 169 | "name": "python", 170 | "nbconvert_exporter": "python", 171 | "pygments_lexer": "ipython3", 172 | "version": "3.9.16" 173 | }, 174 | "toc": { 175 | "base_numbering": 1, 176 | "nav_menu": {}, 177 | "number_sections": true, 178 | "sideBar": true, 179 | "skip_h1_title": false, 180 | "title_cell": "Table of Contents", 181 | "title_sidebar": "Contents", 182 | "toc_cell": false, 183 | "toc_position": { 184 | "height": "calc(100% - 180px)", 185 | "left": "10px", 186 | "top": "150px", 187 | "width": "254px" 188 | }, 189 | "toc_section_display": true, 190 | "toc_window_display": true 191 | } 192 | }, 193 | "nbformat": 4, 194 | "nbformat_minor": 2 195 | } 196 | -------------------------------------------------------------------------------- /contents/hpc/python.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Optimizando código Python\n", 8 | "\n", 9 | "Como ya hemos mencionado **Python** es un lenguaje versátil pero poco eficiente en comparación a lenguajes de bajo nivel (C o Fortran)\n", 10 | "\n", 11 | "Recordemos que **Python** es un lenguaje **interpretado**. Consideremos la operación\n", 12 | "\n", 13 | "```python\n", 14 | " z = x + y\n", 15 | "```\n", 16 | "\n", 17 | "Esta operación sencilla requiere de \n", 18 | "\n", 19 | "- **inferir el tipo** de $x$ e $y$ antes de sumarlos\n", 20 | "- **escoger la función \"suma\" apropiada para el tipo de los argumentos** \n", 21 | "- **retornar el tipo correcto** de z\n", 22 | "\n", 23 | "El costo de las operaciones **destacadas** se llama **overhead**. El *overhead* es el **costo extra** de Python versus los lenguajes compilados\n", 24 | "\n", 25 | "Existen varias maneras de reducir *overhead* y mejorar la eficiencia de un código escrito en Python. En lo que sige revisaremos las siguientes:\n", 26 | "\n", 27 | "- **Conocer el lenguaje**: Usar la sintaxis y estructuras de Python adecuadamente \n", 28 | "- **Vectorización:** Cómputo basado en arreglos con `NumPy` siempre en problemas que lo permitan\n", 29 | "- **Conectar con lenguajes de bajo nivel:** Utilizar `Cython` para crear interfaces de código C eficiente para Python\n", 30 | "\n", 31 | "Antes de empezar revisarlas en detalle se presenta una métrica muy utilizada para comparar algoritmos de acuerdo a su tiempo de ejecución. El ***[speedup](https://en.wikipedia.org/wiki/Speedup)*** es un número que mide el desempeño relativo de dos algoritmos, sistemas o rutinas, definido como\n", 32 | "\n", 33 | "$$\n", 34 | "S_{tiempo} = \\frac{T_{referencia}}{T_{propuesto}}\n", 35 | "$$\n", 36 | "\n", 37 | "donde $T_{propuesto}$ y $T_{referencia}$ son los tiempos de cómputo de nuestra rutina propuesta (optimizada) y de la rutina de referencia (original), respectivamente\n", 38 | "\n", 39 | ":::{note}\n", 40 | "\n", 41 | "Este speedup temporal indica cuantas veces más rápido es nuestra rutina propuesta con respecto a la referencia\n", 42 | "\n", 43 | ":::" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": {}, 49 | "source": [ 50 | "## Conocer el lenguaje para ganar eficiencia\n", 51 | "\n", 52 | "**Python** tiene una curva de aprendizaje suave en comparación a lenguajes de más bajo nivel, es decir que sabiendo muy poco de **Python** ya somos capaces de escribir toda clase de rutinas\n", 53 | "\n", 54 | "Esto tiene un efecto secundario negativo en algunas personas y especialmente en aquellos que ya saben otros lenguajes \n", 55 | "\n", 56 | ":::{error}\n", 57 | "\n", 58 | "Usar Python como si fuera C (u otro lenguaje)\n", 59 | "\n", 60 | ":::\n", 61 | "\n", 62 | "Python ofrece una gran cantidad de [funciones](https://docs.python.org/3/library/functions.html) y [módulos en su librería estándar](https://docs.python.org/3/library/index.html) que son sumamente eficientes\n", 63 | "\n", 64 | ":::{hint}\n", 65 | "\n", 66 | "Usar la sintáxis y las [estructuras de datos](https://docs.python.org/3/tutorial/datastructures.html) de Python adecuadamente es el primer paso para escribir código eficiente. Busque en la documentación de Python las estructuras de datos más apropiadas para cada problema\n", 67 | "\n", 68 | ":::\n", 69 | "\n", 70 | "Si necesita repasar sobre algoritmos se recomienda el siguiente material\n", 71 | "\n", 72 | "- Bibliografía complementaria del curso: [Effective Python](https://effectivepython.com/)\n", 73 | "- [Tratado de algoritmos y estructuras de datos en Python](https://runestone.academy/runestone/books/published/pythonds/index.html)\n", 74 | "- [Consejos de velocidad en la Python wiki](https://wiki.python.org/moin/PythonSpeed)\n", 75 | "- [Complejidad temporal de distintas estructuras de Python](https://wiki.python.org/moin/TimeComplexity)\n", 76 | "\n", 77 | "A continuación veremos algunos consejos generales enfocados a Python" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "## Evita usar `for` siempre que se pueda en favor de las funciones nativas\n", 85 | "\n", 86 | "Muchas veces podemos evitar usar `for` con la estructura de datos o función adecuada.\n", 87 | "\n", 88 | "Para ejemplificar digamos que queremos sumar los valores absolutos de los elementos de una lista:" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 1, 94 | "metadata": { 95 | "ExecuteTime": { 96 | "end_time": "2020-08-19T02:20:47.807885Z", 97 | "start_time": "2020-08-19T02:20:47.168600Z" 98 | } 99 | }, 100 | "outputs": [ 101 | { 102 | "name": "stdout", 103 | "output_type": "stream", 104 | "text": [ 105 | "14.5 ms ± 943 µs per loop (mean ± std. dev. of 5 runs, 3 loops each)\n" 106 | ] 107 | }, 108 | { 109 | "data": { 110 | "text/plain": [ 111 | "4999950000" 112 | ] 113 | }, 114 | "execution_count": 1, 115 | "metadata": {}, 116 | "output_type": "execute_result" 117 | } 118 | ], 119 | "source": [ 120 | "x = [x for x in range(100000)]\n", 121 | "\n", 122 | "# Suma estilo C \n", 123 | "def suma_abs(data):\n", 124 | " resultado = 0\n", 125 | " for i in range(len(data)):\n", 126 | " if data[i] > 0:\n", 127 | " resultado += data[i]\n", 128 | " else:\n", 129 | " resultado -= data[i]\n", 130 | " return resultado\n", 131 | "\n", 132 | "reference = %timeit -r5 -n3 -o suma_abs(x)\n", 133 | "suma_abs(x)" 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": {}, 139 | "source": [ 140 | "**Mejora 1:** No es necesario usar un índice, podemos iterar directamente en los elementos" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 2, 146 | "metadata": {}, 147 | "outputs": [ 148 | { 149 | "name": "stdout", 150 | "output_type": "stream", 151 | "text": [ 152 | "8.54 ms ± 749 µs per loop (mean ± std. dev. of 5 runs, 3 loops each)\n" 153 | ] 154 | }, 155 | { 156 | "data": { 157 | "text/plain": [ 158 | "4999950000" 159 | ] 160 | }, 161 | "execution_count": 2, 162 | "metadata": {}, 163 | "output_type": "execute_result" 164 | } 165 | ], 166 | "source": [ 167 | "def suma_abs(data):\n", 168 | " resultado = 0\n", 169 | " for element in data:\n", 170 | " if element > 0:\n", 171 | " resultado += element\n", 172 | " else:\n", 173 | " resultado -= element\n", 174 | " return resultado\n", 175 | "\n", 176 | "proposal = %timeit -r5 -n3 -o suma_abs(x)\n", 177 | "suma_abs(x)" 178 | ] 179 | }, 180 | { 181 | "cell_type": "markdown", 182 | "metadata": {}, 183 | "source": [ 184 | "El speed up en este caso es:" 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": 3, 190 | "metadata": {}, 191 | "outputs": [ 192 | { 193 | "data": { 194 | "text/plain": [ 195 | "1.697372481705621" 196 | ] 197 | }, 198 | "execution_count": 3, 199 | "metadata": {}, 200 | "output_type": "execute_result" 201 | } 202 | ], 203 | "source": [ 204 | "reference.average/proposal.average" 205 | ] 206 | }, 207 | { 208 | "cell_type": "markdown", 209 | "metadata": {}, 210 | "source": [ 211 | "**Mejora 2:** Operar como una comprensión de lista y luego usar la función sum de Python" 212 | ] 213 | }, 214 | { 215 | "cell_type": "code", 216 | "execution_count": 4, 217 | "metadata": {}, 218 | "outputs": [ 219 | { 220 | "name": "stdout", 221 | "output_type": "stream", 222 | "text": [ 223 | "7.09 ms ± 629 µs per loop (mean ± std. dev. of 5 runs, 3 loops each)\n" 224 | ] 225 | }, 226 | { 227 | "data": { 228 | "text/plain": [ 229 | "(4999950000, 2.0450631952204765)" 230 | ] 231 | }, 232 | "execution_count": 4, 233 | "metadata": {}, 234 | "output_type": "execute_result" 235 | } 236 | ], 237 | "source": [ 238 | "proposal = %timeit -r5 -n3 -o sum([x if x> 0 else -x for x in x])\n", 239 | "sum([x if x> 0 else -x for x in x]), reference.average/proposal.average" 240 | ] 241 | }, 242 | { 243 | "cell_type": "markdown", 244 | "metadata": {}, 245 | "source": [ 246 | "**Mejora 3:** Usar las funciones `sum`, `map` y `abs` nativas de Python" 247 | ] 248 | }, 249 | { 250 | "cell_type": "code", 251 | "execution_count": 5, 252 | "metadata": {}, 253 | "outputs": [ 254 | { 255 | "name": "stdout", 256 | "output_type": "stream", 257 | "text": [ 258 | "4.16 ms ± 198 µs per loop (mean ± std. dev. of 5 runs, 3 loops each)\n" 259 | ] 260 | }, 261 | { 262 | "data": { 263 | "text/plain": [ 264 | "(4999950000, 3.4893538463698914)" 265 | ] 266 | }, 267 | "execution_count": 5, 268 | "metadata": {}, 269 | "output_type": "execute_result" 270 | } 271 | ], 272 | "source": [ 273 | "proposal = %timeit -r5 -n3 -o sum(list(map(abs, x)))\n", 274 | "sum(list(map(abs, x))), reference.average/proposal.average" 275 | ] 276 | }, 277 | { 278 | "cell_type": "markdown", 279 | "metadata": {}, 280 | "source": [ 281 | "## No reinventar la rueda con las estructuras de datos\n", 282 | "\n", 283 | "Verifica si la estructura que necesitas está implementada en Python antes de programarla uno mismo. Como ejemplo digamos que queremos contar la cantidad de elementos de cada tipo en una lista. Podríamos escribir un contador como:" 284 | ] 285 | }, 286 | { 287 | "cell_type": "code", 288 | "execution_count": 6, 289 | "metadata": { 290 | "ExecuteTime": { 291 | "end_time": "2020-08-19T02:20:47.936604Z", 292 | "start_time": "2020-08-19T02:20:47.812910Z" 293 | } 294 | }, 295 | "outputs": [ 296 | { 297 | "name": "stdout", 298 | "output_type": "stream", 299 | "text": [ 300 | "1.92 ms ± 215 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 301 | ] 302 | }, 303 | { 304 | "data": { 305 | "text/plain": [ 306 | "{8: 877,\n", 307 | " 5: 921,\n", 308 | " 0: 928,\n", 309 | " 3: 889,\n", 310 | " 6: 919,\n", 311 | " 7: 935,\n", 312 | " 10: 879,\n", 313 | " 9: 962,\n", 314 | " 2: 948,\n", 315 | " 4: 869,\n", 316 | " 1: 873}" 317 | ] 318 | }, 319 | "execution_count": 6, 320 | "metadata": {}, 321 | "output_type": "execute_result" 322 | } 323 | ], 324 | "source": [ 325 | "import random\n", 326 | "x2 = [random.randint(0, 10) for k in range(10000)]\n", 327 | "\n", 328 | "# Un contador de elementos\n", 329 | "def miCounter(data):\n", 330 | " count = {}\n", 331 | " for element in data:\n", 332 | " if element not in count:\n", 333 | " count[element] = 1\n", 334 | " else:\n", 335 | " count[element] +=1\n", 336 | " return count\n", 337 | "\n", 338 | "reference = %timeit -r7 -n1 -o miCounter(x2)\n", 339 | "miCounter(x2)" 340 | ] 341 | }, 342 | { 343 | "cell_type": "markdown", 344 | "metadata": {}, 345 | "source": [ 346 | "Sin embargo, la clase contador ya existe en `collections`, y es mucho más eficiente que la implementación manual anterior:" 347 | ] 348 | }, 349 | { 350 | "cell_type": "code", 351 | "execution_count": 7, 352 | "metadata": {}, 353 | "outputs": [ 354 | { 355 | "name": "stdout", 356 | "output_type": "stream", 357 | "text": [ 358 | "734 µs ± 110 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)\n" 359 | ] 360 | }, 361 | { 362 | "data": { 363 | "text/plain": [ 364 | "(Counter({9: 962,\n", 365 | " 2: 948,\n", 366 | " 7: 935,\n", 367 | " 0: 928,\n", 368 | " 5: 921,\n", 369 | " 6: 919,\n", 370 | " 3: 889,\n", 371 | " 10: 879,\n", 372 | " 8: 877,\n", 373 | " 1: 873,\n", 374 | " 4: 869}),\n", 375 | " 2.6154451754086665)" 376 | ] 377 | }, 378 | "execution_count": 7, 379 | "metadata": {}, 380 | "output_type": "execute_result" 381 | } 382 | ], 383 | "source": [ 384 | "from collections import Counter\n", 385 | "proposal = %timeit -r7 -n1 -o Counter(x2)\n", 386 | "Counter(x2), reference.average/proposal.average" 387 | ] 388 | }, 389 | { 390 | "cell_type": "markdown", 391 | "metadata": {}, 392 | "source": [ 393 | "## Tener presente el *overhead* de las funciones\n", 394 | "\n", 395 | "Python tiene un *overhead* considerable cada vez que se llama una función. Se puede ganar desempeño haciendo *inlining* de funciones:" 396 | ] 397 | }, 398 | { 399 | "cell_type": "code", 400 | "execution_count": 8, 401 | "metadata": { 402 | "ExecuteTime": { 403 | "end_time": "2020-08-19T02:20:48.717190Z", 404 | "start_time": "2020-08-19T02:20:47.938838Z" 405 | } 406 | }, 407 | "outputs": [ 408 | { 409 | "name": "stdout", 410 | "output_type": "stream", 411 | "text": [ 412 | "22.9 ms ± 1.02 ms per loop (mean ± std. dev. of 7 runs, 3 loops each)\n", 413 | "14.2 ms ± 1.35 ms per loop (mean ± std. dev. of 7 runs, 3 loops each)\n" 414 | ] 415 | }, 416 | { 417 | "data": { 418 | "text/plain": [ 419 | "(True, 1.6171941472628382)" 420 | ] 421 | }, 422 | "execution_count": 8, 423 | "metadata": {}, 424 | "output_type": "execute_result" 425 | } 426 | ], 427 | "source": [ 428 | "import numpy as np\n", 429 | "\n", 430 | "def cuadradomasuno(element):\n", 431 | " return element*element + 1\n", 432 | "\n", 433 | "reference = %timeit -r7 -n3 -o [cuadradomasuno(xi) for xi in x]\n", 434 | "#Inlining: escribo la función textualmente en lugar de evaluarla\n", 435 | "proposal = %timeit -r7 -n3 -o [xi*xi + 1 for xi in x] \n", 436 | "\n", 437 | "same_result = np.allclose([cuadradomasuno(xi) for xi in x], [xi*xi + 1 for xi in x])\n", 438 | "speed_up = reference.average/proposal.average\n", 439 | "same_result, speed_up" 440 | ] 441 | }, 442 | { 443 | "cell_type": "markdown", 444 | "metadata": {}, 445 | "source": [ 446 | "## Usar variables locales dentro de los *loops*\n", 447 | "\n", 448 | "Si estamos obligados a usar `for` podemos ganar algo de rendimiento haciendo copias locales de atributos y funciones. Por ejemplo, digamos que queremos crear una lista con todos los elementos de otra lista que cumplen la condición\n", 449 | "\n", 450 | "$$\n", 451 | "\\sin(x[i]) > 0 \n", 452 | "$$\n", 453 | "\n", 454 | "que se implementa como sigue:" 455 | ] 456 | }, 457 | { 458 | "cell_type": "code", 459 | "execution_count": 9, 460 | "metadata": { 461 | "ExecuteTime": { 462 | "end_time": "2020-08-19T02:20:49.385219Z", 463 | "start_time": "2020-08-19T02:20:48.719642Z" 464 | } 465 | }, 466 | "outputs": [ 467 | { 468 | "name": "stdout", 469 | "output_type": "stream", 470 | "text": [ 471 | "22.9 ms ± 739 µs per loop (mean ± std. dev. of 5 runs, 3 loops each)\n" 472 | ] 473 | } 474 | ], 475 | "source": [ 476 | "import math\n", 477 | "\n", 478 | "# iterando sobre la lista\n", 479 | "def sin_pos(data):\n", 480 | " resultado = []\n", 481 | " for element in data:\n", 482 | " if math.sin(element) > 0:\n", 483 | " resultado.append(element)\n", 484 | " return resultado\n", 485 | "\n", 486 | "reference = %timeit -r5 -n3 -o sin_pos(x)\n", 487 | "resultado1 = sin_pos(x)" 488 | ] 489 | }, 490 | { 491 | "cell_type": "markdown", 492 | "metadata": {}, 493 | "source": [ 494 | "Si hacemos variables locales para el método `append` y la función `sin`:" 495 | ] 496 | }, 497 | { 498 | "cell_type": "code", 499 | "execution_count": 10, 500 | "metadata": {}, 501 | "outputs": [ 502 | { 503 | "name": "stdout", 504 | "output_type": "stream", 505 | "text": [ 506 | "14.4 ms ± 1 ms per loop (mean ± std. dev. of 5 runs, 3 loops each)\n" 507 | ] 508 | }, 509 | { 510 | "data": { 511 | "text/plain": [ 512 | "(True, 1.5929659944837002)" 513 | ] 514 | }, 515 | "execution_count": 10, 516 | "metadata": {}, 517 | "output_type": "execute_result" 518 | } 519 | ], 520 | "source": [ 521 | "# Mejora: variables locales\n", 522 | "def sin_pos(data):\n", 523 | " resultado = []\n", 524 | " append = resultado.append\n", 525 | " sin = math.sin\n", 526 | " for element in data:\n", 527 | " if sin(element) > 0:\n", 528 | " append(element)\n", 529 | " return resultado\n", 530 | "\n", 531 | "proposal = %timeit -r5 -n3 -o sin_pos(x)\n", 532 | "resultado2 = sin_pos(x)\n", 533 | "\n", 534 | "same_result = np.allclose(resultado1, resultado2)\n", 535 | "speed_up = reference.average/proposal.average\n", 536 | "same_result, speed_up" 537 | ] 538 | } 539 | ], 540 | "metadata": { 541 | "kernelspec": { 542 | "display_name": "Python 3 (ipykernel)", 543 | "language": "python", 544 | "name": "python3" 545 | }, 546 | "language_info": { 547 | "codemirror_mode": { 548 | "name": "ipython", 549 | "version": 3 550 | }, 551 | "file_extension": ".py", 552 | "mimetype": "text/x-python", 553 | "name": "python", 554 | "nbconvert_exporter": "python", 555 | "pygments_lexer": "ipython3", 556 | "version": "3.9.16" 557 | }, 558 | "toc": { 559 | "base_numbering": 1, 560 | "nav_menu": {}, 561 | "number_sections": true, 562 | "sideBar": true, 563 | "skip_h1_title": false, 564 | "title_cell": "Table of Contents", 565 | "title_sidebar": "Contents", 566 | "toc_cell": false, 567 | "toc_position": { 568 | "height": "calc(100% - 180px)", 569 | "left": "10px", 570 | "top": "150px", 571 | "width": "254px" 572 | }, 573 | "toc_section_display": true, 574 | "toc_window_display": true 575 | } 576 | }, 577 | "nbformat": 4, 578 | "nbformat_minor": 2 579 | } 580 | -------------------------------------------------------------------------------- /contents/hpc/src/fractal.py: -------------------------------------------------------------------------------- 1 | def evaluate_z(zi, zr, maxiters=50, cr=-0.835, ci=-0.2321): 2 | nit = 0 3 | zi2 = zi**2 4 | zr2 = zr**2 5 | while zi2 + zr2 <= 4. and nit < maxiters: 6 | zi = 2*zr*zi + ci 7 | zr = zr2 - zi2 + cr 8 | zr2 = zr**2 9 | zi2 = zi**2 10 | nit +=1 11 | return nit 12 | 13 | def make_fractal(N, maxiters=50): 14 | image = [] 15 | for i in range(N): 16 | row = [] 17 | for j in range(2*N): 18 | zi = -1.0 + i*2/N 19 | zr = -2.0 + j*2/N 20 | row.append(evaluate_z(zi, zr, maxiters)) 21 | image.append(row) 22 | return image -------------------------------------------------------------------------------- /contents/hpc/vectorization.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Vectorización: Cómputo basado en arreglos con NumPy\n", 8 | "\n", 9 | "Consideremos el escenario en que tenemos un arreglo de datos de gran tamaño y queremos hacer una operación sobre cada elemento.\n", 10 | "\n", 11 | "**Ejemplo:** Dado $\\{x\\}_i$ queremos encontrar\n", 12 | "\n", 13 | "$$\n", 14 | "y_i = \\frac{1}{1 + e^{-x_i}}, \\quad i = 1,2,\\ldots, N\n", 15 | "$$\n", 16 | "\n", 17 | "Los cómputos como el anterior son de tipo *[Single Instruction Multiple Data](https://en.wikipedia.org/wiki/Single_instruction,_multiple_data)* (SIMD), ya que estamos haciendo una misma operación para todos los datos.\n", 18 | "\n", 19 | "Este problema se puede resolver ingenuamente usando un ciclo `for`:\n", 20 | "\n", 21 | "```python \n", 22 | " y = []\n", 23 | " for xi in x:\n", 24 | " y.append(1/(1+math.exp(-xi))\n", 25 | "```\n", 26 | "\n", 27 | "Sin embargo, ya sabemos que esto es ineficiente en \"Python puro\". Las librerías de cómputo científico vistas en este curso nos ofrecen una mejor alternativa. \n", 28 | "\n", 29 | ":::{important}\n", 30 | "\n", 31 | "**NumPy** nos provee de una estructura de arreglo multidimensional (ndarray) y funciones para operarla que están escritas en C y Fortran. \n", 32 | "\n", 33 | ":::\n", 34 | "\n", 35 | "Utilizando **NumPy** podemos reemplazar un ciclo `for` en problemas *SIMD* por operaciones que trabajan sobre todo el arreglo, estas sa llaman **operaciones vectoriales**.\n", 36 | "\n", 37 | "Por ejemplo, asumiendo que `x` es una lista, podemos vectorizar el código del ejemplo anterior como:\n", 38 | "\n", 39 | "```python\n", 40 | " x = np.array(x)\n", 41 | " y = 1/(1+np.exp(-x))\n", 42 | "```\n", 43 | "\n", 44 | ":::{note}\n", 45 | "\n", 46 | "NumPy aplica la función exponencial a todo el arreglo x, luego aplica la aritmética (suma y división) a cada elemento del arreglo (broadcasting) y finalmente retorna un nuevo arreglo con el resultado.\n", 47 | "\n", 48 | ":::\n", 49 | "\n", 50 | "El proceso de reemplazar un ciclo `for` por una operación vectorial se conoce como **vectorización**. A continuación revisaremos mediante ejemplos como implementar este y otros conceptos para mejorar el rendimiento." 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "## Reemplazar ciclo `for` por operaciones vectoriales\n", 58 | "\n", 59 | "Las operaciones vectoriales son **funciones de NumPy** de tipo *element-wise* aplicadas sobre un ndarray. Las funciones *element-wise* son aquellas que actuan sobre todos los elementos del arreglo de forma independiente:\n", 60 | "\n", 61 | "- En capítulos anteriores revisamos algunos ejemplos: exponenciación, raíces, trigonometrícas, etc\n", 62 | "- Las operaciones aritméticas entre ndarrays son por defecto *element-wise*\n", 63 | "\n", 64 | "Luego si tenemos un problema SIMD escrito con un `for` sobre un conjunto de datos podemos:\n", 65 | "\n", 66 | "1. Convertir los datos a ndarray\n", 67 | "1. Escribir la operación con funciones de NumPy *element-wise*\n", 68 | "\n", 69 | "y obtener una ganancia considerable en eficiencia de forma simple y directa." 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "Por ejemplo, notemos la diferencia en tiempo de cómputo al hacer aritmética simple" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 1, 82 | "metadata": { 83 | "ExecuteTime": { 84 | "end_time": "2020-08-19T02:20:50.131710Z", 85 | "start_time": "2020-08-19T02:20:49.387815Z" 86 | } 87 | }, 88 | "outputs": [ 89 | { 90 | "name": "stdout", 91 | "output_type": "stream", 92 | "text": [ 93 | "22.1 ms ± 402 µs per loop (mean ± std. dev. of 7 runs, 3 loops each)\n", 94 | "205 µs ± 76.2 µs per loop (mean ± std. dev. of 7 runs, 3 loops each)\n" 95 | ] 96 | }, 97 | { 98 | "data": { 99 | "text/plain": [ 100 | "(True, 108.00234301051614)" 101 | ] 102 | }, 103 | "execution_count": 1, 104 | "metadata": {}, 105 | "output_type": "execute_result" 106 | } 107 | ], 108 | "source": [ 109 | "import numpy as np\n", 110 | "\n", 111 | "x_ndarray = np.random.randn(100000)\n", 112 | "x_list = list(x_ndarray)\n", 113 | "\n", 114 | "def operacion_simple(data):\n", 115 | " resultado = []\n", 116 | " append = resultado.append\n", 117 | " for elemento in data:\n", 118 | " append(elemento*elemento + elemento)\n", 119 | " return resultado\n", 120 | "\n", 121 | "# Operación usando \"for con mejoras\"\n", 122 | "reference = %timeit -n3 -r7 -o operacion_simple(x_list)\n", 123 | "# Operación usando numpy sobre un ndarray\n", 124 | "proposal = %timeit -n3 -r7 -o x_ndarray*x_ndarray + x_ndarray\n", 125 | "# Comparación entre los resultados\n", 126 | "same_result = np.allclose(operacion_simple(x_list), x_ndarray*x_ndarray + x_ndarray)\n", 127 | "speed_up = reference.average/proposal.average\n", 128 | "same_result, speed_up" 129 | ] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "metadata": {}, 134 | "source": [ 135 | ":::{warning}\n", 136 | "\n", 137 | "Las funciones de NumPy son lentas cuando operan sobre tipos que no son ndarray\n", 138 | "\n", 139 | ":::\n", 140 | "\n", 141 | "Para el ejemplo de $y_i = (1 + e^{-x_i})^{-1}, \\quad i = 1,2,\\ldots, N$" 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": 2, 147 | "metadata": { 148 | "ExecuteTime": { 149 | "end_time": "2020-08-19T02:20:50.770427Z", 150 | "start_time": "2020-08-19T02:20:50.133953Z" 151 | } 152 | }, 153 | "outputs": [ 154 | { 155 | "name": "stdout", 156 | "output_type": "stream", 157 | "text": [ 158 | "17.5 ms ± 1.28 ms per loop (mean ± std. dev. of 7 runs, 3 loops each)\n", 159 | "8.3 ms ± 254 µs per loop (mean ± std. dev. of 7 runs, 3 loops each)\n", 160 | "364 µs ± 11.3 µs per loop (mean ± std. dev. of 7 runs, 3 loops each)\n" 161 | ] 162 | }, 163 | { 164 | "data": { 165 | "text/plain": [ 166 | "True" 167 | ] 168 | }, 169 | "execution_count": 2, 170 | "metadata": {}, 171 | "output_type": "execute_result" 172 | } 173 | ], 174 | "source": [ 175 | "from math import exp\n", 176 | "# usando list comprehension (similar a un \"for mejorado\")\n", 177 | "%timeit -n3 -r7 [1./(1.+exp(xi)) for xi in x_list]\n", 178 | "# usando numpy sobre una lista\n", 179 | "%timeit -n3 -r7 1./(1+np.exp(x_list))\n", 180 | "# usando numpy sobre un ndarray\n", 181 | "%timeit -n3 -r7 1./(1+np.exp(x_ndarray))\n", 182 | "# Comparación entre los resultados\n", 183 | "np.allclose(1./(1+np.exp(x_ndarray)), [1./(1.+exp(xi)) for xi in x_list])" 184 | ] 185 | }, 186 | { 187 | "cell_type": "markdown", 188 | "metadata": {}, 189 | "source": [ 190 | "> Las operación sobre ndarray es casi un orden de magnitud más rápida\n", 191 | "\n", 192 | "**¿Por qué ocurre esto?**\n", 193 | "\n", 194 | "Recuerde que una lista puede tener distintos tipos y además puede estar guardada en distintos sectores de memoria. En cambio, el ndarray:\n", 195 | "\n", 196 | "- Tiene un tipo definido \n", 197 | "- Está guardado en bloques de memoria contiguos\n", 198 | "\n", 199 | "Por ende el ndarray tiene un *overhead* de interpretador mucho menor que la lista. Además NumPy está escrito en C/Fortran, y hacer un loop en memoría contigua en C es muy eficiente.\n", 200 | "\n", 201 | ":::{seealso}\n", 202 | "\n", 203 | "NumPy puede [compilarse con librerías de alto desempeño como openblas o MKL](https://numpy.org/devdocs/user/building.html#accelerated-blas-lapack-libraries). De esta forma se aprovechan mejor las capacidades del hardware (Cache de CPU e instrucciones vectoriales de CPU).\n", 204 | "\n", 205 | ":::\n" 206 | ] 207 | }, 208 | { 209 | "cell_type": "markdown", 210 | "metadata": {}, 211 | "source": [ 212 | "## Convertir operaciones lógicas sobre arreglos en máscaras\n", 213 | "\n", 214 | "Las operaciones lógicas en NumPy también son *element-wise* (Operaciones booleanas, clase NumPy, unidad 1). Si queremos recuperar los elementos de un arreglo que cumplan una cierta condición podemos:\n", 215 | "\n", 216 | "1. Convertir los datos a ndarray\n", 217 | "1. Escribir la operación como una máscara booleana de índices\n", 218 | "\n", 219 | "Consideremos el ejemplo de la lección anterior donde se deseaban recuperar los elementos de una lista tal que $\\sin(x_i)>0$" 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": 3, 225 | "metadata": { 226 | "ExecuteTime": { 227 | "end_time": "2020-08-19T02:20:51.083640Z", 228 | "start_time": "2020-08-19T02:20:50.773167Z" 229 | } 230 | }, 231 | "outputs": [ 232 | { 233 | "name": "stdout", 234 | "output_type": "stream", 235 | "text": [ 236 | "15.2 ms ± 473 µs per loop (mean ± std. dev. of 5 runs, 3 loops each)\n", 237 | "1.54 ms ± 32.7 µs per loop (mean ± std. dev. of 5 runs, 3 loops each)\n" 238 | ] 239 | }, 240 | { 241 | "data": { 242 | "text/plain": [ 243 | "(True, 9.88342694541913)" 244 | ] 245 | }, 246 | "execution_count": 3, 247 | "metadata": {}, 248 | "output_type": "execute_result" 249 | } 250 | ], 251 | "source": [ 252 | "import math\n", 253 | "\n", 254 | "def sin_pos(data):\n", 255 | " resultado = []\n", 256 | " append = resultado.append\n", 257 | " sin = math.sin\n", 258 | " for element in data:\n", 259 | " if sin(element) > 0:\n", 260 | " append(element)\n", 261 | " return resultado\n", 262 | "\n", 263 | "reference = %timeit -r5 -n3 -o sin_pos(x_list)\n", 264 | "proposal = %timeit -r5 -n3 -o x_ndarray[np.sin(x_ndarray) > 0.]\n", 265 | "\n", 266 | "same_result = np.allclose(sin_pos(x_list), x_ndarray[np.sin(x_ndarray) > 0])\n", 267 | "speed_up = reference.average/proposal.average \n", 268 | "same_result, speed_up" 269 | ] 270 | }, 271 | { 272 | "cell_type": "markdown", 273 | "metadata": {}, 274 | "source": [ 275 | "## Evitar copia adicional de datos\n", 276 | "\n", 277 | "Cuando en NumPy ejecutamos\n", 278 | "\n", 279 | "```python\n", 280 | " x = x*x\n", 281 | "```\n", 282 | "\n", 283 | "Ocurre lo siguiente:\n", 284 | "\n", 285 | "1. Se crea una copia interna de x*x\n", 286 | "1. x es direccionado a esa nueva copia\n", 287 | "1. La zona de memoria con el valor original es luego eliminada por el *garbage-collector* de Python\n", 288 | "\n", 289 | "Siempre que no necesitemos el valor original podemos usar operaciones ***in-place*** y ganar rendimiento, ya que evitamos la copia y eliminación adicional" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": 4, 295 | "metadata": { 296 | "ExecuteTime": { 297 | "end_time": "2020-08-19T02:20:51.699699Z", 298 | "start_time": "2020-08-19T02:20:51.085550Z" 299 | } 300 | }, 301 | "outputs": [ 302 | { 303 | "name": "stdout", 304 | "output_type": "stream", 305 | "text": [ 306 | "3.32 ms ± 71.8 µs per loop (mean ± std. dev. of 10 runs, 10 loops each)\n", 307 | "2.25 ms ± 76.9 µs per loop (mean ± std. dev. of 10 runs, 10 loops each)\n" 308 | ] 309 | }, 310 | { 311 | "data": { 312 | "text/plain": [ 313 | "(True, 1.4759441251674865)" 314 | ] 315 | }, 316 | "execution_count": 4, 317 | "metadata": {}, 318 | "output_type": "execute_result" 319 | } 320 | ], 321 | "source": [ 322 | "# Copia interna y cambio de referencia de x_ndarray \n", 323 | "reference = %timeit -r10 -n10 -o x_ndarray = np.zeros(shape=(1000000)); y = x_ndarray*x_ndarray\n", 324 | "# Sin copia interna\n", 325 | "proposal = %timeit -r10 -n10 -o x_ndarray = np.zeros(shape=(1000000)); x_ndarray *= x_ndarray\n", 326 | "\n", 327 | "x_ndarray = np.zeros(shape=(1000000))\n", 328 | "y = x_ndarray*x_ndarray\n", 329 | "x_ndarray *= x_ndarray\n", 330 | "\n", 331 | "same_result = np.allclose(x_ndarray, y)\n", 332 | "speed_up = reference.average/proposal.average\n", 333 | "same_result, speed_up" 334 | ] 335 | }, 336 | { 337 | "cell_type": "markdown", 338 | "metadata": {}, 339 | "source": [ 340 | "Sea $x$ un ndarray, la operación\n", 341 | "\n", 342 | "```python\n", 343 | " x[2:10] \n", 344 | "```\n", 345 | "\n", 346 | "es una \"vista de x\". \n", 347 | "\n", 348 | ":::{hint}\n", 349 | "\n", 350 | "Recordar que las \"vista de arreglo\" no hacen copias en memoria ya que apuntan directamente al arreglo original. Es decir que si modificamos una vista modificamos el original.\n", 351 | "\n", 352 | ":::" 353 | ] 354 | }, 355 | { 356 | "cell_type": "markdown", 357 | "metadata": {}, 358 | "source": [ 359 | "## Aprovechar el *broadcasting* automático de NumPy\n", 360 | "\n", 361 | "Se pueden hacer operaciones vectorizadas con NumPy entre arreglos con tamaños distintos. En ese caso se aplican las reglas de *broadcasting* que se vieron en la lección de NumPy.\n", 362 | "\n", 363 | ":::{note}\n", 364 | "\n", 365 | "El *broadcasting* automático no hace copias en memoria.\n", 366 | "\n", 367 | ":::\n", 368 | "\n", 369 | "**Ejemplo 1:** Si le sumas una constante a un arreglo 1D, la constante se expande y se suma a cada elemento:" 370 | ] 371 | }, 372 | { 373 | "cell_type": "code", 374 | "execution_count": 5, 375 | "metadata": { 376 | "ExecuteTime": { 377 | "end_time": "2020-08-19T02:20:52.810029Z", 378 | "start_time": "2020-08-19T02:20:51.702112Z" 379 | } 380 | }, 381 | "outputs": [ 382 | { 383 | "name": "stdout", 384 | "output_type": "stream", 385 | "text": [ 386 | "942 µs ± 160 µs per loop (mean ± std. dev. of 10 runs, 10 loops each)\n", 387 | "11.1 ms ± 967 µs per loop (mean ± std. dev. of 10 runs, 10 loops each)\n" 388 | ] 389 | }, 390 | { 391 | "data": { 392 | "text/plain": [ 393 | "True" 394 | ] 395 | }, 396 | "execution_count": 5, 397 | "metadata": {}, 398 | "output_type": "execute_result" 399 | } 400 | ], 401 | "source": [ 402 | "N = 1000000\n", 403 | "x = np.zeros(shape=(N, ))\n", 404 | "# broadcasting automático\n", 405 | "%timeit -n10 -r10 x + 1.\n", 406 | "# Agrandando y luego sumando\n", 407 | "%timeit -n10 -r10 x + np.tile([1], len(x))\n", 408 | "# mismo resultado\n", 409 | "np.allclose(x + 1, x + np.tile([1], len(x)))" 410 | ] 411 | }, 412 | { 413 | "cell_type": "markdown", 414 | "metadata": {}, 415 | "source": [ 416 | "**Ejemplo 2:** Si le sumas un arreglo 1D a un arreglo 2D, el arreglo 1D se expande en la dimensión que le falta:" 417 | ] 418 | }, 419 | { 420 | "cell_type": "code", 421 | "execution_count": 6, 422 | "metadata": { 423 | "ExecuteTime": { 424 | "end_time": "2020-08-19T02:21:02.293965Z", 425 | "start_time": "2020-08-19T02:20:52.812659Z" 426 | } 427 | }, 428 | "outputs": [ 429 | { 430 | "name": "stdout", 431 | "output_type": "stream", 432 | "text": [ 433 | "30.9 ms ± 909 µs per loop (mean ± std. dev. of 10 runs, 10 loops each)\n" 434 | ] 435 | }, 436 | { 437 | "data": { 438 | "text/plain": [ 439 | "(10000, 1000)" 440 | ] 441 | }, 442 | "metadata": {}, 443 | "output_type": "display_data" 444 | }, 445 | { 446 | "name": "stdout", 447 | "output_type": "stream", 448 | "text": [ 449 | "98.4 ms ± 1.41 ms per loop (mean ± std. dev. of 10 runs, 10 loops each)\n" 450 | ] 451 | }, 452 | { 453 | "data": { 454 | "text/plain": [ 455 | "True" 456 | ] 457 | }, 458 | "execution_count": 6, 459 | "metadata": {}, 460 | "output_type": "execute_result" 461 | } 462 | ], 463 | "source": [ 464 | "N, M = 10000, 1000\n", 465 | "x = np.zeros(shape=(N, M)) # arreglo de NxM\n", 466 | "y = np.zeros(shape=(N, )) # arreglo sin dimensión\n", 467 | "y_ = y[:, np.newaxis] # arreglo de Nx1\n", 468 | "# broadcasting automático\n", 469 | "%timeit -n10 -r10 x + y_\n", 470 | "display((x + y_).shape)\n", 471 | "# Agrandando y luego sumando\n", 472 | "%timeit -n10 -r10 x + np.tile(y_, (1, x.shape[-1]))\n", 473 | "# mismo resultado\n", 474 | "np.allclose(x + y_, x + np.tile(y_, (1, x.shape[-1])))" 475 | ] 476 | }, 477 | { 478 | "cell_type": "markdown", 479 | "metadata": {}, 480 | "source": [ 481 | "**Ejemplo 3:** Si sumas un arreglo 1D fila y un arreglo 1D columna se crea un arreglo 2D:" 482 | ] 483 | }, 484 | { 485 | "cell_type": "code", 486 | "execution_count": 7, 487 | "metadata": { 488 | "ExecuteTime": { 489 | "end_time": "2020-08-19T02:21:15.025080Z", 490 | "start_time": "2020-08-19T02:21:02.295774Z" 491 | } 492 | }, 493 | "outputs": [ 494 | { 495 | "name": "stdout", 496 | "output_type": "stream", 497 | "text": [ 498 | "32.6 ms ± 1.56 ms per loop (mean ± std. dev. of 10 runs, 10 loops each)\n" 499 | ] 500 | }, 501 | { 502 | "data": { 503 | "text/plain": [ 504 | "(10000, 1000)" 505 | ] 506 | }, 507 | "metadata": {}, 508 | "output_type": "display_data" 509 | }, 510 | { 511 | "name": "stdout", 512 | "output_type": "stream", 513 | "text": [ 514 | "118 ms ± 2.1 ms per loop (mean ± std. dev. of 10 runs, 10 loops each)\n" 515 | ] 516 | }, 517 | { 518 | "data": { 519 | "text/plain": [ 520 | "True" 521 | ] 522 | }, 523 | "execution_count": 7, 524 | "metadata": {}, 525 | "output_type": "execute_result" 526 | } 527 | ], 528 | "source": [ 529 | "N, M = 10000, 1000\n", 530 | "x = np.zeros(shape=(N, 1)) # arreglo columna de Nx1\n", 531 | "y = np.zeros(shape=(1, M)) # arreglo fila de 1xM\n", 532 | "# broadcasting automático\n", 533 | "%timeit -n10 -r10 x + y\n", 534 | "display((x+y).shape)\n", 535 | "# Agrandando y luego sumando\n", 536 | "%timeit -n10 -r10 np.tile(y, (x.shape[0], 1)) + np.tile(x, (1, y.shape[-1]))\n", 537 | "np.allclose(x + y, np.tile(y, (x.shape[0], 1)) + np.tile(x, (1, y.shape[-1])))" 538 | ] 539 | }, 540 | { 541 | "cell_type": "markdown", 542 | "metadata": {}, 543 | "source": [ 544 | ":::{note}\n", 545 | "\n", 546 | "Las dimensiones de dos arreglos son compatibles con *broadcast* automático si **son del mismo tamaño** o **una de ellas es igual a uno**.\n", 547 | "\n", 548 | ":::" 549 | ] 550 | }, 551 | { 552 | "cell_type": "markdown", 553 | "metadata": {}, 554 | "source": [ 555 | "## Utilizar el ordenamiento en memoría más adecuado en cada caso\n", 556 | "\n", 557 | "Los ndarray multidimensionales pueden guardarse en memoria como *row-major* (filas contiguas) o *column-major* (columnas contiguas). Por defecto las matrices en NumPy son *row-major* pero podemos forzar la contigüidad usando el atributo `order` o trasponiendo (ojo que trasponer crea una copia).\n", 558 | "\n", 559 | "Se puede verificar esto con el atributo `flag` de los ndarray:" 560 | ] 561 | }, 562 | { 563 | "cell_type": "code", 564 | "execution_count": 8, 565 | "metadata": { 566 | "ExecuteTime": { 567 | "end_time": "2020-08-19T02:21:15.051641Z", 568 | "start_time": "2020-08-19T02:21:15.027132Z" 569 | } 570 | }, 571 | "outputs": [ 572 | { 573 | "data": { 574 | "text/plain": [ 575 | "array([[0, 1, 2],\n", 576 | " [3, 4, 5]])" 577 | ] 578 | }, 579 | "metadata": {}, 580 | "output_type": "display_data" 581 | }, 582 | { 583 | "data": { 584 | "text/plain": [ 585 | " C_CONTIGUOUS : True\n", 586 | " F_CONTIGUOUS : False\n", 587 | " OWNDATA : False\n", 588 | " WRITEABLE : True\n", 589 | " ALIGNED : True\n", 590 | " WRITEBACKIFCOPY : False" 591 | ] 592 | }, 593 | "metadata": {}, 594 | "output_type": "display_data" 595 | }, 596 | { 597 | "data": { 598 | "text/plain": [ 599 | "array([0, 1, 2, 3, 4, 5])" 600 | ] 601 | }, 602 | "metadata": {}, 603 | "output_type": "display_data" 604 | }, 605 | { 606 | "data": { 607 | "text/plain": [ 608 | " C_CONTIGUOUS : False\n", 609 | " F_CONTIGUOUS : True\n", 610 | " OWNDATA : False\n", 611 | " WRITEABLE : True\n", 612 | " ALIGNED : True\n", 613 | " WRITEBACKIFCOPY : False" 614 | ] 615 | }, 616 | "metadata": {}, 617 | "output_type": "display_data" 618 | }, 619 | { 620 | "data": { 621 | "text/plain": [ 622 | "array([0, 3, 1, 4, 2, 5])" 623 | ] 624 | }, 625 | "metadata": {}, 626 | "output_type": "display_data" 627 | } 628 | ], 629 | "source": [ 630 | "data = np.arange(6).reshape(2, 3)\n", 631 | "display(data)\n", 632 | "# Verificamos los flags\n", 633 | "display(data.flags)\n", 634 | "# Así se ve row-major en memoria \n", 635 | "display(data.ravel())\n", 636 | "# Verificamos los flags\n", 637 | "dataT = data.T\n", 638 | "display(dataT.flags)\n", 639 | "# Así se ve column-major en memoria\n", 640 | "display(dataT.ravel())" 641 | ] 642 | }, 643 | { 644 | "cell_type": "markdown", 645 | "metadata": {}, 646 | "source": [ 647 | ":::{note}\n", 648 | "\n", 649 | "La mayoría de las funciones de NumPy funcionan más rápido en formato *row-major* (formato C). Pero algunas funciones de scipy (heredadas de Fortran) funcionan más rápido en formato *col-major* (formato Fortran).\n", 650 | "\n", 651 | ":::\n", 652 | "\n", 653 | "Es recomendable verificar el orden en memoria que espera la función que vas a utilizar." 654 | ] 655 | }, 656 | { 657 | "cell_type": "code", 658 | "execution_count": 9, 659 | "metadata": { 660 | "ExecuteTime": { 661 | "end_time": "2020-08-19T02:21:36.434997Z", 662 | "start_time": "2020-08-19T02:21:15.054192Z" 663 | } 664 | }, 665 | "outputs": [ 666 | { 667 | "name": "stdout", 668 | "output_type": "stream", 669 | "text": [ 670 | "11.6 µs ± 189 ns per loop (mean ± std. dev. of 10 runs, 100 loops each)\n", 671 | "74.1 ms ± 659 µs per loop (mean ± std. dev. of 10 runs, 10 loops each)\n" 672 | ] 673 | } 674 | ], 675 | "source": [ 676 | "data = np.random.randn(10000, 10000) # (row-major)\n", 677 | "# Sumando una fila\n", 678 | "%timeit -n100 -r10 np.sum(data[0, :])\n", 679 | "# Sumando todas las filas\n", 680 | "%timeit -n10 -r10 np.sum(data, axis=1)" 681 | ] 682 | }, 683 | { 684 | "cell_type": "code", 685 | "execution_count": 10, 686 | "metadata": {}, 687 | "outputs": [ 688 | { 689 | "name": "stdout", 690 | "output_type": "stream", 691 | "text": [ 692 | "32.3 µs ± 8.63 µs per loop (mean ± std. dev. of 10 runs, 100 loops each)\n", 693 | "121 ms ± 2.46 ms per loop (mean ± std. dev. of 10 runs, 10 loops each)\n" 694 | ] 695 | } 696 | ], 697 | "source": [ 698 | "# Sumando una columna\n", 699 | "%timeit -n100 -r10 np.sum(data[:, 0])\n", 700 | "# Sumando todas las columnas\n", 701 | "%timeit -n10 -r10 np.sum(data, axis=0)" 702 | ] 703 | }, 704 | { 705 | "cell_type": "code", 706 | "execution_count": 11, 707 | "metadata": {}, 708 | "outputs": [ 709 | { 710 | "name": "stdout", 711 | "output_type": "stream", 712 | "text": [ 713 | "74.5 ms ± 412 µs per loop (mean ± std. dev. of 10 runs, 10 loops each)\n" 714 | ] 715 | } 716 | ], 717 | "source": [ 718 | "# Sumando todas las columnas de la matriz traspuesta (column major)\n", 719 | "%timeit -n10 -r10 np.sum(data.T, axis=0)" 720 | ] 721 | }, 722 | { 723 | "cell_type": "code", 724 | "execution_count": null, 725 | "metadata": {}, 726 | "outputs": [], 727 | "source": [] 728 | } 729 | ], 730 | "metadata": { 731 | "kernelspec": { 732 | "display_name": "Python 3 (ipykernel)", 733 | "language": "python", 734 | "name": "python3" 735 | }, 736 | "language_info": { 737 | "codemirror_mode": { 738 | "name": "ipython", 739 | "version": 3 740 | }, 741 | "file_extension": ".py", 742 | "mimetype": "text/x-python", 743 | "name": "python", 744 | "nbconvert_exporter": "python", 745 | "pygments_lexer": "ipython3", 746 | "version": "3.9.16" 747 | }, 748 | "toc": { 749 | "base_numbering": 1, 750 | "nav_menu": {}, 751 | "number_sections": true, 752 | "sideBar": true, 753 | "skip_h1_title": false, 754 | "title_cell": "Table of Contents", 755 | "title_sidebar": "Contents", 756 | "toc_cell": false, 757 | "toc_position": { 758 | "height": "calc(100% - 180px)", 759 | "left": "10px", 760 | "top": "150px", 761 | "width": "254px" 762 | }, 763 | "toc_section_display": true, 764 | "toc_window_display": true 765 | } 766 | }, 767 | "nbformat": 4, 768 | "nbformat_minor": 2 769 | } 770 | -------------------------------------------------------------------------------- /contents/jupyter/beyond_python.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Otros lenguajes en Jupyter \n", 8 | "\n", 9 | "A lo largo de este libro se trabaja principalmente con Python y con el kernel de IPython para jupyter \n", 10 | "\n", 11 | "Sin embargo existe una lista de kernels desarrollados por la [comunidad](https://github.com/jupyter/jupyter/wiki/Jupyter-kernels) para otros lenguajes \n", 12 | "\n", 13 | "- [IRkernel](https://github.com/IRkernel/IRkernel) \n", 14 | "- [IJulia](https://github.com/JuliaLang/IJulia.jl)\n", 15 | "- [Ijavascript](https://github.com/n-riesco/ijavascript)\n", 16 | "- [IHaskell](https://github.com/gibiansky/IHaskell)\n", 17 | "- [IRuby](https://github.com/sciruby/iruby)\n", 18 | "- [IElixir](https://github.com/pprzetacznik/IElixir)\n", 19 | "- [Xeus Cling](https://github.com/QuantStack/xeus-cling) (C++)\n", 20 | "\n", 21 | ":::{note}\n", 22 | "\n", 23 | "Algunos de estos se pueden probar en [jupyter.org/try](https://jupyter.org/try)\n", 24 | "\n", 25 | ":::\n", 26 | "\n", 27 | "También hay lenguajes que tienen magias oficiales para usarse dentro del kernel de Python. Estos requieren que sus ejecutables respectivos estén disponibles\n", 28 | "\n", 29 | "Por ejemplo" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": 1, 35 | "metadata": {}, 36 | "outputs": [ 37 | { 38 | "name": "stdout", 39 | "output_type": "stream", 40 | "text": [ 41 | "Hello, world!\n" 42 | ] 43 | } 44 | ], 45 | "source": [ 46 | "%%bash\n", 47 | "\n", 48 | "echo \"Hello, world!\" " 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 2, 54 | "metadata": {}, 55 | "outputs": [ 56 | { 57 | "name": "stdout", 58 | "output_type": "stream", 59 | "text": [ 60 | "Hello, World!\n" 61 | ] 62 | } 63 | ], 64 | "source": [ 65 | "%%perl\n", 66 | "print \"Hello, World!\\n\";" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 3, 72 | "metadata": {}, 73 | "outputs": [ 74 | { 75 | "name": "stdout", 76 | "output_type": "stream", 77 | "text": [ 78 | "Hello, world!\n" 79 | ] 80 | } 81 | ], 82 | "source": [ 83 | "%%ruby\n", 84 | "\n", 85 | "puts 'Hello, world!'" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": null, 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [] 94 | } 95 | ], 96 | "metadata": { 97 | "kernelspec": { 98 | "display_name": "Python 3 (ipykernel)", 99 | "language": "python", 100 | "name": "python3" 101 | }, 102 | "language_info": { 103 | "codemirror_mode": { 104 | "name": "ipython", 105 | "version": 3 106 | }, 107 | "file_extension": ".py", 108 | "mimetype": "text/x-python", 109 | "name": "python", 110 | "nbconvert_exporter": "python", 111 | "pygments_lexer": "ipython3", 112 | "version": "3.8.12" 113 | }, 114 | "toc": { 115 | "base_numbering": 1, 116 | "nav_menu": {}, 117 | "number_sections": true, 118 | "sideBar": true, 119 | "skip_h1_title": false, 120 | "title_cell": "Table of Contents", 121 | "title_sidebar": "Contents", 122 | "toc_cell": false, 123 | "toc_position": {}, 124 | "toc_section_display": true, 125 | "toc_window_display": false 126 | } 127 | }, 128 | "nbformat": 4, 129 | "nbformat_minor": 2 130 | } 131 | -------------------------------------------------------------------------------- /contents/jupyter/img/jupyter1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/jupyter/img/jupyter1.png -------------------------------------------------------------------------------- /contents/jupyter/img/jupyter2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/jupyter/img/jupyter2.png -------------------------------------------------------------------------------- /contents/jupyter/img/jupyter_interface1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/jupyter/img/jupyter_interface1.png -------------------------------------------------------------------------------- /contents/jupyter/img/jupyter_interface2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/jupyter/img/jupyter_interface2.png -------------------------------------------------------------------------------- /contents/jupyter/img/notebook_components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/jupyter/img/notebook_components.png -------------------------------------------------------------------------------- /contents/jupyter/img/valdivia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/jupyter/img/valdivia.png -------------------------------------------------------------------------------- /contents/jupyter/intro.md: -------------------------------------------------------------------------------- 1 | # ¿Qué es Jupyter? 2 | 3 | 4 | [Jupyter](https://jupyter.org/) es un proyecto que incorpora: 5 | 6 | - El formato `notebook` 7 | - Un servidor web para editar y visualizar `notebooks` 8 | - Un protocolo de mensajería para comunicar el `notebook` con un `kernel` 9 | 10 | El `kernel` recibe código y retorna los resultados al `notebook`. En general trabajaremos con [IPython](https://ipython.org/), el intérprete de Python interactivo, como kernel. 11 | 12 | El `notebook` es un formato relativamente nuevo que combina: 13 | 14 | - código 15 | - visualizaciones 16 | - ecuaciones 17 | - texto enriquecido 18 | - imágenes, audio, video 19 | - interfaces de usuario (GUI) 20 | - entre otros 21 | 22 | esto lo hace ideal para 23 | 24 | - explorar y analizar datos de forma interactiva 25 | - comunicar y compartir resultados 26 | - crear "[narrativas científicas](https://github.com/mcburton/computational-narratives-with-jupyter)" interactivas 27 | 28 | 29 | **Ejemplos** 30 | 31 | Revisa uno o más de los siguientes ejemplos para hacerte una idea de lo que se puede hacer con Jupyter 32 | 33 | - Visualización de datos de censo (Estados Unidos): https://anaconda.org/jbednar/census/notebook 34 | - Jupyter notebook sobre reacciones químicas: https://nbviewer.jupyter.org/gist/greglandrum/4316430 35 | - Un tutorial de GIT escrito en jupyter: https://nbviewer.jupyter.org/github/fperez/reprosw/blob/master/Version%20Control.ipynb 36 | - Este libro fue creado en base a jupyter notebooks 37 | 38 | ## Qué no es Jupyter 39 | 40 | Jupyter no es un reemplazo para una IDE completa como [*pycharm*](https://www.jetbrains.com/pycharm/) o [*vscode*](https://code.visualstudio.com/) ni editores como [*vim*](https://www.vim.org/) o [*emacs*](https://www.gnu.org/software/emacs/). Jupyter es un complemento. 41 | 42 | No es directo ni sencillo reutilizar (importar) código que está en jupyter notebook. Por razones como esta los notebooks no suelen ser usados para tareas de producción. 43 | 44 | Si tu notebook tiene rutinas que pueden ser utilizadas por otros notebooks o scripts lo mejor es escribir la rutina como un módulo regular de Python y luego importarlo desde el notebook. 45 | 46 | :::{hint} 47 | 48 | Usando la magia `%autoreload 2` puedes hacer cambios "en vivo" en los módulos importados por el notebook sin tener que reiniciarlo. 49 | 50 | ::: 51 | 52 | Revisa la siguiente presentación sobre [Buenas prácticas con Jupyter notebook](https://docs.google.com/presentation/d/1TKOjhFsYM4R_iIhMGPuS5h3fY_AxHpzxPQ3MKVwmzOc/edit#slide=id.g872e56ba64_0_0) para más consejos. 53 | 54 | 55 | ## ¿Cómo funciona Jupyter? 56 | 57 | La siguiente figura muestra los componentes del ambiente jupyter. 58 | 59 | 60 | 61 | - El **servidor jupyter** es el encargado de administrar los `notebooks`. 62 | - Los usuarios interactuan con los `notebooks` a través de su navegador (*frontend* web) o IDE. 63 | - El proceso encargado de correr los códigos se denomina `kernel`. 64 | - El servidor conecta los notebooks con el kernel usando la librería de mensajería ZeroMQ. 65 | 66 | 67 | **¿Qué lenguajes puedo usar con Jupyter?** 68 | 69 | Existen `kernels` de Python, Julia, Ruby, C y otros lenguajes. En este libro nos enfocaremos en el kernel *Interactive Python* o IPython. 70 | 71 | IPython es un interprete de Python que ofrece varias mejoras tales como: 72 | 73 | - autocompletación de path y módulos 74 | - acceso desde terminal a documentación y código fuente 75 | - búsqueda histórica de comandos 76 | - instrucciones especiales llamadas *magics* que serán vistas más adelante 77 | 78 | 79 | :::{note} 80 | 81 | IPython reemplaza al intérprete convencional de Python. No necesitamos Jupyter para utilizar IPython, simplemente escribe `ipython` en un terminal. 82 | 83 | ::: 84 | 85 | :::{note} 86 | 87 | Además del frontend por defecto existe [jupyter lab](https://jupyter.org/). Este último tiene una interfaz de usuario más similar al de una IDE completa. 88 | 89 | ::: 90 | 91 | ## Creando un ambiente para cómputo interactivo con jupyter 92 | 93 | Utilizando conda creamos un ambiente con Python 3.10 (o superior) con las librerías necesarias: 94 | 95 | conda create -n info147 python=3.10 pip jupyter numpy matplotlib pandas scipy ipympl 96 | 97 | Luego activamos el ambiente: 98 | 99 | conda activate info147 100 | 101 | Finalmente iniciamos el servidor jupyter escribiendo en la terminal: 102 | 103 | jupyter notebook 104 | 105 | Esto abrirá una pestaña de navegador (browser) apuntada en la dirección: 106 | 107 | http://localhost:8888 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /contents/jupyter/script_interesante.py: -------------------------------------------------------------------------------- 1 | def funcion_interesante(n): 2 | """ 3 | Este script es interesante 4 | """ 5 | if n == 1: 6 | return 1 7 | 8 | else: 9 | return n * funcion_interesante(n-1) 10 | 11 | if __name__ == '__main__': 12 | print(funcion_interesante(10)) 13 | -------------------------------------------------------------------------------- /contents/linalg/data/helados.csv: -------------------------------------------------------------------------------- 1 | "","cons","income","price","temp" 2 | "1",0.386,78,0.27,41 3 | "2",0.374,79,0.282,56 4 | "3",0.393,81,0.277,63 5 | "4",0.425,80,0.28,68 6 | "5",0.406,76,0.272,69 7 | "6",0.344,78,0.262,65 8 | "7",0.327,82,0.275,61 9 | "8",0.288,79,0.267,47 10 | "9",0.269,76,0.265,32 11 | "10",0.256,79,0.277,24 12 | "11",0.286,82,0.282,28 13 | "12",0.298,85,0.27,26 14 | "13",0.329,86,0.272,32 15 | "14",0.318,83,0.287,40 16 | "15",0.381,84,0.277,55 17 | "16",0.381,82,0.287,63 18 | "17",0.47,80,0.28,72 19 | "18",0.443,78,0.277,72 20 | "19",0.386,84,0.277,67 21 | "20",0.342,86,0.277,60 22 | "21",0.319,85,0.292,44 23 | "22",0.307,87,0.287,40 24 | "23",0.284,94,0.277,32 25 | "24",0.326,92,0.285,27 26 | "25",0.309,95,0.282,28 27 | "26",0.359,96,0.265,33 28 | "27",0.376,94,0.265,41 29 | "28",0.416,96,0.265,52 30 | "29",0.437,91,0.268,64 31 | "30",0.548,90,0.26,71 32 | -------------------------------------------------------------------------------- /contents/linalg/eigvals.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Problema de los valores y vectores propios\n", 8 | "\n", 9 | "Existen [múltiples sistemas en física](https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors#Applications) que [ocurren naturalmente](https://hubpages.com/education/What-the-Heck-are-Eigenvalues-and-Eigenvectors) como un problema de valores/vectores propios. En esta lección veremos como resolver un problema de este tipo utilizando Python.\n", 10 | "\n", 11 | "## Formulación matemática\n", 12 | "\n", 13 | "Sea una matriz cuadrada $A \\in \\mathbb{R}^{D\\times D}$. El siguiente sistema de ecuaciones de $D$ ecuaciones\n", 14 | "\n", 15 | "$$\n", 16 | "A \\vec v = \\lambda I \\vec v \n", 17 | "$$\n", 18 | "\n", 19 | "que se puede escribir de forma equivalente como\n", 20 | "\n", 21 | "$$\n", 22 | "(A - \\lambda I) \\vec v = 0\n", 23 | "$$\n", 24 | "\n", 25 | "tiene como resultado \n", 26 | "\n", 27 | "- $\\lambda$, los valores propios de $A$\n", 28 | "- $\\vec v$ los vectores propios de $A$\n", 29 | "\n", 30 | "La solución no trivial de este problema ($\\vec v \\neq 0$) se obtiene si $(A - \\lambda I)$ es singular, es decir\n", 31 | "\n", 32 | "$$\n", 33 | "|A - \\lambda I | = 0\n", 34 | "$$\n", 35 | "\n", 36 | "que resulta en un polinomio de grado $D$ cuyas raices son $\\{\\lambda_i\\}$, $i=1,2,\\ldots, D$\n", 37 | "\n", 38 | "Una vez determinado $\\lambda_i$ se pueden usar para despejar $\\vec v_i$" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "metadata": {}, 44 | "source": [ 45 | "**Ejemplo**\n", 46 | "\n", 47 | "Para la matriz $A$ del ejemplo, si igualamos su determinante a cero tenemos\n", 48 | "\n", 49 | "$$\n", 50 | "(1 - \\lambda)^2 - 1/4 = 3/4 - 2\\lambda + \\lambda^2 = 0\n", 51 | "$$\n", 52 | "\n", 53 | "osea $\\lambda_1 = 1.5$ y $\\lambda_2 = 0.5$. Luego para el primer vector propio tenemos un sistema de ecuaciones\n", 54 | "\n", 55 | "$$\n", 56 | "\\begin{split}\n", 57 | "-0.5v_{11} +0.5v_{12} &= 0 \\\\\n", 58 | "0.5 v_{11} -0.5v_{12} &= 0\n", 59 | "\\end{split}\n", 60 | "$$\n", 61 | "\n", 62 | "osea $v_{11} = v_{12}$ con esto podemos construir un vector normalizado genérico $v_1 = \\frac{1}{\\sqrt{2}}\\begin{pmatrix} 1 \\\\ 1 \\end{pmatrix}$\n", 63 | "\n", 64 | "De forma equivalente para $v_2 = \\frac{1}{\\sqrt{2}}\\begin{pmatrix} -1 \\\\ 1 \\end{pmatrix}$\n", 65 | "\n", 66 | "## Cálculo de valores y vectores propios con scipy\n", 67 | "\n", 68 | "El módulo [`linalg`](https://docs.scipy.org/doc/scipy/reference/linalg.html) de scipy ofrece funciones para obtener vectores y valores propios. Los de aplicación más común son:\n", 69 | "\n", 70 | "- `eig(X)`: Retorna una tupla con los valores y vectores propios de `X`\n", 71 | "- `eigvals(X)`: Retorna los valores propios de `X`\n", 72 | "- `eigh(X)`: Retorna una tupla con los valores y vectores propios de `X`, asumiendo que `X` tiene simetría hermítica\n", 73 | "- `eigvalsh(X)`: Retorna los valores propios de `X`, asumiendo que `X` tiene simetría hermítica\n", 74 | "\n", 75 | "Utilicemos `eig` para el ejemplo anterior: " 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 1, 81 | "metadata": {}, 82 | "outputs": [ 83 | { 84 | "data": { 85 | "text/plain": [ 86 | "(array([1.5+0.j, 0.5+0.j]),\n", 87 | " array([[ 0.70710678, -0.70710678],\n", 88 | " [ 0.70710678, 0.70710678]]))" 89 | ] 90 | }, 91 | "execution_count": 1, 92 | "metadata": {}, 93 | "output_type": "execute_result" 94 | } 95 | ], 96 | "source": [ 97 | "import numpy as np\n", 98 | "import scipy.linalg\n", 99 | "\n", 100 | "A = np.array([[1., 0.5], [0.5, 1]])\n", 101 | "evals, evecs = scipy.linalg.eig(A)\n", 102 | "evals, evecs" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "## Descomposición en valores y vectores propios" 110 | ] 111 | }, 112 | { 113 | "cell_type": "markdown", 114 | "metadata": {}, 115 | "source": [] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": null, 120 | "metadata": {}, 121 | "outputs": [], 122 | "source": [] 123 | } 124 | ], 125 | "metadata": { 126 | "kernelspec": { 127 | "display_name": "Python 3 (ipykernel)", 128 | "language": "python", 129 | "name": "python3" 130 | }, 131 | "language_info": { 132 | "codemirror_mode": { 133 | "name": "ipython", 134 | "version": 3 135 | }, 136 | "file_extension": ".py", 137 | "mimetype": "text/x-python", 138 | "name": "python", 139 | "nbconvert_exporter": "python", 140 | "pygments_lexer": "ipython3", 141 | "version": "3.8.12" 142 | }, 143 | "toc": { 144 | "base_numbering": 1, 145 | "nav_menu": {}, 146 | "number_sections": true, 147 | "sideBar": true, 148 | "skip_h1_title": false, 149 | "title_cell": "Table of Contents", 150 | "title_sidebar": "Contents", 151 | "toc_cell": false, 152 | "toc_position": {}, 153 | "toc_section_display": true, 154 | "toc_window_display": false 155 | } 156 | }, 157 | "nbformat": 4, 158 | "nbformat_minor": 2 159 | } 160 | -------------------------------------------------------------------------------- /contents/numpy/img/broadcast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/numpy/img/broadcast.png -------------------------------------------------------------------------------- /contents/numpy/img/ndarray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/numpy/img/ndarray.png -------------------------------------------------------------------------------- /contents/numpy/img/slicing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/numpy/img/slicing.png -------------------------------------------------------------------------------- /contents/numpy/img/transpose.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/numpy/img/transpose.jpg -------------------------------------------------------------------------------- /contents/pandas/groupby.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | blockdiag 10 | blockdiag { 11 | #orientation = portrait 12 | default_fontsize = 14; 13 | default_shape = roundedbox; 14 | A [label="split"] 15 | B [label="apply"] 16 | C [label="combine"] 17 | A -> B 18 | B -> C 19 | group { 20 | color = "#FFFF33"; 21 | fontsize = 10; 22 | label = "groupby" 23 | A -> B; 24 | B -> C; 25 | } 26 | 27 | } 28 | 29 | 30 | 31 | 32 | 33 | 34 | split 35 | 36 | apply 37 | 38 | combine 39 | 40 | 41 | 42 | 43 | groupby 44 | 45 | -------------------------------------------------------------------------------- /contents/preliminaries/env_management.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Administración de ambientes y librerías" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Muchas veces necesitaremos usar una librería específica para un proyecto de programación en particular\n", 15 | "\n", 16 | "Si trabajamos en más de un proyecto surge la necesidad de hacer coexistir distintas versiones de librerías en nuestro sistema\n", 17 | "\n", 18 | "En estos escenarios conviene utilizar **ambientes virtuales**. En particular conviene crear un ambiente virtual para cada proyecto en que trabajemos\n", 19 | "\n", 20 | ":::{note}\n", 21 | "\n", 22 | "Cada ambiente puede tener su propia versión de intérprete y librerías sin entrar en conflicto \n", 23 | "\n", 24 | ":::\n", 25 | "\n", 26 | "Esto también nos abstrae de las librerías que están instaladas en nuestro sistema operativo\n", 27 | "\n" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": {}, 33 | "source": [ 34 | "En esta lección veremos dos opciones para administrar ambientes y librerías\n", 35 | "\n", 36 | "- **Opción 1:** Usar Python virtualenv y el manejador de páquetes PIP (Pip Install Packages) para instalar paquetes de [PyPI](https://pypi.org/)\n", 37 | "- **Opción 2:** Usar Conda \n", 38 | "\n", 39 | "Se describirán ambas pero se recomienda usar **conda** por ser más versatil " 40 | ] 41 | }, 42 | { 43 | "cell_type": "markdown", 44 | "metadata": {}, 45 | "source": [ 46 | "## Python virtualenv + PIP\n", 47 | "\n", 48 | "Para esta opción se requiere tener un intérprete de Python instalado y el paquete *virtualenv*\n", 49 | "\n", 50 | "Para crear un ambiente llamado `foo` en nuestro directorio actual abrimos un terminal y escribimos\n", 51 | " \n", 52 | " virtualenv foo\n", 53 | " \n", 54 | "Para activar el ambiente `foo`\n", 55 | "\n", 56 | " source foo/bin/activate\n", 57 | " \n", 58 | "Con el ambiente activado podemos instalar paquetes usando PIP.\n", 59 | "\n", 60 | "Ejemplo: Instalar el paquete *numpy* versión 1.17 con\n", 61 | " \n", 62 | " pip install numpy==1.17\n", 63 | "\n", 64 | ":::{note}\n", 65 | "\n", 66 | "Los códigos que ejecutemos dentro de foo usarán la versión de intérprete y librerías que hemos instalado en `foo`\n", 67 | "\n", 68 | ":::\n", 69 | "\n", 70 | "Cuando terminamos de trabajar podemos salir del ambiente usando el comando\n", 71 | " \n", 72 | " deactivate\n", 73 | " \n", 74 | "Algunos comandos útiles de PIP (pip --help)\n", 75 | "\n", 76 | " list, search, install, uninstall, show, ...\n", 77 | " " 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "## Conda\n", 85 | "\n", 86 | "[Conda](https://docs.conda.io/en/latest/) es un manejador de ambientes y paquetes para Python y otros lenguajes\n", 87 | "\n", 88 | "Entre sus ventajas se encuentran:\n", 89 | "\n", 90 | "- [Repositorio oficial con miles de paquetes disponibles](https://repo.anaconda.com/pkgs/) \n", 91 | "- Es multiplataforma (Windows, Mac y Linux)\n", 92 | "- No requiere tener compiladores instalados (conda los instala dentro del ambiente)\n", 93 | "- Se puede acceder a más de un repositorio usando *channels*\n", 94 | "- Puede usarse para manejar ambientes de Python, R, Ruby, Lua, Scala, Java, JavaScript, C/ C++, FORTRAN, etc\n", 95 | "\n", 96 | "Conda viene en dos sabores llamados *distribuciones*\n", 97 | "\n", 98 | "- Anaconda: conda + Python + cientos de paquetes y herramientas preinstalados\n", 99 | "- Miniconda: conda + Python\n", 100 | "\n", 101 | ":::{hint}\n", 102 | "\n", 103 | "Sugiero miniconda para tener más control e instalar lo que en realidad necesitaremos\n", 104 | "\n", 105 | ":::\n" 106 | ] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "Para instalar miniconda descarga la versión de 64bits (y Python 3) correspondiente a tu [sistema operativo](https://docs.conda.io/en/latest/miniconda.html)\n", 113 | "\n", 114 | "Luego\n", 115 | "\n", 116 | "- Para instalar en Windows corre el ejecutable \n", 117 | "- Para instalar en Linux abre un terminal y escribe el siguiente comando: `sh Miniconda3-latest-Linux-x86_64.sh`\n", 118 | " \n", 119 | "\n", 120 | " " 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "metadata": {}, 126 | "source": [ 127 | "## Utilizando conda\n", 128 | "\n", 129 | "En lo que sigue se asume la utilización de SO basado en Linux\n", 130 | "\n", 131 | "### Cargar las variables de entorno\n", 132 | "\n", 133 | "Supongamos que miniconda está instalado en el directorio \n", 134 | "\n", 135 | " /home/foo/miniconda3\n", 136 | " \n", 137 | "Primero debemos establecer alguas variables de entorno escribiendo en un terminal\n", 138 | "\n", 139 | " source /home/foo/miniconda3/etc/profile.d/conda.sh\n", 140 | " \n", 141 | "Con las variables de entorno habilitadas podemos usar el comando `conda`\n", 142 | "\n", 143 | ":::{tip}\n", 144 | "\n", 145 | "Dos maneras para que el comando anterior se ejecute automáticamente cada vez que abrimos un terminal:\n", 146 | "\n", 147 | "- Agregar la linea \n", 148 | " \n", 149 | " source /home/foo/miniconda3/etc/profile.d/conda.sh \n", 150 | " al final de tu archivo .bashrc (si usas BASH) o .zshrc (si usas ZSH)\n", 151 | "- Crear un link simbólico\n", 152 | "\n", 153 | " sudo ln -s /home/foo/miniconda3/etc/profile.d/conda.sh /etc/profile.d/conda.sh\n", 154 | "\n", 155 | ":::\n", 156 | "\n", 157 | "### Manejo de ambientes de conda\n", 158 | "\n", 159 | "Podemos listar los ambientes que existen en el equipo\n", 160 | "\n", 161 | " conda env list \n", 162 | " \n", 163 | "Por defecto existirá sólo el ambiente *base*\n", 164 | "\n", 165 | "Para crear un ambiente de conda llamado `bar` \n", 166 | "\n", 167 | " conda create -n bar\n", 168 | " \n", 169 | "Para activar el ambiente llamado `bar`\n", 170 | "\n", 171 | " conda activate bar\n", 172 | " \n", 173 | "Asimismo, podemos desactivar un ambiente con\n", 174 | "\n", 175 | " conda deactivate\n", 176 | " \n", 177 | "Si necesitamos borrar un ambiente llamado `bar` podemos hacerlo con\n", 178 | "\n", 179 | " conda env remove -n bar\n", 180 | " \n", 181 | "### Manejo de paquetes y librerías\n", 182 | " \n", 183 | "(No olvides activar tu ambiente antes de probar los siguientes comandos)\n", 184 | "\n", 185 | "Para buscar un paquete se usa la instrucción *search*, por ejemplo\n", 186 | "\n", 187 | " conda search numpy\n", 188 | " \n", 189 | "Que nos retorna una lista de paquetes con distintas versiones y builds\n", 190 | "\n", 191 | "Podemos instalar una versión en particular usando\n", 192 | "\n", 193 | " conda install numpy=1.16.2=py37_blas_openblash1522bff_0\n", 194 | "\n", 195 | "Para borrar un paquete instalado usamos la instrucción *remove* o *uninstall*\n", 196 | "\n", 197 | " conda remove numpy \n", 198 | " \n", 199 | "\n", 200 | "Para hacer una lista de todos los paquetes instalados en el ambiente se utiliza\n", 201 | "\n", 202 | " conda list\n", 203 | " \n", 204 | "Finalmente podemos actualizar nuestro ambiente con instrucción *update* o *upgrade*\n", 205 | "\n", 206 | " conda update --all\n", 207 | " " 208 | ] 209 | }, 210 | { 211 | "cell_type": "markdown", 212 | "metadata": {}, 213 | "source": [ 214 | "### Manejo de canales \n", 215 | "\n", 216 | "Para ver los canales que tenemos configurados podemos usar\n", 217 | "\n", 218 | " conda config --show channel\n", 219 | "\n", 220 | ":::{note}\n", 221 | "\n", 222 | "Cada repositorio de conda tiene un canal\n", 223 | "\n", 224 | ":::\n", 225 | "\n", 226 | "El orden en que aparecen corresponde a su prioridad\n", 227 | "\n", 228 | ":::{hint}\n", 229 | "\n", 230 | "Un repositorio muy completo y útil es [conda-forge](https://conda-forge.org/)\n", 231 | "\n", 232 | ":::\n", 233 | "\n", 234 | "Para agregar *conda-forge* con prioridad mínima usamos\n", 235 | "\n", 236 | " conda config --append channels conda-forge\n", 237 | " \n", 238 | "Esto quiere decir que primero se busca el paquete en el canal default y si no se encuentra se busca en *conda-forge*\n", 239 | " \n", 240 | "Para agregarlo con prioridad máxima usamos\n", 241 | "\n", 242 | " conda config --add channels conda-forge\n", 243 | " \n", 244 | "Más detalles de [administración de canales en la documentación de conda](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-channels.html)\n" 245 | ] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "metadata": {}, 250 | "source": [ 251 | "### Más sobre ambientes \n", 252 | " \n", 253 | "Podemos crear un nuevo ambiente `bar` que es un clon de un ambiente `foo` con\n", 254 | "\n", 255 | " conda create --name bar --clone foo\n", 256 | " \n", 257 | "Si queremos compartir un ambiente llamado `foo`, podemos exportar sus contenidos a formato `yaml` con \n", 258 | " \n", 259 | " conda activate foo\n", 260 | " conda env export > environment.yml\n", 261 | " \n", 262 | "Luego podemos compartir el archivo environment.yml y otra usuario con conda puede reconstruir `foo` usando\n", 263 | "\n", 264 | " conda env create -f environment.yml \n", 265 | " \n", 266 | "Más detalles de [administración de ambientes en la documentación de conda](https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html)" 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": null, 272 | "metadata": {}, 273 | "outputs": [], 274 | "source": [] 275 | } 276 | ], 277 | "metadata": { 278 | "kernelspec": { 279 | "display_name": "Python 3 (ipykernel)", 280 | "language": "python", 281 | "name": "python3" 282 | }, 283 | "language_info": { 284 | "codemirror_mode": { 285 | "name": "ipython", 286 | "version": 3 287 | }, 288 | "file_extension": ".py", 289 | "mimetype": "text/x-python", 290 | "name": "python", 291 | "nbconvert_exporter": "python", 292 | "pygments_lexer": "ipython3", 293 | "version": "3.8.12" 294 | } 295 | }, 296 | "nbformat": 4, 297 | "nbformat_minor": 4 298 | } 299 | -------------------------------------------------------------------------------- /contents/preliminaries/git.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Control de versiones" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | ":::{epigraph}\n", 15 | "\n", 16 | "-- Alguien que no sabe manejo de versiones trabajando en su tesis\n", 17 | ":::" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "## Manejo de versiones en proyectos de software\n", 25 | "\n", 26 | "\n", 27 | "Los proyectos de software no son estáticos, se agregan, modifican y eliminan funcionalidades continuamente. Lo anterior puede estar motivado por cambios en los requerimientos, cambios en las librerías que utilizamos o cambios en el hardware donde correrá nuestra aplicación.\n", 28 | "\n", 29 | "Los manejadores de versiones mantienen un **historial de los cambios** o modificaciones que hagamos en nuestro proyecto. En general estos cambios irán acompañados con un (1) Mensaje que explica el cambio y con el (2) Nombre del autor del cambio.\n", 30 | "\n", 31 | ":::{important}\n", 32 | "\n", 33 | "Con el historial de cambios podemos devolver nuestro proyecto a estados anteriores. Por ejemplo, si nos enfrentamos a un *bug* en nuestro programa, podemos explorar cual fue el cambio que introdujo el *bug*.\n", 34 | "\n", 35 | ":::\n", 36 | "\n", 37 | "Los manejadores de versiones permiten coordinar versiones paralelas de nuestro proyecto. Estas versiones paralelas se llaman **ramas**. \n", 38 | "\n", 39 | ":::{important}\n", 40 | "\n", 41 | "Utilizando ramas podemos probar nuevas funcionalidades o features sin afectar la aplicación de cara al usuario (rama principal). También las ramas facilitan la colaboración y el trabajo sincronizado cuando varios desarrolladores trabajan en un mismo proyecto\n", 42 | "\n", 43 | ":::\n", 44 | "\n", 45 | "Una vez que la funcionalidad en la rama está solidamente probada está puede fusionarse (*merge*) con la rama principal\n", 46 | "\n", 47 | "\n", 48 | "**En resumen el control de versiones**\n", 49 | "\n", 50 | "- hace que nuestros proyectos sean más fáciles de mantener\n", 51 | "- facilita la colaboración entre desarrolladores\n", 52 | "- le da trazabilidad a nuestros proyectos\n", 53 | "- hace que nuestros resultados sean más fáciles de reproducir\n" 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "## Git\n", 61 | "\n", 62 | "En esta lección vamos a aprender a usar el controlador de versiones [Git](https://git-scm.com/), un sistema libre y gratis de **manejo de versiones distribuido**\n", 63 | "\n", 64 | "Distribuido se refiere a que no es necesario que una unidad central mantega el código del proyecto. Todos los que participan del proyecto tienen **copias locales completas** de la historia del proyecto. \n", 65 | "\n", 66 | "¿Cuáles son las ventajas de Git?\n", 67 | "\n", 68 | "- [Ligero y rápido en comparación a sus competidores](https://git-scm.com/about/small-and-fast)\n", 69 | "- Flexible: Soporta flujos de trabajo muy diversos \n", 70 | "- Gran grado de adopción: Integrado en IDE y plataformas remotas\n", 71 | "\n", 72 | "¿Qué otros manejadores de versiones existen?\n", 73 | "\n", 74 | "- Distribuidos: Mercurial\n", 75 | "- Centralizados: Subversion (SVN)\n" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": {}, 81 | "source": [ 82 | "### Instalación y configuración inicial de Git\n", 83 | "\n", 84 | "En **linux** git está disponible en los repositorios oficiales de cada distribución\n", 85 | "\n", 86 | "- Ubuntu: `sudo apt install git`\n", 87 | "- Fedora: `sudo yum install git`\n", 88 | "- Arch Linux: `sudo pacman -S git`\n", 89 | "\n", 90 | "En **Windows** recomiendo descargar e instalar [Git BASH](https://gitforwindows.org/)\n", 91 | "\n", 92 | "\n", 93 | "**Configuración básica**\n", 94 | "\n", 95 | "Define tu nombre y correo. Con estos datos se firmarán los cambios que agregues al repositorio\n", 96 | "\n", 97 | " git config --global user.name \"Tu nombre aquí\"\n", 98 | "\n", 99 | " git config --global user.email \"tu_email_aquí@example.com\"\n", 100 | " \n", 101 | "Selecciona el nombre de la rama inicial de tu repositorio \n", 102 | " \n", 103 | " git config --global init.defaultBranch main\n", 104 | "\n", 105 | "Selecciona el editor de texto que usará git por defecto (vim, emacs, nano, etc) \n", 106 | "\n", 107 | " git config --global core.editor \n", 108 | " \n", 109 | "Configura git para que utilice colores\n", 110 | "\n", 111 | " git config --global color.ui true\n", 112 | " \n", 113 | "Puedes revisar las opciones que haz configurado con\n", 114 | "\n", 115 | " git config --global --list\n" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": {}, 121 | "source": [ 122 | "## Estructura y flujo de trabajo de un repositorio git\n", 123 | "\n", 124 | "La siguiente [figura](https://www.diegocmartin.com/tutorial-git/) resume muy bien el flujo de trabajo con Git\n", 125 | "\n", 126 | "\n" 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "A continuación se explican los términos del diagrama\n", 134 | "\n", 135 | "Commit\n", 136 | ": Es un conjunto de modificaciones en el código que hemos firmado para incluirlas a la historia del proyecto\n", 137 | "\n", 138 | "Repositorio local (HEAD)\n", 139 | ": Es donde se guarda la historia del proyecto con todos sus *commits*\n", 140 | "\n", 141 | "Workspace o Working directory\n", 142 | ": Es donde se guardan las modificaciones que se están realizando actualmente\n", 143 | "\n", 144 | "Index, Stage o Staging area\n", 145 | ": Es donde se guardan las modificaciones que se desean agregar en el próximo commit. \n", 146 | "\n", 147 | "Repositorio remoto (remote)\n", 148 | ": Es un copia del repositorio que está en otro computador o en la nube (por ejemplo en github)\n", 149 | "\n", 150 | "Un archivo dentro del proyecto puede estar en uno de los siguientes tres estados\n", 151 | "\n", 152 | "Untracked\n", 153 | ": Archivo creado o modificado que no es parte de la historia\n", 154 | "\n", 155 | "Unstaged \n", 156 | ": Archivo modificado que es parte de la historia pero que no está en la *staging area*\n", 157 | "\n", 158 | "Staged\n", 159 | ": Archivo modificado que es parte de la historia y que ha sido incluido al próximo commit\n", 160 | "\n", 161 | "A continuación se muestra como utilizar los comandos de git para realizar las siguientes operaciones\n", 162 | "\n", 163 | "1. Creación de proyectos (repositorios)\n", 164 | "1. Agregar cambios al proyecto\n", 165 | "1. Verificar cambios\n", 166 | "1. Deshacer cambios\n", 167 | "1. Crear y seleccionar ramas" 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": {}, 173 | "source": [ 174 | "### Creación de repositorios\n", 175 | "\n", 176 | "Para crear un proyecto vacio cuya historia está manejada por git creamos una nuevo directorio\n", 177 | "\n", 178 | " mkdir mi_proyecto_nuevo\n", 179 | " cd mi_proyecto_nuevo\n", 180 | " \n", 181 | "y luego usamos el comando\n", 182 | "\n", 183 | " git init\n", 184 | " \n", 185 | "Esto creará un directorio oculto llamado `.git` que mantiene la configuración e historia del repositorio.\n", 186 | "\n", 187 | "También podemos crear un proyecto a partir de un repositorio local con \n", 188 | "\n", 189 | " git clone /path/a/mi/otro/proyecto\n", 190 | " \n", 191 | "O a partir de un repositorio remoto con\n", 192 | "\n", 193 | " git clone usuario@servidor:/path/a/otro/proyecto\n", 194 | " \n", 195 | "Más adelante veremos como se combina esta opción con la plataforma `github`" 196 | ] 197 | }, 198 | { 199 | "cell_type": "markdown", 200 | "metadata": {}, 201 | "source": [ 202 | "### Agregar cambios al repositorio\n", 203 | "\n", 204 | "Si queremos *trackear* o añadir un archivo modificado al área de *stage* utilizamos el comando\n", 205 | "\n", 206 | " git add nombre_de_archivo_cambiado\n", 207 | " \n", 208 | "Si quiero añadir todos los archivos del directorio actual al *staging area* se puede utilizar (con cautela)\n", 209 | "\n", 210 | " git add .\n", 211 | " \n", 212 | "Una vez que hemos terminado de agregar los archivos modificados que deseamos se crea un commit en el repositorio con\n", 213 | "\n", 214 | " git commit -m \"Un mensaje que explica el cambio y por qué fue necesario\"\n", 215 | " \n", 216 | " \n", 217 | ":::{hint}\n", 218 | "\n", 219 | "Escribe buenos mensajes. Esto hará más fácil explorar la historia para ti y para otros desarrolladores\n", 220 | "\n", 221 | ":::\n", 222 | "\n", 223 | "Si queremos modificar el mensaje del último commit podemos utilizar\n", 224 | "\n", 225 | " git commit --amend\n", 226 | " \n", 227 | " \n", 228 | "### Verificando y analizando cambios\n", 229 | " \n", 230 | "Si tenemos un archivo modificado en el workspace podemos compararlo contra su último commit utilizando\n", 231 | "\n", 232 | " git diff nombre_de_archivo\n", 233 | " \n", 234 | "Este comando mostrará resaltadas las lineas que fueron modificadas, agregadas o eliminadas\n", 235 | "\n", 236 | "Si queremos verificar el estado de los archivos del directorio de trabajo utilizamos\n", 237 | "\n", 238 | " git status\n", 239 | " \n", 240 | "Este comando retorna una lista con los archivos indicando si están untracked, unstaged o staged\n", 241 | "\n", 242 | "\n", 243 | "Finalmente si queremos buscar un commit en particular podemos utilizar\n", 244 | "\n", 245 | " git log\n", 246 | " \n", 247 | "Este comando retorna una lista con los commits realizados hasta ahora (nombres de usuario y mensajes)\n", 248 | "\n", 249 | "Pueden agregarse las opciones\n", 250 | "\n", 251 | "- `--author=nombreusuario` muestra sólo los commits de un usuario particular\n", 252 | "- `--stat` muestra solo los archivos cambiaron\n", 253 | "- `--patch` muestra además las líneas agregadas/eliminadas" 254 | ] 255 | }, 256 | { 257 | "cell_type": "markdown", 258 | "metadata": {}, 259 | "source": [ 260 | "### Deshacer cambios\n", 261 | "\n", 262 | "Para descartar los cambios locales que se han realizado a un archivo utilizamos\n", 263 | "\n", 264 | " git checkout -- nombre_de_archivo_cambiado\n", 265 | " \n", 266 | "Esto copia el archivo desde la zona de stage al directorio de trabajo\n", 267 | " \n", 268 | "Para sacar un archivo modificado del próximo commit/cambio utilizamos\n", 269 | "\n", 270 | " git reset nombre_de_archivo_cambiado\n", 271 | " \n", 272 | ":::{danger}\n", 273 | "\n", 274 | "(Usar con cautela) Para descartar todos los cambios y devolver el proyecto completo al último commit\n", 275 | "\n", 276 | " git reset --hard\n", 277 | " \n", 278 | ":::\n", 279 | " \n", 280 | "Para eliminar un archivo del repositorio\n", 281 | "\n", 282 | " git rm --cached nombre_archivo\n", 283 | " \n", 284 | ":::{note}\n", 285 | "\n", 286 | "Con la opción `--cached` el archivo permanece en el disco duro, es decir que sólo se elimina del índice del repositorio\n", 287 | "\n", 288 | ":::\n", 289 | "\n", 290 | "Podemos forzar que git ignore los cambios de un archivo en particular agregando su nombre o ruta en un archivo de texto plano llamado `.gitignore`. Puedes tener varios `.gitignore` dentro de tu repositorio.\n", 291 | "\n", 292 | ":::{hint}\n", 293 | "\n", 294 | "Agrega a `.gitignore` código compilado, archivos binarios pesados o archivos de configuración que contengan información privada (claves/tokens de acceso)\n", 295 | "\n", 296 | ":::" 297 | ] 298 | }, 299 | { 300 | "cell_type": "markdown", 301 | "metadata": {}, 302 | "source": [ 303 | "### Creación y manejo de ramas/branches\n", 304 | "\n", 305 | "Las ramas son muy útiles cuando queremos desarrollar nuevas funcionalidades en base al estado actual del repositorio. Además son particularmente importantes cuando trabajamos en grupo\n", 306 | "\n", 307 | "Para mostrar las ramas que existen en el repositorio\n", 308 | "\n", 309 | " git branch -a\n", 310 | " \n", 311 | "Por defecto tenemos sólo una rama: `main`\n", 312 | " \n", 313 | "Para crear una rama nueva\n", 314 | "\n", 315 | " git branch \"nombre_nueva_rama\"\n", 316 | " \n", 317 | "Puedo cambiar entre ramas\n", 318 | "\n", 319 | " git checkout \"nombre_nueva_rama\"\n", 320 | " \n", 321 | "Para volver a la rama `main`\n", 322 | " \n", 323 | " git checkout main\n", 324 | " \n", 325 | "\n", 326 | "La siguiente figura muestra un ejemplo de trabajo utilizando ramas:\n", 327 | "\n", 328 | "\n", 329 | "\n", 330 | "[Figura tomada de GitFlow](https://github.com/doapps/software/wiki/Gitflow)" 331 | ] 332 | }, 333 | { 334 | "cell_type": "markdown", 335 | "metadata": {}, 336 | "source": [ 337 | "## Trabajando con un repositorio remoto\n", 338 | "\n", 339 | "Los repositorios remotos son versiones de tu proyecto que están almacenados en Internet. Cuando trabajamos en grupo un repositorio remoto permite que todos estén de acuerdo en una versión de la historia\n", 340 | "\n", 341 | "Existen proveedores de hosting para proyectos administrados con Git, los más famosos son [GitHub](http://www.github.com) y [GitLab](https://about.gitlab.com/)\n", 342 | "\n", 343 | "A continuación usaremos GitHub para almancenar una versión remota de nuestro repositorio\n", 344 | "\n", 345 | "**Crearse una cuenta en GitHub**\n", 346 | "\n", 347 | "- Visita el sitio web: https://github.com/join\n", 348 | "- Crea una cuenta (es gratis)\n", 349 | "\n", 350 | "\n", 351 | "**Creando un repositorio en GitHub**\n", 352 | "\n", 353 | "En el sitio web de GitHub, una vez que estés logeado en tu cuenta\n", 354 | "\n", 355 | "- Haz click en el signo + en la esquina superior derecha\n", 356 | "- Selecciona \"New repository\"\n", 357 | "- Escoge un nombre y una descripción\n", 358 | "- Escoge repositorio público\n", 359 | "- (Opcional) Puedes inicializar el repositorio con un archivo `README` y un archivo `.gitignore`\n", 360 | "- Selecciona Create Repository\n" 361 | ] 362 | }, 363 | { 364 | "cell_type": "markdown", 365 | "metadata": {}, 366 | "source": [ 367 | "### Clonando un repositorio remoto de GitHub a mi computador\n", 368 | "\n", 369 | "- Accede al repositorio\n", 370 | "- Selecciona el botón verde: \"Clone or download\"\n", 371 | "- Copia la dirección del repositorio\n", 372 | "- Escribe el comando\n", 373 | "\n", 374 | " git clone https://github.com/nombre_de_usuario/nombre_de_repositorio.git\n", 375 | " \n", 376 | "Esto creará una carpeta llamada \"nombre_de_repositorio\" en el directorio local" 377 | ] 378 | }, 379 | { 380 | "cell_type": "markdown", 381 | "metadata": {}, 382 | "source": [ 383 | "### Enviando commits desde el repositorio local al remoto\n", 384 | "\n", 385 | "Luego de añadir archivos y hacer un commit podemos \"empujar los cambios\" a GitHub usando\n", 386 | "\n", 387 | " git push\n", 388 | " \n", 389 | "Cada vez que hagamos un push se nos pedirán nuestras credenciales. \n", 390 | "\n", 391 | ":::{tip}\n", 392 | "\n", 393 | "Para evitar escribir nuestra clave muchas veces podemos usar \n", 394 | "\n", 395 | " git config credential.helper 'cache --timeout=3600'\n", 396 | " \n", 397 | "Esto configura git para que no pida las credenciales hasta que haya pasado 1 hora \n", 398 | "\n", 399 | ":::\n", 400 | " \n", 401 | "En general no podemos hacer un push en un repositorio que no es nuestro o donde no somos colaboradores. Para aportar un cambio a un repositorio que no administramos debemos hacer un `pull request`\n" 402 | ] 403 | }, 404 | { 405 | "cell_type": "markdown", 406 | "metadata": {}, 407 | "source": [ 408 | "### Trayendo cambios desde el repositorio remoto al local\n", 409 | "\n", 410 | "Para actualizar nuestro repositorio local al último commit del repositorio remoto utilizamos\n", 411 | "\n", 412 | " git pull\n", 413 | " \n", 414 | "La operación anterior corresponde a dos operaciones juntas\n", 415 | "\n", 416 | " git fetch\n", 417 | " \n", 418 | "que trae al repositorio local los cambios del repositorio remoto y \n", 419 | "\n", 420 | " git merge\n", 421 | " \n", 422 | "que trae al directorio de trabajo los contenidos del repositorio local\n", 423 | "\n", 424 | "- Si estamos trabajando sólos y desde un solo directorio de trabajo estos comandos no deberían resultar en error\n", 425 | "- Si estamos trabajando usando varios directorios de trabajo o en grupo puede ocurrir que `git merge` encuentre **conflictos** que deberemos resolver\n", 426 | "\n", 427 | "Para ver los cambios luego de hacer `fetch` y antes de hacer un `merge` podemos usar\n", 428 | "\n", 429 | " git diff origin/master\n", 430 | " " 431 | ] 432 | }, 433 | { 434 | "cell_type": "markdown", 435 | "metadata": {}, 436 | "source": [ 437 | "### Resolviendo conflictos\n", 438 | "\n", 439 | "Digamos que dos personas están trabajando en un mismo proyecto y tienen una copia local hasta el último *commit*\n", 440 | "\n", 441 | "- La primera persona hace modificaciones y las empuja al repositorio\n", 442 | " - Esto funciona ok\n", 443 | "- La segunda persona hace modificaciones y las empuja al repositorio\n", 444 | " - Esto podría no funcionar ya que pueden haber conflictos con lo que se empujó anteriormente\n", 445 | " \n", 446 | "Lo que debe hacer la segunda persona es\n", 447 | "\n", 448 | "- Hacer un pull del repositorio con `git pull`\n", 449 | "- Git detectará los conflictos y se mostrarán como\n", 450 | "\n", 451 | " <<<<< HEAD \n", 452 | " Esto lo escribio persona 2 y no está en el commit de persona 1\n", 453 | " ========\n", 454 | " Esto lo escribio persona 1 y no estába en el directorio de persona 2\n", 455 | " >>>>> origin/master\n", 456 | " \n", 457 | "- Persona 2 tiene que decidir que se queda y que se va\n", 458 | "\n", 459 | "La siguiente figura muestra el resultado de un merge en el histórico de commits\n", 460 | "\n", 461 | "\n", 462 | "\n", 463 | "[Figura tomada del tutorial de Attlasian](https://www.atlassian.com/es/git/tutorials/comparing-workflows)" 464 | ] 465 | }, 466 | { 467 | "cell_type": "markdown", 468 | "metadata": {}, 469 | "source": [ 470 | "## Recursos extra\n", 471 | "\n", 472 | "Para estudiar más a fondo sobre Git recomiendo\n", 473 | "\n", 474 | "1. Muy completo tutorial de [Git de Atlassian](https://www.atlassian.com/es/git/tutorials)\n", 475 | "1. Clases 2 y 3 del curso [CS207 del IACS, Harvard](https://harvard-iacs.github.io/2019-CS207/category/lectures.html)\n", 476 | "1. Libro [Pro Git](https://git-scm.com/book/en/v2/) (libre)\n", 477 | "1. [Como agregar un proyecto local a github](https://help.github.com/es/github/importing-your-projects-to-github/adding-an-existing-project-to-github-using-the-command-line)" 478 | ] 479 | }, 480 | { 481 | "cell_type": "code", 482 | "execution_count": null, 483 | "metadata": {}, 484 | "outputs": [], 485 | "source": [] 486 | } 487 | ], 488 | "metadata": { 489 | "kernelspec": { 490 | "display_name": "Python 3 (ipykernel)", 491 | "language": "python", 492 | "name": "python3" 493 | }, 494 | "language_info": { 495 | "codemirror_mode": { 496 | "name": "ipython", 497 | "version": 3 498 | }, 499 | "file_extension": ".py", 500 | "mimetype": "text/x-python", 501 | "name": "python", 502 | "nbconvert_exporter": "python", 503 | "pygments_lexer": "ipython3", 504 | "version": "3.8.12" 505 | } 506 | }, 507 | "nbformat": 4, 508 | "nbformat_minor": 2 509 | } 510 | -------------------------------------------------------------------------------- /contents/preliminaries/img/debug1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/preliminaries/img/debug1.png -------------------------------------------------------------------------------- /contents/preliminaries/img/debug2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/preliminaries/img/debug2.png -------------------------------------------------------------------------------- /contents/preliminaries/img/git-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/preliminaries/img/git-workflow.png -------------------------------------------------------------------------------- /contents/preliminaries/img/git-workflow2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /contents/preliminaries/img/git-workflow3.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /contents/preliminaries/intro.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Computación científica y ciencia de datos" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "*Ciencia: Scientia: Conocimiento*\n" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Los paradigmas de la ciencia:\n", 22 | "\n", 23 | "\n", 24 | "\n", 25 | "- El primer paradigma es basado en observación y experimentación\n", 26 | "- El segundo paradigma agregó es el teórico, se basa en probar modelos y refutar hipótesis\n", 27 | "- El tercer paradigma es basado en simulaciones: Probamos modelos y análisamos fenómenos utilizando simulaciones computacionales\n", 28 | "- El [cuarto paradigma](https://en.wikipedia.org/wiki/The_Fourth_Paradigm) es basado en los datos: Entender fenómenos en base a datos masivos generados por sensores o simulaciones" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "## Tercer paradigma: Computación Científica\n", 36 | "\n", 37 | "Hoy en día muchos trabajos científicos e ingenieriles incluyen al menos uno de los siguientes aspectos\n", 38 | "- cálculos numéricos\n", 39 | "- simulaciones\n", 40 | "- modelamiento computacional\n", 41 | "- análisis de datos\n", 42 | "\n", 43 | "En resumen\n", 44 | "\n", 45 | "> El computador se ha vuelto esencial para hacer ciencia\n", 46 | "\n", 47 | "y por ende\n", 48 | "\n", 49 | "> El software se ha vuelto esencial para hacer ciencia\n", 50 | "\n", 51 | "En este escenario surge\n", 52 | "\n", 53 | "> La **computación científica** es la disciplina que se encarga de desarrollar la teoría y las técnicas necesarias para resolver problemas matemáticos complejos de ciencias e ingeniería de forma eficiente\n", 54 | "\n", 55 | "**Ejemplo:** Simulación de la unión de dos agujeros negros utilizando datos de LIGO\n", 56 | "\n", 57 | "\n" 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "## Cuarto paradigma: Ciencia de los Datos\n", 65 | "\n", 66 | "Los avances tecnológicos han permitido la generación y captura de una enorme cantidad de datos\n", 67 | "\n", 68 | "Considere por ejemplo las Redes Sociales, el Internet de las Cosas (IoT) o los proyectos smart-city\n", 69 | "\n", 70 | "Esto también ocurre en las ciencias\n", 71 | "\n", 72 | "- Simulaciones con cada vez mayor nivel de resolución\n", 73 | "- Telescopios que cubren mayores áreas del cielo y con mayor profundidad\n", 74 | "- Digitalización de exámenes médicos\n", 75 | "\n", 76 | "El término [*Big Data*](https://www.ibmbigdatahub.com/infographic/four-vs-big-data) se ocupa para describir el escenario tecnológico actual respecto a la abundancia, altas tasas de generación y variedad de datos \n", 77 | "\n", 78 | "En este escenario surge:\n", 79 | "\n", 80 | "> La **ciencia de datos** es la disciplina que busca extraer conocimiento (información) a partir de datos (masivos)\n", 81 | "\n", 82 | "**Ejemplo:** [Super-resolución en imágenes astronómicas usando modelo adversario generativo entrenado en datos de SDSS](https://academic.oup.com/mnrasl/article/467/1/L110/2931732)\n", 83 | "\n", 84 | "\n", 85 | "" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "**Competencias**\n", 93 | "\n", 94 | "La computación científica y la ciencia de los datos combinan competencias de \n", 95 | "\n", 96 | "- Ciencias de la computación: Diseñar algoritmos eficientes y escalables para procesar grandes bases de datos \n", 97 | "- Matemáticas aplicadas y estadística: Diseñar modelos que caractericen y resuman los datos\n", 98 | "\n", 99 | "**Interdiscipina**\n", 100 | "\n", 101 | "La computación científica y la ciencia de los datos son paradigmas naturalmente **interdisciplinares**\n", 102 | "\n", 103 | "> Se debe colaborar con expertos del dominio para formular preguntas científicas e intepretar los resultados de nuestros rutinas computacionales\n", 104 | "\n", 105 | "**Reproducibilidad**\n", 106 | "\n", 107 | "> Un buen software científico debe permitir la replicación y reproducibilidad de los resultados de los experimentos\n" 108 | ] 109 | }, 110 | { 111 | "cell_type": "markdown", 112 | "metadata": {}, 113 | "source": [ 114 | "## ¿Qué podemos esperar de este curso?\n", 115 | "\n", 116 | "En este curso aprenderemos a manejar librerías de computación científica basadas en el lenguaje de programación **Python** " 117 | ] 118 | }, 119 | { 120 | "cell_type": "markdown", 121 | "metadata": {}, 122 | "source": [ 123 | "## ¿Qué es Python?\n", 124 | "\n", 125 | "Python es un lenguaje de programación interpretado y multi-paradigma liberado en 1991 y ampliamente usado en ciencia de los datos \n", 126 | "\n", 127 | "¿Por qué?\n", 128 | "\n", 129 | "- Enfoque en la simpleza, lo cual resulta en código más fácil de mantener y desarrollos más rápidos\n", 130 | "- Rico ecosistema de librerías abiertas para computo científico: [*Numpy*](http://www.numpy.org/), [*Scipy*](https://www.scipy.org/), [*Pandas*](https://pandas.pydata.org/), entre otras que serán estudiadas en este curso\n", 131 | "\n", 132 | "¿Y que hay del desempeño de mis algoritmos versus lenguajes de programación de más bajo nivel? \n", 133 | "\n", 134 | "1. Trade-off entre tiempo de cómputo y horas hombre de programación\n", 135 | "1. Librerías de cómputo científico de Python: Están compiladas con librerías optimizadas de bajo nivel (*e.g.* BLAS, LAPACK)\n", 136 | "1. Si la función que necesito no está en las librerías: Integrar Python con lenguajes de bajo nivel (*e.g.* C++, Fortran)" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "metadata": {}, 143 | "outputs": [], 144 | "source": [] 145 | } 146 | ], 147 | "metadata": { 148 | "kernelspec": { 149 | "display_name": "Python 3 (ipykernel)", 150 | "language": "python", 151 | "name": "python3" 152 | }, 153 | "language_info": { 154 | "codemirror_mode": { 155 | "name": "ipython", 156 | "version": 3 157 | }, 158 | "file_extension": ".py", 159 | "mimetype": "text/x-python", 160 | "name": "python", 161 | "nbconvert_exporter": "python", 162 | "pygments_lexer": "ipython3", 163 | "version": "3.10.9" 164 | } 165 | }, 166 | "nbformat": 4, 167 | "nbformat_minor": 2 168 | } 169 | -------------------------------------------------------------------------------- /contents/sklearn/img/conf-matrix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/sklearn/img/conf-matrix.png -------------------------------------------------------------------------------- /contents/sklearn/img/intro-ml1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/sklearn/img/intro-ml1.png -------------------------------------------------------------------------------- /contents/sklearn/img/intro-ml2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/sklearn/img/intro-ml2.png -------------------------------------------------------------------------------- /contents/sklearn/img/intro-ml4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/sklearn/img/intro-ml4.png -------------------------------------------------------------------------------- /contents/sklearn/img/kmeans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/sklearn/img/kmeans.png -------------------------------------------------------------------------------- /contents/sklearn/intro.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Machine Learning: Conceptos clave" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "## ¿Qué es Machine Learning?" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "Podemos definir *Machine Learning* o Aprendizaje de Máquinas como:\n", 22 | "\n", 23 | "> El estudio de **sistemas** que aprenden reglas o patrones en base a **ejemplos** para resolver una tarea\n", 24 | "\n", 25 | "En este contexto con \"ejemplos\" nos referimos a:\n", 26 | "\n", 27 | "> Datos asociados a la tarea que se quiere resolver\n", 28 | "\n", 29 | "Mientras que sistema (o máquina) correspondería a:\n", 30 | "\n", 31 | "> Algoritmo o modelo matemático que mejora su desempeño entrenándose con los ejemplos\n", 32 | "\n", 33 | "El esquema conceptual general de ML se muestra en la siguiente figura\n", 34 | "\n", 35 | "" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "donde:\n", 43 | "\n", 44 | "1. Conceptualización: Se refiere a identificar el problema\n", 45 | "1. Datos: Se refiere a la recolección, importación, pre-precesamiento y etiquetado de datos\n", 46 | "1. Modelamiento: Se referiere a la selección, entrenamiento y validación del o los modelos\n", 47 | "1. Inferencia: Se refiere a utilizar el modelo para tomar decisiones sobre ejemplos nuevos\n", 48 | "\n", 49 | "En este último punto yace el objetivo principal de Machine Learning (ML).\n", 50 | "\n", 51 | ":::{important}\n", 52 | "\n", 53 | "Entrenamos modelos para clasificar/predecir/agrupar ejemplos que el modelo no ha visto aun. Un modelo que realiza inferencias correctas en ejemplos nuevos es un modelo que ha logrado **generalizar lo aprendido**.\n", 54 | "\n", 55 | ":::\n", 56 | "\n", 57 | "Para que el modelo sea capaz de aprender y generalizar ML combina técnicas de estadísticas y optimización computacional." 58 | ] 59 | }, 60 | { 61 | "cell_type": "markdown", 62 | "metadata": {}, 63 | "source": [ 64 | "## Taxonomía de algoritmos de Machine Learning\n", 65 | "\n", 66 | "Podemos hacer una clasificación gruesa de los algoritmos y modelos de ML en base a las tareas que buscan resolver. \n", 67 | "\n", 68 | "La siguiente figura esquematiza las cuatro tareas más típicas que se resuelven usando ML\n", 69 | "\n", 70 | "\n", 71 | "\n", 72 | "En la figura podemos distinguir cuatro tipos de tareas agrupadas bajo dos paradigmas: Aprendizaje supervisado y Aprendizaje no supervisado.\n", 73 | "\n", 74 | "- Los modelos de aprendizaje no supervisado buscan revelar estructura en los datos sin utilizar **etiquetas**. Por ejemplo estos métodos pueden usarse para encontrar grupos de similitud, jerarquías entre las variables o nuevas representaciones y visualizaciones de los datos. \n", 75 | "- Los modelos de aprendizaje supervisado buscan aprender una función que prediga un objetivo (categórico, discreto o continuo) en base a los datos. En la jerga de ML este objetivo usualmente se denomina **etiqueta** y debe entregarse al modelo durante su entrenamiento. \n" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": {}, 81 | "source": [ 82 | "## Librería scikit-learn\n", 83 | "\n", 84 | "En este capítulo se utilizan métodos de machine learning implementados en la librería de Python [scikit-learn](https://scikit-learn.org). En particular se revisarán:\n", 85 | "\n", 86 | "- Modelos para hacer proyección y reducción de dimensionalidad: [`sklearn.decomposition`](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.decomposition)\n", 87 | "- Modelos para hacer agrupamiento: [`sklearn.cluster`](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.cluster)\n", 88 | "- Modelos para clasificación: [`sklearn.naive`](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.naive_bayes) \n", 89 | "- Funciones para evaluar el desempeño de clasificadores: [`sklearn.metrics`](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.metrics)\n", 90 | "- Funciones para hacer selección de modelos: [`sklearn.model_selection`](https://scikit-learn.org/stable/modules/classes.html#module-sklearn.model_selection)\n", 91 | "\n", 92 | " \n", 93 | ":::{seealso}\n", 94 | "\n", 95 | "Para un tratamiento más profundo sobre métodos de aprendizaje supervisado sugiero revisar [el siguiente material](https://phuijse.github.io/MachineLearningBook/README.html).\n", 96 | "\n", 97 | ":::" 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [] 106 | } 107 | ], 108 | "metadata": { 109 | "kernelspec": { 110 | "display_name": "Python 3 (ipykernel)", 111 | "language": "python", 112 | "name": "python3" 113 | }, 114 | "language_info": { 115 | "codemirror_mode": { 116 | "name": "ipython", 117 | "version": 3 118 | }, 119 | "file_extension": ".py", 120 | "mimetype": "text/x-python", 121 | "name": "python", 122 | "nbconvert_exporter": "python", 123 | "pygments_lexer": "ipython3", 124 | "version": "3.9.16" 125 | }, 126 | "toc": { 127 | "base_numbering": 1, 128 | "nav_menu": {}, 129 | "number_sections": true, 130 | "sideBar": true, 131 | "skip_h1_title": false, 132 | "title_cell": "Table of Contents", 133 | "title_sidebar": "Contents", 134 | "toc_cell": false, 135 | "toc_position": {}, 136 | "toc_section_display": true, 137 | "toc_window_display": true 138 | } 139 | }, 140 | "nbformat": 4, 141 | "nbformat_minor": 4 142 | } 143 | -------------------------------------------------------------------------------- /contents/statistics/data/botany.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/statistics/data/botany.npy -------------------------------------------------------------------------------- /contents/statistics/data/energy.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/statistics/data/energy.npy -------------------------------------------------------------------------------- /contents/statistics/data/mistery_data.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/statistics/data/mistery_data.pkl -------------------------------------------------------------------------------- /contents/statistics/img/stats1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/statistics/img/stats1.png -------------------------------------------------------------------------------- /contents/statistics/img/stats2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/statistics/img/stats2.png -------------------------------------------------------------------------------- /contents/statistics/img/stats3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/statistics/img/stats3.png -------------------------------------------------------------------------------- /contents/statistics/img/stats4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/statistics/img/stats4.png -------------------------------------------------------------------------------- /contents/statistics/img/stats5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/statistics/img/stats5.png -------------------------------------------------------------------------------- /contents/statistics/img/stats7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/statistics/img/stats7.png -------------------------------------------------------------------------------- /contents/statistics/img/stats8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/statistics/img/stats8.png -------------------------------------------------------------------------------- /contents/statistics/intro.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Introducción y fundamentos\n", 8 | "\n", 9 | "\n", 10 | "## Mundo de datos\n", 11 | "\n", 12 | "Los avances tecnológicos recientes nos permiten **medir, almacenar y transmitir** datos de toda índole\n", 13 | "\n", 14 | "Por ejemplo\n", 15 | "\n", 16 | "- Datos comerciales y bancarios\n", 17 | "- Datos de operaciones industriales\n", 18 | "- Datos públicos y gubernamentales\n", 19 | "- Datos científicos y médicos\n", 20 | "- Datos de redes sociales\n", 21 | "- Datos de dispositivos: Smart-hardware e Internet de las cosas\n", 22 | "\n", 23 | "Sin embargo los datos crudos tienen poco valor. \n", 24 | "\n", 25 | "> Debemos **extraer información a partir de los datos** si queremos tener el conocimiento para tomar las mejores decisiones\n", 26 | "\n", 27 | "\n", 28 | "Este proceso se resume conceptualmente en el siguiente diagrama conocido como el modelo [Data-Information-Knowledge (DIK)](https://en.wikipedia.org/wiki/DIKW_pyramid)\n", 29 | "\n", 30 | "\n", 31 | "\n" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [ 38 | "***\n", 39 | "\n", 40 | "Nuestros datos son **mediciones u observaciones** de un **sistema o proceso** que queremos analizar. En base a nuestros datos podemos proponer y ajustar un **modelo** para nuestro sistema. Luego podemos utilizar el modelo para hacer predicciones y tomar decisiones\n", 41 | "\n", 42 | "Este proceso se resume en el siguiente diagrama\n", 43 | "\n", 44 | "\n", 45 | "\n", 46 | "\n", 47 | "Considere por ejemplo el [censo de Chile](https://www.ine.cl/ine-ciudadano/definiciones-estadisticas/censo) \n", 48 | "\n", 49 | "1. El **censo son las observaciones** de un **sistema: La población de Chile**\n", 50 | "1. En base a los datos obtenidos a través de múltiples censos podríamos crear un **modelo para la evolución de la población en una ciudad o región**\n", 51 | "1. Usando el modelo podríamos intentar **predecir el crecimiento poblacional** en un cierto horizonte de años\n", 52 | "1. Esta predicción puede servir como sustento para **desarrollar políticas públicas (tomar decisiones)**\n", 53 | "\n", 54 | "\n", 55 | "\n" 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "metadata": {}, 61 | "source": [ 62 | "## Sistemas, modelos e incertidumbre\n", 63 | "\n", 64 | "Podemos intentar clasificar los sistemas en base a su comportamiento:\n", 65 | "\n", 66 | "- Un sistema **determinista** está gobernado por reglas que nos permiten calcular exactamente su estado final dado un cierto punto de partida o condición inicial\n", 67 | "- Un sistema **estocástico** tiene un componente aleatorio, incluso usando la misma condición inicial el estado final puede ser distinto\n", 68 | "\n", 69 | "En general todos los sistemas complejos del mundo real tienen uno o más componentes aleatorio. Consideremos que\n", 70 | "\n", 71 | "- Las condiciones naturales varían constantemente\n", 72 | "- Los sensores y los equipos de medición están sujetos a ruido\n", 73 | "\n", 74 | "Por ende para hacer predicciones en sistemas complejos debemos manejar su **incerteza**\n" 75 | ] 76 | }, 77 | { 78 | "cell_type": "markdown", 79 | "metadata": {}, 80 | "source": [ 81 | "La incerteza puede tener distintos orígenes. En este apartado revisamos los tres orígenes más comunes\n", 82 | "\n", 83 | "**Incerteza inherente o propia**\n", 84 | "\n", 85 | "Se refiere a sistemas que son naturalmente inciertos. Por ejemplo, si estoy analizando sistemas de partículas, estoy sujeto al [principio cuántico de incertudimbre](https://es.wikipedia.org/wiki/Relaci%C3%B3n_de_indeterminaci%C3%B3n_de_Heisenberg)\n", 86 | "\n", 87 | "> Este tipo de incerteza es en general irreducible\n", 88 | "\n", 89 | "**Incerteza debido a un modelo imperfecto**\n", 90 | "\n", 91 | "Ciertos supuestos o aproximaciones de nuestros modelos pueden introducir incerteza. Por ejemplo un modelo demasiado simple o mal calibrado puede introducir ruido en nuestras predicciones\n", 92 | "\n", 93 | "> Podemos disminuir este tipo de incerteza mejorando nuestro modelo\n", 94 | "\n", 95 | "**Incerteza debido a observaciones imperfectas**\n", 96 | "\n", 97 | "En este caso la incertidumbre puede deberse a que\n", 98 | "\n", 99 | "- nuestras observaciones del sistema son incompletas o parciales\n", 100 | "- nuestros sensores son imperfectos e introducen ruido\n", 101 | "\n", 102 | "En ambos casos lo que observamos no es una representación perfecta del sistema\n", 103 | "\n", 104 | "> Podemos disminuir este tipo de incerteza capturando más datos, mejorando la calidad de nuestros sensores y/o haciendo mediciones que sean representativas del sistema completo\n", 105 | "\n" 106 | ] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "## ¿Qué es la Estadística?\n", 113 | "\n", 114 | "La estadística es la disciplina científica dedicada al desarrollo y estudio de métodos para recopilar, analizar y extraer información de los datos. La estadística busca\n", 115 | "\n", 116 | "- Describir fenómenos complejos a partir de observaciones parciales \n", 117 | "- Inferir propiedades de una población o sistema basándonos en una muestra\n", 118 | "- Usar datos para responder preguntas y tomar decisiones\n", 119 | "\n", 120 | "El trabajo estadístico se puede resumir en el siguiente ciclo\n", 121 | "\n", 122 | "\n", 123 | "\n", 124 | "\n", 125 | "En este capítulo estudiaremos técnicas de estadística descriptiva e inferencial (pasos 3 y 4 del diagrama) y las aplicaremos usando [`scipy.stats`](https://docs.scipy.org/doc/scipy/reference/stats.html) y [`numpy.random`](https://docs.scipy.org/doc/numpy/reference/routines.random.html) \n", 126 | "\n" 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "## Fundamentos de teoría de probabilidades\n", 134 | "\n", 135 | "La Teoría de Probabilidades es la rama de las matemáticas que estudia los fenómenos aleatorios. Considere las siguientes definiciones\n", 136 | "\n", 137 | "Variable aleatoria (VA)\n", 138 | ": Variable que asignamos al resultado de un fenómeno o experimento aleatorio\n", 139 | "\n", 140 | "Soporte o dominio\n", 141 | ": Espacio de valores posibles que puede tomar una VA\n", 142 | "\n", 143 | "Evento/Realización\n", 144 | ": Corresponde al resultado de observar una VA\n", 145 | "\n", 146 | "Probabilidad de un evento \n", 147 | ": Valor en el rango $[0, 1]$ que indica que tan posible (o que tan cierto) es que el evento ocurra\n", 148 | "\n", 149 | "En general se utilizan letras mayúsculas para denotar VAs y letras minúsculas para denotar sus realizaciones. Además usaremos la notación \n", 150 | "\n", 151 | "$$\n", 152 | "x \\sim X\n", 153 | "$$ \n", 154 | "\n", 155 | "para indicar que $x$ es una realización de la VA $X$, o dicho de otro modo que $x$ es el resultado de muestrear $X$\n", 156 | "\n", 157 | "\n", 158 | "**Ejemplo:** El lanzamiento de una moneda es un experimento con resultado aleatorio\n", 159 | "\n", 160 | "\n", 161 | "\n", 162 | "Sea $M$ el resultado de lanzar la moneda. Esta VA binaria tiene dos posibles resultados: 'cara' y 'cruz'.\n", 163 | "\n", 164 | "Si la moneda no está \"trucada\" entonces podríamos esperar que la probabilidad de estos resultados es\n", 165 | "\n", 166 | "$$\n", 167 | "P(M=\\text{cara}) = P(M=\\text{cruz}) = 0.5\n", 168 | "$$\n", 169 | "\n", 170 | "> Este conjunto de probabilidades corresponde a la **distribución** de $M$\n", 171 | "\n", 172 | ":::{seealso}\n", 173 | "\n", 174 | "En la lección siguiente estudiaremos más en profunidad sobre distribuciones de probabilidad\n", 175 | "\n", 176 | ":::" 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "metadata": {}, 182 | "source": [ 183 | "**Interpretación (frecuentista) de probabilidad**\n", 184 | "\n", 185 | "La definición matemática clásica de la probabilidad de un evento asociado a una VA es\n", 186 | "\n", 187 | "> el cociente entre la cantidad de ocurrencias del evento y la suma de la cantidad de todos los eventos posibles\n", 188 | "\n", 189 | "es decir, la **frecuencia relativa** del evento \n", 190 | "\n", 191 | "**Ejemplo:** Lanzamos la moneda del ejemplo anterior $5$ veces y registramos $[\\text{cruz}, \\text{cruz}, \\text{cara}, \\text{cruz}, \\text{cara}]$. Es decir que la frecuencia de $\\text{cruz}$ es 3 y la frecuencia de $\\text{cara}$ es 2. El total de realizaciones es $5$, luego las frecuencias relativas son $3/5$ y $2/5$, respectivamente\n", 192 | "\n" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": null, 198 | "metadata": {}, 199 | "outputs": [], 200 | "source": [] 201 | } 202 | ], 203 | "metadata": { 204 | "kernelspec": { 205 | "display_name": "Python 3 (ipykernel)", 206 | "language": "python", 207 | "name": "python3" 208 | }, 209 | "language_info": { 210 | "codemirror_mode": { 211 | "name": "ipython", 212 | "version": 3 213 | }, 214 | "file_extension": ".py", 215 | "mimetype": "text/x-python", 216 | "name": "python", 217 | "nbconvert_exporter": "python", 218 | "pygments_lexer": "ipython3", 219 | "version": "3.8.12" 220 | }, 221 | "toc": { 222 | "base_numbering": 1, 223 | "nav_menu": {}, 224 | "number_sections": true, 225 | "sideBar": true, 226 | "skip_h1_title": false, 227 | "title_cell": "Table of Contents", 228 | "title_sidebar": "Contents", 229 | "toc_cell": false, 230 | "toc_position": {}, 231 | "toc_section_display": true, 232 | "toc_window_display": true 233 | } 234 | }, 235 | "nbformat": 4, 236 | "nbformat_minor": 4 237 | } 238 | -------------------------------------------------------------------------------- /contents/statistics/more_stats.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Maximum a posteriori (MAP)\n", 8 | "\n", 9 | "- Hasta ahora nos hemos enfocado en la verosimilitud $p(\\mathcal{D}|\\theta)$\n", 10 | "- En realidad lo que más nos interesa es el *posterior* $p(\\theta|\\mathcal{D})$\n", 11 | "\n", 12 | "Bayes nos dice que\n", 13 | "\n", 14 | "$$\n", 15 | "p(\\theta|\\mathcal{D}) = \\frac{p(\\mathcal{D}|\\theta)p(\\theta)}{p(\\mathcal{D})}\n", 16 | "$$\n", 17 | "\n", 18 | "El criterio MAP busca encontrar $\\theta$ que maximiza el posterior. \n", 19 | "\n", 20 | "Es decir la moda del posterior\n", 21 | "\n", 22 | "Usando el logaritmo para escribir\n", 23 | "\n", 24 | "$$\n", 25 | "\\begin{align}\n", 26 | "\\hat \\theta &= \\text{arg}\\max_\\theta \\log p(\\theta|\\mathcal{D}) \\nonumber \\\\\n", 27 | "&= \\text{arg}\\max_\\theta \\log p(\\mathcal{D}|\\theta) + \\log p(\\theta) \\nonumber\n", 28 | "\\end{align}\n", 29 | "$$\n", 30 | "donde omitimos la evidencia $p(\\mathcal{D})$ ya que no depende de $\\theta$\n", 31 | "\n", 32 | "- El criterio MAP consiste en maximizar la **verosimilitud** más el **prior**\n", 33 | "- Usamos el **prior** para agregar información sobre $\\theta$\n" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "metadata": {}, 39 | "source": [ 40 | "### Ejemplo: Regresión con MAP\n", 41 | "\n", 42 | "Quiero modelar una regresión de $N$ parámetros\n", 43 | "$$\n", 44 | "\\begin{align}\n", 45 | "y_i = & \\Phi(x_i) \\theta + \\varepsilon_i \\nonumber \\\\\n", 46 | "&\\varepsilon_i \\sim \\mathcal{N}(0, \\sigma_\\epsilon^2) \\nonumber \\\\\n", 47 | "&y_i|\\theta \\sim \\mathcal{N}(\\Phi(x_i) \\theta, \\sigma_\\epsilon^2) \\nonumber\n", 48 | "\\end{align}\n", 49 | "$$\n", 50 | "es decir **verosimilitud** Gaussiana tal como antes\n", 51 | "\n", 52 | "Adicionalmente asumiremos que $p(\\theta) = \\mathcal{N}(0, \\sigma_\\theta^2)$, es decir **prior** Gaussiano\n", 53 | "\n", 54 | "El estimador MAP es \n", 55 | "\n", 56 | "$$\n", 57 | "\\begin{align}\n", 58 | "\\hat \\theta &= \\text{arg} \\max_\\theta -\\frac{1}{2} \\log(2\\pi\\sigma_\\varepsilon^2) M - \\frac{1}{2\\sigma_\\varepsilon^2} \\sum_{i=1}^M (y_i - \\Phi(x_i) \\theta)^2 -\\frac{1}{2} \\log(2\\pi \\sigma_\\theta^2) N - \\frac{1}{2\\sigma_\\theta^2} \\sum_{j=1}^N \\theta_j^2 \\nonumber \\\\\n", 59 | "&= \\text{arg} \\min_\\theta \\sum_{i=1}^M (y_i - \\Phi(x_i) \\theta)^2 + \\frac{\\sigma_\\varepsilon^2}{\\sigma_\\theta^2} \\sum_{j=1}^N \\theta_j^2 \\nonumber \n", 60 | "\\end{align}\n", 61 | "$$\n", 62 | "\n", 63 | "\n", 64 | "#### Reflexión\n", 65 | "- Si hay mucho ruido ($\\sigma_\\varepsilon^2 \\to \\infty$) entonces ignoro la verosimilitud y le creo al prior\n", 66 | "- Si uso un prior que no me da información ($\\sigma_\\theta^2 \\to \\infty$) entonces lo ignoro y me enfoco en la verosimilitud\n", 67 | "\n", 68 | "#### Relación con lo visto sobre regularización\n", 69 | "\n", 70 | "- Si decimos $\\lambda = \\frac{\\sigma_\\varepsilon^2}{\\sigma_\\theta^2}$ entonces la formulación es equivalente a Mínimos cuadrados regularizado, Ridge Regressión, Tikhonov!\n", 71 | "- Si hubieramos asumido una distribución Laplaciana para $p(\\theta)$ hubieramos obtenido el [LASSO](https://en.wikipedia.org/wiki/Lasso_(statistics))\n" 72 | ] 73 | }, 74 | { 75 | "cell_type": "markdown", 76 | "metadata": {}, 77 | "source": [ 78 | "# Inferencia Bayesiana\n", 79 | "\n", 80 | "- Asumimos que $\\theta$ es una variable aleatoria y que tiene cierta distribución\n", 81 | "- Buscamos estimar el posterior completo $p(\\theta|\\mathcal{D})$\n", 82 | "- El problema es que $p(\\mathcal{D})$ es generalmente incalculable\n", 83 | "- Para proseguir tenemos tres opciones\n", 84 | " 1. Usar distribuciones que sean conjugadas\n", 85 | " 1. Usar una aproximación (inferencia variacional)\n", 86 | " 1. Aprender un sistema que se comporte como el posterior (Markov Chain Monte Carlo) " 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "import pymc3 as pm\n", 96 | "print('Running on PyMC3 v{}'.format(pm.__version__))\n", 97 | "\n", 98 | "temperatura, consumo = df[\"temperatura\"].values, df[\"consumo\"].values\n", 99 | "with pm.Model() as helados:\n", 100 | " sigma = pm.HalfNormal('sigma', sd=10, shape=1)\n", 101 | " theta0 = pm.Normal('intercept', mu=0, sd=10, shape=1)\n", 102 | " theta1 = pm.Normal('slope', mu=0, sd=10, shape=1)\n", 103 | " mu = temperatura*theta1 + theta0\n", 104 | " x_observed = pm.Normal('x_obs', mu=mu, sd=sigma, observed=consumo)\n", 105 | " trace = pm.sample(draws=500, tune=200, init='advi', n_init=30000, \n", 106 | " cores=4, chains=2, live_plot=False)\n", 107 | "display(pm.summary(trace))\n", 108 | "pm.traceplot(trace, figsize=(9, 6), combined=True);" 109 | ] 110 | }, 111 | { 112 | "cell_type": "markdown", 113 | "metadata": {}, 114 | "source": [ 115 | "Más sobre estos temas en el [repositorio de INFO337](https://github.com/magister-informatica-uach/INFO337/blob/master/MCMC/lecture.ipynb) del magíster de informática y en [Ipython](https://ipython-books.github.io/73-getting-started-with-bayesian-methods/) [cookbook](https://ipython-books.github.io/77-fitting-a-bayesian-model-by-sampling-from-a-posterior-distribution-with-a-markov-chain-monte-carlo-method/)" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": {}, 121 | "source": [ 122 | "## FUTURO\n", 123 | "\n", 124 | "Más sobre métodos de monte-carlo\n", 125 | "- https://towardsdatascience.com/a-zero-math-introduction-to-markov-chain-monte-carlo-methods-dcba889e0c50\n", 126 | "- https://skymind.ai/wiki/markov-chain-monte-carlo\n", 127 | "- https://help.xlstat.com/customer/en/portal/articles/2062457-which-statistical-test-should-you-use-" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "execution_count": null, 133 | "metadata": {}, 134 | "outputs": [], 135 | "source": [] 136 | } 137 | ], 138 | "metadata": { 139 | "kernelspec": { 140 | "display_name": "Python 3 (ipykernel)", 141 | "language": "python", 142 | "name": "python3" 143 | }, 144 | "language_info": { 145 | "codemirror_mode": { 146 | "name": "ipython", 147 | "version": 3 148 | }, 149 | "file_extension": ".py", 150 | "mimetype": "text/x-python", 151 | "name": "python", 152 | "nbconvert_exporter": "python", 153 | "pygments_lexer": "ipython3", 154 | "version": "3.8.12" 155 | }, 156 | "toc": { 157 | "base_numbering": 1, 158 | "nav_menu": {}, 159 | "number_sections": true, 160 | "sideBar": true, 161 | "skip_h1_title": false, 162 | "title_cell": "Table of Contents", 163 | "title_sidebar": "Contents", 164 | "toc_cell": false, 165 | "toc_position": {}, 166 | "toc_section_display": true, 167 | "toc_window_display": false 168 | } 169 | }, 170 | "nbformat": 4, 171 | "nbformat_minor": 4 172 | } 173 | -------------------------------------------------------------------------------- /contents/visualization/data/covid19_extract.csv: -------------------------------------------------------------------------------- 1 | Province/State,Country/Region,Lat,Long,1/22/20,1/23/20,1/24/20,1/25/20,1/26/20,1/27/20,1/28/20,1/29/20,1/30/20,1/31/20,2/1/20,2/2/20,2/3/20,2/4/20,2/5/20,2/6/20,2/7/20,2/8/20,2/9/20,2/10/20,2/11/20,2/12/20,2/13/20,2/14/20,2/15/20,2/16/20,2/17/20,2/18/20,2/19/20,2/20/20,2/21/20,2/22/20,2/23/20,2/24/20,2/25/20,2/26/20,2/27/20,2/28/20,2/29/20,3/1/20,3/2/20,3/3/20,3/4/20,3/5/20,3/6/20,3/7/20,3/8/20,3/9/20,3/10/20,3/11/20,3/12/20,3/13/20,3/14/20,3/15/20,3/16/20,3/17/20,3/18/20,3/19/20,3/20/20,3/21/20,3/22/20,3/23/20,3/24/20,3/25/20,3/26/20,3/27/20,3/28/20,3/29/20,3/30/20,3/31/20,4/1/20,4/2/20,4/3/20,4/4/20,4/5/20,4/6/20,4/7/20,4/8/20,4/9/20,4/10/20,4/11/20,4/12/20,4/13/20,4/14/20,4/15/20,4/16/20,4/17/20,4/18/20,4/19/20,4/20/20,4/21/20,4/22/20,4/23/20,4/24/20,4/25/20,4/26/20,4/27/20,4/28/20,4/29/20,4/30/20,5/1/20,5/2/20,5/3/20,5/4/20,5/5/20,5/6/20,5/7/20,5/8/20,5/9/20,5/10/20,5/11/20,5/12/20,5/13/20 2 | ,Argentina,-38.4161,-63.6167,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,2,8,12,12,17,19,19,31,34,45,56,68,79,97,128,158,266,301,387,387,502,589,690,745,820,1054,1054,1133,1265,1451,1451,1554,1628,1715,1795,1975,1975,2142,2208,2277,2443,2571,2669,2758,2839,2941,3031,3144,3435,3607,3780,3892,4003,4127,4285,4428,4532,4681,4783,4887,5020,5208,5371,5611,5776,6034,6278,6563,6879 3 | ,Bolivia,-16.2902,-63.5887,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,3,10,10,11,11,12,12,15,19,24,27,29,32,43,61,74,81,97,107,115,123,132,139,157,183,194,210,264,268,275,300,330,354,397,441,465,493,520,564,598,609,703,807,866,950,1014,1053,1110,1167,1229,1470,1594,1681,1802,1886,2081,2266,2437,2556,2831,2964,3148 4 | ,Brazil,-14.235,-51.9253,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,2,2,2,2,4,4,13,13,20,25,31,38,52,151,151,162,200,321,372,621,793,1021,1546,1924,2247,2554,2985,3417,3904,4256,4579,5717,6836,8044,9056,10360,11130,12161,14034,16170,18092,19638,20727,22192,23430,25262,28320,30425,33682,36658,38654,40743,43079,45757,50036,54043,59324,63100,67446,73235,79685,87187,92202,97100,101826,108620,115455,126611,135773,146894,156061,162699,169594,178214,190137 5 | ,Chile,-35.6751,-71.543,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,4,4,4,8,8,13,23,23,43,61,74,155,201,238,238,434,537,632,746,922,1142,1306,1610,1909,2139,2449,2738,3031,3404,3737,4161,4471,4815,5116,5546,5972,6501,6927,7213,7525,7917,8273,8807,9252,9730,10088,10507,10832,11296,11812,12306,12858,13331,13813,14365,14885,16023,17008,18435,19663,20643,22016,23048,24581,25972,27219,28866,30063,31721,34381 6 | -------------------------------------------------------------------------------- /contents/visualization/data/rrl.dat: -------------------------------------------------------------------------------- 1 | 5.529837000252000144e+04 1.398700000000000010e+01 1.000000000000000021e-02 -1.000000000000000000e+00 2 | 5.542619242238999868e+04 1.425099999999999945e+01 1.200000000000000025e-02 -1.000000000000000000e+00 3 | 5.569335125456999958e+04 1.412800000000000011e+01 1.200000000000000025e-02 -1.000000000000000000e+00 4 | 5.569538036257999920e+04 1.413799999999999990e+01 1.100000000000000110e-02 -1.000000000000000000e+00 5 | 5.569628648609000084e+04 1.400300000000000011e+01 1.000000000000000021e-02 -1.000000000000000000e+00 6 | 5.569830469315999653e+04 1.398799999999999955e+01 1.000000000000000021e-02 -1.000000000000000000e+00 7 | 5.579420266883000295e+04 1.413000000000000078e+01 1.100000000000000110e-02 -1.000000000000000000e+00 8 | 5.580916607695999846e+04 1.428700000000000081e+01 1.399999999999999856e-02 -1.000000000000000000e+00 9 | 5.582312283791999653e+04 1.397200000000000131e+01 1.000000000000000021e-02 -1.000000000000000000e+00 10 | 5.582412000277000334e+04 1.398000000000000043e+01 1.000000000000000021e-02 -1.000000000000000000e+00 11 | 5.583807149205000314e+04 1.400300000000000011e+01 1.000000000000000021e-02 -1.000000000000000000e+00 12 | 5.586600545178000175e+04 1.422099999999999831e+01 1.499999999999999944e-02 -1.000000000000000000e+00 13 | 5.608314749113000289e+04 1.396700000000000053e+01 1.000000000000000021e-02 -1.000000000000000000e+00 14 | 5.608821931133999897e+04 1.401599999999999824e+01 1.499999999999999944e-02 -1.000000000000000000e+00 15 | 5.610515561731000344e+04 1.396199999999999974e+01 1.100000000000000110e-02 -1.000000000000000000e+00 16 | 5.611002678638000361e+04 1.408200000000000074e+01 1.100000000000000110e-02 -1.000000000000000000e+00 17 | 5.611105934918000276e+04 1.408400000000000141e+01 1.000000000000000021e-02 -1.000000000000000000e+00 18 | 5.611426662347000092e+04 1.426999999999999957e+01 1.200000000000000025e-02 -1.000000000000000000e+00 19 | 5.612720814840000094e+04 1.398799999999999955e+01 1.000000000000000021e-02 -1.000000000000000000e+00 20 | 5.613406594359999872e+04 1.406900000000000084e+01 1.100000000000000110e-02 -1.000000000000000000e+00 21 | 5.613720451514000160e+04 1.414200000000000124e+01 1.000000000000000021e-02 -1.000000000000000000e+00 22 | 5.614621966321999935e+04 1.397700000000000031e+01 1.200000000000000025e-02 -1.000000000000000000e+00 23 | 5.615111095427999680e+04 1.426299999999999990e+01 1.300000000000000114e-02 -1.000000000000000000e+00 24 | 5.615299510837999696e+04 1.406200000000000117e+01 1.000000000000000021e-02 -1.000000000000000000e+00 25 | 5.616403264184000000e+04 1.396799999999999997e+01 1.000000000000000021e-02 -1.000000000000000000e+00 26 | 5.617116018556000199e+04 1.404299999999999926e+01 1.200000000000000025e-02 -1.000000000000000000e+00 27 | 5.619106265248999989e+04 1.425599999999999845e+01 1.100000000000000110e-02 -1.000000000000000000e+00 28 | 5.619807063558999653e+04 1.409999999999999964e+01 1.100000000000000110e-02 -1.000000000000000000e+00 29 | 5.619907838287000050e+04 1.406599999999999895e+01 1.100000000000000110e-02 -1.000000000000000000e+00 30 | 5.636538033618000190e+04 1.402400000000000091e+01 1.300000000000000114e-02 -1.000000000000000000e+00 31 | 5.637137312635000126e+04 1.398099999999999987e+01 1.000000000000000021e-02 -1.000000000000000000e+00 32 | 5.637138945046000299e+04 1.399499999999999922e+01 1.100000000000000110e-02 -1.000000000000000000e+00 33 | 5.638237590246000036e+04 1.406900000000000084e+01 1.000000000000000021e-02 -1.000000000000000000e+00 34 | 5.645817189378000330e+04 1.410500000000000043e+01 1.300000000000000114e-02 -1.000000000000000000e+00 35 | 5.647913579125999968e+04 1.409799999999999898e+01 1.100000000000000110e-02 -1.000000000000000000e+00 36 | 5.649724517195000226e+04 1.418099999999999916e+01 1.200000000000000025e-02 -1.000000000000000000e+00 37 | 5.651015744013000221e+04 1.397700000000000031e+01 2.299999999999999961e-02 -1.000000000000000000e+00 38 | 5.651998971167999844e+04 1.400500000000000078e+01 1.000000000000000021e-02 -1.000000000000000000e+00 39 | 5.653606981023000117e+04 1.423400000000000176e+01 1.499999999999999944e-02 -1.000000000000000000e+00 40 | 5.653803158820999670e+04 1.411500000000000021e+01 1.100000000000000110e-02 -1.000000000000000000e+00 41 | 5.657597957216999930e+04 1.417099999999999937e+01 1.200000000000000025e-02 -1.000000000000000000e+00 42 | 5.659601055397000164e+04 1.429099999999999859e+01 1.499999999999999944e-02 -1.000000000000000000e+00 43 | 5.670739317829000356e+04 1.400900000000000034e+01 1.800000000000000211e-02 -2.000000000000000000e+00 44 | 5.672033450388000347e+04 1.414099999999999824e+01 1.499999999999999944e-02 -1.000000000000000000e+00 45 | 5.674136232082000060e+04 1.418900000000000006e+01 1.200000000000000025e-02 -1.000000000000000000e+00 46 | 5.681109353330000158e+04 1.405099999999999838e+01 1.499999999999999944e-02 -2.000000000000000000e+00 47 | 5.681723539344999881e+04 1.401799999999999891e+01 1.000000000000000021e-02 -1.000000000000000000e+00 48 | 5.682717478565000056e+04 1.402400000000000091e+01 1.399999999999999856e-02 -1.000000000000000000e+00 49 | 5.682719203667999682e+04 1.401500000000000057e+01 1.399999999999999856e-02 -1.000000000000000000e+00 50 | 5.683010240961000090e+04 1.398299999999999876e+01 1.000000000000000021e-02 -1.000000000000000000e+00 51 | 5.683115604816999985e+04 1.397499999999999964e+01 1.100000000000000110e-02 -1.000000000000000000e+00 52 | 5.683206031216999691e+04 1.417400000000000126e+01 1.200000000000000025e-02 -1.000000000000000000e+00 53 | 5.683209310725999967e+04 1.401999999999999957e+01 1.600000000000000033e-02 -1.000000000000000000e+00 54 | 5.683313042405000306e+04 1.400599999999999845e+01 1.000000000000000021e-02 -1.000000000000000000e+00 55 | 5.684100889789000212e+04 1.402599999999999980e+01 1.200000000000000025e-02 -1.000000000000000000e+00 56 | 5.684217180625999754e+04 1.417200000000000060e+01 1.100000000000000110e-02 -1.000000000000000000e+00 57 | 5.684622789336000278e+04 1.410200000000000031e+01 1.000000000000000021e-02 -1.000000000000000000e+00 58 | 5.685100200488999690e+04 1.415799999999999947e+01 1.200000000000000025e-02 -1.000000000000000000e+00 59 | 5.686399393198000325e+04 1.401200000000000045e+01 1.000000000000000021e-02 -1.000000000000000000e+00 60 | 5.687022818705000100e+04 1.404599999999999937e+01 1.100000000000000110e-02 -1.000000000000000000e+00 61 | 5.687501254778000293e+04 1.426599999999999824e+01 1.399999999999999856e-02 -1.000000000000000000e+00 62 | 5.687501831736999884e+04 1.428099999999999881e+01 1.399999999999999856e-02 -1.000000000000000000e+00 63 | -------------------------------------------------------------------------------- /contents/visualization/data/valdivia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/contents/visualization/data/valdivia.png -------------------------------------------------------------------------------- /contents/visualization/goodvisualizations.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# ¿Cómo hacer buenas visualizaciones?\n", 8 | "\n", 9 | "El objetivo de una visualización de datos es **comunicar la información de forma clara y simple**\n", 10 | "\n", 11 | "> Esto tiene un aspecto funcional y otro estético que deben estar balanceados\n", 12 | "\n", 13 | "En las lecciones previas aprendido a usar matplotlib: Corresponde al aspecto funcional\n", 14 | "\n", 15 | "> El aspecto estético requiere diseño (y sentido común)\n", 16 | "\n", 17 | "La mejor forma de aprender este aspecto es estudiando ejemplos\n", 18 | "\n", 19 | "- https://informationisbeautiful.net/visualizations/\n", 20 | "- https://bokeh.pydata.org/en/latest/docs/gallery.html\n", 21 | "\n", 22 | "A continuación voy a listar algunos consejos de distintas fuentes" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": {}, 28 | "source": [ 29 | "**Consejo 1:** El siguiente estudio realizó un ranking de las formas más efectivas de comunicar diferencias cuantitativas. Privilega las que están más arriba en la escala de efectividad\n", 30 | "\n", 31 | "\n", 32 | "\n", 33 | "Les recomiendo tomar el *chart challenge* en el link de la imagen" 34 | ] 35 | }, 36 | { 37 | "cell_type": "markdown", 38 | "metadata": {}, 39 | "source": [ 40 | "**Consejo 2:** Menos es más. Muestra sólo lo fundamental y usa color sólo para comunicar\n", 41 | "\n", 42 | "**Consejo 3**: Evita el misterio. Etiqueta tus ejes, ponle título a tus gráficos y usa leyendas siempre que sea necesario\n", 43 | "\n", 44 | "**Consejo 4**: [Evita las paletas de color de tipo arcoíris](https://www.scientificamerican.com/article/end-of-the-rainbow-new-map-scale-is-more-readable-by-people-who-are-color-blind/). Las paletas de tipo arcoiris son más difíciles de interpretar y no son amigables con los daltónicos. Por esta razón la paleta por defecto de matplotlib es viridis que es [perceptualmente-uniforme](https://bids.github.io/colormap/)" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "metadata": {}, 50 | "source": [ 51 | "Puedes ver estos y otros consejos explicados en el siguiente [diagrama](https://www.geckoboard.com/uploads/play-your-charts-right.pdf) de *geckoboard.com*\n", 52 | "\n", 53 | "También les recomiendo ver el siguiente video (en inglés) con más ejemplos y buenas prácticas a considerar" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 1, 59 | "metadata": {}, 60 | "outputs": [ 61 | { 62 | "data": { 63 | "text/html": [ 64 | "\n", 65 | " \n", 73 | " " 74 | ], 75 | "text/plain": [ 76 | "" 77 | ] 78 | }, 79 | "execution_count": 1, 80 | "metadata": {}, 81 | "output_type": "execute_result" 82 | } 83 | ], 84 | "source": [ 85 | "from IPython.display import VimeoVideo\n", 86 | "VimeoVideo('29684853')" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [] 95 | } 96 | ], 97 | "metadata": { 98 | "kernelspec": { 99 | "display_name": "Python 3 (ipykernel)", 100 | "language": "python", 101 | "name": "python3" 102 | }, 103 | "language_info": { 104 | "codemirror_mode": { 105 | "name": "ipython", 106 | "version": 3 107 | }, 108 | "file_extension": ".py", 109 | "mimetype": "text/x-python", 110 | "name": "python", 111 | "nbconvert_exporter": "python", 112 | "pygments_lexer": "ipython3", 113 | "version": "3.8.12" 114 | }, 115 | "toc": { 116 | "base_numbering": 1, 117 | "nav_menu": {}, 118 | "number_sections": true, 119 | "sideBar": true, 120 | "skip_h1_title": false, 121 | "title_cell": "Table of Contents", 122 | "title_sidebar": "Contents", 123 | "toc_cell": false, 124 | "toc_position": {}, 125 | "toc_section_display": true, 126 | "toc_window_display": false 127 | } 128 | }, 129 | "nbformat": 4, 130 | "nbformat_minor": 2 131 | } 132 | -------------------------------------------------------------------------------- /contents/visualization/ipywidgets.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Interfaces de usuario en Jupyter con `ipywidgets`\n", 8 | "\n", 9 | "Jupyter y IPython permiten no sólo visualizar datos sino también interactuar con ellos en tiempo real\n", 10 | "\n", 11 | "Para lograr esto estudiaremos los componentes de la librería [`ipywidgets`](https://ipywidgets.readthedocs.io/en/stable/)\n", 12 | "\n", 13 | ":::{warning}\n", 14 | "\n", 15 | "Los callbacks de los widgets requieren conexión con un intérprete de IPython. Si estás viendo este cuadernillo desde phuijse.github.io/PythonBook entonces los widgets no se visualizarán correctamente\n", 16 | "\n", 17 | ":::" 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "## ¿Qué es un widget?\n", 25 | "\n", 26 | "Un widget es un elemento gráfico que permite interactuar con una aplicación\n", 27 | "\n", 28 | "Un conjunto de widgets forman una interfaz de usuario gráfica (Graphical user interface o GUI)\n", 29 | "\n", 30 | "La siguiente imagen muestra los widgets típicos que se encuentran en las aplicaciones de PC\n", 31 | "\n", 32 | "\n", 33 | "\n", 34 | "La librería `ipywidgets` provee controles que permiten interactuar con funciones de Python \n", 35 | "\n", 36 | "Entre los muchos [widgets disponibles](https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20List.html) se encuentran:\n", 37 | "- Botones e selectores (*check-box*)\n", 38 | "- Listas desplegables (*combo-box*)\n", 39 | "- Campos de ingreso de texto (*text-box*)\n", 40 | "- Deslizadores (*sliders*)\n", 41 | "\n", 42 | "\n", 43 | "**Instalación**\n", 44 | "\n", 45 | "La forma más sencilla de instalar es usando `conda`\n", 46 | "\n", 47 | " conda install ipywidgets\n", 48 | " \n", 49 | "Si lo instalas de otra manera (pip o python setup.py) es necesario habilitar la extensión\n", 50 | "\n", 51 | " pip install ipywidgets --user\n", 52 | " jupyter nbextension enable --py widgetsnbextension\n", 53 | " " 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "## Creación semi-automática de widgets\n", 61 | "\n", 62 | "Una manera rápida de implementar widgets es usar el **decorador `interact`**\n", 63 | "\n", 64 | "> Al aplicar el decorador a una función convertiremos sus argumentos de entrada en widgets\n", 65 | "\n", 66 | "Cada entrada genera y se enlaza a un widget según su tipo:\n", 67 | "\n", 68 | "- Un entero produce un widget `IntSlider`\n", 69 | "- Un flotante produce un widget `FloatSlider`\n", 70 | "- Un booleando produce un widget `Checkbox`\n", 71 | "- Una lista produce un widget `Dropdown`\n", 72 | "- Un string produce un widget `Text`\n", 73 | "\n", 74 | "\n", 75 | "Los argumentos del decorador permiten entregar algunas opciones a los widgets" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 1, 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "%matplotlib inline\n", 85 | "import matplotlib.pyplot as plt\n", 86 | "import numpy as np" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 2, 92 | "metadata": { 93 | "ExecuteTime": { 94 | "end_time": "2020-06-20T17:46:18.332538Z", 95 | "start_time": "2020-06-20T17:46:18.209592Z" 96 | } 97 | }, 98 | "outputs": [ 99 | { 100 | "data": { 101 | "application/vnd.jupyter.widget-view+json": { 102 | "model_id": "3687a27618804ad1b7742236c4f5324b", 103 | "version_major": 2, 104 | "version_minor": 0 105 | }, 106 | "text/plain": [ 107 | "interactive(children=(IntSlider(value=0, description='x', max=10, step=2), FloatSlider(value=0.0, description=…" 108 | ] 109 | }, 110 | "metadata": {}, 111 | "output_type": "display_data" 112 | } 113 | ], 114 | "source": [ 115 | "import ipywidgets as widgets\n", 116 | "\n", 117 | "# Se crea un widget por cada argumento de la función\n", 118 | "@widgets.interact(x=(0, 10, 2), # El mínimo, máximo y paso para x\n", 119 | " y=(-1., 1., 0.01) # El mínimo, máximo y paso para y\n", 120 | " )\n", 121 | "\n", 122 | "def print_cosas(x=0, \n", 123 | " y=0., \n", 124 | " z=True, \n", 125 | " w=['foo','bar'], \n", 126 | " v='foo'): \n", 127 | " display(x, y, z, w, v)" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "## Creación manual de widgets\n", 135 | "\n", 136 | "Para mayor control podemos crear los widgets de nuestra preferencia con sus respectivos constructores y luego enlazarlos a una función usando manualmente con la **función `interact`**\n", 137 | "\n", 138 | "A continuación revisaremos algunos de ellos" 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "metadata": {}, 144 | "source": [ 145 | "### [Widgets numéricos](https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20List.html#Numeric-widgets)\n", 146 | "\n", 147 | "Un desplazador o *slider* es un widget cuyos argumentos son\n", 148 | "\n", 149 | "- min: valor donde inicia\n", 150 | "- max: valor donde termina\n", 151 | "- step: el salto entre valores\n", 152 | "- value: valor inicial\n", 153 | "\n", 154 | "El slider generará números entre esos rangos a medida que interactuamos con él\n", 155 | "\n", 156 | "Se puede crear un desplazador que produce números enteros con `IntSlider` o flotantes con `FloatSlider`\n", 157 | "\n", 158 | "\n", 159 | "**Ejemplo**\n" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": 3, 165 | "metadata": {}, 166 | "outputs": [ 167 | { 168 | "data": { 169 | "application/vnd.jupyter.widget-view+json": { 170 | "model_id": "d8c482f7113d409e9852cae231551252", 171 | "version_major": 2, 172 | "version_minor": 0 173 | }, 174 | "text/plain": [ 175 | "interactive(children=(IntSlider(value=0, description='a', min=-100, step=5), Output()), _dom_classes=('widget-…" 176 | ] 177 | }, 178 | "metadata": {}, 179 | "output_type": "display_data" 180 | }, 181 | { 182 | "data": { 183 | "text/plain": [ 184 | "(a)>" 185 | ] 186 | }, 187 | "execution_count": 3, 188 | "metadata": {}, 189 | "output_type": "execute_result" 190 | } 191 | ], 192 | "source": [ 193 | "f = lambda a: display(a)\n", 194 | "x = widgets.IntSlider(min=-100, max=100, step=5) # Esto crea el widget\n", 195 | "widgets.interact(f, a=x) # Esto enlaza x con a para la función f" 196 | ] 197 | }, 198 | { 199 | "cell_type": "markdown", 200 | "metadata": {}, 201 | "source": [ 202 | "También se pueden generar tuplas de enteros y flotantes usando `IntRangeSlider` y `FloatRangeSlider`, respectivamente\n", 203 | "\n", 204 | "Por otro lado los widgets te tipo text-box `FloatText` y `IntText` pueden usarse para pedir un número al usuario\n", 205 | "\n", 206 | "```python\n", 207 | "f = lambda a: display(a)\n", 208 | "x = widgets.FloatText(description=\"Por favor ingrese un número\")\n", 209 | "widgets.interact(f, a=x) # Esto enlaza el widget al primer argumento de f\n", 210 | "```\n", 211 | "\n", 212 | "En ambos casos podemos obtener el valor de los widgets usando \n", 213 | "\n", 214 | "```python\n", 215 | "x.value\n", 216 | "```\n", 217 | "\n", 218 | "Podemos verificar todos los atributos del widget usando\n", 219 | "\n", 220 | "```python\n", 221 | "x.keys\n", 222 | "```" 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "metadata": {}, 228 | "source": [ 229 | "### [Widgets de texto](https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20List.html#String-widgets)\n", 230 | "\n", 231 | "Sirven para capturar y mostrar strings\n", 232 | "\n", 233 | "- `Text`: Da una linea en blanco para escribir, al apretar Enter se captura el string\n", 234 | "- `Textarea`: Da un bloque de texto para escribir, se comporta igual a `Text`\n", 235 | "- `Label`: Muestra un string\n", 236 | "\n", 237 | "```python\n", 238 | "widgets.Text(value, # Texto por defecto\n", 239 | " placeholder, # Texto que aparece cuando está vacío\n", 240 | " description # Texto que aparece a la izquierda del cuadrado de texto\n", 241 | " )\n", 242 | "```\n", 243 | "**Ejemplo**" 244 | ] 245 | }, 246 | { 247 | "cell_type": "code", 248 | "execution_count": 4, 249 | "metadata": { 250 | "ExecuteTime": { 251 | "end_time": "2020-06-20T17:46:18.345772Z", 252 | "start_time": "2020-06-20T17:46:18.334079Z" 253 | } 254 | }, 255 | "outputs": [ 256 | { 257 | "data": { 258 | "application/vnd.jupyter.widget-view+json": { 259 | "model_id": "ba9b299397004bc585a9076a85a9751b", 260 | "version_major": 2, 261 | "version_minor": 0 262 | }, 263 | "text/plain": [ 264 | "Text(value='', description='Nombre:', placeholder='Escribe tu nombre acá')" 265 | ] 266 | }, 267 | "metadata": {}, 268 | "output_type": "display_data" 269 | } 270 | ], 271 | "source": [ 272 | "widgets.Text(placeholder='Escribe tu nombre acá', description='Nombre:')" 273 | ] 274 | }, 275 | { 276 | "cell_type": "markdown", 277 | "metadata": {}, 278 | "source": [ 279 | "### [Objeto Layout y atributo style](https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20Styling.html)\n", 280 | "\n", 281 | " El objeto `Layout` sirve para dar estilo a los *widgets*\n", 282 | " \n", 283 | "El estilo se explicita usando [CSS](https://www.w3schools.com/css/)\n", 284 | "\n", 285 | "Algunos argumentos útiles son \n", 286 | "- width: ancho del widget en pixeles\n", 287 | "- height: alto del widget en pixeles\n", 288 | "- margin: espacio entre el widget y otros componentes\n", 289 | "\n", 290 | "Cada widget tiene un atributo llamado `style` para personalizarlo \n", 291 | "\n", 292 | "La lista de atributos de estilo se puede acceder con \n", 293 | "\n", 294 | "```python\n", 295 | "x = widgets.Button()\n", 296 | "x.style.keys\n", 297 | "```\n", 298 | "\n", 299 | "**Ejemplo**" 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "execution_count": 5, 305 | "metadata": { 306 | "ExecuteTime": { 307 | "end_time": "2020-06-20T17:46:18.448262Z", 308 | "start_time": "2020-06-20T17:46:18.347550Z" 309 | } 310 | }, 311 | "outputs": [ 312 | { 313 | "data": { 314 | "application/vnd.jupyter.widget-view+json": { 315 | "model_id": "10fbc22ad1cd4a108e22d897edc56556", 316 | "version_major": 2, 317 | "version_minor": 0 318 | }, 319 | "text/plain": [ 320 | "interactive(children=(FloatRangeSlider(value=(-50.0, 50.0), description='Un argumento muy interesante:', layou…" 321 | ] 322 | }, 323 | "metadata": {}, 324 | "output_type": "display_data" 325 | } 326 | ], 327 | "source": [ 328 | "slider_layout = widgets.Layout(width='600px', height='20px', margin='10px')\n", 329 | "\n", 330 | "def mi_funcion(x):\n", 331 | " display(x[0], x[1], (x[1] - x[0]))\n", 332 | "\n", 333 | "range_slider = widgets.FloatRangeSlider(min=-100., max=100., step=0.01, \n", 334 | " continuous_update=True, \n", 335 | " description=r'Un argumento muy interesante:',\n", 336 | " layout=slider_layout)\n", 337 | "range_slider.style.description_width = 'initial'\n", 338 | "range_slider.style.handle_color = 'black'\n", 339 | "\n", 340 | "widgets.interact(mi_funcion, x=range_slider);" 341 | ] 342 | }, 343 | { 344 | "cell_type": "markdown", 345 | "metadata": {}, 346 | "source": [ 347 | "### Widget de tipo contenedor\n", 348 | "\n", 349 | "Son widgets que sirven para organizar otros widgets\n", 350 | "\n", 351 | "Por ejemplo \n", 352 | "- `HBox`: Organiza los widgets en forma horizontal\n", 353 | "- `VBox`: Organiza los widgets en forma vertical\n", 354 | "- `Tab`: Crea pestañas con los widgets\n", 355 | "\n", 356 | "Estos widgets reciben una lista de widgets y pueden anidarse\n", 357 | "\n", 358 | "**Ejemplo**" 359 | ] 360 | }, 361 | { 362 | "cell_type": "code", 363 | "execution_count": 6, 364 | "metadata": { 365 | "ExecuteTime": { 366 | "end_time": "2020-06-20T17:46:18.808180Z", 367 | "start_time": "2020-06-20T17:46:18.779618Z" 368 | } 369 | }, 370 | "outputs": [ 371 | { 372 | "data": { 373 | "application/vnd.jupyter.widget-view+json": { 374 | "model_id": "bd504fab22414c5abaf1845a1cccf778", 375 | "version_major": 2, 376 | "version_minor": 0 377 | }, 378 | "text/plain": [ 379 | "VBox(children=(Text(value='', description='Nombre:'), Text(value='', description='Apellido:')))" 380 | ] 381 | }, 382 | "metadata": {}, 383 | "output_type": "display_data" 384 | } 385 | ], 386 | "source": [ 387 | "firstname = widgets.Text(description='Nombre:')\n", 388 | "lastname = widgets.Text(description='Apellido:')\n", 389 | "widgets.VBox([firstname, lastname])" 390 | ] 391 | }, 392 | { 393 | "cell_type": "markdown", 394 | "metadata": {}, 395 | "source": [ 396 | "## Callbacks y eventos" 397 | ] 398 | }, 399 | { 400 | "cell_type": "markdown", 401 | "metadata": {}, 402 | "source": [ 403 | "### [Widget Button](https://ipywidgets.readthedocs.io/en/stable/examples/Widget%20List.html#Button) y atributo `on_click`\n", 404 | "\n", 405 | "```python\n", 406 | "widgets.Button(description, # Texto en el botón\n", 407 | " button_style='', # Estilo del botón: 'success', 'info', 'warning', 'danger' or ''\n", 408 | " icon='check', # Icono del botón\n", 409 | " ...\n", 410 | " )\n", 411 | "```\n", 412 | "\n", 413 | "Podemos darle funcionalidad al botón enlanzándolo con una función o *callback*. \n", 414 | "\n", 415 | ":::{important}\n", 416 | "\n", 417 | "La función debe tener un argumento. Este argumento corresponde al botón en sí\n", 418 | "\n", 419 | ":::\n", 420 | "\n", 421 | "Especificamos la función utilizando el método `on_click` del botón\n", 422 | "\n", 423 | "**Ejemplo**" 424 | ] 425 | }, 426 | { 427 | "cell_type": "code", 428 | "execution_count": 7, 429 | "metadata": { 430 | "ExecuteTime": { 431 | "end_time": "2020-06-20T17:46:18.889846Z", 432 | "start_time": "2020-06-20T17:46:18.809950Z" 433 | } 434 | }, 435 | "outputs": [ 436 | { 437 | "data": { 438 | "application/vnd.jupyter.widget-view+json": { 439 | "model_id": "d6bce92e94af49949a44634cb402db87", 440 | "version_major": 2, 441 | "version_minor": 0 442 | }, 443 | "text/plain": [ 444 | "HBox(children=(Text(value='', description='Escribir tu nombre:', style=DescriptionStyle(description_width='ini…" 445 | ] 446 | }, 447 | "metadata": {}, 448 | "output_type": "display_data" 449 | } 450 | ], 451 | "source": [ 452 | "insert_name = widgets.Text(description='Escribir tu nombre:')\n", 453 | "insert_name.style.description_width = 'initial'\n", 454 | "push_data = widgets.Button(description='Enviar')\n", 455 | "display(widgets.HBox([insert_name, push_data]))\n", 456 | "\n", 457 | "def boton_apretado(b):\n", 458 | " display(insert_name.value)\n", 459 | " \n", 460 | "push_data.on_click(boton_apretado)" 461 | ] 462 | }, 463 | { 464 | "cell_type": "markdown", 465 | "metadata": {}, 466 | "source": [ 467 | "### Atributo `observe`\n", 468 | "\n", 469 | "Podemos agregar acciones a otros widgets con el método `observe`\n", 470 | "\n", 471 | ":::{important}\n", 472 | "\n", 473 | "`observe` recibe una función de un argumento y el nombre del atributo que queremos \"observar\"\n", 474 | "\n", 475 | ":::\n", 476 | "\n", 477 | "Cada vez que haya un cambio en el atributo se llamará la función que especificamos\n", 478 | "\n", 479 | "El argumento de la función es un diccionario que tiene las siguientes llaves\n", 480 | "\n", 481 | "- `owner` : El widget que provocó el cambio\n", 482 | "- `name` : El nombre del atributo que está cambiando\n", 483 | "- `old` : El valor antiguo del atributo\n", 484 | "- `new` : El valor nuevo del atributo\n", 485 | "\n", 486 | "**Ejemplo**" 487 | ] 488 | }, 489 | { 490 | "cell_type": "code", 491 | "execution_count": 8, 492 | "metadata": { 493 | "ExecuteTime": { 494 | "end_time": "2020-06-20T17:46:18.970168Z", 495 | "start_time": "2020-06-20T17:46:18.891677Z" 496 | } 497 | }, 498 | "outputs": [ 499 | { 500 | "data": { 501 | "application/vnd.jupyter.widget-view+json": { 502 | "model_id": "d2528c7e2c60476986159b7c700cdf09", 503 | "version_major": 2, 504 | "version_minor": 0 505 | }, 506 | "text/plain": [ 507 | "Dropdown(description='Nombre:', options=('Pablo', 'Eliana', 'Hector'), value='Pablo')" 508 | ] 509 | }, 510 | "metadata": {}, 511 | "output_type": "display_data" 512 | } 513 | ], 514 | "source": [ 515 | "def handler(change):\n", 516 | " # change es un diccionario para el atributo value\n", 517 | " display(f\"Hola {change['new']}, Chao {change['old']}\")\n", 518 | "\n", 519 | "sel_slider = widgets.Dropdown(description=\"Nombre:\", \n", 520 | " options=[\"Pablo\", \"Eliana\", \"Hector\"])\n", 521 | "\n", 522 | "display(sel_slider)\n", 523 | "sel_slider.observe(handler, names='value')" 524 | ] 525 | }, 526 | { 527 | "cell_type": "markdown", 528 | "metadata": {}, 529 | "source": [ 530 | "### widget Output \n", 531 | "\n", 532 | "Este es un widget especial que puede usarse para redireccionar las salidas de otros widgets\n", 533 | "\n", 534 | "1. Primero creamos y mostrarmos Output \n", 535 | "1. Luego lo usamos de contexto para la salida de otro widget\n", 536 | "\n", 537 | "**Ejemplo**" 538 | ] 539 | }, 540 | { 541 | "cell_type": "code", 542 | "execution_count": 9, 543 | "metadata": { 544 | "ExecuteTime": { 545 | "end_time": "2020-06-20T17:46:19.051946Z", 546 | "start_time": "2020-06-20T17:46:18.972238Z" 547 | } 548 | }, 549 | "outputs": [ 550 | { 551 | "data": { 552 | "application/vnd.jupyter.widget-view+json": { 553 | "model_id": "5a07aa00e30f4dcea56dadbe4ab57d5b", 554 | "version_major": 2, 555 | "version_minor": 0 556 | }, 557 | "text/plain": [ 558 | "Output(layout=Layout(border='1px solid black'))" 559 | ] 560 | }, 561 | "metadata": {}, 562 | "output_type": "display_data" 563 | } 564 | ], 565 | "source": [ 566 | "out = widgets.Output(layout={'border': '1px solid black'})\n", 567 | "display(out)" 568 | ] 569 | }, 570 | { 571 | "cell_type": "code", 572 | "execution_count": 10, 573 | "metadata": { 574 | "ExecuteTime": { 575 | "end_time": "2020-06-20T17:46:19.182215Z", 576 | "start_time": "2020-06-20T17:46:19.053788Z" 577 | } 578 | }, 579 | "outputs": [ 580 | { 581 | "data": { 582 | "application/vnd.jupyter.widget-view+json": { 583 | "model_id": "4b2ae194d736470888ce349600d55630", 584 | "version_major": 2, 585 | "version_minor": 0 586 | }, 587 | "text/plain": [ 588 | "HBox(children=(Text(value='', description='Escribir tu nombre', style=DescriptionStyle(description_width='init…" 589 | ] 590 | }, 591 | "metadata": {}, 592 | "output_type": "display_data" 593 | } 594 | ], 595 | "source": [ 596 | "def on_change(button):\n", 597 | " with out: \n", 598 | " display(insert_name.value) # Esto se va escribir donde quiera que esté out\n", 599 | "\n", 600 | "insert_name = widgets.Text(description='Escribir tu nombre')\n", 601 | "insert_name.style.description_width = 'initial'\n", 602 | "push_data = widgets.Button(description='Enviar')\n", 603 | "display(widgets.HBox([insert_name, push_data]))\n", 604 | "push_data.on_click(on_change)" 605 | ] 606 | }, 607 | { 608 | "cell_type": "code", 609 | "execution_count": null, 610 | "metadata": {}, 611 | "outputs": [], 612 | "source": [] 613 | } 614 | ], 615 | "metadata": { 616 | "kernelspec": { 617 | "display_name": "Python 3 (ipykernel)", 618 | "language": "python", 619 | "name": "python3" 620 | }, 621 | "language_info": { 622 | "codemirror_mode": { 623 | "name": "ipython", 624 | "version": 3 625 | }, 626 | "file_extension": ".py", 627 | "mimetype": "text/x-python", 628 | "name": "python", 629 | "nbconvert_exporter": "python", 630 | "pygments_lexer": "ipython3", 631 | "version": "3.8.12" 632 | }, 633 | "toc": { 634 | "base_numbering": 1, 635 | "nav_menu": {}, 636 | "number_sections": true, 637 | "sideBar": true, 638 | "skip_h1_title": false, 639 | "title_cell": "Table of Contents", 640 | "title_sidebar": "Contents", 641 | "toc_cell": false, 642 | "toc_position": { 643 | "height": "calc(100% - 180px)", 644 | "left": "10px", 645 | "top": "150px", 646 | "width": "294.4px" 647 | }, 648 | "toc_section_display": true, 649 | "toc_window_display": true 650 | } 651 | }, 652 | "nbformat": 4, 653 | "nbformat_minor": 2 654 | } 655 | -------------------------------------------------------------------------------- /contents/visualization/seaborn.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "%matplotlib inline\n", 10 | "import matplotlib.pyplot as plt\n", 11 | "import numpy as np" 12 | ] 13 | }, 14 | { 15 | "cell_type": "markdown", 16 | "metadata": {}, 17 | "source": [ 18 | "## [Seaborn](https://seaborn.pydata.org/)\n", 19 | "\n", 20 | "Seaborn es una librería de visualización que utiliza matplotlib como backend\n", 21 | "\n", 22 | "Provee más opciones de gráficos y tienen una apariencia por defecto más moderna y acabada \n", 23 | "\n", 24 | "Además se integra mejor con la librería pandas (más en próximas clases)\n", 25 | "\n", 26 | "\n", 27 | "**Instalación**\n", 28 | "\n", 29 | "Con nuestro ambiente conda activado\n", 30 | "\n", 31 | " conda install seaborn" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 2, 37 | "metadata": { 38 | "ExecuteTime": { 39 | "end_time": "2020-05-24T03:35:15.484269Z", 40 | "start_time": "2020-05-24T03:35:11.030054Z" 41 | } 42 | }, 43 | "outputs": [ 44 | { 45 | "ename": "ModuleNotFoundError", 46 | "evalue": "No module named 'seaborn'", 47 | "output_type": "error", 48 | "traceback": [ 49 | "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", 50 | "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", 51 | "Input \u001b[0;32mIn [2]\u001b[0m, in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mseaborn\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01msns\u001b[39;00m\n\u001b[1;32m 2\u001b[0m sns\u001b[38;5;241m.\u001b[39mset()\n", 52 | "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'seaborn'" 53 | ] 54 | } 55 | ], 56 | "source": [ 57 | "import seaborn as sns\n", 58 | "sns.set()" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "Todas las funciones que vimos en la lección de matplotlib tendrán ahora la apariencia de seaborn" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": { 72 | "ExecuteTime": { 73 | "end_time": "2020-05-24T03:35:26.387098Z", 74 | "start_time": "2020-05-24T03:35:26.323924Z" 75 | } 76 | }, 77 | "outputs": [], 78 | "source": [ 79 | "x = np.arange(-2, 2, step=0.01)\n", 80 | "y = np.sin(2.0*np.pi*x) + 0.5*np.random.randn(len(x))\n", 81 | "\n", 82 | "plt.figure(figsize=(6, 3), tight_layout=True)\n", 83 | "plt.plot(x, y);" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": {}, 89 | "source": [ 90 | "### Algunos gráficos implementados en seaborn \n", 91 | "\n", 92 | "Todos los gráficos de seaborn pueden hacerse usando matplotlib (y un poco de esfuerzo extra)\n", 93 | "\n", 94 | "La ventaja de seaborn es que nos da una abstracción superior\n", 95 | "\n", 96 | "Seaborn ofrece `kdeplot` para visualizar distribuciones como alternativa a un histograma " 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": null, 102 | "metadata": { 103 | "ExecuteTime": { 104 | "end_time": "2020-05-24T03:37:19.878074Z", 105 | "start_time": "2020-05-24T03:37:19.801540Z" 106 | } 107 | }, 108 | "outputs": [], 109 | "source": [ 110 | "plt.figure(figsize=(6, 3), tight_layout=True)\n", 111 | "sns.kdeplot(y, shade=True);" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "`kdeplot` también puede usarse para dibujar distribuciones de mayor dimensión\n", 119 | "\n", 120 | "Si queremos dibujar la distribución conjunta con las marginales podemos usar `jointplot`" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": null, 126 | "metadata": { 127 | "ExecuteTime": { 128 | "end_time": "2020-05-24T03:37:56.899056Z", 129 | "start_time": "2020-05-24T03:37:56.199438Z" 130 | } 131 | }, 132 | "outputs": [], 133 | "source": [ 134 | "# plt.figure(figsize=(6, 3), tight_layout=True)\n", 135 | "# sns.kdeplot(x, y, shade=True);\n", 136 | "sns.jointplot(x=x, y=y, kind='kde')" 137 | ] 138 | }, 139 | { 140 | "cell_type": "markdown", 141 | "metadata": {}, 142 | "source": [ 143 | "Otro ejemplo muy util para dibujar correlación entre variables es `pairplot`\n", 144 | "\n", 145 | "Esta función recibe como entrada un objeto DataFrame de pandas" 146 | ] 147 | }, 148 | { 149 | "cell_type": "code", 150 | "execution_count": null, 151 | "metadata": { 152 | "ExecuteTime": { 153 | "end_time": "2020-05-24T03:39:14.023820Z", 154 | "start_time": "2020-05-24T03:39:12.758033Z" 155 | } 156 | }, 157 | "outputs": [], 158 | "source": [ 159 | "import pandas as pd # Si instalaste seaborn con conda, ya tienes instalado pandas\n", 160 | "data = pd.DataFrame(np.array([x, y, y**2]).T)\n", 161 | "sns.pairplot(data);" 162 | ] 163 | } 164 | ], 165 | "metadata": { 166 | "kernelspec": { 167 | "display_name": "Python 3 (ipykernel)", 168 | "language": "python", 169 | "name": "python3" 170 | }, 171 | "language_info": { 172 | "codemirror_mode": { 173 | "name": "ipython", 174 | "version": 3 175 | }, 176 | "file_extension": ".py", 177 | "mimetype": "text/x-python", 178 | "name": "python", 179 | "nbconvert_exporter": "python", 180 | "pygments_lexer": "ipython3", 181 | "version": "3.8.12" 182 | }, 183 | "toc": { 184 | "base_numbering": 1, 185 | "nav_menu": {}, 186 | "number_sections": true, 187 | "sideBar": true, 188 | "skip_h1_title": false, 189 | "title_cell": "Table of Contents", 190 | "title_sidebar": "Contents", 191 | "toc_cell": false, 192 | "toc_position": {}, 193 | "toc_section_display": true, 194 | "toc_window_display": false 195 | } 196 | }, 197 | "nbformat": 4, 198 | "nbformat_minor": 2 199 | } 200 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phuijse/PythonBook/bb2f1f519880e7983845c3145b1239783a1f1202/logo.png --------------------------------------------------------------------------------