贝叶斯用于文档分类

from numpy import *


def loadDataSet():
    # 词条切分后的文档集合,列表每一行代表一个文档
    postingList = [['my', 'dog', 'has', 'flea', 'please'],
                   ['not', 'take', 'him', 'to', 'dog', 'stupid'],
                   ['my', 'is', 'cute', 'love', 'him'],
                   ['stop', 'posting', 'stupid', 'worthless', 'garbage'],
                   ['my', 'licks', 'my', 'to', 'stop', 'him'],
                   ['quit', 'worthless', 'dog', 'stupid']]
    # 由人工标注的每篇文档的类标签
    classVec = [0, 1, 0, 1, 0, 1]
    return postingList, classVec


# 统计所有文档中出现的词条列表
def createVocabList(dataSet):
    # 新建一个存放词条的集合
    vocabSet = set([])
    # 遍历文档集合中的每一篇文档
    for document in dataSet:
        # 将文档列表转为集合的形式,保证每个词条的唯一性
        # 然后与vocabSet取并集,向vocabSet中添加没有出现
        # 的新的词条
        vocabSet = vocabSet | set(document)
    # 再将集合转化为列表,便于接下来的处理
    return list(vocabSet)


# 根据词条列表中的词条是否在文档中出现(出现1,未出现0),将文档转化为词条向量
def setOfWords2Vec(vocabSet, inputSet):
    # 新建一个长度为vocabSet的列表,并且各维度元素初始化为0
    returnVec = [0] * len(vocabSet)
    # 遍历文档中的每一个词条
    for word in inputSet:
        # 如果词条在词条列表中出现
        if word in vocabSet:
            # 通过列表获取当前word的索引(下标)
            # 将词条向量中的对应下标的项由0改为1
            returnVec[vocabSet.index(word)] += 1
        else:
            print('the word: %s is not in my vocabulary! ' % 'word')
    # 返回inputet转化后的词条向量
    return returnVec


# 训练算法,从词向量计算概率p(w0|ci)...及p(ci)
# @trainMatrix:由每篇文档的词条向量组成的文档矩阵
# @trainCategory:每篇文档的类标签组成的向量
def trainNB0(trainMatrix, trainCategory):
    # 获取文档矩阵中文档的数目
    numTrainDocs = len(trainMatrix)  # 6
    # 获取词条向量的长度
    numWords = len(trainMatrix[0])  # 19
    # 所有文档中属于类1所占的比例p(c=1)
    pAbusive = sum(trainCategory) / float(numTrainDocs)  # 3/6=0.5,先验
    # 创建一个长度为词条向量等长的列表
    p0Num = zeros(numWords)
    p1Num = zeros(numWords)
    p0Denom = 0.0
    p1Denom = 0.0
    # 遍历每一篇文档的词条向量
    for i in range(numTrainDocs):
        # 如果该词条向量对应的标签为1
        if trainCategory[i] == 1:
            # 统计所有类别为1的词条向量中各个词条出现的次数
            p1Num += trainMatrix[i]
            # 统计类别为1的词条向量中出现的所有词条的总数
            # 即统计类1所有文档中出现单词的数目
            p1Denom += sum(trainMatrix[i])
        else:
            # 统计所有类别为0的词条向量中各个词条出现的次数
            p0Num += trainMatrix[i]
            # 统计类别为0的词条向量中出现的所有词条的总数
            # 即统计类0所有文档中出现单词的数目
            p0Denom += sum(trainMatrix[i])
    # 利用NumPy数组计算p(wi|c1)
    p1Vect = p1Num / p1Denom  # 为避免下溢出问题,后面会改为log()
    # 利用NumPy数组计算p(wi|c0)
    p0Vect = p0Num / p0Denom  # 为避免下溢出问题,后面会改为log()
    return p0Vect, p1Vect, pAbusive


# 朴素贝叶斯分类函数
# @vec2Classify:待测试分类的词条向量
# @p0Vec:类别0所有文档中各个词条出现的频数p(wi|c0)
# @p0Vec:类别1所有文档中各个词条出现的频数p(wi|c1)
# @pClass1:类别为1的文档占文档总数比例
def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):
    # 根据朴素贝叶斯分类函数分别计算待分类文档属于类1和类0的概率
    print(vec2Classify)
    p1 = sum(vec2Classify * p1Vec) + log(pClass1)
    p0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)
    if p1 > p0:
        return 1
    else:
        return 0


# 分类测试整体函数
# 由数据集获取文档矩阵和类标签向量
allfile, fileClasses = loadDataSet()
# 统计所有文档中出现的词条,存入词条列表
VocabSet = createVocabList(allfile)
# 创建新的列表
trainMat = []
for singlefile in allfile:
    # 将每篇文档利用words2Vec函数转为词条向量,存入文档矩阵中
    trainMat.append(setOfWords2Vec(VocabSet, singlefile))
        # 将文档矩阵和类标签向量转为NumPy的数组形式,方便接下来的概率计算
# 调用训练函数,得到相应概率值
p0V, p1V, pAb = trainNB0(array(trainMat), array(fileClasses))
# 测试文档
testEntry = ['love', 'my', 'cute']
# 将测试文档转为词条向量,并转为NumPy数组的形式
thisDoc = array(setOfWords2Vec(VocabSet, testEntry))
# 利用贝叶斯分类函数对测试文档进行分类并打印
print(testEntry, 'classified as:', classifyNB(thisDoc, p0V, p1V, pAb))
# 第二个测试文档
testEntry1 = ['stupid', 'garbage']
# 同样转为词条向量,并转为NumPy数组的形式
thisDoc1 = array(setOfWords2Vec(VocabSet, testEntry1))
print(testEntry1, 'classified as:', classifyNB(thisDoc1, p0V, p1V, pAb))


 

### C++ 实现朴素贝叶斯算法用于文档分类 尽管大多数关于朴素贝叶斯算法的教程实现都集中在 Python 其他高级语言上,但在某些情况下可能需要使用 C++ 来完成类似的任务。以下是有关如何在 C++ 中实现朴素贝叶斯算法进行文档分类的一些指导。 #### 1. 基本原理 朴素贝叶斯是一种基于概率理论的机器学习算法,其核心思想来源于贝叶斯定理[^3]。该方法假设特征之间相互独立(即“朴素”条件),从而简化计算过程并提高效率。对于文档分类问题,通常会将每个单词视为一个特征,并统计它们在不同类别中的频率分布来构建模型。 #### 2. 数据预处理 为了训练一个有效的朴素贝叶斯分类器,在实际编码之前还需要做好充分的数据准备工作: - **分词**:把原始文本分割成单独词语; - **去除停用词**:过滤掉那些对区分主题帮助不大的常见词汇; - **向量化表示**:通过诸如词袋模型(Bag-of-Words)或者TF-IDF等方式转换为数值型矩阵形式以便后续运算操作; 这些步骤虽然可以在任何编程环境中执行,但对于初学者来说利用现有的库可能会更加方便快捷一些。然而如果坚持要用纯C++来做的话,则需自行编写相应功能模块。 #### 3. 编码指南 下面给出了一段简单的伪代码框架作为参考: ```cpp #include <iostream> #include <map> #include <vector> class NaiveBayes { private: std::map<std::string, double> wordProbabilities; public: void train(const std::vector<std::pair<std::string, bool>>& documents); bool predict(const std::string& document); }; void NaiveBayes::train(const std::vector<std::pair<std::string, bool>>& documents){ // 计算先验概率 P(C) // 统计每类下各词条出现次数 // 平滑处理 防止零频现象发生 } bool NaiveBayes::predict(const std::string& document){ // 对新样本应用上述公式求解最大后验估计值对应的标签即可得到预测结果。 } ``` 请注意这只是一个非常基础版本的设计思路示意而已 ,具体细节部分比如参数调整优化等方面都需要进一步深入探讨研究才行 。另外由于缺乏像Python那样成熟的第三方支持包可供调用所以整个开发周期相对而言也会变得更长更复杂些 。 #### 4. 性能考量与其他选项对比分析 相较于其它主流工具链如Java下的OpenNLP项目里所提供的解决方案 [^4], 使用原生C++ 开发确实存在不少挑战之处 :一方面是因为缺少专门针对自然语言处理领域定制化的高效API接口集合可以直接拿来就用 ; 另外一点则是考虑到跨平台兼容性后期维护成本等问题也值得提前规划考虑进去 。 综上所述 如果只是单纯追求快速原型验证效果而不关心底层机制理解程度高低 的话 推荐优先尝试借助已有的开源资源来进行二次封装改造更为合适合理些 。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值