我在两个不同的表(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中的所有代码。使用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
您有什么建议可以加快此代码的速度吗?
提前谢谢
答案 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')]