在 Stata 中计算不同条件下的观察结果
Counting observations under varying conditions in Stata
我有一个具有以下结构的大型数据集(这里是一个示例):
+-----------------------------------------+
| id date treat match num |
|-----------------------------------------|
| 1 01feb2000 1 2 2 |
| 1 01apr2000 0 . . |
| 1 01jan2002 1 3 1 |
|-----------------------------------------|
| 2 01mar2000 1 3 0 |
| 2 01may2000 0 . . |
|-----------------------------------------|
| 3 01dec2002 1 . . |
+-----------------------------------------+
对于由 id
标识的每个组,我在特定日期发生了特定事件。每次出现都是治疗或对照。每个治疗观察都与某个 id
相匹配。您可以使用给定的 id
、date
、treat
和 match
变量。
我的目标是为每个实际匹配的处理观察计算 num
的值(可能存在处理观察不匹配的情况,请参阅 id
3)。 规则是计算匹配的id
(不管是否处理)在处理的观察日期开始的一年内出现的次数。
示例:第一个处理的观察与 id
2 匹配。id
2 在 2000 年 2 月 1 日之后的下一年内有两个观察。
重要提示:首先,匹配 ID 中首次出现的日期绝不会早于所考虑的治疗观察日期。第二,几个处理观察可以匹配相同的id
.
请注意,此处已提出类似问题 here。在这里,我关心算法的效率,因为我的数据集很大。我的解决方案如下:
gen NUM = .
gen yrafter = 25000 // arbitrary date outside of the panel
format yrafter %td
gen in_window = 0
sort id date
forval i = 1/`=_N' {
if (match[`i'] != .) {
replace yrafter = (date_installation[`i'] + 365) if ags == match[`i']
replace in_window = date_installation <= yrafter & ags == match[`i']
by id: egen NUM_temp = sum(in_window) if ags == match[`i']
replace NUM_temp = 0 if NUM_temp == .
sum NUM_temp if ags == match[`i'], meanonly
replace NUM0 in `i' = r(max)
drop NUM_temp
replace in_window = 0 if ags == match[`i']
}
}
drop yrafter in_window
为了减少迭代次数,我实际上想在处理观察后进行排序,并且只对它们进行迭代。但是,根据我对问题的理解,我不能这样做,因为一些后续命令需要我在上面应用的排序(我对吗?)。
我的策略是迭代每个相关观察:对于匹配的 id
组中的所有观察,我将 yrafter
的值替换为需要考虑的最新可能出现的值。然后在变量 in_window
中,我简单地识别那些在可能的最新日期之前的观察结果(请记住,在 treatment
变量的日期之前不能有任何出现)然后计算所有的观察结果。我将结果保存在 num
中并为下一次迭代设置所有内容。
显然,这需要很多时间。我的第一个猜测是优化循环头,因为检查 if
条件对于 Stata 来说似乎非常耗时。有人有优化的想法吗?
只有当我有正确的代码时,我才会担心效率。以下是错误。
测试 if (match != .)
总是减少到 if (match[1] != .)
。大概您需要依次测试每个值。 http://www.stata.com/support/faqs/programming/if-command-versus-if-qualifier/index.html 可在此处申请。
声明
replace NUM0 in `i' = r(max)
是非法的,应该是
replace NUM0 = r(max) in `i'
我无法对你的主要问题发表评论,因为我不明白你想做什么。我想你的解释是清楚和合乎逻辑的;当我从不做任何类似的事情时,这对我来说太复杂了,无法吸收你所做的全部事情。
按照
的方式尝试一些东西
clear
set more off
*----- example data -----
input ///
id str20 date treat match num
1 01feb2000 1 2 2
1 01apr2000 0 . .
1 01jan2002 1 3 1
2 01mar2000 1 3 0
2 01may2000 0 . .
3 01dec2002 1 . .
end
list, sepby(id)
gen dat = date(date,"DMY")
format %td dat
drop date
order dat, after(id)
list, sepby(id)
*----- what you want -----
gen num2 = .
forvalues i = 1/`=_N' {
if treat[`i'] == 1 {
count if id == match[`i'] & dat <= dat[`i'] + 365
replace num2 = r(N) in `i'
}
}
replace num2 = . if missing(match)
list, sepby(id)
assert num == num2
我没有关于你的数据集大小的信息,所以除非你准确地透露,否则我不会做任何测试。
(我没有检查你的代码。我只是尝试将你的问题的措辞翻译成 Stata 代码。)
我有一个具有以下结构的大型数据集(这里是一个示例):
+-----------------------------------------+
| id date treat match num |
|-----------------------------------------|
| 1 01feb2000 1 2 2 |
| 1 01apr2000 0 . . |
| 1 01jan2002 1 3 1 |
|-----------------------------------------|
| 2 01mar2000 1 3 0 |
| 2 01may2000 0 . . |
|-----------------------------------------|
| 3 01dec2002 1 . . |
+-----------------------------------------+
对于由 id
标识的每个组,我在特定日期发生了特定事件。每次出现都是治疗或对照。每个治疗观察都与某个 id
相匹配。您可以使用给定的 id
、date
、treat
和 match
变量。
我的目标是为每个实际匹配的处理观察计算 num
的值(可能存在处理观察不匹配的情况,请参阅 id
3)。 规则是计算匹配的id
(不管是否处理)在处理的观察日期开始的一年内出现的次数。
示例:第一个处理的观察与 id
2 匹配。id
2 在 2000 年 2 月 1 日之后的下一年内有两个观察。
重要提示:首先,匹配 ID 中首次出现的日期绝不会早于所考虑的治疗观察日期。第二,几个处理观察可以匹配相同的id
.
请注意,此处已提出类似问题 here。在这里,我关心算法的效率,因为我的数据集很大。我的解决方案如下:
gen NUM = .
gen yrafter = 25000 // arbitrary date outside of the panel
format yrafter %td
gen in_window = 0
sort id date
forval i = 1/`=_N' {
if (match[`i'] != .) {
replace yrafter = (date_installation[`i'] + 365) if ags == match[`i']
replace in_window = date_installation <= yrafter & ags == match[`i']
by id: egen NUM_temp = sum(in_window) if ags == match[`i']
replace NUM_temp = 0 if NUM_temp == .
sum NUM_temp if ags == match[`i'], meanonly
replace NUM0 in `i' = r(max)
drop NUM_temp
replace in_window = 0 if ags == match[`i']
}
}
drop yrafter in_window
为了减少迭代次数,我实际上想在处理观察后进行排序,并且只对它们进行迭代。但是,根据我对问题的理解,我不能这样做,因为一些后续命令需要我在上面应用的排序(我对吗?)。
我的策略是迭代每个相关观察:对于匹配的 id
组中的所有观察,我将 yrafter
的值替换为需要考虑的最新可能出现的值。然后在变量 in_window
中,我简单地识别那些在可能的最新日期之前的观察结果(请记住,在 treatment
变量的日期之前不能有任何出现)然后计算所有的观察结果。我将结果保存在 num
中并为下一次迭代设置所有内容。
显然,这需要很多时间。我的第一个猜测是优化循环头,因为检查 if
条件对于 Stata 来说似乎非常耗时。有人有优化的想法吗?
只有当我有正确的代码时,我才会担心效率。以下是错误。
测试
if (match != .)
总是减少到if (match[1] != .)
。大概您需要依次测试每个值。 http://www.stata.com/support/faqs/programming/if-command-versus-if-qualifier/index.html 可在此处申请。声明
replace NUM0 in `i' = r(max)
是非法的,应该是
replace NUM0 = r(max) in `i'
我无法对你的主要问题发表评论,因为我不明白你想做什么。我想你的解释是清楚和合乎逻辑的;当我从不做任何类似的事情时,这对我来说太复杂了,无法吸收你所做的全部事情。
按照
的方式尝试一些东西clear
set more off
*----- example data -----
input ///
id str20 date treat match num
1 01feb2000 1 2 2
1 01apr2000 0 . .
1 01jan2002 1 3 1
2 01mar2000 1 3 0
2 01may2000 0 . .
3 01dec2002 1 . .
end
list, sepby(id)
gen dat = date(date,"DMY")
format %td dat
drop date
order dat, after(id)
list, sepby(id)
*----- what you want -----
gen num2 = .
forvalues i = 1/`=_N' {
if treat[`i'] == 1 {
count if id == match[`i'] & dat <= dat[`i'] + 365
replace num2 = r(N) in `i'
}
}
replace num2 = . if missing(match)
list, sepby(id)
assert num == num2
我没有关于你的数据集大小的信息,所以除非你准确地透露,否则我不会做任何测试。
(我没有检查你的代码。我只是尝试将你的问题的措辞翻译成 Stata 代码。)