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

8
我希望能够为矩阵中的所有行进行两两比较,显然双重循环可以实现,但对于大数据集来说非常昂贵。
我查看了隐式循环如apply()等,但不知道如何避免内部循环。
怎么才能实现呢?
4个回答

9
我假设您想要在矩阵的所有行对之间进行某种比较。您可以使用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:4,1:4?它们是输出的维度吗?但我认为它们应该是FUN的参数。 - rpylearning
原矩阵中有4行。 - Aaron left Stack Overflow
我有一个关于使用结果矩阵中数据的后续问题,这里是相关矩阵,例如。 - rpylearning
抱歉,我的问题是我需要从每一行中检索所有不在(平均值-4个标准差,平均值+4个标准差)范围内的元素,例如0.9将成为具有平均值0.6和标准差0.02的异常值。我想知道是否有一种优雅的方法来做到这一点?谢谢! - rpylearning
@rpylearning:你可能想把这个作为一个新问题添加进去,因为它显然与你最初的问题没有关系。无论如何,“4sd”不是一个标准的异常值度量,所以你可能也需要重新审查一下。 - Nick Sabbe

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" 

您可以在上面看到矩阵的“上三角”部分。
当您有两个不同的向量进行成对操作时,使用Outer()更加合适。如果在单个向量内执行成对操作,则通常可以使用combn。
例如,如果您正在执行outer(x,x,...) ,那么您可能做错了 - 您应该考虑 combn(length(x),2))

我尝试将这种方法应用于获取时间序列列表的交叉相关矩阵,其中我想计算CCF矩阵。 ccff <- function(x){ ccf(x[1], x[2], lag.max = 12, plot = FALSE) }。其中x是时间序列列表。请问如何使用它。adply(combn(tslist, 2), 2, function(x)ccff(x))无法工作。谢谢。 - Anusha
@Anusha 请分享您的示例代码(填充 X 并运行 ccff)- 我会检查它。 您可以使用我的联系表格在 http://gk.palem.in/Contact.html 给我发送代码片段。 - Gopalakrishna Palem
请查看我在以下问题中尝试使用mapply的情况。我很好奇如何使用adply在一组序列对上进行计算:http://stackoverflow.com/questions/25477116/how-to-use-mapply-to-calculate-ccf-for-list-of-pairs-of-time-series。谢谢。 - Anusha
aaply可以用于此目的。我已经在您指定的问题的答案中提供了示例工作代码和注释,链接在这里:http://stackoverflow.com/a/26162253/451456 谢谢。 - Gopalakrishna Palem

0

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

dist(m)^2

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将会丢弃结果,那么我该如何将输出存储在向量中以供进一步分析?我不想仅仅打印结果。


为了存储输出,您可以尝试使用aaplyadply代替a_ply - Gopalakrishna Palem

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