2016-09-04 17 views
10

Her bir id içinde, en az 91 gün arayla satırları tutmak istiyorum. Veritabanım df'un altında, id=1, 5 satıra sahiptir ve id=2, 1 satıra sahiptir.Satırlar, R satırındaki tarihler arasındaki farklara göre nasıl filtrelenir?

id=1 için yalnızca 1., 3. ve 5. satırları tutmak istiyorum.

Bunun nedeni, 1. tarihi ve 2. tarihi karşılaştırırsak, 32 güne kadar farklılık gösterir. Yani, 2 tarihi kaldır. 1. ve 3. tarihleri ​​karşılaştırmaya devam ediyoruz ve 152 güne göre farklılık gösteriyor. Yani, 3. tarihi tutuyoruz.

Şimdi, 1. tarihi referans olarak kullanmak yerine 3. tarihi kullanıyoruz. 3. gün ve 4. tarihler 61 güne göre farklılık gösterir. Yani, 4. tarihi kaldırın. Üçüncü tarihi ve 5. tarihi karşılaştırmaya devam ediyoruz ve 121 güne kadar farklılık gösteriyor. Yani, 5. tarihi tutuyoruz.

Sonunda, tuttuğumuz tarihler 1., 3. ve 5. tarihler. id=2'a gelince, sadece bir satır var, o yüzden bunu koruyoruz. İstenen sonuç dfnew'da gösterilmektedir.

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) 

Ben sadece aşağıdaki gibi id tarafından df gruplama ile başlayan düşünebilirsiniz:

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

Ancak, ben buradan devam etmek için nasıl emin değilim. filter işlevi veya slice ile devam etmeli miyim? Öyleyse nasıl?

cevap

3

bir alternatif, aşağıdaki özyinelemeli işlevi tanımlamaktır. Daha sonra,tarafından dizine eklenen tarihten sonraki 90 gün (91 gün) daha büyük olan first dizinindeki bir sonraki dizin ind.next dizinini bulur. Böyle bir ind.next, ind.next==NA varsa ve ind'u döndürdük. Aksi takdirde, f'u tekrar tekrar ind.next'dan başlayarak ind ile bitiştirilmiş sonucunu döndürürüz. Bu işlev çağrısının sonucu, en az 91 gün ayrılmış satır dizinleridir.

Bu fonksiyonla

, yapabileceğimiz:

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 

Bu fonksiyonun kullanılması date sütun her id grup tarafından artan düzende sıralanır varsayar. Değilse, tarihleri ​​dilimlemeden önce sıralayabiliriz. Bunun verimliliğinden veya R'de yapılan özyinelemenin tehlikelerinden emin değiliz. Umarız, David Arenburg veya başkaları bunun hakkında yorum yapabilir.grup tarafından bunu yapmanın ilk yerine

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

Belki 'Date' sınıfa dönüştürmek:


David Arenburg önerdiği gibi, grup tarafından ilk yerine tarihi sınıfına date dönüştürmek için iyidir –

+0

@DavidArenburg: Teşekkürler, yorumlarınız her zaman çok takdir edilmektedir. Düzenlemeyi yaptım. – aichao

13

Burada hadde sırasında bir girişim

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 

Bu, iki ek sütunlar verecektir verimli olmalıdır inanıyorum data.table katılır ancak IMO bir anlaşma büyük değil bu. Mantıken bu mantıklı ve farklı senaryolarda başarılı bir şekilde test ettim, ancak bazı ek ispat testlerine ihtiyaç duyabilirim.

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))) 
} 

Bu fonksiyon ind = 1 başlayarak date kolonu üzerinde çalışır: dplyr den slice kullanan

İlgili konular