2011-11-18 5 views
4

この質問はR(statプログラミング言語)に関するものですが、私は他の環境に対しては直接的な提案をしています。時間をかけてレコードをマージする

目的は、データフレーム(df)Aの結果をdf Bのサブ要素にマージすることです。これは1対多の関係ですが、のがあります。開始時間と持続時間によって与えられた特定のフレームのフレームにわたって一致する。例えば

、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 

結果:Aからの結果がマージされたデータフレームB。観測結果2と4は、マッチしたもののAのレコードのIDは指定された時間間隔内には収まらなかった。

質問

それはRでの動作のこのソートを実行するとどのようにあなたが始めるだろうことは可能ですか?そうでない場合は、代替ツールを提案できますか?

答えて

4

まず、入力データフレームを設定し、データを設定します。 ABの2つのバージョンのデータフレームを作成します。AtBtは、時間のためのクラス"times"のchronパッケージを使用しています("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"を使用するので、出力"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クラス割り当てヒューリスティックによって自動的に"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機能を採用した文字列のうち、sqliteの中のすべての時間の計算を行うことにより、"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')") 

EDIT:

、文法を修正し、追加のアプローチを加え、固定/ read.table文を改善編集の一連。

EDIT:

簡体/改善最終sqldf声明。

+0

うわー。このような徹底的な答えをありがとう。 – bnjmn

1

merge()と一緒に2つのdata.framesをマージします。次にsubset()の結果のdata.frameは、条件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

関連する問題