Проблемы с памятью (ОЗУ) при использовании пересечения из растрового пакета

У меня проблемы с получением пересечения между двумя большими SpatialPolygonsDataFrame на R. Мои данные полигонов представляют здания и административные границы, и я пытаюсь получить полигоны пересечения между ними.

Я понимаю, что функция пересечения из растрового пакета и gIntersection из пакета rgeos может выполнять эту работу (с некоторыми отличиями), но они не могут обрабатывать все мои полигоны одновременно (около 50 000 полигонов на объект).

По этой причине мне приходится разбивать вычисления внутри цикла, сохраняя результат для каждого шага. Проблема в том, что эти функции продолжают заполнять мою физическую память, и я не могу ее очистить. Я пробовал использовать rm () и gc (), но это ничего не меняет. Проблема с памятью приводит к сбою моего сеанса R, и я не могу выполнить расчет.

Есть ли способ освободить оперативную память во время моделирования в циклах? Или чтобы избежать этой проблемы с памятью?

Вот воспроизводимый пример для случайных многоугольников.

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)
}

Спасибо !


person A.Rogeau    schedule 08.01.2018    source источник
comment
Чтобы избежать проблем с памятью, вы можете переключиться на gdalUtils.   -  person loki    schedule 08.01.2018
comment
Я не знаю этот пакет. Не могли бы вы мне с этим помочь? Какая функция может мне помочь? Я ничего не вижу в памяти или пересечении.   -  person A.Rogeau    schedule 08.01.2018
comment
gdalUtils - очень хороший и полезный пакет, но здесь он не поможет. В основном это игра с растрами. Вы используете растровый пакет, но не на растрах, поэтому я сомневаюсь, что это поможет.   -  person Bastien    schedule 09.01.2018
comment
R не так эффективен для больших ГИС. Я часто предпочитаю использовать R как основу для вызова другого программного обеспечения. По этому поводу RSAGA - мой любимый, за ним следует RQGIS и более сложный RGRASS7. Все, что вам нужно, чтобы установить соответствующее программное обеспечение (можно сделать один снимок с OSGEO4W). Они должны преуспеть в вашей задаче. Я сейчас вроде как занят, если будет возможность позже, выложу пример.   -  person Bastien    schedule 09.01.2018


Ответы (2)


Вы можете рассмотреть возможность использования функций st_intersects и st_intersection пакета sf. Например:

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]],])
  }
}

даст вам intersection_mat длины, равной aaa, и содержащую для каждого объекта 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]] - это пересечение многоугольника 1 из aaa и многоугольника 571 из bbb)

HTH.

person lbusett    schedule 09.01.2018
comment
Спасибо, этот пакет работает отлично! Я фактически использовал функцию sf::intersection непосредственно на двух больших SpatialPolygonsDataFrame. Если пересечение включает в себя разные типы геометрии (например, точки, линии и многоугольники), необходимо разбить intersection_mat по типу. Используйте sf::st_geometry_type перед передачей их обратно пространственным объектам, как это предусмотрено в пакете sp с as( ,"Spatial"). - person A.Rogeau; 10.01.2018
comment
Рад, что помог. Я предлагал двойной переход, потому что не нашел простого способа понять по выходным данным st_intersection, что были создателями различных выходных полигонов. Однако теперь я заметил в справке, что возвращаемый столбец списка геометрии sfc содержит атрибут idx, который представляет собой матрицу n на 2, где каждая строка является индексом соответствующих записей x и y соответственно. - person lbusett; 10.01.2018
comment
Таким образом, цикл по interscection_mat бесполезен (как вы уже видели), и достаточно прямого вызова st_intersection. Если хотите, я могу изменить ответ. - person lbusett; 10.01.2018

Пример отлично работает для меня (8 ГБ ОЗУ) после нескольких изменений цикла. См. ниже. Эти изменения не связаны с использованием памяти - вы не сохраняли результаты.

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'))

Or

shapefile(inters, paste0(j, '.shp'))
person Robert Hijmans    schedule 09.01.2018
comment
Спасибо за Ваш ответ. Мое использование оперативной памяти все еще увеличивается с этим новым циклом. Я действительно не сохранил результаты в своем примере. - person A.Rogeau; 10.01.2018
comment
Использование ОЗУ должно увеличиваться по мере создания новых объектов. Вы можете попробовать записать промежуточные результаты на диск и вернуться к ним позже. Я добавил код для taht. - person Robert Hijmans; 10.01.2018