我正在尝试获取人口普查局有关整个美国按县迁移的数据。由于数据量大,人口普查要求您为数据导入指定一个“ regionin”(即州或县)。因此,我需要遍历所有状态的列表(通过fips代码),以获取所有导入的数据。对于每种状态,我需要的输出是单独的数据框,然后可以将其使用并合并为一个大数据框。这是我编写的代码示例:
library(censusapi)
states <- c("01","02")
for(i in 1:length(states)) {
region = str_glue("state:{states[i]}")
migr = str_glue("migr2010_{states[i]}")
migr <- getCensus(name = "acs/flows", vintage = 2010,
key = "*myAPIkey*",
vars = c("MOVEDNET", "MOVEDIN", "MOVEDOUT", "AGE"),
region = "county:*", regionin = region)
}
我要获取的是每个状态分别为“ migr2010_01”,“ migr2010_02”等的数据框。我实际上要获取的是一个名为“ migr”的数据框,其中仅包含列表中最后一个状态的数据。我知道我的循环中有问题,但是由于我是R循环的新手,所以我不确定在哪里需要进行更改。 谢谢你的想法。
答案 0 :(得分:2)
只需将您的过程转换为函数,然后传递到lapply
或更好的sapply
中以获取命名列表(因为它输入了字符向量)。重新考虑保存结构相似的对象,并可能单独保存许多对象,但是使用一个命名的数据帧列表。避免不必要地淹没全球环境:
library(stringr)
library(censusapi)
states <- c("01","02")
get_census_data <- function(st)
region = str_glue("state:{st}")
migr = str_glue("migr2010_{st}")
migr <- getCensus(name = "acs/flows", vintage = 2010,
key = "*myAPIkey*",
vars = c("MOVEDNET", "MOVEDIN", "MOVEDOUT", "AGE"),
region = "county:*", regionin = region)
}
df_list <- sapply(states, get_census_data, simplify=FALSE)
# df_list <- setNames(lapply(states, get_census_data), states) # EQUIVALENT CALL
如果数据框存储在列表中而不是单独的对象,则不会丢失数据框的功能:
str(df_list$`01`)
head(df_list$`01`)
summary(df_list$`01`)
dim(df_list$`02`)
tail(df_list$`02`)
table(df_list$`02`)
答案 1 :(得分:1)
FAQ 7.21部分回答了此问题。答案最重要的部分是结尾,它说仅使用列表会更容易。
您的代码可以转换为以下内容:
library(censusapi)
library(stringr)
states <- c("01","02")
migr.list <- lapply( states, function(x) {
region = str_glue("state:{x}")
migr = str_glue("migr2010_{x}")
getCensus(name = "acs/flows", vintage = 2010,
key = "*myAPIkey*",
vars = c("MOVEDNET", "MOVEDIN", "MOVEDOUT", "AGE"),
region = "county:*", regionin = region)
})
names(migr.list) <- sprintf("migr2010_%s", states) # optional
现在migr.list
将是一个列表对象,每个元素都是getCensus
返回的数据帧。如果要将这些全部组合成一个数据帧,则可以使用如下代码:
migr <- do.call(rbind, migr.list)
如果要在每个状态下分别运行相同的代码,则可以只使用lapply
或相关功能。从长远来看,这将比通过循环使用get
和assign
更简单,而且更不容易出错。
答案 2 :(得分:0)
您现有的代码将创建一个名为migr
的对象,并为其分配一个字符串,其中包含您要创建的data.frame的名称。然后,使用从普查中提取的data.frame覆盖migr
对象。循环的每次迭代都会覆盖migr
,这就是为什么仅保存循环的最后一次迭代中的数据,然后才将其保存为名为migr
的data.frame的原因。
相反,您需要使用assign
命令将从人口普查中提取的数据分配给migr
中存储的值,如下所示:
library(censusapi)
states <- c("01","02")
for(i in 1:length(states)) {
region = str_glue("state:{states[i]}")
migr = str_glue("migr2010_{states[i]}")
assign(
x = migr,
value = getCensus(name = "acs/flows", vintage = 2010,
key = "*myAPIkey*",
vars = c("MOVEDNET", "MOVEDIN", "MOVEDOUT", "AGE"),
region = "county:*", regionin = region)
)
}
正如其他人所提到的,使用data.frame列表可能比在全局环境中创建多个数据帧更容易。最简单的创建方法是使用lapply
,如下所示:
migr2010 <- lapply(
paste0("state:", c("01", "02")), # replaces region in the original
getCensus,
name = "acs/flows",
vintage = 2010,
key = "*myAPIkey*",
vars = c("MOVEDNET", "MOVEDIN", "MOVEDOUT", "AGE"),
region = "county:*"
)
然后,如果要从中创建单个data.frame,则可以使用dplyr::bind_rows(migr2010)
,data.table::rbindlist(migr2010)
或do.call(rbind, migr2010)
(尽管do.call
慢得多比其他两个)。