2014年7月9日水曜日

FCMPプロシジャと行列計算


FCMPプロシジャはユーザー定義関数を作成するだけでなく、簡単な行列計算をしたい場合にも便利です。

簡単なサンプルとして、以下の連立方程式をFCMPプロシジャによる行列計算で求めてみたいと思います。








ちなみに行列で解を求める式はこんな感じでしょうか。




まずは式の数字部分をデータセット化しておきます。
data DT1;
input A B C D;
cards;
1 1 1 6
2 4 3 19
5 3 2 17
;
run;

 A  B  C  D 
 1 1 1  6
 2 4  3 19
 5 3 2 17


FCMPプロシジャで行列により解を求めます。
proc fcmp;

   *** ① 計算用の配列を定義 ;
   array _ABC [3, 3]   / nosym;
   array _D     [3, 1]   / nosym;
   array _INV  [3, 3]   / nosym;
   array _OUT [3]      / nosym;

   *** ② 計算するデータセットを配列に格納 ;
   rc = read_array("DT1", _ABC, "A","B","C");
   rc = read_array("DT1", _D    , "D");

   *** ③ 行列計算して解を出す ;
   call inv(_ABC, _INV);        * 逆行列 ;
   call mult(_INV, _D, _OUT);  * 行列の積 ;

   *** ④ 結果をデータセットに書き出す ;
   rc = write_array("OUT1", _OUT, "RESULT") ;

run;

データセットOUT1
 RESULT 
 1
 2
 3

 x=1, y=2, z=3 という結果が得られました。


解説
処理のおおまかな流れは、計算用のデータセットを配列に格納 → その配列を使って行列計算 → 出た解をデータセットに吐き出す。。といった感じです。


①まず行列計算で必要になる配列を定義しておきます。

NOSYMをつけると配列に変数を割り当てる必要がなくなります。
(DATAステップのARRAYでいうところの一時配列_TEMPORARY_みたいなもの)


READ_ARRAY関数でデータセットDT1を配列に格納します。

READ_ARRAY("読み込むデータセット",  "読み込んだデータを格納する配列",  "読み込む変数1",  "読み込む変数2"…)


③読み込んだ配列に対して、行列計算して解を出します。

逆行列    … CALL INV( 配列,  結果を格納する配列 )
行列の積 … CALL MULT( 配列1, 配列2,  結果を格納する配列 )


WRITE_ARRAY'関数で解をデータセットOUT1に格納します。

WRITE_ARRAY("出力後データセット名",  "出力する配列",  "出力時の変数名1",  "出力時の変数名2"…)



0 件のコメント:

コメントを投稿