首页 > 代码库 > 朴素贝叶斯

朴素贝叶斯

朴素贝叶斯(Normal Bayes)适用于离散型特征的分类问题。

相比于KNN的纯暴力,决策树的降维以求减少比较次数的优化,NB的优势在于,训练完成之后,分类测试的效率非常高。

设样本数为n,分类数据为m

KNN没有训练过程,需要分类的时候,即时确定分类。总复杂度O(mn^2)

决策树虽然有训练过程,但是是将样本和待分类数据一同拉入树中分类,复杂度估测O((n+m)^2*log(n+m))

NB则是先训练样本,复杂度O(n^2),分类时,对于每个数据,for同时比较所有分类的各个维度,计算p(w|ci),复杂度O(d),总复杂度O(n^2+d)

所以在样本庞大时,NB很有优势,毕竟你总不能每次分类时还处理一下庞大的文本样本吧,提前训练一下,做个预处理,减少分类时的压力。

值得一提的是,NB假设各个特征是相对独立的,而且不能有什么上下文关联(和马科夫链完全不是一个概念)。

所以不要拿NB做文本识别什么的,因为NB会认为“我爱你”、“你爱我”这两个数据是相同的,实际上是不同的。

NB最常见的是用于文本内容的分类(不涉及上下文),此时维度d由总词典单词数确定,这是特例。

对于普通的离散型数据特征,分类比较的维度就是特征维度了,也没必要造词典了。

比如收集你喜欢的妹子和不喜欢的妹子的各个特征来训练,然后对于一个新交往的妹子,你就可以预测会不会喜欢她了。

 

————————————————————————————————————————————————————————————

NB的思路其实不是很复杂(以文本类NB说明,以下的代码确定一个0/1分类)

NB的分类公式P(ci|W)=P(W|ci)*P(ci)/P(W),ci指的是分类。

首先无视掉最后除的P(W),因为P(W)由样本决定,对于所有分类数据P(W)都是一样的。

那么只要看P(W|ci)*P(ci)就行了。

P(ci)=样本中属于这个分类数/总样本数,这个也很好算。

P(W|ci)是重点,NB有个奇怪的假设就是所有特征是独立的,所以P(W|ci)=P(w1,w2,....wn|ci)=P(w1|ci)*P(w2|ci)...P(wn|ci)

P(w1|ci)=所有属于ci的样本在第1维度的累计值/在所有维度的累计值,这里处理条件概率的方式比较特别,其实就是分类累加,然后除一下就有概率了。

目测n=20时,精度就爆了,所以对X=P(W|ci)*P(ci)处理一下,取对数log再比较,变成logX=P(w1|ci)+P(w2|ci)+....P(wn|ci)+P(ci)

 

①读入数据,使用map造词典vocabList, 同时map存下每条样本的各个单词出现次数

②计算训练矩阵trainVec[n][m]

     对于词典中的每个词i

        如果j词条中存在这个词,则trainVec[j][i]=1 or cnt (这里有两个模型,词集模型的每个词只能出现一起所以为1,词袋模型中每个词可以出现多次,所以①中的次数就有用了)

        不存在则trainVec[j][i]=0

③为两个分类累加各个维度的值,形成两个向量p0,p1,并统计该分类的总值p0Sum,p1Sum

   该步需要做一下处理,就是如果某个维度的累加值最后是0,那么算P(w1|ci)*P(w2|ci)...P(wn|ci),最后就会变成0了,然后就是log(0),完蛋啦。

   所以p0、p1的各个维度初始值设为1,那么p0Sum=p1Sum=维度大小,这样既保证每个分类算出的概率和为1,又能避免出现0问题。

④p0/p0Sum得到最后用于分类的p0Vec向量,p1同样处理。

⑤分类,计算P0,P1。方法是扫一遍词典,如果当前词在这个词汇中存在,则P0+=出现次数*p0Vec[i], P1+=出现次数*p1Vec[i]

由于p0Vec,p1Vec记录的是样本生成的多个维度的权,所以P0、P1因为各个维度的权不同,导致大小不同,谁大谁的分类就越有可能。

#include "cstdio"#include "vector"#include "string"#include "iostream"#include "map"#include "math.h"using namespace std;#define maxn 10005int n,tmp,p0Sum,p1Sum,cnt;string line,word;vector<string> wordVec[maxn];vector<int> classVec,trainVec[maxn],v0,v1;map<string,int> vocabList,wordHash[maxn];vector<double> p0Vec,p1Vec;void initProcess(){    cin>>n;getchar();    for(int i=0; i<n; i++)    {        getline(cin,line);        word.clear();        tmp=0;        for(int j=0; j<line.size(); j++)        {            if(line[j]== )            {                wordHash[i][word]++;                vocabList[word]++;                word.clear();                tmp=j+1;            }            else word.push_back(line[j]);        }        if(tmp!=line.size())        {            vocabList[word]++;            wordHash[i][word]++;        }    }    for(int i=0;i<n;i++) {cin>>tmp;classVec.push_back(tmp);if(tmp) cnt++;}    for(map<string,int>::iterator i=vocabList.begin(); i!=vocabList.end(); i++)        for(int j=0; j<n; j++)            if(wordHash[j].count(i->first)) trainVec[j].push_back(wordHash[j][i->first]); //model:bag?set            else trainVec[j].push_back(0);    v0=vector<int>(vocabList.size(),1),p0Vec.resize(vocabList.size());    v1=vector<int>(vocabList.size(),1),p1Vec.resize(vocabList.size());    p0Sum=p1Sum=vocabList.size(); //fixed    for(int i=0; i<n; i++)    {        if(classVec[i]==0)        {            for(int j=0; j<trainVec[i].size(); j++)            {                v0[j]+=trainVec[i][j];                if(trainVec[i][j]==1) p0Sum++;            }        }        else        {            for(int j=0; j<trainVec[i].size(); j++)            {                v1[j]+=trainVec[i][j];                if(trainVec[i][j]==1) p1Sum++;            }        }    }    for(int i=0; i<p0Vec.size(); i++) {p0Vec[i]=log((double)v0[i]/p0Sum);p1Vec[i]=log((double)v1[i]/p1Sum);}}int classify(vector<string> sample){    map<string,int> tt;    for(int i=0;i<sample.size();i++) tt[sample[i]]++;    double p0=0.0,p1=0.0;    int pos=0;    for(map<string,int>::iterator i=vocabList.begin();i!=vocabList.end();i++)    {        if(tt.count(i->first))        {            p0+=p0Vec[pos];            p1+=p1Vec[pos];        }        pos++;    }    p1+=log((double)cnt/n);    p0+=log(1-(double)cnt/n);    if(p0>p1) return 0;    else return 1;}int main(){    freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    initProcess();getchar();    while(getline(cin,line))    {        tmp=0;        word.clear();        vector<string> sample;        for(int j=0; j<line.size(); j++)        {            if(line[j]== )            {                sample.push_back(word);                word.clear();                tmp=j+1;            }            else word.push_back(line[j]);        }        if(tmp!=line.size()) sample.push_back(word);        cout<<"sample: ";        for(int i=0; i<sample.size(); i++) cout<<sample[i]<<" ";        cout<<endl;        int x=classify(sample);        cout<<"class: "<<x<<endl;    }}

 

朴素贝叶斯