机器学习项目之实现垃圾邮件处理1数据清洗

34次阅读

共计 3341 个字符,预计需要花费 9 分钟才能阅读完成。

学习了支持向量机算法后(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, 注意文件的路径问题,特征工程和后面的分类会在下一篇。

正文完
 0