1.数据读取

# ①数据读取
sms=open("./data/SMSSpamCollection",'r',encoding='utf-8')  #数据读取
sms_data=[]         #字符串列表
sms_label=[]
csv_reader=csv.reader(sms,delimiter='\t')

# ②数据预处理
for line in csv_reader:                                 #6.对每封邮件进行预处理
    sms_label.append(line[0])
    sms_data.append(preprocessing(line[1]))             #对每封优先预处理,生成有效词的字符串
sms.close()       #关闭文件

2.数据预处理

def preprocessing(text):
    # 1-2.对输入的文本进行分句、分词,并进分解后的词存放在token中
    tokens=[word for sent in nltk.sent_tokenize(text)for word in nltk.word_tokenize(sent)]

    #3.去除停用词(如i\me\my)
    stops=stopwords.words("english")
    tokens = [token for token in tokens if token not in stops]

    #4.大小写转换,并去掉短于3的词
    tokens=[token.lower() for token in tokens if len(token) >=3]

    #NLTK词性标注(
    nltk.pos_tag(tokens)

    #5.词性还原Lemmatisation
    lemmatizer=WordNetLemmatizer()  #定义还原对象
    tokens=[lemmatizer.lemmatize(token,pos='n')for token in tokens]  #名词(单复数)还原
    tokens=[lemmatizer.lemmatize(token,pos='v')for token in tokens]  #动词(时态)还原
    tokens=[lemmatizer.lemmatize(token,pos='a')for token in tokens]  #形容词(级别)还原

    return tokens;  #返回处理完成后的文本

【以上两步详细请查看作业12朴素贝叶斯-垃圾邮件分类】

3.数据划分—训练集和测试集数据划分

from sklearn.model_selection import train_test_split

x_train,x_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=0, stratify=y_train)

# ③数据划分—训练集和测试集数据划分
# 训练集与测试以8:2的比例划分
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(sms_data, sms_label, test_size=0.2, random_state=0, stratify=sms_label)
print("样本总数:",len(sms_data),"训练集样本总数:",len(x_train),"测试集样本总数:",len(y_train))

垃圾邮件分类 python 垃圾邮件分类问题_数据

4.文本特征提取

sklearn.feature_extraction.text.CountVectorizer

https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.CountVectorizer.html?highlight=sklearn%20feature_extraction%20text%20tfidfvectorizer

sklearn.feature_extraction.text.TfidfVectorizer

https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html?highlight=sklearn%20feature_extraction%20text%20tfidfvectorizer#sklearn.feature_extraction.text.TfidfVectorizer

from sklearn.feature_extraction.text import TfidfVectorizer

tfidf2 = TfidfVectorizer()

观察邮件与向量的关系

# ④文本特征提取
# 将文本数据转化成特征向量的过程,使用较为常用的文本特征表示法——词袋法。
# TfidfVectorizer:把原始文本转化为tf-id的特征矩阵
from sklearn.feature_extraction.text import TfidfVectorizer    
tfidf2 = TfidfVectorizer()
X_train=tfidf2.fit_transform(x_train)   #向量化转化
X_test=tfidf2.transform(x_test)
tfidf2.vocabulary_     #词汇表[单词:所处位置]

垃圾邮件分类 python 垃圾邮件分类问题_召回率_02

向量还原为邮件

#4.2向量转化为邮件
import numpy as np
print("第一个邮件向量",X_train.toarray()[0])
a=np.flatnonzero(X_train.toarray()[0])
print("向量中非零元素位置:",a)
print("向量中非零元素的值:",X_train.toarray()[0][a])
b=tfidf2.vocabulary_   #词汇表
key_list=[]
for key,value in b.items():
    if value in a:
        key_list.append(key)
print("在词汇表中查询到的单词为:",key_list,"向量化前邮件为:",x_train[0])

垃圾邮件分类 python 垃圾邮件分类问题_混淆矩阵_03

5.模型选择

from sklearn.naive_bayes import GaussianNB     高斯朴素贝叶斯模型

from sklearn.naive_bayes import MultinomialNB  多项式分布模型

说明为什么选择这个模型?

高斯分布模型:属正态分布,可以将连续型变量转换成离散型的值;当样本数据中的值大多处于一个相近的区间,而其他区间出现较少时,就较为符合高斯分布模型。

多项式分布模型:多适用于离散型数据的预测。

垃圾邮件分类是以单词在垃圾邮件文本中出现的频率与在其他文本中所出现的频率进行预测,邮件的值是随机散乱的,所以多项式分布模型更为符合。

# ⑤模型选择
from sklearn.naive_bayes import MultinomialNB   #多项式分布模型
mnb=MultinomialNB() #构造模型
mnb.fit(X_train,y_train) #训练模型
pre=mnb.predict(X_test) #预测
print("预测总数:",len(y_test),"预测错误个数:",(pre!=y_test).sum(),"预测正确个数:",(pre==y_test).sum())

垃圾邮件分类 python 垃圾邮件分类问题_召回率_04

6.模型评价:混淆矩阵,分类报告

from sklearn.metrics import confusion_matrix

confusion_matrix = confusion_matrix(y_test, y_predict)

说明混淆矩阵的含义

混淆矩阵也称误差矩阵,是表示精度评价的一种标准格式,用n行n列的矩阵形式来表示。

混淆矩阵的每一列代表了预测类别,每一列的总数表示预测为该类别的数据的数目;

每一行代表了数据的真实归属类别,每一行的数据总数表示该类别的数据实例的数目。

每一列中的数值表示真实数据被预测为该类的数目;

垃圾邮件分类 python 垃圾邮件分类问题_召回率_05

from sklearn.metrics import classification_report

说明准确率、精确率、召回率、F值分别代表的意义

 准确率(正确率)=所有预测正确的样本/总的样本 =(TP+TN)/总

垃圾邮件分类 python 垃圾邮件分类问题_数据_06

 精确率=  将正类预测为正类 / 所有预测为正类 =  TP/(TP+FP)

垃圾邮件分类 python 垃圾邮件分类问题_垃圾邮件分类 python_07

 召回率 = 将正类预测为正类 / 所有正真的正类 =TP/(TP+FN))

垃圾邮件分类 python 垃圾邮件分类问题_召回率_08

 F值 = 精确率 * 召回率 * 2 / ( 精确率 + 召回率) (F 值即为精确率和召回率的调和平均值)

垃圾邮件分类 python 垃圾邮件分类问题_召回率_09

# ⑥模型评价:混淆矩阵,分类报告
from sklearn.metrics import confusion_matrix       #混淆矩阵
from sklearn.metrics import classification_report  #分类报告
cm=confusion_matrix(y_test,pre)
print("混淆矩阵:",cm)
print("预测正确率:",(cm[0][0]+cm[1][1])/np.sum(cm))
print("预测错误率",(cm[0][1]+cm[1][0])/np.sum(cm))
cr=classification_report(y_test,pre)
print("分类报告:\n",cr)

垃圾邮件分类 python 垃圾邮件分类问题_数据_10

7.比较与总结

如果用CountVectorizer进行文本特征生成,与TfidfVectorizer相比,效果如何?

CountVectorizer:只考虑词汇在文本中出现的频率,属于词袋模型特征。

TfidfVectorizer: 除了考量某词汇在文本出现的频率,还关注包含这个词汇的所有文本的数量。能够削减高频没有意义的词汇出现带来的影响, 挖掘更有意义的特征。属于Tfidf特征。

相比之下,文本条目越多,Tfid的效果会越显著。

CountVectorizer与TfidfVectorizer相比,对于负类的预测更加准确,而正类的预测则稍逊色。但总体预测正确率也比TfidfVectorizer稍高,相比之下似乎CountVectorizer更适合进行预测。


from sklearn.feature_extraction.text import CountVectorizer
count=CountVectorizer()
X_train_CV=count.fit_transform(x_train)   #向量化转化
X_test_CV=count.transform(x_test)
mnb.fit(X_train_CV,y_train) #训练模型
pre_CV=mnb.predict(X_test_CV) #预测
cm=confusion_matrix(y_test,pre_CV)
print("CountVectorizer")
print("混淆矩阵:",cm)
print("预测正确率:",(cm[0][0]+cm[1][1])/np.sum(cm))
print("预测错误率",(cm[0][1]+cm[1][0])/np.sum(cm))
cr=classification_report(y_test,pre)
print("分类报告:\n",cr)

垃圾邮件分类 python 垃圾邮件分类问题_数据_11