R의 많은 다각형으로 자르기, 마스크 및 추출 래스터의 속도가 증가합니까?


29

수천 개의 다각형 경계를 기반으로 한 래스터에서 다양한 토지 사용 유형의 면적과 백분율을 추출하고 있습니다. 각 개별 다각형을 반복하고 자르기 한 다음 특정 다각형의 크기로 래스터를 마스크하면 추출 기능이 훨씬 빠르게 작동한다는 것을 알았습니다. 그럼에도 불구하고 속도가 느리고 누군가가 내 코드의 효율성과 속도를 개선하기위한 제안이 있는지 궁금합니다.

나는이 관련 찾은 유일한는 이 응답 하여 제안 로저 Bivand에 의하여 GDAL.open()GDAL.close()뿐만 아니라 getRasterTable()getRasterData(). 나는 그것들을 살펴 보았지만 과거에는 gdal에 문제가 있었고 그것을 구현하는 방법을 알기에 충분히 알지 못한다.

재현 가능한 예 :

library(maptools)  ## For wrld_simpl
library(raster)

## Example SpatialPolygonsDataFrame
data(wrld_simpl) #polygon of world countries
bound <- wrld_simpl[1:25,] #name it this to subset to 25 countries and because my loop is set up with that variable  

## Example RasterLayer
c <- raster(nrow=2e3, ncol=2e3, crs=proj4string(wrld_simpl), xmn=-180, xmx=180, ymn=-90, ymx=90)
c[] <- 1:length(c)

#plot, so you can see it
plot(c)    
plot(bound, add=TRUE) 

지금까지 가장 빠른 방법

result <- data.frame() #empty result dataframe 

system.time(
     for (i in 1:nrow(bound)) { #this is the number of polygons to iterate through
      single <- bound[i,] #selects a single polygon
      clip1 <- crop(c, extent(single)) #crops the raster to the extent of the polygon, I do this first because it speeds the mask up
      clip2 <- mask(clip1,single) #crops the raster to the polygon boundary

      ext<-extract(clip2,single) #extracts data from the raster based on the polygon bound
      tab<-lapply(ext,table) #makes a table of the extract output
      s<-sum(tab[[1]])  #sums the table for percentage calculation
      mat<- as.data.frame(tab) 
      mat2<- as.data.frame(tab[[1]]/s) #calculates percent
      final<-cbind(single@data$NAME,mat,mat2$Freq) #combines into single dataframe
      result<-rbind(final,result)
      })

   user  system elapsed 
  39.39    0.11   39.52 

병렬 처리

병렬 처리는 사용자 시간을 절반으로 줄 였지만 시스템 시간을 두 배로 늘려서 이점을 무시했습니다. 래스터는 이것을 추출 기능에 사용하지만 불행히도 자르기 또는 마스크 기능에는 사용하지 않습니다. 불행하게도, 이것은 "IO"에 의한 "대기" 로 인해 총 경과 시간이 상당히 더 많이 남습니다 .

beginCluster( detectCores() -1) #use all but one core

여러 코어에서 코드를 실행하십시오.

  user  system elapsed 
  23.31    0.68   42.01 

그런 다음 클러스터를 종료하십시오

endCluster()

느린 방법 : 래스터 함수에서 직접 추출을 수행하는 대체 방법은 훨씬 오래 걸리며 원하는 형식으로 데이터를 관리하는 데 확신이 없습니다.

system.time(ext<-extract(c,bound))
   user  system elapsed 
1170.64   14.41 1186.14 

이 R 코드 프로파일 러 ( marcodvisser.github.io/aprof/Tutorial.html )를 사용해보십시오 . 대부분의 시간이 걸리는 라인을 알려줍니다. 이 링크에는 R의 처리 시간 단축에 대한 지침도 있습니다.
J Kelly

그냥 내 두 센트. . . 그러나 자르기의 픽셀 수가 매우 적은 경우 자르기 / 가져 오기 방법이 작동하지 않습니다. 한계가 어디에 있는지 잘 모르겠지만 1-5 픽셀이있는 작물에 문제가있었습니다 (왜 공간 패키지에 새로운 이유가 있는지 정확히 알지 못했지만 자르기 기능은 다음과 같습니다. 따라서 픽셀 경계, 따라서 개별 픽셀을 자르는 데 어려움을 겪습니다). 래스터 패키지에서 추출하면 그러한 문제가 없지만 사용자 시간의 두 배가 넘고 시스템 시간의 두 배가 넘습니다. 저해상도 래스터가있는 사람들에게 경고
만합니다.

2
Rcpp 패키지를 통해 추출을 C로 이동시킨 다소 새로운 패키지 인 velox가 있습니다. 다각형을 사용한 추출 작업에서 속도가 약 10 배 증가합니다.
제프리 에반스

@JeffreyEvans. 지금 Velox를 사용하여이 질문에 대한 답을 테스트하십시오. 그러나 매우 큰 벡터를 할당하는 데 문제가 있습니다.
SeldomSeenSlim

답변:


23

나는 마침내이 기능을 향상시키기 위해왔다. 내 목적을 rasterize()위해 다각형보다 먼저 가장 빠르며 getValues()대신에 사용 한다는 것을 알았습니다 extract(). 래스터 화는 작은 다각형에서 래스터 값을 표로 작성하는 원래 코드보다 훨씬 빠르지 않지만 큰 래스터가 잘리고 값이 추출되는 큰 다각형 영역에서 왔을 때 빛납니다. 또한 함수 getValues()보다 훨씬 빠릅니다 extract().

또한를 사용하여 멀티 코어 처리를 알아 냈습니다 foreach().

이것이 다각형 오버레이에서 래스터 값을 추출하기 위해 R 솔루션을 원하는 다른 사람들에게 유용하기를 바랍니다. 이것은 ArcGIS의 "Tabulate Intersection"과 유사합니다 .이 사용자와 같이 몇 시간 동안 처리 한 후에 빈 출력반환 하는 저에게는 잘 작동하지 않았습니다 .

#initiate multicore cluster and load packages
library(foreach)
library(doParallel)
library(tcltk)
library(sp)
library(raster)

cores<- 7
cl <- makeCluster(cores, output="") #output should make it spit errors
registerDoParallel(cl)

기능은 다음과 같습니다.

multicore.tabulate.intersect<- function(cores, polygonlist, rasterlayer){ 
  foreach(i=1:cores, .packages= c("raster","tcltk","foreach"), .combine = rbind) %dopar% {

    mypb <- tkProgressBar(title = "R progress bar", label = "", min = 0, max = length(polygonlist[[i]]), initial = 0, width = 300) 

    foreach(j = 1:length(polygonlist[[i]]), .combine = rbind) %do% {
      final<-data.frame()
      tryCatch({ #not sure if this is necessary now that I'm using foreach, but it is useful for loops.

        single <- polygonlist[[i]][j,] #pull out individual polygon to be tabulated

        dir.create (file.path("c:/rtemp",i,j,single@data$OWNER), showWarnings = FALSE) #creates unique filepath for temp directory
        rasterOptions(tmpdir=file.path("c:/rtemp",i,j, single@data$OWNER))  #sets temp directory - this is important b/c it can fill up a hard drive if you're doing a lot of polygons

        clip1 <- crop(rasterlayer, extent(single)) #crop to extent of polygon
        clip2 <- rasterize(single, clip1, mask=TRUE) #crops to polygon edge & converts to raster
        ext <- getValues(clip2) #much faster than extract
        tab<-table(ext) #tabulates the values of the raster in the polygon

        mat<- as.data.frame(tab)
        final<-cbind(single@data$OWNER,mat) #combines it with the name of the polygon
        unlink(file.path("c:/rtemp",i,j,single@data$OWNER), recursive = TRUE,force = TRUE) #delete temporary files
        setTkProgressBar(mypb, j, title = "number complete", label = j)

      }, error=function(e){cat("ERROR :",conditionMessage(e), "\n")}) #trycatch error so it doesn't kill the loop

      return(final)
    }  
    #close(mypb) #not sure why but closing the pb while operating causes it to return an empty final dataset... dunno why. 
  }
}

따라서 그것을 사용하려면 single@data$OWNER식별 다각형의 열 이름 (함수에 내장되었을 수있는 추측)에 맞게를 조정하고 다음 을 입력하십시오.

myoutput <- multicore.tabulate.intersect(cores, polygonlist, rasterlayer)

3
사용하는 경우 및 (또는 ) 할 필요가 없기 때문에 제안 getValues보다 훨씬 빠른 제안 extract은 유효 extract하지 않습니다 . 원래 질문의 코드는 두 가지를 모두 수행하며 처리 시간이 두 배로 늘어납니다. croprasterizemask
Robert Hijmans 2016 년

알 수있는 유일한 방법은 테스트하는 것입니다.
djas 2016 년

다각형리스트는 어떤 클래스이며, 다각형리스트 [[i]] [, j]는 여기서 무엇을해야합니까 (ELI5, 제발)? 나는 물건을 병렬 처리하는 초보자이므로 그것을 잘 이해하지 못합니다. polygonlist [[i]] [, j]를 polygonlist [, j]로 변경하기 전까지는 아무것도 반환하지 않는 함수를 얻을 수 없었습니다. 논리적 becaus [, j]는 SpatialPolygonsDataframe의 j 번째 요소입니다. 올바른 수업입니까? 변경 한 후 프로세스가 실행되고 일부 출력이 있지만 여전히 잘못된 것이 있습니다. (n 개의 작은 다각형 내에서 중간 값을 추출하려고하므로 코드의 일부도 변경했습니다).
reima

@RobertH 내 경우에는 자르기 (및 마스킹)가 약 3 배 빠르게 실행됩니다. 나는 1 억 에이커의 래스터를 사용하고 있으며 다각형은 그것의 작은 부분입니다. 다각형으로 자르지 않으면 프로세스가 훨씬 느리게 실행됩니다. 내 결과는 다음과 같습니다 .clip1 <-crop (래스터 레이어, 범위 (단일))> system.time (ext <-extract (clip1, single)) # 자른 래스터 사용자 시스템에서 추출 65.94 0.37 67.22> system.time (ext < -extract (rasterlayer, single)) # 1 억 에이커의 래스터 사용자 시스템에서 추출한 시간은 175.00 4.92 181.10
Luke Macaulay가

4

점, XY 또는 다각형에서 래스터 (래스터 스택) 추출 속도를 높입니다.

좋은 답변 루크. R 마법사 여야합니다! 다음은 코드를 단순화하기위한 약간의 조정입니다 (일부 경우 성능이 약간 향상 될 수 있음). cellFromPolygon (또는 포인트의 경우 cellFromXY)을 사용한 다음 일부 클립 및 getValues를 사용하여 일부 작업을 피할 수 있습니다.

래스터 스택에서 다각형 또는 점 데이터 추출 ------------------------

 library(raster)  
 library(sp)   

  # create polygon for extraction
  xys= c(76.27797,28.39791,
        76.30543,28.39761,
        76.30548,28.40236,
        76.27668,28.40489)
  pt <- matrix(xys, ncol=2, byrow=TRUE)
  pt <- SpatialPolygons(list(Polygons(list(Polygon(pt)), ID="a")));
  proj4string(pt) <-"+proj=longlat +datum=WGS84 +ellps=WGS84"
  pt <- spTransform(pt, CRS("+proj=sinu +a=6371007.181 +b=6371007.181 +units=m"))
  ## Create a matrix with random data & use image()
  xy <- matrix(rnorm(4448*4448),4448,4448)
  plot(xy)

  # Turn the matrix into a raster
  NDVI_stack_h24v06 <- raster(xy)
  # Give it lat/lon coords for 36-37°E, 3-2°S
  extent(NDVI_stack_h24v06) <- c(6671703,7783703,2223852,3335852)
  # ... and assign a projection
  projection(NDVI_stack_h24v06) <- CRS("+proj=sinu +a=6371007.181 +b=6371007.181 +units=m")
  plot(NDVI_stack_h24v06)
  # create a stack of the same raster
  NDVI_stack_h24v06 = stack( mget( rep( "NDVI_stack_h24v06" , 500 ) ) )


  # Run functions on list of points
  registerDoParallel(16)
  ptm <- proc.time()
  # grab cell number
  cell = cellFromPolygon(NDVI_stack_h24v06, pt, weights=FALSE)
  # create a raster with only those cells
  r = rasterFromCells(NDVI_stack_h24v06, cell[[1]],values=F)
  result = foreach(i = 1:dim(NDVI_stack_h24v06)[3],.packages='raster',.combine=rbind,.inorder=T) %dopar% {
     #get value and store
     getValues(crop(NDVI_stack_h24v06[[i]],r))
  }
  proc.time() - ptm
  endCluster()

사용자 시스템 경과 시간 16.682 2.610 2.530

  registerDoParallel(16)
  ptm <- proc.time()
  result = foreach(i = 1:dim(NDVI_stack_h24v06)[3],.packages='raster',.inorder=T,.combine=rbind) %dopar% {
        clip1 <- crop(NDVI_stack_h24v06[[i]], extent(pt)) #crop to extent of polygon
        clip2 <- rasterize(pt, clip1, mask=TRUE) #crops to polygon edge & converts to raster
         getValues(clip2) #much faster than extract
  }
  proc.time() - ptm
  endCluster()

사용자 시스템 경과 33.038 3.511 3.288


두 가지 접근 방식을 실행했으며 사용 사례에서 방법이 약간 느려졌습니다.
Luke Macaulay

2

오버레이의 정밀도 손실이 그다지 중요하지 않은 경우 (시작하는 것이 정확하다고 가정 할 때) 일반적으로 다각형을 래스터로 먼저 변환하여 영역 계산 속도를 크게 높일 수 있습니다. raster패키지는 포함 zonal()의도 한 작업을 위해 잘 작동합니다 기능을. 그러나 표준 인덱싱을 사용하여 항상 동일한 차원의 두 행렬을 부분 집합 할 수 있습니다. 다각형을 유지해야하고 GIS 소프트웨어를 신경 쓰지 않으면 QGIS는 실제로 ArcGIS 또는 ENVI-IDL보다 영역 통계에서 더 빠릅니다.


2

또한 ~ 1kmx1km 그리드에서 ~ 300mx300m 그리드 맵의 토지 등급 클래스의 면적 점유율을 계산하려고 시도하면서 한동안이 문제로 어려움을 겪었습니다. 후자는 다각형 파일이었습니다. 멀티 코어 솔루션을 시도했지만 여전히 그리드 셀 수에 비해 너무 느 렸습니다. 대신에 나는 :

  1. 1kmx1km 그리드를 래스터 화하여 모든 그리드 셀에 고유 번호 제공
  2. gdalUtils 패키지의 allign_raster (또는 gdalwarp)를 r = "near"옵션과 함께 사용하여 1kmx1km 그리드의 해상도를 300mx300m, 같은 투영 등으로 높이십시오.
  3. 래스터 패키지 : stack_file <-stack (lc, grid)를 사용하여 2 단계에서 300mx300m 랜드 커버 맵과 300mx300m 그리드를 쌓으십시오.
  4. 맵을 결합 할 data.frame을 작성하십시오. df <-as.data.frame (rasterToPoints (stack_file))-1kmx1km 맵의 그리드 셀 번호를 300mx300m 랜드 커버 맵에 맵핑합니다.
  5. dplyr을 사용하여 1kmx1km 셀에서 토지 커버 클래스 셀의 점유율을 계산하십시오.
  6. 원래 1kmx1km 그리드에 연결하여 5 단계를 기준으로 새 래스터를 만듭니다.

이 절차는 300mx300m에서> 15 밀 그리드 셀이있는 랜드 커버 맵에서 시도했을 때 PC에서 메모리 문제없이 매우 빠르게 실행됩니다.

불규칙한 모양의 다각형 파일을 래스터 데이터와 결합하려는 경우 위의 접근 방식이 효과가 있다고 가정합니다. 아마도 래스터 화 (래스터 속도가 느림) 또는 gdal_rasterize를 사용하여 폴리곤 파일을 300mx300 그리드로 직접 래스터 화하여 1 단계와 2 단계를 결합 할 수 있습니다. 필자의 경우에도 재 투영이 필요했기 때문에 gdalwarp를 사용하여 재 투영과 분해를 동시에 수행했습니다.


0

큰 모자이크 (50k x 50k)에서 다각형 내부의 값을 추출하려면이 같은 문제에 직면해야합니다. 내 다각형에는 4 점이 있습니다. 내가 찾은 가장 빠른 방법 crop은 다각형의 경계 로 모자이크하고 다각형을 2 개의 삼각형으로 삼각 측량 한 다음 삼각형의 점이 있는지 확인하는 것입니다 (가장 빠른 알고리즘). 와 비교 extract기능, 실행 시간은 0.5 초에 20 초에서 감소한다. 그러나이 함수는 crop여전히 각 다각형마다 약 2 초가 필요합니다.

전체 재현 가능한 예제를 제공 할 수 없습니다. 아래의 R 코드에는 입력 파일이 포함되어 있지 않습니다.

이 방법은 단순한 다각형에서만 작동합니다.

par_dsm <- function(i, image_tif_name, field_plys2) {
    library(raster)
    image_tif <- raster(image_tif_name)
    coor <- field_plys2@polygons[[i]]@Polygons[[1]]@coords
    ext <- extent(c(min(coor[,1]), max(coor[,1]), min(coor[,2]), max(coor[,2])))

    extract2 <- function(u, v, us, vs) {
        u1 <- us[2]  - us[1]
        u2 <- us[3]  - us[2]
        u3 <- us[1]  - us[3]
        v1 <- vs[1]  - vs[2]
        v2 <- vs[2]  - vs[3]
        v3 <- vs[3]  - vs[1]
        uv1 <- vs[2] * us[1] - vs[1] * us[2]
        uv2 <- vs[3] * us[2] - vs[2] * us[3]
        uv3 <- vs[1] * us[3] - vs[3] * us[1]

        s1 <- v * u1 + u * v1 + uv1
        s2 <- v * u2 + u * v2 + uv2
        s3 <- v * u3 + u * v3 + uv3
        pos <- s1 * s2 > 0 & s2 * s3 > 0
        pos 
    }

    system.time({
        plot_rect <- crop(image_tif, ext, snap ='out')
        system.time({
        cell_idx <- cellFromXY(plot_rect, coor[seq(1,4),])
        row_idx <- rowFromCell(plot_rect, cell_idx)
        col_idx <- colFromCell(plot_rect, cell_idx)

        rect_idx <- expand.grid(lapply(rev(dim(plot_rect)[1:2]), function(x) seq(length.out = x)))

        pixel_idx1 <- extract2(
            rect_idx[,2], rect_idx[,1], 
            row_idx[c(1,2,3)], col_idx[c(1,2,3)])
        pixel_idx2 <- extract2(
            rect_idx[,2], rect_idx[,1], 
            row_idx[c(1,4,3)], col_idx[c(1,4,3)])
        pixel_idx <- pixel_idx1 | pixel_idx2
        })
    })
    mean(values(plot_rect)[pixel_idx])
}

# field_plys2: An object of polygons
# image_taf_name: file name of mosaic file
library(snowfall)
sfInit(cpus = 14, parallel = TRUE)
system.time(plot_dsm <- sfLapply(
    seq(along = field_plys2), par_dsm, image_tif_name, field_plys2))
sfStop()
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.