2014-12-21 4 views
4

Прошу прощения за длинный пост, который смешивает несколько вопросов. Если это не подходит, отредактируйте или сообщите, что я должен делать. Я практикую data.table присоединиться, вот воображаемый сценарий:data.table картезированное предупреждение о присоединении к законному соединению

«Два робота, каждый из них имеет 4 позиции в MovementA и 4 позиции в MovementB проблема:. Для каждого робота, от MoveA до MoveB, там являются 4x4 возможные позиционно-пары Найти 4 пары с кратчайшим расстоянием»

Настройка данных

library(data.table) 

set.seed(20141220) 
dtMoveA = data.table(RobotID = rep(1:2, each=4), Position=sample(1:20, 8)) 
dtMoveB = data.table(RobotID = rep(1:2, each=4), Position=sample(1:20, 8)) 

# Review Data 
rbind(cbind(Movement="Move-A", dtMoveA), cbind(Movement="Move-B", dtMoveB)) 

    Movement RobotID Position 
1: Move-A  1  18 
2: Move-A  1  20 
3: Move-A  1  15 
4: Move-A  1  8 
5: Move-A  2  13 
6: Move-A  2  2 
7: Move-A  2  9 
8: Move-A  2  12 
9: Move-B  1  18 
10: Move-B  1  14 
11: Move-B  1  13 
12: Move-B  1  17 
13: Move-B  2  5 
14: Move-B  2  16 
15: Move-B  2  20 
16: Move-B  2  3 

Решение 1 (с использованием dplyr)

library(dplyr) 

dtMoveA %>% 
    inner_join(dtMoveB, by="RobotID") %>% 
    mutate(AbsDistance = abs(Position.x - Position.y)) %>% 
    group_by(RobotID, Position.x) %>% 
    filter(AbsDistance == min(AbsDistance)) %>% 
    arrange(RobotID, Position.x) 

    RobotID Position.x Position.y AbsDistance 
1  1   8   13   5 
2  1   15   14   1 
3  1   18   18   0 
4  1   20   18   2 
5  2   2   3   1 
6  2   9   5   4 
7  2   12   16   4 
8  2   13   16   3 

(попытка) Решение 2 (используя data.table)

setkey(dtMoveA, RobotID) 
setkey(dtMoveB, RobotID) 

dtMoveA[dtMoveB, .(RobotID, Position, i.Position, 
         AbsDistance = abs(Position - i.Position)), allow.cartesian=TRUE 
    ] [, MinDistance := min(AbsDistance), by=list(RobotID, Position) 
    ] [ AbsDistance == MinDistance, .(Position, i.Position, AbsDistance), by=RobotID 
    ] [ order(RobotID, Position)] 

    RobotID Position i.Position AbsDistance 
1:  1  8   13   5 
2:  1  15   14   1 
3:  1  18   18   0 
4:  1  20   18   2 
5:  2  2   3   1 
6:  2  9   5   4 
7:  2  12   16   4 
8:  2  13   16   3 

Вопрос 1 Можете ли вы исправить мою Solution2 с передовой практикой data.table искусства?

Вопрос 2 без параметра allow.cartesian=TRUE data.table предупреждает «Join результаты в 32 строк;. Более 8 = тах (nrow (х), nrow (я)) Проверьте дублирование ключевых значений I, каждый из которых присоединяется к одной и той же группе в x снова и снова. Если все в порядке, попробуйте включить j и отбрасывая by (по-без), чтобы j запускался для каждой группы, чтобы избежать большого выделения. Если вы уверены, что желание продолжить, повторить с allow.cartesian = TRUE "

Действительно ли это декартовый продукт? Здесь объединение производится только по общим значениям ключа, это просто совпадение в данных, которое дает большие результаты соединения.

Вопрос 3 dtMoveA и dtMoveB имеют одинаковые имена столбцов. datatable join делает различие, меняя имя на i.Position. Является ли префикс «i» чем-то жестко запрограммированным? И я полагаю, что i.ColumnName всегда относится к Y-члену в выражении объединения X [Y].

Заранее благодарим за любую помощь.

+1

Вы действительно должны начать привыкать к одному вопросу за сообщение. Если я не ошибаюсь, одна из ваших других должностей на этой неделе содержала около 5 различных вопросов. –

+0

Эти Qs несколько связаны с одной и той же тестовой настройкой. Если я сделаю 3 разных сообщения. Боюсь, мне нужно каждый раз повторять контекст. Тем не менее, я абсолютно не хочу, чтобы кто-то ошибался. Должен ли я удалить Q2, Q3 и создать два новых сообщения? – Polymerase

+0

Ричард, давайте сосредоточимся на этом посту пока. Я достаточно избит на другом посту. Пожалуйста, простите меня за мою прошлую новичковую ошибку и позвольте мне продолжить обучение. – Polymerase

ответ

5

Вопрос 1:

Выглядит здорово! Но эквивалент внутреннего соединения также должен добавить nomatch=0L. В противном случае вы также получите все строки от dtMoveB. Мы не можем использовать by=.EACHI здесь AFAICT.

Прочитано this answer и the answer linked under this comment для понимания цели allow.cartesian = TRUE.

Вопрос 2: Из ?data.table под запись для allow.cartesian:

FALSE предотвращает объединений, которые приведут к более max(nrow(x), nrow(i)) строк. Обычно это вызвано дублирующимися значениями в столбцах соединения i, каждый из которых объединяется в одну и ту же группу в x снова и снова: соединение с неопределенным числом.

Обычно это не предназначено, и соединение необходимо изменить. В этом контексте слово «декартово» используется свободно. Традиционное декартовое соединение (намеренно) трудно достичь в data.table: где каждая строка в i присоединяется к каждой строке в x (результат строки nrow(x) * nrow(i)). «декартово» означает только «большой мультипликативный» смысл.

Ответит ли это на ваш вопрос?

Вопрос 3:

Да. Соединения имеют форму x[i]. Когда x и i разделяют имя столбца и будут в объединенном результате, в этих столбцах будет добавлен префикс i.. Это тот же префикс, который также позволяет вам получить доступ к столбцам i в j, где оба x и i разделяют имя столбца в операциях формы x[i, j] или x[i, j, by=.EACHI].

При подключении вы можете изменить имена на все, что захотите. Здесь вы можете изменить к position.x и position.y с:

dtMoveA[dtMoveB, .(RobotID, Position.x=Position, Position.y=i.Position, 
       AbsDistance = abs(Position - i.Position)), allow.cartesian=TRUE] 

НТН


PS: Если у Вас есть какие-либо предложения, не стесняйтесь, чтобы добавить FR here. Прежде чем это сделать, просмотрите the posting guidelines.

+0

Привет, Арун, Ваши ответы всегда прекрасны, спасибо снова. Я очень удивлен, что получил DT-сообщение в порядке. Что касается allow.cartesian, я подозревал, что это была предосторожность, чтобы предотвратить непреднамеренный взрывоопасный комбинационный взрыв. Но то, что меня выбрало, было словом «декартово» b/c, которое я читал в нем.Теперь я чувствую себя лучше, спасибо. Я думал, что я сделал синтаксическую ошибку соединения где-то, что вызвало перекрестное соединение, которое я не собирался делать. «Я». префикс в порядке, переименовать не нужно, если я знаю, что правило является последовательным, я могу подчиняться умолчанию. FR?!? Пожалуйста, дайте мне несколько лет. Все еще ДД-малыш здесь. – Polymerase

+0

:-) конечно. Просто подумал о чем-то. Часть '[AbsDistance == MinDistance,. (Position, i.Position, AbsDistance), by = RobotID]' не требует группировки. Вам просто нужно получить столбцы .. Вы можете сделать: '[AbsDistance == MinDistance, .SD, .SDcols = c (" Position "," i.Position "," AbsDistance ")]'. – Arun

+0

Спасибо! что: = оператор для добавления столбца в GroupBy действительно опрятен. В SQL или dplyr нет эквивалентности. Следуя вашим советам, последний запрос может быть просто «[AbsDistance == MinDistance]» или '[AbsDistance == MinDistance, .SD]', который также выводит RobotID как информацию, но также включает избыточный столбец MinDistance. Я попытаюсь попытаться выяснить, есть ли способ исключить столбец, например, выбор dplyr (dtResult, -MinDistance). – Polymerase

Смежные вопросы