机器学习之基于文本内容的垃圾短信识别

机器学习之基于文本内容的垃圾短信识别

1.背景与目标
2.数据探索
3.数据预处理
4.文本的向量表示
5.模型训练与评价

1.背景与目标

  • 我国目前的垃圾短信现状
    垃圾短信黑色利益链
    缺乏法律保护
    短信类型日益多变
    在这里插入图片描述
  • 案例目标:垃圾短信识别。
    基于短信文本内容,建立识别模型,准确地识别出垃圾短信,以解决垃圾短信过滤问题

在这里插入图片描述

2.数据探索

  • 总体流程
    在这里插入图片描述
  • 数据展示
    在这里插入图片描述
    *观察数据,请思考:
    建模前需要对文本数据做哪些处理?
    需要怎么评价模型的好坏?
  • 数据分布
    对原始80万条数据进行数据探索,发现数据中并无存在空值,进一步查看垃圾短信和非垃圾短信的分布情况。
    在这里插入图片描述
  • 欠抽样
    在这里插入图片描述
  • 数据抽取
    随机抽取上文的2W条文本处理后的数据的80%作为训练样本,其余作为测试集样本。

3.数据预处理
步骤:数据清洗----分词—添加词典去停用词—绘制词云

  • 去除空格 (空格及全角情况下的空格)
    在这里插入图片描述
  • x序列 (将银行账户、电话、固话、QQ、价格、日期替换成x序列)

在这里插入图片描述

  • 文本去重
    在数据的的储存和提取过程中,由于技术和某些客观的原因,造成了相同短信文本内容缺失等情况,因此需要对文本数据进行去重,去重即仅保留重复文本中的一条记录。

在这里插入图片描述

  • 中文分词
    中文分词是指以词作为基本单元,使用计算机自动对中文文本进行词语的切分,即使词之间有空格,这样方便计算机识别出各语句的重点内容。
    在这里插入图片描述

  • 正向最大匹配法
    在这里插入图片描述

  • NLP概率图:HMM针对中文分词应用-Viterbi算法
    利用Viterbi算法找出一条概率最大路径。
    在这里插入图片描述

  • python 结巴分词(jieba)支持三种分词模式
    支持繁体分词
    支持自定义词典

  • 停用词过滤
    中文表达中最常用的功能性词语是限定词,如“的”、“一个”、“这”、“那”等。这些词语的使用较大的作用仅仅是协助一些文本的名词描述和概念表达,并没有太多的实际含义。
    而大多数时候停用词都是非自动生产、人工筛选录入的,因为需要根据不同的研究主题人为地判断和选择合适的停用词语。
    在这里插入图片描述

  • 绘制词云图
    词云图是文本结果展示的有利工具,通过词云图的展示可以对短信文本数据分词后的高频词予以视觉上的强调突出效果,使得阅读者一眼就可获取到主旨信息。
    在这里插入图片描述垃圾短信

在这里插入图片描述 正常短信

如何将文本数据放入模型?
在这里插入图片描述
4.文本的向量表示

  • 文本分类实例
    1.'My dog has flea problems, help please.’
    2.'Maybe not take him to dog park is stupid.’
    3.'My dalmation is so cute. I love him.’
    4.'Stop posting stupid worthless garbage.’
    5.'Mr licks ate mu steak, what can I do?.’
    6.'Quit buying worthless dog food stupid’
    labels = [0,1,0,1,0,1] #文档标签:是否是消极情感
  • One-Hot表达
    在这里插入图片描述
    在这里插入图片描述
  • TF-IDF权重策略
    在这里插入图片描述

权重策略文档中的高频词应具有表征此文档较高的权重,除非该词也是高文档频率词
TF:Term frequency即关键词词频,是指一篇文档中关键词出现的频率
在这里插入图片描述
IDF:Inverse document frequency指逆向文本频率,是用于衡量关键词权重的指数,由公式

在这里插入图片描述

  • 文本分类实例

1.分词;去除停用词;
2.转换成词频向量
3.转换成TF-IDF权重矩阵
4.特征提取,构建模型

sklearn.feature_extraction.text  #文本特征提取模块
CountVectorizer           #转化词频向量函数
fit_transform()              #转化词频向量方法
get_feature_names()    #获取单词集合方法
toarray()                       #获取数值矩阵方法
TfidfTransformer          #转化tf-idf权重向量函数
fit_transform(counts)   #转成tf-idf权重向量方法
#相应的库
from sklearn.feature_extraction.text import CountVectorizer,TfidfTransformer
from sklearn.naive_bayes import GaussianNB
transformer = TfidfTransformer()      #转化tf-idf权重向量函数
vectorizer = CountVectorizer()        #转化词频向量函数
word_vec = vectorizer.fit_transform(corpus)     #转成词向量
words = vectorizer.get_feature_names()          #单词集合
word_cout = word_vec.toarray()                  #转成ndarray
tfidf = transformer.fit_transform(word_cout)    #转成tf-idf权重向量
tfidf_ma= tfidf.toarray()                       #转成ndarray
clf = GaussianNB().fit(tfidf_ma[:4,:],labels[:4])
res = clf.predict(tfidf_ma[4:,:])

5.模型训练与评价

  • sklearn. model_selection.train_test_split随机划分训练集和测试集

train_test_split是交叉验证中常用的函数,功能是从样本中随机的按比例选取train data和testdata,形式为:
X_train,X_test, y_train, y_test = model_selection.train_test_split(x_data, y_target, test_size=0.4, random_state=0)

train_test_split参数解释:
x_data:所要划分的样本特征集
y_target:所要划分的样本结果
test_size:样本占比,如果是整数的话就是样本的数量
random_state:是随机数的种子。
随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。
随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:
种子不同,产生不同的随机数;种子相同,即使实例不同也产生相同的随机数。

  • 在train和test上提取的feature维度不同,那么怎么让它们相同呢?
    让两个CountVectorizer共享vocabulary
    cv1 = CountVectorizer(vocabulary=cv.vocabulary_)
    cv_test = cv1.fit_transform(x_test)
    print(cv_test.toarray()) # 测试集的文档词条矩阵
    #cv_test、cv_train向量长度应保持一致
  • 混淆矩阵就是汇总分类模型中分类正确和不正确的样本数目的矩阵。对于简单的二分类问题的混淆矩阵如下表:

另,sklearn中自带混淆矩阵及分类报告

from sklearn.metrics import classification_report,confusion_matrix
  • 精确度表示的是分类为负类的样本中实际为负类的样本所占的比例,精确度越高,模型某类的分类效果越好。

在这里插入图片描述

  • 召回率表示被正确分类的负类的比例,召回率越高,表示模型将负类误分为正类的模型概率越低,模型效果越好。

在这里插入图片描述

  • F1值
    F-Measure(又称为F-Score)综合考虑精确度与召回率,其中P指精确率,R指召回率。F-Measure是精确度和召回率的加权调和平均:
    在这里插入图片描述

当参数α=1时,就是最常见的F1值,即:

在这里插入图片描述

利用处理后的训练集通过训练朴素贝叶斯模型,并由测试集进行分类得到模型分类结果,整理汇总成如下混淆矩阵:
在这里插入图片描述

相关代码如下:(其中可以点击此处获取基于文本内容的垃圾短信识别的所需数据)

#data_process (数据预处理)

import pandas as pd
import re
import jieba


def data_process(file='message80W1.csv'):
    data = pd.read_csv(file, header=None, index_col=0)  #把数据读取进来
    #处理数据
    # data.shape#数据的结构
    # data.head()   #看一下前5行,发现头部多了无关标题,用header=None去掉,3列第1列不需要用index_col=0,使第一列为行索引

    # 欠抽样操作
    data.columns = ['label', 'message']  #列名赋值->标签 内容
    n = 5000
    a = data[data['label'] == 0].sample(n)  #反例正常
    b = data[data['label'] == 1].sample(n)  #正例垃圾
    data_new = pd.concat([a, b], axis=0) #纵向拼接
    #data['label'].value_counts()

    data_dup = data_new['message'].drop_duplicates() #短信去重
    data_qumin = data_dup.apply(lambda x: re.sub('x', '', x)) #对敏感字符x替换成空

    jieba.load_userdict('newdic1.txt')     #将自定义的词典加入
    data_cut = data_qumin.apply(lambda x: jieba.lcut(x))  #data去敏的句子进行分词操作,返回列表

    #去除停用词
    stopWords = pd.read_csv('stopword.txt', encoding='GB18030', sep='hahaha', header=None)     #导入停用词,编码,设置分隔符号
    stopWords = ['≮', '≯', '≠', '≮', ' ', '会', '月', '日', '–'] + list(stopWords.iloc[:, 0])  #增加的分词与以列表为形式的原有分词拼接起来

    data_after_stop = data_cut.apply(lambda x: [i for i in x if i not in stopWords])   #将短信中的停用词去掉

    #数据预处理函数封装
    labels = data_new.loc[data_after_stop.index, 'label']   #标签
    adata = data_after_stop.apply(lambda x: ' '.join(x))   #将列表进行拼接
    #' '.join(data_after_stop[236042 ]

    return adata, data_after_stop, labels

#word_cloud (绘制词云)

from data_process import data_process
from wordcloud import WordCloud
import matplotlib.pyplot as plt


adata, data_after_stop, labels = data_process()

word_fre = {}
for i in data_after_stop[labels == 0]:
    for j in i:
        if j not in word_fre.keys():
            word_fre[j] = 1
        else:
            word_fre[j] += 1

mask = plt.imread('duihuakuan.jpg')
wc = WordCloud(mask=mask, background_color='white', font_path=r'C:\Windows\Fonts\simhei.ttf')
wc.fit_words(word_fre)
plt.imshow(wc)

#model(模型构建与性能评估)

from data_process import data_process
from sklearn.naive_bayes import GaussianNB   #导入高斯朴素贝叶斯
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer #导入文本特征提取模块  转换成词频  向量转换成TF-IDF权重矩阵

adata, data_after_stop, lables = data_process()

data_tr, data_te, labels_tr, labels_te = train_test_split(adata, lables, test_size=0.2)

countVectorizer = CountVectorizer()   #使训练集与测试集的列数相同
data_tr = countVectorizer.fit_transform(data_tr)
X_tr = TfidfTransformer().fit_transform(data_tr.toarray()).toarray() #训练集TF-IDF权值

data_te = CountVectorizer(vocabulary=countVectorizer.vocabulary_).fit_transform(data_te)
X_te = TfidfTransformer().fit_transform(data_te.toarray()).toarray()    #测试集TF-IDF权值

model = GaussianNB()
model.fit(X_tr, labels_tr)
model.score(X_te, labels_te)

运行结果:
在这里插入图片描述

本案例教程视频可以参考此链接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章