擅長(zhǎng)用通俗易懂的方式講解深度學(xué)習(xí)和機(jī)器學(xué)習(xí)算法,熟悉Tensorflow,PaddlePaddle等深度學(xué)習(xí)框架,負(fù)責(zé)過(guò)多個(gè)機(jī)器學(xué)習(xí)落地項(xiàng)目,如垃圾評(píng)論自動(dòng)過(guò)濾,用戶分級(jí)精準(zhǔn)營(yíng)銷,分布式深度學(xué)習(xí)平臺(tái)搭建等,都取了的不錯(cuò)的效果。
背景介紹
在我們?nèi)粘I钪?,?jīng)常會(huì)受到各種垃圾郵件,譬如來(lái)自商家的廣告、打折促銷信息、澳門博彩郵件、理財(cái)推廣信息等,一般來(lái)說(shuō)郵件客戶端都會(huì)設(shè)置一定的關(guān)鍵詞屏蔽這種垃圾郵件,或者對(duì)郵件進(jìn)行歸類,但是總會(huì)有一些漏網(wǎng)之魚。??不過(guò),自己手動(dòng)做一個(gè)垃圾郵件分類器也并不是什么難事。傳統(tǒng)的機(jī)器學(xué)習(xí)算法通常會(huì)采用樸素貝葉斯、支持向量機(jī)等算法對(duì)垃圾郵件進(jìn)行過(guò)濾,今天我們主要講如何用PaddlePaddle手寫一個(gè)垃圾郵件分類器。當(dāng)然,在講PaddlePaddle做垃圾郵件處理之前,先回顧一下傳統(tǒng)的機(jī)器學(xué)習(xí)算法是如何對(duì)垃圾郵件進(jìn)行分類的。
了解數(shù)據(jù)集
首先先了解一下今天的數(shù)據(jù)集:trec06c。trec06c是一個(gè)公開的垃圾郵件語(yǔ)料庫(kù),由國(guó)際文本檢索會(huì)議提供,分為英文數(shù)據(jù)集(trec06p)和中文數(shù)據(jù)集(trec06c),其中所含的郵件均來(lái)源于真實(shí)郵件保留了郵件的原有格式和內(nèi)容。文件下載地址:trec06c文件格式:
trec06c│└───data│ │ 000│ │ 001│ │ ...│ └───215└───delay│ │ index└───full│ │ index
文件內(nèi)容:
垃圾郵件示例:本公司有部分普通發(fā)票(商品銷售發(fā)票)增值稅發(fā)票及海關(guān)代征增值稅專用繳款書及其它服務(wù)行業(yè)發(fā)票,公路、內(nèi)河運(yùn)輸發(fā)票??梢砸缘投惵蕿橘F公司代開,本公司具有內(nèi)、外貿(mào)生意實(shí)力,保證我司開具的票據(jù)的真實(shí)性。 希望可以合作!共同發(fā)展!敬侯您的來(lái)電洽談、咨詢! 聯(lián)系人:李先生 聯(lián)系電話:13632588281 如有打擾望諒解,祝商琪。正常郵件示例:講的是孔子后人的故事。一個(gè)老領(lǐng)導(dǎo)回到家鄉(xiāng),跟兒子感情不和,跟貪財(cái)?shù)膶O子孔為本和睦。老領(lǐng)導(dǎo)的弟弟魏宗萬(wàn)是趕馬車的。有個(gè)洋妞大概是考察民俗的,在他們家過(guò)年。孔為本總想出國(guó),被爺爺教育了。最后,一家人基本和解。 順便問(wèn)另一類電影,北京青年電影制片廠的。
數(shù)據(jù)預(yù)處理
拿到數(shù)據(jù)后我們可以很清楚的看到郵件的內(nèi)容,但并不是所有的內(nèi)容都是我們需要的,在這里我們僅提取了郵件中的中文來(lái)作為訓(xùn)練語(yǔ)料。如果仔細(xì)觀察的話,會(huì)發(fā)現(xiàn)不是所有的郵件都能直接打開,數(shù)據(jù)的編碼格式也需要轉(zhuǎn)換成utf-8格式方便我們后面訓(xùn)練使用。所以我們需要對(duì)原始數(shù)據(jù)做一些數(shù)據(jù)預(yù)處理,包括以下幾個(gè)內(nèi)容。
基本步驟
轉(zhuǎn)換源數(shù)據(jù)編碼格式為utf-8格式
過(guò)濾字符
去除所有非中文字符,如標(biāo)點(diǎn)符號(hào)、英文字符、數(shù)字、網(wǎng)站鏈接等特殊字符。
過(guò)濾停用詞
對(duì)郵件內(nèi)容進(jìn)行分詞處理
訓(xùn)練代碼
下面是具體的代碼 transfer.py:
# -*- coding: utf-8 -*-#Created by huxiaoman 2018.1.28#transfer.py:生成spam和ham數(shù)據(jù)import jiebaimport sysimport osimport 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# 加載郵件數(shù)據(jù)的labeldef 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# 讀取郵件數(shù)據(jù),并轉(zhuǎn)換為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)
運(yùn)行腳本
run.sh:
bashif [ $1 = "test" ]; then echo "test" python transfer.py ../test/ ../trec06c/full/indexelse echo "whole" python transfer.py ../trec06c/data/ ../trec06c/full/indexfi
運(yùn)行方式:
sh run.sh
運(yùn)行結(jié)果:
ham.txt: 正樣本,正常郵件。共21373條數(shù)據(jù)。
示例:我 就 鬧 不 明白 了 只要 你 本人 不介意 跟 你 爸爸媽媽 有 何干 為啥 要說(shuō) 呢 ..... 首先 謝謝 大家 安慰 我 。 但是 我 確實(shí) 很 難受 , 我 有 自己 的 苦衷 。 我 不敢 和 我 媽媽 說(shuō) 的 這種 情況 。 我 媽媽 是 那種 特別 容易 擔(dān)心 的 那種 類型 。 而且 我 又 不 在 她 身邊 。 我家 是 外地 的 。 如果 和 媽媽 說(shuō) 了 , 她 一定 不會(huì) 同意 我 和 在 一起 的 。 媽媽 對(duì) 身體健康 看 的 特別 重要 。 有 一年 姐夫 那年 經(jīng)常 流鼻血 , 媽媽 都 特別 擔(dān)心 , 老 催 姐姐 帶 著 去 看看 。
spam.txt: 負(fù)樣本,垃圾郵件。共41627條數(shù)據(jù)。
示例:您好 以下 是 特別 為 閣下 發(fā) 的 香港 信息 圖片 、 景點(diǎn) 等 不 知道 閣下 是否 喜 希望 沒(méi)有 打擾到 閣下 如果 無(wú)法 看到 下面 內(nèi)容 請(qǐng) 稍侯 或者 直接 進(jìn)入 香港 行網(wǎng) 域名論壇 地址 真誠(chéng) 為您服務(wù)
word2vec.txt: 包含所有郵件分詞的內(nèi)容,為Word2Vec提供訓(xùn)練預(yù)料。共63000條數(shù)據(jù)。
示例:我 覺(jué)得 , 負(fù)債 不要緊 , 最 重要 的 是 能 負(fù)得起 這個(gè) 責(zé)任 來(lái) , 欠 了 那么 多錢 , 至少 對(duì) 當(dāng)初 拿出 愛(ài)心 來(lái) 的 網(wǎng)友 們 有 個(gè) 交待 , 還 , 還是 不 還 了 , 或者 , 是 有 這個(gè) 心 但 實(shí)在 沒(méi) 能力 , 說(shuō)明 一聲 還 都 好 不要 連 ID 都 不 激活 了 , 連 手機(jī)號(hào) 都 換 了 … … 別說(shuō) 外地 的 了 , 就 連 北京 的 網(wǎng)友 都 找 不到 他 … … 他 當(dāng)時(shí) 在 水木 fl 版 的 那陣 , 我 旁觀 了 全過(guò)程 。
生成詞向量
傳統(tǒng)方法的局限性
我們知道,分詞后的數(shù)據(jù)是不能直接拿到模型里去訓(xùn)練的,我們需要把詞語(yǔ)轉(zhuǎn)換成詞向量才能進(jìn)行模型的訓(xùn)練,這樣一個(gè)詞可以有一個(gè)多維的詞向量組成。??傳統(tǒng)的方法是one-hot encoding,即用一個(gè)長(zhǎng)向量來(lái)表示一個(gè)詞,向量的長(zhǎng)度為詞典的大小,向量的分量只有一個(gè)1,其余全為0,1的位置即對(duì)應(yīng)改詞在詞典中的位置,如電腦表示為:[0 0 0 0 0 1 0 0 0 0 ],耳機(jī)表示為[0 0 0 0 0 0 0 1 0 ]這種方式如果采用稀疏存儲(chǔ),表達(dá)簡(jiǎn)潔,占用空間少,但是這種方法也有幾個(gè)缺點(diǎn),一是容易受維數(shù)災(zāi)難的困擾,尤其是將其用于 Deep Learning的一些算法時(shí);二是不能很好地刻畫詞與詞之間的相似性,即任意兩個(gè)詞之間都是孤立的。光從這兩個(gè)向量中看不出兩個(gè)詞是否有關(guān)系,損失大部分信息,導(dǎo)致結(jié)果會(huì)有較大偏差。
Word2Vec方法的優(yōu)勢(shì)
在1968年Hinton又提出了Distributed REpresentation,可以O(shè)ne-hot encoding的缺點(diǎn)。其基本想法是直接用一個(gè)普通的向量表示一個(gè)詞,這種向量一般長(zhǎng)成這個(gè)樣子:[0.792, ?0.177, ?0.107, 0.109, ?0.542, ...],也就是普通的向量表示形式。維度以 50 維和 100 維比較常見。當(dāng)然一個(gè)詞怎么表示成這么樣的一個(gè)向量需要通過(guò)訓(xùn)練得到,訓(xùn)練方法較多,word2vec是最常見的一種。需要注意的是,每個(gè)詞在不同的語(yǔ)料庫(kù)和不同的訓(xùn)練方法下,得到的詞向量可能是不一樣的。詞向量一般維數(shù)不高,一般情況下指定1000、500維就可以了,所以用起來(lái)維數(shù)災(zāi)難的機(jī)會(huì)現(xiàn)對(duì)于one-hot representation表示就大大減少了。??由于是用向量表示,而且用較好的訓(xùn)練算法得到的詞向量的向量一般是有空間上的意義的,也就是說(shuō),將所有這些向量放在一起形成一個(gè)詞向量空間,而每一向量則為該空間中的一個(gè)點(diǎn),在這個(gè)空間上的詞向量之間的距離度量也可以表示對(duì)應(yīng)的兩個(gè)詞之間的“距離”。所謂兩個(gè)詞之間的“距離”,就是這兩個(gè)詞之間的語(yǔ)法,語(yǔ)義之間的相似性。??一個(gè)比較不錯(cuò)的應(yīng)用方法是,得到詞向量后,假如對(duì)于某個(gè)詞A,想找出這個(gè)詞最相似的詞,在建立好詞向量后的情況,對(duì)計(jì)算機(jī)來(lái)說(shuō),只要拿這個(gè)詞的詞向量跟其他詞的詞向量一一計(jì)算歐式距離或者cos距離,得到距離最小的那個(gè)詞,就是它最相似的。??所以在這里我們選擇了word2vec方法來(lái)訓(xùn)練生成詞向量。關(guān)于word2vec的原理大家可以在網(wǎng)上搜索學(xué)習(xí),此處不再贅述。
實(shí)現(xiàn)代碼
在數(shù)據(jù)預(yù)處理中我們生成的word2vec.txt就可以放到此處訓(xùn)練word2vec模型生成詞向量了,具體實(shí)現(xiàn)代碼如下: word2vec.py
# -*- coding: utf-8 -*-# Created by huxiaoman 2018.1.28# word2vec.py:生成word2vec模型import osimport sysimport numpy as npfrom gensim.models.word2vec import Word2Vecfrom gensim.corpora.dictionary import Dictionaryimport codecsreload(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數(shù)據(jù)的地址train_path = "rawData/"# 生成的word2vec模型的地址model_path = "/modelPath/"sentences = MySentences(train_path) # 此處min_count=5代表5元模型,size=100代表詞向量維度,worker=15表示15個(gè)線程model = Word2Vec(sentences,min_count = 5,size=100,workers=15)#保存模型model.save(model_path+'/Word2vec_model.pkl')
運(yùn)行方式
python word2vec.py
運(yùn)行結(jié)果
Word2vec_model.pkl
模型訓(xùn)練
生成正負(fù)樣本數(shù)據(jù)并將詞語(yǔ)全部轉(zhuǎn)化為詞向量后我們就可以把數(shù)據(jù)灌倒模型里進(jìn)行訓(xùn)練了,本篇中將采用傳統(tǒng)的機(jī)器學(xué)習(xí)算法svm來(lái)進(jìn)行訓(xùn)練。
具體步驟
加載數(shù)據(jù)集
劃分訓(xùn)練集train、驗(yàn)證集val與測(cè)試集test
定義訓(xùn)練模型,并訓(xùn)練
驗(yàn)證準(zhǔn)確率
實(shí)現(xiàn)代碼
# 構(gòu)建svm模型,加載數(shù)據(jù)等代碼詳見githubdef 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
運(yùn)行方式
python train_svm.py
運(yùn)行結(jié)果
0.73343221
小結(jié)
本篇文章作為用PaddlePaddle處理垃圾郵件實(shí)戰(zhàn)系列的預(yù)熱,主要講了如何對(duì)文本數(shù)據(jù)進(jìn)行數(shù)據(jù)預(yù)處理與過(guò)濾,如何生成詞向量以及用傳統(tǒng)的機(jī)器學(xué)習(xí)方法--支持向量機(jī)訓(xùn)練模型,得到的準(zhǔn)確率為0.73343221。其結(jié)果的好壞取決于詞典的大小,詞向量維度的大小,svm的基本參數(shù)的調(diào)整,在實(shí)際操作過(guò)程中還需要不斷的調(diào)參才能達(dá)到最優(yōu)的效果。下一篇我們將帶領(lǐng)大家如何用PaddlePaddle來(lái)做垃圾郵件處理,用深度學(xué)習(xí)的方法對(duì)垃圾郵件進(jìn)行分類,看看效果是否比傳統(tǒng)的機(jī)器學(xué)習(xí)方法要更好,性能和速度是否能有一定的提升。
-
機(jī)器學(xué)習(xí)
+關(guān)注
關(guān)注
66文章
8449瀏覽量
133136 -
數(shù)據(jù)集
+關(guān)注
關(guān)注
4文章
1209瀏覽量
24851
原文標(biāo)題:PaddlePaddle垃圾郵件處理實(shí)戰(zhàn)(一)
文章出處:【微信號(hào):AI_shequ,微信公眾號(hào):人工智能愛(ài)好者社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
如何防范垃圾郵件?
防范垃圾郵件的秘訣!
看我如何防范垃圾郵件?。?!
基于協(xié)同過(guò)濾的垃圾郵件過(guò)濾系統(tǒng)
代價(jià)敏感支持向量機(jī)在垃圾郵件過(guò)濾中的應(yīng)用
基于樸素貝葉斯算法的垃圾郵件網(wǎng)關(guān)
基于Bayes的一種改良垃圾郵件過(guò)濾模型
垃圾郵件(Spam)與郵件過(guò)濾技術(shù)
![<b class='flag-5'>垃圾郵件</b>(Spam)與<b class='flag-5'>郵件</b>過(guò)濾技術(shù)](https://file1.elecfans.com//web2/M00/A4/9B/wKgZomUMNPSAcoJAAADJSYpoS5E022.jpg)
垃圾郵件詳解
CCERT中文垃圾郵件過(guò)濾解決方案
中文垃圾郵件過(guò)濾郵件服務(wù)器的實(shí)現(xiàn)_李玉峰
反垃圾U-Mail郵件網(wǎng)關(guān)是如何防范垃圾郵件、病毒、釣魚軟件的攻擊?
一個(gè)簡(jiǎn)單的偽貝葉斯垃圾郵件過(guò)濾主程序資料免費(fèi)下載
![<b class='flag-5'>一</b><b class='flag-5'>個(gè)</b>簡(jiǎn)單的偽貝葉斯<b class='flag-5'>垃圾郵件</b>過(guò)濾主程序資料免費(fèi)下載](https://file.elecfans.com/web1/M00/8D/BB/o4YBAFytil6ARqbrAACppu9zURI593.png)
評(píng)論