r - 根据日期识别时间点
问题描述
我有一个数据集,其中在不同时间从同一个人那里收集了多个不同类型的样本,这给了我一个看起来像这样的数据集
Patient SampleType Collection-Date
1 A 15-02-2001
1 B 15-02-2001
2 A 19-02-2001
2 B 19-02-2001
3 A 16-05-2001
3 B 16-05-2001
1 A 16-03-2001
1 B 16-03-2001
3 B 05-03-2001
请注意,日期采用日-月-年格式。我想在 R 中做的是创建一个新变量,我可以使用它来识别每个样本属于哪个时间点,以提供以下输出。
Patient SampleType Collection-Date TimePoint
1 A 15-02-2001 T1
1 B 15-02-2001 T1
2 A 19-02-2001 T1
2 B 19-02-2001 T1
3 A 16-05-2001 T1
3 B 16-05-2001 T1
1 A 16-03-2001 T2
1 B 16-03-2001 T2
3 B 05-03-2001 T2
我已经研究出如何主要使用以下代码来做到这一点:
#generate a key to connect Patients and samples
df<-mutate(df, Key=paste(df$Patient,df$SampleType, sep = "")
#Create a list of Keys
KeyList <- list(df$Key)
#Separate the original data frame based on Key
#Create new dataframes for all values of Key
for (i in unique(DateComp$Key)){
nam<-paste("df", i, sep = ".")
assign(nam, DateComp[DateComp$Key== i,])
}
这将为每个患者样本类型组合生成一个唯一的数据框,然后我可以通过执行以下操作来创建所需的结果:
df.1A[order(as.Date(1A$Collection-Date, format="%d%m%Y")),]
rownames(df.1A)= NULL
df.1A <- mutate(df.1A, TimePoint = paste("TP", row_number(),sep=""))
这主要为患者 1,样本类型 A 创建所需的输出,因为它读取
Patient SampleType Collection-Date Key TimePoint
1 A 15-02-2001 1A TP1
1 A 16-03-2001 1A TP2
但是,这种方法有两个问题:1)我必须为每个唯一创建的数据框手动编写代码
(所以如果有人能解释我如何使用 lapply 函数或类似函数来做到这一点,我将不胜感激)
2) 如果患者第二次就诊时只有一个特定的样本类型,那么它将被标记为时间点 1,而不是时间点 2。有人知道我如何重写代码,这样就不会成为问题了吗?提前致谢!
解决方案
如果我理解正确,OP 想要分别计算每个组合的记录,Patient
并按.SampleType
df
为此目的,它data.table
有一个方便的功能。rowid()
它也可以在dplyr
管道中使用:
library(dplyr)
df %>%
mutate(TimePoint = data.table::rowid(Patient, SampleType, prefix = "TP"))
Patient SampleType Collection-Date TimePoint 1 1 A 15-02-2001 TP1 2 1 B 15-02-2001 TP1 3 2 A 19-02-2001 TP1 4 2 B 19-02-2001 TP1 5 3 A 16-05-2001 TP1 6 3 B 16-05-2001 TP1 7 1 A 16-03-2001 TP2 8 1 B 16-03-2001 TP2 9 3 B 05-03-2001 TP2
这符合 OP 的预期结果。但是,我认为这不是正确的结果。
按日期订购更安全
上面的方法有一个主要缺陷:时间点的编号依赖于给定的行顺序df
。Patient
但是3 和B的行顺序SampleType
不是根据Collection-Date
:
df %>%
mutate(TimePoint = data.table::rowid(Patient, SampleType, prefix = "TP")) %>%
arrange(Patient, SampleType, `Collection-Date`)
Patient SampleType Collection-Date TimePoint 1 1 A 15-02-2001 TP1 2 1 A 16-03-2001 TP2 3 1 B 15-02-2001 TP1 4 1 B 16-03-2001 TP2 5 2 A 19-02-2001 TP1 6 2 B 19-02-2001 TP1 7 3 A 16-05-2001 TP1 8 3 B 05-03-2001 TP2 9 3 B 16-05-2001 TP1
TP2
尽管收集日期早于第 9 行,但第 8 行被标记TP1
。我怀疑这是正确且预期的时间点编号。
因此,在应用该rowid()
函数之前,需要按收集日期对行进行重新排序。
此外,我们还可以纠正另一个缺陷。Collection-Date
不是语法上有效的名称,可能会导致编码问题(除非转义)。
在这里,我们切换到data.table
我更熟悉的语法:
library(data.table)
# coerce to data.table
setDT(df)
# make syntactically valid names
setnames(df, names(df), make.names(names(df)))
# convert character date to class Date
df[, Collection.Date := lubridate::dmy(Collection.Date)]
# order by Date and append rowid counts
df[order(Collection.Date), TimePoint := rowid(Patient, SampleType, prefix = "TP")][]
Patient SampleType Collection.Date TimePoint 1: 1 A 2001-02-15 TP1 2: 1 B 2001-02-15 TP1 3: 2 A 2001-02-19 TP1 4: 2 B 2001-02-19 TP1 5: 3 A 2001-05-16 TP1 6: 3 B 2001-05-16 TP2 7: 1 A 2001-03-16 TP2 8: 1 B 2001-03-16 TP2 9: 3 B 2001-03-05 TP1
请注意, 的行df
尚未重新排列,但rowid()
功能已按正确的顺序应用,因此第 9 行现在已TP1
根据其收集日期正确标记。
数据
library(data.table)
df <- fread(
"Patient SampleType Collection-Date
1 A 15-02-2001
1 B 15-02-2001
2 A 19-02-2001
2 B 19-02-2001
3 A 16-05-2001
3 B 16-05-2001
1 A 16-03-2001
1 B 16-03-2001
3 B 05-03-2001",
data.table = FALSE
)