贝叶斯分类器是一种基于贝叶斯定理的简单概率分类器。

在机器学习中,朴素贝叶斯分类器是一系列以假设特征之间强(朴素)独立下运用贝叶斯定理为基础的简单概率分类器。朴素贝叶斯是文本分类的一种热门(基准)方法,文本分类是以词频为特征判断文件所属类别或其它(如垃圾邮件、合法性、体育或政治等等)的问题。通过适当的预处理,它可以与这个领域更先进的方法(包括支持向量机)相竞争。

朴素贝叶斯分类器是高度可扩展的,因此需要数量与学习问题中的变量(特征/预测器)成线性关系的参数。

在统计学和计算机科学文献中,朴素贝叶斯模型有各种名称,包括简单贝叶斯和独立贝叶斯。所有这些名称都参考了贝叶斯定理在该分类器的决策规则中的使用,但朴素贝叶斯不一定用到贝叶斯方法。

朴素贝叶斯是一种构建分类器的简单方法。该分类器模型会给问题实例分配用特征值表示的类标签,类标签取自有限集合。它不是训练这种分类器的单一算法,而是一系列基于相同原理的算法:所有朴素贝叶斯分类器都假定样本每个特征与其它特征都不相关。举个例子,如果一种水果其具有红,圆,直径大概3英寸等特征,该水果可以被判定为是苹果。尽管这些特征相互依赖或者有些特征由其他特征决定,然而朴素贝叶斯分类器认为这些属性在判定该水果是否为苹果的概率分布上独立的。

对于某些类型的概率模型,在监督式学习的样本集中能获取得非常好的分类效果。在许多实际应用中,朴素贝叶斯模型参数估计使用最大似然估计方法;换而言之,在不用到贝叶斯概率或者任何贝叶斯模型的情况下,朴素贝叶斯模型也能奏效。

朴素贝叶斯分类器的一个优势在于只需要根据少量的训练数据估计出必要的参数(变量的均值和方差)。由于变量独立假设,只需要估计各个变量的方法,而不需要确定整个协方差矩阵。

朴素贝叶斯概率模型:理论上,概率模型分类器是一个条件概率模型:p(C|F1,…,Fn)。独立的类别变量C有若干类别,条件依赖于若干特征变量F1,F2,…,Fn。但问题在于如果特征数量n较大或者每个特征能取大量值时,基于概率模型列出概率表变得不现实。所以我们修改这个模型使之变得可行。贝叶斯定理有以下式子:

用朴素的语言可以表达为:

实际中,我们只关心分式中的分子部分,因为分母不依赖于C而且特征Fi的值是给定的,于是分母可以认为是一个常数。这样分子就等价于联合分布(在概率论中,对两个随机变量X和Y,其联合分布是同时对于X和Y的概率分布。对离散随机变量而言,联合分布概率质量函数为Pr(X=x& Y=y),即P(X=x and Y=y)=P(Y=y|X=x)P(X=x)=P(X=x|Y=y)P(Y=y))模型:p(C,F1,…,Fn)。重复使用链式法则(chain rule,是求复合函数导数的一个法则),可将该式写成条件概率(conditional probability,就是事件A在另外一个事件B已经发生条件下的发生概率,条件概率表示为P(A|B),读作”在B条件下A的概率”)的形式,如下所示:

其中Z(证据因子)是一个只依赖于F1,…,Fn等的缩放因子,当特征变量的值已知时是一个常数。由于分解成所谓的类先验概率p(C)和独立概率分布p(Fi|C),上述概率模型的可掌控性得到很大的提高。如果这是一个k分类问题,且每个p(Fi|C=c)可以表达为r个参数,于是相应的朴素贝叶斯模型有(k-1)+nrk个参数。实际应用中,通常取k=2(二分类问题),r=1(伯努利分布作为特征),因此模型的参数个数为2n+1,其中n是二值分类特征的个数。

从概率模型中构造分类器:以上导出了独立分布特征模型,也就是朴素贝叶斯概率模型。朴素贝叶斯分类器包括了这种模型和相应的决策规则。一个普通的规则就是选出最优可能的那个:这就是最大后验概率(MAP)决策准则。相应的分类器便是如下定义的classify公式:

参数估计:所有的模型参数都可以通过训练集的相关频率来估计。常用方法是概率的最大似然估计。类的先验概率可以通过假设各类等概率来计算(先验概率 = 1 / (类的数量)),或者通过训练集的各类样本出现的次数来估计(A类先验概率=(A类样本的数量)/(样本总数))。为了估计特征的分布参数,我们要先假设训练集数据满足某种分布或者非参数模型。

高斯朴素贝叶斯:如果要处理的是连续数据,一种通常的假设是这些连续数值为高斯分布。例如,假设训练集中有一个连续属性x。我们首先对数据根据类别分类,然后计算每个类别中的x的均值和方差。令μc表示为x在c类上的均值,令σ2c为x类在c类上的方差。在给定类中某个值的概率P(x=v|c),可以通过将v表示为均值为μc,方差为σ2c正态分布计算出来,如下:

处理连续数值问题的另一种常用的技术是通过离散化连续数值的方法。通常,当训练样本数量较少或者是精确的分布已知时,通过概率分布的方法是一种更好的选择。在大量样本的情形下离散化的方法表现更优,因为大量的样本可以学习到数据的分布。由于朴素贝叶斯是一种典型的用到大量样本的方法(越大计算量的模型可以产生越高的分类精确度),所以朴素贝叶斯方法都用到离散化方法,而不是概率分布估计的方法。

样本修正:如果一个给定的类和特征值在训练集中没有一起出现过,那么基于频率的估计下该概率将为0。这将是一个问题。因为与其他概率相乘时将会把其他概率的信息统统去除。所以常常要求要对每个小类样本的概率估计进行修正,以保证不会出现有为0的概率出现。

尽管实际上独立假设常常是不准确的,但朴素贝叶斯分类器的若干特性让其在实践中能够取得令人惊奇的效果。特别地,各类条件特征之间的解耦意味着每个特征的分布都可以独立地被当做一维分布来估计。这样减轻了由于维数灾带来的阻碍,当样本的特征个数增加时就不需要使样本规模呈指数增长。然而朴素贝叶斯在大多数情况下不能对类概率做出非常准确的估计,但在许多应用中这一点并不要求。例如,朴素贝叶斯分类器中,依据最大后验概率决策规则只要正确类的后验概率比其他类要高就可以得到正确的分类。所以不管概率估计轻度的甚至是严重的不精确都不影响正确的分类结果。在这种方式下,分类器可以有足够的鲁棒性去忽略朴素贝叶斯概率模型上存在的缺陷。

以上内容主要摘自: 维基百科

以下code是根据维基百科中对性别分类的介绍实现的C++代码,最终结果与维基百科结果一致:

naive_bayes_classifier.hpp:

#ifndef FBC_NN_NAIVEBAYESCLASSIFIER_HPP_
#define FBC_NN_NAIVEBAYESCLASSIFIER_HPP_#include <vector>
#include <tuple>namespace ANN {template<typename T>
struct sex_info { // height, weight, foot size, sexT height;T weight;T foot_size;int sex; // -1: unspecified, 0: female, 1: male
};template<typename T>
struct MeanVariance { // height/weight/foot_size's mean and varianceT mean_height;T mean_weight;T mean_foot_size;T variance_height;T variance_weight;T variance_foot_size;
};// Gaussian naive Bayes
template<typename T>
class NaiveBayesClassifier {
public:NaiveBayesClassifier() = default;int init(const std::vector<sex_info<T>>& info);int train(const std::string& model);int predict(const sex_info<T>& info) const;int load_model(const std::string& model) const;private:void calc_mean_variance(const std::vector<T>& data, std::tuple<T, T>& mean_variance) const;T calc_attribute_probability(T value, T mean, T variance) const;int store_model(const std::string& model) const;MeanVariance<T> male_mv, female_mv;std::vector<T> male_height, male_weight, male_foot_size;std::vector<T> female_height, female_weight, female_foot_size;T male_p = (T)0.5;T female_p = (T)0.5;int male_train_number = 0;int female_train_number = 0;
};} // namespace ANN#endif // FBC_NN_NAIVEBAYESCLASSIFIER_HPP_

naive_bayes_classifier.cpp:

#include "naive_bayes_classifier.hpp"
#include "common.hpp"
#include <math.h>
#include <iostream>
#include <algorithm>
#include <fstream>namespace ANN {template<typename T>
int NaiveBayesClassifier<T>::init(const std::vector<sex_info<T>>& info)
{int length = info.size();if (length < 2) {fprintf(stderr, "train data length should be > 1: %d\n", length);return -1;}male_train_number = 0;female_train_number = 0;for (int i = 0; i < length; ++i) {if (info[i].sex == 0) {++female_train_number;female_height.push_back(info[i].height);female_weight.push_back(info[i].weight);female_foot_size.push_back(info[i].foot_size);} else {++male_train_number;male_height.push_back(info[i].height);male_weight.push_back(info[i].weight);male_foot_size.push_back(info[i].foot_size);}}male_p = (T)male_train_number / (male_train_number + female_train_number);female_p = (T)female_train_number / (male_train_number + female_train_number);return 0;
}template<typename T>
int NaiveBayesClassifier<T>::train(const std::string& model)
{std::tuple<T, T> mean_variance;calc_mean_variance(male_height, mean_variance);male_mv.mean_height = std::get<0>(mean_variance);male_mv.variance_height = std::get<1>(mean_variance);calc_mean_variance(male_weight, mean_variance);male_mv.mean_weight = std::get<0>(mean_variance);male_mv.variance_weight = std::get<1>(mean_variance);calc_mean_variance(male_foot_size, mean_variance);male_mv.mean_foot_size = std::get<0>(mean_variance);male_mv.variance_foot_size = std::get<1>(mean_variance);calc_mean_variance(female_height, mean_variance);female_mv.mean_height = std::get<0>(mean_variance);female_mv.variance_height = std::get<1>(mean_variance);calc_mean_variance(female_weight, mean_variance);female_mv.mean_weight = std::get<0>(mean_variance);female_mv.variance_weight = std::get<1>(mean_variance);calc_mean_variance(female_foot_size, mean_variance);female_mv.mean_foot_size = std::get<0>(mean_variance);female_mv.variance_foot_size = std::get<1>(mean_variance);CHECK(store_model(model) == 0);return 0;
}template<typename T>
int NaiveBayesClassifier<T>::store_model(const std::string& model) const
{std::ofstream file;file.open(model.c_str(), std::ios::binary);if (!file.is_open()) {fprintf(stderr, "open file fail: %s\n", model.c_str());return -1;}file.write((char*)&male_p, sizeof(male_p));file.write((char*)&male_mv.mean_height, sizeof(male_mv.mean_height));file.write((char*)&male_mv.mean_weight, sizeof(male_mv.mean_weight));file.write((char*)&male_mv.mean_foot_size, sizeof(male_mv.mean_foot_size));file.write((char*)&male_mv.variance_height, sizeof(male_mv.variance_height));file.write((char*)&male_mv.variance_weight, sizeof(male_mv.variance_weight));file.write((char*)&male_mv.variance_foot_size, sizeof(male_mv.variance_foot_size));file.write((char*)&female_p, sizeof(female_p));file.write((char*)&female_mv.mean_height, sizeof(female_mv.mean_height));file.write((char*)&female_mv.mean_weight, sizeof(female_mv.mean_weight));file.write((char*)&female_mv.mean_foot_size, sizeof(female_mv.mean_foot_size));file.write((char*)&female_mv.variance_height, sizeof(female_mv.variance_height));file.write((char*)&female_mv.variance_weight, sizeof(female_mv.variance_weight));file.write((char*)&female_mv.variance_foot_size, sizeof(female_mv.variance_foot_size));file.close();return 0;
}template<typename T>
int NaiveBayesClassifier<T>::predict(const sex_info<T>& info) const
{T male_height_p = calc_attribute_probability(info.height, male_mv.mean_height, male_mv.variance_height);T male_weight_p = calc_attribute_probability(info.weight, male_mv.mean_weight, male_mv.variance_weight);T male_foot_size_p = calc_attribute_probability(info.foot_size, male_mv.mean_foot_size, male_mv.variance_foot_size);T female_height_p = calc_attribute_probability(info.height, female_mv.mean_height, female_mv.variance_height);T female_weight_p = calc_attribute_probability(info.weight, female_mv.mean_weight, female_mv.variance_weight);T female_foot_size_p = calc_attribute_probability(info.foot_size, female_mv.mean_foot_size, female_mv.variance_foot_size);T evidence = male_p * male_height_p * male_weight_p * male_foot_size_p +female_p * female_height_p * female_weight_p * female_foot_size_p;T male_posterior = male_p * male_height_p * male_weight_p * male_foot_size_p /*/ evidence*/;T female_posterior = female_p * female_height_p * female_weight_p * female_foot_size_p /*/ evidence*/;fprintf(stdout, "male posterior probability: %e, female posterior probability: %e\n",male_posterior, female_posterior);if (male_posterior > female_posterior) return 1;else return 0;
}template<typename T>
T NaiveBayesClassifier<T>::calc_attribute_probability(T value, T mean, T variance) const
{return (T)1 / std::sqrt(2 * PI * variance) * std::exp(-std::pow(value - mean, 2) / (2 * variance));
}template<typename T>
int NaiveBayesClassifier<T>::load_model(const std::string& model) const
{std::ifstream file;file.open(model.c_str(), std::ios::binary);if (!file.is_open()) {fprintf(stderr, "open file fail: %s\n", model.c_str());return -1;}file.read((char*)&male_p, sizeof(male_p) * 1);file.read((char*)&male_mv.mean_height, sizeof(male_mv.mean_height) * 1);file.read((char*)&male_mv.mean_weight, sizeof(male_mv.mean_weight) * 1);file.read((char*)&male_mv.mean_foot_size, sizeof(male_mv.mean_foot_size) * 1);file.read((char*)&male_mv.variance_height, sizeof(male_mv.variance_height) * 1);file.read((char*)&male_mv.variance_weight, sizeof(male_mv.variance_weight) * 1);file.read((char*)&male_mv.variance_foot_size, sizeof(male_mv.variance_foot_size) * 1);file.read((char*)&female_p, sizeof(female_p)* 1);file.read((char*)&female_mv.mean_height, sizeof(female_mv.mean_height) * 1);file.read((char*)&female_mv.mean_weight, sizeof(female_mv.mean_weight) * 1);file.read((char*)&female_mv.mean_foot_size, sizeof(female_mv.mean_foot_size) * 1);file.read((char*)&female_mv.variance_height, sizeof(female_mv.variance_height) * 1);file.read((char*)&female_mv.variance_weight, sizeof(female_mv.variance_weight) * 1);file.read((char*)&female_mv.variance_foot_size, sizeof(female_mv.variance_foot_size) * 1);file.close();return 0;
}template<typename T>
void NaiveBayesClassifier<T>::calc_mean_variance(const std::vector<T>& data, std::tuple<T, T>& mean_variance) const
{T sum{ 0 }, sqsum{ 0 };for (int i = 0; i < data.size(); ++i) {sum += data[i];}T mean = sum / data.size();for (int i = 0; i < data.size(); ++i) {sqsum += std::pow(data[i] - mean, 2);}// unbiased sample variancesT variance = sqsum / (data.size() - 1);std::get<0>(mean_variance) = mean;std::get<1>(mean_variance) = variance;
}template class NaiveBayesClassifier<float>;
template class NaiveBayesClassifier<double>;} // namespace ANN

funset.cpp:

#include "funset.hpp"
#include <iostream>
#include "perceptron.hpp"
#include "BP.hpp""
#include "CNN.hpp"
#include "linear_regression.hpp"
#include "naive_bayes_classifier.hpp"
#include "common.hpp"
#include <opencv2/opencv.hpp>// ================================ naive bayes classifier =====================
int test_naive_bayes_classifier_train()
{std::vector<ANN::sex_info<float>> info;info.push_back({ 6.f, 180.f, 12.f, 1 });info.push_back({5.92f, 190.f, 11.f, 1});info.push_back({5.58f, 170.f, 12.f, 1});info.push_back({5.92f, 165.f, 10.f, 1});info.push_back({ 5.f, 100.f, 6.f, 0 });info.push_back({5.5f, 150.f, 8.f, 0});info.push_back({5.42f, 130.f, 7.f, 0});info.push_back({5.75f, 150.f, 9.f, 0});ANN::NaiveBayesClassifier<float> naive_bayes;int ret = naive_bayes.init(info);if (ret != 0) {fprintf(stderr, "naive bayes classifier init fail: %d\n", ret);return -1;}const std::string model{ "E:/GitCode/NN_Test/data/naive_bayes_classifier.model" };ret = naive_bayes.train(model);if (ret != 0) {fprintf(stderr, "naive bayes classifier train fail: %d\n", ret);return -1;}return 0;
}int test_naive_bayes_classifier_predict()
{ANN::sex_info<float> info = { 6.0f, 130.f, 8.f, -1 };ANN::NaiveBayesClassifier<float> naive_bayes;const std::string model{ "E:/GitCode/NN_Test/data/naive_bayes_classifier.model" };int ret = naive_bayes.load_model(model);if (ret != 0) {fprintf(stderr, "load naive bayes classifier model fail: %d\n", ret);return -1;}ret = naive_bayes.predict(info);if (ret == 0) fprintf(stdout, "It is a female\n");else fprintf(stdout, "It is a male\n");return 0;
}

执行结果如下:

GitHub:  https://github.com/fengbingchun/NN_Test

朴素贝叶斯分类器简介及C++实现(性别分类)相关推荐

  1. 基于朴素贝叶斯分类器的西瓜数据集 2.0 预测分类_第十章:利用Python实现朴素贝叶斯模型

    免责声明:本文是通过网络收集并结合自身学习等途径合法获取,仅作为学习交流使用,其版权归出版社或者原创作者所有,并不对涉及的版权问题负责.若原创作者或者出版社认为侵权,请联系及时联系,我将立即删除文章, ...

  2. 机器学习(十一)-Naïve Bayes Classifier朴素贝叶斯分类器及Python实现

    原创不易,转载前请注明博主的链接地址:Blessy_Zhu https://blog.csdn.net/weixin_42555080 本次代码的环境: 运行平台: Windows Python版本: ...

  3. 朴素贝叶斯分类器的应用-转载加我的理解注释

    2019独角兽企业重金招聘Python工程师标准>>> 生活中很多场合需要用到分类,比如新闻分类.病人分类等等. 本文介绍朴素贝叶斯分类器(Naive Bayes classifie ...

  4. (数据科学学习手札30)朴素贝叶斯分类器的原理详解Python与R实现

    一.简介 要介绍朴素贝叶斯(naive bayes)分类器,就不得不先介绍贝叶斯决策论的相关理论: 贝叶斯决策论(bayesian decision theory)是概率框架下实施决策的基本方法.对分 ...

  5. MNIST | 基于朴素贝叶斯分类器的0-9数字手写体识别

    MNIST | 基于朴素贝叶斯分类器的0-9数字手写体识别 1 背景说明 2 关于数据集 2.1 什么是MNIST 2.2 数据集处理 3 代码实现 3.1 文件目录 3.2 核心代码 3.3 注意点 ...

  6. 文本分类(TFIDF/朴素贝叶斯分类器/TextRNN/TextCNN/TextRCNN/FastText/HAN)

    目录 简介 TFIDF 朴素贝叶斯分类器 贝叶斯公式 贝叶斯决策论的理解 极大似然估计 朴素贝叶斯分类器 TextRNN TextCNN TextRCNN FastText HAN Highway N ...

  7. 机器学习基础(六):贝叶斯分类(贝叶斯决策论、朴素/半朴素贝叶斯分类器、贝叶斯网、EM算法)

    6.贝叶斯分类 6.1贝叶斯决策论Bayesian decision theory 概率框架下实施决策的基本方法. 对分类任务来说,在所有相关概率都已知的理想情形下,贝叶斯决策论考虑如何基于这些概率和 ...

  8. 朴素贝叶斯分类器的例子

    一.病人分类的例子 让我从一个例子开始讲起,你会看到贝叶斯分类器很好懂,一点都不难. 某个医院早上收了六个门诊病人,如下表. 症状 职业 疾病 打喷嚏 护士 感冒  打喷嚏 农夫 过敏  头痛 建筑工 ...

  9. [转]朴素贝叶斯分类器的应用

    朴素贝叶斯分类器的应用 作者: 阮一峰 日期: 2013年12月16日 生活中很多场合需要用到分类,比如新闻分类.病人分类等等. 本文介绍朴素贝叶斯分类器(Naive Bayes classifier ...

最新文章

  1. msql 数据去重,仅保留一条
  2. Alibaba Cluster Data 开源:270GB 数据揭秘你不知道的阿里巴巴数据中心
  3. 路径总和 III—leetcode437
  4. 数据结构与算法(基于C++语法实现)
  5. Python自动化二--jmeter分布式测试,抓包,python语法基本介绍
  6. Python的网络编程[1] - FTP 协议[1] - 使用 pyftplib 建立 FTP 服务器
  7. 【nodejs原理源码赏析(3)】欣赏手术级的原型链加工艺术
  8. java 实例域_Java实例域初始化方法及顺序
  9. linux的文件权限分析
  10. PTA L2-006 树的遍历-二叉树的后序遍历+中序遍历,输出层序遍历 团体程序设计天梯赛-练习集...
  11. Restlet 短连接问题
  12. 3V升压5V芯片,3V升压5V电路图
  13. 【ShaderLab学习】AlphaTest AlphaBlend理解[2]
  14. VS2015如何添加头文件
  15. 电商项目5:商品模块
  16. 【Blender】三维建模介绍及Blender入门
  17. 阵列卡服务器装linux,Linux网卡阵列卡安装
  18. 添加个人博客音乐外链
  19. LeetCode day11
  20. U盘安装Fedora 24时出现的几个问题及解决办法

热门文章

  1. 机器学习(实战)facebook地址预测
  2. JS中编写函数去除HTML标签,js函数获取html中className所在的内容并去除标签
  3. php接收不到ajax请求参数,我是否需要在ajax请求和接收该请求的php之间编码/解码查询参数?...
  4. int long java_java long int的区别
  5. hbase 数据插入指定rowkey_「HBase大爆炸」HBase之常用Shell命令
  6. ikbc机械键盘打字出现重复_抖音开啤酒小姐姐同款面具,ikbc白无垢樱花机械键盘开箱体验...
  7. 基于消失点的相机自标定(2)
  8. 剑指offer: 面试题40. 最小的k个数
  9. 强化学习(八) - 深度Q学习(Deep Q-learning, DQL,DQN)原理及相关实例
  10. 在温系统下制作马克系统引导安装镜像启动U盘安装马克OS