JavaとGridDBを用いた気温に基づくアイスクリームの売上予測

はじめに

線形回帰分析は,別の変数の値に基づいて変数の値を予測するのに役立つ.予測される変数は「従属変数」として知られ,他の変数を予測するために使用される変数は「独立変数」として知られる.線形回帰は,1つまたは複数の独立変数との1次方程式の係数を推定する.線形回帰は、予測された出力値と期待された出力値の差を最小化する直線を作成します。

この記事では、JavaとGridDBを使用して、温度に基づいてアイスクリームの販売数を予測する線形回帰モデルを作成します。温度 が独立変数で アイスクリームの売上 が従属変数になります。

パッケージのインポート

まず、GridDBと連携するためのJavaライブラリをインポートしましょう:

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


import java.util.Scanner;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

データをGridDBに書き込みます

使用するデータセットは、異なる温度値に対するアイスクリームの販売数を示しています。このデータセットはトレーニング用とテスト用の2つに分けられています。しかし、トレーニング・データセットをGridDBに移したいです。GridDBには、クエリの高速化など様々なメリットがあるからです。データを格納するためのGridDBコンテナを定義します。コンテナは以下のようにJavaクラスとして定義します:

 static class SalesData {
    @RowKey int id;
        double temperature;
    double icecreamsales;
     }

GridDBコンテナは、SQLのテーブルと見なすことができます。

GridDBコンテナにデータを書き込むには、まずGridDBに接続する必要があります。java.utilパッケージからPropertiesファイルを作成し、以下のようにkey:value`ペアの構文を使ってGridDBの認証情報を入力します:

Properties props = new Properties();
props.setProperty("notificationMember", "127.0.1.1:10001");
props.setProperty("clusterName", "myCluster");
props.setProperty("user", "admin");
props.setProperty("password", "admin");
GridStore store = GridStoreFactory.getInstance().getGridStore(props);

また、データベースを操作するために GridStore 型の変数 store を作成しました。

トレーニングデータセットのGridDBへの格納

トレーニングデータセットをGridDBに格納したいです。まず、データ行を SalesData クラスのインスタンスとして定義します。

SalesData  row1 = new SalesData();
row1.id=1;
row1.temperature=14.2;
row1.icecreamsales=215;

SalesData  row2 = new SalesData();
row2.id=2;
row2.temperature=16.4;
row2.icecreamsales=325;

SalesData  row3 = new SalesData();
row3.id=3;
row3.temperature=11.9;
row3.icecreamsales=185;

SalesData  row4 = new SalesData();
row4.id=4;
row4.temperature=15.2;
row4.icecreamsales=332;

SalesData  row5 = new SalesData();
row5.id=5;
row5.temperature=18.5;
row5.icecreamsales=406;

SalesData  row6 = new SalesData();
row6.id=6;
row6.temperature=19.4;
row6.icecreamsales=412;

SalesData  row7 = new SalesData();
row7.id=7;
row7.temperature=25.1;
row7.icecreamsales=614;

SalesData  row8 = new SalesData();
row8.id=8;
row8.temperature=23.4;
row8.icecreamsales=544;

SalesData  row9 = new SalesData();
row9.id=9;
row9.temperature=18.1;
row9.icecreamsales=421;

SalesData  row10 = new SalesData();
row10.id=10;
row10.temperature=22.6;
row10.icecreamsales=445;

SalesData  row11 = new SalesData();
row11.id=11;
row11.temperature=17.2;
row11.icecreamsales=408;

データを格納する GridDB コンテナ SalesData を選択します:

Collection<String, SalesData> sd= store.putCollection("SalesData", SalesData.class);

コンテナにデータを追加するには put() 関数を使用します:

sd.put(row1);
sd.put(row2);
sd.put(row3);
sd.put(row4);
sd.put(row5);
sd.put(row6);
sd.put(row7);
sd.put(row8);
sd.put(row9);
sd.put(row10);
sd.put(row11);

学習データの取得

GridDBから学習データを取得し、機械学習モデルのフィッティングに使用します。以下のように、SalesData コンテナ内の全てのデータを取得する TQL クエリを作成します:

Query<salesdata> query = sd.query("select *");
RowSet</salesdata><salesdata> rs = query.fetch(false);

while (rs.hasNext()) {
SalesData sd1 = rs.next();
double[][] data = {{sd1.temperature},{sd1.icecreamsales}};
}</salesdata>

TQL 文 select * を使って、コンテナに格納されているすべてのデータを取得しました。データは data という名前の 2D 配列に格納されます。

Weka インスタンスの作成

Weka 機械学習ライブラリを使用して、線形回帰モデルをフィットします。したがって、データを Weka インスタンスに変換する必要があります。まずデータセットの属性を作成し、FastVector データ構造に格納します。それからデータセットの Weka インスタンスを作成します。

まず、属性とインスタンスを格納するデータ構造を作成しましょう:

int numInstances = data[0].length;
FastVector atts = new FastVector();
List<instance> instances = new ArrayList</instance><instance>();</instance>

次に、forループを作成し、それを使ってデータ項目を繰り返し、FastVectorデータ構造に属性を入力します:

for(int dim = 0; dim < 2; dim++)
    {
        Attribute current = new Attribute("Attribute" + dim, dim);

        if(dim == 0)
        {
            for(int obj = 0; obj < numInstances; obj++)
            {
                instances.add(new SparseInstance(numInstances));
            }
        }

        for(int obj = 0; obj < numInstances; obj++)
        {
            instances.get(obj).setValue(current, data[dim][obj]);
            
        }
        atts.addElement(current);
    }

Weka の Instance クラスを使ってインスタンスを生成し、インスタンス変数 newDataset に格納しましょう。

Instances newDataset = new Instances("Dataset", atts, instances.size());

線形回帰モデルのフィット

データインスタンスの準備ができたので、機械学習モデルをあてはめることができます。その前に、Weka から必要なライブラリをインポートしましょう:

import weka.classifiers.Classifier;
import weka.classifiers.Evaluation;
import weka.core.Attribute;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.SparseInstance;

モデルに入力する前に、データセットのクラス属性を指定してみましょう:

newDataset.setClassIndex(1);

Weka ライブラリの LinearRegression() 関数を使って、線形回帰分類器をあてはめることができます:

newDataset.setClassIndex(1);
for(Instance inst : instances)
newDataset.add(inst);
Classifier classifier = new weka.classifiers.functions.LinearRegression();

classifier.buildClassifier(newDataset);
        System.out.println(classifier);

線形回帰モデルの準備ができました!

モデルの評価とテスト

トレーニングデータセットを使ってモデルを評価し、テストデータセットを使ってモデルをテストする。data2`という名前の配列を定義し、テストデータを格納します:

    static double[][] data2 = {{14.2,16.4,11.9},{215,325,185}};

データをモデルに入力するには、まずデータを Weka インスタンスに変換する必要があります。属性は FastVector データ構造に、インスタンスは ArrayList に格納します。これらを定義しましょう:

int numInstances2 = data2[0].length;
        FastVector atts2 = new FastVector();
        List<instance> instances2 = new ArrayList</instance><instance>();</instance>

for`ループでデータを繰り返し、FastVectorに属性を入力します:

for(int dim2 = 0; dim2 < 2; dim2++)
    {
        Attribute current2 = new Attribute("Attribute" + dim2, dim2);

        if(dim2 == 0)
        {
            for(int obj2 = 0; obj2 < numInstances2; obj2++)
            {
                instances2.add(new SparseInstance(numInstances2));
            }
        }

        for(int obj2 = 0; obj2 < numInstances2; obj2++)
        {
            instances2.get(obj2).setValue(current2, data2[dim2][obj2]);
            
        }
        atts2.addElement(current2);
    }

トレーニングデータセットのインスタンスを作成し、インスタンス変数 newDataset2 に格納します:

    Instances newDataset2 = new Instances("Dataset", atts2, instances2.size());

モデルに入力する前に、データセットのclass属性を指定してみましょう:

newDataset2.setClassIndex(1);

次に、データをモデルに入力し、評価サマリーを印刷します:

for(Instance inst2 : instances2)
       newDataset2.add(inst2);

       Evaluation eval = new Evaluation(newDataset);
        eval.evaluateModel(classifier, newDataset2);
    
        System.out.println(eval.toSummaryString());

予測を立てる

これで、我々のモデルを使って、特定の温度値におけるアイスクリームの販売数を予測できるようになりました。テストデータセットの最後のインスタンスを使って予測しましょう:

Instance pd = newDataset2.lastInstance();
double value = classifier.classifyInstance(pd);              
    System.out.println(value);

モデルの実行

以下の URL から Weka API をダウンロードしてください:

http://www.java2s.com/Code/Jar/w/weka.htm I will be using Weka version 3.7.0.

ターミナルで以下のコマンドを実行して、gridstore.jarweka-3-7-0.jar ファイルのクラスパスを設定します:

export CLASSPATH=$CLASSPATH:/usr/share/java/gridstore.jar
export CLASSPATH=$CLASSPATH:/mnt/c/Users/user/Desktop/weka-3.7.0.jar

上記のコマンドはファイルの場所によって変更される可能性があることに注意してください。

次に、以下のコマンドを実行して .java ファイルをコンパイルします:

javac IceSales.java

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

java IceSales

このモデルの相関係数は0.9456でした。相関値は-1から1の間で、1は非常に強い線形相関、-1は逆線形関係、0は関係なしを意味します。このモデルは、198のアイスクリーム売上も予測しました。

ブログの内容について疑問や質問がある場合は 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 *