设置数据
首先设置输入数据框。我们创建两个版本的数据框:A
和B
,只使用字符列来表示时间,At
和Bt
使用chron包中的"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)))
library(chron)
At$StartTime <- times(At$StartTime)
At$Duration <- times(At$Duration)
Bt$Time <- times(Bt$Time)
使用times类的sqldf
现在我们可以使用sqldf包进行计算。我们使用method="raw"
(不会将类分配给输出),因此必须自己为输出的"Time"
列分配"times"
类:
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"
的情况下完成此操作,并且通过sqldf类分配启发式算法,"Time"
列将自动设置为"times"
类:
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中使用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 语句。