R:将列表列表转换为数据框(人口普查数据)

时间:2016-07-17 21:04:54

标签: json r list dataframe census

我正在尝试使用Census API下载特定表并将其保存在数据框中。我成功下载了数据。我为调用组装了适当的URL,然后使用了包'rjson'将URL读入列表。例如:

library(rjson)    

get <- c("B19081_002M")                                      # create vector of vars
datafile <- "http://api.census.gov/data/2009/acs5?"          # ACS 05-09
get <- paste0("get=NAME,", paste(get, collapse = ','))       # variables
geo <- "for=county:*"                                        # all counties
api_key <- "key=KEYHERE"                                     # API key
url <- paste0(datafile, paste(get, geo, api_key, sep = "&")) # creates url
data <- fromJSON(file = url)                                 # read into R

# To see an example of a problematic observation
# (this should return "Hinsdale County, Colorado")

data[[273]]

但是,我很难将其转换为数据框。 fromJSON()函数创建一个列表对象。在大多数情况下,列表对象的元素是每个空间单元的chr向量(例如上例中的县),向量包含表信息和相关的元数据。在这种情况下,我使用下面的工作示例中的方法将列表转换为数据框,其中每行是不同的空间单位,每列是不同的变量。

# Create fake data
x1 <- seq(1:5)
x2 <- rep(5,5)
l1 <- list(x1,x2)

# Convert to df
cols_per_row <- length(unlist(l1[1]))
test1 <- data.frame(matrix(unlist(l1), byrow = TRUE, ncol = cols_per_row))

print(test1) # success!

X1 X2 X3 X4 X5
1  1  2  3  4  5
2  5  5  5  5  5

但是当我对list-in-list对象使用相同的方法时(由于我在API中包含不同的表而出现),我收到错误:

# Create fake data
x1 <- seq(1:5)
x2 <- rep(5,5)
x3 <- list(1,2,3,4,NULL)
l2 <- list(x1,x2,x3)

# Produces an error
cols_per_row <- length(unlist(l2[1]))
test2 <- data.frame(matrix(unlist(l2), byrow = TRUE, ncol = cols_per_row))

Warning message:
In matrix(unlist(l2), byrow = TRUE, ncol = cols_per_row) :
data length [14] is not a sub-multiple or multiple of the number of columns [5]

有人有解决方案吗?

  • 我注意到子列表仅出现在其中一个变量具有NULL值的情况下。
  • 在主列表的元素也是列表的情况下,子列表的长度等于作为向量的主列表元素的向量的长度。

备注

  • 我不需要使用fromJSON并欢迎可能使这更容易的替代方案。
  • 我不想使用'acs'包来完成此任务,所以请不要建议使用它。我正在努力学习如何处理这个问题。

2 个答案:

答案 0 :(得分:2)

我使用真实的查询给你一个黑客:

tmp <- data.frame(matrix(ncol=4))

for(i in 1:length(data)){
  if(length(t(unlist(data[i]))) == 4){
  tmp[i,] <- t(unlist(data[i]))
  } else{
    cat("Row number ", i, "has an abnormal length \n")
  }
}
Row number  273 has an abnormal length 
Row number  550 has an abnormal length 
Row number  1900 has an abnormal length 
Row number  2733 has an abnormal length 
Row number  2737 has an abnormal length 
Row number  2753 has an abnormal length
head(tmp)
1                               NAME B19081_002M state county
2     Aleutians East Borough, Alaska        8469    02    013
3 Aleutians West Census Area, Alaska        7691    02    016
4     Anchorage Municipality, Alaska         920    02    020
5         Bethel Census Area, Alaska        2414    02    050
6        Bristol Bay Borough, Alaska        9635    02    060

仅有6个&gt; 3,000有一个异常的长度,但是如果你想要救援这些行,可以通过添加另一行来填充缺失值并使用占位符。

最后,不要忘记第一行是标题,因此您可以将其写入data.frame的colnames

答案 1 :(得分:0)

也许这就是你所追求的:

simplify2array(l2)

编辑:

上述解决方案无效。作为替代方案,我会用NA替换NULL值:

# Function to replace NULL values to NA values inside a list
listNull2Na <- function(l) sapply(l, function(x) ifelse(is.null(x), NA, x))

# Substitute NULL values in your list and get matrix:
l2 <- sapply(l2, listNull2Na)