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,该作业只统计了每个
(2) 预测
预测时,需要把文件dict1.txt和dict2.txt作为字典加载到内存中,一般而言,dict1.txt很小,而dict2.txt很大,如种类数是100,term总数为10000,0000,则dict2需要保存的记录总数为100*10000 0000=10^10。为了解决该问题,提出以下解决方案:
(1)将种类分片存储到多个文件中。比如,共有100个种类,每10个种类为一组存放到10个字典中(即:某个字典只保存与某10个种类相关的
(2)dict2.txt中实际上存放的是一个稀疏矩阵,稀疏矩阵很适合用HashTable存储,在C++中,很容易想到STL map,实际上,这种方案非常浪费内存。STL map是红黑树,每个节点的数据结构如下:
1
2
3
4
5
6
7
8
9
|
struct
node {
T* data;
// key +value=4+4=8
bool
color,
//ignore
struct
node *father, *left, *right;
}
|
每个节点大约需要8+4*3=20个字节。为了改进该方案,采用vector+二分查找的方案:
首先,将
1
2
3
4
5
|
unsigned
int
FormatToCombinedNumber(unsigned
int
high, unsigned
int
low) {
return
((high & 0x7f) << 24) + (low & 0xffffff);
}
|
然后,将(
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
vector
class
KeyValue {
public
:
void
Set(unsigned
int
t,
float
w) {
term = t;
weight = w;
}
unsigned
int
term;
float
weight;
};
|
最后,当查询一个
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
struct
TermCompare :
public
std::binary_function
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
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()
1
2
3
4
5
|
Map(new_doc):
for
each
class
in dictionary:
Emit(doc,
class
|probility);
|
该Hadoop作业可能运行多次,主要取决于划分的字典数目
(2) 选出最大概率,得到doc的类别
PredcitProbilityCombiner():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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/
作者:Dong,作者介绍:http://dongxicheng.org/about/
from: http://dongxicheng.org/data-mining/naive-bayes-in-hadoop/