Объедините два набора данных на основе уникальных различных временных интервалов, а затем создайте набор данных со всеми несопоставленными значениями (в R) - PullRequest
1 голос
/ 22 февраля 2020

У меня есть два отдельных набора данных: df1 и df2. Я хотел бы создать новый набор данных, df3, который бы соответствовал столбцу конечного времени df1 с отправленным столбцом df2, если даты и время находятся в пределах 20 секунд друг от друга. Наконец, я хотел бы создать окончательный набор данных, который даст мне все значения в наборе данных df2 (отправленный / ID набор данных), которые не соответствуют df1.

 df1

 endtime                     ID

 1/7/2020  1:35:08 AM         A
 1/7/2020  1:39:00 AM         B
 1/20/2020 1:45:00 AM         C



 df2

sent                         ID

1/7/2020  1:35:20 AM          E
1/7/2020  1:42:00 AM          F
1/20/2020 1:55:00 AM          G
1/20/2020 2:00:00 AM          E

Это мой желаемый вывод для df3. Есть только одна строка, потому что есть только два значения, которые соответствуют условию нахождения в пределах 20 секунд от конечного времени и отправленных столбцов.

endtime                  sent 

1/7/2020 1:35:08 AM      1/7/2020  1:35:20 AM    

Желаемый вывод для несопоставленных значений

sent 

1/7/2020  1:42:00 AM
1/20/2020 1:55:00 AM          
1/20/2020 2:00:00 AM          

Вот dput:

df1

structure(list(endtime = structure(c(2L, 3L, 1L), .Label = c("1/10/2020 1:45:00 AM", 
"1/7/2020 1:35:08 AM", "1/7/2020 1:39:00 AM"), class = "factor"), 
ID = structure(1:3, .Label = c("A", "B", "C"), class = "factor")), class = "data.frame", row.names =   c(NA, 
 -3L))





 df2

 structure(list(sent = structure(c(3L, 4L, 1L, 2L), .Label = c("1/20/2020 1:55:00 AM", 
 "1/20/2020 2:00:00 AM", "1/7/2020 1:35:20 AM", "1/7/2020 1:42:00 AM"
 ), class = "factor"), ID = structure(c(1L, 2L, 3L, 1L), .Label = c("E", 
"F", "G"), class = "factor")), class = "data.frame", row.names = c(NA, 
-4L))

Вот что я пробовал:

Я думаю о выполнении левого соединения и сопоставлении значений, или я могу использовать merge (), но сложная часть сопоставляет значения с условным оператором. Любое предложение приветствуется.

     df3<-crossing(endtime = as.POSIXct(df1$endtime,format ="%m/%d/%Y %I:%M:%S %p" ), 
               sent = as.POSIXct(df2$sent, format = "%m/%d/%Y %I:%M:%S %p")) %>% 
     filter((endtime - seconds(20)) <= sent, 
     (endtime + seconds(20)) >= (sent)) %>%
     mutate_all(format, format = "%m/%d/%Y %I:%M:%S %p") %>%
     distinct(sent, .keep_all = TRUE)

Это хорошо работает, но я не знаю, как найти все значения в наборе данных df2, которые по сути являются "оставшимися" и не имеют соответствия. Любое предложение приветствуется.

Ответы [ 2 ]

2 голосов
/ 22 февраля 2020
library(dplyr)
library(tidyr)
library(lubridate)

df1 <- structure(list(endtime = structure(c(2L, 3L, 1L), .Label = c("1/10/2020 1:45:00 AM", "1/7/2020 1:35:08 AM", "1/7/2020 1:39:00 AM"),class = "factor"),
                      ID = structure(1:3, .Label = c("A", "B", "C"), class = "factor")),
                 class = "data.frame", row.names =   c(NA, -3L))

df2 <- structure(list(sent = structure(c(3L, 4L, 1L, 2L), .Label = c("1/20/2020 1:55:00 AM", "1/20/2020 2:00:00 AM", "1/7/2020 1:35:20 AM", "1/7/2020 1:42:00 AM"), class = "factor"),
                      ID = structure(c(1L, 2L, 3L, 1L), .Label = c("E", "F", "G"), class = "factor")),
                 class = "data.frame", row.names = c(NA, -4L))

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

Мне пришлось немного изменить повторное приведение дат, так как не показывало "AM" и "PM" часть даты и времени строка:

# A tibble: 1 x 2
  endtime                sent                  
  <chr>                  <chr>                 
1 "01/07/2020 01:35:08 " "01/07/2020 01:35:20 "

До:

mutate_all(format, format = "%m/%d/%Y %I:%M:%S %p")

После:

mutate_all(format, format = "%m/%d/%Y %H:%M:%S")

Адаптированный код для создания df3:

df3<-crossing(endtime = as.POSIXct(df1$endtime,format ="%m/%d/%Y %I:%M:%S %p" ), 
              sent = as.POSIXct(df2$sent, format = "%m/%d/%Y %I:%M:%S %p")) %>% 
  filter((endtime - seconds(20)) <= sent, 
         (endtime + seconds(20)) >= (sent)) %>%
  mutate_all(format, format = "%m/%d/%Y %H:%M:%S") %>%
  distinct(sent, .keep_all = TRUE)

df3 сейчас:

# A tibble: 1 x 2
  endtime             sent               
  <chr>               <chr>              
1 01/07/2020 01:35:08 01/07/2020 01:35:20

Комментарий: почему sent и endtime переформатируются здесь как строки? Разве вы не хотите их в качестве даты? Потому что нам нужно будет повторно привести их снова ниже.

Предлагаемое решение:

Определение несопоставленных строк:

df1_unmatched <- df1 %>% 
  mutate(endtime = as.POSIXct(endtime,format ="%m/%d/%Y %H:%M:%S" )) %>% 
  filter(!endtime %in% as.POSIXct(df3$endtime,format ="%m/%d/%Y %H:%M:%S" ))

df2_unmatched <- df2 %>% 
  mutate(sent = as.POSIXct(sent, format = "%m/%d/%Y %H:%M:%S")) %>% 
  filter(!sent %in% as.POSIXct(df3$sent,format ="%m/%d/%Y %H:%M:%S" ))


df1_unmatched

Возвращает:

              endtime ID
1 2020-01-07 01:39:00  B
2 2020-01-10 01:45:00  C

И

df2_unmatched

Возвращает:

                 sent ID
1 2020-01-07 01:42:00  F
2 2020-01-20 01:55:00  G
3 2020-01-20 02:00:00  E
1 голос
/ 23 февраля 2020

Использование неэкви в data.table:

df3 <-  df1[, c("st", "et") := .(endtime - 20L, endtime + 20L)][
    df2, on=.(st<=sent, et>=sent), nomatch=0L, .(ID1=x.ID, ID2=i.ID, endtime, sent)]

вывод:

   ID1 ID2             endtime                sent
1:   A   E 2020-01-07 01:35:08 2020-01-07 01:35:20

данные:

library(data.table)
setDT(df1)[, endtime := as.POSIXct(as.character(endtime),format ="%m/%d/%Y %I:%M:%S %p")]
setDT(df2)[, sent := as.POSIXct(as.character(sent), format = "%m/%d/%Y %I:%M:%S %p")]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...