R:将函数应用于矩阵的所有行对而不使用for循环

时间:2011-06-07 17:52:54

标签: r vectorization

我希望对矩阵中的所有行进行所有成对比较,显然,对于大型数据集,双循环将起作用,但是非常昂贵。

我查找了隐式循环,如apply()等,但不知道如何避免内循环。

如何实现?

4 个答案:

答案 0 :(得分:7)

我假设你正在尝试对矩阵的所有行对进行某种类型的比较。 您可以使用outer()遍历所有行索引对,并应用矢量化 比较函数到每个行对。例如。您可以按如下方式计算所有行对之间的欧几里德平方距离:

m <- matrix(1:12,4,3)     
> outer(1:4,1:4, FUN = Vectorize( function(i,j) sum((m[i,]-m[j,])^2 )) )
     [,1] [,2] [,3] [,4]
[1,]    0    3   12   27
[2,]    3    0    3   12
[3,]   12    3    0    3
[4,]   27   12    3    0

答案 1 :(得分:7)

如果你愿意进行自我比较,

outer()可以正常工作 - 例如1-1和2-2等......(矩阵中的对角线值)。另外,outer()执行1-2和2-1比较。

大多数时候成对比较只需要三角比较,没有自我比较和镜像比较。要实现三角比较,请使用combn()方法。

以下是显示outer()combn()

之间差异的示例输出
> v <- c(1,2,3,4)
> outer(v, v, function(x, y) print(paste(x, "-", y)))
 [1] "1 - 1" "2 - 1" "3 - 1" "4 - 1" "1 - 2" "2 - 2" "3 - 2" "4 - 2" "1 - 3" "2 - 3" "3 - 3" "4 - 3" "1 - 4" "2 - 4" "3 - 4" "4 - 4"

请注意上面的“1-1”自我比较。与“1-2”和“2-1”镜像比较。与下面的对比:

> v <- c(1,2,3,4)
> allPairs <- combn(length(v), 2) # choose a pair from 1:length(v)
> a_ply(combn(length(v), 2), 2, function(x) print(paste(x[1],"--",x[2]))) # iterate over all pairs
[1] "1 -- 2"
[1] "1 -- 3"
[1] "1 -- 4"
[1] "2 -- 3"
[1] "2 -- 4"
[1] "3 -- 4" 

您可以在上面看到矩阵的“上三角”部分。

当你有两个不同的向量进行成对操作时,外部()更容易。为了在单个向量中执行成对操作,通常可以使用combn来逃避。

例如,如果您正在执行outer(x,x,...),那么您可能做错了 - 您应该考虑combn(length(x),2))

答案 2 :(得分:0)

也许不像@Prasad这样普遍的解决方案,但在这个特殊的平方和的情况下要快得多:

dist(m)^2

答案 3 :(得分:0)

@Gopalkrishna Palem

我喜欢你的解决方案!但是,我认为你应该使用combn(v,2)而不是combn(length(v),2)。 combn(length(v),2)仅迭代v

的凹凸
> v <- c(3,4,6,7)
> combn(v, 2)
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    3    3    3    4    4    6
[2,]    4    6    7    6    7    7

> combn(length(v), 2)
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    1    1    2    2    3
[2,]    2    3    4    3    4    4

> a_ply(combn(v, 2), 2, function(x) print(paste(x[1],"--",x[2])) )
[1] "3 -- 4"
[1] "3 -- 6"
[1] "3 -- 7"
[1] "4 -- 6"
[1] "4 -- 7"
[1] "6 -- 7"
> a_ply(combn(length(v), 2), 2, function(x) print(paste(x[1],"--",x[2])) )
[1] "1 -- 2"
[1] "1 -- 3"
[1] "1 -- 4"
[1] "2 -- 3"
[1] "2 -- 4"
[1] "3 -- 4"

因此最终结果与combn(v,2)一致。

然后,如果我们有一个数据帧,我们可以使用索引将函数应用于成对行:

> df
  x  y
1 4  8
2 5  9
3 6 10
4 7 11

a_ply(combn(nrow(df), 2), 2, function(x) print(df[x[1],] - df[x[2],]))
   x  y
1 -1 -1
   x  y
1 -2 -2
   x  y
1 -3 -3
   x  y
2 -1 -1
   x  y
2 -2 -2
   x  y
3 -1 -1

但是,a_ply会丢弃结果,那么如何将输出存储在矢量中以供进一步分析?我不想打印结果