如何使用 R 中不同列的数据替换不正确的日期
How to replace incorrect dates by using data from a different column in R
我正在清理一个大型医疗数据集。有些手术日期当然是不可能的(入院日期前一个世纪!)。下面是一个例子 df:
doa = c("2010-08-01", "2010-08-07", "2008-09-01") # date of admission
doo_1 = c("2010-08-02", "1900-01-01", "2008-09-03") # date of first op
doo_2 = c("1800-01-01", "1900-01-01", "2008-09-03") # date of second op
df= data.frame (doa, doo_1, doo_2)
当第 2 列和第 3 列(在实际数据集中有 25 列)中的值小于 doa 时,我想将其替换为 doa+1(因为操作往往在入院后的第二天发生)。
With data.table :您首先创建一个患者编号变量 ptn
DT <- setDT(df)
setnames(DT,"doa","doo")
DT[,ptn := .I]
然后你融化你的数据
plouf <- melt(DT,measure.vars = patterns("^doo"))
plouf[,value:= as.Date(value)]
plouf[,.SD,by = ptn]
ptn variable value
1: 1 doo 2010-08-01
2: 1 doo_1 2010-08-02
3: 1 doo_2 1800-01-01
4: 2 doo 2010-08-07
5: 2 doo_1 1900-01-01
6: 2 doo_2 1900-01-01
7: 3 doo 2008-09-01
8: 3 doo_1 2008-09-03
9: 3 doo_2 2008-09-03
然后您计算每个操作和每个患者的输入日期之间的差异(“by = ptn”分组操作允许这样做,并且您知道因为命名,您的 doa 是每个组中的第一个)
plouf[,diff := value - value[1],by = ptn]
如果差值为负,则将日期设置为输入日期+1
plouf[diff <0,value := value[1]+1,by = ptn]
然后将数据重塑为初始形状
dcast(plouf, ptn ~variable )
ptn doo doo_1 doo_2
1: 1 2010-08-01 2010-08-02 1800-01-02
2: 2 2010-08-07 1900-01-02 1900-01-02
3: 3 2008-09-01 2008-09-03 2008-09-03
不过我还是建议你用最后一个操作 +1 来代替这个奇怪的日期,而不是输入 patient。您可以按照以下步骤
plouf[diff <0,value := as.Date(NA),by = ptn] # create NA to use locf
library(zoo)
plouf[,value := na.locf(value), by = ptn] # use locf
plouf[diff<0, value := value +1] # add one day
dcast(plouf, ptn ~variable )
ptn doo doo_1 doo_2
1: 1 2010-08-01 2010-08-02 2010-08-03
2: 2 2010-08-07 2010-08-08 2010-08-08
3: 3 2008-09-01 2008-09-03 2008-09-03
OP 已要求将不太可能的手术日期替换为 doa + 1
(入院后的第二天)。
如果这个简单的规则将应用于所有 25 列,不需要将数据集从宽格式重塑为长格式并再次回到宽格式。
library(data.table)
# coerce date columns from factor or character to IDate
date_cols <- c("doa", "doo_1", "doo_2")
setDT(df)[, (date_cols) := lapply(.SD, as.IDate), .SDcols = date_cols][]
# replace dates if improbable
df[doo_1 < doa, doo_1 := doa + 1L][]
df[doo_2 < doa, doo_2 := doa + 1L][]
doa doo_1 doo_2
1: 2010-08-01 2010-08-02 2010-08-02
2: 2010-08-07 2010-08-08 2010-08-08
3: 2008-09-01 2008-09-03 2008-09-03
OP 提到生产数据集包含 25 列。这需要一个更灵活的解决方案,其中要处理的列名不是硬编码的,而是在向量中提供的:
op_cols <- c("doo_1", "doo_2")
for (x in op_cols) {
df[get(x) < doa, (x) := doa + 1L]
}
df[]
请注意 data.table 通过引用更新,即不复制整个数据对象,只复制选定的元素。
我正在清理一个大型医疗数据集。有些手术日期当然是不可能的(入院日期前一个世纪!)。下面是一个例子 df:
doa = c("2010-08-01", "2010-08-07", "2008-09-01") # date of admission
doo_1 = c("2010-08-02", "1900-01-01", "2008-09-03") # date of first op
doo_2 = c("1800-01-01", "1900-01-01", "2008-09-03") # date of second op
df= data.frame (doa, doo_1, doo_2)
当第 2 列和第 3 列(在实际数据集中有 25 列)中的值小于 doa 时,我想将其替换为 doa+1(因为操作往往在入院后的第二天发生)。
With data.table :您首先创建一个患者编号变量 ptn
DT <- setDT(df)
setnames(DT,"doa","doo")
DT[,ptn := .I]
然后你融化你的数据
plouf <- melt(DT,measure.vars = patterns("^doo"))
plouf[,value:= as.Date(value)]
plouf[,.SD,by = ptn]
ptn variable value
1: 1 doo 2010-08-01
2: 1 doo_1 2010-08-02
3: 1 doo_2 1800-01-01
4: 2 doo 2010-08-07
5: 2 doo_1 1900-01-01
6: 2 doo_2 1900-01-01
7: 3 doo 2008-09-01
8: 3 doo_1 2008-09-03
9: 3 doo_2 2008-09-03
然后您计算每个操作和每个患者的输入日期之间的差异(“by = ptn”分组操作允许这样做,并且您知道因为命名,您的 doa 是每个组中的第一个)
plouf[,diff := value - value[1],by = ptn]
如果差值为负,则将日期设置为输入日期+1
plouf[diff <0,value := value[1]+1,by = ptn]
然后将数据重塑为初始形状
dcast(plouf, ptn ~variable )
ptn doo doo_1 doo_2
1: 1 2010-08-01 2010-08-02 1800-01-02
2: 2 2010-08-07 1900-01-02 1900-01-02
3: 3 2008-09-01 2008-09-03 2008-09-03
不过我还是建议你用最后一个操作 +1 来代替这个奇怪的日期,而不是输入 patient。您可以按照以下步骤
plouf[diff <0,value := as.Date(NA),by = ptn] # create NA to use locf
library(zoo)
plouf[,value := na.locf(value), by = ptn] # use locf
plouf[diff<0, value := value +1] # add one day
dcast(plouf, ptn ~variable )
ptn doo doo_1 doo_2
1: 1 2010-08-01 2010-08-02 2010-08-03
2: 2 2010-08-07 2010-08-08 2010-08-08
3: 3 2008-09-01 2008-09-03 2008-09-03
OP 已要求将不太可能的手术日期替换为 doa + 1
(入院后的第二天)。
如果这个简单的规则将应用于所有 25 列,不需要将数据集从宽格式重塑为长格式并再次回到宽格式。
library(data.table)
# coerce date columns from factor or character to IDate
date_cols <- c("doa", "doo_1", "doo_2")
setDT(df)[, (date_cols) := lapply(.SD, as.IDate), .SDcols = date_cols][]
# replace dates if improbable
df[doo_1 < doa, doo_1 := doa + 1L][]
df[doo_2 < doa, doo_2 := doa + 1L][]
doa doo_1 doo_2 1: 2010-08-01 2010-08-02 2010-08-02 2: 2010-08-07 2010-08-08 2010-08-08 3: 2008-09-01 2008-09-03 2008-09-03
OP 提到生产数据集包含 25 列。这需要一个更灵活的解决方案,其中要处理的列名不是硬编码的,而是在向量中提供的:
op_cols <- c("doo_1", "doo_2")
for (x in op_cols) {
df[get(x) < doa, (x) := doa + 1L]
}
df[]
请注意 data.table 通过引用更新,即不复制整个数据对象,只复制选定的元素。