SAS入門7

Last-modified: 2014-09-24 (水) 00:08:23

SASマクロ?

SASは,入門1-6で紹介してきた,データステップとプロックステップにしたがって実行されますが,これだけだと少し使い勝手に問題があります.
たとえば,異なる100個のデータセットを印刷したければ,100回PRINTプロシジャを書き並べる必要があります.
ステップは,シーケンスに書き並べたとおりに順次処理されますが,ステップ自体を繰り返したり,共通化して再度呼び出すといった機能を持っていません.
そのため,SAS本来の処理の前に,マクロというSASプログラムをマークアップして,構造化するプリプロセッサ機能があります.
少し本格的な処理をしようとすれば,マクロは知っているとたいへん便利なので,簡単に紹介して,入門の最後とします.

3種類のあやめのデータサンプル

%LETステートメント

まず,覚えておくべきことは,マクロは,SASプログラムの中に,
%で始まるマクロの命令文と,&で始まるマクロ変数で記述されるので,
本来のSASプログラムとマクロ記述部分は,読むときも記述する時も,混乱しないようにしましょう.

さて,もっとも初歩的なマクロ機能に,一部の文字列だけを可変にする%LETがあります.例を示します.

irisのデータセットからあやめ種setosaだけのサブセットを作ることにします.

data iris_setosa;
 set iris;
 if class="setosa";
run;

ここで,2つの点に注意しましょう.

  1. データセット名とIFステートメントの2箇所に 「setosa」が書かれている.
  2. 今後,この処理を別なあやめ種にも応用するかもしれない.
    実際に2箇所だけであれば,たいしたことはありませんが,同じ言葉が
    多数繰り返すことになるなら,共通化したほうがわかりやすいし記述ミスも減らせます.
    そこで,setosaの部分を次のように可変にします.
%let iclass=setosa;
data iris_&iclass;
 set iris;
 if class="&iclass";
run;

%letからセミコロン(;)までは,SASマクロ命令文で,本来のSASプログラムではありません.
ここで,マクロ変数iclassに,文字列 setosa が与えられています.
そして,それ以降は,setosaの代わりに,マクロ変数iclassが,代用されています.
マクロ変数は,本来のSASプログラムと区別するため,&で始めます.
これで,元のプログラムとまったく同じ処理が実行されますが,
もし,あやめ種を別にしたくなったら,%letで,マクロ変数iclassの値だけ変えれば,
他は変更しなくてよくなります.

%MACROステートメント

マクロをサブモジュールとして定義して,繰り返し呼び出すことができます.
その中で使われるマクロ変数を引数として呼び出し時に与えることもできます.

%macro miris(iclass); /*mirisという名前でマクロモジュールを定義*/
data iris_&iclass;
 set iris;
 if class="&iclass";
run;
proc print data=iris_&iclass;
run;
%mend;
%miris(setosa) /* マクロ%mirisの呼び出し*/
%miris(versicolo) /* マクロ%mirisの呼び出し*/
%miris(virginica) /* マクロ%mirisの呼び出し*/

%DO マクロ変数=はじめ %TO 終わり

%macroのマクロモジュールの定義の中では,%DOなどのマクロ制御文も使えます.

%macro miris();
%do i=1 %to 5; /*マクロ変数&iを1から5まで繰り返す*/
data iris&i;
 set iris;
 if &i<=sepalL<&i+1 then output; /*ガク片がi.00~i.99までをirisiとする*/
run;
proc freq data=iris&i;
  tables class;
run;
%end;
%mend;
%miris()

マクロ変数について補足説明しておきます.

  1. マクロ変数は,SASプログラムの一部の代用なので,保持する値は文字列だけです.
  2. マクロ変数は,参照される部分が文字列の途中など区切りが認識できないような部分である場合,ピリオド(.)を使って,変数の終わりを認識させます.
    たとえば,
    %let mvar=test;
    data ds&mvarnew -> mvarが認識できない
    data ds&mvar.new -> data dstestnew と展開される
  3. したがって,マクロ変数をピリオドの前に展開する場合は,ピリオドを2つ並べなければいけない
    data ds&mvar..new -> data dstest.new
  4. 文字定数の中でマクロ変数を参照する場合は,ダブル(")を使うこと
    'this is &mvar data' -> 'this is &mvar data' &mvarという文字列のまま
    "this is &mvar data" -> "this is test data" と展開される

最後にマクロについての注意事項を.

  1. マクロは,実行する本当のSASプログラムをマクロ文の意味にしたがって生成する事前処理機能です.
    したがって%DOで,PRINTプロシジャを1億回繰り返せば,実際にPRINTプロシジャをが1億個連なったSASプログラムが生成され,それをSASが実行開始します.
    そのため,思わぬ実行負荷がかかる場合があるので,どのようにSASプログラムに展開されるかを想定して書いてください.
  2. マクロは,非常に便利で,うまくつかえばかなり複雑な処理でも書くことができます.
    しかし,なるべくマクロはシンプルに,わかりやすい書き方にするよう心がけましょう.
    複雑なマクロプログラムは,書いた本人にも,解読できないということがよくあります.
  3. マクロのヘルプ

    ヘルプメニュー>SASヘルプとドキュメント>目次>SASプロダクト>Base SAS>SASマクロ言語リファレンス>マクロ言語リファレンス>マクロ言語リファレンス

質問・意見

サマリ 質問の要旨を簡潔にお願いします。
お名前
状態
メッセージ

質問・意見一覧

状態
↑(1)
サマリ投稿者ページ名[_past]
無題anonymous?SAS入門7/11207297668
マクロ中でのDOループでの%の使い方についてZOID?SAS入門7/21411484903

以下は、SASのエディタWINDOWでコピペして使えます

/*
SASは,入門1-6で紹介してきた,データステップとプロックステップ
にしたがって実行されますが,これだけだと少し使い勝手に問題があります.
たとえば,異なる100個のデータセットを印刷したければ,
100回PRINTプロシジャを書き並べる必要があります.
ステップは,シーケンスに書き並べたとおりに順次処理されますが,
ステップ自体を繰り返したり,共通化して再度呼び出すといった機能を持っていません.
そのため,SAS本来の処理の前に,マクロというSASプログラムを
マークアップして,構造化するプリプロセッサ機能があります.
少し本格的な処理をしようとすれば,マクロは知っているとたいへん便利なので,
簡単に紹介して,入門の最後とします.
*/


options nocenter compress=yes;
libname mydata "c;\";



/*
3種類のあやめのデータサンプル
*/
data iris;
  length class $ 9;
  input sepalL /*がくの長さ unit=cm*/
        sepalW /*がくの幅 unit=cm*/
        petalL /*花びらの長さ unit=cm*/
        petalW /*花びらの幅 unit=cm*/
        class $ /*あやめの種類*/
                @@; /*データ行を改行しない*/
cards;
5.1 3.5 1.4 0.2 setosa  7.0 3.2 4.7 1.4 versicolor      6.3 3.3 6.0 2.5 virginica
4.9 3.0 1.4 0.2 setosa  6.4 3.2 4.5 1.5 versicolor      5.8 2.7 5.1 1.9 virginica
4.7 3.2 1.3 0.2 setosa  6.9 3.1 4.9 1.5 versicolor      7.1 3.0 5.9 2.1 virginica
4.6 3.1 1.5 0.2 setosa  5.5 2.3 4.0 1.3 versicolor      6.3 2.9 5.6 1.8 virginica
5.0 3.6 1.4 0.2 setosa  6.5 2.8 4.6 1.5 versicolor      6.5 3.0 5.8 2.2 virginica
5.4 3.9 1.7 0.4 setosa  5.7 2.8 4.5 1.3 versicolor      7.6 3.0 6.6 2.1 virginica
4.6 3.4 1.4 0.3 setosa  6.3 3.3 4.7 1.6 versicolor      4.9 2.5 4.5 1.7 virginica
5.0 3.4 1.5 0.2 setosa  4.9 2.4 3.3 1.0 versicolor      7.3 2.9 6.3 1.8 virginica
4.4 2.9 1.4 0.2 setosa  6.6 2.9 4.6 1.3 versicolor      6.7 2.5 5.8 1.8 virginica
4.9 3.1 1.5 0.1 setosa  5.2 2.7 3.9 1.4 versicolor      7.2 3.6 6.1 2.5 virginica
5.4 3.7 1.5 0.2 setosa  5.0 2.0 3.5 1.0 versicolor      6.5 3.2 5.1 2.0 virginica
4.8 3.4 1.6 0.2 setosa  5.9 3.0 4.2 1.5 versicolor      6.4 2.7 5.3 1.9 virginica
4.8 3.0 1.4 0.1 setosa  6.0 2.2 4.0 1.0 versicolor      6.8 3.0 5.5 2.1 virginica
4.3 3.0 1.1 0.1 setosa  6.1 2.9 4.7 1.4 versicolor      5.7 2.5 5.0 2.0 virginica
5.8 4.0 1.2 0.2 setosa  5.6 2.9 3.6 1.3 versicolor      5.8 2.8 5.1 2.4 virginica
5.7 4.4 1.5 0.4 setosa  6.7 3.1 4.4 1.4 versicolor      6.4 3.2 5.3 2.3 virginica
5.4 3.9 1.3 0.4 setosa  5.6 3.0 4.5 1.5 versicolor      6.5 3.0 5.5 1.8 virginica
5.1 3.5 1.4 0.3 setosa  5.8 2.7 4.1 1.0 versicolor      7.7 3.8 6.7 2.2 virginica
5.7 3.8 1.7 0.3 setosa  6.2 2.2 4.5 1.5 versicolor      7.7 2.6 6.9 2.3 virginica
5.1 3.8 1.5 0.3 setosa  5.6 2.5 3.9 1.1 versicolor      6.0 2.2 5.0 1.5 virginica
5.4 3.4 1.7 0.2 setosa  5.9 3.2 4.8 1.8 versicolor      6.9 3.2 5.7 2.3 virginica
5.1 3.7 1.5 0.4 setosa  6.1 2.8 4.0 1.3 versicolor      5.6 2.8 4.9 2.0 virginica
4.6 3.6 1.0 0.2 setosa  6.3 2.5 4.9 1.5 versicolor      7.7 2.8 6.7 2.0 virginica
5.1 3.3 1.7 0.5 setosa  6.1 2.8 4.7 1.2 versicolor      6.3 2.7 4.9 1.8 virginica
4.8 3.4 1.9 0.2 setosa  6.4 2.9 4.3 1.3 versicolor      6.7 3.3 5.7 2.1 virginica
5.0 3.0 1.6 0.2 setosa  6.6 3.0 4.4 1.4 versicolor      7.2 3.2 6.0 1.8 virginica
5.0 3.4 1.6 0.4 setosa  6.8 2.8 4.8 1.4 versicolor      6.2 2.8 4.8 1.8 virginica
5.2 3.5 1.5 0.2 setosa  6.7 3.0 5.0 1.7 versicolor      6.1 3.0 4.9 1.8 virginica
5.2 3.4 1.4 0.2 setosa  6.0 2.9 4.5 1.5 versicolor      6.4 2.8 5.6 2.1 virginica
4.7 3.2 1.6 0.2 setosa  5.7 2.6 3.5 1.0 versicolor      7.2 3.0 5.8 1.6 virginica
4.8 3.1 1.6 0.2 setosa  5.5 2.4 3.8 1.1 versicolor      7.4 2.8 6.1 1.9 virginica
5.4 3.4 1.5 0.4 setosa  5.5 2.4 3.7 1.0 versicolor      7.9 3.8 6.4 2.0 virginica
5.2 4.1 1.5 0.1 setosa  5.8 2.7 3.9 1.2 versicolor      6.4 2.8 5.6 2.2 virginica
5.5 4.2 1.4 0.2 setosa  6.0 2.7 5.1 1.6 versicolor      6.3 2.8 5.1 1.5 virginica
4.9 3.1 1.5 0.1 setosa  5.4 3.0 4.5 1.5 versicolor      6.1 2.6 5.6 1.4 virginica
5.0 3.2 1.2 0.2 setosa  6.0 3.4 4.5 1.6 versicolor      7.7 3.0 6.1 2.3 virginica
5.5 3.5 1.3 0.2 setosa  6.7 3.1 4.7 1.5 versicolor      6.3 3.4 5.6 2.4 virginica
4.9 3.1 1.5 0.1 setosa  6.3 2.3 4.4 1.3 versicolor      6.4 3.1 5.5 1.8 virginica
4.4 3.0 1.3 0.2 setosa  5.6 3.0 4.1 1.3 versicolor      6.0 3.0 4.8 1.8 virginica
5.1 3.4 1.5 0.2 setosa  5.5 2.5 4.0 1.3 versicolor      6.9 3.1 5.4 2.1 virginica
5.0 3.5 1.3 0.3 setosa  5.5 2.6 4.4 1.2 versicolor      6.7 3.1 5.6 2.4 virginica
4.5 2.3 1.3 0.3 setosa  6.1 3.0 4.6 1.4 versicolor      6.9 3.1 5.1 2.3 virginica
4.4 3.2 1.3 0.2 setosa  5.8 2.6 4.0 1.2 versicolor      5.8 2.7 5.1 1.9 virginica
5.0 3.5 1.6 0.6 setosa  5.0 2.3 3.3 1.0 versicolor      6.8 3.2 5.9 2.3 virginica
5.1 3.8 1.9 0.4 setosa  5.6 2.7 4.2 1.3 versicolor      6.7 3.3 5.7 2.5 virginica
4.8 3.0 1.4 0.3 setosa  5.7 3.0 4.2 1.2 versicolor      6.7 3.0 5.2 2.3 virginica
5.1 3.8 1.6 0.2 setosa  5.7 2.9 4.2 1.3 versicolor      6.3 2.5 5.0 1.9 virginica
4.6 3.2 1.4 0.2 setosa  6.2 2.9 4.3 1.3 versicolor      6.5 3.0 5.2 2.0 virginica
5.3 3.7 1.5 0.2 setosa  5.1 2.5 3.0 1.1 versicolor      6.2 3.4 5.4 2.3 virginica
5.0 3.3 1.4 0.2 setosa  5.7 2.8 4.1 1.3 versicolor      5.9 3.0 5.1 1.8 virginica

;
proc print;run;


/*
%LETステートメント
まず,覚えておくべきことは,マクロは,SASプログラムの中に,
%で始まるマクロの命令文と,&で始まるマクロ変数で記述されるので,
本来のSASプログラムとマクロ記述部分は,読むときも記述する時も,
混乱しないようにしましょう.

さて,もっとも初歩的なマクロ機能に,一部の文字列だけを可変にする%LET
があります.例を示します.
irisのデータセットからあやめ種setosaだけのサブセットを作ることにします.
*/

data iris_setosa;
  set iris;
  if class="setosa";
run;

/*
ここで,2つの点に注意しましょう.
1.データセット名とIFステートメントの2箇所に 「setosa」が書かれている.
2.今後,この処理を別なあやめ種にも応用するかもしれない.
実際に2箇所だけであれば,たいしたことはありませんが,同じ言葉が
多数繰り返すことになるなら,共通化したほうがわかりやすいし記述ミスも減らせます.
そこで,setosaの部分を次のように可変にします.
*/

%let iclass=setosa;

data iris_&iclass;
  set iris;
  if class="&iclass";
run;

/*
%letからセミコロン(;)までは,SASマクロ命令文で,本来のSASプログラムではありません.
ここで,マクロ変数iclassに,文字列 setosa が与えられています.
そして,それ以降は,setosaの代わりに,マクロ変数iclassが,代用されています.
マクロ変数は,本来のSASプログラムと区別するため,&で始めます.
これで,元のプログラムとまったく同じ処理が実行されますが,
もし,あやめ種を別にしたくなったら,%letで,マクロ変数iclassの値だけ変えれば,
他は変更しなくてよくなります.
*/


/*
%MACROステートメント
マクロをサブモジュールとして定義して,繰り返し呼び出すことができます.
その中で使われるマクロ変数を引数として呼び出し時に与えることもできます.
*/



%macro miris(iclass); /*mirisという名前でマクロモジュールを定義*/
data iris_&iclass;
  set iris;
  if class="&iclass";
run;
proc print data=iris_&iclass;
run;
%mend;

%miris(setosa) /* マクロ%mirisの呼び出し*/
%miris(versicolo) /* マクロ%mirisの呼び出し*/
%miris(virginica) /* マクロ%mirisの呼び出し*/


/*
%DO マクロ変数=はじめ %TO 終わり 
%macroのマクロモジュールの定義の中では,%DOなどのマクロ制御文も
使えます.
*/


%macro miris();
%do i=1 %to 5; /*マクロ変数&iを1から5まで繰り返す*/
data iris&i;
  set iris;
  if &i<=sepalL<&i+1 then output; /*ガク片がi.00~i.99までをirisiとする*/
run;
proc freq data=iris&i;
  tables class;
run;
%end;
%mend;
%miris()


/*
マクロ変数について補足説明しておきます.
1.マクロ変数は,SASプログラムの一部の代用なので,
保持する値は文字列だけです.
2.マクロ変数は,参照される部分が文字列の途中など区切りが認識できないような
部分である場合,ピリオド(.)を使って,変数の終わりを認識させます.
たとえば,
%let mvar=test;
data ds&mvarnew -> mvarが認識できない
data ds&mvar.new -> data dstestnew と展開される
3.したがって,マクロ変数をピリオドの前に展開する場合は,ピリオドを2つ並べなければいけない
data ds&mvar..new -> data dstest.new
4.文字定数の中でマクロ変数を参照する場合は,ダブル(")を使うこと
'this is &mvar data' -> 'this is &mvar data' &mvarという文字列のまま
"this is &mvar data" -> "this is test data" と展開される
*/



/*
最後にマクロについての注意事項を.

1.マクロは,実行する本当のSASプログラムを
マクロ文の意味にしたがって生成する事前処理機能です.
したがって%DOで,PRINTプロシジャを1億回繰り返せば,
実際にPRINTプロシジャをが1億個連なったSASプログラムが生成され,
それをSASが実行開始します.
そのため,思わぬ実行負荷がかかる場合があるので,どのようにSASプログラムに
展開されるかを想定して書いてください.

2.マクロは,非常に便利で,うまくつかえばかなり複雑な処理でも書くことができます.
しかし,なるべくマクロはシンプルに,わかりやすい書き方にするよう心がけましょう.
複雑なマクロプログラムは,書いた本人にも,解読できないということがよくあります.

3.マクロのヘルプ
ヘルプメニュー>SASヘルプとドキュメント>目次>SASプロダクト>Base SAS
>SASマクロ言語リファレンス>マクロ言語リファレンス>マクロ言語リファレンス

*/



*****************************************************************
END
*****************************************************************;