我想编写一个函数,根据唯一值[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更适合这个。使用其中任何一个开放给建议。
答案 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都有一行。