如何获取第四步中的最大值,也就是如何计算第三步中的各个条件概率最为重要。可以采用如下做法:
- 获取训练数据集,即分类已知的数据集
- 统计得到在各类别下各个特征属性的条件概率估计,即: P(a1|y1),P(a2|y1),...,P(am|y1);P(a1|y2),P(a2|y2),...,P(am|y2);...;P(a1|yn),P(a2|yn),...,P(am|yn)
对于某x来说,分母是固定的,所以只要找出分子最大的即为条件概率最大的。又因为各特征属性是条件独立的,所以有: P(x|yi)P(yi)=P(a1|yi)P(a2|yi)...P(am|yi)P(yi)=P(yi)∏mj=1P(aj|yi)
Additive smoothing
Additive smoothing,又叫Laplacian smoothing或Lidstone smoothing。
当某个类别下某个特征项划分没有出现时, P(ai|yj)=0
,这样最后乘出来的结果会让精确度大大的降低,所以引入Additive smoothing来解决这个问题。其思想是对于这样等于0的情况,将其计数值加1,这样如果训练样本集数量充分大时,并不会对结果产生影响,并且解决了上述频率为0的尴尬局面。
Spark实现贝叶斯算法
训练数据
0,1 0 0 0,2 0 0 0,1 0 0.1 0,2 0 0.2 0,1 0.1 0 0,2 0.2 0 1,0 1 0.1 1,0 2 0.2 1,0.1 1 0 1,0.2 2 0 1,0 1 0 1,0 2 0 2,0.1 0 1 2,0.2 0 2 2,0 0.1 1 2,0 0.2 2 2,0 0 1 2,0 0 2
其中第一列代表类别,训练数据中有三种类别:0、1、2。第2-4列代表数据的三个维度,可以想象成前文中性别分类算法中的头发长度、服饰和体型这三个要素。通常来说为了保证每个要素的权值相差不大,需要取相对的数值,例如头发长度/最长的头发长度。
代码示例
public static void main(String[] args) { SparkConf sparkConf = new SparkConf().setAppName("Bayes").setMaster("local[2]"); JavaSparkContext sc = new JavaSparkContext(sparkConf); JavaRDD<String> data = sc.textFile("/home/yurnom/data/sample_naive_bayes_data.txt"); RDD<LabeledPoint> parsedData = data.map(line -> { String[] parts = line.split(","); double[] values = Arrays.stream(parts[1].split(" ")) .mapToDouble(Double::parseDouble) .toArray(); //LabeledPoint代表一条训练数据,即打过标签的数据 return new LabeledPoint(Double.parseDouble(parts[0]), Vectors.dense(values)); }).rdd(); //分隔为两个部分,60%的数据用于训练,40%的用于测试 RDD<LabeledPoint>[] splits = parsedData.randomSplit(new double[]{0.6, 0.4}, 11L); JavaRDD<LabeledPoint> training = splits[0].toJavaRDD(); JavaRDD<LabeledPoint> test = splits[1].toJavaRDD(); //训练模型, Additive smoothing的值为1.0(默认值) final NaiveBayesModel model = NaiveBayes.train(training.rdd(), 1.0); JavaRDD<Double> prediction = test.map(p -> model.predict(p.features())); JavaPairRDD<Double, Double> predictionAndLabel = prediction.zip(test.map(LabeledPoint::label)); //用测试数据来验证模型的精度 double accuracy = 1.0 * predictionAndLabel.filter(pl -> pl._1().equals(pl._2())).count() / test.count(); System.out.println("Accuracy=" + accuracy); //预测类别 System.out.println("Prediction of (0.5, 3.0, 0.5):" + model.predict(Vectors.dense(new double[]{0.5, 3.0, 0.5}))); System.out.println("Prediction of (1.5, 0.4, 0.6):" + model.predict(Vectors.dense(new double[]{1.5, 0.4, 0.6}))); System.out.println("Prediction of (0.3, 0.4, 2.6):" + model.predict(Vectors.dense(new double[]{0.3, 0.4, 2.6}))); }
结果
Accuracy=1.0 Prediction of (0.5, 3.0, 0.5):1.0 Prediction of (1.5, 0.4, 0.6):0.0 Prediction of (0.3, 0.4, 2.6):2.0
由于数据的人为捏造过度,可以看到此次训练的模型精度十分高为100%,即测试数据的类别和用模型预测出来的对于类别完全吻合,实际生产环境中是无法达到100%的。后面又预测了3个不在训练数据中的数据,结果和大脑判断的类别完全相同。
最后
Naive Bayes是最简单的分类算法之一。由于其简单的特性,使得训练数据的选取对于精确度的影响十分大。在我们的生产环境中,通常将训练数据进行六四分,六分 用来训练数据,四分用来测试精确度。但即便如此,测试输出的精确度也往往高于实际生产环境中的精确度。不断的增加训练模型的数据量是一个较为有效的提高精 度的方法,但提高的范围也十分有限。