集智专栏
资源加载中,请稍后...
集智专栏

用PaddlePaddle调戏邮件诈骗犯-Part1

相关视频地址:深度学习-用PaddlePaddle调戏邮件诈骗犯(1)


在我们日常生活中,经常会受到各种垃圾邮件,譬如来自商家的广告、打折促销信息、澳门博彩邮件、理财推广信息等,一般来说邮件客户端都会设置一定的关键词屏蔽这种垃圾邮件,或者对邮件进行归类,但是总会有一些漏网之鱼。

去年我们曾翻译介绍了这样一个项目:利用机器学习调戏邮件诈骗犯,在识别出广告诈骗邮件之后,再生成文本回复邮件反钓鱼。

不过,自己手动做一个垃圾邮件分类器也并不是什么难事。传统的机器学习算法通常会采用朴素贝叶斯、支持向量机等算法对垃圾邮件进行过滤,今天我们主要讲如何用PaddlePaddle手写一个垃圾邮件分类器。当然,在讲PaddlePaddle做垃圾邮件处理之前,先回顾一下传统的机器学习算法是如何对垃圾邮件进行分类的。



1. 了解数据集

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

文件下载地址:trec06c

文件结构:

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


一级目录:data一级目录:data

二级目录:000二级目录:000


文件内容:

  • 垃圾邮件(spam)示例:本公司有部分普通发票(商品销售发票)增值税发票及海关代征增值税专用缴款书及其它服务行业发票,公路、内河运输发票。可以以低税率为贵公司代开,本公司具有内、外贸生意实力,保证我司开具的票据的真实性。 希望可以合作!共同发展!敬侯您的来电洽谈、咨询! 联系人:李先生 联系电话:13632588281 如有打扰望谅解,祝商琪。

  • 正常邮件(ham)示例:讲的是孔子后人的故事。一个老领导回到家乡,跟儿子感情不和,跟贪财的孙子孔为本和睦。老领导的弟弟魏宗万是赶马车的。有个洋妞大概是考察民俗的,在他们家过年。孔为本总想出国,被爷爷教育了。最后,一家人基本和解。 顺便问另一类电影,北京青年电影制片厂的。

虽然是十年前整理的数据集,但还是很符合我们平时经常收到的垃圾邮件尿性,说明他们的套路也没怎么升级。


每个文件夹里都包含两类邮件样本,而且没什么规律,要从delay/index文件中查看标签:



2. 数据预处理

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

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


2.1 加载邮件标签

程序说明
提取标签
示例代码
def load_label_files(label_file): # 创建空字典存储标签信息 label_dict ={} for line in open(label_file).readlines(): # 标签(Spam/HAM)与对应的文本文件之间有..,以此分割 list1 = line.strip().split("..") # 字典的键(key)为路径,值(value)为标签 label_dict[list1[1].strip()] = list1[0].strip() return label_dict


2.2 加载停用词(stop words)词表

在自然语言当中,有非常多的字符是与内容判断无关的,比如虚词、助词、语气词等。研究者已经总结出了常用的“停用词表”,这里定义一个函数,加载停用词表以备后期匹配使用:

程序说明
停用词
示例代码
def load_stop_train(stop_word_path): # 停用词词典 stop_dict = {} for line in open(stop_word_path).readlines(): line = line.strip() # 键:停用词,值:1 stop_dict[line] = 1 return stop_dict


2.3 判断是否包含中文

TREC06C数据集除了邮件正文,还包含元数据,比如邮件的发送/接收地址,编码格式等等,这些数据暂时不作为判断性质的特征,所以我们定义一个函数,判断每一行是否包含中文,如果是,再做进一步处理。

示例代码
def check_contain_chinese(check_str): for ch in check_str.decode('utf-8'): if u'\u4e00' <= ch <= u'\u9fff': return True return False


2.4 数据预处理

读取邮件文本,转换为utf-8格式并分别生成正负样本文件:ham.txt,spam.txt

程序说明
预处理训练数据
示例代码
import jieba import sys import os import re # 读取邮件数据,并转换为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:]] # 处理文件 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")


2.5 中文分词

截止到这一步,我们把原本错综的文件结构按照标签分别整理到两个文本文件:ham.txtspam.txt中,但预处理还没有结束。在这个项目中,我们对垃圾邮件的判断是基于特定“词汇”的出现频率与标签的相关性,而由于中文的特殊性,“词汇”这个单位并不显式存在,所以还需要一步很重要的工作叫作:分词。

这里我们使用一个很方便的工具,叫作结巴分词

程序说明
分词
示例代码
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")


至此,我们就对训练数据集完成了初步的预处理,以便之后的深度学习阶段使用。相关的辅助数据和产生的中间数据,可以通过下方的链接下载查看。

  • 停用词表:

stop_words.txt

  • 预处理过的文本数据

ham.txt

spam.txt


作为第一部分,本篇代码量较大(这也是trec06c诡异的文件结构的原因),如果你对Python的基本语法还不是很熟悉,我们将在下一篇当中对每个函数做详细的讲解,欢迎关注。

您也许喜欢这些文章

[Pandas] 10分钟Pandas之旅 01

发表至数据科学
Pandas是基于BSD协议的开源Python扩展库,提供高能、易用的结构化数据分析工具。 这是一个面向新手的极简上路指南。本篇介绍Pandas的基础用法,包括:观察数据、取值赋值和处理缺失数据。

[Python爬虫] 「暴力」破解猫眼电影票房数据的反爬虫机制

发表至趣味项目
一套完整的数据分析+机器学习流程,从数据获取(反爬虫机制),数据清洗到最终的机器学习与数据可视化。 猫眼电影票房数据(piaofang.maoyan.com)的反爬虫机制很有趣,是采用了来自美团网的加密字体系统,虽然前端人类读者看到的一切正常,但那是样式表渲染(相当于解密过程)的结果,而爬虫从后台得到的数据,都是密文。 作者直接绕过了破译密码,而是从模式识别的角度,由爬虫自动采集前端图像,再进行分割,最后只用支持向量机分类算法,获得真实的数字。

[Python入门] 01 基本法则

发表至系列教程
Python入门教程系列的第一篇,从最基本的概念与法则开始,面向从未接触过Python甚至没有任何编程基础的读者。 Python是数据科学界最主流的编程语言,相对于传统的Excel等数据处理工具,Python具备处理海量数据的能力,并且可以执行机器学习算法。从数据获取(网络爬虫等工具)、数据清理到数据分析拟合再到最终的可视化呈现,Python都能胜任。

文章评论(1)

团子失格 发表于 7天前 回复
fh1.write(line.encode("utf-8","ingore")+"\n")(#中文分词部分最后一行,ignore写错了) 另外child能否写的更巧妙一些,一下子差点没看懂,另外不知道是数据集之间有什么差距,spam和ham的判断语句要写成大写。都是些很微末的地方,发表一些too simple的建议