Cách lấy số lượng tế bào raster không NA trong đa giác bằng R


8

Tôi đã gặp phải tất cả các vấn đề khi sử dụng ArcGIS ZonalStats và nghĩ rằng R có thể là một cách tuyệt vời. Nói rằng tôi khá mới với R, nhưng có nền tảng mã hóa.

Tình huống là tôi có một số raster và một shapefile đa giác với nhiều tính năng có kích thước khác nhau (mặc dù tất cả các tính năng đều lớn hơn một ô raster và các tính năng đa giác được căn chỉnh theo raster). Tôi đã tìm ra cách lấy giá trị trung bình cho từng tính năng đa giác bằng thư viện raster với trích xuất:

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

Vấn đề tôi có là tôi cũng cần một tỷ lệ dựa trên diện tích giữa diện tích của đa giác và tất cả các ô không NA trong cùng một đa giác. Tôi biết kích thước ô của raster là bao nhiêu và tôi có thể lấy diện tích cho mỗi đa giác, nhưng liên kết bị thiếu là số lượng của tất cả các ô không NA trong mỗi tính năng. Tôi đã quản lý để có được số ô của tất cả các ô trong đa giác proxNA@data$Cnumb1000 <- cellFromPolygon(ras, proxNA)và tôi chắc chắn có một cách để lấy giá trị thực của ô raster, sau đó yêu cầu một vòng lặp để lấy số của tất cả các ô không NA kết hợp với một số đếm, vv NHƯNG, tôi chắc chắn có một cách tốt hơn và nhanh hơn để làm điều đó! Nếu bất kỳ ai trong số các bạn có ý tưởng hoặc có thể chỉ cho tôi đi đúng hướng, tôi sẽ rất biết ơn!


Nếu tôi đã thực sự hoàn thành w / gỡ lỗi phương pháp zonalstats (có thể là cách lý tưởng), tôi sẽ xem xét numpy trước R. Điều đó nói rằng, đang rasgiữ cờ NA sử dụng giá trị hợp pháp? Có vẻ như bạn có thể lọc giá trị đó hoặc lấy số lượng các giá trị đó sau thực tế.
Roland

@Roland: Cảm ơn! NA là NA trong ras và chưa có giá trị cụ thể. Vì vậy, những gì bạn đang nói là tôi có thể lọc NA (hoặc giá trị thay thế) và phân loại cho từng đa giác để lấy số đếm, sau đó trừ đi tổng số ô. Thú vị, nhưng một chút vẫn hơi dài dòng. Tôi đã hy vọng cho một chức năng Count hoặc một cái gì đó dọc theo dòng đó.
Hubert

Bạn có thể có được một vết sưng hạt giống bằng cách không sử dụng định dạng raster. Ưu điểm của raster là bộ nhớ an toàn. Vì bạn đang tạo một đối tượng sp sau đó ép buộc để raster nên bạn mất lợi thế. Giữ cho nó một đối tượng sp và sử dụng "over" sẽ nhanh hơn nhiều so với sử dụng "giải nén". Bạn cũng sẽ được xử lý mọi thứ trong bộ nhớ.
Jeffrey Evans

Câu trả lời:


5

Dữ liệu ví dụ từ 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"))))

Bây giờ sử dụng giải nén

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

Nếu bạn có nhiều trình quét, trước tiên hãy sử dụng ngăn xếp để kết hợp chúng (nếu chúng có cùng mức độ và độ phân giải)

Để có được khu vực đa giác thực tế, bạn không nên sử dụng phương pháp vị trí (i, 'area'). Đối với dữ liệu phẳng, bạn có thể sử dụng rgeos :: gArea (polys, byid = TRUE) Đối với dữ liệu hình cầu (lon / lat), bạn có thể sử dụng geosphere :: areaPolygon


3

Tôi không chắc chắn nếu bạn muốn tỷ lệ dựa trên "giá trị thực" của các khu vực đa giác hoặc các khu vực của các ô giao nhau với chúng. Dưới đây là một số mã ví dụ sử dụng tất cả các ô giao nhau với đa giác (về cơ bản, tỷ lệ của các ô NA với các ô không NA). Đây là một ví dụ giả và bạn sẽ cần phải viết chức năng của riêng bạn.

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

Bạn có thể sử dụng đoạn mã này để thêm một cột khu vực vào dữ liệu đa giác của mình bằng cách trích xuất từ ​​vị trí khu vực. Điều này có thể được sử dụng nếu bạn muốn tỷ lệ bằng cách sử dụng khu vực đa giác "thực".

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

Hiệu quả nhất và nhanh hơn đáng kể, thay thế cho các vòng lặp là "áp dụng" như các hàm. Có một số trong số này có sẵn trong R được sử dụng cho các lớp đối tượng hoặc cấu trúc dữ liệu khác nhau. Trong trường hợp này, vì trích xuất trả về một danh sách, chúng tôi sẽ sử dụng lapply (áp dụng danh sách). Đây là một cách để áp dụng một cơ sở hoặc chức năng tùy chỉnh cho một đối tượng danh sách. Lớp đối tượng được lưu trữ trong danh sách là một vectơ, hàm khá thẳng về phía trước. Nếu bạn sử dụng giải nén trên một đối tượng raster brick hoặc stack, các đối tượng kết quả được lưu trữ trong danh sách sẽ là các đối tượng 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)         

Cảm ơn Jeffrey! Tôi đã học được khá nhiều từ câu trả lời của bạn. Nhưng tôi nghĩ rằng tôi đã không giải thích bản thân mình đủ tốt. Tỷ lệ mà tôi theo sau là Khu vực của các tế bào NonNA trong Poly1 so với Khu vực của Poly1. Một số đa giác không hoàn toàn được bao phủ bởi các tế bào raster. Viết giá trị trung bình của tất cả các ô trong đa giác vào vList là tuyệt vời. Bây giờ tôi chỉ cần lấy số lượng tế bào NonNA mà từ đó giá trị trung bình được lấy từ khi tôi biết diện tích của mỗi ô. Tỷ lệ sau đó có thể dễ dàng xuất phát theo (số ô * diện tích ô) / diện tích đa giác. Cảm ơn nhiều!
Hubert

1

Tôi không có quyền truy cập vào các tệp của bạn, nhưng dựa trên những gì bạn mô tả, điều này sẽ hoạt động:

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