Rを使用してポリゴン内の非NAラスターセルの数を取得する方法


8

私はArcGIS ZonalStatsを使用してあらゆる種類の問題に遭遇しており、Rが優れた方法であると考えました。私はRにかなり慣れていると言いますが、コーディングの背景を得ました。

状況としては、いくつかのラスターと、さまざまなサイズの多くのフィーチャを持つポリゴンシェープファイルがあります(すべてのフィーチャはラスターセルよりも大きく、ポリゴンフィーチャはラスターに位置合わせされています)。抽出付きのラスターライブラリを使用して、各ポリゴンフィーチャの平均値を取得する方法を理解しました。

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

私が抱えている問題は、ポリゴンの面積と同じポリゴン内のすべての非NAセルの間の面積ベースの比率も必要なことです。ラスターのセルサイズがわかっており、各ポリゴンの面積を取得できますが、不足しているリンクは、各フィーチャ内のすべての非NAセルの数です。ポリゴン内のすべてのセルのセル番号を取得するproxNA@data$Cnumb1000 <- cellFromPolygon(ras, proxNA)ことができ、ラスターセルの実際の値を取得する方法があると確信しています。これには、NA以外のすべてのセルの数を取得するためのループが必要です。カウントなど。しかし、私はそれを行うためのはるかに優れた迅速な方法があると確信しています!もしあなたの誰かがアイデアを持っているか、私を正しい方向に向けることができれば、私はとても感謝しています!


zonalstatsアプローチのデバッグを実際に行った場合(これはおそらく理想的な方法です)、Rの前にnumpyを確認します。つまりras、正当な値を使用してNAフラグを保持していますか?その値をフィルタリングするか、事後にこれらの値のカウントを取得できるようです。
Roland

@ローランド:ありがとう!NAはrasのNAであり、特定の値がありません。つまり、NA(または置換値)をフィルター処理し、ポリゴンごとに分類してカウントを取得し、全体のセル数から差し引くことができるということです。おもしろいですが、まだ少し長いです。私はカウント関数またはその線に沿った何かを望んでいました。
Hubert、

ラスター形式を使用しないと、シードバンプを取得できます。ラスターの利点は、メモリが安全であることです。spオブジェクトを作成しているため、ラスターに強制変換すると、利点が失われます。それをspオブジェクトにして「over」を使用すると、「extract」を使用するよりもはるかに高速になります。また、メモリ内のすべてを処理します。
Jeffrey Evans

回答:


5

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

抽出を使用する

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

多くのラスターがある場合は、最初にスタックを使用してそれらを結合します(範囲と解像度が同じ場合)

実際のポリゴン領域を取得するには、slot(i、 'area')アプローチを使用しないでください。平面データの場合はrgeos :: gArea(polys、byid = TRUE)を使用できます。球形データ(lon / lat)の場合はgeosphere :: areaPolygonを使用できます


3

ポリゴン領域の「実際の値」またはそれらと交差するセルの領域の「実際の値」に基づく比率が必要かどうかはわかりません。以下は、ポリゴンと交差するすべてのセルを使用するコードの例です(基本的に、NAセルと非NAセルの比率)。これはダミーの例であり、独自の関数を作成する必要があります。

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

このコードスニペットを使用して、エリアスロットから抽出することにより、エリアデータをポリゴンデータに追加できます。これは、「実際の」ポリゴン領域を使用して比率を設定する場合に使用できます。

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

forループに代わる最も効率的でかなり高速な代替手段は、関数のような「適用」です。Rには、さまざまなオブジェクトクラスやデータ構造に利用できるものが数多くあります。この場合、extractはリストを返すため、lapply(リスト適用)を使用します。これは、リストオブジェクトに基本関数またはカスタム関数を適用する方法です。リストに格納されているオブジェクトクラスはベクトルであり、関数は非常に単純です。ブリックまたはスタックラスタオブジェクトで抽出を使用する場合、リストに保存される結果のオブジェクトは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)         

ジェフリー、ありがとう!私はあなたの答えからかなりのことを学びました。しかし、私は自分自身を十分に説明していなかったと思います。私が求めている比率は、Poly1内のNonNAセルの面積とPoly1の面積です。一部のポリゴンは、ラスターセルで完全に覆われていない。ポリゴン内のすべてのセルの平均値をvListに書き込むのは素晴らしいことです。各セルの面積がわかっているので、平均が導き出されたNonNAセルの数も取得する必要があります。この比率は(セルの数*セルの面積)/ポリゴンの面積で簡単に計算できます。どうもありがとう!
Hubert、

1

私はあなたのファイルにアクセスできませんが、あなたの説明に基づいてこれはうまくいくはずです:

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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.