आर में कई बहुभुजों द्वारा फसल की गति, मुखौटा, और रेखापुंज बढ़ाना?


29

मैं कई हजार बहुभुज सीमाओं के आधार पर एक रेखापुंज से विभिन्न भूमि उपयोग प्रकारों के क्षेत्र और प्रतिशत कवर निकाल रहा हूं। मैंने पाया है कि अर्क समारोह बहुत तेजी से काम करता है यदि मैं प्रत्येक व्यक्ति बहुभुज और फसल के माध्यम से पुनरावृति करता हूं, तो विशेष रूप से बहुभुज के आकार के नीचे रेखापुंज को मुखौटा करता है। बहरहाल, यह बहुत धीमा है, और मुझे आश्चर्य हो रहा है कि क्या किसी के पास मेरे कोड की दक्षता और गति में सुधार के लिए कोई सुझाव है।

केवल एक चीज मैं इस से संबंधित पाया है है यह प्रतिक्रिया है जो का उपयोग कर सुझाव दिया रोजर Bivand द्वारा GDAL.open()और GDAL.close()साथ ही साथ getRasterTable()और getRasterData()। मैंने उन पर गौर किया, लेकिन अतीत में गदगद होने से परेशान थे और इसे लागू करने के तरीके को अच्छी तरह से नहीं जानते।

प्रतिकारक उदाहरण:

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 ) को आज़मा सकते हैं । यह आपको बता सकता है कि कौन सी लाइनें सबसे ज्यादा समय लेती हैं। लिंक भी आर में प्रसंस्करण समय नीचे काटने के लिए दिशा निर्देश है
जम्मू केली

बस यहाँ मेरे दो सेंट। । । लेकिन जब फसल में पिक्सल की संख्या बहुत कम होती है तो फसल / प्राप्त करने की विधि काम नहीं करती है। मुझे यकीन नहीं है कि सीमा कहां है, लेकिन मेरे पास फसलों के मुद्दे थे जहां सिर्फ 1-5 पिक्सेल थे (मैंने सटीक कारण निर्धारित नहीं किया है कि क्यों (बिट अभी भी स्थानिक पैकेज के लिए) लेकिन मैं शर्त लगाता हूं कि फसल का कार्य निर्भर करता है पिक्सेल सीमाएँ, इसलिए इस प्रकार किसी भी व्यक्तिगत पिक्सेल फसल के लिए संघर्ष करता है)। रेखापुंज पैकेज से निकालने के लिए ऐसा कोई मुद्दा नहीं है, लेकिन सहमति दो बार उपयोगकर्ता के समय से अधिक है और सिस्टम समय पर दो बार से अधिक है। जो लोग कम संकल्प rasters (है और में एक करने के लिए बस एक चेतावनी
नील Barsch

2
कुछ नया पैकेज है, वीएलएक्स, जो आरसीपी पैकेज के माध्यम से सी में एक्सट्रैक्ट ले गया है। यह बहुभुज का उपयोग कर निकालने के संचालन पर गति में ~ 10 गुना वृद्धि दे रहा है।
जेफरी इवांस

@ जेफ्री इवांस इस प्रश्न के उत्तर का परीक्षण अब velox का उपयोग करके। हालाँकि इसके साथ बहुत बड़े वैक्टर आवंटित करने में समस्याएँ हैं।
सेलडोमीनसलीम

जवाबों:


23

मैं अंत में इस समारोह में सुधार करने के लिए चारों ओर मिल गया है। मैंने पाया कि मेरे उद्देश्यों के लिए, यह rasterize()पहले बहुभुज के लिए सबसे तेज़ था और getValues()इसके बजाय उपयोग करता था extract()। छोटे बहुभुजों में रेखापुंज मानों को सारणीबद्ध करने के लिए मूल कोड की तुलना में रैस्टराइज़िंग बहुत तेज़ नहीं है, लेकिन यह चमकता है जब यह बड़े बहुभुज क्षेत्रों में आता है जिसमें बड़े चूहों को काट दिया जाता था और जो मान निकाले जाते थे। मैंने यह भी पाया getValues()कि यह extract()फंक्शन की तुलना में बहुत तेज था ।

मैंने भी मल्टी-कोर प्रोसेसिंग का उपयोग करके पता लगाया foreach()

मुझे उम्मीद है कि यह अन्य लोगों के लिए उपयोगी है जो बहुभुज ओवरले से रेखीय मान निकालने के लिए एक आर समाधान चाहते हैं। यह आर्कजीआईएस के "टैब्यूलेट इंटरसेक्शन" के समान है, जो मेरे लिए अच्छी तरह से काम नहीं करता था , इस उपयोगकर्ता की तरह प्रसंस्करण के घंटों के बाद खाली आउटपुट लौटाता है

#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करते हैं तो आपको ऐसा नहीं करना है cropऔर rasterize(या mask)। मूल प्रश्न में कोड दोनों करता है, और यह डबल प्रसंस्करण समय के बारे में होना चाहिए।
रॉबर्ट हिजमन

जानने का एकमात्र तरीका परीक्षण से है।
दज

पॉलीगॉनिस्ट किस वर्ग के यहाँ है, और पॉलीगॉनलिस्ट को [[i]] [, j] यहाँ (ELI5, कृपया) करना चाहिए? मैं सामान रखने के लिए नौसिखिया हूं, इसलिए मुझे यह समझ में नहीं आता है। मैं कुछ भी वापस करने के लिए फ़ंक्शन नहीं प्राप्त कर सका, जब तक कि मैं पॉलीगिनलिस्ट [[i] [, j] से पॉलीगॉनिस्टलिस्ट [, j] में परिवर्तित नहीं हो जाता, जो कि तर्कसंगत है सही वर्ग है? यह बदलने के बाद कि मुझे प्रक्रिया चल रही है और कुछ आउटपुट मिले हैं, लेकिन निश्चित रूप से अभी भी कुछ गड़बड़ है। (मैं n छोटे बहुभुजों के अंदर माध्य मूल्य निकालने की कोशिश करता हूं, इसलिए मैंने कोड को थोड़ा बदल दिया)।
रीमा लागू

@RobertH मेरे मामले में, फसल (और मास्किंग) इसे लगभग 3 गुना तेज चलाती है। मैं एक 100 मिलियन एकड़ रेखापुंज का उपयोग कर रहा हूं और बहुभुज उसी का एक छोटा अंश हैं। यदि मैं बहुभुज की फसल नहीं करता हूं, तो प्रक्रिया बहुत धीमी हो जाती है। यहाँ मेरे परिणाम हैं: क्लिप 1 <- फसल (रैस्टरलेयर, हद (सिंगल))> system.time (ext <-extract (क्लिप 1, सिंगल)) # कस्टम क्रॉप किए गए रास्टर उपयोगकर्ता सिस्टम से हटकर 65.94 0.67 67.22> system.time (ext <) -स्ट्रेक्ट (रिस्टलेयर, सिंगल)) 100 मिलियन एकड़ के रास्टर यूजर सिस्टम से #extracting 175.00 4.92 181.10 समाप्त हुआ
ल्यूक मैकाले

4

बिंदु, XY या बहुभुज से रेखापुंज (रास्टर स्टैक) निकालने की गति

महान जवाब ल्यूक। आप एक आर जादूगर होना चाहिए! यहां आपके कोड को सरल बनाने के लिए एक बहुत ही मामूली ट्विक है (कुछ मामलों में प्रदर्शन में थोड़ा सुधार हो सकता है)। आप 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 समाप्त हो गई


मैंने दो दृष्टिकोणों को चलाया और आपका तरीका मेरे उपयोग के मामले में थोड़ा धीमा हो गया।
ल्यूक मैकाले

2

यदि ओवरले की शुद्धता में कमी बहुत महत्वपूर्ण नहीं है - यह मानते हुए कि शुरू करने के लिए सटीक है - आम तौर पर पॉलीगॉन को एक रेखापुंज में परिवर्तित करके सबसे अधिक आंचलिक गणना गति प्राप्त कर सकते हैं। rasterपैकेज में शामिल zonal()समारोह है, जो इरादा कार्य के लिए अच्छी तरह से काम करना चाहिए। हालाँकि, आप हमेशा मानक अनुक्रमण का उपयोग करते हुए एक ही आयाम के दो मैट्रिक्स का उपसमुच्चय कर सकते हैं। यदि आपको बहुभुज बनाए रखना चाहिए और आपको जीआईएस सॉफ़्टवेयर से कोई आपत्ति नहीं है, तो क्यूजीआईएस वास्तव में आर्कगिस या ईएनवीआई-आईडीएल की तुलना में आंचलिक आँकड़ों पर अधिक तेज़ होना चाहिए।


2

मैं भी कुछ समय तक इससे जूझता रहा, ~ 1kmx1km ग्रिड में ~ 300mx300m ग्रिड मैप के लैंड कवर क्लासेस के एरिया शेयर की गणना करने की कोशिश करता रहा। उत्तरार्द्ध एक बहुभुज फ़ाइल थी। मैंने मल्टीकोर सॉल्यूशन की कोशिश की, लेकिन ग्रिड सेल्स की संख्या के लिए यह अभी भी बहुत धीमी थी। इसके बजाय मैं:

  1. सभी ग्रिड कोशिकाओं को एक अद्वितीय संख्या देते हुए 1 किमी x1 किमी ग्रिड को व्यवस्थित किया
  2. 1kmx1km ग्रिड 300mx300m, उसी प्रक्षेपण आदि के संकल्प को बढ़ाने के लिए r "" पास "विकल्प के साथ gdalUtils पैकेज से allign_rasters (या सीधे gdalwarp) का उपयोग किया।
  3. रैस्टर पैकेज: स्टैक_फाइल <- स्टैक (lc, ग्रिड) का उपयोग करके स्टेप 2 से 300mx300m लैंड कवर मैप और 300mx300m ग्रिड को ढेर करें।
  4. मैप्स को संयोजित करने के लिए एक डेटा.फ्रेम बनाएं: df <- as.data.frame (rasterToPoints (stack_file)), जो 300 मीक्स 300 मीटर भूमि के नक्शे पर 1kmx1km नक्शे के ग्रिड सेल नंबरों को मैप करता है।
  5. 1kmx1km कोशिकाओं में भूमि कवर वर्ग कोशिकाओं की हिस्सेदारी की गणना करने के लिए dplyr का उपयोग करें।
  6. चरण 1 के आधार पर मूल 1kmx1km ग्रिड से जोड़कर एक नया रेखापुंज बनाएँ।

यह प्रक्रिया मेरे पीसी पर बहुत तेज और बिना मेमोरी मुद्दों के चलती है, जब मैंने 300mx300m पर> 15 मिल ग्रिड सेल के साथ लैंड कवर मैप पर इसे आजमाया।

मुझे लगता है कि ऊपर का दृष्टिकोण भी काम करेगा यदि कोई रैगस्टर डेटा के साथ एक बहुभुज फ़ाइल को अनियमित आकृतियों के साथ जोड़ना चाहता है। शायद, कोई भी पॉलीगॉन फ़ाइल को सीधे 300mx300 ग्रिड को rasterize (रैस्टर शायद धीमा) या gdal_rasterize का उपयोग करके सीधे चरण 1 और 2 को जोड़ सकता है। मेरे मामले में मुझे पुन: अस्वीकार करने की आवश्यकता थी और इसलिए मैंने एक ही समय में अस्वीकृति और असहमति दोनों के लिए गाल्डवार्प का इस्तेमाल किया।


0

मुझे एक ही मोज़ेक (50k x 50k) से बहुभुज के अंदर मान निकालने के लिए इसी समस्या का सामना करना पड़ता है। मेरे बहुभुज में केवल 4 अंक हैं। सबसे तेज़ विधि जो मुझे मिली है cropवह बहुभुज की सीमा में मोज़ेक करना है, बहुभुज को 2 त्रिभुजों में त्रिभुज करें, फिर जाँचें कि क्या त्रिभुज में अंक (सबसे तेज़ एल्गोरिथम मुझे मिला)। extractफ़ंक्शन के साथ तुलना करें , रन टाइम को 20 एस से 0.5 एस में घटाया जाता है। हालाँकि, फ़ंक्शन को 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()
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.