如何从列表中删除矩阵,这些矩阵在浮点误差范围内是重复的?

5
这个问题类似于其他语言中的浮点误差问题(例如这里),然而我没有找到一个令人满意的解决方案。
我正在研究一些共享某些特征的矩阵的项目。作为其中的一部分,我需要知道列表中有多少个矩阵是唯一的。
 D <- as.matrix(read.table("datasource",...))
 mat_list <- vector('list',length=length(samples_list))
 mat_list <- lapply(1:length(samples_list),function(i) matrix(data=0,nrow(D),ncol(D)))

此列表由基于samples_list元素的数据计算生成。在mat_list被填充后,我需要去除重复项。运行

mat_list <- unique(mat_list)

这样可以缩小许多范围;但是,其中许多元素实际上在机器误差范围内。函数unique不允许指定精度,并且我无法找到可修改的源代码。

我有一个想法:

ErrorReduction<-function(mat_list, tol=2){
  len <- length(mat_list)
  diff <- mat_list[[i]]-mat_list[[i+1]]
  for(i in 1:len-1){
     if(norm(diff,"i")<tol){
     mat_list[[i+1]] <- mat_list[i]
     }
  }
  mat_list<-unique(mat_list)
  return(mat_list)
}

但这仅考虑了成对差异。使用嵌套的for循环进行操作可能会很简单,但很可能效率低下。

您知道哪些方法或者有什么想法来解决识别和删除与机器误差接近的重复矩阵的问题吗?


你能否举出一些您认为答案是“相等”和“不相等”的例子,并说明原因?目前只有您有“数据源”。我们鼓励使用dput(mat) - IRTFM
2个回答

6

这里有一个函数,它使用outerall.equal应用于每对,并删除所有重复项:

approx.unique <- function(l) {
   is.equal.fun <- function(i, j)isTRUE(all.equal(norm(l[[i]] - l[[j]], "M"), 0))
   is.equal.mat <- outer(seq_along(l), seq_along(l), Vectorize(is.equal.fun))
   is.duplicate <- colSums(is.equal.mat * upper.tri(is.equal.mat)) > 0
   l[!is.duplicate]
}

一个例子:
a <- matrix(runif(12), 4, 3)
b <- matrix(runif(12), 4, 3)
c <- matrix(runif(12), 4, 3)

all <- list(a1 = a, b1 = b, a2 = a, a3 = a, b2 = b, c1 = c)

names(approx.unique(all))
# [1] "a1" "b1" "c1"

这是一种有趣的方法,我不知道all.equal函数。它似乎会使用大量内存:尝试在360x300维度的矩阵集上使用它,你就会明白我的意思。例如:M1 <- matrix(data=0,nrow=360, ncol=300); M2 <- M1 + rep(1e-17,300); all <- list(M1,M2); all <- rep(all,30)这应该识别它们都是零矩阵,但我的12Gb RAM计算机无法处理它。 - Daniel Watkins
@D_Watkins,我稍微编辑了我的答案。这个改变应该更好地利用了内存。 - flodel
为什么不直接使用 is.equal.fun <- function(i, j) all.equal(norm(l[[i]] - l[[j]], "M"), 0) 呢? - Rcoster
你需要将其包装在 isTRUE 中,参见 ?all.equal。看看 all.equal(1, 2) 的输出... - flodel

1

我相信您正在寻找all.equal,它可以比较对象“在机器误差范围内”。请查看?all.equal


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接