JavaとGridDBによるAdaBoost、バギング、スタッキング、およびVotingの実装

AdaBoost、バギング、スタッキング、Votingはすべてアンサンブル学習の手法です。アンサンブル学習は機械学習の一種で、一般に「弱い学習器」や「ベースモデル」と呼ばれる複数のモデルを特定の問題を解決するために学習させ、より良い結果を得るために組み合わせるものです。弱いモデルを正しく組み合わせると、より正確で頑健なモデルが得られるという仮説に基づいています。

ソースコードの全文はこちらをご覧ください。https://github.com/griddbnet/Blogs/tree/adaboost-bagging

それでは、今回使用するアンサンブル学習の方法について説明します。

1. バギング

バギングは “Boostrap Aggregation “の略です。ブートストラップとは、特定の学習セットから、置換を用いて異なるデータセットをサンプリングする手法になります。バギングは、1つの学習アルゴリズムを学習データの異なるサブセットに適用し、サブセットのサンプリングを置換(ブートストラップ)を用いて行うアンサンブル学習の手法です。

アルゴリズムがすべてのサブセットを使って学習された後、バギングでは、異なるサブセットを使ってアルゴリズムが行った予測を集約することで予測を行います。ベース学習器の出力を集約するために、アルゴリズムは、分類には多数決を、回帰問題には平均化を使用します。

2. AdaBoost

AdaBoostは弱い学習器を強い学習器に変換するアルゴリズム群です。このアンサンブル手法は、あらゆる学習アルゴリズムのモデル予測を向上させます。AdaBoostでは、弱い学習器を順次学習させ、各学習器が以前の学習器を修正しようとします。つまり、弱い学習器は前の学習器によって修正され、強い学習器へと変換されます。補正はバイアスを減らすことで行われます。

3. スタッキング

このアンサンブル学習法は、多くの機械学習アルゴリズムをメタ学習によって組み合わせるものです。ベースレベルのアルゴリズムは完全な学習データセットを用いて学習され、メタモデルはすべてのベースレベルのモデルの結果を特徴として学習されます。あまり良くないモデルの予測をより良いモデルの入力として利用することで、予測精度を向上させることができます。

今回は、これらのアンサンブル学習の手法を、JavaとGridDBを用いて実装します。

データセットについて

この記事で使用するデータは、様々な気象条件と、個人が遊ぶことができるかどうかを示しています。データセットには、outlook (見通し), temperature (気温), humidity (湿度), windy (風), play (遊び) の5つの属性があります。最初の4つの属性が独立変数で、最後の属性が従属変数です。データは weather.csv という名前の CSV ファイルに格納されています。

GridDBにデータを格納する

GridDBは、CSVファイルと比較して様々な利点があります。例えば、クエリーはより高速なパフォーマンスを提供します。したがって、CSVファイルからデータを移行し、GridDBに格納することは良いことだと思います。

まず、Javaのコードでこれを実現するためのライブラリをインポートしてみましょう。

import java.io.File;
import java.util.Scanner;
import java.io.IOException;
import java.util.Collection;
import java.util.Properties;

import com.toshiba.mwcloud.gs.Query;
import com.toshiba.mwcloud.gs.RowKey;
import com.toshiba.mwcloud.gs.RowSet;
import com.toshiba.mwcloud.gs.GridStore;
import com.toshiba.mwcloud.gs.Collection;
import com.toshiba.mwcloud.gs.GSException;
import com.toshiba.mwcloud.gs.GridStoreFactory;

GridDBはコンテナにデータを格納します。データの格納に使用するGridDBコンテナを表す静的なJavaクラスを作成しましょう。名前は Weather とします。

public static class Weather {
     @RowKey String outlook;
     String temperature; 
     String humidity;
     String windy;
     String play;
}  

上記の各変数は、GridDB コンテナ内のカラムを表します。SQL のテーブルと同様です。

次に、JavaからGridDBに接続します。これを成功させるためには、認証などの情報を提供する必要があります。以下のコードがその例です。

Properties props = new Properties();
props.setProperty("notificationAddress", "239.0.0.1");
props.setProperty("notificationPort", "31999");
props.setProperty("clusterName", "defaultCluster");
props.setProperty("user", "admin");
props.setProperty("password", "admin");
GridStore store = GridStoreFactory.getInstance().getGridStore(props);

クラスタ名、GriDBに接続するユーザーのユーザー名とパスワードが指定されているのが分かります。接続が確立されたので、作業するコンテナを選択しましょう。

Collection<String, Weather> coll = store.putCollection("col01", Weather.class);

ここでは、コンテナを参照するために coll という名前を使用します。

それでは、CSVファイルからGridDBコンテナにデータを書き込んでみましょう。

File file1 = new File("weather.csv");
Scanner sc = new Scanner(file1);
String data = sc.next();

while (sc.hasNext()){
    String scData = sc.next();
    String dataList[] = scData.split(",");
    String outlook = dataList[0];
    String temperature = dataList[1];
    String humidity = dataList[2];
    String windy = dataList[3];
    String play = dataList[4];
    
    Weather wc = new Weather();
    wc.outlook = outlook;
    wc.temperature = temperature;
    wc.humidity = humidity;
    wc.windy = windy;
    wc.play = play;
    
    coll.append(wc);
}

このコードでは、GridDB コンテナにデータを挿入します。

データを取得する

このデータを使って、アンサンブル学習の手法で様々な機械学習モデルを構築したいのです。つまり、GridDBコンテナからデータを引き出す必要があります。これを実現するのが以下のコードです。

Query<weather> query = coll.query("select *");
RowSet<weather> rs = query.fetch(false);
RowSet res = query.fetch();

ここでは、select * 文を使用して、Weather というGridDBコンテナに格納されているすべてのデータを選択しています。

機械学習モデルの適合

これで、データとアンサンブル学習法を用いて機械学習モデルを当てはめることができるようになりました。使用する手法は、AdaBoost、Bagging、Stacking、Votingなどです。

まず、これらのメソッドを実装するために、Weka API からライブラリをインポートしましょう。

import weka.classifiers.bayes.NaiveBayes;
import weka.classifiers.meta.Bagging;
import weka.core.Instances;
import java.io.BufferedReader;
import java.io.FileReader;
import weka.classifiers.functions.Logistic;
import weka.classifiers.meta.AdaBoostM1;
import weka.classifiers.meta.Stacking;
import weka.classifiers.trees.DecisionStump;
import weka.classifiers.trees.J48;
import weka.classifiers.meta.Vote;
import weka.classifiers.trees.RandomForest;
import weka.classifiers.trees.RandomTree;
import weka.core.converters.ConverterUtils.DataSource;
import weka.classifiers.functions.LinearRegression;
import weka.classifiers.Classifier;

次に、データセット用のバッファードリーダーを作成します。

BufferedReader bufferedReader
    = new BufferedReader(
        new FileReader(res));

// Create dataset instances
Instances datasetInstances
    = new Instances(bufferedReader);

Weka API の AdaBoost() 関数をインスタンス化して、AdaBoost アルゴリズムを使ってデータ上に機械学習モデルを実装するのに役立てましょう。

datasetInstances.setClassIndex(datasetInstances.numAttributes()-1);

/**
 * AdaBoost
 */
AdaBoostM1 learner1 = new AdaBoostM1();
learner1.setClassifier(new DecisionStump());
learner1.setNumIterations(100);
learner1.buildClassifier(datasetInstances);

次に、Baggingアルゴリズムを用いて、データセットに機械学習モデルを実装します。

/**
 * bagging
 */
Bagging learner2 = new Bagging();
learner2.setClassifier(new RandomTree());
learner2.setNumIterations(25);
learner2.buildClassifier(datasetInstances);

Weka API の Stacking() メソッドを使って、Stacking アルゴリズムを用いた機械学習モデルを実装してみましょう。

/**
 * stacking
 */
Stacking learner3 = new Stacking();
learner3.setMetaClassifier(new Logistic());
Classifier[] classifiers = {new J48(), new NaiveBayes(), new RandomForest()};
learner3.setClassifiers(classifiers);
learner3.buildClassifier(datasetInstances);

上記のコードでは、決定木、ナイーブベイズ、ランダムフォレストのアルゴリズムを使って作られた3つのモデルを積み重ねています。

そして最後に、Voting アルゴリズムがどのように機能するかを説明します。上記のベースとなる学習器や分類器、つまり決定木、ナイーブベイズ、ランダムフォレストの学習器の出力を集約したいと思います。以下のように Weka API の Vote() 関数を使用します。

/**
 * voting
 */
Vote vote = new Vote();
vote.setClassifiers(classifiers);
vote.buildClassifier(datasetInstances);

これらのモデルを評価するには、Weka API が提供する Evaluation() 関数を使用します。しかし、その前に以下のように関数をインポートしてください。

import weka.classifiers.Evaluation;

その後、関数をインスタンス化し、評価指標を取得することができます。

Evaluation eval = new Evaluation(datasetInstances);
eval.evaluateModel(classifiers, datasetInstances);

そして、評価指標のサマリーを出力することができます。

System.out.println(eval.toSummaryString());

予測する

我々は、ある人が屋外で遊ぶかどうかを知るために予測することができます。そのためには、データセットの最後のインスタンスを利用します。以下のように、Weka の ClassifyInstance() 関数を使用します。

Instance pred = datasetInstances.lastInstance();
double answer = classifier.classifyInstance(pred);
System.out.println(answer);

モデルのコンパイルと実行

モデルをコンパイルして実行するには、Weka API が必要です。以下のURLからダウンロードしてください。

http://www.java2s.com/Code/Jar/w/weka.htm

次に、gsadm ユーザでログインします。作成した .java ファイルを GridDB の bin フォルダに移動しましょう。移動先は以下の通りです。

/griddb_4.6.0-1_amd64/usr/griddb-4.6.0/bin

Linux端末で以下のコマンドを実行し、gridstore.jarファイルのパスを設定します。

export CLASSPATH=$CLASSPATH:/home/osboxes/Downloads/griddb_4.6.0-1_amd64/usr/griddb-4.6.0/bin/gridstore.jar

次に、以下のコマンドを使用して .java ファイルをコンパイルします。

javac -cp weka-3-7-0/weka.jar EnsembleLearningProject.java

以下のコマンドを実行して、生成された.classファイルを実行します。

java -cp .:weka-3-7-0/weka.jar EnsembleLearningProject

プロジェクトコードは正常に実行されるはずです。予測の出力は1.0になるはずで、これは屋外で遊ぶことができることを意味します。

ブログの内容について疑問や質問がある場合は Q&A サイトである Stack Overflow に質問を投稿しましょう。 GridDB 開発者やエンジニアから速やかな回答が得られるようにするためにも "griddb" タグをつけることをお忘れなく。 https://stackoverflow.com/questions/ask?tags=griddb

Leave a Reply

Your email address will not be published. Required fields are marked *