码迷,mamicode.com
首页 > 其他好文 > 详细

朴素贝叶斯

时间:2015-02-02 01:54:16      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:

朴素贝叶斯(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 10005
int 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;
    }
}

 

朴素贝叶斯

标签:

原文地址:http://www.cnblogs.com/neopenx/p/4266666.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!