2016-12-05 2 views
2

У меня есть dataframe следующим образом:Запись последовательных дней по группе в R

DATE <- as.Date(c('2016-12-01', '2016-12-02', '2016-12-03', '2016-12-04', '2016-12-01', '2016-12-03', '2016-12-04', '2016-12-04')) 
Parent <- c('A','A','A','A','A','A','A','B') 
Child <- c('ab', 'ab', 'ab', 'ab', 'ac','ac', 'ac','bd') 
salary <- c(1000, 100, 4000, 2000,1000,3455,1234,600) 
avg_child_salary <- c(500, 500, 500, 500, 300, 300, 300, 9000) 
Callout <- c('HIGH', 'LOW', 'HIGH', 'HIGH', 'HIGH', 'HIGH', 'HIGH', 'LOW') 
employ.data <- data.frame(DATE, Parent, Child, avg_child_salary, salary, Callout) 

employ.data 

     DATE Parent Child avg_child_salary salary Callout 
1 2016-12-01  A ab    500 1000 HIGH 
2 2016-12-02  A ab    500 100  LOW 
3 2016-12-03  A ab    500 4000 HIGH 
4 2016-12-04  A ab    500 2000 HIGH 
5 2016-12-01  A ac    300 1000 HIGH 
6 2016-12-03  A ac    300 3455 HIGH 
7 2016-12-04  A ac    300 1234 HIGH 
8 2016-12-04  B bd    9000 600  LOW 

Я отфильтрованы только вчерашние данные, являющиеся 2016-12-04 следующим образом:

yesterday <- as.Date(Sys.Date()-1) 
df2<-filter(employ.data, DATE == yesterday) 
df2 

      DATE Parent Child avg_child_salary salary Callout 
    4 2016-12-04  A ab    500 2000 HIGH 
    7 2016-12-04  A ac    300 1234 HIGH 
    8 2016-12-04  B bd    9000 600  LOW 

Моя цель состоит в том, чтобы включить столбец рядом с Callout с указанием количества последовательных дней от 2016-12-04 выносом было HIGH или LOW по Child на основе employ.data данных. Это то, что мне нужно в качестве конечного результата:

  DATE Parent Child avg_child_salary salary Callout Consec. Days with Callout 
    4 2016-12-04  A ab    500 2000 HIGH       2 
    7 2016-12-04  A ac    300 1234 HIGH       2 
    8 2016-12-04  B bd    9000 600  LOW       1 

Спасибо!

ответ

1

Вот другой подход, который довольно грязный, но я думаю, что делает то, что вы хотите:

library(dplyr) 
yesterday <- as.Date(Sys.Date()-1) 
df2 <- employ.data %>% group_by(Child) %>% 
    mutate(`Consec. Days with Callout`=cumsum(rev(cumprod(rev((yesterday-DATE)==(which(DATE == yesterday)-row_number()) & Callout==Callout[DATE == yesterday]))))) %>% 
    filter(DATE == yesterday) 
##Source: local data frame [3 x 7] 
##Groups: Child [3] 
## 
##  DATE Parent Child avg_child_salary salary Callout Consec. Days with Callout 
##  <date> <fctr> <fctr>   <dbl> <dbl> <fctr>      <dbl> 
##1 2016-12-04  A  ab    500 2000 HIGH       2 
##2 2016-12-04  A  ac    300 1234 HIGH       2 
##3 2016-12-04  B  bd    9000 600  LOW       1 

Примечания:

  1. (yesterday-DATE)==(which(DATE == yesterday)-row_number()) & Callout==Callout[DATE == yesterday] вычисляет условие, которое будет TRUE для строки, если Callout является t он тот же, что и Callout для yesterday, и если расстояние в строках от строки yesterday совпадает с расстоянием в днях для даты. Это дает Cond колонку, как показано ниже:

    Source: local data frame [8 x 7] 
    Groups: Child [3] 
    
         DATE Parent Child avg_child_salary salary Callout Cond 
         <date> <fctr> <fctr>   <dbl> <dbl> <fctr> <lgl> 
    1 2016-12-01  A  ab    500 1000 HIGH TRUE 
    2 2016-12-02  A  ab    500 100  LOW FALSE 
    3 2016-12-03  A  ab    500 4000 HIGH TRUE 
    4 2016-12-04  A  ab    500 2000 HIGH TRUE 
    5 2016-12-01  A  ac    300 1000 HIGH FALSE 
    6 2016-12-03  A  ac    300 3455 HIGH TRUE 
    7 2016-12-04  A  ac    300 1234 HIGH TRUE 
    8 2016-12-04  B  bd    9000 600  LOW TRUE 
    
  2. Учитывая это, мы хотим, чтобы считать в обратном порядке ряд последовательных TRUE из ряда, который yesterday (сгруппированные по Child). Чтобы сделать это, мы можем полностью изменить вектор с помощью rev, сделать cumprod, который будет переходить от 1 к 0 как только он встречает FALSE, обратный вектор обратно с помощью rev, и, наконец, сделать cumsum аккумулировать дней подряд. Делать это дает следующее где Consec. Days with Callout столбец интерпретируется как количество предыдущих дней подряд с тем же Callout, как yesterday:

    Source: local data frame [8 x 7] 
    Groups: Child [3] 
    
         DATE Parent Child avg_child_salary salary Callout Consec. Days with Callout 
         <date> <fctr> <fctr>   <dbl> <dbl> <fctr>      <dbl> 
    1 2016-12-01  A  ab    500 1000 HIGH       0 
    2 2016-12-02  A  ab    500 100  LOW       0 
    3 2016-12-03  A  ab    500 4000 HIGH       1 
    4 2016-12-04  A  ab    500 2000 HIGH       2 
    5 2016-12-01  A  ac    300 1000 HIGH       0 
    6 2016-12-03  A  ac    300 3455 HIGH       1 
    7 2016-12-04  A  ac    300 1234 HIGH       2 
    8 2016-12-04  B  bd    9000 600  LOW       1 
    
  3. Наконец, сделайте filter как вы сделали, чтобы сформировать окончательный результат.

+0

У вас возникли проблемы с этим ответом? Если да, просьба оставить комментарий здесь. В противном случае я не получу их напрямую. – aichao

+0

Я считаю, что вы получаете эту ошибку, потому что у вас есть группа, для которой нет даты, которая соответствует «вчера». Это правда? – aichao

2

попробовать это мой человек

library(lubridate) 

df3 <- df2 %>% 
     group_by(child, callout) %>%       
     mutate(DATE = ymd(DATE), 
       consecutive_day_flag = if_else(DATE == (lag(DATE) + days(1)), 1, 0), 
       how_many = sum(consecutive_day_flag)) 
+0

это действительно хорошо спасибо. Единственное, что Consec. Дни с выноском не соответствуют номерам, которые у меня есть сверху. Я предполагаю, что это связано с тем, что не включая 2016-12-04 уже 1 день. Он должен ссылаться на data.data dataframe. Дайте мне знать, если это имеет смысл и спасибо за вашу помощь! –

+0

Прошу прощения за то, что вы не прояснили вопрос, просто пересмотрели вопрос. @Noobie –

+0

последовательным вы имеете в виду только дни, когда следующий день является предыдущим + одним? скажем, суббота после пятницы или понедельника следует за пятницей? Или, может быть, вас волнует только количество уникальных дней? –

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