词向量与垃圾邮件识别
前置知识-词袋和词向量
机器学习模型所接受的样本是一行一行的,每一行都有很多个列,每个列上是对应的数据。一行就是一个向量。
我们要做的就是找寻一个方法,使得一封邮件的文字内容最终变成一个向量。
好在前人已经为了提供了成熟的思考方式。
例如对于,四个文本
- “dog cat fish”
- “dog cat cat”
- “fish bird”
- “bird”
我们可以构建一个如下列表
index | dog | cat | fish | bird |
---|---|---|---|---|
文本1 | 1 | 1 | 1 | 0 |
文本2 | 1 | 2 | 0 | 1 |
文本3 | 0 | 0 | 1 | 1 |
文本4 | 0 | 0 | 0 | 1 |
其中数字代表的是对应文本中对应词的出现次数。
[dog,cat,fish,bird] 我们称呼为词袋。
每一行的数据称为词向量。最终我们将使用词向量去评估是否是垃圾邮件。
词向量模式做了一个天真的假设。
- 文章性质和顺序无关,只与出现的词语的词频有关。
本文中我假设你有机器学习的基础,在此基础上,我们来完整的搭建一个邮件识别demo。
实际上,通过sklearn实现词向量并不难。你可以参考如下代码。
from sklearn.feature_extraction.text import CountVectorizer
texts=["dog cat fish","dog cat cat","fish bird", 'bird'] #文本列表
cv = CountVectorizer() #创建词向量发生器
cv_fit=cv.fit_transform(texts) #文本转词向量
print(cv.get_feature_names()) #打印词袋
print(cv_fit.toarray()) #以矩阵形式打印词向量
['bird', 'cat', 'dog', 'fish']
[[0 1 1 1]
[0 2 1 0]
[1 0 0 1]
[1 0 0 0]]
需要注意的是,sklearn提供的词向量技术十分完善,对应英文文本中符号部分会直接滤除。注意下面的代码加了很多符号。
from sklearn.feature_extraction.text import CountVectorizer
texts=["dog @ cat fish","! dog cat cat","#!@ fish bird", 'bird'] #文本列表
cv = CountVectorizer() #创建词向量发生器
cv_fit=cv.fit_transform(texts) #文本转词向量
print(cv.get_feature_names()) #打印词袋
print(cv_fit.toarray()) #以矩阵形式打印词向量
['bird', 'cat', 'dog', 'fish']
[[0 1 1 1]
[0 2 1 0]
[1 0 0 1]
[1 0 0 0]]
这种强大的特性使得我们在数据清洗上需要完成的工作更少。
数据与代码流程
你可以从这儿下载数据。
链接: https://pan.baidu.com/s/1YQBcsKXvL_0F27xr3YOwxg 提取码: dgid
代码流程如图。
词向量构建
def get_articles(postions,names):
result=[]
for name in names:
with open(postions+"/"+name) as f:
result.append(f.read())
return result
import os
postions=("email/ham","email/spam")
names=tuple(map(os.listdir,postions))
articles=(get_articles(postions[0],names[0]),get_articles(postions[1],names[1]))
from sklearn.feature_extraction.text import CountVectorizer
all_articles=articles[0]+articles[1]
cv = CountVectorizer()
cv_fit=cv.fit_transform(all_articles)
print(cv.get_feature_names())
print(cv_fit.toarray())
机器学习部分
data=cv_fit.toarray()
target=25*[0]+25*[1]
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(data,target,test_size=0.25)
from sklearn.naive_bayes import MultinomialNB
clf = MultinomialNB(alpha=0.0001)
clf.fit(X_train, y_train)
train_score = clf.score(X_train, y_train)
print("train score: {0}".format(train_score))
print("predict: {0}".format(clf.predict(X_test)-y_test)) #显示预测差
train score: 1.0
predict: [0 0 0 0 0 0 0 0 0 0 0 0 0]
结果相当好,全部预测正确