Объединить два набора данных на основе значений POSIXct - PullRequest
0 голосов
/ 13 февраля 2020

Я борюсь за объединение двух наборов данных друг с другом.

Dataset1 содержит «до времени», «после времени» и «канал».

Dataset2 также содержит только один столбец "time" и "channel".

Я хочу добавить двоичный столбец (Да / Нет) к Dataset1 с этим логом c: если в Dataset2 есть строка, где канал == канал, а время находится в пределах «до» и «после» времени, я хочу иметь «ДА». Остальное "НЕТ".

Данные1

ID   Channel   before_time   after_time 
1       A1  2019-09-02 20:13:00 2019-09-02 20:33:00
2       B1  2019-09-02 20:03:00 2019-09-02 20:23:00
3       C1  2019-09-02 20:23:00 2019-09-02 20:43:00
4       D1  2019-09-02 20:23:00 2019-09-02 20:43:00

Данные2

ID_B     Channel_B    Time_B
Hallo       A1        2019-09-02 20:23:00
Hi          B2        2019-09-02 20:05:00
Hoi         C1        2019-09-02 22:23:00

Желаемый выход

ID   Channel   before_time   after_time                     Available
1       A1  2019-09-02 20:13:00 2019-09-02 20:33:00         Yes  # Channel == Channel, Time between before & after
2       B1  2019-09-02 20:03:00 2019-09-02 20:23:00          No  # Channel != Channel
3       C1  2019-09-02 20:23:00 2019-09-02 20:43:00          No  # Time is not between before & after
4       D1  2019-09-02 20:23:00 2019-09-02 20:43:00          No  # There is no matching data where channel is D1

Желаемый результат 2 (комментарии Решения)

Добавление дополнительных столбцов из второго набора данных (Данные2).

ID   Channel   before_time   after_time                     Available   ID_B     
1       A1  2019-09-02 20:13:00 2019-09-02 20:33:00          Yes        Hallo       
2       B1  2019-09-02 20:03:00 2019-09-02 20:23:00          No         x 
3       C1  2019-09-02 20:23:00 2019-09-02 20:43:00          No         x
4       D1  2019-09-02 20:23:00 2019-09-02 20:43:00          No         x

Воспроизводимый пример (данные):

ID <- c("1", "2", "3", "4")
channel <- c("A1", "B1", "C1", "D1)
#startdate <- as.POSIXct(c("2019-09-02 20:23:00", "2019-09-02 20:13:00", "2019-09-02 20:33:00", "2019-09-02 20:33:00"))
before_time <- as.POSIXct(c("2019-09-02 20:13:00", "2019-09-02 20:03:00", "2019-09-02 20:23:00", "2019-09-02 20:23:00"))
after_time  <- as.POSIXct(c("2019-09-02 20:33:00", "2019-09-02 20:23:00", "2019-09-02 20:43:00","2019-09-02 20:43:00"))
data1 <- data.frame(ID, channel,   before_time, after_time)
View(data1)


ID_B <- c("Hallo", "Hi", "Hoi")
channel_B <- c("A1", "B2", "C1")
Time_B <- as.POSIXct(c("2019-09-02 20:23:00", "2019-09-02 20:05:00", "2019-09-02 22:23:00"))
data2 <- data.frame(ID_B, channel_B, Time_B)
View(data2)

Ответы [ 4 ]

2 голосов
/ 14 февраля 2020

Как упомянуто arg0naut91, здесь не равное объединение в data.table:

library(data.table)
setDT(data1)
setDT(data2)
data1[, c("Available", "ID_B") :=
        data2[.SD, on=.(channel_B=channel, Time_B>=before_time, Time_B<=after_time), 
            by=.EACHI, .(.N > 0, ID_B)][, (1L:3L) := NULL]
    ]

вывод:

   ID channel         before_time          after_time Available  ID_B
1:  1      A1 2019-09-02 20:13:00 2019-09-02 20:33:00      TRUE Hallo
2:  2      B1 2019-09-02 20:03:00 2019-09-02 20:23:00     FALSE  <NA>
3:  3      C1 2019-09-02 20:23:00 2019-09-02 20:43:00     FALSE  <NA>
4:  4      D1 2019-09-02 20:23:00 2019-09-02 20:43:00     FALSE  <NA>
1 голос
/ 14 февраля 2020

Может также иметь смысл рассмотреть sqldf, например:

library(sqldf)

sqldf('SELECT t1.ID, t1.channel, 
      t1.before_time, t1.after_time, 
      CASE WHEN t2.ID_B IS NULL THEN "No" ELSE "Yes" END Available 
      FROM data1 t1 LEFT JOIN data2 t2 ON t1.channel = t2.channel_B
      AND t2.Time_B BETWEEN t1.before_time AND t1.after_time')

Вывод:

  ID channel         before_time          after_time Available
1  1      A1 2019-09-02 20:13:00 2019-09-02 20:33:00       Yes
2  2      B1 2019-09-02 20:03:00 2019-09-02 20:23:00        No
3  3      C1 2019-09-02 20:23:00 2019-09-02 20:43:00        No
4  4      D1 2019-09-02 20:23:00 2019-09-02 20:43:00        No

Вот также один из способов сделать это в dplyr:

library(dplyr)

data1 %>%
  left_join(data2,
            by = c('channel' = 'channel_B')
            ) %>%
  mutate(
    Available = ifelse(
      !is.na(Time_B) & Time_B >= before_time & Time_B <= after_time, 'Yes', 'No')
    ) %>%
  select(-ends_with('_B'))

Добавление дополнительного столбца:

# sqldf

sqldf('SELECT t1.ID, t1.channel, 
      t1.before_time, t1.after_time, 
      CASE WHEN t2.ID_B IS NULL THEN "No" ELSE "Yes" END Available,
      CASE WHEN t2.ID_B IS NULL THEN "x" ELSE t2.ID_B END ID_B
      FROM data1 t1 LEFT JOIN data2 t2 ON t1.channel = t2.channel_B
      AND t2.Time_B BETWEEN t1.before_time AND t1.after_time')

# dplyr

data1 %>%
  left_join(data2,
            by = c('channel' = 'channel_B')
  ) %>%
  mutate(
    Available = ifelse(
      !is.na(Time_B) & Time_B >= before_time & Time_B <= after_time, 'Yes', 'No'),
    ID_B = ifelse(
      Available == 'Yes', as.character(ID_B), 'x')
  ) %>%
  select(-Time_B)
1 голос
/ 14 февраля 2020

Вот базовое решение R, использующее merge + ifelse, т. Е.

dfout <- subset(within(merge(data1,data2[-1],by.x = "channel",by.y = "channel_B",all.x = T), 
                       Available <- ifelse(!is.na(Time_B)& Time_B>=before_time & Time_B<=after_time,"Yes","No")),
                select = -Time_B)

, такое что

> dfout
  channel ID         before_time          after_time Available
1      A1  1 2019-09-02 20:13:00 2019-09-02 20:33:00       Yes
2      B1  2 2019-09-02 20:03:00 2019-09-02 20:23:00        No
3      C1  3 2019-09-02 20:23:00 2019-09-02 20:43:00        No
4      D1  4 2019-09-02 20:23:00 2019-09-02 20:43:00        No
1 голос
/ 13 февраля 2020

Это решение должно работать:

df<-(cbind(data1,data2)

df<-df%>%mutate(ID=as.integer(ID),
        channel=as.character(channel),
        ID_B=as.character(ID_B),
        channel_B=as.character(channel_B))

df%>%
  mutate(available= ifelse(channel==channel_B & Time_B >= before_time & Time_B <= after_time, "yes","no"))%>%
  select(-ID_B,Time_B,-channel_B)


 # A tibble: 3 x 5
 ID channel before_time         after_time          available
 <int> <chr>   <dttm>              <dttm>              <chr>    
 1     1 A1      2019-09-02 20:13:00 2019-09-02 20:33:00 yes      
 2     2 B1      2019-09-02 20:03:00 2019-09-02 20:23:00 no       
 3     3 C1      2019-09-02 20:23:00 2019-09-02 20:43:00 no  
...