基于LSTM的短信垃圾信息检测模型

在当今数字化时代,几乎每个人都在使用手机,并且每天都会收到大量的短信和电子邮件。然而,这些信息中很多都是垃圾信息,只有少数是需要的正常信息。本文将介绍如何使用长短期记忆网络(LSTM)来构建一个短信垃圾信息检测模型,帮助区分垃圾短信和正常短信。

数据集介绍

使用的是公开的短信垃圾信息检测数据集,该数据集包含了短信文本及其对应的标签(垃圾信息或正常信息)。

实现过程

首先,需要导入所有必要的库来进行数据预处理

import pandas as pd import numpy as np import re import collections import contractions import seaborn as sns import matplotlib.pyplot as plt plt.style.use('dark_background') import nltk from nltk.stem import WordNetLemmatizer from nltk.corpus import stopwords import warnings warnings.simplefilter(action='ignore', category=Warning) import keras from keras.layers import Dense, Embedding, LSTM, Dropout from keras.models import Sequential from keras.preprocessing.text import Tokenizer from keras.preprocessing.sequence import pad_sequences import pickle

导入短信垃圾信息检测数据集

使用pandas库读取数据集,并查看数据集的前几行以及数据集的形状。

df = pd.read_csv("spam.csv", encoding='latin-1') df.head() df.shape # 输出 - (5572, 8674)

数据集中包含了一些对无用的列,因此需要删除这些列,并为了方便起见,重命名列名。

df.drop(["Unnamed: 2", "Unnamed: 3", "Unnamed: 4"], axis=1, inplace=True) df.columns = ["SpamHam","Tweet"]

接下来,使用seaborn库绘制垃圾短信和正常短信的数量对比图。

sns.countplot(data["SpamHam"])

从图中可以看出,正常短信的数量多于垃圾短信。在进行数据预处理之前,先绘制数据集中不同单词的数量分布图。为此,创建了一个名为word_count_plot的函数。

def word_count_plot(data): # 寻找单词及其计数 word_counter = collections.Counter([word for sentence in data for word in sentence.split()]) most_count = word_counter.most_common(30) # 30个最常见单词 # 排序数据框 most_count = pd.DataFrame(most_count, columns=["Word", "Count"]).sort_values(by="Count") most_count.plot.barh(x = "Word", y = "Count", color="green", figsize=(10, 15))

通过这个函数,可以清楚地看到数据集中的大部分单词都是停用词。因此,需要对数据集进行一些预处理技术。

lem = WordNetLemmatizer() def preprocessing(data): sms = contractions.fix(data) # 将缩写词转换为原始形式(例如:"I'm" 转换为 "I am") sms = sms.lower() # 小写化短信 sms = re.sub(r'https?://S+|www.S+', "", sms).strip() # 移除URL sms = re.sub("[^a-z ]", "", sms) # 移除符号和数字 sms = sms.split() # 分割 # 词形还原和停用词移除 sms = [lem.lemmatize(word) for word in sms if not word in set(stopwords.words("english"))] sms = " ".join(sms) return sms

对数据集应用预处理函数,然后再次绘制单词数量分布图,以查看除了停用词之外的最常见单词。

X = data["v2"].apply(preprocessing) word_count_plot(X)

现在可以看到除了停用词之外的最常见单词。接下来,继续进行预处理。由于输出值(垃圾信息或正常信息)是分类值,需要将它们转换为数值形式。使用LabelEncoder进行编码。

from sklearn.preprocessing import LabelEncoder lb_enc = LabelEncoder() y = lb_enc.fit_transform(data["SpamHam"])

将输出特征转换为数值形式后,接下来,需要将输入特征也转换为数值形式,使用keras的Tokenizer,然后进行填充。

tokenizer = Tokenizer() # 初始化tokenizer tokenizer.fit_on_texts(X)# 适应短信数据 text_to_sequence = tokenizer.texts_to_sequences(X) # 创建数值序列

可以查看一些文本及其对应的数值序列。

for i in range(5): print("Text : ",X[i] ) print("Numerical Sequence : ", text_to_sequence[i])

还可以通过tokenizer.index_word找到对应单词的索引号。

tokenizer.index_word # 这将输出一个索引和单词的字典

这个字典包含了7774个单词,意味着数据集中有7774个唯一的单词。

如所见,在text_to_sequence中,所有的序列长度都不同,这不利于模型训练。因此,需要使所有句子长度相等。为此,用“0”填充序列。

max_length_sequence = max([len(i) for i in text_to_sequence]) padded_sms_sequence = pad_sequences(text_to_sequence, maxlen=max_length_sequence, padding = "pre")

已经准备好了适合输入模型的输入数据。现在,来创建LSTM模型进行训练。

TOT_SIZE = len(tokenizer.word_index)+1 def create_model(): lstm_model = Sequential() lstm_model.add(Embedding(TOT_SIZE, 32, input_length=max_length_sequence)) lstm_model.add(LSTM(100)) lstm_model.add(Dropout(0.4)) lstm_model.add(Dense(20, activation="relu")) lstm_model.add(Dropout(0.3)) lstm_model.add(Dense(1, activation = "sigmoid")) return lstm_model lstm_model = create_model() lstm_model.compile(loss = "binary_crossentropy", optimizer = "adam", metrics = ["accuracy"]) lstm_model.summary() lstm_model.fit(padded_sms_sequence, y, epochs = 5, validation_split=0.2, batch_size=16) pickle.dump(tokenizer, open("sms_spam_tokenizer.pkl", "wb")) pickle.dump(lstm_model, open("lstm_model.pkl", "wb"))
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485