大数据:Spark mlib Naive bayes朴素贝叶斯分类之多元朴素贝叶斯源码分析
Posted raintungli
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大数据:Spark mlib Naive bayes朴素贝叶斯分类之多元朴素贝叶斯源码分析相关的知识,希望对你有一定的参考价值。
1. 什么是朴素贝叶斯
朴素贝叶斯是一种构建分类器,该分类器基于一个理论:所有朴素贝叶斯分类器都假定样本每个特征与其他特征都不相关
2. 朴素贝叶斯概率模型
概率模型分类器是一个条件概率模型:(独立的类别特征C有若干类别,条件依赖于若干特征变量F1,F2,...,Fn) 贝叶斯定理: 我们可以看到分母并不依赖于C,而且特征Fn的概率是给定的,分母可以认为是一个常数。 这样分子就等价于联合分布模型, 使用链式法则,可将该式写成条件概率的形式,如下所示假设每个特征Fi对于其他特征Fj是条件独立的。
这就意味着
3. 多元朴素贝叶斯
p(X|Ck)表示事件i发生的概率,特征向量X=(x1,x2,...,xn),其中xi表示事件i在特定的对象中被观察到的次数。 X的似然函数如下所示:多元朴素贝叶斯分类器:使用对数转化成线性分类器。
如果一个事件在特征向量i中没有出现过,那么i的特征值概率将为0,而0的对数是无效的,需要对每个小类样本概率进行修正,以保证不会出现有为0的概率出现,需要加上平滑系数,常用到的平滑就是加1平滑(也称拉普拉斯平滑)。
多元朴素贝叶斯常用于文档的归类分析
4. Spark实现多元朴素贝叶斯
4.1 计算事件i的特征向量的次数
要实现多元朴素贝叶斯模型,首先要归并同一事件i的特征向量的次数,那么我们很容易想到函数AggregateByKey,事件i作为key进行归并 val aggregated = dataset.select(col($(labelCol)), w, col($(featuresCol))).rdd
.map row => (row.getDouble(0), (row.getDouble(1), row.getAs[Vector](2)))
.aggregateByKey[(Double, DenseVector)]((0.0, Vectors.zeros(numFeatures).toDense))(
seqOp =
case ((weightSum: Double, featureSum: DenseVector), (weight, features)) =>
requireValues(features)
BLAS.axpy(weight, features, featureSum)
(weightSum + weight, featureSum)
,
combOp =
case ((weightSum1, featureSum1), (weightSum2, featureSum2)) =>
BLAS.axpy(1.0, featureSum2, featureSum1)
(weightSum1 + weightSum2, featureSum1)
).collect().sortBy(_._1)
- DataSet的支持:在Spark 2.1后部分mlib库对dataset进行支持,在这种情况下需要把原来的LabeledPoint进行转化成DataSet
- Weight 权重支持:你可以定义每一个特征纬度的权重,特征纬度的权重最后会影响log(P(Ck))的值,默认的权重设置为1
- seqOp:在同一个Partation中的合并操作 combOp: 不同的Partition 的最后合并操作
4.2 计算事件i的概率
val piLogDenom = math.log(numDocuments + numLabels * lambda)
var i = 0
aggregated.foreach case (label, (n, sumTermFreqs)) =>
labelArray(i) = label
piArray(i) = math.log(n + lambda) - piLogDenom
......
计算事件I的概率对数: log(P|Ck) = math.log((n+lambda)/(numDocuments+numLabels*lamdba)) 假如:有两个事件A,B,特征向量是x1,x2,x3 数据集合如下: A 1 2 3 A 3 4 1 B 3 2 4 B 5 7 1 计算log(P|A) n: 就是事件A的数量 2(权重是1的情况下) numDocuments: 就是总数据集合的数量 4 numLabels: 就是合并后剩下的数据集合的数量 2,也就是事件的数量(A,B) lambda:就是为了防止为0的平滑系数
4.3 计算事件i的每个特征的概率
val thetaLogDenom = $(modelType) match
case Multinomial => math.log(sumTermFreqs.values.sum + numFeatures * lambda)
case _ =>
// This should never happen.
throw new UnknownError(s"Invalid modelType: $$(modelType).")
var j = 0
while (j < numFeatures)
thetaArray(i * numFeatures + j) = math.log(sumTermFreqs(j) + lambda) - thetaLogDenom
j += 1
计算每个特征的概率对数:
log(Pxi)=math.log((sumtermfreqs(i)+lambda)/(sumtermfreqs.values.sum+numFeatures*lamdba))
沿用上面的例子:
sumtermfreqs(i):就是每个特征值xi在事件A下的数量
sumtermfreqs.values.sum 就是所有特征值x1...xn在事件A下的数量和
numfeatures: 就是总的特征向量的数量n
4.4 构建矩阵和向量生成模型
向量:事件A,B的概率向量 举证:事件A,B的每一个特征的概率,构成一个以特征数量为行,以事件为列的密度矩阵,保存到朴素贝叶斯模型中去 val pi = Vectors.dense(piArray)
val theta = new DenseMatrix(numLabels, numFeatures, thetaArray, true)
new NaiveBayesModel(uid, pi, theta).setOldLabels(labelArray)
4.5 如何进行分类
按照多元朴素贝叶斯计算模型计算log(P(Ck))+sum(xi*log(Pki))为归为某个事件的概率
log(p(Ck))和log(Pki)都已经在前面计算好了,唯一要做的是将要用于分类的数据*log(Pki)并且求和,加上log(Pck)就可以了,会不会很奇怪为什么是求和而不是求乘法,通常贝叶斯公式都是乘法,因为这里是求了对数,所以乘法变成了加法 如何分类? MAP决策准则:选出算出最大的概率所属的分类
4.6 如何判定模型有效
使用常用的交叉验证方式,将已经分类好的数据集合随机分成测试数据和训练数据,使用训练数据进行训练计算概率矩阵,使用测试数据进行预测分类,计算预测的准确率,设定自己定义的准确率,如果达到就判定训练的模型有效。 val Array(training, test) = data.randomSplit(Array(0.6, 0.4))
val model = NaiveBayes.train(training, lambda = 1.0, modelType = "multinomial")
val predictionAndLabel = test.map(p => (model.predict(p.features), p.label))
val accuracy = 1.0 * predictionAndLabel.filter(x => x._1 == x._2).count() / test.count()
以上是关于大数据:Spark mlib Naive bayes朴素贝叶斯分类之多元朴素贝叶斯源码分析的主要内容,如果未能解决你的问题,请参考以下文章
apache spark mllib naive bayes LabeledPoint 用法
Spark Naive Bayes 模型持久性:理解 pi 和 theta
Spark MLlib速成宝典模型篇04朴素贝叶斯Naive Bayes(Python版)
Spark Naive Bayes 模型 - 没有这样的方法错误