Измерение объема времени со временем в нескольких столбцах - PullRequest
0 голосов
/ 22 января 2019

Я работаю с данными, которые записывают время начала и время окончания взаимодействия.Моя цель - измерить громкость через определенные промежутки времени (например, 12:00, 12:30, 13:00).По сути, моя цель - сделать логическую проверку, чтобы увидеть, соответствует ли временной диапазон, в данном случае часовой блок, временному диапазону, представленному двумя столбцами.Данные выглядят так:


client       start_time     end_time
smith          08:00          10:15
coven          09:30          10:25
peter          07:35          11:30


The result I would like would look like this

time         count
07:00          0
07:30          1
08:00          2
08:30          2
09:00          2
09:30          3
10:00          3
10:30          1
11:00          1
11:30          1

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

Моей первой мыслью было построить действительно широкие столбцы, используя mutate.Я преобразовал времена в целые числа, чтобы мне было легче с ними работать.Это будет работать, но очень медленно, и в конце мне все равно нужно будет найти способ заполнить пропущенные времена в середине.

Я думал об использовании внутри, но я не вижуесли я смогу применить его здесь.

Вот код в том виде, в каком он есть.


library(tidyverse)

df1 <- df1 %>%
  mutate(eight_ = ifelse(start_num >= 480 & start_num <= 539 | end_num >= 480 & end_num <= 539 , 1, 0))

Код работает, как и ожидалось, он помещает 1 в правильный столбец для запуска и остановки.Проблема в том, что я не знаю, как заполнить средние столбцы, которые в настоящее время получают нули.

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Вот решение, которое расширяет интервалы start_time и end_time на 30 minute и подсчитывает результат.

library(tidyverse)
library(lubridate)

df <- tibble(
  client = c("smith", "coven", "peter"),
  start_time = c("08:00", "09:30", "07:35"),
  end_time = c("10:15", "10:25", "11:30")
)

df %>% 
  mutate(
    start_time = floor_date(as.POSIXct(start_time, format = '%H:%M', tz = 'UTC'), unit = '10 minutes'),
    end_time = floor_date(as.POSIXct(end_time, format = '%H:%M', tz = 'UTC'), unit = '10 minutes'),
  ) %>%
  nest(start_time, end_time) %>%
  mutate(time = map(data, ~seq(unique(.x$start_time), unique(.x$end_time), unit = 'min', by = '30 min'))) %>%
  unnest(time) %>% 
  mutate(time = format(time, '%H:%M')) %>% 
  group_by(time) %>% 
  tally()

# A tibble: 9 x 2
  time      n
  <chr> <int>
1 07:30     1
2 08:00     2
3 08:30     2
4 09:00     2
5 09:30     3
6 10:00     3
7 10:30     1
8 11:00     1
9 11:30     1

Если вам нужен полный интервал времени от 07:00 to 11:30, вы можете сделать следующее:

df %>%
  mutate(
    start_time = floor_date(as.POSIXct(start_time, format = "%H:%M", tz = "UTC"), unit = "10 minutes"),
    end_time = floor_date(as.POSIXct(end_time, format = "%H:%M", tz = "UTC"), unit = "10 minutes"),
  ) %>%
  nest(start_time, end_time) %>%
  mutate(time = map(data, ~ seq(unique(.x$start_time), unique(.x$end_time), unit = 'min', by = '30 min'))) %>%
  unnest(time) %>%
  mutate(time = format(time, "%H:%M")) %>%
  group_by(time) %>%
  tally() %>% 
  right_join( # add full sequence of time intervals
    tibble(time = seq(
      as.POSIXct("07:00", format = "%H:%M", tz = "UTC"),
      as.POSIXct("11:30", format = "%H:%M", tz = "UTC"), 
      unit = 'min', by = '30 min'
    )) %>%
      mutate(time = format(time, "%H:%M")),
    by = 'time'
  )

# A tibble: 10 x 2
   time      n
   <chr> <int>
 1 07:00    NA
 2 07:30     1
 3 08:00     2
 4 08:30     2
 5 09:00     2
 6 09:30     3
 7 10:00     3
 8 10:30     1
 9 11:00     1
10 11:30     1
0 голосов
/ 23 января 2019

Я уверен, что должен быть гораздо более простой способ добиться этого, но вот мое решение, использующее tidyverse:

df %>%
 group_by(client) %>%
 do(data.frame(time = seq(as.POSIXct(.$start_time, format = "%H:%M"),
               as.POSIXct(.$end_time, format = "%H:%M"), by = "min"),
               temp = 0)) %>%
 complete(time = seq(as.POSIXct("07:00:00", format = "%H:%M:%S"),
                     as.POSIXct("11:30:00", format = "%H:%M:%S"), by = "min")) %>%
 mutate(time = round_date(time, unit = "30minutes")) %>%
 group_by(client, time) %>%
 summarise(temp = ifelse(any(temp == 0), 1, 0)) %>%
 group_by(time) %>%
 summarise(count = sum(temp, na.rm = TRUE))

   time                count
   <dttm>              <dbl>
 1 2019-01-22 07:00:00    0.
 2 2019-01-22 07:30:00    1.
 3 2019-01-22 08:00:00    2.
 4 2019-01-22 08:30:00    2.
 5 2019-01-22 09:00:00    2.
 6 2019-01-22 09:30:00    3.
 7 2019-01-22 10:00:00    3.
 8 2019-01-22 10:30:00    3.
 9 2019-01-22 11:00:00    1.
10 2019-01-22 11:30:00    1.

Во-первых, он расширяет исходный df для каждого клиента с помощью мелкой последовательности от «start_time» до «end_time». На все минуты назначается ноль в переменной «temp». Во-вторых, используя complete(), он создает мелкую последовательность, которая имеет заданную начальную и конечную точку. Поэтому клиенты, у которых нет данных в некоторых частях данной временной последовательности, будут иметь NA для переменной «temp», иначе 0. В-третьих, используя round_date(), она округляет время в переменной «time» до 30 минут. В-четвертых, он группирует по «client» и «time» и оценивает, есть ли 0 в «temp». Если это так, он присваивает 1, в противном случае - 0. Наконец, он группирует по «времени» и возвращает сумму единиц, указывая на возникновение в данном заданном интервале времени.

Пример данных:

df <- read.table(text = "client       start_time     end_time
smith          08:00          10:15
coven          09:30          10:25
peter          07:35          11:30", header = TRUE, stringsAsFactors = FALSE)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...