2018年2月27日火曜日

CALL CATS / CATX の使いどころ



CATS・CATX関数はご存知でしょうか?
ご存知ないって方は、むかし書いた記事をご覧ください。

http://sas-boubi.blogspot.jp/2017/05/my-favorite-sas-functions-1-cats.html
http://sas-boubi.blogspot.jp/2017/05/my-favorite-sas-functions-2-catx.html


ここから本題
上で紹介した関数とは別に「CALL CATS」,「CALL CATX」ってのもあります。



構文


  CALL CATS( 結果を格納する変数,   変数1, 変数2,… 変数n )


変数1 ~ 変数n の値を結合し、第1引数に指定した変数に結果を格納します。



  CALL CATX( 区切り文字, 結果を格納する変数,   変数1, 変数2,… 変数n )


変数1 ~ 変数n の値を区切り文字付きで結合し、第2引数に指定した変数に結果を格納します。



つまり、CATS関数で以下のように書いていた文が、、
Y = CATS( X1,X2,X3 );

CALL CATSだと以下のように書けます。
CALL CATS( Y, X1,X2,X3 );




「CALL CATS」「CALL CATX」の使いどころ

CATS関数を例に、以下のケースを考えてみます。

data DT1;
    length RESULT $200.;
    X1 = "ab";
    X2 = "cd";
    X3 = "bc";

    /* CATS関数で文字を結合 */
    array AR(*) X1-X3;
    do i = 1 to dim(AR);
       if index(AR(i),"c") then RESULT = cats( RESULT,AR(i) );
    end;
run;

 RESULT  X1  X2  X3 
  cdbc  ab cd  bc

X1~X3 の中で変数値に "c" が含まれているものを結合して変数RESULTに格納しています。


以下は、CALL CATS を使う場合。

    array AR(*) X1-X3;
    do i = 1 to dim(AR);
       if index(AR(i),"c") then call cats( RESULT,AR(i) );
    end;



正直、CATSでもCALL CATSでも文の長さは変わらないのでどっちでもいいんですが、なんとなく
RESULT = cats( RESULT,AR(i) );

と書くより、
call cats( RESULT,AR(i) );

と書く方が綺麗じゃないですか?こっちだと同じ変数名を2回書く必要がないから。



このように、「結果変数 = cats( 結果変数, 変数1,変数2… )」みたいな書き方になる場合は CALL CATS を使う方が良いように思います。(個人的に)





2018年2月20日火曜日

PROC FORMAT入門4 : PICTUREステートメント




今回は「PICTUREステートメント」について。


例えば「1→001、12→012」とか、「1234→12-34、5678→56-78」のように数値を特定の書式に読み替え・変換したい場合に使います。





構文

PROC FORMAT;
      PICTURE フォーマット名
          値  =  '書式の定義'  (オプション)
          値  =  '書式の定義'  (オプション)
          ・・・
      ;
RUN;

※ フォーマット名の末尾は数字NG(例えば「TEST1」など)





* PICTUREフォーマットの定義 ;
proc format;
   picture NINE
       low - high = "99-99"
   ;
   picture ZERO
       low - high = "00-00"
   ;
run;

  • フォーマット「NINE」を定義して、出力する値の書式を '99-99' としています。9の意味は「先頭の数値がないところを0で埋める」という意味で、今回の場合は「123→"01-23"」や「1→"00-01"」のような変換がされる。


  • フォーマット「ZERO」を定義して、出力する値の書式を '00-00' としています。0の意味は「先頭の数値がないところを半角スペース(空白)で埋める」という意味で、今回の場合は「123→" 1-23"」や「1→"    1"」のような変換がされる。


この書式設定に使う 0 や 9 を「数字セレクタ」といいます。
(1 ~ 8 も 9 と同じ意味を持つ数字セレクタです)



ではこのフォーマットを使ってみます。

* Sample Data ;
data DT1;
input X;
cards;
.
1
12
123
1234
12345
;

* フォーマット変換してみる ;
data DT2;
   set DT1;
   length NINE ZERO $10.;
   NINE = put(X,NINE.);
   ZERO = put(X,ZERO.);
run;
 X  NINE  ZERO 
    . 
  
    1 
 00-01     1
   12 
 00-12   12
  123 
 01-23 1-23
  1234 
 12-3412-34
  12345 
 23-4523-45


結果を見ると性質を理解しやすいです。
気をつけたいのが、今回「数字セレクタ」の部分を「00-00」のように4桁しか定義してないから、最後のオブザベーションの結果が「12345→23-45」って感じで桁が足りなくて「1」が切れちゃってるとこですかね。




では続いて、PICTUREフォーマットで用意されているオプションも見ていきましょう。


PICTUREフォーマットのオプション

  オプション内容  プログラム例
フォーマット変換後に半角スペース(空白)となった部分を指定文字で埋める 

 ( FILL = '文字' )
proc format;
   picture test1_
     low - high = '00-00' (fill='*');
run;

フォーマット変換の例
「123」→「*1-23」
「1」    →「****1」

0~9を数字セレクタではなく、文字として扱う

 ( NOEDIT )
proc format;
   picture test2_
     low - high = '00-00' (noedit);
  run;

フォーマット変換の例
「123」→「00-00」
「1」    →「00-00」

フォーマット変換した値の先頭に表示する文字の指定


 ( PREFIX = '文字' )
proc format;
   picture test3_ (default=5)
     low - high = '0000' (prefix='-');
 run;

フォーマット変換の例
「123」→「 -123」
「1」    →「   -1」

フォーマット変換前に変数値に掛ける数値を指定

 MULTIPLIER = 数値 )


※ただし以下リンクの通り、かなり取扱い注意なオプション
(http://sas-boubi.blogspot.jp/2018/03/proc-formatpicture.html)

proc format;
   picture test4_
     low - high = "0000" (multiplier=10);
run;

フォーマット変換の例
「123」→「1230」
「1」    →「  10」





一応、PREFIXオプションだけ詳細説明しときます。
たとえば以下にマイナスの値を含むデータがあります。

* Sample Data ;
data dt1;
input x;
cards;
-12
12
;
 X 
 -12 
   12 



このデータに以下のフォーマットを割り当てると、、

* Mistake (間違っている例) ;
proc format;
   picture test1_ (default=5)
     low - high = '00'
   ;
run;

data dt2;
   set dt1;
   format x test1_.;
run;
 X 
 12 
   12 

数値部分だけになり、マイナス記号が消えてしまいます。



それならば、という事で以下のように '-00' という書式を用意してみますが、、

* Mistake (間違っている例) ;
proc format;
   picture test1_ (default=3)
     low -< 0 = '-00'
     0 - high = '00'
   ;
run;

data dt2;
   set dt1;
   format x test1_.;
run;
 X 
 12 
   12 

やっぱりマイナス記号消えちゃいます。
PICTUREフォーマットは、'-00' みたいに「書式の先頭に文字を入れてもその文字は無視される」という仕様になっています。



なぜそんな仕様なのかよく分かりません。
てことで、先頭に文字を入れたい場合は、prefixオプションを使います。

* 正しい例 ;
proc format;
   picture test1_ (default=3)
     low -< 0 = '00' (prefix="-")
     0 - high = '00'
   ;
run;

data dt2;
   set dt1;
   format x test1_.;
run;
 X 
 -12 
   12 


ちなみに「picture test1_ (default=3)」って感じで、defaultオプションというのを指定していますが、これをつけないと文字切れしちゃうケースがあるのでご注意を!
(理由は以下で紹介している落とし穴と同じ。)

INFORMATの落とし穴【デフォルト長】





2018年2月15日木曜日

ODS OUTPUT の落とし穴 (2)



以下記事の続き。
ODS OUTPUT の落とし穴 (1)



以下のプログラム、WARNINGが出ちゃいますが、どこがおかしいか分かりますか?

proc glm data=sashelp.class;
   class sex;
   model height = sex;
run;

ods output Summary=OUT1;
proc means data=sashelp.class;
   var height;
run;
ods output close;


ログ
WARNING: 出力'Summary'は作成されていません。出力オブジェクト名、ラベル、パスが正しく記述されているかを確認してください。また、要求した出力オブジェクトを作成するために、
         適切なプロシジャオプションが使われているかも確認してください。たとえば、NOPRINTオプションが使われていないことを確認してください。
WARNING: プロシジャステートメントの終わりを検出したので、現在のODS SELECT/EXCLUDE/OUTPUTステートメントをクリアしました。
         対話型プロシジャ(終了するにはquit;をタイプします)が終了していないかもしれません。



この落とし穴にはまってる人たまに見かけます。


これは対話型プロシジャを使う場合に起こる落とし穴です。
(対話型プロシジャについては、「RUNとQUITの違い」をご覧ください。)


今回の例で使用しているGLMプロシジャは対話型プロシジャです。
「QUIT」と書くか、別のDATAステップ・PROCステップが現れるまで、GLMプロシジャは起動したままになります。
なので、以下の青文字部分がGLMプロシジャに対する処理だと判断されてしまいます。


proc glm data=sashelp.class;
   class sex;
   model height = sex;
run;

ods output Summary=OUT1;
proc means data=sashelp.class;
   var height;
run;
ods output close;



解決方法はご存じの通り、「quit;」を入れるだけです。

proc glm data=sashelp.class;
   class sex;
   model height = sex;
run;
quit;

ods output Summary=OUT1;
proc means data=sashelp.class;
   var height;
run;
ods output close;




そもそもSASのマニュアルにも対話型プロシジャにQUITを入れていない例があるので、
この問題に気づかなくても無理はないっちゃないんですが。。


ちなみに、今回紹介した落とし穴は「ods output」だけでなく、「ods select」「ods exclude」とかでも同様に起こる問題です。

2018年2月6日火曜日

PROC FORMAT入門3 : INVALUEステートメント




今回は「INVALUEステートメント」について。


データを読み込む際に「男→1→2」「Y→YES、N→NO」みたいな変換を行うための「インフォーマット」と呼ばれるものを定義するステートメントです。



FORMATプロシジャ入門の第1回の記事で解説したVALUEステートメントと機能が似てるので、区別がついていない方も多いです。




実際、例を見た方が分かり易いです。まずは変換を行うインフォーマットの定義から。




インフォーマットを定義する例

proc format;

   invalue TEST1_
      "MALE"     = 1
      "FEMALE" = 2
   ;
   invalue $TEST2_
      "Y"    = "YES"
      "N"    = "NO"
   ;
run;

  • 「TEST1_」というインフォーマットを定義し、「"MALE"→1、"FEMALE"→2」 という変換を定義
  • 「TEST2_」というインフォーマットを定義し、「"Y"→"YES"、"N"→"NO"」 という変換を定義




構文
PROC FORMAT;

      INVALUE インフォーマット名
         値  =  変換後の値
         値  =  変換後の値
         ・・・
     ;
RUN;



ポイント
  • インフォーマット名の最後は数字じゃダメ(例えば「TEST1」など)
  • 「"Y"→"YES"」のような文字から文字への変換を行うインフォーマットは、インフォーマット名の先頭に「$」をつける(例えば「$TEST」など)





では、先程つくったインフォーマットを使ってみましょう。


インフォーマットを使う例①

data DT1;
   length SEX 8. YN $3.;
   input SEX YN;
   informat SEX TEST1_. YN $TEST2_.;
cards;
MALE Y
FEMALE N
;
 SEX  YN 
  1  YES 
  2  NO


上の例では、CARDSで読み込むデータに対して「INFORMATステートメント」で以下を行なっています。

  • インフォーマット「TEST1_」を使い「"MALE"→1、"FEMALE"→2」に変換した値を変数 SEX に格納
  • インフォーマット「TEST2_」を使い「"Y"→"YES"、"N"→"NO"」に変換した値を変数 YN に格納




構文
INFORMAT  変数名  インフォーマット名. ;



ポイント
  • テキストファイル や CARDS で読み込むデータに対して、インフォーマット変換した値を変数に格納する。
  • インフォーマット名の後ろにドット「.」を入れる必要があります。





インフォーマットを使う例②

* Sample data ;
data DT1;
   length SEX $6. YN $1.;
   SEX="MALE"; YN="Y"; output;
   SEX="FEMALE"; YN="N"; output;
run;

SEX  YN 
 MALE  Y
 FEMALE  N


* 変数値をインフォーマットで変換する ;
data DT3;
   set DT1;
   length SEX2 8. YN2 $3.;
   SEX2 = input( SEX, TEST1_.);
   YN2  = input( YN , $TEST2_.);
run;


SEX 
 YN 
 SEX2 
 YN2 
 MALE
 Y 
  1
 YES 
 FEMALE  
 N
 
 NO



上の例では「INPUT関数」を使って以下を行なっています。
  • 変数 SEX の値を インフォーマット「TEST1_」を使って変換し、変数 SEX2 に格納。
  • 変数 YN の値を インフォーマット「TEST2_」を使って変換し、変数 YN2 に格納。



構文
新規変数名 = INPUT(  変数名 ,  インフォーマット名.  );



ポイント
  • 文字変数に対して、インフォーマットを使って数値または文字に変換します。
  • インフォーマット名の後ろにドット「.」を入れる必要があります。





注意事項


PROC FORMAT入門 : 記事一覧