Sistema de filtrado de spam basado en aprendizaje automático

Prefacio:

Hace algún tiempo escribí un tema: un sistema de filtrado de spam basado en aprendizaje automático , y luego unos zapatos de niños me preguntaron sobre el marco de implementación específico, así que ahora hablemos brevemente sobre eso.

Tabla de contenido

Prefacio:

I. Resumen

2. Recopilación de datos

2.1 Obtener datos del corpus de correo público de SpamAssassin

2.2 Preprocesamiento de datos

2.2.1 Leer datos de correo electrónico

2.2.2 Preprocesamiento de texto

3. Selecciona el modelo

3.1 Modelo de formación

4. Evaluar el rendimiento del modelo

4.1 Conjunto de datos dividido

4.2 Indicadores de evaluación

4.3 Validación cruzada

5. Desplegar el modelo a la aplicación práctica

5.1 Guardar el modelo

5.2 Procesamiento de correo

6. Integrar en el cliente de correo electrónico

6.1 Crear una macro de Outlook

6.2 Crear una secuencia de comandos de Python

6.3 Llamar secuencia de comandos de Python

 6.4 Crear reglas de correo


I. Resumen

En este blog, presentaremos cómo construir un sistema de filtrado de spam basado en el aprendizaje automático. Usaremos el lenguaje de programación Python y algunas bibliotecas comunes de aprendizaje automático para este proyecto. Todo el proyecto se dividirá en las siguientes partes:

1. Descripción general
2. Recopilación y preprocesamiento de datos
3. Seleccionar y entrenar modelos de aprendizaje automático
4. Evaluar el rendimiento del modelo
5. Implementar modelos en aplicaciones prácticas
6. Integrar en clientes

2. Recopilación de datos

2.1 Obtener datos del corpus de correo público de SpamAssassin

( https://spamassassin.apache.org/old/publiccorpus/) para descargar datos de spam y jamón. Hay varios archivos comprimidos que contienen una gran cantidad de datos de correo, necesitamos descomprimir y fusionar estos datos.

Aquí hay un código Python simple para descargar y descomprimir datos de correo:

import os
import tarfile
import urllib.request

# 下载数据集
def download_data(url, target_folder):
    if not os.path.exists(target_folder):
        os.makedirs(target_folder)
    file_name = url.split("/")[-1]
    target_path = os.path.join(target_folder, file_name)
    if not os.path.exists(target_path):
        urllib.request.urlretrieve(url, target_path)
        print(f"Downloaded {file_name}")
    return target_path

# 解压数据集
def extract_data(file_path, target_folder):
    with tarfile.open(file_path, "r:gz") as tar:
        tar.extractall(target_folder)
        print(f"Extracted {os.path.basename(file_path)} to {target_folder}")

# 下载并解压数据集
url_list = [
    "https://spamassassin.apache.org/old/publiccorpus/20021010_easy_ham.tar.bz2",
    "https://spamassassin.apache.org/old/publiccorpus/20021010_hard_ham.tar.bz2",
    "https://spamassassin.apache.org/old/publiccorpus/20021010_spam.tar.bz2"
]

target_folder = "data"
for url in url_list:
    file_path = download_data(url, target_folder)
    extract_data(file_path, target_folder)

2.2 Preprocesamiento de datos

2.2.1 Leer datos de correo electrónico

Necesitamos leer los datos del correo de la carpeta descomprimida. Aquí hay una función simple de Python para leer un archivo de correo:

import os
import email
import email.policy

def read_email(file_path):
    with open(file_path, "rb") as f:
        return email.parser.BytesParser(policy=email.policy.default).parse(f)

ham_folder = "data/easy_ham"
spam_folder = "data/spam"
ham_files = [os.path.join(ham_folder, f) for f in os.listdir(ham_folder)]
spam_files = [os.path.join(spam_folder, f) for f in os.listdir(spam_folder)]
ham_emails = [read_email(f) for f in ham_files]
spam_emails = [read_email(f) for f in spam_files]

2.2.2 Preprocesamiento de texto

Necesitamos preprocesamiento de texto del cuerpo del correo electrónico, incluida la limpieza, la normalización y la vectorización. Aquí hay un código Python simple para implementar estas operaciones:

import re
import nltk
from nltk.corpus import stopwords
from nltk.stem import SnowballStemmer
from sklearn.feature_extraction.text import TfidfVectorizer

nltk.download('stopwords')
stemmer = SnowballStemmer("english")
stop_words = set(stopwords.words("english"))

# 清洗文本
def clean_text(text):
    text = re.sub(r'\W+', ' ', text)  # 移除非字母数字字符
    text = text.lower()  # 转换为小写
    text = re.sub(r'\d+', '', text)  # 移除数字
text = ' '.join([stemmer.stem(word) for word in text.split() if word not in stop_words])  # 移除停用词并进行词干提取
return text
# 提取邮件正文
def get_email_text(email_obj):
parts = []
for part in email_obj.walk():
if part.get_content_type() == 'text/plain':
parts.append(part.get_payload())
return ''.join(parts)

# 对所有邮件进行预处理
ham_texts = [clean_text(get_email_text(email)) for email in ham_emails]
spam_texts = [clean_text(get_email_text(email)) for email in spam_emails]

# 合并数据和标签
texts = ham_texts + spam_texts
labels = [0] * len(ham_texts) + [1] * len(spam_texts)

# 向量化文本
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(texts)
y = labels


Hasta el momento, hemos completado el trabajo de recopilación y preprocesamiento de datos. Obtenemos los datos de correo electrónico vectorizados X y la etiqueta correspondiente y. A continuación, podemos usar estos datos para entrenar un modelo de aprendizaje automático para el filtrado de spam.

3. Selecciona el modelo

En este proyecto, elegimos usar un modelo naive bayesiano. El clasificador bayesiano ingenuo es un clasificador de probabilidad simple basado en el teorema bayesiano, que supone que las características son independientes entre sí. Aunque esta suposición de independencia a menudo no es cierta en las aplicaciones prácticas, los clasificadores Naive Bayesian aún muestran un buen rendimiento en muchos escenarios, especialmente en tareas de clasificación de texto.

3.1 Modelo de formación

Usaremos el módulo MultinomialNB en la biblioteca scikit-learn para implementar el modelo Naive Bayesian y entrenarlo en el conjunto de datos preprocesado. El siguiente es el código de Python para entrenar el modelo:

from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 创建朴素贝叶斯模型并训练
model = MultinomialNB()
model.fit(X_train, y_train)

# 在测试集上进行预测
y_pred = model.predict(X_test)

# 计算评估指标
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)

print(f"Accuracy: {accuracy:.4f}")
print(f"Precision: {precision:.4f}")
print(f"Recall: {recall:.4f}")
print(f"F1 Score: {f1:.4f}")

A través del código anterior, hemos realizado la selección y entrenamiento del modelo Naive Bayesian. Al mismo tiempo, también calculamos la exactitud, la precisión, la recuperación y la puntuación F1 del modelo en el conjunto de prueba para evaluar el rendimiento del modelo. En un paso posterior, usaremos este modelo entrenado para hacer predicciones sobre correos electrónicos reales para determinar si un correo electrónico es spam o no. 

4. Evaluar el rendimiento del modelo

4.1 Conjunto de datos dividido

Dividimos el conjunto de datos preprocesados ​​en conjuntos de entrenamiento y prueba con una proporción de 80% y 20%. Aquí usamos la función train_test_split en la biblioteca scikit-learn para lograrlo. Esta parte del código se ha dado en la parte de entrenamiento del modelo, de la siguiente manera:

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

4.2 Indicadores de evaluación

Evaluamos el rendimiento del modelo utilizando métricas como exactitud, precisión, recuperación y puntuación F1. Esta parte del código también se ha dado en la parte de entrenamiento del modelo, de la siguiente manera:

from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

# 在测试集上进行预测
y_pred = model.predict(X_test)

# 计算评估指标
accuracy = accuracy_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)
recall = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)

print(f"Accuracy: {accuracy:.4f}")
print(f"Precision: {precision:.4f}")
print(f"Recall: {recall:.4f}")
print(f"F1 Score: {f1:.4f}")

4.3 Validación cruzada

Para evaluar el rendimiento del modelo con mayor precisión, podemos utilizar el método de validación cruzada. Aquí, usamos el módulo cross_val_score en la biblioteca scikit-learn para implementar la validación cruzada. El siguiente es el código de Python para evaluar el rendimiento del modelo mediante validación cruzada:

from sklearn.model_selection import cross_val_score

# 使用交叉验证计算评估指标
cv_accuracy = cross_val_score(model, X, y, cv=5, scoring='accuracy').mean()
cv_precision = cross_val_score(model, X, y, cv=5, scoring='precision').mean()
cv_recall = cross_val_score(model, X, y, cv=5, scoring='recall').mean()
cv_f1 = cross_val_score(model, X, y, cv=5, scoring='f1').mean()

print(f"Cross-Validation Accuracy: {cv_accuracy:.4f}")
print(f"Cross-Validation Precision: {cv_precision:.4f}")
print(f"Cross-Validation Recall: {cv_recall:.4f}")
print(f"Cross-Validation F1 Score: {cv_f1:.4f}")

A través del código anterior, hemos realizado la evaluación del rendimiento del modelo, incluida la división de conjuntos de datos, el cálculo de indicadores de evaluación y la validación cruzada. Estos resultados de evaluación pueden ayudarnos a comprender el rendimiento del modelo para predecir mejor el spam en aplicaciones reales.

5. Desplegar el modelo a la aplicación práctica

5.1 Guardar el modelo

Podemos usar la biblioteca pickle de Python para guardar y cargar el modelo. El siguiente es el código de Python para guardar el modelo:

import pickle

# 保存模型
with open('spam_classifier_model.pkl', 'wb') as file:
    pickle.dump(model, file)

# 保存向量化器
with open('vectorizer.pkl', 'wb') as file:
    pickle.dump(vectorizer, file)

5.2 Procesamiento de correo

En la práctica, necesitamos preprocesar los correos electrónicos entrantes para que se ajusten a nuestro modelo entrenado. Esto requiere que implementemos una función de procesamiento de correo electrónico, que incluye principalmente los siguientes pasos:

  1. Extraer cuerpo del correo electrónico: extraiga el contenido del cuerpo del correo electrónico recibido. Puede usar la biblioteca de correo electrónico de Python para analizar el correo electrónico y obtener el cuerpo.

  2. Preprocesamiento de texto: realice las mismas operaciones de preprocesamiento en el contenido de texto extraído que antes, incluidas la limpieza, la normalización y la vectorización.

  3. Predicción del modelo: use el modelo entrenado para predecir el cuerpo del correo electrónico preprocesado. Determine si un correo electrónico es spam o no según el resultado de la predicción.

El siguiente es el código de Python que implementa la función de procesamiento de correo:

import email
from email.message import EmailMessage

# 加载模型和向量化器
with open('spam_classifier_model.pkl', 'rb') as file:
    model = pickle.load(file)

with open('vectorizer.pkl', 'rb') as file:
    vectorizer = pickle.load(file)

# 邮件处理函数
def process_email(raw_email):
    # 解析邮件并提取正文
    email_obj = email.message_from_string(raw_email)
    email_text = get_email_text(email_obj)

    # 文本预处理
    cleaned_text = clean_text(email_text)
    vectorized_text = vectorizer.transform([cleaned_text])

    # 使用模型预测
    prediction = model.predict(vectorized_text)

    return "Spam" if prediction[0] == 1 else "Ham"

# 示例:读取邮件文本并使用处理函数判断是否为垃圾邮件
with open('example_email.txt', 'r') as file:
    raw_email = file.read()

result = process_email(raw_email)
print(f"Result: {result}")

A través del código anterior, hemos realizado la función de implementar el modelo en la aplicación real. Podemos integrar estos códigos en un cliente o servidor de correo electrónico para filtrar spam en tiempo real.

6. Integrar en el cliente de correo electrónico

Para facilitar su uso, podemos integrar filtros de spam en los clientes de correo existentes. Esto requiere que implementemos un complemento o extensión que invoque automáticamente nuestro filtro de correo no deseado para su procesamiento cuando llegue correo nuevo. Cómo se hace esto depende del cliente de correo que se utilice.

Aquí, tomamos Microsoft Outlook como ejemplo para presentar cómo integrar el filtro de spam en el cliente de correo. Outlook admite macros de VBA (Visual Basic para aplicaciones), podemos usar macros de VBA para llamar a nuestro filtro de spam de Python. El método de implementación específico es el siguiente:

6.1 Crear una macro de Outlook

  1. Abra Outlook y haga clic en la pestaña "Desarrollador". Si no ve la pestaña Desarrollador, puede habilitarla en Archivo -> Opciones -> Personalizar la cinta.

  2. Haga clic en el botón "Visual Basic" para abrir el editor de VBA.

  3. En el lado izquierdo del editor de VBA, haga doble clic en "Esta sesión de Outlook" para abrir la ventana de edición de código.

  4. En la ventana de edición de código, ingrese el siguiente código:

    Option Explicit
    
    Sub ProcessNewEmail(Item As Outlook.MailItem)
        ' 调用Python脚本处理邮件,并获得预测结果
        Dim result As String
        result = RunPythonScript("process_email.py", Item.Body)
        
        ' 根据预测结果处理邮件
        If result = "Spam" Then
            ' 将邮件移动到垃圾邮件文件夹
            Dim spamFolder As Outlook.MAPIFolder
            Set spamFolder = Application.Session.GetDefaultFolder(olFolderJunk)
            Item.Move spamFolder
        End If
    End Sub
    

  5. Haga clic en "Archivo" -> "Guardar esta sesión de Outlook".

6.2 Crear una secuencia de comandos de Python

6.2.1 Cree un nuevo archivo de secuencia de comandos de Python process_email.pyy coloque process_emailen él la función de procesamiento de correo implementada previamente. Al mismo tiempo, la función debe modificarse para que acepte el cuerpo del correo electrónico como parámetro y envíe los resultados de la predicción a la salida estándar después del procesamiento.

import sys

def process_email(email_text):
    # ...
    # 文本预处理和模型预测的代码
    # ...

    return "Spam" if prediction[0] == 1 else "Ham"

if __name__ == "__main__":
    email_text = sys.argv[1]
    result = process_email(email_text)
    print(result)

6.2.2 se process_email.pycolocará en la misma carpeta que el archivo del modelo entrenado y el archivo del vectorizador.

6.3 Llamar secuencia de comandos de Python

6.3.1 Para llamar a una secuencia de comandos de Python en VBA, necesitamos crear una RunPythonScriptfunción llamada para ejecutar la secuencia de comandos de Python y devolver el resultado. Ingrese el siguiente código en la ventana de edición de código del editor de VBA:

Function RunPythonScript(scriptPath As String, emailBody As String) As String
    Dim shell As Object
    Dim command As String
    Dim tempFile As String
    Dim fso As Object
    Dim file As Object
    Dim result As String
    
    ' 创建一个临时文件用于存储Python脚本的输出
    Set fso = CreateObject("Scripting.FileSystemObject")
    tempFile = fso.GetSpecialFolder(2) & "\" & fso.GetTempName
    
    ' 构建命令行
command = "python " & scriptPath & " """ & emailBody & """" & " > " & tempFile

' 执行命令行
Set shell = CreateObject("WScript.Shell")
shell.Run command, 0, True

' 读取临时文件中的输出结果
Set file = fso.OpenTextFile(tempFile, 1)
result = file.ReadAll
file.Close

' 删除临时文件
fso.DeleteFile tempFile

' 返回结果
RunPythonScript = Trim(result)

 
6.4 Crear reglas de correo

1. Regrese a la interfaz principal de Outlook, haga clic en "Reglas" -> "Administrar reglas y alertas".

2. Haga clic en "Nueva regla" y seleccione "Correo recibido a través de una cuenta específica".

3. Seleccione su cuenta de correo electrónico y haga clic en Siguiente.

4. No es necesario establecer ninguna condición, simplemente haga clic en "Siguiente" y seleccione "Sí".

5. Seleccione "Ejecutar un script" y haga clic en el enlace "Script".

6. En la ventana emergente, seleccione la macro `ProcessNewEmail` recién creada y haga clic en "Aceptar".

7. Haga clic en Finalizar para guardar la regla.

Ahora, cuando reciba correo nuevo, Outlook llamará automáticamente a nuestro filtro de spam para procesarlo. Si el correo electrónico se considera spam, se moverá a la carpeta de spam.

Cabe señalar que este método se basa en el entorno de Python instalado localmente. Los métodos de integración pueden variar en diferentes clientes de correo. El método de implementación específico depende del cliente de correo utilizado y los métodos de extensión que admita.
 

Supongo que te gusta

Origin blog.csdn.net/a871923942/article/details/130556593
Recomendado
Clasificación