【问题标题】:Create a loop through a list and add outputs to a dataframe通过列表创建循环并将输出添加到数据框
【发布时间】:2019-06-10 13:51:56
【问题描述】:

我想遍历包含世界形状文件的国家名称列表并创建每个国家的单独形状文件。然后我想对每个 shapefile 的栅格进行计算,并将结果强制转换为以国家名称作为 ID 变量的数据框。

我已经为某个国家/地区成功编写了这篇文章,但我正在努力让它正确循环。

liech.map <- world.polys[world.polys$NAME == "Liechtenstein",]
plot(liech.map)

rasters <- stack(raster_1, raster_2)
rasters.values <- extract(rasters, liech.map)
df <- as.data.frame(rasters.values)
var <- as.data.frame(weighted.mean(x=df$raster_1, w=df$raster_2, na.rm=TRUE))

我想做的是从世界多边形 shapefile 中提取国家名称列表,为该国家创建一个单独的多边形并将其循环到每个国家。然后为每个具有国家 ID 的国家/地区输出 1 个带有“var”的数据框。

编辑

这是我到目前为止所做的事情,我真正想做的是向以下代码提供一个 ID 代码/名称列表以循环遍历。我当然可以手动复制粘贴 200 多次,但这似乎太浪费时间了!!

### leichenstein map
## 69.67 sec elapsed
tic()
LTU.map <- world.polys[world.polys$ISO3 == "LTU",]
rasters.values <- extract(rasters, LTU.map)
df <- as.data.frame(rasters.values)
rugged_LTU <- as.data.frame(weighted.mean(x=df$raster_1, w=df$raster_2, na.rm=TRUE))
var_LTU$iso3 <- "LTU"
rm(LTU.map)
toc()

# define master dataframe once
var_master <- var_LTU

### UK map
## 127.31 sec elapsed
tic()
GBR.map <- world.polys[world.polys$ISO3 == "GBR",]
rasters.values <- extract(rasters, GBR.map)
df <- as.data.frame(rasters.values)
rugged_GBR <- as.data.frame(weighted.mean(x=df$raster_1, w=df$raster_2, na.rm=TRUE))
var_GBR$iso3 <- "GBR"
var_master <- rbind(var_master, var_GBR)
rm(GBR.map)
toc()

【问题讨论】:

  • 您好 Picko90,欢迎来到该网站。您能否用一个更具重现性的示例来编辑您的帖子?可以复制/粘贴和运行的东西将是理想的。如果您使用的包带有一些预加载的数据,这通常很容易。现在,你操作的对象的结构我还不清楚,所以很难回答。
  • 嗨,对不起,我是 R 的相对新手,所以我不太确定如何制作可重现的示例......!
  • 你可以看看at this question。在您的示例中,我不知道world.polys 是什么,或者raster_1raster_2 等。请尝试发布一个包含足够代码的独立示例供人们运行它。
  • @Picko90,可以参考How to create a Minimal, Reproducible Example。另外,相关:How to Ask。您最小的、可重复的示例将大大增加您在此站点上获得帮助的机会。

标签: r dataframe polygon raster


【解决方案1】:

首先,我们创建一个要处理的列表。 world.polys 似乎是一个 data.frame 或类似的,我们想把它变成一个命名列表。

polys_by_country <- split(world.polys, word.polys$ISO3)

接下来我们将one国家的代码重构为一个函数:

extract_raster_value <- function(country_map) {
  # Here imagine country map is your LTU.mnap
  rasters.values <- extract(rasters, country_map)
  df <- as.data.frame(rasters.values)
  # compute weighted mean and implicitly return it (last value of function)
  weighted.mean(x=df$raster_1, w=df$raster_2, na.rm=TRUE)
}

好的,因此 extract_raster_value 采用国家地图并返回单个数字,即加权平均值。请注意,无需使用rm“清理”工作区。函数中定义的所有局部变量都只是函数作用域,不会污染全局环境。

您可以检查它是否有效。我必须假设确实如此,因为您没有提供可重现的示例。

LTU.map <- world.polys[world.polys$ISO3 == "LTU",]
extract_raster_value(LTU.map)

下一步是将 extract_raster_value 应用于polys_by_country 的每个元素。

您可以使用基本 R 中的 applylapply 函数,但我更喜欢使用 purrr 包中的 map 系列函数。

library("purrr")

# Apply process_country to each element of the list and return the list of results
map(polys_by_country, process_country)

这将返回一个命名列表,其中名称是 ISO3 名称,值是您的加权平均值。

您可以通过以下方式在命名数字向量中获取结果,而不是列表:

result <- map_dbl(polys_by_country, process_country)

这完全避免了循环(或更准确地说,隐藏了循环)。

如果需要,您可以轻松地将结果转换为 data.frame:

result_df <- data.frame(
  country = names(result),
  value = result
)

当然,根据world.polys 中的实际内容,可能会有更好的方法来做到这一点...通常,如果它是一个data.frame,运行起来会快得多:

library("dplyr")
world.polys %>%
  group_by(ISO3) %>%
  summarise(wm = weighted.mean(raster1, raster2))

【讨论】:

  • 谢谢。我已经更新了我原来的帖子,说明我已经成功了!
  • 好的 - 我编辑了我的答案!当然,手动操作很疯狂 :) 想要循环的反应很好。一旦你意识到你可以自动化多少,你就再也不会回去了。请注意,我无法实际测试代码,因为您没有提供最小的可重现示例(特别是,world.polysraster 未定义)。
  • 编辑了一个错字:我们需要在各种地图功能中使用polys_by_country
  • 再次感谢安托万。这一直有效,直到“地图”命令。当我尝试运行它时,我收到错误“y[i, ] 中的错误:无法从“NULL”类型的对象中获取插槽(“多边形”)”。由于我在 Stata 的背景,我很欣赏这里需要循环,但为此我需要使用我不太熟悉的 R!
猜你喜欢
  • 2019-03-02
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-19
  • 1970-01-01
相关资源
最近更新 更多