ラベル コロンモディファイア の投稿を表示しています。 すべての投稿を表示
ラベル コロンモディファイア の投稿を表示しています。 すべての投稿を表示

inとコロン(:)の合わせ技、文字型に対する接頭一致

リンクサイト「SAS忘備録」で
「条件式(IF/WHERE)におけるINオペレータの小技」
http://sas-boubi.blogspot.jp/2014/01/in.html

の中で

data DT1;
  do V=1 to 6 ;
   output;
  end;
run;
proc print data=DT1 noobs;
 where  V in (1, 3 : 5) ;
run;

とすると






となるように、inの中での3:5が3~5の範囲指定として実行されるという技を紹介されていました。

今回は、文字型について、括弧の中にコロンを入れるのではなく外に出したら、どうなるかを見てみます。

data Q1;
length X $20.;
X='ABCD';output;
X='ABCDEF';output;
X='DEFG';output;
X='AB';output;
X='BBC';output;
X='DBC';output;
run;










こういうデータがあって

data A1;
 set Q1;
 where X in:('ABC','DE','DB');
run;

としたら、どうなるでしょうか?

答えは








です。
これはつまり、Xの値がABCから始まるか、DEから始まるか、DBから始まる場合に抽出しているということです。

keepやdropステートメント等で X_:とするとX_から始まる変数名の変数が対象になったり
set X_:とするとX_から始まるデータセット名のデータセットが対象になったりするのと同じ
前方一致を意味するコロンな使い方です。

なんでinじゃなくて

data A2;
 set Q1;
 where X=:'ABCDE';
run;

でも使え、





こうなります。

コロンは色々使える分、ややこいですね



コロンモディファイアでデータセットオプションを使うと全部にかかる

今回の内容はあまり大したことない話です。
「:」を使った前方一致でデータセットを一括りに処理できるという話を以前しましたが

それに対して、括弧でin=とか keep=とかいわいるデータセットオプションを
つけたらどうなるのか考えたことがなかったので
実際やってみた話です。

data X_1;
do X=1 to 2;
 output;
end;
run;

data X_2;
do X=3 to 4;
 output;
end;
run;

data X_3;
do X=5 to 6;
 output;
end;
run;

data Y_1;
do Y=1 to 2;
 output;
end;
run;

data Y_2;
do Y=3 to 4;
 output;
end;
run;

のようにX_から始まるデータセットが3つ、Y_から始まるデータセットが2つあって
今、新規にAというデータセットを作成する場合、データがXから始まるデータセットから
読まれたものかYからかをフラグ変数を作って判別したいと思います。
(導出元のデータセット名を直接取得する方法については次の投稿で紹介します)

目的局面は


となります


その場合、以下で詰みなのです。

data A;
 set X_:(in=inx)
      Y_:(in=iny)
 ;
 FROMX=inx;
 FROMY=iny;
run;

これはつまり、データセットオプションが対象となるデータセット全てに分配されたイメージ
要は

data A;
 set X_1(in=inx)
      X_2(in=inx)
      X_3(in=inx)
      Y_1(in=iny)
      Y_2(in=iny)
 ;
 FROMX=inx;
 FROMY=iny;
run;

と同じになったいうわけです。

なので例えば、renameやwhereなんかも同様で

data B;
 set X_:(rename=(X=_X) where=(_X>2));
run;

なら結果は


となります。



コロンモディファイアの前方一致をSetコマンドに使用する

SASにおける「:」コロン の利用法についてはSAS Technical News 2010Autumnの
「●意外と知らない!? コロンの活用術をご紹介」で網羅的に紹介されているのですが、
ひとつ納得できないのが、データセット名に対しての前方一致参照の例がなんでproc datasetsやねんというところです。

PROC DATASETS LIBRARY=work;
 DELETE _ : ; /* アンダースコアから始まるデータセットを一括削除 */
QUIT;

いやそれはそれで当然正解なんであっているんですが。

最近、それのせいでデータセット名に対してのコロン前方一致はDATASETSプロシジャ特有の文法であると勘違いしている方がいて、もう全てはSAS社のせいではないかと思います。

要するに何がいいたいかというと

data DS_1;
 X=1;
run;

data DS_A;
 X=2;
run;

data DS_2;
 X=3;
run;

data DS_;
 X=4;
run;

というデータセットがWORKにあって

data OUTPUT;
 set DS_:;
run;

を実行すると上の4つのデータセットがすべてSetの対象となって実行されるということです。
なお、順番は辞書順ですので、実際データセットの中身は以下のようになります




ちなみにこれ、SAS9.2からですので要注意です。

9.2のデータステップ部門における拡張点で一番いけてるのは地味にこれじゃないでしょうか?

はよ後方一致と中間一致のいいやり方もつくってほしいです。SUBSTARめんどう










TRANSPOSE→CATX関数のコンボで縦持ちのデータを1行1変数に指定文字で連結してまとめてみる

CATX関数の使い勝手がよいという話題です。

たとえば以下のようなデータがあったとします。

data Q1;
length ID $10.;
ID='AAA';NO=2;ITEM='ろ';output;
ID='AAA';NO=1;ITEM='い';output;
ID='AAA';NO=3;ITEM='';  output;
ID='AAA';NO=4;ITEM='は';output;
ID='BBB';NO=1;ITEM='A'; output;
ID='BBB';NO=5;ITEM='B'; output;
run;



これをIDごとに、出現するITEMの内容を、NO順に「、」で連結して
ALLITEMという変数にいれるという問題があったとします。
求めたい結果は以下です。


なんか面倒そうだと感じますが、楽勝です。

まず、IDとNOでソートした後、IDをbyで固定してtransposeします。
このときIDステートメント(すみません、変数とまぎらわしいですね)でNOを指定します。


proc sort data=Q1;
 by ID;
run;

proc transpose data=Q1 out=Q2(drop=_NAME_) prefix=ITEM_;
 var ITEM;
 by ID;
 id NO;
run;

すると



のデータセットが得られます。
後はこれを順番に「、」で繋ぎたいのですが、nullの場合は飛ばしたいわけです。
空白が間にはいるのも嫌なので、う~んどうしよう、IFいっぱい書かなきゃいけないかと思いきや

data A;
 set Q2;
  ALLITEM=catx('、',of ITEM_:);
 keep ID ALLITEM;

run;

これで、終わりです。
catx関数は指定した区切り文字で、null以外の値を、前後の空白を除去した上で連結してくれるという、凄く気のきいた関数です。
もちろん
  ALLITEM=catx('、',ITEM_1,ITEM_2,ITEM_3,ITEM_4,ITEM_5);
とかいていいのですが、そうすると元データが増えてNO「6」ができたら
コードを修正する必要がでてしまいます。

TRANSPOSEプロシジャのprefix=は接頭語を指定できるので(suffix=は接尾語)
ここをうまく使えば、NOがどんな数字だろうと、転置後の変数は「ITEM_」から始まります。
そこで of とコロンモディファイアで、配列を使うまでもなくターゲットの変数を全て捕まえることが
できます。

CAT やCATSなど、微妙に違うことをしてくれる関数もあるので調べてみるといいと思います