优化栅格:: calc函数 - 函数1对2 - R

时间:2017-04-13 18:58:38

标签: r raster calc

我正在根据2个栅格(输入ras)和'stratum'栅格计算新的栅格(输出ras)。 Stratum栅格值(1到4)指的是偏差和重量数据帧中的行。 Strata值'4'用于填充Strata栅格中的任何'NA',否则函数会崩溃。需要以下输入。

# load library
library(raster)

# reproducing the bias and weight data.frames
bias <- data.frame(
 ras_1 = c(56,-7,-30,0),
 ras_2 = c(29,18,-52,0),
 ras_3 = c(44,4,-15,0)
)
rownames(bias) <- c("Strat 1","Strat 2","Strat 3","Strat 4") 

weight <- data.frame(
 ras_1 = c(0.56,0.66,0.23,0.33),
 ras_2 = c(0.03,0.18,0.5,0.33),
 ras_3 = c(0.41,0.16,0.22,0.34)
)
rownames(weight) <- c("Strat 1","Strat 2","Strat 3","Strat 4") 

以下函数(fusion)允许我向输入栅格添加“偏置”值。在添加偏差之后,两个校正的输入栅格单元值将乘以权重值,这取决于它们属于哪个层。

输入2个栅格值的结果将被求和并使用'calc'返回。

## Create raster data for input

# create 2 rasters
r1 <- raster(ncol=10,nrow=10)
r2 <- raster(ncol=10,nrow=10)
r1[] <- sample(seq(from = 1, to = 500, by = 1), size = 100, replace = TRUE)
r2[] <- sample(seq(from = 1, to = 500, by = 1), size = 100, replace = TRUE)
r2[1:2] <- NA # include NA in input maps for example purpose

# Create strata raster (4 strata's)
r3 <- raster(ncol=10,nrow=10)
r3[] <- sample(seq(from = 1, to = 4, by = 1), size = 100, replace = TRUE)

Strata.n <- 4 # number of strata values in this example

fusion <- function(x) {
    result <- matrix(NA, dim(x)[1], 1)
    for (n in 1:Strata.n) {
    ok <- !is.na(x[,3]) &  x[,3] == n 
    a <- x[ok,1] + bias[n,1] # add bias to first input raster value             
    b <- x[ok,2] + bias[n,2] # add bias to second input raster value
    result[ok] <- a * weight[n,1] + b * weight[n,2] # Multiply values by weight
  }
  return(result)
}

s <- stack(r1,r2,r3)
Fused.map <- calc(s, fun = fusion, progress = 'text')

上述功能的问题在于:

  • 仅适用于2个栅格
  • 如果一个栅格具有NA,那么该单元格的结果将为NA

    is.na(Fused.map@data@values) # check for NA in the fused map
    

我想要的是:

  • 使用任意数量的输入栅格
  • 的功能
  • 它可以使用NA值(忽略栅格中的NA值)
  • 如果栅格具有NA值,则重新调整'权重',以便剩余的权重值合计为1

修改

以下函数可以满足我的需要,但是比大栅格上面的函数慢得多。融合在10秒内完成,下面的fusion2功能在大型栅格上需要8小时......

fusion2 <- function(x) {
  m <- matrix(x, nrow= 1, ncol=3) # Create matrix per stack of cells
  n <- m[,3] # get the stratum
  g <- m[1:(Strata.n-1)] + as.matrix(bias[n,]) # add bias to raster values
  g[g < 0] <- 0 # set values below 0 to 0
  w <- weight[n,1:(Strata.n-1)] # get correct strata weight values
  w[is.na(g)]<- NA # set weight to NA if (g) raster values are NA
  p <- sum(w, na.rm = T) # calculate sum of weight values
  pp <- w/p # divide weight values by sum to get the proportion to == 1
  pp <- as.numeric(pp)
  result <- as.integer(round(sum(pp*g, na.rm = T))) # return raster value
  return(result)
}

Fused.map <- calc(s, fun = fusion2, progress = 'text')

任何方法都可以将fusion2函数优化为与fusion1类似的方法?

> sessionInfo()
R version 3.3.2 (2016-10-31)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)    

感谢您的时间!

1 个答案:

答案 0 :(得分:1)

似乎有很多不必要的格式转换正在进行,并且使用最简单的数据结构是最快的。 calc参数是一个数字向量,因此您可以在任何地方使用数字向量。此外,舍入和转换为整数是多余的。

fusion3 <- function(x) {
  n <- x[3] # get the stratum
  g <- x[1:(Strata.n-1)] + as.numeric(bias[n,]) # add bias to raster values
  g[g < 0] <- 0 # set values below 0 to 0
  w <- as.numeric(weight[n,1:(Strata.n-1)]) # get correct strata weight values
  w[is.na(g)]<- NA # set weight to NA if (g) raster values are NA
  p <- sum(w, na.rm = T) # calculate sum of weight values
  pp <- w/p # divide weight values by sum to get the proportion to == 1
  result <- as.integer(sum(pp*g, na.rm = T)+0.5) # return raster value
  return(result)
}

在100x100光栅上,原始功能需要:

system.time(Fused.map <- calc(s, fun = fusion, progress = 'text'))
   user  system elapsed 
  0.015   0.000   0.015 
system.time(Fused.map <- calc(s, fun = fusion2, progress = 'text'))
   user  system elapsed 
  8.270   0.078   8.312 

修改后的功能已经快了5倍:

system.time(Fused.map3 <- calc(s, fun = fusion3, progress = 'text'))
   user  system elapsed 
  1.970   0.026   1.987 

接下来,从数据框中预先计算矩阵,这样您就不需要为每个像素执行此操作:

bias_matrix = as.matrix(bias)
weight_matrix = as.matrix(weight)

fusion3 <- function(x) {
  n <- x[3] # get the stratum
  g <- x[1:(Strata.n-1)] + bias_matrix[n,] # add bias to raster values
  g[g < 0] <- 0 # set values below 0 to 0
  w <- weight_matrix[n,1:(Strata.n-1)] # get correct strata weight values
  w[is.na(g)]<- NA # set weight to NA if (g) raster values are NA
  p <- sum(w, na.rm = T) # calculate sum of weight values
  pp <- w/p # divide weight values by sum to get the proportion to == 1
  result <- as.integer(sum(pp*g, na.rm = T)+0.5) # return raster value
  return(result)
}

我们得到:

system.time(Fused.map3 <- calc(s, fun = fusion3, progress = 'text'))
  user  system elapsed 
 0.312   0.008   0.318 

最后,还预先计算1:(Strata.n-1)

bias_matrix = as.matrix(bias)
weight_matrix = as.matrix(weight)
Strata.minus1 = 1:(Strata.n-1)

fusion3 <- function(x) {
  n <- x[3] # get the stratum
  g <- x[Strata.minus1] + bias_matrix[n,] # add bias to raster values
  g[g < 0] <- 0 # set values below 0 to 0
  w <- weight_matrix[n,Strata.minus1] # get correct strata weight values
  w[is.na(g)]<- NA # set weight to NA if (g) raster values are NA
  p <- sum(w, na.rm = T) # calculate sum of weight values
  pp <- w/p # divide weight values by sum to get the proportion to == 1
  result <- as.integer(sum(pp*g, na.rm = T)+0.5) # return raster value
  return(result)
}

我们得到:

system.time(Fused.map3 <- calc(s, fun = fusion3, progress = 'text'))
   user  system elapsed 
  0.252   0.011   0.262 

那还不到0.015,但你还必须考虑到你的原始函数不输出整数,也没有设置低于0到0的值,也不会使比例总和为1,也没有像你提到的那样处理NAs。

请注意,此功能仅适用于两个栅格,因为您将层硬编码为第3层。您应该使用带有两个参数的raster::overlay,层栅格和图层本身(或使用{{1将层栅格作为第1层,但这不是calc的设计目的。)