大数据在不同行和列中的多个匹配

Multiple matches in different row and columns for large data

我在两个不同的 table 中遇到多个匹配问题(100 万行 * 15;3000 * 20)可能会变得更大(1000 万行)。

我的解决方案有效,但我想尽可能快地制作脚本,因为我可能必须将它用于更大的数据帧。我正在使用 r 包 data.table.

考虑两个无法删除行的示例 table:

table 1 - ToMach 列等于 FALSE 表示关联标签不存在于 table2 中,此步骤将要执行的匹配减少两个数量级:

set.seed(99)
table1 <- data.table(Tag = sample(paste0("tag_",1:3), 5, replace = T))
table1[ , ToMatch := ifelse(Tag == "tag_1", F, T)]

table1
     Tag ToMatch
1: tag_2    TRUE
2: tag_1   FALSE
3: tag_3    TRUE
4: tag_3    TRUE
5: tag_2    TRUE

table2:

set.seed(99)
table2 <- data.table(center = sample(paste0("tag_",2:8), 5, replace = T),
                 north  = sample(paste0("tag_",2:8), 5, replace = T),
                 south  = sample(paste0("tag_",2:8), 5, replace = T))

> table2
   center north south
1:  tag_6 tag_8 tag_5
2:  tag_2 tag_6 tag_5
3:  tag_6 tag_4 tag_3
4:  tag_8 tag_4 tag_6
5:  tag_5 tag_3 tag_6

我的objective是在table2中找到table1的标签所在的行(可以在以上各列的任意一列)。我将输出视为列表:

输出:

     Tag ToMatch output
1: tag_2    TRUE      2
2: tag_1   FALSE     NA
3: tag_3    TRUE    3,5
4: tag_3    TRUE    3,5
5: tag_2    TRUE      2

我的解决方案:

要评估 table 1 的哪些行

match.index <- which(table1$ToMatch == T)
> match.index
[1] 1 3 4 5

汇集来自 table 的所有标签 2. 使用 t (tag_6 tag_8 tag_5 tag_2 tag_6 tag_5 ...)

维护行顺序
all.tags <- as.vector(t(table2))
> all.tags
 [1] "tag_6" "tag_8" "tag_5" "tag_2" "tag_6" "tag_5" "tag_6"
 [8] "tag_4" "tag_3" "tag_8" "tag_4" "tag_6" "tag_5" "tag_3"
[15] "tag_6"

预定义一个空列表

list.results <- as.list(rep(as.numeric(NA), dim(table1)[1]))

循环:

for (i in 1:length(match.index)) {

    list.results[[ match.index[i] ]] <- ceiling(

        grep(table1[match.index[i], Tag], all.tags) 

        /3) 
}

# dividing the index of all.tags found with grep by 3 (the original
# number of columns in table2) and rounding up to the closest integer 
# (ceiling) return the index of the original table 2 where the tag 
# is located

最终输出:

> table1[ , output := list.results]
> table1
     Tag ToMatch output
1: tag_2    TRUE      2
2: tag_1   FALSE     NA
3: tag_3    TRUE    3,5
4: tag_3    TRUE    3,5
5: tag_2    TRUE      2

您对加快此代码有什么建议吗?

提前致谢

这里有一些基本的 R 代码可以解决这个问题:

table1 <- within(table1, {
                 output <- NA
                 output[ToMatch] <- sapply(Tag[ToMatch], function(x) 
                                   paste(which(x == table2, arr.ind=TRUE)[,1], collapse=","))
})

哪个returns

表 1

     Tag ToMatch output
1: tag_2    TRUE      2
2: tag_1   FALSE     NA
3: tag_3    TRUE    5,3
4: tag_3    TRUE    5,3
5: tag_2    TRUE      2

这是一个简短的描述。 within 允许在对象(通常是数据框)内引用并减少了一些输入的需要。首先,分配输出 NA。然后,对于要匹配的输出的每个元素(使用 ToMatch),使用 which 和 arr.ind=TRUE 参数找到匹配每个元素的行。 paste 每个元素的结果合并到“,”上。


上面代码的data.table模拟是

table1[, output := NA_character_][as.logical(ToMatch), 
       output := sapply(Tag, function(x) paste(which(x == table2, arr.ind=TRUE)[,1],
                                               collapse=","))][]
     Tag ToMatch output
1: tag_2    TRUE      2
2: tag_1   FALSE     NA
3: tag_3    TRUE    5,3
4: tag_3    TRUE    5,3
5: tag_2    TRUE      2

第一个 [] 为感兴趣的元素创建 NA 向量和第二个子集,并用所需值填充 NA 向量。此 "filling in" 部分代码与上面的代码相同。

难点主要在于table2的广泛代表性。一旦它被融化,剩下的就很简单了:

melt(table2[, id := .I], id = 'id')[
  table1, on = c(value = 'Tag'), .(list(if(ToMatch) id)), by = .EACHI]
#   value   V1
#1: tag_2    2
#2: tag_1 NULL
#3: tag_3  5,3
#4: tag_3  5,3
#5: tag_2    2

如果您有很多重复项 - 事先将您的数据唯一化:

melt(table2[, id := .I], id = 'id')[
  unique(table1), on = c(value = 'Tag'), .(list(if(ToMatch) id)), by = .EACHI][
  table1, on = c(value = 'Tag')]