朴素贝叶斯应用-机器学习-新浪新闻分类器

朴素贝叶斯应用-机器学习-新浪新闻分类器

本文代码及数据均来自于https://cuijiahua.com/blog/2017/11/ml_5_bayes_2.html

这个例子比较有实践意义,不仅使用了jieba、sklearn,并且其中用到的思想也是很实用的。

jieba

"结巴"中文分词:做最好的Python中文分词组件 "Jieba"

jieba有三种分词模式:全模式、精确模式和搜索引擎模式

示例:

#encoding=utf-8
import jieba

seg_list = jieba.cut("我来到北京清华大学",cut_all=True)
print "Full Mode:", "/ ".join(seg_list) #全模式

seg_list = jieba.cut("我来到北京清华大学",cut_all=False)
print "Default Mode:", "/ ".join(seg_list) #精确模式

seg_list = jieba.cut("他来到了网易杭研大厦") #默认是精确模式
print ", ".join(seg_list)

seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造") #搜索引擎模式
print ", ".join(seg_list)

输出:

【全模式】: 我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学

【精确模式】: 我/ 来到/ 北京/ 清华大学

【新词识别】:他, 来到, 了, 网易, 杭研, 大厦    (此处,“杭研”并没有在词典中,但是也被Viterbi算法识别出来了)

【搜索引擎模式】: 小明, 硕士, 毕业, 于, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所, 后, 在, 日本, 京都, 大学, 日本京都大学, 深造

本例来源:https://www.oschina.net/p/jieba

Zip

这里说的zip是Python中的一个函数,它将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表对象。

用法如下:

>>>a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b)     # 打包为元组的列表
[(1, 4), (2, 5), (3, 6)]
>>> zip(a,c)              # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]
>>> zip(*zipped)          # 与 zip 相反,*zipped 可理解为解压,返回二维矩阵式
[(1, 2, 3), (4, 5, 6)]

这里的zip起到的不是数据压缩作用,当然要是硬说也有压缩,两个对象压缩成一个了嘛,但是主要的功能是批量实现key:value,将变量之间的值一一对应。

With

with算是python中“省事”的一个典型了吧,托管了外部资源访问的异常处理、关闭等步骤

在with后面的代码块抛出异常时,exit()方法被执行。开发库时,清理资源,关闭文件等操作,都可以放在exit()方法中。
总之,with-as表达式极大的简化了每次写finally的工作,这对代码的优雅性是有极大帮助的。
如果有多项,可以这样写:

With open(‘1.txt‘) as f1, open(‘2.txt‘) as f2:
do something

如下代码:

file = open("1.txt")
data = file.read()
file.close()123

上面代码存在2个问题:
(1)文件读取发生异常,但没有进行任何处理;
(2)可能忘记关闭文件句柄;

改进

try:
   f = open('xxx')
except:
   print('fail to open')
   exit(-1)
try:
   do something
except:
   do something
finally:
   f.close()1234567891011

虽然这段代码运行良好,但比较冗长。
而使用with的话,能够减少冗长,还能自动处理上下文环境产生的异常。如下面代码:

with open("1.txt") as file:
   data = file.read()

原博主的算法是分布的,我也在jupyter notebook上写成了分布的形式,下面我粘贴上转换成的md文档,包括了源码、一小部分输出(太长了,影响阅读)、我加的一些注释

很长,大家做好准备



数据集已经准备好,接下来,让我们直接进入正题。切分中文语句,编写如下代码:
!下面这段代码在我的电脑上会宕机,就,恩,不运行了吧

# -*- coding: UTF-8 -*-
import os
import jieba

def TextProcessing(folder_path):
    folder_list = os.listdir(folder_path)                        #查看folder_path下的文件
    data_list = []                                                #训练集
    class_list = []

    #遍历每个子文件夹
    for folder in folder_list:
        new_folder_path = os.path.join(folder_path, folder)        #根据子文件夹,生成新的路径
        files = os.listdir(new_folder_path)                        #存放子文件夹下的txt文件的列表

        j = 1
        #遍历每个txt文件
        for file in files:
            if j > 100:                                            #每类txt样本数最多100个
                break
            with open(os.path.join(new_folder_path, file), 'r', encoding = 'utf-8') as f:    #打开txt文件
                raw = f.read()

            word_cut = jieba.cut(raw, cut_all = False)            #精简模式,返回一个可迭代的generator
            word_list = list(word_cut)                            #generator转换为list

            data_list.append(word_list)
            class_list.append(folder)
            j += 1
    print(data_list)
    print(class_list)
if __name__ == '__main__':
    #文本预处理
    folder_path = './SogouC/Sample'                #训练集存放地址
    TextProcessing(folder_path)

代码运行结果如下所示,可以看到,我们已经顺利将每个文本进行切分,并进行了类别标记。

我们将所有文本分成训练集和测试集,并对训练集中的所有单词进行词频统计,并按降序排序。也就是将出现次数多的词语在前,出现次数少的词语在后进行排序。编写代码如下:

# -*- coding: UTF-8 -*-
import os
import random
import jieba

"""
函数说明:中文文本处理

Parameters:
    folder_path - 文本存放的路径
    test_size - 测试集占比,默认占所有数据集的百分之20
Returns:
    all_words_list - 按词频降序排序的训练集列表
    train_data_list - 训练集列表
    test_data_list - 测试集列表
    train_class_list - 训练集标签列表
    test_class_list - 测试集标签列表
Author:
    Jack Cui
Blog:
    http://blog.csdn.net/c406495762
Modify:
    2017-08-22
"""
def TextProcessing(folder_path, test_size = 0.2):
    folder_list = os.listdir(folder_path)                        #查看folder_path下的文件
    data_list = []                                                #数据集数据
    class_list = []                                                #数据集类别

    #遍历每个子文件夹
    for folder in folder_list:
        new_folder_path = os.path.join(folder_path, folder)        #根据子文件夹,生成新的路径
        files = os.listdir(new_folder_path)                        #存放子文件夹下的txt文件的列表

        j = 1
        #遍历每个txt文件
        for file in files:
            if j > 100:                                            #每类txt样本数最多100个
                break
            with open(os.path.join(new_folder_path, file), 'r', encoding = 'utf-8') as f:    #打开txt文件
                raw = f.read()

            word_cut = jieba.cut(raw, cut_all = False)            #精简模式,返回一个可迭代的generator
            word_list = list(word_cut)                            #generator转换为list

            data_list.append(word_list)                            #添加数据集数据
            class_list.append(folder)                            #添加数据集类别
            j += 1

    data_class_list = list(zip(data_list, class_list))            #zip压缩合并,将数据与标签对应压缩
    random.shuffle(data_class_list)                                #将data_class_list乱序
    index = int(len(data_class_list) * test_size) + 1            #训练集和测试集切分的索引值
    train_list = data_class_list[index:]                        #训练集
    test_list = data_class_list[:index]                            #测试集
    train_data_list, train_class_list = zip(*train_list)        #训练集解压缩
    test_data_list, test_class_list = zip(*test_list)            #测试集解压缩

    all_words_dict = {}                                            #统计训练集词频
    for word_list in train_data_list:
        for word in word_list:
            if word in all_words_dict.keys():
                all_words_dict[word] += 1
            else:
                all_words_dict[word] = 1

    #根据键的值倒序排序
    all_words_tuple_list = sorted(all_words_dict.items(), key = lambda f:f[1], reverse = True)
    all_words_list, all_words_nums = zip(*all_words_tuple_list)    #解压缩
    all_words_list = list(all_words_list)                        #转换成列表
    return all_words_list, train_data_list, test_data_list, train_class_list, test_class_list

if __name__ == '__main__':
    #文本预处理
    folder_path = './SogouC/Sample'                #训练集存放地址
    all_words_list, train_data_list, test_data_list, train_class_list, test_class_list = TextProcessing(folder_path, test_size=0.2)
    print(all_words_list)
[',', '的', '\u3000', '。', '\n', ' ', ';', '&', 'nbsp', '、', '在', '了', '“', '”', '是', ':', '\x00', '和', '—', '也', '对', '就', '我', '有', '这', '上', '他', '将', '你', '不', '都', '要', '为', '中', '月', '而', '与', '自己', '一个', '中国', '(', ')', '可以', '年', '导弹', '日', ';', '从', '到', '大陆', '3', '公司', '考生', '等', '.', '人', '时', '火炮', '进行', ')', '(', '旅游', '说', '1', '台军', '会', '个', '没有', '游客', '能', '以', '把', '时间', '但', '认为', '多', '北京', '志愿', '让', '后', '还', '各种', '解放军', '《', '》', '5', '并', '被', '一种', '作战', '已经', '大', '小', '新', '地', '用', '做', '下', '很', '2', '成为', '前', '更', ',', '复习', '-', '大家', '[', ']', '企业', '来', '工作', '选择', '9', '4', '学校', '支付', '我们', '最', '如果', '远程', '…', '10', '这样', '问题', '美国', '去', '给', '可', '比赛', '又', '可能', '一定', '袁', '发展', '分析', '射程', '专业', '能力', '6', '主要', '技术', '着', '?', '!', '向', '考试', '建设', '部署', '完全', '一', '看', '很多', '黄金周', '辅导班', '五一', '因为', '他们', '通过', '使', '部分', '快', '文章', '基础', '2005', '电话', '过', '这些', '就是', '增长', '0', '毕业生', '出', '训练', '学习', '重要', '%', '钱', '分', '填报', '部队', '它', '提高', '时候', '作为', '品牌', '银行', '7', '开始', '计划', '好', '需要', '目前', '市场', 'VS', '接待', '军事', '阵地', '60', '8', ':', '比', '那些', '表现', '/', '坦克', '要求', '这个', '但是', '万人次', '用户', '由', '只有', '期间', '达到', '为了', '管理', '得', '一些', '16', '其中', '30', '科学', '比较', '几乎', '拥有', '网络', '相对', '影响', '最后', '提供', '不是', '其', '销售', '表示', '新浪', '活动', '资料', '情况', '已', '却', '所', '于', '所以', '阅读', '来源', '一旦', '她', '以上', '历史', '讲', '装备', '当', '必须', '系统', '还是', '里', '记者', '实验室', '人才', '题', '再', '考研', '则', '相关', '今年', '2006', '东莞', '该', '起', '专家', '这是', '压制', '对于', '重点', '知道', '词汇', '00', '们', '其他', '及', '上海', '招聘', 'MBA', '公里', '英语', '耿大勇', '参加', '现在', '根据', '由于', '注意', '应该', '第', '准备', '不用', '游戏', '距离', '或', '据', '11', 'A', '服务', '员工', '彻底', '手机', '大批', '岛屿', '阿里', '【', '】', '指挥', '方面', '孩子', '睡眠', '一家', '想', "'", '收入', '沿海', '力气', '摧毁', '图', '全军', '设计', '如', '建议', '什么', '平台', '一批', '机会', '了解', '香港', '不会', '同时', '置于', '全国', '大学生', '"', '数独', '数学', '挑衅', '角度', '20', '不能', '战场', '内', '利用', '才能', '许多', '而且', '还有', '不同', '然后', '地方', '老师', '家', '希望', '高']

all_words_list就是将所有训练集的切分结果通过词频降序排列构成的单词合集。观察一下打印结果,不难发现,这里包含了很多标点符号,很显然,这些标点符号是不能作为新闻分类的特征的。总不能说,应为这个文章逗号多,所以它是xx类新闻吧?为了降低这些高频的符号对分类结果的影响,我们应该怎么做呢?答曰:抛弃他们! 除了这些,还有"在","了"这样对新闻分类无关痛痒的词。并且还有一些数字,数字显然也不能作为分类新闻的特征。所以要消除它们对分类结果的影响,我们可以定制一个规则。

一个简单的规则可以这样制定:首先去掉高频词,至于去掉多少个高频词,我们可以通过观察去掉高频词个数和最终检测准确率的关系来确定。除此之外,去除数字,不把数字作为分类特征。同时,去除一些特定的词语,比如:"的","一","在","不","当然","怎么"这类的对新闻分类无影响的介词、代词、连词。怎么去除这些词呢?可以使用已经整理好的stopwords_cn.txt文本。

为什么要去掉高频词?因为即使对于不同的文章,基础的词都是差不多的,我们要分辨的话应该是通过出现频率较少但是专业性也较强的词入手,而不是这些通用词,所以要把这些“高频且通用”的词去掉

所以我们可以根据这个文档,将这些单词去除,不作为分类的特征。我们取出前100个高频词汇,编写代码如下:

# -*- coding: UTF-8 -*-
import os
import random
import jieba

"""
函数说明:中文文本处理

Parameters:
    folder_path - 文本存放的路径
    test_size - 测试集占比,默认占所有数据集的百分之20
Returns:
    all_words_list - 按词频降序排序的训练集列表
    train_data_list - 训练集列表
    test_data_list - 测试集列表
    train_class_list - 训练集标签列表
    test_class_list - 测试集标签列表
Author:
    Jack Cui
Blog:
    http://blog.csdn.net/c406495762
Modify:
    2017-08-22
"""
def TextProcessing(folder_path, test_size = 0.2):
    folder_list = os.listdir(folder_path)                        #查看folder_path下的文件
    data_list = []                                                #数据集数据
    class_list = []                                                #数据集类别

    #遍历每个子文件夹
    for folder in folder_list:
        new_folder_path = os.path.join(folder_path, folder)        #根据子文件夹,生成新的路径
        files = os.listdir(new_folder_path)                        #存放子文件夹下的txt文件的列表

        j = 1
        #遍历每个txt文件
        for file in files:
            if j > 100:                                            #每类txt样本数最多100个
                break
            with open(os.path.join(new_folder_path, file), 'r', encoding = 'utf-8') as f:    #打开txt文件
                raw = f.read()

            word_cut = jieba.cut(raw, cut_all = False)            #精简模式,返回一个可迭代的generator
            word_list = list(word_cut)                            #generator转换为list

            data_list.append(word_list)                            #添加数据集数据
            class_list.append(folder)                            #添加数据集类别
            j += 1

    data_class_list = list(zip(data_list, class_list))            #zip压缩合并,将数据与标签对应压缩
    random.shuffle(data_class_list)                                #将data_class_list乱序
    index = int(len(data_class_list) * test_size) + 1            #训练集和测试集切分的索引值
    train_list = data_class_list[index:]                        #训练集
    test_list = data_class_list[:index]                            #测试集
    train_data_list, train_class_list = zip(*train_list)        #训练集解压缩
    test_data_list, test_class_list = zip(*test_list)            #测试集解压缩

    all_words_dict = {}                                            #统计训练集词频
    for word_list in train_data_list:
        for word in word_list:
            if word in all_words_dict.keys():
                all_words_dict[word] += 1
            else:
                all_words_dict[word] = 1

    #根据键的值倒序排序
    all_words_tuple_list = sorted(all_words_dict.items(), key = lambda f:f[1], reverse = True)
    all_words_list, all_words_nums = zip(*all_words_tuple_list)    #解压缩
    all_words_list = list(all_words_list)                        #转换成列表
    return all_words_list, train_data_list, test_data_list, train_class_list, test_class_list

"""
函数说明:读取文件里的内容,并去重

Parameters:
    words_file - 文件路径
Returns:
    words_set - 读取的内容的set集合
Author:
    Jack Cui
Blog:
    http://blog.csdn.net/c406495762
Modify:
    2017-08-22
"""
def MakeWordsSet(words_file):
    words_set = set()                                            #创建set集合
    with open(words_file, 'r', encoding = 'utf-8') as f:        #打开文件
        for line in f.readlines():                                #一行一行读取
            word = line.strip()                                    #去回车
            if len(word) > 0:                                    #有文本,则添加到words_set中
                words_set.add(word)
    return words_set                                             #返回处理结果

"""
函数说明:文本特征选取

Parameters:
    all_words_list - 训练集所有文本列表
    deleteN - 删除词频最高的deleteN个词
    stopwords_set - 指定的结束语
Returns:
    feature_words - 特征集
Author:
    Jack Cui
Blog:
    http://blog.csdn.net/c406495762
Modify:
    2017-08-22
"""
def words_dict(all_words_list, deleteN, stopwords_set = set()):
    feature_words = []                            #特征列表
    n = 1
    #从deleteN开始读,这样就去掉高频词了,这是去词的第一步
    for t in range(deleteN, len(all_words_list), 1):
        if n > 1000:                            #feature_words的维度为1000
            break
        #去除不符合要求的项
        #如果这个词不是数字,并且不是指定的结束语,并且单词长度大于1小于5,那么这个词就可以作为特征词
        #isdigit可以判断一个字符或者字符串是不是数字
        #大于1就保证了不会取到一些符号、特殊字符等,小于5是为了卡一些特殊情况
        #这是去词的第二部
        if not all_words_list[t].isdigit() and all_words_list[t] not in stopwords_set and 1 < len(all_words_list[t]) < 5:
            feature_words.append(all_words_list[t])
        n += 1
    return feature_words

if __name__ == '__main__':
    #文本预处理
    folder_path = './SogouC/Sample'                #训练集存放地址
    all_words_list, train_data_list, test_data_list, train_class_list, test_class_list = TextProcessing(folder_path, test_size=0.2)

    #生成stopwords_set
    stopwords_file = './stopwords_cn.txt'
    stopwords_set = MakeWordsSet(stopwords_file)

    feature_words = words_dict(all_words_list, 100, stopwords_set)
    print(feature_words)
['支付', '工作', '目前', '选择', '仿制', '比赛', '成为', '时间', '发展', '主要', '黄金周', '美国', '远程', '可能', '建设', '品牌', '分析', '问题', '记者', '增长', '射程', '银行', '五一', '技术', '部署', '复习', '能力', '完全', '管理', '文章', '辅导班', '时候', '上海', '很多', '需要', '一定', '基础', '学习', '考试', '开始', '毕业生', '重要', '亿美元', '部队', '学校', '表示', '情况', '比较', '提高', '影响', '通过', 'VS', '现在', '表现', '部分', '阵地', '产品', '项目', '使用', '训练', '科学', '发现', '今年', '专家', '几乎', '相对', '资料', '设计', '拥有', '军事', '新浪', '希望', '要求', '最大', '必须', '坦克', '期间', '阅读', '这是', '方面', '应该', '人数', '最后', '印度', '实验室', '英语', '考研', '考古', '一次', '了解', '达到', '收入', '专业', '彻底', '万人次', '装备', '压制', '词汇', '专利', '公里', '参加', '活动', '一直', '一家', '知道', '距离', '作用', '日本', '网络', '角度', '耿大勇', '不用', '大批', '阿里', '岛屿', '计划', '准备', '机会', '国内', '重点', '全国', '销售', '力气', '非常', '接待', '指挥', '协议', 'MBA', '孩子', '沿海', '摧毁', '睡眠', '决定', '方式', '不能', '不同', '看到', '出现', '相关', '行业', '经济', '人才', '正在', '台湾', '建议', '新型', '全军', '挑衅', '置于', '获得', '提供', '不会', '全面', '大学', '招聘', '医院', '进入', '注意', '员工', '目标', '去年', '国家', '告诉', '平台', '战场', '发展观', '纳斯', '自寻死路', '世界领先', '型号', '开战', '金贵', '海量', '之内', '费多', '廉价', '左右', '考虑', '老师', '预期', '用户', '沈阳市', '药厂', '牛奶', '这种', '两个', '成功', '香港', '之后', '我国', '组织', '代表', '显示', '一下', '得到', '利用', '服务', '包括', '价值', '介绍', '军队', '喜欢', '止痛药', '消费者', '系统', '我军', '信息化', '东引岛', '研究', '增加', '知识', '顾客', '是否', '吸引', '武器', '电话', '实现', '语法', '句子', '理由', '赔偿', '分期付款', '未来', '最佳', '特别', '愿意', '结果', '本场', '镇痛药', '药物', '消费', '明显', '同比', '交易', '地方', '过程', '演练', '原因', '火力', '分钟', '写作', '对手', '营养', '辽宁队', '王治郅', '发布', '超过', '面对', '大量', '业务', '社会', '补充', '第一', '大学生', '努力', '领导', '事情', '参与', '连续', '上市', '一批', '景区', '小时', '历史', '帮助', '备考', '利苑', '学员', '认证', '数学', '詹姆斯', '埃及', '生活', '这次', '报道', '一起', '过去', '当时', '理解', '越来越', '水平', '领域', '数量', '不少', '关键', '一年', '产生', '不断', '加强', '发生', '实施', '最近', '患者', '全球', '休闲', '图库', '旅行社', '蓝军', '坚持', '不要', '来源', '今天', '经验', '各型', '客场', '免息', '感到', '姚明', '能够', '亿元', '关系', '调查', '环境', '稳定', '这家', '标志', '容易', '客户', '基本', '文化', '整个', '职业', '支持', '制药', '疼痛', '治疗', '刚刚', '关国光', '媒体', '其实', '条件', '掌握', '一样', '东莞', '复试', '统计', '教育', '推出', '医疗', '我省', '志愿', '伯德', '著名', '感受', '世界', '取得', '有限公司', '电子', '办法', '广东', '标准', '工程', '往往', '培养', '本报记者', '提升', '建立', '因素', '带来', '一场', '以下', '发挥', '投入']

可以看到,我们已经滤除了那些没有用的词组,这个feature_words就是我们最终选出的用于新闻分类的特征。随后,我们就可以根据feature_words,将文本向量化,然后用于训练朴素贝叶斯分类器。这个向量化的思想和第三章的思想一致,因此不再累述。

了解了这些,我们就可以编写代码,通过观察取不同的去掉前deleteN个高频词的个数与最终检测准确率的关系,确定deleteN的取值:

# -*- coding: UTF-8 -*-
from sklearn.naive_bayes import MultinomialNB
import matplotlib.pyplot as plt
import os
import random
import jieba

"""
函数说明:中文文本处理

Parameters:
    folder_path - 文本存放的路径
    test_size - 测试集占比,默认占所有数据集的百分之20
Returns:
    all_words_list - 按词频降序排序的训练集列表
    train_data_list - 训练集列表
    test_data_list - 测试集列表
    train_class_list - 训练集标签列表
    test_class_list - 测试集标签列表
Author:
    Jack Cui
Blog:
    http://blog.csdn.net/c406495762
Modify:
    2017-08-22
"""
def TextProcessing(folder_path, test_size = 0.2):
    folder_list = os.listdir(folder_path)                        #查看folder_path下的文件
    data_list = []                                                #数据集数据
    class_list = []                                                #数据集类别

    #遍历每个子文件夹
    for folder in folder_list:
        new_folder_path = os.path.join(folder_path, folder)        #根据子文件夹,生成新的路径
        files = os.listdir(new_folder_path)                        #存放子文件夹下的txt文件的列表

        j = 1
        #遍历每个txt文件
        for file in files:
            if j > 100:                                            #每类txt样本数最多100个
                break
            with open(os.path.join(new_folder_path, file), 'r', encoding = 'utf-8') as f:    #打开txt文件
                raw = f.read()

            word_cut = jieba.cut(raw, cut_all = False)            #精简模式,返回一个可迭代的generator
            word_list = list(word_cut)                            #generator转换为list

            data_list.append(word_list)                            #添加数据集数据
            class_list.append(folder)                            #添加数据集类别
            j += 1

    data_class_list = list(zip(data_list, class_list))            #zip压缩合并,将数据与标签对应压缩
    random.shuffle(data_class_list)                                #将data_class_list乱序
    index = int(len(data_class_list) * test_size) + 1            #训练集和测试集切分的索引值
    train_list = data_class_list[index:]                        #训练集
    test_list = data_class_list[:index]                            #测试集
    train_data_list, train_class_list = zip(*train_list)        #训练集解压缩
    test_data_list, test_class_list = zip(*test_list)            #测试集解压缩

    all_words_dict = {}                                            #统计训练集词频
    for word_list in train_data_list:
        for word in word_list:
            if word in all_words_dict.keys():
                all_words_dict[word] += 1
            else:
                all_words_dict[word] = 1

    #根据键的值倒序排序
    all_words_tuple_list = sorted(all_words_dict.items(), key = lambda f:f[1], reverse = True)
    all_words_list, all_words_nums = zip(*all_words_tuple_list)    #解压缩
    all_words_list = list(all_words_list)                        #转换成列表
    return all_words_list, train_data_list, test_data_list, train_class_list, test_class_list

"""
函数说明:读取文件里的内容,并去重

Parameters:
    words_file - 文件路径
Returns:
    words_set - 读取的内容的set集合
Author:
    Jack Cui
Blog:
    http://blog.csdn.net/c406495762
Modify:
    2017-08-22
"""
def MakeWordsSet(words_file):
    words_set = set()                                            #创建set集合
    with open(words_file, 'r', encoding = 'utf-8') as f:        #打开文件
        for line in f.readlines():                                #一行一行读取
            word = line.strip()                                    #去回车
            if len(word) > 0:                                    #有文本,则添加到words_set中
                words_set.add(word)
    return words_set                                             #返回处理结果

"""
函数说明:根据feature_words将文本向量化

Parameters:
    train_data_list - 训练集
    test_data_list - 测试集
    feature_words - 特征集
Returns:
    train_feature_list - 训练集向量化列表
    test_feature_list - 测试集向量化列表
Author:
    Jack Cui
Blog:
    http://blog.csdn.net/c406495762
Modify:
    2017-08-22
"""
def TextFeatures(train_data_list, test_data_list, feature_words):
    def text_features(text, feature_words):                        #出现在特征集中,则置1
        text_words = set(text)
        features = [1 if word in text_words else 0 for word in feature_words]
        return features
    train_feature_list = [text_features(text, feature_words) for text in train_data_list]
    test_feature_list = [text_features(text, feature_words) for text in test_data_list]
    return train_feature_list, test_feature_list                #返回结果

"""
函数说明:文本特征选取

Parameters:
    all_words_list - 训练集所有文本列表
    deleteN - 删除词频最高的deleteN个词
    stopwords_set - 指定的结束语
Returns:
    feature_words - 特征集
Author:
    Jack Cui
Blog:
    http://blog.csdn.net/c406495762
Modify:
    2017-08-22
"""
def words_dict(all_words_list, deleteN, stopwords_set = set()):
    feature_words = []                            #特征列表
    n = 1
    for t in range(deleteN, len(all_words_list), 1):
        if n > 1000:                            #feature_words的维度为1000
            break
        #如果这个词不是数字,并且不是指定的结束语,并且单词长度大于1小于5,那么这个词就可以作为特征词
        if not all_words_list[t].isdigit() and all_words_list[t] not in stopwords_set and 1 < len(all_words_list[t]) < 5:
            feature_words.append(all_words_list[t])
        n += 1
    return feature_words

"""
函数说明:新闻分类器

Parameters:
    train_feature_list - 训练集向量化的特征文本
    test_feature_list - 测试集向量化的特征文本
    train_class_list - 训练集分类标签
    test_class_list - 测试集分类标签
Returns:
    test_accuracy - 分类器精度
Author:
    Jack Cui
Blog:
    http://blog.csdn.net/c406495762
Modify:
    2017-08-22
"""
#sklearn将朴素贝叶斯封装成了一个对象,通过MultinomialNB()调用,看下面的代码就能发现,和前面我们写的例子相比,最核心的部分只用了一行,并且只是简单的调用了端口,妙啊
    #fit(训练集的特征列表,训练集的Label列表),返回一个训练好的分类器
    #score(测试集的特征列表,测试集的label列表),返回分类准确率
def TextClassifier(train_feature_list, test_feature_list, train_class_list, test_class_list):
    #print(train_feature_list[0:10])
    #通过上面这个打印命令,我们可以看到输入的也是01向量,而不是原本的数据。所以原理是通用的,只不过这里用sklearn替换了手动写的分类方法罢了
    classifier = MultinomialNB().fit(train_feature_list, train_class_list)
    test_accuracy = classifier.score(test_feature_list, test_class_list)
    return test_accuracy

if __name__ == '__main__':
    #文本预处理
    folder_path = './SogouC/Sample'                #训练集存放地址
    all_words_list, train_data_list, test_data_list, train_class_list, test_class_list = TextProcessing(folder_path, test_size=0.2)

    # 生成stopwords_set
    stopwords_file = './stopwords_cn.txt'
    stopwords_set = MakeWordsSet(stopwords_file)

    test_accuracy_list = []
    deleteNs = range(0, 1000, 20)                #0 20 40 60 ... 980
    for deleteN in deleteNs:
        feature_words = words_dict(all_words_list, deleteN, stopwords_set)
        train_feature_list, test_feature_list = TextFeatures(train_data_list, test_data_list, feature_words)
        test_accuracy = TextClassifier(train_feature_list, test_feature_list, train_class_list, test_class_list)
        test_accuracy_list.append(test_accuracy)

    plt.figure()
    plt.plot(deleteNs, test_accuracy_list)
    plt.title('Relationship of deleteNs and test_accuracy')
    plt.xlabel('deleteNs')
    plt.ylabel('test_accuracy')
    plt.show()
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

我们绘制出了deleteNs和test_accuracy的关系,这样我们就可以大致确定去掉前多少的高频词汇了。每次运行程序,绘制的图形可能不尽相同,我们可以通过多次测试,来决定这个deleteN的取值,然后确定这个参数,这样就可以顺利构建出用于新闻分类的朴素贝叶斯分类器了。我测试感觉450还不错,最差的分类准确率也可以达到百分之50以上。将if name == ‘main‘下的代码修改如下:

if __name__ == '__main__':
    #文本预处理
    folder_path = './SogouC/Sample'                #训练集存放地址
    all_words_list, train_data_list, test_data_list, train_class_list, test_class_list = TextProcessing(folder_path, test_size=0.2)

    # 生成stopwords_set
    stopwords_file = './stopwords_cn.txt'
    stopwords_set = MakeWordsSet(stopwords_file)

    test_accuracy_list = []
    feature_words = words_dict(all_words_list, 450, stopwords_set)
    train_feature_list, test_feature_list = TextFeatures(train_data_list, test_data_list, feature_words)
    test_accuracy = TextClassifier(train_feature_list, test_feature_list, train_class_list, test_class_list)
    test_accuracy_list.append(test_accuracy)
    ave = lambda c: sum(c) / len(c)
    #ave 是一个匿名函数,我们将参数test_accuracy_list传入计算结果
    print(ave(test_accuracy_list))

原文地址:https://www.cnblogs.com/jiading/p/11637027.html

时间: 2024-10-06 08:38:11

朴素贝叶斯应用-机器学习-新浪新闻分类器的相关文章

02-NLP-02-用朴素贝叶斯完成语种检测

用朴素贝叶斯完成语种检测 我们试试用朴素贝叶斯完成一个语种检测的分类器,说起来,用朴素贝叶斯完成这个任务,其实准确度还不错. 机器学习的算法要取得好效果,离不开数据,咱们先拉点数据(twitter数据,包含English, French, German, Spanish, Italian 和 Dutch 6种语言). In [1]: in_f = open('data.csv') lines = in_f.readlines() in_f.close() dataset = [(line.str

stick-learn朴素贝叶斯的三个常用模型:高斯、多项式、伯努利

朴素贝叶斯是一个很不错的分类器,在使用朴素贝叶斯分类器划分邮件有关于朴素贝叶斯的简单介绍. 若一个样本有n个特征,分别用x1,x2,...,xn表示,将其划分到类yk的可能性P(yk|x1,x2,...,xn)为: P(yk|x1,x2,...,xn)=P(yk)∏ni=1P(xi|yk) 上式中等号右侧的各个值可以通过训练得到.根据上面的公式可以求的某个数据属于各个分类的可能性(这些可能性之和不一定是1),该数据应该属于具有最大可能性的分类中. 一般来说,如果一个样本没有特征xi,那么P(xi

机器学习实战教程(五):朴素贝叶斯实战篇之新浪新闻分类

原文链接: Jack-Cui,https://cuijiahua.com/blog/2017/11/ml_5_bayes_2.html 一.前言 上篇文章机器学习实战教程(四):朴素贝叶斯基础篇之言论过滤器讲解了朴素贝叶斯的基础知识.本篇文章将在此基础上进行扩展,你将看到以下内容: 拉普拉斯平滑 垃圾邮件过滤(Python3) 新浪新闻分类(sklearn) 二.朴素贝叶斯改进之拉普拉斯平滑 上篇文章提到过,算法存在一定的问题,需要进行改进.那么需要改进的地方在哪里呢?利用贝叶斯分类器对文档进行

朴素贝叶斯新闻分类,新浪SAE碰到的问题

1 如何将高版本的jdk通过Eclipse编译为较低版本的 2 当前SAE支持的jdk版本是1.6还有web项目war包不能是3.0版本及以上,必须编译为较低版本 3  No context on this server matched or handled this request问题:有的是jdk版本问题,还有是多了tomcat的servlet-api包的问题 4 文件读取中文乱码问题 br = new BufferedReader(new InputStreamReader( new Fi

【机器学习实验】使用朴素贝叶斯进行文本的分类

引言 朴素贝叶斯由贝叶斯定理延伸而来的简单而强大的概率模型,它根据每个特征的概率确定一个对象属于某一类别的概率.该方法基于一个假设,所有特征需要相互独立,即任一特征的值和其他特征的值没有关联关系. 虽然这种条件独立的假设在许多应用领域未必能很好满足,甚至是不成立的.但这种简化的贝叶斯分类器在许多实际应用中还是得到了较好的分类精度.训练模型的过程可以看作是对相关条件概率的计算,它可以用统计对应某一类别的特征的频率来估计. 朴素贝叶斯最成功的一个应用是自然语言处理领域,自然语言处理的的数据可以看做是

机器学习算法( 四、朴素贝叶斯算法)

一.概述 前两章我们要求分类器做出艰难决策,给出“该数据实例属于哪一类”这类问题的明确答案.不过,分类器有时会产生错误结果,这时可以要求分类器给出一个最优的类别猜测结果,同时给出这个猜测的概率估计值. 概率论是许多机器学习算法的基础,所以深刻理解这一主题就显得十分重要.第3章在计算特征值取某个值的概率时涉及了一些概率知识,在那里我们先统计特征在数据集中取某个特定值的次数,然后除以数据集的实例总数,就得到了特征取该值的概率.我们将在此基础上深人讨论.      本章会给出一些使用概率论进行分类的方

《机器学习实战》学习笔记:基于朴素贝叶斯的垃圾邮件过滤

概率是许多机器学习算法的基础,在前面生成决策树的过程中使用了一小部分关于概率的知识,即统计特征在数据集中取某个特定值的次数,然后除以数据集的实例总数,得到特征取该值的概率. 之前的基础实验中简单实现了朴素贝叶斯分类器,并正确执行了文本分类,这一节将贝叶斯运用到实际场景,垃圾邮件过滤这一实际应用. 实例:使用朴素贝叶斯过滤垃圾邮件 在上一节:http://blog.csdn.net/liyuefeilong/article/details/48383175中,使用了简单的文本文件,并从中提取了字符

通俗易懂机器学习——朴素贝叶斯算法

本文将叙述朴素贝叶斯算法的来龙去脉,从数学推导到计算演练到编程实战 文章内容有借鉴网络资料.李航<统计学习方法>.吴军<数学之美>加以整理及补充 基础知识补充: 1.贝叶斯理论–吴军数学之美 http://mindhacks.cn/2008/09/21/the-magical-bayesian-method/ 2.条件概率 3.联合分布 朴素贝叶斯算法 朴素贝叶斯法是基于贝叶斯定理和特征条件独立假设的 分类方法.给定训练数据集,首先基于特征条件独立假设学习 输入/输出的联合概率分布

机器学习实战教程(四):朴素贝叶斯基础篇之言论过滤器

原文链接: Jack-Cui,https://cuijiahua.com/blog/2017/11/ml_4_bayes_1.html 一.前言 朴素贝叶斯算法是有监督的学习算法,解决的是分类问题,如客户是否流失.是否值得投资.信用等级评定等多分类问题.该算法的优点在于简单易懂.学习效率高.在某些领域的分类问题中能够与决策树.神经网络相媲美.但由于该算法以自变量之间的独立(条件特征独立)性和连续变量的正态性假设为前提,就会导致算法精度在某种程度上受影响. 本篇文章将从朴素贝叶斯推断原理开始讲起,