Объединить data.table, когда количество ключевых столбцов отличается

Я пытаюсь понять логику в data.table из документации и немного неясно. Я знаю, что могу просто попробовать это и посмотреть, что произойдет, но я хотел бы убедиться, что нет патологического случая, и поэтому хотел бы знать, как была закодирована логика. Когда два объекта data.table имеют различное количество столбцов ключа, например a имеет 2 и b имеет 3, и вы запускаете c <- a[b], будут a и b объединены просто на первых двух ключевые столбцы или будет ли третий столбец в автоматически объединен с третьим столбцом ключа в b? Пример:

require(data.table)
a <- data.table(id=1:10, t=1:20, v=1:40, key=c("id", "t"))
b <- data.table(id=1:10, v2=1:20, key="id")
c <- a[b]

Это должно выбрать строки a, соответствующие столбцу id в b. Например, для id==1 в b в b есть 2 строки и 4 строки в a, которые должны генерировать 8 строк в c. Это действительно то, что кажется:

> head(c,10)
    id  t  v v2
 1:  1  1  1  1
 2:  1  1 21  1
 3:  1 11 11  1
 4:  1 11 31  1
 5:  1  1  1 11
 6:  1  1 21 11
 7:  1 11 11 11
 8:  1 11 31 11
 9:  2  2  2  2
10:  2  2 22  2

Другой способ попробовать:

d <-b[a]

Это должно сделать то же самое: для каждой строки в a она должна выбрать соответствующую строку в b: поскольку a имеет дополнительный ключевой столбец, t, этот столбец не должен использоваться для сопоставления и соединение должно основываться только на первом ключевом столбце, id должно быть выполнено. Похоже, что это так:

> head(d,10)
    id v2  t  v
 1:  1  1  1  1
 2:  1 11  1  1
 3:  1  1  1 21
 4:  1 11  1 21
 5:  1  1 11 11
 6:  1 11 11 11
 7:  1  1 11 31
 8:  1 11 11 31
 9:  2  2  2  2
10:  2 12  2  2

Может кто-нибудь подтвердить? Чтобы быть ясным: это третий ключевой столбец a, когда-либо используемый в любом из слияний, или data.table использует только min(length(key(DT))) для двух таблиц.

Ответ 1

Хороший вопрос. Сначала правильная терминология (от ?data.table):

[Таблица данных.] может иметь один ключ из одного или нескольких столбцов. Этот ключ можно использовать для индексирования строк вместо имен ростов.

Итак, "ключ" (singlelular) не "ключи" (множественное число). В настоящее время мы можем уйти с "ключами". Но когда дополнительные ключи добавляются в будущем, тогда может быть несколько ключей. Каждый ключ (единственный) может иметь несколько столбцов (множественное число).

В противном случае вы абсолютно правы. Следующий абзац был улучшен в v1.8.2 на основе обратной связи от других, которые также были смущены. От ?data.table:

Когда я является таблицей данных, x должен иметь ключ. я присоединяется к x с помощью x ключа и возвращаются строки в x, которые соответствуют. Соединительное соединение выполняется между каждым столбцом в я до каждого столбца по ключу x; то есть столбец 1 я сопоставляется с первым столбцом ключа x, столбца 2 ко второму и т.д. Соответствие представляет собой двоичный поиск в скомпилированном C в O (log n) времени. Если у я меньше столбцов, чем x, тогда многие строки x будут обычно соответствовать каждой строке i, так как не все столбцы ключа x будут соединены (общий пример использования). Если у меня больше столбцов, чем ключ x, столбцы i, не участвующие в объединении, включаются в результат. Если у меня также есть ключ, это ключевые столбцы, которые используются для соответствия столбцам ключа x (столбец 1 ключа я соединен с столбцом 1 ключа x, столбцом 2 и столбцом 2 и т.д.) И двоичным слиянием из двух таблиц. Во всех объединениях имена столбцов не имеют значения. Столбцы x-ключа объединяются по порядку, начиная с столбца 1, начиная с i, когда я не замкнут, или от столбца 1 от ключа i.


Следуя комментариям, в v1.8.3 (на R-Forge) это теперь читает (изменяется жирным шрифтом):

Когда я является таблицей данных, x должен иметь ключ. я присоединяется к x с помощью x ключа и возвращаются строки в x, которые соответствуют. Соединительное соединение выполняется между каждым столбцом в я до каждого столбца по ключу x; то есть столбец 1 я сопоставляется с первым столбцом ключа x, столбца 2 ко второму и т.д. Соответствие представляет собой двоичный поиск в скомпилированном C в O (log n) времени. Если у я меньше столбцов, чем x, тогда не все столбцы ключа x будут объединены (общий пример использования), и многие строки x будут (обычно) соответствовать каждой строке i. Если у меня больше столбцов, чем ключ x, столбцы i, не участвующие в объединении, включаются в результат. Если у меня также есть ключ, это ключевые столбцы, которые используются для соответствия столбцам ключа x (столбец 1 ключа я соединен с столбцом 1 ключа x, столбец 2 ключа я для столбца 2 ключа x, и т.д. до тех пор, пока используется более короткий ключ) и выполняется двоичное слияние двух таблиц. Во всех объединениях имена столбцов не имеют значения; столбцы x-ключа объединяются по порядку, начиная с столбца 1 и после i, когда я не является ключом, или от столбца 1 от i-го ключа. В коде количество столбцов соединения определяется по min (length (key (x)), if (haskey (i)) length (key (i)) else ncol (i)).

Ответ 2

Цитировать data.table FAQ:

X [Y] - это объединение, поиск X строк с использованием Y (или Y-ключ, если он есть) в качестве индекса. Y [X] является объединением, ища Y строк, используя X (или X-ключ, если он есть) в качестве индекса. merge (X, Y) делает оба пути одновременно. Число строк X [Y] и Y [X] обычно различается; тогда как число строк, возвращаемых слиянием (X, Y) и слиянием (Y, X), одинаково.