【问题标题】:Matching unique and non-unique values between data.tables and update data.table匹配 data.tables 和更新 data.table 之间的唯一值和非唯一值
【发布时间】:2017-02-27 17:06:44
【问题描述】:

我一直致力于根据唯一值和非唯一值在两个大型数据表(每个大约 2500 万条记录)之间匹配值。我昨天发布了一个问题on how to update values in a data.table using another data.table,答案让我想知道如何提高这种匹配的效率。在我的示例中,dt1 包含一个非唯一的区号和一个可以从 1 到 10 的类型(以及一些空白列)。 dt2 包含相同的非唯一区号(尽管与dt1 中的数字不同)、从 1 到 10 的类型和唯一 ID (U_ID)。

我想做的是在dt1dt2 中找到匹配的AREA_CDTYPE 行,并将这些行的U_IDdt2 复制到dt1。问题是 dt1 和 dt2 每个唯一组合的实例数量不同。例如 AREA_CD 'A1' 和 TYPE '1' 在 dt1 中出现 21 次,而在 dt2 中仅出现 20 次。在这些情况下,最小行数(在这种情况下为 20)将应用匹配操作,使 dt1 中的 1 行保持不变(如果 dt2 的行数多于 dt1,则 @987654340 中的行数@ 将被使用)。

这是我的数据集的一个示例。我的实际数据集有大约 25,000,000 行,包含大约 10,000 个独特的区域和从 1 到 10 的类型。

require("data.table")

df1 <-data.frame(AREA_CD = c(rep("A1", 205), rep("A2", 145), rep("A3", 250), rep("A4", 100), rep("A5", 300)), TYPE = rep(1:10), ALLOCATED = 0, U_ID = 0, ID_CD = c(1:1000))
df1$ID_CD <- interaction( "ID", df1$ID_CD, sep = "")

df2 <-data.frame(U_ID = c(1:1000), AREA_CD = c(rep("A1", 200), rep("A2", 155), rep("A3", 245), rep("A4", 90), rep("A5", 310)), TYPE = rep(1:10), ASSIGNED = 0)
df2$U_ID <- interaction( "U", df2$U_ID, sep = "")

dt1 <- as.data.table(df1)
dt2 <- as.data.table(df2)

我正在寻找的输出看起来像这样:

for(o in 1:5){
Ao <- paste("A",o,sep="")
for(i in 1:10){
R.Num <- min(nrow(with(df1, df1[AREA_CD == Ao & TYPE == i ,])), nrow(with(df2, df2[AREA_CD == Ao & TYPE == i ,])))
df1[df1$AREA_CD == Ao & df1$TYPE == i,][1:R.Num,"U_ID"]  <- as.character(df2[df2$AREA_CD == Ao & df2$TYPE == i,][1:R.Num,"U_ID"])
}}

我希望这是有道理的。

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    对于每组AREA_CDTYPE,OP 希望按照它们在两个 data.tables 中出现的顺序一对一匹配行。例如,dt1 中带有AREA_CD == "A1" &amp; TYPE == 1 的第一行应匹配dt2 中带有AREA_CD == "A1" &amp; TYPE == 1 的第一行,然后是第二行,依此类推。

    如果在每个组中添加行索引I(或运行计数),则可以在连接操作中完成此操作:

    # add row indices
    dt1[, I := seq_len(.N), by = .(AREA_CD, TYPE)]
    dt2[, I := seq_len(.N), by = .(AREA_CD, TYPE)]
    
    # alternative code: same result as above but more concise
    dt1[, I := rowid(AREA_CD, TYPE)]
    dt2[, I := rowid(AREA_CD, TYPE)]
    
    
    # right join (all rows of dt1 are used)
    dt0 <- dt2[dt1, on = .(AREA_CD, TYPE, I)]
    
    # show result for one group
    dt0[AREA_CD == "A1" & TYPE == 1, ]
    #    U_ID AREA_CD TYPE ASSIGNED  I ALLOCATED i.U_ID ID_CD
    # 1:   U1      A1    1        0  1         0      0   ID1
    # 2:  U11      A1    1        0  2         0      0  ID11
    # 3:  U21      A1    1        0  3         0      0  ID21
    #...
    #19: U181      A1    1        0 19         0      0 ID181
    #20: U191      A1    1        0 20         0      0 ID191
    #21:   NA      A1    1       NA 21         0      0 ID201
    

    请注意,最后一行在某些列中有 NA。这是因为dt1dt2 中该组的行数不同。 dt1 有 21 行,而 dt2 只有 20 行。所以,dt1 的最后一行在dt2 中没有匹配项。

    或者,内连接只会返回在dt1dt2 中都匹配的行:

    # inner join
    dt0 <- dt2[dt1, on = .(AREA_CD, TYPE, I), nomatch = 0]
    
    # show result for one group
    dt0[AREA_CD == "A1" & TYPE == 1, ]
    #    U_ID AREA_CD TYPE ASSIGNED  I ALLOCATED i.U_ID ID_CD
    # 1:   U1      A1    1        0  1         0      0   ID1
    # 2:  U11      A1    1        0  2         0      0  ID11
    # 3:  U21      A1    1        0  3         0      0  ID21
    #...
    #18: U171      A1    1        0 18         0      0 ID171
    #19: U181      A1    1        0 19         0      0 ID181
    #20: U191      A1    1        0 20         0      0 ID191
    

    现在,该组只返回 20 行。


    数据

    dt1 <- data.table(
      AREA_CD = factor(c(rep("A1", 205), rep("A2", 145), rep("A3", 250), rep("A4", 100), rep("A5", 300))), 
      TYPE = rep(1:10), 
      ALLOCATED = 0, 
      U_ID = 0, 
      ID_CD = factor(paste0("ID", 1:1000)))
    dt2 <- data.table(
      U_ID = factor(paste0("U", 1:1000)), 
      AREA_CD = factor(c(rep("A1", 200), rep("A2", 155), rep("A3", 245), rep("A4", 90), rep("A5", 310))), 
      TYPE = rep(1:10), 
      ASSIGNED = 0)
    

    请注意,ID_CDU_ID 是使用 paste0() 而不是 interaction() 创建的,这被证明是相当慢的。

    【讨论】:

    • I := seq_len(.N), by = .(AREA_CD, TYPE) 应该和I := rowid(AREA_CD, TYPE) 一样,我猜。
    • @Frank 是的,你的权利。 ?rowid 表示它旨在用于交互使用。所以,我决定留在.Nby =。也许,使用rowid() 的代码看起来会更聪明一点?编辑于。
    • @UweBlock 感谢您的回答。它工作得很好,完全符合我的需要。
    猜你喜欢
    • 1970-01-01
    • 2023-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多