J'extrais la superficie et le pourcentage de couverture de différents types d'utilisation des terres à partir d'un raster basé sur plusieurs milliers de limites de polygones. J'ai trouvé que la fonction d'extraction fonctionne beaucoup plus rapidement si j'itère à travers chaque polygone individuel et recadre puis masque le raster jusqu'à la taille du polygone particulier. Néanmoins, c'est assez lent, et je me demande si quelqu'un a des suggestions pour améliorer l'efficacité et la vitesse de mon code.
La seule chose que j'ai trouvée à ce sujet est cette réponse de Roger Bivand qui a suggéré d'utiliser GDAL.open()
et GDAL.close()
ainsi que getRasterTable()
et getRasterData()
. J'ai étudié ces problèmes, mais j'ai eu des problèmes avec gdal dans le passé et je ne le connais pas assez bien pour savoir comment le mettre en œuvre.
Exemple reproductible:
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)
Méthode la plus rapide à ce jour
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
Traitement parallèle
Le traitement parallèle a réduit de moitié le temps de l'utilisateur, mais a annulé l'avantage en doublant le temps système. Raster l'utilise pour la fonction d'extrait, mais malheureusement pas pour la fonction de recadrage ou de masque. Malheureusement, cela laisse un peu plus de temps total écoulé en raison de «l'attente» par le «IO».
beginCluster( detectCores() -1) #use all but one core
exécuter du code sur plusieurs cœurs:
user system elapsed
23.31 0.68 42.01
puis terminez le cluster
endCluster()
Méthode lente: la méthode alternative de faire un extrait directement à partir de la fonction raster prend beaucoup plus de temps, et je ne suis pas sûr de la gestion des données pour les mettre sous la forme que je veux:
system.time(ext<-extract(c,bound))
user system elapsed
1170.64 14.41 1186.14
Réponses:
J'ai enfin réussi à améliorer cette fonction. J'ai trouvé que pour mes besoins, c'était le plus rapide au
rasterize()
polygone en premier et à utiliser à lagetValues()
place deextract()
. La pixellisation n'est pas beaucoup plus rapide que le code d'origine pour tabuler les valeurs de raster dans de petits polygones, mais elle brille quand il s'agit de grandes zones de polygone qui avaient de grands rasters à recadrer et les valeurs extraites. J'ai également trouvé quegetValues()
c'était beaucoup plus rapide que laextract()
fonction.J'ai également compris le traitement multicœur à l'aide de
foreach()
.J'espère que cela est utile pour d'autres personnes qui souhaitent une solution R pour extraire des valeurs raster d'une superposition de polygones. Ceci est similaire à la "Tabulation Intersection" d'ArcGIS, qui ne fonctionnait pas bien pour moi, renvoyant des sorties vides après des heures de traitement, comme cet utilisateur.
Voici la fonction:
Donc, pour l'utiliser, ajustez le
single@data$OWNER
pour qu'il corresponde au nom de la colonne de votre polygone d'identification (devinez qui aurait pu être intégré à la fonction ...) et insérez:la source
getValues
était beaucoup plus rapide que laextract
ne semble pas valable car si vous utilisezextract
vous n'avez pas à fairecrop
etrasterize
(oumask
). Le code de la question d'origine fait les deux, et cela devrait doubler le temps de traitement.Accélérez l'extraction du raster (pile de raster) à partir d'un point, d'un XY ou d'un polygone
Excellente réponse Luke. Vous devez être un assistant R! Voici un ajustement très mineur pour simplifier votre code (peut améliorer légèrement les performances dans certains cas). Vous pouvez éviter certaines opérations en utilisant cellFromPolygon (ou cellFromXY pour les points), puis clip et getValues.
Extraire des données de polygones ou de points à partir de piles de rasters ------------------------
la source
Si une perte de précision de la superposition n'est pas très importante - en supposant qu'elle soit précise pour commencer - on peut généralement atteindre des vitesses de calcul zonales beaucoup plus importantes en convertissant d'abord les polygones en raster. Le
raster
package contient lazonal()
fonction, qui devrait bien fonctionner pour la tâche prévue. Cependant, vous pouvez toujours sous-définir deux matrices de la même dimension à l'aide d'une indexation standard. Si vous devez conserver des polygones et que le logiciel SIG ne vous dérange pas, QGIS est en fait plus rapide aux statistiques zonales qu'ArcGIS ou ENVI-IDL.la source
J'ai également eu du mal avec cela pendant un certain temps, en essayant de calculer la part de la superficie des classes de couverture terrestre d'une carte de grille de ~ 300mx300m dans une grille de ~ 1kmx1km. Ce dernier était un fichier polygonal. J'ai essayé la solution multicœur mais c'était encore trop lent pour le nombre de cellules de grille que j'avais. Au lieu de cela, je:
Cette procédure s'exécute assez rapidement et sans problème de mémoire sur mon PC, lorsque je l'ai essayée sur une carte de couverture terrestre avec> 15 cellules de grille de moulin à 300 mx 300 m.
Je suppose que l'approche ci-dessus fonctionnera également si l'on veut combiner un fichier polygonal avec des formes irrégulières avec des données raster. Peut-être, on pourrait combiner les étapes 1 et 2 en tramant directement le fichier polygonal sur une grille de 300mx300 en utilisant rasterize (raster probablement lent) ou gdal_rasterize. Dans mon cas, j'avais également besoin de reprojeter, alors j'ai utilisé gdalwarp pour reprojeter et désagréger en même temps.
la source
Je dois faire face à ce même problème pour extraire des valeurs à l'intérieur du polygone d'une grande mosaïque (50k x 50k). Mon polygone n'a que 4 points. La méthode la plus rapide que j'ai trouvée est de
crop
mosaïquer en limite de polygone, de trianguler le polygone en 2 triangles, puis de vérifier si les points dans le triangle (l'algorithme le plus rapide que j'ai trouvé). Comparé à laextract
fonction, le temps d'exécution passe de 20 s à 0,5 s. Cependant, la fonctioncrop
nécessite encore environ 2 s pour chaque polygone.Désolé, je ne peux pas fournir l'exemple reproductible complet. Les codes R ci-dessous n'incluent pas les fichiers d'entrées.
Cette méthode ne fonctionne que pour les polygones simples.
la source