Stata:按特定日期范围生成总和/总计并将它们保存为新变量

Stata: Generate sum / total by specific date ranges and save them as a new variable

我使用的面板数据包含几家公司 (id),涵盖从 2008 年 1 月 1 日到 2013 年 1 月 1 日 (dateyear) 的时间段。我想生成新变量 (sum1),其中包含每个公司和特定时间间隔的 var1 每日观察总和。如果间隔等于每年,我将使用函数 total():

 bysort id year: egen sum1=total(var1)

然而,在我的例子中,时间间隔被确定为两个事件之间的间隔。我有一个名为 event 的特殊变量,如果事件发生在特殊日期,则该变量的值为 1,否则为缺失。每个公司有 5 到 10 个事件。事件之间的间隔不相等;因此第一个区间可以包含 60 个观察值,下一个区间可以包含 360 个观察值。不同公司的间隔也不相等。每家公司的第一个时间间隔的起始日期是 2008 年 1 月 1 日。第二个间隔的开始日期是第一个事件的日期 + 1 天。此外,我想考虑缺失值,因此如果公司 x 的 var1 的所有值都缺少变量,公司 x 的 sum1 和特定间隔必须包含缺失值而不是 0.

我的面板是这样的:

   id   date        year    var1    event  sum1(to gen)  event_id(to gen)
   1    1.1.2008    2008    25        .     95 (25+30+40)     1
   1    2.1.2008    2008    30        .     95 (25+30+40)     1
   ...........................................................1      
   1    31.4.2008   2008    40        1     95 (25+30+40)     1
   1    1.5.2008    2008    50        .     160 (50+50+60)    2
   1    2.5.2008    2008    50        .     160 (50+50+60)    2
   .........................................  ................2
   1   31.4.2009    2009    60        1     160 (50+50+60)    2 
   2    1.1.2008    2008    26        .     96 (26+30+40)     1 
   2    2.1.2008    2008    30        .     96 (26+30+40)     1
   ...........................................................1      
   2    31.6.2008   2008    40        1     96 (26+30+40)     1
   2    1.5.2008    2008    51        .     161 (51+50+60)    2
   2    2.5.2008    2008    50        .     161 (51+50+60)    2
   ...........................................................2
   2   31.6.2009    2009    60        1     161 (51+50+60)    2  

我尝试编写不同的循环(whileif),但未能正确完成。我不能使用 rolling,因为我的间隔不一样。

我的另一个想法是首先创建组标识符(称为 event_id),其中包含每个间隔和每个公司的 event_id。然后我可以使用 bysort id event_id: egen sum1=total(var1),但不幸的是我不知道该怎么做。因此,我的面板中的变量 event_idsum1 不存在,并作为我想要实现的输出的示例。

看起来您实际上是在尝试为 ideventid 的独特组合创建总计,而不是 idyear。根据您的示例,事件日期和 "special date" 标志 (event) 在计算所需总和时似乎无关紧要。因此

bysort id eventid: egen _sum = total(var1)

或更简单地说

egen _sum = total(var1) , by(id eventid)

应该都给你你想要的总数。关于

Besides I would like to account for missing values, so if all values of var1 for the company x are missing variable, sum1 for company x and specific interval must contain missing values and not 0.

egen total() 上的 missing 选项应该有助于处理这种情况。


更新

不一定是对其他答案的改进,而是另一种方法(依赖于事件在原始数据中的正确顺序):

clear *
input id str10 date year var1 event DesiredSum 
   1 1.1.2008  2008 25 . 95 
   1 2.1.2008  2008 30 . 95 
   1 30.4.2008 2008 40 1 95 
   1 1.5.2008  2008 50 . 160  
   1 2.5.2008  2008 50 . 160  
   1 30.4.2009 2009 60 1 160  
   2 1.1.2008  2008 26 . 96 
   2 2.1.2008  2008 30 . 96     
   2 30.4.2008 2008 40 1 96
   2 1.5.2008  2008 51 . 161
   2 2.5.2008  2008 50 . 161 
   2 30.6.2009 2009 60 1 161    
end

gen _obs = _n
gen date2 = daily(date, "DMY")
format date2 %td

bys id (_obs): gen eventid = sum(date2 == td(01jan2008)) + sum(event[_n-1] == 1)
egen sum = total(var1) , by(id eventid)  missing

li , sepby(id eventid)

如果您不反对将 event 重新编码为更易于使用的内容,那么以下内容就足够了。我在这里还假设 event 用于标记事件发生的时间间隔的 end(我根据您的示例数据和我的评论做出此假设关于问题)。

clear *
input id str10 date year var1 event DesiredSum 
   1 1.1.2008  2008 25 . 95 
   1 2.1.2008  2008 30 . 95 
   1 31.4.2008 2008 40 1 95 
   1 1.5.2008  2008 50 . 160  
   1 2.5.2008  2008 50 . 160  
   1 31.4.2009 2009 60 1 160  
   2 1.1.2008  2008 26 . 96 
   2 2.1.2008  2008 30 . 96     
   2 31.6.2008 2008 40 1 96
   2 1.5.2008  2008 51 . 161
   2 2.5.2008  2008 50 . 161 
   2 31.6.2009 2009 60 1 161    
 end

 bysort id : gen i = _n  // to maintain sort order

 /* This section of code changes event so that 1 indicates the start of the 
    interval. This data structure makes more sense to me */
 replace event = 0 if mi(event)
 replace event = 2 if event[_n-1] == 1 & _n != 1
 replace event = event - 1 if event > 0
 replace event = 1 in 1

 gen event_id = event
 replace event_id = event_id+event_id[_n-1] if i != 1

 bysort id event_id : egen Sum = total(var1), missing

li id date event_id DesiredSum Sum, sepby(event_id)

当然,如果您不想更改 event,您可以 generate event2 = event 代替 event

我可以通过以下更改来理解示例:

  1. 日期 4 月 31 日和 6 月 31 日是 1 天前的错别字。
  2. 然而,日期 31.6.2008 应该是 30.4.2008。

就是说,时间倒流的一种技巧使法术的细分变得容易。给定每个法术的 ends 的标记 1,然后我们可以使用 sum() 向后累积。这里关键的小细节是 sum() 忽略缺失值,或者更准确地说,将它们视为零。这完全是一个功能,尽管在应用 egen, total() 时并不完全是 OP 想要的。

然后反转法术编号,将时间反转到正常方向并像其他答案一样应用egen。 Reversing 和 reversing back 都只是使用 - 的否定。一旦我们对法术进行了划分,在面板中按日期排序只是装饰性的,但仍然是正确的做法。

有关 Stata 中法术的更多信息,请参阅 here

有关 Statalist 关于如何使用 dataex (SSC) 提供数据示例的提示,稍作修改后也适用于此,请参阅 here

clear *
input id str10 date year var1 event DesiredSum 
   1 1.1.2008  2008 25 . 95 
   1 2.1.2008  2008 30 . 95 
   1 30.4.2008 2008 40 1 95 
   1 1.5.2008  2008 50 . 160  
   1 2.5.2008  2008 50 . 160  
   1 30.4.2009 2009 60 1 160  
   2 1.1.2008  2008 26 . 96 
   2 2.1.2008  2008 30 . 96     
   2 30.4.2008 2008 40 1 96
   2 1.5.2008  2008 51 . 161
   2 2.5.2008  2008 50 . 161 
   2 30.6.2009 2009 60 1 161    
end

gen ddate = -daily(date, "DMY") 
bysort id (ddate): gen EVENT = sum(event) 
replace ddate = -ddate 
by id: replace EVENT = EVENT[_N] - EVENT + 1 
bysort id EVENT (ddate): egen Sum = total(var1), missing
assert Sum == DesiredSum 
list, sepby(id EVENT) 

     +-----------------------------------------------------------------------+
     | id        date   year   var1   event   Desire~m   ddate   EVENT   Sum |
     |-----------------------------------------------------------------------|
  1. |  1    1.1.2008   2008     25       .         95   17532       1    95 |
  2. |  1    2.1.2008   2008     30       .         95   17533       1    95 |
  3. |  1   30.4.2008   2008     40       1         95   17652       1    95 |
     |-----------------------------------------------------------------------|
  4. |  1    1.5.2008   2008     50       .        160   17653       2   160 |
  5. |  1    2.5.2008   2008     50       .        160   17654       2   160 |
  6. |  1   30.4.2009   2009     60       1        160   18017       2   160 |
     |-----------------------------------------------------------------------|
  7. |  2    1.1.2008   2008     26       .         96   17532       1    96 |
  8. |  2    2.1.2008   2008     30       .         96   17533       1    96 |
  9. |  2   30.4.2008   2008     40       1         96   17652       1    96 |
     |-----------------------------------------------------------------------|
 10. |  2    1.5.2008   2008     51       .        161   17653       2   161 |
 11. |  2    2.5.2008   2008     50       .        161   17654       2   161 |
 12. |  2   30.6.2009   2009     60       1        161   18078       2   161 |
     +-----------------------------------------------------------------------+