在咱们平常生活中,常常会受到各类垃圾邮件,譬如来自商家的广告、打折促销信息、澳门博彩邮件、理财推广信息等,通常来讲邮件客户端都会设置必定的关键词屏蔽这种垃圾邮件,或者对邮件进行归类,可是总会有一些漏网之鱼。
不过,本身手动作一个垃圾邮件分类器也并非什么难事。传统的机器学习算法一般会采用朴素贝叶斯、支持向量机等算法对垃圾邮件进行过滤,今天咱们主要讲如何用PaddlePaddle手写一个垃圾邮件分类器。固然,在讲PaddlePaddle作垃圾邮件处理以前,先回顾一下传统的机器学习算法是如何对垃圾邮件进行分类的。python
首先先了解一下今天的数据集:trec06c。trec06c是一个公开的垃圾邮件语料库,由国际文本检索会议提供,分为英文数据集(trec06p)和中文数据集(trec06c),其中所含的邮件均来源于真实邮件保留了邮件的原有格式和内容。
文件下载地址:trec06c
文件格式:git
trec06c │ └───data │ │ 000 │ │ 001 │ │ ... │ └───215 └───delay │ │ index └───full │ │ index
文件内容:github
垃圾邮件示例:本公司有部分普通发票(商品销售发票)增值税发票及海关代征增值税专用缴款书及其它服务行业发票,公路、内河运输发票。能够以低税率为贵公司代开,本公司具备内、外贸生意实力,保证我司开具的票据的真实性。 但愿能够合做!共同发展!敬侯您的来电洽谈、咨询! 联系人:李先生 联系电话:13632588281 若有打扰望谅解,祝商琪。
正常邮件示例:讲的是孔子后人的故事。一个老领导回到家乡,跟儿子感情不和,跟贪财的孙子孔为本和气。老领导的弟弟魏宗万是赶马车的。有个洋妞大概是考察民俗的,在他们家过年。孔为本总想出国,被爷爷教育了。最后,一家人基本和解。 顺便问另外一类电影,北京青年电影制片厂的。算法
拿到数据后咱们能够很清楚的看到邮件的内容,但并非全部的内容都是咱们须要的,在这里咱们仅提取了邮件中的中文来做为训练语料。若是仔细观察的话,会发现不是全部的邮件都能直接打开,数据的编码格式也须要转换成utf-8格式方便咱们后面训练使用。因此咱们须要对原始数据作一些数据预处理,包括如下几个内容。bash
下面是具体的代码 transfer.py:app
# -*- 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
咱们知道,分词后的数据是不能直接拿到模型里去训练的,咱们须要把词语转换成词向量才能进行模型的训练,这样一个词能够有一个多维的词向量组成。
传统的方法是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的一些算法时;二是不能很好地刻画词与词之间的类似性,即任意两个词之间都是孤立的。光从这两个向量中看不出两个词是否有关系,损失大部分信息,致使结果会有较大误差。性能
在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来进行训练。
验证准确率
# 构建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来作垃圾邮件处理,用深度学习的方法对垃圾邮件进行分类,看看效果是否比传统的机器学习方法要更好,性能和速度是否能有必定的提高。