Быстрее unique () для сравнения ключей в двух фреймах данных

#r

#r

Вопрос:

При попытке выполнить следующий анализ с большими данными у меня возникает следующая проблема:

У меня есть два фрейма данных A и B с одним и тем же первичным ключом (по нескольким столбцам), но фрейм данных A дополнительно содержит переменную date.

Теперь я хочу проверить, есть ли для всех уникальных объектов в фрейме данных A запись и в фрейме данных B. Я делаю это с помощью следующей функции:

 checkMissing <- function(A, B, primary_key) {
  A <- unique(A[,primary_key])
  B <- unique(B[,primary_key])
  return(A[!A %in% B,])
}
  

Как оказалось, уникальная часть работает ужасно медленно, когда A получает все больше и больше данных (я проверил что-то вроде 15 миллионов строк, и на моей машине это заняло около 30 секунд).

Есть ли более разумный способ проверить, отсутствуют ли объекты в B, без использования dplyr? (базовый R был бы идеальным, но data.table также работает)

Вот воспроизводимый пример:

 library(tictoc)
checkMissing <- function(A, B, primary_key) {
  tic("making data unique")
  A <- unique(A[,primary_key])
  B <- unique(B[,primary_key])
  toc()
  return(A[!A %in% B,])
}
# creating the dummy key data

ID1 <- 250000
ID2 <- seq(1,ID1/100,1)
ID3 <- seq(1,ID1/10000,1)

tmp <- data.frame("ID1" = seq(1,ID1,1),
                  "ID2" = sample(ID2, ID1, replace = TRUE),
                  "ID3" = sample(ID3, ID1, replace = TRUE)
)

#creating the date sequence
dates <- data.frame("date" = seq.Date(as.Date("2019-01-01"),as.Date("2019-02-28"),1))

#cross join to get data frame A
df.A <- merge(dates,tmp,by=NULL)

# create data frame B
df.B <- unique(df.A[,c("ID1","ID2","ID3")])

tic("overall time")
df.result <- checkMissing(df.A,df.B,c("ID1","ID2","ID3"))
toc()
  

Спасибо!
Стефан

Комментарии:

1. Я думаю, вы ищете средство против объединения? Мои навыки работы с таблицами данных немного подзабыты, но, может быть, это: setDT(df.A)[!df.B, on = c("ID1","ID2","ID3")] ? Возможно, у меня есть два фрейма данных в обратном порядке, я не уверен. (Также есть функция dplyr anti_join, на случай, если другие люди заинтересуются.)

2. Привет @joran, ты прав — это намного быстрее, чем мой первоначальный подход. Спасибо!

Ответ №1:

как отметил джоран в своем комментарии, реализация защиты от объединения в data.table намного быстрее:

 setDT(df.A)[!df.B, on = c("ID1","ID2","ID3")]
  

В моем тесте выполнение данных сократилось с 30-35 секунд до менее чем 2 секунд.

Хотя все еще интересует более быстрая базовая версия R, это правильный ответ.

Лучший Стефан