重新格式化R中的Excel表格

我有一个有多个工作表的Excel文件。 每张表看起来像这样,底部有一些多余的数据

ABC D.... 1 time USA USA USA 2 MD CA PX 3 pork peas nuts 4 jan-11 4 2 2 5 feb-11 4 9 3 6 mar-11 8 8 3 

。 。 workbook1 | workbook2 …..

该文件是11 MB,但是当我尝试使用

 sheet<-readWorksheetFromFile("excelfile.xlsx", sheet = 1) 

我明白了

 Error: OutOfMemoryError (Java): Java heap space 

对于每张工作表,数据占用不同数量的行和列,我想写一些产生这个每张工作表的东西。

我正试图将每列转换成

 country state product unit time USA MD pork 3 jan-11 USA MD pork 3 feb-11 USA MD pork 3 mar-11 ... .. . 

在R中有没有办法做到这一点?

如果电子表格中充满了公式,则可能需要将这些值转换为值,以便轻松读取它们。 否则,我会build议使用像这样的工具 (其中包括其他)来将工作簿中的所有工作表转换为CSV文件并从那里工作。

如果你已经得到这么多,那么可以尝试一下你的问题的“重塑”部分。 在这里,我们假设“A”实际上代表一个CSV文件,其中的内容就是你的问题中的6行显示为样本数据:

 ## Create some sample data A <- tempfile() writeLines(sep="\n", con = A, text = c("time, USA, USA, USA", ", MD, CA, PX", ", pork, peas, nuts", "jan-11, 4, 2, 2", "feb-11, 4, 9, 3", "mar-11, 8, 8, 3")) 

我要做的第一件事是分别读取标题和数据。 要单独读取标题,请使用nrows指定包含标题信息的行数。 要单独读取数据,请指定skip以跳过标题行。

 B <- read.csv(A, header = FALSE, skip = 3, strip.white = TRUE) Bnames <- read.csv(A, header = FALSE, nrows = 3, strip.white = TRUE) 

使用apply将标题行paste在一起以形成生成的data.frame的名称:

 names(B) <- apply(Bnames, 2, function(x) paste(x[x != ""], collapse = "_")) B # time USA_MD_pork USA_CA_peas USA_PX_nuts # 1 jan-11 4 2 2 # 2 feb-11 4 9 3 # 3 mar-11 8 8 3 

现在是将数据从“宽”格式转换为“长格式”的一部分。 有很多方法可以做到这一点,有些使用base R,但最直接的方法是使用“reshape2”包中的meltcolsplit

 library(reshape2) BL <- melt(B, id.vars="time") cbind(BL[c("time", "value")], colsplit(BL$variable, "_", c("country", "state", "product"))) # time value country state product # 1 jan-11 4 USA MD pork # 2 feb-11 4 USA MD pork # 3 mar-11 8 USA MD pork # 4 jan-11 2 USA CA peas # 5 feb-11 9 USA CA peas # 6 mar-11 8 USA CA peas # 7 jan-11 2 USA PX nuts # 8 feb-11 3 USA PX nuts # 9 mar-11 3 USA PX nuts 

不幸的是,XLConnect不太可能在你的应用程序中工作。 我可以确认,在运行Win 7 64bit和64bit R 3.0.2的8GB内存的系统上,XLConnect以22MB的.xlsx文件失败,并且出现同样的错误。 正如@Ista指出的那样,正如这里所解释的,重启R之后,

 options(java.parameters = "-Xmx4096m") library(XLConnect) wb <- loadWorkbook("myWorkBook.xlsx") sheet <- readWorksheet(wb,"Data") 

避免了错误。 但是,导入仍然需要一个多小时 (!!)。

相反,正如@Gaffi所指出的那样,一旦表格“数据”被保存到一个csv文件(~7MB)中,就可以导入,如下所示:

 library(data.table) system.time(sheet <- fread("Data.csv")) user system elapsed 0.84 0.00 0.86 

在不到1秒钟。 在我的testing工作sheet有6列和376,000行。

对不起,这个“第二个答案”,但你真的有两个问题… @阿南达的重塑你的数据的解决scheme是非常优雅的。 这只是另一种思考方式。

如果将inputmatrix转置,则会得到一个新的matrix,其中第一列是国家,第二列是城市,第三列是“types”(因为缺less更好的术语),实际数据位于其他列(所以,每个“时间”都有一个额外的列)。

所以一个不同的方法是先转置,然后融化新的matrix。 这样可以避免创build所有连接的列名,并在稍后将其分开。 问题是, melt.data.frame是非常低效率的非常大量的列(你会在这里)。 所以这样做会比@ Ananda的方法 10倍。

一个解决scheme是使用melt.array (只需调用melt(...)与数组而不是数据框)。 如下所示,这种方法快20倍,大数据集(你的是11MB)。

 library(reshape) # for melt(...) library(microbenchmark) # for microbenchmark(...) # this is just to model your situation with more realistic size # create a large data frame (250 columns of country, city, type; 1000 rows of time) df <- rep(c("USA","UK","FR","CHN","GER"),each=50) # time + 250 columns df <- rbind(df,rep(c(c("NY","SF","CHI","BOS","LA")),each=10)) df <- rbind(df,rep(c("pork","peas","nuts","fruit","other"))) df <- rbind(df,matrix(sample(1:1000,250*1000,replace=T),ncol=250)) df <- cbind(c("time","","", as.character(as.Date(1:1000,origin="2010-01-01"))),df) df <- data.frame(df) # big warning here about duplicated row names; not important # @Ananda'a approach: transform.orig <- function(df){ B <- df[-(1:3),] Bnames <- df[1:3,] names(B) <- apply(Bnames, 2, function(x) paste(x[x != ""], collapse = "_")) BL <- melt(B, id.vars="time") final <- cbind(BL[c("time", "value")], colsplit(BL$variable, "_", c("country", "state", "product"))) return(final) } # transpose approach: transform.new <- function(df) { zz <- t(df) times <- t(zz[1,4:ncol(zz)]) colnames(zz) <- c("country","city","type", times) data <- melt(zz[-1,-(1:3)],varnames=c("id","time")) final <- cbind(country=rep(zz[-1,1],each=ncol(zz)-3), city =rep(zz[-1,2],each=ncol(zz)-3), type =rep(zz[-1,3],each=ncol(zz)-3), data[,-1]) return(final) } # benchmark microbenchmark(transform.orig(df),transform.new(df), times=5, unit="s") Unit: seconds expr min lq median uq max neval transform.orig(df) 9.2511679 9.6986330 9.889457 10.1518191 10.3354328 5 transform.new(df) 0.4383197 0.4724145 0.474212 0.5815531 0.6886383 5 

为了从Excel中读取数据,请尝试openxlsx软件包。 它使用c ++而不是java,并且更好地处理更大的excel文件。

重塑你的数据看看tidyr包。 收集function可以帮助你。