更有效地从空间线叠加多边形或 extract() 栅格数据
More efficiently overlay polygon or extract() raster data from spatial lines
我有一个包含 15 亿条空间线的庞大数据集,这些数据集是我使用 37,000 个点的所有组合创建的。 对于每条空间线,我想提取该线接触的多边形(或光栅 - 无论哪个更快)的最大值。 本质上这是一个非常大的 "spatial join"弧线语。如果在多边形图层上叠加线,则输出将是所有属性字段中空间线的最大值 - 每个属性字段代表一年中的一个月。我还包含了一个栅格数据集,它是从 1990 年 1 月才创建的,分辨率约为 30 米的多边形文件 - 栅格代表了一种我认为可以节省时间的替代方法。多边形和栅格层代表一个大的空间区域:大约 30 公里 x 10 公里。数据可用 here。我包含在 .zip 中的空间线数据集只有 9900 条线,从 15 亿条线的整个数据集中在 运行dom 处采样。
先读入数据
#polygons
poly<-readShapePoly("ls_polys_bin",proj4string=CRS("+proj=utm +zone=21 +south +datum=WGS84 +units=m +no_defs"))
poly$SP_ID<-NULL #deleting this extra field in prep for overlay
#raster - this represents only one month (january 1990)
#raster created from polygon layer but one month only
raster.jan90<-readGDAL("rast_jan90.tif")
raster.jan90<-raster(raster.jan90) #makes it into a raster
#lines (9900 of 1.5 billion included)
lines<-readShapeLines("l_spatial",proj4string=CRS("+proj=utm +zone=21 +south +datum=WGS84 +units=m +no_defs"))
为了使行数据更易于管理,抽取 50 行样本
lines.50<-lines[sample(nrow(lines),50),]
将所有三个图层绘制在一起
plot(raster.jan90)#where green=1
plot(poly, axes=T,cex.axis=0.75, add=T)
plot(lines.50, col="red", add=TRUE)
首先我尝试了一个叠加层,但按照目前的速度,整个 15 亿的数据集在我的机器上 运行 需要大约 844 天
ptm <- proc.time() #start clock
overlays.all<-over(lines.50,poly, fn=max)
ptm.sec.overlay<-proc.time() - ptm # stop clock
ptm.sec.overlay #.56 sec w/ n=12 lines; 2.3 sec w/ 50 lines
接下来我将多边形转换为栅格(仅一个月 - 1990 年 1 月),然后我 运行 一个带有空间线的 extract(),但这花费了更多时间。
ptm <- proc.time() # Start clock
ext.rast.jan90<-extract(raster.jan90,lines.50, fun=max, method=simple)
ptm.sec.ext<-proc.time() - ptm # stop clock
ptm.sec.ext #32 sec w/ n=12 lines; 191 sec w/ n=50 lines
我尝试将所有“0”单元格转换为 "NA" 似乎没有节省时间。 有没有另一种方法可以更有效地完成这种可怕的覆盖或提取()?请注意,这些数据目前被分类为“1”或“0”,但最终我想 运行此代码为连续变量即运行s 0:300。
我认为最快的方法是将线栅格化为与栅格数据相同的栅格。
但是我不会在 R 中将它们栅格化。我会编写一些 C 代码来获取栅格数据和 37,000 个点位置,然后使用 Bresenham 画线算法来获取栅格位置线。在这些位置对栅格进行采样,然后根据需要对该数据执行任何操作。 Bresenham 算法的快速代码应该很容易获得,您甚至可以在 GPU 上找到 运行 的版本以实现大幅加速。什么画直线比显卡快?
我假设您的空间线是两点之间的单条直线段。
或者从亚马逊(或其他一些云提供商)租用 1000 台服务器半天。
这里有一个 hack 应该可以给出一个很好的近似值。它可能会得到改进(getCrds 需要很多时间),包括采取更大的步骤(我不知道这是否适合你)。
library(raster)
raster.jan90 <- raster("rast_jan90.tif")
lines <- shapefile("l_spatial.shp", p4s="+proj=utm +zone=21 +south +datum=WGS84 +units=m +no_defs")
lines.50<-lines[sample(nrow(lines),50),]
test <- function(lns) {
getCrds <- function(i) {
p <- z[[i]][[1]]
s <- (p[2,] - p[1,]) / res(raster.jan90)
step <- round(max(abs(s)))
if ( step < 1 ) {
# these probably should not exist, but they do
return( cbind(i, cellFromXY(raster.jan90, p[1, , drop=FALSE])) )
}
x <- seq(p[1,1], p[2,1], length.out=step)
y <- seq(p[1,2], p[2,2], length.out=step)
cbind(i, unique(cellFromXY(raster.jan90, cbind(x, y))))
}
z <- coordinates(lns)
crd <- sapply(1:length(z), getCrds )
crd <- do.call(rbind, crd)
e <- extract(raster.jan90, crd[, 2])
tapply(e, crd[,1], max)
}
system.time(res <- test(lines.50))
# user system elapsed
# 0.53 0.01 0.55
system.time(res <- test(lines))
# user system elapsed
# 59.72 0.85 60.58
(684481500 * 60.58 / length(lines)) / (3600 * 24) 大约是50天...
在 50 台计算机上仅需 1 天
请注意,行数越多效率越高(因为要查询的唯一单元格相对较少)。
我有一个包含 15 亿条空间线的庞大数据集,这些数据集是我使用 37,000 个点的所有组合创建的。 对于每条空间线,我想提取该线接触的多边形(或光栅 - 无论哪个更快)的最大值。 本质上这是一个非常大的 "spatial join"弧线语。如果在多边形图层上叠加线,则输出将是所有属性字段中空间线的最大值 - 每个属性字段代表一年中的一个月。我还包含了一个栅格数据集,它是从 1990 年 1 月才创建的,分辨率约为 30 米的多边形文件 - 栅格代表了一种我认为可以节省时间的替代方法。多边形和栅格层代表一个大的空间区域:大约 30 公里 x 10 公里。数据可用 here。我包含在 .zip 中的空间线数据集只有 9900 条线,从 15 亿条线的整个数据集中在 运行dom 处采样。
先读入数据
#polygons
poly<-readShapePoly("ls_polys_bin",proj4string=CRS("+proj=utm +zone=21 +south +datum=WGS84 +units=m +no_defs"))
poly$SP_ID<-NULL #deleting this extra field in prep for overlay
#raster - this represents only one month (january 1990)
#raster created from polygon layer but one month only
raster.jan90<-readGDAL("rast_jan90.tif")
raster.jan90<-raster(raster.jan90) #makes it into a raster
#lines (9900 of 1.5 billion included)
lines<-readShapeLines("l_spatial",proj4string=CRS("+proj=utm +zone=21 +south +datum=WGS84 +units=m +no_defs"))
为了使行数据更易于管理,抽取 50 行样本
lines.50<-lines[sample(nrow(lines),50),]
将所有三个图层绘制在一起
plot(raster.jan90)#where green=1
plot(poly, axes=T,cex.axis=0.75, add=T)
plot(lines.50, col="red", add=TRUE)
首先我尝试了一个叠加层,但按照目前的速度,整个 15 亿的数据集在我的机器上 运行 需要大约 844 天
ptm <- proc.time() #start clock
overlays.all<-over(lines.50,poly, fn=max)
ptm.sec.overlay<-proc.time() - ptm # stop clock
ptm.sec.overlay #.56 sec w/ n=12 lines; 2.3 sec w/ 50 lines
接下来我将多边形转换为栅格(仅一个月 - 1990 年 1 月),然后我 运行 一个带有空间线的 extract(),但这花费了更多时间。
ptm <- proc.time() # Start clock
ext.rast.jan90<-extract(raster.jan90,lines.50, fun=max, method=simple)
ptm.sec.ext<-proc.time() - ptm # stop clock
ptm.sec.ext #32 sec w/ n=12 lines; 191 sec w/ n=50 lines
我尝试将所有“0”单元格转换为 "NA" 似乎没有节省时间。 有没有另一种方法可以更有效地完成这种可怕的覆盖或提取()?请注意,这些数据目前被分类为“1”或“0”,但最终我想 运行此代码为连续变量即运行s 0:300。
我认为最快的方法是将线栅格化为与栅格数据相同的栅格。
但是我不会在 R 中将它们栅格化。我会编写一些 C 代码来获取栅格数据和 37,000 个点位置,然后使用 Bresenham 画线算法来获取栅格位置线。在这些位置对栅格进行采样,然后根据需要对该数据执行任何操作。 Bresenham 算法的快速代码应该很容易获得,您甚至可以在 GPU 上找到 运行 的版本以实现大幅加速。什么画直线比显卡快?
我假设您的空间线是两点之间的单条直线段。
或者从亚马逊(或其他一些云提供商)租用 1000 台服务器半天。
这里有一个 hack 应该可以给出一个很好的近似值。它可能会得到改进(getCrds 需要很多时间),包括采取更大的步骤(我不知道这是否适合你)。
library(raster)
raster.jan90 <- raster("rast_jan90.tif")
lines <- shapefile("l_spatial.shp", p4s="+proj=utm +zone=21 +south +datum=WGS84 +units=m +no_defs")
lines.50<-lines[sample(nrow(lines),50),]
test <- function(lns) {
getCrds <- function(i) {
p <- z[[i]][[1]]
s <- (p[2,] - p[1,]) / res(raster.jan90)
step <- round(max(abs(s)))
if ( step < 1 ) {
# these probably should not exist, but they do
return( cbind(i, cellFromXY(raster.jan90, p[1, , drop=FALSE])) )
}
x <- seq(p[1,1], p[2,1], length.out=step)
y <- seq(p[1,2], p[2,2], length.out=step)
cbind(i, unique(cellFromXY(raster.jan90, cbind(x, y))))
}
z <- coordinates(lns)
crd <- sapply(1:length(z), getCrds )
crd <- do.call(rbind, crd)
e <- extract(raster.jan90, crd[, 2])
tapply(e, crd[,1], max)
}
system.time(res <- test(lines.50))
# user system elapsed
# 0.53 0.01 0.55
system.time(res <- test(lines))
# user system elapsed
# 59.72 0.85 60.58
(684481500 * 60.58 / length(lines)) / (3600 * 24) 大约是50天...
在 50 台计算机上仅需 1 天
请注意,行数越多效率越高(因为要查询的唯一单元格相对较少)。