减去所有向量对。

4

我有一个大小为2000 X 700的矩阵。 我想要减去所有可能的行对。 如果x_i代表一行,那么我想要计算:x_1-x_2, x_1-x_3, ..., x_2-x_3,...

例如:

mat 
1 2 3
5 3 2
1 1 6

我的输出应该是

x_1 - x_2: -4 -1  1
x_1 - x_3:  0  1 -3
x_2 - x_3:  4  2 -4

我尝试使用循环,但是太慢了。 有没有一种更有效的计算方法?


1
如果您提供一个简单的可重现示例,其中包含样本输入和期望输出,那么我们更容易帮助您测试和验证可能的解决方案。 - MrFlick
这些并不是所有可能的行对,只有一半。您如何定义所需的行对及其顺序?(例如,您似乎想要row1-row2而不是row2-row1) - Ottie
3个回答

3

或许使用combn

combn(row.names(m1), 2, function(x) m1[x[1],] - m1[x[2],])

它能工作,但对于我的数据大小来说仍然太慢了。那样需要几个小时。 - ari6739
@ari6739 combnexpand.gridexpand_gridouter更快,因为后者会进行两倍数量的比较。 - akrun
@ari6739 你可以尝试这个更快的选项。 - akrun

1
一个相对较快的方法是预先定义一个索引列表,然后在数据上使用它,并将其设为data.table。对于一个2000 x 700的矩阵,整个操作应该在一分钟内完成。
library(data.table)

setDT(mat)

rows <- nrow(mat)
idx <- as.matrix(rbindlist(lapply(1:(rows - 1), function(x) 
  rbindlist(lapply((x + 1):rows, function(y) list(x, y)))))) # takes approx. 6 secs on my crappy system for 2000 x 2000 combinations
idx
     V1 V2
[1,]  1  2
[2,]  1  3
[3,]  2  3

mat[idx[, 1], ] - mat[idx[, 2], ] # takes approx. 12 secs for 700 columns, see below if there's a memory error "Error: vector memory exhausted (limit reached?)"
   V1 V2 V3
1: -4 -1  1
2:  0  1 -3
3:  4  2 -4

如果数据非常宽,由于矢量化的特性,减法操作可能无法适应内存。解决方案是通过循环索引将操作分成较小的块,例如:
rbindlist(apply(
  cbind(unique(floor(c(1, seq(1, nrow(idx), length.out=10)[2:9] + 1))), 
        unique(floor(seq(1, nrow(idx), length.out=10)[2:10]))), 1, function(x)
  mat[idx[x[1]:x[2], 1],] - mat[idx[x[1]:x[2], 2],]))
         V1 V2 V3 V1 V2 V3 V1 V2 V3 V1
      1: -4 -1  1 -4 -1  1 -4 -1  1 -4
      2:  0  1 -3  0  1 -3  0  1 -3  0
      3:  0  0  0  0  0  0  0  0  0  0
      4: -4 -1  1 -4 -1  1 -4 -1  1 -4
      5:  0  1 -3  0  1 -3  0  1 -3  0
     ---                              
1998996:  4  1 -1  4  1 -1  4  1 -1  4
1998997:  0  0  0  0  0  0  0  0  0  0
1998998:  0 -1  3  0 -1  3  0 -1  3  0
1998999: -4 -2  4 -4 -2  4 -4 -2  4 -4
1999000: -4 -1  1 -4 -1  1 -4 -1  1 -4

数据

mat <- structure(list(V1 = c(1L, 5L, 1L), V2 = c(2L, 3L, 1L), V3 = c(3L, 
2L, 6L)), class = "data.frame", row.names = c(NA, -3L))

0
另外一个使用 combn (以及 asplit) 的用途是:
> t(combn(asplit(mat, 1), 2, function(x) do.call(`-`, x)))
     [,1] [,2] [,3]
[1,]   -4   -1    1
[2,]    0    1   -3
[3,]    4    2   -4

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