我有一个x,y,z值的规则矩形网格(图像)。
我还有一条与网格相交的x,y,z线。
对于网格中的每个平面(z层),我想计算网格中每个点与直线与该网格的交点之间的欧几里得距离。
示例:
# create regular 3D array of values
vec <- array(1:21,c(21,21,21))
dimnames(vec) = list(seq(-10,10), seq(-10,10), seq(-10,10))
# convert to data.frame (with names x, y, z, value)
grid <- melt(vec, varnames=c("x","y","z"))
# and a set of points along a line
line <- data.frame(
x = seq(-10, 10),
y = seq(-10, 10),
z = seq(-10, 10)
)
我尝试了几件事,并决定在z值上使用for
循环。
解决方案:
# loop through each z-level to compute the euclidean distance between
# all points on the plane at that level, and
# the point on the line at that level.
tmp = data.frame()
for(i in line$z) {
point <- subset(line, z == i)
plane <- subset(grid, z == i)
plane$euclidean = (plane$x - point$x)^2 + (plane$y - point$y)^2
if(nrow(tmp) == 0) {
tmp = plane
} else {
tmp = rbind(tmp, plane)
}
}
我对这个解决方案并不特别满意,尽管它相对较快。我不喜欢必须拆分并重新组合数据集以产生新的排序/排序的想法,并且当我在r中使用for
循环时,我感觉自己做错了。
我强烈感觉这种方式效率低下,并且可能还有其他(更好的方法)使用以下一种或多种方法来做到这一点:
for
循环,subset
和rbind
方法。 apply
函数之一sp::spDistsN1()
另一种解决方案是在z值上merge
进行网格和线的转换,然后执行直接计算,但是merge
步骤非常缓慢,并且结果数据中的x,y,z列.frame由于列名重复而被重命名。
更新以进行澄清:
data.frame
。 答案 0 :(得分:0)
这是我的tidyverse
尝试,但是如果实际上比您的方法更清晰的话,这不是很明显。从概念上讲,我认为基本上是相同的:对于每个z
,请计算该z
的线点与所有其他点之间的距离。
melt
基本上相同)dist
来计算点与矩阵之间的距离。 dist
实际上是在矩阵的所有行之间进行计算,因此我们只想保留所得三角形距离的底行。但是,它可能仍然比手工完成欧几里得距离还要快。nest
数据,因此我们每个z
都有一行,其中x
和y
作为列表列中的数据框left_join
线上的点,然后使用pmap
应用我们的新功能unnest
退出,因此我们在网格中有x
,y
,z
点,px
和py
的列线相交点,以及distance
,即到该点的距离。网格中每点一行。vec <- array(1:21,c(21,21,21))
dimnames(vec) = list(x = seq(-10,10), y = seq(-10,10), z = seq(-10,10))
library(tidyverse)
grid <- vec %>% # same thing as melt basically
as.tbl_cube(met_name = "value") %>%
as_tibble()
line <- data.frame(
px = seq(-10, 10),
py = seq(-10, 10),
pz = seq(-10, 10)
)
my_dist <- function(point_x, point_y, mat){
point_mat <- rbind(c(point_x, point_y), mat)
dist_mat <- as.matrix(dist(point_mat))
dist_vec <- dist_mat[nrow(dist_mat), 1:(ncol(dist_mat) - 1)]
attributes(dist_vec) <- NULL
return(dist_vec)
}
grid %>%
select(-value) %>%
nest(x, y) %>% # One row per z
left_join(line, by = c("z" = "pz")) %>%
mutate(distance = pmap(list(px, py, data), my_dist)) %>%
unnest() # Expand back out to one row per point
#> # A tibble: 9,261 x 6
#> z px py distance x y
#> <int> <int> <int> <dbl> <int> <int>
#> 1 -10 -10 -10 28.3 -10 -10
#> 2 -10 -10 -10 28.3 -9 -10
#> 3 -10 -10 -10 27.6 -8 -10
#> 4 -10 -10 -10 26.9 -7 -10
#> 5 -10 -10 -10 26.2 -6 -10
#> 6 -10 -10 -10 25.6 -5 -10
#> 7 -10 -10 -10 25 -4 -10
#> 8 -10 -10 -10 24.4 -3 -10
#> 9 -10 -10 -10 23.9 -2 -10
#> 10 -10 -10 -10 23.3 -1 -10
#> # ... with 9,251 more rows
由reprex package(v0.2.0)于2018-09-18创建。