Самый простой способ манипулирования растровыми данными для дискретизации годового распределения дневной температуры - PullRequest
0 голосов
/ 28 мая 2018

У меня есть растровые данные наблюдений за исторической суточной температурой в Германии (историческая среднесуточная температура за 15 лет) в большом RasterBrick объекте.Вот как выглядят мои растровые данные в сетке:

> Temperature_rasterData
class       : RasterBrick 
dimensions  : 31, 37, 1147, 5479  (nrow, ncol, ncell, nlayers)
resolution  : 0.25, 0.25  (x, y)
extent      : 5.75, 15, 47.25, 55  (xmin, xmax, ymin, ymax)
coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0 
data source : in memory
names       : X1980.01.01, X1980.01.02, X1980.01.03, X1980.01.04, X1980.01.05, X1980.01.06, X1980.01.07, X1980.01.08, X1980.01.09, X1980.01.10, X1980.01.11, X1980.01.12, X1980.01.13, X1980.01.14, X1980.01.15, ... 
min values  :       -9.24,      -11.32,      -12.05,      -14.12,       -7.91,       -6.35,       -6.74,       -7.77,       -9.79,      -10.17,      -12.20,      -14.90,      -15.68,      -15.61,      -15.22, ... 
max values  :        2.19,        0.68,        0.30,        2.91,        5.25,        5.03,        4.33,        3.40,        1.52,        0.33,       -1.10,       -1.61,       -3.55,       -0.12,        0.19, ... 

Однако я намерен дискретизировать годовое распределение дневной температуры в фиксированный набор температурных бинов (мне нужно всего 10 бинов для каждого года),Здесь вы можете найти методы подробно: Влияние температуры на производительность и перераспределение факторов .Для этого мне нужно найти максимальное и минимальное значение температуры по всем этим многослойным растровым данным.Причина для нахождения температурного диапазона, потому что мне нужно разделить годовое распределение дневной температуры в каждой сетке на основе MAX/MIN значения температуры.

К сожалению, здесь я не могу воспроизвести эти несколько слоев данных RaterBrickв R, потому что исходные растровые данные с сеткой довольно большие и трудно воспроизвести маленький растр.Я надеюсь, что SO сообщество поймет ситуацию.Вот меньшие растровые данные для воспроизводимого использования: пожалуйста, попробуйте наименьший пример растровых данных , а вот мой R скрипт для обработки загруженных растровых данных:

temp_raster <- raster::stack('~/tg_day_2017_grid_ensmean.nc')
data(wrld_simpl) 
Germany <- wrld_simpl[wrld_simpl@data$NAME == "Germany",]
deu_ext <- extent(Germany)
Deu_crop <- crop(temp_raster ,deu_ext)

для получения температурного диапазонаДля этих более поздних растровых данных я попробовал следующее, и это не очень разумно, потому что мне нужно более упрощенное решение.Вот моя попытка в R:

nms <- names(Deu_crop)
yrs <- unique(sub('X(\\d+).+','\\1',nms))

getRange <- lapply(yrs,function(x) {
    range(Deu_crop[[grep(x,nms)]],na.rm=TRUE)
})

Я действительно не знаю, как дискретизировать данные в большом RasterBrick объекте.В частности, мне не совсем ясно, как манипулировать данными raster с целью дискретизации, потому что эти данные raster имеют несколько слоев с наблюдением огромной дневной средней температуры.Как я могу сделать это в R?Можно ли манипулировать многослойными raster данными для дискретизации?Любая идея?

Если есть более простой способ манипулировать большими данными raster, как я могу дискретизировать годовое распределение дневной температуры и составить гистограмму для каждого года?Есть ли самый простой способ сделать это в R?Заранее спасибо!

Вот вероятный гистограмма, которую я хочу сделать из многослойных raster данных:

enter image description here

Обновление :

Я собираюсь дискретизировать ежегодное распределение ежедневных наблюдений за температурой для каждого года в регионах Германии (AKA, многоугольник), вот области NUTS Германии на лету: шейп-файл Германии .

1 Ответ

0 голосов
/ 30 мая 2018

Вот решение (включая воспроизводимый пример):

library(raster)
library(lubridate)
library(tidyverse)

# creating some fake temperature data which matches your rasterstack

# create template raster
r <- raster(xmn=5.75, xmx= 15, ymn = 47.25, ymx =55,res=c(0.25,0.25))

# add fake temperature values
Deu_crop <- do.call(stack,lapply(1:5479,function(i) setValues(r,round(runif(n = ncell(r),min = -10,max = 25)))))

# add layer names
names(Deu_crop) <- paste0('X',gsub('-','.',ymd('1980.01.01') + days(1:5479)))

# check rasterstack

Deu_crop

# output
#
# class       : RasterStack 
# dimensions  : 31, 37, 1147, 5479  (nrow, ncol, ncell, nlayers)
# resolution  : 0.25, 0.25  (x, y)
# extent      : 5.75, 15, 47.25, 55  (xmin, xmax, ymin, ymax)
# coord. ref. : +proj=longlat +datum=WGS84 +ellps=WGS84 +towgs84=0,0,0 
# names       : X1980.01.02, X1980.01.03, X1980.01.04, X1980.01.05, X1980.01.06, X1980.01.07, ...
# min values  :         -10,         -10,         -10,         -10,         -10,         -10, ...
# max values  :          25,          25,          25,          25,          25,          25, ...

Так что Deu_crop должно быть сопоставимо с вашими данными с точки зрения структуры, конечно со случайными значениями температуры.

Шейп-файл нелегко воспроизвести, поэтому я скачал ваш и использовал его.Как я уже упоминал, некоторые полигоны немного малы для извлечения.

Самый быстрый способ сделать это - растеризовать шейп-файл в соответствии с растром данных, но некоторые полигоны не будут преобразованы, а другие, вероятно, в неправильную ячейку ... так что в этом случае это может бытьЛучше использовать raster::extract напрямую с шейп-файлом, даже если он немного медленный.Но если вам нужно сделать это всего пару раз, это сносно - выпейте кофе тем временем.

shp <- shapefile('eurostat_NUTS3_29-May-18/deu_adm_2006.shp')

# coffee time
e <- extract(Deu_crop,shp)

# add NUTS_ID as names to list 

names(e) <- shp$NUTS_ID

Чтобы рассчитать количество дней в году на одну корзину, я создаю функцию, которая использует tidiverse функциональность и использование lapply для перебора всего списка извлечений (один элемент списка соответствует одному многоугольнику):

# define bins

bins <- seq(-10,25,length.out = 5)

myfun <- function(ix){

gather(data.frame(e[[ix]],stringsAsFactors = F),'colname','temp') %>% 
    group_by(colname) %>% summarise(temp = mean(temp)) %>% ungroup() %>% # spatial mean
    mutate(year = sub('X(\\d{4}).+','\\1',colname)) %>% # get years
  select(- colname) %>% # drop colname column
  mutate(bin1= (temp <= bins[1]) * 1) %>%  # bin1
  mutate(bin2= (temp > bins[1] & temp <= bins[2]) * 1) %>% # bin2
  mutate(bin3= (temp > bins[2] & temp <= bins[3]) * 1) %>% # bin3
  mutate(bin4= (temp > bins[3] & temp <= bins[4]) * 1) %>% # bin4
  mutate(bin5= (temp > bins[4] & temp <= bins[5]) * 1) %>% # bin5
  mutate(bin6= (temp > bins[5]) * 1) %>% select(-temp) %>% # bin6
  group_by(year) %>% summarise_all(funs(sum)) %>% mutate(NUTS_ID = names(e)[ix]) # drop year, calculate occurences and add NUTS_ID

}

# create single dataframe

result <- do.call(rbind,lapply(1:length(e),function(ix) myfun(ix)))

Быстрый просмотр переменной result:

result

# output:
#
# # A tibble: 6,864 x 8
# year  bin1  bin2  bin3  bin4  bin5  bin6 NUTS_ID
# <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>   <chr>
# 1  1980    12    85    91    92    85     0   DEA54
# 2  1981     3    64    99   113    86     0   DEA54
# 3  1982     3    80   113    86    83     0   DEA54
# 4  1983     6    84    90    85   100     0   DEA54
# 5  1984     8    90    92    86    90     0   DEA54
# 6  1985     5    86    85    95    94     0   DEA54
# 7  1986     6    74    97   108    80     0   DEA54
# 8  1987     4    82    99    94    86     0   DEA54
# 9  1988     3    89    87    91    96     0   DEA54
#10  1989     8   103    92    73    89     0   DEA54
# # ... with 6,854 more rows

Обновление:

Для обработки бинов я сначала вычисляю бины по минимуму и максимуму всех данных, а затем использую новую функцию createBins, чтобы добавить их к извлечению каждого многоугольника.Это заменит myfun часть моего оригинального решения.

# new function

createBins <- function(df,bins_mat){

  for (i in 1:nrow(bins_mat)){

    bin <- sprintf('Bin%s;%s;%s',bins_mat[i,1],bins_mat[i,2],bins_mat[i,3])

    if (i ==1) df <- df %>% mutate(!!bin := (temp >= bins_mat[i,2] & temp <= bins_mat[i,3])*1)
    else df <- df %>% mutate(!!bin := (temp > bins_mat[i,2] & temp <= bins_mat[i,3])*1)
  }
  return(df)
}

# new version of myfun

myfun2 <- function(ix,bins_mat){
gather(data.frame(e[[ix]],stringsAsFactors = F),'colname','temp') %>% 
    group_by(colname) %>% summarise(temp = mean(temp)) %>% ungroup() %>% # spatial mean
    mutate(year = sub('X(\\d{4}).+','\\1',colname)) %>% # get years
    select(- colname) %>%  # drop colname column
    createBins(.,bins_mat) %>% select(-temp) %>%  
    group_by(year) %>% summarise_all(funs(sum)) %>% mutate(NUTS_ID = names(e)[ix])
}


# 11 values to create 10 interval bins

bins <- seq(min(cellStats(Deu_crop,'min')),min(cellStats(Deu_crop,'max')),length.out = 11)

# create a bin matrix (number, bin_minimum, bin_maximum) for later function

bins_mat <- cbind(1:10,bins[1:10],bins[2:11])

# create new result

result <- do.call(rbind,lapply(1:length(e),function(ix) myfun2(ix,binsmat)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...