朴素贝叶斯实现垃圾邮件处理

当然前者是老师写的。

训练数据


i n d e x index index是具体数据的文件位置。
在这里插入图片描述
s p a m spam spam是垃圾邮件
s t o p stop stop是停用词,即去掉了一些非实义动词(啊,比如,其实等)

数据预处理

创造一个 d a t a f r a m e dataframe dataframe结构,存储类别和训练数据所在位置。

def load_data():
    df = pd.read_csv('index', sep=' ', names=['spam', 'path'])
    df.spam = df.spam.apply(lambda x: 1 if x == 'spam' else 0)
    df.path = df.path.apply(lambda x: x[1:])#这里是为了去除../的.因为在同一工作目录下
    return df

加载停用词。

def load_stop_list():
    with open('stop', 'r') as f:
        lines = f.readlines()
    stop_list = [i.strip() for i in lines]#移除指定字符,默认是空格或者换行符,这里移除了换行符
    return stop_list

获取邮件的内容

def get_content(path):
    # 邮件数据是 gbk 编码, 忽略无法解码的内容
    with open(path, 'r', encoding='gbk', errors='ignore') as f:
        lines = f.readlines()
    for i in range(len(lines)):
        if lines[i] == '\n':
            #从空行后的第一行开始,因为一开始都是收件人等的信息,第一个空行后才是邮件数据
            lines = lines[i:]
            break
    content = ''.join(''.join(lines).strip().split())#用空格分开
    #''.join()也可以用来转化成字符串
    #.strip()用来移除字符串首位指定字符,去除了空格,\n \t \r字符
    return content

训练

创建词汇字典,为什么要创建这个呢。
因为我们的做法,是把邮件中的每个词汇当做特征,来进行朴素贝叶斯分类。
最后得到每个邮件的词汇字典。

def create_string_word_dict(string, stop_list):
    string = re.findall(u'[\u4E00-\u9FD5]', string)#寻找中文语句
    string = ''.join(string)
    
    word_list = []
    seg_list = jieba.cut(string)#结巴分词,创建词汇
    for word in seg_list:
        if word != '' and word not in stop_list:
            word_list.append(word)#没有被禁用就加入
    word_dict = dict([(word, 1) for word in word_list])#创建字典
    return word_dict

进行训练,得到具体每个词汇对应具体分类的数量。

def train(df):
    train_word_dict = {}
    for word_dict, spam in zip(df.word_dict, df.spam):
        # 统计测试邮件中词语在垃圾邮件和正常邮件中出现的总数
        for w in word_dict:
            train_word_dict.setdefault(w, {0: 0, 1: 0})
            train_word_dict[w][spam] += 1
    ham_count = df.spam.value_counts()[0]
    spam_count = df.spam.value_counts()[1]
    return train_word_dict, spam_count, ham_count

预测

预测就是计算文章内多个词汇对于某个类别的概率,然后相乘。
为了防止溢出,我们用的是 l o g log log

def predict(train_word_dict, spam_count, ham_count, row):
    total_count = ham_count + spam_count
    word_dict = row['word_dict']

    # 正常邮件概率
    hp = math.log(float(ham_count) / total_count)
    # 垃圾邮件概率
    sp = math.log(float(spam_count) / total_count)

    for w in word_dict:
        w = w.strip()
        # 给该词在词典中设定一个默认数0
        train_word_dict.setdefault(w, {0: 0, 1: 0})

        # 该词在词典中正常邮件出现的次数
        pih = train_word_dict[w][0]
        # 平滑处理, 每个词汇基数+1,正常邮件数+2
        hp += math.log((float(pih) + 1) / (ham_count + 2))
        
        pis = train_word_dict[w][1]
        sp += math.log((float(pis) + 1) / (spam_count + 2))
    # 预测结果
    predict_spam = 1 if sp > hp else 0
    # 返回预测是否准确,用于统计
    return 1 if predict_spam == row['spam'] else 0

主程序调用

if __name__ == '__main__':
    df=load_data()#加载邮件数据
    stop_list = load_stop_list()#加载停用词列表
    df['content'] = df.path.apply(lambda x: get_content(x))#提取邮件文本内容
    df['word_dict'] = df.content.apply(lambda x: create_string_word_dict(x, stop_list))#创建邮件字典
    print(df['word_dict'])

train_mails = df.loc[:int(len(df) * 0.8)]
test_mails = df.loc[int(len(df) * 0.8):]#训练集和测试集
train_word_dict, spam_count, ham_count = train(train_mails)
train_word_dict

test_mails_predict = test_mails.apply(
    lambda x: predict(train_word_dict, spam_count, ham_count, x), axis=1)

result = 1 - float(test_mails_predict.value_counts().get(0, 0)) / test_mails_predict.value_counts().sum()
print('预测准确率:', result)

结果

在这里插入图片描述

使用sklearn

之前我们使用结巴分词,留下中文,去掉停用词。

# -*- coding: utf-8 -*-
"""
Created on Sat May  2 17:20:05 2020

@author: DELL
"""
from sklearn.model_selection import  train_test_split
from sklearn.feature_extraction.text import CountVectorizer  # 从sklearn.feature_extraction.text里导入文本特征向量化模块
from sklearn.naive_bayes import MultinomialNB     # 从sklean.naive_bayes里导入朴素贝叶斯模型
from sklearn.metrics import classification_report
import pandas as pd

stop_list=[]

def load_data():
    df = pd.read_csv('index', sep=' ', names=['spam', 'path'])
    df.spam = df.spam.apply(lambda x: 1 if x == 'spam' else 0)
    df.path = df.path.apply(lambda x: x[1:])#这里是为了去除../的.因为不是在同一工作目录下
    return df

def load_stop_list():
    with open('stop', 'r') as f:
        lines = f.readlines()
    stop_list = [i.strip() for i in lines]#移除指定字符,默认是空格或者换行符,这里移除了换行符
    return stop_list

def get_content(path):
    # 邮件数据是 gbk 编码, 忽略无法解码的内容
    with open(path, 'r', encoding='gbk', errors='ignore') as f:
        lines = f.readlines()
    for i in range(len(lines)):
        if lines[i] == '\n':
            #从空行后的第一行开始,因为一开始都是收件人等的信息,第一个空行后才是邮件数据
            lines = lines[i:]
            break
    content = ''.join(''.join(lines).strip().split())
    return content

if __name__ == '__main__':
    df = load_data()#加载邮件数据
    stop_list = load_stop_list()#加载停用词列表
    df['content'] = df.path.apply(lambda x: get_content(x))#提取邮件文本内容
    
X_train,X_test,y_train,y_test = train_test_split(df['content'],df['spam'],test_size=0.2,random_state=33) # 随机采样25%的数据样本作为测试集

#文本特征向量化
vec = CountVectorizer(stop_words=stop_list)#设置停用词
X_train = vec.fit_transform(X_train)
X_test = vec.transform(X_test)

#使用朴素贝叶斯进行训练
mnb = MultinomialNB()   # 使用默认配置初始化朴素贝叶斯
mnb.fit(X_train,y_train)    # 利用训练数据对模型参数进行估计
y_predict = mnb.predict(X_test)     # 对参数进行预测

#获取结果报告
print ('The Accuracy of Naive Bayes Classifier is:', mnb.score(X_test,y_test))

结果如下:
在这里插入图片描述
可以发现,相比较而言,后者略微好一点点。

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值