我一直致力于根据唯一和非唯一值匹配两个大型数据表(每个大约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_CD
和TYPE
中匹配的dt1
和dt2
行,并复制U_ID
来自dt2
到dt1
。问题是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"])
}}
我希望这是有道理的。
答案 0 :(得分:2)
对于AREA_CD
和TYPE
的每个组,OP希望按照它们在data.tables中出现的顺序一对一地匹配行。例如,AREA_CD == "A1" & TYPE == 1
中dt1
的第一行应与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
。这是因为dt1
和dt2
中该组的行数不同。 dt1
有21行,而dt2
只有20行。因此,dt1
的最后一行与dt2
中没有匹配。
或者,内部联接只返回dt1
和dt2
中匹配的行:
# 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_CD
和U_ID
是使用paste0()
而不是interaction()
创建的,结果证明速度相当慢。