Извлечение значений из растра и добавление к существующему фрейму данных - PullRequest
0 голосов
/ 11 апреля 2019

Я пытаюсь извлечь значения из растрового стека и добавить их в существующий фрейм данных. Значения представляют собой набор метрик (PatchStat из пакета r SDMtools), которые я могу извлечь в формат списка, но я застрял, пытаясь привязать значения к существующему фрейму данных.

Входные данные:

library(sp)
library(sf)
library(raster)
library(dplyr)
library(SDMTools)

mydata <- read.table(header=TRUE, text = "
                         animal        X       Y ord.year
1 pb_20414 157978.9 2323819     2009168
2 pb_20414 156476.3 2325586     2009168
3 pb_06817 188512.0 2299679     2006263
4 pb_06817 207270.9 2287248     2006264")

# add rasters

s <- stack(system.file("external/rlogo.grd", package="raster")) 
names(s) <- c('masie_ice_r00_v01_2009168_4km', 'masie_ice_r00_v01_2006263_4km', 'masie_ice_r00_v01_2006264_4km')

# Create sp object

projection <-CRS('+proj=stere +lat_0=90 +lat_ts=60 +lon_0=-80 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +units=m + datum=WGS84 +no_defs +towgs84=0,0,0') # matches MASIE raster
coords <- cbind(mydata$X, mydata$Y)
mydata.sp <- SpatialPointsDataFrame(coords = coords, data = mydata, proj4string = projection)

# Create sf object

mydata.sf <- st_as_sf(mydata) 
mydata.buf30 <- st_buffer(mydata.sf, 30000)

Моя цель - сопоставить каждую точку GPS (X, Y) с правильным GeoTIFF по дате (mydata$ord.year), обрезать растр в (пространственно явный) 30-километровый буфер, запустить PatchStat в программе SDMtools для R и добавить результаты в исходный фрейм данных. Суть в том, что результаты PatchStat предоставляются в кадре данных, поэтому у меня возникают проблемы с сопоставлением этих результатов с моим существующим кадром данных.

Вот пример результатов, представленных при запуске PatchStat:

 patchID n.cell n.core.cell n.edges.perimeter n.edges.internal area core.area perimeter
2       3     73          13                86              206   73        13        86
  perim.area.ratio shape.index frac.dim.index core.area.index
2         1.178082    2.388889       1.430175       0.1780822 

Вот что я смог сделать до сих пор:

# separate date component of TIF name to correspond to mydata$ord.year 

stack <- list()
date<-vector()
for (i in 1:length(rasterlist)) {
  stack[[i]]<-raster(rasterlist[i])
  tt<-unlist(strsplit(names(stack[[i]]), "[_]"))
  date[i]<-tt[which(nchar(tt)==max(nchar(tt)))]
}

st <- stack(stack) # Create rasterstack object

# crop raster to buffer

mydata.sp <- as(mydata.sf, 'Spatial') # back to sp object

# pull raster data from GeoTIFF that corresponds to ordinal date

pat <- list()
for (i in 1:nrow(mydata.sp)) {
  st2<-st[[which(date==mydata.sp$ord.year[i])]]
  GeoCrop <- raster::crop(st2, mydata.sp[i,])
  GeoCrop_mask <- raster::mask(GeoCrop, mydata.sp[i,])
  pat[[i]] <- PatchStat(GeoCrop_mask)}

Кроме того, я исключил один из двух типов растительного покрова, чтобы у каждого элемента в списке была только одна строка: pat2 <- lapply(pat, `[`, -1,) # remove first row in each list element so only one row remains (using program plyr for R)

Теперь я хотел бы сопоставить эти строки с моим исходным фреймом данных, чтобы pat2[[1]] добавлялся к mydata.sp[1,] следующим образом (предполагая, что a, b и c - столбцы метаданных в моем исходном SpatialPointsDataFrame). Я хотел бы, чтобы все столбцы данных из PatchStat были добавлены, но для экономии времени и места я включил только первые три здесь:

a   b   c   PatchID   n.cell   n.core.cell 
1   2   3   3         73       13

Примечание: Если возможно, я бы хотел, чтобы весь этот процесс был включен в цикл for, чтобы минимизировать пространство для ошибок, а также время обработки.

Большое спасибо!

Ответы [ 2 ]

0 голосов
/ 14 апреля 2019

Спасибо за ваши усилия предоставить пример данных. Но это все еще не полностью (это относится к файлам, которых у нас нет. Вы могли бы к этому

library(raster)
library(SDMTools)

s <- stack(system.file("external/rlogo.grd", package="raster")) 
s <- round(s / 50) # to have fewer patches
names(s) <- c('masie_ice_r00_v01_2009168_4km', 'masie_ice_r00_v01_2006263_4km', 'masie_ice_r00_v01_2006264_4km')

df <- data.frame(ord.year=c("2009168", "2009168", "2006263", "2006264"))
pts <- SpatialPoints(cbind(c(20,40,60,80), c(20,40,60,20)))
crs(pts) <- crs(s)
pts <- SpatialPointsDataFrame(pts, df)

Сделать буфер

b <- buffer(pts, 15, dissolve=FALSE)

Получить подходящие имена

nms <- names(s)
nms <- gsub('masie_ice_r00_v01_', '', nms)
nms <- gsub('_4km', '', nms)

Цикл для сопоставления имен и размещения результатов в списке

p <- list()
for (i in 1:length(b)) {
    j <- which(b$ord.year[i] == nms)
    r <- s[[j]]
    z <- crop(r, b[i,])
    z <- mask(z, b[i,])
    p[[i]] <- PatchStat(z)
}

Обратите внимание, что у каждого элемента p есть data.frame с несколькими строками и столбцами.

 p[[1]]
 #patchID n.cell n.core.cell n.edges.perimeter n.edges.internal area core.area perimeter perim.area.ratio shape.index frac.dim.index core.area.index
 #1       1     53           5                68              144   53         5        68        1.2830189    2.266667       1.427207      0.09433962
 #2       2    123           8               182              310  123         8       182        1.4796748    3.956522       1.586686      0.06504065
 #3       3    149          31               190              406  149        31       190        1.2751678    3.800000       1.543074      0.20805369
 #4       4     54           2               114              102   54         2       114        2.1111111    3.800000       1.679578      0.03703704
 #5       5    337         206               146             1202  337       206       146        0.4332344    1.972973       1.236172      0.61127596

Если вы хотите только первые строки

 pp <- t(sapply(p, function(i) i[1,]))

Объединение этого с оригинальными данными. Рамка теперь тривиальна

 dfpp <- cbind(df, pp)
0 голосов
/ 11 апреля 2019

Ну, я сделал эту ужасную вещь и получил то, что хотел. Но мне это не нравится. Если у кого-то есть идея получше, я бы хотел ее услышать!

# Change objects to df  
pat2 <- lapply(pat, `[`, -1,) # remove first row in each list element

library(plyr) # ldply command

pat3 <- ldply (pat2, data.frame)

pat4 <- bind_cols(pb, pat3)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...