{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# UD05 · Notebook 10 — Simular un sistema experto con experta\n", "\n", "**Requisitos**\n", "\n", "Python 3.10+ con `experta`. Recuerda el **parche de compatibilidad**\n", "(`collections.Mapping` desapareció en Python 3.10):\n", "\n", "```python\n", "import collections, collections.abc\n", "if not hasattr(collections, 'Mapping'):\n", " collections.Mapping = collections.abc.Mapping\n", " collections.Iterable = collections.abc.Iterable\n", " collections.MutableMapping = collections.abc.MutableMapping\n", "```\n", "\n", "**Objetivo**: construir un sistema experto que **diagnostique** un problema y lo compare con uno\n", "de **clasificación**, demostrando que un mismo motor simula comportamientos de ámbitos distintos\n", "(CE b).\n", "\n", "Es una **entrega evaluable**: se corrige con la rúbrica de su tarea en Moodle." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fase 1 — Parche e importación" ] }, { "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": [ "%pip install experta\n", "\n", "# experta (2019) rompe en Python 3.10+ porque `collections.Mapping` se eliminó.\n", "# Parche de tres líneas antes de importar (ya documentado en la UD00):\n", "import collections, collections.abc\n", "if not hasattr(collections, 'Mapping'):\n", " collections.Mapping = collections.abc.Mapping\n", " collections.Iterable = collections.abc.Iterable\n", " collections.MutableMapping = collections.abc.MutableMapping\n", "\n", "from experta import *" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**✏️ Respuesta**: ¿por qué el parche tiene que ir **antes** del `import`?\n", "\n", "*(escribe aquí)*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fase 2 — Sistema de diagnóstico de un coche que no arranca\n", "\n", "**Salida esperada:**\n", "\n", "\n", "Anota la salida y explica qué reglas se dispararon y en qué orden." ] }, { "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": [ "class DiagnosticoCoche(KnowledgeEngine):\n", " # TU CÓDIGO: @DefFacts() con el hecho inicial\n", " ...\n", "\n", " # TU CÓDIGO: regla de arranque con salience=10 que declare los sintomas\n", " ...\n", "\n", " # TU CÓDIGO: regla que deduzca la causa\n", " ...\n", "\n", " # TU CÓDIGO: regla que imprima el resultado\n", " ...\n", "\n", "motor = DiagnosticoCoche()\n", "motor.reset() # sin reset() no se cargan los DefFacts\n", "motor.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**✏️ Respuesta**: anota la salida y explica **qué reglas se dispararon y en qué orden**.\n", "\n", "*(escribe aquí)*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fase 3 — Sistema de clasificación (otro ámbito)\n", "\n", "**El fallo más habitual de esta fase**\n", "\n", "Si llamas a `Animales().run()` sin **`reset()`** antes, no se dispara ninguna regla: `run()`\n", "solo ejecuta el ciclo de inferencia sobre los hechos ya cargados, y es `reset()` quien invoca\n", "`@DefFacts()` para cargarlos. Sin ese paso, `engine.facts` queda casi vacío y no hay nada que\n", "coincida con las reglas." ] }, { "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": [ "class Animales(KnowledgeEngine):\n", " # TU CÓDIGO\n", " ...\n", "\n", "motor = Animales()\n", "motor.reset() # sin reset() no se cargan los DefFacts\n", "motor.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**✏️ Respuesta**: ¿qué has tenido que cambiar del motor entre la Fase 2 y la Fase 3? ¿Y qué\n", "has **conservado**? Esa es la idea de fondo del criterio.\n", "\n", "*(escribe aquí)*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fase 4 — Analiza el orden de disparo\n", "\n", "Modifica la regla `mamifero` para que tenga `salience=5` y vuelve a ejecutar. ¿Qué cambia? Explica\n", "la **resolución de conflictos**." ] }, { "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": [ "# TU CÓDIGO: repite el motor de la Fase 3 con la salience cambiada\n", "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**✏️ Respuesta**: ¿qué cambia? Explica la **resolución de conflictos**: cuando varias reglas\n", "están activas a la vez, ¿cómo decide el motor?\n", "\n", "*(escribe aquí)*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fase 5 — Añade una regla con `NOT` y pregunta al usuario" ] }, { "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": [ "class DiagnosticoConPregunta(KnowledgeEngine):\n", " # TU CÓDIGO: usa input() en la regla de arranque y declara el hecho segun la respuesta\n", " ...\n", "\n", "motor = DiagnosticoConPregunta()\n", "motor.reset()\n", "motor.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**✏️ Respuesta**: ¿qué aporta `NOT` que no se pueda hacer con una regla normal?\n", "\n", "*(escribe aquí)*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fase 6 — Analiza la sensibilidad\n", "\n", "Añade una regla con umbral (`usuarios > 50 → critica`) y prueba con distintos valores (40, 55, 50).\n", "¿Qué ocurre justo en el umbral? ¿Cómo lo harías robusto (histéresis, §9)?" ] }, { "cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": [ "# TU CÓDIGO: regla con umbral y las tres pruebas\n", "# Pista: para comparar dentro de un Fact hace falta un constraint de predicado, P(...)\n", "..." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**✏️ Respuesta**: ¿qué ocurre **justo en el umbral**? ¿Cómo lo harías robusto con\n", "**histéresis**?\n", "\n", "*(escribe aquí)*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Entrega\n", "\n", "Recopila las capturas y las explicaciones de las seis fases en **una memoria en PDF**. Se valora que\n", "expliques **qué reglas se dispararon y en qué orden**, no solo la salida final.\n", "\n", "| Fase | Evidencia mínima |\n", "|---|---|\n", "| 1 | El parche aplicado y `experta` importado sin error |\n", "| 2 | El diagnóstico del coche funcionando, con las reglas que se dispararon |\n", "| 3 | La clasificación del guepardo, y por qué el **mismo motor** sirve para otro ámbito |\n", "| 4 | El cambio de `salience` y su efecto en el orden de disparo |\n", "| 5 | La regla con `NOT` y la versión que pregunta al usuario |\n", "| 6 | El umbral probado con tres valores, y tu propuesta de histéresis |\n", "\n", "**Soluciones**\n", "\n", "Las soluciones no se publican: se corrigen y comentan en clase." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.12" } }, "nbformat": 4, "nbformat_minor": 5 }