Stata:替换,如果,forvalues

时间:2013-10-31 21:01:37

标签: loops if-statement stata

use "locationdata.dta", clear
gen ring=.
* Philly City Hall
gen lat_center = 39.9525468
gen lon_center = -75.1638855
destring(INTPTLAT10), replace
destring(INTPTLON10), replace
vincenty INTPTLAT10 INTPTLON10 lat_center lon_center , hav(distance_km) inkm
quietly su distance_km
local min = r(min)
replace ring=0 if (`min' <= distance_km < 1)
local max = ceil(r(max))
* forval loop does not work
forval i=1/`max'{
    local j = `i'+1
    replace ring=`i' if (`i' <= distance_km < `j')
}

我正在从一个点开始画1公里的戒指。代码的最后一部分(forval)不起作用。这里有什么问题?

修改

forval部分的结果如下:

. forval i=1/`max'{
2.         local j = `i'+1
3.         replace ring=`i' if `i' <= distance_km < `j'
4. }
(1746 real changes made)
(0 real changes made)
(0 real changes made)
(0 real changes made)
....

因此,替换不适用于i = 2及更高版本。

1 个答案:

答案 0 :(得分:2)

双重不等式,例如

(`min' <= distance_km < 1)
根据数学惯例有意义的

在Stata中显然是合法的。否则,您的代码将触发语法错误。但是,在评估整个表达式之前,Stata不会进行评估。这里的括号并不重要,因为关键是如何评估它们的内容。事实证明,结果不太可能是你想要的。

更详细:Stata从左到右解释此表达式,如下所示。第一个平等

`min' <= distance_km

为真或假,因此评估为0或1.显然,您想要选择

这样的值
distance_km >= `min' 

并且对于这样的值,上面的不等式为真,并返回1.Stata然后将1的结果转向第二个不等式,评估

1 < 1 

(即第一个不等式< 1的结果),但这对于这些值是错误的。相反,

(`min' <= distance_km < 1)

将被评估为

 0 < 1 

- 这是真的(返回1) - 当且仅当

 `min' > distance_km 

简而言之,您打算采用不同的方式表达,即

  (`min' <= distance_km) & (distance_km < 1)

我猜想这是你问题的根源。

请注意,Stata具有inrange()功能,但这并不是您想要的。

但是,所有这一切,从查看你的代码,不等式和你的循环似乎都是非常不必要的。你希望你的戒指间隔为1公里,所以

 gen ring = floor(distance_km) 
在调用vincenty后,

可以替换整个代码块,因为floor()向下舍入整数结果。你似乎知道它的双胞胎ceil()

其他一些小点,偶然但值得注意:

  1. 您可以一次destring多个变量。

  2. 将常量放在generate的变量中是效率低下的。为此目的使用scalar。 (但是,如果vincenty需要变量作为输入,则会覆盖此点,但会指出vincenty过于严格。)

  3. summarize, meanonly更适合计算最小值和最大值。选项名称在这里具有误导性。有关讨论,请参阅http://www.stata-journal.com/sjpdf.html?articlenum=st0135

  4. 作为一般Stata实践的问题,您的帖子应该解释用户编写的vincenty来自何处,尽管在这种情况下似乎与此无关。

    为了完整性,这里是重写,但您需要根据数据进行测试。

     use "locationdata.dta", clear
     * Philly City Hall
     scalar lat_center = 39.9525468
     scalar lon_center = -75.1638855
     destring INTPTLAT10 INTPTLON10, replace
     vincenty INTPTLAT10 INTPTLON10 lat_center lon_center , hav(distance_km) inkm
     gen ring = floor(distance_km)