Naïve Bayes分类算法在Hadoop上的实现

标签: 数据挖掘 朴素Bayes分类,Hadoop | 发表时间:2011-08-31 15:50 | 作者:Dong Roger
出处:http://dongxicheng.org

1. Naïve Bayes算法介绍

Naïve Bayes是一个简单有效的分类算法,已经得到广泛使用。本文讨论了海量数据(TB级)下Naïve Bayes算法的实现方法,并给出了Hadoop上的实现方案。

2. Naïve Bayes算法介绍

朴素贝叶斯分类器基于一个简单的假定: 在给定目标值时属性值之间相互独立, 即特征对于给定类的影响独立于其它特征。利用该假设,文档d 属于类c 的概率可以表示为:

3. Naïve Bayes算法在Hadoop上实现

分两个阶段进行,首先是训练获取分类器,然后是预测。

(1) 训练

训练阶段要计算两种概率:[1] 每种类别的先验概率 [2] 每个term(单词)在每个类别中得条件概率。

[1] 计算类别的先验概率

由一个Hadoop Job实现,伪代码如下:

该作业主要统计了每种类别文档的总数目,具体概率的计算放在了后面。假设该作业计算得到的数据汇总在了文件dict1.txt中。

[2] 计算term的条件概率

由一个Hadoop job实现,伪代码如下:

其中,c表示种类,w表示word,该作业只统计了每个<c,w>对出现的总次数,具体条件概率计算放在了后面。假设该作业得到的数据汇总在文件dict2.txt中。

(2) 预测

预测时,需要把文件dict1.txt和dict2.txt作为字典加载到内存中,一般而言,dict1.txt很小,而dict2.txt很大,如种类数是100,term总数为10000,0000,则dict2需要保存的记录总数为100*10000 0000=10^10。为了解决该问题,提出以下解决方案:

(1)将种类分片存储到多个文件中。比如,共有100个种类,每10个种类为一组存放到10个字典中(即:某个字典只保存与某10个种类相关的<c,w>对,这个可以通过将同一种类的<c,w>将给相同reduce task处理做到),分批计算。

(2)dict2.txt中实际上存放的是一个稀疏矩阵,稀疏矩阵很适合用HashTable存储,在C++中,很容易想到STL map,实际上,这种方案非常浪费内存。STL map是红黑树,每个节点的数据结构如下:


struct node {

  T* data; // key +value=4+4=8

  bool color,//ignore

  struct node *father, *left, *right;

}

每个节点大约需要8+4*3=20个字节。为了改进该方案,采用vector+二分查找的方案:

首先,将<c,w>对压缩到一个unsigned int中,如,高7位表示种类(事先对种类进行编号,能表示2^7=128个种类),低25位表示term编号(最大可有33554432个term);


unsigned int FormatToCombinedNumber(unsigned int high, unsigned int low) {

  return ((high & 0x7f) << 24) + (low & 0xffffff);

} 

然后,将(<c,w>, 次数)保存到vector中,并事先按照<c,w>(实际上是一个unsigned int)排序。


vector<KeyValue> term_prb;

class KeyValue {

 public:

  void Set(unsigned int t, float w) {

   term = t;

   weight = w;

  }

  unsigned int term;

  float weight;

};

最后,当查询一个<c,w>出现的概率时,只需拼凑<c,w>对应的unsigned int,然后在vector中二分查找即可。


struct TermCompare : public std::binary_function<KeyValue, KeyValue, bool> {

 public:

  bool operator() (const KeyValue &o, const unsigned int term) const {

   return o.term < term;

  }

  bool operator() (const unsigned int term, const KeyValue &o) const {

   return term < o.term;

  }

};

float TermFind(unsigned int key) {

 vector<KeyValue>::iterator index =

 lower_bound(term_prb.begin(), term_prb.end(), key, TermCompare());

 if(index == term_prb.end() || index->term > key ) {

  return default_term_prb;

 } else {

  return index->weight;

 }

}

Hadoop程序首先要加载词典dict1.txt和dict2.txt,并将之分别保存到map和vector两种数据结构中,需要注意的是,加载之前需要将对应的概率(先验概率和调教概率)计算出来,预测的Hadoop伪代码如下:

(1) 多轮预测新doc在每个种类中的概率:

PredcitProbility()


Map(new_doc):

 for each class in dictionary:

  Emit(doc, class|probility); 

该Hadoop作业可能运行多次,主要取决于划分的字典数目

(2) 选出最大概率,得到doc的类别

PredcitProbilityCombiner():


Map(doc):

 Emit(doc, class|probility); //直接输出(1)的结果,让reducer选择

Reduce(doc):

 max_prb=-MIN

 max_class = 0

 for each value v(class|probility):

  if(max_prb < probility) {

   max_prb = probility;

   max_class = class;

  }

Emit(doc, max_class);

该作业的输入是上一个作业的所有输出。

4. 总结

上面共提到4个Hadoop作业,分别为:ClassPrior,ConditionalProbility,PredictProbility和PredictProbilityCombiner,它们的关系如下:

5. 参考资料

(1) 基于MapReduce 的并行贝叶斯分类算法的设计与实现, 丁光.华. 周继鹏. 周敏

原创文章,转载请注明: 转载自董的博客

本文链接地址: http://dongxicheng.org/data-mining/naive-bayes-in-hadoop/

相关 [na ve bayes] 推荐:

Naïve Bayes分类算法在Hadoop上的实现

- Roger - 董的博客
Naïve Bayes算法介绍. Naïve Bayes是一个简单有效的分类算法,已经得到广泛使用. 本文讨论了海量数据(TB级)下Naïve Bayes算法的实现方法,并给出了Hadoop上的实现方案. Naïve Bayes算法介绍. 朴素贝叶斯分类器基于一个简单的假定: 在给定目标值时属性值之间相互独立, 即特征对于给定类的影响独立于其它特征.