Stata:提取值并将其保存为标量(以及更多)

时间:2013-11-05 01:49:26

标签: for-loop stata

此问题是Stata: replace, if, forvalues的后续问题。考虑这些数据:

set seed 123456
set obs 5000
g firmid = "firm" + string(_n)    /* Observation (firm) id */
g nw = floor(100*runiform())      /* Number of workers in a firm */
g double lat = 39+runiform()      /* Latitude in decimal degree of a firm */
g double lon = -76+runiform()     /* Longitude in decimal degree of a firm */

前10个观察结果是:

     +--------------------------------------+
     | firmid   nw         lat          lon |
     |--------------------------------------|
  1. |  firm1   81   39.915526   -75.505018 |
  2. |  firm2   35   39.548523   -75.201567 |
  3. |  firm3   10   39.657866    -75.17988 |
  4. |  firm4   83   39.957938   -75.898837 |
  5. |  firm5   56   39.575881   -75.169157 |
  6. |  firm6   73   39.886184   -75.857255 |
  7. |  firm7   27    39.33288   -75.724665 |
  8. |  firm8   75   39.165549    -75.96502 |
  9. |  firm9   64   39.688819   -75.232764 |
 10. | firm10   76   39.012228   -75.166272 |
     +--------------------------------------+

我需要计算公司1和所有其他公司之间的距离。因此, vincenty 命令如下所示:

. scalar theLat = 39.915526
. scalar theLon = -75.505018
. vincenty lat lon theLat theLon, hav(distance_km) inkm

vincenty命令创建 distance_km 变量,该变量在每个观察点和公司1之间有距离。在这里,我手动复制并粘贴39.915526和-75.505018这两个数字。

问题1 :提取这些数字的语法是什么?

现在,我可以保持距离_km <= 2的观察结果。并且,

. egen near_nw_sum = sum(nw)

将在公司1公里范围内创建工人总数。(或者,崩溃命令可以完成工作。)

问题2 :我必须为所有公司执行此操作,最终数据应如下所示:

     +-----------------------------------------------------------------+
     | firmid   nw         lat          lon            near_nw_sum     |
     |-----------------------------------------------------------------|
  1. |  firm1   81   39.915526   -75.505018  (# workers near firm1)    |
  2. |  firm2   35   39.548523   -75.201567  (# workers near firm2)    |
  3. |  firm3   10   39.657866    -75.17988  (# workers near firm3)    |
  4. |  firm4   83   39.957938   -75.898837  (# workers near firm4)    |
  5. |  firm5   56   39.575881   -75.169157  (# workers near firm5)    |
  6. |  firm6   73   39.886184   -75.857255  (# workers near firm6)    |
  7. |  firm7   27    39.33288   -75.724665  (# workers near firm7)    |
  8. |  firm8   75   39.165549    -75.96502  (# workers near firm8)    |
  9. |  firm9   64   39.688819   -75.232764  (# workers near firm9)    |
 10. | firm10   76   39.012228   -75.166272  (# workers near firm10)   |
     +-----------------------------------------------------------------+

创建 near_nw_sum 变量是我的最终目标。我需要你的帮助来解决我的弱数据管理技巧。

1 个答案:

答案 0 :(得分:2)

以下内容与here基本相同,基于您的“最终目标”。同样,根据原始数据集的大小,它可能很有用。joinby创建观察值,因此您可能超出Stata限制。但是,我相信它能做到你想要的。

clear all
set more off

set seed 123456
set obs 10
g firmid = _n   /* Observation (firm) id */
g nw = floor(100*runiform())      /* Number of workers in a firm */
g double lat = 39+runiform()      /* Latitude in decimal degree of a firm */
g double lon = -76+runiform()     /* Longitude in decimal degree of a firm */
gen dum = 1
list

* joinby procedure
tempfile main
save "`main'"

rename (firmid lat lon nw) =0
joinby dum using "`main'"
drop dum

* Pretty print
sort firmid0 firmid
order firmid0 firmid
list, sepby(firmid0)

* Uncomment if you do not want to include workers in the "base" firm.
*drop if firmid0 == firmid

* Compute distance
vincenty lat0 lon0 lat lon, hav(distance_km) inkm
keep if distance_km <= 40 // an arbitrary distance
list, sepby(firmid0)

* Compute workers of nearby-firms
collapse (sum) nw_sum=nw (mean) nw0 lat0 lon0, by(firmid0)
list

它所做的是形成企业的成对组合来计算距离和附近企业的工人总数。这里不需要像问题1中那样提取标量。此外,不需要将变量firmid转换为字符串变得复杂。

以下克服了Stata限制观察数量的问题。

clear all
set more off

* Create empty database
gen x = .
tempfile results
save "`results'", replace

* Create input for exercise
set seed 123456
set obs 500
g firmid = _n   /* Observation (firm) id */
g nw = floor(100*runiform())      /* Number of workers in a firm */
g double lat = 39+runiform()      /* Latitude in decimal degree of a firm */
g double lon = -76+runiform()     /* Longitude in decimal degree of a firm */
gen dum = 1
*list

* Save number of firms
local size = _N
display "`size'"

* joinby procedure
tempfile main
save "`main'"

timer clear 1
timer clear 2
timer clear 3
timer clear 4

quietly {
    timer on 1
    forvalues i=1/`size'{
        timer on 2
        use "`main'" in `i', clear // assumed sorted on firmid
        rename (firmid lat lon nw) =0

        joinby dum using "`main'", unmatched(using)
        drop _merge dum
        order firmid0 firmid
        timer off 2

        timer on 3
        vincenty lat0 lon0 lat lon, hav(dist) inkm
        timer off 3
        keep if dist <= 40 // an arbitrary distance

        timer on 4
        collapse (sum) nw_sum=nw (mean) nw0 lat0 lon0, by(firmid0)

        append using "`results'"
        save "`results'", replace
        timer off 4
    }
    timer off 1
}

use "`results'", clear
sort firmid0
drop x
list

timer list

然而效率低下,使用timer进行的一些测试表明,大部分计算时间都会进入vincenty命令,而这些命令将无法逃脱。以下是使用英特尔酷睿i5处理器和传统硬盘(不是SSD)进行10,000次观察的时间(以秒为单位)。定时器1是总数,而2,3,4是组件(大约)。定时器3对应vincenty

. timer list
   1:   1953.99 /        1 =    1953.9940
   2:    169.19 /    10000 =       0.0169
   3:   1669.95 /    10000 =       0.1670
   4:     94.47 /    10000 =       0.0094

当然,请注意,在两个代码中都会进行重复的距离计算(例如,计算firm1-firm2和firm2-firm1之间的距离),这可以避免。目前,110,000次观测需要很长时间。从积极的方面来说,我注意到与第一次设置中的相同数量的观察相比,第二次设置需要非常少的RAM。事实上,我的4GB机器与后者冻结了。

另请注意,即使我使用与您相同的种子,数据也是不同的,因为我创建了不同数量的观察结果(不是5000),这对变量创建过程产生了影响。

(顺便说一下,如果您想将值保存为标量,可以使用subscriptingscalar latitude = lat[1])。