2016-09-04 6 views
10

idの範囲内で、少なくとも91日離れている行を保持したいと思います。私のデータフレームdfでは、id=1は5行、id=2は1行です。Rの行間の日付の違いに基づいて行をフィルタリングする方法はありますか?

id=1については、1行目、3行目、5行目のみを保存したいと考えています。

これは、第1の日付と第2の日付を比較すると、32日ごとに異なるためです。したがって、2番目の日付を削除してください。 1日目と3日目の比較を行い、152日の違いがあります。だから、私たちは3日目を維持する。

ここで、最初の日付を参照として使用する代わりに、3番目の日付を使用します。 3日目と4日目は61日ごとに異なります。したがって、4番目の日付を削除してください。 3日目と5日目の比較を行い、121日間が異なります。だから、我々は5日目を維持する。

最終的に、私たちが保持する日付は1日目、3日目および5日目です。 id=2については、1つの行しかないので、私たちはそれを保ちます。希望の結果は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) 

私は次のようにiddfをグループ化から始まると考えることができます:

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

はしかし、私はここから継続する方法を確認していません。 filter機能またはsliceを続行する必要がありますか?もしそうなら、どうですか?

答えて

3

代替的には、次の再帰関数を定義することです。次にind.nextfirstインデックスで、インデックス番号indから90日以上(少なくとも91日間)のインデックスが検索されます。そのような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 

これは、次の2つの追加の列を与える効率的である必要があり、私は信じてい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カラム上で動作:dplyrからsliceを使用

関連する問題