Сгруппированное время tibbletime и использование свернуть_index, получая странные результаты

У меня есть файл (примерно 9K записей), который я хочу сначала агрегировать на основе группы, а затем по датам, которые находятся в пределах семи дней друг от друга. Однако я не понимаю, почему результаты выглядят так, как они. Я понимаю, что есть и другие способы добиться тех же результатов в этом конкретном примере, но это будет намного сложнее, и есть другие причины, по которым я заинтересован в использовании tibbletime. Вот воспроизводимый пример:

library(tidyverse)
library(lubridate)  
library(tibbletime) #devtools::install_github("business-science/tibbletime")

TEST_ROLL <- as_tibble(list(
CITY_ID = c("1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "2", 
"2", "2", "2"),
CAFE_ID = c("1001", "1001", "1001", "1001", "2002", "2002", "2002", "2002", 
"3003", "3003", "3003", "3003", "4004", "4004", "4005", "4005"),
HEALTH_REPORT_ID = c("1425", "1532", "1666", "1989", "2166", "2457", "2776", 
"2999", "3409", "3497", "3595", "3786", "4105", "4511", "4567", "4580"),
REPORT_SUBMIT_DATE = ymd( c( "2013-05-26", "2013-05-27", "2013-05-31", 
"2013-05-31", "2016-05-26", "2016-05-27", "2016-05-31", "2016-05-31", "2018- 
05-26", "2018-05-27", "2018-05-31", "2018-05-31", "2017-01-01", "2017-01- 
05", "2017-02-04", "2017-02-10"))))

Что я хочу сделать, так это, начиная с первого отчета для каждого кафе, считать отчеты о состоянии здоровья, отправленные в течение семи дней друг от друга, только как один отчет, чтобы их не пересчитать.

Сначала я попытался использовать «7 дней» в качестве периода:

TEST_ROLL %>% 
  group_by(CAFE_ID) %>% 
  as_tbl_time(REPORT_SUBMIT_DATE) %>% 
  mutate(ROLL_DATE = collapse_index(REPORT_SUBMIT_DATE, "7 day"))

# A time tibble: 16 x 5
# Index:  REPORT_SUBMIT_DATE
# Groups: CAFE_ID [5]
CITY_ID CAFE_ID HEALTH_REPORT_ID REPORT_SUBMIT_DATE ROLL_DATE 
<chr>   <chr>   <chr>            <date>             <date>    
 1 1       1001    1425             2013-05-26         2013-05-27
 2 1       1001    1532             2013-05-27         2013-05-27
 3 1       1001    1666             2013-05-31         2013-05-31
 4 1       1001    1989             2013-05-31         2013-05-31
 5 1       2002    2166             2016-05-26         2016-05-27
 6 1       2002    2457             2016-05-27         2016-05-27
 7 1       2002    2776             2016-05-31         2016-05-31
 8 1       2002    2999             2016-05-31         2016-05-31
 9 1       3003    3409             2018-05-26         2018-05-27
10 1       3003    3497             2018-05-27         2018-05-27
11 1       3003    3595             2018-05-31         2018-05-31
12 1       3003    3786             2018-05-31         2018-05-31
13 2       4004    4105             2017-01-01         2017-01-05
14 2       4004    4511             2017-01-05         2017-01-05
15 2       4005    4567             2017-02-04         2017-02-04
16 2       4005    4580             2017-02-10         2017-02-10

Это не то, чего я хочу. Если бы это сработало, все четыре отчета по кафе 1001 имели бы одинаковую дату обновления, потому что все они в пределах 7 дней. Так почему же в столбце результатов разделены на две даты?

Просто поигравшись с этим, я попытался использовать «еженедельно» вместо «7 дней», а затем получил такой результат:

TEST_ROLL %>% 
  group_by(CAFE_ID) %>% 
  as_tbl_time(REPORT_SUBMIT_DATE) %>%
  mutate(ROLL_DATE = collapse_index(REPORT_SUBMIT_DATE, "weekly"))

# A time tibble: 16 x 5
# Index:  REPORT_SUBMIT_DATE
# Groups: CAFE_ID [5]
   CITY_ID CAFE_ID HEALTH_REPORT_ID REPORT_SUBMIT_DATE ROLL_DATE 
   <chr>   <chr>   <chr>            <date>             <date>    
 1 1       1001    1425             2013-05-26         2013-05-31
 2 1       1001    1532             2013-05-27         2013-05-31
 3 1       1001    1666             2013-05-31         2013-05-31
 4 1       1001    1989             2013-05-31         2013-05-31
 5 1       2002    2166             2016-05-26         2016-05-27
 6 1       2002    2457             2016-05-27         2016-05-27
 7 1       2002    2776             2016-05-31         2016-05-31
 8 1       2002    2999             2016-05-31         2016-05-31
 9 1       3003    3409             2018-05-26         2018-05-26
10 1       3003    3497             2018-05-27         2018-05-31
11 1       3003    3595             2018-05-31         2018-05-31
12 1       3003    3786             2018-05-31         2018-05-31
13 2       4004    4105             2017-01-01         2017-01-05
14 2       4004    4511             2017-01-05         2017-01-05
15 2       4005    4567             2017-02-04         2017-02-04
16 2       4005    4580             2017-02-10         2017-02-10

Кафе 1001 именно то, что я хотел, но кафе 2002 и 3003 имеют одинаковые даты (разный год), а результат разный.

И кафе 4004 комбинируется как я хочу, но для кафе 4005 всего 6 дней между ними, так что их тоже надо было комбинировать. (Я подытожу/подсчитаю их позже)

Любые идеи, почему это может происходить? Спасибо!!


person Knachman    schedule 05.04.2018    source источник
comment
collapse_index(REPORT_SUBMIT_DATE, "weekly") сворачивает даты, относящиеся к той же неделе, которая начинается в воскресенье. ИМХО, однако, будет намного проще просто принять поведение collapse_index по умолчанию, чем то, чего вы пытаетесь достичь.   -  person hpesoj626    schedule 06.04.2018
comment
Да, с тех пор я понял, почему еженедельник ведет себя таким образом, но интересно, что использование 7 дней все еще не дает желаемого результата. На самом деле я пробовал 8 дней, и, похоже, это работает с моим большим набором данных, хотя я все еще проверяю случай.   -  person Knachman    schedule 06.04.2018
comment
Посмотрите мой ответ, если это поможет, @Knachman   -  person hpesoj626    schedule 06.04.2018
comment
7-дневный период важен, меня совершенно не волнуют календарные недели. Это своего рода первый шаг в анализе, и затем мне нужно будет сгруппировать по дате и определить те отчеты, которые находятся в пределах 45 дней от даты. первая дата отчета, затем после даты отчета в качестве результатов и до даты отчета в качестве предыдущей истории.   -  person Knachman    schedule 06.04.2018
comment
Мне интересно, происходит ли это из-за того, как свернуть_index использует начальную дату, если он вычисляет каждые 7 дней на основе первой даты в индексе, что может не работать с тем, что я пытаюсь сделать.   -  person Knachman    schedule 06.04.2018


Ответы (1)


Я не знаю, является ли то, чего вы пытаетесь достичь, мудрым выбором. Я думаю, что поведение по умолчанию collapse_index(REPORT_SUBMIT_DATE, "weekly") — это разумный поступок.

Вот один из подходов, если вы все же хотите продолжать делать то, что пытаетесь сделать. Я думаю, вам нужно иметь очень хорошее представление о том, какие дни находятся в пределах 7 дней друг от друга в первую очередь.

Date <- TEST_ROLL$REPORT_SUBMIT_DATE
truth_mat <- abs(sapply(Date, 'difftime', Date, unit = 'day')) < 7
indices <- which(truth_mat, arr.ind = TRUE)
as_tibble(indices) %>% group_by(row) %>%
  summarise_at(vars(col), paste, collapse = ', ')

# # A tibble: 16 x 2
#      row col          
#    <int> <chr>        
#  1     1 1, 2, 3, 4   
#  2     2 1, 2, 3, 4   
#  3     3 1, 2, 3, 4   
#  4     4 1, 2, 3, 4   
#  5     5 5, 6, 7, 8   
#  6     6 5, 6, 7, 8   
#  7     7 5, 6, 7, 8   
#  8     8 5, 6, 7, 8   
#  9     9 9, 10, 11, 12
# 10    10 9, 10, 11, 12
# 11    11 9, 10, 11, 12
# 12    12 9, 10, 11, 12
# 13    13 13, 14       
# 14    14 13, 14       
# 15    15 15, 16       
# 16    16 15, 16 

Мы видим, что {1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14} и {15,16} формируют кластеры. Давайте, если hclust может обнаружить эти кластеры.

hc <- hclust(dist(Date))
plot(hc)

введите здесь описание изображения

Здесь мы видим, что можем разрезать дерево на пять ветвей и получить желаемую группировку. Мы видим, что дендограмма показывает то, что мы наблюдали до сих пор. Преимущество использования маршрута hclust заключается в том, что мы можем легко указать эти группы.

TEST_ROLL$Group <- cutree(hc, 5)

TEST_ROLL
# # A tibble: 16 x 5
#    CITY_ID CAFE_ID HEALTH_REPORT_ID REPORT_SUBMIT_DATE  Date
#    <chr>   <chr>   <chr>            <date>             <int>
#  1 1       1001    1425             2013-05-26             1
#  2 1       1001    1532             2013-05-27             1
#  3 1       1001    1666             2013-05-31             1
#  4 1       1001    1989             2013-05-31             1
#  5 1       2002    2166             2016-05-26             2
#  6 1       2002    2457             2016-05-27             2
#  7 1       2002    2776             2016-05-31             2
#  8 1       2002    2999             2016-05-31             2
#  9 1       3003    3409             2018-05-26             3
# 10 1       3003    3497             2018-05-27             3
# 11 1       3003    3595             2018-05-31             3
# 12 1       3003    3786             2018-05-31             3
# 13 2       4004    4105             2017-01-01             4
# 14 2       4004    4511             2017-01-05             4
# 15 2       4005    4567             2017-02-04             5
# 16 2       4005    4580             2017-02-10             5

Обратите внимание, что hclust использует method = 'complete' в качестве евклидова расстояния по умолчанию. Вы можете экспериментировать с другими методами по своему усмотрению. Подробнее см. ?hclust.

Редактировать

Я только что понял, что вы также можете напрямую использовать группы, найденные в truth_mat и indices, таким образом.

groups <- as_tibble(indices) %>% group_by(row) %>%
  summarise_at(vars(col), paste, collapse = ', ') 
TEST_ROLL$group <- groups$col

Затем вы можете group_by столбец group без необходимости hclust.

person hpesoj626    schedule 06.04.2018
comment
Да, это своего рода проблема - это небольшой пример, но мы регулярно делаем это с файлами из сотен тысяч записей, поэтому я действительно ищу простой (желательно аккуратный) способ сделать этот список дат. Я проверю использование hclust и посмотрю, смогу ли я заставить его работать. - person Knachman; 06.04.2018
comment
Я только что понял, что вы можете использовать группу, найденную с помощью truth_mat и indices выше, без использования hclust. - person hpesoj626; 07.04.2018