【问题标题】:How to replace a double for loop with a vector operation如何用向量运算替换双 for 循环
【发布时间】:2016-03-14 04:02:24
【问题描述】:

我正在尝试创建一个自定义分布函数(基于 hasrsine)。现在我的原型是一个双 for 循环。我环顾了矢量化操作,我仍然在学习很多东西(对 R 来说很新),所以不清楚如何清理它。最后,我想要一个 NxN 矩阵来比较地球上各点之间的距离。这是我现在的测试数据:

coord
     Latitude   Longitude
1    16.34577    6.303545
2    12.49475   28.626396
3    27.79462   60.032495
4    44.42699  110.114216
5   -69.85409   87.946878

邪恶的替身for-loop:

for (i in 1:dim(coord)[1]){
  for(j in 1:dim(coord)[1]) # for each column {
    mymat[i,j] = coord[i,1]*coord[j,2]     # custom function for future
  }
} 

结果:

           X1         X2         X3        X4        X5
1   103.03629   467.9204   981.2773  1799.902  1437.559
2    78.76122   357.6796   750.0910  1375.850  1098.874
3   175.20461   795.6596  1668.5801  3060.582  2444.450
4   280.04755  1271.7847  2667.0632  4892.043  3907.215
5  -440.32840 -1999.6708 -4193.5152 -7691.928 -6143.449

当然,对于 5 个样本,没问题。但我有一个 100k 的列表。

我确实在搜索后看到了一个函数

custom.dist <- function(x, my.dist) {
  mat <- sapply(x, function(x.1) sapply(x, function(x.2) my.dist(x.1, x.2)))
  as.dist(mat)
}

但我不明白发生了什么并且无法让它工作,即使使用像 x*y 这样的虚拟函数

【问题讨论】:

  • 请记住,您还可以使用Rcpp - stackoverflow.com/questions/29054459/…
  • 这只是第一列和第二列的外积?即cbind(coord[,1]) %*% rbind(coord[,2])?
  • outer(coord[,1], coord[,2],"*")
  • @Khashaa 刚刚偷看了outer 的源代码,当使用"*" 时,直接跳到coord[ , 1] %*% t(coord[ , 2]) 会更快
  • 或者你真的想在你的循环中间定义一个不同的函数吗?如果是这样,您应该真正指定my.dist 的确切含义

标签: r performance for-loop vectorization


【解决方案1】:

看起来您只想要外部产品。为此有一个函数 - 方便地命名为outer。现在outer 可以应用除乘法以外的函数,但默认是乘法,所以我们不需要显式指定它。

> coord <- cbind(1:5, 2:6)
> coord
     [,1] [,2]
[1,]    1    2
[2,]    2    3
[3,]    3    4
[4,]    4    5
[5,]    5    6
> outer(coord[,1], coord[,2])
     [,1] [,2] [,3] [,4] [,5]
[1,]    2    3    4    5    6
[2,]    4    6    8   10   12
[3,]    6    9   12   15   18
[4,]    8   12   16   20   24
[5,]   10   15   20   25   30

请注意,这种方法也很容易推广到其他二进制函数

> outer(coord[,1], coord[,2], FUN = paste0)
     [,1] [,2] [,3] [,4] [,5]
[1,] "12" "13" "14" "15" "16"
[2,] "22" "23" "24" "25" "26"
[3,] "32" "33" "34" "35" "36"
[4,] "42" "43" "44" "45" "46"
[5,] "52" "53" "54" "55" "56"

【讨论】:

  • @MichaelChirico 将其写为答案。我要离开这个,因为它是一个有效的答案。我知道矩阵运算在这里更快,但有时使用更易读的版本也不错,对我来说这更容易理解。
  • coord[ , 1] %*% t(coord[ , 2]) 对于那些不想向上滚动的人。这真的不是一个单独的答案,因为它几乎正是 outer 在幕后所做的;我只是建议您将其作为您完全可以接受的答案的附录。我的方法可能几乎不会节省时间(除非 as.vector 出于某种原因非常慢)。
  • 这让我走上了正轨,我真正想要的是 2 个 2XN 矩阵(2 列,N 行)a and b 的外积。虽然outer 对单个向量非常有效,但它真的让我陷入了循环。我最终得到的(经过多次努力)是sapply(1:3, function(z) sapply(1:3, function(y) paste(a[y,1],a[y,2],b[y,1],b[y,2]))) 然后我可以用半正弦公式(或任何其他接受 4 个输入的公式)替换“粘贴”部分。我认为我的问题是我默认将向量视为列,而不是行。
猜你喜欢
  • 2019-06-12
  • 1970-01-01
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多