【问题标题】:Converting rasterstack to csv parallel processing in R在R中将rasterstack转换为csv并行处理
【发布时间】:2016-01-21 14:32:01
【问题描述】:

我有大型栅格 (>20 GB),并希望将每个栅格转换为特殊格式的 csv 文件,如下所示:

unique_key_column
x_coordinate
y_coordinate
layer1_values
layer2_values

等等

library(raster)
r <- raster(nrows=10,ncols=10)
r[] <- rnorm(10)
stack <- stack(r,r,r,r,r)

   #create function to convert coordinate to special format
   # -34.9 will be 1034900000 
   # sxxxdddddd, where s= sign (-=1, +=2), x=degrees (34=034), 
   # and d = decimal (.9=900000)

formatCoordinate <- function(x){
  first_part <- ifelse(x < 0 , "1","2")
  second_part <- abs(as.integer(x))
  #make sure 3 part has 6 decimal places, then convert it to string
  third_part <- substr(gsub(".+\\.","",as.character(format(round(x, 2),
                             nsmall = 6))),1,6)
  result <- sprintf("%s%03d%s",first_part,second_part,third_part)
  result
}

  #the actual processing

stack =readAll(stack)
names(stack) <-c("l1", "l2", "l3", "l4", "l5")
#convert rasterStack to dataframe
stackPoints <- as.data.frame(rasterToPoints(stack))
#format x and x coordinates
colX <- formatCoordinate(stackPoints$x)
colY <- formatCoordinate(stackPoints$y)
#combine formatted x and y coordinates to compose a unique key
pK <- paste0(colX, colY )
stackPoints["key"] <- pK
col_idx <- grep("key", names(stackPoints))
stackPoints <- stackPoints[, c(col_idx, (1:ncol(stackPoints))[-col_idx])]
#write results to a csv file
write.table(stackPoints, "r.csv", row.names=F, sep=";", dec=",", append=F)

上面的代码适用于小型栅格,但对于大型栅格,我无法将堆栈加载到 RAM。 有没有办法将我的代码转换为使用并行处理?即使用多核读取光栅并写入 csv,而无需将光栅加载到 RAM(Mac OSX 10.11 和 Ubuntu 14.04,每个 8 核)。 最好的,

【问题讨论】:

  • 你的操作系统是什么?您需要使用的并行库取决于操作系统
  • 感谢您的提示。我有 Mac El-Captain 和 Ubuntu(在两台不同的计算机上)。我在问题中添加了这个细节:D
  • here开始。
  • 如果您在使用单线程时内存不足,增加线程数不一定对您有帮助。
  • 文档中的思路很清晰(不过应用比较难!希望有视频能解释更多应用的思路)。我在这里尝试了类似功能 [cran.r-project.org/web/packages/raster/vignettes/functions.pdf].不幸的是,我没有成功在我的函数的小插图中应用相同的函数

标签: r csv parallel-processing raster r-raster


【解决方案1】:

首先,您想弄清楚如何在单个线程上编写循环,因为从for() 移动到foreach() 将非常简单。我不熟悉 RasterStack 对象,但它看起来像它的层可以用nlayers(x) 计数并且可以用x[[i]] 提取。

所以首先我会编写和调试类似的东西:

for(i in 1:nlayers(stack)){
  #convert layer of rasterStack to dataframe
  layer_pts <- as.data.frame(rasterToPoints(stack[[i]]))

  #write layer_pts to a csv file
}

那么foreach() 就很简单了。请记住,您需要使用 raster 包启动每个线程。对于更快的合并,我推荐data.table

library(foreach)
library(doMC)
library(data.table)
registerDoMC(detectCores() - 2) # for me this is 40 - 2 = 38
layer_list <- 
  foreach(i = 1:nlayers(stack), .packages = c('raster', 'data.table') ) %dopar% {
    #convert layer of rasterStack to data.table
    layer_pts <- as.data.table(rasterToPoints(stack[[i]]))
    setkey(layer_pts, x, y) # data.table can key on x and y, no synthetic key needed
    layer_pts
  }

tbl_out <- Reduce(merge, layer_list) # uses keys from setkey

# if you wanted the "key" column (but not essential)
tbl_out[, key:= paste0( formatCoordinate(x), formatCoordinate(y) ) ]

write.csv(tbl_out, 'r.csv')

请注意,如果内存不足,您可能必须减少使用的内核数量。例如,registerDoMC(4) 基于反复试验。

【讨论】:

  • 太棒了!现在我知道如何轻松使用 foreach 了:D 我在我的数据上进行了尝试,它运行良好且快速。但是我面临一个问题,为一层生成一个 CSV(总共大约 450 个 CSV)。由于 NA 值,CSV 具有不同的行数,因此我无法轻松地将它们连接到每个堆栈的一个 CSV 中(即使使用唯一键。有没有办法解决这个问题?更改循环以剪辑小图块,然后将它们转换为 CSV (然后将它们加在一起)可以产生一致数量的列,但这需要更长的时间并且需要更多的 RAM 等等
  • @user22364 好的,你的第一句话让我觉得你想要每个栅格一个 CSV。但现在我看到了您正在寻找的东西——layer1_values, layer2_values 等都在 CSV 的同一行上。我会考虑的。
  • 非常感谢您的帮助:D
  • @user22364 好的,我想这就是你想要的。
  • 很抱歉回来晚了,周末的烟道可不好!我尝试了您更新的代码,即使使用 2 个内核,R 也崩溃了。我认为原因是内存不足,因为一个完整的堆栈大约 30 GB。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-13
  • 1970-01-01
  • 2021-07-05
相关资源
最近更新 更多