分类算法(2) ---- 朴素贝叶斯算法(NB)

来源:互联网 发布:怎样撤回淘宝手机充值 编辑:程序博客网 时间:2024/06/16 22:15

朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。

朴素贝叶斯分类器假设样本每个特征与其他特征都不相关。


一. 基于离散变量

     下面以一个简单的数据集为例,阐述基于NB的回归/预测模型:

      

     上述三篇文本的词列表如下:

     

    首先可以将上述两篇训练文本(train1和train2),以及一篇测试文本(test1)转为如下向量格式:

     

分析:

     基于NB的回归模型如何在已知train1和train2的标准答案(即公众感到“joy”的概率)分别为0.6和0.7的前提下,预测test1对应的公众感到“joy”的概率值。
    为了便于模型的推导,我们将文本train1记为d1,train2记为d2,test1记为d3,情感joy记为j,词sheva记为s,词goal记为g。我们要估计的是p(d3, j),即文本test1和情感joy的联合概率值(也就是说,100名用户看到test1,会有多大的可能性将它关联到joy)。由于d3包含s和g两个词,因此要估计的p(d3, j)近似等于p(s, g, j),即词sheva、goal和情感joy的联合概率值。基于NB的回归模型利用所有的训练文本及其标准答案来估计这个值:
p(s, g, j) = p(d1, s, g, j) + p(d2, s, g, j) 概率的加法法则,

其中,p(d1, s, g, j) = p(d1, j, s, g) = p(d1, j)p(s | d1, j)p(g | d1, j, s) 概率的乘法法则,同上
上式中,p(d1, j) = 0.6;p(s | d1, j) = 0.33;p(g | d1, j, s) = 0,这里假设给定每篇文本和情感的前提下,词与词之间是独立的,也就是说p(g | d1, j, s) = p(g | d1, j) = 0。
所以,p(d1, s, g, j) = 0.6*0.33*0 = 0。
同理,p(d2, s, g, j) = 0.7*0.25*0.25 = 0.044。
所以,p(s, g, j) = 0 + 0.044 = 0.044。即,基于NB的回归模型会将test1对应的公众感到“joy”的概率值预测为0.044。


存在的问题:

(1)一个词概率为0就会得到全0结果

        解决方法:拉普拉斯平滑,将乘式中所有的0用一个很小的常数代替

(2)乘积过小

     下溢出解决方法:对乘积取自然对数,将相乘变为相加,计算完以后  加上一个数作补偿再做指数变换。

                     (这个方法更大的好处是,可以将计算过程转为非常简单的矩阵乘法)

    预测结果非常小解决方法:将所有结果进行归一化, 算出所有情感值之和,取每一个值除以总和的商。


二. 基于连续变量

   需要将连续变量离散化:

(1)使用相应的离散区间替换连续属性值。但是这种方法不方便控制离散区间划分的粒度。

(2)假设变量服从高斯分布,使用训练数据来估计分布的参数。

附上属性连续型代码,数据集格式为:第一行为58个属性名称,最后一个是分享值(0或1),接下来n行是训练数据集,再继续来m行是预测数据集,其share值为空。需要求出预测数据集的share预测值。

<span style="font-size:14px;">#include <bits/stdc++.h>#define train_n 27751#define test_n 11893#define feature_n 58#define pi acos(-1)#define inf 1000000using namespace std;double MAX[60],MIN[60];struct Continuous{//连续型属性     double mean[2],var[2]; //m/v[i]是share=i的均值和方差 }f[60];typedef vector<double> feature;vector <feature> text; //所有文本vector <int> shares;   //测试文本的share值double p[2];// share=0/1概率 int text_n = test_n+train_n; //所有文本个数 void input(){string line;double data;int n;ifstream fin("Datac_all.csv");getline(fin, line);for(int i=0;i<text_n;i++){ getline(fin, line);istringstream ss(line);feature tmp;while (!ss.eof()){ss >> data;  //忽略逗号 ss.ignore(line.size(), ',');tmp.push_back(data);}text.push_back(tmp);if(i<train_n){shares.push_back(data);    if(data>0) n++;//计算share=1的个数 }}fin.close();p[1] = 1.0*n / train_n;p[0] = 1.0*(train_n-n) / train_n;cout << "The read is done\n";}void train_work()//计算均值(mean)和方差(var) {for (int i=0; i<feature_n; i++)//对每个属性 {for (int j=0; j<train_n; j++){int k = shares[j];f[i].mean[k] += text[j][i];}f[i].mean[1] /= train_n;//share=1的均值 f[i].mean[0] /= train_n;//share=0的均值 for (int j=0; j<train_n; j++){int k = shares[j];f[i].var[k] += (text[j][i]-f[i].mean[k])*(text[j][i]-f[i].mean[k]);}f[i].var[1] /= train_n;//share=1的方差 f[i].var[0] /= train_n;//share=0的方差 }cout << "The train is done\n";}double gauss_probability(int i, int j, int share)//计算概率 {double x = text[i][j];double m = f[j].mean[share];double v = f[j].var[share];return (exp(-(x-m)*(x-m)/(2*v)) / (sqrt(2*pi*v)));//高斯分布 }void predict()//进行预测 {ofstream out("NB.txt");for (int i=train_n; i<text_n; i++){double share = p[1], not_share = p[0];for (int j=0; j<feature_n; j++){share *= gauss_probability(i, j, 1);not_share *= gauss_probability(i, j, 0);}out << (share>not_share) << endl;}cout << "The predict is done\n";}int main(){input();train_work();predict();return 0;}</span>



0 0
原创粉丝点击