(数据挖掘-入门-8)基于朴素贝叶斯的文本分类器

2023-11-13

主要内容:

1、动机

2、基于朴素贝叶斯的文本分类器

3、python实现

 

一、动机

之前介绍的朴素贝叶斯分类器所使用的都是结构化的数据集,即每行代表一个样本,每列代表一个特征属性。

但在实际中,尤其是网页中,爬虫所采集到的数据都是非结构化的,如新闻、微博、帖子等,如果要对对这一类数据进行分类,应该怎么办呢?例如,新闻分类,微博情感分析等。

本文就介绍一种基于朴素贝叶斯的文本分类器。

二、基于朴素贝叶斯的文本分类器

目标:对非结构化的文本进行分类

首先,回顾一下朴素贝叶斯公式:

特征、特征处理:

对于结构化数据,公式中的D代表的是样本或一系列整理或抽象出来的特征或属性,

而在非结构化的数据中,只有文档和单词,文档对应样本,单词对应特征。

如果将单词作为特征,未免特征太多了,一篇文章有那么多单词,而且有些单词并不起什么作用,因此需要对特征即单词进行处理。

停用词:我们将一些常见的词,如the, a, I, is, that等,称为“停用词”,因为它们在很多文章都会出现,不具称为特征的代表性。

模型参数计算:

别忘了,朴素贝叶斯的假设前提:在已知类别下,所有特征是独立的。(在文本中,即不考虑单词之间的次序和相关性)

如何计算模型的参数,即已知类别时某文本的条件概率呢?(这里只是进行简单的统计而已,复杂一点的可以考虑TF-IDF作为单词特征,下面的公式已经做了平滑处理

Wk:表示某个单词

hi: 表示某个类别

nk: 表示单词wk在类别hi中出现的次数

n:表示类别中的单词总数

vocabulary:表示类别中的单词数

分类:

来一篇新文章,如何判断它是属于哪一类呢?

如下公式,分别计算属于每一类的概率,然后取概率最大的作为其类别。

 

应用:

新闻分类、垃圾邮件分类、微博情感分析等等

三、python实现

数据集:

代码:

1、新闻分类

from __future__ import print_function
import os, codecs, math

class BayesText:

    def __init__(self, trainingdir, stopwordlist):
        """This class implements a naive Bayes approach to text
        classification
        trainingdir is the training data. Each subdirectory of
        trainingdir is titled with the name of the classification
        category -- those subdirectories in turn contain the text
        files for that category.
        The stopwordlist is a list of words (one per line) will be
        removed before any counting takes place.
        """
        self.vocabulary = {}
        self.prob = {}
        self.totals = {}
        self.stopwords = {}
        f = open(stopwordlist)
        for line in f:
            self.stopwords[line.strip()] = 1
        f.close()
        categories = os.listdir(trainingdir)
        #filter out files that are not directories
        self.categories = [filename for filename in categories
                           if os.path.isdir(trainingdir + filename)]
        print("Counting ...")
        for category in self.categories:
            print('    ' + category)
            (self.prob[category],
             self.totals[category]) = self.train(trainingdir, category)
        # I am going to eliminate any word in the vocabulary
        # that doesn't occur at least 3 times
        toDelete = []
        for word in self.vocabulary:
            if self.vocabulary[word] < 3:
                # mark word for deletion
                # can't delete now because you can't delete
                # from a list you are currently iterating over
                toDelete.append(word)
        # now delete
        for word in toDelete:
            del self.vocabulary[word]
        # now compute probabilities
        vocabLength = len(self.vocabulary)
        print("Computing probabilities:")
        for category in self.categories:
            print('    ' + category)
            denominator = self.totals[category] + vocabLength
            for word in self.vocabulary:
                if word in self.prob[category]:
                    count = self.prob[category][word]
                else:
                    count = 1
                self.prob[category][word] = (float(count + 1)
                                             / denominator)
        print ("DONE TRAINING\n\n")
                    

    def train(self, trainingdir, category):
        """counts word occurrences for a particular category"""
        currentdir = trainingdir + category
        files = os.listdir(currentdir)
        counts = {}
        total = 0
        for file in files:
            #print(currentdir + '/' + file)
            f = codecs.open(currentdir + '/' + file, 'r', 'iso8859-1')
            for line in f:
                tokens = line.split()
                for token in tokens:
                    # get rid of punctuation and lowercase token
                    token = token.strip('\'".,?:-')
                    token = token.lower()
                    if token != '' and not token in self.stopwords:
                        self.vocabulary.setdefault(token, 0)
                        self.vocabulary[token] += 1
                        counts.setdefault(token, 0)
                        counts[token] += 1
                        total += 1
            f.close()
        return(counts, total)
                    
                    
    def classify(self, filename):
        results = {}
        for category in self.categories:
            results[category] = 0
        f = codecs.open(filename, 'r', 'iso8859-1')
        for line in f:
            tokens = line.split()
            for token in tokens:
                #print(token)
                token = token.strip('\'".,?:-').lower()
                if token in self.vocabulary:
                    for category in self.categories:
                        if self.prob[category][token] == 0:
                            print("%s %s" % (category, token))
                        results[category] += math.log(
                            self.prob[category][token])
        f.close()
        results = list(results.items())
        results.sort(key=lambda tuple: tuple[1], reverse = True)
        # for debugging I can change this to give me the entire list
        return results[0][0]

    def testCategory(self, directory, category):
        files = os.listdir(directory)
        total = 0
        correct = 0
        for file in files:
            total += 1
            result = self.classify(directory + file)
            if result == category:
                correct += 1
        return (correct, total)

    def test(self, testdir):
        """Test all files in the test directory--that directory is
        organized into subdirectories--each subdir is a classification
        category"""
        categories = os.listdir(testdir)
        #filter out files that are not directories
        categories = [filename for filename in categories if
                      os.path.isdir(testdir + filename)]
        correct = 0
        total = 0
        for category in categories:
            print(".", end="")
            (catCorrect, catTotal) = self.testCategory(
                testdir + category + '/', category)
            correct += catCorrect
            total += catTotal
        print("\n\nAccuracy is  %f%%  (%i test instances)" %
              ((float(correct) / total) * 100, total))
            
# change these to match your directory structure
baseDirectory = "20news-bydate/"
trainingDir = baseDirectory + "20news-bydate-train/"
testDir = baseDirectory + "20news-bydate-test/"


stoplistfile = "20news-bydate/stopwords0.txt"
print("Reg stoplist 0 ")
bT = BayesText(trainingDir, baseDirectory + "stopwords0.txt")
print("Running Test ...")
bT.test(testDir)

print("\n\nReg stoplist 25 ")
bT = BayesText(trainingDir, baseDirectory + "stopwords25.txt")
print("Running Test ...")
bT.test(testDir)

print("\n\nReg stoplist 174 ")
bT = BayesText(trainingDir, baseDirectory + "stopwords174.txt")
print("Running Test ...")
bT.test(testDir)
View Code

2、情感分析

from __future__ import print_function
import os, codecs, math

class BayesText:

    def __init__(self, trainingdir, stopwordlist, ignoreBucket):
        """This class implements a naive Bayes approach to text
        classification
        trainingdir is the training data. Each subdirectory of
        trainingdir is titled with the name of the classification
        category -- those subdirectories in turn contain the text
        files for that category.
        The stopwordlist is a list of words (one per line) will be
        removed before any counting takes place.
        """
        self.vocabulary = {}
        self.prob = {}
        self.totals = {}
        self.stopwords = {}
        f = open(stopwordlist)
        for line in f:
            self.stopwords[line.strip()] = 1
        f.close()
        categories = os.listdir(trainingdir)
        #filter out files that are not directories
        self.categories = [filename for filename in categories
                           if os.path.isdir(trainingdir + filename)]
        print("Counting ...")
        for category in self.categories:
            #print('    ' + category)
            (self.prob[category],
             self.totals[category]) = self.train(trainingdir, category,
                                                 ignoreBucket)
        # I am going to eliminate any word in the vocabulary
        # that doesn't occur at least 3 times
        toDelete = []
        for word in self.vocabulary:
            if self.vocabulary[word] < 3:
                # mark word for deletion
                # can't delete now because you can't delete
                # from a list you are currently iterating over
                toDelete.append(word)
        # now delete
        for word in toDelete:
            del self.vocabulary[word]
        # now compute probabilities
        vocabLength = len(self.vocabulary)
        #print("Computing probabilities:")
        for category in self.categories:
            #print('    ' + category)
            denominator = self.totals[category] + vocabLength
            for word in self.vocabulary:
                if word in self.prob[category]:
                    count = self.prob[category][word]
                else:
                    count = 1
                self.prob[category][word] = (float(count + 1)
                                             / denominator)
        #print ("DONE TRAINING\n\n")
                    

    def train(self, trainingdir, category, bucketNumberToIgnore):
        """counts word occurrences for a particular category"""
        ignore = "%i" % bucketNumberToIgnore
        currentdir = trainingdir + category
        directories = os.listdir(currentdir)
        counts = {}
        total = 0
        for directory in directories:
            if directory != ignore:
                currentBucket = trainingdir + category + "/" + directory
                files = os.listdir(currentBucket)
                #print("   " + currentBucket)
                for file in files:
                    f = codecs.open(currentBucket + '/' + file, 'r', 'iso8859-1')
                    for line in f:
                        tokens = line.split()
                        for token in tokens:
                            # get rid of punctuation and lowercase token
                            token = token.strip('\'".,?:-')
                            token = token.lower()
                            if token != '' and not token in self.stopwords:
                                self.vocabulary.setdefault(token, 0)
                                self.vocabulary[token] += 1
                                counts.setdefault(token, 0)
                                counts[token] += 1
                                total += 1
                    f.close()
        return(counts, total)
                    
                    
    def classify(self, filename):
        results = {}
        for category in self.categories:
            results[category] = 0
        f = codecs.open(filename, 'r', 'iso8859-1')
        for line in f:
            tokens = line.split()
            for token in tokens:
                #print(token)
                token = token.strip('\'".,?:-').lower()
                if token in self.vocabulary:
                    for category in self.categories:
                        if self.prob[category][token] == 0:
                            print("%s %s" % (category, token))
                        results[category] += math.log(
                            self.prob[category][token])
        f.close()
        results = list(results.items())
        results.sort(key=lambda tuple: tuple[1], reverse = True)
        # for debugging I can change this to give me the entire list
        return results[0][0]

    def testCategory(self, direc, category, bucketNumber):
        results = {}
        directory = direc + ("%i/" % bucketNumber)
        #print("Testing " + directory)
        files = os.listdir(directory)
        total = 0
        correct = 0
        for file in files:
            total += 1
            result = self.classify(directory + file)
            results.setdefault(result, 0)
            results[result] += 1
            #if result == category:
            #               correct += 1
        return results

    def test(self, testdir, bucketNumber):
        """Test all files in the test directory--that directory is
        organized into subdirectories--each subdir is a classification
        category"""
        results = {}
        categories = os.listdir(testdir)
        #filter out files that are not directories
        categories = [filename for filename in categories if
                      os.path.isdir(testdir + filename)]
        correct = 0
        total = 0
        for category in categories:
            #print(".", end="")
            results[category] = self.testCategory(
                testdir + category + '/', category, bucketNumber)
        return results

def tenfold(dataPrefix, stoplist):
    results = {}
    for i in range(0,10):
        bT = BayesText(dataPrefix, stoplist, i)
        r = bT.test(theDir, i)
        for (key, value) in r.items():
            results.setdefault(key, {})
            for (ckey, cvalue) in value.items():
                results[key].setdefault(ckey, 0)
                results[key][ckey] += cvalue
                categories = list(results.keys())
    categories.sort()
    print(   "\n       Classified as: ")
    header =    "          "
    subheader = "        +"
    for category in categories:
        header += "% 2s   " % category
        subheader += "-----+"
    print (header)
    print (subheader)
    total = 0.0
    correct = 0.0
    for category in categories:
        row = " %s    |" % category 
        for c2 in categories:
            if c2 in results[category]:
                count = results[category][c2]
            else:
                count = 0
            row += " %3i |" % count
            total += count
            if c2 == category:
                correct += count
        print(row)
    print(subheader)
    print("\n%5.3f percent correct" %((correct * 100) / total))
    print("total of %i instances" % total)

# change these to match your directory structure
prefixPath = "reviewPolarityBuckets/review_polarity_buckets/"
theDir = prefixPath + "/txt_sentoken/"
stoplistfile = prefixPath + "stopwords25.txt"
tenfold(theDir, stoplistfile)
View Code

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

(数据挖掘-入门-8)基于朴素贝叶斯的文本分类器 的相关文章

随机推荐

  • 码上行动:利用Python与ChatGPT高效搞定Excel数据分析

    AI时代Excel数据分析提升之道 知识精进 学习答疑 上机实训 综合实战 ChatGPT应用 零基础入门 极速提升数据分析效率 亮点 1 零基础入门宝典 由浅入深讲解 无须额外的背景知识即可学习掌握 2 内容系统全面 可帮助读者快速了解使
  • C0177 [2004普及组-A]不高兴的津津(C语言写)

    题目描述 津津上初中了 妈妈认为津津应该更加用功学习 所以津津除了上学之外 还要参加妈妈为她报名的各科复习班 另外每周妈妈还会送她去学习朗诵 舞蹈和钢琴 但是津津如果一天上课超过八个小时就会不高兴 而且上得越久就会越不高兴 假设津津不会因为
  • 音频PCM数据的单声道、双声道之间的转换

    在使用tinyalsa处理PCM音频数据时发现该设备只能以双声道形式打开设备 tinypcminfo工具可以查看设备信息 out和in里面channels 最大和最小值都是2 但是实际使用中有时候又需要声卡采集和播放单声道数据怎么办 那就只
  • 入门级题解3. 无重复字符的最长子串

    题目 给定一个字符串 s 请你找出其中不含有重复字符的最长子串的长度 思路 这样一来 我们就可以使用 滑动窗口 来解决这个问题了 我们使用两个指针表示字符串中的某个子串 或窗口 的左右边界 其中左指针代表着上文中 枚举子串的起始位置 而右指
  • Niagara官方示例笔记 - 盘点自带重要模块

    Emitter State life cycle生命周期控制 发射器选择system 所有发射器都在system的state里设置生命周期 选择self 发射器独立控制 可以给发射器创建不同类型变量 使用set parameter模块计算
  • 【Vegas原创】ORA-16040 standby destination archive log file is locked解决

    ORA 16040 standby destination archive log file is locked Cause The target standby destination archive log file is curren
  • serverless与容器优缺点

    容器优势 1 可移植性 使用容器 开发人员可以确保他们的应用程序可以在任何云平台或本地服务器上运行 2 轻量化 容器镜像以层叠加 在本地拥有镜像层缓存 计算资源使用方面 容器也比虚拟机更高效 3 快速启动 容器启动在镜像只读层上叠加一层读写
  • 谈谈我们公司如何做Code Review

    研发中心团队越来越庞大了 开发人员越来越多了 和他们聊天过程中 发现开发人员对代码技能的提升很迷茫 诉求越来越浓厚 只不过一个接一个的项目交付没有给他们太多停留的时间 在这种情况下如何给团队营造浓厚的工程师交流氛围呢 方法有多种 最近进行了
  • 35+老测试员生涯回顾,揭秘无力吐槽的自动化真相…

    不知道从什么时候开始 软件测试行业就和 自动化 这个词联系在一起了 对于如今的测试人来说 几乎没有人不知道 自动化测试 甚至查看各大招聘网站 你从任何一个招聘渠道来看最近两年对测试岗位的要求 几乎都要求会自动化测试 而不少人一直认为手工测试
  • JS获取阴历+阳历时间

    1 阴历 获取阴历 start getLunar var nyear var nmonth var nday 1 var nwday var nhrs var nmin var nsec var lmonth lday lleap 农历参数
  • 海思麒麟985性能简介

    海思麒麟985 SoC由中国台湾积体电路制造有限公司打造 是麒麟980的升级改良版 率先使用7nm工艺制作 是对上一代10nm芯片的改进 主要在功耗和性能上做了较大改进 麒麟985大致参数为1 3 4 CPU架构 8核Mali G77 GP
  • mali GPU 官网指南

    1 简介 GPU 图形处理单元 是一种专门在个人电脑 工作站 游戏机和移动设备上图形运算工作的微处理器 以前GPU主要用于图形处理 现在GPU的通用计算技术也得到了飞速发展 事实证明在浮点运算 并行计算等部分计算方面 GPU可以提供数十倍乃
  • 【python】python如何从一个文件中引入另一个文件中的变量

    直接和导入python的函数一样导入变量名即可 十分方便 from target file import variant name
  • STM32学习笔记五、RST复位

    1 STM32硬复位 STM32片内已经有复位电路了 可以不外接复位电路 复位引脚一般不宜悬空 所以STM32在NRST引脚内接了一个上拉电阻 典型值为40K 为了防止外部干扰 STM32数据手册上建议外接一个对地电容 如果用户认为内部上拉
  • java后端接入微信小程序登录功能

    java后端接入微信小程序登录功能 前言 此文章是Java后端接入微信登录功能 由于项目需要 舍弃了解密用户信息的session key 只保留openid用于检索用户信息 后端框架 spring boot 小程序框架 uniapp 流程概
  • 【ROS】虚拟机VMware 安装ROS 一条龙教程+部分报错解决

    前言 Linux下安装ROS真是太多坑了 如何在Linux下安装ROS呢 博主带你少走弯路 目录 前言 第一步 配置软件源 1 打开设置 2 打开软件与更新 3 选源 第二步 设置sources list 第三步 设置密钥 第四步 正式安装
  • C#中断点不能调试问题(当前不会命中断点,还没有为该文档加载任何资料 )

    1 winform 程序中 经常会出现的一个错误 断点不可调试 1 当前不会命中断点 还没有为该文档加载任何资料 问题原因 窗口所在的类库或者项目在应用程序目录中 release或者debug 中只生成了dll文件 没有生成pdb文件 例如
  • css如何实现盒子在鼠标点,掌握CSS定位,才能让“盒子”飞得更高更远更稳

    众所周知 前端CSS中 盒模型 浮动 定位为必须掌握的三座大山 今天就来聊聊定位的那些事 定位是什么 先来看看哪些场景用到定位 如下图所示 凡是有盒子压住另一个盒子的地方都可定位 因为用浮动做不了 如果盒子浮动 会并排但不会出现有层级的观感
  • STM32F4 IAP

    功能实现 正常上电或复位后运行用户Bootloader程序 检查变量存储区的标志位 如果标志位为APP FLAG则跳转到APP程序运行 如果标志位为BOOT FLAG 则运行用户Bootloader程序 等待接收文件并准备IAP升级后跳转到
  • (数据挖掘-入门-8)基于朴素贝叶斯的文本分类器

    主要内容 1 动机 2 基于朴素贝叶斯的文本分类器 3 python实现 一 动机 之前介绍的朴素贝叶斯分类器所使用的都是结构化的数据集 即每行代表一个样本 每列代表一个特征属性 但在实际中 尤其是网页中 爬虫所采集到的数据都是非结构化的