2016年1月27日水曜日

IFN / IFC関数と謎の第4引数




IFN / IFC関数は、簡単に言うとIFステートメントの関数バージョンです。


構文

 IFN (  条件式  , 条件式が真(TRUE)の場合の戻り値 ,  条件式が偽(FALSE)の場合の戻り値 )

戻り値を数値で返したい場合はIFN関数を使い、文字値で返したい場合はIFC関数を使います。






*** サンプルデータ ;
data DT1;
    A=10 ; output;
    A=.  ;  output;
    A=20 ; output;
run;

*** IFC関数を使ってみる ;
data OUT1;
    set DT1;
    length B $30.;
    B = ifc( A<=10 , "10以下", "10より大きい" );
run;

 10  
 10以下  
  .  
 10以下 
 20
 10より大きい  


Aが欠損値の場合にも「10以下」ってなるのはおかしいよねって感じなので、
その場合、以下のようにIFN / IFC関数をネストさせる方法もありますが、、ネスト増やして見づらくなるんだったら、IFステートメント使った方が良いですね。。

B = ifc(A=. ,"未記載", ifc( A<=10 , "10以下", "10より大きい" ) );

 10  
 10以下  
  .  
 未記載
 20
 10より大きい 



謎の第4引数


実はこの関数、謎の第4引数が存在します。

  IFN( 条件式 , 条件式がTRUEの場合の戻り値 ,
                         条件式がFALSEの場合の戻り値 ,
                         条件式欠損値の場合の戻り値  )


ずっと疑問なんですが、この第4引数ってどういう時に使うんでしょうか?
というのも条件式の結果は、TRUE か FALSE しか返しません。

たとえば上の方のサンプルプログラムでIFC関数に書いた条件式 「A<=10」 に対する真偽は以下のようになります。

・ Aの値が10以下の場合        ・・・ TRUE
・ Aの値が10より大きい場合   ・・・ FALSE
・ Aの値が欠損値の場合        ・・・ TRUE (「10以下」と解釈。)


なんでこの関数だけ3値論理?
ということで、こういう時に使えそうねってアイディアがあれば教えてほしいです。



2016年1月25日月曜日

PROC REPORTでグループ毎に空白行を挿入する。



以下は変数SEXの値毎に、空白行を挿入しています。

proc report data=SASHELP.CLASS nowd spanrows;
     column SEX NAME AGE;
     define SEX     / order order=internal missing;
     define NAME  / display;
     define AGE    / display;
     compute after SEX;
        line "";
     endcomp;
run;


  • 変数SEXに対して、ORDERオプションでデータの並び替えを設定。
  • COMPUTE内でLINEステートメントを入れることで空白行を挿入しています。

REPORTプロシジャ自体については入門記事を参照ください。

2016年1月22日金曜日

REPORTプロシジャ入門7:計算項目の追加【COMPUTE】




COMPUTEステートメントについて解説していきます。
重要な注意事項を含むので、ひと通り記事全体をご覧ください。



簡単な例

proc report data=SASHELP.CLASS nowd;
   column NAME HEIGHT WEIGHT FLAG;
   define NAME     / display;
   define HEIGHT  / display;
   define WEIGHT / display;
   define FLAG      / computed;
   
   compute FLAG;
      if HEIGHT > 65 or WEIGHT > 100 then FLAG = 1;
   endcomp;
run;



計算項目「FLAG」を作り、「HEIGHT > 65」or「WEIGHT > 100」の場合に「1」を格納しています。



構文解説

まずは作成する項目をCOLUMNステートメントに指定

   column NAME HEIGHT WEIGHT FLAG;


計算項目であることをDEFINEステートメントに定義しておきます
(「COMPUTED」と指定)

   define FLAG   / computed;


計算内容を「COMPUTE」~「ENDCOMP」内に記述します。
IF文や関数なども使えます。

   compute FLAG;
      if HEIGHT > 65 or WEIGHT > 100 then FLAG = 1;
   endcomp;



重要なのが「COLUMNステートメント」での「計算項目」の指定場所
「計算項目」は、計算時に参照しているどの項目よりも後に指定するのが安全


今回の例で説明すると、
「FLG」の計算には、「HEIGHT」「WEIGHT」を参照しています。

   compute FLAG;
      if HEIGHT > 65 or WEIGHT > 100 then FLAG = 1;
   endcomp;



なので、COLUMNステートメントでは「HEIGHT」「WEIGHT」の後に「FLAG」を指定しています。

   column NAME HEIGHT WEIGHT FLAG;


(SASが内部で処理する順番が関係していそうですが、内部の話なので、明確な理由が説明できません。。)




文字項目を追加する例

proc report data=SASHELP.CLASS nowd;
   column NAME SEX NEWVAR;
   define NAME      / display;
   define SEX         / display;
   define NEWVAR  / computed;
   
   compute NEWVAR / character length=20;
      NEWVAR = compress( NAME || "-" || SEX );
   endcomp;
run;



「NAME」と「SEX」を横棒でつないでくっつけた計算項目「NEWVAR」を作っています。



計算項目が文字の場合は、COMPUTEステートメントで以下のようにLENGTHを定義しておきます。

  COMPUTE  計算項目名  /  CHARACTER LENGTH = 長さ ;



2016年1月21日木曜日

変数属性を定義した空のデータセットを作る 【SQLプロシジャ編】



変数属性の定義はデータステップのATTRIBがよく使われますが、SQLプロシジャでも出来ます。

proc sql;
   create table OUT1  (
        A char(10)  "aa" ,
        B num       "bb" ,
        C num       "cc"  format=yymmdd10.
   );
quit;



作ったデータセットの変数定義を確認してみます。

proc contents data=OUT1 varnum;
run;


おまけ

2016年1月18日月曜日

SORTプロシジャによる降順ソートの便利技




サンプルデータ

data DT1;
input A$ B C$ @@;
cards;
001 1 a 001 1 b 001 2 c 002 1 a 002 2 b
;




通常の降順ソート


変数A, B, Cをキーに、オブザベーションを降順ソートしたい場合、
以下のようにdescendingオプションを変数名の前につけます。

proc sort data=DT1;
   by descending descending B descending C ;
run;




KEYステートメントを使うと。。


上のようにdescendingオプションを全ての変数に指定するのって面倒だなーと思いませんか?
そんな時はKEYステートメントが便利です。

proc sort data=DT1;
   key A B C / descending ;
run;


これはBYステートメントと同様の機能を持ってるうえ、
  • 「KEY  変数名1 変数名2 … / オプション ;」

というように指定した変数すべてにオプションを適用する事ができるんです。




ちなみに変数Aを昇順かつ、B,Cを降順でオブザベーションをソートしたい場合、以下のように書くことも出来ます。

proc sort data=DT1;
   key A ;
   key B C / descending ;
run;




2016年1月14日木曜日

「DO UNTIL」と「DO WHILE」の違い。


「DO UNTILE」と「DO WHILE」の書き方とその違いを紹介。

まずイメージから。。(正確な動きはちょっと違うかも)


















DO UNTIL の例

data DT1;
   X=0;
   do until (X=2);
       X+1;
       put X;
   end;
run;

ログ
1
2



DO WHILE の例

data DT2;
   X=0;
   do while (X<=2);
       X+1;
       put X;
   end;
run;

ログ
1
2
3

ログみて、「あれ? X<=2 の間ループする条件なのに、なぜX=3が出力されてるんだ?」 と思った方は、記事先頭にあるイメージを見ながら 「条件式の真偽判定を行うタイミング」 に注意して考えてみてください。



ちなみに上のような勘違いしやすい書き方より、以下の方がいいかも。(赤字は上の例からの変更箇所)
data DT2;
   X=1;
   do while (X<=3);
       put X;
       X+1;
   end;
run;

ログ
1
2
3

条件式が 「X<=3」 で、ログに出力している値も3以下なので、
こっちの方が条件式を見ただけで、パッと見の動きが分かり易いです。



無限ループに注意

DO UNTILに「絶対に成立しない条件式」を入れたり、
DO WHILEに「常に成立し続ける条件式」を入れると、無限ループになってしまいます。


Windows環境だと、Ctrl + Pause(Break) ⇒ 「サブミットしたステートメントを取り消す」で無限ループから抜けられますが、SAS Enterprise Guideとか他の環境は使った事ないので通用するか分からないし、そもそもPause(Break)キーがないノートPCはどうすればいいんだって感じで、最悪強制終了するはめになるのでご注意ください。。


「do i = 1 to 3」 みたいな書き方で代用できるなら、そちらを使うほうが安全かもです。
⇒ DOループ入門


2016年1月7日木曜日

DOループ入門


SASによるDOループの基本的な書き方を紹介。



基本構文

  DO   [変数]   =   [開始値]   TO   [終了値] ;

        ~ 繰り返し処理するプログラムを記述 ~

  END;

[変数] の値を [開始値] から [終了値] まで変化させながら、DO~END内に書かれた処理を繰り返す。






① 基本
data DT1;
   do i = 1 to 3;
       put i;
   end;
run;

ログ
1
2
3

変数 i の値を 1~3 まで変えながら、DO~END内に書かれた処理を繰り返しています。


ちなみに作成したデータセットDT1の中身を見てみると、、

あれ?終了値は「3」なのに「4」が入ってる?!
安心してください。変数 i の値は終了値をオーバーしていますが、ちゃんと変数 i が 1~3 の時だけDO~END内の処理が行われています。



② 増分の指定
data DT1;
   do i = 1 to 5 by 2;
       put i;
   end;
run;

ログ
1
3
5

変数 i の値を 1~5 まで変えています。 ただしBYで増分を指定しています。
つまり「do i = 1 to 5 by 2」で変数 i の値を 「+2」 ずつ増やすようにしています。



③ 文字の指定
data DT1;
   length VAR $10.;
   do VAR = "a", "b", "c";
       put VAR;
   end;
run;

ログ
a
b
c

「do i = 1, 3, 6;」 のように数値もいける。



関連記事(お暇なときに。。)
「DO UNTIL」と「DO WHILE」の違い



2016年1月5日火曜日

「ODS TEXT= ステートメント」でテキストを挿入する。



「ODS TEXT= ステートメント」 を使うと、自由にテキストを出力することができます。
(ODS LISTINGなどの一部出力には対応していないのでご注意ください)

options nocenter;
ods rtf file="出力先パス\TEST.rtf";

   proc print data=sashelp.class (obs=5);
   run;

   ods text="あああああああいいいいいいうえお";

ods rtf close;


TEST.rtf