Если требуется левое соединение в стиле SQL (как подробно описано в редактировании), это может быть достигнуто с помощью кода, очень похожего на предложение icecreamtoucan в комментариях:
B[A,on=.(name = name, age > age)]
Примечание: если результирующий набор превышает сумму количества строк элементов объединения, data.table
предположит, что вы допустили ошибку (в отличие от механизмов SQL), и выдаст ошибку. Решение (при условии, что вы не совершили ошибку ) заключается в добавлении allow.cartesian = TRUE
.
Кроме того, в отличие от SQL, это объединение не возвращает все столбцы из составных таблиц. Вместо этого (и несколько разочаровывающе для тех, кто приходит из фона SQL) значения столбцов из левой таблицы, используемые в условии неравенства объединения, будут возвращены в столбцах с именами столбца правой таблицы по сравнению с ним в условии неравенства соединения!
Решение здесь (которое я нашел некоторое время назад в другом ответе SO, но не могу найти сейчас) состоит в том, чтобы создать дубликаты столбцов соединения, которые вы хотите сохранить, используйте их для условий соединения, а затем укажите столбцы для хранения в них. объединение.
, например
A <- data.table( group = rep("WIZARD LEAGUE",3)
,name = rep("Fred",time=3)
,status_start = as.Date("2017-01-01") + c(0,370,545)
,status_end = as.Date("2017-01-01") + c(369,544,365*3-1)
,status = c("UNEMPLOYED","EMPLOYED","RETIRED"))
A <- rbind(A, data.table( group = "WIZARD LEAGUE"
,name = "Sally"
,status_start = as.Date("2017-01-01")
,status_end = as.Date("2019-12-31")
,status = "CONTRACTED"))
> A
group name status_start status_end status
1: WIZARD LEAGUE Fred 2017-01-01 2018-01-05 UNEMPLOYED
2: WIZARD LEAGUE Fred 2018-01-06 2018-06-29 EMPLOYED
3: WIZARD LEAGUE Fred 2018-06-30 2019-12-31 RETIRED
4: WIZARD LEAGUE Sally 2017-01-01 2019-12-31 CONTRACTED
B <- data.table( group = rep("WIZARD LEAGUE",time=5)
,loc_start = as.Date("2017-01-01") + 180*0:4
,loc_end = as.Date("2017-01-01") + 180*1:5-1
, loc = c("US","GER","FRA","ITA","MOR"))
> B
group loc_start loc_end loc
1: WIZARD LEAGUE 2017-01-01 2017-06-29 US
2: WIZARD LEAGUE 2017-06-30 2017-12-26 GER
3: WIZARD LEAGUE 2017-12-27 2018-06-24 FRA
4: WIZARD LEAGUE 2018-06-25 2018-12-21 ITA
5: WIZARD LEAGUE 2018-12-22 2019-06-19 MOR
>#Try to join all rows whose date ranges intersect:
>B[A,on=.(group = group, loc_end >= status_start, loc_start <= status_end)]
Ошибка в vecseq (f__, len__, if (allow.cartesian || notjoin ||
! anyDuplicated (f__,: объединить результаты в 12 строк; более 9 =
nrow (х) + nrow (я). Проверьте наличие дублированных значений ключа в i, каждое из которых
присоединяться к той же группе в х снова и снова. Если это нормально, попробуйте
by = .EACHI для запуска j для каждой группы, чтобы избежать большого выделения. Если
Вы уверены, что хотите продолжить, повторите с allow.cartesian = TRUE.
В противном случае, пожалуйста, найдите это сообщение об ошибке в FAQ, Wiki,
Переполнение стека и отслеживание проблем data.table для совета.
>#Try the join with allow.cartesian = TRUE
>#this succeeds but messes up column names
> B[A,on=.(group = group, loc_end >= status_start, loc_start <= status_end), allow.cartesian = TRUE]
group loc_start loc_end loc name status
1: WIZARD LEAGUE 2018-01-05 2017-01-01 US Fred UNEMPLOYED
2: WIZARD LEAGUE 2018-01-05 2017-01-01 GER Fred UNEMPLOYED
3: WIZARD LEAGUE 2018-01-05 2017-01-01 FRA Fred UNEMPLOYED
4: WIZARD LEAGUE 2018-06-29 2018-01-06 FRA Fred EMPLOYED
5: WIZARD LEAGUE 2018-06-29 2018-01-06 ITA Fred EMPLOYED
6: WIZARD LEAGUE 2019-12-31 2018-06-30 ITA Fred RETIRED
7: WIZARD LEAGUE 2019-12-31 2018-06-30 MOR Fred RETIRED
8: WIZARD LEAGUE 2019-12-31 2017-01-01 US Sally CONTRACTED
9: WIZARD LEAGUE 2019-12-31 2017-01-01 GER Sally CONTRACTED
10: WIZARD LEAGUE 2019-12-31 2017-01-01 FRA Sally CONTRACTED
11: WIZARD LEAGUE 2019-12-31 2017-01-01 ITA Sally CONTRACTED
12: WIZARD LEAGUE 2019-12-31 2017-01-01 MOR Sally CONTRACTED
>#Create aliased duplicates of the columns in the inequality condition
>#and specify the columns to keep
> keep_cols <- c(names(A),setdiff(names(B),names(A)))
> A[,start_dup := status_start]
> A[,end_dup := status_end]
> B[,start := loc_start]
> B[,end := loc_end]
>
>#Now the join works as expected (by SQL convention)
>
> B[ A
,..keep_cols
,on=.( group = group
,end >= start_dup
,start <= end_dup)
,allow.cartesian = TRUE]
group name status_start status_end status loc_start loc_end loc
1: WIZARD LEAGUE Fred 2017-01-01 2018-01-05 UNEMPLOYED 2017-01-01 2017-06-29 US
2: WIZARD LEAGUE Fred 2017-01-01 2018-01-05 UNEMPLOYED 2017-06-30 2017-12-26 GER
3: WIZARD LEAGUE Fred 2017-01-01 2018-01-05 UNEMPLOYED 2017-12-27 2018-06-24 FRA
4: WIZARD LEAGUE Fred 2018-01-06 2018-06-29 EMPLOYED 2017-12-27 2018-06-24 FRA
5: WIZARD LEAGUE Fred 2018-01-06 2018-06-29 EMPLOYED 2018-06-25 2018-12-21 ITA
6: WIZARD LEAGUE Fred 2018-06-30 2019-12-31 RETIRED 2018-06-25 2018-12-21 ITA
7: WIZARD LEAGUE Fred 2018-06-30 2019-12-31 RETIRED 2018-12-22 2019-06-19 MOR
8: WIZARD LEAGUE Sally 2017-01-01 2019-12-31 CONTRACTED 2017-01-01 2017-06-29 US
9: WIZARD LEAGUE Sally 2017-01-01 2019-12-31 CONTRACTED 2017-06-30 2017-12-26 GER
10: WIZARD LEAGUE Sally 2017-01-01 2019-12-31 CONTRACTED 2017-12-27 2018-06-24 FRA
11: WIZARD LEAGUE Sally 2017-01-01 2019-12-31 CONTRACTED 2018-06-25 2018-12-21 ITA
12: WIZARD LEAGUE Sally 2017-01-01 2019-12-31 CONTRACTED 2018-12-22 2019-06-19 MOR
Я, конечно, не первый, кто указывает на эти отклонения от соглашения SQL или на то, что воспроизвести эту функциональность довольно громоздко (как показано выше), и я верю, что улучшения активно рассматриваются .
Всем, кто рассматривает альтернативные стратегии (например, пакет sqldf
), я скажу, что, хотя есть достойные альтернативы data.table
, я изо всех сил пытался найти какое-либо решение, которое сравнивается со скоростью data.table
, когда оно очень велико. наборы данных участвуют как в соединениях, так и в других операциях. Излишне говорить, что есть много других преимуществ, которые делают этот пакет незаменимым для меня и многих других. Поэтому для тех, кто работает с большими наборами данных, я бы посоветовал не оставлять соединения data.table
, если вышеприведенное выглядит громоздким и вместо этого либо привыкнуть проходить через эти движения, либо написать вспомогательную функцию, которая копирует последовательность действий до улучшения синтаксис приходит.
Наконец, я не упомянул здесь дизъюнктивные объединения, но, насколько я могу судить, это еще один недостаток подхода data.table
(и еще одна область, где sqldf
полезен). Я обходил их с помощью специальных «хаков», но я был бы признателен за полезные советы о том, как лучше всего их лечить в data.table
.