Desarrollo con Python
  • Conceptos básicos
    • 🐍Introducción a Python
      • 🐍Variables
      • 🐍Strings
      • 🐍Números
      • 🐍Comentarios
      • 🐍Funciones
      • 🐍Funciones Propias
      • 🐍Zen of Python
    • 💿Primer programa
  • Operadores en python
    • ❎Operadores
      • ❎Operadores Aritméticos
      • ❎Operadores de asignación
      • ❎Booleanos
      • ❎Operadores de comparación
      • ❎Operadores lógicos
      • ❎Operadores de identidad
      • ❎Operadores de pertenencia
  • Datos Complejos
    • ▶️Datos complejos
      • ▶️Listas
      • ▶️Tuplas
      • ▶️Diccionarios
      • ▶️Bytes y Bytearrays
      • ▶️Sets
      • ▶️NoneType
    • 💿Caso práctico: Agenda
  • Control de flujo
    • 🛑Estructuras de control de flujo
      • 🛑Sentencias if/elif/else
      • 🛑Sentencia for
      • 🛑Sentencia while
      • 🛑break/continue/pass
    • ⚠️Excepciones en Python3
    • 🎯Caso práctico: 4 in Row
  • Orientacion a objetos
    • 💾Scope y Namespaces
    • 💾Clases en Python 3
    • 💾Métodos y atributos
    • 💾Clases y Objetos
    • 💾Decorators
  • Trabajando con objetos
    • 🔢Trabajando con Objetos
      • 🔢Trabajando con Números
      • 🔢Trabajando con Strings
      • 🔢Trabajando con Listas
      • 🔢Trabajando con Tuplas
      • 🔢Trabajando con Sets
      • 🔢Trabajando con Diccionarios
  • Programación Modular
    • 🧩Programación modular
      • 🧩Paquetes
      • 🧩PIP y paquetes externos
      • 🧩Pandas
      • 🧩NumPy
      • 🧩Matplotlib
      • 📄Caso Práctico
  • Proyectos finales
    • 🐍Videojuego Snake
    • 📥Detección de Spam con Machine Learning
Con tecnología de GitBook
En esta página
  • Enunciado y contexto del ejercicio
  • Conjunto de datos
  • 1. Lectura de los correos electrónicos
  • 2. Procesamiento de texto HTML en los emails
  • 3. Procesamiento de lenguaje natural
  • 4. Procesamiento de texto HTML en los emails
  • 5. Codificando el conjunto de datos
  • 6. Entrenamiento del algoritmo
  • 7. Predicción
  • 8. Evaluación de resultados
  1. Proyectos finales

Detección de Spam con Machine Learning

AnteriorVideojuego Snake

Última actualización hace 1 año

Enunciado y contexto del ejercicio

Se propone la construcción de un sistema de aprendizaje automático capaz de predecir si un correo determinado se corresponde con un correo de SPAM o no, para ello, se utilizará el siguiente conjunto de datos:

Conjunto de datos

The corpus trec07p contains 75,419 messages:

25220 ham
50199 spam

These messages constitute all the messages delivered to a particular server between these dates:

Sun, 8 Apr 2007 13:07:21 -0400
Fri, 6 Jul 2007 07:04:53 -0400

1. Lectura de los correos electrónicos

Antes de comenzar a realizar ninguna acción, debemos implementar una función que lea de disco los correos electrónicos que forman parte del conjunto de datos de manera que podamos visualizar el formato que tienen.

Implementa una función en Python que lea el conjunto de datos de correos electrónicos y las etiquetas asociados a ellos.

Pista: Revisa los archivos que se encuentran en el directorio del conjunto de datos, el archivo full/index contiene la etiqueta de los correos y la ruta al mismo.

f = open('full/index', 'r')
f.read().splitlines()

['spam ../data/inmail.1',
 'ham ../data/inmail.2',
 'spam ../data/inmail.3',
 'spam ../data/inmail.4',
 'spam ../data/inmail.5',
 'spam ../data/inmail.6',
 'spam ../data/inmail.7',
 'spam ../data/inmail.8',
 'spam ../data/inmail.9',
 'ham ../data/inmail.10',
 'spam ../data/inmail.11',
 'spam ../data/inmail.12',
 'spam ../data/inmail.13',
 'spam ../data/inmail.14',
 'spam ../data/inmail.15',
 ...]
def leer_correos(indice, num):
    with open(indice, 'r') as f:
        labels = f.read().splitlines()

    # Leemos los correos de disco
    X = []
    y = []
    for l in labels[:num]:
        label, email_path = l.split(' ../')
        y.append(label)
        with open(email_path, errors='ignore') as f:
            X.append(f.read())
    return X, y
X , y = leer_correos('full/index', 10)

print(X[0])
From RickyAmes@aol.com  Sun Apr  8 13:07:32 2007
Return-Path: <RickyAmes@aol.com>
Received: from 129.97.78.23 ([211.202.101.74])
	by speedy.uwaterloo.ca (8.12.8/8.12.5) with SMTP id l38H7G0I003017;
	Sun, 8 Apr 2007 13:07:21 -0400
Received: from 0.144.152.6 by 211.202.101.74; Sun, 08 Apr 2007 19:04:48 +0100
Message-ID: <WYADCKPDFWWTWTXNFVUE@yahoo.com>
From: "Tomas Jacobs" <RickyAmes@aol.com>
Reply-To: "Tomas Jacobs" <RickyAmes@aol.com>
To: the00@speedy.uwaterloo.ca
Subject: Generic Cialis, branded quality@ 
Date: Sun, 08 Apr 2007 21:00:48 +0300
X-Mailer: Microsoft Outlook Express 6.00.2600.0000
MIME-Version: 1.0
Content-Type: multipart/alternative;
	boundary="--8896484051606557286"
X-Priority: 3
X-MSMail-Priority: Normal
Status: RO
Content-Length: 988
Lines: 24

----8896484051606557286
Content-Type: text/html;
Content-Transfer-Encoding: 7Bit

<html>
<body bgcolor="#ffffff">
<div style="border-color: #00FFFF; border-right-width: 0px; border-bottom-width: 0px; margin-bottom: 0px;" align="center">
<table style="border: 1px; border-style: solid; border-color:#000000;" cellpadding="5" cellspacing="0" bgcolor="#CCFFAA">
<tr>
<td style="border: 0px; border-bottom: 1px; border-style: solid; border-color:#000000;">
<center>
Do you feel the pressure to perform and not rising to the occasion??<br>
</center>
</td></tr><tr>
<td bgcolor=#FFFF33 style="border: 0px; border-bottom: 1px; border-style: solid; border-color:#000000;">
<center>

<b><a href='http://excoriationtuh.com/?lzmfnrdkleks'>Try <span>V</span><span>ia<span></span>gr<span>a</span>.....</a></b></center>
</td></tr><td><center>your anxiety will be a thing of the past and you will<br>
be back to your old self.
</center></td></tr></table></div></body></html>

----8896484051606557286--

print(y[0])
spam

2. Procesamiento de texto HTML en los emails

En este caso práctico relacionado con la detección de correos electrónicos de SPAM, el conjunto de datos que disponemos esta formado por correos electrónicos, con sus correspondientes cabeceras y campos adicionales. Por lo tanto, requieren un preprocesamiento previo a que sean ingeridos por el algoritmo de Machine Learning.

Implementa una clase en Python 3 que permita procesar texto que contiene código HTML y elimine los tags HTML.

from html.parser import HTMLParser

class HTMLStripper(HTMLParser):
    def __init__(self):
        # inicializamos la clase padre
        super().__init__()
        # Atributo que almacena los datos
        self.data = []  # Corregir aquí: self_data -> self.data

    def handle_data(self, data):
        self.data.append(data)
html_parser = HTMLStripper()
html_parser.feed(X[0])

print(''.join(html_parser.data))
From RickyAmes@aol.com  Sun Apr  8 13:07:32 2007
Return-Path: 
Received: from 129.97.78.23 ([211.202.101.74])
	by speedy.uwaterloo.ca (8.12.8/8.12.5) with SMTP id l38H7G0I003017;
	Sun, 8 Apr 2007 13:07:21 -0400
Received: from 0.144.152.6 by 211.202.101.74; Sun, 08 Apr 2007 19:04:48 +0100
Message-ID: 
From: "Tomas Jacobs" 
Reply-To: "Tomas Jacobs" 
To: the00@speedy.uwaterloo.ca
Subject: Generic Cialis, branded quality@ 
Date: Sun, 08 Apr 2007 21:00:48 +0300
X-Mailer: Microsoft Outlook Express 6.00.2600.0000
MIME-Version: 1.0
Content-Type: multipart/alternative;
	boundary="--8896484051606557286"
X-Priority: 3
X-MSMail-Priority: Normal
Status: RO
Content-Length: 988
Lines: 24

----8896484051606557286
Content-Type: text/html;
Content-Transfer-Encoding: 7Bit


Do you feel the pressure to perform and not rising to the occasion??


Try Viagra.....
your anxiety will be a thing of the past and you will
be back to your old self.


----8896484051606557286--
def strip_tags(text):
    html_stripper = HTMLStripper()
    html_stripper.feed(text)
    return ''.join(html_stripper.data)
print(strip_tags(X[0]))

From RickyAmes@aol.com  Sun Apr  8 13:07:32 2007
Return-Path: 
Received: from 129.97.78.23 ([211.202.101.74])
	by speedy.uwaterloo.ca (8.12.8/8.12.5) with SMTP id l38H7G0I003017;
	Sun, 8 Apr 2007 13:07:21 -0400
Received: from 0.144.152.6 by 211.202.101.74; Sun, 08 Apr 2007 19:04:48 +0100
Message-ID: 
From: "Tomas Jacobs" 
Reply-To: "Tomas Jacobs" 
To: the00@speedy.uwaterloo.ca
Subject: Generic Cialis, branded quality@ 
Date: Sun, 08 Apr 2007 21:00:48 +0300
X-Mailer: Microsoft Outlook Express 6.00.2600.0000
MIME-Version: 1.0
Content-Type: multipart/alternative;
	boundary="--8896484051606557286"
X-Priority: 3
X-MSMail-Priority: Normal
Status: RO
Content-Length: 988
Lines: 24

----8896484051606557286
Content-Type: text/html;
Content-Transfer-Encoding: 7Bit


Do you feel the pressure to perform and not rising to the occasion??


Try Viagra.....
your anxiety will be a thing of the past and you will
be back to your old self.


----8896484051606557286--

3. Procesamiento de lenguaje natural

Además de eliminar los posibles tags HTML que se encuentren en el correo electrónico, deben realizarse otras acciones de preprocesamiento para evitar que los mensajes contengan ruido innecesario. Entre ellas se encuentra la eliminación de los signos de puntuación, eliminación de posibles campos del correo electrónico que no son relevantes o eliminación de los afijos de una palabra manteniendo únicamente la raiz de la misma (Stemming).

Explora e implementa diferentes funciones en Python 3 que permitan realizar los procesamientos que se indican en el texto anterior. Ten en cuenta que el texto de los correos electrónicos esta en Inglés.

Pista 1: Ten en cuenta que los correos electrónicos se encuentran en bruto y, por lo tanto, contienen valores que no nos van a resultar de interés, por ejemplo, las cabeceras o el pie del correo electrónico. Utiliza el paquete externo email para procesar los correos y eliminar todo menos el cuerpo del mismo.

dir(email)
['base64mime',
 'charset',
 'encoders',
 'errors',
 'feedparser',
 'header',
 'headerregistry',
 'iterators',
 'message',
 'message_from_binary_file',
 'message_from_bytes',
 'message_from_file',
 'message_from_string', <---- Vamos a usar este método
 'parser',
 'quoprimime',
 'utils']

parsed_mail = email.message_from_string(X[0])

parsed_mail
<email.message.Message at 0x106ad2c50>
cuerpo_email = parsed_mail.get_payload()
cuerpo_email[0].get_payload()
'<html>\n<body bgcolor="#ffffff">\n<div style="border-color: #00FFFF; border-right-width: 0px; border-bottom-width: 0px; margin-bottom: 0px;" align="center">\n<table style="border: 1px; border-style: solid; border-color:#000000;" cellpadding="5" cellspacing="0" bgcolor="#CCFFAA">\n<tr>\n<td style="border: 0px; border-bottom: 1px; border-style: solid; border-color:#000000;">\n<center>\nDo you feel the pressure to perform and not rising to the occasion??<br>\n</center>\n</td></tr><tr>\n<td bgcolor=#FFFF33 style="border: 0px; border-bottom: 1px; border-style: solid; border-color:#000000;">\n<center>\n\n<b><a href=\'http://excoriationtuh.com/?lzmfnrdkleks\'>Try <span>V</span><span>ia<span></span>gr<span>a</span>.....</a></b></center>\n</td></tr><td><center>your anxiety will be a thing of the past and you will<br>\nbe back to your old self.\n</center></td></tr></table></div></body></html>\n\n'
strip_tags(cuerpo_email[0].get_payload())
'\n\nDo you feel the pressure to perform and not rising to the occasion??\n\nTry Viagra.....\nyour anxiety will be a thing of the past and you will\nbe back to your old self.\n\n'
print(strip_tags(cuerpo_email[0].get_payload()))


Do you feel the pressure to perform and not rising to the occasion??


Try Viagra.....
your anxiety will be a thing of the past and you will
be back to your old self.

def get_body(correo):
    # Definimos una función interna que procese el cuerpo
    def parse_body(payload):
        body = []
        if type(payload) is str:
            return[payload]
        elif type(payload) is list:
            for p in payload:
                body += parse_body(p.get_payload())
        return body
        
    parsed_mail = email.message_from_string(correo)
    return parse_body(parsed_mail.get_payload())
get_body(X[2])

['Mega  authenticV I A G R A   $ DISCOUNT priceC I A L I S  $DISCOUNT priceDo not miss IT, CLICK here.\nhttp://www.moujsjkhchum.com\n\n',
 '<HTML><HEAD><TITLE>authentic viagra</TITLE></HEAD>\n<BODY>\nMega  authentic<br>V I A G R A   $ DISCOUNT price<br>C I A L I S  $DISCOUNT price<br><a href="http://www.moujsjkhchum.com">Do not miss IT, CLICK here.</a>\n</BODY></HTML>\n']

Pista 2: Una vez que hayas eliminado todos los componentes del correo menos su cuerpo, explora la librería nltk para eliminar signos de puntuación y afijos. Revisa la clase PorterStemmer() de nltk así como los métodos y atributos nltk.corpus.stopwords.words('english'), string.punctuation y nltk.tokenize.word_tokenize

import nltk

nltk.download('stopwords')
nltk.download('punkt')
stemmer = nltk.PorterStemmer()

stemmer.stem('doing')
'do'

stemmer.stem('making')
'make'
nltk.corpus.stopwords.words('english')
['i',
 'me',
 'my',
 'myself',
 'we',
 'our',
 'ours',
 'ourselves',
 'you',
 "you're",
 "you've",
 "you'll",
 "you'd",
 'your',
 'yours',
 'yourself',
 'yourselves',
 ...]
import string

string.punctuation
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'

"Hola como estas; me llamo Alex...".split() # Los signos de puntuación están pegados a las palabras
['Hola', 'como', 'estas;', 'me', 'llamo', 'Alex...']

from nltk.tokenize import word_tokenize
from nltk.tokenize import word_tokenize

word_tokenize("Hola como estas; me llamo Alex...") # De esta manera separa los signos de puntuación
['Hola', 'como', 'estas', ';', 'me', 'llamo', 'Alex', '...']

4. Procesamiento de texto HTML en los emails

Pon todo lo anterior en común y construye una clase EmailParser que procese los emails aplicando todas las transformaciones que hemos implementado en las secciones anteriores.

Implementa una clase en Python 3 que contenga toda la funcionalidad que hemos visto en el apartado anterior. Implementa una función que permita leer correos electrónicos y aplicarles las transformaciones de manera simultánea.

import email
import re
from nltk.tokenize import word_tokenize
from string import punctuation
from nltk import PorterStemmer
from nltk.corpus import stopwords
from html.parser import HTMLParser

class EmailParser:
    
    def parse(self, correo):
        # Obtenemos el cuerpo del email
        parsed_mail = " ".join(self.get_body(correo))
        # Eliminar los tags html
        parsed_mail = self.strip_tags(parsed_mail)
        # Eliminar las URLs
        parsed_mail = self.remove_urls(parsed_mail)
        # Transformamos el texto en tokens
        parsed_mail = word_tokenize(parsed_mail)
        # Hacemos stemming
        parsed_mail = self.clean_text(parsed_mail)
        return ' '.join(parsed_mail)
        
    def get_body(self, correo):
        # Definimos una función interna que procese el cuerpo
        parsed_mail = email.message_from_string(correo)
        return self._parse_body(parsed_mail.get_payload())
    
    def _parse_body(self, payload):
        body = []
        if type(payload) is str:
            return[payload]
        elif type(payload) is list:
            for p in payload:
                body += self._parse_body(p.get_payload())
        return body
    
    def strip_tags(self, correo):
        html_stripper = HTMLStripper()
        html_stripper.feed(correo)
        return ''.join(html_stripper.data)
    
    def remove_urls(self, correo):
        return re.sub(r'http\S+', '', correo)
    
    def clean_text(self, correo):
        parsed_mail = []
        st = PorterStemmer()
        punct = list(punctuation) + ['\n', '\t']
        for word in correo:
            if word not in stopwords.words('english') and word not in punct:
                #Aplicamos stemming
                parsed_mail.append(st.stem(word))
        return parsed_mail

class HTMLStripper(HTMLParser):
    def __init__(self):
        super().__init__()
        self.data = []

    def handle_data(self, d):
        self.data.append(d)

    def get_data(self):
        return ''.join(self.data)
parser = EmailParser()

parser.parse(X[0])
'do feel pressur perform rise occas tri viagra ..... anxieti thing past back old self'
def crear_dataset(indice, num):
    email_parser = EmailParser()
    X, y = leer_correos(indice, num)
    X_proc = []
    for i, email in zip(range(len(X)), X):
        print('\rParsing email: {0}'.format(i+1), end='')
        X_proc.append(email_parser.parse(email))
    return X_proc, y
X, y = crear_dataset('full/index', 30)
Parsing email: 30

X[0]
'do feel pressur perform rise occas tri viagra ..... anxieti thing past back old self'

y[0]
'spam'

X[25]
'your histori show last order readi refil to visit pleas visit site complet order becaus order us previous prescript pre-approv thank sam mcfarland custom servic'

5. Codificando el conjunto de datos

Con las funciones presentadas anteriormente se permite la lectura de los correos electrónicos de manera programática y el procesamiento de los mismos para eliminar aquellos componentes que no resultan de utilidad para la detección de correos de SPAM. Sin embargo, cada uno de los correos sigue estando representado por un string.

La mayoría de los algoritmos de Machine Learning no son capaces de ingerir texto como parte del conjunto de datos. Por lo tanto, deben aplicarse una serie de funciones adicionales que transformen el texto de los correos electrónicos parseados en una representación numérica.

Aplica alguna técnica de codificación/vectorización sobre los correos electrónicos parseados para transformar el texto en una representación numérica.

Pista: Revisa la clase CountVectorizer de Sklearn para realizar la codificación.

X[0]
'do feel pressur perform rise occas tri viagra ..... anxieti thing past back old self'

X[2]
'mega authenticv i a g r a discount pricec i a l i s discount pricedo miss it click authent viagra mega authenticv i a g r a discount pricec i a l i s discount pricedo miss it click'

X[10]
'good day visit new onlin drug store save upto 85 today special offer viagra for as low as 1.62 per dose ciali super viagra for as low as 4.38 per dose levitra for as low as 4.44 per dose ... much much special offer today.y need 15 minut to be readi for action most need medic avail viagra ciali levitra propecia much much free ship worlwid no doctor visit no prescript full custom satisfactionclick visit new drugstor best regard good day visit new onlin drug store save= upto 85 today special offer viagra for as low as 1.62 per dose br ciali super viagra for as low as 4.38 per dose levitra for as low as 4.44 per dose ... much much special offer today you need 15 minut to be readi for action most need medic avail viagra ciali levitra prope= cia much much free ship worlwid no doctor visit no prescript full custom satisfact click visit new drugstor best regard'
from sklearn.feature_extraction.text import CountVectorizer

vectorizer = CountVectorizer()
vectorizer.fit([X[0], X[2], X[10]])

vectorizer.get_feature_names_out()
array(['15', '38', '44', '62', '85', 'action', 'anxieti', 'as', 'authent',
       'authenticv', 'avail', 'back', 'be', 'best', 'br', 'cia', 'ciali',
       'click', 'custom', 'day', 'discount', 'do', 'doctor', 'dose',
       'drug', 'drugstor', 'feel', 'for', 'free', 'full', 'good', 'it',
       'levitra', 'low', 'medic', 'mega', 'minut', 'miss', 'most', 'much',
       'need', 'new', 'no', 'occas', 'offer', 'old', 'onlin', 'past',
       'per', 'perform', 'prescript', 'pressur', 'pricec', 'pricedo',
       'prope', 'propecia', 'readi', 'regard', 'rise', 'satisfact',
       'satisfactionclick', 'save', 'self', 'ship', 'special', 'store',
       'super', 'thing', 'to', 'today', 'tri', 'upto', 'viagra', 'visit',
       'worlwid', 'you'], dtype=object)

X_vect = vectorizer.transform([X[0]]) # Le pasamos un mail como una lista []

X_vect.toarray()
# Esto nos devuelve un array de 0 y 1, donde 1 es la palabra que se repite en los emails, vemos que la primera que se repite es en la posición 7 que se corresponde con anxieti
array([[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
        0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
        0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
        0, 1, 0, 0, 1, 0, 1, 0, 0, 0]])

X[0]
'do feel pressur perform rise occas tri viagra ..... anxieti thing past back old self'

6. Entrenamiento del algoritmo

¡Enhorabuena! Ya tienes la parte más complicada del ejercicio realizada. En este apartado vamos a entrenar un algoritmo de Machine Learning que aprenderá de los vectores anteriores a clasificar los correos en spam y legítimos.

Utiliza el algoritmo de Machine Learning LogisticRegression para clasificar entre correos electrónicos de spam y legítimos. Puedes encontrar la implementación de este algoritmo en Sklearn.

Pista 1: Comienza leyendo un número de correos pequeño para que no tarde demasiado tiempo, por ejemplo 100 correos. Aplica todas las transformaciones que hemos implementado anteriormente sobre ellos.

# Leemos un subconjunto de 100 correos
X, y = crear_dataset('full/index', 100)

Pista 2: Aplica la vectorización al conjunto de datos para representar los correos de manera numérica.

vectorizer = CountVectorizer()
vectorizer.fit(X)
X_vect = vectorizer.transform(X)

X_vect.toarray()
array([[0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       ...,
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0]])

Podemos leer estos datos de una manera más visual usando Pandas:

import pandas as pd

pd.DataFrame(X_vect.toarray(), columns=[vectorizer.get_feature_names_out()])

Pista 3: Entrena el algoritmo LogisticRegression de Sklearn. Este algoritmo se basa en aprendizaje supervisado y funciona exactamente igual que el algoritmo Perceptron que hemos presentado en secciones anteriores.

from sklearn.linear_model import LogisticRegression

clf = LogisticRegression()
clf.fit(X_vect, y)

7. Predicción

¡Muy bien, ya casi has terminado! Ya tenemos nuestro algoritmo entrenado y listo para realizar predicciones, lo único que nos queda es probar que tal se comporta para correos que no ha visto nunca.

Utiliza el algoritmo de Machine Learning LogisticRegression para predecir si un nuevo correo que no ha visto nunca es spam o legitimo.

Pista: Revisa el método predict() que tiene la clase LogisticRegression. Ten en cuenta que cuando recibas un nuevo correo para el que quieres realizar una predicción debes aplicar sobre él todas las transformaciones que hemos realizado anteriormente. Al aplicar la vectorización utiliza únicamente el método transform() del objeto CountVectorizer.

# Leemos 150 correos de nuestro conjunto de datos y nos quedamos solo con los últimos 50
# Estos últimos 50 correos no se han utilizado en el entrenamiento del algoritmo
X, y = crear_dataset('full/index', 150)
Parsing email: 150

len(X)
150

X_test = X[100:]
y_test = y[100:]

len(X_test)
50

# Aplicamos CountVectorizer
X_test = vectorizer.transform(X_test)
X_test.toarray()
array([[0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0],
       ...,
       [0, 0, 0, ..., 0, 0, 0],
       [0, 1, 0, ..., 0, 0, 0],
       [0, 0, 0, ..., 0, 0, 0]])

# Predicción para un correo
y_pred = clf.predict(X_test)

print('Predicción:', y_pred)
print('Etiquetas reales:', y_test)
Predicción: ['spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam'
 'ham' 'spam' 'spam' 'spam' 'spam' 'spam' 'ham' 'spam' 'spam' 'spam'
 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam'
 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam'
 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam' 'spam']
Etiquetas reales: ['spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'ham', 'spam', 'spam', 'spam', 'spam', 'spam', 'ham', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'ham', 'spam', 'spam', 'ham', 'spam', 'spam', 'ham', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam', 'spam']

8. Evaluación de resultados

Pista: Utiliza una métrica para evaluar los resultados. En este caso, utiliza la métrica accuracy_score. Puedes encontrar esta métrica implementada en Sklearn.

from sklearn.metrics import accuracy_score

print('Precisión: {:.3f}'.format(accuracy_score(y_test, y_pred)))
Precisión: 0.940

Vemos que el algoritmo ha acertado en un 94%, lo que es un porcentaje altísimo

Pista: Revisa la clase HTMLParser para implementar esta sección:

2007 TREC Public Spam Corpus
https://docs.python.org/es/3.8/library/html.parser.html
📥
Page cover image