data.table 对于关系表来说很快,但基本的matrix 真的很快。我的建议是将表格存储为矩阵并使用更简单的子集来比较子矩阵。
从一些示例数据开始:bigmat 是我们将在其中寻找匹配项的大矩阵,smallmat_in 是 bigmat 的子矩阵,smallmat_out 是不在 bigmat 内部的矩阵。
bigmat <- matrix(c(1:50, 1:50), nrow = 10)
smallmat_in <- bigmat[6:8, 2:3]
smallmat_out <- smallmat_in
smallmat_out[6] <- 0
bigmat
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,] 1 11 21 31 41 1 11 21 31 41
# [2,] 2 12 22 32 42 2 12 22 32 42
# [3,] 3 13 23 33 43 3 13 23 33 43
# [4,] 4 14 24 34 44 4 14 24 34 44
# [5,] 5 15 25 35 45 5 15 25 35 45
# [6,] 6 16 26 36 46 6 16 26 36 46
# [7,] 7 17 27 37 47 7 17 27 37 47
# [8,] 8 18 28 38 48 8 18 28 38 48
# [9,] 9 19 29 39 49 9 19 29 39 49
# [10,] 10 20 30 40 50 10 20 30 40 50
smallmat_in
# [,1] [,2]
# [1,] 16 26
# [2,] 17 27
# [3,] 18 28
smallmat_out
# [,1] [,2]
# [1,] 16 26
# [2,] 17 27
# [3,] 18 0
我们可以快速找到bigmat 的哪些元素可以是匹配子矩阵的左上角,而不是尝试遍历bigmat 的每个可能的3x2 子矩阵。
index_matching_first <- function(small, big) {
max_big_row <- nrow(big) - nrow(small) + 1
max_big_col <- ncol(big) - ncol(small) + 1
valid_rows <- seq_len(max_big_row)
valid_cols <- seq_len(max_big_col)
which(big[valid_rows, valid_cols] == small[[1]], arr.ind = TRUE)
}
index_matching_first(smallmat_in, bigmat)
# row col
# [1,] 6 2
# [2,] 6 7
index_matching_first(smallmat_out, bigmat)
# row col
# [1,] 6 2
# [2,] 6 7
smallmat_in 和 smallmat_out 仅在最后一个元素上有所不同,因此它们的第一个元素具有相同的匹配项。接下来,我们将定义一个函数,该函数接受一个小矩阵 (small)、一个大矩阵 (big) 和一个行列对 (big_first_index)。如果行-列对是与small 匹配的big 子矩阵的左上角,则返回TRUE。否则,FALSE。
is_matrix_match <- function(small, big, big_first_index) {
row_indices <- seq(big_first_index[1], by = 1, length.out = nrow(small))
col_indices <- seq(big_first_index[2], by = 1, length.out = ncol(small))
all(small == big[row_indices, col_indices])
}
is_matrix_match(smallmat_in, bigmat, c(6, 2))
# [1] TRUE
is_matrix_match(smallmat_out, bigmat, c(6, 2))
# [1] FALSE
所以当我们给它一个行-列对时,这很有效。我们现在可以在index_matching_first(...) 的输出上迭代地应用这个函数,看看是否找到任何匹配项。
in_matrix <- function(small, big) {
first_matches <- index_matching_first(small, big)
is_same <- apply(
first_matches,
MARGIN = 1,
FUN = is_matrix_match,
small = small,
big = big
)
any(is_same)
}
in_matrix(smallmat_in, bigmat)
# [1] TRUE
in_matrix(smallmat_out, bigmat)
# [1] FALSE
因为这是一个概念验证,所以它没有任何检查(比如确保big 实际上大于small)。这些在生产环境中会很好。
我不知道您正在使用多大的矩阵,但这里是我对更大矩阵的一些速度测量:
hugemat <- matrix(rep_len(1:7, 1e7), nrow = 10)
format(object.size(hugemat), "MB")
# [1] "38.1 Mb"
huge_submat <- hugemat[2:9, 200:300]
huge_not_submat <- huge_submat
huge_not_submat[] <- 1
system.time(in_matrix(huge_submat, hugemat))
# user system elapsed
# 10.51 0.00 10.53
system.time(in_matrix(huge_not_submat, hugemat))
# user system elapsed
# 10.62 0.00 10.69