2016-09-22 62 views
1

我想编写一个函数,根据唯一值[id]子组内的所有其他记录,对数据集中的每条记录执行操作。我很新的R,但我知道,您可以根据使用下面的条件查询的记录的子集:寻找有效的方式来查询R或Stata中的子组观察

df$date[id == "1234"] 

是否有可能取代“1234”从唯一的行衍生变量该功能正在运行?像...

df$date[id == df$id] 

,这样它拉[index]行索引行[id]匹配[id]的[日期]的值。在实践中我会在一个循环,其中对x的值,我用可以查询特定[日期]值使用此:

df$date[id == df$id & order == x] 

我的数据集必须为每个独特的[ID]多个记录。最终,我想将每个记录的[date_1]值与每个索引记录[id]子组中所有其他记录的[date_2]进行比较。数据看起来是这样的:

[id] | [order] | [date_1] | [date_2] | 
-------------------------------------- 
    A | 1 | 1/1 | 1/30 | 
    A | 2 | 1/5 | 1/5 | 
    A | 3 | 1/7 | 1/8 | 
    A | 4 | 1/9 | 1/9 | 
------------------------------------- 
    B | 1 | 3/7 | 3/10 | 
    B | 2 | 4/1 | 4/9 | 
-------------------------------------- 

虽然这可以通过每个唯一值[ID]循环,然后通过每个唯一值[为了]循环来完成,记录数(5-10万)证明该方法极其缓慢且资源密集。我想知道是否有一种更有效的方法来简单地遍历[order]值,然后同时计算每个记录的这个操作。

正如我所说的,我是新来的R,所以我不是万能的确定确切的语法,但我正在想象这样的事情:

for x = 1/max(order){ 
    df$episode_start <- 1 if df$date_1 - df$date_2[id == df$id & order == x] > 1 
    } 

我可以提供更多的细节这个项目的总体目标是否有用。简而言之,这些数据是医院记录,目标是确定开始一个新细分的记录,该记录被定义为在入院后1天内没有事先解除的相遇。数据变得棘手,因为存在重叠的记录(例如,如果病人是长期护理的住院病人,并且不得不去门诊就诊到急诊室) - 在上面的例子中,A2和A3看起来像是基于先前记录的出院日期[日期2]新的遭遇,但是A2,A3和A4都A1的跨度中发生的,所以结果应该是这样的:

[id] | [order] | [date_1] | [date_2] | [episode_start] 
------------------------------------------------------ 
    A | 1 | 1/1 | 1/30 |  1 
    A | 2 | 1/5 | 1/5 |  0 
    A | 3 | 1/7 | 1/8 |  0 
    A | 4 | 1/9 | 1/9 |  0 
----------------------------------------------------- 
    B | 1 | 3/7 | 3/10 |  1 
    B | 2 | 4/1 | 4/9 |  1 
------------------------------------------------------ 

在此先感谢。任何帮助或方向非常感谢。注意:我主要在Stata工作,并试图使用-bysort-命令来做类似的事情,但无济于事。也许以为R更适合这个。使用任一方式打开建议。

+1

如果你要问的Stata过,这是乐观的假设,人们将阅读一个长期以R为中心的问题,然后翻译。有两个人都很流利,但你在这方面的成功几率很低。我建议删除Stata标签,并提一提Stata提出的单独Stata问题,如果您同时寻求Stata建议。当然,我不反对R的问题,但无法解决这个问题。 –

回答

0

这里是什么让你开始R中使用data.table包:

data <- read.table(text = "id order date_1 date_2 
A 1 2016-01-01 2016-01-30 
A 2 2016-01-05 2016-01-05 
A 3 2016-01-07 2016-01-08 
A 4 2016-01-09 2016-01-09 
B 1 2016-03-07 2016-03-10 
B 2 2016-04-01 2016-04-9", header = T) 
library(data.table) 
data$date_1 <- as.Date(data$date_1) 
data$date_2 <- as.Date(data$date_2) 
dt <- data.table(data, key = c("date_1", "date_2")) 

res <- foverlaps(dt, dt, by.x = c("date_1", "date_2"), by.y = c("date_1", "date_2")) 

# Remove matches from irrelevant groups. 
res <- res[id == i.id] 

# Find the period start date. 
res[, min.date := min(i.date_1), by = .(id, order)] 
res[, period.start := (date_1 == min.date)] 

# Order records according to the period start date. 
res <- res[order(id, order, i.date_1)] 
# Remove duplicate rows 
res <- res[, .SD[1], by = .(id, order)] 

# Print resutls. 
res[, .(id, order, date_1, date_2, period.start)][] 

#  id order  date_1  date_2 period.start 
# 1: A  1 2016-01-01 2016-01-30   TRUE 
# 2: A  2 2016-01-05 2016-01-05  FALSE 
# 3: A  3 2016-01-07 2016-01-08  FALSE 
# 4: A  4 2016-01-09 2016-01-09  FALSE 
# 5: B  1 2016-03-07 2016-03-10   TRUE 
# 6: B  2 2016-04-01 2016-04-09   TRUE 
+1

太棒了! - 这看起来完全符合我的需要。我需要花一些时间来熟悉foverlaps(),但是谢谢你指点我。 – d4v1dn

+0

欢迎您! – Bulat

-1

我会使用dplyr包解决这个问题,这是一个可以通过运行install.packages('dplyr')然后library('dplyr')来安装的幻想数据处理工具。

此软件包的cheatsheet文件说明如何非常雄辩地处理数据:https://www.rstudio.com/wp-content/uploads/2015/02/data-wrangling-cheatsheet.pdf

我不能完全确定要计算什么。你是否试图根据每行中的值创建一个新的列?或者,你是否想要计算每个独特的值ID?在前一种情况下,我会使用​​。在后一种情况下,我会使用group_by(id),然后像filter()summarise()这样的函数为每个ID生成一行新的数据帧。

0

一个方便的方式来获得的子集进行处理是使用by。这会自动将您的data.frame(在这种情况下,通过ID)子集并允许您专注于处理每个ID的记录。

result <- by(df, df$id, function(x){ 
       ## identify start dates for sub-group 
      }) 

但是,我怀疑你仍然会发现速度很慢。按照另一个答案中的建议使用data.table应该有助于解决这个问题。

您可以通过在ID组上并行处理来进一步加快处理速度。请参阅foreach包以获取帮助。它可以让你写这样的代码(假设DF $ ID是一个因素):

foreach(i = levels(df$id)) %dopar% { 
    ## Identify start dates for group i 
} 
1

重叠住院的问题,从时间最多可显示时间Statalist。看一个例子here。解决方案是将入场/出场日期二元组转换为长格式,并按时间顺序排列这两个事件。新的医院咒语或者是对患者的第一次观察,或者是在前一次观察结束的时候患者出院。下面是与布拉特的R染料溶液得出的数据为例(修改,添加2个额外的住宿):

* Example generated by -dataex-. To install: ssc install dataex 
clear 
input str1 id byte order str10(date_1 date_2) 
"A" 1 "2016-01-01" "2016-01-30" 
"A" 2 "2016-01-05" "2016-01-05" 
"A" 3 "2016-01-07" "2016-01-08" 
"A" 4 "2016-01-09" "2016-01-09" 
"A" 5 "2016-02-09" "2016-02-09" 
"B" 1 "2016-03-07" "2016-03-10" 
"B" 2 "2016-03-08" "2016-03-08" 
"B" 3 "2016-04-01" "2016-04-9" 
end 

gen ndate1 = date(date_1,"YMD") 
gen ndate2 = date(date_2,"YMD") 
format %td ndate1 ndate2 

* confirm that each observation is uniquely identified by 
isid id order, sort 

* reshape to long; event==1 => admission; event==2 => discharge 
reshape long ndate, i(id order) j(event) 

* push the discharge date a day later (to make consecutive stays overlap) 
replace ndate = ndate + 1 if event == 2 

* define an inout increment for admission and discharge events 
bysort id order (event): gen inout = cond(_n==1,1,-1) 

* for each patient, sort events by date; for multiple events on the same day, 
* put admissions before discharge 
gsort id ndate -event 
by id: gen eventsum = sum(inout) 

* if the previous eventsum is 0, a new hospitalization spell starts 
by id: gen spell = sum(_n == 1 | eventsum[_n-1] == 0) 

* return to the original wide form data 
keep if inout == 1 

* flag the first obs of each spell 
bysort id spell (ndate order): gen newspell = _n == 1 

list id order date_1 date_2 spell newspell, sepby(id spell) 

,结果:

. list id order date_1 date_2 spell newspell, sepby(id spell) 

    +---------------------------------------------------------+ 
    | id order  date_1  date_2 spell newspell | 
    |---------------------------------------------------------| 
    1. | A  1 2016-01-01 2016-01-30  1   1 | 
    2. | A  2 2016-01-05 2016-01-05  1   0 | 
    3. | A  3 2016-01-07 2016-01-08  1   0 | 
    4. | A  4 2016-01-09 2016-01-09  1   0 | 
    |---------------------------------------------------------| 
    5. | A  5 2016-02-09 2016-02-09  2   1 | 
    |---------------------------------------------------------| 
    6. | B  1 2016-03-07 2016-03-10  1   1 | 
    7. | B  2 2016-03-08 2016-03-08  1   0 | 
    |---------------------------------------------------------| 
    8. | B  3 2016-04-01 2016-04-9  2   1 | 
    +---------------------------------------------------------+ 
+0

感谢您在stata中提供一个很好的解决方案。我将支票交给了Bulat的R解决方案(因为我将我的问题集中在R操作上),但实际上我最终将这个解决方案用于我的项目。 'eventsum'方法简单,优雅,快捷。谢谢! – d4v1dn