R은 :

2017-03-09 7 views
0

내가 두 data.frames이 조건 타임 스탬프 간격에 따라 조인 :R은 :

# limits 
    ID Start_1  End_1 Start_2  End_2 
1 A 2013-04-23 2013-06-09 2013-04-26 2017-02-06 
2 B 2013-05-12 2013-08-08 2013-04-26 2017-02-06 
3 C 2013-04-24 2013-04-26 2017-02-05 2017-02-08 

# df (header shown) 
    Timestamp   ID 
1 2013-04-24 14:01:21 A 
2 2013-04-24 14:01:46 B 
3 2013-04-24 14:01:50 C 
4 2013-04-25 00:02:19 A 
5 2013-04-25 02:02:48 B 
6 2013-04-25 04:02:04 C 

을 나는의 타임 스탬프를 기반으로 data.frame df의 열 Pop을 채우려 그 관찰 (df$Timestamp) : df$Timestamp (데이터 프레임에 저장, limits : limits$Start_1limits$End_1) 사이에있는 경우 Pop 열은 '예'로 채워집니다. 아닙니다, '아니오'.

df$Timestamp은 덮어 두 다음 시간 제한 (limits$Start_2limits$End_2)의 Pop 열이 '아마도'로 채워집니다 사이에있는 경우 '예'또는 '아니오'.

셋업은 다음과 같다 :

# main data.frame 
df<-structure(list(Timestamp = structure(c(1366826481, 1366826506, 
              1366826510, 1366862539, 1366869768, 1366876924, 1366948927, 1366948963, 
              1367013725, 1367107304, 1367107308, 1367107316, 1486342833, 1486350011, 
              1486350026, 1486429233, 1486436435, 1486436459, 1486515633, 1486522816, 
              1486522834, 1486530052, 1486537217, 1486537251), 
             class = c("POSIXct","POSIXt"), tzone = ""), 
        ID = structure(c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L,1L, 2L, 3L), 
            .Label = c("A", "B", "C"), class = "factor")), 
       .Names = c("Timestamp", "ID"), row.names = c(NA, -24L), class = "data.frame") 

# data.frame with time limits 
limits<- structure(list(ID = structure(1:3, .Label = c("A", "B", "C"), class = "factor"), 
        Start_1 = structure(c(1366689600, 1368331200, 1366776000), class = c("POSIXct","POSIXt"), tzone = ""), 
        End_1 = structure(c(1370750400, 1375934400,1366948800), class = c("POSIXct", "POSIXt"), tzone = ""), 
        Start_2 = structure(c(1366948800, 1366948800, 1486270800), class = c("POSIXct", "POSIXt"), tzone = ""), 
        End_2 = structure(c(1486357200, 1486357200, 1486530000), class = c("POSIXct", "POSIXt"), tzone = "")), 
       .Names = c("ID","Start_1", "End_1", "Start_2", "End_2"), 
       row.names = c(NA,-3L), class = "data.frame") 

나는 작동하는 것 두 가지 방법이 있지만 그들은 실제 데이터 집합 (수천 행, ID 수백, 여러 $Start과 같은 ID에 대한 $End 기간) 복잡하고, 그것을 ' 그들이 일하는 것을 "신뢰"하기가 어렵습니다.

###### Method 1 ###### 
df1<-df 
df1<-left_join(df1, limits, by="ID") 

df1$Pop<-ifelse(df1$Timestamp>as.POSIXct(df1$Start_1) & 
       df1$Timestamp<as.POSIXct(df1$End_1), "Yes", "No") 
df1$Pop<-ifelse(df1$Timestamp>as.POSIXct(df1$Start_2) & 
         df1$Timestamp<as.POSIXct(df1$End_2), "Maybe", df1$Pop) 
df1$Pop<-as.factor(df1$Pop) 
df1<-df1[,-c(3,6)] 

###### Method 2 ###### 
df2<-df 
df2<-df2[with(df2, order(ID, Timestamp)), ] 
ids<-as.factor(levels(droplevels(df2$ID))) 
tmp<-NULL 
for(i in 1:length(ids)) { 
    tmp[[i]]<-ifelse(df2$Timestamp[which(df2$ID==ids[i])]> as.POSIXct(limits$Start_1[i]) & 
        df2$Timestamp[which(df2$ID==ids[i])]< as.POSIXct(limits$End_1[i]), "Yes", "No") } 
tmp<-data.frame(Pop = unlist(tmp)) # tmp is a list - this turns it into a data-frame 
df2<-cbind(df2,tmp) 

# add 'Maybe' 
tmp2<-NULL 
for(i in 1:length(ids)) { 
    tmp2[[i]]<-df2$Timestamp[which(df2$ID==ids[i])]> as.POSIXct(limits$Start_2[i]) & 
    df2$Timestamp[which(df2$ID==ids[i])]< as.POSIXct(limits$End_2[i]) } 
tmp2<-data.frame(Pop = unlist(tmp2)) 
df2$Pop<-as.character(df2$Pop) 
df2$Pop[which(tmp2$Pop==TRUE)]<-'Maybe' 
df2$Pop<-as.factor(df2$Pop) 
df2<-df2[with(df2, order(Timestamp)), ] 

이런 종류의 결합을 수행하는보다 우아한 방법 (함수, 패키지 사용)이 있습니까?

편집 : 방법에
1의 ifelse(), 내가 limits$Start_1, limits$End_1을 사용했다 등 대신 df1$Start1, df1$End_1의 등

+0

[관련 질문 (http://stackoverflow.com/questions/37289405/dplyr-left-join-by-less-than-greater -than-condition) – Jean

+0

고마워요. 'limits $ Start_1' 등을 기본으로하는'left_join'을 사용하여'df'에 임시 열을 생성 한 다음 사용 후 삭제하는 것이 일반적인 방법입니다. – YGS

답변

0

YGS, 여기에 위의 셋업 코드를 사용하여 data.table 솔루션 (이다 data.frames 주변에는 "as.data.table()"이 붙어 있습니다. 또한 솔루션에서 "예"를 원한다고 예/아니오 답변을 덮어 쓴 것으로 가정합니다.

library(data.table) 

#Set keys on ID's for join 
setkey(df, ID) 
setkey(limits, ID) 

#Join the data.tables on ID 
DT <- df[limits] 

#Create "pop" column and chain to desired columns from user output 
DT <- DT[, ':=' (Pop = ifelse(Timestamp > Start_2 & Timestamp < End_2, "Maybe", 
         ifelse(Timestamp > Start_1 & Timestamp < End_1, "Yes","No")))][, c(1,2,5,6,7)] 

UPDATE : 좀 더 우아한 :

#Create "pop" column 

DT <- df[limits, ':=' (Pop = ifelse(Timestamp > Start_2 & Timestamp < End_2, "Maybe", 
           ifelse(Timestamp > Start_1 & Timestamp < End_1, "Yes","No"))), by = .EACHI, on = "ID"] 
+0

Andrew에게 감사드립니다. 귀하의 솔루션은'dplyr'을 사용하여 제 방법 1의'data.table' 버전 (보다 간결한 조건문 포함)임을 이해합니다. – YGS