├── test ├── utils └── fig │ ├── test │ ├── Papa.png │ ├── papa.png │ ├── thor.png │ └── MexSIAM.gif ├── Ejercicios ├── utils │ └── data │ │ ├── Listas │ │ ├── test │ │ ├── sol01.npy │ │ ├── sol02.npy │ │ ├── sol03.npy │ │ ├── sol04.npy │ │ ├── sol05.npy │ │ ├── sol06.npy │ │ ├── sol07.npy │ │ ├── sol08.npy │ │ ├── sol09.npy │ │ ├── sol10.npy │ │ ├── sol11.npy │ │ ├── sol12.npy │ │ ├── sol13.npy │ │ ├── sol14.npy │ │ └── sol15.npy │ │ └── Diccionarios │ │ ├── test │ │ └── sol01.npy ├── RepresentacionDeDatos.ipynb └── Listas.ipynb ├── 00_Introduccion └── 02_HistoriaIA.ipynb └── 01_IntroduccionAA └── 03_Perceptron.ipynb /test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /utils/fig/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Ejercicios/utils/data/Diccionarios/test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /utils/fig/Papa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/utils/fig/Papa.png -------------------------------------------------------------------------------- /utils/fig/papa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/utils/fig/papa.png -------------------------------------------------------------------------------- /utils/fig/thor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/utils/fig/thor.png -------------------------------------------------------------------------------- /utils/fig/MexSIAM.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/utils/fig/MexSIAM.gif -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol01.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol01.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol02.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol02.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol03.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol03.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol04.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol04.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol05.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol05.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol06.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol06.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol07.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol07.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol08.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol08.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol09.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol09.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol10.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol10.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol11.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol11.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol12.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol12.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol13.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol13.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol14.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol14.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Listas/sol15.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Listas/sol15.npy -------------------------------------------------------------------------------- /Ejercicios/utils/data/Diccionarios/sol01.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jugernaut/MexSIAM/main/Ejercicios/utils/data/Diccionarios/sol01.npy -------------------------------------------------------------------------------- /00_Introduccion/02_HistoriaIA.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [], 7 | "toc_visible": true, 8 | "authorship_tag": "ABX9TyOiCE65s0ipzjtat2NPS9XE", 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | }, 15 | "language_info": { 16 | "name": "python" 17 | } 18 | }, 19 | "cells": [ 20 | { 21 | "cell_type": "markdown", 22 | "metadata": { 23 | "id": "view-in-github", 24 | "colab_type": "text" 25 | }, 26 | "source": [ 27 | "\"Open" 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "source": [ 33 | "\n", 34 | "

MexSIAM

\n", 35 | "

Historia Inteligencia Artificial

\n", 36 | "
\n", 37 | " \n", 38 | "
Profesor: M. en C. Miguel Angel Pérez León.
\n", 39 | "
correo: zeus@ciencias.unam.mx
\n", 40 | "
" 41 | ], 42 | "metadata": { 43 | "id": "4c1ULJt43NVg" 44 | } 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "source": [ 49 | "# Historia\n", 50 | "\n", 51 | "La inteligencia artificial es la disciplina que se ocupa de crear máquinas o sistemas capaces de realizar tareas que normalmente requieren inteligencia humana. El término fue acuñado por el informático John **McCarthy en 1956**, durante la Conferencia de Darmouth, considerada el origen de la IA como campo de estudio, Ssn embargo desde los años 1950 el matemático **Alan Turing** ya se había planteado la pregunta \"¿Pueden pensar las máquinas?\". La idea de construir artefactos inteligentes se remonta a la antigüedad, desde la mitología griega hasta los autómatas medievales. Algunos hitos importantes en la historia de la IA son:\n", 52 | "\n", 53 | "- En 1936, **Alan Turing** publica su artículo sobre los números computables, donde introduce el concepto de algoritmo y sienta las bases de la informática moderna.\n", 54 | "- En 1950, **Turing** propone el Test de Turing, una prueba para evaluar la capacidad de las máquinas de imitar el lenguaje humano, recientemente fue estrenada la pelicula llama \"El código enigma (The Imitation Game)\", la cual muestra un breve vistazo a la vida de este gran matemático\n", 55 | "- En 1956, se celebra la Conferencia de Darmouth, donde se reúnen los principales investigadores en IA y se establecen las metas y los métodos de la disciplina.\n", 56 | "- En 1969, **Marvin Minsky** publica el libro Perceptrones, donde analiza las redes neuronales artificiales y sus aplicaciones al aprendizaje automático.\n", 57 | "- En 1979, se crea el coche Stanford, uno de los primeros vehículos autónomos capaces de navegar por un entorno con obstáculos.\n", 58 | "- En 1996, la supercomputadora **Deep Blue** de IBM derrota al campeón mundial de ajedrez Garry Kasparov.\n", 59 | "- En 2014, **Eugene**, un programa de ordenador, supera el Test de Turing haciéndose pasar por un niño de 13 años.\n", 60 | "- En 2023, **ChatGPT** se convierte en el chatbot más popular y avanzado del mundo, capaz de generar respuestas coherentes y creativas a cualquier tema.\n", 61 | "\n", 62 | "La inteligencia artificial ha evolucionado desde sus inicios hasta convertirse en una tecnología omnipresente y con un enorme potencial para transformar diversos ámbitos de la sociedad, como la educación, la salud, la economía o el entretenimiento. Sin embargo, también plantea importantes desafíos éticos, sociales y legales que requieren una reflexión crítica y una regulación adecuada." 63 | ], 64 | "metadata": { 65 | "id": "84LmSBdM_xtU" 66 | } 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "source": [ 71 | "## Test de Turing\n", 72 | "\n", 73 | "El **test de Turing** es un examen de la capacidad de una máquina para exhibir un comportamiento inteligente similar al de un ser humano o indistinguible de este. Fue propuesto por **Alan Turing** en 1950 en su ensayo “*Computing Machinery and Intelligence*” mientras trabajaba en la Universidad de Mánchester.\n", 74 | "\n", 75 | "
\n", 76 | "\n", 77 | "
\n", 78 | "\n", 79 | "En el test, un humano evalúa conversaciones en lenguaje natural entre un humano y una máquina diseñada para generar respuestas similares a las de un humano. El evaluador sabe que uno de los participantes de la conversación es una máquina y los intervinientes serían separados unos de otros. La conversación estaría limitada a un medio únicamente textual como un teclado de computadora y un monitor por lo que sería irrelevante la capacidad de la máquina de transformar texto en habla.\n", 80 | "\n", 81 | "En el caso de que el evaluador no pueda distinguir entre el humano y la máquina acertadamente (Turing originalmente sugirió que la máquina debía convencer a un evaluador, después de 5 minutos de conversación, el 70 % del tiempo), la máquina habría pasado la prueba. Esta prueba no evalúa el conocimiento de la máquina en cuanto a su capacidad de responder preguntas correctamente, solo se toma en cuenta la capacidad de esta de generar respuestas similares a las que daría un humano.\n", 82 | "\n", 83 | "
\n", 84 | "\n", 86 | "
\n", 87 | "\n", 88 | "¿Alguna vez has interactuado con \"algo\" (chat, llamada de voz, etc.) sin saber realmente si \"eso\" era una persona?" 89 | ], 90 | "metadata": { 91 | "id": "wbikAdn65jGW" 92 | } 93 | }, 94 | { 95 | "cell_type": "markdown", 96 | "source": [ 97 | "## Inteligencia Artificial y Sociedad\n", 98 | "\n", 99 | "La inteligencia artificial (IA) es una de las tecnologías más importantes y revolucionarias del siglo XXI. Su impacto en la sociedad es cada vez mayor, ya que se aplica en diversos ámbitos como la ciencia, la industria, la educación, la salud y el entretenimiento. La IA consiste en crear artefactos capaces de detectar y responder a contextos complejos de forma autónoma, imitando o superando las capacidades humanas. Algunos ejemplos de IA son los asistentes virtuales, los sistemas de reconocimiento facial, los vehículos autónomos y los juegos de estrategia.\n", 100 | "\n", 101 | "La IA ofrece grandes beneficios para el desarrollo humano, como mejorar la productividad, optimizar los recursos, facilitar el acceso al conocimiento y potenciar la creatividad. Sin embargo, también plantea desafíos éticos, sociales y legales que deben ser abordados con responsabilidad y precaución. Algunos de estos desafíos son **el respeto a la privacidad, la seguridad, la equidad, la transparencia y la rendición de cuentas**. Asimismo, es necesario garantizar que la IA se utilice para fines positivos y no para causar daño o discriminación.\n", 102 | "\n", 103 | "El uso de la IA es una realidad que nos afecta a todos y que requiere de una participación activa y crítica de la sociedad. Es importante estar informados sobre sus avances, sus riesgos y sus oportunidades, así como fomentar el diálogo entre los diferentes actores involucrados: científicos, empresarios, políticos, educadores y ciudadanos. Solo así podremos aprovechar el potencial de la IA para mejorar nuestra calidad de vida y construir un futuro más justo y sostenible.\n", 104 | "\n", 105 | "Existen muchas obras literarias y peliculas, documentales etc. que nos dan un vistazo desde diferentes perspectivas de lo que es la IA, aquí algunas de las más famosas:\n", 106 | "\n", 107 | "
\n", 108 | "\n", 110 | "
\n", 111 | "\n", 112 | "
\n", 113 | "\n", 115 | "
\n", 116 | "\n", 117 | "
\n", 118 | "\n", 120 | "
\n", 121 | "\n", 122 | "
\n", 123 | "\n", 125 | "
" 126 | ], 127 | "metadata": { 128 | "id": "OqEtlv9JO9BN" 129 | } 130 | }, 131 | { 132 | "cell_type": "markdown", 133 | "source": [ 134 | "# Herramientas estilo ChatGPT\n", 135 | "\n", 136 | "Las herramientas estilo GPT, son modelos de inteligencia artificial que utilizan una arquitectura llamada **Transformer, que es una red neuronal profunda** que procesa los datos secuenciales mediante la atención. La atención es un mecanismo que le permite al modelo enfocarse en las partes más relevantes de los datos para generar una salida. Estos modelos se entrenan con una gran cantidad de textos conversacionales extraídos de internet, y aprende a generar respuestas coherentes y naturales a partir de palabras clave. ChatGPT o Bing Chat puede adaptarse a diferentes contextos y personalidades, y puede generar textos en diferentes idiomas.\n", 137 | "\n", 138 | "Estas son algunas de las aplicaciones de las herramientas estilo GPT son la generación de contenido creativo, la escritura de resúmenes, la traducción automática y la asistencia en la búsqueda de información.\n", 139 | "\n", 140 | "Algunos ejemplos de herramientas de estilo GPT son:\n", 141 | "\n", 142 | "- **OpenAI GPT-3**: Es el modelo de lenguaje más avanzado y potente hasta la fecha, capaz de generar textos coherentes y relevantes sobre cualquier tema, con diferentes estilos y formatos. Se puede acceder a él a través de una API o de plataformas como Playground o Codex.\n", 143 | "- **Bing chat**: es un chatbot de búsqueda de Microsoft Bing que ayuda a los usuarios a encontrar información y responder preguntas. Como Bing chat, puedo ayudarte a encontrar información en la web y proporcionarte respuestas precisas y detalladas a tus preguntas.\n", 144 | "- **Bard**: es un chatbot de inteligencia artificial (IA) desarrollado por Google que permite a los usuarios colaborar con IA generativa1. A diferencia de su competidor ChatGPT, Bard puede acceder a información actualizada de internet y tiene un botón “Google it” que da acceso directo al buscador. Como un colaborador creativo y útil, Bard puede mejorar tu creatividad y ayudarte a generar contenido.\n", 145 | "- **Hugging Face Transformers**: Es una biblioteca de código abierto que ofrece una colección de modelos de lenguaje pre-entrenados y personalizables, basados en arquitecturas como GPT, BERT o T5. Se puede usar para tareas como la clasificación de textos, el análisis de sentimientos, la generación de resúmenes o la extracción de entidades.\n", 146 | "- **InferKit**: Es una herramienta en línea que permite generar textos a partir de palabras clave o frases iniciales, usando un modelo de lenguaje similar a GPT-3. Se puede ajustar el tono, la longitud y el formato del texto generado, así como elegir entre diferentes temas o categorías.\n", 147 | "\n" 148 | ], 149 | "metadata": { 150 | "id": "_wq9ZDG-O5FH" 151 | } 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "source": [ 156 | "## GitHub Copilot\n", 157 | "\n", 158 | "GitHub Copilot es un nuevo asistente de codificación impulsado por la inteligencia artificial que fue desarrollado por GitHub en colaboración con OpenAI. Este asistente utiliza un modelo de lenguaje de última generación para sugerir y autocompletar el código de manera eficiente. Es un programador de pares de IA que puedes usar para obtener sugerencias para líneas o funciones completas directamente en el editor.\n", 159 | "\n", 160 | "
\n", 161 | "\n", 162 | "
\n", 163 | "\n" 164 | ], 165 | "metadata": { 166 | "id": "MgQo-GblUdOR" 167 | } 168 | }, 169 | { 170 | "cell_type": "markdown", 171 | "source": [ 172 | "## Otras IA's\n", 173 | "\n", 174 | "- **Midjourney**: es un laboratorio independiente de investigación que explora nuevos medios de pensamiento y expande los poderes imaginativos de la especie humana. Está enfocado en diseño, infraestructura humana y IA. El equipo está dirigido por David Holz, cofundador de LeapMotion y cuenta con un increíble conjunto de asesores. También es el nombre que le han dado a su IA, que sirve para crear imágenes a partir de texto, lo que se conoce como text to image. Actualmente, solo se puede utilizar mediante un bot en el Discord oficial del proyecto.\n", 175 | "\n", 176 | "- **DALL·E**: es un sistema de IA desarrollado por OpenAI que puede crear imágenes y arte realistas a partir de una descripción en lenguaje natural. Puede combinar conceptos, atributos y estilos para generar imágenes originales y realistas a partir de una descripción de texto. En enero de 2021, OpenAI presentó DALL·E y un año después, su nuevo sistema, DALL·E 2, genera imágenes más realistas y precisas con una resolución 4 veces mayor.\n", 177 | "\n", 178 | "
\n", 179 | "\n", 180 | "
\n" 181 | ], 182 | "metadata": { 183 | "id": "yQixh9UnbpvO" 184 | } 185 | }, 186 | { 187 | "cell_type": "markdown", 188 | "source": [ 189 | "# ¿Qué necesitamos?\n", 190 | "\n", 191 | "En este curso, vamos a aprender sobre inteligencia Artificial, cómo funciona el aprendizaje de máquina y las aplicaciones que se le ha dado. Para ello vamo a necesitar 3 herramientas fundamentales:\n", 192 | "\n", 193 | "- Matemáticas: Las matemáticas son el estudio de las propiedades y relaciones de los números, las formas, las cantidades y los patrones. Las matemáticas son fundamentales para la inteligencia artificial, ya que permiten modelar y resolver problemas complejos con precisión y eficiencia. Algunas ramas de las matemáticas que se aplican a la **inteligencia artificial son el álgebra lineal, el cálculo, la estadística, la probabilidad, la optimización**, etc. Estas ramas nos ayudan a entender y **manipular los datos, las funciones, las matrices, los vectores, las derivadas, las integrales, las distribuciones, las variables aleatorias, los algoritmos**, etc.\n", 194 | "\n", 195 | "- Programación: La programación es el proceso de crear instrucciones que le dicen a una computadora qué hacer. Para programar, se utiliza un lenguaje de programación, que es un conjunto de reglas y símbolos que permiten expresar las instrucciones de forma comprensible para la computadora. Algunos ejemplos de lenguajes de programación son **Python**, Java, C++, etc. La programación es una habilidad esencial para crear y modificar modelos de inteligencia artificial como chatGPT o Bing chat.\n", 196 | "\n", 197 | "- Los Chats estilo GPT: son modelos de inteligencia artificial que utilizan una arquitectura llamada **Transformer, que es una red neuronal profunda** que procesa los datos secuenciales mediante la atención. La atención es un mecanismo que le permite al modelo enfocarse en las partes más relevantes de los datos para generar una salida. Estos modelos se entrenan con una gran cantidad de textos conversacionales extraídos de internet, y aprende a generar respuestas coherentes y naturales a partir de palabras clave. ChatGPT o Bing Chat puede adaptarse a diferentes contextos y personalidades, y puede generar textos en diferentes idiomas.\n", 198 | "\n", 199 | "Como pueden ver, este tipo de tecnologìas son modelos muy avanzados y potentes que requiere de conocimientos previos de programación y matemáticas para comprender su funcionamiento y sus posibilidades. En este curso, vamos a explorar de manera superficial estos conceptos y a ver cómo podemos utilizar cestas herramientas a nuestro favor para comprender lo que hay detrás del aprendizaje de máquina.\n", 200 | "\n", 201 | "Después de lo mostrado hasta el momento, te planteo la siguiente pregunta, **¿podrías distinguir si este notebook fue creado por una IA o por un humano?**.\n", 202 | "\n", 203 | "¿La siguiente imágen es real o falsa?\n", 204 | "\n", 205 | "
\n", 206 | "\n", 207 | "
\n", 208 | "\n", 209 | "Desde hace mucho tiempo las IA's han estado presentes en nuestras vidas, solo que no lo habíamos notado, **¿alguna vez te has preguntado como sabe facebook o youtube qué anuncios mostrarte?**\n", 210 | "\n", 211 | "Después de lo visto en este notebook lo mejor que podemos hacer es adaptarnos a esta revolución digital (sin mencionar la computación cuántica) y aprovechar la técnología a nuestro favor, ya que de no hacerlo así la selección natural hara su trabajo." 212 | ], 213 | "metadata": { 214 | "id": "YkH0p54n4g47" 215 | } 216 | }, 217 | { 218 | "cell_type": "markdown", 219 | "source": [ 220 | "## Referencias\n", 221 | "\n", 222 | "* Prueba de Turing - Wikipedia, la enciclopedia libre. https://es.wikipedia.org/wiki/Prueba_de_Turing\n", 223 | "* Test de Turing: qué es, cómo funciona, ventajas y limitaciones. https://psicologiaymente.com/cultura/test-turing\n", 224 | "* Medir la inteligencia artificial: el test de Turing | OpenMind. https://www.bbvaopenmind.com/tecnologia/inteligencia-artificial/medir-la-inteligencia-artificial-el-test-de-turing/" 225 | ], 226 | "metadata": { 227 | "id": "8jDqfTViMSkU" 228 | } 229 | } 230 | ] 231 | } -------------------------------------------------------------------------------- /Ejercicios/RepresentacionDeDatos.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "id": "view-in-github", 7 | "colab_type": "text" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "deletable": false, 17 | "editable": false, 18 | "id": "3HIOuyhzps7A", 19 | "nbgrader": { 20 | "cell_type": "markdown", 21 | "checksum": "95676e2022ee6e6fb483d0111e090d21", 22 | "grade": false, 23 | "grade_id": "cell-fcc5055a29935792", 24 | "locked": true, 25 | "schema_version": 3, 26 | "solution": false, 27 | "task": false 28 | } 29 | }, 30 | "source": [ 31 | "\n", 32 | "

Rrepresetación de Datos

\n", 33 | "
\n", 34 | " \n", 35 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 36 | "
" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": { 42 | "deletable": false, 43 | "editable": false, 44 | "nbgrader": { 45 | "cell_type": "markdown", 46 | "checksum": "e3c4b54447cdba4b2ce4d75f6620c947", 47 | "grade": false, 48 | "grade_id": "cell-94a938e213a24a3e", 49 | "locked": true, 50 | "schema_version": 3, 51 | "solution": false, 52 | "task": false 53 | }, 54 | "id": "7t8A2brBnaKr" 55 | }, 56 | "source": [ 57 | "## Las siguientes lineas son de apoyo para que ustedes sólo procesen los ejercicios\n", 58 | "\n", 59 | "**Es necesario ejecutar las siguientes celdas, de otra forma no podrás realizar los ejercicios.**" 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": null, 65 | "metadata": { 66 | "id": "PCnseUnznaKr" 67 | }, 68 | "outputs": [], 69 | "source": [ 70 | "# bibliotecas de evaluacion automatizada\n", 71 | "import numpy as np \n", 72 | "from macti.evaluacion import Evalua\n", 73 | "evaluacion = Evalua('../../MexSIAM/Ejercicios/utils/data/Diccionarios', local=True)" 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": { 79 | "deletable": false, 80 | "editable": false, 81 | "id": "ElKDaY9AqDnp", 82 | "nbgrader": { 83 | "cell_type": "markdown", 84 | "checksum": "ae955622db8a3d261cde506b27565b77", 85 | "grade": false, 86 | "grade_id": "cell-0a7aa1bbb52256c2", 87 | "locked": true, 88 | "schema_version": 3, 89 | "solution": false, 90 | "task": false 91 | } 92 | }, 93 | "source": [ 94 | "# Introducción\n", 95 | "\n", 96 | "Una de las aplicaciones más comúnes que se le da al aprendizaje automaizado, es la clasificación de documentos (facturas, demandas, notas, etc.) y para ellos es necesario encontrar una forma de \"mapear\" un documento de texto en \"algo\" que pueda ser procesado y clasificado por una red neuroal.\n", 97 | "\n", 98 | "Ese algo toma el nombre de **vector característico** y simplemente consiste en encontrar una forma de representar a cada elemento de este espacio multidimensional mediante un vector." 99 | ] 100 | }, 101 | { 102 | "cell_type": "markdown", 103 | "metadata": { 104 | "deletable": false, 105 | "editable": false, 106 | "id": "XRGwWQkOqKWG", 107 | "nbgrader": { 108 | "cell_type": "markdown", 109 | "checksum": "5fc541012bb4fc144a20f3642b0f4443", 110 | "grade": false, 111 | "grade_id": "cell-4c419c8e1f0a701f", 112 | "locked": true, 113 | "schema_version": 3, 114 | "solution": false, 115 | "task": false 116 | } 117 | }, 118 | "source": [ 119 | "## Plantemaniento del problema\n", 120 | "\n", 121 | "Supongamos que se tiene una empresa (caso real) que se dedica a la digitalización de documentos y como servicio agregado desea clasificar cada uno de los documentos que digitaliza.\n", 122 | "\n", 123 | "La idea es usar algún mecanismo de clasificación automatizada para poder llevar a cabo la labor." 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": { 129 | "deletable": false, 130 | "editable": false, 131 | "id": "pGoRyhoqqKR8", 132 | "nbgrader": { 133 | "cell_type": "markdown", 134 | "checksum": "6ecc81489dbfda017f6722f603906ac8", 135 | "grade": false, 136 | "grade_id": "cell-928fa4574107fd40", 137 | "locked": true, 138 | "schema_version": 3, 139 | "solution": false, 140 | "task": false 141 | } 142 | }, 143 | "source": [ 144 | "# Diccionario\n", 145 | "\n", 146 | "El primer paso consiste en identificar cada una de las palabras que puede aparecer en los documentos a clasificar (espacio vectorial), a este conjunto de palabras se le conoce como **diccionario**.\n", 147 | "\n", 148 | "Esta labora es relativamente sencilla de realizar gracias a una estructura de datos conocida como *tablas hash* y una de sus implementaciones en *python* se conoce como diccionarios y se representa mediante el símbolo \"{}\".\n", 149 | "\n", 150 | "A continuación se listan algunos características impor tantes de las *tablas hash\"." 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "metadata": { 156 | "deletable": false, 157 | "editable": false, 158 | "id": "FQpzxO_8qKOu", 159 | "nbgrader": { 160 | "cell_type": "markdown", 161 | "checksum": "6e16d6da7d928cef47e713d788be586f", 162 | "grade": false, 163 | "grade_id": "cell-3eb891909c7afe48", 164 | "locked": true, 165 | "schema_version": 3, 166 | "solution": false, 167 | "task": false 168 | } 169 | }, 170 | "source": [ 171 | "## Características \n", 172 | "\n", 173 | "La función *hash* depende en gran medida del **conjunto de llaves (dominio)** sobre el cual sera definida y también depende del **uso que se le vaya a dar** al la tabla *hash*.\n", 174 | "\n", 175 | "Sin embargo existen 3 propiedades que siempre debe cumplir una función *hash*: \n", 176 | "\n", 177 | "* **Debe ser inyectiva** o dicho de otra manera, debe evitar colisiones en la medida de lo posible, es decir. Sea $f$ la función hash, $X$ el conjunto de llaves (dominio) y $Y$ el conjunto de valores (codominio). $$f:X\\rightarrow Y\\,\\,\\,\\,\\forall a,b\\in X\\,\\mid f(a)=f(b)\\Rightarrow a=b$$.\n", 178 | "* **No debe involucrar demasiados cálculos**, ya que de otra manera las operaciones sobre la tabla hash incrementan su costo (recursos).\n", 179 | "* **No debe ser posible su reconstrucción** tomando como base la salida de esta.\n" 180 | ] 181 | }, 182 | { 183 | "cell_type": "markdown", 184 | "metadata": { 185 | "deletable": false, 186 | "editable": false, 187 | "id": "Rvh4azTzqKJr", 188 | "nbgrader": { 189 | "cell_type": "markdown", 190 | "checksum": "2fe717e7f820bf9948eef387626101c0", 191 | "grade": false, 192 | "grade_id": "cell-5f8b8f8fba9d197e", 193 | "locked": true, 194 | "schema_version": 3, 195 | "solution": false, 196 | "task": false 197 | } 198 | }, 199 | "source": [ 200 | "## Ejemplo función *hash*\n", 201 | "\n", 202 | "El siguiente ejemplo muestra una de muchas formas en como se puede definir la función *hash*, en este ejemplo a la función *hash* le vamos a decir \"polinomio de direccionamiento\" y se emplea de manera frecuente en las ciencias de la computación.\n", 203 | "\n", 204 | "Supongamos que contamos con la siguiente matriz.\n", 205 | "\n", 206 | "$$Sea\\,A\\in M_{2x2}=\\left(\\begin{array}{cc}\n", 207 | "3_{(0,0)} & 6_{(0,1)}\\\\\n", 208 | "7_{(1,0)} & 9_{(1,1)}\n", 209 | "\\end{array}\\right)$$\n", 210 | "\n", 211 | "Por razones de espacio en memoria, necesitamos almacenar los elementos de $A$ en un objeto lineal, digamos una lista. De tal manera que los elementos de $A$ se vean así. \n", 212 | "\n", 213 | "$$\\left[\\begin{array}{cccc}\n", 214 | "3_{0} & 6_{1} & 7_{2} & 9_{3}\\end{array}\\right]$$\n", 215 | "\n", 216 | "Dicho en otras palabras, **necesitamos mapear las tuplas que representan las posiciones de los valores de $A$ en posiciones dentro de la lista**.\n", 217 | "\n", 218 | "Para llevar a cabo este mapeo necesitamos una función *hash*, que en este caso dicha función debe tomar una tupla que representa la entrada de $A$ y debe devolver una localidad de la lista. Es decir.\n", 219 | "\n", 220 | "$$X=\\{(0,0),(0,1),(1,0),(1,1)\\},Y=\\{0,1,2,3\\},f:X\\rightarrow Y$$\n", 221 | "\n", 222 | "Nos gustaría que la entrada (0,0) de A fuera mapeada a la localidad 0 de la lista y así sucesivamente hasta llegar a que la entrada (1,1) se mapeara a la localidad 3 del arreglo, es decir\n", 223 | "\n", 224 | "\\begin{array}{cc}\n", 225 | "f((0,0))=0 & f((0,1))=1\\\\\n", 226 | "f((1,0))=2 & f((1,1))=3\n", 227 | "\\end{array}\n", 228 | "\n", 229 | "Podríamos pensar que una buena forma de definir a $f$, seria $f((x,y))=x+y$, pero veamos que sucede al probarla.\n", 230 | "\n", 231 | "\\begin{array}{c}\n", 232 | "f((0,0))=0+0=0.......\\color{green}{¡bien!}\\\\\n", 233 | "f((0,1))=0+1=1.......\\color{green}{¡bien!}\n", 234 | "\\end{array}\n", 235 | "\n", 236 | "\\begin{array}{c}\n", 237 | "f((1,0))=1+0=1.......\\color{red}{¡colisi\\acute{o}n!}\\\\\n", 238 | "f((0,1))=1=f((1,0))\n", 239 | "\\end{array}\n", 240 | "\n", 241 | "Dado que se tuvo una colisión, es necesario re-definirla de otra manera menos ingenua. Veamos que sucede si definimos a $f$ de la siguiente manera.\n", 242 | "\n", 243 | "$$f((x,y))=2x+y$$\n", 244 | "\n", 245 | "Al probarla, lo que obtenemos es.\\begin{array}{c}\n", 246 | "f((0,0))=2*0+0=0\\\\\n", 247 | "f((0,1))=2*0+1=1\\\\\n", 248 | "f((1,0))=2*1+0=2\\\\\n", 249 | "f((1,1))=2*1+1=3\n", 250 | "\\end{array}\n", 251 | "\n", 252 | "Esta función, no muestra colisiones (al menos en el dominio y codominio definidos), incluso se podría probar que no presentará colisiones para ningún par de tuplas de naturales. Ademas cumple con el resto de las propiedades." 253 | ] 254 | }, 255 | { 256 | "cell_type": "markdown", 257 | "metadata": { 258 | "deletable": false, 259 | "editable": false, 260 | "id": "4ebSFWQRqJ22", 261 | "nbgrader": { 262 | "cell_type": "markdown", 263 | "checksum": "6afa9006a7dd081f2677f4dbad5a0d64", 264 | "grade": false, 265 | "grade_id": "cell-952b14a01faccd07", 266 | "locked": true, 267 | "schema_version": 3, 268 | "solution": false, 269 | "task": false 270 | } 271 | }, 272 | "source": [ 273 | "### Forma general del polinomio de direccionamiento\n", 274 | "\n", 275 | "Así que podemos pensar, que para el caso particular de matrices bidimensionales $A_{(i,j)}\\in M_{ren\\,x\\,col}$ podemos definir la función hash que mapea localidades de dicha matriz en una lista (arreglo) unidimensional de la siguiente forma.\n", 276 | "\n", 277 | "$$f((i,j))=col*i+j$$\n", 278 | "\n", 279 | "
\n", 280 | " \n", 281 | "
\n", 282 | "\n", 283 | "En la imagen podemos ver como se almacena una matriz en localidades de memoria en una computadora, los valores $\\{100, 101, ... , 105\\}$ representan las localidades de la memoria y los valores $\\{X[1,1],X[2,1],...,X[3,2]\\}$ representan los valores de la matriz $X$.\n" 284 | ] 285 | }, 286 | { 287 | "cell_type": "markdown", 288 | "metadata": { 289 | "deletable": false, 290 | "editable": false, 291 | "id": "tuZlv_y-qJw-", 292 | "nbgrader": { 293 | "cell_type": "markdown", 294 | "checksum": "24db11bee30760a7af6bf3819e612761", 295 | "grade": false, 296 | "grade_id": "cell-03055a9d875e8f99", 297 | "locked": true, 298 | "schema_version": 3, 299 | "solution": false, 300 | "task": false 301 | } 302 | }, 303 | "source": [ 304 | "# Ventajas y desventajas de una tabla *hash*\n", 305 | "\n", 306 | "Ya que vimos como es que se construye y se utiliza una tabla de dispersión, vamos a analizar sus ventajas y desventajas:\n", 307 | "\n", 308 | "* La principal ventaja es que **el orden de complejidad para insertar, buscar o eliminar en una tabla *hash* es constante**, es decir $O(1)$.\n", 309 | "\n", 310 | "* Si la función *hash* fue definida siguiendo las características que se piden para este tipo de funciones, utilizar una tabla *hash* se vuelve un procedimiento muy **eficiente y seguro**.\n", 311 | "\n", 312 | "* La principal desventaja de una tabla *hash* es el hecho de que **ni las llaves, ni los valores están obligados a conservar un orden**, así que es difícil ordenar por algún criterio una tabla *hash*.\n", 313 | "\n", 314 | "* Otra desventaja es que **a veces es complicado evitar las colisiones**, así que se tiene que hacer uso de alguna técnica adicional para poder resolver las colisiones." 315 | ] 316 | }, 317 | { 318 | "cell_type": "markdown", 319 | "metadata": { 320 | "deletable": false, 321 | "editable": false, 322 | "id": "ZA5kaSJNqJqE", 323 | "nbgrader": { 324 | "cell_type": "markdown", 325 | "checksum": "358b3e58531cefa74101c94fa0682424", 326 | "grade": false, 327 | "grade_id": "cell-28e35c7faf67eae5", 328 | "locked": true, 329 | "schema_version": 3, 330 | "solution": false, 331 | "task": false 332 | } 333 | }, 334 | "source": [ 335 | "# Diccionarios en *Python*\n", 336 | "\n", 337 | "Los diccionarios de *Python*, son una de muchas formas de poner en práctica el concepto de tablas *hash*, son muy útiles y fáciles de usar.\n", 338 | "\n", 339 | "Además como ya vienen incluidos dentro de las paqueterias de *Python* no hace falta instalar, ni si quiera importar algun paquete para poder hacer uso de los diccionarios." 340 | ] 341 | }, 342 | { 343 | "cell_type": "markdown", 344 | "metadata": { 345 | "deletable": false, 346 | "editable": false, 347 | "id": "2Rbh3uLhqJiM", 348 | "nbgrader": { 349 | "cell_type": "markdown", 350 | "checksum": "96c6077686e9c9b2ae8f4dcd72e90bbe", 351 | "grade": false, 352 | "grade_id": "cell-82a1b65aa556b5f4", 353 | "locked": true, 354 | "schema_version": 3, 355 | "solution": false, 356 | "task": false 357 | } 358 | }, 359 | "source": [ 360 | "## Diccionarios\n", 361 | "\n", 362 | "Dado que las tablas *hash* son muy útiles, la gran mayoría de los lenguajes ya cuenta con alguna implementación de estas, sin embargo a veces es necesario revisar la documentación para poder hacer uso de estas implementaciones. \n", 363 | "\n", 364 | "Por el contrario, *Python* muy a su estilo (*Pythonic way*) cuenta con una implementación (de las muchas que existen) de las tablas *hash* conocida como **diccionarios**. Esta implementación es muy sencilla e intuitiva de utilizar.\n", 365 | "\n", 366 | "La idea detrás de los diccionarios de **Python** es básicamente la misma que la de las tablas *hash*, con la peculiaridad de que el usuario no esta obligado a definir la funcion *hash*.\n", 367 | "\n", 368 | "Es decir que es suficiente con proporcionar la llave y el valor asociado a esta y *Python* se encarga de relacionarlos." 369 | ] 370 | }, 371 | { 372 | "cell_type": "markdown", 373 | "metadata": { 374 | "deletable": false, 375 | "editable": false, 376 | "id": "SUGzOiL6qJaQ", 377 | "nbgrader": { 378 | "cell_type": "markdown", 379 | "checksum": "b8253fe666f0aa571c6a299e1b2ce2f1", 380 | "grade": false, 381 | "grade_id": "cell-2462caf9342f2230", 382 | "locked": true, 383 | "schema_version": 3, 384 | "solution": false, 385 | "task": false 386 | } 387 | }, 388 | "source": [ 389 | "## Sintaxis de los diccionarios\n", 390 | "\n", 391 | "Este tipo de estructuras se emplea principalmente en *data mining* o *big data*, pero no es su único uso, también se puede usar en áreas como *deep learning* o incluso en *natural language processing*. A continuación se muestra un ejemplo de como usar los diccionarios de *Python*.\n", 392 | "\n", 393 | "* `diccionario = {}`: instrucción para crear un diccionario vacío.\n", 394 | "\n", 395 | "* `diccionario['llave'] = valor`: insertamos una llave y un valor en caso de no existir ó se actualiza el valor asociado a la llave.\n", 396 | "\n", 397 | "* `print(diccionario)`: se imprime el diccionario.\n", 398 | "\n", 399 | "* `del(diccionario[llave])`: borra la llave y valor asociado a esta.\n", 400 | "\n", 401 | "* `diccionario.clear()`: borra todas las llaves y valores dentro del diccionario." 402 | ] 403 | }, 404 | { 405 | "cell_type": "markdown", 406 | "metadata": { 407 | "deletable": false, 408 | "editable": false, 409 | "id": "gFt6GN82iXx1", 410 | "nbgrader": { 411 | "cell_type": "markdown", 412 | "checksum": "087e4e129a2a1696a53a53317e694cbf", 413 | "grade": false, 414 | "grade_id": "cell-2bf8427fa1538c61", 415 | "locked": true, 416 | "schema_version": 3, 417 | "solution": false, 418 | "task": false 419 | } 420 | }, 421 | "source": [ 422 | "## Ejemplo diccionarios *Python*\n", 423 | "\n", 424 | "Para el siguiente ejemplo vamos a usar el archivo *ManejoDatos9180.txt* que hemos usado en ocasiones previas.\n", 425 | "\n", 426 | "La diferencia principal es que en esta ocasión vamos a usar diccionarios para almacenar los datos de los alumnos, en lugar de usar una clase para almacenar estos datos." 427 | ] 428 | }, 429 | { 430 | "cell_type": "code", 431 | "execution_count": null, 432 | "metadata": { 433 | "id": "5mS23fksi108" 434 | }, 435 | "outputs": [], 436 | "source": [ 437 | "!wget https://raw.githubusercontent.com/jugernaut/ManejoDatos/desarrollo/utils/ManejodeDatos9180.txt" 438 | ] 439 | }, 440 | { 441 | "cell_type": "markdown", 442 | "metadata": { 443 | "deletable": false, 444 | "editable": false, 445 | "id": "tCcpuWwti2vC", 446 | "nbgrader": { 447 | "cell_type": "markdown", 448 | "checksum": "b219820525df7ba294474b9dbaff9968", 449 | "grade": false, 450 | "grade_id": "cell-e4c918eff818de3e", 451 | "locked": true, 452 | "schema_version": 3, 453 | "solution": false, 454 | "task": false 455 | } 456 | }, 457 | "source": [ 458 | "Una vez que tenemos el archivo en la sesión de *Google Colab*, ahora necesitamos leerlo y usando *regex* vamos a capturar los datos de los alumnos en un diccionario y posteriormente mostramos el contenido de los diccionarios." 459 | ] 460 | }, 461 | { 462 | "cell_type": "code", 463 | "execution_count": null, 464 | "metadata": { 465 | "id": "JbVooa3TjFQP" 466 | }, 467 | "outputs": [], 468 | "source": [ 469 | "import re\n", 470 | "# se abre el archivo\n", 471 | "archivo = open(\"ManejodeDatos9180.txt\")\n", 472 | "# patron para el nombre\n", 473 | "apellido1 = \"\\d+\\s+[áéíóúA-Za-zñÑ]+\"\n", 474 | "# patron para telefono\n", 475 | "telefono = \"\\d+-\\d*-\\d*-*\\d*\"\n", 476 | "\n", 477 | "# eliminamos la prime linea del archivo\n", 478 | "archivo.readline()\n", 479 | "\n", 480 | "# creamos una lista vacia donde guardaremos los diccionarios\n", 481 | "alumnos = []\n", 482 | "\n", 483 | "# leemos cada una de las lineas y usando un determinado patron\n", 484 | "# se capturan numbre completo, carrera, correo y telefono\n", 485 | "for linea in archivo:\n", 486 | " alumnos.append({\"nombre\":re.findall(apellido1, linea), \"telefono\":re.findall(telefono, linea)})\n", 487 | "\n", 488 | "# imprimimos cada uno de los diccionarios que representa a cada alumno\n", 489 | "for alumno in alumnos:\n", 490 | " print(alumno)" 491 | ] 492 | }, 493 | { 494 | "cell_type": "markdown", 495 | "metadata": { 496 | "deletable": false, 497 | "editable": false, 498 | "id": "AfbNdN54Nz3x", 499 | "nbgrader": { 500 | "cell_type": "markdown", 501 | "checksum": "1321b994d39b386cdd1dd91724dcbbf7", 502 | "grade": false, 503 | "grade_id": "cell-bf86512a22323bb8", 504 | "locked": true, 505 | "schema_version": 3, 506 | "solution": false, 507 | "task": false 508 | } 509 | }, 510 | "source": [ 511 | "# Vector Característico\n", 512 | "\n", 513 | "Supongamos que uno de los documentos que necesitamos clasificar de manera automática es el documento \"inteligencia.txt\".\n", 514 | "\n", 515 | "Para poder clasificarlo de manera tradicional (a mano) una forma de hacerlo es, leer palabra por palabra y contar la **frecuencia** de cada una de estas palabras. Probablemente para un par de documentos sea algo asequible procesarlos de esta forma pero para miles de documentos, estos se vuelve una tarea imposible.\n", 516 | "\n", 517 | "Lo ideal es usar los diccionarios de *pthon* y dejar que ellos se encarguen." 518 | ] 519 | }, 520 | { 521 | "cell_type": "markdown", 522 | "metadata": { 523 | "deletable": false, 524 | "editable": false, 525 | "id": "_n6-EsdTb3zI", 526 | "nbgrader": { 527 | "cell_type": "markdown", 528 | "checksum": "d729ca8b4689a5e1205c5818fa5e6591", 529 | "grade": false, 530 | "grade_id": "cell-b103f98c4e2a1ac8", 531 | "locked": true, 532 | "schema_version": 3, 533 | "solution": false, 534 | "task": false 535 | } 536 | }, 537 | "source": [ 538 | "## Contador de palabras\n", 539 | "\n", 540 | "En esta ocasión vamos a usar los diccionarios de *Python* para contar la frecuencia de las palabras en un determinado texto.\n", 541 | "\n", 542 | "Para tal fin vamos a agregar descarar el texto del cual queremos contar la aparición de las palabras.\n", 543 | "\n" 544 | ] 545 | }, 546 | { 547 | "cell_type": "code", 548 | "execution_count": null, 549 | "metadata": { 550 | "id": "vZ8Uy7fPcF9A" 551 | }, 552 | "outputs": [], 553 | "source": [ 554 | "!wget https://raw.githubusercontent.com/jugernaut/ManejoDatos/desarrollo/utils/inteligencia.txt" 555 | ] 556 | }, 557 | { 558 | "cell_type": "markdown", 559 | "metadata": { 560 | "deletable": false, 561 | "editable": false, 562 | "id": "BlwqaYwScayd", 563 | "nbgrader": { 564 | "cell_type": "markdown", 565 | "checksum": "6b4f3bfa75cb4dfd8dcbd8e112744635", 566 | "grade": false, 567 | "grade_id": "cell-e1798c1bb79b5e9e", 568 | "locked": true, 569 | "schema_version": 3, 570 | "solution": false, 571 | "task": false 572 | } 573 | }, 574 | "source": [ 575 | "Ya con el texto en la sesión de lo siguiente es utilizar los diccionarios de *Python* para usar las palabras dentro del texto como llaves y la aparición de las palabras en el texto como valores." 576 | ] 577 | }, 578 | { 579 | "cell_type": "code", 580 | "execution_count": null, 581 | "metadata": { 582 | "id": "vzjDRv9Hc3pS" 583 | }, 584 | "outputs": [], 585 | "source": [ 586 | "# bibliotecas utilizadas\n", 587 | "import re\n", 588 | "from collections import Counter\n", 589 | "\n", 590 | "def data_mining(ruta):\n", 591 | " #abrimos el archivo a leer\n", 592 | " archivo = open(ruta)\n", 593 | " \n", 594 | " # se gudarda en una variable el resultado de leer el archivo\n", 595 | " cadenota = archivo.read()\n", 596 | " \n", 597 | " # generamos una lista con las palabaras utilizando el espacio en blanco\n", 598 | " # como patron delimitador para obtener cada una de las palabras\n", 599 | " lista_palabras = re.split('\\s+', cadenota)\n", 600 | " \n", 601 | " # se crea un diccionario para contar la frecuencia de las palabras\n", 602 | " diccionario = {}\n", 603 | "\n", 604 | " # contamos la frecuencia de cada palabra\n", 605 | " for palabra in lista_palabras:\n", 606 | " # cada palabra es agregada al diccionario, si ya se tiene tal llave se suma 1\n", 607 | " # en caso de no existir dicha palabra se devuelve cero. En cualquier caso\n", 608 | " # se suma uno por cada vez que aparezca dicha palabra\n", 609 | " diccionario[palabra] = diccionario.get(palabra, 0) + 1\n", 610 | " \n", 611 | " # antes de procesar la cadenota deberia pasar un proceso de limpieza en el\n", 612 | " # cual mediante regex se eliminaran palabras muy frecuentes como articulos\n", 613 | " #print(diccionario)\n", 614 | "\n", 615 | " # usando el paquete collections podemos ordenar el diccionario, a pesar\n", 616 | " # de que no es una cualidad de los diccionaros\n", 617 | " contador = Counter(diccionario)\n", 618 | " diccionarioOrdenado = contador.most_common()\n", 619 | "\n", 620 | " # Se imprime el diccionario ordenado para saber facilmente de que trato el\n", 621 | " # el texto de la cadenota\n", 622 | " return diccionarioOrdenado\n", 623 | "\n", 624 | "if __name__ == \"__main__\":\n", 625 | " # ruta donde se ubica el texto a analiza\n", 626 | " print(data_mining(\"inteligencia.txt\"))" 627 | ] 628 | }, 629 | { 630 | "cell_type": "markdown", 631 | "metadata": { 632 | "deletable": false, 633 | "editable": false, 634 | "nbgrader": { 635 | "cell_type": "markdown", 636 | "checksum": "c92607291e93ae7eb3bf056b7b15c123", 637 | "grade": false, 638 | "grade_id": "cell-bae4160958bf1d0b", 639 | "locked": true, 640 | "schema_version": 3, 641 | "solution": false, 642 | "task": false 643 | }, 644 | "id": "fNXQJL9lnaK2" 645 | }, 646 | "source": [ 647 | "# Obtener el vector característico\n", 648 | "\n", 649 | "Considerando la función `data_mining(ruta)` que devuelve el diccionario con la frecuencia de las palabras en el documento ubicado en `ruta` modifica el resultado de la función `data_mining(ruta)` para obtener solo un vector con la frecuencia de las palabras, el resultado debería ser similar a lo siguiente `[51, 17, 15, 14, 12, 10, 10, 10, 9, 9, 6, 6, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,....]` donde cada una de las entradas de este vector es la frecuencia de las palabras." 650 | ] 651 | }, 652 | { 653 | "cell_type": "code", 654 | "execution_count": null, 655 | "metadata": { 656 | "deletable": false, 657 | "nbgrader": { 658 | "cell_type": "code", 659 | "checksum": "901635fb4fd501623a3b60bf5f2b65d2", 660 | "grade": false, 661 | "grade_id": "cell-356c7bce97a45fbb", 662 | "locked": false, 663 | "schema_version": 3, 664 | "solution": true, 665 | "task": false 666 | }, 667 | "id": "TmZIgdZhnaK2" 668 | }, 669 | "outputs": [], 670 | "source": [ 671 | "import numpy as np\n", 672 | "\n", 673 | "vector_caracteristico = []\n", 674 | "\n", 675 | "# YOUR CODE HERE\n", 676 | "raise NotImplementedError()" 677 | ] 678 | }, 679 | { 680 | "cell_type": "code", 681 | "execution_count": null, 682 | "metadata": { 683 | "deletable": false, 684 | "editable": false, 685 | "nbgrader": { 686 | "cell_type": "code", 687 | "checksum": "6b86022135668b1c4ecbfe8e7080c01f", 688 | "grade": true, 689 | "grade_id": "cell-74f91253a10257ed", 690 | "locked": true, 691 | "points": 0, 692 | "schema_version": 3, 693 | "solution": false, 694 | "task": false 695 | }, 696 | "id": "XzOjTYEnnaK3" 697 | }, 698 | "outputs": [], 699 | "source": [ 700 | "evaluacion.verifica(np.array(vector_caracteristico), 1)" 701 | ] 702 | }, 703 | { 704 | "cell_type": "markdown", 705 | "metadata": { 706 | "deletable": false, 707 | "editable": false, 708 | "id": "MMOa0DdUdoyA", 709 | "nbgrader": { 710 | "cell_type": "markdown", 711 | "checksum": "3db58f31fcd5d79d16063390f0dba666", 712 | "grade": false, 713 | "grade_id": "cell-d4ce4152f157d370", 714 | "locked": true, 715 | "schema_version": 3, 716 | "solution": false, 717 | "task": false 718 | } 719 | }, 720 | "source": [ 721 | "La primera lista representa el diccionario con el siguiente formato *'palabra':frecuencia* y la segunda lista, es el diccionario en forma de tuplas pero ya ordenadas de por frecuencia en orden decreciente.\n", 722 | "\n", 723 | "De tal manera que podemos apreciar que la palabra que más aparece en el texto *inteligencia.txt* (descontando artículos, pronombres y preposiciones) es **Aprendizaje**.\n", 724 | "\n", 725 | "Dependiendo de como haya sido definido el diccionario global, esta lista sería el **vector caractistico** de este documento, es decir es un vector que lo representa y mediante el cual puede ser procesado por un *SOM*(igual que los colores) como se vio en la presentación pasada." 726 | ] 727 | }, 728 | { 729 | "cell_type": "markdown", 730 | "metadata": { 731 | "deletable": false, 732 | "editable": false, 733 | "id": "mE-_tFNJfwkZ", 734 | "nbgrader": { 735 | "cell_type": "markdown", 736 | "checksum": "96abc4e29f352516ab19aecbfadaae4c", 737 | "grade": false, 738 | "grade_id": "cell-d787ca49f9309097", 739 | "locked": true, 740 | "schema_version": 3, 741 | "solution": false, 742 | "task": false 743 | } 744 | }, 745 | "source": [ 746 | "## Ley de Zipf\n", 747 | "\n", 748 | "La ley de Zipf es una ley empírica que describe la relación entre la frecuencia y el rango de las palabras en un texto o en un idioma. Según esta ley, la frecuencia de una palabra es inversamente proporcional a su rango, es decir, la palabra más usada tiene una frecuencia dos veces mayor que la segunda más usada, tres veces mayor que la tercera más usada, y así sucesivamente. Esta ley se cumple en la mayoría de las lenguas naturales y artificiales, y también se aplica a otros fenómenos sociales y matemáticos ." 749 | ] 750 | }, 751 | { 752 | "cell_type": "markdown", 753 | "metadata": { 754 | "deletable": false, 755 | "editable": false, 756 | "id": "qmstd-_3Q7D6", 757 | "nbgrader": { 758 | "cell_type": "markdown", 759 | "checksum": "7979d9de95f27200dcc78cf000b5d1e4", 760 | "grade": false, 761 | "grade_id": "cell-bd60c6889c48b2e6", 762 | "locked": true, 763 | "schema_version": 3, 764 | "solution": false, 765 | "task": false 766 | } 767 | }, 768 | "source": [ 769 | "# Preprocesamiento de datos\n", 770 | "\n", 771 | "Siempre es muy útil \"eliminar el ruido\" que pueda haber en los datos a procesar. Con los documentos diitalizados, eso significa eliminar las palabras que no sean legibles y para las imagenes eso significa eliminar los pixeles que no puedan ser identificados.\n", 772 | "\n", 773 | "El preprocesamiento puede ser de diferentes formas, en el caso de las imágenes eso significa pasarlas a escala de grises para que puedan ser procesadas de mejor manera." 774 | ] 775 | }, 776 | { 777 | "cell_type": "markdown", 778 | "metadata": { 779 | "deletable": false, 780 | "editable": false, 781 | "id": "HzT2Ru3rqGhW", 782 | "nbgrader": { 783 | "cell_type": "markdown", 784 | "checksum": "1ffe2d0e2746c2a657c75f4023624928", 785 | "grade": false, 786 | "grade_id": "cell-13c2d21a03c30ec5", 787 | "locked": true, 788 | "schema_version": 3, 789 | "solution": false, 790 | "task": false 791 | } 792 | }, 793 | "source": [ 794 | "# Referencias\n", 795 | "\n", 796 | "* Thomas H. Cormen: Introduction to Algorithms.\n", 797 | "* Libro Web: Introduccion a Python.\n", 798 | "* Daniel T. Joyce: Object-Oriented Data Structures.\n", 799 | "* John C. Mitchell: Concepts in programing Languages." 800 | ] 801 | } 802 | ], 803 | "metadata": { 804 | "colab": { 805 | "provenance": [], 806 | "toc_visible": true, 807 | "include_colab_link": true 808 | }, 809 | "kernelspec": { 810 | "display_name": "Python 3 (ipykernel)", 811 | "language": "python", 812 | "name": "python3" 813 | }, 814 | "language_info": { 815 | "codemirror_mode": { 816 | "name": "ipython", 817 | "version": 3 818 | }, 819 | "file_extension": ".py", 820 | "mimetype": "text/x-python", 821 | "name": "python", 822 | "nbconvert_exporter": "python", 823 | "pygments_lexer": "ipython3", 824 | "version": "3.9.7" 825 | } 826 | }, 827 | "nbformat": 4, 828 | "nbformat_minor": 0 829 | } -------------------------------------------------------------------------------- /Ejercicios/Listas.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "id": "view-in-github", 7 | "colab_type": "text" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": { 16 | "deletable": false, 17 | "editable": false, 18 | "nbgrader": { 19 | "cell_type": "markdown", 20 | "checksum": "047b5554cd64621ff82ececc44a24cd5", 21 | "grade": false, 22 | "grade_id": "cell-07b575e6570d43c4", 23 | "locked": true, 24 | "schema_version": 3, 25 | "solution": false, 26 | "task": false 27 | }, 28 | "id": "DtukHau0beFH" 29 | }, 30 | "source": [ 31 | "\n", 32 | "

Listas

\n", 33 | "
\n", 34 | " \n", 35 | "
Profesor: M. en C. Miguel Angel Pérez León
\n", 36 | "
" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "metadata": { 42 | "deletable": false, 43 | "editable": false, 44 | "id": "WzpLGeqMBap-", 45 | "nbgrader": { 46 | "cell_type": "markdown", 47 | "checksum": "3d8f781eeb7ecbf02655aa2542e06e63", 48 | "grade": false, 49 | "grade_id": "cell-de4c5ec7d4fc7d22", 50 | "locked": true, 51 | "schema_version": 3, 52 | "solution": false, 53 | "task": false 54 | } 55 | }, 56 | "source": [ 57 | "## Wordplay\n", 58 | "\n", 59 | "Constestar los siguientes ejercicios, para ser acredores a los 2 puntos sobre el primer parcial:\n", 60 | " - Debe entrgarse en parejas\n", 61 | " - Todos los ejericicios deben pasar las pruebas\n", 62 | " - en caso de cración de funciones, comentarlas debidamente como como se mostró en clases:\n", 63 | "\n", 64 | "```python\n", 65 | "def nombre_funcion(arg_1:tipo_dato, arg_2:tipo_dato,...,) -> (tipo de dato de vuelta de la función):\n", 66 | " '''descripción de lo que hace la función\n", 67 | " - tipo de dato de entrada y valores que acxepta\n", 68 | " - tipo de dato de salida y valores qeu acepta\n", 69 | "\n", 70 | " poner un ejemplo de lo que hace la funcion\n", 71 | " >>>nombre_funcion(5,3)\n", 72 | " [out] 8\n", 73 | " '''\n", 74 | "```\n", 75 | "\n", 76 | "Todo inciso cuenta con su respectiva validación, **no continuar con incisos que no hayan pasado la validación.**\n", 77 | "\n", 78 | "- (a) Todas las palabras que terminen con *ime*.\n", 79 | "- (b) Cuantas palabras contienen al menos una de las siguientesletras *r, s, t, l, n, e*.\n", 80 | "- (c) Porcentaje de palabras contienen al menos una de las siguientesletras *r, s, t, l, n, e*.\n", 81 | "- (d) Todas las palabras que no contienen vocales (sin ninguna vocal) :).\n", 82 | "- (e) Todas las palabras que contiene todas las vocales.\n", 83 | "- (f) Responder si hay más palabras con 10 letras o con 7 letras.\n", 84 | "- (g) La palabras más larga en la lista.\n", 85 | "- (h) Todos los palindromos (un palindromo es una palabra que se lee igual de izquierda a derecha que vicebersa).\n", 86 | "- (j) Todas las palabras que contiene una *q* sin que sea seguida de una *u*.\n", 87 | "- (k) Todas las palabras que contiene *zu* en cualquier parte de la palabra.\n", 88 | "- (l) Todas las palabras que contienen una *z* y una *w*.\n", 89 | "- (m) Todas las palabras cuya primer letra es una *a*, tercer letra es una *e* y quinta letra es una *i*.\n", 90 | "- (n) Todas las palabras de 2 letras.\n", 91 | "- (o) Todas las palabras de 4 letras que comenzan y terminan con la misma letra.\n", 92 | "- (p) Cuantas vocales contiene una palabra.\n", 93 | "- (q) Todas las palabras que contienen al menos 9 vocales." 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "metadata": { 99 | "deletable": false, 100 | "editable": false, 101 | "nbgrader": { 102 | "cell_type": "markdown", 103 | "checksum": "7cd0c0d877f6ef8eeca72dd0531d0e6c", 104 | "grade": false, 105 | "grade_id": "cell-2494b8a44223bb5d", 106 | "locked": true, 107 | "schema_version": 3, 108 | "solution": false, 109 | "task": false 110 | }, 111 | "id": "A6C6awJLbeFJ" 112 | }, 113 | "source": [ 114 | "## Las siguientes lineas son de apoyo para que ustedes sólo procesen los ejercicios\n", 115 | "\n", 116 | "**Es necesario ejecutar las siguientes celdas, de otra forma no podrás realizar los ejercicios.**" 117 | ] 118 | }, 119 | { 120 | "cell_type": "code", 121 | "execution_count": null, 122 | "metadata": { 123 | "deletable": false, 124 | "editable": false, 125 | "id": "ZeswvqRsBap_", 126 | "nbgrader": { 127 | "cell_type": "code", 128 | "checksum": "57e2bead4db4951a28be8c07ec98e530", 129 | "grade": true, 130 | "grade_id": "cell-ba32c59b74443991", 131 | "locked": true, 132 | "points": 0, 133 | "schema_version": 3, 134 | "solution": false, 135 | "task": false 136 | } 137 | }, 138 | "outputs": [], 139 | "source": [ 140 | "# bibliotecas de evaluacion automatizada\n", 141 | "import numpy as np \n", 142 | "from macti.evaluacion import Evalua\n", 143 | "evaluacion = Evalua('../../MexSIAM/Ejercicios/utils/data/Listas', local=True)\n", 144 | "\n", 145 | "file = open('../../MexSIAM/Ejercicios/utils/data/wordsInEnglish.txt', 'r') #abrir el txt\n", 146 | "words = file.read() # lectura de txt y guardado en la variable words\n", 147 | "file.close() # cerrar el txt\n", 148 | "words[:100]" 149 | ] 150 | }, 151 | { 152 | "cell_type": "code", 153 | "execution_count": null, 154 | "metadata": { 155 | "deletable": false, 156 | "editable": false, 157 | "id": "JRqW7CrTBap_", 158 | "nbgrader": { 159 | "cell_type": "code", 160 | "checksum": "c8f5b655244e159b7c6c0eaaad320697", 161 | "grade": true, 162 | "grade_id": "cell-ce9f090cd2f223c1", 163 | "locked": true, 164 | "points": 0, 165 | "schema_version": 3, 166 | "solution": false, 167 | "task": false 168 | } 169 | }, 170 | "outputs": [], 171 | "source": [ 172 | "words = words.replace('\\n', ', ')" 173 | ] 174 | }, 175 | { 176 | "cell_type": "code", 177 | "execution_count": null, 178 | "metadata": { 179 | "deletable": false, 180 | "editable": false, 181 | "id": "ioWexvwfBaqB", 182 | "nbgrader": { 183 | "cell_type": "code", 184 | "checksum": "54fa515a30c0ee8439f0a12da23936ca", 185 | "grade": true, 186 | "grade_id": "cell-d79c741d2f8ffcf1", 187 | "locked": true, 188 | "points": 0, 189 | "schema_version": 3, 190 | "solution": false, 191 | "task": false 192 | } 193 | }, 194 | "outputs": [], 195 | "source": [ 196 | "'''\n", 197 | "LA VARIABLE WORDS CONTIENE LA LISTA DE PALABRAS, ALGO ASÍ\n", 198 | "a\n", 199 | "aa\n", 200 | "aaa\n", 201 | "aah\n", 202 | "aahed\n", 203 | "aahing\n", 204 | "aahs\n", 205 | "aal\n", 206 | "aalii\n", 207 | "aaliis\n", 208 | "aals\n", 209 | "aam\n", 210 | "aani\n", 211 | "aardvark\n", 212 | "aardvarks\n", 213 | "aardwolf\n", 214 | "aardwolves\n", 215 | "aargh\n", 216 | "aaron\n", 217 | "aaronic\n", 218 | "aaronical\n", 219 | "aaronite\n", 220 | "aaronitic\n", 221 | "aarrgh\n", 222 | "'''\n", 223 | "words = words.split(', ')" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": null, 229 | "metadata": { 230 | "deletable": false, 231 | "editable": false, 232 | "id": "UlcffWFKBaqB", 233 | "nbgrader": { 234 | "cell_type": "code", 235 | "checksum": "c3e1f9644c550e66d93ce99d54049cc1", 236 | "grade": true, 237 | "grade_id": "cell-ca07fb6b3287579d", 238 | "locked": true, 239 | "points": 0, 240 | "schema_version": 3, 241 | "solution": false, 242 | "task": false 243 | } 244 | }, 245 | "outputs": [], 246 | "source": [ 247 | "# UTILIZA LA VARIABLE words para todos los incisos\n", 248 | "len(words)" 249 | ] 250 | }, 251 | { 252 | "cell_type": "markdown", 253 | "metadata": { 254 | "id": "T-wBf6KKbeFM" 255 | }, 256 | "source": [ 257 | "## Consideraciones\n", 258 | "\n", 259 | "- En cada iniciso debes completar el código respetando la variable de retorno\n", 260 | "- Respeta el orden alfabético.\n", 261 | "- Cada inciso contiene su respectiva validación, contesta en orden, no avances si no has resuelto un inciso previo." 262 | ] 263 | }, 264 | { 265 | "cell_type": "code", 266 | "execution_count": null, 267 | "metadata": { 268 | "deletable": false, 269 | "id": "8nN1Am2VBaqC", 270 | "nbgrader": { 271 | "cell_type": "code", 272 | "checksum": "c7143f5fd858d9923753736174ba6c4d", 273 | "grade": false, 274 | "grade_id": "cell-4e4d42ed539f28d6", 275 | "locked": false, 276 | "schema_version": 3, 277 | "solution": true, 278 | "task": false 279 | } 280 | }, 281 | "outputs": [], 282 | "source": [ 283 | "# (a) All words ending in ime.\n", 284 | "def termina_ime():\n", 285 | " # variables auxiliares\n", 286 | " end_ime = []\n", 287 | " count_ime = 0\n", 288 | " # YOUR CODE HERE\n", 289 | " raise NotImplementedError()\n", 290 | " return end_ime" 291 | ] 292 | }, 293 | { 294 | "cell_type": "code", 295 | "execution_count": null, 296 | "metadata": { 297 | "deletable": false, 298 | "editable": false, 299 | "nbgrader": { 300 | "cell_type": "code", 301 | "checksum": "7e8ca8f843d860e2233236306f98778b", 302 | "grade": true, 303 | "grade_id": "cell-b66182bcb97baf18", 304 | "locked": true, 305 | "points": 1, 306 | "schema_version": 3, 307 | "solution": false, 308 | "task": false 309 | }, 310 | "id": "aIbOOY61beFN" 311 | }, 312 | "outputs": [], 313 | "source": [ 314 | "\"\"\"\n", 315 | "Evaluacion del inciso (a)\n", 316 | "\"\"\"\n", 317 | "evaluacion.verifica(np.array([termina_ime()]), 1)" 318 | ] 319 | }, 320 | { 321 | "cell_type": "code", 322 | "execution_count": null, 323 | "metadata": { 324 | "deletable": false, 325 | "id": "NNsVcH0cBaqD", 326 | "nbgrader": { 327 | "cell_type": "code", 328 | "checksum": "72afa886c460930cc41ef4152dd25b42", 329 | "grade": false, 330 | "grade_id": "cell-e8a00f41e432cab4", 331 | "locked": false, 332 | "schema_version": 3, 333 | "solution": true, 334 | "task": false 335 | } 336 | }, 337 | "outputs": [], 338 | "source": [ 339 | "# (b) How many words contain at least one of the letters _r, s, t, l, n, e_.\n", 340 | "def cuantas_contienen():\n", 341 | " # variables auxiliares\n", 342 | " counter = 0\n", 343 | " letters = ['r', 's', 't', 'l', 'n', 'e']\n", 344 | " # YOUR CODE HERE\n", 345 | " raise NotImplementedError()\n", 346 | " return counter" 347 | ] 348 | }, 349 | { 350 | "cell_type": "code", 351 | "execution_count": null, 352 | "metadata": { 353 | "deletable": false, 354 | "editable": false, 355 | "nbgrader": { 356 | "cell_type": "code", 357 | "checksum": "6750ec8390352083579b1cc44330fbc2", 358 | "grade": true, 359 | "grade_id": "cell-7d07e2817f78029c", 360 | "locked": true, 361 | "points": 0, 362 | "schema_version": 3, 363 | "solution": false, 364 | "task": false 365 | }, 366 | "id": "xEkC-i6rbeFN" 367 | }, 368 | "outputs": [], 369 | "source": [ 370 | "evaluacion.verifica(np.array([cuantas_contienen()]), 2)" 371 | ] 372 | }, 373 | { 374 | "cell_type": "code", 375 | "execution_count": null, 376 | "metadata": { 377 | "deletable": false, 378 | "id": "GXfX-6fcBaqE", 379 | "nbgrader": { 380 | "cell_type": "code", 381 | "checksum": "eea8e1d03c37072cf21203dfd0566ad3", 382 | "grade": false, 383 | "grade_id": "cell-95cf6233226ab321", 384 | "locked": false, 385 | "schema_version": 3, 386 | "solution": true, 387 | "task": false 388 | } 389 | }, 390 | "outputs": [], 391 | "source": [ 392 | "# (c) The percentage of words that contain at least one of the letters _r, s, t, l, n, e_.\n", 393 | "def porcentaje():\n", 394 | " # variables auxiliares\n", 395 | " por = 0\n", 396 | " # YOUR CODE HERE\n", 397 | " raise NotImplementedError()\n", 398 | " return por" 399 | ] 400 | }, 401 | { 402 | "cell_type": "code", 403 | "execution_count": null, 404 | "metadata": { 405 | "deletable": false, 406 | "editable": false, 407 | "nbgrader": { 408 | "cell_type": "code", 409 | "checksum": "d4f242176f9eb941017389e149509bd7", 410 | "grade": true, 411 | "grade_id": "cell-f229ebc5365981d1", 412 | "locked": true, 413 | "points": 0, 414 | "schema_version": 3, 415 | "solution": false, 416 | "task": false 417 | }, 418 | "id": "qsDA7Jq5beFO" 419 | }, 420 | "outputs": [], 421 | "source": [ 422 | "evaluacion.verifica(np.array([porcentaje()]), 3)" 423 | ] 424 | }, 425 | { 426 | "cell_type": "code", 427 | "execution_count": null, 428 | "metadata": { 429 | "deletable": false, 430 | "id": "0Em9RJ_PBaqE", 431 | "nbgrader": { 432 | "cell_type": "code", 433 | "checksum": "664d1717c959022e82bee77dae66ef4c", 434 | "grade": false, 435 | "grade_id": "cell-674e7c426b9041a9", 436 | "locked": false, 437 | "schema_version": 3, 438 | "solution": true, 439 | "task": false 440 | } 441 | }, 442 | "outputs": [], 443 | "source": [ 444 | "# (d) All words with no vowels.\n", 445 | "def cuantas_sin_vocales():\n", 446 | " vocales = 'aeiou'\n", 447 | " con_vocales = 0\n", 448 | " # YOUR CODE HERE\n", 449 | " raise NotImplementedError()\n", 450 | " return sin_vocales" 451 | ] 452 | }, 453 | { 454 | "cell_type": "code", 455 | "execution_count": null, 456 | "metadata": { 457 | "deletable": false, 458 | "editable": false, 459 | "nbgrader": { 460 | "cell_type": "code", 461 | "checksum": "99accb8c6f31f47d8d2315c721ef5840", 462 | "grade": true, 463 | "grade_id": "cell-1531f32b5c55cfcf", 464 | "locked": true, 465 | "points": 0, 466 | "schema_version": 3, 467 | "solution": false, 468 | "task": false 469 | }, 470 | "id": "_hwZVlpsbeFP" 471 | }, 472 | "outputs": [], 473 | "source": [ 474 | "evaluacion.verifica(np.array([cuantas_sin_vocales()]), 4)" 475 | ] 476 | }, 477 | { 478 | "cell_type": "code", 479 | "execution_count": null, 480 | "metadata": { 481 | "deletable": false, 482 | "id": "mohBWbk9BaqF", 483 | "nbgrader": { 484 | "cell_type": "code", 485 | "checksum": "f08ff5c20f05e72c6c1fe073988a0512", 486 | "grade": true, 487 | "grade_id": "cell-542b1e45db97b027", 488 | "locked": false, 489 | "points": 0, 490 | "schema_version": 3, 491 | "solution": true, 492 | "task": false 493 | }, 494 | "tags": [] 495 | }, 496 | "outputs": [], 497 | "source": [ 498 | "# (e) All words that contain every vowel.\n", 499 | "def palabras_con_vocales():\n", 500 | " vowels = set(\"aeiou\")\n", 501 | " pal_vocales = 0\n", 502 | " # YOUR CODE HERE\n", 503 | " raise NotImplementedError()\n", 504 | " return pal_vocales" 505 | ] 506 | }, 507 | { 508 | "cell_type": "code", 509 | "execution_count": null, 510 | "metadata": { 511 | "deletable": false, 512 | "editable": false, 513 | "nbgrader": { 514 | "cell_type": "code", 515 | "checksum": "fe92b243a5a3756ef9bd81036d7c5e9e", 516 | "grade": true, 517 | "grade_id": "cell-e88304d62a3ea5e2", 518 | "locked": true, 519 | "points": 0, 520 | "schema_version": 3, 521 | "solution": false, 522 | "task": false 523 | }, 524 | "id": "v97Qcko6beFP" 525 | }, 526 | "outputs": [], 527 | "source": [ 528 | "evaluacion.verifica(np.array([palabras_con_vocales()]), 5)" 529 | ] 530 | }, 531 | { 532 | "cell_type": "code", 533 | "execution_count": null, 534 | "metadata": { 535 | "deletable": false, 536 | "id": "-Qj_oZZ2BaqG", 537 | "nbgrader": { 538 | "cell_type": "code", 539 | "checksum": "4720945962e0a9e618f0a2f8a3ab8ab3", 540 | "grade": true, 541 | "grade_id": "cell-f2d7291c93ce2740", 542 | "locked": false, 543 | "points": 0, 544 | "schema_version": 3, 545 | "solution": true, 546 | "task": false 547 | } 548 | }, 549 | "outputs": [], 550 | "source": [ 551 | "# (f) Whether there are more ten-letter words or seven-letter words.\n", 552 | "\n", 553 | "# Cuenta cuantas palabras hat con 10 letras y cuantas hay con 7 y muestra el resultado\n", 554 | "# YOUR CODE HERE\n", 555 | "raise NotImplementedError()" 556 | ] 557 | }, 558 | { 559 | "cell_type": "code", 560 | "execution_count": null, 561 | "metadata": { 562 | "deletable": false, 563 | "id": "dZtyy6nMBaqH", 564 | "nbgrader": { 565 | "cell_type": "code", 566 | "checksum": "fff26e7280a23755204326bca1b76762", 567 | "grade": false, 568 | "grade_id": "cell-0332bef8945862f3", 569 | "locked": false, 570 | "schema_version": 3, 571 | "solution": true, 572 | "task": false 573 | } 574 | }, 575 | "outputs": [], 576 | "source": [ 577 | "# (g) The longest word in the list.\n", 578 | "def palabra_mas_larga():\n", 579 | " palabra_larga = \"\"\n", 580 | " # YOUR CODE HERE\n", 581 | " raise NotImplementedError()\n", 582 | " return palabra_larga" 583 | ] 584 | }, 585 | { 586 | "cell_type": "code", 587 | "execution_count": null, 588 | "metadata": { 589 | "deletable": false, 590 | "editable": false, 591 | "nbgrader": { 592 | "cell_type": "code", 593 | "checksum": "e14405403f791b2a0fa3cab5377ea3e6", 594 | "grade": true, 595 | "grade_id": "cell-315586f929e4e42d", 596 | "locked": true, 597 | "points": 0, 598 | "schema_version": 3, 599 | "solution": false, 600 | "task": false 601 | }, 602 | "id": "Wjcw36twbeFQ" 603 | }, 604 | "outputs": [], 605 | "source": [ 606 | "evaluacion.verifica(np.array([palabra_mas_larga()]), 6)" 607 | ] 608 | }, 609 | { 610 | "cell_type": "code", 611 | "execution_count": null, 612 | "metadata": { 613 | "deletable": false, 614 | "id": "jj7CvRWKBaqI", 615 | "nbgrader": { 616 | "cell_type": "code", 617 | "checksum": "83f1d4ed10cab07f2fae8c2f5983c5e9", 618 | "grade": false, 619 | "grade_id": "cell-09efb52dfc824777", 620 | "locked": false, 621 | "schema_version": 3, 622 | "solution": true, 623 | "task": false 624 | } 625 | }, 626 | "outputs": [], 627 | "source": [ 628 | "# (h) All palindromes.\n", 629 | "def todos_palindromos():\n", 630 | " palim_list = []\n", 631 | " # YOUR CODE HERE\n", 632 | " raise NotImplementedError()\n", 633 | " return palim_list" 634 | ] 635 | }, 636 | { 637 | "cell_type": "code", 638 | "execution_count": null, 639 | "metadata": { 640 | "deletable": false, 641 | "editable": false, 642 | "nbgrader": { 643 | "cell_type": "code", 644 | "checksum": "1912164b96b3b89008939e75cb723619", 645 | "grade": true, 646 | "grade_id": "cell-4d790160b77a3e33", 647 | "locked": true, 648 | "points": 0, 649 | "schema_version": 3, 650 | "solution": false, 651 | "task": false 652 | }, 653 | "id": "MR4nm418beFR" 654 | }, 655 | "outputs": [], 656 | "source": [ 657 | "evaluacion.verifica(np.array([todos_palindromos()]), 7)" 658 | ] 659 | }, 660 | { 661 | "cell_type": "code", 662 | "execution_count": null, 663 | "metadata": { 664 | "deletable": false, 665 | "id": "TEQayTY4BaqL", 666 | "nbgrader": { 667 | "cell_type": "code", 668 | "checksum": "1fc1c531aebc1da5d8730b0adf3df8f7", 669 | "grade": false, 670 | "grade_id": "cell-45b53faa0bf6d1c7", 671 | "locked": false, 672 | "schema_version": 3, 673 | "solution": true, 674 | "task": false 675 | } 676 | }, 677 | "outputs": [], 678 | "source": [ 679 | "# (j) All words that contain a \"q\" that isn’t followed by a \"u\".\n", 680 | "def contienen_q():\n", 681 | " lista_q = []\n", 682 | " # YOUR CODE HERE\n", 683 | " raise NotImplementedError()\n", 684 | " return lista_q\n", 685 | "\n", 686 | "np.save(\"sol08\", np.array([contienen_q()]))" 687 | ] 688 | }, 689 | { 690 | "cell_type": "code", 691 | "execution_count": null, 692 | "metadata": { 693 | "deletable": false, 694 | "editable": false, 695 | "nbgrader": { 696 | "cell_type": "code", 697 | "checksum": "4f3645ce4e591f2097636b36b20615ad", 698 | "grade": true, 699 | "grade_id": "cell-d3541bc7dca7283c", 700 | "locked": true, 701 | "points": 0, 702 | "schema_version": 3, 703 | "solution": false, 704 | "task": false 705 | }, 706 | "id": "7AETTeXnbeFR" 707 | }, 708 | "outputs": [], 709 | "source": [ 710 | "evaluacion.verifica(np.array([contienen_q()]), 8)" 711 | ] 712 | }, 713 | { 714 | "cell_type": "code", 715 | "execution_count": null, 716 | "metadata": { 717 | "deletable": false, 718 | "id": "Ls5L3LnTBaqL", 719 | "nbgrader": { 720 | "cell_type": "code", 721 | "checksum": "d7a59fc0d03f78dbf0e7d40049c862ec", 722 | "grade": false, 723 | "grade_id": "cell-9a7cb528ca50a995", 724 | "locked": false, 725 | "schema_version": 3, 726 | "solution": true, 727 | "task": false 728 | } 729 | }, 730 | "outputs": [], 731 | "source": [ 732 | "# (k) All words that contain \"zu\" anywhere in the word.\n", 733 | "def contienen_zu():\n", 734 | " lista_zu = []\n", 735 | " # YOUR CODE HERE\n", 736 | " raise NotImplementedError()\n", 737 | " return lista_zu" 738 | ] 739 | }, 740 | { 741 | "cell_type": "code", 742 | "execution_count": null, 743 | "metadata": { 744 | "deletable": false, 745 | "editable": false, 746 | "nbgrader": { 747 | "cell_type": "code", 748 | "checksum": "1672a2366d0a3319b72dc310de5ab07e", 749 | "grade": true, 750 | "grade_id": "cell-cb43bac6df1517e5", 751 | "locked": true, 752 | "points": 0, 753 | "schema_version": 3, 754 | "solution": false, 755 | "task": false 756 | }, 757 | "id": "85mEz0MybeFS" 758 | }, 759 | "outputs": [], 760 | "source": [ 761 | "evaluacion.verifica(np.array([contienen_zu()]), 9)" 762 | ] 763 | }, 764 | { 765 | "cell_type": "code", 766 | "execution_count": null, 767 | "metadata": { 768 | "deletable": false, 769 | "id": "m2EaoTMJBaqN", 770 | "nbgrader": { 771 | "cell_type": "code", 772 | "checksum": "3dfd0903da3a52194bcdec8e4fd40131", 773 | "grade": false, 774 | "grade_id": "cell-065a417e4bb55302", 775 | "locked": false, 776 | "schema_version": 3, 777 | "solution": true, 778 | "task": false 779 | } 780 | }, 781 | "outputs": [], 782 | "source": [ 783 | "# (l) All words that contain both a \"z\" and a \"w\".\n", 784 | "def contienen_zw():\n", 785 | " lista_zw = []\n", 786 | " # YOUR CODE HERE\n", 787 | " raise NotImplementedError()\n", 788 | " return lista_zw" 789 | ] 790 | }, 791 | { 792 | "cell_type": "code", 793 | "execution_count": null, 794 | "metadata": { 795 | "deletable": false, 796 | "editable": false, 797 | "nbgrader": { 798 | "cell_type": "code", 799 | "checksum": "6ccc978d038353fdcc72bfed6ba956c6", 800 | "grade": true, 801 | "grade_id": "cell-2b55811916371a87", 802 | "locked": true, 803 | "points": 0, 804 | "schema_version": 3, 805 | "solution": false, 806 | "task": false 807 | }, 808 | "id": "bym4wELtbeFT" 809 | }, 810 | "outputs": [], 811 | "source": [ 812 | "evaluacion.verifica(np.array([contienen_zw()]), 10)" 813 | ] 814 | }, 815 | { 816 | "cell_type": "code", 817 | "execution_count": null, 818 | "metadata": { 819 | "deletable": false, 820 | "id": "tK22TilXBaqO", 821 | "nbgrader": { 822 | "cell_type": "code", 823 | "checksum": "08b973188c6f1185392106ecfd9ea053", 824 | "grade": false, 825 | "grade_id": "cell-975e84ff27c72d38", 826 | "locked": false, 827 | "schema_version": 3, 828 | "solution": true, 829 | "task": false 830 | } 831 | }, 832 | "outputs": [], 833 | "source": [ 834 | "# (m) All words whose first letter is \"a\", third letter is \"e\" and fifth letter is \"i\".\n", 835 | "def contienen_aei():\n", 836 | " lista_aei = []\n", 837 | " # YOUR CODE HERE\n", 838 | " raise NotImplementedError()\n", 839 | " return lista_aei" 840 | ] 841 | }, 842 | { 843 | "cell_type": "code", 844 | "execution_count": null, 845 | "metadata": { 846 | "deletable": false, 847 | "editable": false, 848 | "nbgrader": { 849 | "cell_type": "code", 850 | "checksum": "30e472766ba882d06ea30d3111a3adc9", 851 | "grade": true, 852 | "grade_id": "cell-699289a59ab6fb8f", 853 | "locked": true, 854 | "points": 0, 855 | "schema_version": 3, 856 | "solution": false, 857 | "task": false 858 | }, 859 | "id": "mB30XtqlbeFT" 860 | }, 861 | "outputs": [], 862 | "source": [ 863 | "evaluacion.verifica(np.array([contienen_aei()]), 11)" 864 | ] 865 | }, 866 | { 867 | "cell_type": "code", 868 | "execution_count": null, 869 | "metadata": { 870 | "deletable": false, 871 | "id": "MMn-3helBaqP", 872 | "nbgrader": { 873 | "cell_type": "code", 874 | "checksum": "4f9b11048e52d045516be1ddc7fb39b6", 875 | "grade": false, 876 | "grade_id": "cell-809b8823d45504fc", 877 | "locked": false, 878 | "schema_version": 3, 879 | "solution": true, 880 | "task": false 881 | } 882 | }, 883 | "outputs": [], 884 | "source": [ 885 | "# (n) All two-letter words.\n", 886 | "def palabras_dea_dos():\n", 887 | " lista_doble = []\n", 888 | " # YOUR CODE HERE\n", 889 | " raise NotImplementedError()\n", 890 | " return lista_doble" 891 | ] 892 | }, 893 | { 894 | "cell_type": "code", 895 | "execution_count": null, 896 | "metadata": { 897 | "deletable": false, 898 | "editable": false, 899 | "nbgrader": { 900 | "cell_type": "code", 901 | "checksum": "b65fffec8feb853ff44189420336b2ce", 902 | "grade": true, 903 | "grade_id": "cell-bf96de2e70e66a10", 904 | "locked": true, 905 | "points": 0, 906 | "schema_version": 3, 907 | "solution": false, 908 | "task": false 909 | }, 910 | "id": "OXdPhfD4beFU" 911 | }, 912 | "outputs": [], 913 | "source": [ 914 | "evaluacion.verifica(np.array([palabras_dea_dos()]), 12)" 915 | ] 916 | }, 917 | { 918 | "cell_type": "code", 919 | "execution_count": null, 920 | "metadata": { 921 | "deletable": false, 922 | "id": "GEZYhRpxBaqQ", 923 | "nbgrader": { 924 | "cell_type": "code", 925 | "checksum": "f765ed13982ca629971017aa4579ed10", 926 | "grade": false, 927 | "grade_id": "cell-2745654b08f8b13d", 928 | "locked": false, 929 | "schema_version": 3, 930 | "solution": true, 931 | "task": false 932 | } 933 | }, 934 | "outputs": [], 935 | "source": [ 936 | "# (o) All four-letter words that start and end with the same letter.\n", 937 | "def inicio_fin():\n", 938 | " lista_if = []\n", 939 | " # YOUR CODE HERE\n", 940 | " raise NotImplementedError()\n", 941 | " return lista_if" 942 | ] 943 | }, 944 | { 945 | "cell_type": "code", 946 | "execution_count": null, 947 | "metadata": { 948 | "deletable": false, 949 | "editable": false, 950 | "nbgrader": { 951 | "cell_type": "code", 952 | "checksum": "3cdac6d463ef1a0e84e23f4e24f4375a", 953 | "grade": true, 954 | "grade_id": "cell-57a86ee16de93f54", 955 | "locked": true, 956 | "points": 0, 957 | "schema_version": 3, 958 | "solution": false, 959 | "task": false 960 | }, 961 | "id": "vfAjwxLabeFU" 962 | }, 963 | "outputs": [], 964 | "source": [ 965 | "evaluacion.verifica(np.array([inicio_fin()]), 13)" 966 | ] 967 | }, 968 | { 969 | "cell_type": "code", 970 | "execution_count": null, 971 | "metadata": { 972 | "deletable": false, 973 | "nbgrader": { 974 | "cell_type": "code", 975 | "checksum": "bf85c77a0c0be631a89f7858a438078c", 976 | "grade": false, 977 | "grade_id": "cell-044aa8301dd78c26", 978 | "locked": false, 979 | "schema_version": 3, 980 | "solution": true, 981 | "task": false 982 | }, 983 | "id": "BzYh7PRMbeFV" 984 | }, 985 | "outputs": [], 986 | "source": [ 987 | "# (p) Define una funcion que recib una palabra y cuente el numero de vocales\n", 988 | "def cuenta_vocales(palabra):\n", 989 | " vocales = 'aeiou'\n", 990 | " vocales_palabras = []\n", 991 | " # YOUR CODE HERE\n", 992 | " raise NotImplementedError()\n", 993 | " return cuantas_vocales " 994 | ] 995 | }, 996 | { 997 | "cell_type": "code", 998 | "execution_count": null, 999 | "metadata": { 1000 | "deletable": false, 1001 | "editable": false, 1002 | "nbgrader": { 1003 | "cell_type": "code", 1004 | "checksum": "083a46a8e522e14b0b1b324e348652e3", 1005 | "grade": true, 1006 | "grade_id": "cell-bfd81d8ef50963be", 1007 | "locked": true, 1008 | "points": 0, 1009 | "schema_version": 3, 1010 | "solution": false, 1011 | "task": false 1012 | }, 1013 | "id": "bZAzE9HHbeFd" 1014 | }, 1015 | "outputs": [], 1016 | "source": [ 1017 | "evaluacion.verifica(np.array([cuenta_vocales('por eso guero')]), 14)" 1018 | ] 1019 | }, 1020 | { 1021 | "cell_type": "markdown", 1022 | "metadata": { 1023 | "deletable": false, 1024 | "editable": false, 1025 | "nbgrader": { 1026 | "cell_type": "markdown", 1027 | "checksum": "204e598b1e0c1e9e11932585c45fc218", 1028 | "grade": false, 1029 | "grade_id": "cell-d3ba5499bf8d456c", 1030 | "locked": true, 1031 | "schema_version": 3, 1032 | "solution": false, 1033 | "task": false 1034 | }, 1035 | "id": "jdd9p5J2beFd" 1036 | }, 1037 | "source": [ 1038 | "### HINT PUEDES USAR FUNCIONES PREVIAS" 1039 | ] 1040 | }, 1041 | { 1042 | "cell_type": "code", 1043 | "execution_count": null, 1044 | "metadata": { 1045 | "deletable": false, 1046 | "id": "b2fwTdC0BaqR", 1047 | "nbgrader": { 1048 | "cell_type": "code", 1049 | "checksum": "27e6fd79d3cfa6789e9a0c7443e58e24", 1050 | "grade": false, 1051 | "grade_id": "cell-d539e99000ae5c9e", 1052 | "locked": false, 1053 | "schema_version": 3, 1054 | "solution": true, 1055 | "task": false 1056 | } 1057 | }, 1058 | "outputs": [], 1059 | "source": [ 1060 | "# (q) All words that contain at least nine vowels.\n", 1061 | "def nueve_vocales():\n", 1062 | " vocales = 0\n", 1063 | " p_list = []\n", 1064 | " # YOUR CODE HERE\n", 1065 | " raise NotImplementedError()\n", 1066 | " return vocales" 1067 | ] 1068 | }, 1069 | { 1070 | "cell_type": "code", 1071 | "execution_count": null, 1072 | "metadata": { 1073 | "deletable": false, 1074 | "editable": false, 1075 | "nbgrader": { 1076 | "cell_type": "code", 1077 | "checksum": "cea269abdc09a313a9260763766df119", 1078 | "grade": true, 1079 | "grade_id": "cell-c5a11374a50894e8", 1080 | "locked": true, 1081 | "points": 0, 1082 | "schema_version": 3, 1083 | "solution": false, 1084 | "task": false 1085 | }, 1086 | "id": "7PU5L5t-beFe" 1087 | }, 1088 | "outputs": [], 1089 | "source": [ 1090 | "evaluacion.verifica(np.array([nueve_vocales()]), 15)" 1091 | ] 1092 | } 1093 | ], 1094 | "metadata": { 1095 | "accelerator": "GPU", 1096 | "colab": { 1097 | "provenance": [], 1098 | "toc_visible": true, 1099 | "include_colab_link": true 1100 | }, 1101 | "kernelspec": { 1102 | "display_name": "Python 3 (ipykernel)", 1103 | "language": "python", 1104 | "name": "python3" 1105 | }, 1106 | "language_info": { 1107 | "codemirror_mode": { 1108 | "name": "ipython", 1109 | "version": 3 1110 | }, 1111 | "file_extension": ".py", 1112 | "mimetype": "text/x-python", 1113 | "name": "python", 1114 | "nbconvert_exporter": "python", 1115 | "pygments_lexer": "ipython3", 1116 | "version": "3.9.7" 1117 | }, 1118 | "toc": { 1119 | "base_numbering": 1, 1120 | "nav_menu": {}, 1121 | "number_sections": true, 1122 | "sideBar": true, 1123 | "skip_h1_title": false, 1124 | "title_cell": "Table of Contents", 1125 | "title_sidebar": "Contents", 1126 | "toc_cell": false, 1127 | "toc_position": {}, 1128 | "toc_section_display": true, 1129 | "toc_window_display": false 1130 | }, 1131 | "varInspector": { 1132 | "cols": { 1133 | "lenName": 16, 1134 | "lenType": 16, 1135 | "lenVar": 40 1136 | }, 1137 | "kernels_config": { 1138 | "python": { 1139 | "delete_cmd_postfix": "", 1140 | "delete_cmd_prefix": "del ", 1141 | "library": "var_list.py", 1142 | "varRefreshCmd": "print(var_dic_list())" 1143 | }, 1144 | "r": { 1145 | "delete_cmd_postfix": ") ", 1146 | "delete_cmd_prefix": "rm(", 1147 | "library": "var_list.r", 1148 | "varRefreshCmd": "cat(var_dic_list()) " 1149 | } 1150 | }, 1151 | "types_to_exclude": [ 1152 | "module", 1153 | "function", 1154 | "builtin_function_or_method", 1155 | "instance", 1156 | "_Feature" 1157 | ], 1158 | "window_display": false 1159 | }, 1160 | "vscode": { 1161 | "interpreter": { 1162 | "hash": "0a68ab044c6ea367198d7b58f0f8352272d5267d2d2c131306c104f6e9ede3d6" 1163 | } 1164 | } 1165 | }, 1166 | "nbformat": 4, 1167 | "nbformat_minor": 0 1168 | } -------------------------------------------------------------------------------- /01_IntroduccionAA/03_Perceptron.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [], 7 | "toc_visible": true, 8 | "authorship_tag": "ABX9TyMWs67hOjfB6wVOXLShq+Hf", 9 | "include_colab_link": true 10 | }, 11 | "kernelspec": { 12 | "name": "python3", 13 | "display_name": "Python 3" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "markdown", 19 | "metadata": { 20 | "id": "view-in-github", 21 | "colab_type": "text" 22 | }, 23 | "source": [ 24 | "\"Open" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "id": "wXSdMY-R3hny" 31 | }, 32 | "source": [ 33 | "\n", 34 | "

MexSIAM

\n", 35 | "

Perceptrón

\n", 36 | "
\n", 37 | " \n", 38 | "
Profesor: M. en C. Miguel Angel Pérez León.
\n", 39 | "
correo: zeus@ciencias.unam.mx
\n", 40 | "
" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": { 46 | "id": "UdSUVg0fNCxN" 47 | }, 48 | "source": [ 49 | "# Introducción\n", 50 | "\n", 51 | "El perceptrón es un tipo de neurona artificial que fue inventada en 1957 por [Frank Rosenblatt](https://news.cornell.edu/stories/2019/09/professors-perceptron-paved-way-ai-60-years-too-soon).\n", 52 | "\n", 53 | "Las principales diferencias con respecto a las neuronas vistas previamente es que el perceptrón es capaz de aprender (machine learning) y además su valores de entrada y de salida son binarios. Aunque no es complicado modificar el modelo para tratar con campos no binarios." 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": { 59 | "id": "pv34b5WB2PKL" 60 | }, 61 | "source": [ 62 | "# Anatomía del Perceptrón\n", 63 | "\n", 64 | "Todos los elementos vistos previamente se mantienen.\n", 65 | "\n", 66 | "* **Entradas**\n", 67 | "* **Pesos**\n", 68 | "* **Sesgo**\n", 69 | "* **Función de activación**\n", 70 | "\n", 71 | "Aunque para el caso particular del perceptrón, la función de activavción será la conocida como **paso binario** y es tan sencilla como la siguiente imagen." 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "metadata": { 77 | "colab": { 78 | "base_uri": "https://localhost:8080/", 79 | "height": 430 80 | }, 81 | "id": "401mBZpW5qmw", 82 | "outputId": "acf28a4e-c7f4-49e3-b473-ba6541ffde8c" 83 | }, 84 | "source": [ 85 | "# se importan algunas funciones importantes\n", 86 | "import matplotlib.pyplot as plt\n", 87 | "import numpy as np\n", 88 | "%matplotlib inline\n", 89 | "import math\n", 90 | "# dominio de las graficas\n", 91 | "x = np.linspace(-3, 3, 20)\n", 92 | "\n", 93 | "# funciones comunes de activasion\n", 94 | "PasoBinario = lambda x: np.heaviside(x,0)\n", 95 | "\n", 96 | "# Definimos algunos parámetros para la gráfica\n", 97 | "plt.plot(x, PasoBinario(x),label=\"Paso Binario\")\n", 98 | "plt.grid()\n", 99 | "plt.legend()\n", 100 | "\n", 101 | "# Mostramos la leyenda de las gráficas\n", 102 | "plt.show()" 103 | ], 104 | "execution_count": null, 105 | "outputs": [ 106 | { 107 | "output_type": "display_data", 108 | "data": { 109 | "text/plain": [ 110 | "
" 111 | ], 112 | "image/png": "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bgkAMxFGAJimjp4RACKMADARc0YASIQRACZyh1fTMEwDJDLCCADTMEwDQCKMADARwzQAJMIIABPRMwJAIowAMFEdc0YAiDACwEQM0wCQCCMATNLk86vJF5DU+mwaAImLMALAFO4Tu6867Dal8sBeIKERRgCYIjRfJDM9STywF0hshBEApqhraJ0vMiA92eSWADAbYQSAKUIPycskjAAJjzACwBTuBsIIgFaEEQCmCC3rZZgGAGEEgCnCE1idhBEg0RFGAJiCOSMAQggjAEzBahoAIYQRAKaoYwIrgBMIIwBMEQojA5kzAiQ8wggAU7iZMwLgBMIIAFOE5oywmgYAYQRAzHlbAqr3+iUxgRUAYQSACUJDNDablJGaZHJrAJiNMAIg5twndl/NTE+W3c4je4FERxgBEHOhlTQM0QCQCCMATHByK/gUk1sCwAoIIwBiLrQVPD0jAKQehpHVq1crNzdXaWlpmjp1qrZv327ouvXr18tms+maa67pycsCiBPhreBZ1gtAPQgjGzZsUFFRkUpKSvT+++9rwoQJys/P16FDh7q8bt++ffrFL36h73//+z1uLID4wJwRAKeKOIysXLlSCxcu1IIFCzRu3DitWbNGTqdTa9eu7fQav9+vG2+8UStWrNBZZ531jRoMoO+rC62mYc4IAEkRLfD3er3asWOHiouLw8fsdrtmzpypqqqqTq978MEHNXToUN100036y1/+0u3rNDc3q7m5Ofy1x+ORJPl8Pvl8vkia3KXQvXrznvGKWkWGenXt6+OtYSQj1U6tIkCtjKNWxkWzVkbvGVEYOXLkiPx+v7Kystocz8rK0q5duzq85q9//at+//vfa+fOnYZfp7S0VCtWrGh3fMuWLXI6nZE02ZDy8vJev2e8olaRoV4d27PfLsmuL//2icq//lgStYoEtTKOWhkXjVo1NDQYOi+qWx8eO3ZM8+bN09NPP63Bgwcbvq64uFhFRUXhrz0ej3JycjR79my5XK5ea5/P51N5eblmzZql5GTGrrtCrSJDvbr29JfvSG6PfpA3WRePGkCtDOJ9ZRy1Mi6atQqNbHQnojAyePBgORwO1dbWtjleW1ur7Ozsdud//vnn2rdvn+bMmRM+FggEWl84KUm7d+/W2Wef3e661NRUpaamtjuenJwclTdVtO4bj6hVZKhXx9xNrV2338pID9eHWhlHrYyjVsZFo1ZG7xfRBNaUlBRNmjRJFRUV4WOBQEAVFRXKy8trd/55552nDz/8UDt37gz/ueqqqzRjxgzt3LlTOTk5kbw8gDjBahoAp4p4mKaoqEgFBQWaPHmypkyZolWrVqm+vl4LFiyQJM2fP18jRoxQaWmp0tLSdP7557e5fsCAAZLU7jiAxNDiD+hYU4skaQCraQCoB2Hkuuuu0+HDh7V8+XLV1NRo4sSJ2rx5c3hSa3V1tex2NnYF0DHPiSAiSa60JAUDfhNbA8AKejSBtbCwUIWFhR1+r7Kysstrn3vuuZ68JIA4Edp9NSMtSUkOu3yEESDh0YUBIKbCz6VhK3gAJxBGAMSUOzx5lfkiAFoRRgDE1Nc8JA/AaQgjAGIqtKw3k2W9AE4gjACIKeaMADgdYQRATLlPDNMMZI8RACcQRgDEVKhnhGEaACGEEQAxFd4Knp4RACcQRgDEVHjOCD0jAE4gjACIKTdLewGchjACIKZYTQPgdIQRADETCATlDk9gZc4IgFaEEQAxc6ypRcFg63+zmgZACGEEQMzUNbbOF+mX4lBKEr9+ALTitwGAmGFZL4COEEYAxEzoIXkM0QA4FWEEQMy4WUkDoAOEEQAxExqm4bk0AE5FGAEQM6EwkknPCIBTEEYAxExoNQ1bwQM4FWEEQMy4G5gzAqA9wgiAmDn5kDzmjAA4iTACIGbqQkt76RkBcArCCICYOdkzQhgBcBJhBEDMuNmBFUAHCCMAYiIYDJ7sGWGYBsApCCMAYuJ4c4v8gdZH9rIdPIBTEUYAxERow7O0ZLvSkh0mtwaAlRBGAMRE+Im9LOsFcBrCCICYCO++ynwRAKchjACIiTp2XwXQCcIIgJhg91UAnSGMAIgJdwPDNAA6RhgBEBOhYRq2ggdwOsIIgJhgmAZAZwgjAGKCCawAOkMYARAT7tDSXnZfBXAawgiAmGDOCIDOEEYAxARzRgB0hjACIOqCwaDqWNoLoBOEEQBR1+D1y+dvfWIvYQTA6QgjAKIuNEST4rArnSf2AjgNYQRA1J06RGOz2UxuDQCrIYwAiDo3e4wA6AJhBEDUsZIGQFcIIwCijj1GAHSFMAIg6urYfRVAFwgjAKKOOSMAukIYARB1Jx+Sx5wRAO0RRgBEXWiYJpNhGgAdIIwAiLo6hmkAdIEwAiDqwmGEpb0AOkAYARB14dU09IwA6ABhBEDUhfcZYc4IgA4QRgBEVZPPr+aWgCRpYD+GaQC0RxgBEFWhXpEku039UnhiL4D2ehRGVq9erdzcXKWlpWnq1Knavn17p+c+/fTT+v73v6+BAwdq4MCBmjlzZpfnA4gvp84X4Ym9ADoScRjZsGGDioqKVFJSovfff18TJkxQfn6+Dh061OH5lZWVuv766/Xmm2+qqqpKOTk5mj17tg4cOPCNGw/A+pgvAqA7EYeRlStXauHChVqwYIHGjRunNWvWyOl0au3atR2e/+KLL+rWW2/VxIkTdd555+mZZ55RIBBQRUXFN248AOtj91UA3UmK5GSv16sdO3aouLg4fMxut2vmzJmqqqoydI+Ghgb5fD4NGjSo03Oam5vV3Nwc/trj8UiSfD6ffD5fJE3uUuhevXnPeEWtIkO9Tjp6vFGS5EpzdFgPamUctTKOWhkXzVoZvactGAwGjd704MGDGjFihLZt26a8vLzw8bvvvltvvfWW3n333W7vceutt+qNN97Qxx9/rLS0tA7PeeCBB7RixYp2x9etWyen02m0uQAsoOKATX+sduiiIQH939EBs5sDIIYaGhp0ww03yO12y+VydXpeRD0j39Qjjzyi9evXq7KystMgIknFxcUqKioKf+3xeMJzTbr6YSLl8/lUXl6uWbNmKTmZ8eyuUKvIUK+TPtnymVS9V98enasrrjiv3feplXHUyjhqZVw0axUa2ehORGFk8ODBcjgcqq2tbXO8trZW2dnZXV7761//Wo888oj+/Oc/a/z48V2em5qaqtTU1HbHk5OTo/KmitZ94xG1igz1kjzNfknSoP5pXdaCWhlHrYyjVsZFo1ZG7xfRBNaUlBRNmjSpzeTT0GTUU4dtTverX/1KDz30kDZv3qzJkydH8pIA+ri6BraCB9C1iIdpioqKVFBQoMmTJ2vKlClatWqV6uvrtWDBAknS/PnzNWLECJWWlkqSHn30US1fvlzr1q1Tbm6uampqJEn9+/dX//79e/FHAWBFLO0F0J2Iw8h1112nw4cPa/ny5aqpqdHEiRO1efNmZWVlSZKqq6tlt5/scHnyySfl9Xp17bXXtrlPSUmJHnjggW/WegCWV9fI0l4AXevRBNbCwkIVFhZ2+L3Kyso2X+/bt68nLwEgTrhPDNMMZJgGQCd4Ng2AqAr3jKTTMwKgY4QRAFHT3OJXg7d1NU0mPSMAOkEYARA17hO9InablJEa022NAPQhhBEAUeM+ZSWN3c4TewF0jDACIGpYSQPACMIIgKhhjxEARhBGAEQNu68CMIIwAiBq3OFlvYQRAJ0jjACImtAwDXNGAHSFMAIgar4+MUzDnBEAXSGMAIiak6tpCCMAOkcYARA1oX1GBjJMA6ALhBEAUVPXeGKYhp4RAF0gjACImvAEVuaMAOgCYQRA1LhZTQPAAMIIgKjw+QM61twiiZ4RAF0jjACICs+JlTSS5CKMAOgCYQRAVISW9brSkuTgib0AukAYARAV7L4KwCjCCICocDfykDwAxhBGAERFqGeEreABdIcwAiAqvmaYBoBBhBEAUeE+8ZA8lvUC6A5hBEBUhFbTDGTOCIBuEEYAREV4zgjDNAC6QRgBEBWhnhGGaQB0hzACICrCc0YYpgHQDcIIgKgI94wQRgB0gzACICpO7jPCnBEAXSOMAOh1/kBQniZ6RgAYQxgB0OuONfkUDLb+NzuwAugOYQRArwsN0fRPTVKyg18zALrGbwkAvS40eZVeEQBGEEYA9LqvWdYLIAKEEQC9zt3A5FUAxhFGAPS6uvBD8ljWC6B7hBEAvY4NzwBEgjACoNfVMUwDIAKEEQC9zh1+SB7DNAC6RxgB0OtCc0Yy6RkBYABhBECvC88ZYZ8RAAYQRgD0upNLexmmAdA9wgiAXsdqGgCRIIwA6FWBQPCUfUYIIwC6RxgB0KuOe1sUOPHEXhdhBIABhBEAvaquvnWIJj3ZobRkh8mtAdAXEEYA9Kq6Rh6SByAyhBEAvSq0+2omQzQADCKMAOhVoZU0A1nWC8AgwgiAXuVuYJgGQGQIIwB6FQ/JAxApwgiAXhUapsnkIXkADCKMAOhV9IwAiBRhBECvcjey+yqAyBBGAPQqekYARIowAqBXMWcEQKR6FEZWr16t3NxcpaWlaerUqdq+fXuX5//Hf/yHzjvvPKWlpemCCy5QWVlZjxoLwProGQEQqYjDyIYNG1RUVKSSkhK9//77mjBhgvLz83Xo0KEOz9+2bZuuv/563XTTTfrggw90zTXX6JprrtFHH330jRsPwFqCwVOe2EsYAWBQxGFk5cqVWrhwoRYsWKBx48ZpzZo1cjqdWrt2bYfn//a3v9Vll12mu+66S2PHjtVDDz2k73znO/q3f/u3b9x4ANZS7/Wr5cQjewcwTAPAoKRITvZ6vdqxY4eKi4vDx+x2u2bOnKmqqqoOr6mqqlJRUVGbY/n5+Xrttdc6fZ3m5mY1NzeHv/Z4PJIkn88nn88XSZO79Pu/fKGqvXa99/onstuZPtOVQCCg6i+plVGJWq8Gr1+SlJJkl0N++XyBbq8J/Z3uzb/b8YpaGUetjItmrYzeM6IwcuTIEfn9fmVlZbU5npWVpV27dnV4TU1NTYfn19TUdPo6paWlWrFiRbvjW7ZskdPpjKTJXVr/oUP7jtulmq967Z7xjVpFJnHr5XL49ac//Smia8rLy6PUmvhDrYyjVsZFo1YNDQ2GzosojMRKcXFxm94Uj8ejnJwczZ49Wy6Xq9de5+igfdq2c5dGjRolRwL967Un/IGA9u7dS60MSuh62aRLxwzRxJwBhk73+XwqLy/XrFmzlJzMPJOuUCvjqJVx0axVaGSjOxGFkcGDB8vhcKi2trbN8draWmVnZ3d4TXZ2dkTnS1JqaqpSU1PbHU9OTu7VQv3f7+Zq0NFPdEX+GN6s3fD5fCor+5xaGUS9Itfbf7/jGbUyjloZF41aGb1fRP9kS0lJ0aRJk1RRURE+FggEVFFRoby8vA6vycvLa3O+1NoV1Nn5AAAgsUQ8TFNUVKSCggJNnjxZU6ZM0apVq1RfX68FCxZIkubPn68RI0aotLRUknT77bfrBz/4gR577DH96Ec/0vr16/Xee+/pd7/7Xe/+JAAAoE+KOIxcd911Onz4sJYvX66amhpNnDhRmzdvDk9Sra6ubrN6YNq0aVq3bp3uu+8+3XPPPTrnnHP02muv6fzzz++9nwIAAPRZPZrAWlhYqMLCwg6/V1lZ2e7Y3LlzNXfu3J68FAAAiHMJNs0fAABYDWEEAACYijACAABMRRgBAACmIowAAABTEUYAAICpCCMAAMBUhBEAAGAqwggAADBVj3ZgjbVgMCjJ+KOIjfL5fGpoaJDH4+Gpjt2gVpGhXsZRK+OolXHUyrho1ir0uR36HO9Mnwgjx44dkyTl5OSY3BIAABCpY8eOKTMzs9Pv24LdxRULCAQCOnjwoDIyMmSz2Xrtvh6PRzk5Odq/f79cLlev3TceUavIUC/jqJVx1Mo4amVcNGsVDAZ17NgxDR8+vM1DdE/XJ3pG7Ha7zjjjjKjd3+Vy8WY1iFpFhnoZR62Mo1bGUSvjolWrrnpEQpjACgAATEUYAQAApkroMJKamqqSkhKlpqaa3RTLo1aRoV7GUSvjqJVx1Mo4K9SqT0xgBQAA8Suhe0YAAID5CCMAAMBUhBEAAGAqwggAADAVYeQUV111lUaOHKm0tDQNGzZM8+bN08GDB81uluXs27dPN910k0aNGqX09HSdffbZKikpkdfrNbtplvTwww9r2rRpcjqdGjBggNnNsZTVq1crNzdXaWlpmjp1qrZv3252kyxp69atmjNnjoYPHy6bzabXXnvN7CZZVmlpqS666CJlZGRo6NChuuaaa7R7926zm2VJTz75pMaPHx/e7CwvL09/+tOfTGkLYeQUM2bM0B/+8Aft3r1bL7/8sj7//HNde+21ZjfLcnbt2qVAIKCnnnpKH3/8sX7zm99ozZo1uueee8xumiV5vV7NnTtXixcvNrsplrJhwwYVFRWppKRE77//viZMmKD8/HwdOnTI7KZZTn19vSZMmKDVq1eb3RTLe+utt7RkyRK98847Ki8vl8/n0+zZs1VfX2920yznjDPO0COPPKIdO3bovffe06WXXqqrr75aH3/8cewbE0SnNm7cGLTZbEGv12t2UyzvV7/6VXDUqFFmN8PSnn322WBmZqbZzbCMKVOmBJcsWRL+2u/3B4cPHx4sLS01sVXWJyn46quvmt2MPuPQoUNBScG33nrL7Kb0CQMHDgw+88wzMX9dekY6cfToUb344ouaNm0aj582wO12a9CgQWY3A32E1+vVjh07NHPmzPAxu92umTNnqqqqysSWId643W5J4vdTN/x+v9avX6/6+nrl5eXF/PUJI6dZunSp+vXrp29961uqrq7Wxo0bzW6S5e3Zs0ePP/64brnlFrObgj7iyJEj8vv9ysrKanM8KytLNTU1JrUK8SYQCOiOO+7QxRdfrPPPP9/s5ljShx9+qP79+ys1NVWLFi3Sq6++qnHjxsW8HXEfRpYtWyabzdbln127doXPv+uuu/TBBx9oy5Ytcjgcmj9/voIJskltpLWSpAMHDuiyyy7T3LlztXDhQpNaHns9qRWA2FqyZIk++ugjrV+/3uymWNaYMWO0c+dOvfvuu1q8eLEKCgr0ySefxLwdcb8d/OHDh/X3v/+9y3POOusspaSktDv+1VdfKScnR9u2bTOl2yrWIq3VwYMHNX36dH33u9/Vc889J7s97rNtWE/eV88995zuuOMO1dXVRbl11uf1euV0OvXSSy/pmmuuCR8vKChQXV0dPZJdsNlsevXVV9vUDe0VFhZq48aN2rp1q0aNGmV2c/qMmTNn6uyzz9ZTTz0V09dNiumrmWDIkCEaMmRIj64NBAKSpObm5t5skmVFUqsDBw5oxowZmjRpkp599tmECiLSN3tfQUpJSdGkSZNUUVER/lANBAKqqKhQYWGhuY1DnxYMBnXbbbfp1VdfVWVlJUEkQoFAwJTPvLgPI0a9++67+u///m9973vf08CBA/X555/r/vvv19lnn50QvSKROHDggKZPn64zzzxTv/71r3X48OHw97Kzs01smTVVV1fr6NGjqq6ult/v186dOyVJo0ePVv/+/c1tnImKiopUUFCgyZMna8qUKVq1apXq6+u1YMECs5tmOcePH9eePXvCX+/du1c7d+7UoEGDNHLkSBNbZj1LlizRunXrtHHjRmVkZITnIGVmZio9Pd3k1llLcXGxLr/8co0cOVLHjh3TunXrVFlZqTfeeCP2jYn5+h2L+p//+Z/gjBkzgoMGDQqmpqYGc3Nzg4sWLQp+9dVXZjfNcp599tmgpA7/oL2CgoIOa/Xmm2+a3TTTPf7448GRI0cGU1JSglOmTAm+8847ZjfJkt58880O30MFBQVmN81yOvvd9Oyzz5rdNMv5x3/8x+CZZ54ZTElJCQ4ZMiT4wx/+MLhlyxZT2hL3c0YAAIC1JdZAPwAAsBzCCAAAMBVhBAAAmIowAgAATEUYAQAApiKMAAAAUxFGAACAqQgjAADAVIQRAABgKsIIAAAwFWEEAACYijACAABM9f8BkpAxZrnM9RAAAAAASUVORK5CYII=\n" 113 | }, 114 | "metadata": {} 115 | } 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "metadata": { 121 | "id": "YsMAqa3YbTyo" 122 | }, 123 | "source": [ 124 | "Es decir.\n", 125 | "\n", 126 | "$$f\\left(x\\right)=\\begin{cases}\n", 127 | "1 \\quad si & x\\gt0\\\\\n", 128 | "0 \\quad & e.o.c.\n", 129 | "\\end{cases}$$\n", 130 | "\n", 131 | "En el contexto de las redes neuronales podemos pensar en esta función de la siguiente manera.\n", 132 | "\n", 133 | "$$f\\left(\\vec{x}\\right)=\\begin{cases}\n", 134 | "1 \\quad si & \\vec{w}\\circ\\vec{x} +b\\gt0\\\\\n", 135 | "0 \\quad & e.o.c.\n", 136 | "\\end{cases}$$\n", 137 | "\n", 138 | "Donde:\n", 139 | "\n", 140 | "* $\\vec{w}$ es el vector de pesos asociados a las entradas.\n", 141 | "* $\\vec{x}$ es el vector de entradas.\n", 142 | "* $b$ es el sesgo o *bias*.\n", 143 | "\n", 144 | "Estos cambios en la función de activación se deben a que, para fines prácticos es mejor pensar en las entradas de una neurona (o red neuronal) como un vector, además recordemos que las *GPU's* estan optimizadas para operaciones con vectores y con matrices." 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": { 150 | "id": "i_9Fue_POL2I" 151 | }, 152 | "source": [ 153 | "# Ejemplo operador $AND$\n", 154 | "\n", 155 | "Igual que en el caso del cerebro humano, existen diferentes zonas del cerebro que muestran actividad con diferentes estimulos, tratemos de diseñar un perceptrón (neurona artificial) que reproduzca el comportamiento del operador logico $AND$ (&&). \n", 156 | "\n", 157 | "Recordemos la tabla de verdad de este operador lógico.\n", 158 | "\n", 159 | "| $x_1$ | $x_2$ | $and$ | \n", 160 | "| :-: | :-:| :-: | \n", 161 | "| 0 | 0 | 0 |\n", 162 | "| 0 | 1 | 0 |\n", 163 | "| 1 | 0 | 0 |\n", 164 | "| 1 | 1 | 1 |\n", 165 | "\n", 166 | "La idea es que podamos definir un algoritmo que funcione como el operador lógico $AND$.\n", 167 | "\n", 168 | "Pensemos que este perceptrón luce de esta forma.\n", 169 | "\n", 170 | "
\n", 171 | "\n", 172 | "
\n", 173 | "\n" 174 | ] 175 | }, 176 | { 177 | "cell_type": "markdown", 178 | "metadata": { 179 | "id": "K8A4aZheBeMH" 180 | }, 181 | "source": [ 182 | "## Inteligencia Artificial (tradicional)\n", 183 | "\n", 184 | "La forma más sencilla de definir este operador es con un *if*, es decir." 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "metadata": { 190 | "id": "uVCn6cCWyiDZ", 191 | "colab": { 192 | "base_uri": "https://localhost:8080/" 193 | }, 194 | "outputId": "3e25c0cb-b957-4992-f8b8-49c0ff15cad1" 195 | }, 196 | "source": [ 197 | "'''\n", 198 | "versión primitiva del perceptron\n", 199 | "x: vector de entradas\n", 200 | "w: vector de pesos\n", 201 | "'''\n", 202 | "def perceptrAND(x, w=None, b=None):\n", 203 | " if x[0]==1 and x[1]==1:\n", 204 | " return 1\n", 205 | " else:\n", 206 | " return 0\n", 207 | "\n", 208 | "# prueba de la funcion, ¡CAMBIA EL VECTOR DE ENRTADAS!\n", 209 | "print(perceptrAND([0,0])) \n" 210 | ], 211 | "execution_count": null, 212 | "outputs": [ 213 | { 214 | "output_type": "stream", 215 | "name": "stdout", 216 | "text": [ 217 | "0\n" 218 | ] 219 | } 220 | ] 221 | }, 222 | { 223 | "cell_type": "markdown", 224 | "metadata": { 225 | "id": "U9f3yuaYCoXf" 226 | }, 227 | "source": [ 228 | "Esta es la forma tradicional en la cual se resolvían muchos de los problemas de inteligencia artificial antes de la llegada del *machine learning*.\n", 229 | "\n", 230 | "El código de la celda anterior funciona y resuelve el problema planteado inicialmente, sin embargo **esta solución es estática**, ya no puede modificarse por si misma para \"aprender\" un nuevo comportamiento." 231 | ] 232 | }, 233 | { 234 | "cell_type": "markdown", 235 | "metadata": { 236 | "id": "2oe9M4cTDbNP" 237 | }, 238 | "source": [ 239 | "## Razonamiento cognitivo\n", 240 | "\n", 241 | "Veamos otra forma de solucionar el mismo problema.\n", 242 | "\n", 243 | "Lo primero que debemos notar de la tabla de verdad es que, si **cambiamos el orden de las entradas** ($x_1, x_2$) en cada caso, el resultado no cambia.\n", 244 | "\n", 245 | "Lo segundo que hay que notar es que la suma $\\vec{w} * \\vec{x} +b$ siempre debe ser negativa, excepto cuando $x_1=1$ y $x_2=1$, tal como se muestra en la tabla de verdad.\n", 246 | "\n", 247 | "Reescribiendo nuestra tabla de verdad para considerar las entradas del perceptrón la podemos pensar de la siguiente forma.\n", 248 | "\n", 249 | "\\begin{array}{c}\n", 250 | "1w_1+1w_2+b>0\\\\\n", 251 | "0w_1+1w_2+b\\leq0\\\\\n", 252 | "1w_1+0w_2+b\\leq0\\\\\n", 253 | "0w_1+0w_2+b\\leq0 \\tag{1}\n", 254 | "\\end{array}\n", 255 | "\n", 256 | "Por otro lado, sabemos que:\n", 257 | "\n", 258 | "* $x*0=0$\n", 259 | "* $1x+1x=2x $\n", 260 | "* $1x=x$\n", 261 | "\n", 262 | "Combinando (1), lo que sabemos y el hecho de que $w_1 = w_2 = w$ debido a que **ambas entradas son igual de importantes**, podemos simplificar lo anterior de la siguiente forma.\n", 263 | "\n", 264 | "\\begin{array}{c}\n", 265 | "2w+b>0\\\\\n", 266 | "w+b\\leq0\\\\\n", 267 | "b\\leq0\\\\ \\tag{2}\n", 268 | "\\end{array}\n", 269 | "\n", 270 | "De (2) podemos concluir que $2w+b$ tiene que ser un valor **positivo**, $w+b$ es **negativo o cero** y $b$ es un valor **negativo o cero**.\n", 271 | "\n", 272 | "Notemos que:\n", 273 | "\n", 274 | "\n", 275 | "* $b$ no puede ser cero, ya que que de ser así $2w\\gt0$ y $w\\leq0$, lo que no puede ser verdad. Por lo tanto **$b$ no puede ser cero**.\n", 276 | "* $w$ debe ser positivo, si $w$ fuese negativo $2w$ también sería negativo y $2w+b$ no podría ser un valor positivo y $2w+b\\gt0$ no podría ser verdad. Por lo tanto **$w$ debe ser positivo**.\n", 277 | "* ya que $w$ debe ser positivo, $b$ no puede ser cero, entonces para que $w+b\\leq0$ sea verdadero debemos elegir a **$b$ como el opuesto aditivo de $w$**.\n", 278 | "\n", 279 | "¡¡¡Ya lo tenemos!!!, modificando el código de la celda anterior tenemos lo siguiente." 280 | ] 281 | }, 282 | { 283 | "cell_type": "code", 284 | "metadata": { 285 | "colab": { 286 | "base_uri": "https://localhost:8080/" 287 | }, 288 | "id": "I6y-Gw3IIvtL", 289 | "outputId": "aedfacbd-305c-4b12-b3a2-0205f2900896" 290 | }, 291 | "source": [ 292 | "'''\n", 293 | "versión mejorada del perceptron\n", 294 | "x: vector de entradas\n", 295 | "w: vector de pesos\n", 296 | "'''\n", 297 | "def perceptrAND2(x, w):\n", 298 | " return np.heaviside(x[0]*w[0]+x[1]*w[1]+w[2], 0)\n", 299 | "\n", 300 | "# prueba de la funcion ¡CAMBIA EL VECTOR DE ENRTADAS!\n", 301 | "print(perceptrAND2([0,1],[1,1,-1])) \n" 302 | ], 303 | "execution_count": null, 304 | "outputs": [ 305 | { 306 | "output_type": "stream", 307 | "name": "stdout", 308 | "text": [ 309 | "0.0\n" 310 | ] 311 | } 312 | ] 313 | }, 314 | { 315 | "cell_type": "markdown", 316 | "metadata": { 317 | "id": "-c6Y423jLKLG" 318 | }, 319 | "source": [ 320 | "La celda superior muestra una versión mejorada del `perceptrAND` que hace uso del conocimiento previo (axiomas matemáticos y razonamiento) y de los estimulos externos (entradas $\\vec{x}$).\n", 321 | "\n", 322 | "Sin embargo tiene el mismo problema que la versión previa del `perceptrAND`." 323 | ] 324 | }, 325 | { 326 | "cell_type": "markdown", 327 | "metadata": { 328 | "id": "o-Y0ImDdOhj3" 329 | }, 330 | "source": [ 331 | "# Perceptrón\n", 332 | "\n", 333 | "La parte realmente trascendente del modelo perceptrón es el proceso de aprendizaje, esto convierte al perceptrón en un algoritmo que aprende de la experiencia y modifica su comportamiento, veamos como se lleva a cabo este proceso.\n", 334 | "\n", 335 | "\n" 336 | ] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "metadata": { 341 | "id": "2F4nh1heOnZU" 342 | }, 343 | "source": [ 344 | "## Aprendizaje\n", 345 | "\n", 346 | "Estos son los pasos descritos en lenguaje natural, que llevan al perceptrón a ajustar sus pesos $\\vec{w}$ y sesgo $b$ para realizar el proceso de aprendizaje, es decir, que logre clasificar de manera acertada el conjunto de datos que recibe como entradas $\\vec{x}$.\n", 347 | "\n", 348 | "1. Dar un valor inicial para el vector de pesos $\\vec{w}$, a veces aleatorio, o de manera más sencilla, el vector cero $\\vec{0}$.\n", 349 | "2. Para cada tupla de entrada del conjunto de entrenamiento, el perceptrón realiza las siguientes acciones:\n", 350 | "> * Tratará de dar una predicción para los valores de entrada.\n", 351 | "> * Esta predicción se compara con la salida esperada.\n", 352 | "> * Evalua la siguiente tupla.\n", 353 | "\n", 354 | "Antes de continuar hay un par de cosas que debemos definir, de manera muy similar al error que se tiene en una aproximación numérica, vamos a determinar que tan buena es la predicción del perceptrón de la siguiente forma.\n", 355 | "\n", 356 | "`salida_esperada - salida_actual`\n", 357 | "\n", 358 | "En otras palabras, necesitamos una forma de evaluar el desempeño del perceptrón y una forma de hacerlo es mediante la resta anterior. Eso lo podemos poner en términos matemáticos tal como sigue y posteriormente le llamaremos **función de costos** o **función perdida**.\n", 359 | "\n", 360 | "$$e=y-f(\\vec{x})$$\n", 361 | "\n", 362 | "Donde $e$ es el error que se tiene entre la salida esperada denotada por $y$ contra la salida del perceptrón $f(\\vec{x})$.\n", 363 | "\n", 364 | "Dado que ambos valores son binarios, $e=y-f(\\vec{x})$ solo puede producir 3 valores, que se muestran a continuación.\n", 365 | "\n", 366 | "| $y$ | $$f(\\vec{x})$$ | $$y - f$$ | \n", 367 | "| :-: | :-: | :-: | \n", 368 | "| 1 | 1 | 0 |\n", 369 | "| 0 | 0 | 0 |\n", 370 | "| 1 | 0 | 1 |\n", 371 | "| 0 | 1 |-1 |\n", 372 | "\n", 373 | "La idea es minimizar nuestro error (función de costos), así que para este fin veamos una frase celebre del creador del perceptrón **Frank Rosenblatt**.\n", 374 | "\n", 375 | "> * *Si la neurona se activa cuando no lo deseamos, suprimela*.\n", 376 | "> * *Si la neurona no se activa cuando lo deseamos, exitala*.\n", 377 | "> * *Si la neurona se activa cuando lo deseamos, no la molestes*.\n", 378 | "\n", 379 | "Ya sabemos como evaluar el desempeño de nuestro perceptrón, ahora solo resta definir como suprimirlo y como exitarlo." 380 | ] 381 | }, 382 | { 383 | "cell_type": "markdown", 384 | "metadata": { 385 | "id": "WvAgphBSRqvy" 386 | }, 387 | "source": [ 388 | "## Premio y Castigo\n", 389 | "\n", 390 | "**Castigo**: Si el perceptrón devuelve un 1 ($f(\\vec{x})=1$), cuando el resultado esperado era un 0 ($y=0$), necesitamos hacer un ajuste disminuyendo el valor de $\\vec{w}\\circ\\vec{x}$, ya que lo que se busca es que $f(\\vec{x})=\\vec{w}\\circ\\vec{x}\\leq 0$.\n", 391 | "\n", 392 | "**Castigo**: Si el perceptrón devuelve un 0 ($f(\\vec{x})=0$), cuando el resultado esperado era un 1 ($y=1$), necesitamos hacer un ajuste aumentando el valor de $\\vec{w}\\circ\\vec{x}$, ya que lo que se busca es que $f(\\vec{x})=\\vec{w}\\circ\\vec{x}\\gt 0$.\n", 393 | "\n", 394 | "**Premio**: Si el perceptrón devuelve el valor esperado ($f(\\vec{x})=y$) entonces hay que darle un premio, es decir, no hacer algo ya que la neurona está funcionando como debe ser.\n", 395 | "\n", 396 | "Dado que no podemos modificar los valores de las entradas $\\vec{x}$ ya que son los datos que usa el perceptrón para realizar sus predicciones, solo resta modificar los valores de $\\vec{w}$.\n", 397 | "\n", 398 | "Así que en pseudocódigo, lo anterior se traduce en lo siguiente.\n", 399 | "\n", 400 | "\\begin{array}{ccc}\n", 401 | "\\vec{w}\\leftarrow\\vec{w}+\\vec{x} & si & y-f(\\vec{x})==1\\\\\n", 402 | "\\vec{w}\\leftarrow\\vec{w}-\\vec{x} & si & y-f(\\vec{x})==-1\\\\\n", 403 | "\\vec{w}\\leftarrow\\vec{w} & si & y-f(\\vec{x})==0 \\tag{3}\n", 404 | "\\end{array}\n", 405 | "\n", 406 | "En pocas palabras, para incrementar el valor de $\\vec{w}$ simplemente sumamos $\\vec{x}$ y para disminuir el valor de $\\vec{w}$ simplemente restamos $\\vec{x}$.\n", 407 | "\n", 408 | "Dado que $y-f(\\vec{x})$ produce $1$, $-1$ ó $0$ podemos simplificar reescribiendo (3). Y de manera similar trabajamos con el sesgo ($b$), con la diferencia de que simplemente se multiplica por $1$, es decir.\n", 409 | "\n", 410 | "\\begin{array}{ccc}\n", 411 | "\\vec{w}\\leftarrow\\vec{w}+(y-f(\\vec{x}))*\\vec{x}\\\\\n", 412 | "b\\leftarrow b+(y-f(\\vec{x}))*1\\tag{4}\n", 413 | "\\end{array}\n", 414 | "\n", 415 | "¡¡¡Listo!!!, gracias a la expresión $(4)$ ya tenemos el mecanismo que llevará a nuestro perceptrón a aprender y adaptarse a los datos de entrada.\n", 416 | "\n", 417 | "Vamos a usar los siguientes datos de entrenamiento.\n", 418 | "\n", 419 | "| $x_1$ | $x_2$ | Salida esperada | \n", 420 | "| :-: | :-:| :-: | \n", 421 | "| 0 | 0 | 0 |\n", 422 | "| 0 | 1 | 0 |\n", 423 | "| 1 | 0 | 0 |\n", 424 | "| 1 | 1 | 1 |\n", 425 | "\n" 426 | ] 427 | }, 428 | { 429 | "cell_type": "markdown", 430 | "metadata": { 431 | "id": "sGRmBag0dqmI" 432 | }, 433 | "source": [ 434 | "## Entrenamiento\n", 435 | "\n", 436 | "#Valores iniciales del vector $\\vec{w}$.\n", 437 | "\n", 438 | "w = [0, 0, 0] => [bias, w1, w2]\n", 439 | "\n", 440 | "#Entradas de entrenamiento\n", 441 | "\n", 442 | "x = [1, 1, 1] => [entrada_bias, x1, x2]\n", 443 | "\n", 444 | "y = 1\n", 445 | "\n", 446 | "#Salida del perceptrón\n", 447 | "\n", 448 | "f(x) = 1 if w · x > 0,\n", 449 | " 0 otro caso\n", 450 | "\n", 451 | "w · x == (0 * 1) + (0 * 1) + (0 * 1) == 0 \n", 452 | " ∴ f(x) = 0\n", 453 | "\n", 454 | "#Comparando resultados\n", 455 | "\n", 456 | "e = y - f(x) => 1\n", 457 | "\n", 458 | "#Manazo por que no fue el resultado esperado\n", 459 | "\n", 460 | "w <- w + 1 * x => [1, 1, 1]\n", 461 | "\n", 462 | "Y este procedimiento se repite con todos los datos de entrada." 463 | ] 464 | }, 465 | { 466 | "cell_type": "markdown", 467 | "metadata": { 468 | "id": "ZgDwxOwHfKgY" 469 | }, 470 | "source": [ 471 | "# Implementación\n", 472 | "\n", 473 | "Dado que el proceso de aprendizaje es un proceso sumamente repetitivo y gracias a que tenemos un algoritmo para llevarlo a cabo, lo más sencillo es plasmar estos conceptos en código de *Python*.\n", 474 | "\n", 475 | "Además vamos a usar el paradigma orientado a objetos para darle una apariencia similar a las que se usan en *API's* como *TensorFlow*." 476 | ] 477 | }, 478 | { 479 | "cell_type": "code", 480 | "metadata": { 481 | "id": "rydpZ9rAPUVi" 482 | }, 483 | "source": [ 484 | "'''\n", 485 | "MIT License\n", 486 | "Copyright (c) 2018 Thomas Countz\n", 487 | "Codigo tomado del sitio\n", 488 | "https://medium.com/@thomascountz/19-line-line-by-line-python-perceptron-b6f113b161f3\n", 489 | "'''\n", 490 | "import numpy as np\n", 491 | "\n", 492 | "# Definicion de la clase que hereda de la clase object\n", 493 | "class Perceptron(object):\n", 494 | " '''\n", 495 | " Constructor que recibe los siguientes parametros\n", 496 | " num_entradas: numero de entradas del vector de entradas\n", 497 | " limite: es el limite de iteraciones mientras entrenamos\n", 498 | " tasa_aprendizaje: magnitud en la que se incrementan los pesos\n", 499 | " '''\n", 500 | " def __init__(self, num_entradas, limite=15, tasa_aprendizaje=0.01):\n", 501 | " self.limite = limite\n", 502 | " self.tasa_aprendizaje = tasa_aprendizaje\n", 503 | " self.pesos = np.zeros(num_entradas + 1) #se suma uno por el bias\n", 504 | " \n", 505 | " '''\n", 506 | " Metodo que nos devuelve la prediccion del perceptron\n", 507 | " entradas: vector de entradas para realizar la prediccion\n", 508 | " '''\n", 509 | " def prediccion(self, entradas):\n", 510 | " # suma ponderada x*w, pesos[0] = bias\n", 511 | " suma = np.dot(entradas, self.pesos[1:]) + self.pesos[0]\n", 512 | " # funcion de activacion equivalente a np.heaviside\n", 513 | " if suma > 0:\n", 514 | " activacion = 1\n", 515 | " else:\n", 516 | " activacion = 0 \n", 517 | " return activacion\n", 518 | "\n", 519 | " '''\n", 520 | " Metodo que entrena al percetron\n", 521 | " entradas_ent: vector de vectores de entradas para entrenar\n", 522 | " etiquetas: valores esperados por cada entrada del vector de entradas\n", 523 | " '''\n", 524 | " def entrenamiento(self, entradas_ent, etiquetas, debbug=False):\n", 525 | " # por cada epoca en el limite de entrenamientos\n", 526 | " for _ in range(self.limite):\n", 527 | " # tomamos una entrada y su respectiva etiqueta\n", 528 | " for entrada, etiqueta in zip(entradas_ent, etiquetas):\n", 529 | " prediccion = self.prediccion(entrada)\n", 530 | " # ajuste de pesos w <- w + (y-f(x)) * x \n", 531 | " self.pesos[1:] += self.tasa_aprendizaje * (etiqueta - prediccion) * entrada\n", 532 | " # ajuste del bias\n", 533 | " self.pesos[0] += self.tasa_aprendizaje * (etiqueta - prediccion) # *1\n", 534 | " # (SECCION DE DEBUGEO)\n", 535 | " if debbug:\n", 536 | " if prediccion != etiqueta:\n", 537 | " print(\"chanclazo por no aprender\")\n", 538 | " input(\"Continuar?\")\n", 539 | " else:\n", 540 | " print(\"bien hecho muchacho\")\n", 541 | " input(\"Continuar?\")\n", 542 | " #self.grafica()\n", 543 | " \n", 544 | " def grafica(self):\n", 545 | " print(self.pesos)\n", 546 | " # dominio de la grafica\n", 547 | " dominio = np.linspace(-0.25, 1.25, 10)\n", 548 | " # funcion a graficar\n", 549 | " graf = lambda x: (-self.pesos[0]-self.pesos[1]*x)/self.pesos[2]\n", 550 | "\n", 551 | " # definimos algunos parámetros para la gráfica\n", 552 | " fig, ax = plt.subplots()\n", 553 | " # recta generada por el perceptron\n", 554 | " ax.plot(dominio, graf(dominio))\n", 555 | " # valores de entrada para el perceptron\n", 556 | " xs = [0,1,0,1]\n", 557 | " ys = [0,0,1,1]\n", 558 | " # etiquetas \n", 559 | " ax.scatter(xs, ys)\n", 560 | " ax.annotate('(0,0)', (xs[0],ys[0]), xytext=(0.125, 0.125), arrowprops = dict( arrowstyle=\"->\",\n", 561 | " connectionstyle=\"angle3,angleA=0,angleB=-90\")) \n", 562 | " ax.annotate('(1,0)', (xs[1],ys[1]), xytext=(1, 0.125), arrowprops = dict( arrowstyle=\"->\",\n", 563 | " connectionstyle=\"angle3,angleA=0,angleB=-90\")) \n", 564 | " ax.annotate('(0,1)', (xs[2],ys[2]), xytext=(0.125, 0.75), arrowprops = dict( arrowstyle=\"->\",\n", 565 | " connectionstyle=\"angle3,angleA=0,angleB=-90\")) \n", 566 | " ax.annotate('(1,1)', (xs[3],ys[3]), xytext=(1, 0.75), arrowprops = dict( arrowstyle=\"->\",\n", 567 | " connectionstyle=\"angle3,angleA=0,angleB=-90\")) \n", 568 | " # ejes coordenados\n", 569 | " ax.axhline(y=0, color='k')\n", 570 | " ax.axvline(x=0, color='k')\n", 571 | " plt.title(\"Perceptrón\")\n", 572 | "\n", 573 | " plt.grid()\n", 574 | " plt.show()\n" 575 | ], 576 | "execution_count": null, 577 | "outputs": [] 578 | }, 579 | { 580 | "cell_type": "markdown", 581 | "metadata": { 582 | "id": "taS2cMdvkq5o" 583 | }, 584 | "source": [ 585 | "## Ejecución\n", 586 | "\n", 587 | "Veamos los resultados." 588 | ] 589 | }, 590 | { 591 | "cell_type": "code", 592 | "metadata": { 593 | "id": "vYyNXFZApHrE", 594 | "colab": { 595 | "base_uri": "https://localhost:8080/" 596 | }, 597 | "outputId": "68654d8e-8d1e-472d-b8ed-d8d71fa02518" 598 | }, 599 | "source": [ 600 | "# entrenamiento AND\n", 601 | "entradas_ent = []\n", 602 | "entradas_ent.append(np.array([1, 1]))\n", 603 | "entradas_ent.append(np.array([1, 0]))\n", 604 | "entradas_ent.append(np.array([0, 1]))\n", 605 | "entradas_ent.append(np.array([0, 0]))\n", 606 | "\n", 607 | "etiquetas = np.array([1, 0, 0, 0])\n", 608 | "\n", 609 | "'''# entrenamiento OR\n", 610 | "entradas_ent = []\n", 611 | "entradas_ent.append(np.array([1, 1]))\n", 612 | "entradas_ent.append(np.array([1, 0]))\n", 613 | "entradas_ent.append(np.array([0, 1]))\n", 614 | "entradas_ent.append(np.array([0, 0]))\n", 615 | "\n", 616 | "etiquetas = np.array([1, 1, 1, 0])'''\n", 617 | "\n", 618 | "perceptron = Perceptron(2)\n", 619 | "perceptron.entrenamiento(entradas_ent, etiquetas)\n", 620 | "\n", 621 | "entradas = np.array([0, 0])\n", 622 | "print(perceptron.prediccion(entradas))\n", 623 | "\n", 624 | "entradas = np.array([1, 0])\n", 625 | "print(perceptron.prediccion(entradas))\n", 626 | "\n", 627 | "entradas = np.array([0, 1])\n", 628 | "print(perceptron.prediccion(entradas))\n", 629 | "\n", 630 | "entradas = np.array([1, 1])\n", 631 | "print(perceptron.prediccion(entradas))\n", 632 | "\n", 633 | "# vector que contiene el sesgo y pesos\n", 634 | "print(perceptron.pesos)" 635 | ], 636 | "execution_count": null, 637 | "outputs": [ 638 | { 639 | "output_type": "stream", 640 | "name": "stdout", 641 | "text": [ 642 | "0\n", 643 | "0\n", 644 | "0\n", 645 | "1\n", 646 | "[-0.02 0.01 0.02]\n" 647 | ] 648 | } 649 | ] 650 | }, 651 | { 652 | "cell_type": "markdown", 653 | "metadata": { 654 | "id": "Fk2wDVwTD976" 655 | }, 656 | "source": [ 657 | "# ¿Regresión lógica (mínimos cuadrados)?\n", 658 | "\n", 659 | "Después de haber entrenado al `perceptrón`, comprobar que logró aprender y que ya se comporta como esperamos, ¿qué podémos decir respecto a sus pesos y el sesgo (*bias*)?.\n", 660 | "\n", 661 | "Como puedes ver, estos valores corresponden a lo siguiente.\n", 662 | "\n", 663 | "\\begin{array}{c}\n", 664 | "b = -0.2\\\\\n", 665 | "w_1=0.1\\\\\n", 666 | "w_2=0.2 \\tag{5}\n", 667 | "\\end{array}\n", 668 | "\n", 669 | "Si usamos estos parámetros para mostrar gráficamente los resultados de nuestro `perceptrón`, tendríamos lo siguiente.\n", 670 | "\n", 671 | "\\begin{array}{ccc}\n", 672 | "\\vec{w}\\circ\\vec{x}+b & = & w_{1}*x_{1}+w_{2}*x_{2}+b\\\\\n", 673 | " & = & 0.1*x_{1}+0.2*x_{2}-0.2\\\\\n", 674 | " & \\Rightarrow & x_{2}=\\frac{0.2-0.1*x_{1}}{0.2}\n", 675 | "\\end{array}\n", 676 | "\n", 677 | "Con lo que obtenemos la siguiente gráfica." 678 | ] 679 | }, 680 | { 681 | "cell_type": "code", 682 | "metadata": { 683 | "id": "SyZ87bwbJV4N", 684 | "colab": { 685 | "base_uri": "https://localhost:8080/", 686 | "height": 453 687 | }, 688 | "outputId": "a5292ce3-fa8e-4db1-96b4-fe5dd5e9f9ee" 689 | }, 690 | "source": [ 691 | "# dominio de la grafica\n", 692 | "dominio = np.linspace(-0.25, 1.25, 10)\n", 693 | "# funcion a graficar\n", 694 | "graf = lambda x: (0.2-0.1*x)/0.2\n", 695 | "\n", 696 | "# definimos algunos parámetros para la gráfica\n", 697 | "fig, ax = plt.subplots()\n", 698 | "# recta generada por el perceptron\n", 699 | "ax.plot(dominio, graf(dominio))\n", 700 | "# valores de entrada para el perceptron\n", 701 | "xs = [0,1,0,1]\n", 702 | "ys = [0,0,1,1]\n", 703 | "# etiquetas \n", 704 | "ax.scatter(xs, ys)\n", 705 | "ax.annotate('(0,0)', (xs[0],ys[0]), xytext=(0.125, 0.125), arrowprops = dict( arrowstyle=\"->\",\n", 706 | " connectionstyle=\"angle3,angleA=0,angleB=-90\")) \n", 707 | "ax.annotate('(1,0)', (xs[1],ys[1]), xytext=(1, 0.125), arrowprops = dict( arrowstyle=\"->\",\n", 708 | " connectionstyle=\"angle3,angleA=0,angleB=-90\")) \n", 709 | "ax.annotate('(0,1)', (xs[2],ys[2]), xytext=(0.125, 0.75), arrowprops = dict( arrowstyle=\"->\",\n", 710 | " connectionstyle=\"angle3,angleA=0,angleB=-90\")) \n", 711 | "ax.annotate('(1,1)', (xs[3],ys[3]), xytext=(1, 0.75), arrowprops = dict( arrowstyle=\"->\",\n", 712 | " connectionstyle=\"angle3,angleA=0,angleB=-90\")) \n", 713 | "# ejes coordenados\n", 714 | "ax.axhline(y=0, color='k')\n", 715 | "ax.axvline(x=0, color='k')\n", 716 | "plt.title(\"Perceptrón\")\n", 717 | "\n", 718 | "plt.grid()\n", 719 | "plt.show()" 720 | ], 721 | "execution_count": null, 722 | "outputs": [ 723 | { 724 | "output_type": "display_data", 725 | "data": { 726 | "text/plain": [ 727 | "
" 728 | ], 729 | "image/png": "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\n" 730 | }, 731 | "metadata": {} 732 | } 733 | ] 734 | }, 735 | { 736 | "cell_type": "markdown", 737 | "metadata": { 738 | "id": "-QM9ENukM-ka" 739 | }, 740 | "source": [ 741 | "Con esta gráfica se puede apreciar, que el `perceptrón` fue capaz de encontrar los valores de los pesos y sesgo que nos ayudan a dividir (ó en otras palabras a **clasificar**) los valores de entrada que se le muestran al mismo.\n", 742 | "\n", 743 | "Es curioso que todo este procedimiento se asemeja al procedimiento de regresión lineal haciendo uso de **mínimos cuadrados**.\n", 744 | "\n", 745 | "Puedes encontrar una explicación más detallada de este procedimiento en el siguiente [enlace](https://colab.research.google.com/github/jugernaut/Prometeo/blob/master/04_M%C3%A9todosNum%C3%A9ricos/02_M%C3%ADnimosCuadrados/01_Minimos_cuadrados.ipynb)." 746 | ] 747 | }, 748 | { 749 | "cell_type": "markdown", 750 | "metadata": { 751 | "id": "kVIBoj3V2WOc" 752 | }, 753 | "source": [ 754 | "# Aprendizaje\n", 755 | "\n", 756 | "Como podemos notar, el `perceptrón` ha aprendido y después de haberlo entrenado ya logra reproducir el comportamiento del operador lógico *AND* (&&) y eso que solo hemos hecho uso de un solo `perceptrón`.\n", 757 | "\n", 758 | "Ya que comprendimos su funcionamiento, surgen nuevas preguntas:\n", 759 | "\n", 760 | "* ¿Podémos hacer que este `perceptrón` logre \"aprender\" **cualquier comportamiento**, por ejemplo el operador $OR$ o el operador $XOR$?. Resuelve el siguiente problema [$XOR$](https://towardsdatascience.com/how-neural-networks-solve-the-xor-problem-59763136bdd7).\n", 761 | "* ¿Qué sucede si generamos \"capas\" de **perceptrones enlazados** donde las salidas de toda una capa sean las entradas de otra nueva capa?.\n", 762 | "* ¿Podémos pensar en el proceso de aprendizaje como un **problema de minimización** de costos?, y de ser así ¿conoces algúna función matemática que nos ayude a encontrar **valores mínimos**?.\n", 763 | "\n", 764 | "\n", 765 | "\n", 766 | "\n" 767 | ] 768 | }, 769 | { 770 | "cell_type": "markdown", 771 | "metadata": { 772 | "id": "oniRCJqcpkPf" 773 | }, 774 | "source": [ 775 | "
\n", 776 | "\n", 777 | "
" 778 | ] 779 | }, 780 | { 781 | "cell_type": "markdown", 782 | "metadata": { 783 | "id": "_AQHpP046Z6_" 784 | }, 785 | "source": [ 786 | "# Referencias\n", 787 | "\n", 788 | "* [Prometeo](https://github.com/jugernaut/Prometeo)\n", 789 | "* [Perceptrón](https://medium.com/@thomascountz/19-line-line-by-line-python-perceptron-b6f113b161f3)\n", 790 | "* [Brilliant](https://brilliant.org/practice/intelligent-computers-menace/?chapter=introduction-to-neural-networks)\n", 791 | "* [Simulador](https://ml4a.github.io/ml4a/es/neural_networks/)\n", 792 | "* [NetLogo](https://ccl.northwestern.edu/netlogo/)\n", 793 | "* [Red neuronal desde cero](https://futurelab.mx/redes%20neuronales/inteligencia%20artificial/2019/06/25/intro-a-redes-neuronales-pt-1/)\n", 794 | "* [Libro Web](http://neuralnetworksanddeeplearning.com/index.html)\n", 795 | "* [Aprendizaje profundo](https://www.deeplearningbook.org/)\n", 796 | "* [Lista de videos](https://www.youtube.com/playlist?list=PLo8YL3HL50lUHQS80oE_ypxFi0Y3uCVal)\n", 797 | "* [Algebra Lineal](https://www.youtube.com/playlist?list=PLIb_io8a5NB2DddFf-PwvZDCOUNT1GZoA)\n" 798 | ] 799 | } 800 | ] 801 | } --------------------------------------------------------------------------------