Stata:按特定日期范围生成总和/总计并将它们保存为新变量
Stata: Generate sum / total by specific date ranges and save them as a new variable
我使用的面板数据包含几家公司 (id
),涵盖从 2008 年 1 月 1 日到 2013 年 1 月 1 日 (date
、year
) 的时间段。我想生成新变量 (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
我尝试编写不同的循环(while
、if
),但未能正确完成。我不能使用 rolling
,因为我的间隔不一样。
我的另一个想法是首先创建组标识符(称为 event_id
),其中包含每个间隔和每个公司的 event_id
。然后我可以使用 bysort id event_id: egen sum1=total(var1)
,但不幸的是我不知道该怎么做。因此,我的面板中的变量 event_id
和 sum1
不存在,并作为我想要实现的输出的示例。
看起来您实际上是在尝试为 id
和 eventid
的独特组合创建总计,而不是 id
和 year
。根据您的示例,事件日期和 "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
。
我可以通过以下更改来理解示例:
- 日期 4 月 31 日和 6 月 31 日是 1 天前的错别字。
- 然而,日期 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 |
+-----------------------------------------------------------------------+
我使用的面板数据包含几家公司 (id
),涵盖从 2008 年 1 月 1 日到 2013 年 1 月 1 日 (date
、year
) 的时间段。我想生成新变量 (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
我尝试编写不同的循环(while
、if
),但未能正确完成。我不能使用 rolling
,因为我的间隔不一样。
我的另一个想法是首先创建组标识符(称为 event_id
),其中包含每个间隔和每个公司的 event_id
。然后我可以使用 bysort id event_id: egen sum1=total(var1)
,但不幸的是我不知道该怎么做。因此,我的面板中的变量 event_id
和 sum1
不存在,并作为我想要实现的输出的示例。
看起来您实际上是在尝试为 id
和 eventid
的独特组合创建总计,而不是 id
和 year
。根据您的示例,事件日期和 "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
。
我可以通过以下更改来理解示例:
- 日期 4 月 31 日和 6 月 31 日是 1 天前的错别字。
- 然而,日期 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 |
+-----------------------------------------------------------------------+