r добавление группы с помощью функции накопления dplyr

Для тестового набора данных, который выглядит следующим образом,

testdf1 <- structure(list(ShinyUsrId = c(16338, 16338, 16338, 16338, 16338), 
               ButtonId = c(11, 12, 11, 11, 14), V3 = c(1519971165, 
               1520741372, 1520741372, 1521094311, 1513576204), 
              timediff = c(0, 770207, 0, 0, 0)), .Names = c("ShinyUsrId", 
              "ButtonId", "V3", "timediff"), row.names = c(NA, -5L), class = 
              "data.frame")


            ShinyUsrId   ButtonId  Button_PressDate       time_diff     
            16338           11     2018-03-02 06:12:45    0
            16338           12     2018-03-11 04:09:32    770207
            16338           11     2018-03-11 04:09:32    0
            16338           11     2018-03-15 06:11:51    0
            16338           14     2017-12-18 05:50:04    0

Этот код ниже сворачивает последовательные строки, где разница во времени (timediff) составляет менее 60 секунд.

    g <- 0
    Collpase_testdf1 <- mutate(testdf1, date_groups =
                          accumulate(testdf1$timediff, function(x, y)
                            if (y - x < 60)
                              g
                            else {
                              g <<- g + 1
                            })) %>%
     group_by(date_groups) %>%
     summarise(
     ButtonId             = paste(ButtonId  , collapse = ", "),
     ShinyUsrId                = paste(ShinyUsrId, collapse = ", "),         
     time_diff           = paste(timediff, collapse = ", ")
  )

Таким образом, результат выглядит так, как и ожидалось.

     date_groups ButtonId        ShinyUsrId                  time_diff                   
       0         11              16338                        0              
       1         12, 11, 11, 14  16338, 16338, 16338, 16338   770207, 0, 0, 0

Теперь, если мой набор данных содержит разные идентификаторы пользователей, как показано ниже

       testdf1 <- structure(list(ShinyUsrId = c(16338, 16338, 15148, 84756, 
                84756), 
               ButtonId = c(11, 12, 11, 11, 14), V3 = c(1519971165, 
               1520741372, 1520741372, 1521094311, 1513576204), 
              timediff = c(0, 770207, 0, 0, 0)), .Names = c("ShinyUsrId", 
              "ButtonId", "V3", "timediff"), row.names = c(NA, -5L), class = 
              "data.frame")


            ShinyUsrId   ButtonId  Button_PressDate       time_diff     
            16338           11     2018-03-02 06:12:45    0
            16338           11     2018-03-11 04:09:32    770207
            15148           11     2018-03-11 04:09:32    0
            84756           11     2018-03-15 06:11:51    0
            84756           11     2017-12-18 05:50:04    0

Как мне включить параметр group_by, чтобы мой вывод выглядел так, как показано ниже

      date_groups ButtonId        ShinyUsrId                  time_diff                   
       0         11              16338                        0              
       1         12,             16338                        770207
       2         11              15148                        0
       3         11,14           84756                        0,0

Я знаю, что могу сделать это с помощью цикла for, но мне любопытно, как это сделать с помощью параметра group_by?


Тестовый набор данных 2

testdf1 <- structure(list(ShinyUsrId = c(1765, 1765, 1765, 1765, 
                    1765), 
                   ButtonId = c(18, 18, 17, 17, 121), V3 = c(1519971165, 
                   1520741372, 1520741372, 1521094311, 1513576204), 
                  timediff = c(0, 880, 3502, 13148814, 1210)), .Names = c("ShinyUsrId", 
                  "ButtonId", "V3", "timediff"), row.names = c(NA, -5L), class = 
                  "data.frame")

            ShinyUsrId   ButtonId  Button_PressDate       time_diff     
            1765            18     2018-03-02 06:12:45    0
            1765            18     2018-03-11 04:09:32    880
            1765            17     2018-03-11 04:09:32    3502
            1765            17     2018-03-15 06:11:51    13148814
            1765            121    2017-12-18 05:50:04    1210

Ожидаемый результат

       date_groups ButtonId        ShinyUsrId                  time_diff                   
       0            18              1765                        0              
       1            18              1765                        880
       2            17              1765                        3502
       3            17              1765                        13148814                         
       4            121             1765                        1210

Сценарий тестового набора данных 3

testdf1 <- structure(list(ShinyUsrId = c(13679, 13679, 13679, 13679,13679,13679, 13679, 13679, 13679,13679, 13679,13679), 
                          ButtonId = c(23, 184, 184, 23, 184,184,23,23,184,184,184,23), 
               ButtonPressDate <- lubridate::ymd_hms(c('2017-11-05 06:34:59', '2017-11-05 06:34:59', '2017-12-07 00:27:53', '2017-12-07 00:53:47', '2017-12-07 01:03:05','2018-03-08 00:28:09', '2018-03-08 00:28:09', '2018-03-08 00:45:02', '2018-03-08 00:45:02', '2018-03-24 13:13:15','2018-05-05 06:22:57', '2018-05-05 06:22:57')), 
                          timediff = c(0, 0, 2742774, 1554, 558, 7860304, 0, 1013, 0, 1427293, 3604182, 0)), 
                     .Names = c("ShinyUsrId","ButtonId", "V3", "timediff"), row.names = c(NA, -12L), class = "data.frame")




  ShinyUsrId ButtonId     ButtonPressDate timediff
       13679       23 2017-11-05 06:34:59        0
       13679      184 2017-11-05 06:34:59        0
       13679      184 2017-12-07 00:27:53  2742774
       13679       23 2017-12-07 00:53:47     1554
       13679      184 2017-12-07 01:03:05      558
       13679      184 2018-03-08 00:28:09  7860304
       13679       23 2018-03-08 00:28:09        0
       13679       23 2018-03-08 00:45:02     1013
       13679      184 2018-03-08 00:45:02        0
       13679      184 2018-03-24 13:13:15  1427293
       13679      184 2018-05-05 06:22:57  3604182
       13679       23 2018-05-05 06:22:57        0

Ожидаемый результат

       date_groups ButtonId        ShinyUsrId     timediff
       0           23, 184         13679,13679     0,0         
       1           184             13679           2742774   
       2           23              13679           1554      
       3           184             13679           558       
       4           184, 23         13679, 13679    7860304, 0
       5           23, 184         13679, 13679    1013, 0   
       6           184             13679           1427293   
       7           184, 23         13679, 13679    3604182, 0

person Sundown Brownbear    schedule 12.03.2019    source источник


Ответы (1)


Поскольку ваша функция использует оператор <<-, я не уверен, что вы можете сделать это напрямую. Один из способов — разделить data.frame на list из data.frames с помощью ShinyUsrId, а затем использовать map_dfr(), но как насчет того, чтобы избавиться от <<- и accumulate(), используя lag()?

Collpase_testdf1 <- testdf1 %>%
  group_by(ShinyUsrId) %>%
  mutate(date_groups = cumsum(time_diff - lag(time_diff, default = 0) > 60)) %>%
  group_by(ShinyUsrId, date_groups) %>%
  summarise(
     ButtonId             = paste(ButtonId  , collapse = ", "),
     time_diff            = paste(timediff, collapse = ", ")
  )
person kwiscion    schedule 12.03.2019
comment
это хорошая идея, но есть что-то в использовании функции задержки, и результат не такой, как ожидалось. Он не должен сворачивать первые две строки вместе, потому что timediff равен 0 и 770207 секунд, что больше 60 секунд, поэтому они должны оставаться отдельными. - person Sundown Brownbear; 12.03.2019
comment
Извините, должно быть > вместо < в cumsum(). Починил это. - person kwiscion; 12.03.2019
comment
Никаких проблем. Похоже, в этой логике все еще есть дыры. Например, я обновил свой вопрос новым набором тестовых данных в самом низу моего вопроса, и текущее решение объединяет последние две строки, timediff 13148814, 1210 вместе. Эти два должны быть отдельными. Любая идея, почему? - person Sundown Brownbear; 12.03.2019
comment
Код добавляет 1 к date_groups каждый раз, когда разница между timediff в текущей строке и в предыдущей больше 60. В приведенном вами примере есть 1210 - 13148814 = -13147604, поэтому меньше 60. Возможно, вы ожидаете, что вместо этого будет проверено абсолютное значение разницы? - person kwiscion; 12.03.2019
comment
это моя ошибка, прошу прощения, надеюсь, модератор не посадит меня на подгузник. Обещаю, это будет мой последний запрос на изменение. Я загрузил последний сценарий (тестовый набор данных 3) в вопросе выше, где cumsum( abs(time_diff - lag(time_diff, default = 0)) > 60)) не работает. Он не объединяет строки с timediff 7860304, 0 и 1013,0 и 3604182,0. Какие изменения я должен внести в функцию cumsum, чтобы приспособиться к этому сценарию. Это моя последняя смена. После этого больше нет. - person Sundown Brownbear; 13.03.2019
comment
Не волнуйтесь, мы здесь, чтобы найти хорошее решение. Я начинаю блуждать, если разница time_diff между строками действительно то, что вам нужно. Разве сам nt it the time_diff`а должен быть меньше 60? - person kwiscion; 13.03.2019
comment
спасибо kwiscion хороший вопрос 1) time_diff - это разница во времени между двумя последовательными строками, это правильно. 2) Любая последовательная строка time_diff, длина которой меньше 60 секунд, считается частью одного и того же экземпляра времени и, следовательно, сворачивает их. Например, timediff 7860304, 0 эти две строки указывают, что щелчок пользователя происходит в одно и то же время, поэтому они сворачиваются. Однако 7860304-0 не меньше 60, но они встречаются в одно и то же время, поэтому их необходимо свернуть. Аналогично 1013,0 и 3604182,0. - person Sundown Brownbear; 13.03.2019
comment
В таком случае я думаю, что cumsum(time_diff > 60) достаточно. Пожалуйста, отредактируйте свой вопрос, чтобы отразить это. - person kwiscion; 13.03.2019
comment
Я думаю, вы уже ответили на вопрос, когда вас спросили, действительно ли time_diff между строками мне нужно. Это заставило думать по-другому, и я использовал столбец ButtonPressDate вместо time_diff, и это сработало отлично. Еще раз спасибо и извините за кучу вопросов. - person Sundown Brownbear; 13.03.2019