Почему X присоединяется к data.tables, не допускает полного внешнего соединения или левого соединения?

Это немного философский вопрос о синтаксисе соединения data.table. Я нахожу все больше и больше использования для data.tables, но все еще учась …

Формат соединения X[Y] для data.tables очень краткий, удобный и эффективный, но, насколько я могу судить, он поддерживает только внутренние соединения и внешние внешние соединения. Чтобы получить левое или полное внешнее соединение, мне нужно использовать merge :

  • X[Y, nomatch = NA] – все строки в Y – правое внешнее соединение (по умолчанию)
  • X[Y, nomatch = 0] – только строки со X[Y, nomatch = 0] в X и Y – внутреннее соединение
  • merge(X, Y, all = TRUE) – все строки из X и Y – полное внешнее соединение
  • merge(X, Y, all.x = TRUE) – все строки в X – левом внешнем соединении

Мне кажется, что было бы удобно, если бы формат X[Y] поддерживал все 4 типа объединений. Есть ли причина, по которой поддерживаются только два типа соединений?

Для меня значения nomatch = 0 и nomatch = NA не очень интуитивно понятны для выполняемых действий. Мне легче понять и запомнить синтаксис merge : all = TRUE , all.x = TRUE и all.y = TRUE . Поскольку операция X[Y] напоминает merge намного больше, чем match , почему бы не использовать синтаксис merge для объединений, а не параметр nomatch функции nomatch ?

Вот примеры кода из 4 типов соединений:

 # sample X and Y data.tables library(data.table) X <- data.table(t = 1:4, a = (1:4)^2) setkey(X, t) X # ta # 1: 1 1 # 2: 2 4 # 3: 3 9 # 4: 4 16 Y <- data.table(t = 3:6, b = (3:6)^2) setkey(Y, t) Y # tb # 1: 3 9 # 2: 4 16 # 3: 5 25 # 4: 6 36 # all rows from Y - right outer join X[Y] # default # tab # 1: 3 9 9 # 2: 4 16 16 # 3: 5 NA 25 # 4: 6 NA 36 X[Y, nomatch = NA] # same as above # tab # 1: 3 9 9 # 2: 4 16 16 # 3: 5 NA 25 # 4: 6 NA 36 merge(X, Y, by = "t", all.y = TRUE) # same as above # tab # 1: 3 9 9 # 2: 4 16 16 # 3: 5 NA 25 # 4: 6 NA 36 identical(X[Y], merge(X, Y, by = "t", all.y = TRUE)) # [1] TRUE # only rows in both X and Y - inner join X[Y, nomatch = 0] # tab # 1: 3 9 9 # 2: 4 16 16 merge(X, Y, by = "t") # same as above # tab # 1: 3 9 9 # 2: 4 16 16 merge(X, Y, by = "t", all = FALSE) # same as above # tab # 1: 3 9 9 # 2: 4 16 16 identical( X[Y, nomatch = 0], merge(X, Y, by = "t", all = FALSE) ) # [1] TRUE # all rows from X - left outer join merge(X, Y, by = "t", all.x = TRUE) # tab # 1: 1 1 NA # 2: 2 4 NA # 3: 3 9 9 # 4: 4 16 16 # all rows from both X and Y - full outer join merge(X, Y, by = "t", all = TRUE) # tab # 1: 1 1 NA # 2: 2 4 NA # 3: 3 9 9 # 4: 4 16 16 # 5: 5 NA 25 # 6: 6 NA 36 

Обновление: data.table v1.9.6 представил синтаксис on= , который позволяет ad hoc присоединяться к полям, отличным от первичного ключа. Ответ jangorecki на вопрос Как объединить (объединить) кадры данных (внутренний, внешний, левый, правый)? содержит некоторые примеры дополнительных типов соединений, которые может обрабатывать data.table.

Цитировать с помощью таблицы данных.table FAQ 1.12

1,12

В чем разница между X [Y] и слиянием (X, Y)?

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

Число строк X[Y] и Y[X] обычно различается; тогда как число строк, возвращаемых merge(X,Y) и merge(Y,X) одинаково. НО, что не хватает основной точки. Большинство задач требуют что-то делать с данными после объединения или слияния. Зачем объединять все столбцы данных, только чтобы потом использовать их подмножество? Вы можете предложить merge(X[,ColsNeeded1],Y[,ColsNeeded2]) , но это делает копии merge(X[,ColsNeeded1],Y[,ColsNeeded2]) данных, и для этого требуется программист, какие столбцы нужны. X[Y,j ] в data.table делает все это за один шаг для вас. Когда вы пишете X[Y,sum(foo*bar)] , data.table автоматически проверяет выражение j, чтобы увидеть, какие столбцы он использует. Он будет только подмножать только эти столбцы; остальные игнорируются. Память создается только для столбцов, которые используются j, а столбцы Y имеют стандартные правила рециркуляции R в контексте каждой группы. Скажем, foo находится в X, а bar находится в Y (вместе с 20 другими столбцами в Y). Разве X[Y,sum(foo*bar)] быстрее запускается и быстрее запускается, чем слияние, за которым следует подмножество?

Если вы хотите, чтобы левое внешнее соединение X[Y]

 le <- Y[X] mallx <- merge(X, Y, all.x = T) # the column order is different so change to be the same as `merge` setcolorder(le, names(mallx)) identical(le, mallx) # [1] TRUE 

Если вы хотите, чтобы полное внешнее соединение

 # the unique values for the keys over both data sets unique_keys <- unique(c(X[,t], Y[,t])) Y[X[J(unique_keys)]] ## tba ## 1: 1 NA 1 ## 2: 2 NA 4 ## 3: 3 9 9 ## 4: 4 16 16 ## 5: 5 25 NA ## 6: 6 36 NA # The following will give the same with the column order X,Y X[Y[J(unique_keys)]] 

Ответ @ mnel – это место, так что согласитесь с этим ответом. Это просто продолжение, слишком долго для комментариев.

Как говорит mnel, левое / правое внешнее соединение получается путем замены Y и X : Y[X] -vs- X[Y] . Таким образом, в этом синтаксисе поддерживаются 3 из 4 типов соединений, а не 2, iiuc.

Добавление четвертого кажется хорошей идеей. Предположим, мы добавили full=TRUE или both=TRUE или merge=TRUE (не уверен, что имя лучшего аргумента?), Тогда мне не приходило в голову, что X[Y,j,merge=TRUE] был бы полезен по причинам после BUT в FAQ 1.12. Новый запрос функции теперь добавлен и связан здесь, спасибо:

FR # 2301: Добавить merge = TRUE аргумент для X [Y] и Y [X] join, как merge ().

В последних версиях ускорился merge.data.table (например, сделав небольшую копию внутри, чтобы, например, установить ключи более эффективно). Поэтому мы пытаемся приблизить merge() и X[Y] и предоставить все возможности пользователю для полной гибкости. Есть плюсы и минусы обоих. Еще один выдающийся запрос функции:

FR # 2033: Добавить by.x и by.y в файл merge.data.table

Если есть другие, пожалуйста, держите их в покое.

По этой части в вопросе:

почему бы не использовать синтаксис слияния для объединений, а не параметр номенклатуры функции соответствия?

Если вы предпочитаете синтаксис merge() и его 3 аргумента all , all.x и all.y то просто используйте это вместо X[Y] . Думайте, что он должен охватывать все случаи. Или вы имели в виду, почему аргумент представляет собой единственную nomatch в [.data.table ? Если это так, то это просто так, как это было изначально задано в FAQ 2.14: «Не могли бы вы объяснить, почему data.table вдохновляется синтаксисом A [B] в базе?». Но также, nomatch только принимает два значения в настоящее время 0 и NA . Это может быть расширено, чтобы отрицательное значение означало что-то, или 12 означало бы использование значений 12-й строки для заполнения NA, например, или nomatch в будущем может быть вектором или даже самим data.table .

Гектометр Как бы без взаимодействия взаимодействовать с merge = TRUE? Возможно, нам стоит взять это на помощь .

Этот «ответ» является предложением для обсуждения: как указано в моем комментарии, я предлагаю добавить параметр join в [.data.table (), чтобы включить дополнительные типы соединений, то есть: X[Y,j,join=string] . В дополнение к 4 типам обычных объединений я также предлагаю поддерживать 3 типа эксклюзивных объединений и перекрестное соединение.

Предполагается, что значения строки join (и псевдонимы) для различных типов соединений:

  1. "all.y" и "right" – правое соединение, настоящие data.table default (nomatch = NA) – все Y строк с NA, где нет соответствия X;
  2. "both" и "inner" internal "inner" – внутреннее соединение (nomatch = 0) – только строки, в которых соответствуют X и Y;

  3. "all.x" и "left" – left join – все строки из X, NA, где нет Y:

  4. "outer" и "full" – полное внешнее соединение – все строки из X и Y, NA, где нет совпадений

  5. "only.x" и "not.y" – non-join или anti-join возвращают X строк, где нет совпадения Y

  6. "only.y" и "not.x" – неприсоединение или анти-объединение, возвращающее Y строк, где нет соответствия X
  7. "not.both" – эксклюзивное соединение, возвращающее строки X и Y, где нет соответствия другой таблице, то есть исключительной или (XOR)
  8. "cross" – cross join или декартово произведение с каждой строкой X, соответствующей каждой строке Y

Значение по умолчанию – join="all.y" которое соответствует join="all.y" по умолчанию.

Строковые значения «all», «all.x» и «all.y» соответствуют параметрам merge() . «Правильные», «левые», «внутренние» и «внешние» строки могут быть более пригодны для пользователей SQL.

«Оба» и «not.both» строки – мое лучшее предложение на данный момент – но у кого-то могут быть лучшие строковые предложения для внутреннего соединения и эксклюзивного соединения. (Я не уверен, что «эксклюзивный» – это правильная терминология, исправьте меня, если есть правильный термин для присоединения «XOR»).

Использование join="not.y" является альтернативой для X[-Y,j] или X[!Y,j] синтаксиса неприсоединения и, возможно, более ясным (для меня), хотя я не уверен, что они то же (новая функция в data.table версии 1.8.3).

Иногда может быть полезно перекрестное соединение, но оно может не соответствовать парадигме data.table.

  • Как сопоставить вектор значений другому вектору с моей собственной пользовательской картой в R
  • Импорт данных из файла JSON в R
  • Замена чисел в диапазоне с коэффициентом
  • Как сохранить data.frame в R?
  • Установка кривой плотности на гистограмму в R
  • Матричная версия cor.test ()
  • Как я могу организовать произвольное количество ggplots, используя grid.arrange?
  • Упорядоченный график столбцов в ggplot
  • Количество строк в каждой группе
  • Что делает .SD в data.table в R
  • Построить несколько строк на одном графике
  • Interesting Posts

    WaitAll для нескольких дескрипторов в streamе STA не поддерживается

    Как загрузить систему Linux без графического сервера

    Агрегация по уникальному идентификатору и объединение связанных значений в строку

    База данных – Версии данных

    Каталоги Linux для сопоставления с SSD

    Невозможно освободить константные указатели в C

    Невозможно передать строку в int. Ошибка msg: строка ввода не была в правильном формате

    Как работает RewriteBase в .htaccess

    Как я могу обновить внешний вид JFreeChart после того, как он станет видимым?

    Можно ли увеличить ширину раздела «Все приложения» в меню «Пуск» Windows 10?

    Как мне связать связанный с enum combobox с настраиваемым форматированием строк для значений enums?

    Theme.AppCompat.Light.DarkActionBar – Ресурс не найден

    Преобразование из двоичных данных в элемент управления изображением в ASP.NET

    Какой профиль использует Selenium WebDriver по умолчанию?

    jQuery: как получить, какая кнопка была нажата при отправке формы?

    Давайте будем гением компьютера.