如何遍历列表并在 R 中创建单独的数据帧
how to loop through list and create separate dataframes in R
我正在尝试按县提取整个美国人口普查局的移民数据。由于数据的大小,人口普查要求您为数据导入指定 "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 循环的新手。
感谢您的任何想法。
您现有的代码会创建一个名为 migr
的对象,并为其分配一个字符串,其中包含您要创建的 data.frame 的名称。然后用从人口普查中提取的 data.frame 覆盖 migr
对象。循环的每次迭代,你覆盖 migr
,这就是为什么只保存循环的最后一次迭代的数据,然后只作为一个名为 migr
.[=23 的 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
比其他两个慢很多)。
只需将您的过程转换为一个函数并传递给 lapply
或更好的 sapply
以获取命名列表(因为它输入了一个字符向量)。重新考虑保存类似的结构,并可能分别保存许多对象,但使用 one 命名的数据帧列表。避免不必要地淹没全球环境:
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`)
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
返回的数据框。如果你想将这些全部组合成 1 个数据框,你可以使用如下代码:
migr <- do.call(rbind, migr.list)
如果你想 运行 每个州的相同代码,那么你可以只使用 lapply
或相关函数。在长 运行 中,这将比使用 get
和 assign
循环更简单且更不容易出错。
我正在尝试按县提取整个美国人口普查局的移民数据。由于数据的大小,人口普查要求您为数据导入指定 "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 循环的新手。 感谢您的任何想法。
您现有的代码会创建一个名为 migr
的对象,并为其分配一个字符串,其中包含您要创建的 data.frame 的名称。然后用从人口普查中提取的 data.frame 覆盖 migr
对象。循环的每次迭代,你覆盖 migr
,这就是为什么只保存循环的最后一次迭代的数据,然后只作为一个名为 migr
.[=23 的 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
比其他两个慢很多)。
只需将您的过程转换为一个函数并传递给 lapply
或更好的 sapply
以获取命名列表(因为它输入了一个字符向量)。重新考虑保存类似的结构,并可能分别保存许多对象,但使用 one 命名的数据帧列表。避免不必要地淹没全球环境:
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`)
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
返回的数据框。如果你想将这些全部组合成 1 个数据框,你可以使用如下代码:
migr <- do.call(rbind, migr.list)
如果你想 运行 每个州的相同代码,那么你可以只使用 lapply
或相关函数。在长 运行 中,这将比使用 get
和 assign
循环更简单且更不容易出错。