垃圾邮件检测:第2部分

2021-11-10 17:33:46 浏览数 (1)


磐创AI分享

作者 | Md Sohel Mahmood 编译 | VK 来源 | Towards Data Science

介绍

对自然语言进行分类是当今自然语言处理面临的巨大挑战之一。

它涉及到能够有效区分目标文本和正常文本的技术。其他服务,如聊天机器人,也严重依赖用户输入的文本。他们需要处理大量数据,以确定用户需求并引导正确的路径。

Tensorflow的使用

在本垃圾邮件分类器的第1部分中,我展示了如何使用nltk包对文本进行词干分析和分类,然后将其输入分类器模型,以训练并最终评估模型性能。我已经展示了朴素贝叶斯、SVC和随机森林作为电子邮件分类器的性能。

https://towardsdatascience.com/ml-classifier-performance-comparison-for-spam-emails-detection-77749926d508

在本文中,我将演示如何使用Tensorflow对电子邮件进行token化和有效分类。让我们开始吧。

代码语言:javascript复制
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences

我已经包括了pad_sequence,它将用于使所有文本数组大小相等。padding可以根据最大尺寸进行,可以是后填充或预填充。下面定义超参数

代码语言:javascript复制
vocab_size = 1000
embedding_dim = 64
max_length = 120
trunc_type='post'
padding_type='post'
oov_tok = "<OOV>"

用户可以使用这些参数来防止训练数据过拟合。例如,可以减少词汇量,以尽量减少对低频词的过拟合。同样,嵌入维数越低,模型得到训练的速度就越快。我还包括了一个词汇表外单词的标记。

我将使用第1部分中使用的相同数据集。

代码语言:javascript复制
spam = pd.read_csv('spam.csv',  encoding='latin-1')
spam = spam.filter(['v1','v2'], axis=1)
spam.columns = ['label', 'text']

sentences = []
labels = []
for i in range(0,spam.shape[0],1):
    sentences.append(spam['text'][i])
    labels.append(spam['label'][i])

我已经分配了整个数据集的80%用于训练,剩下的将用于测试。

代码语言:javascript复制
training_size = int(spam.shape[0]*0.8)
training_sentences = sentences[0:training_size]
testing_sentences = sentences[training_size:]
training_labels_str = labels[0:training_size]
testing_labels_str = labels[training_size:]
对标签进行编码

由于数据集的标签为字符串,因此将通过编码为0和1(0表示垃圾邮件,1表示真实文本)将其转换为整数。

代码语言:javascript复制
training_labels = [0] * len(training_labels_str)
for ind,item in enumerate(training_labels_str):
    if item == 'ham':
        training_labels[ind] = 1
    else:
        training_labels[ind] = 0

testing_labels = [0] * len(testing_labels_str)
for ind,item in enumerate(testing_labels_str):
    if item == 'ham':
        testing_labels[ind] = 1
    else:
        testing_labels[ind] = 0

接下来将完成将文本和标签转换为numpy数组。

代码语言:javascript复制
training_padded = np.array(training_padded)
testing_padded = np.array(testing_padded)

training_labels = np.array(training_labels)
testing_labels = np.array(testing_labels)

tokenizer = Tokenizer(num_words=vocab_size, oov_token=oov_tok)
tokenizer.fit_on_texts(training_sentences)

word_index = tokenizer.word_index

如前所述,需要进行填充以使数组长度相等。

代码语言:javascript复制
training_sequences = tokenizer.texts_to_sequences(training_sentences)
training_padded = pad_sequences(training_sequences, maxlen=max_length, padding=padding_type, truncating=trunc_type)

testing_sequences = tokenizer.texts_to_sequences(testing_sentences)
testing_padded = pad_sequences(testing_sequences, maxlen=max_length, padding=padding_type, truncating=trunc_type)
模型定义

然后使用RNN和双向LSTM算法定义模型。这里利用双向LSTM在RNN上获得最佳性能。

代码语言:javascript复制
model = tf.keras.Sequential([
    tf.keras.layers.Embedding(vocab_size, embedding_dim, input_length=max_length),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(32)),
    tf.keras.layers.Dense(24, activation='relu'),
    tf.keras.layers.Dropout(0.25),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

adam = tf.keras.optimizers.Adam(learning_rate=0.0001, beta_1=0.9, beta_2=0.999, amsgrad=False)

model.compile(loss='binary_crossentropy',optimizer=adam,metrics=['accuracy'])
model.summary()
代码语言:javascript复制
num_epochs = 20
history = model.fit(training_padded, training_labels, epochs=num_epochs, 
                    validation_data=(testing_padded, testing_labels), verbose=1)
训练模型

经过20个epoch后,模型得到了良好的训练,验证数据(此处为测试数据)的准确度约为98%

然后预测。

代码语言:javascript复制
X_train = training_padded
X_test = testing_padded

y_train = training_labels
y_test = testing_labels

from sklearn.metrics import confusion_matrix, classification_report, accuracy_score
y_pred = model.predict(X_test)

# 将预测值转换为0或1
y_prediction = [0] * y_pred.shape[0]
for ind,item in enumerate(y_pred):
    if item > 0.5:
        y_prediction[ind] = 1
    else:
        y_prediction[ind] = 0

rep = classification_report(y_test, y_prediction)

报告显示,该模型对这两个文本类都有很好的精确度、召回率和F1分数(0表示垃圾邮件,1表示正常邮件)。对于0,召回率比精度稍低,这表明存在一些假阴性。该模型错误地将一些正常电子邮件识别为垃圾邮件。

我们可以识别任何示例文本,以检查它是垃圾邮件还是正常文本。由于tokenizer已经定义,我们不再需要再次定义它。我们所需要的只是token化示例文本,用0填充它,然后传递给模型进行预测。

选择一些朗朗上口的词,如“WINNER”, “free”, ”prize”,最终会使此文本被检测为垃圾邮件。

代码语言:javascript复制
sample_text = ["Winner!!! Darling please click the link to claim your free prize"]

sample_text_tokenized  = tokenizer.texts_to_sequences(sample_text)
sample_text_tokenized_padded = pad_sequences(sample_text_tokenized, maxlen=max_length, padding=padding_type, truncating=trunc_type)

# 0是垃圾邮件,1是正常邮件
pred = float(model.predict(sample_text_tokenized_padded))
if (pred>0.5):
    print ("This is a real email")
else:
    print("This is a spam")
结论

本文演示了如何使用Tensorflow有效地训练具有高精度的NLP模型,然后评估模型性能参数,如精度、召回率和F1分数。有了这个小数据集,20个epoch似乎可以生成一个优秀的模型,验证准确率约为98%。

Github页面:https://mdsohelmahmood.github.io/2021/06/23/Spam-email-classification-Part2-Tensorflow.html

0 人点赞