当前位置: 首页 > 知识库问答 >
问题:

哪些行/列是R矩阵中其他行/列的重复?

南门嘉
2023-03-14

我有一个矩阵,有很多行和列

x <- matrix(c(1, 1, 3, 3, 55, 55, 1, 3, 3, 1,
              1, 1, 3, 3, 55, 55, 1, 3, 9, 1), ncol = 2)

使用

x[!duplicated(x, MARGIN = 1), ]

我想确定原始矩阵中每一行的第一次出现:这里有向量

1 1 3 3 5 5 1 3 9 1

我想出的最好的方法是使用既不高效也不优雅的循环的复杂和迂回的方法。我也知道data.frames的可能解决方案;那些涉及将行连接到字符串中的解决方案也是相当资源密集型的。

有没有使用基本R的优雅解决方案?

# Identify duplicates
duplicate <- duplicated(x, MARGIN = 1)

# Identify first occurrence of each duplicate
firstDup <- duplicated(x, MARGIN = 1, fromLast = TRUE) & !duplicate
indices <- which(firstDup)

# Initialize index for unique rows
index <- seq_len(dim(x)[1])

cf <- duplicate
for (i in indices) {
  # Duplicates must occur after first occurrence
  cf[seq_len(i)] <- FALSE
  dups <- apply(x[cf, , drop = FALSE], 1L, identical, x[i, ])
  index[which(cf)[dups]] <- i
}
index

共有3个答案

顾曾笑
2023-03-14

@MikaelJagan的答案基于asplit匹配(

列表匹配可能非常缓慢,最好避免,除非是在简单的情况下。

在这里,我们比较了他们的asplit答案与其他基本R答案的性能:

  • @Onyanbu的答案基于粘贴
  • @汤玛西斯科的答案基于互动

作为比较点,我们将这些与两个非基准R答案一起进行基准测试(认识到OP只要求基准R):

  • @MikaelJagan的Rcpp答案,与其他答案不同之处在于避免了矩阵x的副本
library("microbenchmark")
library("data.table")
data.table 1.14.2 using 4 threads (see ?getDTthreads).  Latest news: r-datatable.com
f_asplit <- function(x) {
  l <- asplit(x, 1L)
  match(l, l)
}
f_paste <- function(x) {
  s <- do.call(paste, as.data.frame(x))
  match(s, s)
}
f_interaction1 <- function(x) {
  z <- as.integer(interaction(as.data.frame(x)))
  ave(seq_along(z), z, FUN = function(x) x[1L])
}
f_interaction2 <- function(x) {
  z <- as.integer(interaction(as.data.frame(x)))
  match(z, z)
}
f_join <- function(x) {
  d <- as.data.table(x)
  d[d, on = names(d), mult = "first", which = TRUE]
}
Rcpp::sourceCpp('<copy source code from @MikaelJagan\'s answer here>')

bm <- function(x, times) {
  microbenchmark(
    f_asplit(x), 
    f_paste(x), 
    f_interaction1(x), 
    f_interaction2(x),
    f_join(x),
    match_row(x),
    times = times,
    check = "identical",
    setup = gc(FALSE)
  )
}

我们首先评估了5e 06-by-2整数矩阵的性能:

set.seed(1L)
x <- matrix(sample(10L, size = 1e+07L, replace = TRUE), ncol = 2L)
bm(x, times = 10L)
Unit: milliseconds
              expr        min         lq       mean     median         uq        max neval
       f_asplit(x) 16637.5798 18733.3617 19013.3497 18782.1677 18838.6351 23053.6849    10
        f_paste(x)   504.7293   506.9240   508.1568   507.4751   509.3188   512.8925    10
 f_interaction1(x)   403.5811   406.8908   412.0491   408.4909   409.9671   431.4656    10
 f_interaction2(x)   233.4562   234.1044   241.6112   235.8503   236.9662   295.3077    10
         f_join(x)   114.2941   114.6058   117.4835   115.3864   119.4647   128.0236    10
      match_row(x)   460.6730   464.8487   467.1219   467.5593   469.2787   472.8399    10

基于asplit的答案确实比基本R选项慢了很多。基于交互的答案是快速的(使用匹配比使用ave更快),甚至可以与使用data.table和4个OpenMP线程的答案相媲美,这是最快的。

上述结果不能推广到所有矩阵输入,部分原因是基于交互作用的函数与ncol(x)的伸缩性较差:如果x的每列都有u唯一元素,则可能的交互作用数为u^ncol(x)。基于paste的函数似乎更健壮。

在第二组计时中,我们使用了行数较少(5e 05)列数较多(20)的矩阵。在使用“简单”系统的初始运行中。时间f_交互1f_交互2均出错:

set.seed(1L)
x <- matrix(sample(10L, size = 1e+07L, replace = TRUE), ncol = 20L)
system.time(f_interaction1(x))
# Error: cannot allocate vector of size 7.5 Gb
# Timing stopped at: 328.8 29.05 379.9

system.time(f_interaction2(x))
# Error: cannot allocate vector of size 7.5 Gb
# Timing stopped at: 173.2 6.05 200.4

其余函数都可以处理5e 05-by-20整数矩阵,并使用microbenchmark进行进一步评估:

microbenchmark(
    f_asplit(x), 
    f_paste(x), 
    f_join(x),
    match_row(x),
    times = 10L,
    check = "identical",
    setup = gc(FALSE)
  )

# still running...

袁泰平
2023-03-14

如果你有大矩阵,那么下面的解决方案可能就足够了:

l <- do.call(paste, data.frame(x))
match(l, l)
[1] 1 1 3 3 5 5 1 3 9 1
权承
2023-03-14

这个怎么样?

l <- asplit(x, 1L)
match(l, l)
 [1] 1 1 3 3 5 5 1 3 9 1

这里,我们使用asplit获取x行的列表l,并使用match获取每行第一次出现的索引。

 类似资料:
  • 为了简单起见,我将column称为col。为什么矩阵是[行,列]而不是[列,行]?这给我带来了很多头痛和困惑。 我的思路是这样的:1.一个正则数组, 就像一个矩阵,有一行和多列。它的符号是这样的:啊,如果我们有另一个维度, 现在有行了。因此,让我们在'n',arr[n,rows]之后记下这些行,但现实告诉我们,情况并非如此。 对不起,如果我混淆了你,对不起我的无知。

  • 中的值匹配功能非常有用。但据我理解,它不足以支持二维或高维输入。 例如,假设和是相同列数的矩阵,我想将的行与的行进行匹配。“R”函数调用不这样做。列表的输入也存在同样的不足。 我已经实现了我自己的版本,名为(附在下面),但我想知道您对此任务的解决方案是什么。

  • 我有两个列表,每个列表中有两个矩阵。。是否有一种方法可以对它们进行矩阵计算,即相加,其中matrix1中的蓝色矩阵与matrix2中的蓝色矩阵相加,matrix1中的红色矩阵与matrix2中的红色矩阵相加。我能想到的唯一方法是在循环中进行计算 请注意,我将有大约10个,以及不止一组(即蓝色、红色、绿色、紫色)

  • 我不是高级R用户。我主要用它来进行矩阵代数计算。我有一个大矩阵(9400×9400;675.1MB),我想反转。我尝试了“解决”函数和“胆量2inv”,我得到了“错误在......‘a’一定是一个复杂的矩阵”。我也尝试了从MASS包的ginv函数,我得到了错误消息在svd(X)错误:无限或丢失值在'x'。我确信我的矩阵没有空(全零)列或行。我检查了使用:从数据框中删除具有零值的列,我得到了相同的矩

  • 我正在实现一个稀疏矩阵类,使用映射向量来存储数据(映射表示矩阵的一行,其中键是列的索引,值是该位置的maitrix的值)我已经编写了计算行列式的函数,但我不知道是否有一种方法可以计算这种节省的时间(因为矩阵是稀疏的,大多数值为零)在这里我的实现: 这是类接口 我计算行列式的方式是什么?假设运算符()以这种方式重载 提前感谢您的帮助

  • 我有一个非常大的100000左右的平方矩阵,我想知道这个矩阵的行列式值是否为零。 最快的方法是什么? 我必须在C中实现它