专有软件会生成丑陋的 excel 表格……我可以将它们放入 R 中吗?
Proprietary software produces ugly excel tables...can I get them into R?
我们收集蝙蝠调用并对其进行分析,结果是一场噩梦。我想简化我们的流程,但我很难过。我如何从 excel 中提取几十个文件,它们看起来像这样:
并获取导入以添加行,以便每组四行 spaced 乘 2 行(即第 3-6、9-12、15-18 行等——这是每个项目的相同间距)被导入直到达到空 space(每个项目的重复次数不同)?我还想 endCol
每个四行段为空 space...
我可以轻松地指定给定站点的范围,使用:
df<-t(readWorksheetFromFile("file directory",sheet=2,
header=FALSE,startCol=2,startRow=3,endCol=5,endRow=6))
然后它变得很丑陋,但我已经做到了:
colnames(df)<-c("Species","n","percent","mle")
BCID.df<-transform(BCID.df,Species=as.character(as.character(Species)),
n=as.numeric(as.character(n)),percent=as.numeric(as.character(percent)),
mle=as.numeric(as.character(mle)))
输出按照我想要的方式格式化,但我需要修复 endRow
和 endCol
,并且不知道如何...任何建议将不胜感激。
快速而肮脏,但如果每个块的尺寸相同,这应该可行,如示例所示:
library(XLConnect)
# Read the whole sheet in once
df <- readWorksheetFromFile("file directory",sheet=2, header=FALSE)
# Figure out how many code chunks you have (each appears to be 7 rows)
nChunks <- floor(nrow(df)/7)
# create blank list where you can house the different chunks
l <- vector("list", length=nChunks)
# Iterate over the chunks reading them each in to their own list element
for(i in 1:nChunks){
if(i > 1){
l[[i]] <- t(readWorksheetFromFile("file directory", sheet=2, header=FALSE, startCol=2, startRow=3, endCol=5, endRow=6))
}
else{
l[[i]] <- t(readWorksheetFromFile("file directory", sheet=2, header=FALSE, startCol=2, startRow=3+(7*i), endCol=5, endRow=6+(7*i)))
}
}
然后您可以进行相同的转换,但是 lapply 可以利用列表中的块。
不同的可能列标签使这有点复杂,但由于您说列名集的数量相对较少,我只想编写一个根据初始名称替换它们的函数:
renameCols <- function(x){
# First possible permutation
if(identical(colnames(x),c("nameOfColumn1","nameOfColumn2","nameOfColumn3")) {colnames(x) <- c("newName1","newName2","newName3")}
# Second possible permutation
if(identical(colnames(x),c("nameOfColumn1","nameOfColumn2","nameOfColumn3")) {colnames(x) <- c("newName1","newName2","newName3")}
# ... etc
return(x)
}
然后将列名替换函数应用于每个块(每个块存储在列表的不同元素中):
lapply(l, renameCols)
我会像评论中提到的@Frank 那样解决这个问题。我将整个文件作为一个大文件读取,然后根据文件路径信息将其拆分为一个列表。一旦这些被分成一个列表,每个数据集都可以在 lapply
循环中清理。
我正在通过 readxl::read_excel
读取整个文件,但如果您愿意,您可以通过 XLconnect 中的函数读取整个文件。
library(readxl)
orig = read_excel("test.xlsx", col_names = FALSE)
一些假数据的前六行看起来像:
X0 X1 X2 X3 X4 X5 X6
<chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 c:\file directory\acoustic data\Site 10\20160517 <NA> <NA> <NA> <NA> <NA> <NA>
2 identification summary <NA> <NA> <NA> <NA> <NA> <NA>
3 ID EPFU LANO <NA> MID <NA> <NA>
4 N 70 12 <NA> 4 <NA> <NA>
5 % 16 3 <NA> 13 <NA> <NA>
6 MLE(p) 1E-3 2E-3 <NA> <NA> <NA> <NA>
这个原始文件应该拆分成单独的 tables,这可以根据包含以 "c:" 开头的文件路径信息的行来完成。要弄清楚它们在哪里,请在整个数据集的第一列使用 cumsum
和 grepl
。
groups = cumsum(grepl("c:", orig$X0))
使用此矢量拆分文件,通过 split
.
将每个单独的 table 保存到列表中
orig_list = split(orig, groups)
现在剩下的工作是清理每个数据集,转置内容并删除任何额外的行和列。这也是您可以从文件路径中提取站点和日期信息以添加到数据集以使事情井井有条的地方,我对此进行了演示,但并非绝对必要。我把这一切都放到了一个函数中,以便在 lapply
中使用。请注意,我曾在某一时刻使用 readr::type_convert
来确保正确转换数字变量。
clean_data = function(data) {
# Get rid of any empty headers (missing values in first column)
new = data[!is.na(data[,1]),]
# Transpose
new = t(new)
# Put into data.frame, removing extraneous columns 1 to 2
# and using first row as variable names
# Convert variables to appropriate type at same time using readr::type_convert
new2 = readr::type_convert(as.data.frame(new[-1, -(1:2)]))
names(new2) = new[1, -(1:2)]
# Add site and date columns by pulling info from original "c:\..." cell
new2$site = unlist(strsplit(new[1], "\\"))[4]
new2$date = unlist(strsplit(new[1], "\\"))[5]
# Remove everything after first missing ID
new2[cumsum(is.na(new2$ID)) == 0,]
}
现在遍历所有块并清理每个块。生成的清理文件将在列表中。如果需要,您可以将它们行绑定到一个数据集中。
lapply(orig_list, clean_data)
我知道这是旧的 post,但我还是会添加我的 .02。我认为您应该使用一些简单的 VBA 来组织 Excel 中的所有内容,然后将结构良好的文件读入 R。我认为使用 [=12= 这样的事情要容易得多],与在 R 中做所有事情相比,你可以清楚地看到。您应该始终使用正确的工具来完成工作。
我们收集蝙蝠调用并对其进行分析,结果是一场噩梦。我想简化我们的流程,但我很难过。我如何从 excel 中提取几十个文件,它们看起来像这样:
并获取导入以添加行,以便每组四行 spaced 乘 2 行(即第 3-6、9-12、15-18 行等——这是每个项目的相同间距)被导入直到达到空 space(每个项目的重复次数不同)?我还想 endCol
每个四行段为空 space...
我可以轻松地指定给定站点的范围,使用:
df<-t(readWorksheetFromFile("file directory",sheet=2,
header=FALSE,startCol=2,startRow=3,endCol=5,endRow=6))
然后它变得很丑陋,但我已经做到了:
colnames(df)<-c("Species","n","percent","mle")
BCID.df<-transform(BCID.df,Species=as.character(as.character(Species)),
n=as.numeric(as.character(n)),percent=as.numeric(as.character(percent)),
mle=as.numeric(as.character(mle)))
输出按照我想要的方式格式化,但我需要修复 endRow
和 endCol
,并且不知道如何...任何建议将不胜感激。
快速而肮脏,但如果每个块的尺寸相同,这应该可行,如示例所示:
library(XLConnect)
# Read the whole sheet in once
df <- readWorksheetFromFile("file directory",sheet=2, header=FALSE)
# Figure out how many code chunks you have (each appears to be 7 rows)
nChunks <- floor(nrow(df)/7)
# create blank list where you can house the different chunks
l <- vector("list", length=nChunks)
# Iterate over the chunks reading them each in to their own list element
for(i in 1:nChunks){
if(i > 1){
l[[i]] <- t(readWorksheetFromFile("file directory", sheet=2, header=FALSE, startCol=2, startRow=3, endCol=5, endRow=6))
}
else{
l[[i]] <- t(readWorksheetFromFile("file directory", sheet=2, header=FALSE, startCol=2, startRow=3+(7*i), endCol=5, endRow=6+(7*i)))
}
}
然后您可以进行相同的转换,但是 lapply 可以利用列表中的块。
不同的可能列标签使这有点复杂,但由于您说列名集的数量相对较少,我只想编写一个根据初始名称替换它们的函数:
renameCols <- function(x){
# First possible permutation
if(identical(colnames(x),c("nameOfColumn1","nameOfColumn2","nameOfColumn3")) {colnames(x) <- c("newName1","newName2","newName3")}
# Second possible permutation
if(identical(colnames(x),c("nameOfColumn1","nameOfColumn2","nameOfColumn3")) {colnames(x) <- c("newName1","newName2","newName3")}
# ... etc
return(x)
}
然后将列名替换函数应用于每个块(每个块存储在列表的不同元素中):
lapply(l, renameCols)
我会像评论中提到的@Frank 那样解决这个问题。我将整个文件作为一个大文件读取,然后根据文件路径信息将其拆分为一个列表。一旦这些被分成一个列表,每个数据集都可以在 lapply
循环中清理。
我正在通过 readxl::read_excel
读取整个文件,但如果您愿意,您可以通过 XLconnect 中的函数读取整个文件。
library(readxl)
orig = read_excel("test.xlsx", col_names = FALSE)
一些假数据的前六行看起来像:
X0 X1 X2 X3 X4 X5 X6
<chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 c:\file directory\acoustic data\Site 10\20160517 <NA> <NA> <NA> <NA> <NA> <NA>
2 identification summary <NA> <NA> <NA> <NA> <NA> <NA>
3 ID EPFU LANO <NA> MID <NA> <NA>
4 N 70 12 <NA> 4 <NA> <NA>
5 % 16 3 <NA> 13 <NA> <NA>
6 MLE(p) 1E-3 2E-3 <NA> <NA> <NA> <NA>
这个原始文件应该拆分成单独的 tables,这可以根据包含以 "c:" 开头的文件路径信息的行来完成。要弄清楚它们在哪里,请在整个数据集的第一列使用 cumsum
和 grepl
。
groups = cumsum(grepl("c:", orig$X0))
使用此矢量拆分文件,通过 split
.
orig_list = split(orig, groups)
现在剩下的工作是清理每个数据集,转置内容并删除任何额外的行和列。这也是您可以从文件路径中提取站点和日期信息以添加到数据集以使事情井井有条的地方,我对此进行了演示,但并非绝对必要。我把这一切都放到了一个函数中,以便在 lapply
中使用。请注意,我曾在某一时刻使用 readr::type_convert
来确保正确转换数字变量。
clean_data = function(data) {
# Get rid of any empty headers (missing values in first column)
new = data[!is.na(data[,1]),]
# Transpose
new = t(new)
# Put into data.frame, removing extraneous columns 1 to 2
# and using first row as variable names
# Convert variables to appropriate type at same time using readr::type_convert
new2 = readr::type_convert(as.data.frame(new[-1, -(1:2)]))
names(new2) = new[1, -(1:2)]
# Add site and date columns by pulling info from original "c:\..." cell
new2$site = unlist(strsplit(new[1], "\\"))[4]
new2$date = unlist(strsplit(new[1], "\\"))[5]
# Remove everything after first missing ID
new2[cumsum(is.na(new2$ID)) == 0,]
}
现在遍历所有块并清理每个块。生成的清理文件将在列表中。如果需要,您可以将它们行绑定到一个数据集中。
lapply(orig_list, clean_data)
我知道这是旧的 post,但我还是会添加我的 .02。我认为您应该使用一些简单的 VBA 来组织 Excel 中的所有内容,然后将结构良好的文件读入 R。我认为使用 [=12= 这样的事情要容易得多],与在 R 中做所有事情相比,你可以清楚地看到。您应该始终使用正确的工具来完成工作。