#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! Законы природы всегда остаются в силе. Это утверждение иногда верно.