【问题标题】:How can I to write Mata value to a txt-file?如何将 Mata 值写入 txt 文件?
【发布时间】:2017-06-25 11:57:25
【问题描述】:

我正在使用 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

所以它似乎有效。

我不明白为什么它可以在独立文件中工作,而不是在循环中。有什么帮助吗?

【问题讨论】:

    标签: stata


    【解决方案1】:

    为什么会这样?

    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 循环相同,仅以宏的值开头,没有任何实际的宏。

    这意味着,由于您将第一个 if 包装在 for 循环中,因此在执行循环之前,其中的宏会立即展开。您的 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循环被编译后才循环运行。

    如果这没有意义,Bill Gould 将在文章中进行更深入的介绍。

    这对您的代码意味着什么?

    您仍然可以在 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 块、for 循环或函数中,而是被编译然后立即执行,一个接一个。它们不是一次全部编译并作为一个块执行的。

    这意味着更改宏值的较早行会影响后面的行。当这些行编译在一起时,情况并非如此。

    【讨论】:

    • 马特,谢谢你非常详细的回答。我现在明白了很多。同时,我将循环的内容放在另一个 do-file 中,然后从循环中调用它。在这种情况下,宏似乎会随着每次迭代而更新并做我想做的事。但是您的解决方案要优雅得多。再次感谢你!我花了几天时间试图弄清楚。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-16
    • 2013-10-04
    • 2020-12-07
    相关资源
    最近更新 更多