楼主: xingxf
7240 35

[编程问题求助] 生成过去特定一段时间特定条件下某ID重复出现的次数 [推广有奖]

  • 0关注
  • 50粉丝

已卖:3687份资源

副教授

12%

还不是VIP/贵宾

-

威望
0
论坛币
60582 个
通用积分
772.4445
学术水平
224 点
热心指数
251 点
信用等级
138 点
经验
20775 点
帖子
753
精华
0
在线时间
522 小时
注册时间
2011-3-12
最后登录
2025-4-1

楼主
xingxf 发表于 2013-5-1 02:05:06 |AI写论文
10000论坛币
有如下格式数据:
id           date                  B         E         MA       Var1         Var2        Var3     
AA   1980/01/02             1          .           .
B     1980/01/31             0          .           .
C     1982/02/16             .           .           1
D     1982/03/18             .           0           .
AA    1982/03/21            .           1           .
AA    1982/03/21            1          .            .
B      1982/03/22            
AA    1983/06/30            .           0            .
E      1985/11/22            0          .             .
AA    1985/12/31            0          .             .
G      1987/01/01            .           .             1
D      1991/02/27            .           1            .
.
AA    1999/03/16            .             .            1
.
Z     2010/12/31             0           .             .


想在Var1列生成本行对应id过去5年在B=1的情况下重复出现的次数(不计当次),在Var2列生成本行对应id过去5年在E=1的情况下重复出现的次数(不计当次),在Var3列生成本行对应id过去5年在MA=1的情况下重复出现的次数(不计当次)。举例来说,对应AA 1985/12/31行,Var1应显示1,Var2应显示1,Var3应显示0

我根据以前dxystata在类似问题中的程序,改写程序如下:
gen Var1=.
local N = _N
forvalues i = 1/`N' {
count if B==1&id==id[`i'] & (date[`i']-date)/365.2<=5 & (date[`i']-date)/365.2>0
replace var1=r(N) in `i'
}
但是这个程序运算速度比较慢,遇到观察值为几十万的情况,几个小时也出不了结果。

哪位高人有比较好的解决办法啊?非常感谢!!!

根据jonathanjp引用Nick Cox的建议,我编写如下代码,优点是不需要任何循环,因此速度快,缺点是如果数据量比较大,例如我提供的样本,会占用大量内存,甚至超过32G。
bys id Date: egen total_B=total(B)
bys id Date: egen total_E=total(E)
bys id Date: egen total_MA=total(MA)
duplicates drop id Date, force
egen ID=group(id)
xtset ID Date
tsfill
bys ID (Date): gen sum_B=sum(total_B)
bys ID (Date): gen freq_B=l.sum_B-l1827.sum_B
bys ID (Date): gen sum_E=sum(total_E)
bys ID (Date): gen freq_E=l.sum_E-l1827.sum_E
bys ID (Date): gen sum_MA=sum(total_MA)
bys ID (Date): gen freq_MA=l.sum_MA-l1827.sum_MA
drop if missing(id)

根据jonathanjp引用Michael Barker的程序,我进行了试验,运行速度也不快,而且结果有问题,但是思路有帮助。我一开始写的那个程序把每一个obs和其他所有obs进行比较,比较是否id一致及是否在5年之内,这样在样本大的情况下,运行速度自然很慢。现在有没有可能在一开始按时间sort数据的情况下,循环程序截止在5年的时间范围内?

目前为止,不管使用循环还是不使用循环,如果想解决速度问题,voodoo提出的“分而治之”的思路是最佳方案。

我把voodoo的“分而治之”的方法评为最佳答案,这个方法唯一的缺点是需要写的程序较为复杂,但是这种“分而治之”的思路是很好用的,而且程序运行速度比较快,不过多耗费系统资源。我写的上面这个不需要循环的程序运行速度最快而且代码比较简洁,但是必须保证内存足够大(建议16G或以上)。





最佳答案

voodoo 查看完整内容

在楼上程序的基础上加入“分而治之”的做法,将总样本划分为若干个小样本,在我的电脑上程序运行时间缩减至楼上程序的10%!只需303秒即解决问题!!
关键词:forvalues forvalue values Count Stata 时间

回帖推荐

voodoo 发表于29楼  查看完整内容

假如数据量较小的话(先“分而治之”?),这段程序可行。但tsfill也极为耗费时间,在我的电脑上保留前10000个样本,不用tsfill的full选项,程序运行总耗时11秒。那500000个样本,也要550秒。不见得比我15楼提出的程序节约多少时间。:-)

jonathanjp 发表于25楼  查看完整内容

Another tip from Michael Barker (Statalist) ----------------------------------------------------------------- It looks like you are comparing each observation to every other observation in your data set. If your data are sorted, you only have to look back within each 5-year window for each id. If your data are sorted descending by date, the code would look like this: gen temp = flag lo ...

jonathanjp 发表于16楼  查看完整内容

我将你的问题发在了Statalist,Nick Cox这样回复: I don't know a sure-fire way to speed this up. It might just be faster if you -expand-ed the data to one observation for every day. Then the code would be simpler, but you would end up with several millions of observations. Or you could translate the code into Mata. 以上信息,仅供参考。

voodoo 发表于15楼  查看完整内容

在楼上程序的基础上加入“分而治之”的做法,将总样本划分为若干个小样本,在我的电脑上程序运行时间缩减至楼上程序的10%!只需303秒即解决问题!!

本帖被以下文库推荐

沙发
voodoo 发表于 2013-5-1 02:05:07
在楼上程序的基础上加入“分而治之”的做法,将总样本划分为若干个小样本,在我的电脑上程序运行时间缩减至楼上程序的10%!只需303秒即解决问题!
  1. //        以下程序尽管循环部分并未优化,但只需根据你的数据对数据进行清洁,并合并重复样本的信息,就可将程序运行时间缩短至原来的20%!这事实上也说明了在数据管理过程中理解数据的重要性。
  2. //        加入“分而治之”的做法,分30个子样本,程序运行时间进一步缩减至未采取此做法前的10%!
  3. set rmsg on
  4. set more off
  5. global NSMPL = 30        // 分而治之以加速循环计算效率,分NSMPL个子样本

  6. use sample.dta, clear
  7. count        // 看看共有多少样本

  8. //        #1
  9. //        根据你的说明,B E MA取值要么1,要么missing,不应为0啊?
  10. //        将0替换为.,然后删除三个变量均为.的样本
  11. //        竟然多达26万个,节约50%的时间
  12. foreach v in B E MA {
  13.         replace `v' = . if `v' == 0
  14. }
  15. drop if missing(B) & missing(E) & missing(MA)
  16. save sample2, replace

  17. //        #2
  18. //        循环计算
  19. /*
  20.         //        #2.0
  21.         //        10000样本先试一下
  22. sort id date
  23. keep in 1/10000
  24. */
  25.         //        #2.1
  26.         //        用`v't合并重复样本的信息,然后删除重复样本
  27. foreach v in B E MA {
  28.         bysort id date: egen `v't = total(`v')
  29.         drop `v'
  30. }
  31. duplicates drop id date, force

  32.         //        #2.2
  33.         //        删除只有一个date的,肯定无需进入循环
  34. by id: gen N = _N
  35. drop if N == 1
  36. drop N
  37. count        // 看看还剩下多少样本

  38.         //        #2.3
  39.         //        按总样本id数划分为NSMPL个子样本
  40. sort id date
  41. by id: gen _tagid = (_n==1)
  42. gen id2 = sum(_tagid)
  43. su id2, meanonly
  44. local cid = ceil(r(max)/$NSMPL)        // 每个子样本id数
  45. drop _tagid

  46. local j = 1
  47. forval i = 1/`=$NSMPL-1' {        // 前NSMPL-1个子样本
  48.         preserve
  49.         keep if inrange(id2, `j', `j'+`cid'-1)
  50.         drop id2
  51.         local j = `j' + `cid'
  52.         save _smpl`i', replace
  53.         restore
  54. }
  55. keep if inrange(id2, `j', `j'+`cid'-1)        // 最后一个子样本
  56. drop id2
  57. save _smpl$NSMPL, replace

  58.         //        #2.4
  59.         //        三重循环计算目标变量
  60. forval i = 1/$NSMPL {        // 子样本集循环
  61.         use _smpl`i', clear
  62.         foreach v in B E MA {        // 变量循环
  63.                 gen Var_`v' = .
  64.                 qui forval j = 1/`=_N' {        // 子样本内循环
  65.                         su `v't if id==id[`j'] & inrange((date[`j']-date), 1, 1826)
  66.                         replace Var_`v' = r(sum) in `j'
  67.                 }
  68.                 drop `v't
  69.         }
  70.         save _smpl`i'_, replace
  71. }
  72.         
  73.         //        #2.5     
  74.         //        和原来的样本数据合并
  75. clear
  76. forval i = 1/$NSMPL {
  77.         append using _smpl`i'_
  78. }
  79. save _SMPL_, replace

  80. use sample2, clear
  81. merge m:1 id date using _SMPL_, nogen
  82. save sample2, replace

  83.         //        #2.6
  84.         //        收尾
  85. /*
  86. foreach v in B E MA {
  87.         replace Var_`v' = 0 if missing(Var_`v')
  88. }
  89. */
  90. save sample2, replace

  91. forval i = 1/$NSMPL {
  92.         erase _smpl`i'.dta
  93.         erase _smpl`i'_.dta
  94. }
  95. erase _SMPL_.dta

  96. set rmsg off
  97. set more off
复制代码
已有 1 人评分学术水平 热心指数 信用等级 收起 理由
xingxf + 5 + 5 + 5 精彩帖子

总评分: 学术水平 + 5  热心指数 + 5  信用等级 + 5   查看全部评分

巫毒上传,必属佳品!
坛友下载,三思后行!

藤椅
xingxf 发表于 2013-5-1 02:07:40
这是上面问题的示例文件。

sample.rar
下载链接: https://bbs.pinggu.org/a-1320984.html

1.66 MB

示例文件

本附件包括:

  • sample.dta

板凳
dxystata 发表于 2013-5-1 11:57:38
用 12-Core Stata/MP

报纸
jonathanjp 发表于 2013-5-1 13:35:51
你的数据里有很多重复的观测,删掉后能好一些。

地板
voodoo 发表于 2013-5-1 16:00:32
答案和问题是相关的。请你再澄清一下关于你样本的性质:
1. 为什么存在很多完全相同的duplicate obs?
2. id很多,且每个id的样本数多少也差很多呢?
3. 你所附的sample是你所拥有的全部样本,还是它仅是你所有样本的一个样本而已?
总之,请问这是关于什么研究的样本?
巫毒上传,必属佳品!
坛友下载,三思后行!

7
xingxf 发表于 2013-5-1 17:01:24
dxystata 发表于 2013-5-1 11:57
用 12-Core Stata/MP
我用的就是这个版本,跑了10多小时了,没出结果,哈哈

8
sungmoo 发表于 2013-5-1 17:01:55
jonathanjp 发表于 2013-5-1 13:35
你的数据里有很多重复的观测,删掉后能好一些。
对于完全相同的行(重复值),楼主要如何处理?

9
xingxf 发表于 2013-5-1 17:02:16
jonathanjp 发表于 2013-5-1 13:35
你的数据里有很多重复的观测,删掉后能好一些。
重复的观测值是必须的,没有办法去掉

10
xingxf 发表于 2013-5-1 17:04:13
dxystata 发表于 2013-5-1 11:57
用 12-Core Stata/MP
说错了哈哈,我是4-core版本,找不到12-core版本,我也只有i7的4核8线程机器,没有12-core的机器

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注jltj
拉您入交流群
GMT+8, 2025-12-5 23:02