[英]Merge Records Over Time Interval
首先讓我說這個問題與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
使用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)))
# 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"
列將通過sqldf類賦值啟發式自動設置為"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中使用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語句。
這是一個例子:
# 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看起來在范圍內。 是否有意義?
將兩個data.frames與merge()
在一起。 然后使用條件time >= startTime & time <= startTime + Duration
或任何對你有意義的規則, subset()
結果data.frame。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.