按时间间隔合并记录
让我先说这个问题与R(统计编程语言)有关,但我为其他环境提供了直接的建议。按时间间隔合并记录
目标是将数据框(df)A的结果合并到df B中的子元素。这是一对多关系,但是,这里的扭曲,一旦记录与键匹配,他们也必须匹配由开始时间和持续时间给定的特定时间帧。
例如,在DF A中的记录数:
OBS ID StartTime Duration Outcome
1 01 10:12:06 00:00:10 Normal
2 02 10:12:30 00:00:30 Weird
3 01 10:15:12 00:01:15 Normal
4 02 10:45:00 00:00:02 Normal
而且从DF B:
OBS ID Time
1 01 10:12:10
2 01 10:12:17
3 02 10:12:45
4 01 10:13:00
从合并的期望的结果将是:
OBS ID Time Outcome
1 01 10:12:10 Normal
3 02 10:12:45 Weird
期望结果:数据框B,结果合并到A中。注意事项2和4被删除,因为它们虽然匹配A中记录的ID不符合给定的时间间隔。
问题
是否有可能进行这种操作的在R和你将如何开始?如果没有,你可以建议一个替代工具吗?
设置数据
首先设置输入数据帧。我们创建一个数据帧的两个版本:A
和B
只使用字符列的时间和At
和Bt
使用克隆氏病包"times"
类的时间(其中有超过"character"
类的优点是可以添加和减去它们):
LinesA <- "OBS ID StartTime Duration Outcome
1 01 10:12:06 00:00:10 Normal
2 02 10:12:30 00:00:30 Weird
3 01 10:15:12 00:01:15 Normal
4 02 10:45:00 00:00:02 Normal"
LinesB <- "OBS ID Time
1 01 10:12:10
2 01 10:12:17
3 02 10:12:45
4 01 10:13:00"
A <- At <- read.table(textConnection(LinesA), header = TRUE,
colClasses = c("numeric", rep("character", 4)))
B <- Bt <- read.table(textConnection(LinesB), header = TRUE,
colClasses = c("numeric", rep("character", 2)))
# in At and Bt convert times columns to "times" class
library(chron)
At$StartTime <- times(At$StartTime)
At$Duration <- times(At$Duration)
Bt$Time <- times(Bt$Time)
sqldf与次类
现在我们可以使用sqldf包进行计算。我们使用method="raw"
(不分配类输出),所以我们必须在"times"
类分配给输出"Time"
列我们自己:
library(sqldf)
out <- sqldf("select Bt.OBS, ID, Time, Outcome from At join Bt using(ID)
where Time between StartTime and StartTime + Duration",
method = "raw")
out$Time <- times(as.numeric(out$Time))
结果是:
> out
OBS ID Time Outcome
1 1 01 10:12:10 Normal
2 3 02 10:12:45 Weird
随着开发版本sqldf这样做可以不用method="raw"
而"Time"
列会自动设置为"times"
class by sqldf class assignment heuristic:
library(sqldf)
source("http://sqldf.googlecode.com/svn/trunk/R/sqldf.R") # grab devel ver
sqldf("select Bt.OBS, ID, Time, Outcome from At join Bt using(ID)
where Time between StartTime and StartTime + Duration")
sqldf与字符类
它实际上可能不通过执行sqlite的所有时间计算出使用的SQLite的strftime函数的字符串使用"times"
类。 SQL语句是可惜稍稍更复杂:
sqldf("select B.OBS, ID, Time, Outcome from A join B using(ID)
where strftime('%s', Time) - strftime('%s', StartTime)
between 0 and strftime('%s', Duration) - strftime('%s', '00:00:00')")
编辑:
了一系列固定的语法,增加了额外的方法和固定/改善read.table
声明的修改。
编辑:
简体/改进最终sqldf声明。
将两个data.frames与merge()
合并在一起。然后subset()
生成的数据帧与条件time >= startTime & time <= startTime + Duration
或任何规则对您有意义。
这里是一个例子:
# first, merge by ID
z <- merge(A[, -1], B, by = "ID")
# convert string to POSIX time
z <- transform(z,
s_t = as.numeric(strptime(as.character(z$StartTime), "%H:%M:%S")),
dur = as.numeric(strptime(as.character(z$Duration), "%H:%M:%S")) -
as.numeric(strptime("00:00:00", "%H:%M:%S")),
tim = as.numeric(strptime(as.character(z$Time), "%H:%M:%S")))
# subset by time range
subset(z, s_t < tim & tim < s_t + dur)
输出:
ID StartTime Duration Outcome OBS Time s_t dur tim
1 1 10:12:06 00:00:10 Normal 1 10:12:10 1321665126 10 1321665130
2 1 10:12:06 00:00:10 Normal 2 10:12:15 1321665126 10 1321665135
7 2 10:12:30 00:00:30 Weird 3 10:12:45 1321665150 30 1321665165
OBS#2看起来是在范围内。是否有意义?
oops。我的意思是obs 2超出范围。你是对的。 – bnjmn
哇。谢谢你这样彻底的回答。 – bnjmn