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

时间:2016-11-08 18:38:59

标签: r grep data.table match large-data

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

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

考虑两个不能删除行的示例表:

表1 - ToMach列等于FALSE意味着表2中不存在关联的标记,此步骤减少了要执行的匹配的两个数量级:

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

表2:

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

我的目标是找到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

我的解决方案:

要评估的表1的哪些行

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

汇总表格2中的所有代码。使用ttag_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

您有什么建议可以加快此代码的速度吗?

提前谢谢

2 个答案:

答案 0 :(得分:1)

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

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

返回

表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矢量。代码的“填写”部分与上面的代码相同。

答案 1 :(得分:1)

困难主要在于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')]