【问题标题】:R convert list of lists to dataframeR将列表列表转换为数据框
【发布时间】:2015-11-14 00:59:05
【问题描述】:

我需要处理受密码保护的 Excel (xlsx) 工作簿中提供的数据。出于法律原因,我无法创建不受保护的 Excel 文件或 csv 文件等并从那里进行处理。没有一个 Excel 导入包可以处理受密码保护的工作簿。

从这个答案Import password-protected xlsx workbook into R 我已经设法提取数据。但是,它是以字符列表格式导入的。我的列表的输出如下所示:

list(list("ID", "ID1", "ID2"),
     list("V2", NULL, "text2"),
     list("Name", "John Smith", "Mary Brown"),
     list("Score", 1, 2),
     list("email", "JS@gmail.com", "MB@gov.uk"))

我想要的是一个带有列 ID、V2 等的数据框,如下所示:

   ID    V2     Name        Score  email
   ID1   NULL   John Smith  1      JS@gmail.com
   ID2   text2  Mary Brown  2      MS@gov.uk

原始 Excel 工作簿中存在空单元格,因此使用 unlist 的解决方案将不起作用。

结合R list to data frame 和其他类似问题的答案,我得到以下代码(其中 listform 是列表的名称):

matform <- as.matrix(sapply(listform, function(s) s)) # retains empty
df <- data.frame(matform[2:nrow(matform),])
names(df) = matform[1,]

这很接近,但数据框将列表作为列。所以str(df) 产生:

'data.frame':   2 obs. of  5 variables:
 $ ID:List of 2
  ..$ : chr "ID1"
  ..$ : chr "ID2"
 $ V2:List of 2
  ..$ : NULL
  ..$ : chr "text2"
and so on

【问题讨论】:

  • 你能分享一个缺少数据的例子吗?
  • 对于我最初认为解决方案将是一行的问题来说,这是一个令人惊讶的棘手问题。
  • 已修改示例数据,因此存在 NULL 值。这打破了 unlist 的所有答案。

标签: r list dataframe


【解决方案1】:

第一步:提取名称:

names = lapply(listform, `[[`, 1)
data = setNames(lapply(listform, `[`, -1), names)

第二步:取消列出数据并绑定列

result = as.data.frame(sapply(data, unlist))

这里的魔法发生在sapply,它在内部调用simplify2array。最后需要as.data.frame 从结果矩阵中创建一个data.frame,并为各个列分配适当的数据类型。

上面的代码有一个问题:列类型可能不是你想要的。这可以通过以下方式修复:

col_classes = sapply(lapply(listform, `[[`, 2), typeof)
result = as.data.frame(sapply(data, unlist), stringsAsFactors = FALSE)
for (col in seq_len(ncol(result)))
    class(result[[col]]) = col_classes[col]

现在你会得到以下结果:

> str(result)
'data.frame':   2 obs. of  5 variables:
 $ ID   : chr  "ID1" "ID2"
 $ V2   : chr  "text1" "text2"
 $ Name : chr  "John Smith" "Mary Brown"
 $ Score: num  1 2
 $ email: chr  "JS@gmail.com" "MB@gov.uk"

我认为,这就是你想要的。

【讨论】:

  • 谢谢,我刚试过这个,它似乎不起作用。我应该在你有数据的地方使用我的列表(listform)还是我的数据框(df)?无论哪种方式,我似乎都没有得到一个合理的数据框。
  • @JenB 是的,对不起。使用listform 而不是data,我会修改答案。此代码绝对适用于您的示例数据。
  • 这得到了正确的结构,但不幸的是它无法处理 Excel 工作簿中的空单元格(这是 unlist 的问题)。我将尝试使用 sapply 中的 function(s) s,我认为为空瓶输入 NULL。
  • @JenB function (s) s 实际上什么都不做。与identity 相同,应用身份不是有意义的操作。你可以直接调用simplify2array(listform),而不是调用sapply来实现这个效果。但是,更好的解决方案是在应用我的代码之前填充空元素。顺便说一句,您代码中的as.matrix 也是一个多余的空操作。
  • 你是对的,没有区别 :) 所以我将不得不研究添加一些先前的代码来用 NA 填充列表
【解决方案2】:

“data.table”包中的“SetDT”似乎很强大:

> library(data.table)

> null2na <- function(x){ ifelse(is.null(x),NA,x)}

> f <- function(x){sapply(x,null2na)}

> L <- list(list("ID", "ID1", "ID2"),
+           list("V2", NULL, "text2"),
+           list("Name", "John Smith", "Mary Brown"),
+           list("S ..." ... [TRUNCATED] 

> L <- setDT(L)[, lapply(.SD, f)]

> setnames(L,colnames(L),unlist(L[1,]))

> L <- L[-1,]

> L
    ID    V2       Name Score        email
1: ID1    NA John Smith     1 JS@gmail.com
2: ID2 text2 Mary Brown     2    MB@gov.uk

> str(L)
Classes ‘data.table’ and 'data.frame':  2 obs. of  5 variables:
 $ ID   : chr  "ID1" "ID2"
 $ V2   : chr  NA "text2"
 $ Name : chr  "John Smith" "Mary Brown"
 $ Score: chr  "1" "2"
 $ email: chr  "JS@gmail.com" "MB@gov.uk"
 - attr(*, ".internal.selfref")=<externalptr> 
> 

(数据表是更好的数据框。)

函数“f”做了两项工作:它“取消列出”s 并将 NULL 转换为 NA。

【讨论】:

  • 不完全。试试str(L)。所有列仍然是列表。
  • 知道如何解决吗?
  • L &lt;- setDT(L)[, lapply(.SD, unlist)][-1] 可能(而L 是原始列表)
  • unlist 无法处理底层数据中的空单元格
  • 现在列表消失了,NULL 是 NA,通过蛮力。
【解决方案3】:

这是使用data.table v1.9.5 的一种方式(用于transpose() 函数):

require(data.table) # v1.9.5+
setDT(sapply(ll, function(x) setattr(transpose(x[-1L]), 'names', x[[1L]])))[]
#     ID    V2       Name Score        email
# 1: ID1    NA John Smith     1 JS@gmail.com
# 2: ID2 text2 Mary Brown     2    MB@gov.uk

使用setDF() 而不是setDT() 来返回data.frame

【讨论】:

  • 找不到transpose函数
  • 您是否尝试过按照答案中的说明进行操作?或者例如点击链接?提示 - “使用 data.table v1.9.5*
猜你喜欢
  • 2015-04-16
  • 1970-01-01
  • 2020-07-29
  • 1970-01-01
  • 1970-01-01
  • 2022-06-27
  • 1970-01-01
  • 2021-08-14
  • 1970-01-01
相关资源
最近更新 更多