proc scaprocの世界

最近、面白そうだなと思って注目してるプロシジャを紹介します。
その名もProc SCAPROCです。なんて読むのでしょうね。

9.2からいるので、さして新しくもないですね。知ってました?
こいつの機能はずばりSAS Code Analyzerです。

ちょっと奥深いので、何回かにわけるかも。
とりあえず今回はさわりだけ。

実行されたSASコードが何をしているのかを分析し、その結果を出力してくれます。

「proc scaproc;record "★出力先指定" オプション;run;」
として、そこから
「proc scaproc; write; run;」までの間に実行されるSASコードが分析対象になります。

使い方的にはproc printtoに似てますね。

例えば
proc scaproc;
record "★出力先指定\record.txt"
attr
;
run;

data OUT;
set sashelp.class;
 Z=999;
run;

proc summary data=sashelp.class(keep=age);
var age;
output out=summary mean=mean;
run;


proc scaproc; write; run;

とすると、
どんなデータセットが読み込まれ、どんなデータセットが出力されたのか?
ステップに何秒かかったか?動きのあったマクロ変数は?などの情報を、ちょっと人間には優しくない形式ですが、だしてくれます。オプションの種類と出力の解読方法についてはまた今度くわしく。


以下が出力されたファイルの中身です(一部抜粋)


* JOBSPLIT: DATASET INPUT SEQ #C00003.CLASS.DATA */
/* JOBSPLIT: DATASET OUTPUT SEQ WORK.OUT.DATA */
/* JOBSPLIT: ATTR #C00003.CLASS.DATA INPUT VARIABLE:Name TYPE:CHARACTER LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CLASS.DATA INPUT VARIABLE:Sex TYPE:CHARACTER LENGTH:1 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CLASS.DATA INPUT VARIABLE:Age TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CLASS.DATA INPUT VARIABLE:Height TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CLASS.DATA INPUT VARIABLE:Weight TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:Make TYPE:CHARACTER LENGTH:13 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:Model TYPE:CHARACTER LENGTH:40 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:Type TYPE:CHARACTER LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:Origin TYPE:CHARACTER LENGTH:6 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:DriveTrain TYPE:CHARACTER LENGTH:5 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:MSRP TYPE:NUMERIC LENGTH:8 LABEL: FORMAT:DOLLAR8. INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:Invoice TYPE:NUMERIC LENGTH:8 LABEL: FORMAT:DOLLAR8. INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:EngineSize TYPE:NUMERIC LENGTH:8 LABEL:Engine Size (L) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:Cylinders TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:Horsepower TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:MPG_City TYPE:NUMERIC LENGTH:8 LABEL:MPG (City) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:MPG_Highway TYPE:NUMERIC LENGTH:8 LABEL:MPG (Highway) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:Weight TYPE:NUMERIC LENGTH:8 LABEL:Weight (LBS) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:Wheelbase TYPE:NUMERIC LENGTH:8 LABEL:Wheelbase (IN) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR #C00003.CARS.DATA INPUT VARIABLE:Length TYPE:NUMERIC LENGTH:8 LABEL:Length (IN) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Name TYPE:CHARACTER LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Sex TYPE:CHARACTER LENGTH:1 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Age TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Height TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Weight TYPE:NUMERIC LENGTH:8 LABEL:Weight (LBS) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Make TYPE:CHARACTER LENGTH:13 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Model TYPE:CHARACTER LENGTH:40 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Type TYPE:CHARACTER LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Origin TYPE:CHARACTER LENGTH:6 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:DriveTrain TYPE:CHARACTER LENGTH:5 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:MSRP TYPE:NUMERIC LENGTH:8 LABEL: FORMAT:DOLLAR8. INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Invoice TYPE:NUMERIC LENGTH:8 LABEL: FORMAT:DOLLAR8. INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:EngineSize TYPE:NUMERIC LENGTH:8 LABEL:Engine Size (L) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Cylinders TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Horsepower TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:MPG_City TYPE:NUMERIC LENGTH:8 LABEL:MPG (City) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:MPG_Highway TYPE:NUMERIC LENGTH:8 LABEL:MPG (Highway) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Wheelbase TYPE:NUMERIC LENGTH:8 LABEL:Wheelbase (IN) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Length TYPE:NUMERIC LENGTH:8 LABEL:Length (IN) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA OUTPUT VARIABLE:Z TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ELAPSED 5  */
/* JOBSPLIT: SYSSCP LIN X64 */
/* JOBSPLIT: PROCNAME DATASTEP */
/* JOBSPLIT: STEP SOURCE FOLLOWS */

data OUT;
set sashelp.class
 sashelp.cars;
 Z=999;
run;


/* JOBSPLIT: DATASET INPUT SEQ WORK.OUT.DATA */
/* JOBSPLIT: DATASET OUTPUT SEQ WORK.SUMMARY.DATA */
/* JOBSPLIT: FILE OUTPUT /home/morioka0380/record.txt */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Name TYPE:CHARACTER LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Sex TYPE:CHARACTER LENGTH:1 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Age TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Height TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Weight TYPE:NUMERIC LENGTH:8 LABEL:Weight (LBS) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Make TYPE:CHARACTER LENGTH:13 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Model TYPE:CHARACTER LENGTH:40 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Type TYPE:CHARACTER LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Origin TYPE:CHARACTER LENGTH:6 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:DriveTrain TYPE:CHARACTER LENGTH:5 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:MSRP TYPE:NUMERIC LENGTH:8 LABEL: FORMAT:DOLLAR8. INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Invoice TYPE:NUMERIC LENGTH:8 LABEL: FORMAT:DOLLAR8. INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:EngineSize TYPE:NUMERIC LENGTH:8 LABEL:Engine Size (L) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Cylinders TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Horsepower TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:MPG_City TYPE:NUMERIC LENGTH:8 LABEL:MPG (City) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:MPG_Highway TYPE:NUMERIC LENGTH:8 LABEL:MPG (Highway) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Wheelbase TYPE:NUMERIC LENGTH:8 LABEL:Wheelbase (IN) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Length TYPE:NUMERIC LENGTH:8 LABEL:Length (IN) FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.OUT.DATA INPUT VARIABLE:Z TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.SUMMARY.DATA OUTPUT VARIABLE:_TYPE_ TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.SUMMARY.DATA OUTPUT VARIABLE:_FREQ_ TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: ATTR WORK.SUMMARY.DATA OUTPUT VARIABLE:mean TYPE:NUMERIC LENGTH:8 LABEL: FORMAT: INFORMAT: */
/* JOBSPLIT: SYMBOL GET SYSSUMSTACKODS */
/* JOBSPLIT: SYMBOL GET SYSSUMTRACE */
/* JOBSPLIT: ELAPSED 8  */
/* JOBSPLIT: PROCNAME SUMMARY */
/* JOBSPLIT: STEP SOURCE FOLLOWS */

proc summary data=OUT;
var age;
output out=summary mean=mean;
run;

inputされたデータセットの変数情報とoutputの変数情報をだすためにattrオプションをつけてます。
これを使って差分を考えれば、一応、そのステップで新規に作成されたであろう変数を、ある程度特定できますね

X軸の値ラベルに改行を含む場合、axistableで実装するのは邪道っすか?って話

sgの機能は凄い充実してるし、未だ凄い勢いで増え続けてるけど、たまに、えっ!ていうのがなかったりしますよね。
或いは、あるのかもしれないけど、もはや指定できるオプションが多すぎて、目的のものをうまく探せないっていう。

例えば、聞きたいんですけど、以下のような軸ラベルのグラフをSGで描く場合って皆さん一体どうしてるんです?




























軸の値ラベルに改行ってどうしてます?って話です。
そもそもそんなデザインのグラフにしないっていうのはなしで。

離散値であれば、軸のtype=discreteしてsplitcharで指定して区切ればいいですけど、
未だ最新verでも連続量に対応してないですよね?
unicodeで改行コード打ち込んでもなんかうまくいかないです。多分fontを対応しているものに変えればできるんだろうけど、それはしたくない。

やっぱannotateデータセット作ってsgannoで描いてるんでしょうか?
こんなちょっとしたことのために、annotate作るのは正直しゃくですよね。十分慣れてるならいいですけど

ふと思ったんですけど、annotate作るぐらいなら、xaxistableで軸附属表を軸の値ラベルに見せかけてみたらどうです?
本来の軸値ラベルと、軸ラベルは消してしまって、表で表現しちゃうっていう。

実は先の図は実際にその方法(以下のコード)で書いたやつです。

data Q1;
call streaminit(1234);
do i=1 to 10;
 X=round(rand('uniform')*10,0.1);
 Y=round(rand('uniform')*100,1);
 output;
end;
drop i;
run;

data xa;
do X=1 to 10;
xvalue1=cats(X);
xvalue2="時間";
xvalue3="経過後";
if X=5 then xvalue4="経過時間";
else xvalue4 ="";
output;
end;
run;

data A;
set xa Q1;
run;

proc sgplot data=A;
scatter x=X y=Y;
xaxis display=(nolabel novalues) values=(1 to 10 );
xaxistable xvalue1 xvalue2 xvalue3/x=X nolabel;
xaxistable xvalue4/x=X nolabel valueattrs=(size=11) pad=(top=10);
run;


axistableの本来の使用目的から外れている気がしますが、annotateの構造より正直
万人に受け入れやすいと思うんですけど、どうなんでしょう




小技というか裏技? subpad関数は現実に存在しない場所から文字をもってこれる

すっかり久しぶりの更新になってしまいました

この1ヶ月ほど色々ありました

藤井聡太が勝ったりとか、負けたりとか、また勝ったりとか。
あとは特に何もないですね。

リハビリにしょうもない記事をひとつ

subpad関数のリファレンスを読むと

・SUBPAD(string, position <, length>)

第2引数のpositionに関しては正の整数です。
と書いてある。

そんな風に書かれると、0とか負の整数指定したらどうなるのかって
試してみたくなるのが人の性ってもんですね。

というわけでやってみます。

data A;
X="ABCDE";
do i = 5 to -5 by -1;
Y=subpad(X,i);
output;
end;
run;

どうせエラーになるんだろうなぁと思っていたら

おおぅ、ログにはなにもでず、正常に実行完了。

そして中身をみると






















0番目の文字位置とか-1番目の文字位置とか存在しない場所から半角スペースとってきてる。亜空間でも見に行ったんですかね。

任意の数だけデータを半角スペース下げするのに使えるかなぁ。
でも正規なリファレンスに反した書き方だから、将来的にエラーにされても文句いえんなぁ