2016-11-08 68 views
0

我在两个不同的表(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 

我的目标是找到表2表1哪里的标签被发现的行(可在以上各列的任何一列中)。我想输出为列表:

输出:

 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 

你有什么建议,以加快这一代码?

预先感谢您

+0

任何好的理由,表1中的重复行?如果您对速度感兴趣,那么这种数据结构决策可能是一个减速带。同样,使用'melt(table2 [,r:= .I],“r”,value.name =“Tag”)可以更好地实现表格2的宽格式存储...... – Frank

+1

@Frank,上表是具有更多字段的较大表格的快照。在现实中,没有行将被复制 –

回答

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')] 
+0

好吧,我研究了你的代码,我想我几乎可以得到它的全部。感谢它非常好。你能否澄清一下_。(list(if(ToMatch)id))_ part是做什么的? –

+0

@GeraldT它创建一个'list'列,其中如果'ToMatch'为'TRUE',则列表的条目是匹配的ID,否则为空 – eddi

+0

@ eddi你知道为什么'on ='Tag''没有工作?从'example(data.table)'看来它应该起作用。非常感谢,我觉得我从你的回答中学到了很多东西。 –

1

这里有一个位的基础R代码将这样的伎俩:

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

返回

table1的

 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载体填充。代码的“填写”部分与上面的代码相同。

+0

感谢您的答案,它的工作原理。但是你的解决方案产生一个字符列而不是列表列:) –

相关问题