2017-01-11 7 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

две вещи. 1) Старайтесь не называть объекты после функций (образец также является функцией). 2) Непонятно, что вы спрашиваете: – Sotos

+0

вам нужно сегодня + 14 наблюдений (строк) или сегодня + 14 дней? последнее намного сложнее. –

+0

Ваш выход правильный? bcoz 'x_plus14 [1]' должно быть '2' –

ответ

5

Добавление другого подхода, основанного на findInterval:

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

спасибо, @alexis_laz за ваш ответ и помощь (снова)! Мне очень нравится, насколько он прост и элегантен, и он основан на базе 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

получил эту проблему !! Я включил настоящую дату. Просто введите 'date + 1' вместо' date' в 'between()' –

+0

@ KasiaKulma нужно уточнить, включать ли текущую дату или нет, хотя она упомянула в вопросе.Потому что число не совпало для первой строки –

+0

спасибо за это; и да, теперь я отредактировал сообщение, чтобы он пояснил, что текущее вхождение, если оно «x == 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 помощь. Я получил несколько разные счета из-за <= и >= в вспомогательной функции x_next(), если вы их правильно настроите, я думаю, вы сможете получить то, что хотите. НТН.

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

эй @ Аксан, не понимаю, почему downvote ... я беру то, что вы сказали, - 'sum (x)' будет, очевидно, суммироваться по всем «x = 1». использование 'map_dbl' - это выбор _a_, но в этом случае не ошибочный ... – davidski

+0

Простите, я пропустил' sum (x) '. Но вы все еще получаете слишком высокие счета? – Axeman

2

Сжатое dplyr и purrr решение:

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' и дает' x_plus30 == 1' в строке 6, так как оттуда до конца месяца есть 2 'x == 1 'вхождения (исключая текущий). Еще более удивительно, что все остальные экземпляры были рассчитаны правильно! –

+0

Это из-за повторяющихся дат в строках 6 и 7. Вы можете использовать 'между (sample $ date,.,. + 14)', но тогда сами даты также будут включены, и мы закончим с 3. – Axeman

+0

, это прекрасно , Я всегда могу извлечь из него 1. Если вы отредактируете свой ответ таким образом, я с радостью приму его. –

 Смежные вопросы

  • Нет связанных вопросов^_^