匹配data.tables和update data.table

时间:2017-02-27 17:06:45

标签: r data.table

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

我想要做的是找到AREA_CDTYPE中匹配的dt1dt2行,并复制U_ID来自dt2dt1。问题是dt1和dt2没有相同数量的每个唯一组合的实例。例如AREA_CD' A1'和TYPE' 1'在dt1中出现21次,在dt2中出现仅20次。在这些实例中,最小行数(在这种情况下为20)将应用匹配操作,而dt1中的1行未经修改(如果dt2的行数多于dt1,则将使用dt1中的行数。

以下是我的数据集示例。我的实际数据集大约有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"])
}}

我希望这是有道理的。

1 个答案:

答案 0 :(得分:2)

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

如果添加了每个组中的行索引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()创建的,结果证明速度相当慢。