前言
隨著微信的迅速發(fā)展,工作和生活中的交流也更多依賴于此,但是由于郵件的正式性和規(guī)范性,其仍然不可被取代。但是不管是企業(yè)內部工作郵箱,還是個人郵箱,總是收到各種各樣的垃圾郵件,包括商家的廣告、打折促銷信息、澳門博彩郵件、理財推廣信息等等,不管如何進行垃圾郵件分類,總有漏網之魚。最重要的是,不同用戶對于垃圾郵件的定義并不一致。
而且大部分用戶網絡安全意識比較一般,萬一誤點垃圾郵件上鉤,或者因為垃圾郵件淹沒了工作中的關鍵信件,則會給個人或者企業(yè)造成損失。
垃圾郵件識別一直以來都是痛點難點,雖然方法無非是基于貝葉斯學習或者是概率統(tǒng)計還是深度學習的方法,但是由于業(yè)務場景的多樣化,垃圾郵件花樣實在太多了,所以傳統(tǒng)垃圾郵件攔截器總是有點跟不上。
因此打算針對同一數(shù)據(jù)集,逐步嘗試各種方法,來進行垃圾郵件的識別分類——希望假以時日,這種定制化的垃圾郵件識別工具能大幅提升用戶的郵箱使用體驗。
一、整體思路
總的來說,一封郵件可以分為發(fā)送人、接收人、抄送人、主題、時間、內容等要素,所以很自然的可以認為主要通過上述要素中的發(fā)送方、主題以及內容來進行垃圾郵件判斷。
因此我們依次對上述要素進行分析:
- 垃圾郵件內容分類(通過提取垃圾郵件內容進行判斷)
- 中文垃圾郵件分類
- 英文垃圾郵件分類
- 垃圾郵件標題分類
- 垃圾郵件發(fā)送方分類
最終,我們可以根據(jù)這三個維度進行綜合評判,從而實現(xiàn)垃圾郵件的準確分類。本文將根據(jù)郵件內容進行垃圾郵件分類。
二、中文郵件內容分類實現(xiàn)步驟
1.數(shù)據(jù)集介紹
TREC 2006 Spam Track Public Corpora首先我們選擇TREC 2006 Spam Track Public Corpora這一個公開的垃圾郵件語料庫。該語料庫由國際文本檢索會議提供,分為英文數(shù)據(jù)集(trec06p)和中文數(shù)據(jù)集(trec06c),其中所含的郵件均來源于真實郵件保留了郵件的原有格式和內容。
文件目錄形式:delay和full分別是一種垃圾郵件過濾器的過濾機制,full目錄下,是理想的郵件分類結果,我們可以視為研究的標簽。
trec06c
│
└───data
│ ? │ ? 000
│ ? │ ? 001
│ ? │ ? ...
│ ? └───215
└───delay
│ ? │ ? index
└───full
│ ? │ ? index?
2.數(shù)據(jù)加載
2.1 從eml格式中提取郵件要素并且存儲成csv
由于目前數(shù)據(jù)集是存儲成郵件的形式,并且通過索引進行垃圾郵件標注,所以我們先提取每一封郵件的發(fā)件人、收件人、抄送人、主題、發(fā)送時間、內容以及是否垃圾郵件標簽。
mailTable=pd.DataFrame(columns=('Sender','Receiver','CarbonCopy','Subject','Date','Body','isSpam'))
# path='trec06p/full/../data/000/004'
# emlContent= emlAnayalyse(path)
# print(emlContent)
f = open('trec06c/full/index', 'r')
csvfile=open('mailChinese.csv','w',newline='',encoding='utf-8')
writer=csv.writer(csvfile)
for line in f:
str_list = line.split(" ")
print(str_list[1])
# 設置垃圾郵件的標簽為0
if str_list[0] == 'spam':
label = '0'
# 設置正常郵件標簽為1
elif str_list[0] == 'ham':
label = '1'
emlContent= emlAnayalyse('trec06c/full/' + str(str_list[1].split("\n")[0]))
if emlContent is not None:
writer.writerow([emlContent[0],emlContent[1],emlContent[2],emlContent[3],emlContent[4],emlContent[5],label])
其中emlAnayalyze函數(shù)利用flanker庫中的mime,可以將郵件中的發(fā)件人、收件人、抄送人、主題、發(fā)送時間、內容等要素提取出來,具體可以參考我的這篇文章python幾行代碼實現(xiàn)郵件解析_Yunlord的博客-CSDN博客_flanker 郵件解析,然后存成csv,方便后續(xù)郵件分析。
2.2 從csv中提取郵件內容進行分類
def get_data(path):
'''
獲取數(shù)據(jù)
:return: 文本數(shù)據(jù),對應的labels
'''
maildf = pd.read_csv(path,header=None, names=['Sender','Receiver','“CarbonCopy','Subject','Date','Body','isSpam'])
filteredmaildf=maildf[maildf['Body'].notnull()]
corpus=filteredmaildf['Body']
labels=filteredmaildf['isSpam']
corpus=list(corpus)
labels=list(labels)
return corpus, labels
通過get_data函數(shù)讀取csv格式數(shù)據(jù),并且提取出內容不為空的數(shù)據(jù),和對應的標簽。
?可以看到一共有40348個數(shù)據(jù)。
from sklearn.model_selection import train_test_split
# 對數(shù)據(jù)進行劃分
train_corpus, test_corpus, train_labels, test_labels = train_test_split(corpus, labels,
test_size=0.3, random_state=0)
然后通過?sklearn.model_selection庫中的train_test_split函數(shù)劃分訓練集、驗證集。
# 進行歸一化
norm_train_corpus = normalize_corpus(train_corpus)
norm_test_corpus = normalize_corpus(test_corpus)
?然后通過normalize_corpus函數(shù)對數(shù)據(jù)進行預處理。
def textParse(text):
listOfTokens=jieba.lcut(text)
newList=[re.sub(r'\W*','',s) for s in listOfTokens]
filtered_text=[tok for tok in newList if len(tok)>0]
return filtered_text
def remove_stopwords(tokens):
filtered_tokens = [token for token in tokens if token not in stopword_list]
filtered_text = ' '.join(filtered_tokens)
return filtered_text
def normalize_corpus(corpus, tokenize=False):
normalized_corpus = []
for text in corpus:
filtered_text = textParse(filtered_text)
filtered_text = remove_stopwords(filtered_text)
normalized_corpus.append(filtered_text)
return normalized_corpus
里面包括textParse、remove_stopwords這兩個數(shù)據(jù)預處理操作。
textParse函數(shù)先通過jieba進行分詞,然后去除無用字符。
remove_stopwords函數(shù)先是加載stop_words.txt停用詞表,然后去除停用詞。
從而實現(xiàn)數(shù)據(jù)預處理。
2.3?構建詞向量
# 詞袋模型特征
bow_vectorizer, bow_train_features = bow_extractor(norm_train_corpus)
bow_test_features = bow_vectorizer.transform(norm_test_corpus)
# tfidf 特征
tfidf_vectorizer, tfidf_train_features = tfidf_extractor(norm_train_corpus)
tfidf_test_features = tfidf_vectorizer.transform(norm_test_corpus)
其中bow_extractor,tfidf_extractor兩個函數(shù)分別將訓練集轉化為詞袋模型特征和tfidf特征。
from sklearn.feature_extraction.text import CountVectorizer
def bow_extractor(corpus, ngram_range=(1, 1)):
vectorizer = CountVectorizer(min_df=1, ngram_range=ngram_range)
features = vectorizer.fit_transform(corpus)
return vectorizer, features
from sklearn.feature_extraction.text import TfidfTransformer
def tfidf_transformer(bow_matrix):
transformer = TfidfTransformer(norm='l2',
smooth_idf=True,
use_idf=True)
tfidf_matrix = transformer.fit_transform(bow_matrix)
return transformer, tfidf_matrix
from sklearn.feature_extraction.text import TfidfVectorizer
def tfidf_extractor(corpus, ngram_range=(1, 1)):
vectorizer = TfidfVectorizer(min_df=1,
norm='l2',
smooth_idf=True,
use_idf=True,
ngram_range=ngram_range)
features = vectorizer.fit_transform(corpus)
return vectorizer, features
2.4 訓練模型以及評估
對如上兩種不同的向量表示法,分別訓練貝葉斯分類器、邏輯回歸分類器、支持向量機分類器,從而驗證效果。
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import SGDClassifier
from sklearn.linear_model import LogisticRegression
mnb = MultinomialNB()
svm = SGDClassifier(loss='hinge', n_iter_no_change=100)
lr = LogisticRegression()
# 基于詞袋模型的多項樸素貝葉斯
print("基于詞袋模型特征的貝葉斯分類器")
mnb_bow_predictions = train_predict_evaluate_model(classifier=mnb,
train_features=bow_train_features,
train_labels=train_labels,
test_features=bow_test_features,
test_labels=test_labels)
# 基于詞袋模型特征的邏輯回歸
print("基于詞袋模型特征的邏輯回歸")
lr_bow_predictions = train_predict_evaluate_model(classifier=lr,
train_features=bow_train_features,
train_labels=train_labels,
test_features=bow_test_features,
test_labels=test_labels)
# 基于詞袋模型的支持向量機方法
print("基于詞袋模型的支持向量機")
svm_bow_predictions = train_predict_evaluate_model(classifier=svm,
train_features=bow_train_features,
train_labels=train_labels,
test_features=bow_test_features,
test_labels=test_labels)
joblib.dump(svm, 'svm_bow.pkl')
# 基于tfidf的多項式樸素貝葉斯模型
print("基于tfidf的貝葉斯模型")
mnb_tfidf_predictions = train_predict_evaluate_model(classifier=mnb,
train_features=tfidf_train_features,
train_labels=train_labels,
test_features=tfidf_test_features,
test_labels=test_labels)
# 基于tfidf的邏輯回歸模型
print("基于tfidf的邏輯回歸模型")
lr_tfidf_predictions=train_predict_evaluate_model(classifier=lr,
train_features=tfidf_train_features,
train_labels=train_labels,
test_features=tfidf_test_features,
test_labels=test_labels)
# 基于tfidf的支持向量機模型
print("基于tfidf的支持向量機模型")
svm_tfidf_predictions = train_predict_evaluate_model(classifier=svm,
train_features=tfidf_train_features,
train_labels=train_labels,
test_features=tfidf_test_features,
test_labels=test_labels)
輸出結果如下所示?
總結
通過針對郵件內容,并且轉化為兩種不同的詞向量進行不同模型的訓練,從而得到基于tfidf的支持向量機模型效果最好,可以達到98%的準確率。
想要一起從小白到大神,學習自然語言處理的朋友們可以點擊下方鏈接或者訂閱我的自然語言處理從小白到精通專欄,里面涉及到的工程部署以及完整代碼實踐全部免費贈送。
參考:文章來源:http://www.zghlxwxcb.cn/news/detail-481766.html
使用PaddleNLP識別垃圾郵件(一):準確率98.5%的垃圾郵件分類器 - 飛槳AI Studio - 人工智能學習與實訓社區(qū)文章來源地址http://www.zghlxwxcb.cn/news/detail-481766.html
到了這里,關于垃圾郵件識別(一):用機器學習做中文郵件內容分類的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!