热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【深度学习系列】PaddlePaddle垃圾邮件处理实战(一)

PaddlePaddle垃圾邮件处理实战(一)背景介绍  在我们日常生活中,经常会受到各种垃圾邮件,譬如来自商家的广告、打折促销信息、澳门博彩邮件、理财推广信息等,一般来说邮件客户端都会设置一

PaddlePaddle垃圾邮件处理实战(一)

背景介绍

  在我们日常生活中,经常会受到各种垃圾邮件,譬如来自商家的广告、打折促销信息、澳门博彩邮件、理财推广信息等,一般来说邮件客户端都会设置一定的关键词屏蔽这种垃圾邮件,或者对邮件进行归类,但是总会有一些漏网之鱼。
  不过,自己手动做一个垃圾邮件分类器也并不是什么难事。传统的机器学习算法通常会采用朴素贝叶斯、支持向量机等算法对垃圾邮件进行过滤,今天我们主要讲如何用PaddlePaddle手写一个垃圾邮件分类器。当然,在讲PaddlePaddle做垃圾邮件处理之前,先回顾一下传统的机器学习算法是如何对垃圾邮件进行分类的。

了解数据集

  首先先了解一下今天的数据集:trec06c。trec06c是一个公开的垃圾邮件语料库,由国际文本检索会议提供,分为英文数据集(trec06p)和中文数据集(trec06c),其中所含的邮件均来源于真实邮件保留了邮件的原有格式和内容。
文件下载地址:trec06c
文件格式:

trec06c
│
└───data
│   │   000
│   │   001
│   │   ...
│   └───215
└───delay
│   │   index
└───full
│   │   index   

文件内容:

垃圾邮件示例:本公司有部分普通发票(商品销售发票)增值税发票及海关代征增值税专用缴款书及其它服务行业发票,公路、内河运输发票。可以以低税率为贵公司代开,本公司具有内、外贸生意实力,保证我司开具的票据的真实性。 希望可以合作!共同发展!敬侯您的来电洽谈、咨询! 联系人:李先生 联系电话:13632588281 如有打扰望谅解,祝商琪。
正常邮件示例:讲的是孔子后人的故事。一个老领导回到家乡,跟儿子感情不和,跟贪财的孙子孔为本和睦。老领导的弟弟魏宗万是赶马车的。有个洋妞大概是考察民俗的,在他们家过年。孔为本总想出国,被爷爷教育了。最后,一家人基本和解。 顺便问另一类电影,北京青年电影制片厂的。

数据预处理

  拿到数据后我们可以很清楚的看到邮件的内容,但并不是所有的内容都是我们需要的,在这里我们仅提取了邮件中的中文来作为训练语料。如果仔细观察的话,会发现不是所有的邮件都能直接打开,数据的编码格式也需要转换成utf-8格式方便我们后面训练使用。所以我们需要对原始数据做一些数据预处理,包括以下几个内容。

基本步骤

  • 转换源数据编码格式为utf-8格式
  • 过滤字符
    • 去除所有非中文字符,如标点符号、英文字符、数字、网站链接等特殊字符。
  • 过滤停用词
  • 对邮件内容进行分词处理

训练代码

下面是具体的代码 transfer.py:

# -*- coding: utf-8 -*-
#Created by huxiaoman 2018.1.28
#transfer.py:生成spam和ham数据
import jieba
import sys
import os
import re

# 判断邮件中的字符是否是中文
def check_contain_chinese(check_str):
    for ch in check_str.decode('utf-8'):
        if u'\u4e00' <= ch <= u'\u9fff':
            return True
    return False

# 加载邮件数据的label
def load_label_files(label_file):
    label_dict ={}
    for line in open(label_file).readlines():
        list1 = line.strip().split("..")
        label_dict[list1[1].strip()] = list1[0].strip()
    return label_dict

# 加载停用词词表
def load_stop_train(stop_word_path):
    stop_dict = {}
    for line in open(stop_word_path).readlines():
        line = line.strip()
        stop_dict[line] = 1
    return stop_dict

# 读取邮件数据,并转换为utf-8格式,生成spam和ham样本
def read_files(file_path,label_dict,stop_dict,spam_file_path,ham_file_path):
    parents = os.listdir(file_path)
    spam_file = open(spam_file_path,'a')
    ham_file = open(ham_file_path,'a')
    for parent in parents:
        child = os.path.join(file_path,parent)
        if os.path.isdir(child):
            read_files(child,label_dict,stop_dict,spam_file_path,ham_file_path)
        else:
            print child[10:]
            label = "unk"
            if child[10:] in label_dict:
                label = label_dict[child[10:]]
            # deal file
            temp_list = []
            for line in open(child).readlines():
                line = line.strip().decode("gbk",'ignore').encode('utf-8')
                if not check_contain_chinese(line):
                    continue
                seg_list = jieba.cut(line, cut_all=False)
                for word in seg_list:
                    if word in stop_dict:
                        continue
                    else:
                        temp_list.append(word)
            line = " ".join(temp_list)
            print label
            if label == "spam":
                spam_file.write(line.encode("utf-8","ignore") + "\n")
            if label == "ham":
                ham_file.write(line.encode("utf-8","ignore")+"\n")

# 生成word2vec词表
def generate_word2vec(file_path,label_dict,stop_dict,word_vec):
    parents = os.listdir(file_path)
    fh1 = open(word_vec,'a')
    i = 0

    for parent in parents:
        child = os.path.join(file_path,parent)
        if os.path.isdir(child):
            generate_word2vec(child,label_dict,stop_dict,word_vec)
        else:
            print child[10:]
            i += 1
            print i
            label = "unk"
            if child[10:] in label_dict:
                label = label_dict[child[10:]]
            # deal file
            temp_list = []
            for line in open(child).readlines():
                line = line.strip().decode("gbk",'ignore').encode('utf-8')
                if not check_contain_chinese(line):
                    continue
                if len(line) == 0:
                    continue
                seg_list = jieba.cut(line, cut_all=False)
                for word in seg_list:
                    if word in stop_dict:
                        continue
                    else:
                        temp_list.append(word)
            line = " ".join(temp_list)
            fh1.write(line.encode("utf-8","ingore")+"\n")

if __name__=="__main__":
    file_path = sys.argv[1]
    label_path = sys.argv[2]
    stop_word_path = "stop_words.txt"
    word_vec_path = "word2vec.txt"
    spam_data = "spam.txt"
    ham_data = "ham.txt"
    label_dict = load_label_files(label_path)
    stop_dict = load_stop_train(stop_word_path)
    read_files(file_path,label_dict,stop_dict,spam_data,ham_data)

运行脚本

run.sh:

bashif [ $1 = "test" ]; then
    echo "test"
    python transfer.py ../test/ ../trec06c/full/index
else
    echo "whole"
    python transfer.py ../trec06c/data/ ../trec06c/full/index
fi

运行方式:

sh run.sh

运行结果:

  • ham.txt: 正样本,正常邮件。共21373条数据。
    • 示例:我 就 闹 不 明白 了 只要 你 本人 不介意 跟 你 爸爸妈妈 有 何干 为啥 要说 呢 ..... 首先 谢谢 大家 安慰 我 。 但是 我 确实 很 难受 , 我 有 自己 的 苦衷 。 我 不敢 和 我 妈妈 说 的 这种 情况 。 我 妈妈 是 那种 特别 容易 担心 的 那种 类型 。 而且 我 又 不 在 她 身边 。 我家 是 外地 的 。 如果 和 妈妈 说 了 , 她 一定 不会 同意 我 和 在 一起 的 。 妈妈 对 身体健康 看 的 特别 重要 。 有 一年 姐夫 那年 经常 流鼻血 , 妈妈 都 特别 担心 , 老 催 姐姐 带 着 去 看看 。
  • spam.txt: 负样本,垃圾邮件。共41627条数据。
    • 示例:您好 以下 是 特别 为 阁下 发 的 香港 信息 图片 、 景点 等 不 知道 阁下 是否 喜 希望 没有 打扰到 阁下 如果 无法 看到 下面 内容 请 稍侯 或者 直接 进入 香港 行网 域名论坛 地址 真诚 为您服务
  • word2vec.txt: 包含所有邮件分词的内容,为Word2Vec提供训练预料。共63000条数据。
    • 示例:我 觉得 , 负债 不要紧 , 最 重要 的 是 能 负得起 这个 责任 来 , 欠 了 那么 多钱 , 至少 对 当初 拿出 爱心 来 的 网友 们 有 个 交待 , 还 , 还是 不 还 了 , 或者 , 是 有 这个 心 但 实在 没 能力 , 说明 一声 还 都 好 不要 连 ID 都 不 激活 了 , 连 手机号 都 换 了 … … 别说 外地 的 了 , 就 连 北京 的 网友 都 找 不到 他 … … 他 当时 在 水木 fl 版 的 那阵 , 我 旁观 了 全过程 。

生成词向量

传统方法的局限性

  我们知道,分词后的数据是不能直接拿到模型里去训练的,我们需要把词语转换成词向量才能进行模型的训练,这样一个词可以有一个多维的词向量组成。
  传统的方法是one-hot encoding,即用一个长向量来表示一个词,向量的长度为词典的大小,向量的分量只有一个1,其余全为0,1的位置即对应改词在词典中的位置,如电脑表示为:[0 0 0 0 0 1 0 0 0 0 ],耳机表示为[0 0 0 0 0 0 0 1 0 ]这种方式如果采用稀疏存储,表达简洁,占用空间少,但是这种方法也有几个缺点,一是容易受维数灾难的困扰,尤其是将其用于 Deep Learning的一些算法时;二是不能很好地刻画词与词之间的相似性,即任意两个词之间都是孤立的。光从这两个向量中看不出两个词是否有关系,损失大部分信息,导致结果会有较大偏差。

Word2Vec方法的优势

  在1968年Hinton又提出了Distributed REpresentation,可以解决One-hot encoding的缺点。其基本想法是直接用一个普通的向量表示一个词,这种向量一般长成这个样子:[0.792, −0.177, −0.107, 0.109, −0.542, ...],也就是普通的向量表示形式。维度以 50 维和 100 维比较常见。当然一个词怎么表示成这么样的一个向量需要通过训练得到,训练方法较多,word2vec是最常见的一种。需要注意的是,每个词在不同的语料库和不同的训练方法下,得到的词向量可能是不一样的。词向量一般维数不高,一般情况下指定1000、500维就可以了,所以用起来维数灾难的机会现对于one-hot representation表示就大大减少了。
  由于是用向量表示,而且用较好的训练算法得到的词向量的向量一般是有空间上的意义的,也就是说,将所有这些向量放在一起形成一个词向量空间,而每一向量则为该空间中的一个点,在这个空间上的词向量之间的距离度量也可以表示对应的两个词之间的“距离”。所谓两个词之间的“距离”,就是这两个词之间的语法,语义之间的相似性。
  一个比较爽的应用方法是,得到词向量后,假如对于某个词A,想找出这个词最相似的词,在建立好词向量后的情况,对计算机来说,只要拿这个词的词向量跟其他词的词向量一一计算欧式距离或者cos距离,得到距离最小的那个词,就是它最相似的。
  所以在这里我们选择了word2vec方法来训练生成词向量。关于word2vec的原理大家可以在网上搜索学习,此处不再赘述。

实现代码

  在数据预处理中我们生成的word2vec.txt就可以放到此处训练word2vec模型生成词向量了,具体实现代码如下: word2vec.py

# -*- coding: utf-8 -*-
# Created by huxiaoman 2018.1.28
# word2vec.py:生成word2vec模型

import os
import sys
import numpy as np
from gensim.models.word2vec import Word2Vec
from gensim.corpora.dictionary import Dictionary
import codecs

reload(sys)
sys.setdefaultencoding( "utf-8" )

class MySentences(object):
    def __init__(self, dirname):
        self.dirname = dirname

    def __iter__(self):
        for fname in os.listdir(self.dirname):
            for line in codecs.open(os.path.join(self.dirname, fname),"r", encoding="utf-8",errors="ignore"):
                yield line.strip().split()

# word2vec.txt数据的地址
train_path = "rawData/"

# 生成的word2vec模型的地址
model_path = "/modelPath/"
sentences = MySentences(train_path) 

# 此处min_count=5代表5元模型,size=100代表词向量维度,worker=15表示15个线程
model = Word2Vec(sentences,min_count = 5,size=100,workers=15)

#保存模型
model.save(model_path+'/Word2vec_model.pkl')

运行方式

python word2vec.py

运行结果

Word2vec_model.pkl 

模型训练

  生成正负样本数据并将词语全部转化为词向量后我们就可以把数据灌倒模型里进行训练了,本篇中将采用传统的机器学习算法svm来进行训练。

具体步骤

  • 加载数据集
  • 划分训练集train、验证集val与测试集test
  • 定义训练模型,并训练
  • 验证准确率

    实现代码

    # 构建svm模型,加载数据等代码详见github
    def get_svm_model(x_train,y_train,x_val,y_val):
    model = SVC(C=1,kernel='rbf',max_iter=10,gamma=1,probability=True)
    model.fit(x_train,y_train)
    pred=model.predict(x_val)
    fpr,tpr,thresholds = roc_curve(y_val, pred, pos_label=2)
    score = metrics.f1_score(y_val,pred)
    print score

    运行方式

    python train_svm.py

    运行结果

    0.73343221

小结

  本篇文章作为用PaddlePaddle处理垃圾邮件实战系列的预热,主要讲了如何对文本数据进行数据预处理与过滤,如何生成词向量以及用传统的机器学习方法--支持向量机训练模型,得到的准确率为0.73343221。其结果的好坏取决于词典的大小,词向量维度的大小,svm的基本参数的调整,在实际操作过程中还需要不断的调参才能达到最优的效果。下一篇我们将带领大家如何用PaddlePaddle来做垃圾邮件处理,用深度学习的方法对垃圾邮件进行分类,看看效果是否比传统的机器学习方法要更好,性能和速度是否能有一定的提升。

  • 本文受Modify的博文启发所写,所有含有Modify博文内容的部分都已经过Modify本人的同意。本文首发于景略集智,并由景略集智制作成“PaddlePaddle调戏邮件诈骗犯”系列视频。如果有不懂的,欢迎在评论区中提问~

推荐阅读
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 1.如何在运行状态查看源代码?查看函数的源代码,我们通常会使用IDE来完成。比如在PyCharm中,你可以Ctrl+鼠标点击进入函数的源代码。那如果没有IDE呢?当我们想使用一个函 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 使用Vultr云服务器和Namesilo域名搭建个人网站
    本文详细介绍了如何通过Vultr云服务器和Namesilo域名搭建一个功能齐全的个人网站,包括购买、配置服务器以及绑定域名的具体步骤。文章还提供了详细的命令行操作指南,帮助读者顺利完成建站过程。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 三星W799在2011年的表现堪称经典,以其独特的双屏设计和强大的功能引领了双模手机的潮流。本文详细介绍其配置、功能及锁屏设置。 ... [详细]
  • 本文详细介绍了如何解决Uploadify插件在Internet Explorer(IE)9和10版本中遇到的点击失效及JQuery运行时错误问题。通过修改相关JavaScript代码,确保上传功能在不同浏览器环境中的一致性和稳定性。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 数据管理权威指南:《DAMA-DMBOK2 数据管理知识体系》
    本书提供了全面的数据管理职能、术语和最佳实践方法的标准行业解释,构建了数据管理的总体框架,为数据管理的发展奠定了坚实的理论基础。适合各类数据管理专业人士和相关领域的从业人员。 ... [详细]
  • 掌握远程执行Linux脚本和命令的技巧
    本文将详细介绍如何利用Python的Paramiko库实现远程执行Linux脚本和命令,帮助读者快速掌握这一实用技能。通过具体的示例和详尽的解释,让初学者也能轻松上手。 ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 从 .NET 转 Java 的自学之路:IO 流基础篇
    本文详细介绍了 Java 中的 IO 流,包括字节流和字符流的基本概念及其操作方式。探讨了如何处理不同类型的文件数据,并结合编码机制确保字符数据的正确读写。同时,文中还涵盖了装饰设计模式的应用,以及多种常见的 IO 操作实例。 ... [详细]
author-avatar
纽约纽约MrWaNg
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有