目次
1. IF-THENステートメントを使った条件別処理
ある条件が成り立つオブザべーションに絞って特定のステートメントを実行したい場合や、条件別に適用するステートメントを変更したい場合などは、IF-THENステートメントを使用する。
【IF-THENステートメントの基本書式】
IF 条件式1 THEN ステートメント1; ELSE IF 条件式2 THEN ステートメント2; ・・・ ELSE ステートメントN;
・条件式1が成立する場合、ステートメント1を実行する。
・条件式1が成立せず、条件式2が成立する場合、ステートメント2を実行する。
・いずれの条件式も成立しない場合、ステートメントNを実行する。
比較演算子と論理演算子
条件式は、比較演算子および論理演算子を組み合わせて作成する。論理演算子は、複数の比較演算を組み合わせるときに使用する。条件式内では、算術演算子も含めて、カッコを使った任意な優先順位の指定をすることができる。
比較演算子
比較演算子 | 定義 | 使用例 | 実行の優先順位 |
= | 等しい | x = y | 3 |
NE | 等しくない | x ne y | |
> | より大きい | x > y | |
< | より小さい | x < y | |
>= | 以上 | x >= y | |
<= | 以下 | x <= y | |
IN | リストの中の1つ以上と等しい | x in (a, b, c) |
※INの使用例はカンマ区切りではなく、ブランク「x in (a b c)」で記述しても良い。
論理演算子
論理演算子 | 定義 | 使用例 | 実行の優先順位 |
& または AND | 論理積(かつ) | (a>b) & (c<0) | 4 |
| または OR | 論理和(または) | (a>b) | (c<0) | 5 |
^ または NOT | 否定 | not(a>b & c<0) | 1 |
ちなみに、優先順位2に該当するのは、算術演算子である。
2. IF-THENステートメントで複数のステートメントを実行
IF-THEN-ELSEステートメントで、条件分岐先として複数のステートメントを指定したい場合は、DO-ENDステートメントを併用すれば良い。
IF 条件式1 THEN DO; ステートメント1_1; ステートメント1_2; ・・・; END; ELSE IF 条件式2 THEN DO; ステートメント2_1; ステートメント2_2; ・・・; END; ・・・; ELSE DO; ステートメントN_1; ステートメントN_2; ・・・; END;
【事前準備】
まず、以下のように、サンプルSASデータセットlistを用意する。
data list; infile datalines dlm="," dsd missover; input first_name :$20. last_name :$20. sex :8. age :8. ; datalines; Kaori,Ito,2,22 Hideki,Tanaka,1,35 Taro,Yamada,1,30 Hiroki,Sato,1,25 Mizue,Ishii,2,54 Yuko,Koyama,2,30 Ichiro,Suzuki,1,. Shinji,Suda,1,27 Reiko,Yamauchi,2,42 Mituru,Adachi,3,45 ; run;
【例】
そして、以下のように、SASデータセットlistに対し、条件分岐を掛け、list_categoryを作成する。
data list_category; set list; length age_label $20.; if age < 20 then do; age_cat =99; age_label="不明"; end; else if 20 <= age < 30 then do; age_cat =1; age_label="20代"; end; else if 30 <= age < 40 then do; age_cat =2; age_label="30代"; end; else if 40 <= age < 50 then do; age_cat =3; age_label="40代"; end; else do; age_cat =4; age_label="50代以上"; end; run;
※ちなみに、7オブザベーション目の数値変数の欠損値「age=.」は、最小値として扱われるので、一番最初の条件式「age < 20」に当てはまることになる。
3. SELECT-WHENステートメント
IF-THEN-ELSEステートメントと同様に、条件分岐を行うために使用する。構文的に分岐処理の構造が分かりやすく記述できるので、条件分岐の数が多い場合は、IF-THEN-ELSEよりも、こちらを使う方が可読性が高まることがある。
【書式1】 SELECT; WHEN(条件1) ステートメント1; WHEN(条件2) ステートメント2; ・・・; OTHERWISE ステートメントN; END;
【例】
先ほどの、list_categoryを作成したIFステートメントを、SELECTステートメントで書き換えてみる。
data list_category_select1; set list; length age_label $20.; select; when(age < 20) do; age_cat =99; age_label="不明"; end; when(20 <= age < 30) do; age_cat =1; age_label="20代"; end; when(30 <= age < 40) do; age_cat =2; age_label="30代"; end; when(40 <= age < 50) do; age_cat =3; age_label="40代"; end; otherwise do; age_cat =4; age_label="50代以上"; end; end; run;
【書式2】 SELECT(選択式); WHEN (値1) ステートメント1; WHEN (値2) ステートメント2; ・・・; OTHERWISE ステートメントN; END; 【例】 data list_category_select2; set list; length sex_label $20.; select(sex); when(1) sex_label="男性"; when(2) sex_label="女性"; otherwise sex_label="不明"; end; run;
【IF-THEN-ELSEステートメントとの違い】
①指定した条件のいずれにも合致しない場合、エラーで終了する
基本的に、エラー回避のため、OTHERWISEを使用する。
②指定した条件群の複数に合致する場合は、最初に合致した条件のみに分岐する
IF-THENの場合、ELSEを使用しなければ複数の条件を同時に扱うことが可能である。
4. 条件式評価の実際
SASが条件式を評価し、条件が成り立つ・成り立たないのいずれかに判断する処理は「①比較演算・論理演算の実施」→「②演算の結果算出された数値に対して条件判断」という2ステップでおこなわれる。
まず、SASは比較演算子や論理演算子が含まれている式(条件式)に対しては必ず「比較演算・論理演算」と呼ばれる演算処理を行うことになっている。例えば比較式(x=y)が指定されている場合、その式が成り立つのであれば条件式の演算結果は1という数値になる。逆に比較式が成り立たない場合、演算結果は0という数値になる。つまり、条件式が比較演算・論理演算によって「1または0」どちらかの数値に置き換えられるというわけである。
そして、IF-THENステートメントによる条件分岐の実態は、与えられた条件式の演算結果である数値の内容に応じて条件分岐をおこなうことなのである。すなわち条件式の値が1(正確には0でも欠損値でもない)の場合、条件が成り立った(論理用語では「真」と呼ぶ)としてTHEN以下のステートメントが実行される。値が0(または欠損値)の場合は、条件が成り立たない(論理用語では「偽」と呼ぶ)としてELSE以下のステートメントが実行されるというわけだ。
data _null_; /*真*/ x = 1; if x then put x= "なので真である"; else put x= "なので偽である"; /*偽*/ x = 0; if x then put x= "なので真である"; else put x= "なので偽である"; /*偽*/ x = .; if x then put x= "なので真である"; else put x= "なので偽である"; /*真*/ if 1 or . or 0 then put ".と0以外を含むので真である"; else put ".または0なので偽である"; /*偽*/ if . or 0 then put ".と0以外を含むので真である"; else put ".または0なので偽である"; run;
上記のプログラムを実行すると、以下のログが出力される。
※SASデータセットを作成せずに、ログのみ出力したい場合など、DATAステートメントで「data _null_;」と指定する。
5. DOステートメント(反復処理)
あるSASステートメントの処理を繰り返し実行したいときは、DOステートメントを用いて反復処理を行う。
【書式1】 DO インデックス変数 = 初期値 TO 終了値 [BY 増分値]; ステートメント1; ステートメント2; ・・・; END; [BY 増分値]は省略することができ、省略した場合は1としてカウントアップする。 【例】 data sample_do1; do i = 1 to 2; do j = 1 to 10 by 2; output; end; end; run;
【実行結果】
【書式2】 DO インデックス変数 = 値1, 値2, 値3, ・・・, 値N; ステートメント1; ステートメント2; ・・・; END; 【例】 data sample_do2; length name $20.; do name = "Yamada", "Tanaka", "Suzuki", "Sato", "Uchida"; output; end; run;
【実行結果】
6. ARRAYステートメント(配列処理)
配列とは、複数の変数をまとめて定義した一時的な変数グループのことである。例えば複数の変数に対して同一処理をおこないたい場合、その変数群を配列として定義しておけば、変数指定の記述が大幅に省力化することができる。
配列の定義はARRAYステートメントで行う。
ARRAY 配列名(要素数) [$] [長さ] 変数リスト [(初期値リスト)];
・変数リストには、文字変数か数値変数のいずれかしか指定できない。
・配列の定義と同時に、初期値を割り当てることも可能で、長さも指定できる。
・要素数には、変数リストに指定した変数の数を指定しても良いが、一次元配列の場合はアスタリスク「*」を指定することもできる。
・要素数を囲むカッコには、丸カッコ()だけでなく、中カッコ{}や大カッコ[]も使用できる。
・配列は、定義したDATAステップ内だけで有効である。
・配列名は、通常の変数名と同様に、最大32バイト、先頭文字は数字以外、半角英数字と記号アンダースコア「_」のみで指定し、他の配列名、変数名、関数名などと被らないようにする。
※既存の配列名を指定した場合は上書きされ、関数名と同じにした場合は、それ以降のステートメントでその関数は使用できなくなる(配列名と見なされる)。
【例1】変数リストに、配列定義より前のステートメントで作成した数値変数を指定している data sample_array1; a1 = 1; a2 = 2; a3 = 3; array _a(3) a1 - a3; do i = 1 to 3; b = 11 * _a(i); output; end; drop i; run;
【実行結果】
【例2】変数リストに文字変数を指定し、同時に初期値も与える場合
data sample_array2; keep no name ; array _a(*) $20. a1 - a3 ("山田" "鈴木" "田中"); length no 8. name $20. ; do no = 1 to dim(_a); name = _a(no); output; end; run;
・要素数にアスタリスク「*」を指定している。
・DOステートメントの終了値にDIM関数を指定し、配列「_a」の要素数を取得している。
【実行結果】