为什么data.tables的X [Y]连接不允许完整的外连接或左连接?

这是关于data.table连接语法的一个哲学问题。 我正在为data.tables找到越来越多的用途,但仍然在学习......

data.tables的连接格式X[Y]非常简洁,方便和高效,但据我所知,它只支持内连接和右外连接。 要获得左或全外连接,我需要使用merge

  • X[Y, nomatch = NA] - Y中的所有行 - 右外部X[Y, nomatch = NA] (默认)
  • X[Y, nomatch = 0] - 只有X和Y都有匹配的行 - 内连接
  • merge(X, Y, all = TRUE) - 来自X和Y的所有行 - 完全外连接
  • merge(X, Y, all.x = TRUE) - X中的所有行 - 左外连接
  • 在我看来,如果X[Y]连接格式支持所有4种类型的连接,那将会很方便。 是否有原因只支持两种类型的连接?

    对于我来说, nomatch = 0nomatch = NA参数值对于正在执行的操作并不是非常直观。 我更容易理解和记住merge语法: all = TRUEall.x = TRUEall.y = TRUE 。 由于X[Y]操作类似于merge而不是match ,为什么不使用merge语法来进行连接而不是match函数的nomatch match参数?

    以下是4种连接类型的代码示例:

    # sample X and Y data.tables
    library(data.table)
    X <- data.table(t = 1:4, a = (1:4)^2)
    setkey(X, t)
    X
    #    t  a
    # 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
    #    t  b
    # 1: 3  9
    # 2: 4 16
    # 3: 5 25
    # 4: 6 36
    
    # all rows from Y - right outer join
    X[Y]  # default
    #  t  a  b
    # 1: 3  9  9
    # 2: 4 16 16
    # 3: 5 NA 25
    # 4: 6 NA 36
    
    X[Y, nomatch = NA]  # same as above
    #    t  a  b
    # 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
    #    t  a  b
    # 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]  
    #    t  a  b
    # 1: 3  9  9
    # 2: 4 16 16
    
    merge(X, Y, by = "t")  # same as above
    #    t  a  b
    # 1: 3  9  9
    # 2: 4 16 16
    
    merge(X, Y, by = "t", all = FALSE)  # same as above
    #    t  a  b
    # 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)
    #    t  a  b
    # 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)
    #    t  a  b
    # 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=语法,它允许在主键以外的字段上进行临时连接。 jangorecki对问题的回答如何连接(合并)数据框架(内部,外部,左侧,右侧)? 提供了data.table可以处理的其他连接类型的一些示例。


    引用data.table常见问题解答1.12

    1.12

    X [Y]和merge(X,Y)有什么区别?

  • X[Y]是一个连接,使用Y(或Y的键,如果它有一个)作为索引查找X的行。
  • Y[X]是一个连接,使用X查找Y的行(或X的键,如果它有一个)
  • merge(X,Y)执行两种方式。
  • X[Y]Y[X]的行数通常不同; 而merge(X,Y)merge(Y,X)返回的行数相同。 但错过了主要观点。 加入或合并后,大多数任务都需要对数据执行一些操作。 为什么要合并所有的数据列,只能在事后使用它们的一小部分? 您可能会建议merge(X[,ColsNeeded1],Y[,ColsNeeded2]) ,但需要复制子数据集的副本,并且它要求程序员确定需要哪些列。 data.table中的X[Y,j ]为您完成所有步骤。 当你写X[Y,sum(foo*bar)] ,data.table将自动检查j表达式以查看它使用的列。 它只会对这些列进行分组; 其他人被忽略。 内存仅为j使用的列创建,Y列在每个组的上下文中享受标准R回收规则。 假设foo在X中,而bar在Y中(Y中还有20个其他列)。 是不是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)]]
    ##   t  b  a
    ## 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所说,通过交换YX来获得左/右外部连接: Y[X] -vs- X[Y] 。 所以在这种语法中支持4种连接类型中的3种,而不是2,iiuc。

    添加第4个似乎是一个好主意。 假设我们添加了full=TRUEboth=TRUEmerge=TRUE (不确定最佳参数名称?),那么在X[Y,j,merge=TRUE]之前它没有出现,在FAQ 1.12之后。 现在添加新功能请求并将其链接回来,谢谢:

    FR#2301:为X [Y]和Y [X]连接添加merge = TRUE参数,就像merge()一样。

    最近的版本加快了merge.data.table (例如,通过内部浅拷贝来更有效地设置密钥)。 所以我们试图让merge()X[Y]更接近,并为用户提供所有选项以获得充分的灵活性。 两者都有优点和缺点。 另一个突出的功能要求是:

    FR#2033:将by.x和by.y添加到merge.data.table

    如果有其他人,请保持他们来。

    通过这部分的问题:

    为什么不使用合并语法而不是匹配函数的不匹配参数?

    如果您更喜欢merge()语法及其3个参数allall.xall.y那么只需使用它而不是X[Y] 。 认为它应该涵盖所有的情况。 还是你的意思是为什么的说法单nomatch[.data.table ? 如果是这样,那么FAQ2.14看起来很自然:“你能否进一步解释为什么data.table是基于A [B]语法的启发?”。 而且,不nomatch只有0NA两个值。 这可能会延长,所以负值意味着什么,或者12将意味着使用第12行的值来填充NA,例如,或者将来可能不nomatch可能是矢量,或者甚至本身是data.table

    嗯。 by-without-by如何与merge = TRUE交互? 也许我们应该把这个转到数据表的帮助。


    这个“答案”是一个讨论的建议:正如我的评论所指出的,我建议在[.data.table()中添加一个join参数以启用其他类型的连接,即: X[Y,j,join=string] 。 除了4种常规联接之外,我还建议支持3种类型的联合联接和交叉联接。

    建议各种连接类型的join字符串值(和别名)为:

  • "all.y""right" - 右连接,当前data.table默认值(nomatch = NA) - 所有Y行与NAs没有X匹配;
  • "both""inner" - 内连接(nomatch = 0) - 只有X和Y匹配的行;

  • "all.x""left" - 左连接 - 来自X的所有行,没有Y匹配的NA:

  • "outer""full" - 完整的外连接 - X和Y的所有行,不匹配的NAs

  • "only.x""not.y" - 非连接或反连接返回没有Y匹配的X行

  • "only.y""not.x" - 在没有X匹配的情况下,非连接或反连接返回Y行
  • "not.both" - 独占连接返回与其他表不匹配的X和Y行,即异或(XOR)
  • "cross" - 交叉连接或笛卡尔乘积与X的每一行匹配到Y的每一行
  • 默认值是join="all.y" ,它对应于当前的默认值。

    “all”,“all.x”和“all.y”字符串值对应于merge()参数。 “右”,“左”,“内”和“外”字符串可能更适合SQL用户。

    “both”和“not.both”字符串是我目前最好的建议 - 但是对于内部联接和独占联接,有人可能会有更好的字符串建议。 (我不确定“独占”是否是正确的术语,如果有适合“异或”连接的术语,请纠正我。)

    使用join="not.y"X[-Y,j]X[!Y,j]非连接语法的替代方法,对我来说可能更清晰,尽管我不确定它们是否是相同(data.table版本1.8.3中的新功能)。

    交叉连接有时可能非常方便,但它可能不适合data.table范例。

    链接地址: http://www.djcxy.com/p/24917.html

    上一篇: Why does X[Y] join of data.tables not allow a full outer join, or a left join?

    下一篇: LEFT OUTER JOIN in LINQ