Cara mendapatkan jumlah sel raster non-NA dalam poligon menggunakan R


8

Saya telah mengalami berbagai masalah menggunakan ArcGIS ZonalStats dan berpikir R bisa menjadi cara yang hebat. Mengatakan bahwa saya cukup baru untuk R, tetapi mendapat latar belakang pengkodean.

Situasinya adalah bahwa saya memiliki beberapa raster dan poligon bentuk dengan banyak fitur ukuran yang berbeda (meskipun semua fitur lebih besar dari sel raster dan fitur poligon disejajarkan dengan raster). Saya telah menemukan cara untuk mendapatkan nilai rata-rata untuk setiap fitur poligon menggunakan perpustakaan raster dengan ekstrak:

#load packages required
require(rgdal)
require(sp)
require(raster)
# ---Set the working directory-------
datdir <- "/test_data/"

#Read in grid of water depth
ras <- raster("test_data/raster/pl_sm_rp1000/w001001.adf")

#read in polygon shape file
proxNA <- shapefile("test_data/proxy/PL_proxy_WD_NA_test") 

#calc mean depth per polygon feature
#unweighted - only assigns grid to district if centroid is in that district
proxNA$RP1000 <- extract(ras, proxNA, fun = mean, na.rm = TRUE, weights = FALSE)

#plot depth values 
spplot(proxNA[,'RP1000'])

Masalah yang saya miliki adalah bahwa saya juga membutuhkan rasio berbasis area antara area poligon dan semua sel non NA dalam poligon yang sama. Saya tahu apa ukuran sel raster itu dan saya bisa mendapatkan luas untuk setiap poligon, tetapi tautan yang hilang adalah jumlah semua sel non-NA di setiap fitur. Saya berhasil mendapatkan nomor sel semua sel dalam poligon proxNA@data$Cnumb1000 <- cellFromPolygon(ras, proxNA)dan saya yakin ada cara untuk mendapatkan nilai aktual dari sel raster, yang kemudian membutuhkan loop untuk mendapatkan jumlah semua sel non-NA dikombinasikan dengan hitungan, dll. TAPI, saya yakin ada cara yang jauh lebih baik dan lebih cepat untuk melakukan itu! Jika ada di antara Anda yang memiliki ide atau dapat mengarahkan saya ke arah yang benar, saya akan sangat berterima kasih!


Jika saya benar-benar selesai dengan debug pendekatan zonalstats (yang mungkin akan menjadi cara yang ideal), saya akan melihat numpy sebelum R. Yang mengatakan, apakah rasmemegang bendera NA menggunakan nilai yang sah? Sepertinya Anda bisa memfilter untuk nilai itu atau mendapatkan hitungan dari nilai-nilai itu setelah faktanya.
Roland

@Rand: Terima kasih! NA adalah NA dalam ras dan belum mendapatkan nilai tertentu. Jadi yang Anda katakan adalah saya bisa memfilter untuk NA (atau nilai penggantian) dan mengkategorikan untuk setiap poligon untuk mendapatkan hitungan, lalu kurangi dari jumlah sel keseluruhan. Menarik, tapi agak masih bertele-tele. Saya berharap untuk fungsi Hitungan atau sesuatu di sepanjang garis itu.
Hubert

Anda bisa mendapatkan benjolan benih dengan tidak menggunakan format raster. Keuntungan dari raster adalah memori yang aman. Karena Anda membuat objek sp maka paksaan untuk raster Anda kehilangan keuntungan. Menyimpannya sebagai objek sp dan menggunakan "lebih" akan jauh lebih cepat daripada menggunakan "ekstrak". Anda juga akan memproses semuanya dalam memori.
Jeffrey Evans

Jawaban:


5

Contoh data dari Jeffrey

library(raster)
r <- raster(ncols=10, nrows=10)
set.seed(0)
x <- runif(ncell(r))
x[round(runif(25,1,100),digits=0)] <- NA
r[] <- x
cds1 <- rbind(c(-180,-20), c(-160,5), c(-60, 0), c(-160,-60), c(-180,-20))
cds2 <- rbind(c(80,0), c(100,60), c(120,0), c(120,-55), c(80,0))
polys <- SpatialPolygons(list(Polygons(list(Polygon(cds1)), 1),  Polygons(list(Polygon(cds2)), 2)))
polys <- SpatialPolygonsDataFrame(polys, data.frame(ID=sapply(slot(polys, "polygons"), function(x) slot(x, "ID"))))

Sekarang gunakan ekstrak

extract(r, polys, fun=function(x, ...) length(na.omit(x))/length(x))
#[1] 0.8333333 0.6666667

Jika Anda memiliki banyak raster, pertama gunakan stack untuk menggabungkannya (jika mereka memiliki tingkat dan resolusi yang sama)

Untuk mendapatkan area poligon yang sebenarnya Anda tidak harus menggunakan pendekatan slot (i, 'area'). Untuk data planar Anda dapat menggunakan rgeos :: gArea (polys, byid = TRUE) Untuk data bola (lon / lat) Anda dapat menggunakan geosphere :: areaPolygon


3

Saya tidak yakin apakah Anda ingin rasio berdasarkan "nilai riil" area poligon atau area sel yang memotongnya. Berikut adalah beberapa contoh kode yang menggunakan semua sel yang memotong poligon (pada dasarnya, rasio sel NA dengan sel non-NA). Ini adalah contoh tiruan dan Anda harus menulis fungsi Anda sendiri.

    # Create some example data
    require(raster)
    require(sp)

    r <- raster(ncols=10, nrows=10)
      x <- runif(ncell(r))
        x[round(runif(25,1,100),digits=0)] <- NA
          r[] <- x
      cds1 <- rbind(c(-180,-20), c(-160,5), c(-60, 0), c(-160,-60), c(-180,-20))
        cds2 <- rbind(c(80,0), c(100,60), c(120,0), c(120,-55), c(80,0))
          polys <- SpatialPolygons(list(Polygons(list(Polygon(cds1)), 1), 
                                   Polygons(list(Polygon(cds2)), 2)))
            polys <- SpatialPolygonsDataFrame(polys, data.frame(ID=sapply(slot(polys, "polygons"), 
                                              function(x) slot(x, "ID"))))
plot(r)
  plot(polys, add=TRUE)

Anda dapat menggunakan potongan kode ini untuk menambahkan kolom area ke data poligon Anda dengan mengekstraksi dari slot area. Ini dapat digunakan jika Anda ingin membuat perbandingan menggunakan area poligon "nyata".

# Add area of polygon(s)
polys@data <- data.frame(polys@data, Area=sapply(slot(polys, 'polygons'), 
                         function(i) slot(i, 'area')))  

Alternatif yang paling efisien, dan lebih cepat, untuk loop adalah "berlaku" seperti fungsi. Ada sejumlah ini tersedia di R yang digunakan untuk kelas objek atau struktur data yang berbeda. Dalam hal ini, karena ekstrak mengembalikan daftar, kami akan menggunakan lapply (daftar berlaku). Ini adalah cara untuk menerapkan fungsi basis atau kustom ke objek daftar. Kelas objek yang disimpan dalam daftar adalah vektor, fungsinya cukup lurus ke depan. Jika Anda menggunakan ekstrak pada objek bata atau tumpukan raster objek yang dihasilkan disimpan dalam daftar akan menjadi objek data.frame.

# On a single raster object, extract returns list object with stored vectors.                           
( vList <- extract(r, polys, na.rm=FALSE) )
  class(vList)

# Use lapply to apply function that calculates ratio of NA to non-NA values
#   wrapping lapply in unlist() collapses result into a vector  
aRatio <- function(x) { if(length(x[is.na(x)]) > 0) (length(x[is.na(x)]) / length(x[!is.na(x)])) else 0 }  
  ( vArea <- unlist( lapply(vList, FUN=aRatio ) ) )

# Assign ordered vector back to polygons
polys@data <- data.frame(polys@data, NAratio=vArea)
  str(polys@data)         

Terima kasih Jeffrey! Saya telah belajar sedikit dari jawaban Anda. Tapi saya pikir saya tidak menjelaskan diri saya dengan cukup baik. Rasio yang saya cari adalah Luas Sel NonNA dalam Poli1 dan Luas Poli1. Beberapa poligon tidak seluruhnya ditutupi oleh sel raster. Menulis nilai rata-rata dari semua sel dalam poligon ke dalam vList itu bagus. Sekarang saya hanya perlu mendapatkan jumlah sel NonNA juga dari mana rata-rata diturunkan karena saya tahu luas masing-masing sel. Rasio ini kemudian dapat dengan mudah diperoleh dengan (jumlah sel * area sel) / area poligon. Terimakasih banyak!
Hubert

1

Saya tidak memiliki akses ke file Anda, tetapi berdasarkan apa yang Anda uraikan, ini seharusnya berfungsi:

library(raster)
mask_layer=shapefile(paste0(shapedir,"AOI.shp"))
original_raster=raster(paste0(template_raster_dir,"temp_raster_DecDeg250.tif"))
nonNA_raster=!is.na(original_raster)
masked_img=mask(nonNA_raster,mask_layer) #based on centroid location of cells
nonNA_count=cellStats(masked_img, sum)
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.