機器學習項目之實現垃圾郵件處理(1)——數據清洗

學習了支持向量機算法後(SVM)想自己用一些數據集來嘗試一下,在網絡上找了一個垃圾郵件處理的數據集正好適用於SVM支持向量算法,所以在這裏不講SVM算法內容,而是分享我是如何用Python來實現的。
具體數據集:[郵件數據集][1]
[1]: https://pan.baidu.com/s/1ivQmo-04fCa3qVG0SAiUtQ

1. 首先查看數據集

這是數據集中的一封郵件

郵件中有很多中特徵值,有些是有用的有些卻無法幫助我們判斷是否是垃圾郵件,所以這裏我們選取其中4個特徵值(From,To,Data,Content)。
(1、郵件的內容分析——主要包含:發件人、收件人、發件時間以及郵件的內容)
![分類][3]
(2、是否爲垃圾郵件的標籤,spam——是垃圾郵件;ham——不是垃圾郵件)

2. 分析數據集

分析:垃圾郵件處理問題是一個**監督學習**,僅用來分類郵件好壞固爲**二分類**問題,分類內容爲**長文本**。
所有非向量形式的特徵工程,首先要轉換成向量的形式
該數據集適合很多種模型(貝葉斯,KNN),在這裏我用SVM來解決

3. 開始進行數據清洗的工作

引入模塊常用功能

import os

索引文件(分類標籤)讀取,該文件中分爲兩列
第一列:分類標籤是否爲垃圾郵件(是:spam、否:ham);
第二列:存放郵件對應文件夾路徑,兩列之間通過空格分割

def read_index_file(file_path):
    type_dict={"spam":"1","ham":"0"}        #用字典存放分類的垃圾郵件(0/1)
    index_file=open(file_path)
    index_dict={}        #存儲分類後得到的結構字典
    
    try:
        for line in index_file:        #按照行來讀取
            arr=line.split(" ")        #從每行的第一個空格分開
            
            if len(arr) == 2:
                key,value = arr        #將key和value分別賦值前後兩段
            #將value中的數據規整,將../data去掉
            value=value.replace("../data","").replace("\n","")
            #將每一個值是1/0對應加入數據字典中
            index_dict[value]=type_dict[key.lower()]        #將spam/ham中可能出現的大寫字母換成小寫
    finally:
        index_file.close()
    return index_dict   

郵件的文件內容數據讀取

def read_file(file_path):
    #打開郵件只讀r,編碼方式gb2312,錯誤忽略
    file=open(file_path,"r",encoding="gb2312",errors="ignore")
    content_dict={}
    
    try:
        is_content = False
        for line in file:        #按行讀取
            line = line.strip()        #去掉每行的空格
            if line.startswith("From:"):
                #將From:後的內容加入數據字典,將key="from:",value=line[5:]5以後的內容
                content_dict["from:"]=line[5:]
            elif line.startswith("To:"):
                content_dict["to:"]=line[3:]
            elif line.startswith("Date:"):
                content_dict["date:"]=line[5:]
            elif not line:
                # 郵件內容與上面信息存在着第一個空行,遇到空行時,這裏標記爲True以便進行下面的郵件內容處理
                # line文件的行爲空時是False,不爲空時是True
                is_content = True
            #如果這一行是空行表明下一行開始是具體的內容(content),則開始處理郵件
            if is_content:
                if "content" in content_dict:
                    #如果這一行有內容則加入字典
                    content_dict["content"] += line
                else:
                    #如果這一行沒有內容則不加入,繼續下一行
                    content_dict["content"] = line
    finally:
        file.close()
 
    return content_dict

3、郵件數據處理(內容的拼接,並用逗號進行分割)

def process_file(file_path):
    content_dict = read_file(file_path)
    
    #進行處理(拼接),get()函數返回指定鍵的值,指定鍵的值不存在用指定的默認值unkown代替
    #2,是將需要是數據特徵取出來放在鍵值對中保存,3,則是將所有的特徵值合併成,進行拼接
    result_str = content_dict.get("from","unkown").replace(",","").strip()+","
    result_str += content_dict.get("to:","unkown").replace(",","").strip()+","
    result_str += content_dict.get("date:","unkown").replace(",","").strip()+","
    result_str += content_dict.get("content","unkown").replace(",","").strip()
    return result_str

4、開始進行數據處理——函數調用

## os.listdir    返回指定的文件夾包含的文件或文件夾包含的名稱列表
index_dict = read_index_file('../data/full/index')        #調用第一個函數
list0 = os.listdir('../data/data')
#開始打印list0
for l1 in list0:        #循環000-299
    l1_path = '../data/data/' + l1         #l1_path   ../data/data/(215)
    print('開始處理文件夾:'+l1_path)
    list1 = os.listdir(l1_path)        #list1:['000', '001', '002', '003'....'299']
    #將list1打印出來
    write_file_path = '../data/process01_' + l1        #用這個來存放
    with open(write_file_path,"w",encoding='utf-8') as writer:
        for l2 in list1:        #l2循環000-299
            l2_path = l1_path + "/" + l2        #l2_path = ../data/data/(000-215)/(000-299)
            #這就得到了具體的文件內容,然後進行文件數據的讀取
            index_key = "/" + l1 + "/" + l2        #index_key = /(000-215)/(000-299)
            
            if index_key in index_dict:
                #讀取數據
                content_str = process_file(l2_path)        #3的函數,用來拼接數據元素,及特徵值的合併
                #添加分類標籤(0/1),可用逗號隔開
                content_str += "," + index_dict[index_key] + "\n"
                #進行數據的輸出
                writer.writelines(content_str)

處理結果

將所有構建好的內容進行合併

with open('../data/result_process01','w',encoding="utf-8") as writer:
    #將所有內容合併到result_process01中
    for l1 in list0:
        file_path = '../data/process01_' + l1
        print("開始合併文件:" + file_path)
        
        with open(file_path, encoding='utf-8') as file:
            for line in file:
                writer.writelines(line)

處理結果

清洗結果

到這一步數據的清洗就完成了,所有我們需要的特徵值都被整合到了一起,並且爲郵件做了加上了是否爲垃圾郵件的標記。
處理結果
推薦使用jupyter,注意文件的路徑問題,特徵工程和後面的分類會在下一篇。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章