18

我正在尝试将嵌套列表结构转换为数据框。该列表类似于以下内容(它是使用 httr 包读取的解析 JSON 的序列化数据)。

  myList <- list(object1 = list(w=1, x=list(y=0.1, z="cat")), object2 = list(w=NULL, x=list(z="dog")))

编辑:我原来的示例数据太简单了。实际数据参差不齐,这意味着并非每个对象都存在所有变量,并且某些列表元素为 NULL。我编辑了数据以反映这一点。

unlist(myList)在递归展平列表方面做得很好,然后我可以lapply很好地展平所有对象。

  flatList <- lapply(myList, FUN= function(object) {return(as.data.frame(rbind(unlist(object))))}) 

最后,我可以使用plyr::rbind.fill

  myDF <- do.call(plyr::rbind.fill, flatList)
  str(myDF)

  #'data.frame':    2 obs. of  3 variables:
  #$ w  : Factor w/ 2 levels "1","2": 1 2
  #$ x.y: Factor w/ 2 levels "0.1","0.2": 1 2
  #$ x.z: Factor w/ 2 levels "cat","dog": 1 2

问题是 w 和 xy 现在被解释为字符向量,默认情况下它们被解析为数据帧中的因子。我相信这unlist()是罪魁祸首,但我想不出另一种递归展平列表结构的方法。一种解决方法是对数据帧进行后处理,然后分配数据类型。确定向量是有效数字向量还是整数向量的最佳方法是什么?

4

6 回答 6

16

正如这里所讨论的,检查是否as.numeric返回NA值是检查字符串是否包含数字数据的一种简单方法。现在您可以执行以下操作:

myDF2 <- lapply(myDF, function(col) {
  if (suppressWarnings(all(!is.na(as.numeric(as.character(col)))))) {
    as.numeric(as.character(col))
  } else {
    col
  }
})
str(myDF2)
# List of 3
#  $ w  : num [1:2] 1 2
#  $ x.y: num [1:2] 0.1 0.2
#  $ x.z: Factor w/ 2 levels "cat","dog": 1 2
于 2014-06-09T21:22:18.227 回答
11

当包含 NA 时,@josliber 的函数将不起作用(尽管它很好地回答了示例数据的问题)。@Amy M 的功能应该可以工作,但需要加载Hmisc包。

像这样的东西怎么样:

can.be.numeric <- function(x) {
    stopifnot(is.atomic(x) || is.list(x)) # check if x is a vector
    numNAs <- sum(is.na(x))
    numNAs_new <- suppressWarnings(sum(is.na(as.numeric(x))))
    return(numNAs_new == numNAs)
}

它计算NA输入向量NA中的 s 和输出中的 sas.numeric()并返回TRUE向量是否可以“安全地”转换为numeric(即不添加任何NA附加值)。

于 2017-12-06T15:30:25.530 回答
1

我没有看到 plyr::ldply 与常规基本 R 方法相比有任何优势:

 do.call(rbind, lapply(myList, data.frame) )
#-------------

        w x.y x.z
object1 1 0.1 cat
object2 2 0.2 dog

问题的出现是由于错误地尝试“扁平化”数据而不考虑其内在结构。

于 2014-06-09T21:38:58.547 回答
1

您可以使用plyr::ldply

ldply(myList,.fun=function(x)data.frame(x))

      .id w x.y x.z
1 object1 1 0.1 cat
2 object2 2 0.2 dog
于 2014-06-09T21:27:27.720 回答
0

如果您只想转换在读入时被错误归类为字符的全数字向量,您还可以使用包中的all.is.numeric函数Hmisc

myDF2 <- lapply(myDF, Hmisc::all.is.numeric, what = "vector", extras = NA)

如果向量仅包含数字,则选择what = "vector"会将向量转换为数字。NA 或其他类型的缺失值将阻止转换,除非它们在上述extras参数中指定。

但是请注意,如果应用于包含 Date 或 POSIXct 向量的整个 data.frame,这些也将转换为数字。为了防止这种情况,您可以将其包装在如下函数中:

catchNumeric <- function(dtcol) {
  require(Hmisc)
  if (is.character(dtcol)) {
    dtcol1 = all.is.numeric(dtcol, what = "vector", extras = NA)
  } else {
    dtcol1 = dtcol
  }
  return(dtcol1)
}

然后应用于您的data.frame:

myDF2 <- lapply(myDF, catchNumeric)
于 2017-09-05T19:39:34.630 回答
0

如果您有一个带有字符串的列表或向量,并且只想将数字转换为数字,则可能的解决方案是:

catchNumeric <- function(mylist) {
  newlist <- suppressWarnings(as.numeric(mylist))
  mylist <- as.list(mylist)
  mylist[!is.na(newlist)] <- newlist[!is.na(newlist)]
  mylist
}

> catchNumeric(c("123", "c12", "abc", "123.12"))
[[1]]
[1] 123

[[2]]
[1] "c12"

[[3]]
[1] "abc"

[[4]]
[1] 123.12

> catchNumeric(list("123", "c12", "abc", "123.12"))
[[1]]
[1] 123

[[2]]
[1] "c12"

[[3]]
[1] "abc"

[[4]]
[1] 123.12
于 2017-09-21T16:30:11.303 回答