dplyr-安排、分组、计算日期差异
我有一个大数据集,显示了从健康事件到随后的疾病事件的儿童随访情况 我试图使用dplyr来计算健康事件和第一次生病事件之间的时间 模拟数据集 模拟输出数据集 我只能使用dplyr按id和日期对数据进行排序,然后按id分组:dplyr-安排、分组、计算日期差异,r,dplyr,R,Dplyr,我有一个大数据集,显示了从健康事件到随后的疾病事件的儿童随访情况 我试图使用dplyr来计算健康事件和第一次生病事件之间的时间 模拟数据集 模拟输出数据集 我只能使用dplyr按id和日期对数据进行排序,然后按id分组: df2 <- df1 %>% arrange(id, date_follow_up) %>% group_by(id) 在计算日期差异并将其添加到每个人的健康事件行旁边时,您需要帮助:这里有一种方法,但如果您每个ID有多个健康事件,您可能需要调整它以使其更加
df2 <- df1 %>% arrange(id, date_follow_up) %>% group_by(id)
在计算日期差异并将其添加到每个人的健康事件行旁边时,您需要帮助:这里有一种方法,但如果您每个ID有多个健康事件,您可能需要调整它以使其更加可靠:
# turn dates into subtractable Date class
df1 %>% mutate(date_follow_up = as.Date(date_follow_up, '%m/%d/%y')) %>%
group_by(id) %>%
# Add new column. If there is a "healthy" event,
mutate(diff_time = ifelse(event == 'healthy',
# subtract the date from the minimum "sick" date
min(date_follow_up[event == 'sick']) - date_follow_up,
# else if it isn't a "healthy" event, return NA.
NA))
## Source: local data frame [6 x 4]
##
## id event date_follow_up diff_time
## <dbl> <chr> <date> <dbl>
## 1 1 healthy 2015-04-01 3
## 2 1 2015-04-02 NA
## 3 1 2015-04-03 NA
## 4 1 sick 2015-04-04 NA
## 5 1 sick 2015-04-05 NA
## 6 1 2015-04-06 NA
这里有一种方法,但如果您每个ID有多个健康事件,您可能需要调整它以变得更健壮:
# turn dates into subtractable Date class
df1 %>% mutate(date_follow_up = as.Date(date_follow_up, '%m/%d/%y')) %>%
group_by(id) %>%
# Add new column. If there is a "healthy" event,
mutate(diff_time = ifelse(event == 'healthy',
# subtract the date from the minimum "sick" date
min(date_follow_up[event == 'sick']) - date_follow_up,
# else if it isn't a "healthy" event, return NA.
NA))
## Source: local data frame [6 x 4]
##
## id event date_follow_up diff_time
## <dbl> <chr> <date> <dbl>
## 1 1 healthy 2015-04-01 3
## 2 1 2015-04-02 NA
## 3 1 2015-04-03 NA
## 4 1 sick 2015-04-04 NA
## 5 1 sick 2015-04-05 NA
## 6 1 2015-04-06 NA
这里是使用dplyr的另一种方法,尽管与早期的解决方案相比它稍微长一点
library(dplyr)
df1$date_follow_up <- as.Date(df1$date_follow_up, "%m/%d/%y")
df1 %>% group_by(id, event) %>%
filter(event %in% c("healthy", "sick")) %>%
slice(which.min(date_follow_up)) %>% group_by(id) %>%
mutate(diff_time = lead(date_follow_up) - date_follow_up) %>%
right_join(df1, by = c("id", "event" , "date_follow_up"))
# Output
Source: local data frame [6 x 4]
Groups: id [?]
id event date_follow_up diff_time
<dbl> <chr> <date> <S3: difftime>
1 1 healthy 2015-04-01 3 days
2 1 2015-04-02 NA days
3 1 2015-04-03 NA days
4 1 sick 2015-04-04 NA days
5 1 sick 2015-04-05 NA days
6 1 2015-04-06 NA days
这里是使用dplyr的另一种方法,尽管与早期的解决方案相比它稍微长一点
library(dplyr)
df1$date_follow_up <- as.Date(df1$date_follow_up, "%m/%d/%y")
df1 %>% group_by(id, event) %>%
filter(event %in% c("healthy", "sick")) %>%
slice(which.min(date_follow_up)) %>% group_by(id) %>%
mutate(diff_time = lead(date_follow_up) - date_follow_up) %>%
right_join(df1, by = c("id", "event" , "date_follow_up"))
# Output
Source: local data frame [6 x 4]
Groups: id [?]
id event date_follow_up diff_time
<dbl> <chr> <date> <S3: difftime>
1 1 healthy 2015-04-01 3 days
2 1 2015-04-02 NA days
3 1 2015-04-03 NA days
4 1 sick 2015-04-04 NA days
5 1 sick 2015-04-05 NA days
6 1 2015-04-06 NA days
我对你的数据做了更多的修改,以便彻底检查这个案例。我的建议与阿利斯泰尔的建议相似。我的建议可以为mydf中的id 2生成NA,而alistaire建议创建Inf。首先,我将字符中的日期转换为日期对象。然后,我按id对数据进行分组,并通过从生病的第一天(即日期跟进)减去健康的第一天(即日期跟进)[event==health][1]来计算时间差[event==sick][1]。最后,我用NA替换了不相关行的时差
id event date_follow_up
1 1 healthy 4/1/15
2 1 4/2/15
3 1 4/3/15
4 1 sick 4/4/15
5 1 sick 4/5/15
6 2 4/1/15
7 2 healthy 4/2/15
8 2 4/3/15
9 2 4/4/15
10 2 4/5/15
11 3 4/1/15
12 3 healthy 4/2/15
13 3 sick 4/3/15
14 3 4/4/15
15 3 4/5/15
library(dplyr)
mutate(mydf, date_follow_up = as.Date(date_follow_up, format = "%m/%d/%y")) %>%
group_by(id) %>%
mutate(foo = date_follow_up[event == "sick"][1] - date_follow_up[event == "healthy"][1],
foo = replace(foo, which(event != "healthy"), NA))
Source: local data frame [15 x 4]
Groups: id [3]
id event date_follow_up foo
<int> <chr> <date> <S3: difftime>
1 1 healthy 2015-04-01 3 days
2 1 2015-04-02 NA days
3 1 2015-04-03 NA days
4 1 sick 2015-04-04 NA days
5 1 sick 2015-04-05 NA days
6 2 2015-04-01 NA days
7 2 healthy 2015-04-02 NA days
8 2 2015-04-03 NA days
9 2 2015-04-04 NA days
10 2 2015-04-05 NA days
11 3 2015-04-01 NA days
12 3 healthy 2015-04-02 1 days
13 3 sick 2015-04-03 NA days
14 3 2015-04-04 NA days
15 3 2015-04-05 NA days
资料
我对您的数据进行了更多的修改,以彻底检查这个案例。我的建议与alistaire的建议类似。我的建议可以在mydf中为id 2生成NA,而alistaire的建议创建Inf。首先,我将字符中的日期转换为日期对象。然后,我按id对数据进行分组,并通过减去t来计算时差健康的第一天,即从生病的第一天开始的日期跟进[event==Health][1],即日期跟进[event==sick][1]。最后,我用NA替换了不相关行的时差
id event date_follow_up
1 1 healthy 4/1/15
2 1 4/2/15
3 1 4/3/15
4 1 sick 4/4/15
5 1 sick 4/5/15
6 2 4/1/15
7 2 healthy 4/2/15
8 2 4/3/15
9 2 4/4/15
10 2 4/5/15
11 3 4/1/15
12 3 healthy 4/2/15
13 3 sick 4/3/15
14 3 4/4/15
15 3 4/5/15
library(dplyr)
mutate(mydf, date_follow_up = as.Date(date_follow_up, format = "%m/%d/%y")) %>%
group_by(id) %>%
mutate(foo = date_follow_up[event == "sick"][1] - date_follow_up[event == "healthy"][1],
foo = replace(foo, which(event != "healthy"), NA))
Source: local data frame [15 x 4]
Groups: id [3]
id event date_follow_up foo
<int> <chr> <date> <S3: difftime>
1 1 healthy 2015-04-01 3 days
2 1 2015-04-02 NA days
3 1 2015-04-03 NA days
4 1 sick 2015-04-04 NA days
5 1 sick 2015-04-05 NA days
6 2 2015-04-01 NA days
7 2 healthy 2015-04-02 NA days
8 2 2015-04-03 NA days
9 2 2015-04-04 NA days
10 2 2015-04-05 NA days
11 3 2015-04-01 NA days
12 3 healthy 2015-04-02 1 days
13 3 sick 2015-04-03 NA days
14 3 2015-04-04 NA days
15 3 2015-04-05 NA days
资料
我们还可以使用data.table。将“data.frame”转换为“data.table”setDTmydf,使用as.date更改“date\u follow\u up to date”的类,按“id”分组,并通过获取逻辑向量事件==health的累积和创建分组变量,我们得到第一个生病“事件”的“date\u follow\u”与第一个“date\u fo”的差值如果某一特定群体中有任何生病的“事件”或其他返回NA,则允许健康的“事件”
library(data.table)
setDT(mydf)[, date_follow_up := as.Date(date_follow_up, "%m/%d/%y")
][, foo := if(any(event == "sick"))
as.integer(date_follow_up[which(event=="sick")[1]] -
date_follow_up[1] )
else NA_integer_ ,
by = .(grp= cumsum(event == "healthy"), id)]
然后,对于所有不健康的事件,我们可以将foo更改为NA
mydf[event!= "healthy", foo := NA_integer_]
mydf
# id event date_follow_up foo
# 1: 1 healthy 2015-04-01 3
# 2: 1 2015-04-02 NA
# 3: 1 2015-04-03 NA
# 4: 1 sick 2015-04-04 NA
# 5: 1 sick 2015-04-05 NA
# 6: 2 2015-04-01 NA
# 7: 2 healthy 2015-04-02 NA
# 8: 2 2015-04-03 NA
# 9: 2 2015-04-04 NA
#10: 2 2015-04-05 NA
#11: 3 2015-04-01 NA
#12: 3 healthy 2015-04-02 1
#13: 3 sick 2015-04-03 NA
#14: 3 2015-04-04 NA
#15: 3 2015-04-05 NA
#16: 4 2015-04-01 NA
#17: 4 healthy 2015-04-02 3
#18: 4 2015-04-03 NA
#19: 4 2015-04-04 NA
#20: 4 sick 2015-04-05 NA
#21: 4 sick 2015-04-06 NA
#22: 4 2015-04-07 NA
#23: 4 healthy 2015-04-08 2
#24: 4 2015-04-09 NA
#25: 4 sick 2015-04-10 NA
注意:在这里,我准备了一个特定id可能存在多个健康/疾病“事件”的数据
数据
我们还可以使用data.table。将“data.frame”转换为“data.table”setDTmydf,使用as.date更改“date\u follow\u up to date”的类,按“id”分组,并通过获取逻辑向量事件==health的累积和创建分组变量,我们得到第一个生病“事件”的“date\u follow\u”与第一个“date\u fo”的差值如果某一特定群体中有任何生病的“事件”或其他返回NA,则允许健康的“事件”
library(data.table)
setDT(mydf)[, date_follow_up := as.Date(date_follow_up, "%m/%d/%y")
][, foo := if(any(event == "sick"))
as.integer(date_follow_up[which(event=="sick")[1]] -
date_follow_up[1] )
else NA_integer_ ,
by = .(grp= cumsum(event == "healthy"), id)]
然后,对于所有不健康的事件,我们可以将foo更改为NA
mydf[event!= "healthy", foo := NA_integer_]
mydf
# id event date_follow_up foo
# 1: 1 healthy 2015-04-01 3
# 2: 1 2015-04-02 NA
# 3: 1 2015-04-03 NA
# 4: 1 sick 2015-04-04 NA
# 5: 1 sick 2015-04-05 NA
# 6: 2 2015-04-01 NA
# 7: 2 healthy 2015-04-02 NA
# 8: 2 2015-04-03 NA
# 9: 2 2015-04-04 NA
#10: 2 2015-04-05 NA
#11: 3 2015-04-01 NA
#12: 3 healthy 2015-04-02 1
#13: 3 sick 2015-04-03 NA
#14: 3 2015-04-04 NA
#15: 3 2015-04-05 NA
#16: 4 2015-04-01 NA
#17: 4 healthy 2015-04-02 3
#18: 4 2015-04-03 NA
#19: 4 2015-04-04 NA
#20: 4 sick 2015-04-05 NA
#21: 4 sick 2015-04-06 NA
#22: 4 2015-04-07 NA
#23: 4 healthy 2015-04-08 2
#24: 4 2015-04-09 NA
#25: 4 sick 2015-04-10 NA
注意:在这里,我准备了一个特定id可能存在多个健康/疾病“事件”的数据
数据
使用@akrun的示例数据,这里有一种使用data.table中的滚动联接的方法: 其思想是:对于dt1中的每个健康日期,获取dt2中第一个生病日期的索引>=健康日期 然后直接减去这两个日期得到最终结果
dt[event == "healthy",
diff := as.integer(dt2$date_follow_up[idx] - dt1$date_follow_up)]
使用@akrun的示例数据,这里有一种使用data.table中的滚动联接的方法: 其思想是:对于dt1中的每个健康日期,获取dt2中第一个生病日期的索引>=健康日期 然后直接减去这两个日期得到最终结果
dt[event == "healthy",
diff := as.integer(dt2$date_follow_up[idx] - dt1$date_follow_up)]
你还考虑了可能的情况。再加上一个反馈给你。“JasZurro谢谢,是的,我有点好奇我的第一个解决方案是否适用于它。”AkRun我相信OP有足够的事情来考虑他/她如何解决这个难题。嗨,Akrun,谢谢,考虑到多个健康/生病的事件。非常感谢。现在看看如何真实数据回应:hi@akrun,我在更大的数据集上试用过,效果很好。但是,我需要做一些调整。到目前为止,脚本为每个人寻找每个健康事件之后的第一个生病事件。请帮助我调整:对于每个人,按日期对条目进行排序,如果第一个条目是健康的,然后发现第一个生病的事件,并在日期上有所不同。它不应该考虑更多的健康事件跟随你进一步考虑可能的情况。再加上一个回到你。:“JasZurro谢谢,是的,我有点好奇我的第一个解决方案是否适用于我。”
我相信OP有足够的事情来考虑他/她如何解决这个难题。嗨,Akrun,谢谢你,并且考虑到多重健康/病态的事件。非常感谢。现在看看真实数据是如何反应的:hi@akrun,我已经在更大的数据集上试用过了,效果非常好。但是,我需要做一些调整。到目前为止,脚本将查找每个个体的每个健康事件之后的第一个生病事件。请帮助我调整:对于每个人,按日期对条目进行排序,如果第一个条目是健康的,那么找到接下来的第一个生病事件并获得日期差异。它不应该考虑后续的健康事件,感谢反馈,在运行最后一行代码时,我得到了错误:[.DAT.TabDelt2,Dt1,Loop--INF,其中=true,on = .id::找不到函数.HI,谢谢反馈,运行最后一行代码时,我得到了错误:[.data.tabledt2,dt1,roll=-Inf,which=TRUE,on=.id,:找不到函数。嗨,Jazzurro,就像Akrun一样,我很感谢您考虑到多个健康/疾病事件以及您如何满足其他id。让我看看真正的数据如何响应。Cheers@K.Kariuki很高兴能帮助你。嗨,爵士音乐,就像Akrun的一样,我很感激考虑多个健康/疾病事件,以及您如何满足其他id。让我看看真实数据如何响应。Cheers@K.Kariuki很高兴能为您提供帮助。嗨,Alistare。感谢您的反馈。Akrun和Jazzurro承办了多项健康活动。不过,非常感谢:嗨,Alistare。谢谢您的反馈。Akrun和Jazzurro承办了r多个健康事件。不过,非常感谢:嗨,Sumedh,谢谢。我在我发布的原始数据集上测试了它,效果很好。然后我在Akrun的数据集上进行了测试,该数据集与真实数据类似,我有多个健康/疾病事件,但失败了,出现以下错误:警告消息:在右侧\u join\u implx,y,by$x,by$y:join character vect或者和因子,强制转换为字符向量。仍然非常感谢..嗨,Sumedh,谢谢。我在我发布的原始数据集上测试了它,效果很好。然后我在Akrun的数据集上进行了测试,该数据集与真实数据类似,我有多个健康/疾病事件,但失败了,错误如下:警告消息:在右侧加入\u implx,y,by$x,by$y:joining字符向量和因子,强制转换为字符向量。仍然非常感谢。。