从 R 的 sf 包中并行化 st_union

Parallelize st_union from R's sf package

我有一些大型 shapefile,其中包含数百万个多边形,我需要对其进行溶解。根据 shapefile,我需要按组溶解或只对所有使用 st_union。我一直在使用 st_par function 并且它对大多数 sf 应用程序都非常有效。尽管当我在 st_union 上使用此函数时,它 returns 是一个列表,但我不知道如何并行化 sf 溶解函数 st_union.

任何建议都会很有帮助!这是一个小代码片段来说明我的观点。

library(sf)
library(assertthat)
library(parallel)

us_shp <- "data/cb_2016_us_state_20m/cb_2016_us_state_20m.shp"
if (!file.exists(us_shp)) {
  loc <- "https://www2.census.gov/geo/tiger/GENZ2016/shp/cb_2016_us_state_20m.zip"
  dest <- paste0("data/cb_2016_us_state_20m", ".zip")
  download.file(loc, dest)
  unzip(dest, exdir = "data/cb_2016_us_state_20m")
  unlink(dest)
  assert_that(file.exists(us_shp))
}

usa <- st_read("data/cb_2016_us_state_20m/cb_2016_us_state_20m.shp", quiet= TRUE) %>%
  filter(!(STUSPS %in% c("AK", "HI", "PR")))

test <- usa %>%
  st_par(., st_union, n_cores = 2)

我认为你可以通过对原始文件进行小的修改来解决你的具体问题st_par function
然而,这只是一个快速而大胆的修复,这可能会破坏该函数其他用途的代码。
该函数的作者当然可以提供更好的修复...

library(parallel)
# Paralise any simple features analysis.
st_par <- function(sf_df, sf_func, n_cores, ...){

    # Create a vector to split the data set up by.
    split_vector <- rep(1:n_cores, each = nrow(sf_df) / n_cores, length.out = nrow(sf_df))

    # Perform GIS analysis
    split_results <- split(sf_df, split_vector) %>%
        mclapply(function(x) sf_func(x), mc.cores = n_cores)

    # Combine results back together. Method of combining depends on the output from the function.
    if ( length(class(split_results[[1]]))>1 | class(split_results[[1]])[1] == 'list' ){
        result <- do.call("c", split_results)
        names(result) <- NULL
    } else {
        result <- do.call("rbind", split_results)
    }

    # Return result
    return(result)
}

我试图将其用于 st_join,但 运行 遇到了 returned 数据类型的问题。在更仔细地查看结果时,很明显 split_results 只是 sf 对象的列表。我最终修改了代码以使用 dplyr::bind_rows() 来获得我想要的。

“组合”可能需要更多逻辑来处理不同的 return 类型,但这适用于 st_join 函数。

# Parallelise any simple features analysis.
st_par <- function(sf_df, sf_func, n_cores, ...) {

  # Create a vector to split the data set up by.
  split_vector <- rep(1:n_cores, each = nrow(sf_df) / n_cores, length.out = nrow(sf_df))

  # Perform GIS analysis
  split_results <- split(sf_df, split_vector) %>%
    mclapply(function(x) sf_func(x, ...), mc.cores = n_cores)

  # Combine results back together. Method of combining probably depends on the
  # output from the function. For st_join it is a list of sf objects. This
  # satisfies my needs for reverse geocoding
  result <- dplyr::bind_rows(split_results)

  # Return result
  return(result)
}