前言
本項(xiàng)目采用樸素貝葉斯和支持向量機(jī)(SVM)分類模型作為基礎(chǔ),通過對(duì)垃圾郵件和正常郵件的數(shù)據(jù)進(jìn)行訓(xùn)練,旨在實(shí)現(xiàn)垃圾郵件的自動(dòng)識(shí)別功能。
通過訓(xùn)練這兩個(gè)分類模型,我們的目標(biāo)是建立一個(gè)高效準(zhǔn)確的垃圾郵件識(shí)別系統(tǒng)。當(dāng)接收到新的郵件時(shí),系統(tǒng)將對(duì)郵件文本進(jìn)行預(yù)處理,并利用訓(xùn)練好的模型進(jìn)行分類。根據(jù)模型的預(yù)測(cè)結(jié)果,我們可以準(zhǔn)確地判斷郵件是否為垃圾郵件,從而進(jìn)行相應(yīng)的處理。
垃圾郵件識(shí)別技術(shù)在郵件過濾和信息安全領(lǐng)域具有重要意義,可以幫助用戶過濾掉大量的垃圾郵件,提高工作效率和信息安全性。
總體設(shè)計(jì)
本部分包括系統(tǒng)整體結(jié)構(gòu)圖和系統(tǒng)流程圖。
系統(tǒng)整體結(jié)構(gòu)圖
系統(tǒng)整體結(jié)構(gòu)如圖所示。
系統(tǒng)流程圖
系統(tǒng)流程如圖所示。
運(yùn)行環(huán)境
本部分包括 Python 環(huán)境、Pycharm 環(huán)境和 ChatterBot 環(huán)境。
Python 環(huán)境
需要 Python 3.6 及以上配置,在 Windows 環(huán)境下載 Anaconda 完成 Python 所需的配置,下載地址:https://www.anaconda.com/,也可以下載虛擬機(jī)在 Linux 環(huán)境下運(yùn)行代碼。
安裝pytesseract
從 github 網(wǎng)站下載與 python PIL 庫配搭使用的文字引擎 pytesseract。同時(shí)注意安裝好PIL庫。
pip install Pillow
注冊(cè)百度云賬號(hào)
注冊(cè)百度云賬號(hào),分別建立圖像文字識(shí)別和圖像識(shí)別的小程序。
模塊實(shí)現(xiàn)
本項(xiàng)目包括 3 個(gè)模塊:數(shù)據(jù)模塊、模型構(gòu)建、附加功能,下面分別給出各模塊的功能介紹及相關(guān)代碼。
1. 數(shù)據(jù)模塊
數(shù)據(jù)下載地址:https://pan.baidu.com/s/1nZsCT1nDq-265-ZOWapjpw,提取碼:xw25,訓(xùn)練數(shù)據(jù)集為 7063 封正常郵件(data/normal 文件夾下),7775 封垃圾郵件(data/spam 文件夾下)。測(cè)試數(shù)據(jù)集:共 392 封郵件(data/test 文件夾下)。
首先,用正則表達(dá)式過濾掉非中文字符;其次,用 jieba 分詞庫對(duì)語句進(jìn)行分詞,并清除一些停用詞,最后,用上述結(jié)果創(chuàng)建詞典,格式為:{“詞 1”: 詞 1 詞頻, “詞 2”:詞 2 詞頻…},相關(guān)代碼如下:
stopWords = getStopWords(txt_path='./data/stopWords.txt')
wordsDict = wordsCount(filepath='./data/normal', stopWords=stopWords)
wordsDict = wordsCount(filepath='./data/spam', stopWords=stopWords, wordsDict=wordsDict)
準(zhǔn)備詞典,把每封信的內(nèi)容轉(zhuǎn)換為詞向量,其維度為4000,每一維代表一個(gè)高頻詞在該封信中出現(xiàn)的頻率,將這些詞向量合并為一個(gè)特征向量矩陣,大小為:(7063+7775)*4000,前7063行是正常郵件的特征向量,其余為垃圾郵件的特征向量。相關(guān)代碼如下:
normal_path = './data/normal'
spam_path = './data/spam'
wordsDict = readDict(filepath='./wordsDict.pkl')
normals = getFilesList(filepath=normal_path)
spams = getFilesList(filepath=spam_path)
fvs = []
for normal in normals:
fv = extractFeatures(filepath=os.path.join(normal_path, normal), wordsDict=wordsDict, fv_len=4000)
fvs.append(fv)
normal_len = len(fvs)
for spam in spams:
fv = extractFeatures(filepath=os.path.join(spam_path, spam), wordsDict=wordsDict, fv_len=4000)
fvs.append(fv)
spam_len = len(fvs) - normal_len
print('[INFO]: Noraml-%d, Spam-%d' % (normal_len, spam_len))
fvs = mergeFv(fvs)
saveNparray(np_array=fvs, savepath='./fvs_%d_%d.npy' % (normal_len, spam_len))
2. 模型構(gòu)建
使用 scikit-learn 機(jī)器學(xué)習(xí)庫訓(xùn)練分類器,模型選擇樸素貝葉斯分類器和 SVM(支持向量機(jī))。
-
樸素貝葉斯算法
(1) 當(dāng)收到一封未知郵件時(shí),假定它是垃圾郵件和正常郵件的概率各為 50%。
(2) 解析該郵件,提取每個(gè)詞,計(jì)算該詞的概率,也就是垃圾郵件的概率。
(3) 提取該郵件中 p(s|w)最高的 15 個(gè)詞,計(jì)算聯(lián)合概率。
(4) 設(shè)定閾值判斷。 -
SVM(支持向量機(jī))
一個(gè)線性分類器的學(xué)習(xí)目標(biāo)要在n維的數(shù)據(jù)空間中找到一個(gè)超平面,把空間切割開,超平面的方程表示相關(guān)代碼如下:
def train(normal_len, spam_len, fvs):
train_labels = np.zeros(normal_len+spam_len)
train_labels[normal_len:] = 1
#SVM
model1 = LinearSVC()
model1.fit(fvs, train_labels)
joblib.dump(model1, 'LinearSVC.m')
#貝葉斯
model2 = MultinomialNB()
model2.fit(fvs, train_labels)
joblib.dump(model2, 'MultinomialNB.m')
- 實(shí)現(xiàn)代碼
#Utils模塊
import re
import os
import jieba
import pickle
import numpy as np
#獲取停用詞列表
def getStopWords(txt_path='./data/stopWords.txt'):
stopWords = []
with open(txt_path, 'r') as f:
for line in f.readlines():
stopWords.append(line[:-1])
return stopWords
#把list統(tǒng)計(jì)進(jìn)dict
def list2Dict(wordsList, wordsDict):
for word in wordsList:
if word in wordsDict.keys():
wordsDict[word] += 1
else:
wordsDict[word] = 1
return wordsDict
#獲取文件夾下所有文件名
def getFilesList(filepath):
return os.listdir(filepath)
#統(tǒng)計(jì)某文件夾下所有郵件的詞頻
def wordsCount(filepath, stopWords, wordsDict=None):
if wordsDict is None:
wordsDict = {}
wordsList = []
filenames = getFilesList(filepath)
for filename in filenames:
with open(os.path.join(filepath, filename), 'r') as f:
for line in f.readlines():
#過濾非中文字符
pattern = re.compile('[^\u4e00-\u9fa5]')
line = pattern.sub("", line)
words_jieba = list(jieba.cut(line))
for word in words_jieba:
if word not in stopWords and word.strip != '' and word != None:
wordsList.append(word)
wordsDict = list2Dict(wordsList, wordsDict)
return wordsDict
#保存字典類型數(shù)據(jù)
def saveDict(dict_data, savepath='./results.pkl'):
with open(savepath, 'wb') as f:
pickle.dump(dict_data, f)
#讀取字典類型數(shù)據(jù)
def readDict(filepath):
with open(filepath, 'rb') as f:
dict_data = pickle.load(f)
return dict_data
#對(duì)輸入的字典按鍵值排序(降序)后返回前topk組數(shù)據(jù)
def getDictTopk(dict_data, topk=4000):
data_list=sorted(dict_data.items(),key=lambda dict_data:-dict_data[1])
data_list = data_list[:topk]
return dict(data_list)
#提取文本特征向量
def extractFeatures(filepath, wordsDict, fv_len=4000):
fv = np.zeros((1, fv_len))
words = []
with open(filepath) as f:
for line in f.readlines():
pattern = re.compile('[^\u4e00-\u9fa5]')
line = pattern.sub("", line)
words_jieba = list(jieba.cut(line))
words += words_jieba
for word in set(words):
for i, d in enumerate(wordsDict):
if d[0] == word:
fv[0, i] = words.count(word)
return fv
#合并特征向量
def mergeFv(fvs):
return np.concatenate(tuple(fvs), axis=0)
#保存np.array()數(shù)據(jù)
def saveNparray(np_array, savepath):
np.save(savepath, np_array)
#讀取np.array()數(shù)據(jù)
def readNparray(filepath):
return np.load(filepath)
#Train模塊
#模型訓(xùn)練
import os
import numpy as np
from utils import *
from sklearn.externals import joblib
from sklearn.metrics import confusion_matrix
from sklearn.svm import SVC, NuSVC, LinearSVC
from sklearn.naive_bayes import MultinomialNB, GaussianNB, BernoulliNB
def train(normal_len, spam_len, fvs):
train_labels = np.zeros(normal_len+spam_len)
train_labels[normal_len:] = 1
#SVM
model1 = LinearSVC()
model1.fit(fvs, train_labels)
joblib.dump(model1, 'LinearSVC.m')
#貝葉斯
model2 = MultinomialNB()
model2.fit(fvs, train_labels)
joblib.dump(model2, 'MultinomialNB.m')
#測(cè)試
def test(model_path, fvs, labels):
model = joblib.load(model_path)
result = model.predict(fvs)
print(confusion_matrix(labels, result))
if __name__ == '__main__':
#第一部分,可選
'''
stopWords = getStopWords(txt_path='./data/stopWords.txt')
wordsDict = wordsCount(filepath='./data/normal', stopWords=stopWords)
wordsDict = wordsCount(filepath='./data/spam', stopWords=stopWords, wordsDict=wordsDict)
saveDict(dict_data=wordsDict, savepath='./results.pkl')
'''
#第二部分,可選
'''
wordsDict = readDict(filepath='./results.pkl')
wordsDict = getDictTopk(dict_data=wordsDict, topk=4000)
saveDict(dict_data=wordsDict, savepath='./wordsDict.pkl')
'''
#第三部分,可選
'''
normal_path = './data/normal'
spam_path = './data/spam'
wordsDict = readDict(filepath='./wordsDict.pkl')
normals = getFilesList(filepath=normal_path)
spams = getFilesList(filepath=spam_path)
fvs = []
for normal in normals:
fv = extractFeatures(filepath=os.path.join(normal_path, normal), wordsDict=wordsDict, fv_len=4000)
fvs.append(fv)
normal_len = len(fvs)
for spam in spams:
fv=extractFeatures(filepath=os.path.join(spam_path,spam), wordsDict=wordsDict, fv_len=4000)
fvs.append(fv)
spam_len = len(fvs) - normal_len
print('[INFO]: Noraml-%d, Spam-%d' % (normal_len, spam_len))
fvs = mergeFv(fvs)
saveNparray(np_array=fvs, savepath='./fvs_%d_%d.npy' % (normal_len, spam_len))
'''
#第四部分,可選
'''
fvs = readNparray(filepath='fvs_7063_7775.npy')
normal_len = 7063
spam_len = 7775
train(normal_len, spam_len, fvs)
'''
#第五部分
wordsDict = readDict(filepath='./wordsDict.pkl')
test_normalpath = './data/test/normal'
test_spampath = './data/test/spam'
test_normals = getFilesList(filepath=test_normalpath)
test_spams = getFilesList(filepath=test_spampath)
normal_len = len(test_normals)
spam_len = len(test_spams)
fvs = []
for test_normal in test_normals: fv=extractFeatures(filepath=os.path.join(test_normalpath,test_normal), wordsDict=wordsDict, fv_len=4000)
fvs.append(fv)
for test_spam in test_spams:
fv = extractFeatures(filepath=os.path.join(test_spampath, test_spam), wordsDict=wordsDict, fv_len=4000)
fvs.append(fv)
fvs = mergeFv(fvs)
labels = np.zeros(normal_len+spam_len)
labels[normal_len:] = 1
test(model_path='LinearSVC.m', fvs=fvs, labels=labels)
test(model_path='MultinomialNB.m', fvs=fvs, labels=labels)
3. 附加功能
訓(xùn)練數(shù)據(jù)后,得到詞頻統(tǒng)計(jì)和對(duì)應(yīng)向量集,而附加功能主要實(shí)現(xiàn)圖片的文字提取、類型識(shí)別和網(wǎng)頁文字爬取的功能。針對(duì)一封帶圖片的郵件,先后經(jīng)過文字識(shí)別和圖像識(shí)別處理,將結(jié)果寫入同一個(gè)文件,得到測(cè)試集,訓(xùn)練集采用文字郵件的訓(xùn)練數(shù)據(jù),測(cè)試集從百度圖片官網(wǎng)提取,網(wǎng)址:https://image.baidu.com/。
圖片文字識(shí)別可以使用兩種方法調(diào)用,小伙伴們可以根據(jù)實(shí)際情況來選擇,具體如下:
1. 圖片文字識(shí)別(搜索引擎)
使用Python自帶的PIL庫和配套的pytesseract引擎,實(shí)現(xiàn)圖片文字識(shí)別,在調(diào)試時(shí)發(fā)現(xiàn),圖片顏色如果過于復(fù)雜,將會(huì)影響文字識(shí)別的準(zhǔn)確性,因此,將圖片進(jìn)行二值化處理,提高文字識(shí)別準(zhǔn)確性。當(dāng)然選擇這種方法的話,是完全開源免費(fèi)的。
from PIL import Image #導(dǎo)入PIL庫
import pytesseract#對(duì)應(yīng)文字引擎
def getMessage(path_name):
text = pytesseract.image_to_string(r'D:\學(xué)習(xí)\大三下學(xué)期\信息系統(tǒng)設(shè)計(jì)\圖片\hh.jpg',lang='chi_sim')#圖片的路徑
def get_bin_table(threshold = 230):
#獲取灰度轉(zhuǎn)二值的映射table
table = []
for i in range(256):#將圖片二值化
if i < threshold:
table.append(0)
else:
table.append(1)
return table
image = Image.open(r'D:\學(xué)習(xí)\大三下學(xué)期\信息系統(tǒng)設(shè)計(jì)\圖片\hh.jpg')
imgry = image.convert('L') #轉(zhuǎn)化為灰度圖
table = get_bin_table()
out = imgry.point(table, '1')
getMessage(out)
print(text)#輸出結(jié)果
通過多次實(shí)驗(yàn),通過文字搜索引擎實(shí)現(xiàn)圖片文字識(shí)別準(zhǔn)確度不高,一旦有復(fù)雜的文字會(huì)直接影響效果,因此,改為調(diào)用百度 API 實(shí)現(xiàn)圖片文字識(shí)別。
2. 圖片文字識(shí)別(調(diào)用API)
1)獲取 access_token
#編碼:utf-8
import requests
#client_id 為官網(wǎng)獲取的AK, client_secret 為官網(wǎng)獲取的SK
host='https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=hr9lw2FxcviEMa7yyNg4pZB6&client_secret=Q3aEXILXYOWGZsmvoeGhfPk0mdTgQeXN'
response = requests.get(host)
print(response.json())
效果演示如下圖:
2)識(shí)別文件夾內(nèi)圖片的文字
獲取access_token復(fù)制到如下代碼中:
import requests
import base64
import os
class Orc_main():
def orc_look(self, path):
access_token = "24.1c62a660cc5efe228e228f22a7ccc03d.2592000.1589900797.
282335-19504458" #采用上一段代碼的access_token
with open(path, 'rb') as f:
image_data = f.read()#讀取圖片
base64_ima = base64.b64encode(image_data)
data = {
'image': base64_ima
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token=" + str(access_token)#通過百度API調(diào)用
r = requests.post(url, params=headers, data=data).json()
for word in r['words_result']:
yield word['words']
# 返回一個(gè)生成器
if __name__ == '__main__':
om = Orc_main()
for i in range (1,41):#采用40張圖片作為訓(xùn)練數(shù)據(jù)集
path = "D:\\學(xué)習(xí)\\大三下學(xué)期\\信息系統(tǒng)設(shè)計(jì)\\圖片\\normal\\"+str(i)+".jpg"
#圖片文件路徑
f=open('D:\\學(xué)習(xí)\\大三下學(xué)期\\信息系統(tǒng)設(shè)計(jì)\\垃圾郵件識(shí)別\\data\\picture\\normal\\'+str(i),'w+')
#輸出文件無后綴名,與測(cè)試的文字郵件統(tǒng)一格式,且讀寫方式為w+代表沒有可創(chuàng)建,并且寫入內(nèi)容會(huì)覆蓋
words = om.orc_look(path)
#輸出文字(返回結(jié)果)
for word in words:
print(word)#輸出檢查
f.write(word+'\n')#寫入文件,每次回車,方便查閱
f.close()#關(guān)閉文件,否則會(huì)出現(xiàn)問題
3)圖片識(shí)別(調(diào)用API)
相關(guān)代碼如下:
from urllib import request
import ssl
import json
import os
import re
#官網(wǎng)獲取到的apiid和apisecret
apiId='W4sDdigCM9jHDycQGkcSd41X' # 替換成你注冊(cè)的apiid
apiSecret='1E4hiZp9i1EGiG38NbnoGk0ZoiECjUhq' # 替換成你注冊(cè)的apiSecret
if __name__ == '__main__':
import requests
import base64
gcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
#client_id 為官網(wǎng)獲取的AK, client_secret 為官網(wǎng)獲取的SK
host = 'https://aip.baidubce.com/oauth/2.0/token?grant_'\
'type=client_credentials&client_id='+apiId+'&client_secret='+ apiSecret
req = request.Request(host)
response=request.urlopen(req, context=gcontext).read().decode('UTF-8')
result = json.loads(response)
host='https://aip.baidubce.com/rest/2.0/image-classify/v2/advanced_general'
headers={
'Content-Type':'application/x-www-form-urlencoded'
}
access_token= result['access_token']
host=host+'?access_token='+access_token
data={}
data['access_token']=access_token
for i in range(1,41):
pic= "D:\\學(xué)習(xí)\\大三下學(xué)期\\信息系統(tǒng)設(shè)計(jì)\\圖片\\spam\\"+str(i)+".jpg"
ff = open(pic, 'rb')#打開圖片
img = base64.b64encode(ff.read())
data['image'] =img#統(tǒng)一圖片格式
res = requests.post(url=host,headers=headers,data=data)
req=res.json()
f=open('D:\\學(xué)習(xí)\\大三下學(xué)期\\信息系統(tǒng)設(shè)計(jì)\\垃圾郵件識(shí)別\\data\\picture\\spam\\'+str(i),'a+')
#由于已經(jīng)存在了寫入的文本,所以讀寫方式為a,繼續(xù)寫入并不會(huì)覆蓋文本
q=req['result']#得到的是各種分類器識(shí)別的結(jié)果和打分
qq=re.sub("[A-Za-z0-9\!\%\[\]\,\。]", "", str(q))
qqq=str(qq).replace('\'', '').replace('.','').replace(':','').replace('{','').replace('}','')
#通過正則表達(dá)式 replace函數(shù)去掉標(biāo)點(diǎn)和多余英文,保留分類器名稱和分類結(jié)果
f.write(str(qqq)+'\n')
print(req['result'][0]['keyword'])
print(req['result'])
print(qqq) #輸出結(jié)果作為進(jìn)度檢查
f.close()#關(guān)閉文件
注意:通過所有類型的識(shí)別器識(shí)別,得到的結(jié)果為列表,再用正則表達(dá)式處理后寫入文本,在文字提取結(jié)果之后寫入文件即圖片先后經(jīng)過文字識(shí)別和圖像識(shí)別得到的文字結(jié)果。
下圖為測(cè)試圖片:
識(shí)別結(jié)果如下圖:
4)網(wǎng)頁文本提取
主要針對(duì)網(wǎng)址的電子郵件,通過 request 庫爬取其網(wǎng)頁源碼內(nèi)容,正則表達(dá)式處理后得到文本,處理方式和文本郵件相同。
相關(guān)代碼如下:
import requests
from bs4 import BeautifulSoup
def get_html(url):
headers = { 'User-Agent':'Mozilla/5.0(Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36(KHTML, like Gecko) Chrome/52 .0.2743. 116 Safari/537.36' }
#模擬瀏覽器訪問
response = requests.get(url,headers = headers) #請(qǐng)求訪問網(wǎng)站
html = response.text #獲取網(wǎng)頁源碼
return html #返回網(wǎng)頁源碼
soup = BeautifulSoup(get_html('https://www.baidu.com/'), 'html.parser')
#初始化BeautifulSoup庫,并設(shè)置解析器
print(get_html('https://www.baidu.com/'))
a=get_html('https://www.baidu.com/')
for li in soup.find_all(name='li'): #遍歷父節(jié)點(diǎn)
for a in li.find_all(name='a'): #遍歷子節(jié)點(diǎn)
if a.string==None:
pass
else:
print(a.string)
#輸出結(jié)果是純文本,同樣,只要是純文本的內(nèi)容都可以由主程序處理
系統(tǒng)測(cè)試
本部分包括準(zhǔn)確率和測(cè)試結(jié)果。
1. 文字郵件測(cè)試準(zhǔn)確率
SVM 測(cè)試準(zhǔn)確率 93%+,如表2-1 所示,樸素貝葉斯測(cè)試準(zhǔn)確率 87%+,如表 2-2 所示,預(yù)測(cè)模型訓(xùn)練比較成功。
2. 網(wǎng)頁測(cè)試結(jié)果
網(wǎng)頁測(cè)試和圖片郵件測(cè)試是同樣的訓(xùn)練集,如表 2-3 所示。
工程源代碼下載
詳見本人博客資源下載頁文章來源:http://www.zghlxwxcb.cn/news/detail-488140.html
其它資料下載
如果大家想繼續(xù)了解人工智能相關(guān)學(xué)習(xí)路線和知識(shí)體系,歡迎大家翻閱我的另外一篇博客《重磅 | 完備的人工智能AI 學(xué)習(xí)——基礎(chǔ)知識(shí)學(xué)習(xí)路線,所有資料免關(guān)注免套路直接網(wǎng)盤下載》
這篇博客參考了Github知名開源平臺(tái),AI技術(shù)平臺(tái)以及相關(guān)領(lǐng)域?qū)<遥篋atawhale,ApacheCN,AI有道和黃海廣博士等約有近100G相關(guān)資料,希望能幫助到所有小伙伴們。文章來源地址http://www.zghlxwxcb.cn/news/detail-488140.html
到了這里,關(guān)于基于機(jī)器學(xué)習(xí)算法:樸素貝葉斯和SVM 分類-垃圾郵件識(shí)別分類系統(tǒng)(含Python工程全源碼)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!