ラベル ステートメント: DO の投稿を表示しています。 すべての投稿を表示
ラベル ステートメント: DO の投稿を表示しています。 すべての投稿を表示

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」の違い



2015年7月6日月曜日

配列(ARRAYステートメント)入門



ARRAYステートメントによる配列の定義方法を紹介していきます。

(※ 書き方のパターンがたくさんあるので、触りのみに留めます)




構文

ARRAY  配列名( 要素数 )   割り当てる変数 ;




array  AR(3) A B C;


まず「array AR(3)」で、ARという配列を定義し、変数や値を3つ割り当てられるようにしてます。
次の「A B C」でこの配列に変数A, B, Cを割り当てています。

割り当てた変数は「AR(1)」や「AR(2)」というように「配列名(要素番号)」で参照する事が出来ます。






具体例

data DT1;
   array AR(3) A B C;

   AR(1) = 10;
   AR(2) = 20;
   AR(3) = 30;
run;

 A  
 B  
 C  
 10 
 20 
 30 


解説
arrayステートメントで各配列に以下の変数を割り当てています。
AR(1) は変数A
AR(2) は変数B
AR(3) は変数C
そのため、「AR(1) = 10;」 と書くと 「A = 10;」 と書いたのと同じ意味になります。


ちなみに配列に割り当ててる変数が「A B C」の3つなので、当然要素数も3つだろってことで、「array AR(*) A B C;」というように、要素数をアスタリスク(*)で省略して書けます。


ここで注意点!
配列に割り当てる変数は、
  • すべて同じ型である必要があります(全て文字変数、または全て数値変数)
  • 「lengthを定義してない新規文字変数」を配列に割り当てる場合は、先にlengthステートメント等で長さを定義しておくのを忘れずに。



実践例

以下は変数が欠損値であればいっぺんに0に置き換える例です。

* サンプルデータ ;
data SAMPLE1;
input A B C;
cards;
10 . 20
. . 30
;

 A  
 B  
 C  
 10 
 . 
 20 
 . 
 . 
 30 

* 欠損値を0に置き換える ;
data DT2;
   set SAMPLE1;
   array AR(*) A B C;
   do i = 1 to dim(AR);
       if AR(i) = . then AR(i)=0;
   end;
   drop i;
run;

 A  
 B  
 C  
 10 
 0
 20 
 0
 0
 30 


解説
array AR(*) A B C;

まず配列ARに変数A,B,Cを割り当てます。


do i = 1 to dim(AR);
   if AR(i) = . then AR(i)=0;
end;

DIM関数は、配列の要素数を返してくれる関数です。つまり

do i = 1 to dim(AR);
   処理
end;

で、変数 i の値を1~3 (配列の要素数) まで変化させながら中の処理を繰り返します。

中の処理 「if AR(i) = . then AR(i)=0」 は、配列の要素番号を1~3まで変化させながら処理が繰り返されるので、以下のように配列に割り当てた変数全てに処理が行われます。
if A = . then A=0;
if B = . then B=0;
if C = . then C=0;


ARRAYとDOループの組み合わせはよく見かける鉄板コンビです。



2015年6月9日火曜日

複数の変数から、欠損値以外の値を左にシフトしたい。



やりたい事

* サンプルデータ ;
data DT1;
input (SUBJID A B C D) ($);
cards;
001 .  bb .  aa
002 .  .  cc .
003 aa .  cc bb
004 . . .  .
;







上のデータで変数A, B, C, D のうち、非欠損値を左にシフトしたい。




では解決法。と、その前に前提条件
  • 左にシフトしたい変数はすべて同じ型であること。


解決法

data DT2;
   set DT1;
   length COL1-COL4 $5.;

   array AR1(*) A B C D;
   array AR2(*) COL1-COL4;

   NO = 0;

   do i=1 to dim(AR1);
       if not missing(AR1(i)) then do;
           NO + 1;
           AR2(NO) = AR1(i);
       end;
   end;
run;

概要
まず変数A, B, C, D を配列に入れる。
配列の値をループで順番に見ていき、もし非欠損値だったら新しい変数COL1~COL4へ順番に放り込んでいく。




なんか他にいい方法あったら教えてほしいです。


2015年4月28日火曜日

IFステートメントとDOループは繋げて書ける。


タイトルの通りですが、つい最近まで繋げて書けないと思ってました。

* Sample Data ;
data DT1;
   do A=1 to 3;
      output;
   end;
run;

 A 
  1 
  2  
  3  

* IF THEN DOループ ;
data DT2;
   set DT1;

   if A=2 then do B=1 to 3;
      output;
   end;

   else output;
run;

 A 
  B  
  1 
  . 
  2  
  1 
  2  
  2 
  2  
  3 
  3  
  . 

「IF文による条件に当てはまった時だけ、DOループをまわす」って感じになります。

これ知るまでは以下みたいに書いてました。

data DT2;
   set DT1;

   if A=2 then do;
      do B=1 to 3;
         output;
      end;
   end;

   else output;
run;


SAS覚え中の人に言ったら、「知ってた」って言われたんで多分知らなかったの私だけっぽい。