在访问矩阵的所有列组合时,如何避免双for循环?
我一直试图在互联网上找到解决办法,但没有解决我的具体问题。 矩阵D告诉我一组矩形(列)的最大和最小x和y坐标。现在我想知道,其中一些相交的频率。我想到的评估两个列是否相交的方法需要遍历所有可能的列组合(也可以是“向后”)。现在对我来说,第一个直观的解决方案是将一个for循环通过列嵌套到另一个做同样事情的循环中。以下是一个例子:在访问矩阵的所有列组合时,如何避免双for循环?,r,R,我一直试图在互联网上找到解决办法,但没有解决我的具体问题。 矩阵D告诉我一组矩形(列)的最大和最小x和y坐标。现在我想知道,其中一些相交的频率。我想到的评估两个列是否相交的方法需要遍历所有可能的列组合(也可以是“向后”)。现在对我来说,第一个直观的解决方案是将一个for循环通过列嵌套到另一个做同样事情的循环中。以下是一个例子: n <- 5 D <- matrix(c(1,2,1,2,1,3,1,3,2,4,2,4,3,5,1,2,3,4,2,4),nrow=4,ncol=n)
n <- 5
D <- matrix(c(1,2,1,2,1,3,1,3,2,4,2,4,3,5,1,2,3,4,2,4),nrow=4,ncol=n)
E <- mat.or.vec(nr=n, nc=n)
for (i in 1:n){
for (j in 1:n){
if (i != j &&
(D[1,i] <= D[1,j] & D[1,j] < D[2,i]) &&
((D[3,i] <= D[3,j] & D[3,j] < D[4,i]) | (D[3,i] < D[4,j] & D[4,j] <= D[4,i]))) {
E[i,j] <- 1
}
}
}
[,1] [,2] [,3] [,4] [,5]
[1,] 0 1 0 0 0
[2,] 1 0 1 0 0
[3,] 0 0 0 0 1
[4,] 0 0 0 0 0
[5,] 0 0 0 0 0
我们看到,部分循环已经比完整循环有了显著的改进,但只比使用空间对象的解决方案稍好一点。因此,我决定采用罗兰解决方案。再次感谢 这不是我的专业领域,但您应该使用spatial软件包
library(sp)
library(rgeos)
n <- 5
D <- matrix(c(1,2,1,2,1,3,1,3,2,4,2,4,3,5,1,2,3,4,2,4),nrow=4,ncol=n)
D1 <- t(D)
D1 <- D1[, c(1, 3, 2, 3, 2, 4, 1, 4)]
ID <- paste0('rect', seq_len(nrow(D1)))
# Create SP
#http://stackoverflow.com/a/26620550/1412059
polys <- SpatialPolygons(mapply(function(poly, id) {
xy <- matrix(poly, ncol=2, byrow=TRUE)
Polygons(list(Polygon(xy)), ID=id)
}, split(D1, row(D1)), ID))
# Create SPDF
polys.df <- SpatialPolygonsDataFrame(polys, data.frame(id=ID, row.names=ID))
plot(polys.df, col=rainbow(50, alpha=0.5))
例如,rect2
和rect3
重叠,您尚未识别:
plot(polys.df[2:3,], col=rainbow(50, alpha=0.5))
还是它们互相包容
gContains(polys.df, byid = TRUE)
例如rect2
包含rect1
:
plot(polys.df[1:2,], col=rainbow(50, alpha=0.5))
等等
最后,您可以执行以下操作:
res <- gOverlaps(polys.df, byid = TRUE) |
gContains(polys.df, byid = TRUE) |
gWithin(polys.df, byid = TRUE) |
gCovers(polys.df, byid = TRUE)
diag(res) <- 0
# rect1 rect2 rect3 rect4 rect5
#rect1 0 1 0 0 0
#rect2 1 0 1 0 0
#rect3 0 1 0 0 1
#rect4 0 0 0 0 0
#rect5 0 0 1 0 0
res我喜欢罗兰的答案的原因有很多,而不是我将在这里给出的答案
代码更能说明正在做什么。(六个月后,当您回到这里时,这一点非常重要)
它更具概括性,适用于空间对象可以处理的任何形状
它有很好的工具来说明这个问题
尽管如此,我还是要提供一种可能比空间方法运行得更快的替代解决方案。但是,这仅适用于矩形
首先,我们将依赖于一个逻辑测试,该测试基于。然后我们可以编写一个函数来执行这个测试,如下所示
intersecting_rects <- function(edge1, edge2){
#* index 1 is left edge, index 2 is right edge
#* index 3 is lower edge, index 4 is upper edge
(edge1[1] < edge2[2] && edge1[2] > edge2[1] &&
edge1[3] < edge2[4] && edge1[4] > edge2[3])
}
还不错!但它与罗兰的答案相比如何呢?让我们把它全部设置好,并运行一个粗略的比较(主要警告:这个比较是在一组小得可笑的矩形上进行的,我不认为这会很好地扩展,但是如果你能在100个矩形上运行它,它应该会让你很好地了解什么是最快的)
库(sp)
图书馆(rgeos)
图书馆(微基准)
#*矩形比较函数
相交直线边2[1]&&
edge1[3]edge2[3])
}
n请提供一个最小的可复制示例。如果你有一个相对较小的矩形数,我会考虑给他们每个位字段,然后“油漆”(或)矩阵与他们。嗯,我有大约4000个,所以这是一个相对较小的数字?如果我错了,请纠正我,但<代码> e <代码>应该是一个对称矩阵,不是吗?也就是说,既然E[2,3]==1
,那么E[3,2]==1
?换句话说,当矩形2与矩形3相交时,矩形3不也与矩形2相交吗?我问的原因是,如果这是真的,你不需要在矩阵的全维上循环。你只需要做上矩阵或三角矩阵,它可以把你的循环一分为二。而且,for
循环的名声不好。如果使用得当,它真的不是那么糟糕的工具<代码>for
循环在必须重新评估所创建的对象类型,或用于生成不断扩展的对象时,性能往往最差。您已经预先定义了E
的维度,并且没有更改其大小或类型,这一事实应该可以最大限度地减少与for
循环相关的问题。我认为你必须非常有创意才能让某些东西运行得更快。我想我的答案对于大量多边形的缩放效果要好得多。也许OP可以用她的实际数据集进行基准测试。(对于创建我在粗略搜索中没有找到的空间多边形,可能还有更快的解决方案。)@Roland,我实际上对此有些怀疑,但这只是因为gOverlaps
等中的逻辑被推广到了n边多边形。但我想这需要一个更大的实验来找出答案。正如本文的要点()所指出的,我需要一个更好的方式来度过我的周五早晨。为什么我觉得这些谜题如此有趣?总之,Gist创建了n个可以比较的矩形的随机集合。只要我的方法正确设置了矩形,我认为这是一个有效的比较。但是,如果我们不进行所有4个测试,我们可能会改进解决方案的时间安排。如果OP只需要一个方向的结果,前两个就足够了,例如三角形矩阵。嘿,多亏了你们两位,下周我回去工作时,我会尝试两种解决方案,并将结果发布在这里。但我已经可以说,我喜欢罗兰的答案是,它给了我一个很好的情节来检查我的计算是否有意义。
res <- gOverlaps(polys.df, byid = TRUE) |
gContains(polys.df, byid = TRUE) |
gWithin(polys.df, byid = TRUE) |
gCovers(polys.df, byid = TRUE)
diag(res) <- 0
# rect1 rect2 rect3 rect4 rect5
#rect1 0 1 0 0 0
#rect2 1 0 1 0 0
#rect3 0 1 0 0 1
#rect4 0 0 0 0 0
#rect5 0 0 1 0 0
intersecting_rects <- function(edge1, edge2){
#* index 1 is left edge, index 2 is right edge
#* index 3 is lower edge, index 4 is upper edge
(edge1[1] < edge2[2] && edge1[2] > edge2[1] &&
edge1[3] < edge2[4] && edge1[4] > edge2[3])
}
n <- 5
D <- matrix(c(1,2,1,2,1,3,1,3,2,4,2,4,3,5,1,2,3,4,2,4),nrow=4,ncol=n)
E<-mat.or.vec(nr=n,nc=n)
for (i in 1:n){
for (j in (i:n)[-1]){
E[i, j] <- as.numeric(intersecting_rects(D[, i], D[, j]))
}
}
E[lower.tri(E)] <- t(E)[lower.tri(E)]
E
library(sp)
library(rgeos)
library(microbenchmark)
#* Rectangles Comparison Function
intersecting_rects <- function(edge1, edge2){
(edge1[1] < edge2[2] && edge1[2] > edge2[1] &&
edge1[3] < edge2[4] && edge1[4] > edge2[3])
}
n <- 5
D <- matrix(c(1,2,1,2,1,3,1,3,2,4,2,4,3,5,1,2,3,4,2,4),nrow=4,ncol=n)
#* Set up the Spatial Obects
D1 <- t(D)
D1 <- D1[, c(1, 3, 2, 3, 2, 4, 1, 4)]
ID <- paste0('rect', seq_len(nrow(D1)))
# Create SP
#https://stackoverflow.com/a/26620550/1412059
polys <- SpatialPolygons(mapply(function(poly, id) {
xy <- matrix(poly, ncol=2, byrow=TRUE)
Polygons(list(Polygon(xy)), ID=id)
}, split(D1, row(D1)), ID))
# Create SPDF
polys.df <- SpatialPolygonsDataFrame(polys, data.frame(id=ID, row.names=ID))
#* Benchmark the speeds
microbenchmark(
poly = {
res <- gOverlaps(polys.df, byid = TRUE) |
gContains(polys.df, byid = TRUE) |
gWithin(polys.df, byid = TRUE) |
gCovers(polys.df, byid = TRUE)
diag(res) <- 0
},
full_loop = {
E <- mat.or.vec(nr=n, nc=n)
for (i in 1:n){
for (j in 1:n){
E[i, j] <- as.numeric(intersecting_rects(D[, i], D[, j]))
}
}
},
partial_loop = {
E <- mat.or.vec(nr=n, nc=n)
for (i in 1:n){
for (j in (i:n)[-1]){
E[i, j] <- as.numeric(intersecting_rects(D[, i], D[, j]))
}
}
E[lower.tri(E)] <- t(E)[lower.tri(E)]
}
)
Unit: microseconds
expr min lq mean median uq max neval cld
poly 2656.800 2720.8745 2812.72787 2767.2080 2811.4875 4200.736 100 b
full_loop 108.795 116.5650 122.77029 120.8170 127.2690 175.947 100 a
partial_loop 69.500 76.3905 87.01193 85.7745 94.1325 166.857 100 a