You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:03:37