代码之家  ›  专栏  ›  技术社区  ›  s_baldur

左联接(一列)首选哪个data.table语法

  •  3
  • s_baldur  · 技术社区  · 6 年前

    我应该如何开始考虑我喜欢哪种语法?

    我的标准是效率(这是第一个)和可读性/可维护性。

    这个

    A <- B[A, on = .(id)] # wow such. concision
    

    或者那个

    A[B, on = .(id), comment := i.comment]
    

    甚至(正如Pogibas所暗示的那样):

    A <- merge(A, B, all.x = TRUE)
    

    为了完整性,一个更基本的方法是使用 match() :

    A[, comment := B[chmatch(A[["id"]], id), comment]]
    

    实例数据:

    library(data.table)
    A <- data.table(id = letters[1:10], amount = rnorm(10)^2)
    B <- data.table(id = c("c", "d", "e"), comment = c("big", "slow", "nice"))
    
    1 回复  |  直到 6 年前
        1
  •  9
  •   Frank    6 年前

    为了提高效率和可维护性,我更喜欢“更新连接”习惯用法:**

    DT[WHERE, v := FROM[.SD, on=, x.v]]
    

    它是对所示内容的扩展 vignette("datatable-reference-semantics") 在“通过引用更新一些列行”下- 子赋值 通过引用“。一旦连接上有一个小片段可用,这也应该是一个很好的参考。

    这是有效的,因为它只使用 WHERE 并在适当位置修改或添加列,而不是像更简洁的左联接那样创建新表。 FROM[DT, on=] .

    它使我的代码更具可读性,因为我可以很容易地看到连接点是添加列 v ;我不必考虑SQL中的“左/右”行话,也不必考虑连接后是否保留行数。

    它对于代码维护很有用,因为如果以后我想了解 DT 有一列名为 V ,我可以搜索我的代码 v := ,同时 从[dt,on = ] 隐藏要添加的新列。此外,它还允许 哪里 条件,而左联接没有。例如,如果 using FROM to "fill" NAs in an existing column v .


    与其他更新连接方法相比 DT[FROM, on=, v := i.v] 我可以想到两个优点。首先是使用 哪里 子句,第二个是在联接出现问题时通过警告实现透明性,如中的重复匹配 条件是 on= 规则。下面是一个扩展操作示例的示例:

    library(data.table)
    A <- data.table(id = letters[1:10], amount = rnorm(10)^2)
    B2 <- data.table(
      id = c("c", "d", "e", "e"), 
      ord = 1:4, 
      comment = c("big", "slow", "nice", "nooice")
    )
    
    # left-joiny update
    A[B2, on=.(id), comment := i.comment, verbose=TRUE]
    # Calculated ad hoc index in 0.000s elapsed (0.000s cpu) 
    # Starting bmerge ...done in 0.000s elapsed (0.000s cpu) 
    # Detected that j uses these columns: comment,i.comment 
    # Assigning to 4 row subset of 10 rows
    
    # my preferred update
    A[, comment2 := B2[A, on=.(id), x.comment]]
    # Warning message:
    # In `[.data.table`(A, , `:=`(comment2, B2[A, on = .(id), x.comment])) :
    #   Supplied 11 items to be assigned to 10 items of column 'comment2' (1 unused)
    
        id     amount comment comment2
     1:  a 0.20000990    <NA>     <NA>
     2:  b 1.42146573    <NA>     <NA>
     3:  c 0.73047544     big      big
     4:  d 0.04128676    slow     slow
     5:  e 0.82195377  nooice     nice
     6:  f 0.39013550    <NA>   nooice
     7:  g 0.27019768    <NA>     <NA>
     8:  h 0.36017876    <NA>     <NA>
     9:  i 1.81865721    <NA>     <NA>
    10:  j 4.86711754    <NA>     <NA>
    

    在左侧的join-flavered更新中,您将静默获取 comment 即使有两场比赛 id == "e" ;在其他更新中,您会收到一条有用的警告消息(升级到 an error in a future release )甚至打开 verbose=TRUE 使用左边的joini方法并不能提供信息——它说有四行被更新了,但没有说一行被更新了两次。


    我发现当我的数据被安排到一组整洁的/关系表中时,这种方法最有效。一个很好的参考是 Hadley Wickham's paper .

    **在这个成语中, on = 部分应该用连接列名称和规则来填充,比如 on=.(id) on=.(from_date >= dt_date) . 可以通过 roll= , mult= nomatch= . 见 ?data.table 详情。感谢@ryoda在评论中注意到这一点。