如何用purrr::map替代lapply处理tidycensus指定州郡数据?
用purrr::pmap()简化tidycensus批量下载代码并修复报错
首先咱们先拆解你遇到的两个核心问题:
- 参数顺序错误:你在Map调用里把
get_Census的参数传反了——原函数的参数是(x,y,z)对应state, county, year,但你写的get_Census(i, x, z)把county(i)当成了state参数,state(x)当成了county参数,这就导致了FIPS代码不匹配的警告(比如把亚利桑那州的代码04当成了某个州的county代码)。 - 返回值类型问题:
st_write返回的是完整的sf对象,嵌套的lapply/Map组合期望返回长度为1的原子向量,这就触发了Result 1 is not a length 1 atomic vector的错误。
下面是用purrr包重构的更简洁、更易维护的方案:
步骤1:整理所有下载任务
把需要的state-county-year组合整理成一个数据框,所有任务一目了然,后续修改或新增都非常方便:
library(tidycensus) library(sf) library(purrr) library(dplyr) # 替换成你的API密钥 mykey <- "youhavetogetyourownimafraid" setwd("N:/Dropbox/_BonesFirst/149_Transit_Metros_BG_StateSplit_by_R") # 整理所有下载任务:每行对应一个state-county-year组合 census_tasks <- tibble( state = c(rep("04", 1), rep("06", 3), rep("08", 3), rep("27", 3), rep("37", 1), rep("48", 4), rep("49", 1), rep("53", 2)), county = c("013", "067", "073", "113", "005", "031", "035", "037", "053", "123", "119", "085", "113", "121", "201", "035", "033", "053"), year = rep("2000", length(county)) )
步骤2:优化下载函数
调整函数参数名(让参数名和数据框列名一致,彻底避免传参错误),并设置合理的返回值(如果不需要保留数据,返回invisible(NULL)可以节省内存并避免报错):
get_Census <- function(state, county, year) { # 生成输出文件名 output_name <- paste0("transitmetro_", state, "_", county, "_", year) # 下载普查数据 census_data <- get_decennial( geography = "block group", variables = "P001001", sumfile = "sf1", key = mykey, state = state, county = county, year = year, geometry = TRUE ) # 写入Shapefile,quiet=TRUE可以减少冗余输出 st_write(census_data, paste0(output_name, ".shp"), quiet = TRUE) # 如果不需要保留数据,返回invisible(NULL);如果需要保留,返回census_data invisible(NULL) }
步骤3:用purrr::pmap批量执行
pmap可以完美处理多参数的批量任务,它会自动根据数据框的列名匹配函数参数,彻底避免参数顺序错误:
# 批量执行所有下载任务 pmap(census_tasks, get_Census)
可选:保留下载的数据并命名列表
如果你需要把每个下载的sf对象保存到列表里,可以修改函数返回census_data,然后给列表命名:
# 修改函数返回下载的数据 get_Census <- function(state, county, year) { output_name <- paste0("transitmetro_", state, "_", county, "_", year) census_data <- get_decennial( geography = "block group", variables = "P001001", sumfile = "sf1", key = mykey, state = state, county = county, year = year, geometry = TRUE ) st_write(census_data, paste0(output_name, ".shp"), quiet = TRUE) census_data } # 执行并命名列表 tibble_list <- pmap(census_tasks, get_Census) names(tibble_list) <- paste0("tibble", census_tasks$state, "_", census_tasks$county, "_10")
为什么这个方案更好?
- 可读性强:用数据框管理所有任务,比多个分散的列表更容易维护
- 避免参数错误:
pmap通过参数名匹配,不用再担心参数顺序搞反 - 代码简洁:替代了重复的
lapply调用,减少冗余代码
内容的提问来源于stack exchange,提问作者Mox
相关产品推荐
相关产品推荐

