Левое соединение с использованием data.table

Предположим, что у меня есть два data.table's:

А:

  A  B
1: 1 12
2: 2 13
3: 3 14
4: 4 15

В:

   A  B
1: 2 13
2: 3 14

и у меня есть следующий код:

merge_test = merge(dataA, dataB, by="A", all.data=TRUE)

Я получаю:

   A B.x B.y
1: 2  13  13
2: 3  14  14

Тем не менее, я хочу, чтобы все строки в dataA в финальной объединенной таблице. Есть ли способ сделать это?

Ответ 1

Вы можете попробовать это:

# used data
# set the key in 'B' to the column which you use to join
A <- data.table(a = 1:4, b = 12:15)
B <- data.table(a = 2:3, b = 13:14, key = 'a') 

B[A]

Ответ 2

Если вы хотите добавить значения b для B в A, то лучше всего объединить A с B и обновить A по ссылке следующим образом:

A[B, on = 'a', bb := i.b]

который дает:

> A
   a  b bb
1: 1 12 NA
2: 2 13 13
3: 3 14 14
4: 4 15 NA

Это лучший подход, чем использование B[A, on='a'] поскольку последний просто выводит результат на консоль. Если вы хотите вернуть результаты обратно в A, вам нужно использовать A <- B[A, on='a'] что даст вам тот же результат.

Причина, по которой A[B, on = 'a', bb := ib] лучше, чем A <- B[A, on = 'a'] заключается в эффективности использования памяти. При A[B, on = 'a', bb := ib] расположение A в памяти остается неизменным:

> address(A)
[1] "0x102afa5d0"
> A[B, on = 'a', bb := i.b]
> address(A)
[1] "0x102afa5d0"

С другой стороны, с A <- B[A, on = 'a'], новый объект создается и сохраняется в памяти как A и, следовательно, имеет другое место в памяти:

> address(A)
[1] "0x102abae50"
> A <- B[A, on = 'a']
> address(A)
[1] "0x102aa7e30"

Использование merge (merge.data.table) приводит к аналогичному изменению расположения в памяти:

> address(A)
[1] "0x111897e00"
> A <- merge(A, B, by = 'a', all.x = TRUE)
> address(A)
[1] "0x1118ab000"

Таким образом, для эффективности памяти лучше использовать синтаксис "update-by-reference-join":

A[B, on = 'a', bb := i.b] 

Хотя это не имеет заметного различия с такими маленькими наборами данных, оно имеет значение для больших наборов данных, для которых был разработан data.table.

Вероятно, также стоит упомянуть, что порядок A остается прежним.


Чтобы увидеть влияние на скорость и использование памяти, сделайте бенчмаркинг с некоторыми большими наборами данных (данные см. Во 2-й части используемого раздела данных ниже):

library(bench)
bm <- mark(AA <- BB[AA, on = .(aa)],
           AA[BB, on = .(aa), cc := cc],
           iterations = 1)

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

> bm[,c(1,3,5)]
# A tibble: 2 x 3
  expression                         median mem_alloc
  <bch:expr>                       <bch:tm> <bch:byt>
1 AA <- BB[AA, on = .(aa)]            4.98s     4.1GB
2 AA[BB, on = .(aa), ':='(cc, cc)] 560.88ms   384.6MB

Таким образом, в этой настройке "обновление по ссылке-соединение" происходит примерно в 9 раз быстрее и потребляет в 11 раз меньше памяти.

ПРИМЕЧАНИЕ. Увеличение скорости и использование памяти могут различаться в разных настройках.


Используемые данные:

# initial datasets
A <- data.table(a = 1:4, b = 12:15)
B <- data.table(a = 2:3, b = 13:14)

# large datasets for the benchmark
set.seed(2019)
AA <- data.table(aa = 1:1e8, bb = sample(12:19, 1e7, TRUE))
BB <- data.table(aa = sample(AA$a, 2e5), cc = sample(2:8, 2e5, TRUE))