R:

2017-01-11 4 views
4

私の簡略化されたデータは、次のようになり、将来の指定した時間内に特定のイベントの発生回数を計算します。R:

set.seed(1453); x = sample(0:1, 10, TRUE) 
date = c('2016-01-01', '2016-01-05', '2016-01-07', '2016-01-12', '2016-01-16', '2016-01-20', 
      '2016-01-20', '2016-01-25', '2016-01-26', '2016-01-31') 


df = data.frame(x, date = as.Date(date)) 


df 
x  date 
1 2016-01-01 
0 2016-01-05 
1 2016-01-07 
0 2016-01-12 
0 2016-01-16 
1 2016-01-20 
1 2016-01-20 
0 2016-01-25 
0 2016-01-26 
1 2016-01-31 

私は指定された時間内にx == 1ために発生回数を計算したいのですが、例えば14と30現在の日付からの日数(ただし、現在のエントリを除くことがx == 1であれば、所望の出力は次のようになります。

solution 
x  date x_plus14 x_plus30 
1 2016-01-01  1  3 
0 2016-01-05  1  4 
1 2016-01-07  2  3 
0 2016-01-12  2  3 
0 2016-01-16  2  3 
1 2016-01-20  2  2 
1 2016-01-20  1  1 
0 2016-01-25  1  1 
0 2016-01-26  1  1 
1 2016-01-31  0  0 

理想的には、私はこれはdplyrになりたいが、それはあります。?多くのあなたの助けのおかげでこれを達成するためにどのように任意のアイデア!

+1

2つのこと。 1)関数の後にオブジェクトの名前を付けないでください(サンプルも関数です)。 2) – Sotos

+0

あなたが今日+ 14回の観測(行)または今日+ 14日を必要としているかどうかは不明です。後者はずっと複雑です。 –

+0

の出力が正しいですか? bcoz 'x_plus14 [1]'は '2'でなければなりません –

答えて

5

cs = cumsum(df$x) # cumulative number of occurences 
data.frame(df, 
      plus14 = cs[findInterval(df$date + 14, df$date, left.open = TRUE)] - cs, 
      plus30 = cs[findInterval(df$date + 30, df$date, left.open = TRUE)] - cs) 
# x  date plus14 plus30 
#1 1 2016-01-01  1  3 
#2 0 2016-01-05  1  4 
#3 1 2016-01-07  2  3 
#4 0 2016-01-12  2  3 
#5 0 2016-01-16  2  3 
#6 1 2016-01-20  2  2 
#7 1 2016-01-20  1  1 
#8 0 2016-01-25  1  1 
#9 0 2016-01-26  1  1 
#10 1 2016-01-31  0  0 
+0

お返事ありがとうございました。私は本当にシンプルでエレガントなのが好きで、ベースRに基づいています。 –

+0

@KasiaKulma:ようこそ。 'findInterval'は実際にこのような状況に便利です。また、すべての日付をすべての日付と比較することを避け、特定の日付からエントリ数を返します。良い一日を! –

+0

これは本当にエレガントです! –

4

は、以前の私は、現在の日付とその番号が一致しませんでした含めていませんでした。

library(data.table) 
setDT(df)[, `:=`(x14 = sum(df$x[between(df$date, date, date + 14, incbounds = FALSE)]), 
       x30 = sum(df$x[between(df$date, date, date + 30, incbounds = FALSE)])), 
       by = date] 

#  x  date x14 x30 
# 1: 1 2016-01-01 1 3 
# 2: 0 2016-01-05 1 4 
# 3: 1 2016-01-07 2 3 
# 4: 0 2016-01-12 2 3 
# 5: 0 2016-01-16 2 3 
# 6: 1 2016-01-20 1 1 
# 7: 1 2016-01-20 1 1 
# 8: 0 2016-01-25 1 1 
# 9: 0 2016-01-26 1 1 
# 10: 1 2016-01-31 0 0 

それとも一般的な解決策はいけません任意の範囲で動作する

vec <- c(14, 30) # Specify desired ranges 
setDT(df)[, paste0("x", vec) := 
      lapply(vec, function(i) sum(df$x[between(df$date, 
                date, 
                date + i, 
                incbounds = FALSE)])), 
      by = date] 
+0

問題を手に入れました!私は現在の日付を含んでいた。 'between()'の 'date'の代わりに' date + 1'をつけてください。 –

+0

@KasiaKulmaは、質問に言及していますが、現在の日付を含めるかどうかを明確にする必要があります。最初の行の番号が一致しなかったため、 –

+0

これはありがたいです。そして、はい、私は現在のオカレンスが 'x == 1 'であれば、計算に含めてはならないことを明確にするように投稿を編集しました。私は元のデータセットと同じ日付で複数の出現を見つけることができますので、解決策が現在のレコードを含む場合は常に1を抽出することができます –

1

もう1つのこととして、あなたはその日を数えないので、関数の名前(サンプル)でオブジェクトの名前を付けてはいけません。しかし、コード怒鳴るご希望の出力を再現:

set.seed(1453); 
x = sample(0:1, 10, TRUE) 
date = c('2016-01-01', '2016-01-05', '2016-01-07', '2016-01-12', '2016-01-16', '2016-01-20', 
      '2016-01-20', '2016-01-25', '2016-01-26', '2016-01-31') 


sample = data.frame(x = x, date = as.Date(sample$date)) 

getOccurences <- function(one_row, sample_data, date_range){ 
    one_date <- as.Date(one_row[2]) 
    sum(sample$x[sample_data$date > one_date & 
       sample_data$date < one_date + date_range]) 
} 

sample$x_plus14 <- apply(sample,1,getOccurences, sample, 14) 
sample$x_plus30 <- apply(sample,1,getOccurences, sample, 30) 

sample 

    x  date x_plus14 x_plus30 
1 1 2016-01-01  1  3 
2 0 2016-01-05  1  4 
3 1 2016-01-07  2  3 
4 0 2016-01-12  2  3 
5 0 2016-01-16  2  3 
6 1 2016-01-20  1  1 
7 1 2016-01-20  1  1 
8 0 2016-01-25  1  1 
9 0 2016-01-26  1  1 
10 1 2016-01-31  0  0 
2

は、ここではいくつかのdplyr + purrr助けを借りて、それで私の刺します。あなたが望むものを手に入れることができるはずだと思っていますが、助手のに<=>=という若干異なるカウントがあります。 hth。

library("tidyverse") 
library("lubridate") 
set.seed(1453) 

x = sample(0:1, 10, TRUE) 
dates = c('2016-01-01', '2016-01-05', '2016-01-07', '2016-01-12', '2016-01-16', '2016-01-20', 
     '2016-01-20', '2016-01-25', '2016-01-26', '2016-01-31') 

df = data_frame(x = x, dates = lubridate::as_date(dates)) 

# helper function to calculate the sum of xs in the next days_in_future 
x_next <- function(d, days_in_future) { 

    df %>% 
    # subset on days of interest 
    filter(dates > d & dates <= d + days(days_in_future)) %>% 
    # sum up xs 
    summarise(sum = sum(x)) %>% 
    # have to unlist them so that the (following) call to mutate works 
    unlist(use.names=F) 
    } 

# mutate your df 
df %>% 
    mutate(xplus14 = map(dates, x_next, 14), 
     xplus30 = map(dates, x_next, 30)) 
+0

私はあなたが 'x'が1であるべきであると考慮していないと思います。また、あなたは' map_dbl'を使うべきです。 – Axeman

+0

ちょっと@Axeman、なぜdownvote ...私はあなたが言ったことを取っている - 理解していない '合計(x)'は明らかにすべての 'x = 1'のみを合計します。 'map_dbl'は_a_ choiceですが、この場合は間違っていません... – davidski

+0

申し訳ありませんが、私は' sum(x) 'を見逃しました。しかし、あなたはまだ高すぎるカウントを取得していますか? – Axeman

2

簡潔dplyrpurrrソリューション:findIntervalに基づいて別のアプローチを追加

library(tidyverse) 

sample %>% 
    mutate(x_plus14 = map(date, ~sum(x == 1 & between(date, . + 1, . + 14))), 
     x_plus30 = map(date, ~sum(x == 1 & between(date, . + 1, . + 30)))) 
x  date x_plus14 x_plus30 
1 1 2016-01-01  1  4 
2 0 2016-01-05  1  4 
3 1 2016-01-07  2  3 
4 0 2016-01-12  2  3 
5 0 2016-01-16  2  3 
6 1 2016-01-20  1  1 
7 1 2016-01-20  1  1 
8 0 2016-01-25  1  1 
9 0 2016-01-26  1  1 
10 1 2016-01-31  0  0 
+0

ありがとう、@Axeman、そのために、私はあなたのソリューションの明快さとコンパクトさが本当に好きです。しかし、あなたの(そして他の)解が 'x_plus14 == 1 'を与え、行6に' x_plus30 == 1'を与える​​理由は分かりません。月末までに 'x == 1 'オカレンス(現在のものを除く)。他のすべてのインスタンスが正しく計算されていることはさらに驚きです! –

+0

これは6行目と7行目の日付が重複しているためです。「(sample $ date、。、。+ 14)」を使用できますが、日付自体も含めて3になります。 – Axeman

+0

私はいつもそれから1を抽出することができます。このように答えを編集すると、私はうれしくそれを受け入れるでしょう –