基于KNN的垃圾邮件分类实验

本次实验中我使用到的是I. Androutsopoulos, J. Koutsias, K.V. Chandrinos, George Paliouras和 C.D. Spyropoulos的 "An Evaluation of Naive Bayesian Anti-Spam Filtering"中使用到的垃圾邮件语料库:lingspam_public。
其中包含有四个子目录bare、lemm、lemm_stop和stop。这4个目录中的每一个都包含10个子目录(第1部分,…第10部分),其中9部分用作训练,1部分用作测试。
下面开始实验:

读取文件

我们的实验数据集共11572封邮件,包括9648封非垃圾邮件,1924封垃圾邮件,其中每封垃圾邮件文件名含有"spmsg"。由于邮件的文本中从第三行开始为正文,并且我们只在正文内容上进行文本分析,因此,读取邮件从第三行开始,并对每封邮件进行文本预处理。

def read_file(position):
    print(position)
    rea=""
    with open(position, "r",encoding='utf-8') as f:
            next(f)
            next(f)    
            rea = f.read()
    f.close()
    return rea

邮件文本预处理

  1. 去除非字母符号。
    使用正则表达式将非文字类的符号,如标点符号、数字或特殊字符等去除。
data=re.sub(r'[^A-Za-z]', ' ', data)
  1. 将字母转换为小写
    将字母转换为小写,同时由于英文单词之间以空格作为自然分界符,因此以空格为间隔直接进行分词。
str_list = data.lower().split()
  1. 去除停用词
    将介词等对垃圾邮件判断无关的词移除,并在停词表中增加人名等使词典改进。
stop_words = set(stopwords.words('english'))
filtered_sentence = [w for w in str_list if not w in stop_words]
  1. 词形还原
    词形还原,使得单词含义被保留。英语分词后,根据其词性将单词还原为字典中原型词汇。先使用nltk.pos_tag()获取单词在句子中的词性,再使用wnl.lemmatize()函数可以进行词形还原。
# 获取单词词性
def get_wordnet_pos(tag):
    if tag.startswith('J'):
        return wordnet.ADJ
    elif tag.startswith('V'):
        return wordnet.VERB
    elif tag.startswith('N'):
        return wordnet.NOUN
    elif tag.startswith('R'):
        return wordnet.ADV
    else:
        return None
        
tagged_sent = pos_tag(filtered_sentence)
        wnl = WordNetLemmatizer()
        lemmas_sent = []
        for tag in tagged_sent:
            wordnet_pos = get_wordnet_pos(tag[1]) or wordnet.NOUN
            lemmas_sent.append(wnl.lemmatize(tag[0], pos=wordnet_pos)) # 词形还原

创建词典

对清理后的邮件文本单词列表进行词频统计,取出出现频率前3000个单词作为词典保存。(当然也可以分别取垃圾邮件和正常邮件中词频前2000单词,合并组成一个词典)

特征提取

词典完成后,对数据集中每一封邮件提取维度是3001的词数向量,其中第一列存放邮件类别,0表示此邮件为垃圾邮件,1表示此邮件为正常邮件,之后的3000列存放词典对应的词在此邮件中的出现次数。
最后生成一个11572*3001的特征向量矩阵。

模型训练预测

使用scikit-learn机器学习库训练分类器,输入样本数据和结构化的输出结果,运行k-近邻算法(KNN)判定输入数据属于哪一个分类。由于3000个单词属性的数值对于计算结果的影响是相等的,数据已经在同一尺度,因此可以不用进行数值归一化,而是直接将向量放入KNN分类器中,在试验中准确率无变化也说明其对结果无明显影响。
首先,提供数据集的90%作为训练样本来训练分类器,而使用其余的10%数据去测试分类器,检测分类器的正确率。
之后,在运行算法前,调整并指定超参数:使用交叉验证法,得到最优K值,此时K=4,即计算距离后,选取距离最小的前4个点,选择这4个最相似数据中出现次数最多的分类,作为新数据的分类。在多次试验后,选取weights = ‘uniform’,即不考虑距离权重这个超参数,所有的邻近点的权重都是相等的;选取p=1,使用曼哈顿距离计算两点距离,而非欧式距离。
最后算法结论得出,错误率在可接受范围内,则可以运行k-近邻算法进行分类。

最后结果

实验最后准确率

需要注意的地方

将词干提取改为词形还原后,准确率从98.88%提升到99.05%。说明在该实验中更适合使用词形还原。

说明k值过小时,例如取1时,是选取最近的一个点,这使得模型出现过拟合现象。
因此之后可以选用交叉验证法选择合适的k值,最后实验准确率提高到99.827%。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ellie是个昵称

您的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值