2019年7月30日火曜日

頭に「Q」がつくマクロ関数の用途




  • 「%SUBSTR」 に対して 「%QSUBSTR」
  • %UPCASE」 に対して 「%QUPCASE」


...のように、頭に「Q」がつくマクロ関数をご存知でしょうか?
今回は、このQつきマクロ関数を解説したいと思います。




以下はマクロ変数Xに「Mr&Mrs Smith」という文字を格納しています。

%let x = %nrstr(Mr&Mrs Smith);



ここからが問題。
このマクロ変数Xの「頭6バイトを抽出したい」とします。

%put %substr( &x, 1, 6 );

ログ
 WARNING: MRSのシンボリック参照を解決できません。



WARNINGが出ました。
これはマクロ関数「%SUBSTR」の戻り値が「Mr&Mrs」となるわけですが、「&Mrs」の部分をマクロ変数としてSASが認識してしまい、「そんなマクロ変数ないよ」って言われてます。



ここでQつきマクロ関数の出番!

%put %qsubstr( &x, 1, 6 );

ログ
Mr&Mrs



うまくいきました!
このQつきのやつは「マクロ関数の戻り値に特殊文字を含む場合、その文字をクォート処理」してくれます



まぁ以下のように%nrbquoteとか使ってクォート処理してもいいけど、、

%put %nrbquote( %substr( &x, 1, 6 ) );

ログ
Mr&Mrs


Qつきマクロ関数の用途を理解していれば、こんなめんどくさい書き方しなくてもOKってのが分かりますね!


2019年7月24日水曜日

ARRAYステートメントでのLENGTH指定





配列に定義した新たな変数にLENGTHを割り当てたい場合は、以下のような感じで書きますが、、

data test;
    length a b c $10.;
    array ar(3) a b c;
run;




ARRAYステートメントで直接定義することも可能

data test;
    array ar(3) $10. a b c;
run;



2019年7月19日金曜日

「PROC REPORT」の「COMPUTE」がうまく動かないんだけど




以下の失敗例をご覧ください。

* 失敗例 ;
proc report data=sashelp.class;
    column name age;
    compute age;
        if age=13 then call define("age","style","style=[color=blue]");
    endcomp;
run;


「AGE=13だったらAGEの文字色を青にする」というのがやりたかったのに、青になってないじゃん、っていう失敗例です。




解説


さて、何がまずかったでしょうか。
まずは以下の前提知識が必要なのでお目通しを。。

REPORTプロシジャ入門4:集計【ANALYSIS】
REPORTプロシジャ入門10:数値変数の落とし穴



上のリンクの入門記事でも解説した通り、

REPORTプロシジャに指定した ”数値項目” は、以下のように「analysis sum」オプションが勝手について実行されます。

proc report data=sashelp.class;
    column name age;
    define name / display;
    define age / analysis sum;
run;



analysis項目だと、COMPUTEの中では以下のように「項目名.統計量」という書き方をする必要があります。

proc report data=sashelp.class;
    column name age;
    compute age;
        if age.sum=13 then call define("age.sum","style","style=[color=blue]");
    endcomp;
run;



もしくは「analysis項目じゃないよ」っていうのをSASに教えるために、DISPLAYオプションを明示的に指定してあげます。

proc report data=sashelp.class;
    column name age;
    define age / display;
    compute age;
        if age=13 then call define("age","style","style=[color=blue]");
    endcomp;
run;



2019年7月16日火曜日

【PROC COMPARE入門】データセット間の変数値の比較





データセット間の変数値を比較する「PROC COMPARE」をご紹介。




構文 1

PROC COMPARE  BASE=データセット1  COMPARE=データセット2 ;
RUN ;

  • 「データセット1」と「データセット2」を比較します。
  • 上から順に同じ位置にあるオブザベーション同士を比較します。
  • 同じ変数名同士を比較します。


イメージ(黄色部分が比較対象)






構文 2

PROC COMPARE  BASE=データセット1  COMPARE=データセット2 ;
      ID   ID変数1   ID変数2 … ;
RUN ;


  • 「データセット1」と「データセット2」を比較します。
  • ID変数の値が共通するオブザベーション同士を比較します。
  • 同じ変数名同士を比較します。


変数XをIDとしたときのイメージ(黄色部分が比較対象)








* sample data ;
data dt1;
input x y$ z;
cards;
1 aa 10
2 bb 20
4 cc 30
;

data dt2;
input x y$ z;
cards;
1 aa 10
2 bb 20
3 cc 30
4 dd 40
;

* proc compare ; 
proc compare base=dt1 compare=dt2;
    id x;
run;




出力結果

1. 「データセットの要約レポート」


各データセットの「変数の数」「OBSの数」「共通変数の数」「ID変数の数」などが表示されます。



2. 「オブザベーションの要約レポート」「値の比較の要約レポート」


「共通するOBSの数」「共通しないOBSの数」「比較変数のいずれかが等しくないOBSの数」「すべての比較変数が同等なOBSの数」などなどが表示されます。



3. 変数値の比較結果


実際の不一致箇所が表示されます。



出力結果の確認の流れ(最低限)

  • 「データセットの要約レポート」で、狙い通りのOBS/変数が比較対象になってるか確認。
  • 「オブザベーションの要約レポート」で不一致となったOBSがあるか確認
  • 不一致のOBSがある場合は「変数値の比較結果」から実際の不一致箇所を確認



2019年7月9日火曜日

「_NULL_の活用」PROC SORT編




以前「_NULL_」について紹介しました。
https://sas-boubi.blogspot.com/search/label/_NULL_



「_NULL_」のちょっとしたテクニックとして、私は以下のような使い方をすることがあります。

* sample data ;
data test;
input a;
cards;
1
2
2
3
;

* _null_ を使う ;
proc sort data=test nouniquekey out=_null_ uniqueout=out1;
    by a;
run;


NOUNIQUEKEYについては以下の記事をご覧ください。
https://sas-boubi.blogspot.com/2014/03/sort.html




ポイント
  • 今回の例では「out=」に出力されるデータセットが別に要らなかったので「out=_null_」として出力しないようにしてます。
  • (もし「out=」を省略すると、「data=」に指定したデータセットに直接上書きしてしまうので、それの予防措置)



実は以前書いた記事でもこのテクニックを使ってます。
https://sas-boubi.blogspot.com/2019/06/blog-post.html



2019年7月5日金曜日

「ORDER=DATA」「ORDER=FREQ」の落とし穴




以前「ORDER=オプション」を紹介しました。

このオプションの「ORDER=DATA」と「ORDER=FREQ」には注意が必要です。
以下の例が想定通りの結果になるか各自確認してみてください。



「ORDER=DATA」の挙動確認

* サンプルデータ ;
data test;
input x y:$1.;
cards;
1 b
1 a
2 c
2 a
2 b
;

* PROC REPORTで「ORDER=DATA」 ;
proc report data=test;
   define x / order order=data;
   define y / order order=data;
run;

「x=2の時の順番が「c → a → b」から「b → a → c」になってしまった?」と疑問に思った方は要注意!


解説

「ORDER=DATA」は「データセットに格納されてるままの順番」に出力されると思いがちですが、
登場した値の順に並び替える」というのが正確ですね。今回の例では、

  • x=1 の時「b → a」の順に値が登場します。
  • x=2 の時「c → a → b」の順に値が登場していますが、上で既に「b → a」の順で登場しているので、「b → a → c」の順に並び替えられます。



「ORDER=FREQ」の挙動確認

* サンプルデータ ;
data test2;
input x y:$1.;
cards;
1 a
1 a
1 b
2 a
2 b
2 b
2 b
2 c
2 c
;


* PROC SUMMARYで「ORDER=FREQ」 ;
proc summary data=test2 print order=freq;
   class x y;
run;

「全然、度数が多い順に並んでない?」と疑問に思った方は要注意!


解説

まずCLASS編数 x, y について、別々に度数を計算します。

  • x=1 の度数: 3
  • x=2 の度数: 6
    • x の値で度数が多い順は「2 → 1

  • y=a の度数: 3
  • y=b の度数: 4
  • y=c の度数: 2
    • y の値で度数が多い順は「b → a → c

てことで、x =「2 → 1」、y = 「b → a → c」の順番で並び替えられます。