【问题标题】:Memory (RAM) issues using intersect from raster package使用光栅包相交的内存 (RAM) 问题
【发布时间】:2018-06-17 12:24:42
【问题描述】:

我无法在 R 上获取两个大型 SpatialPolygonsDataFrame 之间的交集。我的多边形数据代表建筑物和行政边界,我正在尝试获取它们之间的交集多边形。

我知道 raster 包中的 intersect 函数和 rgeos 包中的 gIntersection 可以完成这项工作(有一些差异),但它们不能一次处理我的所有多边形(大约 50.000 个多边形/实体)。

出于这个原因,我必须在一个循环中拆分我的计算,保存每个步骤的结果。问题是:这些功能不断填满我的物理内存,我无法清理它。我尝试使用 rm() 和 gc(),但它并没有改变任何事情。内存问题使我的 R 会话崩溃,我无法进行计算。

有没有办法在模拟期间在循环中释放 RAM?还是为了避免这个内存问题?

这里有一个可重现的例子,用于随机多边形。

library(raster)
library(sp)
library(rgeos)

#Generating 50000 points (for smaller polygons) and 150000 (for larger polygons) in a square of side 100000
size=100000

Nb_points1=50000
Nb_points2=150000
start_point=matrix(c(sample(x = 1:size,size = Nb_points1,replace = T),sample(x = 1:size,size = Nb_points1,replace = T)),ncol=2)
start_point2=matrix(c(sample(x = 1:size,size = Nb_points2,replace = T),sample(x = 1:size,size = Nb_points2,replace = T)),ncol=2)

#Defining different sides length
radius=sample(x = 1:50,size = Nb_points1,replace = T)
radius2=sample(x = 1:150,size = Nb_points2,replace = T)

#Generating list of polygons coordinates
coords=list()
for(y in 1:Nb_points1){
  xmin=max(0,start_point[y,1]-radius[y])
  xmax=min(size,start_point[y,1]+radius[y])
  ymin=max(0,start_point[y,2]-radius[y])
  ymax=min(size,start_point[y,2]+radius[y])
  coords[[y]]=matrix(c(xmin,xmin,xmax,xmax,ymin,ymax,ymax,ymin),ncol=2)
}

coords2=list()
for(y in 1:Nb_points2){
  xmin=max(0,start_point2[y,1]-radius2[y])
  xmax=min(size,start_point2[y,1]+radius2[y])
  ymin=max(0,start_point2[y,2]-radius2[y])
  ymax=min(size,start_point2[y,2]+radius2[y])
  coords2[[y]]=matrix(c(xmin,xmin,xmax,xmax,ymin,ymax,ymax,ymin),ncol=2)
}

#Generating 75000 polygons
Poly=SpatialPolygons(Srl = lapply(1:Nb_points1,function(y) Polygons(srl = list(Polygon(coords=coords[y],hole = F)),ID = y)),proj4string = CRS('+init=epsg:2154'))
Poly2=SpatialPolygons(Srl = lapply(1:Nb_points2,function(y)Polygons(srl =  list(Polygon(coords=coords2[y],hole = F)),ID = y)),proj4string = CRS('+init=epsg:2154'))

#Union of overlapping polygons
aaa=gUnionCascaded(Poly)
bbb=gUnionCascaded(Poly2)

aaa=disaggregate(aaa)
bbb=disaggregate(bbb)

intersection=gIntersects(spgeom1 = aaa,bbb,byid = T,returnDense = F)

#Loop on the intersect function
pb <- txtProgressBar(min = 0, max = ceiling(length(aaa)/1000), style = 3)

for(j in 1:ceiling(length(aaa)/1000)){
  tmp_aaa=aaa[((j-1)*1000+1):(j*1000),]
  tmp_bbb=bbb[unique(unlist(intersection[((j-1)*1000+1):(j*1000)])),]
  List_inter=intersect(tmp_aaa,tmp_bbb)
  gc()
  gc()
  gc()
  setTxtProgressBar(pb, j)
}

谢谢!

【问题讨论】:

  • 为避免内存问题,您可以切换到gdalUtils
  • 我不知道这个包。你能帮我吗?什么功能可以帮助我?我没有看到任何关于记忆或交叉点的信息。
  • gdalUtils 是一个非常好的和有用的包,但在这里没有帮助。主要是玩光栅。您使用 raster 包,但不是在 raster 上,所以我怀疑它会有所帮助。
  • R 对于大型 GIS 的东西来说效率不高。我经常喜欢使用 R 作为基础来调用其他软件。为此,RSAGA 是我最喜欢的,其次是RQGIS,而不是更复杂的RGRASS7。都需要你安装相应的软件(可以用OSGEO4W一键搞定)。他们应该成功地完成你的任务。我现在有点忙,如果以后有机会我会发布一个例子。

标签: r r-raster sp sf


【解决方案1】:

在对循环进行了一些更改后,该示例对我来说很好(8 GB RAM)。见下文。这些更改与内存使用无关——您没有存储结果。

List_inter <- list()

for(j in 1:ceiling(length(aaa)/1000)){
    begin <- (j-1) * 1000 + 1
    end <- min((j*1000), length(aaa))
    tmp_aaa <- aaa[begin:end,]
    tmp_bbb <- bbb[unique(unlist(intersection[begin:end])),]
    List_inter[[j]] <- intersect(tmp_aaa,tmp_bbb)
    cat(j, "\n"); flush.console()
}

x <- do.call(bind, List_inter)

或者,您可以将中间结果写入磁盘,稍后再处理:

inters <- intersect(tmp_aaa,tmp_bbb)
saveRDS(inters, paste0(j, '.rds'))

或者

shapefile(inters, paste0(j, '.shp'))

【讨论】:

  • 感谢您的回答。我的 RAM 使用量仍然随着这个新循环而增加。在我的示例中,我确实没有存储结果。
  • RAM 使用应该随着您创建新对象而增加。您可以尝试将中间结果写入磁盘,稍后再返回。我已经为 taht 添加了一些代码。
【解决方案2】:

您可以考虑使用包sfst_intersectsst_intersection 函数。例如:

aaa2 <- sf::st_as_sf(aaa)
bbb2 <- sf::st_as_sf(bbb)
intersections_mat <- sf::st_intersects(aaa2, bbb2)
intersections <- list()
for (int in seq_along(intersections_mat)){
  if (length(intersections_mat[[int]]) != 0){
    intersections[[int]] <- sf::st_intersection(aaa2[int,], 
    bbb2[intersections_mat[[int]],])
  }
}

会给你一个长度等于aaaintersection_mat,并且对于aaa的每个特征,包含与之相交的bbb元素的“索引”(“空”,如果没有找到交叉):

> intersections_mat
Sparse geometry binary predicate list of length 48503, where the predicate was `intersects'
first 10 elements:
 1: 562
 2: (empty)
 3: 571
 4: 731
 5: (empty)
 6: (empty)
 7: (empty)
 8: 589
 9: 715
 10: (empty)

,以及一个包含相交多边形列表的intersection 列表:

>head(intersections)
[[1]]
Simple feature collection with 1 feature and 0 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: 98873 ymin: 33 xmax: 98946 ymax: 98
epsg (SRID):    2154
proj4string:    +proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
                        geometry
1 POLYGON ((98873 33, 98873 9...

[[2]]
NULL

[[3]]
Simple feature collection with 1 feature and 0 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: 11792 ymin: 3 xmax: 11806 ymax: 17
epsg (SRID):    2154
proj4string:    +proj=lcc +lat_1=49 +lat_2=44 +lat_0=46.5 +lon_0=3 +x_0=700000 +y_0=6600000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
                        geometry
1 POLYGON ((11792 3, 11792 17...

(即,intersections[[1]]aaa 的多边形 1 和 bbb 的多边形 571 之间的交集)

HTH。

【讨论】:

  • 谢谢,这个包完美运行!我其实直接在两个大的SpatialPolygonsDataFrame上使用了sf::intersection函数。如果交叉点包含不同的几何类型(例如点、线和多边形),则需要按类型“拆分”intersection_mat。使用sf::st_geometry_type,然后再将它们传递回空间对象,如sp 包中的as( ,"Spatial") 所示。
  • 很高兴它有帮助。我建议“双通道”,因为我没有找到一种简单的方法来从 st_intersection 的输出中理解不同输出多边形的“起源”是什么。但是,我现在在帮助中注意到“返回的 sfc 几何列表列带有一个属性 idx,它是一个 n×2 矩阵,每一行分别是 x 和 y 对应条目的索引”。跨度>
  • interscection_mat 上的循环因此是无用的(正如您已经看到的),直接调用 st_intersection 就足够了。如果您愿意,我可以修改回复。
猜你喜欢
  • 2020-03-05
  • 1970-01-01
  • 1970-01-01
  • 2011-08-01
  • 2011-05-11
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 2019-10-08
相关资源
最近更新 更多