JavaとGridDBを用いたテキスト分類器

テキストデータは、電子メール、チャットでの会話、ソーシャルメディア、Webサイトなど、あらゆるところに存在します。テキストデータには多くの情報が含まれていますが、その非構造化データの性質上、情報を抽出することが困難な場合があります。非構造化データからインサイトを抽出するには、データの分類に多くの時間とコストがかかります。

自然言語処理(NLP)技術を用いたテキスト分類器は、高速でスケーラブル、かつコスト効率の高い方法でデータを構造化する代替方法を提供します。

テキストの分類は、テキストをグループに分けて整理することで、「テキストタグ付」または「テキスト分類」とも呼ばれます。自然言語処理では、テキストデータを分析し、その内容に応じてあらかじめ定義されたカテゴリーに分類することが可能です。

今回は、JavaとGridDBを使って、テキスト分類器を実装します。テキスト分類器の目的は、メールをspamとhamのどちらかに分類することです。

全ソースとデータはこちらでご覧いただけます。
https://github.com/griddbnet/Blogs/tree/text-classifier

データについて

使用するデータは、電子メールがスパムかハムかを示すものです。データは mssspam.csv という名前のカンマ区切り値 (CSV) ファイルに保存されています。データには spamclasstext という2つのフィールドがあります。最初のフィールドはメールがスパム (迷惑メール) かハム (迷惑メールでないもの) かを示しており、spamham の2つの値のみを取ります。2つ目のフィールドはメールの本文を表しています。

GridDBにデータを格納する

CSVファイルから直接データを利用することも可能です。しかし、GridDBには、データの整理やクエリの性能向上など、多くの利点があります。そこで、CVSファイルからGridDBにデータを移行することにします。

まずは、GridDBにデータを格納するために、いくつかのライブラリをインポートしてみましょう。

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クラスを作成しましょう。

public static class EmailClassification{
    @RowKey String spamclass;
    String text;
}

上記の静的クラスは、2つの変数を持ちます。この 2 つの変数は、GridDB コンテナの 2 つのカラムに対応します。

GridDBにデータを移動するためには、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);

上記の内容を、お使いのGridDBの仕様に置き換えてください。

これで、データを格納するコンテナを選択できるようになりました。

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

コンテナのインスタンスが作成されました。このインスタンスは、コンテナを参照するために使用することができます。

それでは、CSVファイルからデータを取り出し、GridDBに挿入してみましょう。

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

while (sc.hasNext()){
    String scData = sc.next();
    String dataList[] = scData.split(",");
    String spamclass = dataList[0];
    String text = dataList[1];

    EmailClassification ec = new EmailClassification();
    ec.spamclass = spamclass;
    ec.text = text;

    coll.append(ec);
}

上記のコードでは、CSV ファイルからデータを取り出し、GridDB コンテナに挿入しています。

データを取得する

このデータをテキスト分類に利用したいので、GridDBコンテナからデータを取り出してみましょう。

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

select *文は、GridDBコンテナに格納されているデータをすべて選択するのに役立ちました。

テキスト分類の実装

データの準備ができたので、次はテキスト分類器を実装していきます。まず、テキスト分類器を実装するために使用するライブラリをインポートしましょう。

import java.io.*;
import weka.core.*;
import java.util.List;
import java.util.Random;
import weka.filters.Filter;
import java.util.ArrayList;
import weka.core.Instances;
import weka.core.FastVector;
import weka.classifiers.Evaluation;
import weka.classifiers.bayes.NaiveBayes;
import weka.classifiers.meta.FilteredClassifier;
import weka.core.converters.ArffLoader.ArffReader;
import weka.filters.unsupervised.attribute.StringToWordVector;

データセットを読み込むためのバッファードリーダーを作成します。

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

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

これでテキスト分類器を実装することができました。ここでは、StringToWordVector フィルタ (テキストを特徴ベクトルの形で表現するためのもの) と NaiveBayes 分類器 (学習を容易にするためのもの) を組み合わせて使用します。

datasetInstances.setClassIndex(0);
StringToWordVector filter = new StringToWordVector();
filter.setAttributeIndices("last");
FilteredClassifier classifier = new FilteredClassifier();
classifier.setFilter(filter);
classifier.setClassifier(new NaiveBayes());
classifier.buildClassifier(datasetInstances);
System.out.println(classifier);

データセットのクラスは、最初の属性に設定されています。次にフィルタを作成し、テキストから特徴量に変換する属性を設定します。次に、FilteredClassifier クラスのオブジェクトを作成し、先ほどのフィルタと新しい NaiveBayes 分類器を追加します。データセットは、最初の属性としてクラス、2番目の属性としてテキストを持つ必要があります。

モデルを評価する

これでモデルを評価し、そのパフォーマンス統計を見ることができます。次のコードはそのための助けになります。

Evaluation eval = new Evaluation(datasetInstances);
eval.crossValidateModel(classifier, datasetInstances, 4, new Random(1));
System.out.println(eval.toSummaryString());

このコードでは、テキスト分類器の評価指標を返します。

テキストの分類

さて、モデルの準備ができたので、それを使って予測をしてみましょう。予測を行う目的は、メールをスパムかハムに分類することです。

データセットの最後のインスタンスをスパムとハムのどちらかに分類してみましょう。次のコードはそれを示すものです。

Instance pred = datasetInstances.lastInstance();
double answer = classifier.classifyInstance(pred);
System.out.println("Class predicted: " + pred.classAttribute().value((int) 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 TextClassification.java

最後に、以下のコマンドを実行することで生成される .class ファイルを実行します。

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

テキスト分類器は、メールを「ハム」と正しく分類します。

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