ひとつのマクロステップ内で重複しなければ何でもいい一時的な値をもつマクロ変数&sysindex。 たとえばデータステップ内でツール的に利用するマクロなんかで、配列名やハッシュオブジェクト名みたいに1データステップ内で同名存在ができないものを生成するケースなどに使えます って話

(追記-最初にあげたときマクロの内容や画像が派手に間違えてました。ごめんなさい。
同時に指摘いただいた4名の方々有難うございます。ちゃんと見てる人いるんですね、反省します..)

こないだ電車乗ってたら、ブログに長いタイトルつける奴は仕事できない奴だっていってるおじさんがいました。要点がまとめれていないからだそうです。僕もそう思います。

さて、もう言いたいことはタイトルで言ってしまったので、これ以上何もないのですが説明します。

例えば以前の記事で、SASには現状、文字型の非欠損値をカウントする変数がないって話をしました
http://sas-tumesas.blogspot.jp/2015/02/blog-post.html

それをマクロをサブルーチン的に使って解決しようと考えたとします。
以下のようなデータがあり

data Q1;
A='';B='a';C='a';D='a';E='a';output;
A='a';B='';C='a';D='';E='a';output;
A='';B='a';C='';D='a';E='';output;
A='a';B='a';C='a';D='a';E='a';output;
run;











以下のようにマクロを組んでみました。

%macro ar(varlist);
array AR $ &varlist;
CN=0;
do over AR;
 CN + ^missing(AR);
end;
drop CN;
%mend ar;


早速そのマクロを使って、変数A B Cのうち値があるものの数をカウントしてみます。

options mprint;

data A1;
set Q1;
%ar(A B C)
count_A_B_C=CN;
run;











はい、できました。
ちなみにoptions mprintをつけたのでログにはこんな感じで展開されたものが
でています


そこで調子にのって、同じステップなの中でC D Eに対してもやってみようとします

data A2;
set Q1;
%ar(A B C)
count_A_B_C=CN;
%ar(C D E)
count_C_D_E=CN;
run;

はい、エラーになりました。








これはarマクロの中でarrayステートメントで配列名「AR」を生成してるんですが
arマクロを2回以上入れると、マクロが展開されたとき、1つのデータステップの中で配列「AR」を
複数回宣言することになります。そしてそれはSASの文法上NGなので通りませんぜと。

じゃあ、どうするか。
このマクロにとって、配列は、カウント処理の際のみに必要なものであって
CNが計算できた後は意味がなく、配列の名前についてもどうでもいいわけです。

たとえば、引数の変数名を全部文字連結して配列名にするようにしてもいいですが
配列名は32文字までなので、長い変数をたくさん指定すればエラーになってしまいます。

乱数とかでもいいですが、たまたま衝突する可能性は、まあ一応ゼロではありません。

じゃあ、パラメーターひとつ増やして、使用時に毎回配列名も指定させます?
使い捨ての名前にそこまで手を煩わせたくないな~

じゃあ、どうするのか?
ここでsysindexを使います。こいつはsasを開いてから閉じるまでの
sasセッションの中で、呼び出される都度+1された連番が入るので
決して重複しないという性質をもっています

以下のようにマクロを書き直しました。

%macro ar2(varlist);
array AR&sysindex $ &varlist;
CN=0;
do over AR&sysindex;
 CN + ^missing(AR&sysindex);
end;
drop CN;
%mend ar2;

では再度実行してみます。

data A3;
set Q1;
%ar2(A B C)
count_A_B_C=CN;
%ar2(C D E)
count_C_D_E=CN;
run;

無事できました。


ログを見てみると、さっきと違ってAR5とAR6というように
勝手に配列名に連番が付与されていることで、名前の衝突が回避されていることが
わかります。

ちなみに、なぜ5から始まっているかというと

まず最初何もしていない状態が1で

最初データセットA1を作った際に一回%arを呼び出したので
ここで+1されて2になってます。

続いて、結局エラーになりましたがA2で二回呼び出しているので
+1 +1 で4になってます。

だから今回5なんですね。ユーザーが意識しようがしまいが内部的に自動カウント
されているわけです。

SASはfcmpプロシジャの機能がアレなんで、マクロを関数やサブルーチンなどステップ内での
ツール的に使いたいケースも多いんですが、そういう時に知ってると役立ちます

9.4から登場した拡張属性(Extended Attribute)はあんまり話題になんないねって話

昔、とある場所でデータセットをみていた際、変数に全部に長~いラベルがついてました
例えば、[XX_日付型_データAA由来] のようにその変数の元の参照先や、詳細な型について記載されてました。

誰がみても、その変数の詳細がわかるようにと、義務づけられてるそうです。

まあ、確かにSASって文字型と数値型しかないので、普通にプロシジャに数値型全指定でかけたら
日付もIDも集計してくれたりするし、データセットいじってる内に、この変数ってどっからきたの?みたいなこともあります。

まあ、定義書で管理すればいいんじゃないって気がしてましたし、
ラベルでそういうのを管理するのは限界があるよな~って思いました。

データセット自体にXMLのように自由に属性つけれれば管理がはかどるのにって思う方もいるのでしょう。

そんなあなたに朗報。9.4から自分で好きに属性を定義して、それをデータセットに付与することが
できるようになりました。

それが拡張属性です!

9.4で登場した新機能のひとつですが、DS2やFedSQLに輪をかけて影が薄い!!
誰も話題にしてないこと、この上なしです。

例えば以下のようなデータセットがあるとします。

data Q1;
x=1;y=19562;z=320;output;
x=2;y=19566;z=280;output;
x=3;y=19569;z=120;output;
format y yymmdds10.;
run;











これに、その変数の説明と、参照元、型の補足(日付なのか、IDとかみたいに質的なものなのかとか)を
それぞれ
detail source cate という適当な属性を作って付与してみようと思います。

以下を実行します

proc datasets nolist;                             
   modify Q1;     
      xattr add var x (detail="ユーザーID" source='登録情報' cate="ID") 
                    y (detail="XX日" source='20XX年情報' cate='日付')                    
                    z (detail="売り上げ(千円)" source='売り上げ情報' cate="量的変数")
;                    
run;                 
quit;

拡張属性はいまのとこ、proc datesetsでしか作れないみたいです。attribステートメントとかでも
作れればいいのにね。

文法は上記のとおりで、xattr add varで変数に対する拡張属性を付与できます。
ちなみにvarのところをdsにすると、データセットにも属性を定義できます。

脱線しますが、ラベルにもあまり使われていないですが、データセットラベルというのが
昔からありました。
「データセットラベルの話」
http://sas-tumesas.blogspot.jp/2014/08/blog-post_31.html


で、話を戻して、拡張属性を付与したら、そのデータセットをcontentsプロシジャで確認してみましょう。
(ods ooutputは後で使うのでおまけです)

ods output ExtendedAttributesVar=xattr_ds;
proc contents data=Q1;
run;



























このように、付与した拡張属性を参照することができました。


例えばこれを使って、拡張属性で「cate」の値が「量的変数」の変数のみを
meansにかけたいな~と思ったら、さっきods outputでデータセット化しておいたものを
使って

data _null_;
length target $1000.;
set xattr_ds end=eof;
retain target;
where ExtendedAttribute='cate' & AttributeCharValue='量的変数';
target=catx(' ',target,attributevariable);
if eof then call symputx('target',target);
run;


proc means data=Q1;
var ⌖
run;

上記のようにかけるわけですね。

拡張属性、バリバリ利用してますって方がいれば、どんなことしてるか是非教えてほしいです