{ "cells": [ { "cell_type": "markdown", "id": "9f22c112528f9104", "metadata": { "collapsed": false, "id": "9f22c112528f9104" }, "source": [ "# UD03 · Notebook 1 — Introducción al procesamiento del lenguaje natural\n", "\n", "Muchas de las operaciones actuales de procesamiento del lenguaje natural se basan en *aprendizaje automático* y *aprendizaje profundo*. Hasta hace poco, sin embargo, estas operaciones se basaban en reglas y estadísticas. En esta práctica, veremos cómo usar algunas de estas técnicas básicas para trabajar con texto.\n", "\n", "En esta práctica veremos las operaciones básicas dadas por las librerías de Python más utilizadas para preprocesar el texto y las representaciones que podemos obtener.\n", "\n", "## Tokenización\n", "\n", "La tokenización es el proceso de dividir una cadena de caracteres en unidades más pequeñas. Estas unidades pueden ser palabras, personajes, frases, etc.\n", "\n", "Esta es una operación básica y necesaria para aplicar cualquier técnica de procesamiento del lenguaje natural.En esta práctica usaremos la palabra tokenización, es decir, dividiremos el texto en palabras.\n", "\n", "Para hacer esto, usaremos la librería [TextBlob](https://textblob.readnedocs.io/en/dev/). Esta librería nos permitirá un texto simple de manera simple." ] }, { "cell_type": "code", "execution_count": null, "id": "daa463042a366512", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:38.226841Z", "start_time": "2024-01-24T12:01:06.507611Z" }, "colab": { "base_uri": "https://localhost:8080/" }, "id": "daa463042a366512", "outputId": "1881cee7-f173-4808-9999-1df7f2c73d27" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Requirement already satisfied: textblob==0.19.0 in /usr/local/lib/python3.11/dist-packages (0.19.0)\n", "Requirement already satisfied: nltk>=3.9 in /usr/local/lib/python3.11/dist-packages (from textblob==0.19.0) (3.9.1)\n", "Requirement already satisfied: click in /usr/local/lib/python3.11/dist-packages (from nltk>=3.9->textblob==0.19.0) (8.1.8)\n", "Requirement already satisfied: joblib in /usr/local/lib/python3.11/dist-packages (from nltk>=3.9->textblob==0.19.0) (1.4.2)\n", "Requirement already satisfied: regex>=2021.8.3 in /usr/local/lib/python3.11/dist-packages (from nltk>=3.9->textblob==0.19.0) (2024.11.6)\n", "Requirement already satisfied: tqdm in /usr/local/lib/python3.11/dist-packages (from nltk>=3.9->textblob==0.19.0) (4.67.1)\n", "Requirement already satisfied: gensim in /usr/local/lib/python3.11/dist-packages (4.3.3)\n", "Requirement already satisfied: numpy<2.0,>=1.18.5 in /usr/local/lib/python3.11/dist-packages (from gensim) (1.26.4)\n", "Requirement already satisfied: scipy<1.14.0,>=1.7.0 in /usr/local/lib/python3.11/dist-packages (from gensim) (1.13.1)\n", "Requirement already satisfied: smart-open>=1.8.1 in /usr/local/lib/python3.11/dist-packages (from gensim) (7.1.0)\n", "Requirement already satisfied: wrapt in /usr/local/lib/python3.11/dist-packages (from smart-open>=1.8.1->gensim) (1.17.2)\n" ] } ], "source": [ "%pip install textblob==0.19.0\n", "%pip install gensim" ] }, { "cell_type": "markdown", "id": "a58c2aae9a15103d", "metadata": { "collapsed": false, "id": "a58c2aae9a15103d" }, "source": [ "Para tokenizar un texto con TextBlob antes teneamos que bajar los 'corpus'. Los corpus son conjuntos de datos que nos permiten usar las características de la librería." ] }, { "cell_type": "code", "execution_count": null, "id": "3075d22fccd656d2", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:43.614935Z", "start_time": "2024-01-24T12:01:38.225263Z" }, "colab": { "base_uri": "https://localhost:8080/" }, "id": "3075d22fccd656d2", "outputId": "fa10c5d8-33f3-4b5e-fa8e-b059acef469a" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "[nltk_data] Downloading package brown to /root/nltk_data...\n", "[nltk_data] Unzipping corpora/brown.zip.\n", "[nltk_data] Downloading package punkt_tab to /root/nltk_data...\n", "[nltk_data] Unzipping tokenizers/punkt_tab.zip.\n", "[nltk_data] Downloading package wordnet to /root/nltk_data...\n", "[nltk_data] Downloading package averaged_perceptron_tagger_eng to\n", "[nltk_data] /root/nltk_data...\n", "[nltk_data] Unzipping taggers/averaged_perceptron_tagger_eng.zip.\n", "[nltk_data] Downloading package conll2000 to /root/nltk_data...\n", "[nltk_data] Unzipping corpora/conll2000.zip.\n", "[nltk_data] Downloading package movie_reviews to /root/nltk_data...\n", "[nltk_data] Unzipping corpora/movie_reviews.zip.\n", "Finished.\n" ] } ], "source": [ "!python -m textblob.download_corpora" ] }, { "cell_type": "markdown", "id": "75355725643ddfd7", "metadata": { "collapsed": false, "id": "75355725643ddfd7" }, "source": [ "### Tokenización de palabras" ] }, { "cell_type": "markdown", "id": "8b84aac281b92f2a", "metadata": { "collapsed": false, "id": "8b84aac281b92f2a" }, "source": [ "Una vez que hemos bajado el modelo, podemos tokenizar el texto. Para hacer esto, primero debemos importar la librería.\n", "\n", "A continuación, crearemos un objeto `textblob` con el texto que queremos tokenizar. Este objeto nos permitirá acceder a la funcionalidad de la librería.\n", "\n", "Finalmente, usaremos la función de `words` para tokenizar el texto." ] }, { "cell_type": "code", "execution_count": null, "id": "2d21a73a1faf29a", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:43.861694Z", "start_time": "2024-01-24T12:01:43.623536Z" }, "colab": { "base_uri": "https://localhost:8080/" }, "id": "2d21a73a1faf29a", "outputId": "71a8f0ae-cfe6-4a25-c8ef-ac5e81d2ac69" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "WordList(['El', 'Barça', 'es', 'el', 'mejor', 'equipo', 'del', 'mundo', 'A', 'veces'])" ] }, "metadata": {}, "execution_count": 3 } ], "source": [ "# Importamos la librería\n", "from textblob import TextBlob\n", "\n", "# Creamos un objeto TextBLOB con el texto que queremos tokenizar\n", "text = \"El Barça es el mejor equipo del mundo. A veces.\"\n", "blob = TextBlob(text)\n", "\n", "# Tokenizamos el texto\n", "tokens = blob.words\n", "\n", "# Mostramos los tokens\n", "tokens" ] }, { "cell_type": "markdown", "id": "973a6d15145f4f69", "metadata": { "collapsed": false, "id": "973a6d15145f4f69" }, "source": [ "Una de las funciones más interesantes de TextBlob es que nos permite obtener la categoría gramatical de cada palabra. Para hacer esto, utilizaremos el atributo `tags` del objeto `TextBlob`." ] }, { "cell_type": "code", "execution_count": null, "id": "97bc4cc46ccc4b1a", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.128781Z", "start_time": "2024-01-24T12:01:43.651475Z" }, "colab": { "base_uri": "https://localhost:8080/" }, "id": "97bc4cc46ccc4b1a", "outputId": "29651614-b5ed-4c19-dd63-a4ca9d100e11" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "[('El', 'NNP'),\n", " ('Barça', 'NNP'),\n", " ('es', 'VBZ'),\n", " ('el', 'FW'),\n", " ('mejor', 'JJ'),\n", " ('equipo', 'NN'),\n", " ('del', 'FW'),\n", " ('mundo', 'NN'),\n", " ('A', 'DT'),\n", " ('veces', 'NNS')]" ] }, "metadata": {}, "execution_count": 4 } ], "source": [ "# Obtenemos la categoría gramatical de cada palabra\n", "# Las categorías de gramática se pueden consultar en: https://www.clips.uantwerpen.be/pages/mbsp-tags\n", "\n", "tags = blob.tags\n", "\n", "tags" ] }, { "cell_type": "markdown", "id": "257af34438f5bb17", "metadata": { "collapsed": false, "id": "257af34438f5bb17" }, "source": [ "También podemos hacer la `extracción de frase nominal`. Esta función nos permite obtener los grupos de palabras que componen un nombre." ] }, { "cell_type": "code", "execution_count": null, "id": "9ecb674665f481ba", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.500952Z", "start_time": "2024-01-24T12:01:43.670643Z" }, "id": "9ecb674665f481ba", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "524f2cb0-8cde-48c4-b1fc-98252256eafb" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "WordList(['el barça', 'es el mejor equipo del mundo'])" ] }, "metadata": {}, "execution_count": 5 } ], "source": [ "# Conseguimos las frases nominales\n", "\n", "nps = blob.noun_phrases\n", "\n", "nps" ] }, { "cell_type": "markdown", "id": "71daa861f8f2f398", "metadata": { "collapsed": false, "id": "71daa861f8f2f398" }, "source": [ "### Tokenización de frases\n", "\n", "En algunos casos, también es necesario tokenizar el texto en oraciones. Para hacer esto, utilizaremos la función `sentences` del objeto `TextBlob`." ] }, { "cell_type": "code", "execution_count": null, "id": "9a35f363ff99bedf", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.503925Z", "start_time": "2024-01-24T12:01:43.683607Z" }, "id": "9a35f363ff99bedf", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "d461adfc-b240-43d8-90c5-663e1a93af21" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "[Sentence(\"El Barça es el mejor equipo del mundo.\"), Sentence(\"A veces.\")]" ] }, "metadata": {}, "execution_count": 6 } ], "source": [ "# Tokenizamos el text en oraciones\n", "\n", "text = \"El Barça es el mejor equipo del mundo. A veces. \"\n", "blob = TextBlob(text)\n", "sentences = blob.sentences\n", "\n", "sentences" ] }, { "cell_type": "markdown", "id": "abc5c0978ac88feb", "metadata": { "collapsed": false, "id": "abc5c0978ac88feb" }, "source": [ "## Stopwords y signos de puntuación\n", "\n", "* Las *stopwords* son palabras que no proporcionan información relevante para la tarea que estamos haciendo. Por ejemplo, en la tarea de clasificación de texto, las *stopwords* no proporcionan información para la clasificación.\n", "\n", "Por lo tanto, en muchos casos, es aconsejable eliminar las *stopwords* en el texto antes de aplicar cualquier técnica de procesamiento del lenguaje natural.\n", "\n", "TextBlob nos permite eliminar las *stopwords* del texto.Para hacer esto, usaremos la lista *stopwords* que tiene NLTK (librería en la que se basa TextBloB)." ] }, { "cell_type": "code", "execution_count": null, "id": "c81ba5087a3c67d5", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.650908Z", "start_time": "2024-01-24T12:01:43.696Z" }, "id": "c81ba5087a3c67d5", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "6b24fb32-13eb-4997-cf93-31946edd51fa" }, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "[nltk_data] Downloading package stopwords to /root/nltk_data...\n", "[nltk_data] Unzipping corpora/stopwords.zip.\n" ] }, { "output_type": "execute_result", "data": { "text/plain": [ "['de',\n", " 'la',\n", " 'que',\n", " 'el',\n", " 'en',\n", " 'y',\n", " 'a',\n", " 'los',\n", " 'del',\n", " 'se',\n", " 'las',\n", " 'por',\n", " 'un',\n", " 'para',\n", " 'con',\n", " 'no',\n", " 'una',\n", " 'su',\n", " 'al',\n", " 'lo',\n", " 'como',\n", " 'más',\n", " 'pero',\n", " 'sus',\n", " 'le',\n", " 'ya',\n", " 'o',\n", " 'este',\n", " 'sí',\n", " 'porque',\n", " 'esta',\n", " 'entre',\n", " 'cuando',\n", " 'muy',\n", " 'sin',\n", " 'sobre',\n", " 'también',\n", " 'me',\n", " 'hasta',\n", " 'hay',\n", " 'donde',\n", " 'quien',\n", " 'desde',\n", " 'todo',\n", " 'nos',\n", " 'durante',\n", " 'todos',\n", " 'uno',\n", " 'les',\n", " 'ni',\n", " 'contra',\n", " 'otros',\n", " 'ese',\n", " 'eso',\n", " 'ante',\n", " 'ellos',\n", " 'e',\n", " 'esto',\n", " 'mí',\n", " 'antes',\n", " 'algunos',\n", " 'qué',\n", " 'unos',\n", " 'yo',\n", " 'otro',\n", " 'otras',\n", " 'otra',\n", " 'él',\n", " 'tanto',\n", " 'esa',\n", " 'estos',\n", " 'mucho',\n", " 'quienes',\n", " 'nada',\n", " 'muchos',\n", " 'cual',\n", " 'poco',\n", " 'ella',\n", " 'estar',\n", " 'estas',\n", " 'algunas',\n", " 'algo',\n", " 'nosotros',\n", " 'mi',\n", " 'mis',\n", " 'tú',\n", " 'te',\n", " 'ti',\n", " 'tu',\n", " 'tus',\n", " 'ellas',\n", " 'nosotras',\n", " 'vosotros',\n", " 'vosotras',\n", " 'os',\n", " 'mío',\n", " 'mía',\n", " 'míos',\n", " 'mías',\n", " 'tuyo',\n", " 'tuya',\n", " 'tuyos',\n", " 'tuyas',\n", " 'suyo',\n", " 'suya',\n", " 'suyos',\n", " 'suyas',\n", " 'nuestro',\n", " 'nuestra',\n", " 'nuestros',\n", " 'nuestras',\n", " 'vuestro',\n", " 'vuestra',\n", " 'vuestros',\n", " 'vuestras',\n", " 'esos',\n", " 'esas',\n", " 'estoy',\n", " 'estás',\n", " 'está',\n", " 'estamos',\n", " 'estáis',\n", " 'están',\n", " 'esté',\n", " 'estés',\n", " 'estemos',\n", " 'estéis',\n", " 'estén',\n", " 'estaré',\n", " 'estarás',\n", " 'estará',\n", " 'estaremos',\n", " 'estaréis',\n", " 'estarán',\n", " 'estaría',\n", " 'estarías',\n", " 'estaríamos',\n", " 'estaríais',\n", " 'estarían',\n", " 'estaba',\n", " 'estabas',\n", " 'estábamos',\n", " 'estabais',\n", " 'estaban',\n", " 'estuve',\n", " 'estuviste',\n", " 'estuvo',\n", " 'estuvimos',\n", " 'estuvisteis',\n", " 'estuvieron',\n", " 'estuviera',\n", " 'estuvieras',\n", " 'estuviéramos',\n", " 'estuvierais',\n", " 'estuvieran',\n", " 'estuviese',\n", " 'estuvieses',\n", " 'estuviésemos',\n", " 'estuvieseis',\n", " 'estuviesen',\n", " 'estando',\n", " 'estado',\n", " 'estada',\n", " 'estados',\n", " 'estadas',\n", " 'estad',\n", " 'he',\n", " 'has',\n", " 'ha',\n", " 'hemos',\n", " 'habéis',\n", " 'han',\n", " 'haya',\n", " 'hayas',\n", " 'hayamos',\n", " 'hayáis',\n", " 'hayan',\n", " 'habré',\n", " 'habrás',\n", " 'habrá',\n", " 'habremos',\n", " 'habréis',\n", " 'habrán',\n", " 'habría',\n", " 'habrías',\n", " 'habríamos',\n", " 'habríais',\n", " 'habrían',\n", " 'había',\n", " 'habías',\n", " 'habíamos',\n", " 'habíais',\n", " 'habían',\n", " 'hube',\n", " 'hubiste',\n", " 'hubo',\n", " 'hubimos',\n", " 'hubisteis',\n", " 'hubieron',\n", " 'hubiera',\n", " 'hubieras',\n", " 'hubiéramos',\n", " 'hubierais',\n", " 'hubieran',\n", " 'hubiese',\n", " 'hubieses',\n", " 'hubiésemos',\n", " 'hubieseis',\n", " 'hubiesen',\n", " 'habiendo',\n", " 'habido',\n", " 'habida',\n", " 'habidos',\n", " 'habidas',\n", " 'soy',\n", " 'eres',\n", " 'es',\n", " 'somos',\n", " 'sois',\n", " 'son',\n", " 'sea',\n", " 'seas',\n", " 'seamos',\n", " 'seáis',\n", " 'sean',\n", " 'seré',\n", " 'serás',\n", " 'será',\n", " 'seremos',\n", " 'seréis',\n", " 'serán',\n", " 'sería',\n", " 'serías',\n", " 'seríamos',\n", " 'seríais',\n", " 'serían',\n", " 'era',\n", " 'eras',\n", " 'éramos',\n", " 'erais',\n", " 'eran',\n", " 'fui',\n", " 'fuiste',\n", " 'fue',\n", " 'fuimos',\n", " 'fuisteis',\n", " 'fueron',\n", " 'fuera',\n", " 'fueras',\n", " 'fuéramos',\n", " 'fuerais',\n", " 'fueran',\n", " 'fuese',\n", " 'fueses',\n", " 'fuésemos',\n", " 'fueseis',\n", " 'fuesen',\n", " 'sintiendo',\n", " 'sentido',\n", " 'sentida',\n", " 'sentidos',\n", " 'sentidas',\n", " 'siente',\n", " 'sentid',\n", " 'tengo',\n", " 'tienes',\n", " 'tiene',\n", " 'tenemos',\n", " 'tenéis',\n", " 'tienen',\n", " 'tenga',\n", " 'tengas',\n", " 'tengamos',\n", " 'tengáis',\n", " 'tengan',\n", " 'tendré',\n", " 'tendrás',\n", " 'tendrá',\n", " 'tendremos',\n", " 'tendréis',\n", " 'tendrán',\n", " 'tendría',\n", " 'tendrías',\n", " 'tendríamos',\n", " 'tendríais',\n", " 'tendrían',\n", " 'tenía',\n", " 'tenías',\n", " 'teníamos',\n", " 'teníais',\n", " 'tenían',\n", " 'tuve',\n", " 'tuviste',\n", " 'tuvo',\n", " 'tuvimos',\n", " 'tuvisteis',\n", " 'tuvieron',\n", " 'tuviera',\n", " 'tuvieras',\n", " 'tuviéramos',\n", " 'tuvierais',\n", " 'tuvieran',\n", " 'tuviese',\n", " 'tuvieses',\n", " 'tuviésemos',\n", " 'tuvieseis',\n", " 'tuviesen',\n", " 'teniendo',\n", " 'tenido',\n", " 'tenida',\n", " 'tenidos',\n", " 'tenidas',\n", " 'tened']" ] }, "metadata": {}, "execution_count": 7 } ], "source": [ "# Obtenemos las stopwords\n", "import nltk\n", "nltk.download('stopwords')\n", "from nltk.corpus import stopwords\n", "stop = stopwords.words('spanish')\n", "\n", "stop" ] }, { "cell_type": "markdown", "id": "476130c1178cb27a", "metadata": { "collapsed": false, "id": "476130c1178cb27a" }, "source": [ "A continuación veremos un ejemplo de cómo eliminar los *stopwords* de un texto." ] }, { "cell_type": "code", "execution_count": null, "id": "73809b0f6613d867", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.738575Z", "start_time": "2024-01-24T12:01:43.729312Z" }, "id": "73809b0f6613d867", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "f32c06b2-a927-47ed-930a-a8c66cc0d175" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "['El', 'Barça', 'mejor', 'equipo', 'mundo', 'A', 'veces']" ] }, "metadata": {}, "execution_count": 8 } ], "source": [ "# Eliminamos las palabras de parada de un texto\n", "\n", "text = \"El Barça es el mejor equipo del mundo. A veces.\"\n", "blob = TextBlob(text)\n", "tokens = [token for token in blob.words if token not in stop]\n", "\n", "tokens" ] }, { "cell_type": "markdown", "id": "d009063a838fcd0a", "metadata": { "collapsed": false, "id": "d009063a838fcd0a" }, "source": [ "También podemos ver cómo, junto con las palabras de parada, también se eliminan los signos de puntuación." ] }, { "cell_type": "markdown", "id": "6bea4cdedd34fef6", "metadata": { "collapsed": false, "id": "6bea4cdedd34fef6" }, "source": [ "## Lematización i stemming\n", "\n", "La **Lematización** es el proceso de convertir una palabra en su forma base. Por ejemplo, la palabra *está* se convierte en *estar*.\n", "\n", "El **Stemming**, por otro lado, es eliminar los añadidos de las palabras. Por ejemplo, la palabra *estar* se convierte *est*.\n", "\n", "Ambas técnicas nos permiten reducir el vocabulario del texto y, por lo tanto, reducir la dimensionalidad de los vectores de la palabra; Lo que puede ayudarnos a mejorar el rendimiento de nuestros modelos.\n", "\n", "Vemos un ejemplo de cómo aplicar la lematización y el stemming de TextBlob." ] }, { "cell_type": "code", "execution_count": null, "id": "cb4548e61f0f9167", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.773350Z", "start_time": "2024-01-24T12:01:43.754840Z" }, "id": "cb4548e61f0f9167", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "d968680d-74fa-41b7-cf02-9b80e61fb033" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "(['The',\n", " 'titular',\n", " 'threat',\n", " 'of',\n", " 'The',\n", " 'Blob',\n", " 'ha',\n", " 'always',\n", " 'struck',\n", " 'me',\n", " 'a',\n", " 'the',\n", " 'ultimate',\n", " 'movie',\n", " 'monster',\n", " 'an',\n", " 'insatiably',\n", " 'hungry',\n", " 'amoeba-like',\n", " 'mass',\n", " 'able',\n", " 'to',\n", " 'penetrate',\n", " 'virtually',\n", " 'any',\n", " 'safeguard',\n", " 'capable',\n", " 'of',\n", " 'a',\n", " 'a',\n", " 'doomed',\n", " 'doctor',\n", " 'chillingly',\n", " 'describes',\n", " 'it',\n", " 'assimilating',\n", " 'flesh',\n", " 'on',\n", " 'contact',\n", " 'Snide',\n", " 'comparison',\n", " 'to',\n", " 'gelatin',\n", " 'be',\n", " 'damned',\n", " 'it',\n", " \"'s\",\n", " 'a',\n", " 'concept',\n", " 'with',\n", " 'the',\n", " 'most',\n", " 'devastating',\n", " 'of',\n", " 'potential',\n", " 'consequence',\n", " 'not',\n", " 'unlike',\n", " 'the',\n", " 'grey',\n", " 'goo',\n", " 'scenario',\n", " 'proposed',\n", " 'by',\n", " 'technological',\n", " 'theorist',\n", " 'fearful',\n", " 'of',\n", " 'artificial',\n", " 'intelligence',\n", " 'run',\n", " 'rampant'],\n", " ['the',\n", " 'titular',\n", " 'threat',\n", " 'of',\n", " 'the',\n", " 'blob',\n", " 'ha',\n", " 'alway',\n", " 'struck',\n", " 'me',\n", " 'as',\n", " 'the',\n", " 'ultim',\n", " 'movi',\n", " 'monster',\n", " 'an',\n", " 'insati',\n", " 'hungri',\n", " 'amoeba-lik',\n", " 'mass',\n", " 'abl',\n", " 'to',\n", " 'penetr',\n", " 'virtual',\n", " 'ani',\n", " 'safeguard',\n", " 'capabl',\n", " 'of',\n", " 'as',\n", " 'a',\n", " 'doom',\n", " 'doctor',\n", " 'chillingli',\n", " 'describ',\n", " 'it',\n", " 'assimil',\n", " 'flesh',\n", " 'on',\n", " 'contact',\n", " 'snide',\n", " 'comparison',\n", " 'to',\n", " 'gelatin',\n", " 'be',\n", " 'damn',\n", " 'it',\n", " \"'s\",\n", " 'a',\n", " 'concept',\n", " 'with',\n", " 'the',\n", " 'most',\n", " 'devast',\n", " 'of',\n", " 'potenti',\n", " 'consequ',\n", " 'not',\n", " 'unlik',\n", " 'the',\n", " 'grey',\n", " 'goo',\n", " 'scenario',\n", " 'propos',\n", " 'by',\n", " 'technolog',\n", " 'theorist',\n", " 'fear',\n", " 'of',\n", " 'artifici',\n", " 'intellig',\n", " 'run',\n", " 'rampant'])" ] }, "metadata": {}, "execution_count": 9 } ], "source": [ "# Lematizamos y stemmizamos un texto\n", "\n", "text = \"\"\"\n", "The titular threat of The Blob has always struck me as the ultimate movie\n", "monster: an insatiably hungry, amoeba-like mass able to penetrate\n", "virtually any safeguard, capable of--as a doomed doctor chillingly\n", "describes it--\"assimilating flesh on contact.\n", "Snide comparisons to gelatin be damned, it's a concept with the most\n", "devastating of potential consequences, not unlike the grey goo scenario\n", "proposed by technological theorists fearful of\n", "artificial intelligence run rampant.\n", "\"\"\"\n", "#text = \"Serias un buen cantante, si no fuera por la voz.\"\n", "blob = TextBlob(text)\n", "\n", "# Lematizamos\n", "lemmas = [token.lemmatize() for token in blob.words]\n", "\n", "# Stemmizamos\n", "\n", "stemes = [token.stem() for token in blob.words]\n", "\n", "lemmas, stemes" ] }, { "cell_type": "markdown", "id": "44eea0e5658d55b4", "metadata": { "collapsed": false, "id": "44eea0e5658d55b4" }, "source": [ "## N-grams\n", "\n", "Los N-Grrams son secuencias de n palabras consecutivas. Por ejemplo, si tenemos el siguiente texto: *'El ​​Barça es el mejor equipo del mundo'*, los N-gramas de 2 palabras serían: *'El Barça', 'Barça es', 'es el', 'el mejor', 'mejor equipo', 'equipo del', 'del mundo'*.\n", "\n", "Los N-Grams nos permiten tener en cuenta la relación entre palabras consecutivas. Por ejemplo, en el texto anterior, si solo usamos Unigrammes, no sabremos que *'mejor'* y *'equipo'* están relacionados. Sin embargo, si usamos Bigramas, sabremos que *'mejor equipo'* están relacionados.\n", "\n", "Para crear los N-Grams en TextBlob, usaremos la función `ngrams`." ] }, { "cell_type": "code", "execution_count": null, "id": "ef9376a1122fc5fd", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.777081Z", "start_time": "2024-01-24T12:01:43.799597Z" }, "id": "ef9376a1122fc5fd", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "74a6160e-a583-4301-ed86-6c1527486be2" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "[WordList(['El', 'Barça']),\n", " WordList(['Barça', 'es']),\n", " WordList(['es', 'el']),\n", " WordList(['el', 'mejor']),\n", " WordList(['mejor', 'equipo']),\n", " WordList(['equipo', 'del']),\n", " WordList(['del', 'mundo'])]" ] }, "metadata": {}, "execution_count": 10 } ], "source": [ "# Creamos bigrams de un texto\n", "\n", "text = \"El Barça es el mejor equipo del mundo.\"\n", "blob = TextBlob(text)\n", "bigrams = blob.ngrams(n=2)\n", "\n", "bigrams" ] }, { "cell_type": "markdown", "id": "8f60d714bf9586f2", "metadata": { "collapsed": false, "id": "8f60d714bf9586f2" }, "source": [ "## Representación del texto\n", "\n", "Una vez que hemos procesado el texto previamente, debemos representarlo en un formato que la computadora pueda entender.\n", "\n", "Veremos algunas de las representaciones más utilizadas en el procesamiento del lenguaje natural. En esta práctica, nos centraremos en algunas de las representaciones más utilizadas en las tareas de clasificación de texto.\n", "\n", "### Codificación de un solo estado\n", "\n", "La representación *una codificación única* es crear un vector para cada documento. Este vector tiene tantas dimensiones como palabras diferentes en el vocabulario. Cada dimensión del vector representa una palabra del vocabulario y el valor de la dimensión es 1 si la palabra aparece en el documento y 0 si no aparece.\n", "\n", "Por ejemplo, si tenemos el siguiente vocabulario: *'Casa', 'Coche', 'Avión'* y el siguiente documento: *'Casa coche casa'*, el vector resultante sería: *\\[1, 1, 0]*.\n", "\n", "Usaremos la clase `OneHotencoder` de la librería `Sklearn` para crear la representación *una codificación única*.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "19dcca3bebde5a6b", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.817981Z", "start_time": "2024-01-24T12:01:43.816680Z" }, "id": "19dcca3bebde5a6b", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "8bb6c64b-e3f6-4ba8-b0ce-1eab60e798d8" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "array([[0., 0., 1., 0., 0., 0., 0.],\n", " [0., 1., 0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 1., 0., 0.],\n", " [0., 0., 0., 1., 0., 0., 0.],\n", " [0., 0., 0., 0., 0., 1., 0.],\n", " [1., 0., 0., 0., 0., 0., 0.],\n", " [0., 0., 0., 0., 0., 0., 1.]])" ] }, "metadata": {}, "execution_count": 10 } ], "source": [ "import numpy\n", "from sklearn import preprocessing\n", "\n", "# Creamos la representación de rendimiento única de un texto\n", "\n", "text = \"El Barça es el mejor equipo del mundo. A veces.\"\n", "blob = TextBlob(text)\n", "tokens = numpy.array([token for token in blob.words if token not in stop])\n", "\n", "encoder = preprocessing.OneHotEncoder()\n", "\n", "encoded = encoder.fit_transform(tokens.reshape(-1, 1)).toarray()\n", "encoded" ] }, { "cell_type": "markdown", "id": "aad667c94d047037", "metadata": { "collapsed": false, "id": "aad667c94d047037" }, "source": [ "### Bolsa de palabras\n", "\n", "La representación *Bolsa de palabras* es crear un vector para cada documento. Este vector tiene tantas dimensiones como palabras diferentes en el vocabulario. Cada dimensión del vector representa una palabra del vocabulario y el valor de la dimensión es el número de apariencias de esta palabra en el documento.\n", "\n", "Por ejemplo, si tenemos el siguiente vocabulario: *'Casa', 'Coche', 'Avion'* y el siguiente documento: *'Casa Coche Casa'*, el vector resultante sería: *\\[2, 1, 0]*.\n", "\n", "Para crear la representación *Bolsa de palabras* Usaremos la clase `Countorizer` de la librería `Sklearn`'." ] }, { "cell_type": "code", "execution_count": null, "id": "4673ccc11709bc65", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.826140Z", "start_time": "2024-01-24T12:01:43.935113Z" }, "id": "4673ccc11709bc65", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "58c255e1-6a9b-4dbb-fdeb-db05e397d45f" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "['casa' 'me' 'paso' 'trabajo' 'vida']\n", "[[2 1 1 2 1]]\n" ] } ], "source": [ "# Creamos la representación de la bolsa de palabras de un texto\n", "\n", "from sklearn.feature_extraction.text import CountVectorizer\n", "\n", "text = \"Me paso la vida del trabajo a casa y de casa al trabajo.\"\n", "blob = TextBlob(text)\n", "tokens = [token for token in blob.words if token not in stop]\n", "text = ' '.join(tokens)\n", "\n", "vectorizer = CountVectorizer()\n", "bow = vectorizer.fit_transform([text])\n", "\n", "print(vectorizer.get_feature_names_out())\n", "print(bow.toarray())" ] }, { "cell_type": "markdown", "id": "aff61ee98abadd2a", "metadata": { "collapsed": false, "id": "aff61ee98abadd2a" }, "source": [ "### TF-IDF\n", "\n", "La representación TF-IDF (*Frecuencia de documento inversa*) es crear un vector para cada documento. Este vector tiene tantas dimensiones como palabras diferentes en el vocabulario. Cada dimensión del vector representa una palabra del vocabulario y el valor de la dimensión es el producto de la frecuencia de la palabra en el documento (TF) y la frecuencia inversa de la palabra en el conjunto de documentos (IDF).\n", "\n", "Por ejemplo, si tenemos el siguiente vocabulario: *'Casa', 'coche', 'Avion'* y el siguiente documento: *'Casa Coche Casa'*, el vector resultante sería: *\\[2/3, 1/3, 0]*.\n", "\n", "Para crear la representación TF-IDF, utilizaremos la clase `TFIDFVectorizer` de la librería `sklearn`." ] }, { "cell_type": "code", "execution_count": null, "id": "5745e2e4c168600e", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.855983Z", "start_time": "2024-01-24T12:01:43.980211Z" }, "id": "5745e2e4c168600e", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "87d19d88-19a1-4c40-c97a-b259a2b47860" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "['casa' 'me' 'paso' 'trabajo' 'vida']\n", "[[0.60302269 0.30151134 0.30151134 0.60302269 0.30151134]]\n" ] } ], "source": [ "# Creamos la representación TF-IDF de un texto\n", "\n", "from sklearn.feature_extraction.text import TfidfVectorizer\n", "\n", "text = \"Me paso la vida del trabajo a casa y de casa al trabajo.\"\n", "blob = TextBlob(text)\n", "tokens = [token for token in blob.words if token not in stop]\n", "text = ' '.join(tokens)\n", "\n", "vectorizer = TfidfVectorizer()\n", "tfidf = vectorizer.fit_transform([text])\n", "\n", "print(vectorizer.get_feature_names_out())\n", "print(tfidf.toarray())" ] }, { "cell_type": "markdown", "id": "fc7984789df920d", "metadata": { "collapsed": false, "id": "fc7984789df920d" }, "source": [ "### Word2Vec\n", "\n", "Word2Vec es un algoritmo que nos permite representar palabras en un espacio vectorial. Esta representación nos permite tener en cuenta la semántica de las palabras. Por ejemplo, si representamos las palabras *'rey'* y *'reina'* en un espacio vectorial, veremos que la distancia entre los vectores es menor que la distancia entre los vectores de *'rey'* y *'coche'* .\n", "\n", "Para crear la representación Word2Vec, usaremos la clase `Word2Vec` de la librería `Gensim`." ] }, { "cell_type": "code", "execution_count": null, "id": "c9506855ed1f3fe1", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.872657Z", "start_time": "2024-01-24T12:01:44.025925Z" }, "id": "c9506855ed1f3fe1", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "328f38b9-bf05-4d71-87ba-71f0dce62d67" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "array([-5.3622725e-04, 2.3643136e-04, 5.1033497e-03, 9.0092728e-03,\n", " -9.3029495e-03, -7.1168090e-03, 6.4588725e-03, 8.9729885e-03,\n", " -5.0154282e-03, -3.7633716e-03, 7.3805046e-03, -1.5334714e-03,\n", " -4.5366134e-03, 6.5540518e-03, -4.8601604e-03, -1.8160177e-03,\n", " 2.8765798e-03, 9.9187379e-04, -8.2852151e-03, -9.4488179e-03,\n", " 7.3117660e-03, 5.0702621e-03, 6.7576934e-03, 7.6286553e-04,\n", " 6.3508903e-03, -3.4053659e-03, -9.4640139e-04, 5.7685734e-03,\n", " -7.5216377e-03, -3.9361035e-03, -7.5115822e-03, -9.3004224e-04,\n", " 9.5381187e-03, -7.3191668e-03, -2.3337686e-03, -1.9377411e-03,\n", " 8.0774371e-03, -5.9308959e-03, 4.5162440e-05, -4.7537340e-03,\n", " -9.6035507e-03, 5.0072931e-03, -8.7595852e-03, -4.3918253e-03,\n", " -3.5099984e-05, -2.9618145e-04, -7.6612402e-03, 9.6147433e-03,\n", " 4.9820580e-03, 9.2331432e-03, -8.1579173e-03, 4.4957981e-03,\n", " -4.1370760e-03, 8.2453608e-04, 8.4986202e-03, -4.4621765e-03,\n", " 4.5175003e-03, -6.7869602e-03, -3.5484887e-03, 9.3985079e-03,\n", " -1.5776526e-03, 3.2137157e-04, -4.1406299e-03, -7.6826881e-03,\n", " -1.5080082e-03, 2.4697948e-03, -8.8802696e-04, 5.5336617e-03,\n", " -2.7429771e-03, 2.2600652e-03, 5.4557943e-03, 8.3459532e-03,\n", " -1.4537406e-03, -9.2081428e-03, 4.3705525e-03, 5.7178497e-04,\n", " 7.4419081e-03, -8.1328274e-04, -2.6384138e-03, -8.7530091e-03,\n", " -8.5655687e-04, 2.8265631e-03, 5.4014288e-03, 7.0526563e-03,\n", " -5.7031214e-03, 1.8588197e-03, 6.0888636e-03, -4.7980510e-03,\n", " -3.1072604e-03, 6.7976294e-03, 1.6314756e-03, 1.8991709e-04,\n", " 3.4736372e-03, 2.1777749e-04, 9.6188262e-03, 5.0606038e-03,\n", " -8.9173904e-03, -7.0415605e-03, 9.0145587e-04, 6.3925339e-03],\n", " dtype=float32)" ] }, "metadata": {}, "execution_count": 13 } ], "source": [ "# Creamos la representación de Word2Vec de un texto\n", "\n", "from gensim.models import Word2Vec\n", "\n", "text = \"Me paso la vida del trabajo a casa y de casa al trabajo.\"\n", "blob = TextBlob(text)\n", "tokens = [token for token in blob.words if token not in stop]\n", "\n", "model = Word2Vec([tokens], min_count=1)\n", "model.wv['casa']" ] }, { "cell_type": "markdown", "id": "6924355f3a8c8081", "metadata": { "collapsed": false, "id": "6924355f3a8c8081" }, "source": [ "## Otras funcionalidades de TextBlob (A partir de aquí... en Ingles)\n", "\n", "TextBlob nos permite realizar otras tareas de procesamiento del lenguaje natural. Estas son algunas de estas funcionalidades.\n", "\n", "### Análisis de sentimientos\n", "\n", "TextBlob nos permite analizar los sentimientos de un texto.Para hacer esto, utilizaremos el atributo `sentiment` del objeto `TextBlob`. Este atributo nos devuelve un objeto `Sentiment` con dos atributos: `polarity` y `subjectivity`. La polaridad es un valor entre -1 y 1 que indica si el texto es positivo o negativo. La subjetividad es un valor entre 0 y 1 que indica si el texto es objetivo o subjetivo." ] }, { "cell_type": "code", "execution_count": null, "id": "b61aaad91e8e76c5", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:44.886046Z", "start_time": "2024-01-24T12:01:44.081959Z" }, "id": "b61aaad91e8e76c5", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "b337b98a-5b07-4dd5-d460-9a553d36d8ee" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "Sentiment(polarity=-0.15, subjectivity=0.4)" ] }, "metadata": {}, "execution_count": 16 } ], "source": [ "# Analizamos los sentimientos de un texto\n", "\n", "text = \"This song is great!, it's the best song I've heard.\"\n", "blob = TextBlob(text)\n", "blob.sentiment" ] }, { "cell_type": "markdown", "id": "a9f55cf26922583c", "metadata": { "collapsed": false, "id": "a9f55cf26922583c" }, "source": [ "### Clasificación\n", "\n", "TextBlob nos permite clasificar el texto utilizando diferentes clasificadores. Para hacer esto, primero debemos entrenar el clasificador.\n", "\n", "En esta práctica, usaremos el clasificador *Naive Bayes* para clasificar el texto. Para entrenar el clasificador, usaremos la clase `NaiveBayesClasifier` de la librería `Textblob.Clasifiers`.\n", "\n", "Una vez que el clasificador ha sido entrenado, podemos clasificar el texto utilizando la clasificación del objeto `NaiveBayesClasifier`.\n", "\n", "A continuación, veremos un ejemplo de cómo clasificar el texto con TextBlob." ] }, { "cell_type": "code", "execution_count": null, "id": "6e18a286e19e6d06", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:45.801479Z", "start_time": "2024-01-24T12:01:44.136838Z" }, "id": "6e18a286e19e6d06", "colab": { "base_uri": "https://localhost:8080/", "height": 36 }, "outputId": "0a2d75af-a0b3-4de7-9dce-a6755fd2be0a" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "'Bug'" ], "application/vnd.google.colaboratory.intrinsic+json": { "type": "string" } }, "metadata": {}, "execution_count": 17 } ], "source": [ "#Primero crearemos los datos de capacitación y prueba\n", "\n", "# Training data\n", "train = [\n", " ('The application crashes when I try to open it.', 'Bug'),\n", " ('I would like to request a new feature.', 'Feature Request'),\n", " ('How do I reset my password?', 'Question'),\n", " ('There is a typo on the main page.', 'Bug'),\n", " ('Could you add support for multiple languages?', 'Feature Request'),\n", " ('Where can I find the user manual?', 'Question'),\n", "]\n", "\n", "# Testing data\n", "test = [\n", " ('The app is not responding.', 'Bug'),\n", " ('I think it would be great if you could add a dark mode.', 'Feature Request'),\n", " ('What is the maximum file size I can upload?', 'Question'),\n", "]\n", "\n", "# Entrenamos el clasificador\n", "\n", "from textblob.classifiers import NaiveBayesClassifier\n", "\n", "classifier = NaiveBayesClassifier(train)\n", "\n", "# Clasificamos texto\n", "\n", "classifier.classify('The app crashes when I try to upload a file.')" ] }, { "cell_type": "code", "execution_count": null, "id": "7fb538dfdb84eb1e", "metadata": { "ExecuteTime": { "end_time": "2024-01-24T12:01:45.806246Z", "start_time": "2024-01-24T12:01:44.231080Z" }, "id": "7fb538dfdb84eb1e", "colab": { "base_uri": "https://localhost:8080/" }, "outputId": "a63bfb70-14c1-480e-ac69-feb2e79bdfb2" }, "outputs": [ { "output_type": "execute_result", "data": { "text/plain": [ "1.0" ] }, "metadata": {}, "execution_count": 18 } ], "source": [ "classifier.accuracy(test)" ] }, { "cell_type": "markdown", "id": "ed611a019c31f00c", "metadata": { "collapsed": false, "id": "ed611a019c31f00c" }, "source": [ "# Conclusiones\n", "\n", "En esta práctica, hemos visto cómo el texto previo al proceso y cómo representarlo en un formato que la computadora pueda entender.Además, hemos visto cómo usar algunas de las características de TextBlob y librerías relacionadas.\n", "\n", "TextBlob, sin embargo, se basa en NLTK, una librería que se basa en reglas y, como hemos visto en teoría, estas librerías no siempre funcionan bien. Por lo tanto, en la siguiente práctica veremos cómo usar herramientas basadas en redes neuronales para preprocesar y clasificarlo." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.6" }, "colab": { "provenance": [] } }, "nbformat": 4, "nbformat_minor": 5 }