[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[dennou-ruby:001292] Re: initialize mathod



西澤様:

堀之内です。

> しかし、欠損値処理をする NArray を作ろうと思ったら、継承をつかわ
> ず、NArray をラッピングする手もあります。つまり、@xxxxxx に加えて
> 本体も、内部変数の NArray のオブジェクトとして陽に持つ。そのほう
> が随分作りやすく、ソースコードの見通しも良くなるだろうと思います
> が如何でしょう。もとの NArray のメソッドのうち、そのまま使えるも
> のについては、継承しなくても、まとめて簡単に「委譲」できますし。

考えてみると、継承した場合にどうすれば欠損値処理が出来るのかわか
りません。もともと NArray に mask を導入して貰った時から(私がパッ
チを作りました)、データとマスクを内部変数にもつ欠損値処理クラス
を作ることを想定してました。ちなみに、初期化のイメージはこんな感
じ:

   a = NArrayMiss.new( nary, 'miss_val' => 999.0 )
   a = NArrayMiss.new( nary, 'valid_range' => [-1e33,1e33] )
   a = NArrayMiss.new( nary, 'valid_min' => -1e33 )
   a = NArrayMiss.new( nary, 'valid_max' => 1e33 )

   a = NArrayMiss.new( nary, mask )   # nary と mask は同じ形の NArray

つまり、もとの NArray データ(上ではnary)と、その中での欠損値指定
を与えて、内部的に @xxxxxx を生成して持っておく。欠損値指定は上記
の全種類に対応できる必要があります。

もちろん、単項演算や2項演算では欠損値をよけて演算します。2項演
算ではこんな感じ:

 def mlt(a, b)  # あとで演算子 * に割り当て
   mask = a.mask | b.mask
   ac,bc = b.coerce(a)
   data = ac.data.dup    # data は中身のデータを dup せずに返すとする
   data[mask] = ac.data[mask] * bc.data[mask]
   NArrayMiss.new(data, mask)
 end

ここで注意すべきは、欠損部分に入っている値が大きくてもオーバーフ
ローしないよう、欠損部分は演算すべきではないということです。

なお、欠損値を取り込んで NArray に変換するメソッドも必要です。こ
んな感じ。

  nary = a.to_na( miss_val )
  nary, miss_val = a.to_na_set_miss

欠損値に miss_val を代入した NArray を返す。後者は、データがとる
値の範囲の外に(大きく外れたところ)に欠損値を自動設定して代入し、
それも返す。

あと、非欠損部分に関する平均等が取れるように必要な(新しい)メソッ
ドも用意する。どういうことかと言うと、欠損が無い場合は、

  nary.sum(0) / nary.shape[0]

だけで1次元目の平均が取れるけど、欠損があれば分母は定数でないの
で、欠損部分除いて数えて配列で返すメソッドが必要だということです。
shape の定義は今まで通りであるべきなので、別の名前が必要(例えば
count_valid とか?):

  a.sum(0) / a.count_valid(0)

あと、欠損でないのが最低何個ないといけないというしばりも、設けら
れないといけない:

  a.sum(0) / a.count_valid(0, 'min_count' => 5)

あるいは、

  a.sum(0, 'min_count' => 5) / a.count_valid(0)

(sum と count_valid の引数の仕様は同じにする。2項演算では mask 
の "or" を取るルールより、いずれも
    a.sum(0, 'min_count' => 5) / a.count_valid(0, 'min_count' => 5)
と同じ)

--
堀之内 武