├── _config.yml ├── LICENSE ├── README.md ├── 00. Introducción.ipynb ├── 09. Interpolación.ipynb ├── 11. Ecuaciones_diferenciales.ipynb ├── 02. Importar_Exportar.ipynb ├── 05. Preparar_data.ipynb ├── 03. Analizar_data.ipynb ├── 07. Atributos.ipynb ├── 01. Resumen.ipynb ├── 04. Visualizar_data.ipynb ├── 10. Resolver_ecuaciones.ipynb ├── 06. Regresión.ipynb └── 12. Series_de_tiempo.ipynb /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Santiago D. Salas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Python 🐍 Ciencia de Datos con el TCLab 2 | 3 | ¡Bienvenidos a este curso de Ciencia de Datos en Python en idioma castellano! Este curso está diseñado para ayudarte a desarrollar habilidades en Ciencia de Datos y Aprendizaje Automático (Machine Learning) en Python. Un [curso introductorio a Python en idioma inglés](https://github.com/APMonitor/begin_python) está disponible para programadores sin experiencia previa. Este curso tiene tutoriales disponibles en YouTube para cada ejercicio, en caso de existir inquietudes. Una particularidad de este curso es que trabaja con temas básicos o introductorios y luego evalúa tus conocimientos con datos de un HARDWARE llamado TCLab (un Arduino) que controla dos calentadores y mide sus temperaturas. Esto nos permite observar que el código en Python tiene un IMPACTO REAL al momento de generar información y tomar acciones. 4 | 5 | [![Python Data Science](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/Intro.png/:/rs=w:1440,h:1440)](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67) 6 | 7 | Una de las mejores formas de iniciar o estudiar un lenguaje de programación es trabajando en un PROYECTO. Los ejercicios están diseñados para aprender habilidades de programación en Python enfocado a Ciencia de Datos. Las aplicaciones de la Ciencia de Datos se encuentran en casi TODAS las industrias. Los datos sin procesar se pueden transformar en información procesable que impulsa al descubrimiento científico, innovación y desarrollo. 8 | 9 | ### Contenidos 10 | 11 | Hay 12 lecciones para ayudarte a aprender Ciencia de Datos en Python utilizando el TCLab. Lo primero es [instalar Anaconda](https://www.youtube.com/watch?v=3EXB38O0ni0&t=6s) para abrir y ejecutar los archivos de IPython en Jupyter notebook. Se puede utilizar cualquier plataforma que ejecute código en Python (IDLE (python.org), Spyder, PyCharm, y otras) pero Jupyter notebook es requerido para abrir y ejecutar el IPython notebook con archivos (`.ipynb`). Todos los archivos de IPython notebook (`.ipynb`) en idioma castellano se pueden [descargar desde este link](https://github.com/APMonitor/ciencia_de_datos/archive/refs/heads/main.zip). No olvides descomprimir desde la carpeta (extraer los archivos) y copiarlos en una carpeta de tu elección antes de empezar. 12 | 13 | 1. [Resumen](https://github.com/APMonitor/ciencia_de_datos/blob/main/01.%20Resumen.ipynb) 14 | 2. [Importar y Exportar datos](https://github.com/APMonitor/ciencia_de_datos/blob/main/02.%20Importar_Exportar.ipynb) 15 | 3. [Análisis de datos](https://github.com/APMonitor/ciencia_de_datos/blob/main/03.%20Analizar_data.ipynb) 16 | 4. [Visualización de datos](https://github.com/APMonitor/ciencia_de_datos/blob/main/04.%20Visualizar_data.ipynb) 17 | 5. [Preparación de datos (limpiar, escalar y dividir)](https://github.com/APMonitor/ciencia_de_datos/blob/main/05.%20Preparar_data.ipynb) 18 | 6. [Regresión](https://github.com/APMonitor/ciencia_de_datos/blob/main/06.%20Regresi%C3%B3n.ipynb) 19 | 7. [Atributos](https://github.com/APMonitor/ciencia_de_datos/blob/main/07.%20Atributos.ipynb) 20 | 8. [Clasificación](https://github.com/APMonitor/ciencia_de_datos/blob/main/08.%20Clasificaci%C3%B3n.ipynb) 21 | 9. [Interpolación](https://github.com/APMonitor/ciencia_de_datos/blob/main/09.%20Interpolaci%C3%B3n.ipynb) 22 | 10. [Resolución de ecuaciones](https://github.com/APMonitor/ciencia_de_datos/blob/main/10.%20Resolver_ecuaciones.ipynb) 23 | 11. [Ecuaciones diferenciales](https://github.com/APMonitor/ciencia_de_datos/blob/main/11.%20Ecuaciones_diferenciales.ipynb) 24 | 12. [Series de tiempo](https://github.com/APMonitor/ciencia_de_datos/blob/main/12.%20Series_de_tiempo.ipynb) 25 | 26 | ### Encuesta 27 | 28 | Este trabajo es parte de una investigación que busca cuantificar el impacto de integrar Hardware (TCLab) con Software (Programación en Python). 29 | Por favor ayúdanos completando la siguiente **Encuesta de INICIO de Curso**. 30 | 31 | [![Inicio](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/Inicio.png/:/rs=w:1440,h:1440)](https://forms.office.com/Pages/ResponsePage.aspx?id=r4yvt9iDREaFrjF8VFIjwUHkKiCq1wxFstxAwkoFiilUQVZDTk5MM0ZXOTdONjc1SFlZVTQ3VlJMNi4u) 32 | 33 | Una vez que finalices el curso, también nos gustaría saber que tal te pareció. 34 | 35 | Por favor ayúdanos completando la siguiente **Encuesta de FINAL de Curso**. 36 | 37 | [![Final](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/Final.png/:/rs=w:1440,h:1440)](https://forms.office.com/Pages/ResponsePage.aspx?id=r4yvt9iDREaFrjF8VFIjwUHkKiCq1wxFstxAwkoFiilUOExRVkVMWlZERVcyWlpUU1EyTFg4T1Q3WC4u) 38 | 39 | ### Instalar Python 40 | 41 | [Descargar e instalar Anaconda para utilizar Jupyter](https://docs.anaconda.com/anaconda/install/) o [mira este video para instalar Anaconda](https://www.youtube.com/watch?v=3EXB38O0ni0&t=6s). 42 | 43 | [![Instalar Anaconda](http://img.youtube.com/vi/LrMOrMb8-3s/0.jpg)](https://www.youtube.com/watch?v=3EXB38O0ni0&t=6s "Install Anaconda") 44 | 45 | Instrucciones adicionales de como [instalar Python y manejar sus módulos está disponible aquí en idioma inglés!](https://apmonitor.com/pdc/index.php/Main/InstallPython). 46 | 47 | ### Obtén tu TCLab 48 | 49 | Vas a necesitar un [TCLab kit](https://apmonitor.com/heat.htm) para completar los ejercicios. El TCLab está disponible para [compra en Amazon](https://www.amazon.com/TCLab-Temperature-Control-Lab/dp/B07GMFWMRY). 50 | 51 | [Laboratorio de control de temperatura](http://apmonitor.com/pdc/uploads/Main/tclab_connect.png "TCLab") 52 | 53 | ### Soporte 54 | 55 | ¡Nos encantaría escuchar cualquier comentario o problema! Siempre estamos tratando de mejorar este curso y nos gustaría conocer su experiencia. Para soporte (en idioma inglés): support@apmonitor.com. 56 | 57 | ### Recursos adicionales 58 | 59 | - [Begin Python Course](https://github.com/APMonitor/begin_python) 60 | - [Engineering Programming Course](https://apmonitor.com/che263) with [Source Code](https://github.com/APMonitor/learn_python) 61 | - [Temperature Control Lab (TCLab) Kit](http://apmonitor.com/pdc/index.php/Main/ArduinoTemperatureControl) 62 | - [Jupyter as interactive environment for Python, Julia, R](https://jupyter.org/) 63 | -------------------------------------------------------------------------------- /00. Introducción.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### Python 🐍 Ciencia de Datos con el TCLab\n", 8 | "\n", 9 | "¡Bienvenidos a este curso de Ciencia de Datos en Python en idioma castellano! Este curso está diseñado para ayudarte a desarrollar habilidades en Ciencia de Datos y Aprendizaje Automático (Machine Learning) en Python. Un [curso introductorio a Python en idioma inglés](https://github.com/APMonitor/begin_python) está disponible para programadores sin experiencia previa. Este curso tiene tutoriales disponibles en YouTube para cada ejercicio, en caso de existir inquietudes. Una particularidad de este curso es que trabaja con temas básicos o introductorios y luego evalúa tus conocimientos con datos de un HARDWARE llamado TCLab (un Arduino) que controla dos calentadores y mide sus temperaturas. Esto nos permite observar que el código en Python tiene un IMPACTO REAL al momento de generar información y tomar acciones.\n", 10 | "\n", 11 | "[![Python Data Science](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/Intro.png/:/rs=w:1440,h:1440)](https://www.youtube.com/watch?v=_CDWwLho5Is&list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67&index=2)\n", 12 | "\n", 13 | "Una de las mejores formas de iniciar o estudiar un lenguaje de programación es trabajando en un PROYECTO. Los ejercicios están diseñados para aprender habilidades de programación en Python enfocado a Ciencia de Datos. Las aplicaciones de la Ciencia de Datos se encuentran en casi TODAS las industrias. Los datos sin procesar se pueden transformar en información procesable que impulsa al descubrimiento científico, innovación y desarrollo.\n", 14 | "\n", 15 | "### Contenidos\n", 16 | "\n", 17 | "Hay 12 lecciones para ayudarte a aprender Ciencia de Datos en Python utilizando el TCLab. Lo primero es [instalar Anaconda](https://www.youtube.com/watch?v=3EXB38O0ni0&t=6s) para abrir y ejecutar los archivos de IPython en Jupyter notebook. Se puede utilizar cualquier plataforma que ejecute código en Python (IDLE (python.org), Spyder, PyCharm, y otras) pero Jupyter notebook es requerido para abrir y ejecutar el IPython notebook con archivos (`.ipynb`). Todos los archivos de IPython notebook (`.ipynb`) en idioma castellano se pueden [descargar desde este link](https://github.com/APMonitor/ciencia_de_datos/archive/refs/heads/main.zip). No olvides descomprimir desde la carpeta (extraer los archivos) y copiarlos en una carpeta de tu elección antes de empezar.\n", 18 | "\n", 19 | "1. [Resumen](https://github.com/APMonitor/ciencia_de_datos/blob/main/01.%20Resumen.ipynb)\n", 20 | "2. [Importar y Exportar datos](https://github.com/APMonitor/ciencia_de_datos/blob/main/02.%20Importar_Exportar.ipynb)\n", 21 | "3. [Análisis de datos](https://github.com/APMonitor/ciencia_de_datos/blob/main/03.%20Analizar_data.ipynb)\n", 22 | "4. [Visualización de datos](https://github.com/APMonitor/ciencia_de_datos/blob/main/04.%20Visualizar_data.ipynb)\n", 23 | "5. [Preparación de datos (limpiar, escalar y dividir)](https://github.com/APMonitor/ciencia_de_datos/blob/main/05.%20Preparar_data.ipynb)\n", 24 | "6. [Regresión](https://github.com/APMonitor/ciencia_de_datos/blob/main/06.%20Regresi%C3%B3n.ipynb)\n", 25 | "7. [Atributos](https://github.com/APMonitor/ciencia_de_datos/blob/main/07.%20Atributos.ipynb)\n", 26 | "8. [Clasificación](https://github.com/APMonitor/ciencia_de_datos/blob/main/08.%20Clasificaci%C3%B3n.ipynb)\n", 27 | "9. [Interpolación](https://github.com/APMonitor/ciencia_de_datos/blob/main/09.%20Interpolaci%C3%B3n.ipynb)\n", 28 | "10. [Resolución de ecuaciones](https://github.com/APMonitor/ciencia_de_datos/blob/main/10.%20Resolver_ecuaciones.ipynb)\n", 29 | "11. [Ecuaciones diferenciales](https://github.com/APMonitor/ciencia_de_datos/blob/main/11.%20Ecuaciones_diferenciales.ipynb)\n", 30 | "12. [Series de tiempo](https://github.com/APMonitor/ciencia_de_datos/blob/main/12.%20Series_de_tiempo.ipynb)\n", 31 | "\n", 32 | "### Encuesta\n", 33 | "\n", 34 | "Este trabajo es parte de una investigación que busca cuantificar el impacto de integrar Hardware (TCLab) con Software (Programación en Python).\n", 35 | "\n", 36 | "Por favor ayúdanos completando la siguiente **Encuesta de INICIO de Curso**.\n", 37 | "\n", 38 | "[![Inicio](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/Inicio.png/:/rs=w:1440,h:1440)](https://forms.office.com/Pages/ResponsePage.aspx?id=r4yvt9iDREaFrjF8VFIjwUHkKiCq1wxFstxAwkoFiilUQVZDTk5MM0ZXOTdONjc1SFlZVTQ3VlJMNi4u)\n", 39 | "\n", 40 | "Una vez que finalices el curso, también nos gustaría saber que tal te pareció.\n", 41 | "\n", 42 | "Por favor ayúdanos completando la siguiente **Encuesta de FINAL de Curso**.\n", 43 | "\n", 44 | "[![Final](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/Final.png/:/rs=w:1440,h:1440)](https://forms.office.com/Pages/ResponsePage.aspx?id=r4yvt9iDREaFrjF8VFIjwUHkKiCq1wxFstxAwkoFiilUOExRVkVMWlZERVcyWlpUU1EyTFg4T1Q3WC4u)\n", 45 | "\n", 46 | "### Instalar Python\n", 47 | "\n", 48 | "[Descargar e instalar Anaconda para utilizar Jupyter](https://docs.anaconda.com/anaconda/install/) o [mira este video para instalar Anaconda](https://www.youtube.com/watch?v=3EXB38O0ni0&t=6s).\n", 49 | "\n", 50 | "[![Instalar Anaconda](http://img.youtube.com/vi/LrMOrMb8-3s/0.jpg)](https://www.youtube.com/watch?v=3EXB38O0ni0&t=6s \"Install Anaconda\")\n", 51 | "\n", 52 | "Instrucciones adicionales de como [instalar Python y manejar sus módulos está disponible aquí en idioma inglés!](https://apmonitor.com/pdc/index.php/Main/InstallPython).\n", 53 | "\n", 54 | "### Obtén tu TCLab\n", 55 | "\n", 56 | "Vas a necesitar un [TCLab kit](https://apmonitor.com/heat.htm) para completar los ejercicios. El TCLab está disponible para [compra en Amazon](https://www.amazon.com/TCLab-Temperature-Control-Lab/dp/B07GMFWMRY). \n", 57 | "\n", 58 | "[Laboratorio de control de temperatura](http://apmonitor.com/pdc/uploads/Main/tclab_connect.png \"TCLab\")\n", 59 | "\n", 60 | "### Soporte\n", 61 | "\n", 62 | "¡Nos encantaría escuchar cualquier comentario o problema! Siempre estamos tratando de mejorar este curso y nos gustaría conocer su experiencia. Para soporte (en idioma inglés): support@apmonitor.com.\n", 63 | "\n", 64 | "### Recursos adicionales\n", 65 | "\n", 66 | "- [Begin Python Course](https://github.com/APMonitor/begin_python)\n", 67 | "- [Engineering Programming Course](https://apmonitor.com/che263) with [Source Code](https://github.com/APMonitor/learn_python)\n", 68 | "- [Temperature Control Lab (TCLab) Kit](http://apmonitor.com/pdc/index.php/Main/ArduinoTemperatureControl)\n", 69 | "- [Jupyter as interactive environment for Python, Julia, R](https://jupyter.org/)" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": {}, 76 | "outputs": [], 77 | "source": [] 78 | } 79 | ], 80 | "metadata": { 81 | "kernelspec": { 82 | "display_name": "Python 3", 83 | "language": "python", 84 | "name": "python3" 85 | }, 86 | "language_info": { 87 | "codemirror_mode": { 88 | "name": "ipython", 89 | "version": 3 90 | }, 91 | "file_extension": ".py", 92 | "mimetype": "text/x-python", 93 | "name": "python", 94 | "nbconvert_exporter": "python", 95 | "pygments_lexer": "ipython3", 96 | "version": "3.8.5" 97 | } 98 | }, 99 | "nbformat": 4, 100 | "nbformat_minor": 1 101 | } 102 | -------------------------------------------------------------------------------- /09. Interpolación.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 9. Interpolación\n", 8 | "\n", 9 | "[Playlist de Ciencia de Datos en castellano](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67)\n", 10 | "[![Ciencia de Datos en Python](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/10-0001.png/:/rs=w:1280,h:720)](https://www.youtube.com/watch?v=w97CsaLuEvI&list=PLLBUgWXdTBDg1Qgmwt4jKtVn9BWh5-zgy \"Python Data Science\")\n", 11 | "\n", 12 | "La interpolación construye nuevos puntos de predicción a partir de un conjunto discreto de datos conocidos. Existen muchos tipos de interpolación, tales como interpolación por el vecino más próximo (constante por partes), lineal, polinomial, [splines cúbicos](https://apmonitor.com/wiki/index.php/Main/ObjectCspline), y [splines base](https://apmonitor.com/wiki/index.php/Main/ObjectBspline). En la interpolación, los datos proporcionan la forma de la función aproximada, con ecuaciones polinómicas por partes o de orden superior para coincidir exactamente con los puntos de datos en esas ubicaciones discretas dadas.\n", 13 | "\n", 14 | "![charge](https://apmonitor.com/che263/uploads/Begin_Python/charge.png)\n", 15 | "\n", 16 | "### Interpolación en 1D\n", 17 | "\n", 18 | "La librería `scipy.interpolate` contiene una función para interpolación unidimensional (`interp1d`), donde `kind` (tipo) es `nearest` (más cercano), `previous` (anterior), `next` (siguiente), `zero` (cero), `linear` (lineal), `quadratic` (cuadrático), `cubic` (cúbico), o un número como `0`-`3`." 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "import numpy as np\n", 28 | "x = np.array([0,1,2,3,4,5])\n", 29 | "y = np.array([0.1,0.25,0.3,0.5,1.0,0.9])\n", 30 | "\n", 31 | "# Interpolación en 1D\n", 32 | "from scipy.interpolate import interp1d\n", 33 | "f = interp1d(x,y,kind='cubic')\n", 34 | "print(f(4.5)) # predice en 4.5" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "![analyze](https://apmonitor.com/che263/uploads/Begin_Python/analyze.png)\n", 42 | "\n", 43 | "### Gráfica de Interpolación 1D\n", 44 | "\n", 45 | "Varias de las interpolaciones de 1D se muestran gráficamente. No olvides agregar puntos adicionales como `xp = np.linspace (0,5,100)` al trazar la interpolación o todo se verá como una interpolación lineal." 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": null, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "xp = np.linspace(0,5,100)\n", 55 | "y1 = interp1d(x,y,kind='nearest')\n", 56 | "y2 = interp1d(x,y,kind=1)\n", 57 | "y3 = interp1d(x,y,kind=3)\n", 58 | "\n", 59 | "import matplotlib.pyplot as plt\n", 60 | "%matplotlib inline\n", 61 | "plt.plot(xp,y1(xp),'g-',label='Nearest')\n", 62 | "plt.plot(xp,y2(xp),'r--',label='Linear Interp')\n", 63 | "plt.plot(xp,y3(xp),'k:',label='Cubic Spline')\n", 64 | "plt.plot(x,y,'bo',label='Data')\n", 65 | "plt.legend()\n", 66 | "plt.show()" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "Una precaución al obtener valores de una interpolación es que habrá un error como `ValueError: A value in x_new is above the interpolation range.` (\"Un valor en x_new está por encima del rango de interpolación\") si solicita un valor fuera de la región de interpolación como \"f (5.5)\"." 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": {}, 79 | "source": [ 80 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 81 | "\n", 82 | "### Actividad de Interpolación\n", 83 | "\n", 84 | "Crea una interpolación lineal con los siguientes datos:\n", 85 | "\n", 86 | "```python\n", 87 | "xr = [0.0,1.0,2.0,5.0]\n", 88 | "yr = [0.2,0.4,1.05,1.7]\n", 89 | "```\n", 90 | "\n", 91 | "Utiliza la interpolación para predecir valores en `xr=3.5`." 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": null, 97 | "metadata": {}, 98 | "outputs": [], 99 | "source": [] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": {}, 104 | "source": [ 105 | "![gekko](https://apmonitor.com/che263/uploads/Begin_Python/gekko.png)\n", 106 | "\n", 107 | "El tipo de `spline` es importante para determinadas aplicaciones, como optimización. Los `solvers` basados en gradientes tienen un mejor desempeño con funciones continuas que también tienen gradientes continuos. Por esta razón, puede ser preferible un `spline` cuadrático o cúbico a una interpolación lineal. El siguiente es un ejemplo de optimización con una `spline` cúbica en Gekko. La función original es $ \\frac{1}{1 + 25 \\, x ^ 2} $ con el objetivo de encontrar el máximo usando solo valores de función en `xr = [- 1.0 -0.8 -0.5 -0.25 -0.1 0.1 0.2 0.5 ] `.\n" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": null, 113 | "metadata": {}, 114 | "outputs": [], 115 | "source": [ 116 | "from gekko import GEKKO\n", 117 | "import numpy as np\n", 118 | "import matplotlib.pyplot as plt\n", 119 | "\n", 120 | "# generar datos\n", 121 | "def f(x):\n", 122 | " return 1.0/(1.0+25.0*x**2)\n", 123 | "xr = np.array([-1.0,-0.8,-0.5,-0.25,-0.1,0.1,0.2,0.5])\n", 124 | "yr = f(xr)\n", 125 | "\n", 126 | "# crear spline cúbica y maximizar\n", 127 | "c = GEKKO(remote=False)\n", 128 | "xg = c.Var(); yg = c.Var()\n", 129 | "c.cspline(xg,yg,xr,yr,True)\n", 130 | "c.Maximize(yg)\n", 131 | "c.solve(disp=False)\n", 132 | "\n", 133 | "xp = np.linspace(-1,0.5,100)\n", 134 | "plt.plot(xp,f(xp),'b-',label=r'$f(x) = \\frac{1}{1+25x^2}$')\n", 135 | "plt.plot(xr,yr,'ro',label='Data')\n", 136 | "plt.plot(xg.value[0],yg.value[0],'kx',label='C-spline Maximum')\n", 137 | "plt.legend(loc='best')\n", 138 | "plt.show()" 139 | ] 140 | }, 141 | { 142 | "cell_type": "markdown", 143 | "metadata": {}, 144 | "source": [ 145 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 146 | "\n", 147 | "### Actividad de `Spline` Cúbico\n", 148 | "\n", 149 | "Crea un `Spline` Cúbico con los siguientes datos:\n", 150 | "\n", 151 | "```python\n", 152 | "xr = [0.0,1.0,2.0,3.0,4.0,5.0]\n", 153 | "yr = [46.0,6.6,0.13,0.026,3.84,33.0]\n", 154 | "```\n", 155 | "\n", 156 | "Construye un `spline` cúbico y encuentra el valor mínimo de la función." 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": {}, 169 | "source": [ 170 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 171 | "\n", 172 | "### Interpolación en 2D\n", 173 | "\n", 174 | "También existe una función para interpolación bidimensional (`interp2d`) donde se puede establecer su tipo o `kind` como `linear` o `cubic`." 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": null, 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "# Interpolación 2D\n", 184 | "from scipy.interpolate import interp2d\n", 185 | "x2 = np.arange(-1.5, 1.01, 0.5)\n", 186 | "y2 = np.arange(-1.5, 1.01, 0.5)\n", 187 | "xx, yy = np.meshgrid(x2, y2)\n", 188 | "zz = np.sin(xx**2+yy**2)\n", 189 | "f2 = interp2d(x2, y2, zz, kind='cubic')\n", 190 | "print(f2(4.5,1)) # predice z en (x=4.5, y=1)" 191 | ] 192 | }, 193 | { 194 | "cell_type": "markdown", 195 | "metadata": {}, 196 | "source": [ 197 | "![analyze](https://apmonitor.com/che263/uploads/Begin_Python/analyze.png)\n", 198 | "\n", 199 | "### Gráfica de Interpolación 3D\n", 200 | "\n", 201 | "Un gráfico 3D muestra los puntos de datos en \"rojo\" (red) y la interpolación cúbica en \"azul\" (blue). El gráfico incluye un gráfico de dispersión 3D para los datos y un gráfico de superficie para la `spline` cúbica." 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": null, 207 | "metadata": {}, 208 | "outputs": [], 209 | "source": [ 210 | "from mpl_toolkits.mplot3d import Axes3D\n", 211 | "fig = plt.figure(figsize=(8,5))\n", 212 | "ax = fig.add_subplot(111, projection='3d')\n", 213 | "ax.scatter(xx,yy,zz,color='red',label='Data')\n", 214 | "xe = np.arange(-1.5, 1.01, 0.1)\n", 215 | "ye = np.arange(-1.5, 1.01, 0.1)\n", 216 | "xxe, yye = np.meshgrid(xe, ye)\n", 217 | "fe = np.empty_like(xxe)\n", 218 | "for i in range(np.size(fe,0)):\n", 219 | " for j in range(np.size(fe,1)):\n", 220 | " fe[i,j] = f2(xxe[i,j],yye[i,j])\n", 221 | "ax.plot_surface(xxe,yye,fe,color='blue',alpha=0.7)\n", 222 | "plt.legend()\n", 223 | "plt.show()" 224 | ] 225 | }, 226 | { 227 | "cell_type": "markdown", 228 | "metadata": {}, 229 | "source": [ 230 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 231 | "\n", 232 | "### Actividad con el TCLab\n", 233 | "\n", 234 | "![temperature](https://apmonitor.com/che263/uploads/Begin_Python/temperature.png)\n", 235 | "\n", 236 | "### Registrar Temperaturas\n", 237 | "\n", 238 | "Enciende el calentador de 1% a 100% y registra $T_1$ y $T_2$ cada 10 segundos durante 3 minutos. Los datos deben incluir un total de 19 puntos de datos para cada sensor de temperatura y el tiempo de registro, comenzando desde cero.\n", 239 | "\n", 240 | "![connections](https://apmonitor.com/che263/uploads/Begin_Python/connections.png)" 241 | ] 242 | }, 243 | { 244 | "cell_type": "code", 245 | "execution_count": null, 246 | "metadata": {}, 247 | "outputs": [], 248 | "source": [] 249 | }, 250 | { 251 | "cell_type": "markdown", 252 | "metadata": {}, 253 | "source": [ 254 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 255 | "\n", 256 | "### Interpolación\n", 257 | "\n", 258 | "Crea una función de interpolación entre los puntos medidos para $T_1$ utilizando una interpolación lineal. Muestra los $T_1$ registrados como puntos rojos y la interpolación lineal como una línea negra. Agrega etiquetas X y etiquetas Y, así como una leyenda del gráfico." 259 | ] 260 | }, 261 | { 262 | "cell_type": "code", 263 | "execution_count": null, 264 | "metadata": {}, 265 | "outputs": [], 266 | "source": [] 267 | }, 268 | { 269 | "cell_type": "markdown", 270 | "metadata": {}, 271 | "source": [ 272 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 273 | "\n", 274 | "### Interpolación vs. Regresión\n", 275 | "\n", 276 | "Crea una función de interpolación entre los puntos medidos para $T_2$ usando un `spline` cúbico. Compara el `spline` cúbico por partes con una regresión polinomial de tercer orden. Muestra los $T_2$ registrados como puntos azules, la interpolación `spline` cúbica como una línea discontinua negra y la regresión polinomial como una línea punteada roja. Agrega las etiquetas apropiadas." 277 | ] 278 | }, 279 | { 280 | "cell_type": "code", 281 | "execution_count": null, 282 | "metadata": {}, 283 | "outputs": [], 284 | "source": [] 285 | } 286 | ], 287 | "metadata": { 288 | "kernelspec": { 289 | "display_name": "Python 3", 290 | "language": "python", 291 | "name": "python3" 292 | }, 293 | "language_info": { 294 | "codemirror_mode": { 295 | "name": "ipython", 296 | "version": 3 297 | }, 298 | "file_extension": ".py", 299 | "mimetype": "text/x-python", 300 | "name": "python", 301 | "nbconvert_exporter": "python", 302 | "pygments_lexer": "ipython3", 303 | "version": "3.7.6" 304 | } 305 | }, 306 | "nbformat": 4, 307 | "nbformat_minor": 2 308 | } 309 | -------------------------------------------------------------------------------- /11. Ecuaciones_diferenciales.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Una vez finalizado el curso, por favor ayúdanos completando la siguiente **Encuesta de FINAL del curso**.\n", 8 | "\n", 9 | "[![Final](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/Final.png/:/rs=w:1440,h:1440)](https://forms.office.com/Pages/ResponsePage.aspx?id=r4yvt9iDREaFrjF8VFIjwUHkKiCq1wxFstxAwkoFiilUOExRVkVMWlZERVcyWlpUU1EyTFg4T1Q3WC4u)\n", 10 | "\n", 11 | "## 11. Ecuaciones Diferenciales\n", 12 | "\n", 13 | "[Playlist de Ciencia de Datos en castellano](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67)\n", 14 | "[![Ciencia de Datos en Python](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/12-0001.png/:/rs=w:1160,h:653)](https://www.youtube.com/watch?v=HReAo38LoM4&list=PLLBUgWXdTBDg1Qgmwt4jKtVn9BWh5-zgy \"Python Data Science\")\n", 15 | "\n", 16 | "Algunas ecuaciones con términos diferenciales surgen de relaciones fundamentales como conservación de masa, energía y momento. Por ejemplo, la aculumación de masa $\\frac{dm}{dt}$ en un volumen de control es igual a la masa que entra $\\dot m_{in}$ menos la masa que sale $\\dot m_{out}$ de ese volumen. \n", 17 | "\n", 18 | "$\\frac{dm}{dt} = \\dot m_{in} - \\dot m_{out}$\n", 19 | "\n", 20 | "Se puede desarrollar un modelo dinámico mediante regresión de datos o con relaciones fundamentales sin necesidad de datos. Incluso las relaciones fundamentales pueden tener parámetros desconocidos o inciertos. Un enfoque para el modelado dinámico es combinar relaciones físicas fundamentales con Ciencia de Datos. Este enfoque usa lo mejor de ambos métodos porque crea un modelo que se alinea con los valores medidos y puede extrapolarse a regiones donde los datos son limitados o inexistentes. \n", 21 | "\n", 22 | "![exercise](https://apmonitor.com/che263/uploads/Begin_Python/exercise.png)\n", 23 | "\n", 24 | "En este primer ejercicio para [resolver ecuaciones diferenciales](https://www.youtube.com/watch?v=v9fGOHQMeIA) vamos a utilizar `odeint`. Los mismos ejemplos también serán [resueltos con Gekko](https://apmonitor.com/pdc/index.php/Main/PythonDifferentialEquations). Ambos alcanzan resultados equivalentes de simulación. Sin embargo, Gekko está diseñado para usar ecuaciones diferenciales en optimización o combinarse con aprendizaje automático (machine learning). La función `odeint` tiene como propósito principal resolver ecuaciones diferenciales ordinarias (EDO), y requiere tres entradas (inputs).\n", 25 | "\n", 26 | " y = odeint(model, y0, t)\n", 27 | "\n", 28 | "1. `model` Nombre de la Función que devuelve la derivada para un par de valores solicitados `y`, `t`, de la forma `dydt = model(y,t)`.\n", 29 | "2. `y0` Condiciones iniciales.\n", 30 | "3. `t` Puntos de tiempo donde se reporta la solución. \n", 31 | "\n", 32 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 33 | "\n", 34 | "### Resolver Ecuaciones Diferenciales\n", 35 | "\n", 36 | "Resolveremos la ecuación diferencial con la condición inicial $y(0) = 5$:\n", 37 | "\n", 38 | "$ k \\, \\frac{dy}{dt} = -y$\n", 39 | "\n", 40 | "Donde $k=10$. La solución para `y` se reporta desde un tiempo inicial `0` hasta un tiempo final `20`. También se grafica el resultado para $y(t)$ vs. $t$. Notemos cómo se establece la ecuación para obtener la derivada como `dydt = -(1.0/k) * y` a partir de la función." 41 | ] 42 | }, 43 | { 44 | "cell_type": "code", 45 | "execution_count": null, 46 | "metadata": {}, 47 | "outputs": [], 48 | "source": [ 49 | "import numpy as np\n", 50 | "from scipy.integrate import odeint\n", 51 | "\n", 52 | "# función que devuelve dy/dt\n", 53 | "def model(y,t):\n", 54 | " k = 10.0\n", 55 | " dydt = -(1.0/k) * y\n", 56 | " return dydt\n", 57 | "\n", 58 | "y0 = 5 # condición inicial\n", 59 | "t = np.linspace(0,20) # puntos de tiempo\n", 60 | "y = odeint(model,y0,t) # resolución de la ODE\n", 61 | "\n", 62 | "import matplotlib.pyplot as plt\n", 63 | "%matplotlib inline\n", 64 | "plt.plot(t,y)\n", 65 | "plt.xlabel('Tiempo'); plt.ylabel('y(t)')\n", 66 | "\n", 67 | "plt.show()" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": {}, 73 | "source": [ 74 | "![gekko](https://apmonitor.com/che263/uploads/Begin_Python/gekko.png)\n", 75 | "\n", 76 | "### Resolver Ecuaciones Diferenciales con Gekko\n", 77 | "\n", 78 | "[Python Gekko](https://gekko.readthedocs.io/en/latest/) resuelve la misma ecuación diferencial. Está diseñado para problemas a gran escala. El [tutorial de Gekko en inglés](https://apmonitor.com/wiki/index.php/Main/GekkoPythonOptimization) nos muestra cómo resolver otro tipo de problemas con ecuaciones y optimización." 79 | ] 80 | }, 81 | { 82 | "cell_type": "code", 83 | "execution_count": null, 84 | "metadata": {}, 85 | "outputs": [], 86 | "source": [ 87 | "from gekko import GEKKO\n", 88 | "\n", 89 | "m = GEKKO(remote=False) # modelo GEKKO\n", 90 | "m.time = np.linspace(0,20) # puntos de tiempo\n", 91 | "y = m.Var(5.0); k = 10.0 # variables y constantes GEKKO\n", 92 | "m.Equation(k*y.dt()+y==0) # Ecuación GEKKO\n", 93 | "\n", 94 | "m.options.IMODE = 4 # Simulación dinámica\n", 95 | "m.solve(disp=False) # Resolución\n", 96 | "\n", 97 | "plt.plot(m.time,y)\n", 98 | "plt.xlabel('Tiempo'); plt.ylabel('y(t)')\n", 99 | "plt.show()" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "metadata": {}, 105 | "source": [ 106 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 107 | "\n", 108 | "### Actividad sobre Ecuaciones Diferenciales\n", 109 | "\n", 110 | "Resuelve la ecuación diferencial con condición inicial $y(0) = 10$:\n", 111 | "\n", 112 | "$ k \\, \\frac{dy}{dt} = -y$\n", 113 | "\n", 114 | "Compara las primeras cinco soluciones de `y` entre los tiempos `0` y `20` con `k=[1,2,5,10,20]`." 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": null, 120 | "metadata": {}, 121 | "outputs": [], 122 | "source": [] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": {}, 127 | "source": [ 128 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 129 | "\n", 130 | "### Solución Simbólica \n", 131 | "\n", 132 | "Los problemas con ecuaciones diferenciales que tienen solución analítica pueden expresarse simbólicamente. Una librería con símbolos matemáticos en Python es `sympy`. Sympy determina la solución analítica como $y(x)=C_1 \\, \\exp{\\left(-\\frac{x}{k}\\right)}$. Con la condición inicial $y(0)=5$, y la constante $C_1$ igual a 5." 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": null, 138 | "metadata": {}, 139 | "outputs": [], 140 | "source": [ 141 | "from IPython.display import display\n", 142 | "import sympy as sym\n", 143 | "from sympy.abc import x, k\n", 144 | "y = sym.Function('y')\n", 145 | "ans = sym.dsolve(sym.Derivative(y(x), x) + y(x)/k, y(x))\n", 146 | "display(ans)" 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 154 | "\n", 155 | "### Resolver Ecuaciones Diferenciales con Entradas (Input) `u`\n", 156 | "\n", 157 | "Las ecuaciones diferenciales también pueden tener una entrada (atributo) que cambie desde una fuente externa (entrada exógena). Por ejemplo, cambios interactivos debido a medidas de un sensor, a personas (manualmente) o seleccionados por un computador.\n", 158 | "\n", 159 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 160 | "\n", 161 | "Calcula la respuesta `y(t)` cuando la entrada `u` cambia desde `0` a `2` en `t = 5`.\n", 162 | "\n", 163 | "$2 \\frac{dy(t)}{dt} + y(t) = u(t)$\n", 164 | "\n", 165 | "La condición inicial es `y(0)=1` y la solución puede calcularse hasta `t=15`. **Ayuda**: La expresión `y(t)` no es equivalente a `y` multiplicado por `t`. Esta indica que `y` cambia con el tiempo y se escribe como una función del tiempo. Hay ejemplos adicionales para [odeint en inglés](https://apmonitor.com/pdc/index.php/Main/SolveDifferentialEquations) y [Gekko en inglés](https://apmonitor.com/pdc/index.php/Main/PythonDifferentialEquations) por si necesitas ayuda." 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": null, 171 | "metadata": {}, 172 | "outputs": [], 173 | "source": [] 174 | }, 175 | { 176 | "cell_type": "markdown", 177 | "metadata": {}, 178 | "source": [ 179 | "### Actividad con el TCLab\n", 180 | "\n", 181 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 182 | "\n", 183 | "### Recolección de Datos\n", 184 | "\n", 185 | "![connections](https://apmonitor.com/che263/uploads/Begin_Python/connections.png)\n", 186 | "\n", 187 | "Enciende el calentador 1 al 100% y guarda el valor de $T_1$ cada 5 segundos durante 3 minutos. Los datos deben incluir un total de 37 puntos para cada sensor de temperatura." 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "execution_count": null, 193 | "metadata": {}, 194 | "outputs": [], 195 | "source": [ 196 | "import numpy as np\n", 197 | "import pandas as pd\n", 198 | "import tclab\n", 199 | "import time\n", 200 | "# Recolectar datos por 3 minutos, cada 5 segundos\n", 201 | "n = 37\n", 202 | "tm = np.linspace(0,180,n)\n", 203 | "t1s = np.empty(n); t2s = np.empty(n)\n", 204 | "with tclab.TCLab() as lab:\n", 205 | " lab.Q1(100); lab.Q2(0)\n", 206 | " print('Tiempo T1 T2')\n", 207 | " for i in range(n):\n", 208 | " t1s[i] = lab.T1; t2s[i] = lab.T2\n", 209 | " print(tm[i],t1s[i],t2s[i])\n", 210 | " time.sleep(5.0)\n", 211 | "# Colocar en un Dataframe\n", 212 | "data = pd.DataFrame(np.column_stack((tm,t1s,t2s)),\\\n", 213 | " columns=['Tiempo','T1','T2'])\n", 214 | "data.to_csv('11-data.csv',index=False)" 215 | ] 216 | }, 217 | { 218 | "cell_type": "markdown", 219 | "metadata": {}, 220 | "source": [ 221 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 222 | "\n", 223 | "### Resolver Ecuaciones Diferenciales\n", 224 | "\n", 225 | "Usa los parámetros `a`, `b` y `c` del módulo [10. Resolver Ecuaciones](https://github.com/APMonitor/data_science/blob/master/10.%20Solve_Equations.ipynb) o utiliza los siguientes valores:\n", 226 | "\n", 227 | "| Parámetro | Valor |\n", 228 | "|------|------|\n", 229 | "| a | 78.6 |\n", 230 | "| b | -50.3 |\n", 231 | "| c | -0.003677 |\n", 232 | "\n", 233 | "Resuelve la ecuación diferencial ordinaria (ODE en inglés) con estos valores.\n", 234 | "\n", 235 | "$\\frac{dT_1}{dt} = c (T_1-a)$\n", 236 | "\n", 237 | "La condición inicial para $T_1$ es $a + b$. Muestra la solución para la ODE en el intervalo de tiempo desde `0` hasta `180` segundos. Grafica el valor medido de $T_1$ en la misma figura que muestra la predicción de la temperatura por la ODE. Añade las etiquetas necesarias en el gráfico." 238 | ] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "execution_count": null, 243 | "metadata": {}, 244 | "outputs": [], 245 | "source": [] 246 | } 247 | ], 248 | "metadata": { 249 | "kernelspec": { 250 | "display_name": "Python 3", 251 | "language": "python", 252 | "name": "python3" 253 | }, 254 | "language_info": { 255 | "codemirror_mode": { 256 | "name": "ipython", 257 | "version": 3 258 | }, 259 | "file_extension": ".py", 260 | "mimetype": "text/x-python", 261 | "name": "python", 262 | "nbconvert_exporter": "python", 263 | "pygments_lexer": "ipython3", 264 | "version": "3.7.6" 265 | } 266 | }, 267 | "nbformat": 4, 268 | "nbformat_minor": 2 269 | } 270 | -------------------------------------------------------------------------------- /02. Importar_Exportar.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### Encuesta\n", 8 | "\n", 9 | "Este trabajo es parte de una investigación que busca cuantificar el impacto de integrar Hardware (TCLab) con Software (Programación en Python).\n", 10 | "\n", 11 | "Si ya realizaste la encuesta continúa a **2. Importar y Exportar Datos**. De lo contrario, por favor completa la siguiente encuesta de **INICIO de Curso**.\n", 12 | "\n", 13 | "[![Inicio](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/Inicio.png/:/rs=w:1440,h:1440)](https://forms.office.com/Pages/ResponsePage.aspx?id=r4yvt9iDREaFrjF8VFIjwUHkKiCq1wxFstxAwkoFiilUQVZDTk5MM0ZXOTdONjc1SFlZVTQ3VlJMNi4u)\n", 14 | "\n", 15 | "## 2. Importar y Exportar Datos\n", 16 | "\n", 17 | "[Playlist de Ciencia de Datos en castellano](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67)\n", 18 | "[![Ciencia de Datos en Python](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/3-0002.png/:/rs=w:1160,h:653)](https://www.youtube.com/watch?v=_KxudbrxS4A&list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67&index=3)\n", 19 | "\n", 20 | "Python tiene funciones para leer, crear, o borrar archivos. Los pasos de alto nivel para aplicaciones de Ciencia de Datos consisten en importar datos, analizarlos y exportar los resultados.\n", 21 | "\n", 22 | "### `open` para leer o escribir\n", 23 | "\n", 24 | "Una función básica para trabajar con archivos es `open(filename,mode)`. El `filename` es un \"string\" (caracteres) que identifica el archivo a abrir y `mode` indica cómo se debe abrir el archivo: `'r'` para leer, `'a'` para añadir (append), `'w'` para escribir, y `'x'` para crear (devuelve un error si el archivo existe). También puede especificar si el archivo debe manejarse como un archivo de texto `'t'` o binario `'b'`. Los valores predeterminados son `'rt'` para leer un archivo en modo texto." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "# escribir un archivo de prueba con un mensaje\n", 34 | "f = open('02-file.txt','w')\n", 35 | "f.write('Este es un archivo de prueba')\n", 36 | "f.close()\n", 37 | "\n", 38 | "import os\n", 39 | "print('Archivo guardado en: ' + os.getcwd())\n", 40 | "\n", 41 | "# leer e imprimir el contenido del archivo\n", 42 | "f = open('02-file.txt')\n", 43 | "print(f.read())\n", 44 | "f.close()" 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "metadata": {}, 50 | "source": [ 51 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 52 | "\n", 53 | "### Escribir archivos de datos\n", 54 | "\n", 55 | "Un archivo de datos común es el \"Comma Separated Value\" (CSV) -valor separado por coma- donde las entradas están delimitadas (separadas) por una coma. Hay algunos datos `m` que nos gustaría escribir en un archivo CSV con encabezados en `clist`. Este ejemplo muestra cómo escribir el archivo CSV con varios módulos.\n", 56 | "\n", 57 | "```\n", 58 | "x,y,z\n", 59 | "1,2,3\n", 60 | "4,5,6\n", 61 | "7,8,9\n", 62 | "```\n", 63 | "\n", 64 | "Después de ejecutar cada celda, abrimos el archivo en su directorio de ejecución con Excel o un editor de texto.\n", 65 | "\n", 66 | "#### (Abrir) `open` y el módulo `csv`\n", 67 | "\n", 68 | "El comando `with` cierra automáticamente el archivo cuando se completan los comandos dentro del bloque. El `newline=''` es necesario solamente para Windows. La función `writerow` escribe una fila del archivo CSV." 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": null, 74 | "metadata": {}, 75 | "outputs": [], 76 | "source": [ 77 | "clist = ['x','y','z']\n", 78 | "m = [[1,2,3],\\\n", 79 | " [4,5,6],\\\n", 80 | " [7,8,9]]\n", 81 | "\n", 82 | "import csv\n", 83 | "with open('02-data1.csv',mode='w',newline='') as f:\n", 84 | " cw = csv.writer(f)\n", 85 | " cw.writerow(clist)\n", 86 | " for i in range(len(m)):\n", 87 | " cw.writerow(m[i])" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "#### escribir en CSV con `numpy`\n", 95 | "\n", 96 | "La librería numérica de Python `numpy` es utilizada a lo largo de este curso. La función `np.savetxt` requiere el nombre del archivo, los datos `m`, el tipo de delimitador `,`, y el encabezado. Si `comments=''` es omitido entonces el encabezado va a tener un signo `#` enfrente." 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": null, 102 | "metadata": {}, 103 | "outputs": [], 104 | "source": [ 105 | "import numpy as np\n", 106 | "np.savetxt('02-data2.csv',m,delimiter=',',comments='',header='x,y,z')" 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "metadata": {}, 112 | "source": [ 113 | "#### escribir en CSV con `pandas`\n", 114 | "\n", 115 | "El módulo `pandas` requiere que la data este con la estructura `DataFrame` para escritura." 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": {}, 122 | "outputs": [], 123 | "source": [ 124 | "import pandas as pd\n", 125 | "df = pd.DataFrame(m,columns=clist)\n", 126 | "df.to_csv('02-data3.csv',index=False)" 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "#### `pandas` escribe en XLSX y JSON\n", 134 | "\n", 135 | "`pandas` también puede escribir otros archivos como json o Excel. Puede que necesites instalar openpyxl para escribir el archivo Excel. Puedes hacer esto en una celda anotando `!pip install openpyxl` e incluir `--user` si no tienes privilegios de administrador.Es posible que debas reiniciar el kernel del IPython notebook antes de que pip instale la librería `openpyxl`." 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [ 144 | "df.to_json('02-data3.json',orient='table',index=False)\n", 145 | "df.to_excel('02-data3.xlsx',index=False)" 146 | ] 147 | }, 148 | { 149 | "cell_type": "markdown", 150 | "metadata": {}, 151 | "source": [ 152 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 153 | "\n", 154 | "### Actividad de Escritura\n", 155 | "\n", 156 | "Utiliza `numpy` para crear `51` valores igualmente espaciados para `x` entre `0` y `100`. Calcular `y=x**2` y `z=x**3` que se derivan de `x`. Almacena `x`, `y`, y `z` en un archivo CSV con los encabezados del archivo `02-test.csv`." 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": null, 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": {}, 169 | "source": [ 170 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 171 | "\n", 172 | "### Lee Archivos de Datos\n", 173 | "\n", 174 | "Al igual que para escribir archivos CSV, existen librerías para leer archivos de datos.\n", 175 | "\n", 176 | "#### Utiliza `numpy` para leer un CSV\n", 177 | "\n", 178 | "La función `np.loadtxt` lee datos de un archivo CSV con la opción `skiprows=1` para omitir la fila del encabezado. Numpy no etiqueta las filas o columnas y solo almacena los valores CSV." 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": null, 184 | "metadata": {}, 185 | "outputs": [], 186 | "source": [ 187 | "data = np.loadtxt('02-data1.csv',delimiter=',',skiprows=1)\n", 188 | "print(data)" 189 | ] 190 | }, 191 | { 192 | "cell_type": "markdown", 193 | "metadata": {}, 194 | "source": [ 195 | "#### Utiliza `pandas` para leer un CSV\n", 196 | "\n", 197 | "La función `pd.read_csv` lee datos de un archivo CSV incluyendo la fila del encabezado. Las funciones `data.head()` y `data.tail()` imprime los primeros o últimos 5 valores, respectivamente." 198 | ] 199 | }, 200 | { 201 | "cell_type": "code", 202 | "execution_count": null, 203 | "metadata": {}, 204 | "outputs": [], 205 | "source": [ 206 | "data = pd.read_csv('02-data1.csv')\n", 207 | "data.head()" 208 | ] 209 | }, 210 | { 211 | "cell_type": "markdown", 212 | "metadata": {}, 213 | "source": [ 214 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 215 | "\n", 216 | "### Actividad de Leer\n", 217 | "\n", 218 | "Utiliza `pandas` para leer el archivo `02-test.csv` creado anteriormente. Muestra las primeras 5 filas del archivo." 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": null, 224 | "metadata": {}, 225 | "outputs": [], 226 | "source": [] 227 | }, 228 | { 229 | "cell_type": "markdown", 230 | "metadata": {}, 231 | "source": [ 232 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 233 | "\n", 234 | "### Eliminar Archivos de Datos\n", 235 | "\n", 236 | "También es posible eliminar archivos usando la librería `os` (operating system) de sistema operativo.\n", 237 | "\n", 238 | "```python\n", 239 | "import os\n", 240 | "os.remove('02-data1.csv')\n", 241 | "```\n", 242 | "\n", 243 | "El módulo `glob` genera una lista de archivos que inician con `02-data` y terminan con `.csv`. Utiliza el carácter comodín `*` para seleccionar cualquier archivo que coincida con la primera y la última parte.\n", 244 | "\n", 245 | "```python\n", 246 | "['02-data1.csv', '02-data2.csv', '02-data3.csv']\n", 247 | "```\n", 248 | "\n", 249 | "Si la primera letra de la respuesta del usuario es `y`entonces borra estos archivos." 250 | ] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": null, 255 | "metadata": {}, 256 | "outputs": [], 257 | "source": [ 258 | "import os\n", 259 | "import glob\n", 260 | "filelist = glob.glob('02-data*.csv')\n", 261 | "\n", 262 | "if filelist==[]:\n", 263 | " print('No files to delete')\n", 264 | " ans='no'\n", 265 | "else:\n", 266 | " ans = input('Delete files '+str(filelist)+'? ')\n", 267 | "\n", 268 | "if ans[0].lower()=='y':\n", 269 | " for f in filelist:\n", 270 | " os.remove(f)" 271 | ] 272 | }, 273 | { 274 | "cell_type": "markdown", 275 | "metadata": {}, 276 | "source": [ 277 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 278 | "\n", 279 | "### Actividad de Borrar\n", 280 | "\n", 281 | "Elimina el archivo `02-test.csv` utilizando Python." 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": null, 287 | "metadata": {}, 288 | "outputs": [], 289 | "source": [] 290 | }, 291 | { 292 | "cell_type": "markdown", 293 | "metadata": {}, 294 | "source": [ 295 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 296 | "\n", 297 | "### Actividad con el TCLab\n", 298 | "\n", 299 | "![connections](https://apmonitor.com/che263/uploads/Begin_Python/connections.png)\n", 300 | "\n", 301 | "Escribir el archivo de datos `02-tclab.csv` con 5 columnas que incluyan tiempo en segundos (`t`), niveles de calentador (`Q1` y `Q2`), y temperaturas (`lab.T1` y `lab.T2`). Incluye una fila de datos cada segundo durante 20 segundos. El script de inicio solo imprime esos valores en la pantalla, pero también deben guardarse en un archivo." 302 | ] 303 | }, 304 | { 305 | "cell_type": "code", 306 | "execution_count": null, 307 | "metadata": {}, 308 | "outputs": [], 309 | "source": [ 310 | "import tclab\n", 311 | "import time\n", 312 | "n = 20\n", 313 | "Q1 = 30; Q2 = 70\n", 314 | "with tclab.TCLab() as lab:\n", 315 | " lab.Q1(Q1); lab.Q2(Q2)\n", 316 | " with open('02-tclab.csv',mode='w',newline='') as f:\n", 317 | " cw = csv.writer(f)\n", 318 | " cw.writerow(['t','Q1','Q2','T1','T2'])\n", 319 | " # print('t Q1 Q2 T1 T2')\n", 320 | " for t in range(n):\n", 321 | " print(t,Q1,Q2,lab.T1,lab.T2)\n", 322 | " cw.writerow([t,Q1,Q2,lab.T1,lab.T2])\n", 323 | " time.sleep(1)" 324 | ] 325 | }, 326 | { 327 | "cell_type": "markdown", 328 | "metadata": {}, 329 | "source": [ 330 | "Lee el archivo `02-tclab.csv` e imprima las primeras 5 filas. Si no tienes el TCLab, lee el archivo de datos del `url` utilizando `data=pd.read_csv(url)`\n", 331 | "\n", 332 | "```python\n", 333 | "# lee este archivo si no tienes un TCLab\n", 334 | "url = 'http://apmonitor.com/pdc/uploads/Main/tclab_data2.txt'\n", 335 | "```" 336 | ] 337 | }, 338 | { 339 | "cell_type": "code", 340 | "execution_count": null, 341 | "metadata": {}, 342 | "outputs": [], 343 | "source": [] 344 | } 345 | ], 346 | "metadata": { 347 | "kernelspec": { 348 | "display_name": "Python 3", 349 | "language": "python", 350 | "name": "python3" 351 | }, 352 | "language_info": { 353 | "codemirror_mode": { 354 | "name": "ipython", 355 | "version": 3 356 | }, 357 | "file_extension": ".py", 358 | "mimetype": "text/x-python", 359 | "name": "python", 360 | "nbconvert_exporter": "python", 361 | "pygments_lexer": "ipython3", 362 | "version": "3.7.6" 363 | } 364 | }, 365 | "nbformat": 4, 366 | "nbformat_minor": 2 367 | } 368 | -------------------------------------------------------------------------------- /05. Preparar_data.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 5. Preparación de Datos\n", 8 | "\n", 9 | "[Playlist de Ciencia de Datos en castellano](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67)\n", 10 | "[![Ciencia de Datos en Python](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/6-0001.png/:/rs=w:1160,h:653)](https://www.youtube.com/watch?v=otKULhEP-ik&list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67&index=6)\n", 11 | "\n", 12 | "Gran parte del trabajo en Ciencia de Datos y Aprendizaje Automático (Machine Learning) consiste en obtener datos limpios y en la forma correcta. Esto puede incluir limpieza de datos para eliminar valores atípicos o mala información, escalado para algoritmos de aprendizaje automático o machine learning, división en grupos de entrenamiento y prueba, y enumeración de datos tipo \"string\". Todo esto debe suceder antes de la regresión, clasificación u otro entrenamiento aplicado al modelo. Afortunadamente, existen funciones que nos ayudan a automatizar la preparación de los datos.\n", 13 | "\n", 14 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 15 | "\n", 16 | "### Generar Datos de Muestra\n", 17 | "\n", 18 | "Ejecuta la siguiente celda para generar datos de muestra dañados con NaN (not a number) y valores atípicos que son puntos de datos erróneos que están muy por fuera de la tendencia esperada." 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "import numpy as np\n", 28 | "import pandas as pd\n", 29 | "np.random.seed(1)\n", 30 | "n = 100\n", 31 | "tt = np.linspace(0,n-1,n)\n", 32 | "x = np.random.rand(n)+10+np.sqrt(tt)\n", 33 | "y = np.random.normal(10,x*0.01,n)\n", 34 | "x[1] = np.nan; y[2] = np.nan # 2 NaN (not a number)\n", 35 | "for i in range(3): # añade 3 valores atípicos (datos malos)\n", 36 | " ri = np.random.randint(0,n)\n", 37 | " x[ri] += np.random.rand()*100\n", 38 | "data = pd.DataFrame(np.vstack((tt,x,y)).T,\\\n", 39 | " columns=['time','x','y'])\n", 40 | "data.head()" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "![analyze](https://apmonitor.com/che263/uploads/Begin_Python/analyze.png)\n", 48 | "\n", 49 | "### Visualización de los Datos\n", 50 | "\n", 51 | "Los valores atípicos se muestran en un gráfico semi-log. Los valores `NaN` no se muestran en la gráfica y son puntos faltantes." 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "import matplotlib.pyplot as plt\n", 61 | "%matplotlib inline\n", 62 | "plt.semilogy(tt,x,'r.',label='x')\n", 63 | "plt.semilogy(tt,y,'b.',label='y')\n", 64 | "plt.legend(); plt.xlabel('tiempo')\n", 65 | "plt.text(50,60,'Valores atípicos')\n", 66 | "plt.show()" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 74 | "\n", 75 | "### Eliminar Valores Atípicos y Datos Erróneos\n", 76 | "\n", 77 | "Los valores NaN se eliminan con `numpy` identificando filas `ix` que contienen `NaN`. A continuación, las filas se eliminan con `z=z[~iz]` donde `~` Es un operador `not`." 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "z = np.array([[ 1, 2],\n", 87 | " [ np.nan, 3],\n", 88 | " [ 4, np.nan],\n", 89 | " [ 5, 6]])\n", 90 | "iz = np.any(np.isnan(z), axis=1)\n", 91 | "print(~iz)\n", 92 | "z = z[~iz]\n", 93 | "print(z)" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": {}, 99 | "source": [ 100 | "El método `dropna` es un comando que quita filas `NaN` en un `pandas` `DataFrame`. La fila 1 y 2 son removidas." 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": null, 106 | "metadata": {}, 107 | "outputs": [], 108 | "source": [ 109 | "# eliminar cualquier fila con valores erróneos (NaN)\n", 110 | "data = data.dropna()\n", 111 | "data.head()" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "Existen varias técnicas gráficas para detectar valores atípicos. Un diagrama de caja o histograma muestra los 3 puntos periféricos." 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "plt.boxplot(data['x'])\n", 128 | "plt.show()" 129 | ] 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "metadata": {}, 134 | "source": [ 135 | "Una prueba de Grubbs u [otra medida estadística](https://towardsdatascience.com/ways-to-detect-and-remove-the-outliers-404d16608dba) puede detectar valores atípicos. La prueba de Grubbs asume datos univariados, normalmente distribuidos y está destinada a detectar solo un valor atípico. En la práctica, muchos valores atípicos se eliminan al remover puntos que violan un límite de cambio, o límites superior/inferior. El enunciado `data[data['x']<30]` mantiene las filas donde x es menor a 30." 136 | ] 137 | }, 138 | { 139 | "cell_type": "code", 140 | "execution_count": null, 141 | "metadata": {}, 142 | "outputs": [], 143 | "source": [ 144 | "data = data[data['x']<30]\n", 145 | "plt.boxplot(data['x'])\n", 146 | "plt.show()" 147 | ] 148 | }, 149 | { 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 154 | "\n", 155 | "### Actividad con Tiempo\n", 156 | "\n", 157 | "Sin mirar tu reloj, ejecuta la siguiente celda para registrar intervalos de 1 segundo durante 10 segundos. Cuando ejecutes la celda, presiona `Enter` cada vez que creas que ha pasado 1 segundo. Después de recopilar los datos, utiliza un diagrama de caja para identificar cualquier punto de datos en `tsec` que son valores atípicos." 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": null, 163 | "metadata": {}, 164 | "outputs": [], 165 | "source": [ 166 | "import time\n", 167 | "from IPython.display import clear_output\n", 168 | "tsec = []\n", 169 | "input('Presiona \"Enter\" para grabar intervalos de 1 segundo'); t = time.time()\n", 170 | "for i in range(10):\n", 171 | " clear_output(); input('Presiona \"Enter\": ' + str(i+1))\n", 172 | " tsec.append(time.time()-t); t = time.time()\n", 173 | "clear_output(); print('Completo. Agrega un diagrama de caja para identificar valores atípicos')" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": null, 179 | "metadata": {}, 180 | "outputs": [], 181 | "source": [ 182 | "# Agregar un diagrama de caja para identificar valores atípicos" 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": {}, 188 | "source": [ 189 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 190 | "\n", 191 | "### Escala de Datos\n", 192 | "\n", 193 | "La librería `sklearn` tiene un módulo de pre-procesamiento (`preprocessing`) para implementar métodos de escalado estándar. El `StandardScalar` se muestra a continuación. Cada columna se normaliza a una media cero y una desviación estándar de uno. Los métodos de escalado comunes `fit_transform(X)` para ajuste y `transform(X)` transformación basado en otro ajuste, y `inverse_transform(Xs)` para volver a escalar a la representación original." 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": null, 199 | "metadata": {}, 200 | "outputs": [], 201 | "source": [ 202 | "from sklearn.preprocessing import StandardScaler\n", 203 | "s = StandardScaler()\n", 204 | "ds = s.fit_transform(data)\n", 205 | "print(ds[0:5]) # imprime 5 filas" 206 | ] 207 | }, 208 | { 209 | "cell_type": "markdown", 210 | "metadata": {}, 211 | "source": [ 212 | "El valor `ds` se devuelve como un array `numpy` así que tenemos que convertirlo de nuevo a `pandas` `DataFrame`, reutilizando los nombres de columna `data`." 213 | ] 214 | }, 215 | { 216 | "cell_type": "code", 217 | "execution_count": null, 218 | "metadata": {}, 219 | "outputs": [], 220 | "source": [ 221 | "ds = pd.DataFrame(ds,columns=data.columns)\n", 222 | "ds.head()" 223 | ] 224 | }, 225 | { 226 | "cell_type": "markdown", 227 | "metadata": {}, 228 | "source": [ 229 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 230 | "\n", 231 | "### Dividir Datos\n", 232 | "\n", 233 | "Los datos se dividen en grupos de entrenamiento y prueba para separar una fracción de las filas para evaluar modelos de clasificación o regresión. Una división típica es 80% para entrenamiento y 20% para pruebas, aunque el rango depende de la cantidad de datos disponibles y del objetivo del estudio." 234 | ] 235 | }, 236 | { 237 | "cell_type": "code", 238 | "execution_count": null, 239 | "metadata": {}, 240 | "outputs": [], 241 | "source": [ 242 | "divide = int(len(ds)*0.8)\n", 243 | "train = ds[0:divide]\n", 244 | "test = ds[divide:]\n", 245 | "print(len(train),len(test))" 246 | ] 247 | }, 248 | { 249 | "cell_type": "markdown", 250 | "metadata": {}, 251 | "source": [ 252 | "El `train_test_split` es una función de `sklearn` que tiene el propósito específico de dividir los datos en grupos de entrenamiento y prueba. Existen opciones como `shuffle=True` para aleatorizar la selección en cada conjunto. " 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": null, 258 | "metadata": {}, 259 | "outputs": [], 260 | "source": [ 261 | "from sklearn.model_selection import train_test_split\n", 262 | "train,test = train_test_split(ds, test_size=0.2, shuffle=True)\n", 263 | "print(len(train),len(test))" 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": {}, 269 | "source": [ 270 | "### Actividad con el TCLab\n", 271 | "\n", 272 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 273 | "\n", 274 | "### Datos con Valores Erróneos y Atípicos\n", 275 | "\n", 276 | "Genera un nuevo archivo de datos con algunos datos incorrectos insertados aleatoriamente (3 minutos) o lee el archivo de datos de [un link en la web](https://apmonitor.com/do/uploads/Main/tclab_bad_data.txt) con el siguiente código." 277 | ] 278 | }, 279 | { 280 | "cell_type": "code", 281 | "execution_count": null, 282 | "metadata": {}, 283 | "outputs": [], 284 | "source": [ 285 | "import tclab, time, csv\n", 286 | "import numpy as np\n", 287 | "\n", 288 | "try:\n", 289 | " with tclab.TCLab() as lab:\n", 290 | " with open('05-tclab.csv',mode='w',newline='') as f:\n", 291 | " cw = csv.writer(f)\n", 292 | " cw.writerow(['Time','Q1','Q2','T1','T2'])\n", 293 | " print('t Q1 Q2 T1 T2')\n", 294 | " for t in range(180):\n", 295 | " T1 = lab.T1; T2 = lab.T2\n", 296 | " # insertar valores malos\n", 297 | " bad = np.random.randint(0,30)\n", 298 | " T1=np.nan if bad==10 else T1\n", 299 | " T2=np.nan if bad==15 else T2\n", 300 | " # insertar número aleatorio (potencial valor atípico)\n", 301 | " outlier = np.random.randint(-40,150)\n", 302 | " T1=outlier if bad==20 else T1\n", 303 | " T2=outlier if bad==25 else T2\n", 304 | " # cambiar el calentador\n", 305 | " if t%30==0:\n", 306 | " Q1 = np.random.randint(0,81)\n", 307 | " Q2 = np.random.randint(0,81)\n", 308 | " lab.Q1(Q1); lab.Q2(Q2)\n", 309 | " cw.writerow([t,Q1,Q2,T1,T2])\n", 310 | " if t%10==0:\n", 311 | " print(t,Q1,Q2,T1,T2)\n", 312 | " time.sleep(1)\n", 313 | " data5=pd.read_csv('05-tclab.csv')\n", 314 | "except:\n", 315 | " print('Conectar el TCLab para generar nuevos datos')\n", 316 | " print('Importar datos de un repositorio en línea')\n", 317 | " url = 'http://apmonitor.com/do/uploads/Main/tclab_bad_data.txt'\n", 318 | " data5=pd.read_csv(url)" 319 | ] 320 | }, 321 | { 322 | "cell_type": "markdown", 323 | "metadata": {}, 324 | "source": [ 325 | "### Limpiar, Escalar y Dividir Datos\n", 326 | "\n", 327 | "Después de generar e importar `data5`, eliminar filas con valores `NaN` o valores atípicos en las columnas `T1` o `T2`. Escala los datos con `StandardScalar` en `scikit`. Divide los datos en grupos de entrenamiento (80%) y prueba (20%). " 328 | ] 329 | }, 330 | { 331 | "cell_type": "code", 332 | "execution_count": null, 333 | "metadata": {}, 334 | "outputs": [], 335 | "source": [] 336 | } 337 | ], 338 | "metadata": { 339 | "kernelspec": { 340 | "display_name": "Python 3", 341 | "language": "python", 342 | "name": "python3" 343 | }, 344 | "language_info": { 345 | "codemirror_mode": { 346 | "name": "ipython", 347 | "version": 3 348 | }, 349 | "file_extension": ".py", 350 | "mimetype": "text/x-python", 351 | "name": "python", 352 | "nbconvert_exporter": "python", 353 | "pygments_lexer": "ipython3", 354 | "version": "3.7.6" 355 | } 356 | }, 357 | "nbformat": 4, 358 | "nbformat_minor": 2 359 | } 360 | -------------------------------------------------------------------------------- /03. Analizar_data.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 3. Análisis de Datos\n", 8 | "\n", 9 | "[Playlist de Ciencia de Datos en castellano](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67)\n", 10 | "[![Ciencia de Datos en Python](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/4-0001.png/:/rs=w:1160,h:653)](https://www.youtube.com/watch?v=YlkNDdsxhgc&list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67&index=4)\n", 11 | "\n", 12 | "Una vez que los datos se leen en Python, un primer paso es analizarlos con estadísticos de resumen (summary statistics). Esto es particularmente cierto si el conjunto de datos es grande. Los estadísticos de resumen incluyen el conteo, la media, la desviación estándar, el máximo, el mínimo y la información de cuartiles para las columnas de datos.\n", 13 | "\n", 14 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 15 | "\n", 16 | "### Generar Datos\n", 17 | "\n", 18 | "Ejecuta la siguiente celda para:\n", 19 | "\n", 20 | "- Generar `n` valores espaciados linealmente entre `0` y `n-1` con `np.linspace(start,end,count)`\n", 21 | "- Selecciona muestras aleatorias de una distribución uniforme entre 0 y 1 con `np.random.rand(count)`\n", 22 | "- Selecciona muestras aleatorias de una distribución normal (gaussiana) con `np.random.normal(mean,std,count)`\n", 23 | "- Combinar `time`, `x`, e `y` con una columna vertical `np.vstack` y transponer `.T` para datos orientados a columnas.\n", 24 | "- Guardar un archivo de texto CSV `03-data.csv` con encabezado `time,x,y`." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "import numpy as np\n", 34 | "np.random.seed(0)\n", 35 | "n = 1000\n", 36 | "time = np.linspace(0,n-1,n)\n", 37 | "x = np.random.rand(n)\n", 38 | "y = np.random.normal(1,1,n)\n", 39 | "data = np.vstack((time,x,y)).T\n", 40 | "np.savetxt('03-data.csv',data,header='time,x,y',delimiter=',',comments='')" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 48 | "\n", 49 | "### Distribuciones de Datos\n", 50 | "\n", 51 | "El histograma es una vista previa de cómo crear gráficos para que los datos se puedan ser evaluados visualmente. [04. Visualización de datos](https://github.com/APMonitor/ciencia_de_datos/blob/main/04.%20Visualizar_data.ipynb) muestra cómo crear gráficos para el análisis de datos." 52 | ] 53 | }, 54 | { 55 | "cell_type": "code", 56 | "execution_count": null, 57 | "metadata": {}, 58 | "outputs": [], 59 | "source": [ 60 | "import matplotlib.pyplot as plt\n", 61 | "%matplotlib inline\n", 62 | "plt.hist(x,10,label='x')\n", 63 | "plt.hist(y,60,label='y',alpha=0.7)\n", 64 | "plt.ylabel('Count'); plt.legend()\n", 65 | "plt.show()" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 73 | "\n", 74 | "### Análisis de Datos con `numpy`\n", 75 | "\n", 76 | "La función `np.loadtxt` lee el archivo de datos CSV `03-data.csv`. Numpy alcula con `size` las dimensiones, con `mean` el promedio, con `std` la desviación estándar, y con `median` la mediana a manera de estadísticos de resumen. Si no especificas el eje (`axis`) entonces `numpy` da una estadística en ambas filas (`axis=0`) y columnas (`axis=1`)." 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "metadata": {}, 83 | "outputs": [], 84 | "source": [ 85 | "import numpy as np\n", 86 | "data = np.loadtxt('03-data.csv',delimiter=',',skiprows=1)\n", 87 | "\n", 88 | "print('Dimensión (filas,columnas):')\n", 89 | "print(np.size(data,0),np.size(data,1))\n", 90 | "\n", 91 | "print('Promedio:')\n", 92 | "print(np.mean(data,axis=0))\n", 93 | "\n", 94 | "print('Desviación Estándar:')\n", 95 | "print(np.std(data,0))\n", 96 | "\n", 97 | "print('Mediana:')\n", 98 | "print(np.median(data,0))" 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": {}, 104 | "source": [ 105 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 106 | "\n", 107 | "### Analizar datos\n", 108 | "\n", 109 | "1. Calcule la media, la desviación estándar y la mediana de `x*y`\n", 110 | "2. Calcule el sesgo o `skew` de `x*y` con `scipy.stats` [función de sesgo](https://docs.scipy.org/doc/scipy-0.15.1/reference/generated/scipy.stats.skew.html)." 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 125 | "\n", 126 | "### Análisis de Datos con `pandas`\n", 127 | "\n", 128 | "Pandas simplifica el análisis de datos con la función `.describe()` que es un método de`DataFrame` que se crea con `pd.read_csv()`. Ten en cuenta que el archivo de datos puede ser un nombre de archivo local o una dirección web como \n", 129 | "\n", 130 | "```python\n", 131 | "url='https://apmonitor.com/pdc/uploads/Main/tclab_data2.txt'\n", 132 | "data = pd.read_csv(url)\n", 133 | "data.describe()\n", 134 | "```" 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": {}, 141 | "outputs": [], 142 | "source": [ 143 | "import pandas as pd\n", 144 | "data = pd.read_csv('03-data.csv')\n", 145 | "data.describe()" 146 | ] 147 | }, 148 | { 149 | "cell_type": "markdown", 150 | "metadata": {}, 151 | "source": [ 152 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 153 | "\n", 154 | "### Análisis de Datos con `pandas-profiling`\n", 155 | "\n", 156 | "Pandas Profiling es una herramienta de análisis de datos para un resumen más profundo de los datos que la función `descibe()`. [Instalar la librería](https://pandas-profiling.github.io/pandas-profiling/docs/master/rtd/pages/installation.html) con:\n", 157 | "\n", 158 | "```python\n", 159 | "pip install --user pandas-profiling[notebook]\n", 160 | "jupyter nbextension enable --py widgetsnbextension\n", 161 | "```\n", 162 | "\n", 163 | "Debes reiniciar el kernel antes de continuar. La instalación solo necesita ejecutarse una vez." 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": null, 169 | "metadata": {}, 170 | "outputs": [], 171 | "source": [ 172 | "try:\n", 173 | " import pandas as pd\n", 174 | " from pandas_profiling import ProfileReport\n", 175 | " import os\n", 176 | "except:\n", 177 | " !pip install --user pandas-profiling\n", 178 | " !jupyter nbextension enable --py widgetsnbextension\n", 179 | " print('Reinicia el kernel antes de continuar')\n", 180 | " \n", 181 | "# import data\n", 182 | "url='https://apmonitor.com/pdc/uploads/Main/tclab_data2.txt'\n", 183 | "data = pd.read_csv(url)" 184 | ] 185 | }, 186 | { 187 | "cell_type": "markdown", 188 | "metadata": {}, 189 | "source": [ 190 | "Después de instalar `pandas-profiling` y habilitar la extensión del widget, ahora puedes importar y analizar datos. Algunas funciones toman mucho tiempo con sets de datos grandes. Dos métodos para trabajar con sets de datos grandes se indican a continuación:\n", 191 | "\n", 192 | "1. Submuestrear los conjuntos de datos con `data = data[::10]` para tomar cada 10ma fila.\n", 193 | "2. Usar la opción `minimal` para evitar el análisis correlación y otros análisis que son lentos con sets de datos grandes." 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": null, 199 | "metadata": {}, 200 | "outputs": [], 201 | "source": [ 202 | "profile = ProfileReport(data, explorative=True, minimal=False)" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "El informe de perfil se puede guardar como una página web interactiva. La página web se guarda en el directorio de trabajo actual que se muestra con `os.getcwd()`." 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": null, 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [ 218 | "profile.to_file('report.html')\n", 219 | "print('File report.html saved to '+os.getcwd())" 220 | ] 221 | }, 222 | { 223 | "cell_type": "markdown", 224 | "metadata": {}, 225 | "source": [ 226 | "El informe de perfil también se puede ver en el Jupyter Notebook." 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": null, 232 | "metadata": {}, 233 | "outputs": [], 234 | "source": [ 235 | "profile.to_widgets()" 236 | ] 237 | }, 238 | { 239 | "cell_type": "markdown", 240 | "metadata": {}, 241 | "source": [ 242 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 243 | "\n", 244 | "### Actividad con el TCLab\n", 245 | "\n", 246 | "![connections](https://apmonitor.com/che263/uploads/Begin_Python/connections.png)\n", 247 | "\n", 248 | "### Generar el Set de Datos 1\n", 249 | "\n", 250 | "Genera un archivo a partir de los datos del TCLab en segundos (`t`), niveles de calentador (`Q1` y `Q2`), y temperaturas (`lab.T1` y `lab.T2`). Registra los datos cada segundo durante 120 segundos y cambia los niveles del calentador cada 30 segundos a un número aleatorio entre 0 y 80 con `np.random.randint()`. No es necesario cambiar el programa, solo ejecútalo durante 2 minutos para almacenar los datos. Si no cuentas con un dispositivo TCLab, lee el Archivo de Datos 1 de [este link online](https://apmonitor.com/do/uploads/Main/tclab_dyn_data2.txt)." 251 | ] 252 | }, 253 | { 254 | "cell_type": "code", 255 | "execution_count": null, 256 | "metadata": {}, 257 | "outputs": [], 258 | "source": [ 259 | "import tclab, time, csv\n", 260 | "import pandas as pd\n", 261 | "import numpy as np\n", 262 | "try:\n", 263 | " # conectar al TCLab si está disponible\n", 264 | " n = 120 \n", 265 | " with open('03-tclab1.csv',mode='w',newline='') as f:\n", 266 | " cw = csv.writer(f)\n", 267 | " cw.writerow(['Time','Q1','Q2','T1','T2'])\n", 268 | " with tclab.TCLab() as lab:\n", 269 | " print('t Q1 Q2 T1 T2')\n", 270 | " for t in range(n):\n", 271 | " if t%30==0:\n", 272 | " Q1 = np.random.randint(0,81)\n", 273 | " Q2 = np.random.randint(0,81)\n", 274 | " lab.Q1(Q1); lab.Q2(Q2)\n", 275 | " cw.writerow([t,Q1,Q2,lab.T1,lab.T2])\n", 276 | " if t%5==0:\n", 277 | " print(t,Q1,Q2,lab.T1,lab.T2)\n", 278 | " time.sleep(2)\n", 279 | " file = '03-tclab1.csv'\n", 280 | " data1=pd.read_csv(file)\n", 281 | "except:\n", 282 | " print('No se encontró ningún dispositivo TCLab, leyendo el archivo en línea')\n", 283 | " url = 'http://apmonitor.com/do/uploads/Main/tclab_dyn_data2.txt'\n", 284 | " data1=pd.read_csv(url)" 285 | ] 286 | }, 287 | { 288 | "cell_type": "markdown", 289 | "metadata": {}, 290 | "source": [ 291 | "### Leer el Set de Datos 2\n", 292 | "\n", 293 | "Utiliza `requests` para descargar un archivo de datos del TCLab de muestra para el análisis. Se guarda como `03-tclab2.csv`." 294 | ] 295 | }, 296 | { 297 | "cell_type": "code", 298 | "execution_count": null, 299 | "metadata": {}, 300 | "outputs": [], 301 | "source": [ 302 | "import requests\n", 303 | "import os\n", 304 | "url = 'http://apmonitor.com/pdc/uploads/Main/tclab_data2.txt'\n", 305 | "r = requests.get(url)\n", 306 | "with open('03-tclab2.csv', 'wb') as f:\n", 307 | " f.write(r.content)\n", 308 | " \n", 309 | "print('File 03-tclab2.csv recuperado al directorio de trabajo actual: ')\n", 310 | "print(os.getcwd())" 311 | ] 312 | }, 313 | { 314 | "cell_type": "markdown", 315 | "metadata": {}, 316 | "source": [ 317 | "### Análisis de Datos\n", 318 | "\n", 319 | "Lee los archivos `03-tclab1.csv` y `03-tclab2.csv` y muestra los estadísticos de resumen para cada uno con `data.describe()`. Utiliza los estadísticos de resumen para comparar el número de muestras y las diferencias en el valor de desviación estándar y promedio para `T1` y `T2`." 320 | ] 321 | }, 322 | { 323 | "cell_type": "code", 324 | "execution_count": null, 325 | "metadata": {}, 326 | "outputs": [], 327 | "source": [] 328 | }, 329 | { 330 | "cell_type": "markdown", 331 | "metadata": {}, 332 | "source": [ 333 | "Utiliza la librería `pandas-profiling` para generar un informe de análisis de datos. Observa la distribución y correlación de las variables `Q1` y `T1`." 334 | ] 335 | }, 336 | { 337 | "cell_type": "code", 338 | "execution_count": null, 339 | "metadata": {}, 340 | "outputs": [], 341 | "source": [] 342 | } 343 | ], 344 | "metadata": { 345 | "kernelspec": { 346 | "display_name": "Python 3", 347 | "language": "python", 348 | "name": "python3" 349 | }, 350 | "language_info": { 351 | "codemirror_mode": { 352 | "name": "ipython", 353 | "version": 3 354 | }, 355 | "file_extension": ".py", 356 | "mimetype": "text/x-python", 357 | "name": "python", 358 | "nbconvert_exporter": "python", 359 | "pygments_lexer": "ipython3", 360 | "version": "3.7.6" 361 | } 362 | }, 363 | "nbformat": 4, 364 | "nbformat_minor": 2 365 | } 366 | -------------------------------------------------------------------------------- /07. Atributos.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 7. Atributos\n", 8 | "\n", 9 | "[Playlist de Ciencia de Datos en castellano](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67)\n", 10 | "[![Ciencia de Datos en Python](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/8-0001.png/:/rs=w:1160,h:653)](https://www.youtube.com/watch?v=NlN_bVHwcmE&list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67&index=8)\n", 11 | "\n", 12 | "**La clasificación** predice *etiquetas discretas (resultados)* como `sí` /` no`, `Verdadero` /` Falso`, o cualquier tipo de variable discreta, como una letra mediante reconocimiento de texto. Un ejemplo de clasificación es sugerir una película que querrás ver (etiqueta) en base al historial de visualización (o atributo(s)). **La Regresión**, a diferencia de la clasificación, da resultados continuos, como un número real dentro de un rango. Un ejemplo de regresión es construir una correlación de la temperatura de una olla con agua (etiqueta) basada en el tiempo que se ha estado calentando (atributo). Los valores de temperatura son continuos, mientras que la siguiente película es una de las muchas opciones discretas.\n", 13 | "\n", 14 | "![list](https://apmonitor.com/che263/uploads/Begin_Python/list.png)\n", 15 | "\n", 16 | "Los atributos son variables de entrada para modelos de regresión o clasificación. **Los atributos son entradas** y **las etiquetas son los resultados medidos**. A continuación se muestra una tabla de términos con terminología de aprendizaje automático (machine learning), optimización, \"GEKKO\" y una breve descripción.\n", 17 | "\n", 18 | "\n", 19 | "| **Machine Learning** | **Optimización** | **Estimación en Gekko** | **Descripción** |\n", 20 | "| ----------- | ----------- | ----------- | ----------- |\n", 21 | "| Pérdida | Función objetivo | `m.Minimize()` | La representación matemática de la diferencia entre los valores medidos y los valores predichos |\n", 22 | "| Ponderaciones | Parámetros ajustables | Valores fijos (`m.FV()`) con `STATUS=1` | Valores ajustables para minimizar la función objetivo |\n", 23 | "| Etiqueta | Resultado medido | Variable controlada (`m.CV()`) con `FSTATUS=1` | Mediciones u observaciones de las variables predichas |\n", 24 | "| Atributo | Entrada medida | Parámetro (`m.Param()`) | Mediciones de entrada que se usan para predecir las etiquetas (resultados) a la salida |\n", 25 | "| Entrenar | Optimizar | Resolver (`m.solve()`) | Ajustar los parámetros ajustables (ponderaciones) para minimizar la función objetivo (pérdida) |\n", 26 | "| Testear | Evaluar | Resolver `STATUS=0` para `m.FV()` | Predecir las etiquetas con el modelo ajustado para evaluar el desempeño del clasificador o regresor | \n", 27 | "| Regresor o Clasificador | Modelo | `m = GEKKO()` | Ecuaciones matemáticas y parámetros que utilizan los atributos de entrada y devuelven como resultado las etiquetas de salida |\n", 28 | "\n", 29 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 30 | "\n", 31 | "La selección y creación de atributos es un paso importante en machine learning. Un número muy grande de atributos podría provocar un incremento en la probabilidad de que el regresor o clasificador tenga errores en las predicciones. Con muchos atributos, una entrada podría ser un valor \"malo\" y causar una predicción errónea. Además, mientras más atributos, más tiempo es necesario para limpiar los datos, entrenar los modelos y predecir resultados. A continuación se mostrarán métodos para seleccionar los mejores atributos para clasificación y regresión." 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [ 38 | "![analyze](https://apmonitor.com/che263/uploads/Begin_Python/analyze.png)\n", 39 | "\n", 40 | "### Identificar Atributos y Etiquetas\n", 41 | "\n", 42 | "El primer paso para construir un regresor o clasificador es determinar qué medidas (atributos de entrada y etiquetas de salida) están disponibles. Puedes seleccionar las columnas de datos como atributos o generar [atributos derivados](https://towardsdatascience.com/automated-feature-engineering-in-python-99baf11cc219) con una librería como [`Featuretools`](https://towardsdatascience.com/why-automated-feature-engineering-will-change-the-way-you-do-machine-learning-5c15bf188b96).\n", 43 | "\n", 44 | "Es posible que gustes utilizar los datos del mercado de valores para obtener un indicador de cuándo comprar (`1`) o cuándo vender (`-1`). Este indicador es una etiqueta. Importa los datos de las acciones diarias de Google durante 23 días.\n" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": null, 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "import pandas as pd\n", 54 | "import numpy as np\n", 55 | "url = 'http://apmonitor.com/che263/uploads/Main/goog.csv'\n", 56 | "data = pd.read_csv(url)\n", 57 | "data = data.drop(columns=['Adj Close'])\n", 58 | "data.head()" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "Los atributos pueden ser cualquiera de las categorías que puedan ser útiles para predecir un cambio futuro en el precio de las acciones. La columna `Open`, la diferencia entre las columnas `High` y `Low` (`Volatility`), la diferencia entre las columnas `Close` y `Open` (`Change`) y la columna `Volume` son ejemplos de atributos. Con `.diff ()` se calcula la diferencia, y con `.fillna (0)` se reemplaza cualquier valor `NaN` por cero. Agrega cualquier otro atributo adicional que te gustaría considerar." 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "features = ['Open','Volatility','Change','Volume']\n", 75 | "data['Volatility'] = (data['High']-data['Low']).diff()\n", 76 | "data['Change'] = (data['Close']-data['Open']).diff()\n", 77 | "# Algún otro atributo?\n", 78 | "data.head()" 79 | ] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": {}, 84 | "source": [ 85 | "Una etiqueta (resultado) para la clasificación es el signo (`+` o `-`) del precio de cierre de un día para otro. Con `np.roll (, -1)` se desplazan todos los valores una casilla hacia arriba para indicar el cambio respecto al día siguiente en esa misma fila. Con `np.sign ()` se obtiene el signo de la diferencia como un indicador de compra o venta, y `.dropna ()` elimina la última fila que es `NaN`." 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": null, 91 | "metadata": {}, 92 | "outputs": [], 93 | "source": [ 94 | "data['Close_diff'] = np.roll(data['Close'].diff(),-1)\n", 95 | "data=data.dropna()\n", 96 | "label = ['Buy/Sell']\n", 97 | "data['Buy/Sell'] = np.sign(data['Close_diff'])\n", 98 | "data.head()" 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": {}, 104 | "source": [ 105 | "![power](https://apmonitor.com/che263/uploads/Begin_Python/power.png)\n", 106 | "\n", 107 | "### Seleccionar los Mejores Atributos\n", 108 | "\n", 109 | "Ahora que hemos creado varios atributos queremos seleccionar los mejores para predecir las etiquetas de salida. Hay varios métodos para evaluar cuántos atributos se necesitan (correlación) y cuáles son los mejores (selección). El primer paso es separar la entrada `X` y la salida` Y` mediante una escala de los datos (de `0` a` 1`)." 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": null, 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "data[features+label].head()" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "from sklearn.preprocessing import MinMaxScaler\n", 128 | "s = MinMaxScaler()\n", 129 | "ds = s.fit_transform(data[features+label])\n", 130 | "ds = pd.DataFrame(ds,columns=data[features+label].columns)\n", 131 | "X = ds[features]\n", 132 | "y = ds[label]\n", 133 | "ds.head()" 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": {}, 139 | "source": [ 140 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 141 | "\n", 142 | "#### Selección\n", 143 | "\n", 144 | "Existen pruebas estadísticas que muestran cuáles atributos mantienen una fuerte relación con la etiqueta de salida. Una herramienta es el método de scikit-learn `SelectKBest` que tiene pruebas estadísticas asociadas. Este método utiliza una prueba $ \\ chi ^ 2 $ para atributos no negativos y selecciona 10 de los mejores atributos para predecir la salida." 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": null, 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "from sklearn.feature_selection import SelectKBest\n", 154 | "from sklearn.feature_selection import chi2\n", 155 | "import matplotlib.pyplot as plt\n", 156 | "%matplotlib inline\n", 157 | "bestfeatures = SelectKBest(score_func=chi2, k='all')\n", 158 | "fit = bestfeatures.fit(X,y)\n", 159 | "dfscores = pd.DataFrame(fit.scores_)\n", 160 | "dfcolumns = pd.DataFrame(X.columns)\n", 161 | "scores = pd.concat([dfcolumns,dfscores],axis=1)\n", 162 | "scores.columns = ['Specs','Score']\n", 163 | "scores.index = features\n", 164 | "scores.plot(kind='bar')\n", 165 | "plt.show()" 166 | ] 167 | }, 168 | { 169 | "cell_type": "markdown", 170 | "metadata": {}, 171 | "source": [ 172 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 173 | "\n", 174 | "En base a esta información, elimina cualquier atributo que tenga puntuación baja con `.remove ()`." 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": null, 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "# Elimine cualquier atributo con puntuación baja usando features.remove('')\n", 184 | "print(features)" 185 | ] 186 | }, 187 | { 188 | "cell_type": "markdown", 189 | "metadata": {}, 190 | "source": [ 191 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 192 | "\n", 193 | "#### Importancia del Atributo\n", 194 | "\n", 195 | "Existe un método que utiliza un clasificador en base a árboles (Tree Based Classifier) que califica a cada atributo. Una calificación alta significa más importancia y relevancia en la predicción de la variable de salida. Los resultados cambian con cada análisis, debido a la naturaleza estocástica del cálculo. No obstante, la Volatilidad (`Volatility`) es un factor que normalmente puntúa entre los más altos." 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": null, 201 | "metadata": {}, 202 | "outputs": [], 203 | "source": [ 204 | "from sklearn.ensemble import ExtraTreesClassifier\n", 205 | "model = ExtraTreesClassifier(n_estimators=100)\n", 206 | "model.fit(X,np.ravel(y))\n", 207 | "\n", 208 | "feat_importances = pd.Series(model.feature_importances_, index=X.columns)\n", 209 | "feat_importances.nlargest(4).plot(kind='bar')\n", 210 | "plt.show()" 211 | ] 212 | }, 213 | { 214 | "cell_type": "markdown", 215 | "metadata": {}, 216 | "source": [ 217 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 218 | "\n", 219 | "#### Matriz de Correlación con Mapa de Calor\n", 220 | "\n", 221 | "La correlación nos muestra qué tanto se relacionan unos atributos con otros. Un valor elevado, ya sea positivo o negativo, indica que las variables están relacionadas. Si se tienen variables correlacionadas entonces puede eliminarse una de ellas, pues ambas proveen información similar. Un mapa de calor es una cuadrícula visual simétrica de la matriz de correlación. La diagonal siempre toma el valor de 1, pues cualquier variable se relaciona perfectamente consigo misma. En base al mapa de calor, determina qué variables están más relacionadas y podrían eliminarse." 222 | ] 223 | }, 224 | { 225 | "cell_type": "code", 226 | "execution_count": null, 227 | "metadata": {}, 228 | "outputs": [], 229 | "source": [ 230 | "import seaborn as sns\n", 231 | "corrmat = ds.corr()\n", 232 | "top_features = corrmat.index\n", 233 | "plt.figure(figsize=(5,5))\n", 234 | "sns.heatmap(ds[top_features].corr(),annot=True,cmap=\"RdYlGn\") #\n", 235 | "b, t = plt.ylim(); plt.ylim(b+0.5, t-0.5) # soluciona el problema en matplotlib 3.1.1\n", 236 | "plt.show()" 237 | ] 238 | }, 239 | { 240 | "cell_type": "markdown", 241 | "metadata": {}, 242 | "source": [ 243 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 244 | "\n", 245 | "### Actividad con el TCLab\n", 246 | "\n", 247 | "![connections](https://apmonitor.com/che263/uploads/Begin_Python/connections.png)\n", 248 | "\n", 249 | "Considera cómo se podría determinar si el calentador del TCLab está encendido o apagado sin conocer el valor `Q1`. Probablemente mediríamos la temperatura `T1` y se observaría si la temperatura está subiendo o bajando. Sin embargo, simplemente observar la temperatura y la pendiente no es suficiente porque la temperatura continúa aumentando durante 10 a 20 segundos, después de que se apaga el calentador. Por tal motivo, debe calcular la segunda derivada de la temperatura para clasificar el estado del calentador como encendido o apagado. Una segunda derivada positiva es otra pista de que el calentador está encendido.\n", 250 | "\n", 251 | "![temperature](https://apmonitor.com/che263/uploads/Begin_Python/temperature.png)\n", 252 | "\n", 253 | "Ya sea que el calentador esté encendido o apagado (*resultado medido*), la temperatura y las derivadas son los *atributos*. Ejecuta el siguiente código para generar datos de temperatura con el calentador encendido al 100% o apagado al 0% en intervalos de 20 a 30 segundos durante 3 minutos." 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": null, 259 | "metadata": {}, 260 | "outputs": [], 261 | "source": [ 262 | "import tclab, time\n", 263 | "import numpy as np\n", 264 | "import pandas as pd\n", 265 | "try:\n", 266 | " with tclab.TCLab() as lab:\n", 267 | " n = 180; t = np.linspace(0,n-1,n) \n", 268 | " Q1 = np.zeros(n); T1 = np.zeros(n)\n", 269 | " Q2 = np.zeros(n); T2 = np.zeros(n) \n", 270 | " Q1[20:41] = 100.0; Q1[60:91] = 100.0\n", 271 | " Q1[150:181] = 100.0; Q1[190:206] = 100.0\n", 272 | " Q1[220:251] = 100.0; Q1[260:291] = 100.0\n", 273 | " print('Tiempo Q1 Q2 T1 T2')\n", 274 | " for i in range(180):\n", 275 | " T1[i] = lab.T1; T2[i] = lab.T2\n", 276 | " lab.Q1(Q1[i])\n", 277 | " if i%10==0:\n", 278 | " print(int(t[i]),Q1[i],Q2[i],T1[i],T2[i])\n", 279 | " time.sleep(1)\n", 280 | " data = np.column_stack((t,Q1,Q2,T1,T2))\n", 281 | " data7 = pd.DataFrame(data,columns=['Tiempo','Q1','Q2','T1','T2'])\n", 282 | " data7.to_csv('07-tclab.csv',index=False)\n", 283 | "except:\n", 284 | " print('Conecte el TCLab para generar nuevos datos')\n", 285 | " print('Importando datos en línea')\n", 286 | " url = 'http://apmonitor.com/do/uploads/Main/tclab_data5.txt'\n", 287 | " data7 = pd.read_csv(url)" 288 | ] 289 | }, 290 | { 291 | "cell_type": "markdown", 292 | "metadata": {}, 293 | "source": [ 294 | "### Crear Atributos\n", 295 | "\n", 296 | "Crea tres atributos a partir de los datos incluyendo la temperatura y sus derivadas.\n", 297 | "\n", 298 | "- Temperatura: $T_1$\n", 299 | "- Primera derivada de la temperatura: $\\frac{dT_1}{dt}$\n", 300 | "- Segunda derivada de la temperatura: $\\frac{d^2T_1}{dt^2}$\n", 301 | "\n", 302 | "Añade las derivadas como columnas en `data7`." 303 | ] 304 | }, 305 | { 306 | "cell_type": "code", 307 | "execution_count": null, 308 | "metadata": {}, 309 | "outputs": [], 310 | "source": [] 311 | }, 312 | { 313 | "cell_type": "markdown", 314 | "metadata": {}, 315 | "source": [ 316 | "### Escalar Datos\n", 317 | "\n", 318 | "Escala `data7` de forma que resulten valores entre `0` y `1` utilizando `d7 = s.fit_transform(data7)`. No olvides volver a traducir los valores escalados a un `pandas` DataFrame." 319 | ] 320 | }, 321 | { 322 | "cell_type": "code", 323 | "execution_count": null, 324 | "metadata": {}, 325 | "outputs": [], 326 | "source": [] 327 | }, 328 | { 329 | "cell_type": "markdown", 330 | "metadata": {}, 331 | "source": [ 332 | "### Calificar Atributos\n", 333 | "\n", 334 | "Utiliza `SelectKBest` para determinar los mejores atributos." 335 | ] 336 | }, 337 | { 338 | "cell_type": "code", 339 | "execution_count": null, 340 | "metadata": {}, 341 | "outputs": [], 342 | "source": [] 343 | }, 344 | { 345 | "cell_type": "markdown", 346 | "metadata": {}, 347 | "source": [ 348 | "### Correlacionar Atributos\n", 349 | "\n", 350 | "Genera un mapa de calor para determinar la correlación entre los atributos. " 351 | ] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": null, 356 | "metadata": {}, 357 | "outputs": [], 358 | "source": [] 359 | } 360 | ], 361 | "metadata": { 362 | "kernelspec": { 363 | "display_name": "Python 3", 364 | "language": "python", 365 | "name": "python3" 366 | }, 367 | "language_info": { 368 | "codemirror_mode": { 369 | "name": "ipython", 370 | "version": 3 371 | }, 372 | "file_extension": ".py", 373 | "mimetype": "text/x-python", 374 | "name": "python", 375 | "nbconvert_exporter": "python", 376 | "pygments_lexer": "ipython3", 377 | "version": "3.7.6" 378 | } 379 | }, 380 | "nbformat": 4, 381 | "nbformat_minor": 2 382 | } 383 | -------------------------------------------------------------------------------- /01. Resumen.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "### Encuesta\n", 8 | "\n", 9 | "Este trabajo es parte de una investigación que busca cuantificar el impacto de integrar Hardware (TCLab) con Software (Programación en Python).\n", 10 | "\n", 11 | "Si ya realizaste la encuesta continúa a **1. Resumen**. De lo contrario, por favor completa la siguiente encuesta de **INICIO de Curso**.\n", 12 | "\n", 13 | "[![Inicio](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/Inicio.png/:/rs=w:1440,h:1440)](https://forms.office.com/Pages/ResponsePage.aspx?id=r4yvt9iDREaFrjF8VFIjwUHkKiCq1wxFstxAwkoFiilUQVZDTk5MM0ZXOTdONjc1SFlZVTQ3VlJMNi4u)\n", 14 | "\n", 15 | "## 1. Resumen\n", 16 | "\n", 17 | "[Playlist de Ciencia de Datos en castellano](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67)\n", 18 | "[![Ciencia de Datos en Python](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/2-0001.png/:/rs=w:1160,h:653)](https://www.youtube.com/watch?v=p32iBkGy5Uo&list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67&index=3)\n", 19 | "\n", 20 | "### Introducción\n", 21 | "\n", 22 | "¡¡BIENVENIDOS al curso de Ciencia de Datos con Python en castellano!! Este curso recorre habilidades básicas de la Ciencia de Datos y Aprendizaje Automático para analizar datos y crear información procesable. Aborda los principales pasos del proceso estándar entre industrias para el ciclo de Minería de Datos (CRISP-DM, por sus siglas en inglés) que tiene 6 fases:\n", 23 | "\n", 24 | "1. **Comprensión empresarial:** propósito del proyecto de Ciencia de Datos.\n", 25 | "2. **Comprensión de datos:** evaluar los datos disponibles para cada caso particular.\n", 26 | "3. **Preparación de datos:** análisis exploratorio de datos, \"feature engineering\" (ingeniería de características) y transformaciones.\n", 27 | "4. **Modelado:** seleccionar y entrenar regresores o clasificadores.\n", 28 | "5. **Evaluación:** modelos de prueba con varios criterios.\n", 29 | "6. **Implementación:** fase de producción para implementar modelos en \"data pipelines\".\n", 30 | "\n", 31 | "Los 12 CAPÍTULOS están diseñados para completarse en 2-3 horas (15-20 minutos cada uno), pero se pueden omitir algunas secciones si ya se tienen conocimientos previos.\n", 32 | "\n", 33 | "1. [Resumen](https://github.com/APMonitor/ciencia_de_datos/blob/main/01.%20Resumen.ipynb)\n", 34 | "2. [Importar y Exportar datos](https://github.com/APMonitor/ciencia_de_datos/blob/main/02.%20Importar_Exportar.ipynb)\n", 35 | "3. [Análisis de datos](https://github.com/APMonitor/ciencia_de_datos/blob/main/03.%20Analizar_data.ipynb)\n", 36 | "4. [Visualización de datos](https://github.com/APMonitor/ciencia_de_datos/blob/main/04.%20Visualizar_data.ipynb)\n", 37 | "5. [Preparación de datos (limpiar, escalar y dividir)](https://github.com/APMonitor/ciencia_de_datos/blob/main/05.%20Preparar_data.ipynb)\n", 38 | "6. [Regresión](https://github.com/APMonitor/ciencia_de_datos/blob/main/06.%20Regresi%C3%B3n.ipynb)\n", 39 | "7. [Atributos](https://github.com/APMonitor/ciencia_de_datos/blob/main/07.%20Atributos.ipynb)\n", 40 | "8. [Clasificación](https://github.com/APMonitor/ciencia_de_datos/blob/main/08.%20Clasificaci%C3%B3n.ipynb)\n", 41 | "9. [Interpolación](https://github.com/APMonitor/ciencia_de_datos/blob/main/09.%20Interpolaci%C3%B3n.ipynb)\n", 42 | "10. [Resolución de ecuaciones](https://github.com/APMonitor/ciencia_de_datos/blob/main/10.%20Resolver_ecuaciones.ipynb)\n", 43 | "11. [Ecuaciones diferenciales](https://github.com/APMonitor/ciencia_de_datos/blob/main/11.%20Ecuaciones_diferenciales.ipynb)\n", 44 | "12. [Series de tiempo](https://github.com/APMonitor/ciencia_de_datos/blob/main/12.%20Series_de_tiempo.ipynb)\n", 45 | "\n", 46 | "Se recomienda seguir las lecciones una por una porque estas se basan en información de cada capítulo anterior.\n", 47 | "\n", 48 | "### Proyecto Final\n", 49 | "\n", 50 | "![cell](https://apmonitor.com/che263/uploads/Begin_Python/cell.png)\n", 51 | "\n", 52 | "Diseñaremos un teléfono celular de próxima generación donde la batería y el procesador generan mucho calor. El objetivo que tenemos es asegurarnos de que el material entre ellos evite el sobrecalentamiento de la batería por parte del procesador.\n", 53 | "\n", 54 | "![battery_cpu](https://apmonitor.com/che263/uploads/Begin_Python/battery_cpu.png)\n", 55 | "\n", 56 | "El proyecto final ayudará a responder preguntas sobre las propiedades del material para predecir la temperatura de la batería y el procesador. Utiliza datos del laboratorio de control de temperatura (TCLab) para determinar la conductividad térmica. Se recomienda mirar el [Proyecto Final](https://github.com/APMonitor/data_science/blob/master/04.%20Visualize.ipynb) después de pasar por las 12 lecciones y cuando estés listo para este desafío!!!" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "### ¿Qué ejecuta los comandos de Python?\n", 64 | "\n", 65 | "El ejecutable de Python acciona los comandos. Un Jupyter notebook inicia una sesión de Python llamada kernel. Reiniciar el kernel elimina cualquiera de los resultados de las celdas anteriores y detiene cualquier código en ejecución." 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "import sys\n", 75 | "print(sys.executable)" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": {}, 81 | "source": [ 82 | "### ¿Dónde está el directorio de trabajo actual?\n", 83 | "\n", 84 | "El directorio de trabajo actual está en la misma carpeta del IPython notebook en ejecución. También es donde se almacenarán y recuperarán los archivos. Es posible cambiar el directorio de trabajo actual con `os.chdir(path)`" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": null, 90 | "metadata": {}, 91 | "outputs": [], 92 | "source": [ 93 | "import os\n", 94 | "print(os.getcwd())" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "metadata": {}, 100 | "source": [ 101 | "Hay archivos de Jupyter notebook separados para ayudar con la instalación del TCLab. También se puede consultar en [Preguntas Frecuentes](https://apmonitor.com/pdc/index.php/Main/ArduinoSetup) (en inglés) para problemas de configuración y resolución de problemas. Más información sobre la instalación del paquete TCLab está disponible en el IPython notebook __TCLab Help__." 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "![exercise](https://apmonitor.com/che263/uploads/Begin_Python/exercise.png)\n", 109 | "\n", 110 | "### Librerías de Python requeridas\n", 111 | "\n", 112 | "Es importante que consideremos las librerías para Ciencia de Datos y Aprendizaje Automático por el ritmo de nuevos lanzamientos y/o actualizaciones. En este sentido, puede ser necesario instalar la última versión o una versión específica anterior.\n", 113 | "\n", 114 | "Para instalar las librerías, utiliza `pip` (o `conda`). Una alternativa es iniciar \"Anaconda prompt\" del menú inicio, puedes iniciar DOS prompt al presionar las teclas Windows-key + r `cmd`, o el terminal en MacOS/Linux y digitar:\n", 115 | "\n", 116 | "![gekko](https://apmonitor.com/che263/uploads/Begin_Python/gekko.png)\n", 117 | "\n", 118 | "```\n", 119 | "python -m pip install gekko\n", 120 | "```\n", 121 | "\n", 122 | "Si deseas ejecutar este comando en Jupyter notebook utiliza un signo de exclamación al frente, de esta forma:\n", 123 | "\n", 124 | "```python\n", 125 | "!python -m pip install gekko\n", 126 | "```\n", 127 | "\n", 128 | "Si deseas estar seguro de que estás usando la distribución del Python kernel actual, usa: `sys.executable`.\n", 129 | "\n", 130 | "```python\n", 131 | "import sys\n", 132 | "!{sys.executable} -m pip install gekko\n", 133 | "```\n", 134 | "\n", 135 | "Las librerías que se utilizan en estos módulos son: `gekko`, `keras`, `numpy`, `pandas`, `pyserial`, `sklearn`, `tclab`, `tensorflow`, y otras. En caso de existir algún error de que falta una librería entonces `!pip install gekko` es la forma más común y fácil para instalarlo desde el notebook. El símbolo `!` le indica a Jupyter que corra desde el sistema de comando y no con Python. A pesar de que `!` es opcional a `pip` en la última versión de Jupyter. Añadir `--user` (no un nombre de usuario específico) si deseas tener privilegios de administrador en el computador. El administrador de librerías `pip` obtiene la [última versión de gekko](https://pypi.org/project/gekko/) desde `pypi` y lo instala en la distribución de Python." 136 | ] 137 | }, 138 | { 139 | "cell_type": "markdown", 140 | "metadata": {}, 141 | "source": [ 142 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 143 | "\n", 144 | "### Instalar la librería" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": null, 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "!python -m pip install --user gekko" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": {}, 159 | "source": [ 160 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 161 | "\n", 162 | "### Lista de paquetes y versiones disponibles" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": null, 168 | "metadata": {}, 169 | "outputs": [], 170 | "source": [ 171 | "!python -m pip list" 172 | ] 173 | }, 174 | { 175 | "cell_type": "markdown", 176 | "metadata": {}, 177 | "source": [ 178 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 179 | "\n", 180 | "### Desinstalar la librería\n", 181 | "\n", 182 | "Para desinstalar (`uninstall`) una libería se debe utilizar la línea de comando porque nos preguntará por una respuesta sí o no \n", 183 | "(`yes`/`no`) o podemos añadir que sí (`--yes`) al inicio para responder automáticamente y confirmar el mensaje. No olvides reinstalar la librería, en caso de requerirla." 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": null, 189 | "metadata": {}, 190 | "outputs": [], 191 | "source": [ 192 | "!python -m pip uninstall gekko --yes" 193 | ] 194 | }, 195 | { 196 | "cell_type": "markdown", 197 | "metadata": {}, 198 | "source": [ 199 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 200 | "\n", 201 | "### Instalar una versión específica\n", 202 | "\n", 203 | "Es posible que debas obtener una versión de librería particular especificando una versión como `0.2.0`." 204 | ] 205 | }, 206 | { 207 | "cell_type": "code", 208 | "execution_count": null, 209 | "metadata": {}, 210 | "outputs": [], 211 | "source": [ 212 | "!python -m pip install gekko==0.2.0" 213 | ] 214 | }, 215 | { 216 | "cell_type": "markdown", 217 | "metadata": {}, 218 | "source": [ 219 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 220 | "\n", 221 | "### Actualización de una librería\n", 222 | "\n", 223 | "Si tienes una versión anterior y deseas actualizar a la última versión estable, utiliza `--upgrade`" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": null, 229 | "metadata": {}, 230 | "outputs": [], 231 | "source": [ 232 | "!python -m pip install gekko --upgrade" 233 | ] 234 | }, 235 | { 236 | "cell_type": "markdown", 237 | "metadata": {}, 238 | "source": [ 239 | "![list](https://apmonitor.com/che263/uploads/Begin_Python/list.png)\n", 240 | "\n", 241 | "### `pip` Resumen\n", 242 | "\n", 243 | "La herramienta `pip` facilita la gestión de librerías en Python utilizando `install`, `list`, y comandos `uninstall`.\n", 244 | "\n", 245 | "```python\n", 246 | "!python -m pip {command} {package name}\n", 247 | "```" 248 | ] 249 | }, 250 | { 251 | "cell_type": "markdown", 252 | "metadata": {}, 253 | "source": [ 254 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 255 | "\n", 256 | "### Instalar el módulo TCLab\n", 257 | "\n", 258 | "Necesitas un TCLab para realizar algunos ejercicios, sin embargo hay archivos de datos de muestra disponibles si no tienes un dispositivo. El [TCLab](https://apmonitor.com/heat.htm) está disponible para compra en línea a través de [Amazon](https://www.amazon.com/TCLab-Temperature-Control-Lab/dp/B07GMFWMRY) o con otras [opciones disponibles](https://apmonitor.com/pdc/index.php/Main/PurchaseLabKit).\n", 259 | "\n", 260 | "![connections_no_power](https://apmonitor.com/che263/uploads/Begin_Python/connections_no_power.png)\n", 261 | "\n", 262 | "Como primer paso, conecta el TCLab (utiliza el cable USB azul solamente) e instala la librería con `python -m pip install tclab` o corriendo la celda inferior (`Ctrl+Enter`). Reinicia el kernel de Python con `Kernel...Restart & Run All` disponible en el menú en caso de haber algún error al importar `tclab` después de la instalación." 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": null, 268 | "metadata": {}, 269 | "outputs": [], 270 | "source": [ 271 | "# instalar el tclab\n", 272 | "try:\n", 273 | " import tclab\n", 274 | "except:\n", 275 | " # Necesario para comunicarse a través del puerto USB.\n", 276 | " !python -m pip install --user pyserial\n", 277 | " # El usuario (--user) se coloca para cuentas sin privilegios de administrador\n", 278 | " !python -m pip install --user tclab \n", 279 | " # reiniciar el kernel si no importa\n", 280 | " try:\n", 281 | " import tclab\n", 282 | " except:\n", 283 | " print('Reiniciar el kernel desde el menú si el kernel no responde')\n", 284 | " print('Reiniciar el kernel automáticamente...')\n", 285 | " import IPython\n", 286 | " app = IPython.Application.instance()\n", 287 | " app.kernel.do_shutdown(restart=True) " 288 | ] 289 | }, 290 | { 291 | "cell_type": "markdown", 292 | "metadata": {}, 293 | "source": [ 294 | "### Prueba LED del TCLab\n", 295 | "\n", 296 | "El siguiente código muestra cómo encender el LED durante 5 segundos. Solo necesitas conectar el cable USB azul a tu computador. El cable de alimentación blanco es necesario para conectar el calentador para el siguiente ejemplo." 297 | ] 298 | }, 299 | { 300 | "cell_type": "code", 301 | "execution_count": null, 302 | "metadata": {}, 303 | "outputs": [], 304 | "source": [ 305 | "import tclab\n", 306 | "import time\n", 307 | "\n", 308 | "with tclab.TCLab() as lab:\n", 309 | " lab.LED(100)\n", 310 | " time.sleep(5.0) # espera 5.0 segundos\n", 311 | " lab.LED(0)" 312 | ] 313 | }, 314 | { 315 | "cell_type": "markdown", 316 | "metadata": {}, 317 | "source": [ 318 | "### Prueba de calentador del TCLab\n", 319 | "\n", 320 | "![connections](https://apmonitor.com/che263/uploads/Begin_Python/connections.png)\n", 321 | "\n", 322 | "El siguiente código muestra cómo encender el calentador `Q1`. Se lee la temperatura `T1` antes y después de una pausa de 10 segundos. Debes conectar el cable de alimentación blanco y conectar la fuente de energía. El cable de alimentación blanco es necesario para suministrar energía a los calentadores." 323 | ] 324 | }, 325 | { 326 | "cell_type": "code", 327 | "execution_count": null, 328 | "metadata": {}, 329 | "outputs": [], 330 | "source": [ 331 | "with tclab.TCLab() as lab:\n", 332 | " print(lab.T1) # imprime la temperatura 1\n", 333 | " lab.Q1(100) # activar Q1 al 100%\n", 334 | " time.sleep(15) # duerme por 15 segundos\n", 335 | " print(lab.T1) # imprime la temperatura 1" 336 | ] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "metadata": {}, 341 | "source": [ 342 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 343 | "\n", 344 | "### Actividad con el TCLab\n", 345 | "\n", 346 | "Las funciones del TCLab permiten que Python interactúe con el TCLab a través de la conección por USB.\n", 347 | "\n", 348 | "| **Función del TCLab** | **Ejemplo** | **Descripción** |\n", 349 | "| ----------- | ----------- | ----------- |\n", 350 | "| `TCLab()` | `tclab.TCLab()` | Crea un nuevo objeto del laboratorio y se conecta |\n", 351 | "| `LED` | `lab.LED(45)` | Enciende el LED al 45%. El rango válido es 0-100% |\n", 352 | "| `Q1` | `lab.Q1(63)` | Encender el calentador 1 (`Q1`) a 63%. El rango válido es 0-100% |\n", 353 | "| `Q2` | `lab.Q2(28)` | Encender el calentador 2 (`Q2`) to 28%. El rango válido es 0-100% |\n", 354 | "| `T1` | `print(lab.T1)` | Leer la temperatura 1 (`T1`) en °C. El rango válido es -40 a 150°C (sensor TMP36) |\n", 355 | "| `T2` | `print(lab.T2)` | Leer la temperatura 2 (`T2`) en °C con +/- 1°C de incertidumbre (sensor TMP36) |\n", 356 | "| `close()` | `lab.close()` | Finaliza la conexión USB con el TCLab - no es necesaria si se utiliza `with` para abrir |\n", 357 | "\n", 358 | "Completa los siguientes ejercicios.\n", 359 | "\n", 360 | "### Acciona el LED\n", 361 | "\n", 362 | "Acciona el LED 5 veces por 1 segundo cada uno." 363 | ] 364 | }, 365 | { 366 | "cell_type": "code", 367 | "execution_count": null, 368 | "metadata": {}, 369 | "outputs": [], 370 | "source": [] 371 | }, 372 | { 373 | "cell_type": "markdown", 374 | "metadata": {}, 375 | "source": [ 376 | "### Alcanza la temperatura de 50°C\n", 377 | "\n", 378 | "Enciende el calentador 1 (`Q1`) a 80% hasta que `T1` alcance 50°C. Actualiza el tiempo de acción (`t`) del LED.\n", 379 | "\n", 380 | "$t = \\frac{50-T_1}{10}$\n", 381 | "\n", 382 | "Esto muestra una indicación visual de la temperatura (`T1`) con la fórmula para alternar el tiempo libre y el tiempo activo. A medida que la temperatura se acerca a 50°C, el LED se acciona de forma más rápida hasta que se apaga.\n", 383 | "\n", 384 | "Utiliza un lazo `while lab.T1<50:` para continuamente verificar que la temperatura es menor que 50°C." 385 | ] 386 | }, 387 | { 388 | "cell_type": "code", 389 | "execution_count": null, 390 | "metadata": {}, 391 | "outputs": [], 392 | "source": [] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": null, 397 | "metadata": {}, 398 | "outputs": [], 399 | "source": [] 400 | } 401 | ], 402 | "metadata": { 403 | "kernelspec": { 404 | "display_name": "Python 3", 405 | "language": "python", 406 | "name": "python3" 407 | }, 408 | "language_info": { 409 | "codemirror_mode": { 410 | "name": "ipython", 411 | "version": 3 412 | }, 413 | "file_extension": ".py", 414 | "mimetype": "text/x-python", 415 | "name": "python", 416 | "nbconvert_exporter": "python", 417 | "pygments_lexer": "ipython3", 418 | "version": "3.8.5" 419 | }, 420 | "widgets": { 421 | "application/vnd.jupyter.widget-state+json": { 422 | "state": {}, 423 | "version_major": 2, 424 | "version_minor": 0 425 | } 426 | } 427 | }, 428 | "nbformat": 4, 429 | "nbformat_minor": 2 430 | } 431 | -------------------------------------------------------------------------------- /04. Visualizar_data.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 4. Visualización de Datos\n", 8 | "\n", 9 | "[Playlist de Ciencia de Datos en castellano](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67)\n", 10 | "[![Ciencia de Datos en Python](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/5-0001.png/:/rs=w:1160,h:653)](https://www.youtube.com/watch?v=GHZIkEwlu7M&list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67&index=5)\n", 11 | "\n", 12 | "Además de los estadísticos de resumen, la visualización de datos ayuda a comprender las características de los datos y cómo se relacionan las diferentes variables.\n", 13 | "\n", 14 | "![analyze](https://apmonitor.com/che263/uploads/Begin_Python/analyze.png)\n", 15 | "\n", 16 | "Hay muchos ejemplos de visualización de datos con [Matplotlib](https://matplotlib.org/gallery/index.html), [Seaborn](https://seaborn.pydata.org/examples/index.html), y [Plotly](https://plot.ly/python/). En este tutorial, revisamos algunos ejemplos para visualizar:\n", 17 | "\n", 18 | "- series de tiempo: línea\n", 19 | "- variables correlacionadas: dispersión, diagrama de pares\n", 20 | "- distribuciones de datos: barra, caja, violín, distribución, diagrama conjunto\n", 21 | "\n", 22 | "Cada gráfico se muestra con una de las librerías de gráficos. Matplotlib es una librería de nivel base de Python, Seaborn utiliza matplotlib y automatiza gráficos más complejos, y Plotly crea gráficos interactivos." 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "import matplotlib.pyplot as plt\n", 32 | "%matplotlib inline\n", 33 | "import seaborn as sns\n", 34 | "import plotly.express as px" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 42 | "\n", 43 | "### Generar Datos\n", 44 | "\n", 45 | "Ejecuta la siguiente celda para:\n", 46 | "\n", 47 | "- Generar `n` valores espaciados linealmente entre `0` y `n-1` con `np.linspace(start,end,count)`\n", 48 | "- Selecciona muestras aleatorias de una distribución uniforme entre 0 y 1 con `np.random.rand(count)`\n", 49 | "- Selecciona muestras aleatorias de una distribución normal (gaussiana) con `np.random.normal(mean,std,count)`\n", 50 | "- Crea una serie de tiempo que cambie según `y[i]*0.1` manteniendose en el rango de `-3` a `3`\n", 51 | "- Combina `tt`, `x`, `y`, y `z` con una columna vertical `np.vstack` y transponer `.T` para datos orientados a columnas.\n", 52 | "- Crear una DataFrame pandas con columnas `tt`, `x`, `y`, y `z`" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "import numpy as np\n", 62 | "import pandas as pd\n", 63 | "np.random.seed(0) # cambiar \"seed\" para una respuesta diferente\n", 64 | "n = 1000\n", 65 | "tt = np.linspace(0,n-1,n)\n", 66 | "x = np.random.rand(n)+tt/500\n", 67 | "y = np.random.normal(0,x,n)\n", 68 | "z = [0]\n", 69 | "for i in range(1,n):\n", 70 | " z.append(min(max(-3,z[i-1]+y[i]*0.1),3))\n", 71 | "data = pd.DataFrame(np.vstack((tt,x,y,z)).T,\\\n", 72 | " columns=['time','x','y','z'])\n", 73 | "data['w'] = '0-499'\n", 74 | "for i in range(int(n/2),n):\n", 75 | " data.at[i,'w'] = '500-999'\n", 76 | "data.head()" 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "metadata": {}, 82 | "source": [ 83 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 84 | "\n", 85 | "### Gráfico\n", 86 | "\n", 87 | "El gráfico \"plot\" es el más básico. Hay un tutorial introductorio a gráficos en el [curso introductorio a Python en inglés, Lección 12](https://github.com/APMonitor/begin_python/blob/master/12.%20Plotting.ipynb). Visita este curso si necesitas más información sobre gráficos básicos como `plt.plot()`" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": null, 93 | "metadata": {}, 94 | "outputs": [], 95 | "source": [ 96 | "plt.plot(tt,z)\n", 97 | "plt.show()" 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": {}, 103 | "source": [ 104 | "La línea del gráfico puede ser cambiada y mejorada utilizando estilos seleccionados. A continuación se muestra un ejemplo con opciones comunes.\n", 105 | "\n", 106 | "**c=Colors** (Color)\n", 107 | "\n", 108 | " ============= ===============================\n", 109 | " Carácter Color\n", 110 | " ============= ===============================\n", 111 | " ``'b'`` azul\n", 112 | " ``'g'`` verde\n", 113 | " ``'r'`` rojo\n", 114 | " ``'y'`` amarillo\n", 115 | " ``'k'`` negro\n", 116 | " ============= ===============================\n", 117 | "\n", 118 | "**m=Markers** (Marca)\n", 119 | "\n", 120 | " ============= ===============================\n", 121 | " Carácter Descripción\n", 122 | " ============= ===============================\n", 123 | " ``'.'`` punto\n", 124 | " ``'o'`` círculo\n", 125 | " ``'s'`` cuadrado\n", 126 | " ``'^'`` triángulo\n", 127 | " ``'*'`` estrella\n", 128 | " ============= ===============================\n", 129 | "\n", 130 | "**ln=Line Styles** (Estilo de línea)\n", 131 | "\n", 132 | " ============= ===============================\n", 133 | " Carácter Descripción\n", 134 | " ============= ===============================\n", 135 | " ``'-'`` línea contínua\n", 136 | " ``'--'`` línea discontínua\n", 137 | " ``'-.'`` línea de puntos y guiones\n", 138 | " ``':'`` línea de puntos\n", 139 | " ============= ===============================" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": null, 145 | "metadata": {}, 146 | "outputs": [], 147 | "source": [ 148 | "plt.figure(1,figsize=(10,6)) # ajustar el tamaño de la figura\n", 149 | "ax=plt.subplot(2,1,1) # sub-gráfico 1\n", 150 | "plt.plot(tt,z,'r-',linewidth=3,label='z') # gráfico con línea roja\n", 151 | "ax.grid() # agregar cuadrícula\n", 152 | "plt.ylabel('z'); plt.legend() # agregar ylabel (nombre en eje y), leyenda\n", 153 | "plt.subplot(2,1,2) # sub-gráfico 2\n", 154 | "plt.plot(tt,x,'b.',label='x') # gráfico de puntos azules\n", 155 | "plt.plot(tt,y,color='orange',label='y',alpha=0.7) # gráfico anaranjado\n", 156 | "plt.xlabel('time'); plt.legend() # leyenda\n", 157 | "plt.savefig('04-myFig.png',transparent=True,dpi=600) # guardar el gráfico\n", 158 | "plt.show() # indicar el gráfico" 159 | ] 160 | }, 161 | { 162 | "cell_type": "markdown", 163 | "metadata": {}, 164 | "source": [ 165 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 166 | "\n", 167 | "### Actividad de Gráficos\n", 168 | "\n", 169 | "Crea una gráfica con los datos:\n", 170 | "\n", 171 | "```python\n", 172 | "xt = [0,0.1,0.2,0.3,0.5,0.8,1.0]\n", 173 | "yt = [1.0,2.1,3.5,6.5,7.2,5.9,6.3]\n", 174 | "```" 175 | ] 176 | }, 177 | { 178 | "cell_type": "markdown", 179 | "metadata": {}, 180 | "source": [ 181 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 182 | "\n", 183 | "### Gráfico de Dispersión\n", 184 | "\n", 185 | "Los gráficos de dispersión son similares a los gráficos regulares, pero muestran puntos individuales en lugar de valores conectados en serie. Matplotlib y Plotly se utilizan en este ejemplo. Matplotlib es rápido y sencillo mientras Plotly tiene características para gráficos interactivos!" 186 | ] 187 | }, 188 | { 189 | "cell_type": "code", 190 | "execution_count": null, 191 | "metadata": {}, 192 | "outputs": [], 193 | "source": [ 194 | "# matplotlib\n", 195 | "plt.scatter(x,y)\n", 196 | "plt.show()" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "metadata": {}, 203 | "outputs": [], 204 | "source": [ 205 | "# plotly\n", 206 | "fig = px.scatter(data,x='x',y='y',color='w',size='x',hover_data=['w'])\n", 207 | "fig.show()" 208 | ] 209 | }, 210 | { 211 | "cell_type": "markdown", 212 | "metadata": {}, 213 | "source": [ 214 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 215 | "\n", 216 | "### Actividad con Gráfico de Dispersión\n", 217 | "\n", 218 | "Crear un gráfico de dispersión con `matplotlib` o `plotly` que ilustre `xt` combinado con `yt` y `zt`:\n", 219 | "\n", 220 | "```python\n", 221 | "xt = np.array([0,0.1,0.2,0.3,0.5,0.8,1.0])\n", 222 | "yt = np.array([1.0,2.1,3.5,6.5,7.2,5.9,6.3])\n", 223 | "zt = xt*yt\n", 224 | "```\n", 225 | "\n", 226 | "Cambia la forma de los puntos a un cuadrado para `yt` y un triángulo para `zt`. Agregua una etiqueta para indicar qué puntos son `yt` y `zt`." 227 | ] 228 | }, 229 | { 230 | "cell_type": "code", 231 | "execution_count": null, 232 | "metadata": {}, 233 | "outputs": [], 234 | "source": [] 235 | }, 236 | { 237 | "cell_type": "markdown", 238 | "metadata": {}, 239 | "source": [ 240 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 241 | "\n", 242 | "### Gráfico de Barras\n", 243 | "\n", 244 | "Los gráficos de barras ilustran un histograma en un rango de intervalo. La opción `alpha` es la transparencia entre `0` y `1`. Un valor de `0.7` es un buen valor para mostrar los datos subyacentes y superpuestos." 245 | ] 246 | }, 247 | { 248 | "cell_type": "code", 249 | "execution_count": null, 250 | "metadata": {}, 251 | "outputs": [], 252 | "source": [ 253 | "bins = np.linspace(-3,3,31)\n", 254 | "plt.hist(y,bins,label='y')\n", 255 | "plt.hist(z,bins,alpha=0.7,label='z')\n", 256 | "plt.legend()\n", 257 | "plt.show()" 258 | ] 259 | }, 260 | { 261 | "cell_type": "markdown", 262 | "metadata": {}, 263 | "source": [ 264 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 265 | "\n", 266 | "### Actividad con Gráfico de Barras\n", 267 | "\n", 268 | "Genera un diagrama de barras que muestre la distribución de `xt`, `yt`, y `zt`:\n", 269 | "\n", 270 | "```python\n", 271 | "nt = 1000\n", 272 | "xt = np.random.rand(nt)\n", 273 | "yt = np.random.normal(0,1,nt)\n", 274 | "zt = xt*yt\n", 275 | "```\n", 276 | "\n", 277 | "Utiliza `bins = np.linspace(-3,3,31)` para crear el histograma." 278 | ] 279 | }, 280 | { 281 | "cell_type": "code", 282 | "execution_count": null, 283 | "metadata": {}, 284 | "outputs": [], 285 | "source": [] 286 | }, 287 | { 288 | "cell_type": "markdown", 289 | "metadata": {}, 290 | "source": [ 291 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 292 | "\n", 293 | "### Gráfico de Pares\n", 294 | "\n", 295 | "Un gráfico de pares o pair plot muestra la correlación entre variables. Tiene distribuciones en la diagonal y diagramas de dispersión en el resto de lugares. Un gráfico de pares también muestra un color diferente (`hue`) por categoría `w`. Los gráficos de pares muestran correlaciones entre pares de variables que pueden estar relacionadas y dan una buena indicación de las características (entradas explicativas) que se utilizan para clasificación o regresión." 296 | ] 297 | }, 298 | { 299 | "cell_type": "code", 300 | "execution_count": null, 301 | "metadata": {}, 302 | "outputs": [], 303 | "source": [ 304 | "sns.pairplot(data[['x','y','z','w']],hue=('w'))\n", 305 | "plt.show()" 306 | ] 307 | }, 308 | { 309 | "cell_type": "markdown", 310 | "metadata": {}, 311 | "source": [ 312 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 313 | "\n", 314 | "### Actividad con Gráfico de Pares\n", 315 | "\n", 316 | "Crea un gráfico de pares que muestra la correlación entre `xt`, `yt`, y `zt` Entre los primeros 500 y segundos 500 valores aleatorios que están categorizados como `Dist`. Crea un DataFrame de `pandas` con:\n", 317 | "\n", 318 | "```python\n", 319 | "nt = 100\n", 320 | "xt = np.random.rand(nt)\n", 321 | "yt = np.random.normal(0,1,nt)\n", 322 | "zt = xt*yt\n", 323 | "dt = pd.DataFrame(np.column_stack([xt,yt,zt]),columns=['xt','yt','zt'])\n", 324 | "dt['Dist'] = 'First'\n", 325 | "for i in range(int(nt/2),nt):\n", 326 | " dt.at[i,'Dist'] = 'Second'\n", 327 | "```" 328 | ] 329 | }, 330 | { 331 | "cell_type": "code", 332 | "execution_count": null, 333 | "metadata": {}, 334 | "outputs": [], 335 | "source": [] 336 | }, 337 | { 338 | "cell_type": "markdown", 339 | "metadata": {}, 340 | "source": [ 341 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 342 | "\n", 343 | "### Diagrama de Caja\n", 344 | "\n", 345 | "Un diagrama de caja muestra los cuartiles de datos. En este caso, compararemos los primeros 500 puntos con los últimos 500 puntos." 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "execution_count": null, 351 | "metadata": {}, 352 | "outputs": [], 353 | "source": [ 354 | "sns.boxplot(x='w',y='x',data=data)\n", 355 | "plt.show()" 356 | ] 357 | }, 358 | { 359 | "cell_type": "markdown", 360 | "metadata": {}, 361 | "source": [ 362 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 363 | "\n", 364 | "### Actividad con Diagrama de Caja\n", 365 | "\n", 366 | "Crea un diagrama de caja que muestre los cuartiles de `yt` por la primera y segunda serie como se indica en `Dist`." 367 | ] 368 | }, 369 | { 370 | "cell_type": "code", 371 | "execution_count": null, 372 | "metadata": {}, 373 | "outputs": [], 374 | "source": [] 375 | }, 376 | { 377 | "cell_type": "markdown", 378 | "metadata": {}, 379 | "source": [ 380 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 381 | "\n", 382 | "### Diagrama de Violín\n", 383 | "\n", 384 | "Un diagrama de violín combina los cuartiles del diagrama de caja con la distribución." 385 | ] 386 | }, 387 | { 388 | "cell_type": "code", 389 | "execution_count": null, 390 | "metadata": {}, 391 | "outputs": [], 392 | "source": [ 393 | "sns.violinplot(x='w',y='x',data=data,size=6)\n", 394 | "plt.show()" 395 | ] 396 | }, 397 | { 398 | "cell_type": "markdown", 399 | "metadata": {}, 400 | "source": [ 401 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 402 | "\n", 403 | "### Actividad con Diagrama de Violín\n", 404 | "\n", 405 | "Crea un diagrama de violín que muestre los cuartiles y la distribución de `zt` por primera y segunda serie como se indica en `Dist` en la DataFrame `dt`." 406 | ] 407 | }, 408 | { 409 | "cell_type": "code", 410 | "execution_count": null, 411 | "metadata": {}, 412 | "outputs": [], 413 | "source": [] 414 | }, 415 | { 416 | "cell_type": "markdown", 417 | "metadata": {}, 418 | "source": [ 419 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 420 | "\n", 421 | "### Gráfico Conjunto\n", 422 | "\n", 423 | "Un gráfico conjunto muestra dos variables, con las distribuciones univariadas y conjuntas. Intenta `kind='reg'`, `'kde'`, y `'hex'` para ver diferentes estilos de gráficos conjuntos." 424 | ] 425 | }, 426 | { 427 | "cell_type": "code", 428 | "execution_count": null, 429 | "metadata": {}, 430 | "outputs": [], 431 | "source": [ 432 | "sns.jointplot('x','z',data=data,kind=\"reg\") #hex, kde, reg\n", 433 | "plt.show()" 434 | ] 435 | }, 436 | { 437 | "cell_type": "markdown", 438 | "metadata": {}, 439 | "source": [ 440 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 441 | "\n", 442 | "### Actividad con Gráfico Conjunto\n", 443 | "\n", 444 | "Crea una gráfica conjunta que muestre la distribución conjunta de `yt` y `zt` en el DataFrame `dt`." 445 | ] 446 | }, 447 | { 448 | "cell_type": "code", 449 | "execution_count": null, 450 | "metadata": {}, 451 | "outputs": [], 452 | "source": [] 453 | }, 454 | { 455 | "cell_type": "markdown", 456 | "metadata": {}, 457 | "source": [ 458 | "### Actividad con el TCLab\n", 459 | "\n", 460 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)" 461 | ] 462 | }, 463 | { 464 | "cell_type": "markdown", 465 | "metadata": {}, 466 | "source": [ 467 | "### Generar o Recuperar Datos \n", 468 | "\n", 469 | "![connections](https://apmonitor.com/che263/uploads/Begin_Python/connections.png)\n", 470 | "\n", 471 | "Carga un archivo de datos de muestra si no cuentas con un TCLab. De lo contrario, genera un archivo a partir de los datos del TCLab con segundos (`t`), niveles de calentador (`Q1` y `Q2`), y temperaturas (`lab.T1` y `lab.T2`). Registra los datos cada segundo durante 120 segundos y cambia los niveles del calentador cada 30 segundos a un número aleatorio entre 0 y 80 con `np.random.randint()`. No es necesario cambiar este programa, solo ejecútalo para recolectar los datos durante 2 minutos." 472 | ] 473 | }, 474 | { 475 | "cell_type": "code", 476 | "execution_count": null, 477 | "metadata": {}, 478 | "outputs": [], 479 | "source": [ 480 | "import tclab, time, csv\n", 481 | "import numpy as np\n", 482 | "try:\n", 483 | " n = 120 \n", 484 | " with open('04-tclab.csv',mode='w',newline='') as f:\n", 485 | " cw = csv.writer(f)\n", 486 | " cw.writerow(['Time','Q1','Q2','T1','T2'])\n", 487 | " with tclab.TCLab() as lab:\n", 488 | " print('t Q1 Q2 T1 T2')\n", 489 | " for t in range(n):\n", 490 | " if t%30==0:\n", 491 | " Q1 = np.random.randint(0,81)\n", 492 | " Q2 = np.random.randint(0,81)\n", 493 | " lab.Q1(Q1); lab.Q2(Q2)\n", 494 | " cw.writerow([t,Q1,Q2,lab.T1,lab.T2])\n", 495 | " if t%5==0:\n", 496 | " print(t,Q1,Q2,lab.T1,lab.T2)\n", 497 | " time.sleep(1)\n", 498 | " data4=pd.read_csv('04-tclab.csv')\n", 499 | "except:\n", 500 | " print('Conectar al TCLab para generar datos')\n", 501 | " url = 'http://apmonitor.com/do/uploads/Main/tclab_dyn_data2.txt'\n", 502 | " data4=pd.read_csv(url)\n", 503 | " data4.columns = ['Time','Q1','Q2','T1','T2']\n", 504 | " \n", 505 | "data4.head() " 506 | ] 507 | }, 508 | { 509 | "cell_type": "markdown", 510 | "metadata": {}, 511 | "source": [ 512 | "### Análisis Gráfico\n", 513 | "\n", 514 | "Analizar `Q1`, `Q2`, `T1`, y `T2` gráficamente con un gráfico de series de tiempo y un gráfico de pares. La serie de tiempo debe mostrar `Q1` y `Q2` en la subgráfica superior, y `T1` y `T2` en la subgráfica inferior. El diagrama de pares debe ser un gráfico de cuadrícula `2x2` que muestra los pares calentador / temperatura como `Q1`/`T1`, `Q2`/`T2`." 515 | ] 516 | }, 517 | { 518 | "cell_type": "code", 519 | "execution_count": null, 520 | "metadata": {}, 521 | "outputs": [], 522 | "source": [] 523 | } 524 | ], 525 | "metadata": { 526 | "kernelspec": { 527 | "display_name": "Python 3", 528 | "language": "python", 529 | "name": "python3" 530 | }, 531 | "language_info": { 532 | "codemirror_mode": { 533 | "name": "ipython", 534 | "version": 3 535 | }, 536 | "file_extension": ".py", 537 | "mimetype": "text/x-python", 538 | "name": "python", 539 | "nbconvert_exporter": "python", 540 | "pygments_lexer": "ipython3", 541 | "version": "3.7.6" 542 | } 543 | }, 544 | "nbformat": 4, 545 | "nbformat_minor": 2 546 | } 547 | -------------------------------------------------------------------------------- /10. Resolver_ecuaciones.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 10. Resolver Ecuaciones\n", 8 | "\n", 9 | "[Playlist de Ciencia de Datos en castellano](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67)\n", 10 | "[![Python Data Science](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/11-0001.png/:/rs=w:1280,h:720)](https://www.youtube.com/watch?v=c40z75JnT44&list=PLLBUgWXdTBDg1Qgmwt4jKtVn9BWh5-zgy \"Python Data Science\")\n", 11 | "\n", 12 | "Las ecuaciones son fundamentales en Ciencia de Datos. Permiten convertir datos en información procesable mediante el desarrollo de expresiones matemáticas que describen sistemas físicos. Algunas expresiones matemáticas son simples y pueden calcularse secuencialmente, por ejemplo:\n", 13 | "\n", 14 | "$x=1 \\quad y=x^2+2x-4$\n", 15 | "\n", 16 | "La solución es $x=1$, $y=1+2-4=-1$. \n", 17 | "\n", 18 | "Considera el caso donde $x$ también depende de $y$.\n", 19 | "\n", 20 | "$x=y \\quad y=x^2+2x-4$\n", 21 | "\n", 22 | "Hay dos soluciones que se calculan a partir de la fórmula cuadrática $y=\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}$\n", 23 | "\n", 24 | "$0=y^2+(2y-y)-4$, \n", 25 | "\n", 26 | "$\\quad y^2+y-4 = 0$, con $a=1$, $b=1$ y $c=-4$.\n", 27 | "\n", 28 | "$y = \\frac{-1 \\pm \\sqrt{17}}{2} = {1.56,-2.56}$\n", 29 | "\n", 30 | "Hay dos métodos para resolver este problema. El primero es una **solución numérica**, donde la computadora usa métodos de prueba y error para hallar la solución. Se utilizan métodos numéricos cuando hay un gran número de ecuaciones y no hay solución analítica. El segundo método es una **solución simbólica** que genera una solución exacta.\n", 31 | "\n", 32 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 33 | "\n", 34 | "### Solución Numérica\n", 35 | "\n", 36 | "Los problemas complejos y a gran escala utilizan una solución numérica, por ejemplo con `fsolve` o `gekko`. Se requiere una función que devuelva el error residual de la ecuación. Este residual es $f(y)=y^2+y-4$, que no es igual a cero cuando el valor de $y$ no es la solución correcta. Un valor inicial de `1` o `-2` da un resultado diferente porque se empieza cerca de uno u otro. \n", 37 | "\n", 38 | "#### Solución con Scipy fsolve" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": null, 44 | "metadata": {}, 45 | "outputs": [], 46 | "source": [ 47 | "from scipy.optimize import fsolve\n", 48 | "def f(y):\n", 49 | " return y**2+y-4\n", 50 | "z = fsolve(f,1); print(z)\n", 51 | "z = fsolve(f,-2); print(z)" 52 | ] 53 | }, 54 | { 55 | "cell_type": "markdown", 56 | "metadata": {}, 57 | "source": [ 58 | "![gekko](https://apmonitor.com/che263/uploads/Begin_Python/gekko.png)\n", 59 | "\n", 60 | "**Solución con Python Gekko**" 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "from gekko import GEKKO\n", 70 | "m = GEKKO(remote=False)\n", 71 | "#Declaración de la variable y. y=1\n", 72 | "y = m.Var(1)\n", 73 | "#Declaración de la ecuación\n", 74 | "m.Equation(y**2+y-4==0)\n", 75 | "#Resolución\n", 76 | "m.solve(disp=False)\n", 77 | "print(y.value)\n", 78 | "#Valor inicial y=-2\n", 79 | "y.value = -2\n", 80 | "m.solve(disp=False); print(y.value)" 81 | ] 82 | }, 83 | { 84 | "cell_type": "markdown", 85 | "metadata": {}, 86 | "source": [ 87 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 88 | "\n", 89 | "### Resolver 2 Ecuaciones\n", 90 | "\n", 91 | "Es similar tener una o dos ecuaciones\n", 92 | "\n", 93 | "$y=x^2+2x-4$\n", 94 | "\n", 95 | "$x=y$\n", 96 | "\n", 97 | "La función devuelve el error residual de cada ecuación como una lista. \n", 98 | "\n", 99 | "Se requieren dos valores iniciales. \n", 100 | "\n", 101 | "Este mismo método también se aplica para más ecuaciones. Los algoritmos que resuelven ecuaciones (solvers) pueden solucionar problemas con miles o millones de variables!!\n", 102 | "\n", 103 | "**Solución con Scipy `fsolve`**" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": null, 109 | "metadata": {}, 110 | "outputs": [], 111 | "source": [ 112 | "from scipy.optimize import fsolve\n", 113 | "def f(z):\n", 114 | " x,y = z\n", 115 | " return [x-y,y-x**2-2*x+4]\n", 116 | "z = fsolve(f,[1,1]); print(z)\n", 117 | "z = fsolve(f,[-2,-2]); print(z)" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "![gekko](https://apmonitor.com/che263/uploads/Begin_Python/gekko.png)\n", 125 | "\n", 126 | "**Solución con Python Gekko**" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "metadata": {}, 133 | "outputs": [], 134 | "source": [ 135 | "m = GEKKO(remote=False)\n", 136 | "x=m.Var(); y = m.Var(1);\n", 137 | "m.Equations([y==x**2+2*x-4, x==y])\n", 138 | "m.solve(disp=False)\n", 139 | "print(x.value, y.value)\n", 140 | "\n", 141 | "x.value=-2; y.value=-2\n", 142 | "m.solve(disp=False)\n", 143 | "print(x.value, y.value)" 144 | ] 145 | }, 146 | { 147 | "cell_type": "markdown", 148 | "metadata": {}, 149 | "source": [ 150 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 151 | "\n", 152 | "### Resolver 3 Ecuaciones\n", 153 | "\n", 154 | "$x^2+y^2+z^2=1$\n", 155 | "\n", 156 | "$x-2y+3z=0.5$\n", 157 | "\n", 158 | "$x+y+z=0$\n", 159 | "\n", 160 | "Resuelve el problema con 3 variables y 3 ecuaciones.\n", 161 | "\n", 162 | "**Solución con Scipy `fsolve`**" 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": null, 168 | "metadata": {}, 169 | "outputs": [], 170 | "source": [] 171 | }, 172 | { 173 | "cell_type": "markdown", 174 | "metadata": {}, 175 | "source": [ 176 | "![gekko](https://apmonitor.com/che263/uploads/Begin_Python/gekko.png)\n", 177 | "\n", 178 | "**Solución con Python Gekko**" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": null, 184 | "metadata": {}, 185 | "outputs": [], 186 | "source": [] 187 | }, 188 | { 189 | "cell_type": "markdown", 190 | "metadata": {}, 191 | "source": [ 192 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 193 | "\n", 194 | "### Solución Simbólica\n", 195 | "\n", 196 | "Es posible expresar simbólicamente la solución analítica de problemas simples. Una librería con símbolos matemáticos en Python es `sympy`. La función `display` está disponible para imprimir la ecuación en Jupyter notebook. Se requiere importar `from IPython.display import display`. \n" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": null, 202 | "metadata": {}, 203 | "outputs": [], 204 | "source": [ 205 | "from IPython.display import display\n", 206 | "import sympy as sym\n", 207 | "x = sym.Symbol('x')\n", 208 | "y = sym.Symbol('y')\n", 209 | "ans = sym.nonlinsolve([x-y, y-x**2-2*x+4], [x,y])\n", 210 | "display(ans)" 211 | ] 212 | }, 213 | { 214 | "cell_type": "markdown", 215 | "metadata": {}, 216 | "source": [ 217 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 218 | "\n", 219 | "### Resolver Simbólicamente 3 Ecuaciones\n", 220 | "\n", 221 | "$x\\,y\\,z=0$\n", 222 | "\n", 223 | "$x\\,y=0$\n", 224 | "\n", 225 | "$x+5\\,y+z$\n", 226 | "\n", 227 | "Resuelve el problema con 3 variables y 3 ecuaciones de forma simbólica. El problema está subespecificado, por lo que una de las variables aparecerá en la solución; es decir, hay un set infinito de soluciones. " 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": null, 233 | "metadata": { 234 | "scrolled": true 235 | }, 236 | "outputs": [], 237 | "source": [] 238 | }, 239 | { 240 | "cell_type": "markdown", 241 | "metadata": {}, 242 | "source": [ 243 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 244 | "\n", 245 | "### Ecuaciones Lineales\n", 246 | "\n", 247 | "Puedes resolver ecuaciones lineales en Python. Existen métodos eficientes como `x = np.linalg.solve(A,b)` para resolver ecuaciones de tipo $A x = b$ con la matriz $A$ y los vectores $x$ y $b$.\n", 248 | "\n", 249 | "$A = \\begin{bmatrix}3 & 2\\\\ 1 & 2 \\end{bmatrix} \\quad b = \\begin{bmatrix}1 \\\\ 0 \\end{bmatrix}$" 250 | ] 251 | }, 252 | { 253 | "cell_type": "code", 254 | "execution_count": null, 255 | "metadata": {}, 256 | "outputs": [], 257 | "source": [ 258 | "import numpy as np\n", 259 | "A = np.array([[3,2],[1,2]])\n", 260 | "b = np.array([1,0])\n", 261 | "\n", 262 | "x = np.linalg.solve(A,b)\n", 263 | "print(x)" 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": {}, 269 | "source": [ 270 | "La solución simbólica para este set de ecuaciones lineales está disponible con la función `sympy` `linsolve`. Si el problema es lineal, se prefiere usar `linsolve` porque es más eficiente que `nonlinsolve`, pero puede resolver los dos." 271 | ] 272 | }, 273 | { 274 | "cell_type": "code", 275 | "execution_count": null, 276 | "metadata": {}, 277 | "outputs": [], 278 | "source": [ 279 | "import sympy as sym\n", 280 | "x, y = sym.symbols('x y')\n", 281 | "ans = sym.linsolve([3*x + 2*y - 1, x + 2*y], (x, y))\n", 282 | "sym.pprint(ans)" 283 | ] 284 | }, 285 | { 286 | "cell_type": "markdown", 287 | "metadata": {}, 288 | "source": [ 289 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 290 | "\n", 291 | "### Optimización\n", 292 | "\n", 293 | "Cuando hay más variables que ecuaciones, el problema está subespecificado y no puede hallarse solución con una función como `fsolve` (para problemas lineales y no lineales) o `linalg.solve` (solo para problemas lineales). Se requiere información adicional para guiar la selección de las variables extra.\n", 294 | "\n", 295 | "Una función objetivo $J(x)$ es una manera de especificar el problema para que exista solución única. El objetivo es minimizar $x_1 x_4 \\left(x_1 + x_2 + x_3\\right) + x_3$. Las dos ecuaciones que guían la selección de dos variables son las restricciones de desigualdad $\\left(x_1 x_2 x_3 x_4 \\ge 25\\right)$ y de igualdad $\\left(x_1^2 + x_2^2 + x_3^2 + x_4^2 = 40\\right)$. Las cuatro variables deben estar entre `1` (límite inferior) y `5` (límite superior).\n", 296 | "\n", 297 | "\n", 298 | "$\\quad \\min x_1 x_4 \\left(x_1 + x_2 + x_3\\right) + x_3$\n", 299 | "\n", 300 | "$\\quad \\mathrm{s.t.:} \\quad x_1 x_2 x_3 x_4 \\ge 25$\n", 301 | "\n", 302 | "$\\quad x_1^2 + x_2^2 + x_3^2 + x_4^2 = 40$\n", 303 | "\n", 304 | "$\\quad 1\\le x_1, x_2, x_3, x_4 \\le 5$\n", 305 | "\n", 306 | "con valores iniciales:\n", 307 | "\n", 308 | "$\\quad x_0 = (1,5,5,1)$\n", 309 | "\n", 310 | "Información adicional sobre optimización encontrarás en el [Curso de Diseño y Optimización en inglés](https://apmonitor.com/me575) y en el [Libro de Diseño y Optimización en inglés](https://apmonitor.com/me575/index.php/Main/BookChapters).\n", 311 | "\n", 312 | "Referencia:\n", 313 | "Optimization Methods for Engineering Design, Parkinson, A.R., Balling, R., and J.D. Hedengren, Second Edition, Brigham Young University, 2018.\n", 314 | "\n", 315 | "El primer método de resolución es con `scipy.optimize.minimize`. Las funciones en esta librería trabajan bien con problemas de tamaño moderado y modelos de caja negra, donde una función objetivo está disponible a través de la llamada a una función (function call)." 316 | ] 317 | }, 318 | { 319 | "cell_type": "code", 320 | "execution_count": null, 321 | "metadata": {}, 322 | "outputs": [], 323 | "source": [ 324 | "import numpy as np\n", 325 | "from scipy.optimize import minimize\n", 326 | "\n", 327 | "def objective(x):\n", 328 | " return x[0]*x[3]*(x[0]+x[1]+x[2])+x[2]\n", 329 | "\n", 330 | "def constraint1(x):\n", 331 | " return x[0]*x[1]*x[2]*x[3]-25.0\n", 332 | "\n", 333 | "def constraint2(x):\n", 334 | " sum_eq = 40.0\n", 335 | " for i in range(4):\n", 336 | " sum_eq = sum_eq - x[i]**2\n", 337 | " return sum_eq\n", 338 | "\n", 339 | "# condiciones iniciales\n", 340 | "n = 4\n", 341 | "x0 = np.zeros(n)\n", 342 | "x0[0] = 1.0\n", 343 | "x0[1] = 5.0\n", 344 | "x0[2] = 5.0\n", 345 | "x0[3] = 1.0\n", 346 | "\n", 347 | "# optimización\n", 348 | "b = (1.0,5.0)\n", 349 | "bnds = (b, b, b, b)\n", 350 | "con1 = {'type': 'ineq', 'fun': constraint1} \n", 351 | "con2 = {'type': 'eq', 'fun': constraint2}\n", 352 | "cons = ([con1,con2])\n", 353 | "solution = minimize(objective,x0,method='SLSQP',\\\n", 354 | " bounds=bnds,constraints=cons)\n", 355 | "x = solution.x\n", 356 | "\n", 357 | "# mostrar objetivo final\n", 358 | "print('Final Objective: ' + str(objective(x)))\n", 359 | "\n", 360 | "# imprimir solución\n", 361 | "print('Solution')\n", 362 | "print('x1 = ' + str(x[0]))\n", 363 | "print('x2 = ' + str(x[1]))\n", 364 | "print('x3 = ' + str(x[2]))\n", 365 | "print('x4 = ' + str(x[3]))" 366 | ] 367 | }, 368 | { 369 | "cell_type": "markdown", 370 | "metadata": {}, 371 | "source": [ 372 | "![gekko](https://apmonitor.com/che263/uploads/Begin_Python/gekko.png)\n", 373 | "\n", 374 | "### Optimización con Gekko\n", 375 | "\n", 376 | "[Python Gekko](https://gekko.readthedocs.io/en/latest/) también resuelve problemas de optimización. Usa diferenciación automática y algoritmos (solvers) basados en gradientes como `APOPT` o `IPOPT` para hallar una solución. Este método de solución es mejor para problemas a gran escala. [Tutoriales Adicionales sobre Gekko en inglés](https://apmonitor.com/wiki/index.php/Main/GekkoPythonOptimization) muestran cómo resolver otro tipo de problemas de optimización." 377 | ] 378 | }, 379 | { 380 | "cell_type": "code", 381 | "execution_count": null, 382 | "metadata": {}, 383 | "outputs": [], 384 | "source": [ 385 | "from gekko import GEKKO\n", 386 | "m = GEKKO(remote=False)\n", 387 | "\n", 388 | "# Inicializar Variables\n", 389 | "x1,x2,x3,x4 = [m.Var(lb=1, ub=5) for i in range(4)]\n", 390 | "\n", 391 | "# Condiciones Iniciales\n", 392 | "x1.value = 1\n", 393 | "x2.value = 5\n", 394 | "x3.value = 5\n", 395 | "x4.value = 1\n", 396 | "\n", 397 | "# Ecuaciones\n", 398 | "m.Equation(x1*x2*x3*x4>=25)\n", 399 | "m.Equation(x1**2+x2**2+x3**2+x4**2==40)\n", 400 | "\n", 401 | "# Objetivo\n", 402 | "m.Obj(x1*x4*(x1+x2+x3)+x3)\n", 403 | "\n", 404 | "# Resolver\n", 405 | "m.solve(disp=False)\n", 406 | "\n", 407 | "# Objectivo Final\n", 408 | "print('Final Objective: ' + str(m.options.objfcnval))\n", 409 | "\n", 410 | "# Imprimir soluciones\n", 411 | "print('Solution')\n", 412 | "print('x1: ' + str(x1.value))\n", 413 | "print('x2: ' + str(x2.value))\n", 414 | "print('x3: ' + str(x3.value))\n", 415 | "print('x4: ' + str(x4.value))" 416 | ] 417 | }, 418 | { 419 | "cell_type": "markdown", 420 | "metadata": {}, 421 | "source": [ 422 | "### Actividad con el TCLab\n", 423 | "\n", 424 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 425 | "\n", 426 | "### Recolección de Datos\n", 427 | "\n", 428 | "![connections](https://apmonitor.com/che263/uploads/Begin_Python/connections.png)\n", 429 | "\n", 430 | "Enciende el calentador 1 al 100% y graba $T_1$ cada 10 segundos por 3 minutos. Los datos deben incluir un total de 19 puntos para cada sensor de temperatura y el tiempo, iniciando en cero. Toma nota de los puntos de temperatura en 0, 90 y 180 segundos." 431 | ] 432 | }, 433 | { 434 | "cell_type": "code", 435 | "execution_count": null, 436 | "metadata": {}, 437 | "outputs": [], 438 | "source": [] 439 | }, 440 | { 441 | "cell_type": "markdown", 442 | "metadata": {}, 443 | "source": [ 444 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 445 | "\n", 446 | "### Ecuaciones Lineales\n", 447 | "\n", 448 | "Se requieren tres puntos para especificar un polinomio de grado 2 de la forma $y =a_0 + a_1 \\; x + a_2 \\; x^2$. Crea una regresión cuadrática para $T_2$ usando solo el primer, medio y último punto. Supón que los puntos para $T_2$ son los siguientes: \n", 449 | "\n", 450 | "| Tiempo (sec) | Temperatura (°C) |\n", 451 | "|------|------|\n", 452 | "| 0 | 23.0 |\n", 453 | "| 90 | 33.0 |\n", 454 | "| 180 | 43.0 |\n", 455 | "\n", 456 | "Resuelve la regresión lineal como un set de tres ecuaciones que se derivan conectando los tres puntos a la ecuación polinómica. Crea tres ecuaciones que consideren $y=T_2$ y $x=tiempo$.\n", 457 | "\n", 458 | "$\\quad a_0 + a_1 \\; 0 + a_2 \\; 0^2 = 23.0$\n", 459 | "\n", 460 | "$\\quad a_0 + a_1 \\; 90 + a_2 \\; 90^2 = 33.0$\n", 461 | "\n", 462 | "$\\quad a_0 + a_1 \\; 180 + a_2 \\; 180^2 = 43.0$\n", 463 | "\n", 464 | "En forma de matriz, el set de ecuaciones lineales es: \n", 465 | "\n", 466 | "$\\quad \\begin{bmatrix}1 & 0 & 0 \\\\ 1 & 90 & 90^2 \\\\ 1 & 180 & 180^2 \\end{bmatrix}\\begin{bmatrix}a_0\\\\a_1\\\\a_2\\end{bmatrix} = \\begin{bmatrix}23.0\\\\33.0\\\\43.0\\end{bmatrix}$\n", 467 | "\n", 468 | "Resuelve el set de ecuaciones para hallar los parámetros cuadráticos $a_0$, $a_1$ y $a_2$ con los datos recolectados al inicio de la actividad con el TCLab. Dibuja el ajuste cuadrático con los datos para asegurar que la curva pasa por los tres puntos indicados." 469 | ] 470 | }, 471 | { 472 | "cell_type": "code", 473 | "execution_count": null, 474 | "metadata": {}, 475 | "outputs": [], 476 | "source": [] 477 | }, 478 | { 479 | "cell_type": "markdown", 480 | "metadata": {}, 481 | "source": [ 482 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 483 | "\n", 484 | "### Ecuaciones No Lineales\n", 485 | "\n", 486 | "Ajusta los datos de $T_1$ a una correlación no lineal usando solo tres puntos.\n", 487 | "\n", 488 | "$\\quad T_1 = a + b \\exp{(c \\, tiempo)}$\n", 489 | "\n", 490 | "Se requieren únicamente tres puntos para especificar un modelo con tres parámetros. Cuando hay más del mínimo número de puntos requerido, usualmente se ejecuta una regresión de mínimos cuadrados para minimizar el cuadrado del error entre los valores medidos y predecidos. Para este ejercicio, usa solo tres puntos (primero, medio y último) de los datos $T_1$. Supón que los puntos para $T_1$ son los siguientes: \n", 491 | "\n", 492 | "\n", 493 | "| Tiempo (sec) | Temperatura (°C) |\n", 494 | "|------|------|\n", 495 | "| 0 | 22.0 |\n", 496 | "| 90 | 42.0 |\n", 497 | "| 180 | 52.0 |\n", 498 | "\n", 499 | "Resuelve para hallar los tres parámetros a partir de las tres ecuaciones que intersecan a los datos requeridos. \n", 500 | "\n", 501 | "$\\quad 22.0 = a + b \\exp{(c \\, 0)}$\n", 502 | "\n", 503 | "$\\quad 42.0 = a + b \\exp{(c \\, 90.3)}$\n", 504 | "\n", 505 | "$\\quad 52.0 = a + b \\exp{(c \\, 180.5)}$\n", 506 | "\n", 507 | "Resuelve este set de ecuaciones para los parámetros desconocidos $a$, $b$ y $c$ con los datos recolectados al inicio de esta actividad. Utiliza como valores iniciales $a=100$, $b=-100$ y $c=-0.01$. Grafica el ajuste no lineal con los datos para asegurar que este pasa por los tres puntos especificados. Añade las etiquetas necesarias en el gráfico." 508 | ] 509 | }, 510 | { 511 | "cell_type": "code", 512 | "execution_count": null, 513 | "metadata": {}, 514 | "outputs": [], 515 | "source": [] 516 | } 517 | ], 518 | "metadata": { 519 | "kernelspec": { 520 | "display_name": "Python 3", 521 | "language": "python", 522 | "name": "python3" 523 | }, 524 | "language_info": { 525 | "codemirror_mode": { 526 | "name": "ipython", 527 | "version": 3 528 | }, 529 | "file_extension": ".py", 530 | "mimetype": "text/x-python", 531 | "name": "python", 532 | "nbconvert_exporter": "python", 533 | "pygments_lexer": "ipython3", 534 | "version": "3.7.6" 535 | } 536 | }, 537 | "nbformat": 4, 538 | "nbformat_minor": 2 539 | } 540 | -------------------------------------------------------------------------------- /06. Regresión.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "## 6. Regresión\n", 8 | "\n", 9 | "[Playlist de Ciencia de Datos en castellano](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67)\n", 10 | "[![Ciencia de Datos en Python](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/7-0001.png/:/rs=w:1160,h:653)](https://www.youtube.com/watch?v=Uj8x651vPrQ&list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67&index=7)\n", 11 | "\n", 12 | "Regresión es el proceso de obtener los parámetros de un modelo para ajustar una predicción `y` a valores medidos `z`. Tenemos variables independientes `x` como entradas del modelo para generar predicciones `y`. Para aprendizaje automático (machine learning), el objetivo es minimizar una función de pérdida ajustando los parámetros del modelo. Una función de pérdida común es la suma de los errores cuadrados entre los valores predichos `y` y valores medidos `z`.\n", 13 | "\n", 14 | " x = Variable independiente o de entrada\n", 15 | " y = Variable dependiente o de salida\n", 16 | " z = Variable medida u observada (análoga con variable de salida)\n", 17 | "\n", 18 | "![temperature](https://apmonitor.com/che263/uploads/Begin_Python/temperature.png)\n", 19 | "\n", 20 | "El objetivo es minimizar una función de pérdida, como una suma de errores cuadrados entre los valores medidos y predichos:\n", 21 | "\n", 22 | "$Loss = \\sum_{i=1}^{n}\\left(y_i-z_i\\right)^2$\n", 23 | "\n", 24 | "donde `n` es el número de observaciones. La regresión requiere datos etiquetados (valores de salida) para el entrenamiento. Por otra parte, la clasificación puede ser supervisada (con `z` medidas, con etiquetas) o sin supervisión (con `z` medidas, sin etiquetas). Ejecuta el siguiente código y obtén 30 puntos de datos con variables de entrada `x` y variables de salida o medidas `z`." 25 | ] 26 | }, 27 | { 28 | "cell_type": "code", 29 | "execution_count": null, 30 | "metadata": {}, 31 | "outputs": [], 32 | "source": [ 33 | "import numpy as np\n", 34 | "import pandas as pd\n", 35 | "import matplotlib.pyplot as plt\n", 36 | "%matplotlib inline\n", 37 | "n = 31\n", 38 | "x = np.linspace(0,3,n)\n", 39 | "z = np.array([1.89,-0.12,-0.32,2.11,-0.25,1.01,0.17,2.75,2.01,5.5,\\\n", 40 | " 0.87,3.31,2.29,2.73,3.67,3.92,4.29,5.27,3.85,4.26,\\\n", 41 | " 5.75,5.82,6.36,9.13,7.61,9.52,9.53,12.49,12.29,13.7,14.12])\n", 42 | "data = pd.DataFrame(np.vstack((x,z)).T,columns=['x','z'])\n", 43 | "plt.plot(x,z,'ro',label='Medido')\n", 44 | "plt.xlabel('x'); plt.ylabel('z'); plt.legend()\n", 45 | "plt.show()" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 53 | "\n", 54 | "### Regresión Lineal\n", 55 | "\n", 56 | "Hay muchas maneras de formular un modelo, como lineal, polinomial y no lineal. Un modelo lineal común es una línea con pendiente `a` y la intersección `b`.\n", 57 | "\n", 58 | " y = a x + b\n", 59 | " \n", 60 | "Un método simple para regresión lineal es utilizando `numpy` para ajustar `p=np.polyfit(x,y,1)` y evaluar el modelo `np.polyval(p,x)`. Ejecuta el siguiente código para determinar la pendiente y la intersección que minimizan la suma de los errores cuadrados (mínimos cuadrados) entre los valores predichos `y` con los medidos `z`." 61 | ] 62 | }, 63 | { 64 | "cell_type": "code", 65 | "execution_count": null, 66 | "metadata": {}, 67 | "outputs": [], 68 | "source": [ 69 | "p1 = np.polyfit(x,z,1)\n", 70 | "\n", 71 | "print('Pendiente, intersección:' + str(p1))\n", 72 | "\n", 73 | "plt.plot(x,z,'ro',label='Medido (z)')\n", 74 | "plt.plot(x,np.polyval(p1,x),'b-',label='Predicho o estimado (y)')\n", 75 | "plt.legend(); plt.show()" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": {}, 81 | "source": [ 82 | "El valore $R^2$ se puede calcular con los valores medidos (verdaderos) y los valores del modelo (predichos) para cualquier modelo de regresión, no solo modelos lineales.\n", 83 | "\n", 84 | "```python\n", 85 | "from sklearn.metrics import r2_score\n", 86 | "meas = [3.0, 2.0, 1.9, 7.1]\n", 87 | "model = [2.5, 1.8, 2.0, 8.0]\n", 88 | "r2_score(meas, model)\n", 89 | "```\n", 90 | "\n", 91 | "Otra libería es `statsmodels` la cual realiza el análisis estándar de mínimos cuadrados ordinarios (MCO) con un buen informe resumido. La entrada `x` se aumenta con columnas `np.ones(n)` para obtener también la intersección\n", 92 | "\n", 93 | "```python\n", 94 | "xc = np.vstack((x,np.ones(n))).T\n", 95 | "```\n", 96 | "\n", 97 | "y esto también se lo logra con `xc=sm.add_constant(x)`." 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [ 106 | "import statsmodels.api as sm\n", 107 | "xc = sm.add_constant(x)\n", 108 | "model = sm.OLS(z,xc).fit()\n", 109 | "predictions = model.predict(xc)\n", 110 | "model.summary()" 111 | ] 112 | }, 113 | { 114 | "cell_type": "markdown", 115 | "metadata": {}, 116 | "source": [ 117 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 118 | "\n", 119 | "### Actividad de Regresión Lineal\n", 120 | "\n", 121 | "Crea un modelo lineal con los siguientes datos:\n", 122 | "\n", 123 | "```python\n", 124 | "xr = [0.0,1.0,2.0,3.5,5.0]\n", 125 | "yr = [0.7,0.55,0.34,0.3,0.2]\n", 126 | "```\n", 127 | "\n", 128 | "Calcular el valor $R^2$ y mostrar los datos y el ajuste lineal en una gráfica." 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": null, 134 | "metadata": {}, 135 | "outputs": [], 136 | "source": [] 137 | }, 138 | { 139 | "cell_type": "markdown", 140 | "metadata": {}, 141 | "source": [ 142 | "![debug](https://apmonitor.com/che263/uploads/Begin_Python/debug.png)\n", 143 | "\n", 144 | "### Regresión Polinomial\n", 145 | "\n", 146 | "Un modelo polinomial también puede ser cuadrático:\n", 147 | "\n", 148 | " y = a x^2 + b x + c\n", 149 | " \n", 150 | "Un modelo cuadrático es realmente un modelo lineal con dos entradas `x` y `z = x^2`.\n", 151 | "\n", 152 | " y = a z + b x + c\n", 153 | " \n", 154 | "Esto también se denomina regresión lineal múltiple cuando hay más de una entrada `y = f(x,z)` donde `f` es una función de entradas `x` y `z`." 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": null, 160 | "metadata": {}, 161 | "outputs": [], 162 | "source": [ 163 | "p2 = np.polyfit(x,z,2)\n", 164 | "print(p2)\n", 165 | "plt.plot(x,z,'ro',label='Medido (z)')\n", 166 | "plt.plot(x,np.polyval(p2,x),'b-',label='Predicho (y)')\n", 167 | "plt.legend(); plt.show()" 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "metadata": {}, 173 | "source": [ 174 | "Hay más información sobre los coeficientes para el ajuste cuadrático si utilizas `statsmodels`." 175 | ] 176 | }, 177 | { 178 | "cell_type": "code", 179 | "execution_count": null, 180 | "metadata": {}, 181 | "outputs": [], 182 | "source": [ 183 | "import statsmodels.api as sm\n", 184 | "xc = np.vstack((x**2,x,np.ones(n))).T\n", 185 | "model = sm.OLS(z,xc).fit()\n", 186 | "predictions = model.predict(xc)\n", 187 | "model.summary()" 188 | ] 189 | }, 190 | { 191 | "cell_type": "markdown", 192 | "metadata": {}, 193 | "source": [ 194 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 195 | "\n", 196 | "### Actividad de Regresión Polinomial\n", 197 | "\n", 198 | "Crear un modelo polinomial con los datos:\n", 199 | "\n", 200 | "```python\n", 201 | "xr = [0.0,1.0,2.0,3.5,5.0]\n", 202 | "yr = [1.7,1.45,1.05,0.4,0.2]\n", 203 | "```\n", 204 | "\n", 205 | "Indica el modelo polinomial en una gráfica." 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": null, 211 | "metadata": {}, 212 | "outputs": [], 213 | "source": [] 214 | }, 215 | { 216 | "cell_type": "markdown", 217 | "metadata": {}, 218 | "source": [ 219 | "![list](https://apmonitor.com/che263/uploads/Begin_Python/list.png)\n", 220 | "\n", 221 | "### Regresión No Lineal\n", 222 | "\n", 223 | "Para regresión no lineal podemos utilizar una herramienta diferente como `curve_fit` que requiere la función `f` que retorna una predicción. También requiere los datos `x` y `z`. Los parámetros desconocidos `a` y `b` son ajustados para que la variable de salida coincida con la medida u observación `z`." 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": null, 229 | "metadata": {}, 230 | "outputs": [], 231 | "source": [ 232 | "from scipy.optimize import curve_fit\n", 233 | "def f(x,a,b):\n", 234 | " return a * np.exp(b*x)\n", 235 | "p, pcov = curve_fit(f,x,z)\n", 236 | "print('p = '+str(p))\n", 237 | "plt.plot(x,z,'ro')\n", 238 | "plt.plot(x,f(x,*p),'b-')\n", 239 | "plt.show()" 240 | ] 241 | }, 242 | { 243 | "cell_type": "code", 244 | "execution_count": null, 245 | "metadata": {}, 246 | "outputs": [], 247 | "source": [] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 254 | "\n", 255 | "### Actividad de Regresión No Lineal\n", 256 | "\n", 257 | "Crea un modelo no lineal con los datos:\n", 258 | "\n", 259 | "$y = a \\ln\\left( b \\, x \\right)$\n", 260 | "\n", 261 | "```python\n", 262 | "xr = [0.1,1.0,2.0,3.5,5.0]\n", 263 | "yr = [0.2,0.4,1.05,1.45,1.7]\n", 264 | "```\n", 265 | "\n", 266 | "Muestra el modelo no lineal en una gráfica." 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": null, 272 | "metadata": {}, 273 | "outputs": [], 274 | "source": [] 275 | }, 276 | { 277 | "cell_type": "markdown", 278 | "metadata": {}, 279 | "source": [ 280 | "![exercise](https://apmonitor.com/che263/uploads/Begin_Python/exercise.png)\n", 281 | "\n", 282 | "### Aprendizaje Automático o Machine Learning\n", 283 | "\n", 284 | "El aprendizaje automático corresponde a algoritmos de computador y modelos estadísticos que se basan en patrones e inferencias. Estos algoritmos realizan una tarea específica sin instrucciones explícitas. Los modelos de regresión con aprendizaje automático pueden ser tan simples como una regresión lineal o tan complejos como el aprendizaje profundo (deep learning). Este tutorial indica varios métodos de regresión con `scikit-learn`.\n", 285 | "\n", 286 | "#### Generar Datos\n", 287 | "\n", 288 | "Para hacer que la gráfica sea interactiva, agregua el comando: \n", 289 | "\n", 290 | "```python\n", 291 | "%matplotlib notebook\n", 292 | "```" 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "execution_count": null, 298 | "metadata": {}, 299 | "outputs": [], 300 | "source": [ 301 | "%matplotlib inline\n", 302 | "from mpl_toolkits.mplot3d import Axes3D\n", 303 | "\n", 304 | "import math\n", 305 | "def f(x,y):\n", 306 | " return 2*math.cos(x)*y + x*math.cos(y) - 3*x*y\n", 307 | "\n", 308 | "n = 500\n", 309 | "x = (np.random.rand(n)-0.5)*2.0\n", 310 | "y = (np.random.rand(n)-0.5)*2.0\n", 311 | "z = np.empty_like(x)\n", 312 | "for i in range(n):\n", 313 | " z[i] = f(x[i],y[i])\n", 314 | "data = pd.DataFrame(np.vstack((x,y,z)).T,columns=['x','y','z'])\n", 315 | "\n", 316 | "fig = plt.figure()\n", 317 | "ax = fig.add_subplot(111, projection='3d')\n", 318 | "ax.scatter(x,y,z,c=z,cmap='plasma')\n", 319 | "plt.show()" 320 | ] 321 | }, 322 | { 323 | "cell_type": "markdown", 324 | "metadata": {}, 325 | "source": [ 326 | "#### Escalamiento de Datos o Normalización\n", 327 | "\n", 328 | "Los datos se pueden escalar con un \"Standard Scalar\" o simplemente se dejan sin escalar porque los valores (`x`, `y`, `z`) ya están cerca de los rangos aceptables. Si se desea escalar, se lo puede hacer con algunas líneas de código adicionales y cambios en los gráficos.\n", 329 | "\n", 330 | "```python\n", 331 | "from sklearn.preprocessing import StandardScaler\n", 332 | "s = StandardScaler()\n", 333 | "ds = s.fit_transform(data)\n", 334 | "ds = pd.DataFrame(ds,columns=data.columns)\n", 335 | "```\n", 336 | "\n", 337 | "Los datos se dividen en conjuntos de entrenamiento y prueba con `train_test_split`." 338 | ] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "execution_count": null, 343 | "metadata": {}, 344 | "outputs": [], 345 | "source": [ 346 | "# sin escalado de datos\n", 347 | "ds = data\n", 348 | "\n", 349 | "# división de datos entre conjuntos de entrenamiento y prueba\n", 350 | "from sklearn.model_selection import train_test_split\n", 351 | "train,test = train_test_split(ds, test_size=0.2, shuffle=True)" 352 | ] 353 | }, 354 | { 355 | "cell_type": "markdown", 356 | "metadata": {}, 357 | "source": [ 358 | "#### Función para graficar\n", 359 | "\n", 360 | "Ejecuta el siguiente código para que cada uno de los modelos de regresión se entrenen y se muestren en un gráfico de superficie y de dispersión 3D." 361 | ] 362 | }, 363 | { 364 | "cell_type": "code", 365 | "execution_count": null, 366 | "metadata": {}, 367 | "outputs": [], 368 | "source": [ 369 | "def fit(method):\n", 370 | " # crear puntos para trazar la superficie\n", 371 | " xp = np.arange(-1, 1, 0.1)\n", 372 | " yp = np.arange(-1, 1, 0.1)\n", 373 | " XP, YP = np.meshgrid(xp, yp)\n", 374 | "\n", 375 | " model = method.fit(train[['x','y']],train['z'])\n", 376 | " zp = method.predict(np.vstack((XP.flatten(),YP.flatten())).T)\n", 377 | " ZP = zp.reshape(np.size(XP,0),np.size(XP,1))\n", 378 | "\n", 379 | " r2 = method.score(test[['x','y']],test['z'])\n", 380 | " print('R^2: ' + str(r2))\n", 381 | "\n", 382 | " fig = plt.figure()\n", 383 | " ax = fig.add_subplot(111, projection='3d')\n", 384 | " ax.scatter(ds['x'],ds['y'],ds['z'],c=z,cmap='plasma',label='data')\n", 385 | " ax.plot_surface(XP, YP, ZP, cmap='coolwarm',alpha=0.7,\n", 386 | " linewidth=0, antialiased=False)\n", 387 | " plt.show()\n", 388 | " return" 389 | ] 390 | }, 391 | { 392 | "cell_type": "markdown", 393 | "metadata": {}, 394 | "source": [ 395 | "#### Regresión Lineal con `sklearn`\n", 396 | "\n", 397 | "El regresor más simple es un modelo lineal. Este modelo no funciona muy bien con los datos no lineales, pero predice la pendiente de los datos." 398 | ] 399 | }, 400 | { 401 | "cell_type": "code", 402 | "execution_count": null, 403 | "metadata": { 404 | "scrolled": false 405 | }, 406 | "outputs": [], 407 | "source": [ 408 | "from sklearn import linear_model\n", 409 | "lm = linear_model.LinearRegression()\n", 410 | "fit(lm)" 411 | ] 412 | }, 413 | { 414 | "cell_type": "markdown", 415 | "metadata": {}, 416 | "source": [ 417 | "#### K-Nearest Neighbors" 418 | ] 419 | }, 420 | { 421 | "cell_type": "code", 422 | "execution_count": null, 423 | "metadata": { 424 | "scrolled": true 425 | }, 426 | "outputs": [], 427 | "source": [ 428 | "from sklearn.neighbors import KNeighborsRegressor\n", 429 | "knn = KNeighborsRegressor(n_neighbors=2)\n", 430 | "fit(knn)" 431 | ] 432 | }, 433 | { 434 | "cell_type": "markdown", 435 | "metadata": {}, 436 | "source": [ 437 | "#### Vectores de Soporte Regresión o Support Vector Regressor" 438 | ] 439 | }, 440 | { 441 | "cell_type": "code", 442 | "execution_count": null, 443 | "metadata": { 444 | "scrolled": true 445 | }, 446 | "outputs": [], 447 | "source": [ 448 | "from sklearn import svm\n", 449 | "s = svm.SVR(gamma='scale')\n", 450 | "fit(s)" 451 | ] 452 | }, 453 | { 454 | "cell_type": "markdown", 455 | "metadata": {}, 456 | "source": [ 457 | "#### Perceptrón Multicapa (Red Neuronal)" 458 | ] 459 | }, 460 | { 461 | "cell_type": "code", 462 | "execution_count": null, 463 | "metadata": {}, 464 | "outputs": [], 465 | "source": [ 466 | "from sklearn.neural_network import MLPRegressor\n", 467 | "nn = MLPRegressor(hidden_layer_sizes=(3), \n", 468 | " activation='tanh', solver='lbfgs')\n", 469 | "fit(nn)" 470 | ] 471 | }, 472 | { 473 | "cell_type": "markdown", 474 | "metadata": {}, 475 | "source": [ 476 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 477 | "\n", 478 | "### Actividad de Modelos de Regresión\n", 479 | "\n", 480 | "Encuentra otro [regresor en scikit-learn](https://scikit-learn.org/stable/supervised_learning.html) como *Decision Tree Regressor* o *Passive Agressive Regressor*. Entrena y prueba el regresor con la función `fit()` de este Jupyter Notebook como se indica a continuación:\n", 481 | "\n", 482 | "*Decision Tree Regressor*\n", 483 | "\n", 484 | "```python\n", 485 | "from sklearn import tree\n", 486 | "dt = tree.DecisionTreeRegressor()\n", 487 | "fit(dt)\n", 488 | "```\n", 489 | "\n", 490 | "*Passive Aggressive Regressor*\n", 491 | "\n", 492 | "```python\n", 493 | "from sklearn.linear_model import PassiveAggressiveRegressor\n", 494 | "par = PassiveAggressiveRegressor(max_iter=2000,tol=1e-3)\n", 495 | "fit(par)\n", 496 | "```\n", 497 | "\n", 498 | "Cambia las opciones del regresor si puede mejorar el valor $R^2$ de tal forma que `PassiveAggressiveRegressor` tenga `max_iter=2000`." 499 | ] 500 | }, 501 | { 502 | "cell_type": "code", 503 | "execution_count": null, 504 | "metadata": {}, 505 | "outputs": [], 506 | "source": [] 507 | }, 508 | { 509 | "cell_type": "markdown", 510 | "metadata": {}, 511 | "source": [ 512 | "![gekko](https://apmonitor.com/che263/uploads/Begin_Python/gekko.png)\n", 513 | "\n", 514 | "### Aprendizaje profundo\n", 515 | "\n", 516 | "El aprendizaje profundo (Deep Learning) es una regresión con una red neuronal de múltiples capas. La regresión con aprendizaje profundo tiene paquetes especializados como [Tensorflow](https://www.tensorflow.org) diseñado para datos a gran escala, o [Gekko](https://gekko.readthedocs.io/en/latest/) diseñado para estructuras de modelos configurables. A continuación se muestra un ejemplo utilizando Gekko, para más información mira el [tutorial de Deep Learning usando Gekko en inglés](https://apmonitor.com/do/index.php/Main/DeepLearning). Este mismo ejemplo con Keras (Tensorflow) también se muestra en el enlace." 517 | ] 518 | }, 519 | { 520 | "cell_type": "code", 521 | "execution_count": null, 522 | "metadata": {}, 523 | "outputs": [], 524 | "source": [ 525 | "from gekko import brain\n", 526 | "\n", 527 | "x = np.linspace(0.0,2*np.pi)\n", 528 | "y = np.sin(x)\n", 529 | "\n", 530 | "b = brain.Brain(remote=False)\n", 531 | "b.input_layer(1)\n", 532 | "b.layer(linear=2)\n", 533 | "b.layer(tanh=2)\n", 534 | "b.layer(linear=2)\n", 535 | "b.output_layer(1)\n", 536 | "b.learn(x,y,disp=False) \n", 537 | "\n", 538 | "xp = np.linspace(-2*np.pi,4*np.pi,100)\n", 539 | "yp = b.think(xp) \n", 540 | "\n", 541 | "plt.figure()\n", 542 | "plt.plot(x,y,'bo',label='medila (etiqueta)')\n", 543 | "plt.plot(xp,yp[0],'r-',label='modelo')\n", 544 | "plt.legend(); plt.show()" 545 | ] 546 | }, 547 | { 548 | "cell_type": "markdown", 549 | "metadata": {}, 550 | "source": [ 551 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 552 | "\n", 553 | "### Actividad con el TCLab\n", 554 | "\n", 555 | "### Guardar Datos de Temperatura\n", 556 | "\n", 557 | "![connections](https://apmonitor.com/che263/uploads/Begin_Python/connections.png)\n", 558 | "\n", 559 | "Pon el calentador 1 en 80% con `lab.Q1(80)` y el calentador 2 a 60% con `lab.Q1(60)`. Registra las temperaturas (`lab.T1` y `lab.T2`) cada 0.5 segundos (utiliza `time.sleep(0.5)`) durante 30 segundos. Almacene los valores de tiempo, temperatura 1 y temperatura 2 en `numpy` arrays. Utiliza __time.time()__ para obtener la hora actual en segundos." 560 | ] 561 | }, 562 | { 563 | "cell_type": "code", 564 | "execution_count": null, 565 | "metadata": {}, 566 | "outputs": [], 567 | "source": [] 568 | }, 569 | { 570 | "cell_type": "markdown", 571 | "metadata": {}, 572 | "source": [ 573 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 574 | "\n", 575 | "### Regresión Lineal\n", 576 | "\n", 577 | "Crea un modelo lineal para `T2` con regresión. Reporta el valor $R^2$. Agrega la línea de regresión como una línea de color negro a un gráfico con la medida `T2` como círculos azules. Agregue etiquetas apropiadas a la gráfica." 578 | ] 579 | }, 580 | { 581 | "cell_type": "code", 582 | "execution_count": null, 583 | "metadata": {}, 584 | "outputs": [], 585 | "source": [] 586 | }, 587 | { 588 | "cell_type": "markdown", 589 | "metadata": {}, 590 | "source": [ 591 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 592 | "\n", 593 | "### Regresión no Lineal\n", 594 | "\n", 595 | "Cree una regresión no lineal para `T1`. Ajusta los datos $T_1$ con:\n", 596 | "\n", 597 | "1. un modelo no lineal de la forma $T_1 = a + b \\exp{(c \\, t)}$ donde `a`, `b`, y `c` son parámetros de ajuste.\n", 598 | "2. un modelo no lineal que utiliza un regresor en `scikit-learn`, `keras (tensorflow)`, o `gekko`\n", 599 | "\n", 600 | "Reporta el valor $R^2$ para cada uno." 601 | ] 602 | }, 603 | { 604 | "cell_type": "code", 605 | "execution_count": null, 606 | "metadata": {}, 607 | "outputs": [], 608 | "source": [] 609 | } 610 | ], 611 | "metadata": { 612 | "kernelspec": { 613 | "display_name": "Python 3", 614 | "language": "python", 615 | "name": "python3" 616 | }, 617 | "language_info": { 618 | "codemirror_mode": { 619 | "name": "ipython", 620 | "version": 3 621 | }, 622 | "file_extension": ".py", 623 | "mimetype": "text/x-python", 624 | "name": "python", 625 | "nbconvert_exporter": "python", 626 | "pygments_lexer": "ipython3", 627 | "version": "3.7.6" 628 | } 629 | }, 630 | "nbformat": 4, 631 | "nbformat_minor": 2 632 | } 633 | -------------------------------------------------------------------------------- /12. Series_de_tiempo.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "Una vez finalizado el curso, por favor ayúdanos completando la siguiente **Encuesta de FINAL del curso**.\n", 8 | "\n", 9 | "[![Final](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/Final.png/:/rs=w:1440,h:1440)](https://forms.office.com/Pages/ResponsePage.aspx?id=r4yvt9iDREaFrjF8VFIjwUHkKiCq1wxFstxAwkoFiilUOExRVkVMWlZERVcyWlpUU1EyTFg4T1Q3WC4u)\n", 10 | "\n", 11 | "## 12. Series de tiempo\n", 12 | "\n", 13 | "[Playlist de Ciencia de Datos en castellano](https://www.youtube.com/playlist?list=PLjyvn6Y1kpbEmRY4-ELeRA80ZywV7Xd67)\n", 14 | "[![Python Data Science](https://img1.wsimg.com/isteam/ip/aab852a2-7b1f-49c0-92af-9206f2ec6a75/13-0001.png/:/rs=w:1160,h:653)](https://www.youtube.com/watch?v=yfgE0GheCWY&list=PLLBUgWXdTBDg1Qgmwt4jKtVn9BWh5-zgy \"Python Data Science\")\n", 15 | "\n", 16 | "Datos de **series de tiempo** se producen secuencialmente a medida que se registran nuevas mediciones. Los modelos derivados de datos dan una idea de lo que sucede a continuación. También muestran cómo se puede cambiar el sistema para lograr un resultado futuro diferente. Los modelos de series de tiempo son una representación de un sistema dinámico en tiempo discreto. Poner un modelo en forma de serie de tiempo es la base de muchos métodos de dinámica y control. Un **Digital Twin** o gemelo digital, es una representación virtual de un proceso que se ejecuta en paralelo al sistema físico. Un modelo de serie temporal puede considerarse un Digital Twin en la definición limitada de entradas y salidas específicas incluidas en el modelo. A continuación se muestra un modelo de serie de tiempo con una sola entrada `u` y una sola salida `y` con `k` como índice que hace referencia al intervalo de tiempo.\n", 17 | "\n", 18 | "$y_{k+1} = \\sum_{i=1}^{n_a} a_i y_{k-i+1} + \\sum_{i=1}^{n_b} b_i u_{k-i+1}$\n", 19 | "\n", 20 | "Los modelos de serie de tiempo Time series models se utilizan para identificación de sistemas y control. Hay información adicional sobre tipos específicos de series de tiempo y modelos dinámicos, como [ARX (Auto-Regressive exogenous inputs o entradas exógenas auto-regresivas)](https://apmonitor.com/wiki/index.php/Apps/ARXTimeSeries), modelos [Espacio-estado discretos](https://apmonitor.com/wiki/index.php/Apps/DiscreteStateSpace), y modelos [Espacio-estado continuos](https://apmonitor.com/wiki/index.php/Apps/LinearStateSpace)." 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "metadata": {}, 26 | "source": [ 27 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 28 | "\n", 29 | "### Predecir la Respuesta de Series de Tiempo `y` con Cambios en la Entrada `u`\n", 30 | "\n", 31 | "De manera similar a los modelos de ecuaciones diferenciales, un modelo de serie temporal puede tener una entrada (atributo) que cambia por una fuente externa, como la que cambia activamente a un sensor de medición, una persona (manualmente) o un computador.\n", 32 | "\n", 33 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 34 | "\n", 35 | "Calcula la respuesta `y` cuando la entrada `u` cambia de `0` a `100` con `k=5`. Utiliza los valores $n_a$=3, $n_b$=1, $n_u$=1, y $n_y$=1. El modelo de series de tiempo es: \n", 36 | "\n", 37 | "$y_{k+1} = a_1 \\, y_k + a_2 \\, y_{k-1} + a_3 \\, y_{k-2} + b_1 \\, u_k$\n", 38 | "\n", 39 | "| **Parámetro** | **Valor** |\n", 40 | "| ----------- | ----------- |\n", 41 | "| $a_1$ | 0.6 |\n", 42 | "| $a_2$ | -0.15 |\n", 43 | "| $a_3$ | 0.46 |\n", 44 | "| $b_1$ | 0.08 |\n", 45 | "\n", 46 | "La condición inicial es $y_0, y_1, y_2 = 0$ y la solución debe calcularse hasta $k=100$. Completa la ecuación para la serie de tiempo en el ciclo.\n", 47 | "\n", 48 | "```python\n", 49 | " y[k+1] = y[k] # completa la ecuación de series de tiempo aquí\n", 50 | "```" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": null, 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "import numpy as np\n", 60 | "import pandas as pd\n", 61 | "n = 101\n", 62 | "t = np.linspace(0,100,101)\n", 63 | "u = np.zeros(n); u[5:]=100\n", 64 | "y = np.zeros(n)\n", 65 | "\n", 66 | "a = [0.6,-0.15,0.46]\n", 67 | "b = [0.08]\n", 68 | "\n", 69 | "for i in range(2,n-1):\n", 70 | " k = int(t[i])\n", 71 | " y[k+1] = y[k] # completa la ecuación de series de tiempo aquí\n", 72 | " \n", 73 | "import matplotlib.pyplot as plt\n", 74 | "%matplotlib inline\n", 75 | "plt.plot(t,y,t,u)\n", 76 | "plt.show()" 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "metadata": {}, 82 | "source": [ 83 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 84 | "\n", 85 | "### Regresión de Series de Tiempo\n", 86 | "\n", 87 | "Ahora que has simulado un modelo de series de tiempo, el siguiente paso es determinar los coeficientes a partir de los datos. La función de Gekko `sysid` automatiza el proceso de identificación de sistemas de una serie de tiempo.\n", 88 | "\n", 89 | "![gekko](https://apmonitor.com/che263/uploads/Begin_Python/gekko.png)\n", 90 | "\n", 91 | "Puedes acceder a la ayuda sobre esta función con `help(m.sysid)`. Parte de la ayuda se indica a continuación.\n", 92 | "\n", 93 | " y,p,K = sysid(t,u,y,na=1,nb=1,shift='calc',pred='model')\n", 94 | "\n", 95 | " Input: t = time data\n", 96 | " u = input data for the regression\n", 97 | " y = output data for the regression \n", 98 | " na = number of output coefficients (default=1)\n", 99 | " nb = number of input coefficients (default=1)\n", 100 | " nk = input delay steps (default=0)\n", 101 | " shift (optional) = \n", 102 | " 'none' (no shift)\n", 103 | " 'init' (initial pt),\n", 104 | " 'mean' (mean center)\n", 105 | " 'calc' (calculate c)\n", 106 | " pred (option) = \n", 107 | " 'model' for output error regression form, implicit solution\n", 108 | " 'meas' for ARX regression form, explicit solution\n", 109 | " Using 'model' favors an unbiased model prediction but\n", 110 | " can require more time to compute, especially for large\n", 111 | " data sets\n", 112 | " Using 'meas' computes the coefficients of the time series\n", 113 | " model with an explicit solution\n", 114 | " \n", 115 | " Output: returns\n", 116 | " ypred (predicted outputs)\n", 117 | " p as coefficient dictionary with keys 'a','b','c'\n", 118 | " K gain matrix\n", 119 | " \n", 120 | "Hay varias opciones como `pred`, `meas` o `model`. Con `meas`, el siguiente paso de la serie de tiempo se predice de una medida anteriorcomo en la forma `ARX`. Con `model`, utiliza las predicciones del modelo anterior para predecir el próximo paso de tiempo. Esto también se conoce como modelo de error de salida o \"Output Error\" (`OE`) model. Debes usar `pred=meas` si se trata de un conjunto de datos grande ya que hará más rápido resolverlo.\n", 121 | "\n", 122 | "Lo más importante es decidir cuántos coeficientes incluir en el modelo estableciendo `na` y `nb`. Es importante comenzar con números pequeños y solo agregar coeficientes adicionales si se necesita más precisión para predecir dinámicas de orden superior. Otro factor es `shift` donde `init` es preferible si se está comenzando desde condiciones de estado estacionario. De lo contrario `mean` o `calc` son buenas opciones para crear un modelo no sesgado y que no tenga un \"offset\" en las predicciones.\n", 123 | "\n", 124 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 125 | "\n", 126 | "Cambia el número de coeficientes `na` y `nb` y observa la precisión de las predicciones. Además, establece `na=2` y `nb=2` y cambia `pred=model`.\n", 127 | "\n", 128 | "```python\n", 129 | "na = 2 # coeficientes de salida\n", 130 | "nb = 2 # coeficientes de entrada\n", 131 | "yp,p,K = m.sysid(t,u,y,na,nb,pred='meas')\n", 132 | "```\n", 133 | "\n", 134 | "¿Cuánto se tarda en resolver a medida que aumentamos el número de coeficiente o cambiamos `pred`? Se puede cronometrar con la función:\n", 135 | "\n", 136 | "```python\n", 137 | "import time\n", 138 | "start = time.time()\n", 139 | "### la función\n", 140 | "print('Elapsed time: ' + str(time.time()-start))\n", 141 | "```" 142 | ] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "execution_count": null, 147 | "metadata": {}, 148 | "outputs": [], 149 | "source": [ 150 | "from gekko import GEKKO\n", 151 | "import numpy as np\n", 152 | "import pandas as pd\n", 153 | "import matplotlib.pyplot as plt\n", 154 | "\n", 155 | "# cargar datos y analizar en columnas\n", 156 | "url = 'http://apmonitor.com/pdc/uploads/Main/tclab_data4.txt'\n", 157 | "data = pd.read_csv(url)\n", 158 | "t = data['Time']\n", 159 | "u = data['Q1']\n", 160 | "y = data['T1']\n", 161 | "\n", 162 | "# generar modelo de series de tiempo\n", 163 | "m = GEKKO(remote=False)\n", 164 | "\n", 165 | "# identificación del sistema\n", 166 | "na = 2 # coeficientes de salida\n", 167 | "nb = 2 # coeficientes de entrada\n", 168 | "yp,p,K = m.sysid(t,u,y,na,nb,pred='meas')\n", 169 | "\n", 170 | "plt.figure(figsize=(10,6))\n", 171 | "plt.subplot(2,1,1)\n", 172 | "plt.plot(t,u)\n", 173 | "plt.legend([r'$Q_1$ (%)'])\n", 174 | "plt.ylabel('MV Calentador (%)')\n", 175 | "plt.subplot(2,1,2)\n", 176 | "plt.plot(t,y,'b-',label=r'$T_{1,meas}$')\n", 177 | "plt.plot(t,yp,'r--',label=r'$T_{1,pred}$')\n", 178 | "plt.legend(); plt.ylabel('CV Temp (°C)')\n", 179 | "plt.xlabel('Tiempo (s)'); plt.savefig('12-sysid.png')" 180 | ] 181 | }, 182 | { 183 | "cell_type": "markdown", 184 | "metadata": {}, 185 | "source": [ 186 | "![idea](https://apmonitor.com/che263/uploads/Begin_Python/idea.png)\n", 187 | "\n", 188 | "### Simular Series de Tiempo\n", 189 | "\n", 190 | "También puede haber múltiples entradas y múltiples salidas, como cuando $n_a$=2, $n_b$=1, $n_u$=2, y $n_y$=2.\n", 191 | "\n", 192 | "$y_{1,k+1} = a_{1,1} \\, y_{1,k} + a_{2,1} \\, y_{1,k-1} + b_{1,1} \\, u_{1,k} + b_{1,2} \\, u_{2,k}$\n", 193 | "\n", 194 | "$y_{2,k+1} = a_{1,2} \\, y_{2,k} + a_{2,2} \\, y_{2,k-1} + b_{2,1} \\, u_{1,k} + b_{2,2} \\, u_{2,k}$\n", 195 | "\n", 196 | "Gekko tiene el modelo `arx` que resuelve modelos de series de tiempo una vez que han sido identificados. Requiere un diccionario de Python con $A\\in\\mathbb{R}^{n_a \\, \\mathrm{x} \\, n_y}$, $B\\in\\mathbb{R}^{n_y \\, \\mathrm{x} \\, \\left(n_b \\mathrm{x} n_u\\right)}$, y $C\\in\\mathbb{R}^{n_y}$ matrices de coeficientes. Este diccionario se crea automáticamente con la función de Gekko `sysid` (identificación de sistemas). A continuación tenemos un ejemplo para crear un diccionario manualmente.\n", 197 | "\n", 198 | "```python\n", 199 | " # python dictionary\n", 200 | " p = {'a':A,'b':B,'c':C}\n", 201 | "```\n", 202 | "\n", 203 | "$A = \\begin{bmatrix}0.36788 & 0.36788 \\\\ 0.223 & -0.136\\end{bmatrix}$\n", 204 | "$B = \\begin{bmatrix}0.63212 & 0.18964 \\\\ 0.31606 & 1.2642\\end{bmatrix}$\n", 205 | "$C = \\begin{bmatrix}0 & 0\\end{bmatrix}$\n", 206 | "\n", 207 | "[Tutoriales adicionales de Gekko en inglés](https://apmonitor.com/wiki/index.php/Main/GekkoPythonOptimization) nos indican cómo resolver otro tipo de ecuaciones y problemas de optimización." 208 | ] 209 | }, 210 | { 211 | "cell_type": "code", 212 | "execution_count": null, 213 | "metadata": {}, 214 | "outputs": [], 215 | "source": [ 216 | "import numpy as np\n", 217 | "from gekko import GEKKO\n", 218 | "import matplotlib.pyplot as plt\n", 219 | "%matplotlib inline\n", 220 | "\n", 221 | "na = 2 # Número de coeficientes A\n", 222 | "nb = 1 # Número de coeficientes B\n", 223 | "ny = 2 # Número de variables de salida\n", 224 | "nu = 2 # Número de variables de entrada\n", 225 | "\n", 226 | "# A (na x ny)\n", 227 | "A = np.array([[0.36788,0.36788],\\\n", 228 | " [0.223,-0.136]]) \n", 229 | "# B (ny x (nb x nu))\n", 230 | "B1 = np.array([0.63212,0.18964]).T\n", 231 | "B2 = np.array([0.31606,1.26420]).T\n", 232 | "B = np.array([[B1],[B2]])\n", 233 | "\n", 234 | "C = np.array([0,0])\n", 235 | "\n", 236 | "# Crear un diccionario de parámetros\n", 237 | "p = {'a':A,'b':B,'c':C}\n", 238 | "\n", 239 | "# Crea un modelo GEKKO\n", 240 | "m = GEKKO(remote=False)\n", 241 | "\n", 242 | "# Construye un modelo de GEKKO ARX\n", 243 | "y,u = m.arx(p)\n", 244 | "\n", 245 | "# Establece entradas\n", 246 | "tf = 20 # tiempo final\n", 247 | "u1 = np.zeros(tf+1)\n", 248 | "u2 = u1.copy()\n", 249 | "u1[5:] = 3.0\n", 250 | "u2[10:] = 5.0\n", 251 | "u[0].value = u1\n", 252 | "u[1].value = u2\n", 253 | "\n", 254 | "# Establece nombres\n", 255 | "mv1 = u[0]; mv2 = u[1]\n", 256 | "cv1 = y[0]; cv2 = y[1]\n", 257 | "\n", 258 | "# Opciones\n", 259 | "m.time = np.linspace(0,tf,tf+1)\n", 260 | "m.options.imode = 4; m.options.nodes = 2\n", 261 | "\n", 262 | "# Simula\n", 263 | "m.solve(disp=False)\n", 264 | "\n", 265 | "plt.figure(figsize=(10,6))\n", 266 | "plt.subplot(2,1,1)\n", 267 | "plt.plot(m.time,mv1.value,'r-',label=r'$MV_1$')\n", 268 | "plt.plot(m.time,mv2.value,'b--',label=r'$MV_2$')\n", 269 | "plt.ylabel('MV')\n", 270 | "plt.legend(loc='best')\n", 271 | "plt.subplot(2,1,2)\n", 272 | "plt.plot(m.time,cv1.value,'r:',label=r'$CV_1$')\n", 273 | "plt.plot(m.time,cv2.value,'b.-',label=r'$CV_2$')\n", 274 | "plt.ylabel('CV'); plt.xlabel('Time (sec)')\n", 275 | "plt.legend(loc='best')\n", 276 | "plt.show()" 277 | ] 278 | }, 279 | { 280 | "cell_type": "markdown", 281 | "metadata": {}, 282 | "source": [ 283 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 284 | "\n", 285 | "### Actividad con el TCLab\n", 286 | "\n", 287 | "Ejecuta el \"script\" para generar datos para la identificación de un sistema ARX y el controlador de modelo predictivo (MPC - Model Predictive Controller).\n", 288 | "\n", 289 | "![connections](https://apmonitor.com/che263/uploads/Begin_Python/connections.png)" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": null, 295 | "metadata": {}, 296 | "outputs": [], 297 | "source": [ 298 | "import numpy as np\n", 299 | "import pandas as pd\n", 300 | "import tclab\n", 301 | "import time\n", 302 | "import matplotlib.pyplot as plt\n", 303 | "%matplotlib inline\n", 304 | "\n", 305 | "# Generar datos con el Arduino\n", 306 | "filename = '12-tclab.csv'\n", 307 | "\n", 308 | "# Salto escalón de los calentadores\n", 309 | "Q1d = np.zeros(601)\n", 310 | "Q1d[10:100] = 80\n", 311 | "Q1d[100:200] = 20\n", 312 | "Q1d[200:300] = 70\n", 313 | "Q1d[300:400] = 50\n", 314 | "Q1d[400:500] = 100\n", 315 | "Q1d[500:] = 0\n", 316 | "\n", 317 | "Q2d = np.zeros(601)\n", 318 | "Q2d[50:150] = 35\n", 319 | "Q2d[150:250] = 95\n", 320 | "Q2d[250:350] = 25\n", 321 | "Q2d[350:450] = 100\n", 322 | "Q2d[450:550] = 45\n", 323 | "Q2d[550:] = 0\n", 324 | "\n", 325 | "# Conectar al Arduino\n", 326 | "a = tclab.TCLab()\n", 327 | "fid = open(filename,'w')\n", 328 | "fid.write('Tiempo,Q1,Q2,T1,T2\\n')\n", 329 | "fid.close()\n", 330 | "\n", 331 | "# Correr la prueba (por 20 minutos)\n", 332 | "for i in range(601):\n", 333 | " # Establecer valores del calentador\n", 334 | " a.Q1(Q1d[i])\n", 335 | " a.Q2(Q2d[i])\n", 336 | " print('Tiempo: ' + str(2*i) + \\\n", 337 | " ' Q1: ' + str(Q1d[i]) + \\\n", 338 | " ' Q2: ' + str(Q2d[i]) + \\\n", 339 | " ' T1: ' + str(a.T1) + \\\n", 340 | " ' T2: ' + str(a.T2))\n", 341 | " # Espera por 2 segundos\n", 342 | " time.sleep(2)\n", 343 | " fid = open(filename,'a')\n", 344 | " fid.write(str(2*i)+','+str(Q1d[i])+','+str(Q2d[i])+',' \\\n", 345 | " +str(a.T1)+','+str(a.T2)+'\\n')\n", 346 | " fid.close()\n", 347 | "# Cierra la conexión con el Arduino\n", 348 | "a.close()\n", 349 | "\n", 350 | "# lee los datos del archivo\n", 351 | "data = pd.read_csv(filename)\n", 352 | "\n", 353 | "# Grafica las medidas\n", 354 | "plt.figure()\n", 355 | "plt.subplot(2,1,1)\n", 356 | "plt.plot(data['Tiempo'],data['Q1'],'r-',label='Calentador 1')\n", 357 | "plt.plot(data['Tiempo'],data['Q2'],'b--',label='Calentador 2')\n", 358 | "plt.ylabel('Calentador (%)')\n", 359 | "plt.legend(loc='best')\n", 360 | "plt.subplot(2,1,2)\n", 361 | "plt.plot(data['Tiempo'],data['T1'],'r.',label='Temp. 1')\n", 362 | "plt.plot(data['Tiempo'],data['T2'],'b.',label='Temp. 2')\n", 363 | "plt.ylabel('Temp (°C)')\n", 364 | "plt.legend(loc='best')\n", 365 | "plt.xlabel('Tiempo (s)')\n", 366 | "plt.savefig('12-tclab.png')\n", 367 | "\n", 368 | "plt.show()" 369 | ] 370 | }, 371 | { 372 | "cell_type": "markdown", 373 | "metadata": {}, 374 | "source": [ 375 | "![expert](https://apmonitor.com/che263/uploads/Begin_Python/expert.png)\n", 376 | "\n", 377 | "### MPC con Modelo de Series de Tiempo\n", 378 | "\n", 379 | "Ejecuta la siguiente aplicación con el TCLab conectado. Utiliza los datos de la prueba del ejercicio anterior para crear un modelo de series de tiempo. A continuación, la aplicación utiliza esta serie de tiempo para crear una aplicación de MPC que optimiza los calentadores a los valores de temperatura objetivo. Mientras el MPC funciona, sopla los calentadores para causar una \"perturbación\". Observa cómo cambia el perfil del calentador previsto a medida que se aplica esta perturbación.\n", 380 | "\n", 381 | "