Pol*_*ase 4 join r cartesian-product data.table
我很抱歉提前发帖混淆了几个问题.如果不合适,请编辑或建议我应该做什么.我正在练习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
Run Code Online (Sandbox Code Playgroud)
解决方案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
Run Code Online (Sandbox Code Playgroud)
(尝试)解决方案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
Run Code Online (Sandbox Code Playgroud)
问题1您能否通过data.table art的良好实践来纠正我的Solution2?
没有参数allow.cartesian=TRUEdata.table的问题2警告
"连接结果为32行;超过8 =最大值(nrow(x),nrow(i)).检查i中的重复键值,每个键值都加入到同一组中x一遍又一遍.如果没关系,请尝试包含j并删除by(by-without-by),以便为每个组运行j以避免大量分配.如果您确定要继续,请使用allow.cartesian = TRUE重新运行"
它真的是笛卡尔积吗?这里只对公共密钥值进行连接,这只是数据的巧合,产生了很大的连接结果.
问题3 dtMoveA和dtMoveB具有相同的列名.数据表连接通过将名称更改为来区分i.Position."i"前缀是硬编码的吗?我想i.ColumnName总是适用于X [Y]连接表达式中的Y成员.
在此先感谢您的帮助.
问题1:
看起来很棒!但是内连接的等价物也是要添加的nomatch=0L.否则你也会得到所有的行dtMoveB.我们不能在by=.EACHI这里使用AFAICT.
阅读此回答和本评论中链接的答案,以了解其目的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]
Run Code Online (Sandbox Code Playgroud)
HTH
PS:如果您有任何建议,请随时在此处添加FR .请在执行此操作之前查看发布指南.