我有两个矩阵,一个是通过删除一些行来生成另一个矩阵。例如:
m = matrix(1:18, 6, 3)
m1 = m[c(-1, -3, -6),]
假设我不知道m中哪些行被消除以创建m1,我应该如何通过比较两个矩阵找到它?我想要的结果如下:
1, 3, 6
我正在处理的实际矩阵非常大。我想知道是否有任何有效的方法来进行。
答案 0 :(得分:3)
以下是一些方法:
1)如果我们可以假设m
中没有重复的行 - 问题中的示例就是这种情况 - 那么:
which(tail(!duplicated(rbind(m1, m)), nrow(m)))
## [1] 1 3 6
2)转置m
和m1
提供tm
和tm1
,因为处理列比处理行更有效。
定义match_indexes(i)
,返回向量r,使m[r, ]
中的每一行都匹配m1[i, ]
。
将其应用于1:n1中的每个i并从1:n中删除结果。
n <- nrow(m); n1 <- nrow(m1)
tm <- t(m); tm1 <- t(m1)
match_indexes <- function(i) which(colSums(tm1[, i] == tm) == n1)
setdiff(1:n, unlist(lapply(1:n1, match_indexes)))
## [1] 1 3 6
3)计算每个矩阵的交互向量,然后使用setdiff
和最后match
来获取索引:
i <- interaction(as.data.frame(m))
i1 <- interaction(as.data.frame(m1))
match(setdiff(i, i1), i)
## [1] 1 3 6
已添加如果m
中可能存在重复项,那么(1)和(3)将只返回m
中任何多次出现的行中的第一行而不是m1
1}}。
m <- matrix(1:18, 6, 3)
m1 <- m[c(2, 4, 5),]
m <- rbind(m, m[1:2, ])
# 1
which(tail(!duplicated(rbind(m1, m)), nrow(m)))
## 1 3 6
# 2
n <- nrow(m); n1 <- nrow(m1)
tm <- t(m); tm1 <- t(m1)
match_indexes <- function(i) which(colSums(tm1[, i] == tm) == n1)
setdiff(1:n, unlist(lapply(1:n1, match_indexes)))
## 1 3 6 7
# 3
i <- interaction(as.data.frame(m))
i1 <- interaction(as.data.frame(m1))
match(setdiff(i, i1), i)
## 1 3 6
答案 1 :(得分:2)
一种可能的方法是将每一行表示为字符串:
x1 <- apply(m, 1, paste0, collapse = ';')
x2 <- apply(m1, 1, paste0, collapse = ';')
which(!x1 %in% x2)
# [1] 1 3 6
使用我的解决方案和G. Grothendieck's solutions的大矩阵的一些基准:
set.seed(123)
m <- matrix(rnorm(20000 * 5000), nrow = 20000)
m1 <- m[-sample.int(20000, 1000), ]
system.time({
which(tail(!duplicated(rbind(m1, m)), nrow(m)))
})
# user system elapsed
# 339.888 2.368 342.204
system.time({
x1 <- apply(m, 1, paste0, collapse = ';')
x2 <- apply(m1, 1, paste0, collapse = ';')
which(!x1 %in% x2)
})
# user system elapsed
# 395.428 0.568 395.955
system({
n <- nrow(m); n1 <- nrow(m1)
tm <- t(m); tm1 <- t(m1)
match_indexes <- function(i) which(colSums(tm1[, i] == tm) == n1)
setdiff(1:n, unlist(lapply(1:n1, match_indexes)))
})
# > 15 min, not finish
system({
i <- interaction(as.data.frame(m))
i1 <- interaction(as.data.frame(m1))
match(setdiff(i, i1), i)
})
# run out of memory. My 32G RAM machine crashed.
答案 2 :(得分:1)
我们也可以使用do.call
which(!do.call(paste, as.data.frame(m)) %in% do.call(paste, as.data.frame(m1)))
#[1] 1 3 6