Как превратить две петли в Двойную петлю в Stata?

#loops #for-loop #foreach #stata

Вопрос:

У меня есть эти два функциональных (рабочих) цикла:

 * Loop that creates 1/0 variables  foreach x in m1 m2 m3 m4 {   gen yn_`x' = beforedate * `x'  }         * Loop that creates four dichotomous lag variables foreach x in 0 3 12 18 {   gen lag`x' = refdate gt; (date   30 * `x')   }  

И я хочу объединить петли в одну двойную петлю. Ниже приведена моя попытка сделать это, но она не работает.

 foreach x in m1 m2 m3 m4 {  foreach y in 0 3 12 18 {   gen yn_`x' = beforedate * `x'  gen lag`y' = refdate gt; (date   30 * `y')   }   }   

Ошибка, которую я получаю (ниже). Эта ошибка, похоже, связана с моими интервалами и вкладками (но я не совсем уверен в этом).

переменная yn_m1 уже определена.

Образец моих данных:

 * Example generated by -dataex-. To install: ssc install dataex clear input float id byte(m1 m2 m3 m4) float(beforedate refdate) int date  1 . . . . 0 16594 .  2 . . . . 0 18228 .  3 . . . . 0 18238 .  4 . . . . 0 18237 .  5 0 0 0 0 1 18016 16324  6 . . . . 0 16324 .  7 . . . . 0 16914 .  8 1 0 0 0 1 18226 17333  9 . . . . 0 17096 . 10 0 0 0 0 0 17961 17962 11 . . . . 0 16978 . 12 . . . . 0 17844 . 13 . . . . 0 17207 . 14 . . . . 0 17141 . 15 . . . . 0 16338 . 16 . . . . 0 16100 . 17 . . . . 0 17498 . 18 . . . . 0 17394 . 19 . . . . 0 18207 . 20 . . . . 0 18043 . 21 . . . . 0 16851 . 22 . . . . 0 18027 . 23 . . . . 0 17723 . 24 . . . . 0 16475 . 25 1 1 0 0 1 16097 16079 26 . . . . 0 16613 . 27 . . . . 0 17350 . 28 . . . . 0 17972 . 29 . . . . 0 18009 . 30 1 0 0 0 0 18008 18184 31 . . . . 0 16840 . 32 0 1 0 0 1 18179 17370 33 . . . . 0 16224 . 34 . . . . 0 17400 . 35 . . . . 0 17015 . 36 . . . . 0 16880 . 37 . . . . 0 16637 . 38 . . . . 0 16566 . 39 . . . . 0 17056 . 40 . . . . 0 18073 . 41 . . . . 0 17076 . 42 0 1 0 0 0 16179 17447 43 . . . . 0 16422 . 44 . . . . 0 16184 . 45 . . . . 0 16495 . 46 . . . . 0 17168 . 47 1 1 0 0 0 18001 18001 48 . . . . 0 16649 . 49 . . . . 0 17150 . 50 . . . . 0 17426 . 51 . . . . 0 16237 . 52 1 0 0 0 0 17681 17841 53 0 1 0 0 1 17874 16377 54 . . . . 0 16992 . 55 0 1 0 0 1 16377 16307 56 0 1 0 0 0 18066 18149 57 . . . . 0 16428 . 58 . . . . 0 18256 . 59 . . . . 0 16845 . 60 0 1 0 0 1 17997 16631 61 . . . . 0 17899 . 62 . . . . 0 16849 . 63 . . . . 0 16687 . 64 . . . . 0 18074 . 65 . . . . 0 17428 . 66 . . . . 0 16140 . 67 0 1 0 0 0 17938 18004 68 . . . . 0 16326 . 69 . . . . 0 17362 . 70 0 1 0 0 1 16954 16079 71 0 0 0 0 1 17974 16853 72 1 0 0 0 0 17077 17892 73 1 0 1 0 0 16453 17787 74 . . . . 0 18148 . 75 . . . . 0 18042 . 76 . . . . 0 16156 . 77 . . . . 0 16509 . 78 . . . . 0 17285 . 79 . . . . 0 16348 . 80 . . . . 0 17908 . 81 1 1 0 0 0 17932 17992 82 . . . . 0 17436 . 83 . . . . 0 17900 . 84 . . . . 0 16644 . 85 0 0 0 0 0 17170 18108 86 . . . . 0 17292 . 87 . . . . 0 16874 . end format %td refdate format %d date  

Комментарии:

1. Почему вы недовольны своими отдельными циклами? Ваш комбинированный цикл делает другое, он повторяется 4×4 = 16 раз, в то время как ваш исходный код повторяется 2×4 = 8 раз.

2. Люди часто пишут вложенные циклы, когда проблема требует параллельных циклов. Здесь все петли имеют общее то, что они состоят из более чем 4 элементов.

Ответ №1:

Чтобы сделать то, что предлагают Ник и Ваутер, вам нужно поместить два списка, которые вы передаете foreach , в локальные, а затем просмотреть их вместе:

 * loops in parallel  local mlist "m1 m2 m3 m4" local nlist "0 3 12 18" local n : word count `nlist'  local m : word count `mlist' assert `n'==`m' // require same length   forvalues i = 1/`n' {  local a : word `i' of `mlist'  local b : word `i' of `nlist'  gen yn_`a'_II = beforedate * `a'  gen lag`b'_II = refdate gt; (date   30 * `b')  }   

Этот метод полезен во многих случаях, даже если этот пример не относится к их числу.

РЕДАКТИРОВАТЬ NJC

Если вы возьмете линию, в которой вы можете ясно видеть, что в каждом случае есть четыре элемента, это можно свести к

 local nlist "0 3 12 18"  forvalues i = 1/4 {  local n : word `i' of `nlist'  gen yn_m`i'_II = beforedate * m'i'   gen lag`b'_II = refdate gt; (date   30 * `n')  }   

и действительно, к этому

 tokenize "0 3 12 18"  forvalues i = 1/4 {  gen yn_m`i'_II = beforedate * m'i'   gen lag`b'_II = refdate gt; (date   30 * ``i'')  }   

Хотя вы можете это сделать, я (NJC) не думаю, что это особенно хороший стиль для объединения несвязанных циклов, подобных этому. Люди, читающие ваш код, могут быть озадачены этим, если вы не добавите пояснительный комментарий, который скорее отменяет любую аккуратность в кодировании.

КОНЕЦ РЕДАКТИРОВАНИЯ

Комментарии:

1. Подробное руководство по параллельным циклам опубликовано в журнале Stata 21(4) 2021 года.

2. Это иллюстрирует второй закон ответа на вопросы с тегами Stata: @Nick Cox написал статью в журнале Stata , которая отвечает на этот вопрос.

3. Ha! Законы природы всегда остаются в силе. Это утверждение иногда верно.