我很抱歉提前发帖混淆了几个问题。如果不合适,请编辑或建议我应该做什么。我正在练习data.table join,这是一个想象的场景:
"两个机器人,每个机器人在MovementA中有4个位置,在MovementB中有4个位置。 要解决的问题:对于每个机器人,从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 您能否使用data.table art的优秀做法更正我的Solution2?
没有参数allow.cartesian=TRUE
data.table警告的 问题2
"将结果加入32行;超过8 = max(nrow(x),nrow(i))。检查i中的重复键值,每个键值一遍又一遍地连接到x中的同一组。如果可以,请尝试包括j
并删除by
(by-without-by),以便为每个组运行j以避免大量分配。如果您确定要继续,请重新运行allow.cartesian = TRUE"
它真的是笛卡尔产品吗?这里只对公共密钥值进行连接,这只是数据的巧合,产生了很大的连接结果。
问题3 dtMoveA和dtMoveB具有相同的列名。数据表连接通过将名称更改为i.Position
来区分。是"我"硬编码的前缀?我想 i.ColumnName 总是适用于X [Y]连接表达式中的Y成员。
提前感谢您的帮助。
答案 0 :(得分: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
中的每一行(a {{ 1}}行结果)。的'笛卡尔'只是意味着一个大的乘法'感。强>
这会回答你的问题吗?
问题3:
是。联接的格式为nrow(x) * nrow(i)
。当x[i]
和x
共享列名并且将在联接结果中时,这些列会添加i
前缀。它具有相同的前缀,还允许您访问i.
中的i
列,其中j
和x
共享列名称表单i
或x[i, j]
。
加入时,您可以将名称更改为您喜欢的任何名称。在这里,您可以使用:
更改为x[i, j, by=.EACHI]
和position.x
position.y
HTH
PS:如果您有任何建议,请随时添加FR here。请在执行此操作之前查看the posting guidelines。