В R: объединить два кадра данных на основе условия периода времени - PullRequest
0 голосов
/ 07 февраля 2020

Будучи новичком в R, я пытаюсь объединить два фрейма данных с учетом условия периода времени .

df1 <- data.frame("first_event" = c("4f7d", "a10a", "e79b"), "second_event" = c("9346","a839", "d939"), "device_serial" = c("123","123","123") , "start_timestamp" = c("2019-12-06 11:47:0", "2019-09-06 11:47:0", "2019-09-05 10:00:00"),"end_timestamp" = c("2020-01-10 12:59:38", "2019-11-22 12:06:28", "2019-11-22 12:06:28"), "exp_id" = NA)

df2 <- data.frame("device_serial" =  c("123","123") , exp_id= c("a","b") ,    start_timestamp = c("2019-12-03 07:12:20", "2019-09-04 10:00:00") ,       end_timestamp = c("2020-01-17 00:05:10", NULL)     ,    current_event_id = c("1", "2")   ,current_event_timestamp= c("2020-01-17 00:05:09", "2020-01-17 00:05:09"))

Это немного сложно объяснить, я сделаю все возможное, чтобы представить проблему.

По сути, я наблюдаю за некоторыми экспедициями (df2 ) и я хочу знать, какие события (df1) связаны с определенной экспедицией (посмотрите на exp_id в df1, я хочу заполнить этот столбец).

Обратите внимание, что каждая экспедиция создается устройством, и, очевидно, каждое событие генерируется устройством. Вы можете сказать, что это возможно, если объединить две таблицы на основе идентификатора устройства . Однако проблема в том, что каждое устройство может быть связано с несколькими экспедициями. Таким образом, цель состоит в том, чтобы увидеть в течение определенного периода времени, какое устройство было связано с какой экспедицией, чтобы мы могли сопоставить события с этой экспедицией. Если вы посмотрите на третий ряд df1, вы увидите трудности, с которыми я столкнулся при условии периода времени. Поскольку, учитывая продолжительность записи третьего ряда, мы не можем связать ее с экспедицией a.

Здесь возникает другая проблема. Иногда экспедиции не заканчиваются, поэтому мы должны учитывать отметку времени последнего увиденного события (которая является current_event_timestamp в df2).

>df1

first_event   second_event      device_serial      start_timestamp        end_timestamp           exp_id
  4f7d            9346             123           2019-12-06 11:47:0     2020-01-10 12:59:38         NA
  a10a            a839             123             2019-09-06 11:47:0    2019-11-22 12:06:28        NA
  e79b            d939             123           "2019-09-05 10:00:00"    "2019-11-22 12:06:28")    NA

>df2
device_serial   exp_id    start_timestamp        end_timestamp         current_event_id   current_event_timestamp

   123             a      2019-12-03 07:12:20    2020-01-17 00:05:10        1             2020-01-17 00:05:09

   123             b      2019-09-04 10:00:00    NULL                       2             2019-11-23 12:06:28

Результат, который я ищу for это таблица типа df3:

>df3
first_event   second_event      device_serial      start_timestamp        end_timestamp           exp_id
  4f7d            9346             123           2019-12-06 11:47:0     2020-01-10 12:59:38         a
  a10a            a839             123             2019-09-06 11:47:0    2019-11-22 12:06:28        b
 e79b            d939             123           "2019-09-05 10:00:00"    "2019-11-22 12:06:28")     b

Спасибо, что прочитали этот вопрос и помогли мне его решить.

1 Ответ

0 голосов
/ 08 февраля 2020

Вот несколько советов, если я вас правильно понял.

Во-первых, ваши данные с несколькими правками:

  1. За комментарий @ r2evans, я предполагаю, что NULL должен был быть NA_real
  2. "current_event_timestamp" из df2 в первом блоке кода не соответствует тому, что вы набрали во втором блоке; Я использовал дату и время из второго блока, так как это привело к ответу, который вы искали
df1 <- data.frame("first_event" = c("4f7d", "a10a", "e79b"), 
                  "second_event" = c("9346","a839", "d939"), 
                  "device_serial" = c("123","123","123") , 
                  "start_timestamp" = c("2019-12-06 11:47:0", "2019-09-06 11:47:0", "2019-09-05 10:00:00"),
                  "end_timestamp" = c("2020-01-10 12:59:38", "2019-11-22 12:06:28", "2019-11-22 12:06:28"), 
                  "exp_id" = NA)

df2 <- data.frame("device_serial" =  c("123","123") , 
                  exp_id= c("a","b") ,    
                  start_timestamp = c("2019-12-03 07:12:20", "2019-09-04 10:00:00") ,       
                  end_timestamp = c("2020-01-17 00:05:10", NA_real_)     ,   
                  current_event_id = c("1", "2")   ,
                  current_event_timestamp= c("2020-01-17 00:05:09", "2019-11-23 12:06:28"))

Теперь, чтобы привести данные в порядок.

Два основных момента:

  1. Кажется, что столбцы start_timestamp и end_timestamp в df1 относятся к началу и концу событий , тогда как эти одинаковые имена столбцов в df2 см. начало и конец экспедиций . В этом случае рекомендуется назначать имена этих переменных, отражающие тот факт, что содержащиеся в них данные различаются. В этом случае это различие важно при объединении двух таблиц.
  2. По крайней мере, в вашем примере df s, обратите внимание, что все столбцы изначально считывались как факторы. С переменными, как правило, гораздо проще работать, если они хранятся в виде данных, которые они представляют, и это особенно верно для данных даты и времени.
library(dplyr)
library(lubridate)
df1 <- df1 %>% 
  as_tibble(df1) %>% # convert to tibble; prints data type of each column
  select(-exp_id, evnt_start = start_timestamp, evnt_end = end_timestamp) %>% # removing exp_id (not necessary, & messes up join) & changing names of time cols.
  mutate(evnt_start = as_datetime(evnt_start), # converting time columns to datetime type
         evnt_end = as_datetime(evnt_end))
df1
# A tibble: 3 x 5
  first_event second_event device_serial evnt_start          evnt_end           
  <fct>       <fct>        <fct>         <dttm>              <dttm>             
1 4f7d        9346         123           2019-12-06 11:47:00 2020-01-10 12:59:38
2 a10a        a839         123           2019-09-06 11:47:00 2019-11-22 12:06:28
3 e79b        d939         123           2019-09-05 10:00:00 2019-11-22 12:06:28
df2 <-  df2 %>% 
  as_tibble(df2) %>% # convert to tibble
  rename(exp_start = start_timestamp, exp_end = end_timestamp) %>% # changing names of time cols
  mutate_at(.vars=c("exp_start", "exp_end", "current_event_timestamp"), ~as_datetime(.)) # converting time cols from factor into datetime type

df2
# A tibble: 2 x 6
  device_serial exp_id exp_start           exp_end             current_event_id current_event_timestamp
  <fct>         <fct>  <dttm>              <dttm>              <fct>            <dttm>                 
1 123           a      2019-12-03 07:12:20 2020-01-17 00:05:10 1                2020-01-17 00:05:09    
2 123           b      2019-09-04 10:00:00 NA                  2                2019-11-23 12:06:28    

Теперь попробуйте найти решение, используя dplyr::left_join и dplyr::filter:

df3 <- df2 %>% 
  mutate(exp_end_or_current = if_else(is.na(exp_end), current_event_timestamp, exp_end)) %>% #creating a new col with either exp_end OR, if NA, then current timestamp
  left_join(df1, ., by = ("device_serial")) %>%  #join df2 to df1 by serial #
  filter(evnt_start > exp_start & evnt_end < exp_end_or_current) %>%  #filter, keeping only records where EVENT start & end times are between expedition start & end times 
  select(-c(exp_end, current_event_id, current_event_timestamp))
df3
# A tibble: 3 x 8
  first_event second_event device_serial evnt_start          evnt_end            exp_id exp_start           exp_end_or_current 
  <fct>       <fct>        <fct>         <dttm>              <dttm>              <fct>  <dttm>              <dttm>             
1 4f7d        9346         123           2019-12-06 11:47:00 2020-01-10 12:59:38 a      2019-12-03 07:12:20 2020-01-17 00:05:10
2 a10a        a839         123           2019-09-06 11:47:00 2019-11-22 12:06:28 b      2019-09-04 10:00:00 2019-11-23 12:06:28
3 e79b        d939         123           2019-09-05 10:00:00 2019-11-22 12:06:28 b      2019-09-04 10:00:00 2019-11-23 12:06:28
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...