R—在数据帧中创建条件和作为新列的更快方法
我最初的问题 我有一个医院就诊的数据框架,如下所示:R—在数据帧中创建条件和作为新列的更快方法,r,dplyr,R,Dplyr,我最初的问题 我有一个医院就诊的数据框架,如下所示: df = data.frame(PNUM = c(1,1,1,1,2,2,2,2), indate=as.Date(c("2016-01-03","2016-05-05","2017-02-03", "2017-06-07","2016-01-03","2016-05-05", "
df = data.frame(PNUM = c(1,1,1,1,2,2,2,2),
indate=as.Date(c("2016-01-03","2016-05-05","2017-02-03",
"2017-06-07","2016-01-03","2016-05-05",
"2017-02-03","2017-06-07")),
Inpatient=c(0,1,0,1,1,1,1,0),
AnE=c(1,0,1,0,0,0,0,1))
PNUM indate Inpatient AnE sum_365_Inpatient sum_365_AnE
1 1 2016-01-03 0 1 0 0
2 1 2016-05-05 1 0 0 1
3 1 2017-02-03 0 1 1 0
4 1 2017-06-07 1 0 0 1
5 2 2016-01-03 1 0 0 0
6 2 2016-05-05 1 0 1 0
7 2 2017-02-03 1 0 1 0
8 2 2017-06-07 0 1 1 0
输出:
PNUM indate Inpatient AnE
1 1 2016-01-03 0 1
2 1 2016-05-05 1 0
3 1 2017-02-03 0 1
4 1 2017-06-07 1 0
5 2 2016-01-03 1 0
6 2 2016-05-05 1 0
7 2 2017-02-03 1 0
8 2 2017-06-07 0 1
现在,我想添加列,以反映当前“indate”之前365天的“住院”和“电子”就诊次数。预期结果如下所示:
df = data.frame(PNUM = c(1,1,1,1,2,2,2,2),
indate=as.Date(c("2016-01-03","2016-05-05","2017-02-03",
"2017-06-07","2016-01-03","2016-05-05",
"2017-02-03","2017-06-07")),
Inpatient=c(0,1,0,1,1,1,1,0),
AnE=c(1,0,1,0,0,0,0,1))
PNUM indate Inpatient AnE sum_365_Inpatient sum_365_AnE
1 1 2016-01-03 0 1 0 0
2 1 2016-05-05 1 0 0 1
3 1 2017-02-03 0 1 1 0
4 1 2017-06-07 1 0 0 1
5 2 2016-01-03 1 0 0 0
6 2 2016-05-05 1 0 1 0
7 2 2017-02-03 1 0 1 0
8 2 2017-06-07 0 1 1 0
我已经找到了一种方法来实现这一点(见下文),但速度非常慢(对于一个包含10000行的新列,大约需要4分钟)。我的原始数据帧有200万行和>100列,我想为它们创建这些总和。我对R比较陌生,通过将几个类似问题的内容组合在一起,创建了以下解决方案。我想这不是很有效。我将非常感谢任何关于如何改进我的代码的建议
这是我非常低效的解决方案
我首先定义了一个函数,该函数计算某个特定列回顾X天的总和(另外受到ID的限制,因为我只想要来自同一个人的事件)
为此设计了一个非等联接 对于互斥伪列的情况… 首先,一些设置
# go to long form
library(data.table)
DT = melt(setDT(df), id=c("PNUM", "indate"), variable.name = "status")[value == 1, !"value"]
setorder(DT, PNUM, indate)
# use integer dates
DT[, indate := as.IDate(indate)]
PNUM indate status
1: 1 2016-01-03 AnE
2: 1 2016-05-05 Inpatient
3: 1 2017-02-03 AnE
4: 1 2017-06-07 Inpatient
5: 2 2016-01-03 Inpatient
6: 2 2016-05-05 Inpatient
7: 2 2017-02-03 Inpatient
8: 2 2017-06-07 AnE
数一数
for (s in unique(DT$status)){
DT[, paste0("n365_", s) :=
.SD[status == s][.SD[, .(PNUM, d_dn = indate - 365L, d_up = indate)],
on=.(PNUM, indate >= d_dn, indate < d_up),
.N, by=.EACHI]$N
][]
}
PNUM indate status n365_AnE n365_Inpatient
1: 1 2016-01-03 AnE 0 0
2: 1 2016-05-05 Inpatient 1 0
3: 1 2017-02-03 AnE 0 1
4: 1 2017-06-07 Inpatient 1 0
5: 2 2016-01-03 Inpatient 0 0
6: 2 2016-05-05 Inpatient 0 1
7: 2 2017-02-03 Inpatient 0 1
8: 2 2017-06-07 AnE 0 1
通常,对整数的联接/查找比对浮点数的联接/查找更快,这就是为什么在这里进行转换。
lappy
和for
循环方式是等效的,尽管lappy
方式只涉及构建查找这些
一次,因此可能会更快。非等联接就是为了实现这一点而设计的
对于互斥伪列的情况…
首先,一些设置
# go to long form
library(data.table)
DT = melt(setDT(df), id=c("PNUM", "indate"), variable.name = "status")[value == 1, !"value"]
setorder(DT, PNUM, indate)
# use integer dates
DT[, indate := as.IDate(indate)]
PNUM indate status
1: 1 2016-01-03 AnE
2: 1 2016-05-05 Inpatient
3: 1 2017-02-03 AnE
4: 1 2017-06-07 Inpatient
5: 2 2016-01-03 Inpatient
6: 2 2016-05-05 Inpatient
7: 2 2017-02-03 Inpatient
8: 2 2017-06-07 AnE
数一数
for (s in unique(DT$status)){
DT[, paste0("n365_", s) :=
.SD[status == s][.SD[, .(PNUM, d_dn = indate - 365L, d_up = indate)],
on=.(PNUM, indate >= d_dn, indate < d_up),
.N, by=.EACHI]$N
][]
}
PNUM indate status n365_AnE n365_Inpatient
1: 1 2016-01-03 AnE 0 0
2: 1 2016-05-05 Inpatient 1 0
3: 1 2017-02-03 AnE 0 1
4: 1 2017-06-07 Inpatient 1 0
5: 2 2016-01-03 Inpatient 0 0
6: 2 2016-05-05 Inpatient 0 1
7: 2 2017-02-03 Inpatient 0 1
8: 2 2017-06-07 AnE 0 1
通常,对整数的联接/查找比对浮点数的联接/查找更快,这就是为什么在这里进行转换。
lappy
和for
循环方式是等效的,尽管lappy
方式只涉及构建查找这些
一次,因此可能更快。Wow。看起来不错。但是,是否可以使用我的原始虚拟变量而不是状态来执行此操作?正如我在文章中提到的,我有100个变量,其中大多数变量并不相互排斥(例如,也可能有一行是“AnE”和“住院患者”)。很抱歉,我对data.table语法没有任何经验,无法理解;我来编辑。我没有注意到它们可能不是相互排斥的。非常感谢。第二个版本非常好用。哇。看起来不错。但是,是否可以使用我的原始虚拟变量而不是状态来执行此操作?正如我在文章中提到的,我有100个变量,其中大多数变量并不相互排斥(例如,也可能有一行是“AnE”和“住院患者”)。很抱歉,我对data.table语法没有任何经验,无法理解;我来编辑。我没有注意到它们可能不是相互排斥的。非常感谢。第二个版本非常好用。