ループに関するエトセトラ

ループコマンドは繰り返し実行するコマンドを指定して自動化するという、

プログラミングらしいコマンドですが、本稿では以下のコンテンツに沿って説明していきます.

コンテンツ
  1. 種類と具体的な使い方について:foreach, forvalues
  2. 注意点

① 種類と使い方について

1)foreachの基本構文:foreachの直後の要素は3つ.

  ⇒ local変数名、in または of リストタイプ、数列または文字列

.foreach lclname in または of リストタイプ 数列または文字列 {
       `lclname' を含んだcommand syntax
        } 
規則1. “{” のあとはコメント以外は何も書かない
規則2. コマンドsyntaxは新しい行にする
規則3. “}” は新しい行で、単独にする

そして以下のパターンがあります.

1. foreach lclname in any_list {
2. foreach lclname of local local_macro_name   {
3. foreach lclname of global global_macro_name   {
4. foreach lclname of varlist  varlist    {
5. foreach lclname of newlist  newvarlist {
6. foreach lclname of numlist  numlist    {

2)forvalues の基本構文

.forvalues lclname = range {
       `lclname' を含んだcommand syntax
        } 
rangeの表現方法
1. #1(#d)#2      : #1 ~ #2の範囲で、#dずつの幅で    
2. #1/#2         : #1 ~ #2 の範囲のすべての整数     
3. #1 #t to #2   : #1 ~ #2の範囲で、#t – #1ずつの幅で
4. #1 #t :  #2    : #1 ~ #2の範囲で、#t – #1ずつの幅で

② 注意点

1)数が多すぎるエラー

参照URL

foreach lclname of num 1/1600以上の数値 {
     } 

“invalid numlist has too many elements”

というエラーがでてしまいます.

forvalues lclname = 1/1600以上の数値 {
     } 

これならOKのようです.

2)変数名ではなく値でループを回したい①

.foreach lclname of varlist var1 var2 var3 … {

ここでvar1~3は変数名でなければなりません.

(後から使う新しい変数名のときは “varlist” ではなく ”numlist” で書きますが)

このとき、“varlist” の代わりに

”local +文字列の入ったlocal macro”

とすればlocal変数に格納された数列をあたかも一つ一つを変数として扱うようにループコマンドを走らせることができます.

例えばある条件で絞り込んだIDのリストで、特定変数の結果を表示させたい場合、”levelsof”を使うと便利です.

.levelsof ID if (条件節) , local(levels)
.foreach lclname of local levels {
.list ID var1 var2 var3 ... if ID== "`lclname'"
} 

このとき、”ID”という変数に含まれ、特定の条件で絞り込まれた値が数列としてlocal 変数である”levels”の中に格納されます.

そのlocal変数を呼び出すことで中に格納された値でループを回せるという優れものです.

sysuse census, clear
  levelsof state in 1/10, local(levels)
        foreach v of local levels {
                display "`v'" 
        } 

3)変数名ではなく値でループを回したい②

  ⇒ Macroで連番を振ってループに乗せる

local macroにしてもglobal macroにしても、

展開中のデータの変数リストに無い文字列を入れる場合には、

その文字列を ” ” で括って作ればいいのですが、

それに連番を振ると、さらに楽になります.

例.

.local lclname1 “string1”

.local lclname2 “string2”

.local lclname3 “string3”

.local lclname4 “string4”

このように定義しておくと、変数の一部に文字列が含まれているような状況のときに便利です.

例えば、

 forvalues n = 1/4 {
   `lclname`n'' を一部に含んだ変数を用いたコマンドsyntax
} 

これのいいところは、

foreach v of varlist string1 string2 string3 string4 {
...
} 

としたときに、もし string1 という変数が存在しないと

エラーが帰ってきてしまうのですが、

それを防げるという点にあります.

例えば、複合心血管イベントのそれぞれのイベント発生率を計算するループを作りたい場合、

そのイベントの名前が生存分析の要素となる変数(イベント有無、イベントまでの時間など)にいろいろ使われている場合に便利です.

例えば、aval_cvd はCVDイベントまでの時間、cnsr_cvdはイベント有無の変数として、

local cvd1 "cvd"
local cvd2 "hf"
local cvd3 "cad"
local cvd4 "stroke"
forvalues n = 1/4 {
stset aval_`cvd`n'' , failure(cnsr_`cvd`n'' == 0)
count if cnsr_`cvd`n'' == 0
local ev = r(N)
stsum
local ir = r(ir)*1000
noi disp "`cvd`n''", `ev', %4.1f `ir'
}

こうすればイベント発生数と発生率(1000人年当たり)がきれいに出力され、結果を整えるのがとても楽です.

まとめ

・ループコマンドについてまとめました.

・local macroなどと組み合わせてちょっとした工夫をすると結果の出力が楽になります.

コメント

  1. […] ループを使って繰り返しのコマンドをひとまとめにするコツを以前の記事でまとめていますが、今回は、ループをいくつも重ねてすっきり洗練されたプログラムを書くコツをまとめてみたいと思います. […]

タイトルとURLをコピーしました