Java 机器学习库Smile实战(二)AdaBoost

时间:2022-05-03
本文章向大家介绍Java 机器学习库Smile实战(二)AdaBoost,主要内容包括1. AdaBoost算法简介、2. 参数解释、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

1. AdaBoost算法简介

Boost 算法系列的起源来自于PAC Learnability(PAC 可学习性)。这套理论主要研究的是什么时候一个问题是可被学习的,当然也会探讨针对可学习的问题的具体的学习算法。这套理论是由Valiant提出来的,也因此(还有其他贡献哈)他获得了2010年的图灵奖。下面是他的照片:

PAC 定义了学习算法的强弱:

弱学习算法 — 识别错误率小于1/2(即准确率仅比随机猜测略高的学习算法);

强学习算法 — 识别准确率很高并能在多项式时间内完成的学习算法。

同时 ,Valiant和 Kearns首次提出了 PAC学习模型中弱学习算法和强学习算法的等价性问题,即任意给定仅比随机猜测略好的弱学习算法 ,是否可以将其提升为强学习算法 ? 如果二者等价 ,那么只需找到一个比随机猜测略好的弱学习算法就可以将其提升为强学习算法 ,而不必寻找很难获得的强学习算法。 也就是这种猜测,让无数牛人去设计算法来验证PAC理论的正确性。

不过很长一段时间都没有一个切实可行的办法来实现这个理想。细节决定成败,再好的理论也需要有效的算法来执行。终于功夫不负有心人, Schapire在1996年提出一个有效的算法真正实现了这个夙愿,它的名字叫AdaBoost。AdaBoost把多个不同的决策树用一种非随机的方式组合起来,表现出惊人的性能!第一,把决策树的准确率大大提高,可以与SVM媲美。第二,速度快,且基本不用调参数。第三,几乎不Overfitting。我估计当时Breiman和Friedman肯定高兴坏了,因为眼看着他们提出的CART正在被SVM比下去的时候,AdaBoost让决策树起死回生!Breiman情不自禁地在他的论文里赞扬AdaBoost是最好的现货方法(off-the-shelf,即“拿下了就可以用”的意思)。

下面是Adaboost 算法的实现思想:

接下来是Smile库中的AdaBoost算法的用法实战程序:

import smile.classification.AdaBoost;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by zhanghuayan on 2017/1/17.
 */
public class AdaBoostTest {

  public static void main(String[] args) throws Exception {

        List<List<Double>> datas = 
                          new ArrayList<List<Double>>();
        List<Double> data = new ArrayList<Double>();
        List<Integer> labels = new ArrayList<Integer>();

        String line;
        List<String> lines;
        File file = new File("iris.txt");
        BufferedReader reader = 
                        new BufferedReader(new FileReader(file));
        while ((line = reader.readLine()) != null) {
            lines = Arrays.asList(line.trim().split("t"));
            for (int i = 0; i < lines.size() - 1; i++) {
                data.add(Double.parseDouble(lines.get(i)));
            }
            labels.add(Integer.parseInt(lines.get(lines.size() - 1)));

            datas.add(data);
            data = new ArrayList<Double>();

        }

        //转换label
        int[] label = new int[labels.size()];
        for (int i = 0; i < label.length; i++) {
            label[i] = labels.get(i);
        }

        //转换属性
        int rows = datas.size();
        int cols = datas.get(0).size();
        double[][] srcData = new double[rows][cols];
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                srcData[i][j] = datas.get(i).get(j);
            }
        }


        AdaBoost adaBoost = 
                     new AdaBoost(srcData, label, 4, 8);
        double right = 0;
        for (int i = 0; i < srcData.length; i++) {
            int tag = adaBoost.predict(srcData[i]);
            if (i % 10 == 0) System.out.println();
            System.out.print(tag + " ");
            if (tag == label[i]) {
                right += 1;
            }
        }
        right = right / srcData.length;
        System.out.println("Accrurate: " + right * 100 + "%");
    }
} 

数据集与Java机器学习库Smile实战(一)SVM中的iris数据集格式一致。下面是程序输出的结果:

0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 
1 1 1 1 1 1 1 1 1 1 
1 1 1 1 1 1 1 1 1 1 
1 1 1 1 1 1 1 1 1 1 
1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2 
2 2 2 2 2 2 2 2 2 2 
2 2 2 2 2 2 2 2 2 2 
2 2 2 2 2 2 2 2 2 2 
2 2 2 2 2 2 2 2 2 2

Accrurate: 100.0%

当然这里的训练数据和测试数据使用的是同一数据,所以可能出现过拟合现象。因此现实训练的时候应采取例如交叉验证等技术手段调整参数。

2. 参数解释

第3个参数是子树的个数,第4个参数是每个子树最大叶子节点数:

AdaBoost adaBoost = new AdaBoost(srcData, label, 4, 8);

训练好了之后就可以如下调用predict()方法:

int tag = adaBoost.predict(srcData[i]);