Tăng tốc độ cắt, mặt nạ và trích xuất raster bằng nhiều đa giác trong R?


29

Tôi đang trích xuất diện tích và tỷ lệ phần trăm của các loại sử dụng đất khác nhau từ một raster dựa trên hàng ngàn ranh giới đa giác. Tôi đã thấy rằng hàm trích xuất hoạt động nhanh hơn nhiều nếu tôi lặp qua từng đa giác riêng lẻ và cắt sau đó che dấu raster xuống kích thước của đa giác cụ thể. Tuy nhiên, nó khá chậm và tôi tự hỏi liệu có ai có bất kỳ đề xuất nào để cải thiện hiệu quả và tốc độ mã của tôi không.

Điều duy nhất tôi tìm thấy liên quan đến điều này là phản hồi này của Roger Bivand, người đã đề xuất sử dụng GDAL.open()GDAL.close()cũng như getRasterTable()getRasterData(). Tôi đã xem xét những thứ đó, nhưng đã gặp rắc rối với gdal trong quá khứ và không biết nó đủ rõ để biết cách thực hiện nó.

Ví dụ sinh sản:

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) 

Phương pháp nhanh nhất cho đến nay

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 

Tiến trình song song

Xử lý song song giúp giảm một nửa thời gian của người dùng, nhưng phủ nhận lợi ích bằng cách nhân đôi thời gian hệ thống. Raster sử dụng chức năng này cho chức năng giải nén, nhưng không may cho chức năng cắt xén hoặc mặt nạ. Thật không may, điều này để lại một lượng lớn thời gian trôi qua do "chờ đợi xung quanh" bởi "IO".

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

chạy mã trên nhiều lõi:

  user  system elapsed 
  23.31    0.68   42.01 

sau đó kết thúc cụm

endCluster()

Phương pháp chậm: Phương pháp thay thế để thực hiện trích xuất trực tiếp từ chức năng raster mất nhiều thời gian hơn và tôi không chắc chắn về việc quản lý dữ liệu để đưa nó vào dạng tôi muốn:

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

Bạn có thể thử trình lược tả mã R này ( marcodvisser.github.io/aprof/Tutorial.html ). Nó có thể cho bạn biết những dòng nào chiếm phần lớn thời gian. Liên kết cũng có hướng dẫn cắt giảm thời gian xử lý trong R.
J Kelly

Chỉ hai xu của tôi ở đây. . . nhưng phương thức crop / getvalues ​​không hoạt động khi số pixel trong vùng cắt rất thấp. Tôi không chắc giới hạn ở đâu, nhưng tôi gặp vấn đề với các loại cây trồng chỉ có 1-5 pixel (Tôi chưa xác định lý do chính xác tại sao (bit mới vẫn còn cho các gói không gian) nhưng tôi cá là chức năng cắt ảnh phụ thuộc vào do đó, các ranh giới pixel, do đó đấu tranh để cắt bất kỳ pixel riêng lẻ nào). Trích xuất từ ​​gói raster không có vấn đề như vậy, nhưng đồng ý là hơn hai lần thời gian của người dùng và nhiều hơn hai lần về thời gian hệ thống. Chỉ là một cảnh báo cho những người có raster độ phân giải thấp (và một
Neal Barsch

2
Có một gói hơi mới, velox, đã chuyển trích xuất vào C thông qua gói Rcpp. Nó đang tăng ~ 10 lần tốc độ cho các hoạt động giải nén bằng cách sử dụng đa giác.
Jeffrey Evans

@JeffreyEvans. Kiểm tra câu trả lời cho câu hỏi này bằng cách sử dụng velox ngay bây giờ. Có vấn đề với nó phân bổ các vectơ cực lớn tuy nhiên.
SeldomSeenSlim

Câu trả lời:


23

Cuối cùng tôi đã nhận được để cải thiện chức năng này. Tôi thấy rằng với mục đích của mình, nó nhanh nhất rasterize()là đa giác trước và sử dụng getValues()thay vì extract(). Việc rasterizing không nhanh hơn nhiều so với mã ban đầu để lập bảng giá trị raster trong các đa giác nhỏ, nhưng nó tỏa sáng khi đến các khu vực đa giác lớn có các raster lớn bị cắt và các giá trị được trích xuất. Tôi cũng tìm thấy getValues()nhanh hơn nhiều so với extract()chức năng.

Tôi cũng đã tìm ra cách xử lý đa lõi bằng cách sử dụng foreach().

Tôi hy vọng điều này hữu ích cho những người khác muốn có giải pháp R để trích xuất các giá trị raster từ lớp phủ đa giác. Điều này tương tự như "Giao lộ theo bảng" của ArcGIS, không hoạt động tốt với tôi, trả lại kết quả đầu ra trống sau nhiều giờ xử lý, như người dùng này.

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

Đây là chức năng:

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

Vì vậy, để sử dụng nó, hãy điều chỉnh single@data$OWNERcho phù hợp với tên cột của đa giác nhận dạng của bạn (đoán có thể đã được tích hợp vào hàm ...) và đặt vào:

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

3
Đề xuất getValuesnhanh hơn nhiều so với đề xuất extractcó vẻ không hợp lệ vì nếu bạn sử dụng, extractbạn không phải thực hiện croprasterize(hoặc mask). Mã trong câu hỏi ban đầu thực hiện cả hai và điều đó sẽ làm tăng gấp đôi thời gian xử lý.
Robert Hijmans

cách duy nhất để biết là bằng cách thử nghiệm.
djas

Lớp nào là đa giác ở đây, và đa giác [[i]] [, j] nên làm gì ở đây (ELI5, làm ơn)? Tôi là người mới làm việc song song, vì vậy tôi không hiểu điều đó lắm. Tôi không thể lấy hàm để trả về bất cứ thứ gì, cho đến khi tôi đổi thành đa giác [[i]] [, j] thành đa giác [, j], có vẻ như logic becaus [, j] là phần tử thứ j của SpatialPolygonsDataframe, nếu điều đó lớp học có đúng không? Sau khi thay đổi, tôi đã chạy quá trình và một số đầu ra, nhưng chắc chắn vẫn có gì đó không đúng. (Tôi cố gắng trích xuất giá trị trung bình bên trong n đa giác nhỏ, vì vậy tôi cũng thay đổi một chút mã).
reima

@RobertH Trong trường hợp của tôi, việc cắt xén (và mặt nạ) làm cho nó chạy nhanh hơn khoảng 3 lần. Tôi đang sử dụng một raster 100 triệu mẫu Anh và các đa giác là một phần rất nhỏ trong số đó. Nếu tôi không cắt theo đa giác, quá trình sẽ chạy chậm hơn nhiều. Đây là kết quả của tôi: clip1 <- crop (rasterlayer, scope (single))> system.time (ext <-extract (clip1, single)) #extracting từ hệ thống người dùng raster đã cắt xén 65.94 0.37 67.22> system.time (ext < -extract (rasterlayer, single)) #extracting từ hệ thống người dùng raster 100 triệu acre đã trôi qua 175.00 4.92 181.10
Luke Macaulay

4

Tăng tốc trích xuất raster (ngăn xếp raster) từ điểm, XY hoặc Đa giác

Luke trả lời tuyệt vời. Bạn phải là một thuật sĩ R! Đây là một tinh chỉnh rất nhỏ để đơn giản hóa mã của bạn (có thể cải thiện hiệu suất một chút trong một số trường hợp). Bạn có thể tránh một số thao tác bằng cách sử dụng cellFromPolygon (hoặc cellFromXY cho các điểm) và sau đó cắt clip và getValues.

Trích xuất dữ liệu đa giác hoặc điểm từ ngăn xếp raster ------------------------

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

hệ thống người dùng đã trôi qua 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()

hệ thống người dùng đã trôi qua 33.038 3.511 3.288


Tôi đã chạy hai cách tiếp cận và phương pháp của bạn xuất hiện chậm hơn một chút trong trường hợp sử dụng của tôi.
Luke Macaulay

2

Nếu sự mất mát về độ chính xác của lớp phủ không quá quan trọng - giả sử nó bắt đầu chính xác - người ta thường có thể đạt được tốc độ tính toán khu vực lớn hơn nhiều bằng cách trước tiên chuyển đổi đa giác thành raster. Các rastergói chứa các zonal()chức năng, mà nên làm việc tốt cho công việc dự định. Tuy nhiên, bạn luôn có thể tập hợp hai ma trận có cùng kích thước bằng cách sử dụng lập chỉ mục tiêu chuẩn. Nếu bạn phải duy trì đa giác và bạn không bận tâm đến phần mềm GIS, thì QGIS thực sự phải nhanh hơn về thống kê khu vực so với ArcGIS hoặc ENVI-IDL.


2

Tôi cũng vật lộn với điều này một thời gian, cố gắng tính toán tỷ lệ diện tích của các lớp che phủ đất của bản đồ lưới ~ 300mx300m trong lưới ~ 1kmx1km. Cái sau là một tập tin đa giác. Tôi đã thử giải pháp đa lõi nhưng điều này vẫn quá chậm so với số lượng ô lưới tôi có. Thay vào đó tôi:

  1. Rasterized lưới 1kmx1km cung cấp cho tất cả các ô lưới một số duy nhất
  2. Đã sử dụng allign_rasters (hoặc gdalwarp trực tiếp) từ gói gdalUtils với tùy chọn r = "gần" để tăng độ phân giải của lưới 1kmx1km lên 300mx300m, cùng một phép chiếu, v.v.
  3. Xếp chồng bản đồ che phủ đất 300mx300m và lưới 300mx300m từ bước 2, sử dụng gói raster: stack_file <- stack (lc, lưới).
  4. Tạo một data.frame để kết hợp các bản đồ: df <- as.data.frame (rasterToPoints (stack_file)), ánh xạ các số ô của bản đồ 1kmx1km vào bản đồ che phủ đất 300mx300m
  5. Sử dụng dplyr để tính toán tỷ lệ các ô lớp phủ đất trong các ô 1kmx1km.
  6. Tạo một raster mới trên cơ sở bước 5 bằng cách liên kết nó với lưới 1kmx1km ban đầu.

Quy trình này chạy khá nhanh và không gặp vấn đề về bộ nhớ trên máy tính của tôi, khi tôi đã thử nó trên bản đồ che phủ mặt đất với các ô lưới> 15 mill ở 300mx300m.

Tôi giả sử cách tiếp cận ở trên cũng sẽ hoạt động nếu một người muốn kết hợp một tệp đa giác với hình dạng không đều với dữ liệu raster. Có lẽ, người ta có thể kết hợp bước 1 & 2 bằng cách raster trực tiếp tệp đa giác thành lưới 300mx300 bằng cách sử dụng rasterize (raster có thể chậm) hoặc gdal_rasterize. Trong trường hợp của tôi, tôi cũng cần phải reproject vì vậy tôi đã sử dụng gdalwarp để cả hai từ chối và phân tách cùng một lúc.


0

Tôi phải đối mặt với vấn đề tương tự này để trích xuất các giá trị bên trong đa giác từ một bức tranh lớn (50k x 50k). Đa giác của tôi chỉ có 4 điểm. Phương pháp nhanh nhất tôi tìm thấy là cropkhảm vào liên kết của đa giác, tam giác đa giác thành 2 hình tam giác, sau đó kiểm tra xem các điểm trong tam giác (Thuật toán nhanh nhất tôi tìm thấy). So sánh với extractchức năng, thời gian chạy được giảm từ 20 s xuống 0,5 s. Tuy nhiên, hàm cropvẫn cần khoảng 2 giây cho mỗi đa giác.

Xin lỗi tôi không thể cung cấp ví dụ tái sản xuất đầy đủ. Các mã R bên dưới không bao gồm các tệp đầu vào.

Phương pháp này chỉ làm việc cho các đa giác đơn giản.

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()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.