【问题标题】:Count observations within dynamic range计数动态范围内的观测值
【发布时间】:2014-11-08 12:55:08
【问题描述】:

考虑以下示例:

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

【问题讨论】:

    标签: stata


    【解决方案1】:

    我假设治疗不能在前一次治疗的 1 年内发生(在组中)。这在您的示例数据中是正确的,但通常可能并非如此。但是,假设是这种情况,那么这应该有效。我正在使用位于 SSC (ssc install carryforward) 上的 carryforward。就像您的 latestDate 想法一样,我在最近一次治疗后一年确定并计算该窗口中的观察次数。

    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
    

    我不能保证这会比循环更快,但我怀疑它会。

    【讨论】:

    • 我认为即使在上一次治疗后一年内有治疗效果也很好。
    • 我想这取决于正确的计数规则。如果下一次处理(和任何其他观察)应该算作 NUM 中的额外 +1,那么它不会(我不认为,因为 yrafter 将停止继续前进)。但如果这无关紧要(或者如果 NUM 规则是在下一次治疗之前和一年内还有多少),那么你是对的,没关系。
    • 我同意。这是我的解释,至少。原始海报必须澄清。
    • 很抱歉对我的数据集的解释不准确!让我填补这个空白:如果在去年和同一组内没有观察到,则治疗变量的值为 1(正如您已经弄清楚的那样)。因此,变量 NUM 也不可能必须考虑处理 = 1 的观察 - 请记住,NUM 应该排除给出时间框架起点的观察。原则上,一个组中可能有两个观测值具有相同的日期。据我了解,所有要求都已满足。
    【解决方案2】:

    这个问题并不完全清楚。

    考虑以下具有两个不同结果的数据,num2num3

      +-----------------------------------------+
      |     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) 后一年内的 所有 观察,这些观察等于 0 或1 代表treat。例如,01feb2000 之后,有 3 个观测值符合时间跨度条件;两个有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)
    

    对于您的问题,甚至可能有两种以上的解释,但我会保留它。

    (请注意,我已更改您的示例数据以包含可能使问题更现实的案例。)

    【讨论】:

    • 我很抱歉不准确!我希望我在评论中提供了所有缺失的信息作为对 jfeigenbaum 帖子的回应。除此之外,我将使用此信息编辑我的初始问题。
    • 在这种背景下,日期为 01nov2000 的观察值在变量处理中的值为 0,而日期为 01may2002 的观察值的值为 1。因此,num3 列将满足我的要求要求(但仅因为在这 1 年的时间范围内不能发生处理 = 1 次观察)。这又是由于我提供的信息不足。感谢您的努力,罗伯托·费雷尔!
    • 太棒了。感谢您提供反馈。
    猜你喜欢
    • 2020-12-05
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 2018-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多