考虑以下示例:
input group day month year number treatment NUM
1 1 2 2000 1 1 2
1 1 6 2000 2 0 .
1 1 9 2000 3 0 .
1 1 5 2001 4 0 .
1 1 1 2010 5 1 1
1 1 5 2010 6 0 .
2 1 1 2001 1 1 0
2 1 3 2002 2 1 0
end
gen date = mdy(month,day,year)
format date %td
drop day month year
对于每组,我有不同的观察数。每个观察指的是用日期指定的事件。可变数字是每个组中的编号。
现在,我想计算从该组内每次治疗观察日期(不包括其自身)开始一年内发生的观察次数。这意味着,我想创建变量NUM我已经在上面的例子中加入了。我不关心治疗次数= 0。
编辑开始:发现以下信息缺失但是必须解决此问题:如果去年同一组内没有观察,则治疗变量的值为1 。因此,变量NUM也不可能必须考虑处理= 1的观察。原则上,组内可能有两个具有相同日期的观察值。 编辑结束
我调查了Stata tip 51: Events in intervals。它似乎可以解决我的数据集很大(> 1 mio观察),这样它真的非常低效 - 特别是因为我不关心所有治疗= 0观察。
我想知道是否有其他选择。我的方法是在每组中查找仍然在1年范围内的最新日期(并且可能将其存储在变量latestDate中)。然后我只是简单地从处理= 0变量的值中减去从观察值变量中得到的值。
注意:我的效率低下"代码如下所示
gsort -treatment
gen treatment_id = _n
replace treatment_id = . if treatment==0
gen count=.
sum treatment_id, meanonly
qui forval i = 1/`r(max)'{
count if inrange(date-date[`i'],1,365) & group == group[`i']
replace count = r(N) in `i'
}
sort group date
答案 0 :(得分:2)
我假设治疗不能在前一次治疗的1年内发生(在该组中)。在您的示例数据中也是如此,但一般情况下可能不正确。但是,假设情况确实如此,那么这应该有效。我正在使用SSC上的carryforward
(ssc install carryforward
)。就像你最近的日期想法一样,我在最近一次治疗后一年确定并计算该窗口中的观察数量。
sort group date
gen yrafter = (date + 365) if treatment == 1
by group: carryforward yrafter, replace
format yrafter %td
gen in_window = date <= yrafter & treatment == 0
egen answer = sum(in_window), by(group yrafter)
replace answer = . if treatment == 0
我不能保证这会比循环更快,但我怀疑它会是。
答案 1 :(得分:2)
问题并不完全清楚。
使用两个不同的结果num2
和num3
来考虑以下数据:
+-----------------------------------------+
| date2 group treat num2 num3 |
|-----------------------------------------|
| 01feb2000 1 1 3 2 |
| 01jun2000 1 0 . . |
| 01sep2000 1 0 . . |
| 01nov2000 1 1 0 0 |
| 01may2002 1 0 . . |
| 01jan2010 1 1 1 1 |
| 01may2010 1 0 . . |
|-----------------------------------------|
| 01jan2001 2 1 0 0 |
| 01mar2002 2 1 0 0 |
+-----------------------------------------+
变量num2
的计算假设您有兴趣计算在经过处理的观察(treat == 1
)后一年内的所有观察,是那些观察treat
等于0或1。例如,在01feb2000之后,有三个观察符合时间跨度条件;其中两个人treat==0
,一个人treat == 1
,他们都被计算在内。
变量num3
也计算观察后的一年内观察结果,但仅计算treat == 0
的情况。
num2
是根据您引用的文章的精神使用代码计算的。使用in
可以提高运行效率,并且没有gsort
(如代码中所示),这非常慢。我假设每个group
都没有重复日期:
clear
set more off
input ///
group str15 date count treat num
1 01.02.2000 1 1 2
1 01.06.2000 2 0 .
1 01.09.2000 3 0 .
1 01.11.2000 3 1 .
1 01.05.2002 4 0 .
1 01.01.2010 5 1 1
1 01.05.2010 6 0 .
2 01.01.2001 1 1 0
2 01.03.2002 2 1 0
end
list
gen date2 = date(date,"DMY")
format date2 %td
drop date count num
order date
list, sepby(group)
*----- what you want -----
gen num2 = .
isid group date, sort
forvalues j = 1/`=_N' {
count in `j'/L if inrange(date2 - date2[`j'], 1, 365) & group == group[`j']
replace num2 = r(N) in `j'
}
replace num2 = . if !treat
list, sepby(group)
num3
使用与@jfeigenbaum发布的精神(和结果)类似的代码计算:
<snip>
*----- what you want -----
isid group date, sort
by group: gen indicat = sum(treat)
sort group indicat, stable
by group indicat: egen num3 = total(inrange(date2 - date2[1], 1, 365))
replace num3 = . if !treat
list, sepby(group)
对于您的问题,可能有两种以上的解释,但我会留下它。
(请注意,我已将您的示例数据更改为包含可能使问题更加真实的案例。)