R:将不同嵌套度的列表转换为数据框

时间:2016-07-23 00:27:26

标签: r validation object types

简介

我正在尝试将Census API调用的输出(保存为.rds file here)转换为R数据框对象。为方便起见,我们调用对象'x'。

  • 对象x是一个列表,其中每个元素都是美国县。
  • 每个县也是一个清单。
  • 县列表的每个元素都是一个块组。
  • 每个块组包含一个常量的元素数(让我们称之为z)。如果其中一个元素的值为“NULL”,则块组是另一个列表。如果没有元素是值“NULL”,则块组是字符向量。
  • 如果其中一个元素的值为“NULL”,则结果列表将包含类“NULL”的元素(如果它是值“NULL”)。否则,它是“字符”类。
  • 我知道县的数量,但没有其他变量的长度。每个县可能有不同数量的区块组,但每个区块组都有相同的z元素,无论其类别如何。

更确切地说是

  • x的每个元素都是一个列表

      # Both of below return 'list'
      class(x[i])
      class(x[[i]])
    
  • 该列表的每个元素都是......

    • 字符向量

      # Returns 'list'
       class(x[[i]][k])
      
      
      # Returns 'character'
       class(x[[i]][[k]])
      
    • 列表

      # Returns 'list'
       class(x[[i]][k])
      
      
      # Returns 'list'
       class(x[[i]][[k]])
      

元素是列表还是字符向量的决定因素是值“NULL”是否出现在数据行中。如果该行的一个元素是“NULL”,则该元素是一个列表。如果该行的所有元素都不是“NULL”,那么该元素就是一个字符向量。

  • 如果以上是列表,如果值为NULL,则列表中的每个元素都是“NULL”类;如果值不是“NULL”,则列表中的每个元素都是类字符

        # Returns 'list'
         class(x[[i]][[k]][g])
    
        # Returns "NULL" if "NULL" else "character"
         class(x[[i]][[k]][[g]])
    

问题

有人可以提出将其转换为数据框的方法吗?我很难搞清楚如何将块组元素转换为我可以应用(或循环)的对象。

编辑:数据的一个例子

响应可重现示例的请求,请参阅以下代码。它演示了我的数据的小版本(我的数据包含许多县,黑组和变量)。请注意,每个块组向量或列表的长度等于变量的数量,因为向量的元素是该相应变量的块组的值。我的目标是生成一个列名为var1,var2,var3,var4的数据框,而每一行代表一个块组的值。

set.seed(5) 

# County 1
bezz <- c("var1","var2","var3","var4")          # variable names
bizz <- as.character(round(rnorm(4),2))         # block group 1.1
buzz <- list("NULL","NULL","2","94389")         # block group 1.2
bozz <- as.character(round(rnorm(4),2))         # block group 1.3
bazz <- list("NULL","NULL","888888888","NULL")  # block group 1.4
foo <- list(bezz, bizz,buzz,bozz,bazz)          # county 1 object

# County 2
fezz <- c("var1","var2","var3","var4")          # variable names
fizz <- list("NULL","2","NULL","94389")         # block group 2.1
fuzz <- as.character(round(rnorm(4),2))         # block group 2.2
fozz <- as.character(round(rnorm(4),2))         # block group 2.3
bar <- list(fezz, fizz,fuzz,fozz)               # county 2 object

# County 3
lezz <- c("var1","var2","var3","var4")          # variable names
luzz <- as.character(round(rnorm(4),2))         # block group 3.1
baz <- list(lezz, luzz)                         # county 3 object

# API output
mydata <- list(foo,bar,baz)                     # all counties in a list 

1 个答案:

答案 0 :(得分:1)

此解决方案要求将所有NULL转换为NA。由于所有数据都显示为数字,因此使用了as.numeric(),如果不是您想要的话,只需删除。

这应该需要一段时间,也许有更有效的方法来解决这个问题。这两个循环可以合二为一,但为了清楚起见,NULLNA循环已经分开了。

have <- readRDS("~/R/SO/acs0509_block_group_call.Rds")

# replace NULL's with NA's
for(i in seq_along(have)) {
  for(j in seq_along(have[[i]])) {
    for(k in seq_along(have[[i]][[j]])) {
      have[[i]][[j]][[k]] <- ifelse(is.null(have[[i]][[j]][[k]]),NA,have[[i]][[j]][[k]])
    }
  }
}

# initiate "want" data.frame with an arbitrary row
want <- as.data.frame(t(as.numeric(have[[1]][[2]])))
colnames(want) <- have[[1]][[1]]

ins.row <- 1

for(i in 1:length(have)) {
  for(j in 2:(length(have[[i]]))) {
    if(is.list(have[[i]][[j]]))
      want[ins.row,] <- as.numeric(unlist(have[[i]][[j]]))
    else
      want[ins.row,] <- as.numeric(have[[i]][[j]])
    ins.row <- ins.row + 1
  }
}