我正在使用Stata 14 SE。我有相当长的脚本,利用嵌套循环生成一些蒙特卡罗数据。在某些时候循环可能会失败,然后我想将它写入一个txt文件,以便我知道它在什么时候失败。
为此,我使用以下代码。这部分是在一个函数的几个循环内,在一些其他循环中被调用。
if(f_iterations == f_it_max - 1) {
stata(`" display "Price Iteration Failed" "')
st_local("filenumber_ll",filenumber)
st_local("j_ll",strofreal(j))
st_local("filenumber_ll")
st_local("j_ll")
stata(`" display "Filenumber=`filenumber_ll'" "')
stata(`" display "J=`j_ll'" "')
stata(`" file write myfile4 `" Failure in file `filenumber_ll', market `j_ll' "' _n "')
}
它在Stata中返回以下输出:
Price Iteration Failed
001
2
Filenumber=
J=
正如您所见,Stata看到" filenumber_ll"的价值。和" j_ll"但拒绝显示它并写入文件。
顺便说一下,我也在独立代码中尝试了这些命令:
mata
j=5
filenumber="filenumber"
filenumber
st_local("j_ll",strofreal(j))
st_local("filenumber_ll",filenumber)
stata(`" display "Filenumber=`filenumber_ll'" "')
stata(`" display "J=`j_ll'" "')
stata(`" file open myfile25 using `"!test.txt"', write replace "')
stata(`" file write myfile25 `"Failure in file `filenumber_ll', market `j_ll'"' _n "')
stata(`" file close myfile25 "')
end
然后我收到这个输出:
filenumber
Filenumber=filenumber
J=5
所以它似乎有效。
我不明白为什么它在独立文件中工作,但不在循环中。有什么帮助吗?
答案 0 :(得分:2)
Bill Gould写了一篇非常有用的文章,名为 Mata Matters: Macros 。我建议阅读整篇文章,但我会注意到一个重要的部分是在Stata和Mata中宏的扩展方式不同。
在Stata中,for循环中宏的值可以随着循环的每次迭代而改变:
forvalues i = 1/100 {
* The for-loop has only one line of code and one macro,
* but the macro expands to 100 different values over
* the course of the loop.
display `i'
}
但是,在Mata中,宏只扩展一次 - 编译Mata函数或语句时。如果再次运行该函数,则宏不会再次展开,即使其值已更改。
换句话说,首先编译Mata代码,在此期间所有宏都会立即展开一次,然后执行编译后的代码。执行的代码是否会更改宏的值并不重要,因为宏将永远不会再在该Mata代码中进行扩展。
对于for循环,就好像Mata在循环中搜索任何宏,用它们的值替换它们,然后才运行for循环。生成的代码与您编写只包含宏开头的for循环的代码相同,没有任何实际的宏。
这意味着,由于您在for循环中包含了第一个if
,因此在执行循环之前,其中的宏会立即展开。您的if
块包含以下行:
st_local("j_ll",strofreal(j))
st_local("filenumber_ll",filenumber)
stata(`" display "Filenumber=`filenumber_ll'" "')
stata(`" display "J=`j_ll'" "')
如果首次编译for循环时未设置`j_ll'
和`filenumber'
,则会立即将其展开。它与您键入的内容完全相同:
st_local("j_ll",strofreal(j))
st_local("filenumber_ll",filenumber)
stata(`" display "Filenumber=" "')
stata(`" display "J=" "')
只有扩展宏并且编译的for循环才是循环运行。
如果这没有意义,比尔古尔德在文章中更深入。
您仍然可以在Mata中访问宏的更改值,您无法使用`localname'
语法来执行此操作。相反,请使用st_local()
。你的最后两行将成为:
stata(`" display "Filenumber="' + st_local("filenumber_ll") + `"" "')
stata(`" display "J="' + st_local("j_ll") + `"" "')
如果在编译Mata代码后需要访问单个宏的更改值或宏集的值,请使用st_local()
。 `localname'
通常保留用于在编译Mata代码之前访问宏集的不变值。
现在,这两行并不是世界上最易读的代码。要简化它,只需使用已存在的Mata变量:
stata(`" display "Filenumber="' + filenumber + `"" "')
stata(`" display "J="' + strofreal(j) + `"" "')
更好的是,将stata(`"display ..."')
替换为Mata display()
函数:
display("Filenumber=" + filenumber)
display("J=" + strofreal(j))
同样,使用fopen()
和其他Mata文件函数而不是stata(`"file ..."')
。或者不使用文件,只需在代码末尾显示的Mata变量中保存所需的值,或使用_error()
引发错误并立即停止代码。
您的代码以交互方式工作,因为交互式语句不包含在if-block,for-loop或函数中,然后编译然后立即执行,一个接一个。它们不是一次编译而是作为一个块执行。
这意味着更改宏值的早期行会影响后面的行。线条编译在一起时并非如此。