垃圾邮件识别,算是一个二分类问题,也是一个相对简单的文本分类问题。
本文数据来自UCI机器学习仓库中的垃圾信息数据集,从http://archive.ics.uci.edu/ml/datasets/sms+spam+collection下载。
文件中每一行由两部分组成,行首是标签 spam/ham(spam 代表垃圾邮件),中间空一格,之后是邮件内容。
以下代码是一个整体,如需复制,将除了函数部分的代码按顺序复制,函数需要放在库和其它代码之间
需要用到的库:
import nltk
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
数据提取
源文件无类型后缀,就当作普通文本文件读取:
sms_data = open('.\SMSSpamCollection', 'r', encoding='utf-8')
x = []
y = []
for line in sms_data.readlines():
data = line.split('\t')
y.append(data[0])
x.append(data[1].split('\n')[0])
sms_data.close()
数据预处理
上面倒数第二行里面使用了一个自定义函数,把与邮件内容关系不大的单词(停用词等)去除,这样做能减少特征数量但对训练精度没什么影响
因为数据集中的内容为英文,这里我使用 NLTK 库进行处理,如果选择中文数据更推荐使用 jieba 库
def text_dispose(text):
# 将每个单词和符号分开
sentences = nltk.sent_tokenize(text)
words = [word for sent in sentences for word in nltk.word_tokenize(sent)]
stops = stopwords.words('english')
# 去除停用词
words = [word for word in words if words not in stops]
words = [words.lower() for words in words if len(words) >= 3]
# 词汇化
lemmatizer = WordNetLemmatizer()
words = [lemmatizer.lemmatize(words) for words in words]
dispose_text = ' '.join(words)
return dispose_text
数据拆分及文本特征处理
数据拆分成常见的三七开
特征处理是文本分类的关键部分,因为我们不可能把整个文本内容直接放进模型中训练,所以需要将文本表示为计算机可以识别的、能够代表该文档特征的特征矩阵
# 拆分
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1)
# 特征处理
vectorizer = TfidfVectorizer(min_df=2, ngram_range=(1,2), stop_words='english', strip_accents='unicode',norm='l2')
X_train = vectorizer.fit_transform(x_train)
X_test = vectorizer.transform(x_test)
TfidfVectorizer
可以把原始文本转化为 TF-IDF
的特征矩阵
选择模型并训练
这里使用朴素贝叶斯分类器
model = MultinomialNB()
model.fit(X_train,y_train)
score = model.score(X_test, y_test)
print(score)
因为 sklearn 的高度封装,只需几行代码就可以使用特定算法。我们不需要写出算法的流程,只要知道其功能即可,所以 sklearn 适用于快速构建模型。当然如果想让算法定制性更强,则需要自行构建
看评分结果:
0.9689181111775254