我需要处理在受密码保护的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
答案 0 :(得分:3)
> 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”执行两个作业:“取消列出”并将NULL转换为NA。
答案 1 :(得分:2)
第一步:提取名称:
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"
我认为,这就是你想要的。
答案 2 :(得分:2)
使用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
。