2016-09-04 2 views
10

id 내에 적어도 91 일 간격으로 행을 보관하고 싶습니다. 내 데이터 프레임 df에는 id=1에 5 개의 행이 있고 id=2에는 1 개의 행이 있습니다.R의 행 사이의 날짜 차이를 기준으로 행을 필터링하는 방법?

id=1의 경우 1, 3 및 5 번째 행만 유지하고 싶습니다.

첫 번째 날짜와 두 번째 날짜를 비교하면 32 일 차이가 있기 때문입니다. 따라서 2 번째 날짜는 삭제하십시오. 첫 번째와 세 번째 날짜를 비교하기 위해 152 일 차이가납니다. 그래서 우리는 3 번째 데이트를 유지합니다.

이제 첫 번째 날짜를 참조로 사용하는 대신 세 번째 날짜를 사용합니다. 세 번째 날짜와 네 번째 날짜는 61 일 차이가납니다. 4 번째 날짜를 삭제하십시오. 우리는 3 번째 날짜와 5 번째 날짜를 비교하기 위해 진행하며 121 일 차이가납니다. 그래서, 우리는 5 번째 날짜를 유지합니다.

결국 우리가 유지하는 날짜는 1, 3 및 5 번째 날짜입니다. id=2의 경우 행이 하나뿐이므로 저장해 두었습니다. 원하는 결과는 dfnew에 표시됩니다.

df <- read.table(header = TRUE, text = " 
id var1 date   
1 A  2006-01-01 
1 B  2006-02-02 
1 C  2006-06-02 
1 D  2006-08-02 
1 E  2007-12-01 
2 F  2007-04-20 
",stringsAsFactors=FALSE) 

dfnew <- read.table(header = TRUE, text = " 
id var1 date   
1 A  2006-01-01 
1 C  2006-06-02 
1 E  2007-12-01 
2 F  2007-04-20 
",stringsAsFactors=FALSE) 

난 단지 다음과 같이 id하여 df를 그룹화 시작으로 생각할 수 있습니다 :

library(dplyr) 
dfnew <- df %>% group_by(id) 

는 그러나, 나는 여기에서 계속하는 방법을 모르겠습니다. filter 기능 또는 slice으로 진행해야합니까? 그렇다면 어떻게?

답변

3

대안은 다음의 재귀 함수를 정의하는 것이다. 다음 ind.next 에 의해 인덱싱 된 날짜보다 90 일 (적어도 91 일)보다 큰 first 인덱스 인 인덱스를 찾습니다. 그러한 ind.next이 없으면 ind.next==NA이며 우리는 단지 ind을 반환합니다. 그렇지 않으면 ind.next으로 시작하는 f을 반복적으로 호출하고 그 결과를 ind과 연결하여 반환합니다. 이 함수 호출의 최종 결과는 적어도 91 일만큼 떨어진 행 인덱스입니다.

이 기능을

, 우리는 할 수 있습니다

result <- df %>% group_by(id) %>% slice(f(as.Date(date, format="%Y-%m-%d"))) 
##Source: local data frame [4 x 3] 
##Groups: id [2] 
## 
##  id var1  date 
## <int> <chr>  <chr> 
##1  1  A 2006-01-01 
##2  1  C 2006-06-02 
##3  1  E 2007-12-01 
##4  2  F 2007-04-20 

이 기능의 사용은 date 열이 각 id 그룹별로 오름차순으로 정렬되어 있다고 가정합니다. 그렇지 않은 경우 슬라이싱하기 전에 날짜를 정렬 할 수 있습니다. 이것의 효율성이나 R에서 재귀 호출의 위험에 대해 확신하지 못했습니다. David Arenburg 또는 다른 사람들이 이에 대해 언급 할 수 있기를 바랍니다.그룹에 의해 그 일의 첫번째 대신

result <- df %>% mutate(date=as.Date(date, format="%Y-%m-%d")) %>% 
       group_by(id) %>% slice(f(date)) 
##Source: local data frame [4 x 3] 
##Groups: id [2] 
## 
##  id var1  date 
## <int> <chr>  <date> 
##1  1  A 2006-01-01 
##2  1  C 2006-06-02 
##3  1  E 2007-12-01 
##4  2  F 2007-04-20 
+0

은 아마'Date' 클래스로 변환 :


데이비드 Arenburg에 의해 제안, 그룹에 의해 처음으로 대신 Date 클래스에 date를 변환하는 것이 좋습니다 –

+0

@DavidArenburg : 감사합니다. 귀하의 의견은 항상 높이 평가됩니다. 나는 편집을했다. – aichao

13

여기 롤링을 사용하여 시도가

library(data.table) 
# Set minimum distance 
mindist <- 91L 
# Make sure it is a real Date 
setDT(df)[, date := as.IDate(date)] 
# Create a new column with distance + 1 to roll join too 
df[, date2 := date - (mindist + 1L)] 
# Perform a rolling join per each value in df$date2 that has atleast 91 difference from df$date 
unique(df[df, on = c(id = "id", date = "date2"), roll = -Inf], by = c("id", "var1")) 
# id var1  date  date2 i.var1  i.date 
# 1: 1 A 2005-10-01 2005-10-01  A 2006-01-01 
# 2: 1 C 2006-03-02 2006-03-02  C 2006-06-02 
# 3: 1 E 2007-08-31 2007-08-31  E 2007-12-01 
# 4: 2 F 2007-01-18 2007-01-18  F 2007-04-20 

이 당신에게 두 개의 추가 열을 줄 것이다 효율적인해야 내가 믿는 data.table에 조인하지만이 IMO 거래의 큰 아니에요입니다. 논리적으로 말이 되겠지만 여러 시나리오에서 성공적으로 테스트를 해봤지만 추가적인 증거 테스트가 필요할 수 있습니다.

library(dplyr) 
f <- function(d, ind=1) { 
    ind.next <- first(which(difftime(d,d[ind], units="days") > 90)) 
    if (is.na(ind.next)) 
    return(ind) 
    else 
    return(c(ind, f(d,ind.next))) 
} 

이 함수 ind = 1에서 시작 date 열 동작 : dplyrslice에서 사용

관련 문제