data.table笛卡尔加入合法连接的警告

时间:2014-12-21 06:39:56

标签: r join data.table cartesian-product

我很抱歉提前发帖混淆了几个问题。如果不合适,请编辑或建议我应该做什么。我正在练习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成员。

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:5)

问题1:

看起来很棒!但是内部联接的等价物也是添加nomatch=0L。否则,您还会获得dtMoveB的所有行。我们无法在此使用by=.EACHI AFAICT。

阅读this answerthe 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列,其中jx共享列名称表单ix[i, j]

的操作

加入时,您可以将名称更改为您喜欢的任何名称。在这里,您可以使用:

更改为x[i, j, by=.EACHI]position.x
position.y

HTH


PS:如果您有任何建议,请随时添加FR here。请在执行此操作之前查看the posting guidelines