引数指定の際のofとカンマ区切りの細かい話

最近ちょっと更新が途絶えてましたが元気です。

さて、昔、人にプログラムをあげた時に
s = sum(of a -numeric- e) ;
みたいな書き方を入れていたんですが、なんですかこれ??って
質問が来たことがあります。

特定の関数で、複数の引数を指定するときの方法として
カンマで区切って列記する方法と、ofで指定する方法があります
(併用もできます)。

が、うっかりしていると慣れた人でもハマりやすい罠があるので
おさらいしてみようと思います。

テストデータ

data Q1;
 x1=1;x2=2;x3=3;x4=4;x5=5;
run;

まずは基本。
x1からx5まで全部の合計をだすには例えば以下のように書きます。

data A1;
 set Q1;
 y1 = sum(x1,x2,x3,x4,x5);
 y2 = sum(of x1-x5);
 put (y1-y2) (=/);
run;

ログに
y1=15
y2=15

とでます。あってます。

y1は基本で、対象の変数を全部カンマ区切りで指定します。
y2はofを使用しています。
これから詳しく見ていきますが、ofを使うと

①of x1-x10  (変数の末尾の連番指定)
②of id--y (データセットの格納順 idからyまでの間にある変数全部)
③of _all_ や of _numeric_; や of _character_;(全変数や全数値変数や全文字変数)
④of ax{*} (配列を指定)
⑤of x: (コロンモディファイア指定→xから始まる変数名のもの全て)
⑥of x1 x3 x5 (変数列記 変数だけでなく①から⑤までのものを全て空白区切りで列記できる)

といった指定が可能になります(他にもあったら教えてください)。

で、とても便利なのですが、よくやってしまうのが

data A3;
 set Q1;
 y3 = sum(x1-x5);
 put y3=;
run;

結果は
y3=-4

なんで値がマイナスになっているかというと
of をつけないと x1からx5を引いた単一の値がsum関数の対象になってしまってるんですね。

続いて、複数の変数リストを指定する場合ですが

data A4;
 set Q1;
 y4 = sum(of x1-x2 x4-x5);
 y5 = sum(x1-x2 , x4-x5);
 y6 = sum(of x1-x2 , of x4-x5);
 y7 = sum(of x1-x2 , x4 , x5);
 put (y4-y7) (=/);
run;

結果は
y4=12
y5=-2
y6=12
y7=12

y4のようにof の後、空白でリストを区切ればOKです。
先ほどと同様にy5のようにしてしまうと x1引くx2とx4引くx5の値の合計値がでてしまいます。
意外と盲点なのが、y6のようにカンマで区切っても、その中ごとにofをつけてやれば
コードとして正しいということなんですね。
同様にy7のようにof指定とカンマ区切りを併用することもできます。
y4のようにカンマつけなきゃ一つのofで済む話なのに、なんで敢えてこういうことを書くかというと
例えば、プログラム仕様書の条件式や指定変数からコードを自動生成したりする場合、
仕様書の記載法と生成ロジックを考えなきゃいけないわけですが、そういう時に
こういう書き方でも式が正しく成立している(していない)といったケースを多く知ってると意外と役立つと思います。

で、次は、対象の変数に個々にマイナスをかけて合計したい場合です。
質問方向が反転の項目とかでそういうことありますよね。

以下を実行すると

data A5;
 set Q1;
 y8 = sum(-x1,-x2,-x3);
 y9 = sum(of -x1 -x2 -x3);
 put (y8-y9) (=/);
run;

結果は
y8=-6
y9=.

となってy8は正しいですがy9は正しく計算されません。
ofの場合、カンマ区切りと違ってマイナスつけはできないのです。

マイナスつけができないというより、もっと広く言えば
以下のように

data A6;
 set Q1;
 y10 = sum(x1+x2,x1*x2);
 y11 = sum(of x1+x2 x1*x2);
 put (y10-y11) (=/);
run;

結果は(y11のせいでエラーになりますが個別にだすと)

y10=5
y11=.

つまり、ofは変数の一括指定のためのキーワードで計算式を引数には
とれないうことです


さて次は、of使うといろいろできるよという例ですね

data A7;
 set Q1;
 array x{*} x: ;
 y11 = sum(of x{*});
 y12 = sum(of x{*} , x2 , of x3-x5  , of x:);
 put (y11-y12) (=/);
run;

結果
y11=15
y12=44

y11についてはカンマで区切らなければofは一個で、後は空白区切りでOKですからね。


最後は冒頭で述べた例に戻ります。
以下のテストデータがあり

data Q2;
 a=1;b=2;c=3;d='AAA';e=4;
run;

--を使うことによって変数の格納順を利用できます。

data A8;
 set Q2;
 y13= sum(of a--c);
 put y13 = ;
run;

結果
y13=6

で、以下の例のy13のように_numeric_としてデータセット内の
全数値型変数を対象にできるのですが、

さらにそれを--と組み合わせてy14のようにかくと


data A9;
 set Q2;
 y14 = sum(of _numeric_);
 y15 = sum(of a -numeric- e);
 put (y14-y15) (=/);
run;

y14=10
y15=10

aからeの間に格納されている変数のうち、数値型のものに
限るという指定ができます。

ながながと細かい話でした

0 件のコメント:

コメントを投稿