Help us understand the problem. What is going on with this article?

Bayes Server で missing valueに対応するには?

More than 1 year has passed since last update.

missing value

欠損値を扱う場合、補完をする場合とそのままNAとして扱う場合があります。
bayesean networkの場合はそれ自身が補完に利用することもできるため、NAとしてそのまま渡したい場合があります。

Bayes Serverでは以下のように、欠損値をそのまま扱うことができます。
基本的にはEvidenceがすべてそろわなくても、学習、推論ができるという事なので、他のモデルよりも欠損値の扱いは、straightだと思います。

Tutorial 7 - Missing data

GUI では

例えば、Tutorialにあるような、空白セルのあるExcelファイルを読み込んでも大丈夫です。
image.png

Batchクエリーなどの画面で見られますデータはこのように空白になったまま読み込まれています。

image.png

プログラム(C#)では

ネイティブのC#のコードを見ると、以下のように まずdataReaderCommandというものでevidenceReaderCommandに渡すDataTableを作成しています。

            var dataReaderCommand = CreateDataReaderCommand();
            var variableReferences = network.Variables.Select(v => new VariableReference(v, ColumnValueType.Name, v.Name)).ToArray();
            var evidenceReaderCommand = new EvidenceReaderCommand(
                dataReaderCommand,
                variableReferences,
                new ReaderOptions());

CreateDataReaderCommandという関数は以下のようにDataTableを単純に作成しているだけのように見えます。

            var data = new DataTable();
            data.Columns.Add("A", typeof(string));
            data.Columns.Add("B", typeof(string));
            data.Columns.Add("C", typeof(string));
            data.Rows.Add("True", "False", "True");
            data.Rows.Add("True", "True", "True");

DataTableは、DataRowコレクションの要素として持っていますが、DataRow自体はコレクションではなくてIItemArrayというインターフェイスを持っているだけのようです。
Columnが先に指定されているわけですから、列方向には、NULLを要素に入れてもいけそうな雰囲気があります。

単純なList<>などのコレクションだと普通はNULLは入らないのですが、どうやって実装するべきかは良くわかりません。(C#のdoubleにはNaNがあるんですが、これを使うとはちょっと思えない)

実はC#は使っていないので、ここは宿題にします。たぶんNULLいけそうな雰囲気ってことだけ。

プログラム(R)では

Rから呼び出しているのですが、まずそのラップ先であるJavaはどうか?
同じコードのJava版を見ますと、以下のように、同じようなインターフェイスを持っているようです。

        DataTable data = new DataTable();
        DataColumnCollection columns = data.getColumns();
        columns.add("A", String.class);
        columns.add("B", String.class);
        columns.add("C", String.class);
        DataRowCollection rows = data.getRows();
        rows.add("True", "False", "True");
        rows.add("True", "True", "True");

Rから同じことをするには、ここにあるように、まず同じdata.frameを作ります。
注意点はRのdata.frameにはNULLは入れられず、NAが欠損値として扱われることです。

RからJavaラッパーを呼ぶヘルパーコードが公開されていますが、以下のRのdata.frameからJavaラッパー経由でdataTableを作る関数が、ややおおざっぱすぎます。

toDataTable <- function(df) {

  dt <- new(DataTable)

  dfTypes <- sapply(df, typeof)
  dfClasses <- sapply(df, class)
  dfNames <- names(df)

  columnCount <- length(dfNames)

  for (i in 1:columnCount)
  {
    dt$getColumns()$add(dfNames[i], toJavaClass(dfTypes[i], dfClasses[i]))
  }

  for (r in 1:nrow(df))
  {
    values <- lapply(df[r,], function(x) {
      return(toJavaObject(x))
    })

    values <- .jarray(values, contents.class = "java.lang.Object")
    dt$getRows()$add(values)
  }

  return(dt)

}

このままNA入りのdata.frameを渡すと、なぜか”NaN入りのDataTableは受け付けないぞ!"というエラーで怒られます。

これだと、toJavaObject()内では、NAを無理やりJavaのNAに変換しようとするようなので、うまくNULLとして伝わっていないようです。
差し当たり、以下のように欠損値ぽいものが来たら、全部NULLに変換してしまうことにしたら、うまくいきました。

        values <- lapply(df[r,], function(x) {
            if (!is.null(x) & !is.nan(x) & !is.na(x)) {
                return(toJavaObject(x))
            } else {
                return(NULL)
            }
        })

本当にNULLでいいのかどうか、C#で叩いてみて検証も後日行いたいと思います。

Masutani
データサイエンティストをしています。地理空間情報系の処理を主に扱っています。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away