2011-11-18 92 views
4

讓我先說這個問題與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和你將如何開始?如果沒有,你可以建議一個替代工具嗎?

回答

4

設置數據

首先設置輸入數據幀。我們創建一個數據幀的兩個版本:AB只使用字符列的時間和AtBt使用克隆氏病包"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聲明。

+0

哇。謝謝你這樣徹底的回答。 – bnjmn

1

將兩個data.frames與merge()合併在一起。然後subset()生成的數據幀與條件time >= startTime & time <= startTime + Duration或任何規則對您有意義。

2

這裏是一個例子:

# 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看起來是在範圍內。是否有意義?

+0

oops。我的意思是obs 2超出範圍。你是對的。 – bnjmn