{ "cells": [ { "cell_type": "markdown", "id": "69988c40-42d4-49e3-b539-4e1458f92a93", "metadata": {}, "source": [ "# Clasificación de textos con deep learning" ] }, { "cell_type": "code", "execution_count": 1, "id": "e038198f-51e3-487a-b787-d1f583d8925e", "metadata": { "tags": [] }, "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", "import warnings\n", "warnings.filterwarnings(\"ignore\")" ] }, { "cell_type": "code", "execution_count": 2, "id": "858b9278-4539-47a1-aa08-09e3fc26ac48", "metadata": { "tags": [] }, "outputs": [], "source": [ "df = pd.read_csv('spam.csv', encoding = \"ISO-8859-1\")" ] }, { "cell_type": "code", "execution_count": 3, "id": "68ec7038-0dea-4beb-b90d-a0ace9d11492", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
v1v2Unnamed: 2Unnamed: 3Unnamed: 4
0hamGo until jurong point, crazy.. Available only ...NaNNaNNaN
1hamOk lar... Joking wif u oni...NaNNaNNaN
2spamFree entry in 2 a wkly comp to win FA Cup fina...NaNNaNNaN
3hamU dun say so early hor... U c already then say...NaNNaNNaN
4hamNah I don't think he goes to usf, he lives aro...NaNNaNNaN
..................
5567spamThis is the 2nd time we have tried 2 contact u...NaNNaNNaN
5568hamWill Ì_ b going to esplanade fr home?NaNNaNNaN
5569hamPity, * was in mood for that. So...any other s...NaNNaNNaN
5570hamThe guy did some bitching but I acted like i'd...NaNNaNNaN
5571hamRofl. Its true to its nameNaNNaNNaN
\n", "

5572 rows × 5 columns

\n", "
" ], "text/plain": [ " v1 v2 Unnamed: 2 \\\n", "0 ham Go until jurong point, crazy.. Available only ... NaN \n", "1 ham Ok lar... Joking wif u oni... NaN \n", "2 spam Free entry in 2 a wkly comp to win FA Cup fina... NaN \n", "3 ham U dun say so early hor... U c already then say... NaN \n", "4 ham Nah I don't think he goes to usf, he lives aro... NaN \n", "... ... ... ... \n", "5567 spam This is the 2nd time we have tried 2 contact u... NaN \n", "5568 ham Will Ì_ b going to esplanade fr home? NaN \n", "5569 ham Pity, * was in mood for that. So...any other s... NaN \n", "5570 ham The guy did some bitching but I acted like i'd... NaN \n", "5571 ham Rofl. Its true to its name NaN \n", "\n", " Unnamed: 3 Unnamed: 4 \n", "0 NaN NaN \n", "1 NaN NaN \n", "2 NaN NaN \n", "3 NaN NaN \n", "4 NaN NaN \n", "... ... ... \n", "5567 NaN NaN \n", "5568 NaN NaN \n", "5569 NaN NaN \n", "5570 NaN NaN \n", "5571 NaN NaN \n", "\n", "[5572 rows x 5 columns]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df" ] }, { "cell_type": "markdown", "id": "60c38961-a84a-463f-824a-aaa1416ff260", "metadata": {}, "source": [ "Borramos columnas innecesarias" ] }, { "cell_type": "code", "execution_count": 4, "id": "82ed545a-0e0f-481b-b48f-78a21eb1b9a8", "metadata": {}, "outputs": [], "source": [ "df = df.iloc [:,0:2]" ] }, { "cell_type": "code", "execution_count": 5, "id": "4efe99c6-92d8-4f27-896d-39951bbfdd8a", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
v1v2
0hamGo until jurong point, crazy.. Available only ...
1hamOk lar... Joking wif u oni...
2spamFree entry in 2 a wkly comp to win FA Cup fina...
3hamU dun say so early hor... U c already then say...
4hamNah I don't think he goes to usf, he lives aro...
\n", "
" ], "text/plain": [ " v1 v2\n", "0 ham Go until jurong point, crazy.. Available only ...\n", "1 ham Ok lar... Joking wif u oni...\n", "2 spam Free entry in 2 a wkly comp to win FA Cup fina...\n", "3 ham U dun say so early hor... U c already then say...\n", "4 ham Nah I don't think he goes to usf, he lives aro..." ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head()" ] }, { "cell_type": "code", "execution_count": 6, "id": "4d5e87d1-6e9e-4762-9a5e-b2bc13903e71", "metadata": {}, "outputs": [], "source": [ "df.columns = ['Target','Email']" ] }, { "cell_type": "code", "execution_count": 7, "id": "2181f246-94c3-4d46-991d-425c3233c01f", "metadata": {}, "outputs": [], "source": [ "from nltk.corpus import stopwords\n", "from nltk import *\n", "from sklearn.feature_extraction.text import TfidfVectorizer\n", "from nltk.stem import WordNetLemmatizer\n", "import matplotlib.pyplot as plt\n", "from sklearn.model_selection import train_test_split" ] }, { "cell_type": "markdown", "id": "466d6e33-4d60-408c-9d42-31e2e94e6b86", "metadata": {}, "source": [ "Eliminamos stoprwords" ] }, { "cell_type": "code", "execution_count": 8, "id": "49a3a84c-8fe1-4187-8a6c-19ae88973b8a", "metadata": {}, "outputs": [], "source": [ "stop = stopwords.words('english')\n", "df['Email'] = df['Email'].apply(lambda x: \" \".join(x for x in x.split() if x not in stop))" ] }, { "cell_type": "code", "execution_count": 9, "id": "6659ca0c-30ea-48ef-a736-69d2f434ee79", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
TargetEmail
0hamGo jurong point, crazy.. Available bugis n gre...
1hamOk lar... Joking wif u oni...
2spamFree entry 2 wkly comp win FA Cup final tkts 2...
3hamU dun say early hor... U c already say...
4hamNah I think goes usf, lives around though
.........
5567spamThis 2nd time tried 2 contact u. U å£750 Pound...
5568hamWill Ì_ b going esplanade fr home?
5569hamPity, * mood that. So...any suggestions?
5570hamThe guy bitching I acted like i'd interested b...
5571hamRofl. Its true name
\n", "

5572 rows × 2 columns

\n", "
" ], "text/plain": [ " Target Email\n", "0 ham Go jurong point, crazy.. Available bugis n gre...\n", "1 ham Ok lar... Joking wif u oni...\n", "2 spam Free entry 2 wkly comp win FA Cup final tkts 2...\n", "3 ham U dun say early hor... U c already say...\n", "4 ham Nah I think goes usf, lives around though\n", "... ... ...\n", "5567 spam This 2nd time tried 2 contact u. U å£750 Pound...\n", "5568 ham Will Ì_ b going esplanade fr home?\n", "5569 ham Pity, * mood that. So...any suggestions?\n", "5570 ham The guy bitching I acted like i'd interested b...\n", "5571 ham Rofl. Its true name\n", "\n", "[5572 rows x 2 columns]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df" ] }, { "cell_type": "markdown", "id": "64d4bd65-e54e-4b68-814d-5014aeb1d1ba", "metadata": {}, "source": [ "Eliminar símbolos puntuación..." ] }, { "cell_type": "code", "execution_count": 10, "id": "d3ae4a7d-a104-4685-9dca-366805ff7be7", "metadata": {}, "outputs": [], "source": [ "df['Email'] = df['Email'].apply(lambda x: re.sub('[!@#$:).;,?&]',' ', x.lower()))" ] }, { "cell_type": "code", "execution_count": 11, "id": "07d61f4f-c20e-4bfa-9fcf-393f16313446", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
TargetEmail
0hamgo jurong point crazy available bugis n gre...
1hamok lar joking wif u oni
2spamfree entry 2 wkly comp win fa cup final tkts 2...
3hamu dun say early hor u c already say
4hamnah i think goes usf lives around though
.........
5567spamthis 2nd time tried 2 contact u u å£750 pound...
5568hamwill ì_ b going esplanade fr home
5569hampity * mood that so any suggestions
5570hamthe guy bitching i acted like i'd interested b...
5571hamrofl its true name
\n", "

5572 rows × 2 columns

\n", "
" ], "text/plain": [ " Target Email\n", "0 ham go jurong point crazy available bugis n gre...\n", "1 ham ok lar joking wif u oni \n", "2 spam free entry 2 wkly comp win fa cup final tkts 2...\n", "3 ham u dun say early hor u c already say \n", "4 ham nah i think goes usf lives around though\n", "... ... ...\n", "5567 spam this 2nd time tried 2 contact u u å£750 pound...\n", "5568 ham will ì_ b going esplanade fr home \n", "5569 ham pity * mood that so any suggestions \n", "5570 ham the guy bitching i acted like i'd interested b...\n", "5571 ham rofl its true name\n", "\n", "[5572 rows x 2 columns]" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df" ] }, { "cell_type": "code", "execution_count": 12, "id": "1026e418-7700-4e01-a8b8-6befa3663521", "metadata": {}, "outputs": [], "source": [ "df['Email'] = df['Email'].apply(lambda x: re.sub('[áéíóúå]','', x))" ] }, { "cell_type": "code", "execution_count": 13, "id": "418f4d96-685e-4094-a0ec-bf87437778ff", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
TargetEmail
0hamgo jurong point crazy available bugis n gre...
1hamok lar joking wif u oni
2spamfree entry 2 wkly comp win fa cup final tkts 2...
3hamu dun say early hor u c already say
4hamnah i think goes usf lives around though
.........
5567spamthis 2nd time tried 2 contact u u £750 pound ...
5568hamwill ì_ b going esplanade fr home
5569hampity * mood that so any suggestions
5570hamthe guy bitching i acted like i'd interested b...
5571hamrofl its true name
\n", "

5572 rows × 2 columns

\n", "
" ], "text/plain": [ " Target Email\n", "0 ham go jurong point crazy available bugis n gre...\n", "1 ham ok lar joking wif u oni \n", "2 spam free entry 2 wkly comp win fa cup final tkts 2...\n", "3 ham u dun say early hor u c already say \n", "4 ham nah i think goes usf lives around though\n", "... ... ...\n", "5567 spam this 2nd time tried 2 contact u u £750 pound ...\n", "5568 ham will ì_ b going esplanade fr home \n", "5569 ham pity * mood that so any suggestions \n", "5570 ham the guy bitching i acted like i'd interested b...\n", "5571 ham rofl its true name\n", "\n", "[5572 rows x 2 columns]" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df" ] }, { "cell_type": "markdown", "id": "b83108c3-cd46-41c7-86f8-8af524595f56", "metadata": {}, "source": [ "Separamos los datos de la variable clase" ] }, { "cell_type": "code", "execution_count": 14, "id": "614d6cff-d1f2-42ee-90cc-bff7ecac87a3", "metadata": {}, "outputs": [], "source": [ "df2=df[['Email', 'Target']]" ] }, { "cell_type": "markdown", "id": "434869e0-bcd3-41bf-ad0b-9bf0d82cc5e4", "metadata": {}, "source": [ "Dividimos los datos en train y test en una proporción de 80:20" ] }, { "cell_type": "code", "execution_count": 15, "id": "b14d96d9-b25c-4bad-b89d-ddf91bc3d3a4", "metadata": {}, "outputs": [], "source": [ "train, test = train_test_split(df2, test_size=0.2)\n", "# Define the sequence lengths, max number of words and embedding dimensions\n", "# Sequence length of each sentence. If more, truncate. If less, pad with zeros" ] }, { "cell_type": "markdown", "id": "9ac9ef3d-aa2a-4111-a9aa-f5b4dee768ed", "metadata": {}, "source": [ "Definimos las variables longuitud máxima de la sentencia y las n palabras más frecuentes" ] }, { "cell_type": "code", "execution_count": 16, "id": "9e6c9321-e433-4d87-83fd-fb4c08d3e57b", "metadata": {}, "outputs": [], "source": [ "long_max_sentencia = 300\n", "num_palabras = 20000" ] }, { "cell_type": "markdown", "id": "703bfe28-f46b-497a-835a-4670363ff79f", "metadata": {}, "source": [ "Keras nos permite usar Redes Neuronales con datos de texto.\n", "Para ello necesitamos que los datos de entrada, esteń codificados, de manera que cada palabra esté representada como un número entero único." ] }, { "cell_type": "code", "execution_count": 17, "id": "8e9dc00a-804d-423b-a3dc-3b68db0b1081", "metadata": {}, "outputs": [], "source": [ "from keras.preprocessing.text import Tokenizer\n", "\n", "# Tokenizamos las 20000 palabras más frecuentes\n", "tokenizer = Tokenizer(num_palabras)\n", "\n", "# Creamos un índice de vocabulario basado en la frecuencia de las palabras\n", "tokenizer.fit_on_texts(train.Email)\n", "\n", "# Transformamos cada texto en los textos en una secuencia de números.\n", "# Básicamente cogemos cada palabra y la sustitímos por el valor entero\n", "# generado en fit_on_texts\n", "train_sequences = tokenizer.texts_to_sequences(train.Email)\n", "test_sequences = tokenizer.texts_to_sequences(test.Email)" ] }, { "cell_type": "code", "execution_count": 18, "id": "73bc2a85-add8-454b-8d4b-f4f296bacd03", "metadata": { "scrolled": true, "tags": [] }, "outputs": [ { "data": { "text/plain": [ "{1: 'i',\n", " 2: 'u',\n", " 3: 'call',\n", " 4: '2',\n", " 5: 'you',\n", " 6: 'get',\n", " 7: \"i'm\",\n", " 8: 'ur',\n", " 9: '4',\n", " 10: 'lt',\n", " 11: 'gt',\n", " 12: 'now',\n", " 13: 'free',\n", " 14: 'ok',\n", " 15: 'go',\n", " 16: 'know',\n", " 17: 'it',\n", " 18: 'like',\n", " 19: 'got',\n", " 20: 'good',\n", " 21: 'me',\n", " 22: 'no',\n", " 23: 'come',\n", " 24: 'day',\n", " 25: 'time',\n", " 26: 'love',\n", " 27: 'text',\n", " 28: 'want',\n", " 29: 'send',\n", " 30: 'txt',\n", " 31: 'going',\n", " 32: 'still',\n", " 33: 'one',\n", " 34: 'n',\n", " 35: 'home',\n", " 36: 'do',\n", " 37: 'so',\n", " 38: 'lor',\n", " 39: 'da',\n", " 40: 'stop',\n", " 41: 'r',\n", " 42: 'need',\n", " 43: \"i'll\",\n", " 44: 'sorry',\n", " 45: 'back',\n", " 46: 'but',\n", " 47: 'today',\n", " 48: 'how',\n", " 49: 'if',\n", " 50: 'see',\n", " 51: 'pls',\n", " 52: 'my',\n", " 53: 'reply',\n", " 54: 'k',\n", " 55: 'new',\n", " 56: 'mobile',\n", " 57: 'dont',\n", " 58: 'tell',\n", " 59: 'the',\n", " 60: 'take',\n", " 61: 'we',\n", " 62: 'hi',\n", " 63: 'later',\n", " 64: 'please',\n", " 65: 'what',\n", " 66: 'phone',\n", " 67: 'think',\n", " 68: 'ì',\n", " 69: 'just',\n", " 70: 'your',\n", " 71: 'msg',\n", " 72: 'and',\n", " 73: '1',\n", " 74: 'this',\n", " 75: 'night',\n", " 76: 'hey',\n", " 77: 'great',\n", " 78: 'claim',\n", " 79: 'can',\n", " 80: 'hope',\n", " 81: 'a',\n", " 82: 'dear',\n", " 83: 'much',\n", " 84: 'give',\n", " 85: 'week',\n", " 86: 'is',\n", " 87: 'well',\n", " 88: 'oh',\n", " 89: 'way',\n", " 90: 'happy',\n", " 91: 'make',\n", " 92: 'yes',\n", " 93: 'in',\n", " 94: 'to',\n", " 95: 'wat',\n", " 96: 'c',\n", " 97: 'work',\n", " 98: 'message',\n", " 99: 'www',\n", " 100: 'its',\n", " 101: 'ask',\n", " 102: 'have',\n", " 103: 'not',\n", " 104: 'number',\n", " 105: 'right',\n", " 106: 'said',\n", " 107: 'prize',\n", " 108: 'that',\n", " 109: 'say',\n", " 110: 'there',\n", " 111: 'are',\n", " 112: 'then',\n", " 113: 'yeah',\n", " 114: 'tomorrow',\n", " 115: 'find',\n", " 116: 'e',\n", " 117: 'life',\n", " 118: 'meet',\n", " 119: 'cash',\n", " 120: 'already',\n", " 121: 'amp',\n", " 122: 'really',\n", " 123: 'im',\n", " 124: 'win',\n", " 125: '3',\n", " 126: 'would',\n", " 127: 'only',\n", " 128: 'morning',\n", " 129: 'pick',\n", " 130: 'miss',\n", " 131: 'let',\n", " 132: 'lol',\n", " 133: '150p',\n", " 134: 'nokia',\n", " 135: 'sent',\n", " 136: 'thanks',\n", " 137: 't',\n", " 138: 'buy',\n", " 139: 'he',\n", " 140: 'every',\n", " 141: 'last',\n", " 142: 'us',\n", " 143: 'cos',\n", " 144: 'b',\n", " 145: 'anything',\n", " 146: 'urgent',\n", " 147: 'sure',\n", " 148: 'contact',\n", " 149: 'also',\n", " 150: 'went',\n", " 151: 'nice',\n", " 152: 'com',\n", " 153: '5',\n", " 154: 'min',\n", " 155: 'babe',\n", " 156: 'place',\n", " 157: 'keep',\n", " 158: 'up',\n", " 159: 'first',\n", " 160: 'uk',\n", " 161: 'out',\n", " 162: '50',\n", " 163: 'care',\n", " 164: 'something',\n", " 165: 'wait',\n", " 166: 'next',\n", " 167: 'even',\n", " 168: 'chat',\n", " 169: 'per',\n", " 170: 'tonight',\n", " 171: 'cant',\n", " 172: 'around',\n", " 173: 'service',\n", " 174: 'tone',\n", " 175: 'someone',\n", " 176: 'sleep',\n", " 177: 'she',\n", " 178: 'coming',\n", " 179: 'will',\n", " 180: 'money',\n", " 181: 'thing',\n", " 182: 'all',\n", " 183: 'things',\n", " 184: \"can't\",\n", " 185: 'could',\n", " 186: 'when',\n", " 187: 'ya',\n", " 188: 'leave',\n", " 189: 'late',\n", " 190: 'gud',\n", " 191: 'co',\n", " 192: 'where',\n", " 193: 'gonna',\n", " 194: 'v',\n", " 195: \"i've\",\n", " 196: 'yet',\n", " 197: 'for',\n", " 198: 'always',\n", " 199: 'wan',\n", " 200: '18',\n", " 201: 'wish',\n", " 202: 'dun',\n", " 203: 'feel',\n", " 204: 'sms',\n", " 205: 'help',\n", " 206: 'x',\n", " 207: 'customer',\n", " 208: 's',\n", " 209: 'soon',\n", " 210: 'did',\n", " 211: 'year',\n", " 212: 'waiting',\n", " 213: '16',\n", " 214: 'special',\n", " 215: 'many',\n", " 216: 'ìï',\n", " 217: 'on',\n", " 218: 'holiday',\n", " 219: 'friend',\n", " 220: 'done',\n", " 221: 'haha',\n", " 222: '6',\n", " 223: 'try',\n", " 224: 'lunch',\n", " 225: 'live',\n", " 226: 'or',\n", " 227: 'hello',\n", " 228: 'thk',\n", " 229: 'may',\n", " 230: 'name',\n", " 231: 'getting',\n", " 232: 'stuff',\n", " 233: 'yup',\n", " 234: 'man',\n", " 235: \"that's\",\n", " 236: 'guaranteed',\n", " 237: 'thats',\n", " 238: 'people',\n", " 239: 'smile',\n", " 240: 'mins',\n", " 241: 'fine',\n", " 242: 'friends',\n", " 243: 'best',\n", " 244: 'long',\n", " 245: 'use',\n", " 246: 'draw',\n", " 247: 'bit',\n", " 248: 'thought',\n", " 249: \"it's\",\n", " 250: 'never',\n", " 251: 'here',\n", " 252: 'cs',\n", " 253: 'word',\n", " 254: 'cool',\n", " 255: 'told',\n", " 256: 'as',\n", " 257: 'heart',\n", " 258: 'car',\n", " 259: 'talk',\n", " 260: 'real',\n", " 261: 'line',\n", " 262: 'class',\n", " 263: '£1',\n", " 264: 'ill',\n", " 265: 'too',\n", " 266: 'better',\n", " 267: 'play',\n", " 268: 'at',\n", " 269: 'chance',\n", " 270: 'meeting',\n", " 271: 'account',\n", " 272: 'enjoy',\n", " 273: 'job',\n", " 274: 'receive',\n", " 275: 'yo',\n", " 276: 'house',\n", " 277: 'latest',\n", " 278: 'days',\n", " 279: 'ready',\n", " 280: 'they',\n", " 281: '7',\n", " 282: 'check',\n", " 283: 'person',\n", " 284: 'office',\n", " 285: 'dinner',\n", " 286: 'start',\n", " 287: 'big',\n", " 288: 'trying',\n", " 289: 'am',\n", " 290: '1st',\n", " 291: 'mind',\n", " 292: 'world',\n", " 293: 'lot',\n", " 294: 'nothing',\n", " 295: 'luv',\n", " 296: 'shows',\n", " 297: 'again',\n", " 298: 'problem',\n", " 299: 'wanna',\n", " 300: 'called',\n", " 301: 'bt',\n", " 302: 'girl',\n", " 303: 'lar',\n", " 304: 'finish',\n", " 305: 'sir',\n", " 306: 'birthday',\n", " 307: 'cost',\n", " 308: 'her',\n", " 309: 'actually',\n", " 310: 'was',\n", " 311: 'ah',\n", " 312: 'landline',\n", " 313: 'wk',\n", " 314: 'why',\n", " 315: 'camera',\n", " 316: 'with',\n", " 317: 'princess',\n", " 318: 'end',\n", " 319: 'dat',\n", " 320: 'liao',\n", " 321: 'might',\n", " 322: 'pa',\n", " 323: 'dis',\n", " 324: 'awarded',\n", " 325: 'plan',\n", " 326: 'box',\n", " 327: 'xxx',\n", " 328: 'tv',\n", " 329: 'guess',\n", " 330: 'god',\n", " 331: 'watch',\n", " 332: 'boy',\n", " 333: 'ever',\n", " 334: 'eat',\n", " 335: 'shopping',\n", " 336: 'shall',\n", " 337: 'quite',\n", " 338: 'orange',\n", " 339: 'jus',\n", " 340: 'video',\n", " 341: 'half',\n", " 342: '150ppm',\n", " 343: 'minutes',\n", " 344: 'baby',\n", " 345: 'from',\n", " 346: 'award',\n", " 347: 'sat',\n", " 348: 'calls',\n", " 349: 'part',\n", " 350: 'of',\n", " 351: 'room',\n", " 352: 'left',\n", " 353: 'apply',\n", " 354: 'aight',\n", " 355: \"he's\",\n", " 356: 'leh',\n", " 357: 'watching',\n", " 358: '£1000',\n", " 359: 'two',\n", " 360: 'guys',\n", " 361: 'hear',\n", " 362: 'bad',\n", " 363: 'speak',\n", " 364: 'rate',\n", " 365: 'didnt',\n", " 366: 'offer',\n", " 367: 'xmas',\n", " 368: 'pay',\n", " 369: 'po',\n", " 370: 'early',\n", " 371: 'wont',\n", " 372: 'month',\n", " 373: 'face',\n", " 374: 'afternoon',\n", " 375: 'code',\n", " 376: 'den',\n", " 377: 'remember',\n", " 378: 'reach',\n", " 379: 'decimal',\n", " 380: 'details',\n", " 381: 'important',\n", " 382: 'look',\n", " 383: 'able',\n", " 384: 'working',\n", " 385: '9',\n", " 386: 'join',\n", " 387: 'looking',\n", " 388: 'sexy',\n", " 389: 'had',\n", " 390: 'tones',\n", " 391: 'maybe',\n", " 392: 'ringtone',\n", " 393: 'selected',\n", " 394: 'another',\n", " 395: 'wife',\n", " 396: 'thanx',\n", " 397: 'must',\n", " 398: 'shit',\n", " 399: 'dunno',\n", " 400: 'though',\n", " 401: 'fun',\n", " 402: '10',\n", " 403: 'school',\n", " 404: 'probably',\n", " 405: 'weekend',\n", " 406: 'y',\n", " 407: 'asked',\n", " 408: 'easy',\n", " 409: 'network',\n", " 410: 'll',\n", " 411: 'collection',\n", " 412: 'came',\n", " 413: 'update',\n", " 414: 'bus',\n", " 415: 'bed',\n", " 416: '2nd',\n", " 417: 'havent',\n", " 418: 'little',\n", " 419: 'juz',\n", " 420: 'missed',\n", " 421: 'dad',\n", " 422: 'says',\n", " 423: 'everything',\n", " 424: 'since',\n", " 425: 'town',\n", " 426: 'mail',\n", " 427: 'net',\n", " 428: 'wot',\n", " 429: 'tmr',\n", " 430: 'collect',\n", " 431: \"don't\",\n", " 432: 'okay',\n", " 433: 'sweet',\n", " 434: 'put',\n", " 435: 'g',\n", " 436: 'any',\n", " 437: '8',\n", " 438: 'enough',\n", " 439: 'wanted',\n", " 440: 'evening',\n", " 441: 'either',\n", " 442: 'abt',\n", " 443: 'means',\n", " 444: 'bored',\n", " 445: 'colour',\n", " 446: \"''\",\n", " 447: 'making',\n", " 448: 'doing',\n", " 449: 'won',\n", " 450: 'friendship',\n", " 451: 'entry',\n", " 452: 'anyway',\n", " 453: 'be',\n", " 454: 'messages',\n", " 455: 'de',\n", " 456: 'over',\n", " 457: 'made',\n", " 458: 'lei',\n", " 459: 'book',\n", " 460: 'address',\n", " 461: '£100',\n", " 462: 'weekly',\n", " 463: 'music',\n", " 464: 'makes',\n", " 465: '000',\n", " 466: 'kiss',\n", " 467: 'd',\n", " 468: 'away',\n", " 469: 'true',\n", " 470: 'guy',\n", " 471: 'oso',\n", " 472: \"how's\",\n", " 473: 'todays',\n", " 474: 'nite',\n", " 475: 'top',\n", " 476: 'plus',\n", " 477: 'mob',\n", " 478: 'years',\n", " 479: 'ard',\n", " 480: 'food',\n", " 481: 'plz',\n", " 482: 'bring',\n", " 483: \"there's\",\n", " 484: 'hav',\n", " 485: 'words',\n", " 486: 'else',\n", " 487: 'our',\n", " 488: 'valid',\n", " 489: 'times',\n", " 490: '500',\n", " 491: 'alright',\n", " 492: 'stay',\n", " 493: \"what's\",\n", " 494: 'pain',\n", " 495: 'fuck',\n", " 496: 'national',\n", " 497: 'driving',\n", " 498: 'wid',\n", " 499: 'tot',\n", " 500: 'without',\n", " 501: 'sleeping',\n", " 502: 'happen',\n", " 503: 'till',\n", " 504: 'wif',\n", " 505: 'hour',\n", " 506: 'huh',\n", " 507: 'id',\n", " 508: 'available',\n", " 509: 'hair',\n", " 510: 'him',\n", " 511: 'full',\n", " 512: 'story',\n", " 513: 'took',\n", " 514: 'haf',\n", " 515: 'game',\n", " 516: 'yesterday',\n", " 517: 'saw',\n", " 518: \"we're\",\n", " 519: 'thank',\n", " 520: 'show',\n", " 521: 'double',\n", " 522: 'coz',\n", " 523: 'wen',\n", " 524: 'comes',\n", " 525: 'minute',\n", " 526: 'delivery',\n", " 527: 'hot',\n", " 528: 'texts',\n", " 529: '10p',\n", " 530: 'sae',\n", " 531: 'dude',\n", " 532: 'busy',\n", " 533: 'mean',\n", " 534: 'tried',\n", " 535: 'chikku',\n", " 536: 'charge',\n", " 537: 'eve',\n", " 538: 'games',\n", " 539: 'hurt',\n", " 540: 'after',\n", " 541: 'lose',\n", " 542: 'run',\n", " 543: 'gift',\n", " 544: 'row',\n", " 545: 'thinking',\n", " 546: 'wake',\n", " 547: 'worry',\n", " 548: 'online',\n", " 549: 'movie',\n", " 550: 'test',\n", " 551: \"we'll\",\n", " 552: 'order',\n", " 553: 'leaving',\n", " 554: 'post',\n", " 555: 'aft',\n", " 556: 'ring',\n", " 557: 'price',\n", " 558: 'missing',\n", " 559: 'shop',\n", " 560: 'await',\n", " 561: 'pm',\n", " 562: 'trip',\n", " 563: 'feeling',\n", " 564: '£5000',\n", " 565: 'email',\n", " 566: '86688',\n", " 567: 'answer',\n", " 568: 'points',\n", " 569: 'change',\n", " 570: 'lucky',\n", " 571: 'unsubscribe',\n", " 572: 'hours',\n", " 573: 'family',\n", " 574: 'beautiful',\n", " 575: 'club',\n", " 576: 'forgot',\n", " 577: 'attempt',\n", " 578: 'forget',\n", " 579: 'more',\n", " 580: 'together',\n", " 581: 'set',\n", " 582: 'whats',\n", " 583: 'til',\n", " 584: 'angry',\n", " 585: 'goin',\n", " 586: 'smiling',\n", " 587: 'congrats',\n", " 588: 'should',\n", " 589: 'calling',\n", " 590: 'gd',\n", " 591: 'nt',\n", " 592: 'dating',\n", " 593: 'xx',\n", " 594: 'wil',\n", " 595: 'drive',\n", " 596: 'final',\n", " 597: 'believe',\n", " 598: 'off',\n", " 599: 'voucher',\n", " 600: 'everyone',\n", " 601: 'search',\n", " 602: 'land',\n", " 603: 'mine',\n", " 604: 'walk',\n", " 605: '£500',\n", " 606: '11',\n", " 607: 'pounds',\n", " 608: 'gr8',\n", " 609: 'neva',\n", " 610: 'treat',\n", " 611: 'found',\n", " 612: 'date',\n", " 613: 'pics',\n", " 614: 'lesson',\n", " 615: 'sounds',\n", " 616: '8007',\n", " 617: 'opt',\n", " 618: 'news',\n", " 619: 'msgs',\n", " 620: 'private',\n", " 621: 'started',\n", " 622: 'taking',\n", " 623: 'oredi',\n", " 624: 'fri',\n", " 625: 'question',\n", " 626: \"c's\",\n", " 627: 'second',\n", " 628: 'drop',\n", " 629: 'fone',\n", " 630: 'pub',\n", " 631: 'auction',\n", " 632: 'cause',\n", " 633: 'hit',\n", " 634: 'college',\n", " 635: '750',\n", " 636: 'project',\n", " 637: 'noe',\n", " 638: 'vouchers',\n", " 639: 'sad',\n", " 640: 'sch',\n", " 641: 'sun',\n", " 642: 'm',\n", " 643: 'poly',\n", " 644: 'card',\n", " 645: 'hard',\n", " 646: 'old',\n", " 647: 'mum',\n", " 648: 'quiz',\n", " 649: 'decided',\n", " 650: 'cum',\n", " 651: 'drink',\n", " 652: 'choose',\n", " 653: 'lots',\n", " 654: 'close',\n", " 655: 'blue',\n", " 656: 'company',\n", " 657: '100',\n", " 658: 'prob',\n", " 659: 'head',\n", " 660: 'sister',\n", " 661: 'goes',\n", " 662: 'tho',\n", " 663: 'suite342',\n", " 664: '2lands',\n", " 665: 'okie',\n", " 666: 'statement',\n", " 667: 'bonus',\n", " 668: 'expires',\n", " 669: 'rite',\n", " 670: 'darlin',\n", " 671: 'mate',\n", " 672: 'mah',\n", " 673: 'visit',\n", " 674: 'gone',\n", " 675: 'tomo',\n", " 676: 'http',\n", " 677: 'alone',\n", " 678: '£2000',\n", " 679: '12hrs',\n", " 680: 'pobox',\n", " 681: 'awesome',\n", " 682: 'used',\n", " 683: 'far',\n", " 684: 'crazy',\n", " 685: 'ltd',\n", " 686: 'anytime',\n", " 687: 'camcorder',\n", " 688: '08000930705',\n", " 689: 'boytoy',\n", " 690: 'secret',\n", " 691: 'park',\n", " 692: '30',\n", " 693: 'frnds',\n", " 694: 'goodmorning',\n", " 695: 'meant',\n", " 696: 'frm',\n", " 697: 'course',\n", " 698: 'player',\n", " 699: 'dreams',\n", " 700: 'whatever',\n", " 701: 'credit',\n", " 702: 'finished',\n", " 703: 'congratulations',\n", " 704: 'lets',\n", " 705: '£350',\n", " 706: 'f',\n", " 707: 'frnd',\n", " 708: 'reason',\n", " 709: 'anyone',\n", " 710: 'unlimited',\n", " 711: '08000839402',\n", " 712: 'tc',\n", " 713: 'light',\n", " 714: 'telling',\n", " 715: 'saying',\n", " 716: 'sunday',\n", " 717: 'knw',\n", " 718: 'w',\n", " 719: 'services',\n", " 720: 'takes',\n", " 721: 'wants',\n", " 722: 'yr',\n", " 723: 'identifier',\n", " 724: 'yours',\n", " 725: 'mates',\n", " 726: 'earlier',\n", " 727: 'needs',\n", " 728: 'open',\n", " 729: 'chennai',\n", " 730: 'log',\n", " 731: 'surprise',\n", " 732: 'fucking',\n", " 733: 'lovely',\n", " 734: 'worth',\n", " 735: 'saturday',\n", " 736: 'th',\n", " 737: 'info',\n", " 738: 'etc',\n", " 739: 'balance',\n", " 740: 'stupid',\n", " 741: 'operator',\n", " 742: 'break',\n", " 743: 'snow',\n", " 744: 'ni8',\n", " 745: 'brother',\n", " 746: 'happiness',\n", " 747: 'loving',\n", " 748: 'ha',\n", " 749: 'wit',\n", " 750: 'finally',\n", " 751: 'felt',\n", " 752: 'sis',\n", " 753: 'numbers',\n", " 754: 'parents',\n", " 755: 'simple',\n", " 756: 'winner',\n", " 757: 'pic',\n", " 758: 'type',\n", " 759: 'motorola',\n", " 760: 'mobileupd8',\n", " 761: 'touch',\n", " 762: 'who',\n", " 763: 'luck',\n", " 764: 'hand',\n", " 765: 'fast',\n", " 766: 'tired',\n", " 767: 'gal',\n", " 768: 'currently',\n", " 769: 'friday',\n", " 770: 'download',\n", " 771: 'age',\n", " 772: 'pass',\n", " 773: 'least',\n", " 774: 'smth',\n", " 775: 'girls',\n", " 776: 'fr',\n", " 777: 'kind',\n", " 778: 'mrng',\n", " 779: 'wow',\n", " 780: 'weeks',\n", " 781: 'bank',\n", " 782: 'march',\n", " 783: 'ends',\n", " 784: 'within',\n", " 785: 'happened',\n", " 786: 'christmas',\n", " 787: 'lost',\n", " 788: 'hold',\n", " 789: 'sex',\n", " 790: 'fancy',\n", " 791: 'whole',\n", " 792: 'john',\n", " 793: 'feels',\n", " 794: 'yar',\n", " 795: 'sound',\n", " 796: 'gotta',\n", " 797: 'dnt',\n", " 798: 'case',\n", " 799: 'abiola',\n", " 800: 'kate',\n", " 801: 'carlos',\n", " 802: 'understand',\n", " 803: 'eh',\n", " 804: 'p',\n", " 805: \"'\",\n", " 806: 'knew',\n", " 807: '\\x89û',\n", " 808: 'reading',\n", " 809: 'b4',\n", " 810: 'ten',\n", " 811: 'direct',\n", " 812: 'mobiles',\n", " 813: 'before',\n", " 814: 'valued',\n", " 815: 'read',\n", " 816: 'pretty',\n", " 817: 'cut',\n", " 818: 'comin',\n", " 819: 'hmm',\n", " 820: 'entered',\n", " 821: 'by',\n", " 822: 'invited',\n", " 823: 'w1j6hl',\n", " 824: 'sea',\n", " 825: 'side',\n", " 826: 'ago',\n", " 827: 'police',\n", " 828: 'txts',\n", " 829: 'rs',\n", " 830: 'picking',\n", " 831: 'bslvyl',\n", " 832: 'via',\n", " 833: 'ex',\n", " 834: 'which',\n", " 835: 'mayb',\n", " 836: 'wkly',\n", " 837: 'warm',\n", " 838: 'merry',\n", " 839: '£2',\n", " 840: 'bout',\n", " 841: 'does',\n", " 842: 'freemsg',\n", " 843: 'remove',\n", " 844: 'thinks',\n", " 845: 'song',\n", " 846: 'savamob',\n", " 847: 'offers',\n", " 848: '£3',\n", " 849: '2003',\n", " 850: 'enter',\n", " 851: '87066',\n", " 852: 'complimentary',\n", " 853: '£10',\n", " 854: 'once',\n", " 855: 'sending',\n", " 856: '800',\n", " 857: 'un',\n", " 858: 'mu',\n", " 859: 'rates',\n", " 860: 'leaves',\n", " 861: 'tonite',\n", " 862: '0800',\n", " 863: 'ipod',\n", " 864: \"i'd\",\n", " 865: 'father',\n", " 866: 'nyt',\n", " 867: 'swing',\n", " 868: 'usf',\n", " 869: 'match',\n", " 870: 'exam',\n", " 871: 'bath',\n", " 872: 'gn',\n", " 873: 'ge',\n", " 874: 'same',\n", " 875: 'correct',\n", " 876: 'wonderful',\n", " 877: 'gas',\n", " 878: 'gym',\n", " 879: 'extra',\n", " 880: 'heard',\n", " 881: 'hmmm',\n", " 882: '20',\n", " 883: 'ldn',\n", " 884: 'hg',\n", " 885: 'party',\n", " 886: 'smoke',\n", " 887: 'months',\n", " 888: 'askd',\n", " 889: 'press',\n", " 890: 'them',\n", " 891: '£250',\n", " 892: 'semester',\n", " 893: 'mom',\n", " 894: 'darren',\n", " 895: 'move',\n", " 896: 'ans',\n", " 897: 'monday',\n", " 898: 'almost',\n", " 899: 'nah',\n", " 900: 'hows',\n", " 901: 'been',\n", " 902: 'information',\n", " 903: 'oops',\n", " 904: 'std',\n", " 905: 'booked',\n", " 906: 'safe',\n", " 907: 'woke',\n", " 908: 'area',\n", " 909: 'red',\n", " 910: 'computer',\n", " 911: 'terms',\n", " 912: 'txting',\n", " 913: 'yep',\n", " 914: 'knows',\n", " 915: 'wrong',\n", " 916: 'otherwise',\n", " 917: 'outside',\n", " 918: 'uncle',\n", " 919: 'die',\n", " 920: 'tickets',\n", " 921: 'listen',\n", " 922: 'reveal',\n", " 923: 'cheap',\n", " 924: '04',\n", " 925: 'store',\n", " 926: 'redeemed',\n", " 927: 'immediately',\n", " 928: 'point',\n", " 929: 'phones',\n", " 930: 'couple',\n", " 931: 'england',\n", " 932: 'ringtones',\n", " 933: 'slow',\n", " 934: 'loads',\n", " 935: 'plans',\n", " 936: 'tel',\n", " 937: 'none',\n", " 938: 'rest',\n", " 939: 'hoping',\n", " 940: 'valentines',\n", " 941: 'mm',\n", " 942: 'wishing',\n", " 943: '\\x89ûò',\n", " 944: 'dogging',\n", " 945: '2nite',\n", " 946: 'link',\n", " 947: 'wonder',\n", " 948: 'about',\n", " 949: 'deep',\n", " 950: 'very',\n", " 951: 'india',\n", " 952: 'pray',\n", " 953: 'his',\n", " 954: 'ending',\n", " 955: 'ac',\n", " 956: 'ass',\n", " 957: 'sofa',\n", " 958: 'were',\n", " 959: 'ice',\n", " 960: 'muz',\n", " 961: 'shower',\n", " 962: 'convey',\n", " 963: 'questions',\n", " 964: 'sony',\n", " 965: 'don',\n", " 966: 'il',\n", " 967: 'street',\n", " 968: 'hee',\n", " 969: 'somebody',\n", " 970: 'rock',\n", " 971: 'write',\n", " 972: 'paper',\n", " 973: 'doin',\n", " 974: 'comuk',\n", " 975: 'less',\n", " 976: 'del',\n", " 977: 'call2optout',\n", " 978: 'welcome',\n", " 979: 'seen',\n", " 980: 'xy',\n", " 981: 'wap',\n", " 982: 'jay',\n", " 983: 'content',\n", " 984: 'supposed',\n", " 985: 'difficult',\n", " 986: 'moment',\n", " 987: 'film',\n", " 988: 'studying',\n", " 989: 'lazy',\n", " 990: 'voice',\n", " 991: 'asking',\n", " 992: 'din',\n", " 993: 'starts',\n", " 994: 'fantastic',\n", " 995: 'awaiting',\n", " 996: 'pete',\n", " 997: 'bill',\n", " 998: 'glad',\n", " 999: 'medical',\n", " 1000: 'comp',\n", " ...}" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tokenizer.index_word " ] }, { "cell_type": "code", "execution_count": 19, "id": "bf186840-023d-4dd4-ae49-303451f4a363", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[[7, 45, 1403, 16, 279],\n", " [46, 1216, 1085, 374],\n", " [619,\n", " 41,\n", " 25,\n", " 772,\n", " 280,\n", " 2545,\n", " 109,\n", " 1,\n", " 545,\n", " 2,\n", " 105,\n", " 149,\n", " 447,\n", " 2,\n", " 67,\n", " 773,\n", " 9,\n", " 986,\n", " 590,\n", " 591,\n", " 1217,\n", " 2546,\n", " 2547],\n", " [3855, 508],\n", " [113, 1404]]" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "train_sequences [0:5]" ] }, { "cell_type": "code", "execution_count": 20, "id": "8c052a25-3063-4873-81c5-a47ab346c76f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Tenemos 7928 tokens únicos.\n" ] } ], "source": [ "# Creamos un diccionario que contenga las palabras y su índice (el opuesto a index_word)\n", "word_index = tokenizer.word_index\n", "print('Tenemos %s tokens únicos.' % len(word_index))" ] }, { "cell_type": "code", "execution_count": 21, "id": "fe133f28-89eb-4ffb-901c-434d3f886de4", "metadata": {}, "outputs": [], "source": [ "from tensorflow.keras.preprocessing.sequence import pad_sequences\n", "\n", "# con pad_sequences conseguimos que todas las secuencias de datos tengan la misma longuitud\n", "train_data = pad_sequences(train_sequences, maxlen=long_max_sentencia)\n", "test_data = pad_sequences(test_sequences, maxlen=long_max_sentencia)" ] }, { "cell_type": "code", "execution_count": 22, "id": "279d712b-0316-4437-873d-b6705d4d0536", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(4457, 300)\n", "(1115, 300)\n" ] } ], "source": [ "print(train_data.shape)\n", "print(test_data.shape)" ] }, { "cell_type": "code", "execution_count": 23, "id": "8e413ab7-515f-4786-b811-1968485ea5bd", "metadata": {}, "outputs": [], "source": [ "train_labels = train['Target']\n", "test_labels = test['Target']" ] }, { "cell_type": "code", "execution_count": 206, "id": "e6a40a79-402a-4d4c-aa44-55119164df56", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5363 ham\n", "3347 ham\n", "5086 ham\n", "763 ham\n", "1555 ham\n", "Name: Target, dtype: object" ] }, "execution_count": 206, "metadata": {}, "output_type": "execute_result" } ], "source": [ "train_labels.head()" ] }, { "cell_type": "code", "execution_count": 24, "id": "5e526e2f-8c83-46b8-96d2-7813fd6e7566", "metadata": {}, "outputs": [], "source": [ "from sklearn.preprocessing import LabelEncoder" ] }, { "cell_type": "markdown", "id": "65adde90-6511-4e82-bfd2-0943bfdd00c9", "metadata": {}, "source": [ "Convertimos la matriz de caracteres en un matriz numérica. Asignamos los niveles a etiquetas únicas. (Similar a OneHot Encoding)" ] }, { "cell_type": "code", "execution_count": 25, "id": "b611f7c3-b1dd-4fcb-a5f6-f708faa73263", "metadata": {}, "outputs": [], "source": [ "le = LabelEncoder()\n", "le.fit(train_labels)\n", "train_labels = le.transform(train_labels)\n", "test_labels = le.transform(test_labels)" ] }, { "cell_type": "code", "execution_count": 26, "id": "d7f68673-5fec-4602-993d-a45881958e6e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['ham' 'spam']\n", "(array([0, 1]), array([3842, 615]))\n", "(array([0, 1]), array([983, 132]))\n" ] } ], "source": [ "print(le.classes_)\n", "print(np.unique(train_labels, return_counts=True))\n", "print(np.unique(test_labels, return_counts=True))" ] }, { "cell_type": "markdown", "id": "507c2847-027f-4559-a77a-d9350c4c9129", "metadata": {}, "source": [ "Convertimos los vectores train_labels y test_labels en una matriz binaria" ] }, { "cell_type": "code", "execution_count": 27, "id": "e2c6c3c7-6d86-496c-8b77-2019fad45ec0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Dimensiones del tensor con los datos de entrenamiento: (4457, 300)\n", "Dimensiones del tensor con las etiquetas de entrenamiento: (4457, 2)\n", "Dimensiones del tensor con los datos de test: (1115, 300)\n", "Dimensiones del tensor con las etiquetas de test: (1115, 2)\n" ] } ], "source": [ "from tensorflow.keras.utils import to_categorical\n", "\n", "labels_train = to_categorical(np.asarray(train_labels))\n", "labels_test = to_categorical(np.asarray(test_labels))\n", "print('Dimensiones del tensor con los datos de entrenamiento:', train_data.shape)\n", "print('Dimensiones del tensor con las etiquetas de entrenamiento:', labels_train.shape)\n", "print('Dimensiones del tensor con los datos de test:', test_data.shape)\n", "print('Dimensiones del tensor con las etiquetas de test:', labels_test.shape)" ] }, { "cell_type": "code", "execution_count": 28, "id": "8e8fe210-b33c-42d7-973c-bb40a7e8d31c", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 0, 0, ..., 1403, 16, 279],\n", " [ 0, 0, 0, ..., 1216, 1085, 374],\n", " [ 0, 0, 0, ..., 1217, 2546, 2547],\n", " ...,\n", " [ 0, 0, 0, ..., 102, 3857, 3858],\n", " [ 0, 0, 0, ..., 25, 2548, 2549],\n", " [ 0, 0, 0, ..., 375, 2550, 668]], dtype=int32)" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "train_data[0:10]" ] }, { "cell_type": "code", "execution_count": 29, "id": "7fc979ab-7852-4e1c-b3d8-80c5241b5ad8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1., 0.],\n", " [1., 0.],\n", " [1., 0.],\n", " ...,\n", " [1., 0.],\n", " [1., 0.],\n", " [1., 0.]], dtype=float32)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "labels_train" ] }, { "cell_type": "code", "execution_count": 30, "id": "e4836523-879d-41de-adb1-8ceafcf79a48", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 0, 0, ..., 28, 23, 1070],\n", " [ 0, 0, 0, ..., 3, 63, 270],\n", " [ 0, 0, 0, ..., 199, 765, 33],\n", " ...,\n", " [ 0, 0, 0, ..., 494, 50, 432],\n", " [ 0, 0, 0, ..., 1523, 118, 801],\n", " [ 0, 0, 0, ..., 97, 196, 164]], dtype=int32)" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "test_data[0:10]" ] }, { "cell_type": "code", "execution_count": 31, "id": "37e1b192-73c2-48cf-ab10-ea8234395a05", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1., 0.],\n", " [1., 0.],\n", " [1., 0.],\n", " ...,\n", " [0., 1.],\n", " [0., 1.],\n", " [1., 0.]], dtype=float32)" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "labels_test" ] }, { "cell_type": "markdown", "id": "836157d5-2438-4623-a746-a11c5d25a11c", "metadata": {}, "source": [ "Podemos entrenar un modelo en Keras para que acepte texto codificado como lo hemos hecho, a través de una capa **Embedding** (incrustación).\n", "Se trata de una capa flexible que puede utilizarse de diversas maneras:\n", "\n", "* Se puede utilizar sola para aprender una incrustación de palabras que se puede guardar y utilizar en otro modelo más adelante.\n", "* Puede utilizarse como parte de un modelo de aprendizaje profundo en el que la incrustación se aprende junto con el propio modelo.\n", "* Puede utilizarse para cargar un modelo de incrustación de palabras preentrenado, un tipo de aprendizaje por transferencia.\n", "\n", "La capa de incrustación se define como la primera capa oculta de una red. Debe especificar 3 argumentos:\n", "\n", "* **input_dim**: Es el tamaño del vocabulario en los datos de texto. Por ejemplo, si los datos están codificados en números enteros con valores entre 0 y 10, el tamaño del vocabulario sería de 11 palabras.\n", "* **output_dim**: Es el tamaño del espacio vectorial en el que se incrustarán las palabras. Define el tamaño de los vectores de salida de esta capa para cada palabra. Por ejemplo, puede ser 32 o 100 o incluso más grande. Aquí tenemos que probar diferentes valores para resolver el problema.\n", "* **input_length**: Esta es la longitud de las secuencias de entrada. Por ejemplo, si todos los documentos de entrada están compuestos por 1000 palabras, ésto sería 1000." ] }, { "cell_type": "code", "execution_count": 32, "id": "1c3e45f9-94f5-4caa-aad4-19d9c3c2850d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "300\n" ] } ], "source": [ "tamanio_incrustacion = 100\n", "print(long_max_sentencia)" ] }, { "cell_type": "markdown", "id": "ae470293-1528-4cdb-95c6-2ea6f38ceb77", "metadata": { "tags": [] }, "source": [ "# Modelado y predicción" ] }, { "cell_type": "markdown", "id": "a6954021-0cc1-4ea1-836f-e9d4e43c3340", "metadata": {}, "source": [ "## Clasificador con una Red Neuronal Convolucional" ] }, { "cell_type": "code", "execution_count": 33, "id": "11e1cfe6-9ae0-41c5-80e5-e4edcc9bf9bb", "metadata": {}, "outputs": [], "source": [ "import sys, os, re, csv, codecs\n", "from keras.preprocessing.text import Tokenizer\n", "from keras.preprocessing.sequence import pad_sequences\n", "from keras.layers import Dense, Input, LSTM, Embedding, Dropout, Activation\n", "from keras.layers import Bidirectional, GlobalMaxPool1D, Conv1D, SimpleRNN\n", "from keras.models import Model\n", "from keras.models import Sequential\n", "from keras import initializers, regularizers, constraints, optimizers, layers\n", "from keras.layers import Dense, Input, Flatten, Dropout, BatchNormalization\n", "from keras.layers import Conv1D, MaxPooling1D, Embedding\n", "from keras.models import Sequential" ] }, { "cell_type": "code", "execution_count": 63, "id": "4e5fd647-b9e6-40e6-9dbc-fcb75d77cf91", "metadata": { "scrolled": true, "tags": [] }, "outputs": [], "source": [ "model = Sequential()\n", "model.add(Embedding(num_palabras, tamanio_incrustacion, input_length=long_max_sentencia))\n", "model.add(Dropout(0.5))\n", "model.add(Conv1D(128, 5, activation='relu'))\n", "model.add(MaxPooling1D(5))\n", "model.add(Dropout(0.5))\n", "model.add(BatchNormalization())\n", "model.add(Conv1D(128, 5, activation='relu'))\n", "model.add(MaxPooling1D(5))\n", "model.add(Dropout(0.5))\n", "model.add(BatchNormalization())\n", "model.add(Flatten())\n", "model.add(Dense(128, activation='relu'))\n", "model.add(Dense(2, activation='softmax'))\n", "model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['acc'])" ] }, { "cell_type": "code", "execution_count": 67, "id": "da8a57f1-e7cf-4dd2-a507-27eb3a6cec30", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/5\n", "70/70 [==============================] - 3s 25ms/step - loss: 0.3665 - acc: 0.8595 - val_loss: 0.3461 - val_acc: 0.8816\n", "Epoch 2/5\n", "70/70 [==============================] - 2s 22ms/step - loss: 0.1330 - acc: 0.9571 - val_loss: 0.3278 - val_acc: 0.8816\n", "Epoch 3/5\n", "70/70 [==============================] - 2s 22ms/step - loss: 0.0717 - acc: 0.9809 - val_loss: 0.4762 - val_acc: 0.8816\n", "Epoch 4/5\n", "70/70 [==============================] - 2s 23ms/step - loss: 0.0475 - acc: 0.9874 - val_loss: 0.5376 - val_acc: 0.9300\n", "Epoch 5/5\n", "70/70 [==============================] - 2s 22ms/step - loss: 0.0353 - acc: 0.9912 - val_loss: 0.6283 - val_acc: 0.9776\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from keras.callbacks import TensorBoard\n", "# para gpu\n", "tensorboard_cb = TensorBoard(os.getcwd())\n", "model.fit(train_data, \n", " labels_train,\n", " batch_size=64,\n", " epochs=5,\n", " validation_data=(test_data, labels_test),\n", " # para gpu\n", " callbacks=[tensorboard_cb]\n", " )" ] }, { "cell_type": "code", "execution_count": 76, "id": "1be8f507-0fde-455c-9808-1cbecf9182f2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0.9979972 , 0.00200277],\n", " [0.99803907, 0.00196095],\n", " [0.9962423 , 0.00375777],\n", " ...,\n", " [0.03286883, 0.9671312 ],\n", " [0.02835551, 0.97164446],\n", " [0.9965096 , 0.00349036]], dtype=float32)" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "prediccion1=model.predict(test_data)\n", "prediccion1" ] }, { "cell_type": "markdown", "id": "23c45fd3-7fb1-4737-bb92-0e0d6ea38fb9", "metadata": {}, "source": [ "## Evaluamos..." ] }, { "cell_type": "code", "execution_count": 80, "id": "852c54c2-cf41-4448-8eb6-f5be9c21d6a3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "precision: [0.98891129 0.98373984]\n", "recall: [0.99796541 0.91666667]\n", "fscore: [0.99341772 0.94901961]\n", "support: [983 132]\n", "############################\n", " precision recall f1-score support\n", "\n", " 0 0.99 1.00 0.99 983\n", " 1 0.98 0.92 0.95 132\n", "\n", " micro avg 0.99 0.99 0.99 1115\n", " macro avg 0.99 0.96 0.97 1115\n", "weighted avg 0.99 0.99 0.99 1115\n", " samples avg 0.99 0.99 0.99 1115\n", "\n" ] } ], "source": [ "import sklearn\n", "from sklearn.metrics import precision_recall_fscore_support as score \n", "precision, recall, fscore, support = score(labels_test, prediccion1.round())\n", "print('precision: {}'.format(precision))\n", "print('recall: {}'.format(recall))\n", "print('fscore: {}'.format(fscore))\n", "print('support: {}'.format(support))\n", "print(\"############################\")\n", "print(sklearn.metrics.classification_report(labels_test,prediccion1.round()))" ] }, { "cell_type": "markdown", "id": "2f4c990b-0fdb-414a-b512-0eab1a7b13a4", "metadata": {}, "source": [ "## Clasificador con una Red Neuronal Recurrente" ] }, { "cell_type": "code", "execution_count": 41, "id": "ad8bd858-6324-4d95-84fc-3cbfe9b473df", "metadata": { "tags": [] }, "outputs": [], "source": [ "from keras.layers.recurrent import SimpleRNN" ] }, { "cell_type": "code", "execution_count": 70, "id": "a55d6f21-762d-468c-b823-3b0914ca0259", "metadata": {}, "outputs": [], "source": [ "model = Sequential()\n", "model.add(Embedding(num_palabras, tamanio_incrustacion, input_length=long_max_sentencia))\n", "model.add(SimpleRNN(2, input_shape=(None,1)))\n", "model.add(Dense(2,activation='softmax'))\n", "model.compile(loss = 'binary_crossentropy', optimizer='adam',metrics = ['accuracy'])" ] }, { "cell_type": "code", "execution_count": 72, "id": "db0dcd2a-370d-4724-b609-07965a1e659a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/5\n", "279/279 [==============================] - 44s 157ms/step - loss: 0.4174 - accuracy: 0.9652 - val_loss: 0.2968 - val_accuracy: 0.9865\n", "Epoch 2/5\n", "279/279 [==============================] - 44s 159ms/step - loss: 0.2349 - accuracy: 0.9912 - val_loss: 0.1911 - val_accuracy: 0.9892\n", "Epoch 3/5\n", "279/279 [==============================] - 44s 158ms/step - loss: 0.1493 - accuracy: 0.9960 - val_loss: 0.1383 - val_accuracy: 0.9857\n", "Epoch 4/5\n", "279/279 [==============================] - 44s 157ms/step - loss: 0.1020 - accuracy: 0.9987 - val_loss: 0.1085 - val_accuracy: 0.9874\n", "Epoch 5/5\n", "279/279 [==============================] - 44s 158ms/step - loss: 0.0743 - accuracy: 0.9991 - val_loss: 0.0878 - val_accuracy: 0.9883\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# para gpu\n", "tensorboard_cb = TensorBoard(os.getcwd())\n", "\n", "model.fit(train_data, \n", " labels_train,\n", " batch_size=16,\n", " epochs=5,\n", " validation_data=(test_data, labels_test),\n", " # para gpu\n", " callbacks=[tensorboard_cb]\n", " )" ] }, { "cell_type": "code", "execution_count": 73, "id": "f31b3f14-38be-402e-9b6d-5dbfe4efe93a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[0.9979972 , 0.00200277],\n", " [0.99803907, 0.00196095],\n", " [0.9962423 , 0.00375777],\n", " ...,\n", " [0.03286883, 0.9671312 ],\n", " [0.02835551, 0.97164446],\n", " [0.9965096 , 0.00349036]], dtype=float32)" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "prediccion_Srnn=model.predict(test_data)\n", "prediccion_Srnn" ] }, { "cell_type": "markdown", "id": "47ca18e9-d239-4c57-8f1d-87f95c2799f5", "metadata": {}, "source": [ "## Evaluamos..." ] }, { "cell_type": "code", "execution_count": 78, "id": "5ab6cd13-850c-4a42-ac46-46d2914e1e26", "metadata": {}, "outputs": [], "source": [ "precision, recall, fscore, support = score(labels_test, prediccion_Srnn.round())" ] }, { "cell_type": "code", "execution_count": 79, "id": "ad7209dc-2d7a-4532-acaa-db7ca0ac47a4", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "precision: [0.98891129 0.98373984]\n", "recall: [0.99796541 0.91666667]\n", "fscore: [0.99341772 0.94901961]\n", "support: [983 132]\n", "############################\n", " precision recall f1-score support\n", "\n", " 0 0.99 1.00 0.99 983\n", " 1 0.98 0.92 0.95 132\n", "\n", " micro avg 0.99 0.99 0.99 1115\n", " macro avg 0.99 0.96 0.97 1115\n", "weighted avg 0.99 0.99 0.99 1115\n", " samples avg 0.99 0.99 0.99 1115\n", "\n" ] } ], "source": [ "print('precision: {}'.format(precision))\n", "print('recall: {}'.format(recall))\n", "print('fscore: {}'.format(fscore))\n", "print('support: {}'.format(support))\n", "print(\"############################\")\n", "print(sklearn.metrics.classification_report(labels_test, prediccion_Srnn.round()))" ] }, { "cell_type": "markdown", "id": "584b5f55-982d-41ed-8bfa-b111873701d3", "metadata": {}, "source": [ "## Clasificador con una Red Neuronal LSTM (LongShort-Term Memory)" ] }, { "cell_type": "markdown", "id": "c960225b-4a93-420f-b4a4-e57a160ff66c", "metadata": {}, "source": [ "Las LSTM son un tipo especial de redes recurrentes. La característica principal de las redes recurrentes es que la información puede persistir introduciendo bucles en el diagrama de la red, por lo que, básicamente, pueden «recordar» estados previos y utilizar esta información para decidir cuál será el siguiente. Esta característica las hace muy adecuadas para manejar series cronológicas. Mientras las redes recurrentes estándar pueden modelar dependencias a corto plazo (es decir, relaciones cercanas en la serie cronológica), las LSTM pueden aprender dependencias largas, por lo que se podría decir que tienen una «memoria» a más largo plazo." ] }, { "cell_type": "markdown", "id": "3ae06e0e-31d7-4eff-a089-f08aa1ade505", "metadata": {}, "source": [ "En el campo del internet de las cosas (IoT), el mantenimiento predictivo es otro ámbito en el que los datos de serie cronológica son muy importantes. Entre otros temas, el mantenimiento predictivo incluye la gestión de averías: predicción, clasificación y diagnóstico. Una rutina de mantenimiento predictivo para un dispositivo o conjunto de dispositivos determinados (ordenadores, generadores eléctricos, máquinas de fabricación, etc.) registra una serie de lecturas de datos a lo largo del tiempo y utiliza estos datos para hallar patrones que sirvan para predecir averías o comportamientos anómalos. Esta predicción se puede utilizar para activar medidas correctivas y así evitar efectos indeseados en el sistema." ] }, { "cell_type": "code", "execution_count": 81, "id": "c162181a-32e1-4cc7-902d-6d4c81cbac56", "metadata": { "scrolled": true, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:Layer lstm_5 will not use cuDNN kernels since it doesn't meet the criteria. It will use a generic GPU kernel as fallback when running on GPU.\n", "Epoch 1/5\n", "279/279 [==============================] - 73s 110ms/step - loss: 0.1231 - accuracy: 0.9574 - val_loss: 0.2037 - val_accuracy: 0.9776\n", "Epoch 2/5\n", "279/279 [==============================] - 25s 90ms/step - loss: 0.0101 - accuracy: 0.9971 - val_loss: 0.0451 - val_accuracy: 0.9865\n", "Epoch 3/5\n", "279/279 [==============================] - 25s 89ms/step - loss: 0.0025 - accuracy: 0.9993 - val_loss: 0.0376 - val_accuracy: 0.9892\n", "Epoch 4/5\n", "279/279 [==============================] - 25s 90ms/step - loss: 0.0031 - accuracy: 0.9993 - val_loss: 1.2488 - val_accuracy: 0.6574\n", "Epoch 5/5\n", "279/279 [==============================] - 25s 90ms/step - loss: 5.3188e-04 - accuracy: 1.0000 - val_loss: 0.0567 - val_accuracy: 0.9892\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = Sequential()\n", "model.add(Embedding(num_palabras, tamanio_incrustacion, input_length=long_max_sentencia))\n", "# para usar con cpu\n", "# model.add(LSTM(16, activation='relu', return_sequences=True))\n", "# para usar con gpu\n", "model.add(LSTM(16, activation='tanh', unroll=True, return_sequences=True))\n", "model.add(Dropout(0.2))\n", "model.add(BatchNormalization())\n", "model.add(Flatten())\n", "model.add(Dense(2,activation='softmax'))\n", "model.compile(loss = 'binary_crossentropy', optimizer='adam',metrics = ['accuracy'])\n", "\n", "# para gpu\n", "tensorboard_cb = TensorBoard(os.getcwd())\n", "\n", "model.fit(train_data, \n", " labels_train,\n", " batch_size=16,\n", " epochs=5,\n", " validation_data=(test_data, labels_test),\n", " # para gpu\n", " callbacks=[tensorboard_cb]\n", " )" ] }, { "cell_type": "code", "execution_count": 82, "id": "acbacd93-3c22-4ec8-a7a2-65854affc804", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1.0000000e+00, 1.5661773e-17],\n", " [1.0000000e+00, 1.4541863e-12],\n", " [1.0000000e+00, 9.4708269e-12],\n", " ...,\n", " [1.9187454e-13, 1.0000000e+00],\n", " [5.3611057e-12, 1.0000000e+00],\n", " [1.0000000e+00, 4.2458295e-13]], dtype=float32)" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "prediccion_lstm=model.predict(test_data)\n", "prediccion_lstm" ] }, { "cell_type": "markdown", "id": "076bb994-1ac9-4d85-9ce0-9d651c4ab1fb", "metadata": {}, "source": [ "## Evaluamos..." ] }, { "cell_type": "code", "execution_count": 83, "id": "6d06b9f4-1dae-46c5-b23e-bd005b8ea334", "metadata": { "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "precision: [0.98892246 0.99180328]\n", "recall: [0.99898271 0.91666667]\n", "fscore: [0.99392713 0.95275591]\n", "support: [983 132]\n", "############################\n", " precision recall f1-score support\n", "\n", " 0 0.99 1.00 0.99 983\n", " 1 0.99 0.92 0.95 132\n", "\n", " micro avg 0.99 0.99 0.99 1115\n", " macro avg 0.99 0.96 0.97 1115\n", "weighted avg 0.99 0.99 0.99 1115\n", " samples avg 0.99 0.99 0.99 1115\n", "\n" ] } ], "source": [ "precision, recall, fscore, support = score(labels_test, prediccion_lstm.round())\n", "print('precision: {}'.format(precision))\n", "print('recall: {}'.format(recall))\n", "print('fscore: {}'.format(fscore))\n", "print('support: {}'.format(support))\n", "print(\"############################\")\n", "print(sklearn.metrics.classification_report(labels_test, prediccion_lstm.round()))" ] }, { "cell_type": "markdown", "id": "256e10d4-e52e-43b9-bbe4-70baaceab282", "metadata": {}, "source": [ "In bidirectional LSTMs, inputs are fed in two ways: one\n", "from previous to future and the other going backward from future to\n", "past, helping in learning future representation as well. Bidirectional\n", "LSTMs are known for producing very good results as they are capable of\n", "understanding the context better." ] }, { "cell_type": "markdown", "id": "03795275-6e2b-4cee-b9f0-ce41aa2211e1", "metadata": {}, "source": [ "## Clasificación con Red Neuronal Bidireccional LSTM" ] }, { "cell_type": "markdown", "id": "10652709-6675-4aeb-8450-b82b78abbb75", "metadata": {}, "source": [ "Este tipo de redes, permiten correlacionar no sólo los datos pasados, sino también los futuros." ] }, { "attachments": { "a77be5a9-25a3-49b5-811a-a6904d9e8871.jpeg": { "image/jpeg": "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DGqHILSGzz2+dl/+Jrva4n4lRMNL0u8T71tqUMhPoo3ZoA7aio4G328Teqg/pUlABRRRQAUUUUAQi2gE5nESiUjBfHNKlvDHM8qRqsj/AHmA5NS0UAVrqwtL0KLm3jl2nI3jOKnjjSJAiKFUdAKdRQByXgr/AI//ABV/2GZf/QUrra5LwV/x/wDir/sMy/8AoKV1tABRRRQAUUUUAFFFFACMMqR6iuB+HjNbaz4o0xjxDqBZB6DavSu/rhNHc2vxX1m12gJPaLOMDq2/H9KAO7ooooAKKKKACmsqupVgCp6g06igCFLW3jgMCRIsR/gA4p8cSRRhI1CoOgFPooAqrptklx9oW2jE398LzVPxP/yKesf9eM3/AKLatasnxR/yKesf9eM3/oDUAO8M/wDIq6P/ANeUP/oArUrL8M/8iro//XlD/wCgCtSgAooooAKKKKACiiigDlPiLZJe+DLveGPksk429fkYN/StnQLoX3h7Trof8traN/zUGk8Q2/2rw5qUOMlrWQD67Tisn4eSM/gnTkk+/EgiP1UYoA6miiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAqOWaOCIyTOqIvJZjgCor6+t9Os5bu6kWOGJSzMx7V51FBqPxLu2muTJaeGUbCwdHufc/wCz17UAal98QmubtrHwzpkurTqdrSpxEn1JI/SojonjrWFD3uuxaWrHPl2K7iP++1Ndnp2l2Wk2aWtjbpBCvRUGKuUAebXHwru74wtd+MtXkeGQSodsfysOh+7VgeDPFdg6yWHjK6m28+VdRptb2O1c16DRQB563jHxH4dZV8S6L5ltnBvLHlB7kMc/pXZaVrWn63aLc6fdJPGf7p5H4VeZVdSrAFTwQa4LWvBdzpV42t+EGFpebt09qOI7gd8j1oA7+iud8JeKrbxRpxkVTDdwnZcW78MjfSuioAKKKKACuL+Km8fD3U5YsiSFDIpH8JAPNdpXJ/ExC/w317H8No7fpQB0GlSebpFnJnO6BDn/AICKuVleGpfO8NadJjGYF4/CtWgAooooAKKKKACsrW/EOmeH7M3Oo3SQoOgPJY+gArN8W+LIvDtvHBDG1zqVydttbJyWPqfQVmeH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" } }, "cell_type": "markdown", "id": "1fda1748-22f6-4370-b875-c5e120f9f1cf", "metadata": {}, "source": [ "![lstm bidireccional.jpeg](attachment:a77be5a9-25a3-49b5-811a-a6904d9e8871.jpeg)" ] }, { "cell_type": "code", "execution_count": 84, "id": "da7e036c-4c9a-447d-b755-4196390afcd7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/3\n", "279/279 [==============================] - 10s 24ms/step - loss: 0.1712 - accuracy: 0.9421 - val_loss: 0.0381 - val_accuracy: 0.9919\n", "Epoch 2/3\n", "279/279 [==============================] - 6s 21ms/step - loss: 0.0149 - accuracy: 0.9964 - val_loss: 0.0431 - val_accuracy: 0.9919\n", "Epoch 3/3\n", "279/279 [==============================] - 6s 21ms/step - loss: 0.0049 - accuracy: 0.9991 - val_loss: 0.0403 - val_accuracy: 0.9937\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = Sequential()\n", "model.add(Embedding(num_palabras,tamanio_incrustacion,input_length=long_max_sentencia))\n", "# para cpu\n", "# model.add(Bidirectional(LSTM(16, return_sequences=True, dropout=0.1, recurrent_dropout=0.1)))\n", "# para gpu\n", "model.add(Bidirectional(LSTM(16, return_sequences=True, dropout=0.1, recurrent_dropout=0)))\n", "model.add(Conv1D(16, kernel_size = 3, padding = \"valid\", kernel_initializer = \"glorot_uniform\"))\n", "model.add(GlobalMaxPool1D())\n", "model.add(Dense(50, activation=\"relu\"))\n", "model.add(Dropout(0.1))\n", "model.add(Dense(2,activation='softmax'))\n", "model.compile(loss = 'binary_crossentropy', optimizer='adam',metrics = ['accuracy'])\n", "\n", "# para gpu\n", "tensorboard_cb = TensorBoard(os.getcwd())\n", "\n", "model.fit(train_data, \n", " labels_train,\n", " batch_size=16,\n", " epochs=3,\n", " validation_data=(test_data, labels_test),\n", " # para gpu\n", " callbacks=[tensorboard_cb]\n", " )" ] }, { "cell_type": "code", "execution_count": 85, "id": "96a60998-b323-45c1-8a88-f352048ad557", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[1.0000000e+00, 9.3309129e-09],\n", " [1.0000000e+00, 1.5192081e-09],\n", " [9.9999988e-01, 1.4341482e-07],\n", " ...,\n", " [1.6063229e-11, 1.0000000e+00],\n", " [1.5419819e-09, 1.0000000e+00],\n", " [9.9999976e-01, 2.9184721e-07]], dtype=float32)" ] }, "execution_count": 85, "metadata": {}, "output_type": "execute_result" } ], "source": [ "prediccion_blstm=model.predict(test_data)\n", "prediccion_blstm" ] }, { "cell_type": "code", "execution_count": 86, "id": "4d004b3a-5aea-488d-99bb-f416a08273d7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "precision: [0.99292929 1. ]\n", "recall: [1. 0.9469697]\n", "fscore: [0.9964521 0.97276265]\n", "support: [983 132]\n", "############################\n", " precision recall f1-score support\n", "\n", " 0 0.99 1.00 1.00 983\n", " 1 1.00 0.95 0.97 132\n", "\n", " micro avg 0.99 0.99 0.99 1115\n", " macro avg 1.00 0.97 0.98 1115\n", "weighted avg 0.99 0.99 0.99 1115\n", " samples avg 0.99 0.99 0.99 1115\n", "\n" ] } ], "source": [ "precision, recall, fscore, support = score(labels_test, prediccion_blstm.round())\n", "print('precision: {}'.format(precision))\n", "print('recall: {}'.format(recall))\n", "print('fscore: {}'.format(fscore))\n", "print('support: {}'.format(support))\n", "print(\"############################\")\n", "print(sklearn.metrics.classification_report(labels_test, prediccion_blstm.round()))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.13" } }, "nbformat": 4, "nbformat_minor": 5 }