SAS MACRO プログラミング#
このレッスンでは、SASマクロ言語で最も一般的に使用される機能を紹介します。プログラムを繰り返し実行する必要がある場合は、コードにマクロを使用することを真剰に検討する価値があります。なぜなら、
マクロを使用すると、プログラムの1か所を変更するだけで、SASがその変更をプログラム全体に反映させることができます
マクロを使用すると、同じプログラムまたは異なるプログラムで、コードの一部を一度書いて何度も使用できます
マクロを使用すると、プログラムをデータ駆動型にすることができ、SASが実際のデータ値に基づいて動作を決定できます
導入とさらなる例については、以下を参照してください。
Little SAS Book: A Primer, 5th ed.の第7章「Writing Flexible Code with the SAS Macro Facility」
Learning SAS by Example: A Programmer’s Guideの第25章「Introducing the SAS Macro Language」
ここの例では、心疾患のリスクに関する大規模な縦断的疫学研究であるデータセットFraminghamを使用します。fghm113.sas7bdatというデータセットファイルをダウンロードして、任意のフォルダーに置いてください。次に、以下のコードでLIBNAMEパスをこのフォルダーを指すように変更してください。
libname myData "/folders/myfolders/SAS_Notes/data";
*Create a temporary data set, so that we don't save changes to the original data set.;
data fghmtemp;
set myData.fghm113;
run;
/*Now let's code some variables with some more descriptive values.
SEX (Gender): 1=Men
2=Women
Period (Examination cycle): 1=Period1
2=Period2
3=Period3
BPMEDS (Use of anti-hypertensive meds): 0=Not currently
1=Currently use
CURSMOKE (Currently smoke?): 0=No
1=Yes
DIABETES: 0=Not diabetic
1=Diabetic
PREVAP (Have angina pectoric?): 0=No
1=Yes
PREVCHD (Coronary heart disease?): 0=No
1=Yes
PREVMI (Myocardial infarction?): 0=No
1=Yes
PREVSTRK (Had a stroke?): 0=No
1=Yes
PREVHYP (Hypertensive? sys bp >=140 or dyas bp >= 90): 0=no
1=yes
*/
proc format;
value YNfmt 0="No"
1="Yes";
value perfmt 1="Period 1"
2="Period 2"
3="Period 3";
value gndrfmt 1="Men"
2="Women";
run;
data fghmtemp;
set fghmtemp;
format prevap ynfmt.
diabetes ynfmt.
cursmoke ynfmt.
bpmeds ynfmt.
prevchd ynfmt.
prevmi ynfmt.
prevstrk ynfmt.
prevhyp ynfmt.
sex gndrfmt.;
run;
*Check to see if the formatting was done correctly;
proc contents data = fghmtemp;
run;
proc print data = fghmtemp (obs=5);
run;
CONTENTS プロシジャ
データセット名 | WORK.FGHMTEMP | オブザベーション数 | 500 |
---|---|---|---|
メンバータイプ | DATA | 変数の数 | 21 |
エンジン | V9 | インデックス数 | 0 |
作成日時 | 2024/06/06 08:36:05 | オブザベーションのバッファ長 | 168 |
更新日時 | 2024/06/06 08:36:05 | 削除済みオブザベーション数 | 0 |
保護 | 圧縮済み | NO | |
データセットタイプ | ソート済み | NO | |
ラベル | |||
データ表現 | SOLARIS_X86_64, LINUX_X86_64, ALPHA_TRU64, LINUX_IA64 | ||
エンコード | utf-8 Unicode (UTF-8) |
エンジン/ホスト関連情報 | |
---|---|
データセットのページサイズ | 131072 |
データセットのページ数 | 1 |
データページの先頭 | 1 |
ページごとの最大OBS数 | 779 |
先頭ページのOBS数 | 500 |
データセットの修復数 | 0 |
ファイル名 | /saswork/SAS_workED820000E33E_odaws01-apse1.oda.sas.com/SAS_work826B0000E33E_odaws01-apse1.oda.sas.com/fghmtemp.sas7bdat |
作成したリリース | 9.0401M7 |
作成したホスト | Linux |
I ノード番号 | 536886844 |
アクセス権限 | rw-r--r-- |
所有者名 | user-name |
ファイルサイズ | 256KB |
ファイルサイズ (バイト) | 262144 |
変数と属性リスト (アルファベット順) | ||||||
---|---|---|---|---|---|---|
# | 変数 | タイプ | 長さ | 出力形式 | 入力形式 | ラベル |
4 | AGE | 数値 | 8 | BEST12. | F12. | Age (years) at examination |
9 | BMI | 数値 | 8 | BEST12. | F12. | Body Mass Index (kr/(M*M) |
11 | BPMEDS | 数値 | 8 | YNFMT. | F12. | Anti-hypertensive meds Y/N |
8 | CIGPDAY | 数値 | 8 | BEST12. | F12. | Cigarettes per day |
7 | CURSMOKE | 数値 | 8 | YNFMT. | F12. | Current Cig Smoker Y/N |
10 | DIABETES | 数値 | 8 | YNFMT. | F12. | Diabetic Y/N |
6 | DIABP | 数値 | 8 | BEST12. | F12. | Diastolic BP mmHg |
13 | GLUCOSE | 数値 | 8 | BEST12. | F12. | Casual Glucose mg/dL |
20 | HDLC | 数値 | 8 | BEST12. | F12. | HDL Cholesterol mg/dL |
12 | HEARTRTE | 数値 | 8 | BEST12. | F12. | Ventricular Rate (beats/min) |
21 | LDLC | 数値 | 8 | BEST12. | F12. | LDL Cholesterol mg/dL |
19 | PERIOD | 数値 | 8 | BEST12. | F12. | Examination cycle |
15 | PREVAP | 数値 | 8 | YNFMT. | F12. | Prevalent Angina |
14 | PREVCHD | 数値 | 8 | YNFMT. | F12. | Prevalent CHD (MI,AP,CI) |
18 | PREVHYP | 数値 | 8 | YNFMT. | F12. | Prevalent Hypertension |
16 | PREVMI | 数値 | 8 | YNFMT. | F12. | Prevalent MI (Hosp,Silent) |
17 | PREVSTRK | 数値 | 8 | YNFMT. | F12. | Prevalent Stroke (Infarct,Hem) |
2 | RANDID | 数値 | 8 | BEST12. | F12. | Random ID |
1 | SEX | 数値 | 5 | GNDRFMT. | F12. | SEX |
5 | SYSBP | 数値 | 8 | BEST12. | F12. | Systolic BP mmHg |
3 | TOTCHOL | 数値 | 8 | BEST12. | F12. | Serum Cholesterol mg/dL |
OBS | SEX | RANDID | TOTCHOL | AGE | SYSBP | DIABP | CURSMOKE | CIGPDAY | BMI | DIABETES | BPMEDS | HEARTRTE | GLUCOSE | PREVCHD | PREVAP | PREVMI | PREVSTRK | PREVHYP | PERIOD | HDLC | LDLC |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | Women | 11263 | 220 | 55 | 180 | 106 | No | 0 | 31.17 | Yes | Yes | 86 | 81 | No | No | No | No | Yes | 3 | 46 | 135 |
2 | Men | 16365 | 211 | 55 | 173 | 123 | No | 0 | 29.11 | No | Yes | 75 | 85 | No | No | No | No | Yes | 3 | 48 | 163 |
3 | Women | 43770 | 283 | 64 | 159 | 69 | No | 0 | 32.93 | Yes | No | 70 | 230 | No | No | No | No | Yes | 3 | 45 | 238 |
4 | Men | 47561 | 290 | 56 | 132 | 70 | Yes | 40 | 22.73 | No | No | 100 | 90 | No | No | No | No | Yes | 3 | 54 | 236 |
5 | Women | 55965 | 298 | 72 | 109 | 60 | No | 0 | 26.2 | No | No | 80 | 100 | No | No | No | No | No | 3 | 38 | 260 |
マクロ変数と %LET#
%LET macro-variable-name = value;
ここで、macro-variable-nameは、標準のSAS名の規則(32文字以内、文字またはアンダースコアで始まり、文字、数字、アンダースコアのみを含む)に従って作成する名前です。valueは、マクロ変数名に置き換えられるテキストで、長さは最大64,000文字です。以下のステートメントはそれぞれマクロ変数を作成します。
%LET iterations = 5;
%LET winner = Lance Armstrong;
値には引用符は付けません。先頭と末尾のスペースは切り捨てられ、等号とセミコロンの間のすべてがマクロ変数の値になります。
マクロ変数を使用するには、前にアンパサンド(&)と後ろにピリオド(.)を追加し、マクロ変数名を値を置き換えたい場所に挿入するだけです。
ピリオドは省略可能ですが、後ろに文字を続ける場合には必須になるので、つけるのを習慣にしておくことをおすすめします。
例えば、
DO i = 1 TO &iterations.
TITLE "First: &winner.";
このコードの行があるプログラムを実行すると、最初にマクロプロセッサがマクロ変数の値を置き換えてSASコードを生成します。
DO i = 1 TO 5;
TITLE "First: Lance Armstrong";
そして、生成されたコードを通常どおり実行します。
例#
次のプログラムでは、3つのマクロ変数を使用してデータセット名と、そのデータセットから使用する2つの変数名を指定し、これらを使用して分割表とカイ2乗検定の出力を作成します。ここでは、糖尿病と過去の心血管疾患の関係をカイ2乗検定と分割表で示します。
%let response = prevchd;
%let predictor = diabetes;
%let dataset = fghmtemp;
title "&predictor vs &response.";
proc freq data = &dataset.;
table &predictor. * &response. / chisq;
run;
title;
FREQ プロシジャ
|
|
DIABETES * PREVCHD の統計量
統計量 | 自由度 | 値 | p 値 |
---|---|---|---|
カイ 2 乗値 | 1 | 7.8534 | 0.0051 |
尤度比カイ 2 乗値 | 1 | 6.3873 | 0.0115 |
連続性補正カイ 2 乗値 | 1 | 6.5483 | 0.0105 |
Mantel-Haenszel のカイ 2 乗値 | 1 | 7.8377 | 0.0051 |
ファイ係数 | 0.1253 | ||
一致係数 | 0.1244 | ||
Cramer の V 統計量 | 0.1253 |
Fisher の正確検定 | |
---|---|
セル (1,1) 度数 (F) | 408 |
左側 Pr <= F | 0.9972 |
右側 Pr >= F | 0.0090 |
表の確率 (P) | 0.0062 |
両側 Pr <= P | 0.0119 |
標本サイズ = 500
マクロ変数「response」と「predictor」は、TABLEステートメントとTITLEステートメントの両方を更新するために使用されていることに注目してください。マクロプロセッサを通過した後、次のSASコードが生成され実行されます。
title "diabetes vs prevchd";
proc freq data = fghmtemp;
table diabetes * prevchd / chisq;
run;
これは短いプログラムで、マクロ変数の出現回数は数回しかありませんでした。しかし、マクロ変数の出現回数が数十回あるような長いプログラムを想像してみてください。プログラムの冒頭でマクロ変数を一度変更するだけで、多くの時間と手間を節約できるでしょう。
マクロの機能#
同じプログラムステートメントを繰り返し書いていることに気づいたら、マクロを作成することを検討するべきかもしれません。マクロは、名前が付けられたSASステートメントのグループにすぎません。そのステートメントのグループを実行したい場合は、ステートメントを再入力する代わりにそのマクロを使用します。
マクロの一般的な形式は次のとおりです。
%MACRO macro-name(parameter-1=, parameter-2=,..., parameter-n= );
macro-text
%MEND macro-name;
例えば、「month」と「region」というパラメータを持つマクロ%MONTHLYREPORTの場合、次のように始まるでしょう。
%MACRO monthlyreport(month=, region= );
次に、マクロを呼び出す際は、等号の後にマクロ変数の値を指定します。
%monthlyreport(month=May, region=West);
例#
次のプログラムでは、前の%LETマクロ変数を使用したコードをマクロ関数に変更し、指定したデータセットの指定した2つの変数間でカイ2乗検定と分割表を作成します。
%macro twobytwo(dataset, predictor, response);
title "&predictor. vs &response.";
proc freq data = &dataset.;
table &predictor.*&response. / chisq;
run;
title;
%mend twobytwo;
%twobytwo(fghmtemp, diabetes, prevchd);
FREQ プロシジャ
|
|
DIABETES * PREVCHD の統計量
統計量 | 自由度 | 値 | p 値 |
---|---|---|---|
カイ 2 乗値 | 1 | 7.8534 | 0.0051 |
尤度比カイ 2 乗値 | 1 | 6.3873 | 0.0115 |
連続性補正カイ 2 乗値 | 1 | 6.5483 | 0.0105 |
Mantel-Haenszel のカイ 2 乗値 | 1 | 7.8377 | 0.0051 |
ファイ係数 | 0.1253 | ||
一致係数 | 0.1244 | ||
Cramer の V 統計量 | 0.1253 |
Fisher の正確検定 | |
---|---|
セル (1,1) 度数 (F) | 408 |
左側 Pr <= F | 0.9972 |
右側 Pr >= F | 0.0090 |
表の確率 (P) | 0.0062 |
両側 Pr <= P | 0.0119 |
標本サイズ = 500
前と同じ出力を取得できましたが、今回はマクロを使用しています。またマクロでパラメータ名を指定していません。マクロの実行にパラメータ名を使用しない場合は、パラメータの値を正しい順序で指定する必要があります。この例では、マクロ twobytwoはデータセットを最初に、次に予測変数(行変数)、最後に応答変数(列変数)を想定しています。
MPRINT システムオプション#
マクロプロセッサが解決したプログラムをSASが扱うことを示しましたが、通常はこれらのステートメントは表示されません。ただし、プログラムでMPRINTシステムオプションを指定すると、SASはマクロから生成された解決済みのステートメントをログに出力します。これはデバッグ目的で役立ちます。MPRINTオプションを有効にするには、次のようにOPTIONSステートメントを実行します。
OPTIONS MPRINT;
ログは次のようになります。(この例ではPROC FREQのNOPRINTオプションを追加して出力を抑制しています。)
%macro twobytwo(dataset, predictor, response);
title "&predictor. vs &response.";
proc freq data = &dataset. noprint;
table &predictor.*&response. / chisq;
run;
title;
%mend twobytwo;
options mprint;
%twobytwo(fghmtemp, diabetes, prevchd);
options nomprint;
15 SAS システム 2024年 6月 6日 木曜日 08時35分00秒
171 ods listing close;ods html5 (id=saspy_internal) file=_tomods1 options(bitmap_mode='inline') device=svg style=HTMLBlue;
171 ! ods graphics on / outputfmt=png;
172
173 options notes ;
174 %macro twobytwo(dataset, predictor, response);
175 title "&predictor. vs &response.";
176 proc freq data = &dataset. noprint;
177 table &predictor.*&response. / chisq;
178 run;
179 title;
180 %mend twobytwo;
181
182 options mprint;
183
184 %twobytwo(fghmtemp, diabetes, prevchd);
MPRINT(TWOBYTWO): title "diabetes vs prevchd";
MPRINT(TWOBYTWO): proc freq data = fghmtemp noprint;
MPRINT(TWOBYTWO): table diabetes*prevchd / chisq;
MPRINT(TWOBYTWO): run;
NOTE: 表示出力または出力データセットへの有効な要求がないため、処理が終了されます。
NOTE: PROCEDURE FREQ処理(合計処理時間):
処理時間 0.00 秒
ユーザーCPU時間 0.00 秒
システムCPU時間 0.00 秒
メモリ 332.96k
OSメモリ 18848.00k
タイムスタンプ 2024/06/06 午前08:37:15
ステップ数 11 スイッチ数 0
ページフォルト回数 0
ページリクレーム回数 54
ページスワップ回数 0
自発的コンテキストスイッチ回数 0
非自発的コンテキストスイッチ回数 0
ブロック入力操作回数 0
ブロック出力操作回数 0
MPRINT(TWOBYTWO): title;
185
186 options nomprint;
187
188
189 ods html5 (id=saspy_internal) close;ods listing;
190
16 SAS システム 2024年 6月 6日 木曜日 08時35分00秒
191
MPRINTオプションを使用すると、SASがMPRINTの後にマクロの名前(この場合はtwobytwo)を表示して、そのマクロによって生成されたステートメントをラベル付けしていることが分かります。MPRINTシステムオプションを使用すると、マクロが生成する標準的なSASステートメントを簡単に確認できます。
%DO ループ#
DOループは繰り返しのコードを簡素化するのに役立ちますが、通常のDOループはデータステップ内でしか使用できません。変数を少し変えながら同じプロシージャを繰り返し実行したい場合はどうすればよいでしょうか。このような場合、%DOループが役立ちます。このステートメントの一般的な形式は次のとおりです。
%DO index-variable = start TO end;
SAS code;
%END;
index-variableはループのカウンター変数としてのマクロ変数で、startからendまで動作します。このようなループはPROCステップやデータステップの外で使用でき、複数のこれらのステップをループ処理できます。
例#
以下のように大量の変数の組み合わせが異なる2x2表を作成したいとします。
title "prevap vs prevchd";
proc freq data = fghmtemp;
table prevap * prevchd / chisq;
run;
title "diabetes vs prevchd";
proc freq data = fghmtemp;
table diabetes * prevchd / chisq;
run;
title "prevmi vs prevchd";
proc freq data = fghmtemp;
table prevmi * prevchd / chisq;
run;
title "prevstrk vs prevchd";
proc freq data = fghmtemp;
table prevstrk * prevchd / chisq;
run;
title "prevhyp vs prevchd";
proc freq data = fghmtemp;
table prevhyp * prevchd / chisq;
run;
FREQ プロシジャ
|
|
PREVAP * PREVCHD の統計量
統計量 | 自由度 | 値 | p 値 |
---|---|---|---|
WARNING: セルの25%において、期待度数が5より小さくなっています。 カイ2乗検定は妥当な検定でないと思われます。 |
|||
カイ 2 乗値 | 1 | 337.9100 | <.0001 |
尤度比カイ 2 乗値 | 1 | 209.3011 | <.0001 |
連続性補正カイ 2 乗値 | 1 | 328.4425 | <.0001 |
Mantel-Haenszel のカイ 2 乗値 | 1 | 337.2342 | <.0001 |
ファイ係数 | 0.8221 | ||
一致係数 | 0.6350 | ||
Cramer の V 統計量 | 0.8221 |
Fisher の正確検定 | |
---|---|
セル (1,1) 度数 (F) | 443 |
左側 Pr <= F | 1.0000 |
右側 Pr >= F | <.0001 |
表の確率 (P) | <.0001 |
両側 Pr <= P | <.0001 |
標本サイズ = 500
FREQ プロシジャ
|
|
DIABETES * PREVCHD の統計量
統計量 | 自由度 | 値 | p 値 |
---|---|---|---|
カイ 2 乗値 | 1 | 7.8534 | 0.0051 |
尤度比カイ 2 乗値 | 1 | 6.3873 | 0.0115 |
連続性補正カイ 2 乗値 | 1 | 6.5483 | 0.0105 |
Mantel-Haenszel のカイ 2 乗値 | 1 | 7.8377 | 0.0051 |
ファイ係数 | 0.1253 | ||
一致係数 | 0.1244 | ||
Cramer の V 統計量 | 0.1253 |
Fisher の正確検定 | |
---|---|
セル (1,1) 度数 (F) | 408 |
左側 Pr <= F | 0.9972 |
右側 Pr >= F | 0.0090 |
表の確率 (P) | 0.0062 |
両側 Pr <= P | 0.0119 |
標本サイズ = 500
FREQ プロシジャ
|
|
PREVMI * PREVCHD の統計量
統計量 | 自由度 | 値 | p 値 |
---|---|---|---|
WARNING: セルの25%において、期待度数が5より小さくなっています。 カイ2乗検定は妥当な検定でないと思われます。 |
|||
カイ 2 乗値 | 1 | 256.8548 | <.0001 |
尤度比カイ 2 乗値 | 1 | 153.8559 | <.0001 |
連続性補正カイ 2 乗値 | 1 | 247.5882 | <.0001 |
Mantel-Haenszel のカイ 2 乗値 | 1 | 256.3411 | <.0001 |
ファイ係数 | 0.7167 | ||
一致係数 | 0.5826 | ||
Cramer の V 統計量 | 0.7167 |
Fisher の正確検定 | |
---|---|
セル (1,1) 度数 (F) | 443 |
左側 Pr <= F | 1.0000 |
右側 Pr >= F | <.0001 |
表の確率 (P) | <.0001 |
両側 Pr <= P | <.0001 |
標本サイズ = 500
FREQ プロシジャ
|
|
PREVSTRK * PREVCHD の統計量
統計量 | 自由度 | 値 | p 値 |
---|---|---|---|
WARNING: セルの25%において、期待度数が5より小さくなっています。 カイ2乗検定は妥当な検定でないと思われます。 |
|||
カイ 2 乗値 | 1 | 5.4832 | 0.0192 |
尤度比カイ 2 乗値 | 1 | 3.7434 | 0.0530 |
連続性補正カイ 2 乗値 | 1 | 3.1716 | 0.0749 |
Mantel-Haenszel のカイ 2 乗値 | 1 | 5.4723 | 0.0193 |
ファイ係数 | 0.1047 | ||
一致係数 | 0.1042 | ||
Cramer の V 統計量 | 0.1047 |
Fisher の正確検定 | |
---|---|
セル (1,1) 度数 (F) | 438 |
左側 Pr <= F | 0.9925 |
右側 Pr >= F | 0.0519 |
表の確率 (P) | 0.0444 |
両側 Pr <= P | 0.0519 |
標本サイズ = 500
FREQ プロシジャ
|
|
PREVHYP * PREVCHD の統計量
統計量 | 自由度 | 値 | p 値 |
---|---|---|---|
カイ 2 乗値 | 1 | 8.6231 | 0.0033 |
尤度比カイ 2 乗値 | 1 | 9.2098 | 0.0024 |
連続性補正カイ 2 乗値 | 1 | 7.8028 | 0.0052 |
Mantel-Haenszel のカイ 2 乗値 | 1 | 8.6059 | 0.0034 |
ファイ係数 | 0.1313 | ||
一致係数 | 0.1302 | ||
Cramer の V 統計量 | 0.1313 |
Fisher の正確検定 | |
---|---|
セル (1,1) 度数 (F) | 191 |
左側 Pr <= F | 0.9993 |
右側 Pr >= F | 0.0021 |
表の確率 (P) | 0.0013 |
両側 Pr <= P | 0.0039 |
標本サイズ = 500
コードはすべて同じですが、行の変数のみがPROC FREQの呼び出しごとに変更されています。このコードを何度も書く代わりに、%DOループを使用できます。出力を短くするため、最初の2つのPROC FREQの呼び出しだけを使用します。
%macro twobytwov2(dataset, predictor, response);
%do i=1 %to %sysfunc(countw(&predictor., ' '));
%let dep = %scan(&predictor., &i.);
title "&dep. vs &response.";
proc freq data = &dataset.;
table &dep. * &response. / chisq;
run;
title;
%end;
%mend;
*%twobytwov2(fghmtemp, prevap diabetes prevmi prevstrk prevhyp, prevchd);
%twobytwov2(fghmtemp, prevap diabetes, prevchd);
FREQ プロシジャ
|
|
PREVAP * PREVCHD の統計量
統計量 | 自由度 | 値 | p 値 |
---|---|---|---|
WARNING: セルの25%において、期待度数が5より小さくなっています。 カイ2乗検定は妥当な検定でないと思われます。 |
|||
カイ 2 乗値 | 1 | 337.9100 | <.0001 |
尤度比カイ 2 乗値 | 1 | 209.3011 | <.0001 |
連続性補正カイ 2 乗値 | 1 | 328.4425 | <.0001 |
Mantel-Haenszel のカイ 2 乗値 | 1 | 337.2342 | <.0001 |
ファイ係数 | 0.8221 | ||
一致係数 | 0.6350 | ||
Cramer の V 統計量 | 0.8221 |
Fisher の正確検定 | |
---|---|
セル (1,1) 度数 (F) | 443 |
左側 Pr <= F | 1.0000 |
右側 Pr >= F | <.0001 |
表の確率 (P) | <.0001 |
両側 Pr <= P | <.0001 |
標本サイズ = 500
FREQ プロシジャ
|
|
DIABETES * PREVCHD の統計量
統計量 | 自由度 | 値 | p 値 |
---|---|---|---|
カイ 2 乗値 | 1 | 7.8534 | 0.0051 |
尤度比カイ 2 乗値 | 1 | 6.3873 | 0.0115 |
連続性補正カイ 2 乗値 | 1 | 6.5483 | 0.0105 |
Mantel-Haenszel のカイ 2 乗値 | 1 | 7.8377 | 0.0051 |
ファイ係数 | 0.1253 | ||
一致係数 | 0.1244 | ||
Cramer の V 統計量 | 0.1253 |
Fisher の正確検定 | |
---|---|
セル (1,1) 度数 (F) | 408 |
左側 Pr <= F | 0.9972 |
右側 Pr >= F | 0.0090 |
表の確率 (P) | 0.0062 |
両側 Pr <= P | 0.0119 |
標本サイズ = 500
この マクロでは、代わりに行の変数のリストをスペース区切りでパラメータ「predictor」に渡します。前回学んだCOUNTWとSCAN関数は今回もデータステップの外で使用する必要があるため、%SYSFUNC マクロ関数を使ってこれらの関数を評価する必要があります。COUNTWはリスト内の単語数(この場合はスペースで区切られている)を数えることを思い出してください。SASには既にSCAN のマクロバージョンである%SCANがあり、これを使って行変数のリストを処理できます。残りのコードは前と同じですが、%DOループを使って「predictor」内の行変数のリストを処理する必要があります。
マクロの条件付きロジック#
マクロとマクロ変数を使用すると、非常に柔軟性が高まります。さらにその柔軟性を高めるには、%IFなどの条件付きマクロステートメントを使用します。マクロでの条件付きロジックに使用されるステートメントの一般的な形式は次のとおりです。
%IF condition %THEN action;
%ELSE %IF condition %THEN action;
%ELSE action;
%IF condition %THEN %DO;
action;
%END;
これらのステートメントは、標準のSASコードにも同様のものがあるので見覚えがあるかもしれません。しかし、これらと標準のものを混同しないでください。DOループと同様に、通常のIF/THEN/ELSEステートメントはデータステップ内でしか使用できません。%IF/%THEN/%ELSEステートメントは、データステップやPROCステップの外で、他のマクロの中でも使用できます。
例#
次のプログラムでは、マクロtwobytwoに「Yes」または「No」の値を取るパラメータを作成することで、PROC FREQからリスク差の出力を要求するかどうかを指定できるようにしています。
%macro twobytwov2(dataset, predictor, response, rd=no);
%do i=1 %to %sysfunc(countw(&predictor., ' '));
%let dep = %scan(&predictor., &i.);
%if &rd. = no %then %do;
title "&dep. vs &response.";
proc freq data = &dataset.;
table &dep. * &response. / chisq;
run;
title;
%end;
%else %if &rd. = yes %then %do;
title "&dep. vs &response.";
proc freq data = &dataset.;
table &dep. * &response. / chisq riskdiff;
run;
title;
%end;
%end;
%mend;
%twobytwov2(dataset=fghmtemp, predictor=diabetes, response=prevchd, rd=yes);
*%twobytwov2(dataset=fghmtemp, predictor=diabetes, response=prevchd);
FREQ プロシジャ
|
|
DIABETES * PREVCHD の統計量
統計量 | 自由度 | 値 | p 値 |
---|---|---|---|
カイ 2 乗値 | 1 | 7.8534 | 0.0051 |
尤度比カイ 2 乗値 | 1 | 6.3873 | 0.0115 |
連続性補正カイ 2 乗値 | 1 | 6.5483 | 0.0105 |
Mantel-Haenszel のカイ 2 乗値 | 1 | 7.8377 | 0.0051 |
ファイ係数 | 0.1253 | ||
一致係数 | 0.1244 | ||
Cramer の V 統計量 | 0.1253 |
Fisher の正確検定 | |
---|---|
セル (1,1) 度数 (F) | 408 |
左側 Pr <= F | 0.9972 |
右側 Pr >= F | 0.0090 |
表の確率 (P) | 0.0062 |
両側 Pr <= P | 0.0119 |
列 1 リスクの推定値 | ||||||
---|---|---|---|---|---|---|
リスク | ASE | 95% 信頼限界 |
正確 95% 信頼限界 |
|||
行 1 - 行 2 の差 | ||||||
行 1 | 0.8987 | 0.0142 | 0.8709 | 0.9264 | 0.8672 | 0.9249 |
行 2 | 0.7609 | 0.0629 | 0.6376 | 0.8841 | 0.6123 | 0.8741 |
合計 | 0.8860 | 0.0142 | 0.8581 | 0.9139 | 0.8548 | 0.9125 |
差 | 0.1378 | 0.0645 | 0.0115 | 0.2642 |
列 2 リスクの推定値 | ||||||
---|---|---|---|---|---|---|
リスク | ASE | 95% 信頼限界 |
正確 95% 信頼限界 |
|||
行 1 - 行 2 の差 | ||||||
行 1 | 0.1013 | 0.0142 | 0.0736 | 0.1291 | 0.0751 | 0.1328 |
行 2 | 0.2391 | 0.0629 | 0.1159 | 0.3624 | 0.1259 | 0.3877 |
合計 | 0.1140 | 0.0142 | 0.0861 | 0.1419 | 0.0875 | 0.1452 |
差 | -0.1378 | 0.0645 | -0.2642 | -0.0115 |
標本サイズ = 500
rdパラメータは「Yes」か「No」を受け取り、デフォルト値は「No」です。「No」を指定した場合(または空白のままにした場合)は、カイ2乗の出力のみが得られます。rdに「Yes」を指定すると、カイ2乗の出力とリスク差の出力の両方が得られます。 マクロ定義でrdのデフォルト値を指定していることに注目してください。デフォルト値を指定すると、位置パラメータを作成することになり、この場合、マクロを呼び出す際にはすべてのパラメータをパラメータ名=パラメータ値の形式で指定する必要があります。
データ駆動プログラム - CALL SYMPUT#
CALL SYMPUTマクロルーチンを使用すると、マクロプログラムがデータを見て、自身で何をすべきかを決定できます。CALL Symputはデータステップから値を取り、その値をマクロ変数に割り当てます。あとでそのマクロ変数をプログラムで使用できます。
CALL SYMPUTには多くの形式がありますが、単一の値を単一のマクロ変数に割り当てる場合は、次の一般的な形式でCALL SYMPUTを使用します。
CALL SYMPUTX("macro-variable", value);
実際に使用するCALLルーチンとしては、CALL SYMPUTではなくCALL SYMPUTXをおすすめします。
CALL SYMPUTで必要になる第二引数を数値から文字値に変換する、先頭や末尾の余分なブランクを除く処理がCALL SYMPUTXでは自動で行われます。
ここで、macro-variableは新しいまたは既存のマクロ変数の名前で、引用符で囲まれています。valueはデータステップ内の変数名で、その現在値をそのマクロ変数に割り当てる値です。
CALL SYMPUTはしばしばIF/THEN/ELSEステートメントで使用されます。例えば
IF Place = 1 THEN
CALL SYMPUTX("WinningTime", Time);
このステートメントは、「Place」の値が1のときに、マクロ変数「WinningTime」を作成し、その値を変数「Time」の現在値に設定するようにしています。
CALL SYMPUTでマクロ変数を作成しても、同じデータステップ内でその変数を使用することができないことには注意が必要です。その理由は次のとおりです。マクロコードを実行すると、最初にマクロプロセッサによって解決され、次にコンパイルされ、最後に実行されます。実行段階でようやくSASがデータを認識します。CALL SYMPUTは実行段階でデータ値を取得し、後で使用するためにマクロプロセッサにその値を渡します。そのため、CALL SYMPUTをデータステップに配置する必要がありますが、その後のステップでしか使用できません。
例#
次のプログラムでは、PROC FREQによって計算された期待度数を使用して、カイ2乗検定のp値とフィッシャーの正確確率検定のp値のどちらを返すかを判断しています。カイ2乗検定を使用するための一般的な規則の1つは、すべての期待度数が5以上であることです。
次のコードは予備的なものであり、マクロを定義する方法を見つけるために実行しています。
/*First, we will need to write and test our code for selecting only the output we want before
we make our updated macro. We want to run a continuity adjusted chi-square test or
Fisher's exact test if the expected counts are too small. We only want the table with row percentages
and the result of the correct test in our output.*/
*ODS TRACE ON;
proc freq data = fghmtemp;
table prevap*prevchd / expected chisq;
ods output CrossTabFreqs = ct ChiSq = chi FishersExact = fet;
run;
*ODS TRACE OFF;
*Lot's of missing data. We only want to use non missing values;
proc print data = ct;
run;
/* Test how to clean the resulting datasets */
/* Remove the missing values and get the cells with epxected countes less than 5 */
title '/* Test how to clean the resulting datasets */';
proc print data=ct;
where expected < 5 and prevap ^= . and prevchd ne .;
run;
title;
*Create an indicator variable that is 1 if there is at least one cell with expected count less than 5;
%let low_count = 0;
data _null_; *Run through the data set without creating a new one;
set ct;
if expected < 5 and prevap ^= . and prevchd ^= . then call symput('low_count', 1);
RUN;
%put &=low_count; *Should show value of 1 in the log file.;
/* Now, that we can check to see if the expected cell counts are less than 5,
* we need to see how we can clean the chi-square or Fisher tables to print only
* the test name and p-value.
*/
proc print data=chi;
run;
*Select the row for the continuity adjusted chi-square test;
data chi2;
set chi;
where statistic="Continuity Adj. Chi-Square";
drop TABLE DF VALUE;
run;
proc print data = chi2;
run;
*Do the same thing for Fisher's exact test;
proc print data = fet;
run;
data fet2 (rename = (cValue1 = Prob));
set fet;
Statistic = "Fisher's Exact Test";
where NAME1 = "XP2_FISH";
keep statistic cValue1;
run;
data fet2;
retain Statistic Prob;
set fet2;
run;
proc print data = fet2;
run;
FREQ プロシジャ
|
|
PREVAP * PREVCHD の統計量
統計量 | 自由度 | 値 | p 値 |
---|---|---|---|
WARNING: セルの25%において、期待度数が5より小さくなっています。 カイ2乗検定は妥当な検定でないと思われます。 |
|||
カイ 2 乗値 | 1 | 337.9100 | <.0001 |
尤度比カイ 2 乗値 | 1 | 209.3011 | <.0001 |
連続性補正カイ 2 乗値 | 1 | 328.4425 | <.0001 |
Mantel-Haenszel のカイ 2 乗値 | 1 | 337.2342 | <.0001 |
ファイ係数 | 0.8221 | ||
一致係数 | 0.6350 | ||
Cramer の V 統計量 | 0.8221 |
Fisher の正確検定 | |
---|---|
セル (1,1) 度数 (F) | 443 |
左側 Pr <= F | 1.0000 |
右側 Pr >= F | <.0001 |
表の確率 (P) | <.0001 |
両側 Pr <= P | <.0001 |
標本サイズ = 500
OBS | Table | PREVAP | PREVCHD | _TYPE_ | _TABLE_ | Frequency | Expected | Percent | RowPercent | ColPercent | Missing |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 表 : PREVAP * PREVCHD | No | No | 11 | 1 | 443 | 407.56 | 88.60 | 96.30 | 100.00 | . |
2 | 表 : PREVAP * PREVCHD | No | Yes | 11 | 1 | 17 | 52.44 | 3.40 | 3.70 | 29.82 | . |
3 | 表 : PREVAP * PREVCHD | No | . | 10 | 1 | 460 | . | 92.00 | . | . | . |
4 | 表 : PREVAP * PREVCHD | Yes | No | 11 | 1 | 0 | 35.44 | 0.00 | 0.00 | 0.00 | . |
5 | 表 : PREVAP * PREVCHD | Yes | Yes | 11 | 1 | 40 | 4.56 | 8.00 | 100.00 | 70.18 | . |
6 | 表 : PREVAP * PREVCHD | Yes | . | 10 | 1 | 40 | . | 8.00 | . | . | . |
7 | 表 : PREVAP * PREVCHD | . | No | 01 | 1 | 443 | . | 88.60 | . | . | . |
8 | 表 : PREVAP * PREVCHD | . | Yes | 01 | 1 | 57 | . | 11.40 | . | . | . |
9 | 表 : PREVAP * PREVCHD | . | . | 00 | 1 | 500 | . | 100.00 | . | . | 0 |
OBS | Table | PREVAP | PREVCHD | _TYPE_ | _TABLE_ | Frequency | Expected | Percent | RowPercent | ColPercent | Missing |
---|---|---|---|---|---|---|---|---|---|---|---|
5 | 表 : PREVAP * PREVCHD | Yes | Yes | 11 | 1 | 40 | 4.56 | 8.00 | 100.00 | 70.18 | . |
OBS | Table | Statistic | DF | Value | Prob |
---|---|---|---|---|---|
1 | 表 : PREVAP * PREVCHD | カイ 2 乗値 | 1 | 337.9100 | <.0001 |
2 | 表 : PREVAP * PREVCHD | 尤度比カイ 2 乗値 | 1 | 209.3011 | <.0001 |
3 | 表 : PREVAP * PREVCHD | 連続性補正カイ 2 乗値 | 1 | 328.4425 | <.0001 |
4 | 表 : PREVAP * PREVCHD | Mantel-Haenszel のカイ 2 乗値 | 1 | 337.2342 | <.0001 |
5 | 表 : PREVAP * PREVCHD | ファイ係数 | _ | 0.8221 | _ |
6 | 表 : PREVAP * PREVCHD | 一致係数 | _ | 0.6350 | _ |
7 | 表 : PREVAP * PREVCHD | Cramer の V 統計量 | _ | 0.8221 | _ |
OBS | Table | Name1 | Label1 | cValue1 | nValue1 |
---|---|---|---|---|---|
1 | 表 : PREVAP * PREVCHD | Cell1_FREQ | セル (1,1) 度数 (F) | 443 | 443.000000 |
2 | 表 : PREVAP * PREVCHD | XPL_FISH | 左側 Pr <= F | 1.0000 | 1.000000 |
3 | 表 : PREVAP * PREVCHD | XPR_FISH | 右側 Pr >= F | <.0001 | 6.222358E-46 |
4 | 表 : PREVAP * PREVCHD | . | |||
5 | 表 : PREVAP * PREVCHD | P_TABLE | 表の確率 (P) | <.0001 | 6.125565E-43 |
6 | 表 : PREVAP * PREVCHD | XP2_FISH | 両側 Pr <= P | <.0001 | 6.222358E-46 |
OBS | Statistic | Prob |
---|---|---|
1 | Fisher's Exact Test | <.0001 |
前のコードは探索的なものであり、ODSテーブル名を確認し、必要なデータをこれらのテーブルから抽出する方法を確認するためのものです。次のコードが最終的な動作するマクロです。
%macro twobytwov3(dataset, predictor, response);
%let n = %sysfun(countw(&predictor.));
%let i = 1;
%let dep = %scan(&predictor., &i.);
%do %while(&dep. ^=);
title;
ods select none;
ods output crosstabfreqs = ct ChiSq = chi FishersExact = fet;
proc freq data = &dataset.;
table &dep.*&response. / chisq expected;
run;
title "&dep. vs &response.";
ods select CrossTabFreqs;
proc freq data = &dataset.;
table &dep.*&response. / nocol nopercent;
run;
title;
%let low_count = 0;
data _null_; *Run through the data set without creating a new one;
set ct;
if expected < 5 and &dep. ^= . and &response. ^= . then call symputx('low_count', 1);
run;
%if &low_count. = 0 %then %do;
data chi;
set chi;
where statistic="Continuity Adj. Chi-Square";
drop TABLE DF VALUE;
run;
proc print data = chi;
run;
%end;
%else %do;
data fet (rename = (cValue1 = Prob));
set fet;
Statistic = "Fisher's Exact Test";
where NAME1 = "XP2_FISH";
keep statistic cValue1;
run;
data fet;
retain Statistic Prob;
set fet;
run;
proc print data = fet;
run;
%end;
%let i = %eval(&i. + 1);
%let dep = %scan(&predictor., &i);
%end;
%mend;
%twobytwov3(fghmtemp, prevap diabetes prevmi prevstrk prevhyp, prevchd);
FREQ プロシジャ
|
|
OBS | Statistic | Prob |
---|---|---|
1 | Fisher's Exact Test | <.0001 |
FREQ プロシジャ
|
|
FREQ プロシジャ
|
|
OBS | Statistic | Prob |
---|---|---|
1 | Fisher's Exact Test | <.0001 |
FREQ プロシジャ
|
|
OBS | Statistic | Prob |
---|---|---|
1 | Fisher's Exact Test | 0.0519 |
FREQ プロシジャ
|
|
このプログラムはPROC FREQを使用して期待度数を計算し、ODS OUTPUTを使用してこのテーブルを抽出します。いずれかのセルの期待度数が5未満の場合、CALL SYMPUTはマクロ変数lowcountの値を1に設定します。それ以外の場合は初期値0のままです。このマクロ変数は、%IFステートメントでカイ2乗検定のp値かフィッシャーの正確確率検定のp値を保存して出力するかを判断するのに使用されます。
演習#
量的変数の値を以下のように4つのカテゴリーに分割するマクロを書いてください。:
X < Q1の場合、group = 1
Q1 < X < Medianの場合、group = 2
Median < X < Q3の場合、group = 3
Q3 < Xの場合、group = 4
このマクロの定義は次のようになります。%quartilesmacro(mydata, qvar, round, out);
mydata: 量的変数を含むデータセット
qvar: 量的変数の名前
round: 小数点以下の桁数
out: 出力データセット名。この中にカテゴリ化された変数「qvar_cat」が含まれます。例えば、「qvar」が”bmi”の場合、出力変数は「bmi_cat」になります。