foreach命令宏中的多个本地

时间:2017-10-28 21:57:41

标签: stata stata-macros

我有一个包含多个子组(变量economist)和日期(变量temps99)的数据集。

我想运行一个不接受tabsplitbysort前缀的by命令。所以我创建了一个宏来将tabsplit命令应用于我的数据中的每个子组。

例如:

levelsof economist, local(liste)

foreach gars of local liste {
    display "`gars'"
    tabsplit SubjectCategory if economist=="`gars'", p(;) sort 
    return list
    replace nbcateco = r(r) if economist == "`gars'"
}

对于每个子组,Stata运行tabsplit命令,并使用变量nbcateco来存储计数结果。

我在约会时做了同样的事情,所以随着时间的推移我可以进行r(r)的演变:

levelsof temps99, local(liste23)

foreach time of local liste23 {
    display "`time'"
    tabsplit SubjectCategory if temps99 == "`time'", p(;) sort
    return list
    replace nbcattime = r(r) if temps99 == "`time'"
}

现在我希望按日期economist在每个子组temps99上执行此操作。我尝试了多种组合,但我对宏不是很好(但是?)。

我想要的是能够随着时间的推移为我的每个小组提供r(r)

2 个答案:

答案 0 :(得分:2)

这是一个解决方案,展示了如何计算每个分组中不同发布类别的数量。这使用runby(来自SSC)。 runby遍历每个by-group,每次用当前副组的数据替换内存中的数据。对于每个副组,执行用户程序中包含的命令。当用户的程序终止时留在存储器中的任何内容被认为是结果并累积。处理完所有组后,这些结果将替换内存中的数据。

我使用了verbose选项,因为我想使用漂亮的格式为每个分组显示结果。通过拆分每个列表,转换为长布局,并将每个不同值减少到一个观察值来完成不同类别列表的推导。 distinct_categories程序生成一个变量,其中包含按组的不同类别的最终计数。

* create a demontration dataset
* ------------------------------------------------------------------------------
clear all
set seed 12345

* Example generated by -dataex-. To install: ssc install dataex
clear
input str19 economist
"Carmen M. Reinhart" 
"Janet Currie"       
"Asli Demirguc-Kunt" 
"Esther Duflo"       
"Marianne Bertrand"  
"Claudia Goldin"     
"Bronwyn Hughes Hall"
"Serena Ng"          
"Anne Case"          
"Valerie Ann Ramey"  
end

expand 20
bysort economist: gen temps99 = 1998 + _n
gen pubs = runiformint(1,10)
expand pubs
sort economist temps99
gen pubid = _n
local nep NEP-AGR NEP-CBA NEP-COM NEP-DEV NEP-DGE NEP-ECM NEP-EEC NEP-ENE ///
          NEP-ENV NEP-HIS NEP-INO NEP-INT NEP-LAB NEP-MAC NEP-MIC NEP-MON ///
          NEP-PBE NEP-TRA NEP-URE
gen SubjectCategory = ""
forvalues i=1/19 {
    replace SubjectCategory = SubjectCategory + " " + word("`nep'",`i') ///
        if runiform() < .1
}
replace SubjectCategory = subinstr(trim(SubjectCategory)," ",";",.)
leftalign   // from SSC
* ------------------------------------------------------------------------------


program distinct_categories
  dis _n _n _dup(80) "-"
  dis as txt "fille = " as res economist[1] as txt _col(68) " temps = " as res temps99[1]

  // if there are no subjects for the group, exit now to avoid a no obs error
  qui count if !mi(trim(SubjectCategory))
  if r(N) == 0 exit

  // split categories, reshape to a long layout, and reduce to unique values
  preserve
  keep pubid SubjectCategory
  quietly {
    split SubjectCategory, parse(;) gen(cat)
    reshape long cat, i(pubid)
    bysort cat: keep if _n == 1
    drop if mi(cat)
  }

  // show results and generate the wanted variable
  list cat
  local distinct = _N
  dis _n as txt "distinct = " as res `distinct'
  restore
  gen wanted = `distinct'
end

runby distinct_categories, by(economist temps99) verbose

答案 1 :(得分:1)

我认为这是XY问题的一个例子。见http://xyproblem.info/

tabsplit是来自SSC的包tab_chi中的命令。就像我写的那样,我对它没有负面的感觉,但这里似乎没有必要。

您想要计算字符串变量中的类别:分号是您的分隔符。所以计算分号并添加1.

local SC SubjectCategory
gen NCategory = 1 + length(`SC') - length(subinstr(`SC', ";", "", .)) 

然后(例如)tabletabstat会让您进一步探索感兴趣的群组。

要查看计数概念,请考虑3个类别,包含2个分号。

. display length("frog;toad;newt")
14

. display length(subinstr("frog;toad;newt", ";", "", .))
12

如果我们用空字符串替换每个分号,则长度的变化是删除的分号数。请注意,我们不必更改变量来执行此操作。然后添加1.另请参阅this paper

那就是说,扩展你的方法的方法可能是

egen class = group(economist temps99), label 
su class, meanonly 
local nclass = r(N)
gen result = . 

forval i = 1/`nclass' {
    di "`: label (class) `i''" 
    tabsplit SubjectCategory if class == `i', p(;) sort
    return list
    replace result = r(r) if class == `i'
}

使用statsby会更好。另见this FAQ