dplyr: cbind столбцы на основе метки времени - PullRequest
0 голосов
/ 05 ноября 2018

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

У меня есть два data.frames df1 и df2. Я хочу отсортировать «cbind» значения столбца time2 от df2 до df1, но только если совпадения user_id и place_id:

> head(df1)
                time1 user_id   place_id
1 2018-06-09 12:56:12  sdkID1  place_ID1
2 2018-06-24 05:15:07  sdkID1  place_ID1
3 2018-06-12 04:15:21  sdkID1 place_ID10
4 2018-06-12 14:56:42  sdkID1 place_ID17
5 2018-05-16 18:21:51  sdkID1 place_ID20
6 2018-07-11 12:19:27  sdkID1 place_ID21
> head(df2)
                time2 user_id   place_id
1 2018-06-09 13:12:39  sdkID1  place_ID1
2 2018-06-24 06:52:51  sdkID1  place_ID1
3 2018-06-12 05:50:19  sdkID1 place_ID10
4 2018-05-16 19:42:59  sdkID1 place_ID20
5 2018-07-11 12:23:44  sdkID1 place_ID21
6 2018-06-13 11:56:05  sdkID1 place_ID34

Однако у меня нет никакой переменной id, чтобы проверить, что time2 из df2 принадлежит df1. Чтобы оживить ситуацию, для некоторых событий у меня нет отметки времени, чтобы соответствовать df1.

Я хочу что-то вроде:

> head(result)
                time1 user_id   place_id               time2 
1 2018-06-09 12:56:12  sdkID1  place_ID1 2018-06-09 13:12:39 
2 2018-06-24 05:15:07  sdkID1  place_ID1 2018-06-24 06:52:51 
3 2018-06-12 04:15:21  sdkID1 place_ID10 2018-06-12 05:50:19 
4 2018-06-12 14:56:42  sdkID1 place_ID17                  NA
5 2018-05-16 18:21:51  sdkID1 place_ID20 2018-05-16 19:42:59 
6 2018-07-11 12:19:27  sdkID1 place_ID21 2018-07-11 12:23:44 

Есть ли способ взять time2-time1 только оставить строки с положительная разница во времени? Я знаю, что есть. Но тогда у меня есть случаи как первые две строки, которые имеют одинаковые user_id и place_id и таким образом я получаю результаты 2018-06-24 06:52:51 - 2018-06-24 05:15:07 и 2018-06-24 06:52:51 - 2018-06-09 12:56:12. Мне нужно только первое отличие.

Представьте, что время1 - это прибытие, а время2 - это отправление. В основном моя проблема сводится к тому, чтобы выяснить, какие поезда или самолеты работают. Мне нужен какой-то способ понять, что 2018-06-24 06:52:51 - 2018-06-24 05:15:07 то же самое, и что 2018-06-24 06:52:51 - 2018-06-09 12:56:12 - это не тот же поезд или самолет.

Поскольку я хочу перевести код на SQL, решение должно основываться на dplyr. Я пробовал что-то вроде df1 %>% group_by(user_id,place_id), но сейчас я определенно застрял. Вот некоторые примеры данных

set.seed(42)
u <- runif(1000, 0, 60) # "noise" to add or subtract from some timepoint
df1<-data.frame(time1=as.POSIXlt(sort(u)*100000, origin = "2018-05-03 08:00:00"),
                user_id=sample(rep(paste0('sdkID',1:60)),1000,replace=TRUE),
                place_id=sample(rep(paste0('place_ID',1:60)),1000,replace=TRUE))

df1=df1[order(df1$user_id,df1$place_id,df1$time1),]

df2=df1[-sample(1:1000,200),]  
df2$time1<-df2$time1+u[-sample(1:1000,200)]*100

## cleaning up
colnames(df2)[1]='time2'
rownames(df1)=1:1000
rownames(df2)=1:800

Ответы [ 3 ]

0 голосов
/ 05 ноября 2018

Я считаю, что следующее решает вашу проблему.

library(dplyr)

result <- df1 %>%
  left_join(df2, by = c("user_id", "place_id")) %>%
  mutate(Diff = difftime(time1.y, time1.x, units = "secs"),
         Diff = as.numeric(Diff)) %>%
  filter(Diff > 0) %>%
  arrange(user_id, place_id, time1.x) %>%
  group_by(time1.x) %>%
  mutate(time1 = first(time1.x), time2 = time1.y) %>%
  ungroup() %>%
  select(-Diff, -time1.x, -time1.y)

head(result)
## A tibble: 6 x 4
#  user_id place_id   time1               time2              
#  <fct>   <fct>      <dttm>              <dttm>             
#1 sdkID1  place_ID1  2018-05-14 06:53:01 2018-05-14 08:24:30
#2 sdkID1  place_ID18 2018-06-05 04:38:53 2018-06-05 06:12:35
#3 sdkID1  place_ID19 2018-05-22 19:20:40 2018-05-22 19:49:17
#4 sdkID1  place_ID25 2018-06-15 08:55:55 2018-06-15 10:18:58
#5 sdkID1  place_ID27 2018-05-06 17:34:40 2018-05-15 17:17:48
#6 sdkID1  place_ID27 2018-05-06 17:34:40 2018-06-11 15:14:07
0 голосов
/ 06 ноября 2018

На основе ответов @RuiBarradas и @kon_u мне удалось решить мою проблему. Поскольку оба лишь частично поняли проблему (частично из-за того, что я недостаточно четко сформулировал описание проблемы), я поделюсь своим полным решением:

result<-df1 %>%
       left_join(df2, by = c("user_id", "place_id")) %>%
       mutate(Diff = difftime(time2, time1, units = "secs"),
                           Diff = as.numeric(Diff)) %>%
       filter(Diff > 0) %>%
       arrange(user_id, place_id, time1,time2) %>%
       group_by(user_id, place_id,time2) %>% 
       filter(Diff==min(Diff)) %>%
      right_join(df1,by=c("user_id", "place_id","time1"))
0 голосов
/ 05 ноября 2018

Предложить использование lubridate: работа с датами и временем в R для расчета минимальной разницы во времени.

library(dplyr)
library(lubridate)

# Codes Given
set.seed(42)
u <- runif(1000, 0, 60) # "noise" to add or subtract from some timepoint
df1<-data.frame(time1=as.POSIXlt(sort(u)*100000, origin = "2018-05-03 08:00:00"),
                user_id=sample(rep(paste0('sdkID',1:60)),1000,replace=TRUE),
                place_id=sample(rep(paste0('place_ID',1:60)),1000,replace=TRUE))

df1=df1[order(df1$user_id,df1$place_id,df1$time1),]

df2=df1[-sample(1:1000,200),]  
df2$time1<-df2$time1+u[-sample(1:1000,200)]*100

# dplyr operations
df_3 = df1 %>% left_join(df2, by = c('user_id', 'place_id'))
df_3$time_diff = abs(ymd_hms(df_3$time1.x) - ymd_hms(df_3$time1.y))
df_3 %>% 
    arrange(-desc(user_id), -desc(place_id), -desc(time_diff)) %>% 
    group_by(user_id, place_id) %>%
    slice(which.min(time_diff))

enter image description here

Дополнительные ресурсы:

  1. https://cran.r -project.org / веб / пакеты / lubridate / виньетки / lubridate.html
  2. Расчет разницы во времени между двумя столбцами
  3. https://data.library.virginia.edu/working-with-dates-and-time-in-r-using-the-lubridate-package/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...