0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Java初心者】Wekaによる機械学習 10-ファイルを作らずArffデータ作成

Last updated at Posted at 2026-01-10

プログラムにWekaエンジンを組み込むシーンを考える

これまで、Arffをファイルで用意し、それで学習したり、テストをしたりしていました。

ただ、Javaプログラムの中でWekaエンジンを使って分類や予測をする場合、本番データはファイルに保存されない状態で取得することかあります。

このため、ファイルに出力せずArffを定義し、データを挿入する方法を考えてみました。

WekaのAPIサンプルにも同じようなことが書かれていますが、それにコメントをつけた程度のサンプルとなります。

Javaで書いてみました

今回も mini-wekaを使います。また、ログ出力のために、log4jを依存ライブラリーに組み込みます。
実行ディレクトリに log4j2.xml を入れています。

package example20260110;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.Utils;
import weka.core.converters.ArffLoader;
import weka.filters.Filter;
import weka.filters.unsupervised.attribute.StringToWordVector;
import weka.filters.unsupervised.instance.SparseToNonSparse;

/**
 *
 * @author XXX
 */
public class CreateInstances {

    static {
        System.setProperty("log4j.configurationFile", "log4j2.xml");
    }
    // log4jのlogger
    private static final Logger logger = (Logger) LogManager.getLogger(CreateInstances.class);

    public static void main(String[] args) throws Exception {
        logger.debug("開始");
        logger.debug("attributesは属性の一覧");
        ArrayList<Attribute> attributes = new ArrayList<>();
        logger.debug("定義します");

        logger.debug("0番目の属性は:IDという名前。数値。Double型が入る");
        attributes.add(new Attribute("ID"));
        logger.debug("1番目の属性:クラス分けなので、まず定義する");
        String[] attr2Classes = "日,月,火,水,木,金,土".split(",");
        ArrayList<String> attVals = new ArrayList<>();
        attVals.addAll(Arrays.asList(attr2Classes));
        logger.debug("1番目の属性:曜日という名前で上記で定義したクラスとする");
        attributes.add(new Attribute("曜日", attVals));
        logger.debug("2番目の属性:テキスト1 という名前のString型");
        attributes.add(new Attribute("テキスト1", (ArrayList<String>) null));
        logger.debug("3番目の属性:誕生日という名前の日付型");
        attributes.add(new Attribute("誕生日", "yyyy/MM/dd"));

        logger.debug("Instacesに収める。説明はMyInstancesでデータ数はまだゼロ");
        Instances newInstances = new Instances("MyInstances", attributes, 0);

        logger.debug("定義されたInstances\n" + newInstances);

        logger.debug("データを入れます");
        logger.debug("0番目のAttr:IDは1.0");
        double[] vals = new double[newInstances.numAttributes()];
        vals[0] = 1.0;
        logger.debug("1番目のAttr:曜日は月");
        vals[1] = attVals.indexOf("月");
        logger.debug("2番目のAttr:テキスト1は「テスト の データ」");
        vals[2] = newInstances.attribute(2).addStringValue("テスト");
        logger.debug("3番目のAttr:誕生日は「1960/02/03」");
        vals[3] = newInstances.attribute(3).parseDate("1960/02/03");
        logger.debug("dataに格納する。1.0は重み");
        var instance = new DenseInstance(1.0, vals);
        newInstances.add(instance);

        logger.debug("完成したデータ\n" + newInstances);

        //--
        logger.debug("ARFFLoader使い新しいInstancesを作ります");
        ArffLoader af = new ArffLoader();
        try (InputStream in = new ByteArrayInputStream(newInstances.toString().getBytes())) {
            af.setSource(in);
        }
        Instances arffloaderInstances = af.getDataSet();
        logger.debug("説明はarffloaderInstancesData");
        arffloaderInstances.setRelationName("arffloaderInstancesData");
        arffloaderInstances.clear();

        logger.debug("内容をクリアしたデータ\n" + arffloaderInstances);
        //--
        logger.debug("CSV文字列からデータを抽出して入れます");
        String myCsv = "1,水,文字列 の テスト,1970/11/14";
        logger.debug("データ:" + myCsv);

        String[] mydata = myCsv.split(",");

        int arffloaderNumArrriButes = arffloaderInstances.numAttributes();
        logger.debug("dataのnumAttributes:" + arffloaderNumArrriButes);
        double[] newvals = new double[arffloaderInstances.numAttributes()];
        for (int i = 0; i < arffloaderNumArrriButes; i++) {
            logger.debug(i + "番目:" + mydata[i]);

            // ポイント。Date型はnumeric型ともみなされるため最初に確認する
            if (arffloaderInstances.attribute(i).isDate()) {
                logger.debug("Dateです");
                newvals[i] = arffloaderInstances.attribute(i).parseDate(mydata[i]);
                continue;
            }

            if (arffloaderInstances.attribute(i).isNumeric()) {
                logger.debug("Numericです");
                newvals[i] = Double.parseDouble(mydata[i]);
                continue;
            }

            if (arffloaderInstances.attribute(i).isNominal()) {
                logger.debug("Nominalです");
                newvals[i] = arffloaderInstances.attribute(i).indexOfValue(mydata[i]);
                continue;
            }

            if (arffloaderInstances.attribute(i).isString()) {
                logger.debug("Stringです");
                newvals[i] = arffloaderInstances.attribute(i).addStringValue(mydata[i]);
                continue;
            }
            logger.debug("欠損値とします");
            newvals[i] = Utils.missingValue();
        }

        Instance newinstance = new DenseInstance(1.0, newvals);

        arffloaderInstances.add(newinstance);
        logger.debug("完成したArffデータ\n" + arffloaderInstances);
    }
}

実行結果

2026/01/10 21:18:50.190 DEBUG - 開始
2026/01/10 21:18:50.191 DEBUG - attributesは属性の一覧
2026/01/10 21:18:50.191 DEBUG - 定義します
2026/01/10 21:18:50.191 DEBUG - 0番目の属性は:IDという名前。数値。Double型が入る
2026/01/10 21:18:50.192 DEBUG - 1番目の属性:クラス分けなので、まず定義する
2026/01/10 21:18:50.192 DEBUG - 1番目の属性:曜日という名前で上記で定義したクラスとする
2026/01/10 21:18:50.192 DEBUG - 2番目の属性:テキスト1 という名前のString型
2026/01/10 21:18:50.192 DEBUG - 3番目の属性:誕生日という名前の日付型
2026/01/10 21:18:50.196 DEBUG - Instacesに収める。説明はMyInstancesでデータ数はまだゼロ
2026/01/10 21:18:50.200 DEBUG - 定義されたInstances
@relation MyInstances

@attribute ID numeric
@attribute 曜日 {日,月,火,水,木,金,土}
@attribute テキスト1 string
@attribute 誕生日 date yyyy/MM/dd

@data

2026/01/10 21:18:50.200 DEBUG - データを入れます
2026/01/10 21:18:50.200 DEBUG - 0番目のAttr:IDは1.0
2026/01/10 21:18:50.200 DEBUG - 1番目のAttr:曜日は月
2026/01/10 21:18:50.200 DEBUG - 2番目のAttr:テキスト1は「テスト の データ」
2026/01/10 21:18:50.200 DEBUG - 3番目のAttr:誕生日は「1960/02/03」
2026/01/10 21:18:50.200 DEBUG - dataに格納する。1.0は重み
2026/01/10 21:18:50.202 DEBUG - 完成したデータ
@relation MyInstances

@attribute ID numeric
@attribute 曜日 {日,月,火,水,木,金,土}
@attribute テキスト1 string
@attribute 誕生日 date yyyy/MM/dd

@data
1,月,テスト,1960/02/03
2026/01/10 21:18:50.202 DEBUG - ARFFLoader使い新しいInstancesを作ります
2026/01/10 21:18:50.204 DEBUG - 説明はarffloaderInstancesData
2026/01/10 21:18:50.204 DEBUG - 内容をクリアしたデータ
@relation arffloaderInstancesData

@attribute ID numeric
@attribute 曜日 {日,月,火,水,木,金,土}
@attribute テキスト1 string
@attribute 誕生日 date yyyy/MM/dd

@data

2026/01/10 21:18:50.204 DEBUG - CSV文字列からデータを抽出して入れます
2026/01/10 21:18:50.205 DEBUG - データ:1,水,文字列 の テスト,1970/11/14
2026/01/10 21:18:50.205 DEBUG - dataのnumAttributes:4
2026/01/10 21:18:50.206 DEBUG - 0番目:1
2026/01/10 21:18:50.206 DEBUG - Numericです
2026/01/10 21:18:50.206 DEBUG - 1番目:水
2026/01/10 21:18:50.206 DEBUG - Nominalです
2026/01/10 21:18:50.206 DEBUG - 2番目:文字列 の テスト
2026/01/10 21:18:50.206 DEBUG - Stringです
2026/01/10 21:18:50.206 DEBUG - 3番目:1970/11/14
2026/01/10 21:18:50.206 DEBUG - Dateです
2026/01/10 21:18:50.207 DEBUG - 完成したArffデータ
@relation arffloaderInstancesData

@attribute ID numeric
@attribute 曜日 {日,月,火,水,木,金,土}
@attribute テキスト1 string
@attribute 誕生日 date yyyy/MM/dd

@data
1,水,'文字列 の テスト',1970/11/14

感想

  • ポイントとしてソースに書いてありますが、Data型の判別に苦労しました
  • 作りたいArffの属性定義は、Yamlデータなどで書いておき、それを読ませることも面白いかもしれません
  • ただ、空データのArffを手で書いて、読み込ませることが現実的かもしれません
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?