大型栅格数据的矩阵索引匹配

时间:2019-06-25 20:22:28

标签: r matrix indexing raster large-data

我有一个较大的栅格数据(X),其尺寸为32251 * 51333。 X的值是另一个数组(Y)的重复,其大小为3 * 10 ^ 6。 现在,我想通过将X的值与Y的每个值进行匹配来更改X的值,例如,我可以像这样编程

for (i in 1:length(Y)){
 X[X==Y[i]] = Z[i]   #Z is just another array with the same size as Y
}

问题在于,首先匹配X[X==Y[i]] = Z[i]的索引不起作用,因为X太大。几分钟后,程序会通过给出错误"Error: cannot allocate vector of size 6.2 Gb".来停止 其次,即使Y的大小为10 ^ 6,从1到length(Y)的循环也可能需要“永远”才能完成。

我想到的一种方法是将X分成小块,然后对每个块进行索引匹配。但是我觉得这仍然需要很多时间。

是否有更好的方法来实现上述目标?

第一次更新:

由于@Lyngbakr提供的示例,我将进一步阐述这个问题。由于我使用的栅格很大(32251 * 51333),因此似乎无法上传。 @Lyngbakr给出的示例与我想要的非常相似,除了创建的栅格太小之外。现在,按照该示例,我通过生成尺寸为3000 * 2700的更大的栅格进行了两次测试。参见下面的代码。

#Method 1: Use subs
start_time <- Sys.time()
Y <- 1:9
Z <- 91:99
X <- raster(matrix(rep(Y, 3), nrow=3000,ncol = 2700))
df <- data.frame(Y, Z)
X <- subs(X, df)
end_time <- Sys.time()
end_time - start_time
#Time difference of 2.248908 mins

#Method 2: Use for loop
start_time <- Sys.time()
Y <- 1:9
Z <- 91:99
X <- raster(matrix(rep(Y, 3), nrow=3000,ncol = 2700))
for (i in 1:length(Y)){
  X[X==Y[i]]=Z[i] #this indexing of R seems not efficient if X becomes large
}
end_time <- Sys.time()
end_time - start_time
#Time difference of 10.22717 secs

如您所见,简单的 for 循环比subs函数更有效。请记住,示例中显示的栅格仍然比我使用的栅格小(大约小100倍)。此外,示例中的数组Y非常小。现在的问题可能是,如何加快方法2(这只是一个简单的for循环)?

1 个答案:

答案 0 :(得分:0)

您正在寻找subs函数。我不知道它是否适用于大型栅格,但是您可以尝试以下方法。

我加载了raster包并创建了一些虚拟数据。 (如果您在问题中提供数据,这将真的会有所帮助。)然后,我绘制结果。

# Load library
library(raster)
#> Loading required package: sp

# Z holds values that will replace Y
Y <- 1:9
Z <- 91:99

# Create dummy raster
X <- raster(matrix(rep(Y, 3), ncol = 9))

# Examine raster
plot(X)

如您所见,X只是一堆Y个矢量修补在一起。接下来,我将YZ绑定到一个数据帧df中。

# Combine y & z into a data frame
df <- data.frame(Y, Z)

最后,我使用subsY的值替换为Z的值。

# Substitute Z for Y in X
X <- subs(X, df)

快速浏览一下栅格,表明值已正确替换。

# Examine raster
plot(X)

reprex package(v0.2.1.9000)于2019-06-25创建


更新

当性能成为问题时,

Rcpp确实很有帮助。下面,我比较三种方法:

  1. 在R中循环(来自问题)
  2. 使用光栅包中的subs
  3. 使用Rcpp在C ++中循环

顺便说一句,Sys.time()并不是检查性能的好方法,因此我建议使用microbenchmark

# Load library
library(raster)

# Define vectors and raster
Y <- 1:9
Z <- 91:99
X <- raster(matrix(rep(Y, 3), nrow = 3000, ncol = 2700))

method_1subs函数。

# Using subs function
method_1 <- function(){
  df <- data.frame(Y, Z)
  X <- subs(X, df)
}

method_2是您的原始循环方法。

# Using R loop
method_2 <- function(){
  for (i in 1:length(Y)){
    X[X==Y[i]]=Z[i] 
  }
  X
}

method_3是用C ++实现的循环方法。

# Using Rcpp loops
src <-
"Rcpp::NumericMatrix subs_cpp(Rcpp::NumericMatrix X, Rcpp::NumericVector Y, Rcpp::NumericVector Z){
  for(int i = 0; i < Y.length(); ++i){
    for(int j = 0; j < X.ncol(); ++j){
      for(int k = 0; k < X.nrow(); ++k){
        if(X(k, j) == Y(i)){
          X(k, j) = Z(i);
        }
      }
    }
  }  

  return X;
}"

Rcpp::cppFunction(src)

method_3 <- function(){
  subs_cpp(as.matrix(X), Y, Z)
}

在这里,我对这些方法进行基准测试。

# Run benchmarking
microbenchmark::microbenchmark(method_1(), method_2(), method_3(), times = 10)

# Unit: milliseconds
#       expr        min         lq       mean     median         uq       max neval
# method_1() 16861.5447 17737.2124 19321.5674 18628.8573 20117.0159 25506.208    10
# method_2()   671.2223   677.6029  1111.3935   738.6216  1657.0542  2163.137    10
# method_3()   316.9810   319.1484   481.3548   320.2337   326.7133  1477.454    10

如您所见,Rcpp方法是迄今为止最快的方法。

您还可以比较输出,以确保它们使用较小的栅格产生相同的结果。

# Examine all three outputs with smaller raster
X <- raster(matrix(rep(Y, 3), ncol = 9))

plot(method_1(), main = "Method 1")
plot(method_2(), main = "Method 2")
plot(raster(method_3()), main = "Method 3") # Needs to converted into a raster

它们看起来都一样。请注意,对于第三种方法,需要将结果从矩阵转换回栅格。