寻找有效的方法来查询R或Stata中的子组观察

时间:2016-09-22 21:54:37

标签: r stata

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

df$date[id == "1234"]

是否可以替换" 1234"使用从函数运行的唯一行派生的变量?有点像...

df$date[id == df$id]

,以便拉出[date]的值,其中[id]匹配索引行的[id]?实际上我会在循环中使用它,对于x的值,我可以使用以下方法查询特定的[date]值:

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]然后循环遍历每个唯一值[order]来完成,但记录数量(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看起来像是基于先前记录的排放日期[date_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更适合这个。使用其中任何一个开放给建议。

4 个答案:

答案 0 :(得分:1)

医院住院重叠的问题不时出现在Statalist上。查看示例here。解决方案是将入院/出院日期dyad转换为长形式并按时间顺序排列两个事件。新的医院咒语要么是患者的第一次观察,要么是在前一次观察结束时患者离开医院时。以下是从Bulat的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 |
     +---------------------------------------------------------+

答案 1 :(得分: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

答案 2 :(得分: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
}

答案 3 :(得分:-1)

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

此软件包的备忘单解释了如何非常雄辩地操作数据:https://www.rstudio.com/wp-content/uploads/2015/02/data-wrangling-cheatsheet.pdf

我不完全确定你想要计算什么。您是否尝试根据每行中的值进行计算来创建新列?或者,您是否尝试为ID的每个唯一值计算某些内容?在前一种情况下,我会使用dplyr::mutate(df, newcolumn = some_operation)。在后一种情况下,我会使用group_by(id),然后使用filter()summarise()等函数生成一个新数据框,每个ID都有一行。